diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index f1dbf744dc4..081d0136be9 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,16 +4,20 @@ updates:
- package-ecosystem: "npm"
directory: "/website"
schedule:
- interval: "daily"
+ interval: "weekly"
commit-message:
prefix: "chore"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
- interval: "daily"
+ interval: "weekly"
commit-message:
prefix: "chore"
+ groups:
+ all:
+ patterns:
+ - "*"
- package-ecosystem: "gomod"
directory: "/"
@@ -26,3 +30,36 @@ updates:
update-types:
- "version-update:semver-major"
- "version-update:semver-minor"
+ groups:
+ k8s:
+ patterns:
+ - "k8s.io/*"
+ - "sigs.k8s.io/*"
+
+ - package-ecosystem: "docker"
+ directory: /
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore"
+
+ - package-ecosystem: "docker"
+ directory: "/build/tooling"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore"
+
+ - package-ecosystem: "docker"
+ directory: "/test/externaldata/dummy-provider"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore"
+
+ - package-ecosystem: "docker"
+ directory: "/test/image"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore"
diff --git a/.github/workflows/benchmark.yaml b/.github/workflows/benchmark.yaml
index 8b9fcbd76aa..40203bff4ce 100644
--- a/.github/workflows/benchmark.yaml
+++ b/.github/workflows/benchmark.yaml
@@ -3,47 +3,47 @@ on:
issue_comment:
types: [created]
-jobs:
+permissions:
+ contents: read
+
+jobs:
benchmark:
name: "Benchmark"
if: github.event.issue.pull_request && github.event.comment.body == '/benchmark'
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
timeout-minutes: 60
permissions:
contents: write
pull-requests: write
steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
- uses: izhangzhihao/delete-comment@98aa1ea5c6304048edf951c20b3114e03c785c79
- with:
+ with:
github_token: ${{ secrets.GITHUB_TOKEN }}
delete_user_name: github-actions[bot]
issue_number: ${{ github.event.issue.number }}
- - name: install kubebuilder
- run: |
- curl -L -O "https://github.com/kubernetes-sigs/kubebuilder/releases/download/v${KUBEBUILDER_VERSION}/kubebuilder_${KUBEBUILDER_VERSION}_linux_amd64.tar.gz" &&\
- tar -zxvf kubebuilder_${KUBEBUILDER_VERSION}_linux_amd64.tar.gz &&\
- sudo mv kubebuilder_${KUBEBUILDER_VERSION}_linux_amd64 /usr/local/kubebuilder
- env:
- KUBEBUILDER_VERSION: 2.3.1
-
- name: Update status
- uses: peter-evans/create-or-update-comment@v2
+ uses: peter-evans/create-or-update-comment@c6c9a1a66007646a28c153e2a8580a5bad27bcfa # v3.0.2
with:
issue-number: ${{ github.event.issue.number }}
body: |
[Running benchmark here...](${{ github.server.url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
- name: Check out base code into the Go module directory
- uses: actions/checkout@v3
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v3.5.2
with:
ref: ${{ github.base_ref }}
- name: Run benchmarks on base ref
run: make benchmark-test BENCHMARK_FILE_NAME="../base_benchmarks.txt"
-
+
- name: Check out code into the Go module directory
- uses: actions/checkout@v3
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v3.5.2
- name: Run benchmark with incoming changes
run: make benchmark-test BENCHMARK_FILE_NAME="pr_benchmarks.txt"
@@ -61,11 +61,11 @@ jobs:
echo '$delimiter' >> $GITHUB_OUTPUT
- name: Create commit comment
- uses: peter-evans/create-or-update-comment@v2
+ uses: peter-evans/create-or-update-comment@c6c9a1a66007646a28c153e2a8580a5bad27bcfa # v3.0.2
with:
issue-number: ${{ github.event.issue.number }}
body: |
This PR compares its performance to the latest released version. If it performs significantly lower, consider optimizing your changes to improve the performance.
- ```
+ ```
${{ steps.get-comment-body.outputs.msg }}
```
diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml
index 8d56a47bed3..4b410e173dd 100644
--- a/.github/workflows/codeql.yaml
+++ b/.github/workflows/codeql.yaml
@@ -11,21 +11,26 @@ permissions: read-all
jobs:
analyze:
name: Analyze
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
permissions:
security-events: write
steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
- name: Checkout repository
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
- name: Initialize CodeQL
- uses: github/codeql-action/init@a34ca99b4610d924e04c68db79e503e1f79f9f02
+ uses: github/codeql-action/init@fdcae64e1484d349b3366718cdfef3d404390e85
with:
languages: go
- name: Autobuild
- uses: github/codeql-action/autobuild@a34ca99b4610d924e04c68db79e503e1f79f9f02
+ uses: github/codeql-action/autobuild@fdcae64e1484d349b3366718cdfef3d404390e85
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@a34ca99b4610d924e04c68db79e503e1f79f9f02
+ uses: github/codeql-action/analyze@fdcae64e1484d349b3366718cdfef3d404390e85
diff --git a/.github/workflows/dapr-pubsub.yaml b/.github/workflows/dapr-pubsub.yaml
new file mode 100644
index 00000000000..5f74ffd9cb7
--- /dev/null
+++ b/.github/workflows/dapr-pubsub.yaml
@@ -0,0 +1,64 @@
+name: dapr-pubsub
+on:
+ push:
+ paths:
+ - "pkg/pubsub/dapr"
+ - "test/pubsub/**"
+ pull_request:
+ paths:
+ - "pkg/pubsub/dapr"
+ - "test/pubsub/**"
+permissions: read-all
+
+jobs:
+ dapr_test:
+ name: "Dapr pubsub test"
+ runs-on: ubuntu-22.04
+ timeout-minutes: 15
+ strategy:
+ matrix:
+ DAPR_VERSION: ["1.10"]
+ steps:
+ - name: Check out code into the Go module directory
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
+
+ - name: Bootstrap e2e
+ run: |
+ mkdir -p $GITHUB_WORKSPACE/bin
+ mkdir .tmp
+ echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH
+ make e2e-bootstrap
+ make e2e-helm-install
+ helm repo add dapr https://dapr.github.io/helm-charts/
+ helm repo add bitnami https://charts.bitnami.com/bitnami
+ helm repo update
+ helm upgrade --install dapr dapr/dapr --version=${{ matrix.DAPR_VERSION }} --namespace dapr-system --create-namespace --wait --debug
+ helm upgrade --install redis bitnami/redis --namespace default --set image.tag=7.0-debian-11 --wait --debug
+ make e2e-subscriber-build-load-image
+ make e2e-subscriber-deploy
+
+ - name: Run e2e
+ run: |
+ make docker-buildx IMG=gatekeeper-e2e:latest
+ make e2e-build-load-externaldata-image
+ make docker-buildx-crds CRD_IMG=gatekeeper-crds:latest
+ kind load docker-image --name kind gatekeeper-e2e:latest gatekeeper-crds:latest
+ kubectl create ns gatekeeper-system
+ make e2e-publisher-deploy
+ make e2e-helm-deploy HELM_REPO=gatekeeper-e2e HELM_CRD_REPO=gatekeeper-crds HELM_RELEASE=latest ENABLE_PUBSUB=true
+ make test-e2e ENABLE_PUBSUB_TESTS=1
+
+ - name: Save logs
+ if: ${{ always() }}
+ run: |
+ kubectl logs -n fake-subscriber -l app=sub --tail=-1 > logs-audit-subscribe.json
+ kubectl logs -n gatekeeper-system -l control-plane=audit-controller --tail=-1 > logs-audit-publish.json
+
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v3
+ if: ${{ always() }}
+ with:
+ name: pubsub-logs
+ path: |
+ logs-*.json
+
diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml
new file mode 100644
index 00000000000..48a9079fa9b
--- /dev/null
+++ b/.github/workflows/dependency-review.yml
@@ -0,0 +1,27 @@
+# Dependency Review Action
+#
+# This Action will scan dependency manifest files that change as part of a Pull Request,
+# surfacing known-vulnerable versions of the packages declared or updated in the PR.
+# Once installed, if the workflow run is marked as required,
+# PRs introducing known-vulnerable packages will be blocked from merging.
+#
+# Source repository: https://github.com/actions/dependency-review-action
+name: 'Dependency Review'
+on: [pull_request]
+
+permissions:
+ contents: read
+
+jobs:
+ dependency-review:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
+ - name: 'Checkout Repository'
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v3.5.2
+ - name: 'Dependency Review'
+ uses: actions/dependency-review-action@6c5ccdad469c9f8a2996bfecaec55a631a347034 # v3.1.0
diff --git a/.github/workflows/license-lint.yaml b/.github/workflows/license-lint.yaml
new file mode 100644
index 00000000000..5a9dcd8b463
--- /dev/null
+++ b/.github/workflows/license-lint.yaml
@@ -0,0 +1,42 @@
+name: license-lint
+on:
+ push:
+ paths:
+ - "go.mod"
+ - "go.sum"
+ - "vendor/**"
+ pull_request:
+ paths:
+ - "go.mod"
+ - "go.sum"
+ - "vendor/**"
+
+permissions:
+ contents: read
+
+jobs:
+ license-lint:
+ name: "license-lint"
+ runs-on: ubuntu-22.04
+ timeout-minutes: 5
+ permissions:
+ contents: read
+ steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
+ - name: Set up Go
+ uses: actions/setup-go@v4 # v4.0.1
+ with:
+ go-version: "1.21"
+
+ - name: Check out code into the Go module directory
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v3.5.2
+
+ - name: license-lint
+ run: |
+ export GOPATH="$HOME/go"
+ PATH="$GOPATH/bin:$PATH"
+ ./third_party/k8s.io/kubernetes/hack/verify-licenses.sh
diff --git a/.github/workflows/pre-release.yaml b/.github/workflows/pre-release.yaml
new file mode 100644
index 00000000000..3b6852fc171
--- /dev/null
+++ b/.github/workflows/pre-release.yaml
@@ -0,0 +1,73 @@
+name: pre-release
+on:
+ push:
+ branches:
+ - master
+
+permissions: read-all
+
+env:
+ IMAGE_REPO: openpolicyagent/gatekeeper
+ CRD_IMAGE_REPO: openpolicyagent/gatekeeper-crds
+ GATOR_IMAGE_REPO: openpolicyagent/gator
+
+jobs:
+ pre-release:
+ name: "Pre Release"
+ runs-on: "ubuntu-22.04"
+ if: github.ref == 'refs/heads/master' && github.event_name == 'push' && github.repository == 'open-policy-agent/gatekeeper'
+ timeout-minutes: 30
+ steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
+ - name: Check out code into the Go module directory
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
+
+ - name: Publish development
+ run: |
+ make docker-login
+
+ tokenUri="https://auth.docker.io/token?service=registry.docker.io&scope=repository:${{ env.IMAGE_REPO }}:pull&scope=repository:${{ env.CRD_IMAGE_REPO }}:pull&scope=repository:${{ env.GATOR_IMAGE_REPO }}:pull"
+ bearerToken="$(curl --silent --get $tokenUri | jq --raw-output '.token')"
+ listUri="https://registry-1.docker.io/v2/${{ env.IMAGE_REPO }}/tags/list"
+ authz="Authorization: Bearer $bearerToken"
+ version_list="$(curl --silent --get -H "Accept: application/json" -H "$authz" $listUri | jq --raw-output '.')"
+ exists=$(echo $version_list | jq --arg t ${GITHUB_SHA::7} '.tags | index($t)')
+ if [[ $exists == null ]]
+ then
+ make docker-buildx-dev \
+ DEV_TAG=${GITHUB_SHA::7} \
+ PLATFORM="linux/amd64,linux/arm64,linux/arm/v7" \
+ OUTPUT_TYPE=type=registry \
+ GENERATE_ATTESTATIONS=true
+ fi
+
+ listUri="https://registry-1.docker.io/v2/${{ env.CRD_IMAGE_REPO }}/tags/list"
+ version_list="$(curl --silent --get -H "Accept: application/json" -H "$authz" $listUri | jq --raw-output '.')"
+ exists=$(echo $version_list | jq --arg t ${GITHUB_SHA::7} '.tags | index($t)')
+ if [[ $exists == null ]]
+ then
+ make docker-buildx-crds-dev \
+ DEV_TAG=${GITHUB_SHA::7} \
+ PLATFORM="linux/amd64,linux/arm64" \
+ OUTPUT_TYPE=type=registry \
+ GENERATE_ATTESTATIONS=true
+ fi
+
+ listUri="https://registry-1.docker.io/v2/${{ env.GATOR_IMAGE_REPO }}/tags/list"
+ version_list="$(curl --silent --get -H "Accept: application/json" -H "$authz" $listUri | jq --raw-output '.')"
+ exists=$(echo $version_list | jq --arg t ${GITHUB_SHA::7} '.tags | index($t)')
+ if [[ $exists == null ]]
+ then
+ make docker-buildx-gator-dev \
+ DEV_TAG=${GITHUB_SHA::7} \
+ PLATFORM="linux/amd64,linux/arm64,linux/arm/v7" \
+ OUTPUT_TYPE=type=registry \
+ GENERATE_ATTESTATIONS=true
+ fi
+ env:
+ DOCKER_USER: ${{ secrets.DOCKER_USER }}
+ DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
diff --git a/.github/workflows/release-pr.yaml b/.github/workflows/release-pr.yaml
index c9dc9b577a0..6024bff084b 100644
--- a/.github/workflows/release-pr.yaml
+++ b/.github/workflows/release-pr.yaml
@@ -15,12 +15,17 @@ permissions:
jobs:
create-release-pull-request:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
- - name: Set up Go 1.19
- uses: actions/setup-go@v3
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
with:
- go-version: 1.19
+ egress-policy: audit
+
+ - name: Set up Go
+ uses: actions/setup-go@v4 # v4.0.1
+ with:
+ go-version: "1.21"
- name: Set release version and target branch for vNext
if: github.event_name == 'push'
@@ -54,7 +59,7 @@ jobs:
echo "TARGET_BRANCH=master" >> ${GITHUB_ENV}
fi
- - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
+ - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
with:
fetch-depth: 0
@@ -72,7 +77,7 @@ jobs:
run: make version-docs NEWVERSION=v${MAJOR_VERSION}.${MINOR_VERSION}.x
- name: Create release pull request
- uses: peter-evans/create-pull-request@v4
+ uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # v5.0.2
with:
commit-message: "chore: Prepare ${{ env.NEWVERSION }} release"
title: "chore: Prepare ${{ env.NEWVERSION }} release"
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
new file mode 100644
index 00000000000..ff777f95381
--- /dev/null
+++ b/.github/workflows/release.yaml
@@ -0,0 +1,157 @@
+name: release
+on:
+ push:
+ tags:
+ - 'v*'
+
+env:
+ IMAGE_REPO: openpolicyagent/gatekeeper
+ CRD_IMAGE_REPO: openpolicyagent/gatekeeper-crds
+ GATOR_IMAGE_REPO: openpolicyagent/gator
+
+permissions:
+ contents: read
+
+jobs:
+ tagged-release:
+ name: "Tagged Release"
+ runs-on: "ubuntu-22.04"
+ permissions:
+ contents: write
+ if: startsWith(github.ref, 'refs/tags/v') && github.repository == 'open-policy-agent/gatekeeper'
+ timeout-minutes: 45
+ steps:
+ - name: Cleanup disk
+ run: |
+ # Filter out local helm-gh-pages image so we don't delete it
+ docker system prune -a -f --filter "label!=org.opencontainers.image.source=https://github.com/stefanprodan/alpine-base"
+
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
+ - name: Check out code into the Go module directory
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
+
+ - name: Set up Go
+ uses: actions/setup-go@v4 # v4.0.1
+ with:
+ go-version: "1.21"
+
+ - name: Get tag
+ id: get_version
+ run: |
+ echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
+
+ - name: Publish release
+ run: |
+ make docker-login
+
+ tokenUri="https://auth.docker.io/token?service=registry.docker.io&scope=repository:${{ env.IMAGE_REPO }}:pull&scope=repository:${{ env.CRD_IMAGE_REPO }}:pull&scope=repository:${{ env.GATOR_IMAGE_REPO }}:pull"
+ bearerToken="$(curl --silent --get $tokenUri | jq --raw-output '.token')"
+ listUri="https://registry-1.docker.io/v2/${{ env.IMAGE_REPO }}/tags/list"
+ authz="Authorization: Bearer $bearerToken"
+ version_list="$(curl --silent --get -H "Accept: application/json" -H $authz $listUri | jq --raw-output '.')"
+ exists=$(echo $version_list | jq --arg t ${TAG} '.tags | index($t)')
+ if [[ $exists == null ]]
+ then
+ make docker-buildx-release \
+ VERSION=${TAG} \
+ PLATFORM="linux/amd64,linux/arm64,linux/arm/v7" \
+ OUTPUT_TYPE=type=registry \
+ GENERATE_ATTESTATIONS=true
+ fi
+
+ listUri="https://registry-1.docker.io/v2/${{ env.CRD_IMAGE_REPO }}/tags/list"
+ version_list="$(curl --silent --get -H "Accept: application/json" -H $authz $listUri | jq --raw-output '.')"
+ exists=$(echo $version_list | jq --arg t ${TAG} '.tags | index($t)')
+ if [[ $exists == null ]]
+ then
+ make docker-buildx-crds-release \
+ VERSION=${TAG} \
+ PLATFORM="linux/amd64,linux/arm64" \
+ OUTPUT_TYPE=type=registry \
+ GENERATE_ATTESTATIONS=true
+ fi
+
+ listUri="https://registry-1.docker.io/v2/${{ env.GATOR_IMAGE_REPO }}/tags/list"
+ version_list="$(curl --silent --get -H "Accept: application/json" -H $authz $listUri | jq --raw-output '.')"
+ exists=$(echo $version_list | jq --arg t ${TAG} '.tags | index($t)')
+ if [[ $exists == null ]]
+ then
+ make docker-buildx-gator-release \
+ VERSION=${TAG} \
+ PLATFORM="linux/amd64,linux/arm64,linux/arm/v7" \
+ OUTPUT_TYPE=type=registry \
+ GENERATE_ATTESTATIONS=true
+ fi
+ env:
+ DOCKER_USER: ${{ secrets.DOCKER_USER }}
+ DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
+
+ - name: Bootstrap e2e
+ run: |
+ mkdir -p $GITHUB_WORKSPACE/bin
+ echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH
+ make e2e-bootstrap
+
+ - name: Verify release
+ run: |
+ make e2e-verify-release IMG=${{ env.IMAGE_REPO }}:${TAG} USE_LOCAL_IMG=false
+
+ - name: Build gator-cli
+ shell: bash
+ run: |
+ set -e
+ build() {
+ export GOOS="$(echo ${1} | cut -d '-' -f 1)"
+ export GOARCH="$(echo ${1} | cut -d '-' -f 2)"
+ FILENAME=${GITHUB_WORKSPACE}/_dist/gator-${TAG}-${GOOS}-${GOARCH}
+ # build the binary
+ make bin/gator-${GOOS}-${GOARCH}
+ # rename the binary to gator
+ tmp_dir=$(mktemp -d)
+ cp bin/gator-${GOOS}-${GOARCH} ${tmp_dir}/gator
+ pushd ${tmp_dir}
+ tar -czf ${FILENAME}.tar.gz gator*
+ popd
+ }
+
+ mkdir -p _dist
+
+ i=0
+ for os_arch_extension in $PLATFORMS; do
+ build ${os_arch_extension} &
+ pids[${i}]=$!
+ ((i=i+1))
+ done
+
+ # wait for all pids
+ for pid in ${pids[*]}; do
+ wait $pid
+ done
+
+ pushd _dist
+ # consolidate tar's sha256sum into a single file
+ find . -type f -name '*.tar.gz' | sort | xargs sha256sum >> sha256sums.txt
+ popd
+ env:
+ PLATFORMS: "linux-amd64 linux-arm64 darwin-amd64 darwin-arm64"
+
+ - name: Create GitHub release
+ uses: marvinpinto/action-automatic-releases@919008cf3f741b179569b7a6fb4d8860689ab7f0 # v1.2.1
+ with:
+ repo_token: "${{ secrets.GITHUB_TOKEN }}"
+ prerelease: false
+ files: |
+ _dist/sha256sums.txt
+ _dist/*.tar.gz
+
+ - name: Publish Helm chart
+ uses: stefanprodan/helm-gh-pages@0ad2bb377311d61ac04ad9eb6f252fb68e207260 # v1.7.0
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ charts_dir: charts
+ target_dir: charts
+ linting: off
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
new file mode 100644
index 00000000000..303791cfb9e
--- /dev/null
+++ b/.github/workflows/scorecards.yml
@@ -0,0 +1,76 @@
+# This workflow uses actions that are not certified by GitHub. They are provided
+# by a third-party and are governed by separate terms of service, privacy
+# policy, and support documentation.
+
+name: Scorecard supply-chain security
+on:
+ # For Branch-Protection check. Only the default branch is supported. See
+ # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
+ branch_protection_rule:
+ # To guarantee Maintained check is occasionally updated. See
+ # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
+ schedule:
+ - cron: '20 7 * * 2'
+ push:
+ branches: ["master"]
+
+# Declare default permissions as read only.
+permissions: read-all
+
+jobs:
+ analysis:
+ name: Scorecard analysis
+ runs-on: ubuntu-latest
+ permissions:
+ # Needed to upload the results to code-scanning dashboard.
+ security-events: write
+ # Needed to publish results and get a badge (see publish_results below).
+ id-token: write
+ contents: read
+ actions: read
+
+ steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
+ - name: "Checkout code"
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v3.5.2
+ with:
+ persist-credentials: false
+
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@483ef80eb98fb506c348f7d62e28055e49fe2398 # v2.3.0
+ with:
+ results_file: results.sarif
+ results_format: sarif
+ # (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
+ # - you want to enable the Branch-Protection check on a *public* repository, or
+ # - you are installing Scorecards on a *private* repository
+ # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
+ # repo_token: ${{ secrets.SCORECARD_TOKEN }}
+
+ # Public repositories:
+ # - Publish results to OpenSSF REST API for easy access by consumers
+ # - Allows the repository to include the Scorecard badge.
+ # - See https://github.com/ossf/scorecard-action#publishing-results.
+ # For private repositories:
+ # - `publish_results` will always be set to `false`, regardless
+ # of the value entered here.
+ publish_results: true
+
+ # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
+ # format to the repository Actions tab.
+ - name: "Upload artifact"
+ uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
+ with:
+ name: SARIF file
+ path: results.sarif
+ retention-days: 5
+
+ # Upload the results to GitHub's code scanning dashboard.
+ - name: "Upload to code-scanning"
+ uses: github/codeql-action/upload-sarif@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1
+ with:
+ sarif_file: results.sarif
diff --git a/.github/workflows/upgrade.yaml b/.github/workflows/upgrade.yaml
index cb34c4657e0..1e0f5bcbbca 100644
--- a/.github/workflows/upgrade.yaml
+++ b/.github/workflows/upgrade.yaml
@@ -18,14 +18,19 @@ env:
jobs:
helm_upgrade:
name: "[Helm] Upgrade test"
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
timeout-minutes: 15
strategy:
matrix:
HELM_VERSION: ["3.7.2"]
steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
- name: Check out code into the Go module directory
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
- name: Bootstrap e2e
run: |
@@ -61,12 +66,26 @@ jobs:
- name: Upgrade Helm version
run: |
- make e2e-build-load-image IMG=gatekeeper-e2e-helm:latest CRD_IMG=gatekeeper-crds:latest
- make e2e-helm-upgrade HELM_VERSION=${{ matrix.HELM_VERSION }} HELM_REPO=gatekeeper-e2e-helm HELM_CRD_REPO=gatekeeper-crds HELM_RELEASE=latest
+ make docker-buildx \
+ IMG=gatekeeper-e2e:latest \
+ GATEKEEPER_NAMESPACE=${{ matrix.GATEKEEPER_NAMESPACE }}
- - name: Manually apply the CRDs. Helm will not update CRDs.
- run: |
- kustomize build config/crd | kubectl apply -f -
+ make docker-buildx-crds \
+ CRD_IMG=gatekeeper-crds:latest \
+ GATEKEEPER_NAMESPACE=${{ matrix.GATEKEEPER_NAMESPACE }}
+
+ make e2e-build-load-externaldata-image \
+ GATEKEEPER_NAMESPACE=${{ matrix.GATEKEEPER_NAMESPACE }}
+
+ kind load docker-image --name kind \
+ gatekeeper-e2e:latest \
+ gatekeeper-crds:latest
+
+ make e2e-helm-upgrade \
+ HELM_VERSION=${{ matrix.HELM_VERSION }} \
+ HELM_REPO=gatekeeper-e2e \
+ HELM_CRD_REPO=gatekeeper-crds \
+ HELM_RELEASE=latest
- name: Run e2e after upgrade
run: |
@@ -80,7 +99,7 @@ jobs:
kubectl logs -n gatekeeper-system -l run=dummy-provider --tail=-1 > logs-${{ matrix.HELM_VERSION }}-dummy-provider-post-upgrade.json
- name: Upload artifacts
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
if: ${{ always() }}
with:
name: logs
diff --git a/.github/workflows/website.yaml b/.github/workflows/website.yaml
index d9d0d8e996b..90b8f5d7b45 100644
--- a/.github/workflows/website.yaml
+++ b/.github/workflows/website.yaml
@@ -7,21 +7,32 @@ on:
paths:
- ".github/workflows/website.yaml"
- "website/**"
+ pull_request:
+ branches:
+ - master
+ paths:
+ - ".github/workflows/website.yaml"
+ - "website/**"
permissions:
contents: write
jobs:
deploy:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
defaults:
run:
working-directory: website
steps:
- - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
+ - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
- name: Setup Node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
with:
node-version: "16"
@@ -30,7 +41,7 @@ jobs:
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- name: Cache dependencies
- uses: actions/cache@v3
+ uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-website-${{ hashFiles('**/yarn.lock') }}
@@ -40,8 +51,10 @@ jobs:
- run: yarn install --frozen-lockfile
- run: yarn build
+ # deploy only after PR is merged to master
- name: Deploy
- uses: peaceiris/actions-gh-pages@v3.9.2
+ if: github.ref == 'refs/heads/master' && github.event_name == 'push' && github.repository == 'open-policy-agent/gatekeeper'
+ uses: peaceiris/actions-gh-pages@373f7f263a76c20808c831209c920827a82a2847 # v3.9.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./website/build
diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml
index b0e6ddacd9a..31981dcb799 100644
--- a/.github/workflows/workflow.yaml
+++ b/.github/workflows/workflow.yaml
@@ -1,4 +1,4 @@
-name: build_test_release
+name: build_test
on:
push:
paths-ignore:
@@ -23,80 +23,103 @@ on:
- "**.md"
- "!cmd/build/helmify/static/README.md"
-env:
- GITHUB_REPO: open-policy-agent/gatekeeper
- IMAGE_REPO: openpolicyagent/gatekeeper
- CRD_IMAGE_REPO: openpolicyagent/gatekeeper-crds
- GATOR_IMAGE_REPO: openpolicyagent/gator
+permissions: read-all
jobs:
lint:
name: "Lint"
- runs-on: ubuntu-latest
- timeout-minutes: 5
- permissions:
- contents: read
+ runs-on: ubuntu-22.04
+ timeout-minutes: 7
steps:
- - name: Set up Go 1.19
- uses: actions/setup-go@v3
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
+ - name: Set up Go
+ uses: actions/setup-go@v4 # v4.0.1
with:
- go-version: 1.19
+ go-version: "1.21"
- name: Check out code into the Go module directory
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
# source: https://github.com/golangci/golangci-lint-action
- name: golangci-lint
- uses: golangci/golangci-lint-action@v3
+ uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0
with:
# version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
- version: v1.48.0
+ version: v1.51.2
test:
name: "Unit test"
- runs-on: ubuntu-latest
- timeout-minutes: 10
- permissions:
- contents: read
+ runs-on: ubuntu-22.04
+ timeout-minutes: 20
steps:
- - name: Set up Go 1.19
- uses: actions/setup-go@v3
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
+ - name: Set up Go
+ uses: actions/setup-go@v4 # v4.0.1
with:
- go-version: 1.19
+ go-version: "1.21"
- name: Check out code into the Go module directory
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
- name: Unit test
- run: |
- curl -L -O "https://github.com/kubernetes-sigs/kubebuilder/releases/download/v${KUBEBUILDER_VERSION}/kubebuilder_${KUBEBUILDER_VERSION}_linux_amd64.tar.gz" &&\
- tar -zxvf kubebuilder_${KUBEBUILDER_VERSION}_linux_amd64.tar.gz &&\
- sudo mv kubebuilder_${KUBEBUILDER_VERSION}_linux_amd64 /usr/local/kubebuilder
- make native-test
- env:
- KUBEBUILDER_VERSION: 2.3.1
+ run: make native-test
- name: Codecov Upload
- uses: codecov/codecov-action@v3
+ uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4
with:
flags: unittests
file: ./cover.out
fail_ci_if_error: false
+ check_manifest:
+ name: "Check codegen and manifest"
+ runs-on: ubuntu-22.04
+ timeout-minutes: 10
+ steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
+ - name: Check out code into the Go module directory
+ uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.2
+ - name: Set up Go
+ uses: actions/setup-go@v4 # v4.0.1
+ with:
+ go-version: "1.21"
+ - name: Check go.mod and manifests
+ run: |
+ # there should be no additional manifest or go.mod changes
+ go mod tidy
+ git diff --exit-code
+ make generate manifests
+ git diff --exit-code
+
gator_test:
name: "Test Gator"
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
timeout-minutes: 5
- permissions:
- contents: read
steps:
- - name: Set up Go 1.19
- uses: actions/setup-go@v3
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
with:
- go-version: 1.19
+ egress-policy: audit
+
+ - name: Set up Go
+ uses: actions/setup-go@v4 # v4.0.1
+ with:
+ go-version: "1.21"
- name: Check out code into the Go module directory
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
- name: Download e2e dependencies
run: |
@@ -109,21 +132,24 @@ jobs:
build_test:
name: "Build and Test"
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
timeout-minutes: 15
- permissions:
- contents: read
strategy:
matrix:
- KUBERNETES_VERSION: ["1.23.13", "1.24.7", "1.25.3", "1.26.0"]
+ KUBERNETES_VERSION: ["1.25.8", "1.26.3", "1.27.1", "1.28.0"]
steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
- name: Check out code into the Go module directory
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
- - name: Set up Go 1.19
- uses: actions/setup-go@v3
+ - name: Set up Go
+ uses: actions/setup-go@v4 # v4.0.1
with:
- go-version: 1.19
+ go-version: "1.21"
- name: Bootstrap e2e
run: |
@@ -133,11 +159,18 @@ jobs:
- name: Run e2e
run: |
- make e2e-build-load-image IMG=gatekeeper-e2e:latest CRD_IMG=gatekeeper-crds:latest
- make deploy IMG=gatekeeper-e2e:latest USE_LOCAL_IMG=true
- go mod tidy
- # there should be no additional manifest or go.mod changes
- git diff --exit-code
+ make docker-buildx \
+ IMG=gatekeeper-e2e:latest
+
+ make e2e-build-load-externaldata-image
+
+ kind load docker-image --name kind \
+ gatekeeper-e2e:latest
+
+ make deploy \
+ IMG=gatekeeper-e2e:latest \
+ USE_LOCAL_IMG=true
+
make test-e2e
- name: Save logs
@@ -147,7 +180,7 @@ jobs:
kubectl logs -n gatekeeper-system -l control-plane=audit-controller --tail=-1 > logs-audit.json
- name: Upload artifacts
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
if: ${{ always() }}
with:
name: logs
@@ -156,17 +189,20 @@ jobs:
helm_build_test:
name: "[Helm] Build and Test"
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
timeout-minutes: 15
- permissions:
- contents: read
strategy:
matrix:
HELM_VERSION: ["3.7.2"]
GATEKEEPER_NAMESPACE: ["gatekeeper-system", "custom-namespace"]
steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
- name: Check out code into the Go module directory
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
- name: Bootstrap e2e
run: |
@@ -176,9 +212,30 @@ jobs:
- name: Run e2e
run: |
- make e2e-build-load-image IMG=gatekeeper-e2e-helm:latest CRD_IMG=gatekeeper-crds:latest GATEKEEPER_NAMESPACE=${{ matrix.GATEKEEPER_NAMESPACE }}
- make e2e-helm-deploy HELM_REPO=gatekeeper-e2e-helm HELM_CRD_REPO=gatekeeper-crds HELM_RELEASE=latest HELM_VERSION=${{ matrix.HELM_VERSION }} GATEKEEPER_NAMESPACE=${{ matrix.GATEKEEPER_NAMESPACE }}
- make test-e2e GATEKEEPER_NAMESPACE=${{ matrix.GATEKEEPER_NAMESPACE }}
+ make docker-buildx \
+ IMG=gatekeeper-e2e:latest \
+ GATEKEEPER_NAMESPACE=${{ matrix.GATEKEEPER_NAMESPACE }}
+
+ make docker-buildx-crds \
+ CRD_IMG=gatekeeper-crds:latest \
+ GATEKEEPER_NAMESPACE=${{ matrix.GATEKEEPER_NAMESPACE }}
+
+ make e2e-build-load-externaldata-image \
+ GATEKEEPER_NAMESPACE=${{ matrix.GATEKEEPER_NAMESPACE }}
+
+ kind load docker-image --name kind \
+ gatekeeper-e2e:latest \
+ gatekeeper-crds:latest
+
+ make e2e-helm-deploy \
+ HELM_REPO=gatekeeper-e2e \
+ HELM_CRD_REPO=gatekeeper-crds \
+ HELM_RELEASE=latest \
+ HELM_VERSION=${{ matrix.HELM_VERSION }} \
+ GATEKEEPER_NAMESPACE=${{ matrix.GATEKEEPER_NAMESPACE }}
+
+ make test-e2e \
+ GATEKEEPER_NAMESPACE=${{ matrix.GATEKEEPER_NAMESPACE }}
- name: Save logs
if: ${{ always() }}
@@ -188,7 +245,7 @@ jobs:
kubectl logs -n ${{ matrix.GATEKEEPER_NAMESPACE }} -l run=dummy-provider --tail=-1 > logs-helm-${{ matrix.HELM_VERSION }}-${{ matrix.GATEKEEPER_NAMESPACE }}-dummy-provider.json
- name: Upload artifacts
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
if: ${{ always() }}
with:
name: helm-logs
@@ -197,18 +254,22 @@ jobs:
build_test_generator_expansion:
name: "[Generator Resource Expansion] Build and Test"
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
timeout-minutes: 15
- permissions:
- contents: read
+
steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
- name: Check out code into the Go module directory
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
- - name: Set up Go 1.19
- uses: actions/setup-go@v3
+ - name: Set up Go
+ uses: actions/setup-go@v4 # v4.0.1
with:
- go-version: 1.19
+ go-version: "1.21"
- name: Bootstrap e2e
run: |
@@ -218,11 +279,19 @@ jobs:
- name: Run e2e
run: |
- make e2e-build-load-image IMG=gatekeeper-e2e:latest CRD_IMG=gatekeeper-crds:latest
- make deploy IMG=gatekeeper-e2e:latest USE_LOCAL_IMG=true ENABLE_GENERATOR_EXPANSION=true
- go mod tidy
- # there should be no additional manifest or go.mod changes
- git diff --exit-code
+ make docker-buildx \
+ IMG=gatekeeper-e2e:latest
+
+ make e2e-build-load-externaldata-image
+
+ kind load docker-image --name kind \
+ gatekeeper-e2e:latest
+
+ make deploy \
+ IMG=gatekeeper-e2e:latest \
+ USE_LOCAL_IMG=true \
+ ENABLE_GENERATOR_EXPANSION=true
+
make test-e2e ENABLE_GENERATOR_EXPANSION_TESTS=1
- name: Save logs
@@ -232,7 +301,7 @@ jobs:
kubectl logs -n gatekeeper-system -l control-plane=audit-controller --tail=-1 > logs-generatorexpansion-audit.json
- name: Upload artifacts
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
if: ${{ always() }}
with:
name: generatorexpansion-logs
@@ -241,13 +310,16 @@ jobs:
scan_vulnerabilities:
name: "[Trivy] Scan for vulnerabilities"
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
timeout-minutes: 15
- permissions:
- contents: read
steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0
+ with:
+ egress-policy: audit
+
- name: Check out code into the Go module directory
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
+ uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
- name: Download trivy
run: |
@@ -256,177 +328,22 @@ jobs:
tar zxvf trivy_${{ env.TRIVY_VERSION }}_Linux-64bit.tar.gz
echo "$(pwd)" >> $GITHUB_PATH
env:
- TRIVY_VERSION: "0.32.1"
+ TRIVY_VERSION: "0.41.0"
- name: Run trivy on git repository
run: |
- trivy fs --format table --ignore-unfixed --skip-dirs website --security-checks vuln .
+ trivy fs --format table --ignore-unfixed --skip-dirs website --scanners vuln .
- name: Build docker images
- run: make docker-build
-
- - name: Run trivy on images
- run: |
- for img in "openpolicyagent/gatekeeper:latest" "openpolicyagent/gatekeeper-crds:latest"; do
- for vuln_type in "os" "library"; do
- trivy image --ignore-unfixed --vuln-type="${vuln_type}" "${img}"
- done
- done
-
- pre-release:
- name: "Pre Release"
- runs-on: "ubuntu-latest"
- if: github.ref == 'refs/heads/master' && github.event_name == 'push' && github.repository == 'open-policy-agent/gatekeeper'
- needs: [lint, test, build_test, helm_build_test, scan_vulnerabilities]
- timeout-minutes: 30
- permissions:
- contents: read
- steps:
- - name: Check out code into the Go module directory
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
-
- - name: make docker-push-dev
- run: |
- tokenUri="https://auth.docker.io/token?service=registry.docker.io&scope=repository:${{ env.IMAGE_REPO }}:pull&scope=repository:${{ env.CRD_IMAGE_REPO }}:pull&scope=repository:${{ env.GATOR_IMAGE_REPO }}:pull"
- bearerToken="$(curl --silent --get $tokenUri | jq --raw-output '.token')"
- listUri="https://registry-1.docker.io/v2/${{ env.IMAGE_REPO }}/tags/list"
- authz="Authorization: Bearer $bearerToken"
- version_list="$(curl --silent --get -H "Accept: application/json" -H "$authz" $listUri | jq --raw-output '.')"
- exists=$(echo $version_list | jq --arg t ${GITHUB_SHA::7} '.tags | index($t)')
- if [[ $exists == null ]]
- then
- make docker-login
- make docker-buildx-dev DEV_TAG=${GITHUB_SHA::7}
- fi
-
- listUri="https://registry-1.docker.io/v2/${{ env.CRD_IMAGE_REPO }}/tags/list"
- version_list="$(curl --silent --get -H "Accept: application/json" -H "$authz" $listUri | jq --raw-output '.')"
- exists=$(echo $version_list | jq --arg t ${GITHUB_SHA::7} '.tags | index($t)')
- if [[ $exists == null ]]
- then
- make docker-login
- make docker-buildx-crds-dev DEV_TAG=${GITHUB_SHA::7}
- fi
-
- listUri="https://registry-1.docker.io/v2/${{ env.GATOR_IMAGE_REPO }}/tags/list"
- version_list="$(curl --silent --get -H "Accept: application/json" -H "$authz" $listUri | jq --raw-output '.')"
- exists=$(echo $version_list | jq --arg t ${GITHUB_SHA::7} '.tags | index($t)')
- if [[ $exists == null ]]
- then
- make docker-login
- make docker-buildx-gator-dev DEV_TAG=${GITHUB_SHA::7}
- fi
- env:
- DOCKER_USER: ${{ secrets.DOCKER_USER }}
- DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
-
- tagged-release:
- name: "Tagged Release"
- runs-on: "ubuntu-latest"
- permissions:
- contents: write
- if: startsWith(github.ref, 'refs/tags/v') && github.repository == 'open-policy-agent/gatekeeper'
- needs: [lint, test, build_test, helm_build_test, scan_vulnerabilities]
- timeout-minutes: 45
- steps:
- - name: Check out code into the Go module directory
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
-
- - name: Set up Go 1.19
- uses: actions/setup-go@v3
- with:
- go-version: 1.19
-
- - name: Get tag
- id: get_version
run: |
- echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
+ make docker-buildx \
+ IMG=gatekeeper-e2e:latest
- - name: Publish release
- run: |
- tokenUri="https://auth.docker.io/token?service=registry.docker.io&scope=repository:${{ env.IMAGE_REPO }}:pull&scope=repository:${{ env.CRD_IMAGE_REPO }}:pull&scope=repository:${{ env.GATOR_IMAGE_REPO }}:pull"
- bearerToken="$(curl --silent --get $tokenUri | jq --raw-output '.token')"
- listUri="https://registry-1.docker.io/v2/${{ env.IMAGE_REPO }}/tags/list"
- authz="Authorization: Bearer $bearerToken"
- version_list="$(curl --silent --get -H "Accept: application/json" -H $authz $listUri | jq --raw-output '.')"
- exists=$(echo $version_list | jq --arg t ${TAG} '.tags | index($t)')
- if [[ $exists == null ]]
- then
- make docker-login
- make docker-buildx-release VERSION=${TAG}
- fi
-
- listUri="https://registry-1.docker.io/v2/${{ env.CRD_IMAGE_REPO }}/tags/list"
- version_list="$(curl --silent --get -H "Accept: application/json" -H $authz $listUri | jq --raw-output '.')"
- exists=$(echo $version_list | jq --arg t ${TAG} '.tags | index($t)')
- if [[ $exists == null ]]
- then
- make docker-login
- make docker-buildx-crds-release VERSION=${TAG}
- fi
-
- listUri="https://registry-1.docker.io/v2/${{ env.GATOR_IMAGE_REPO }}/tags/list"
- version_list="$(curl --silent --get -H "Accept: application/json" -H $authz $listUri | jq --raw-output '.')"
- exists=$(echo $version_list | jq --arg t ${TAG} '.tags | index($t)')
- if [[ $exists == null ]]
- then
- make docker-login
- make docker-buildx-gator-release VERSION=${TAG}
- fi
- env:
- DOCKER_USER: ${{ secrets.DOCKER_USER }}
- DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
+ make docker-buildx-crds \
+ CRD_IMG=gatekeeper-crds:latest
- - name: Bootstrap e2e
- run: |
- mkdir -p $GITHUB_WORKSPACE/bin
- echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH
- make e2e-bootstrap
-
- - name: Verify release
- run: |
- make e2e-verify-release IMG=${{ env.IMAGE_REPO }}:${TAG} USE_LOCAL_IMG=false
-
- - name: Build gator-cli
+ - name: Run trivy on images
run: |
- build() {
- export GOOS="$(echo ${1} | cut -d '-' -f 1)"
- export GOARCH="$(echo ${1} | cut -d '-' -f 2)"
- FILENAME=${GITHUB_WORKSPACE}/_dist/gator-${TAG}-${GOOS}-${GOARCH}
- # build the binary
- make bin/gator-${GOOS}-${GOARCH}
- # rename the binary to gator
- tmp_dir=$(mktemp -d)
- cp bin/gator-${GOOS}-${GOARCH} ${tmp_dir}/gator
- pushd ${tmp_dir}
- tar -czf ${FILENAME}.tar.gz gator*
- popd
- }
- mkdir -p _dist
- for os_arch_extension in $PLATFORMS; do
- build ${os_arch_extension} &
+ for img in "gatekeeper-e2e:latest" "gatekeeper-crds:latest"; do
+ trivy image --ignore-unfixed --vuln-type="os,library" "${img}"
done
- wait
- pushd _dist
- # consolidate tar's sha256sum into a single file
- find . -type f -name '*.tar.gz' | sort | xargs sha256sum >> sha256sums.txt
- popd
- env:
- PLATFORMS: "linux-amd64 linux-arm64 darwin-amd64 darwin-arm64"
-
- - name: Create GitHub release
- uses: "marvinpinto/action-automatic-releases@v1.2.1"
- with:
- repo_token: "${{ secrets.GITHUB_TOKEN }}"
- prerelease: false
- files: |
- _dist/sha256sums.txt
- _dist/*.tar.gz
-
- - name: Publish Helm chart
- uses: stefanprodan/helm-gh-pages@v1.7.0
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- charts_dir: charts
- target_dir: charts
- linting: off
diff --git a/.gitignore b/.gitignore
index 128e3756cde..329c0880ded 100644
--- a/.gitignore
+++ b/.gitignore
@@ -362,3 +362,6 @@ tilt-settings.json
# dummy provider's certificate directory
test/externaldata/dummy-provider/certs/
+
+# annotations for dapr
+annotations.yaml
diff --git a/.go-version b/.go-version
index 815d5ca06d5..3500250a4b0 100644
--- a/.go-version
+++ b/.go-version
@@ -1 +1 @@
-1.19.0
+1.21.0
diff --git a/.golangci.yaml b/.golangci.yaml
index c25c0889316..45f97871159 100644
--- a/.golangci.yaml
+++ b/.golangci.yaml
@@ -1,5 +1,7 @@
run:
timeout: 5m
+ skip-files:
+ - pkg/target/matchcrd_constant.go
linters-settings:
gocritic:
@@ -20,15 +22,16 @@ linters-settings:
locale: US
staticcheck:
# Select the Go version to target. The default is '1.13'.
- go: "1.19"
+ go: "1.21"
linters:
disable-all: true
enable:
- - deadcode
- errcheck
+ - errorlint
- exportloopref
- forcetypeassert
+ - gci
- gocritic
- goconst
- godot
@@ -43,8 +46,7 @@ linters:
- misspell
- revive # replacement for golint
- staticcheck
- - structcheck
- typecheck
+ - unconvert
- unused
- - varcheck
- whitespace
diff --git a/.trivyignore b/.trivyignore
new file mode 100644
index 00000000000..b583a1d2c18
--- /dev/null
+++ b/.trivyignore
@@ -0,0 +1,3 @@
+# false positive due to prometheus versioning
+# https://github.com/aquasecurity/trivy/issues/2992
+CVE-2019-3826
diff --git a/Dockerfile b/Dockerfile
index 442ab2c731e..0e26d65ff5b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
ARG BUILDPLATFORM="linux/amd64"
-ARG BUILDERIMAGE="golang:1.19-bullseye"
+ARG BUILDERIMAGE="golang:1.21-bullseye"
# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
ARG BASEIMAGE="gcr.io/distroless/static:nonroot"
@@ -11,30 +11,22 @@ ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT=""
ARG LDFLAGS
+ARG BUILDKIT_SBOM_SCAN_STAGE=true
ENV GO111MODULE=on \
- CGO_ENABLED=0 \
+ CGO_ENABLED=1 \
GOOS=${TARGETOS} \
GOARCH=${TARGETARCH} \
GOARM=${TARGETVARIANT}
WORKDIR /go/src/github.com/open-policy-agent/gatekeeper
+COPY . .
-COPY pkg/ pkg/
-COPY third_party/ third_party/
-COPY vendor/ vendor/
-COPY main.go main.go
-COPY apis/ apis/
-COPY go.mod .
-
-RUN go build -mod vendor -a -ldflags "${LDFLAGS:--X github.com/open-policy-agent/gatekeeper/pkg/version.Version=latest}" -o manager main.go
+RUN go build -mod vendor -a -ldflags "${LDFLAGS}" -o manager
FROM $BASEIMAGE
WORKDIR /
-
COPY --from=builder /go/src/github.com/open-policy-agent/gatekeeper/manager .
-
USER 65532:65532
-
ENTRYPOINT ["/manager"]
diff --git a/Makefile b/Makefile
index ca2010e7f7d..5062b80c201 100644
--- a/Makefile
+++ b/Makefile
@@ -9,13 +9,15 @@ GATOR_IMG := $(GATOR_REPOSITORY):latest
DEV_TAG ?= dev
USE_LOCAL_IMG ?= false
ENABLE_GENERATOR_EXPANSION ?= false
+ENABLE_PUBSUB ?= false
+AUDIT_CONNECTION ?= "audit"
+AUDIT_CHANNEL ?= "audit"
-VERSION := v3.12.0-beta.0
+VERSION := v3.14.0
KIND_VERSION ?= 0.17.0
# note: k8s version pinned since KIND image availability lags k8s releases
-KUBERNETES_VERSION ?= 1.26.0
-KUBEBUILDER_VERSION ?= 3.8.0
+KUBERNETES_VERSION ?= 1.28.0
KUSTOMIZE_VERSION ?= 3.8.9
BATS_VERSION ?= 1.8.2
ORAS_VERSION ?= 0.16.0
@@ -23,34 +25,27 @@ BATS_TESTS_FILE ?= test/bats/test.bats
HELM_VERSION ?= 3.7.2
NODE_VERSION ?= 16-bullseye-slim
YQ_VERSION ?= 4.30.6
-FRAMEWORKS_VERSION ?= $(shell go list -f '{{ .Version }}' -m github.com/open-policy-agent/frameworks/constraint)
-OPA_VERSION ?= $(shell go list -f '{{ .Version }}' -m github.com/open-policy-agent/opa)
HELM_ARGS ?=
GATEKEEPER_NAMESPACE ?= gatekeeper-system
# When updating this, make sure to update the corresponding action in
# workflow.yaml
-GOLANGCI_LINT_VERSION := v1.45.2
+GOLANGCI_LINT_VERSION := v1.51.2
# Detects the location of the user golangci-lint cache.
GOLANGCI_LINT_CACHE := $(shell pwd)/.tmp/golangci-lint
BENCHMARK_FILE_NAME ?= benchmarks.txt
+FAKE_SUBSCRIBER_IMAGE ?= fake-subscriber:latest
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
BIN_DIR := $(abspath $(ROOT_DIR)/bin)
-BUILD_COMMIT := $(shell ./build/get-build-commit.sh)
-BUILD_TIMESTAMP := $(shell ./build/get-build-timestamp.sh)
-BUILD_HOSTNAME := $(shell ./build/get-build-hostname.sh)
+LDFLAGS := "-X github.com/open-policy-agent/gatekeeper/v3/pkg/version.Version=$(VERSION)"
-LDFLAGS := "-X github.com/open-policy-agent/gatekeeper/pkg/version.Version=$(VERSION) \
- -X github.com/open-policy-agent/gatekeeper/pkg/version.Vcs=$(BUILD_COMMIT) \
- -X github.com/open-policy-agent/gatekeeper/pkg/version.Timestamp=$(BUILD_TIMESTAMP) \
- -X github.com/open-policy-agent/gatekeeper/pkg/version.Hostname=$(BUILD_HOSTNAME) \
- -X main.frameworksVersion=$(FRAMEWORKS_VERSION) \
- -X main.opaVersion=$(OPA_VERSION)"
+PLATFORM ?= linux/amd64
+OUTPUT_TYPE ?= type=docker
MANAGER_IMAGE_PATCH := "apiVersion: apps/v1\
\nkind: Deployment\
@@ -67,6 +62,7 @@ MANAGER_IMAGE_PATCH := "apiVersion: apps/v1\
\n - --port=8443\
\n - --logtostderr\
\n - --emit-admission-events\
+\n - --admission-events-involved-namespace\
\n - --exempt-namespace=${GATEKEEPER_NAMESPACE}\
\n - --operation=webhook\
\n - --operation=mutation-webhook\
@@ -87,6 +83,7 @@ MANAGER_IMAGE_PATCH := "apiVersion: apps/v1\
\n name: manager\
\n args:\
\n - --emit-audit-events\
+\n - --audit-events-involved-namespace\
\n - --operation=audit\
\n - --operation=status\
\n - --operation=mutation-status\
@@ -100,11 +97,17 @@ else
GOBIN=$(shell go env GOBIN)
endif
+ifdef GENERATE_ATTESTATIONS
+_ATTESTATIONS := --attest type=sbom --attest type=provenance,mode=max
+endif
+
all: lint test manager
# Run tests
-native-test:
- GO111MODULE=on go test -mod vendor ./pkg/... ./apis/... ./cmd/gator/... -race -bench . -coverprofile cover.out
+native-test: envtest
+ KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(KUBERNETES_VERSION) --bin-dir $(LOCALBIN) -p path)" \
+ GO111MODULE=on \
+ go test -mod vendor ./pkg/... ./apis/... ./cmd/gator/... -race -bench . -coverprofile cover.out
.PHONY: benchmark-test
benchmark-test:
@@ -144,7 +147,7 @@ e2e-dependencies:
# Download and install kind
curl -L https://github.com/kubernetes-sigs/kind/releases/download/v${KIND_VERSION}/kind-linux-amd64 --output ${GITHUB_WORKSPACE}/bin/kind && chmod +x ${GITHUB_WORKSPACE}/bin/kind
# Download and install kubectl
- curl -L https://storage.googleapis.com/kubernetes-release/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl -o ${GITHUB_WORKSPACE}/bin/kubectl && chmod +x ${GITHUB_WORKSPACE}/bin/kubectl
+ curl -L https://dl.k8s.io/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl -o ${GITHUB_WORKSPACE}/bin/kubectl && chmod +x ${GITHUB_WORKSPACE}/bin/kubectl
# Download and install kustomize
curl -L https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${KUSTOMIZE_VERSION}/kustomize_v${KUSTOMIZE_VERSION}_linux_amd64.tar.gz -o kustomize_v${KUSTOMIZE_VERSION}_linux_amd64.tar.gz && tar -zxvf kustomize_v${KUSTOMIZE_VERSION}_linux_amd64.tar.gz && chmod +x kustomize && mv kustomize ${GITHUB_WORKSPACE}/bin/kustomize
# Download and install bats
@@ -164,7 +167,11 @@ e2e-build-load-image: docker-buildx e2e-build-load-externaldata-image
e2e-build-load-externaldata-image: docker-buildx-builder
./test/externaldata/dummy-provider/scripts/generate-tls-certificate.sh
- docker buildx build --platform="linux/amd64" -t dummy-provider:test --load -f test/externaldata/dummy-provider/Dockerfile test/externaldata/dummy-provider
+ docker buildx build \
+ --platform="$(PLATFORM)" \
+ --output=$(OUTPUT_TYPE) \
+ -t dummy-provider:test \
+ -f test/externaldata/dummy-provider/Dockerfile test/externaldata/dummy-provider
kind load docker-image --name kind dummy-provider:test
e2e-verify-release: e2e-build-load-externaldata-image patch-image deploy test-e2e
@@ -178,6 +185,30 @@ e2e-helm-install:
./.staging/helm/linux-amd64/helm version --client
e2e-helm-deploy: e2e-helm-install
+ifeq ($(ENABLE_PUBSUB),true)
+ @echo 'auditPodAnnotations: {dapr.io/enabled: "true", dapr.io/app-id: "audit", dapr.io/metrics-port: "9999"}' > .tmp/annotations.yaml
+ ./.staging/helm/linux-amd64/helm install manifest_staging/charts/gatekeeper --name-template=gatekeeper \
+ --namespace ${GATEKEEPER_NAMESPACE} \
+ --debug --wait \
+ --set image.repository=${HELM_REPO} \
+ --set image.crdRepository=${HELM_CRD_REPO} \
+ --set image.release=${HELM_RELEASE} \
+ --set postInstall.labelNamespace.image.repository=${HELM_CRD_REPO} \
+ --set postInstall.labelNamespace.image.tag=${HELM_RELEASE} \
+ --set postInstall.labelNamespace.enabled=true \
+ --set postInstall.probeWebhook.enabled=true \
+ --set emitAdmissionEvents=true \
+ --set emitAuditEvents=true \
+ --set admissionEventsInvolvedNamespace=true \
+ --set auditEventsInvolvedNamespace=true \
+ --set disabledBuiltins={http.send} \
+ --set logMutations=true \
+ --set audit.enablePubsub=${ENABLE_PUBSUB} \
+ --set audit.connection=${AUDIT_CONNECTION} \
+ --set audit.channel=${AUDIT_CHANNEL} \
+ --values .tmp/annotations.yaml \
+ --set mutationAnnotations=true;
+else
./.staging/helm/linux-amd64/helm install manifest_staging/charts/gatekeeper --name-template=gatekeeper \
--namespace ${GATEKEEPER_NAMESPACE} --create-namespace \
--debug --wait \
@@ -190,9 +221,12 @@ e2e-helm-deploy: e2e-helm-install
--set postInstall.probeWebhook.enabled=true \
--set emitAdmissionEvents=true \
--set emitAuditEvents=true \
+ --set admissionEventsInvolvedNamespace=true \
+ --set auditEventsInvolvedNamespace=true \
--set disabledBuiltins={http.send} \
--set logMutations=true \
- --set mutationAnnotations=true;\
+ --set mutationAnnotations=true
+endif
e2e-helm-upgrade-init: e2e-helm-install
./.staging/helm/linux-amd64/helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts;\
@@ -201,6 +235,8 @@ e2e-helm-upgrade-init: e2e-helm-install
--debug --wait \
--set emitAdmissionEvents=true \
--set emitAuditEvents=true \
+ --set admissionEventsInvolvedNamespace=true \
+ --set auditEventsInvolvedNamespace=true \
--set postInstall.labelNamespace.enabled=true \
--set postInstall.probeWebhook.enabled=true \
--set disabledBuiltins={http.send} \
@@ -222,17 +258,32 @@ e2e-helm-upgrade:
--set postInstall.probeWebhook.enabled=true \
--set emitAdmissionEvents=true \
--set emitAuditEvents=true \
+ --set admissionEventsInvolvedNamespace=true \
+ --set auditEventsInvolvedNamespace=true \
--set disabledBuiltins={http.send} \
--set logMutations=true \
--set mutationAnnotations=true;\
+e2e-subscriber-build-load-image:
+ docker buildx build --platform="linux/amd64" -t ${FAKE_SUBSCRIBER_IMAGE} --load -f test/pubsub/fake-subscriber/Dockerfile test/pubsub/fake-subscriber
+ kind load docker-image --name kind ${FAKE_SUBSCRIBER_IMAGE}
+
+e2e-subscriber-deploy:
+ kubectl create ns fake-subscriber
+ kubectl get secret redis --namespace=default -o yaml | sed 's/namespace: .*/namespace: fake-subscriber/' | kubectl apply -f -
+ kubectl apply -f test/pubsub/fake-subscriber/manifest/subscriber.yaml
+
+e2e-publisher-deploy:
+ kubectl get secret redis --namespace=default -o yaml | sed 's/namespace: .*/namespace: gatekeeper-system/' | kubectl apply -f -
+ kubectl apply -f test/pubsub/publish-components.yaml
+
# Build manager binary
manager: generate
- GO111MODULE=on go build -mod vendor -o bin/manager -ldflags $(LDFLAGS) main.go
+ GO111MODULE=on go build -mod vendor -o bin/manager -ldflags $(LDFLAGS)
# Build manager binary
manager-osx: generate
- GO111MODULE=on go build -mod vendor -o bin/manager GOOS=darwin -ldflags $(LDFLAGS) main.go
+ GO111MODULE=on go build -mod vendor -o bin/manager GOOS=darwin -ldflags $(LDFLAGS)
# Run against the configured Kubernetes cluster in ~/.kube/config
run: generate manifests
@@ -241,7 +292,7 @@ run: generate manifests
# Install CRDs into a cluster
install: manifests
docker run -v $(shell pwd)/config:/config -v $(shell pwd)/vendor:/vendor \
- k8s.gcr.io/kustomize/kustomize:v${KUSTOMIZE_VERSION} build \
+ registry.k8s.io/kustomize/kustomize:v${KUSTOMIZE_VERSION} build \
/config/crd | kubectl apply -f -
# Deploy controller in the configured Kubernetes cluster in ~/.kube/config
@@ -250,8 +301,10 @@ ifeq ($(ENABLE_GENERATOR_EXPANSION),true)
@grep -q -v 'enable-generator-resource-expansion' ./config/overlays/dev/manager_image_patch.yaml && sed -i '/- --operation=webhook/a \ \ \ \ \ \ \ \ - --enable-generator-resource-expansion=true' ./config/overlays/dev/manager_image_patch.yaml
@grep -q -v 'enable-generator-resource-expansion' ./config/overlays/dev/manager_image_patch.yaml && sed -i '/- --operation=audit/a \ \ \ \ \ \ \ \ - --enable-generator-resource-expansion=true' ./config/overlays/dev/manager_image_patch.yaml
endif
- docker run -v $(shell pwd)/config:/config -v $(shell pwd)/vendor:/vendor \
- k8s.gcr.io/kustomize/kustomize:v${KUSTOMIZE_VERSION} build \
+ docker run \
+ -v $(shell pwd)/config:/config \
+ -v $(shell pwd)/vendor:/vendor \
+ registry.k8s.io/kustomize/kustomize:v${KUSTOMIZE_VERSION} build \
/config/overlays/dev | kubectl apply -f -
# Generate manifests e.g. CRD, RBAC etc.
@@ -263,14 +316,15 @@ manifests: __controller-gen
paths="./apis/..." \
paths="./pkg/..." \
output:crd:artifacts:config=config/crd/bases
+ ./build/update-match-schema.sh
rm -rf manifest_staging
mkdir -p manifest_staging/deploy/experimental
mkdir -p manifest_staging/charts/gatekeeper
docker run --rm -v $(shell pwd):/gatekeeper \
- k8s.gcr.io/kustomize/kustomize:v${KUSTOMIZE_VERSION} build \
+ registry.k8s.io/kustomize/kustomize:v${KUSTOMIZE_VERSION} build \
/gatekeeper/config/default -o /gatekeeper/manifest_staging/deploy/gatekeeper.yaml
docker run --rm -v $(shell pwd):/gatekeeper \
- k8s.gcr.io/kustomize/kustomize:v${KUSTOMIZE_VERSION} build \
+ registry.k8s.io/kustomize/kustomize:v${KUSTOMIZE_VERSION} build \
--load_restrictor LoadRestrictionsNone /gatekeeper/cmd/build/helmify | go run cmd/build/helmify/*.go
# lint runs a dockerized golangci-lint, and should give consistent results
@@ -287,7 +341,7 @@ generate: __conversion-gen __controller-gen
$(CONTROLLER_GEN) object:headerFile=./hack/boilerplate.go.txt paths="./apis/..." paths="./pkg/..."
$(CONVERSION_GEN) \
--output-base=/gatekeeper \
- --input-dirs=./apis/mutations/v1,./apis/mutations/v1beta1,./apis/mutations/v1alpha1,./apis/expansion/v1alpha1 \
+ --input-dirs=./apis/mutations/v1,./apis/mutations/v1beta1,./apis/mutations/v1alpha1,./apis/expansion/v1alpha1,./apis/syncset/v1alpha1 \
--go-header-file=./hack/boilerplate.go.txt \
--output-file-base=zz_generated.conversion
@@ -307,90 +361,88 @@ endif
docker-login:
@docker login -u $(DOCKER_USER) -p $(DOCKER_PASSWORD) $(REGISTRY)
-# Tag for Dev
-docker-tag-dev:
- @docker tag $(IMG) $(REPOSITORY):$(DEV_TAG)
- @docker tag $(IMG) $(REPOSITORY):dev
- @docker tag $(CRD_IMG) $(CRD_REPOSITORY):$(DEV_TAG)
- @docker tag $(CRD_IMG) $(CRD_REPOSITORY):dev
- @docker tag $(GATOR_IMG) $(GATOR_REPOSITORY):$(DEV_TAG)
- @docker tag $(GATOR_IMG) $(GATOR_REPOSITORY):dev
-
-# Tag for Dev
-docker-tag-release:
- @docker tag $(IMG) $(REPOSITORY):$(VERSION)
- @docker tag $(CRD_IMG) $(CRD_REPOSITORY):$(VERSION)
- @docker tag $(GATOR_IMG) $(GATOR_REPOSITORY):$(VERSION)
-
-# Push for Dev
-docker-push-dev: docker-tag-dev
- @docker push $(REPOSITORY):$(DEV_TAG)
- @docker push $(REPOSITORY):dev
- @docker push $(CRD_REPOSITORY):$(DEV_TAG)
- @docker push $(CRD_REPOSITORY):dev
- @docker push $(GATOR_REPOSITORY):$(DEV_TAG)
- @docker push $(GATOR_REPOSITORY):dev
-
-# Push for Release
-docker-push-release: docker-tag-release
- @docker push $(REPOSITORY):$(VERSION)
- @docker push $(CRD_REPOSITORY):$(VERSION)
- @docker push $(GATOR_REPOSITORY):$(VERSION)
-
-# Add crds to gatekeeper-crds image
-# Build gatekeeper image
-docker-build: build-crds
- docker build --pull -f crd.Dockerfile .staging/crds/ --build-arg LDFLAGS=${LDFLAGS} --build-arg KUBE_VERSION=${KUBERNETES_VERSION} --build-arg TARGETOS="linux" --build-arg TARGETARCH="amd64" -t ${CRD_IMG}
- docker build --pull . --build-arg LDFLAGS=${LDFLAGS} -t ${IMG}
+docker-build: docker-buildx
docker-buildx-builder:
if ! docker buildx ls | grep -q container-builder; then\
- docker buildx create --name container-builder --use;\
+ docker buildx create --name container-builder --use --bootstrap;\
+ docker buildx inspect;\
fi
# Build image with buildx to build cross platform multi-architecture docker images
# https://docs.docker.com/buildx/working-with-buildx/
-docker-buildx: build-crds docker-buildx-builder
- docker buildx build --build-arg LDFLAGS=${LDFLAGS} --platform "linux/amd64" \
- -t $(IMG) \
- . --load
- docker buildx build --build-arg LDFLAGS=${LDFLAGS} --build-arg KUBE_VERSION=${KUBERNETES_VERSION} --platform "linux/amd64" \
+docker-buildx: docker-buildx-builder
+ docker buildx build \
+ $(_ATTESTATIONS) \
+ --build-arg LDFLAGS=${LDFLAGS} \
+ --platform="$(PLATFORM)" \
+ --output=$(OUTPUT_TYPE) \
+ -t $(IMG) .
+
+docker-buildx-crds: build-crds docker-buildx-builder
+ docker buildx build \
+ $(_ATTESTATIONS) \
+ --build-arg LDFLAGS=${LDFLAGS} \
+ --platform="$(PLATFORM)" \
+ --output=$(OUTPUT_TYPE) \
-t $(CRD_IMG) \
- -f crd.Dockerfile .staging/crds/ --load
+ -f crd.Dockerfile .staging/crds/
docker-buildx-dev: docker-buildx-builder
- docker buildx build --build-arg LDFLAGS=${LDFLAGS} --platform "linux/amd64,linux/arm64,linux/arm/v7" \
+ docker buildx build \
+ $(_ATTESTATIONS) \
+ --build-arg LDFLAGS=${LDFLAGS} \
+ --platform="$(PLATFORM)" \
+ --output=$(OUTPUT_TYPE) \
-t $(REPOSITORY):$(DEV_TAG) \
- -t $(REPOSITORY):dev \
- . --push
+ -t $(REPOSITORY):dev .
docker-buildx-crds-dev: build-crds docker-buildx-builder
- docker buildx build --build-arg LDFLAGS=${LDFLAGS} --build-arg KUBE_VERSION=${KUBERNETES_VERSION} --platform "linux/amd64,linux/arm64,linux/arm/v7" \
+ docker buildx build \
+ $(_ATTESTATIONS) \
+ --build-arg LDFLAGS=${LDFLAGS} \
+ --platform="$(PLATFORM)" \
+ --output=$(OUTPUT_TYPE) \
-t $(CRD_REPOSITORY):$(DEV_TAG) \
-t $(CRD_REPOSITORY):dev \
- -f crd.Dockerfile .staging/crds/ --push
+ -f crd.Dockerfile .staging/crds/
docker-buildx-release: docker-buildx-builder
- docker buildx build --build-arg LDFLAGS=${LDFLAGS} --platform "linux/amd64,linux/arm64,linux/arm/v7" \
- -t $(REPOSITORY):$(VERSION) \
- . --push
+ docker buildx build \
+ $(_ATTESTATIONS) \
+ --build-arg LDFLAGS=${LDFLAGS} \
+ --platform="$(PLATFORM)" \
+ --output=$(OUTPUT_TYPE) \
+ -t $(REPOSITORY):$(VERSION) .
docker-buildx-crds-release: build-crds docker-buildx-builder
- docker buildx build --build-arg LDFLAGS=${LDFLAGS} --build-arg KUBE_VERSION=${KUBERNETES_VERSION} --platform "linux/amd64,linux/arm64,linux/arm/v7" \
+ docker buildx build \
+ $(_ATTESTATIONS) \
+ --build-arg LDFLAGS=${LDFLAGS}\
+ --platform="$(PLATFORM)" \
+ --output=$(OUTPUT_TYPE) \
-t $(CRD_REPOSITORY):$(VERSION) \
- -f crd.Dockerfile .staging/crds/ --push
+ -f crd.Dockerfile .staging/crds/
# Build gator image
docker-buildx-gator-dev: docker-buildx-builder
- docker buildx build --build-arg LDFLAGS=${LDFLAGS} --platform "linux/amd64,linux/arm64,linux/arm/v6"\
+ docker buildx build \
+ $(_ATTESTATIONS) \
+ --build-arg LDFLAGS=${LDFLAGS} \
+ --platform="$(PLATFORM)" \
+ --output=$(OUTPUT_TYPE) \
-t ${GATOR_REPOSITORY}:${DEV_TAG} \
-t ${GATOR_REPOSITORY}:dev \
- -f gator.Dockerfile . --push
+ -f gator.Dockerfile .
docker-buildx-gator-release: docker-buildx-builder
- docker buildx build --build-arg LDFLAGS=${LDFLAGS} --platform "linux/amd64,linux/arm64,linux/arm/v6"\
+ docker buildx build \
+ $(_ATTESTATIONS) \
+ --build-arg LDFLAGS=${LDFLAGS} \
+ --platform="$(PLATFORM)" \
+ --output=$(OUTPUT_TYPE) \
-t ${GATOR_REPOSITORY}:${VERSION} \
- -f gator.Dockerfile . --push
+ -f gator.Dockerfile .
# Update manager_image_patch.yaml with image tag
patch-image:
@@ -401,11 +453,6 @@ ifeq ($(USE_LOCAL_IMG),true)
endif
@sed -i'' -e 's@image: .*@image: '"${IMG}"'@' ./config/overlays/dev/manager_image_patch.yaml
-# Push the docker image
-docker-push:
- docker push ${IMG}
- docker push ${CRD_IMG}
-
release-manifest:
@sed -i'' -e 's@image: $(REPOSITORY):$(VERSION)@image: $(REPOSITORY):'"$(NEWVERSION)"'@' ./config/manager/manager.yaml
@sed -i "s/appVersion: $(VERSION)/appVersion: ${NEWVERSION}/" ./cmd/build/helmify/static/Chart.yaml
@@ -436,7 +483,7 @@ promote-staging-manifest:
# Delete gatekeeper from a cluster. Note this is not a complete uninstall, just a dev convenience
uninstall:
docker run -v $(shell pwd)/config:/config -v $(shell pwd)/vendor:/vendor \
- k8s.gcr.io/kustomize/kustomize:v${KUSTOMIZE_VERSION} build \
+ registry.k8s.io/kustomize/kustomize:v${KUSTOMIZE_VERSION} build \
/config/overlays/dev | kubectl delete -f -
__controller-gen: __tooling-image
@@ -446,18 +493,32 @@ __conversion-gen: __tooling-image
CONVERSION_GEN=docker run --rm -v $(shell pwd):/gatekeeper gatekeeper-tooling conversion-gen
__tooling-image:
- docker build build/tooling \
+ docker buildx build build/tooling \
+ --platform="$(PLATFORM)" \
+ --output=$(OUTPUT_TYPE) \
-t gatekeeper-tooling
__test-image:
docker buildx build test/image \
- -t gatekeeper-test \
- --load \
+ --platform="$(PLATFORM)" \
+ --output=$(OUTPUT_TYPE) \
--build-arg YQ_VERSION=$(YQ_VERSION) \
--build-arg BATS_VERSION=$(BATS_VERSION) \
--build-arg ORAS_VERSION=$(ORAS_VERSION) \
--build-arg KUSTOMIZE_VERSION=$(KUSTOMIZE_VERSION) \
- --build-arg KUBEBUILDER_VERSION=$(KUBEBUILDER_VERSION)
+ -t gatekeeper-test
+
+## Location to install dependencies to
+LOCALBIN ?= $(shell pwd)/.tmp/bin
+$(LOCALBIN):
+ mkdir -p $(LOCALBIN)
+
+ENVTEST ?= $(LOCALBIN)/setup-envtest
+
+.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@v0.0.0-20230118154835-9241bceb3098
.PHONY: vendor
vendor:
@@ -469,7 +530,7 @@ gator: bin/gator-$(GOOS)-$(GOARCH)
mv bin/gator-$(GOOS)-$(GOARCH) bin/gator
bin/gator-$(GOOS)-$(GOARCH):
- GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $(BIN_DIR)/gator-$(GOOS)-$(GOARCH) -ldflags $(LDFLAGS) ./cmd/gator
+ GOOS=$(GOOS) GOARCH=$(GOARCH) CGO_ENABLED=0 GO111MODULE=on go build -o $(BIN_DIR)/gator-$(GOOS)-$(GOARCH) -ldflags $(LDFLAGS) ./cmd/gator
tilt-prepare:
mkdir -p .tiltbuild/charts
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 00000000000..e9dcaed4090
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,12 @@
+approvers:
+- dhaiducek
+- gparvin
+- JustinKuli
+- mprahl
+- yiraeChristineKim
+reviewers:
+- dhaiducek
+- gparvin
+- JustinKuli
+- mprahl
+- yiraeChristineKim
diff --git a/README.md b/README.md
index 80d7982a031..24d48f2d355 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# Gatekeeper
+
+
## How is Gatekeeper different from OPA?
Compared to using [OPA with its sidecar kube-mgmt](https://www.openpolicyagent.org/docs/kubernetes-admission-control.html) (aka Gatekeeper v1.0), Gatekeeper introduces the following functionality:
diff --git a/Tiltfile b/Tiltfile
index 90dbbd45d94..6ec4cc7e97f 100644
--- a/Tiltfile
+++ b/Tiltfile
@@ -16,10 +16,8 @@ allow_k8s_contexts(settings.get("allowed_contexts", []))
if settings.get("trigger_mode", "auto").lower() == "manual":
trigger_mode(TRIGGER_MODE_MANUAL)
-LDFLAGS = "-X github.com/open-policy-agent/gatekeeper/pkg/version.Version=latest"
-
TILT_DOCKERFILE = """
-FROM golang:1.19-bullseye as tilt-helper
+FROM golang:1.21-bullseye as tilt-helper
# Support live reloading with Tilt
RUN wget --output-document /restart.sh --quiet https://raw.githubusercontent.com/tilt-dev/rerun-process-wrapper/60eaa572cdf825c646008e1ea28b635f83cefb38/restart.sh && \
wget --output-document /start.sh --quiet https://raw.githubusercontent.com/tilt-dev/rerun-process-wrapper/60eaa572cdf825c646008e1ea28b635f83cefb38/start.sh && \
@@ -36,7 +34,7 @@ COPY bin/manager .
def build_manager():
cmd = [
"make tilt-prepare",
- "GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -mod vendor -a -ldflags \"" +
+ "GO111MODULE=on CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -mod vendor -a -ldflags \"" +
LDFLAGS + "\" -o .tiltbuild/bin/manager",
]
local_resource(
@@ -74,7 +72,7 @@ def build_crds():
context=".staging/crds/",
target="build",
only="crds",
- build_args={"KUBE_VERSION": "1.23.0"},
+ build_args={"KUBE_VERSION": "1.28.0"},
live_update=[
sync(".staging/crds/", "/crds"),
],
@@ -90,7 +88,8 @@ def deploy_gatekeeper():
name="gatekeeper",
namespace="gatekeeper-system",
values=[".tiltbuild/charts/gatekeeper/values.yaml"],
- set=["{}={}".format(k, str(v).lower()) for k, v in helm_values.items()],
+ set=["{}={}".format(k, str(v).lower())
+ for k, v in helm_values.items()],
))
# add label to resources
@@ -102,16 +101,19 @@ def deploy_gatekeeper():
port = int(helm_values["audit.metricsPort"])
k8s_resource(
workload="gatekeeper-audit",
- port_forwards=[port_forward(port, name="View metrics", link_path="/metrics")],
+ port_forwards=[port_forward(
+ port, name="View metrics", link_path="/metrics")],
)
if "controllerManager.metricsPort" in helm_values:
port = int(helm_values["controllerManager.metricsPort"])
k8s_resource(
workload="gatekeeper-controller-manager",
- port_forwards=[port_forward(port, name="View metrics", link_path="/metrics")],
+ port_forwards=[port_forward(
+ port, name="View metrics", link_path="/metrics")],
)
+
build_manager()
build_crds()
diff --git a/apis/addtoscheme_config_v1alpha1.go b/apis/addtoscheme_config_v1alpha1.go
index 94f5a13b20a..2489ece65ff 100644
--- a/apis/addtoscheme_config_v1alpha1.go
+++ b/apis/addtoscheme_config_v1alpha1.go
@@ -16,7 +16,7 @@ limitations under the License.
package apis
import (
- "github.com/open-policy-agent/gatekeeper/apis/config/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
)
func init() {
diff --git a/apis/addtoscheme_expansion_v1alpha1.go b/apis/addtoscheme_expansion_v1alpha1.go
index 9ee067684e1..8ceb6f96fad 100644
--- a/apis/addtoscheme_expansion_v1alpha1.go
+++ b/apis/addtoscheme_expansion_v1alpha1.go
@@ -16,7 +16,7 @@ limitations under the License.
package apis
import (
- "github.com/open-policy-agent/gatekeeper/apis/expansion/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/v1alpha1"
)
func init() {
diff --git a/apis/addtoscheme_expansion_v1beta1.go b/apis/addtoscheme_expansion_v1beta1.go
new file mode 100644
index 00000000000..2c6a1b569f2
--- /dev/null
+++ b/apis/addtoscheme_expansion_v1beta1.go
@@ -0,0 +1,25 @@
+/*
+
+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 apis
+
+import (
+ "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/v1beta1"
+)
+
+func init() {
+ // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
+ AddToSchemes = append(AddToSchemes, v1beta1.AddToScheme)
+}
diff --git a/apis/addtoscheme_mutations_v1.go b/apis/addtoscheme_mutations_v1.go
index 481ce040ef2..5526bbce219 100644
--- a/apis/addtoscheme_mutations_v1.go
+++ b/apis/addtoscheme_mutations_v1.go
@@ -16,7 +16,7 @@ limitations under the License.
package apis
import (
- v1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1"
+ v1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1"
)
func init() {
diff --git a/apis/addtoscheme_mutations_v1alpha1.go b/apis/addtoscheme_mutations_v1alpha1.go
index 66941f5952c..66ee0290a14 100644
--- a/apis/addtoscheme_mutations_v1alpha1.go
+++ b/apis/addtoscheme_mutations_v1alpha1.go
@@ -16,7 +16,7 @@ limitations under the License.
package apis
import (
- "github.com/open-policy-agent/gatekeeper/apis/mutations/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1alpha1"
)
func init() {
diff --git a/apis/addtoscheme_mutations_v1beta1.go b/apis/addtoscheme_mutations_v1beta1.go
index fb23cd2115a..fd99a4b3b0a 100644
--- a/apis/addtoscheme_mutations_v1beta1.go
+++ b/apis/addtoscheme_mutations_v1beta1.go
@@ -16,7 +16,7 @@ limitations under the License.
package apis
import (
- "github.com/open-policy-agent/gatekeeper/apis/mutations/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1beta1"
)
func init() {
diff --git a/apis/addtoscheme_status_v1beta1.go b/apis/addtoscheme_status_v1beta1.go
index 8510a869921..596bd73945a 100644
--- a/apis/addtoscheme_status_v1beta1.go
+++ b/apis/addtoscheme_status_v1beta1.go
@@ -16,7 +16,7 @@ limitations under the License.
package apis
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
)
func init() {
diff --git a/apis/addtoscheme_syncset_v1alpha1.go b/apis/addtoscheme_syncset_v1alpha1.go
new file mode 100644
index 00000000000..a389152b0fe
--- /dev/null
+++ b/apis/addtoscheme_syncset_v1alpha1.go
@@ -0,0 +1,10 @@
+package apis
+
+import (
+ "github.com/open-policy-agent/gatekeeper/v3/apis/syncset/v1alpha1"
+)
+
+func init() {
+ // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
+ AddToSchemes = append(AddToSchemes, v1alpha1.AddToScheme)
+}
diff --git a/apis/config/v1alpha1/config_types.go b/apis/config/v1alpha1/config_types.go
index fc74bddbd68..d3a5b7da3d2 100644
--- a/apis/config/v1alpha1/config_types.go
+++ b/apis/config/v1alpha1/config_types.go
@@ -16,7 +16,7 @@ limitations under the License.
package v1alpha1
import (
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -63,8 +63,8 @@ type SyncOnlyEntry struct {
}
type MatchEntry struct {
- Processes []string `json:"processes,omitempty"`
- ExcludedNamespaces []util.Wildcard `json:"excludedNamespaces,omitempty"`
+ Processes []string `json:"processes,omitempty"`
+ ExcludedNamespaces []wildcard.Wildcard `json:"excludedNamespaces,omitempty"`
}
type ReadinessSpec struct {
diff --git a/apis/config/v1alpha1/zz_generated.deepcopy.go b/apis/config/v1alpha1/zz_generated.deepcopy.go
index c7b1a2b5ca6..2df3903752c 100644
--- a/apis/config/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/config/v1alpha1/zz_generated.deepcopy.go
@@ -21,7 +21,7 @@ limitations under the License.
package v1alpha1
import (
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
runtime "k8s.io/apimachinery/pkg/runtime"
)
@@ -149,7 +149,7 @@ func (in *MatchEntry) DeepCopyInto(out *MatchEntry) {
}
if in.ExcludedNamespaces != nil {
in, out := &in.ExcludedNamespaces, &out.ExcludedNamespaces
- *out = make([]util.Wildcard, len(*in))
+ *out = make([]wildcard.Wildcard, len(*in))
copy(*out, *in)
}
}
diff --git a/apis/expansion/unversioned/expansiontemplate_types.go b/apis/expansion/unversioned/expansiontemplate_types.go
index 74d3385a895..050eceec6e1 100644
--- a/apis/expansion/unversioned/expansiontemplate_types.go
+++ b/apis/expansion/unversioned/expansiontemplate_types.go
@@ -16,7 +16,8 @@ limitations under the License.
package unversioned
import (
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ statusv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -63,7 +64,13 @@ type ExpansionTemplate struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
- Spec ExpansionTemplateSpec `json:"spec,omitempty"`
+ Spec ExpansionTemplateSpec `json:"spec,omitempty"`
+ Status ExpansionTemplateStatus `json:"status,omitempty"`
+}
+
+// ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+type ExpansionTemplateStatus struct {
+ ByPod []statusv1alpha1.ExpansionTemplatePodStatusStatus `json:"byPod,omitempty"`
}
// +kubebuilder:object:root=true
diff --git a/apis/expansion/unversioned/zz_generated.deepcopy.go b/apis/expansion/unversioned/zz_generated.deepcopy.go
index c3b73060f42..3cd1633496d 100644
--- a/apis/expansion/unversioned/zz_generated.deepcopy.go
+++ b/apis/expansion/unversioned/zz_generated.deepcopy.go
@@ -21,7 +21,8 @@ limitations under the License.
package unversioned
import (
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
runtime "k8s.io/apimachinery/pkg/runtime"
)
@@ -31,6 +32,7 @@ func (in *ExpansionTemplate) DeepCopyInto(out *ExpansionTemplate) {
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
+ in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpansionTemplate.
@@ -106,6 +108,28 @@ func (in *ExpansionTemplateSpec) DeepCopy() *ExpansionTemplateSpec {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExpansionTemplateStatus) DeepCopyInto(out *ExpansionTemplateStatus) {
+ *out = *in
+ if in.ByPod != nil {
+ in, out := &in.ByPod, &out.ByPod
+ *out = make([]v1beta1.ExpansionTemplatePodStatusStatus, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpansionTemplateStatus.
+func (in *ExpansionTemplateStatus) DeepCopy() *ExpansionTemplateStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ExpansionTemplateStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GeneratedGVK) DeepCopyInto(out *GeneratedGVK) {
*out = *in
diff --git a/apis/expansion/v1alpha1/doc.go b/apis/expansion/v1alpha1/doc.go
index 30787b738c9..d6fccb77cc6 100644
--- a/apis/expansion/v1alpha1/doc.go
+++ b/apis/expansion/v1alpha1/doc.go
@@ -1,5 +1,5 @@
// Package v1alpha1 includes v1alpha1 expansion
-// +k8s:conversion-gen=github.com/open-policy-agent/gatekeeper/apis/expansion/unversioned
-// -external-types=github.com/open-policy-agent/gatekeeper/apis/expansion/v1alpha1
+// +k8s:conversion-gen=github.com/open-policy-agent/gatekeeper/v3/apis/expansion/unversioned
+// -external-types=github.com/open-policy-agent/gatekeeper/v3/apis/expansion/v1alpha1
package v1alpha1
diff --git a/apis/expansion/v1alpha1/expansion_template_types.go b/apis/expansion/v1alpha1/expansion_template_types.go
deleted file mode 100644
index 3b710013f56..00000000000
--- a/apis/expansion/v1alpha1/expansion_template_types.go
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
-
-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 (
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
-// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
-
-// ExpansionTemplateSpec defines the desired state of ExpansionTemplate.
-type ExpansionTemplateSpec struct {
- // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
- // Important: Run "make" to regenerate code after modifying this file
-
- // ApplyTo lists the specific groups, versions and kinds of generator resources
- // which will be expanded.
- ApplyTo []match.ApplyTo `json:"applyTo,omitempty"`
-
- // TemplateSource specifies the source field on the generator resource to
- // use as the base for expanded resource. For Pod-creating generators, this
- // is usually spec.template
- TemplateSource string `json:"templateSource,omitempty"`
-
- // GeneratedGVK specifies the GVK of the resources which the generator
- // resource creates.
- GeneratedGVK GeneratedGVK `json:"generatedGVK,omitempty"`
-
- // EnforcementAction specifies the enforcement action to be used for resources
- // matching the ExpansionTemplate. Specifying an empty value will use the
- // enforcement action specified by the Constraint in violation.
- EnforcementAction string `json:"enforcementAction,omitempty"`
-}
-
-type GeneratedGVK struct {
- Group string `json:"group,omitempty"`
- Version string `json:"version,omitempty"`
- Kind string `json:"kind,omitempty"`
-}
-
-// +kubebuilder:object:root=true
-// +kubebuilder:resource:path="expansiontemplate"
-// +kubebuilder:resource:scope="Cluster"
-
-// ExpansionTemplate is the Schema for the ExpansionTemplate API.
-type ExpansionTemplate struct {
- metav1.TypeMeta `json:",inline"`
- metav1.ObjectMeta `json:"metadata,omitempty"`
-
- Spec ExpansionTemplateSpec `json:"spec,omitempty"`
-}
-
-// +kubebuilder:object:root=true
-
-// ExpansionTemplateList contains a list of ExpansionTemplate.
-type ExpansionTemplateList struct {
- metav1.TypeMeta `json:",inline"`
- metav1.ListMeta `json:"metadata,omitempty"`
- Items []ExpansionTemplate `json:"items"`
-}
-
-func init() {
- SchemeBuilder.Register(&ExpansionTemplate{}, &ExpansionTemplateList{})
-}
diff --git a/apis/expansion/v1alpha1/expansiontemplate_types.go b/apis/expansion/v1alpha1/expansiontemplate_types.go
new file mode 100644
index 00000000000..e693f08dfcf
--- /dev/null
+++ b/apis/expansion/v1alpha1/expansiontemplate_types.go
@@ -0,0 +1,88 @@
+/*
+
+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 (
+ status "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
+// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
+
+// ExpansionTemplateSpec defines the desired state of ExpansionTemplate.
+type ExpansionTemplateSpec struct {
+ // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+
+ // ApplyTo lists the specific groups, versions and kinds of generator resources
+ // which will be expanded.
+ ApplyTo []match.ApplyTo `json:"applyTo,omitempty"`
+
+ // TemplateSource specifies the source field on the generator resource to
+ // use as the base for expanded resource. For Pod-creating generators, this
+ // is usually spec.template
+ TemplateSource string `json:"templateSource,omitempty"`
+
+ // GeneratedGVK specifies the GVK of the resources which the generator
+ // resource creates.
+ GeneratedGVK GeneratedGVK `json:"generatedGVK,omitempty"`
+
+ // EnforcementAction specifies the enforcement action to be used for resources
+ // matching the ExpansionTemplate. Specifying an empty value will use the
+ // enforcement action specified by the Constraint in violation.
+ EnforcementAction string `json:"enforcementAction,omitempty"`
+}
+
+type GeneratedGVK struct {
+ Group string `json:"group,omitempty"`
+ Version string `json:"version,omitempty"`
+ Kind string `json:"kind,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:resource:path="expansiontemplate"
+// +kubebuilder:resource:scope="Cluster"
+// +kubebuilder:subresource:status
+// +kubebuilder:storageversion
+
+// ExpansionTemplate is the Schema for the ExpansionTemplate API.
+type ExpansionTemplate struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec ExpansionTemplateSpec `json:"spec,omitempty"`
+ Status ExpansionTemplateStatus `json:"status,omitempty"`
+}
+
+// ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+type ExpansionTemplateStatus struct {
+ ByPod []status.ExpansionTemplatePodStatusStatus `json:"byPod,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ExpansionTemplateList contains a list of ExpansionTemplate.
+type ExpansionTemplateList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []ExpansionTemplate `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&ExpansionTemplate{}, &ExpansionTemplateList{})
+}
diff --git a/apis/expansion/v1alpha1/zz_generated.conversion.go b/apis/expansion/v1alpha1/zz_generated.conversion.go
index 16c04fddadb..be5e5e654d5 100644
--- a/apis/expansion/v1alpha1/zz_generated.conversion.go
+++ b/apis/expansion/v1alpha1/zz_generated.conversion.go
@@ -22,8 +22,9 @@ package v1alpha1
import (
unsafe "unsafe"
- unversioned "github.com/open-policy-agent/gatekeeper/apis/expansion/unversioned"
- match "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ unversioned "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/unversioned"
+ v1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ match "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
)
@@ -65,6 +66,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
+ if err := s.AddGeneratedConversionFunc((*ExpansionTemplateStatus)(nil), (*unversioned.ExpansionTemplateStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1alpha1_ExpansionTemplateStatus_To_unversioned_ExpansionTemplateStatus(a.(*ExpansionTemplateStatus), b.(*unversioned.ExpansionTemplateStatus), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*unversioned.ExpansionTemplateStatus)(nil), (*ExpansionTemplateStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_unversioned_ExpansionTemplateStatus_To_v1alpha1_ExpansionTemplateStatus(a.(*unversioned.ExpansionTemplateStatus), b.(*ExpansionTemplateStatus), scope)
+ }); err != nil {
+ return err
+ }
if err := s.AddGeneratedConversionFunc((*GeneratedGVK)(nil), (*unversioned.GeneratedGVK)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_GeneratedGVK_To_unversioned_GeneratedGVK(a.(*GeneratedGVK), b.(*unversioned.GeneratedGVK), scope)
}); err != nil {
@@ -83,6 +94,9 @@ func autoConvert_v1alpha1_ExpansionTemplate_To_unversioned_ExpansionTemplate(in
if err := Convert_v1alpha1_ExpansionTemplateSpec_To_unversioned_ExpansionTemplateSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
+ if err := Convert_v1alpha1_ExpansionTemplateStatus_To_unversioned_ExpansionTemplateStatus(&in.Status, &out.Status, s); err != nil {
+ return err
+ }
return nil
}
@@ -96,6 +110,9 @@ func autoConvert_unversioned_ExpansionTemplate_To_v1alpha1_ExpansionTemplate(in
if err := Convert_unversioned_ExpansionTemplateSpec_To_v1alpha1_ExpansionTemplateSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
+ if err := Convert_unversioned_ExpansionTemplateStatus_To_v1alpha1_ExpansionTemplateStatus(&in.Status, &out.Status, s); err != nil {
+ return err
+ }
return nil
}
@@ -156,6 +173,26 @@ func Convert_unversioned_ExpansionTemplateSpec_To_v1alpha1_ExpansionTemplateSpec
return autoConvert_unversioned_ExpansionTemplateSpec_To_v1alpha1_ExpansionTemplateSpec(in, out, s)
}
+func autoConvert_v1alpha1_ExpansionTemplateStatus_To_unversioned_ExpansionTemplateStatus(in *ExpansionTemplateStatus, out *unversioned.ExpansionTemplateStatus, s conversion.Scope) error {
+ out.ByPod = *(*[]v1beta1.ExpansionTemplatePodStatusStatus)(unsafe.Pointer(&in.ByPod))
+ return nil
+}
+
+// Convert_v1alpha1_ExpansionTemplateStatus_To_unversioned_ExpansionTemplateStatus is an autogenerated conversion function.
+func Convert_v1alpha1_ExpansionTemplateStatus_To_unversioned_ExpansionTemplateStatus(in *ExpansionTemplateStatus, out *unversioned.ExpansionTemplateStatus, s conversion.Scope) error {
+ return autoConvert_v1alpha1_ExpansionTemplateStatus_To_unversioned_ExpansionTemplateStatus(in, out, s)
+}
+
+func autoConvert_unversioned_ExpansionTemplateStatus_To_v1alpha1_ExpansionTemplateStatus(in *unversioned.ExpansionTemplateStatus, out *ExpansionTemplateStatus, s conversion.Scope) error {
+ out.ByPod = *(*[]v1beta1.ExpansionTemplatePodStatusStatus)(unsafe.Pointer(&in.ByPod))
+ return nil
+}
+
+// Convert_unversioned_ExpansionTemplateStatus_To_v1alpha1_ExpansionTemplateStatus is an autogenerated conversion function.
+func Convert_unversioned_ExpansionTemplateStatus_To_v1alpha1_ExpansionTemplateStatus(in *unversioned.ExpansionTemplateStatus, out *ExpansionTemplateStatus, s conversion.Scope) error {
+ return autoConvert_unversioned_ExpansionTemplateStatus_To_v1alpha1_ExpansionTemplateStatus(in, out, s)
+}
+
func autoConvert_v1alpha1_GeneratedGVK_To_unversioned_GeneratedGVK(in *GeneratedGVK, out *unversioned.GeneratedGVK, s conversion.Scope) error {
out.Group = in.Group
out.Version = in.Version
diff --git a/apis/expansion/v1alpha1/zz_generated.deepcopy.go b/apis/expansion/v1alpha1/zz_generated.deepcopy.go
index 8b08913b818..d44b368c3a1 100644
--- a/apis/expansion/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/expansion/v1alpha1/zz_generated.deepcopy.go
@@ -21,7 +21,8 @@ limitations under the License.
package v1alpha1
import (
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
"k8s.io/apimachinery/pkg/runtime"
)
@@ -31,6 +32,7 @@ func (in *ExpansionTemplate) DeepCopyInto(out *ExpansionTemplate) {
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
+ in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpansionTemplate.
@@ -106,6 +108,28 @@ func (in *ExpansionTemplateSpec) DeepCopy() *ExpansionTemplateSpec {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExpansionTemplateStatus) DeepCopyInto(out *ExpansionTemplateStatus) {
+ *out = *in
+ if in.ByPod != nil {
+ in, out := &in.ByPod, &out.ByPod
+ *out = make([]v1beta1.ExpansionTemplatePodStatusStatus, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpansionTemplateStatus.
+func (in *ExpansionTemplateStatus) DeepCopy() *ExpansionTemplateStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ExpansionTemplateStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GeneratedGVK) DeepCopyInto(out *GeneratedGVK) {
*out = *in
diff --git a/apis/expansion/v1beta1/doc.go b/apis/expansion/v1beta1/doc.go
new file mode 100644
index 00000000000..50225e0afde
--- /dev/null
+++ b/apis/expansion/v1beta1/doc.go
@@ -0,0 +1,5 @@
+// Package v1beta1 includes v1beta1 expansion
+
+// +k8s:conversion-gen=github.com/open-policy-agent/gatekeeper/v3/apis/expansion/unversioned
+// -external-types=github.com/open-policy-agent/gatekeeper/v3/apis/expansion/v1beta1
+package v1beta1
diff --git a/apis/expansion/v1beta1/expansiontemplate_types.go b/apis/expansion/v1beta1/expansiontemplate_types.go
new file mode 100644
index 00000000000..7a3bd77e946
--- /dev/null
+++ b/apis/expansion/v1beta1/expansiontemplate_types.go
@@ -0,0 +1,87 @@
+/*
+
+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 v1beta1
+
+import (
+ status "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
+// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
+
+// ExpansionTemplateSpec defines the desired state of ExpansionTemplate.
+type ExpansionTemplateSpec struct {
+ // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+
+ // ApplyTo lists the specific groups, versions and kinds of generator resources
+ // which will be expanded.
+ ApplyTo []match.ApplyTo `json:"applyTo,omitempty"`
+
+ // TemplateSource specifies the source field on the generator resource to
+ // use as the base for expanded resource. For Pod-creating generators, this
+ // is usually spec.template
+ TemplateSource string `json:"templateSource,omitempty"`
+
+ // GeneratedGVK specifies the GVK of the resources which the generator
+ // resource creates.
+ GeneratedGVK GeneratedGVK `json:"generatedGVK,omitempty"`
+
+ // EnforcementAction specifies the enforcement action to be used for resources
+ // matching the ExpansionTemplate. Specifying an empty value will use the
+ // enforcement action specified by the Constraint in violation.
+ EnforcementAction string `json:"enforcementAction,omitempty"`
+}
+
+type GeneratedGVK struct {
+ Group string `json:"group,omitempty"`
+ Version string `json:"version,omitempty"`
+ Kind string `json:"kind,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:resource:path="expansiontemplate"
+// +kubebuilder:resource:scope="Cluster"
+// +kubebuilder:subresource:status
+
+// ExpansionTemplate is the Schema for the ExpansionTemplate API.
+type ExpansionTemplate struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec ExpansionTemplateSpec `json:"spec,omitempty"`
+ Status ExpansionTemplateStatus `json:"status,omitempty"`
+}
+
+// ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+type ExpansionTemplateStatus struct {
+ ByPod []status.ExpansionTemplatePodStatusStatus `json:"byPod,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ExpansionTemplateList contains a list of ExpansionTemplate.
+type ExpansionTemplateList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []ExpansionTemplate `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&ExpansionTemplate{}, &ExpansionTemplateList{})
+}
diff --git a/apis/expansion/v1beta1/groupversion_info.go b/apis/expansion/v1beta1/groupversion_info.go
new file mode 100644
index 00000000000..843f98e7ecf
--- /dev/null
+++ b/apis/expansion/v1beta1/groupversion_info.go
@@ -0,0 +1,38 @@
+/*
+
+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 v1beta1 contains API Schema definitions for the expansion v1beta1 API group
+// +kubebuilder:object:generate=true
+// +groupName=expansion.gatekeeper.sh
+package v1beta1
+
+import (
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+ // GroupVersion is group version used to register these objects.
+ GroupVersion = schema.GroupVersion{Group: "expansion.gatekeeper.sh", Version: "v1beta1"}
+
+ // SchemeBuilder is used to add go types to the GroupVersionKind scheme.
+ SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+ localSchemeBuilder = runtime.NewSchemeBuilder(SchemeBuilder.AddToScheme)
+
+ // AddToScheme adds the types in this group-version to the given scheme.
+ AddToScheme = localSchemeBuilder.AddToScheme
+)
diff --git a/apis/expansion/v1beta1/zz_generated.conversion.go b/apis/expansion/v1beta1/zz_generated.conversion.go
new file mode 100644
index 00000000000..ae75d025441
--- /dev/null
+++ b/apis/expansion/v1beta1/zz_generated.conversion.go
@@ -0,0 +1,218 @@
+//go:build !ignore_autogenerated
+// +build !ignore_autogenerated
+
+/*
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+// Code generated by conversion-gen. DO NOT EDIT.
+
+package v1beta1
+
+import (
+ unsafe "unsafe"
+
+ unversioned "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/unversioned"
+ v1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ match "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ conversion "k8s.io/apimachinery/pkg/conversion"
+ runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+func init() {
+ localSchemeBuilder.Register(RegisterConversions)
+}
+
+// RegisterConversions adds conversion functions to the given scheme.
+// Public to allow building arbitrary schemes.
+func RegisterConversions(s *runtime.Scheme) error {
+ if err := s.AddGeneratedConversionFunc((*ExpansionTemplate)(nil), (*unversioned.ExpansionTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1beta1_ExpansionTemplate_To_unversioned_ExpansionTemplate(a.(*ExpansionTemplate), b.(*unversioned.ExpansionTemplate), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*unversioned.ExpansionTemplate)(nil), (*ExpansionTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_unversioned_ExpansionTemplate_To_v1beta1_ExpansionTemplate(a.(*unversioned.ExpansionTemplate), b.(*ExpansionTemplate), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*ExpansionTemplateList)(nil), (*unversioned.ExpansionTemplateList)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1beta1_ExpansionTemplateList_To_unversioned_ExpansionTemplateList(a.(*ExpansionTemplateList), b.(*unversioned.ExpansionTemplateList), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*unversioned.ExpansionTemplateList)(nil), (*ExpansionTemplateList)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_unversioned_ExpansionTemplateList_To_v1beta1_ExpansionTemplateList(a.(*unversioned.ExpansionTemplateList), b.(*ExpansionTemplateList), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*ExpansionTemplateSpec)(nil), (*unversioned.ExpansionTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1beta1_ExpansionTemplateSpec_To_unversioned_ExpansionTemplateSpec(a.(*ExpansionTemplateSpec), b.(*unversioned.ExpansionTemplateSpec), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*unversioned.ExpansionTemplateSpec)(nil), (*ExpansionTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_unversioned_ExpansionTemplateSpec_To_v1beta1_ExpansionTemplateSpec(a.(*unversioned.ExpansionTemplateSpec), b.(*ExpansionTemplateSpec), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*ExpansionTemplateStatus)(nil), (*unversioned.ExpansionTemplateStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1beta1_ExpansionTemplateStatus_To_unversioned_ExpansionTemplateStatus(a.(*ExpansionTemplateStatus), b.(*unversioned.ExpansionTemplateStatus), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*unversioned.ExpansionTemplateStatus)(nil), (*ExpansionTemplateStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_unversioned_ExpansionTemplateStatus_To_v1beta1_ExpansionTemplateStatus(a.(*unversioned.ExpansionTemplateStatus), b.(*ExpansionTemplateStatus), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*GeneratedGVK)(nil), (*unversioned.GeneratedGVK)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1beta1_GeneratedGVK_To_unversioned_GeneratedGVK(a.(*GeneratedGVK), b.(*unversioned.GeneratedGVK), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*unversioned.GeneratedGVK)(nil), (*GeneratedGVK)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_unversioned_GeneratedGVK_To_v1beta1_GeneratedGVK(a.(*unversioned.GeneratedGVK), b.(*GeneratedGVK), scope)
+ }); err != nil {
+ return err
+ }
+ return nil
+}
+
+func autoConvert_v1beta1_ExpansionTemplate_To_unversioned_ExpansionTemplate(in *ExpansionTemplate, out *unversioned.ExpansionTemplate, s conversion.Scope) error {
+ out.ObjectMeta = in.ObjectMeta
+ if err := Convert_v1beta1_ExpansionTemplateSpec_To_unversioned_ExpansionTemplateSpec(&in.Spec, &out.Spec, s); err != nil {
+ return err
+ }
+ if err := Convert_v1beta1_ExpansionTemplateStatus_To_unversioned_ExpansionTemplateStatus(&in.Status, &out.Status, s); err != nil {
+ return err
+ }
+ return nil
+}
+
+// Convert_v1beta1_ExpansionTemplate_To_unversioned_ExpansionTemplate is an autogenerated conversion function.
+func Convert_v1beta1_ExpansionTemplate_To_unversioned_ExpansionTemplate(in *ExpansionTemplate, out *unversioned.ExpansionTemplate, s conversion.Scope) error {
+ return autoConvert_v1beta1_ExpansionTemplate_To_unversioned_ExpansionTemplate(in, out, s)
+}
+
+func autoConvert_unversioned_ExpansionTemplate_To_v1beta1_ExpansionTemplate(in *unversioned.ExpansionTemplate, out *ExpansionTemplate, s conversion.Scope) error {
+ out.ObjectMeta = in.ObjectMeta
+ if err := Convert_unversioned_ExpansionTemplateSpec_To_v1beta1_ExpansionTemplateSpec(&in.Spec, &out.Spec, s); err != nil {
+ return err
+ }
+ if err := Convert_unversioned_ExpansionTemplateStatus_To_v1beta1_ExpansionTemplateStatus(&in.Status, &out.Status, s); err != nil {
+ return err
+ }
+ return nil
+}
+
+// Convert_unversioned_ExpansionTemplate_To_v1beta1_ExpansionTemplate is an autogenerated conversion function.
+func Convert_unversioned_ExpansionTemplate_To_v1beta1_ExpansionTemplate(in *unversioned.ExpansionTemplate, out *ExpansionTemplate, s conversion.Scope) error {
+ return autoConvert_unversioned_ExpansionTemplate_To_v1beta1_ExpansionTemplate(in, out, s)
+}
+
+func autoConvert_v1beta1_ExpansionTemplateList_To_unversioned_ExpansionTemplateList(in *ExpansionTemplateList, out *unversioned.ExpansionTemplateList, s conversion.Scope) error {
+ out.ListMeta = in.ListMeta
+ out.Items = *(*[]unversioned.ExpansionTemplate)(unsafe.Pointer(&in.Items))
+ return nil
+}
+
+// Convert_v1beta1_ExpansionTemplateList_To_unversioned_ExpansionTemplateList is an autogenerated conversion function.
+func Convert_v1beta1_ExpansionTemplateList_To_unversioned_ExpansionTemplateList(in *ExpansionTemplateList, out *unversioned.ExpansionTemplateList, s conversion.Scope) error {
+ return autoConvert_v1beta1_ExpansionTemplateList_To_unversioned_ExpansionTemplateList(in, out, s)
+}
+
+func autoConvert_unversioned_ExpansionTemplateList_To_v1beta1_ExpansionTemplateList(in *unversioned.ExpansionTemplateList, out *ExpansionTemplateList, s conversion.Scope) error {
+ out.ListMeta = in.ListMeta
+ out.Items = *(*[]ExpansionTemplate)(unsafe.Pointer(&in.Items))
+ return nil
+}
+
+// Convert_unversioned_ExpansionTemplateList_To_v1beta1_ExpansionTemplateList is an autogenerated conversion function.
+func Convert_unversioned_ExpansionTemplateList_To_v1beta1_ExpansionTemplateList(in *unversioned.ExpansionTemplateList, out *ExpansionTemplateList, s conversion.Scope) error {
+ return autoConvert_unversioned_ExpansionTemplateList_To_v1beta1_ExpansionTemplateList(in, out, s)
+}
+
+func autoConvert_v1beta1_ExpansionTemplateSpec_To_unversioned_ExpansionTemplateSpec(in *ExpansionTemplateSpec, out *unversioned.ExpansionTemplateSpec, s conversion.Scope) error {
+ out.ApplyTo = *(*[]match.ApplyTo)(unsafe.Pointer(&in.ApplyTo))
+ out.TemplateSource = in.TemplateSource
+ if err := Convert_v1beta1_GeneratedGVK_To_unversioned_GeneratedGVK(&in.GeneratedGVK, &out.GeneratedGVK, s); err != nil {
+ return err
+ }
+ out.EnforcementAction = in.EnforcementAction
+ return nil
+}
+
+// Convert_v1beta1_ExpansionTemplateSpec_To_unversioned_ExpansionTemplateSpec is an autogenerated conversion function.
+func Convert_v1beta1_ExpansionTemplateSpec_To_unversioned_ExpansionTemplateSpec(in *ExpansionTemplateSpec, out *unversioned.ExpansionTemplateSpec, s conversion.Scope) error {
+ return autoConvert_v1beta1_ExpansionTemplateSpec_To_unversioned_ExpansionTemplateSpec(in, out, s)
+}
+
+func autoConvert_unversioned_ExpansionTemplateSpec_To_v1beta1_ExpansionTemplateSpec(in *unversioned.ExpansionTemplateSpec, out *ExpansionTemplateSpec, s conversion.Scope) error {
+ out.ApplyTo = *(*[]match.ApplyTo)(unsafe.Pointer(&in.ApplyTo))
+ out.TemplateSource = in.TemplateSource
+ if err := Convert_unversioned_GeneratedGVK_To_v1beta1_GeneratedGVK(&in.GeneratedGVK, &out.GeneratedGVK, s); err != nil {
+ return err
+ }
+ out.EnforcementAction = in.EnforcementAction
+ return nil
+}
+
+// Convert_unversioned_ExpansionTemplateSpec_To_v1beta1_ExpansionTemplateSpec is an autogenerated conversion function.
+func Convert_unversioned_ExpansionTemplateSpec_To_v1beta1_ExpansionTemplateSpec(in *unversioned.ExpansionTemplateSpec, out *ExpansionTemplateSpec, s conversion.Scope) error {
+ return autoConvert_unversioned_ExpansionTemplateSpec_To_v1beta1_ExpansionTemplateSpec(in, out, s)
+}
+
+func autoConvert_v1beta1_ExpansionTemplateStatus_To_unversioned_ExpansionTemplateStatus(in *ExpansionTemplateStatus, out *unversioned.ExpansionTemplateStatus, s conversion.Scope) error {
+ out.ByPod = *(*[]v1beta1.ExpansionTemplatePodStatusStatus)(unsafe.Pointer(&in.ByPod))
+ return nil
+}
+
+// Convert_v1beta1_ExpansionTemplateStatus_To_unversioned_ExpansionTemplateStatus is an autogenerated conversion function.
+func Convert_v1beta1_ExpansionTemplateStatus_To_unversioned_ExpansionTemplateStatus(in *ExpansionTemplateStatus, out *unversioned.ExpansionTemplateStatus, s conversion.Scope) error {
+ return autoConvert_v1beta1_ExpansionTemplateStatus_To_unversioned_ExpansionTemplateStatus(in, out, s)
+}
+
+func autoConvert_unversioned_ExpansionTemplateStatus_To_v1beta1_ExpansionTemplateStatus(in *unversioned.ExpansionTemplateStatus, out *ExpansionTemplateStatus, s conversion.Scope) error {
+ out.ByPod = *(*[]v1beta1.ExpansionTemplatePodStatusStatus)(unsafe.Pointer(&in.ByPod))
+ return nil
+}
+
+// Convert_unversioned_ExpansionTemplateStatus_To_v1beta1_ExpansionTemplateStatus is an autogenerated conversion function.
+func Convert_unversioned_ExpansionTemplateStatus_To_v1beta1_ExpansionTemplateStatus(in *unversioned.ExpansionTemplateStatus, out *ExpansionTemplateStatus, s conversion.Scope) error {
+ return autoConvert_unversioned_ExpansionTemplateStatus_To_v1beta1_ExpansionTemplateStatus(in, out, s)
+}
+
+func autoConvert_v1beta1_GeneratedGVK_To_unversioned_GeneratedGVK(in *GeneratedGVK, out *unversioned.GeneratedGVK, s conversion.Scope) error {
+ out.Group = in.Group
+ out.Version = in.Version
+ out.Kind = in.Kind
+ return nil
+}
+
+// Convert_v1beta1_GeneratedGVK_To_unversioned_GeneratedGVK is an autogenerated conversion function.
+func Convert_v1beta1_GeneratedGVK_To_unversioned_GeneratedGVK(in *GeneratedGVK, out *unversioned.GeneratedGVK, s conversion.Scope) error {
+ return autoConvert_v1beta1_GeneratedGVK_To_unversioned_GeneratedGVK(in, out, s)
+}
+
+func autoConvert_unversioned_GeneratedGVK_To_v1beta1_GeneratedGVK(in *unversioned.GeneratedGVK, out *GeneratedGVK, s conversion.Scope) error {
+ out.Group = in.Group
+ out.Version = in.Version
+ out.Kind = in.Kind
+ return nil
+}
+
+// Convert_unversioned_GeneratedGVK_To_v1beta1_GeneratedGVK is an autogenerated conversion function.
+func Convert_unversioned_GeneratedGVK_To_v1beta1_GeneratedGVK(in *unversioned.GeneratedGVK, out *GeneratedGVK, s conversion.Scope) error {
+ return autoConvert_unversioned_GeneratedGVK_To_v1beta1_GeneratedGVK(in, out, s)
+}
diff --git a/apis/expansion/v1beta1/zz_generated.deepcopy.go b/apis/expansion/v1beta1/zz_generated.deepcopy.go
new file mode 100644
index 00000000000..6ae018f2d27
--- /dev/null
+++ b/apis/expansion/v1beta1/zz_generated.deepcopy.go
@@ -0,0 +1,146 @@
+//go:build !ignore_autogenerated
+// +build !ignore_autogenerated
+
+/*
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1beta1
+
+import (
+ statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExpansionTemplate) DeepCopyInto(out *ExpansionTemplate) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+ in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpansionTemplate.
+func (in *ExpansionTemplate) DeepCopy() *ExpansionTemplate {
+ if in == nil {
+ return nil
+ }
+ out := new(ExpansionTemplate)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ExpansionTemplate) 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 *ExpansionTemplateList) DeepCopyInto(out *ExpansionTemplateList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]ExpansionTemplate, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpansionTemplateList.
+func (in *ExpansionTemplateList) DeepCopy() *ExpansionTemplateList {
+ if in == nil {
+ return nil
+ }
+ out := new(ExpansionTemplateList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ExpansionTemplateList) 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 *ExpansionTemplateSpec) DeepCopyInto(out *ExpansionTemplateSpec) {
+ *out = *in
+ if in.ApplyTo != nil {
+ in, out := &in.ApplyTo, &out.ApplyTo
+ *out = make([]match.ApplyTo, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ out.GeneratedGVK = in.GeneratedGVK
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpansionTemplateSpec.
+func (in *ExpansionTemplateSpec) DeepCopy() *ExpansionTemplateSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ExpansionTemplateSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExpansionTemplateStatus) DeepCopyInto(out *ExpansionTemplateStatus) {
+ *out = *in
+ if in.ByPod != nil {
+ in, out := &in.ByPod, &out.ByPod
+ *out = make([]statusv1beta1.ExpansionTemplatePodStatusStatus, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpansionTemplateStatus.
+func (in *ExpansionTemplateStatus) DeepCopy() *ExpansionTemplateStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ExpansionTemplateStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *GeneratedGVK) DeepCopyInto(out *GeneratedGVK) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeneratedGVK.
+func (in *GeneratedGVK) DeepCopy() *GeneratedGVK {
+ if in == nil {
+ return nil
+ }
+ out := new(GeneratedGVK)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/apis/mutations/unversioned/assign_types.go b/apis/mutations/unversioned/assign_types.go
index 6068544eea6..f8a4b15df15 100644
--- a/apis/mutations/unversioned/assign_types.go
+++ b/apis/mutations/unversioned/assign_types.go
@@ -16,9 +16,9 @@ limitations under the License.
package unversioned
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
diff --git a/apis/mutations/unversioned/assignimage_types.go b/apis/mutations/unversioned/assignimage_types.go
new file mode 100644
index 00000000000..a02ad637d41
--- /dev/null
+++ b/apis/mutations/unversioned/assignimage_types.go
@@ -0,0 +1,90 @@
+/*
+
+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 unversioned
+
+import (
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
+// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
+
+// AssignImageSpec defines the desired state of AssignImage.
+type AssignImageSpec struct {
+ // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+
+ // ApplyTo lists the specific groups, versions and kinds a mutation will be applied to.
+ // This is necessary because every mutation implies part of an object schema and object
+ // schemas are associated with specific GVKs.
+ ApplyTo []match.ApplyTo `json:"applyTo,omitempty"`
+
+ // Match allows the user to limit which resources get mutated.
+ // Individual match criteria are AND-ed together. An undefined
+ // match criteria matches everything.
+ Match match.Match `json:"match,omitempty"`
+
+ // Location describes the path to be mutated, for example: `spec.containers[name: main].image`.
+ Location string `json:"location,omitempty"`
+
+ // Parameters define the behavior of the mutator.
+ Parameters AssignImageParameters `json:"parameters,omitempty"`
+}
+
+type AssignImageParameters struct {
+ PathTests []PathTest `json:"pathTests,omitempty"`
+
+ // AssignDomain sets the domain component on an image string. The trailing
+ // slash should not be included.
+ AssignDomain string `json:"assignDomain,omitempty"`
+
+ // AssignPath sets the domain component on an image string.
+ AssignPath string `json:"assignPath,omitempty"`
+
+ // AssignImage sets the image component on an image string. It must start
+ // with a `:` or `@`.
+ AssignTag string `json:"assignTag,omitempty"`
+}
+
+// AssignImageStatus defines the observed state of AssignImage.
+type AssignImageStatus struct {
+ // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+
+ ByPod []v1beta1.MutatorPodStatusStatus `json:"byPod,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// AssignImage is the Schema for the assign API.
+type AssignImage struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec AssignImageSpec `json:"spec,omitempty"`
+ Status AssignImageStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// AssignImageList contains a list of AssignImage.
+type AssignImageList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []AssignImage `json:"items"`
+}
diff --git a/apis/mutations/unversioned/assignmetadata_types.go b/apis/mutations/unversioned/assignmetadata_types.go
index 6a93bbcdb9d..04273454390 100644
--- a/apis/mutations/unversioned/assignmetadata_types.go
+++ b/apis/mutations/unversioned/assignmetadata_types.go
@@ -16,8 +16,8 @@ limitations under the License.
package unversioned
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
diff --git a/apis/mutations/unversioned/externaldata_types.go b/apis/mutations/unversioned/externaldata_types.go
index bab01ee8e5e..78c29c4179f 100644
--- a/apis/mutations/unversioned/externaldata_types.go
+++ b/apis/mutations/unversioned/externaldata_types.go
@@ -5,8 +5,8 @@ import (
"errors"
"fmt"
- "github.com/open-policy-agent/gatekeeper/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/externaldata"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
diff --git a/apis/mutations/unversioned/modifyset_types.go b/apis/mutations/unversioned/modifyset_types.go
index 356981cf790..755164aad27 100644
--- a/apis/mutations/unversioned/modifyset_types.go
+++ b/apis/mutations/unversioned/modifyset_types.go
@@ -16,8 +16,8 @@ limitations under the License.
package unversioned
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
diff --git a/apis/mutations/unversioned/value.go b/apis/mutations/unversioned/value.go
index d90f1434acf..52652a7c82a 100644
--- a/apis/mutations/unversioned/value.go
+++ b/apis/mutations/unversioned/value.go
@@ -5,7 +5,7 @@ import (
"fmt"
"reflect"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
var (
diff --git a/apis/mutations/unversioned/value_test.go b/apis/mutations/unversioned/value_test.go
index 30991da2652..65d85279bb8 100644
--- a/apis/mutations/unversioned/value_test.go
+++ b/apis/mutations/unversioned/value_test.go
@@ -5,8 +5,8 @@ import (
"reflect"
"testing"
- "github.com/open-policy-agent/gatekeeper/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/externaldata"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
diff --git a/apis/mutations/unversioned/zz_generated.deepcopy.go b/apis/mutations/unversioned/zz_generated.deepcopy.go
index 14832664613..0b0c3a9bb23 100644
--- a/apis/mutations/unversioned/zz_generated.deepcopy.go
+++ b/apis/mutations/unversioned/zz_generated.deepcopy.go
@@ -21,8 +21,8 @@ limitations under the License.
package unversioned
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
"k8s.io/apimachinery/pkg/runtime"
)
@@ -82,6 +82,131 @@ func (in *AssignField) DeepCopy() *AssignField {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AssignImage) DeepCopyInto(out *AssignImage) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+ in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AssignImage.
+func (in *AssignImage) DeepCopy() *AssignImage {
+ if in == nil {
+ return nil
+ }
+ out := new(AssignImage)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *AssignImage) 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 *AssignImageList) DeepCopyInto(out *AssignImageList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]AssignImage, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AssignImageList.
+func (in *AssignImageList) DeepCopy() *AssignImageList {
+ if in == nil {
+ return nil
+ }
+ out := new(AssignImageList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *AssignImageList) 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 *AssignImageParameters) DeepCopyInto(out *AssignImageParameters) {
+ *out = *in
+ if in.PathTests != nil {
+ in, out := &in.PathTests, &out.PathTests
+ *out = make([]PathTest, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AssignImageParameters.
+func (in *AssignImageParameters) DeepCopy() *AssignImageParameters {
+ if in == nil {
+ return nil
+ }
+ out := new(AssignImageParameters)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AssignImageSpec) DeepCopyInto(out *AssignImageSpec) {
+ *out = *in
+ if in.ApplyTo != nil {
+ in, out := &in.ApplyTo, &out.ApplyTo
+ *out = make([]match.ApplyTo, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ in.Match.DeepCopyInto(&out.Match)
+ in.Parameters.DeepCopyInto(&out.Parameters)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AssignImageSpec.
+func (in *AssignImageSpec) DeepCopy() *AssignImageSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(AssignImageSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AssignImageStatus) DeepCopyInto(out *AssignImageStatus) {
+ *out = *in
+ if in.ByPod != nil {
+ in, out := &in.ByPod, &out.ByPod
+ *out = make([]v1beta1.MutatorPodStatusStatus, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AssignImageStatus.
+func (in *AssignImageStatus) DeepCopy() *AssignImageStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(AssignImageStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AssignList) DeepCopyInto(out *AssignList) {
*out = *in
diff --git a/apis/mutations/v1/assign_types.go b/apis/mutations/v1/assign_types.go
index 7df489dec80..a771f0b94e8 100644
--- a/apis/mutations/v1/assign_types.go
+++ b/apis/mutations/v1/assign_types.go
@@ -16,9 +16,9 @@ limitations under the License.
package v1
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
diff --git a/apis/mutations/v1/assignmetadata_types.go b/apis/mutations/v1/assignmetadata_types.go
index 3e623c1b582..641767c2948 100644
--- a/apis/mutations/v1/assignmetadata_types.go
+++ b/apis/mutations/v1/assignmetadata_types.go
@@ -16,8 +16,8 @@ limitations under the License.
package v1
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
diff --git a/apis/mutations/v1/doc.go b/apis/mutations/v1/doc.go
index bd3e26d94be..d6c413b2c7e 100644
--- a/apis/mutations/v1/doc.go
+++ b/apis/mutations/v1/doc.go
@@ -1,5 +1,5 @@
// Package v1 includes v1 mutators
-// +k8s:conversion-gen=github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned
-// -external-types=github.com/open-policy-agent/gatekeeper/apis/mutations/v1beta1
+// +k8s:conversion-gen=github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned
+// -external-types=github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1beta1
package v1
diff --git a/apis/mutations/v1/externaldata_types.go b/apis/mutations/v1/externaldata_types.go
index b88bc1ea055..20a9c662471 100644
--- a/apis/mutations/v1/externaldata_types.go
+++ b/apis/mutations/v1/externaldata_types.go
@@ -1,7 +1,7 @@
package v1
import (
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
// ExternalData describes the external data source to use for the mutation.
diff --git a/apis/mutations/v1/modifyset_types.go b/apis/mutations/v1/modifyset_types.go
index b2a768fa579..5efcede93ab 100644
--- a/apis/mutations/v1/modifyset_types.go
+++ b/apis/mutations/v1/modifyset_types.go
@@ -16,8 +16,8 @@ limitations under the License.
package v1
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
diff --git a/apis/mutations/v1/value.go b/apis/mutations/v1/value.go
index 877d80d4a69..0786d60a201 100644
--- a/apis/mutations/v1/value.go
+++ b/apis/mutations/v1/value.go
@@ -1,8 +1,8 @@
package v1
import (
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
type AssignField struct {
diff --git a/apis/mutations/v1/zz_generated.conversion.go b/apis/mutations/v1/zz_generated.conversion.go
index 71689e6d74a..07c30314620 100644
--- a/apis/mutations/v1/zz_generated.conversion.go
+++ b/apis/mutations/v1/zz_generated.conversion.go
@@ -22,11 +22,11 @@ package v1
import (
unsafe "unsafe"
- unversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- v1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- match "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- tester "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
- types "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ unversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ v1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ match "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ tester "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ types "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
)
diff --git a/apis/mutations/v1/zz_generated.deepcopy.go b/apis/mutations/v1/zz_generated.deepcopy.go
index bf207418367..fc732100f53 100644
--- a/apis/mutations/v1/zz_generated.deepcopy.go
+++ b/apis/mutations/v1/zz_generated.deepcopy.go
@@ -21,8 +21,8 @@ limitations under the License.
package v1
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
"k8s.io/apimachinery/pkg/runtime"
)
diff --git a/apis/mutations/v1alpha1/assign_types.go b/apis/mutations/v1alpha1/assign_types.go
index 2c673877bba..9ad9f23fa1f 100644
--- a/apis/mutations/v1alpha1/assign_types.go
+++ b/apis/mutations/v1alpha1/assign_types.go
@@ -16,9 +16,9 @@ limitations under the License.
package v1alpha1
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
diff --git a/apis/mutations/v1alpha1/assignimage_types.go b/apis/mutations/v1alpha1/assignimage_types.go
new file mode 100644
index 00000000000..77d7abdd63e
--- /dev/null
+++ b/apis/mutations/v1alpha1/assignimage_types.go
@@ -0,0 +1,97 @@
+/*
+
+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 (
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
+// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
+
+// AssignImageSpec defines the desired state of AssignImage.
+type AssignImageSpec struct {
+ // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+
+ // ApplyTo lists the specific groups, versions and kinds a mutation will be applied to.
+ // This is necessary because every mutation implies part of an object schema and object
+ // schemas are associated with specific GVKs.
+ ApplyTo []match.ApplyTo `json:"applyTo,omitempty"`
+
+ // Match allows the user to limit which resources get mutated.
+ // Individual match criteria are AND-ed together. An undefined
+ // match criteria matches everything.
+ Match match.Match `json:"match,omitempty"`
+
+ // Location describes the path to be mutated, for example: `spec.containers[name: main].image`.
+ Location string `json:"location,omitempty"`
+
+ // Parameters define the behavior of the mutator.
+ Parameters AssignImageParameters `json:"parameters,omitempty"`
+}
+
+type AssignImageParameters struct {
+ PathTests []PathTest `json:"pathTests,omitempty"`
+
+ // AssignDomain sets the domain component on an image string. The trailing
+ // slash should not be included.
+ AssignDomain string `json:"assignDomain,omitempty"`
+
+ // AssignPath sets the domain component on an image string.
+ AssignPath string `json:"assignPath,omitempty"`
+
+ // AssignImage sets the image component on an image string. It must start
+ // with a `:` or `@`.
+ AssignTag string `json:"assignTag,omitempty"`
+}
+
+// AssignImageStatus defines the observed state of AssignImage.
+type AssignImageStatus struct {
+ // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+
+ ByPod []v1beta1.MutatorPodStatusStatus `json:"byPod,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:resource:path="assignimage"
+// +kubebuilder:resource:scope="Cluster"
+// +kubebuilder:subresource:status
+
+// AssignImage is the Schema for the assignimage API.
+type AssignImage struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec AssignImageSpec `json:"spec,omitempty"`
+ Status AssignImageStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// AssignImageList contains a list of AssignImage.
+type AssignImageList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []AssignImage `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&AssignImage{}, &AssignImageList{})
+}
diff --git a/apis/mutations/v1alpha1/assignmetadata_types.go b/apis/mutations/v1alpha1/assignmetadata_types.go
index 5516f7bb663..db3c5e90005 100644
--- a/apis/mutations/v1alpha1/assignmetadata_types.go
+++ b/apis/mutations/v1alpha1/assignmetadata_types.go
@@ -16,8 +16,8 @@ limitations under the License.
package v1alpha1
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
diff --git a/apis/mutations/v1alpha1/doc.go b/apis/mutations/v1alpha1/doc.go
index 06f0502febf..14d2c346c74 100644
--- a/apis/mutations/v1alpha1/doc.go
+++ b/apis/mutations/v1alpha1/doc.go
@@ -1,5 +1,5 @@
// Package v1alpha1 includes v1alpha1 mutators
-// +k8s:conversion-gen=github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned
-// -external-types=github.com/open-policy-agent/gatekeeper/apis/mutations/v1alpha1
+// +k8s:conversion-gen=github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned
+// -external-types=github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1alpha1
package v1alpha1
diff --git a/apis/mutations/v1alpha1/externaldata_types.go b/apis/mutations/v1alpha1/externaldata_types.go
index d37d7717977..b9a65e39ab5 100644
--- a/apis/mutations/v1alpha1/externaldata_types.go
+++ b/apis/mutations/v1alpha1/externaldata_types.go
@@ -1,7 +1,7 @@
package v1alpha1
import (
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
// ExternalData describes the external data source to use for the mutation.
diff --git a/apis/mutations/v1alpha1/modifyset_types.go b/apis/mutations/v1alpha1/modifyset_types.go
index 0c084cc071f..d98c6a196fa 100644
--- a/apis/mutations/v1alpha1/modifyset_types.go
+++ b/apis/mutations/v1alpha1/modifyset_types.go
@@ -16,8 +16,8 @@ limitations under the License.
package v1alpha1
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
diff --git a/apis/mutations/v1alpha1/value.go b/apis/mutations/v1alpha1/value.go
index 422daa82408..c91693b7561 100644
--- a/apis/mutations/v1alpha1/value.go
+++ b/apis/mutations/v1alpha1/value.go
@@ -1,8 +1,8 @@
package v1alpha1
import (
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
type AssignField struct {
diff --git a/apis/mutations/v1alpha1/zz_generated.conversion.go b/apis/mutations/v1alpha1/zz_generated.conversion.go
index 8e4eb5e6ad6..c31ff7e8264 100644
--- a/apis/mutations/v1alpha1/zz_generated.conversion.go
+++ b/apis/mutations/v1alpha1/zz_generated.conversion.go
@@ -22,11 +22,11 @@ package v1alpha1
import (
unsafe "unsafe"
- unversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- v1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- match "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- tester "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
- types "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ unversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ v1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ match "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ tester "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ types "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
)
@@ -58,6 +58,56 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
+ if err := s.AddGeneratedConversionFunc((*AssignImage)(nil), (*unversioned.AssignImage)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1alpha1_AssignImage_To_unversioned_AssignImage(a.(*AssignImage), b.(*unversioned.AssignImage), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*unversioned.AssignImage)(nil), (*AssignImage)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_unversioned_AssignImage_To_v1alpha1_AssignImage(a.(*unversioned.AssignImage), b.(*AssignImage), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*AssignImageList)(nil), (*unversioned.AssignImageList)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1alpha1_AssignImageList_To_unversioned_AssignImageList(a.(*AssignImageList), b.(*unversioned.AssignImageList), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*unversioned.AssignImageList)(nil), (*AssignImageList)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_unversioned_AssignImageList_To_v1alpha1_AssignImageList(a.(*unversioned.AssignImageList), b.(*AssignImageList), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*AssignImageParameters)(nil), (*unversioned.AssignImageParameters)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1alpha1_AssignImageParameters_To_unversioned_AssignImageParameters(a.(*AssignImageParameters), b.(*unversioned.AssignImageParameters), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*unversioned.AssignImageParameters)(nil), (*AssignImageParameters)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_unversioned_AssignImageParameters_To_v1alpha1_AssignImageParameters(a.(*unversioned.AssignImageParameters), b.(*AssignImageParameters), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*AssignImageSpec)(nil), (*unversioned.AssignImageSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1alpha1_AssignImageSpec_To_unversioned_AssignImageSpec(a.(*AssignImageSpec), b.(*unversioned.AssignImageSpec), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*unversioned.AssignImageSpec)(nil), (*AssignImageSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_unversioned_AssignImageSpec_To_v1alpha1_AssignImageSpec(a.(*unversioned.AssignImageSpec), b.(*AssignImageSpec), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*AssignImageStatus)(nil), (*unversioned.AssignImageStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1alpha1_AssignImageStatus_To_unversioned_AssignImageStatus(a.(*AssignImageStatus), b.(*unversioned.AssignImageStatus), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddGeneratedConversionFunc((*unversioned.AssignImageStatus)(nil), (*AssignImageStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_unversioned_AssignImageStatus_To_v1alpha1_AssignImageStatus(a.(*unversioned.AssignImageStatus), b.(*AssignImageStatus), scope)
+ }); err != nil {
+ return err
+ }
if err := s.AddGeneratedConversionFunc((*AssignList)(nil), (*unversioned.AssignList)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_AssignList_To_unversioned_AssignList(a.(*AssignList), b.(*unversioned.AssignList), scope)
}); err != nil {
@@ -297,6 +347,136 @@ func Convert_unversioned_AssignField_To_v1alpha1_AssignField(in *unversioned.Ass
return autoConvert_unversioned_AssignField_To_v1alpha1_AssignField(in, out, s)
}
+func autoConvert_v1alpha1_AssignImage_To_unversioned_AssignImage(in *AssignImage, out *unversioned.AssignImage, s conversion.Scope) error {
+ out.ObjectMeta = in.ObjectMeta
+ if err := Convert_v1alpha1_AssignImageSpec_To_unversioned_AssignImageSpec(&in.Spec, &out.Spec, s); err != nil {
+ return err
+ }
+ if err := Convert_v1alpha1_AssignImageStatus_To_unversioned_AssignImageStatus(&in.Status, &out.Status, s); err != nil {
+ return err
+ }
+ return nil
+}
+
+// Convert_v1alpha1_AssignImage_To_unversioned_AssignImage is an autogenerated conversion function.
+func Convert_v1alpha1_AssignImage_To_unversioned_AssignImage(in *AssignImage, out *unversioned.AssignImage, s conversion.Scope) error {
+ return autoConvert_v1alpha1_AssignImage_To_unversioned_AssignImage(in, out, s)
+}
+
+func autoConvert_unversioned_AssignImage_To_v1alpha1_AssignImage(in *unversioned.AssignImage, out *AssignImage, s conversion.Scope) error {
+ out.ObjectMeta = in.ObjectMeta
+ if err := Convert_unversioned_AssignImageSpec_To_v1alpha1_AssignImageSpec(&in.Spec, &out.Spec, s); err != nil {
+ return err
+ }
+ if err := Convert_unversioned_AssignImageStatus_To_v1alpha1_AssignImageStatus(&in.Status, &out.Status, s); err != nil {
+ return err
+ }
+ return nil
+}
+
+// Convert_unversioned_AssignImage_To_v1alpha1_AssignImage is an autogenerated conversion function.
+func Convert_unversioned_AssignImage_To_v1alpha1_AssignImage(in *unversioned.AssignImage, out *AssignImage, s conversion.Scope) error {
+ return autoConvert_unversioned_AssignImage_To_v1alpha1_AssignImage(in, out, s)
+}
+
+func autoConvert_v1alpha1_AssignImageList_To_unversioned_AssignImageList(in *AssignImageList, out *unversioned.AssignImageList, s conversion.Scope) error {
+ out.ListMeta = in.ListMeta
+ out.Items = *(*[]unversioned.AssignImage)(unsafe.Pointer(&in.Items))
+ return nil
+}
+
+// Convert_v1alpha1_AssignImageList_To_unversioned_AssignImageList is an autogenerated conversion function.
+func Convert_v1alpha1_AssignImageList_To_unversioned_AssignImageList(in *AssignImageList, out *unversioned.AssignImageList, s conversion.Scope) error {
+ return autoConvert_v1alpha1_AssignImageList_To_unversioned_AssignImageList(in, out, s)
+}
+
+func autoConvert_unversioned_AssignImageList_To_v1alpha1_AssignImageList(in *unversioned.AssignImageList, out *AssignImageList, s conversion.Scope) error {
+ out.ListMeta = in.ListMeta
+ out.Items = *(*[]AssignImage)(unsafe.Pointer(&in.Items))
+ return nil
+}
+
+// Convert_unversioned_AssignImageList_To_v1alpha1_AssignImageList is an autogenerated conversion function.
+func Convert_unversioned_AssignImageList_To_v1alpha1_AssignImageList(in *unversioned.AssignImageList, out *AssignImageList, s conversion.Scope) error {
+ return autoConvert_unversioned_AssignImageList_To_v1alpha1_AssignImageList(in, out, s)
+}
+
+func autoConvert_v1alpha1_AssignImageParameters_To_unversioned_AssignImageParameters(in *AssignImageParameters, out *unversioned.AssignImageParameters, s conversion.Scope) error {
+ out.PathTests = *(*[]unversioned.PathTest)(unsafe.Pointer(&in.PathTests))
+ out.AssignDomain = in.AssignDomain
+ out.AssignPath = in.AssignPath
+ out.AssignTag = in.AssignTag
+ return nil
+}
+
+// Convert_v1alpha1_AssignImageParameters_To_unversioned_AssignImageParameters is an autogenerated conversion function.
+func Convert_v1alpha1_AssignImageParameters_To_unversioned_AssignImageParameters(in *AssignImageParameters, out *unversioned.AssignImageParameters, s conversion.Scope) error {
+ return autoConvert_v1alpha1_AssignImageParameters_To_unversioned_AssignImageParameters(in, out, s)
+}
+
+func autoConvert_unversioned_AssignImageParameters_To_v1alpha1_AssignImageParameters(in *unversioned.AssignImageParameters, out *AssignImageParameters, s conversion.Scope) error {
+ out.PathTests = *(*[]PathTest)(unsafe.Pointer(&in.PathTests))
+ out.AssignDomain = in.AssignDomain
+ out.AssignPath = in.AssignPath
+ out.AssignTag = in.AssignTag
+ return nil
+}
+
+// Convert_unversioned_AssignImageParameters_To_v1alpha1_AssignImageParameters is an autogenerated conversion function.
+func Convert_unversioned_AssignImageParameters_To_v1alpha1_AssignImageParameters(in *unversioned.AssignImageParameters, out *AssignImageParameters, s conversion.Scope) error {
+ return autoConvert_unversioned_AssignImageParameters_To_v1alpha1_AssignImageParameters(in, out, s)
+}
+
+func autoConvert_v1alpha1_AssignImageSpec_To_unversioned_AssignImageSpec(in *AssignImageSpec, out *unversioned.AssignImageSpec, s conversion.Scope) error {
+ out.ApplyTo = *(*[]match.ApplyTo)(unsafe.Pointer(&in.ApplyTo))
+ out.Match = in.Match
+ out.Location = in.Location
+ if err := Convert_v1alpha1_AssignImageParameters_To_unversioned_AssignImageParameters(&in.Parameters, &out.Parameters, s); err != nil {
+ return err
+ }
+ return nil
+}
+
+// Convert_v1alpha1_AssignImageSpec_To_unversioned_AssignImageSpec is an autogenerated conversion function.
+func Convert_v1alpha1_AssignImageSpec_To_unversioned_AssignImageSpec(in *AssignImageSpec, out *unversioned.AssignImageSpec, s conversion.Scope) error {
+ return autoConvert_v1alpha1_AssignImageSpec_To_unversioned_AssignImageSpec(in, out, s)
+}
+
+func autoConvert_unversioned_AssignImageSpec_To_v1alpha1_AssignImageSpec(in *unversioned.AssignImageSpec, out *AssignImageSpec, s conversion.Scope) error {
+ out.ApplyTo = *(*[]match.ApplyTo)(unsafe.Pointer(&in.ApplyTo))
+ out.Match = in.Match
+ out.Location = in.Location
+ if err := Convert_unversioned_AssignImageParameters_To_v1alpha1_AssignImageParameters(&in.Parameters, &out.Parameters, s); err != nil {
+ return err
+ }
+ return nil
+}
+
+// Convert_unversioned_AssignImageSpec_To_v1alpha1_AssignImageSpec is an autogenerated conversion function.
+func Convert_unversioned_AssignImageSpec_To_v1alpha1_AssignImageSpec(in *unversioned.AssignImageSpec, out *AssignImageSpec, s conversion.Scope) error {
+ return autoConvert_unversioned_AssignImageSpec_To_v1alpha1_AssignImageSpec(in, out, s)
+}
+
+func autoConvert_v1alpha1_AssignImageStatus_To_unversioned_AssignImageStatus(in *AssignImageStatus, out *unversioned.AssignImageStatus, s conversion.Scope) error {
+ out.ByPod = *(*[]v1beta1.MutatorPodStatusStatus)(unsafe.Pointer(&in.ByPod))
+ return nil
+}
+
+// Convert_v1alpha1_AssignImageStatus_To_unversioned_AssignImageStatus is an autogenerated conversion function.
+func Convert_v1alpha1_AssignImageStatus_To_unversioned_AssignImageStatus(in *AssignImageStatus, out *unversioned.AssignImageStatus, s conversion.Scope) error {
+ return autoConvert_v1alpha1_AssignImageStatus_To_unversioned_AssignImageStatus(in, out, s)
+}
+
+func autoConvert_unversioned_AssignImageStatus_To_v1alpha1_AssignImageStatus(in *unversioned.AssignImageStatus, out *AssignImageStatus, s conversion.Scope) error {
+ out.ByPod = *(*[]v1beta1.MutatorPodStatusStatus)(unsafe.Pointer(&in.ByPod))
+ return nil
+}
+
+// Convert_unversioned_AssignImageStatus_To_v1alpha1_AssignImageStatus is an autogenerated conversion function.
+func Convert_unversioned_AssignImageStatus_To_v1alpha1_AssignImageStatus(in *unversioned.AssignImageStatus, out *AssignImageStatus, s conversion.Scope) error {
+ return autoConvert_unversioned_AssignImageStatus_To_v1alpha1_AssignImageStatus(in, out, s)
+}
+
func autoConvert_v1alpha1_AssignList_To_unversioned_AssignList(in *AssignList, out *unversioned.AssignList, s conversion.Scope) error {
out.ListMeta = in.ListMeta
out.Items = *(*[]unversioned.Assign)(unsafe.Pointer(&in.Items))
diff --git a/apis/mutations/v1alpha1/zz_generated.deepcopy.go b/apis/mutations/v1alpha1/zz_generated.deepcopy.go
index 4ac3428f126..274942c8825 100644
--- a/apis/mutations/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/mutations/v1alpha1/zz_generated.deepcopy.go
@@ -21,8 +21,8 @@ limitations under the License.
package v1alpha1
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
"k8s.io/apimachinery/pkg/runtime"
)
@@ -82,6 +82,131 @@ func (in *AssignField) DeepCopy() *AssignField {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AssignImage) DeepCopyInto(out *AssignImage) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+ in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AssignImage.
+func (in *AssignImage) DeepCopy() *AssignImage {
+ if in == nil {
+ return nil
+ }
+ out := new(AssignImage)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *AssignImage) 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 *AssignImageList) DeepCopyInto(out *AssignImageList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]AssignImage, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AssignImageList.
+func (in *AssignImageList) DeepCopy() *AssignImageList {
+ if in == nil {
+ return nil
+ }
+ out := new(AssignImageList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *AssignImageList) 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 *AssignImageParameters) DeepCopyInto(out *AssignImageParameters) {
+ *out = *in
+ if in.PathTests != nil {
+ in, out := &in.PathTests, &out.PathTests
+ *out = make([]PathTest, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AssignImageParameters.
+func (in *AssignImageParameters) DeepCopy() *AssignImageParameters {
+ if in == nil {
+ return nil
+ }
+ out := new(AssignImageParameters)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AssignImageSpec) DeepCopyInto(out *AssignImageSpec) {
+ *out = *in
+ if in.ApplyTo != nil {
+ in, out := &in.ApplyTo, &out.ApplyTo
+ *out = make([]match.ApplyTo, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ in.Match.DeepCopyInto(&out.Match)
+ in.Parameters.DeepCopyInto(&out.Parameters)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AssignImageSpec.
+func (in *AssignImageSpec) DeepCopy() *AssignImageSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(AssignImageSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AssignImageStatus) DeepCopyInto(out *AssignImageStatus) {
+ *out = *in
+ if in.ByPod != nil {
+ in, out := &in.ByPod, &out.ByPod
+ *out = make([]v1beta1.MutatorPodStatusStatus, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AssignImageStatus.
+func (in *AssignImageStatus) DeepCopy() *AssignImageStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(AssignImageStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AssignList) DeepCopyInto(out *AssignList) {
*out = *in
diff --git a/apis/mutations/v1beta1/assign_types.go b/apis/mutations/v1beta1/assign_types.go
index db4e6fdd2c9..582055271cf 100644
--- a/apis/mutations/v1beta1/assign_types.go
+++ b/apis/mutations/v1beta1/assign_types.go
@@ -16,9 +16,9 @@ limitations under the License.
package v1beta1
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
diff --git a/apis/mutations/v1beta1/assignmetadata_types.go b/apis/mutations/v1beta1/assignmetadata_types.go
index e4616db8e69..66275960e29 100644
--- a/apis/mutations/v1beta1/assignmetadata_types.go
+++ b/apis/mutations/v1beta1/assignmetadata_types.go
@@ -16,8 +16,8 @@ limitations under the License.
package v1beta1
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
diff --git a/apis/mutations/v1beta1/doc.go b/apis/mutations/v1beta1/doc.go
index 1c9681af2ce..9e9820159be 100644
--- a/apis/mutations/v1beta1/doc.go
+++ b/apis/mutations/v1beta1/doc.go
@@ -1,5 +1,5 @@
// Package v1beta1 includes v1beta1 mutators
-// +k8s:conversion-gen=github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned
-// -external-types=github.com/open-policy-agent/gatekeeper/apis/mutations/v1beta1
+// +k8s:conversion-gen=github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned
+// -external-types=github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1beta1
package v1beta1
diff --git a/apis/mutations/v1beta1/externaldata_types.go b/apis/mutations/v1beta1/externaldata_types.go
index 80ed4815f79..bcf42999ccf 100644
--- a/apis/mutations/v1beta1/externaldata_types.go
+++ b/apis/mutations/v1beta1/externaldata_types.go
@@ -1,7 +1,7 @@
package v1beta1
import (
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
// ExternalData describes the external data source to use for the mutation.
diff --git a/apis/mutations/v1beta1/modifyset_types.go b/apis/mutations/v1beta1/modifyset_types.go
index 81a72f0f72e..621fc591b57 100644
--- a/apis/mutations/v1beta1/modifyset_types.go
+++ b/apis/mutations/v1beta1/modifyset_types.go
@@ -16,8 +16,8 @@ limitations under the License.
package v1beta1
import (
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
diff --git a/apis/mutations/v1beta1/value.go b/apis/mutations/v1beta1/value.go
index 3b63b610a65..b14ffd0edb7 100644
--- a/apis/mutations/v1beta1/value.go
+++ b/apis/mutations/v1beta1/value.go
@@ -1,8 +1,8 @@
package v1beta1
import (
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
type AssignField struct {
diff --git a/apis/mutations/v1beta1/zz_generated.conversion.go b/apis/mutations/v1beta1/zz_generated.conversion.go
index 6e6963f0e3c..ef91907c361 100644
--- a/apis/mutations/v1beta1/zz_generated.conversion.go
+++ b/apis/mutations/v1beta1/zz_generated.conversion.go
@@ -22,11 +22,11 @@ package v1beta1
import (
unsafe "unsafe"
- unversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- statusv1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- match "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- tester "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
- types "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ unversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ match "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ tester "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ types "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
)
diff --git a/apis/mutations/v1beta1/zz_generated.deepcopy.go b/apis/mutations/v1beta1/zz_generated.deepcopy.go
index 071b5f3873e..50ef1e24539 100644
--- a/apis/mutations/v1beta1/zz_generated.deepcopy.go
+++ b/apis/mutations/v1beta1/zz_generated.deepcopy.go
@@ -21,8 +21,8 @@ limitations under the License.
package v1beta1
import (
- statusv1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
"k8s.io/apimachinery/pkg/runtime"
)
diff --git a/apis/status/v1beta1/constraintpodstatus_types.go b/apis/status/v1beta1/constraintpodstatus_types.go
index e91fca1dfeb..250886b29a4 100644
--- a/apis/status/v1beta1/constraintpodstatus_types.go
+++ b/apis/status/v1beta1/constraintpodstatus_types.go
@@ -18,8 +18,8 @@ package v1beta1
import (
"strings"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -113,5 +113,5 @@ func KeyForConstraint(id string, constraint *unstructured.Unstructured) (string,
// because K8s requires all lowercase letters for resource names
kind := strings.ToLower(constraint.GetObjectKind().GroupVersionKind().Kind)
name := constraint.GetName()
- return dashPacker(id, kind, name)
+ return DashPacker(id, kind, name)
}
diff --git a/apis/status/v1beta1/constraintpodstatus_types_test.go b/apis/status/v1beta1/constraintpodstatus_types_test.go
index ca7f6be1633..db88a672f71 100644
--- a/apis/status/v1beta1/constraintpodstatus_types_test.go
+++ b/apis/status/v1beta1/constraintpodstatus_types_test.go
@@ -1,14 +1,13 @@
package v1beta1_test
import (
- "strings"
"testing"
"github.com/google/go-cmp/cmp"
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/test/testutils"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
@@ -53,7 +52,7 @@ func TestNewConstraintStatusForPod(t *testing.T) {
v1beta1.ConstraintNameLabel: "a-constraint",
v1beta1.ConstraintKindLabel: "AConstraintKind",
v1beta1.PodLabel: podName,
- v1beta1.ConstraintTemplateNameLabel: strings.ToLower(cstrKind),
+ v1beta1.ConstraintTemplateNameLabel: "aconstraintkind",
})
err = controllerutil.SetOwnerReference(pod, wantStatus, scheme)
diff --git a/apis/status/v1beta1/constrainttemplatepodstatus_types.go b/apis/status/v1beta1/constrainttemplatepodstatus_types.go
index 1b9e0e77399..1850ec7de60 100644
--- a/apis/status/v1beta1/constrainttemplatepodstatus_types.go
+++ b/apis/status/v1beta1/constrainttemplatepodstatus_types.go
@@ -17,8 +17,8 @@ package v1beta1
import (
templatesv1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -88,5 +88,5 @@ func NewConstraintTemplateStatusForPod(pod *corev1.Pod, templateName string, sch
// KeyForConstraintTemplate returns a unique status object name given the Pod ID and
// a template object.
func KeyForConstraintTemplate(id string, templateName string) (string, error) {
- return dashPacker(id, templateName)
+ return DashPacker(id, templateName)
}
diff --git a/apis/status/v1beta1/constrainttemplatepodstatus_types_test.go b/apis/status/v1beta1/constrainttemplatepodstatus_types_test.go
index 9a96178cb8a..beff7cf95ce 100644
--- a/apis/status/v1beta1/constrainttemplatepodstatus_types_test.go
+++ b/apis/status/v1beta1/constrainttemplatepodstatus_types_test.go
@@ -4,10 +4,10 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/test/testutils"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
diff --git a/apis/status/v1beta1/expansiontemplatepodstatus_types.go b/apis/status/v1beta1/expansiontemplatepodstatus_types.go
new file mode 100644
index 00000000000..1d7cad6829b
--- /dev/null
+++ b/apis/status/v1beta1/expansiontemplatepodstatus_types.go
@@ -0,0 +1,83 @@
+package v1beta1
+
+import (
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+)
+
+// ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+type ExpansionTemplatePodStatusStatus struct {
+ // Important: Run "make" to regenerate code after modifying this file
+ ID string `json:"id,omitempty"`
+ TemplateUID types.UID `json:"templateUID,omitempty"`
+ Operations []string `json:"operations,omitempty"`
+ ObservedGeneration int64 `json:"observedGeneration,omitempty"`
+ Errors []*ExpansionTemplateError `json:"errors,omitempty"`
+}
+
+// +kubebuilder:object:generate=true
+
+type ExpansionTemplateError struct {
+ Type string `json:"type,omitempty"`
+ Message string `json:"message"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:resource:scope=Namespaced
+
+// ExpansionTemplatePodStatus is the Schema for the expansiontemplatepodstatuses API.
+type ExpansionTemplatePodStatus struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Status ExpansionTemplatePodStatusStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ExpansionTemplatePodStatusList contains a list of ExpansionTemplatePodStatus.
+type ExpansionTemplatePodStatusList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []ExpansionTemplatePodStatus `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&ExpansionTemplatePodStatus{}, &ExpansionTemplatePodStatusList{})
+}
+
+// NewExpansionTemplateStatusForPod returns an expansion template status object
+// that has been initialized with the bare minimum of fields to make it functional
+// with the expansion template status controller.
+func NewExpansionTemplateStatusForPod(pod *corev1.Pod, templateName string, scheme *runtime.Scheme) (*ExpansionTemplatePodStatus, error) {
+ obj := &ExpansionTemplatePodStatus{}
+ name, err := KeyForExpansionTemplate(pod.Name, templateName)
+ if err != nil {
+ return nil, err
+ }
+ obj.SetName(name)
+ obj.SetNamespace(util.GetNamespace())
+ obj.Status.ID = pod.Name
+ obj.Status.Operations = operations.AssignedStringList()
+ obj.SetLabels(map[string]string{
+ ExpansionTemplateNameLabel: templateName,
+ PodLabel: pod.Name,
+ })
+
+ if err := controllerutil.SetOwnerReference(pod, obj, scheme); err != nil {
+ return nil, err
+ }
+
+ return obj, nil
+}
+
+// KeyForExpansionTemplate returns a unique status object name given the Pod ID and
+// a template object.
+func KeyForExpansionTemplate(id string, templateName string) (string, error) {
+ return DashPacker(id, templateName)
+}
diff --git a/apis/status/v1beta1/labels.go b/apis/status/v1beta1/labels.go
index 9456c8f948f..0f0caca91ce 100644
--- a/apis/status/v1beta1/labels.go
+++ b/apis/status/v1beta1/labels.go
@@ -2,6 +2,7 @@ package v1beta1
// Label keys used for internal gatekeeper operations.
const (
+ ExpansionTemplateNameLabel = "internal.gatekeeper.sh/expansiontemplate-name"
ConstraintNameLabel = "internal.gatekeeper.sh/constraint-name"
ConstraintKindLabel = "internal.gatekeeper.sh/constraint-kind"
ConstraintTemplateNameLabel = "internal.gatekeeper.sh/constrainttemplate-name"
diff --git a/apis/status/v1beta1/mutatorpodstatus_types.go b/apis/status/v1beta1/mutatorpodstatus_types.go
index 83ed175d931..fa13849eee2 100644
--- a/apis/status/v1beta1/mutatorpodstatus_types.go
+++ b/apis/status/v1beta1/mutatorpodstatus_types.go
@@ -18,9 +18,9 @@ package v1beta1
import (
"strings"
- mtypes "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ mtypes "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -113,5 +113,5 @@ func KeyForMutatorID(id string, mID mtypes.ID) (string, error) {
// We must do this because K8s requires all lowercase letters for resource names
kind := strings.ToLower(mID.Kind)
name := mID.Name
- return dashPacker(id, kind, name)
+ return DashPacker(id, kind, name)
}
diff --git a/apis/status/v1beta1/mutatorpodstatus_types_test.go b/apis/status/v1beta1/mutatorpodstatus_types_test.go
index 2a9ab785f27..496a9a7744f 100644
--- a/apis/status/v1beta1/mutatorpodstatus_types_test.go
+++ b/apis/status/v1beta1/mutatorpodstatus_types_test.go
@@ -4,11 +4,11 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/testhelpers"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/test/testutils"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/testhelpers"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
diff --git a/apis/status/v1beta1/util.go b/apis/status/v1beta1/util.go
index 58f1cbd117b..decb0905526 100644
--- a/apis/status/v1beta1/util.go
+++ b/apis/status/v1beta1/util.go
@@ -32,7 +32,7 @@ func dashExtractor(val string) []string {
return tokens
}
-// dashPacker puts a list of strings into a dash-separated format. Note that
+// DashPacker puts a list of strings into a dash-separated format. Note that
// it cannot handle empty strings, as that makes the dash separator for the empty
// string reduce to an escaped dash. This is fine because none of the packed strings
// are allowed to be empty. If this changes in the future, we could create a placeholder
@@ -43,17 +43,17 @@ func dashExtractor(val string) []string {
// which is also disallowed by the schema (and would require an additional placeholder
// character to fix). Finally, note that it is impossible to distinguish between
// a nil list of strings and a list of one empty string.
-func dashPacker(vals ...string) (string, error) {
+func DashPacker(vals ...string) (string, error) {
if len(vals) == 0 {
- return "", fmt.Errorf("dashPacker cannot pack an empty list of strings")
+ return "", fmt.Errorf("DashPacker cannot pack an empty list of strings")
}
b := strings.Builder{}
for i, val := range vals {
if strings.HasPrefix(val, "-") || strings.HasSuffix(val, "-") {
- return "", fmt.Errorf("dashPacker cannot pack strings that begin or end with a dash: %+v", vals)
+ return "", fmt.Errorf("DashPacker cannot pack strings that begin or end with a dash: %+v", vals)
}
if len(val) == 0 {
- return "", fmt.Errorf("dashPacker cannot pack empty strings: %v", vals)
+ return "", fmt.Errorf("DashPacker cannot pack empty strings: %v", vals)
}
if i != 0 {
b.WriteString("-")
diff --git a/apis/status/v1beta1/util_test.go b/apis/status/v1beta1/util_test.go
index 592b9bd1226..47e4a58db20 100644
--- a/apis/status/v1beta1/util_test.go
+++ b/apis/status/v1beta1/util_test.go
@@ -91,12 +91,12 @@ var dashingTestCases = []struct {
func TestDashPacker(t *testing.T) {
for _, tc := range dashingTestCases {
t.Run(tc.name, func(t *testing.T) {
- gotPacked, err := dashPacker(tc.extracted...)
+ gotPacked, err := DashPacker(tc.extracted...)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(tc.packed, gotPacked); diff != "" {
- t.Fatal("got dashPacker(tc.extracted...) != tc.packed, want equal")
+ t.Fatal("got DashPacker(tc.extracted...) != tc.packed, want equal")
}
})
}
diff --git a/apis/status/v1beta1/zz_generated.deepcopy.go b/apis/status/v1beta1/zz_generated.deepcopy.go
index dddc9496679..5a42224d349 100644
--- a/apis/status/v1beta1/zz_generated.deepcopy.go
+++ b/apis/status/v1beta1/zz_generated.deepcopy.go
@@ -212,6 +212,110 @@ func (in *Error) DeepCopy() *Error {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExpansionTemplateError) DeepCopyInto(out *ExpansionTemplateError) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpansionTemplateError.
+func (in *ExpansionTemplateError) DeepCopy() *ExpansionTemplateError {
+ if in == nil {
+ return nil
+ }
+ out := new(ExpansionTemplateError)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExpansionTemplatePodStatus) DeepCopyInto(out *ExpansionTemplatePodStatus) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpansionTemplatePodStatus.
+func (in *ExpansionTemplatePodStatus) DeepCopy() *ExpansionTemplatePodStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ExpansionTemplatePodStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ExpansionTemplatePodStatus) 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 *ExpansionTemplatePodStatusList) DeepCopyInto(out *ExpansionTemplatePodStatusList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]ExpansionTemplatePodStatus, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpansionTemplatePodStatusList.
+func (in *ExpansionTemplatePodStatusList) DeepCopy() *ExpansionTemplatePodStatusList {
+ if in == nil {
+ return nil
+ }
+ out := new(ExpansionTemplatePodStatusList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ExpansionTemplatePodStatusList) 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 *ExpansionTemplatePodStatusStatus) DeepCopyInto(out *ExpansionTemplatePodStatusStatus) {
+ *out = *in
+ if in.Operations != nil {
+ in, out := &in.Operations, &out.Operations
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+ if in.Errors != nil {
+ in, out := &in.Errors, &out.Errors
+ *out = make([]*ExpansionTemplateError, len(*in))
+ for i := range *in {
+ if (*in)[i] != nil {
+ in, out := &(*in)[i], &(*out)[i]
+ *out = new(ExpansionTemplateError)
+ **out = **in
+ }
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpansionTemplatePodStatusStatus.
+func (in *ExpansionTemplatePodStatusStatus) DeepCopy() *ExpansionTemplatePodStatusStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ExpansionTemplatePodStatusStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MutatorError) DeepCopyInto(out *MutatorError) {
*out = *in
diff --git a/apis/syncset/v1alpha1/groupversion_info.go b/apis/syncset/v1alpha1/groupversion_info.go
new file mode 100644
index 00000000000..0763852909e
--- /dev/null
+++ b/apis/syncset/v1alpha1/groupversion_info.go
@@ -0,0 +1,20 @@
+// Package v1alpha1 contains API Schema definitions for the SyncSet v1alpha1 API group
+// +kubebuilder:object:generate=true
+// +groupName=syncset.gatekeeper.sh
+package v1alpha1
+
+import (
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+ // GroupVersion is group version used to register these objects.
+ GroupVersion = schema.GroupVersion{Group: "syncset.gatekeeper.sh", Version: "v1alpha1"}
+
+ // SchemeBuilder is used to add go types to the GroupVersionKind scheme.
+ SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+ // AddToScheme adds the types in this group-version to the given scheme.
+ AddToScheme = SchemeBuilder.AddToScheme
+)
diff --git a/apis/syncset/v1alpha1/syncset_types.go b/apis/syncset/v1alpha1/syncset_types.go
new file mode 100644
index 00000000000..d03b53c5bff
--- /dev/null
+++ b/apis/syncset/v1alpha1/syncset_types.go
@@ -0,0 +1,39 @@
+package v1alpha1
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+type SyncSetSpec struct {
+ GVKs []GVKEntry `json:"gvks,omitempty"`
+}
+
+type GVKEntry struct {
+ Group string `json:"group,omitempty"`
+ Version string `json:"version,omitempty"`
+ Kind string `json:"kind,omitempty"`
+}
+
+// +kubebuilder:resource:scope=Cluster
+// +kubebuilder:object:root=true
+
+// SyncSet is the Schema for the SyncSet API.
+type SyncSet struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec SyncSetSpec `json:"spec,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// SyncSetList contains a list of SyncSet.
+type SyncSetList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []SyncSet `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&SyncSet{}, &SyncSetList{})
+}
diff --git a/apis/syncset/v1alpha1/zz_generated.deepcopy.go b/apis/syncset/v1alpha1/zz_generated.deepcopy.go
new file mode 100644
index 00000000000..f3e663e93e0
--- /dev/null
+++ b/apis/syncset/v1alpha1/zz_generated.deepcopy.go
@@ -0,0 +1,118 @@
+//go:build !ignore_autogenerated
+// +build !ignore_autogenerated
+
+/*
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *GVKEntry) DeepCopyInto(out *GVKEntry) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GVKEntry.
+func (in *GVKEntry) DeepCopy() *GVKEntry {
+ if in == nil {
+ return nil
+ }
+ out := new(GVKEntry)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SyncSet) DeepCopyInto(out *SyncSet) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SyncSet.
+func (in *SyncSet) DeepCopy() *SyncSet {
+ if in == nil {
+ return nil
+ }
+ out := new(SyncSet)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SyncSet) 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 *SyncSetList) DeepCopyInto(out *SyncSetList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]SyncSet, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SyncSetList.
+func (in *SyncSetList) DeepCopy() *SyncSetList {
+ if in == nil {
+ return nil
+ }
+ out := new(SyncSetList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SyncSetList) 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 *SyncSetSpec) DeepCopyInto(out *SyncSetSpec) {
+ *out = *in
+ if in.GVKs != nil {
+ in, out := &in.GVKs, &out.GVKs
+ *out = make([]GVKEntry, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SyncSetSpec.
+func (in *SyncSetSpec) DeepCopy() *SyncSetSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(SyncSetSpec)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/build/get-build-commit.sh b/build/get-build-commit.sh
deleted file mode 100755
index 5c386553cf3..00000000000
--- a/build/get-build-commit.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env bash
-
-GIT_SHA=$(git rev-parse --short HEAD)
-
-if [ -z "$(git status --porcelain 2>/dev/null)" ]; then
- echo $GIT_SHA
-else
- echo "$GIT_SHA-dirty"
-fi
diff --git a/build/get-build-hostname.sh b/build/get-build-hostname.sh
deleted file mode 100755
index 0ed5c926ced..00000000000
--- a/build/get-build-hostname.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/bin/env bash
-
-hostname -f
diff --git a/build/get-build-timestamp.sh b/build/get-build-timestamp.sh
deleted file mode 100755
index 8ba5567b6d1..00000000000
--- a/build/get-build-timestamp.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/bin/env bash
-
-date -u +"%Y-%m-%dT%H:%M:%SZ"
diff --git a/build/tooling/Dockerfile b/build/tooling/Dockerfile
index c9815eb6c77..0a8251a4f1f 100644
--- a/build/tooling/Dockerfile
+++ b/build/tooling/Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.19-bullseye
+FROM golang:1.21-bullseye@sha256:26c7537d6ac3827eb4638034d16edc64de57bb011c8cc8fe301ac13a6568f6f4
RUN GO111MODULE=on go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.10.0
RUN GO111MODULE=on go install k8s.io/code-generator/cmd/conversion-gen@v0.25.4
diff --git a/build/tooling/vendormanifests.go b/build/tooling/vendormanifests.go
new file mode 100644
index 00000000000..9dc075b235f
--- /dev/null
+++ b/build/tooling/vendormanifests.go
@@ -0,0 +1,9 @@
+// This is used for vendoring frameworks to Gatekeeper.
+
+//go:build tools
+
+package build
+
+import (
+ _ "github.com/open-policy-agent/frameworks/constraint/deploy"
+)
diff --git a/build/update-match-schema.sh b/build/update-match-schema.sh
new file mode 100755
index 00000000000..14c55a6577a
--- /dev/null
+++ b/build/update-match-schema.sh
@@ -0,0 +1,21 @@
+# This script builds a golang string constant containing the YAML code for the
+# Match CRD. This is needed to auto generate the JSONSchemaProps for Match. It
+# will parse the YAML for the Match CRD, found in $CRD_FILE, and output to
+# $GO_FILE.
+
+GO_FILE="./pkg/target/matchcrd_constant.go"
+SRC_FILE="./pkg/mutation/match/match_types.go"
+CRD_FILE="./config/crd/bases/match.gatekeeper.sh_matchcrd.yaml"
+
+cat << EOF > ${GO_FILE}
+package target
+
+// DO NOT MODIFY THIS FILE DIRECTLY!
+// This file is generated from $SRC_FILE via "make manifests".
+
+const matchYAML = \`
+EOF
+
+# Escape backticks in the yaml, add terminating backtick
+cat ${CRD_FILE} | sed "s/\`/\`+\"\`\"+\`/g" >> ${GO_FILE}
+echo "\`" >> ${GO_FILE}
diff --git a/build/vendormanifests.go b/build/vendormanifests.go
deleted file mode 100644
index a5a216e1fcd..00000000000
--- a/build/vendormanifests.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// +build tools
-
-package build
-
-import (
- _ "github.com/open-policy-agent/frameworks/constraint/deploy"
-)
-
diff --git a/charts/gatekeeper/Chart.yaml b/charts/gatekeeper/Chart.yaml
index 38a5497d03d..695bff1ac0d 100644
--- a/charts/gatekeeper/Chart.yaml
+++ b/charts/gatekeeper/Chart.yaml
@@ -4,8 +4,8 @@ name: gatekeeper
icon: https://open-policy-agent.github.io/gatekeeper/website/img/logo.svg
keywords:
- open policy agent
-version: 3.12.0-beta.0
+version: 3.14.0
home: https://github.com/open-policy-agent/gatekeeper
sources:
- https://github.com/open-policy-agent/gatekeeper.git
-appVersion: v3.12.0-beta.0
+appVersion: v3.14.0
diff --git a/charts/gatekeeper/README.md b/charts/gatekeeper/README.md
index 4278419da1c..fe841a46a52 100644
--- a/charts/gatekeeper/README.md
+++ b/charts/gatekeeper/README.md
@@ -27,7 +27,8 @@ _See [helm install](https://helm.sh/docs/helm/helm_install/) for command documen
## Upgrade Chart
**Upgrading from < v3.4.0**
-Chart 3.4.0 deprecates support for Helm 2 and also removes the creation of the `gatekeeper-system` Namespace from within the chart. This follows Helm 3 Best Practices.
+Chart 3.4.0 deprecates support for Helm 2 and also removes the creation of the `gatekeeper-system` Namespace from within
+the chart. This follows Helm 3 Best Practices.
Option 1:
A simple way to upgrade is to uninstall first and re-install with 3.4.0 or greater.
@@ -39,7 +40,9 @@ $ helm install -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper --creat
```
Option 2:
-Run the `helm_migrate.sh` script before installing the 3.4.0 or greater chart. This will remove the Helm secret for the original release, while keeping all of the resources. It then updates the annotations of the resources so that the new chart can import and manage them.
+Run the `helm_migrate.sh` script before installing the 3.4.0 or greater chart. This will remove the Helm secret for the
+original release, while keeping all of the resources. It then updates the annotations of the resources so that the new
+chart can import and manage them.
```console
$ helm_migrate.sh
@@ -47,153 +50,178 @@ $ helm install -n gatekeeper-system gatekeeper gatekeeper/gatekeeper
```
**Upgrading from >= v3.4.0**
+
```console
$ helm upgrade -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper
```
_See [helm 2 to 3](https://helm.sh/docs/topics/v2_v3_migration/) for Helm 2 migration documentation._
-
## Exempting Namespace
-The Helm chart automatically sets the Gatekeeper flag `--exempt-namespace={{ .Release.Namespace }}` in order to exempt the namespace where the chart is installed, and adds the `admission.gatekeeper.sh/ignore` label to the namespace during a post-install hook.
+The Helm chart automatically sets the Gatekeeper flag `--exempt-namespace={{ .Release.Namespace }}` in order to exempt
+the namespace where the chart is installed, and adds the `admission.gatekeeper.sh/ignore` label to the namespace during
+a post-install hook.
-_See [Exempting Namespaces](https://open-policy-agent.github.io/gatekeeper/website/docs/exempt-namespaces) for more information._
+_See [Exempting Namespaces](https://open-policy-agent.github.io/gatekeeper/website/docs/exempt-namespaces) for more
+information._
## Parameters
-| Parameter | Description | Default |
-| :-------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------ |
-| postInstall.labelNamespace.enabled | Add labels to the namespace during post install hooks | `true` |
-| postInstall.labelNamespace.extraNamespaces | The extra namespaces that need to have the label during post install hooks | `[]` |
-| postInstall.labelNamespace.extraAnnotations | Extra annotations added to the post install Job | `{}` |
-| postInstall.labelNamespace.image.repository | Image with kubectl to label the namespace | `openpolicyagent/gatekeeper-crds` |
-| postInstall.labelNamespace.image.tag | Image tag | Current release version: `v3.12.0-beta.0` |
-| postInstall.labelNamespace.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
-| postInstall.labelNamespace.image.pullSecrets | Image pullSecrets | `[]` |
-| postInstall.labelNamespace.extraRules | Extra rules for the gatekeeper-update-namespace-label Role | `[]` |
-| postInstall.probeWebhook.enabled | Probe webhook API post install. When enabled along with `postInstall.labelNamespace.enabled`, this probe will run as part of `postInstall.labelNamespace` Job as an initContainer | `true` |
-| postInstall.probeWebhook.image.repository | Image with curl to probe the webhook API | `curlimages/curl` |
-| postInstall.probeWebhook.image.tag | Image tag | `7.83.1` |
-| postInstall.probeWebhook.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
-| postInstall.probeWebhook.image.pullSecrets | Image pullSecrets | `[]` |
-| postInstall.probeWebhook.waitTimeout | Total time to wait for the webhook API to become available | `60` |
-| postInstall.probeWebhook.httpTimeout | HTTP client timeout | `2` |
-| postInstall.probeWebhook.insecureHTTPS | Ignore server SSL certificate | `false` |
-| postInstall.affinity | The affinity to use for pod scheduling in postInstall hook jobs | `{}` |
-| postInstall.tolerations | The tolerations to use for pod scheduling in postInstall hook jobs | `[]` |
-| postInstall.nodeSelector | The node selector to use for pod scheduling in postInstall hook jobs | `kubernetes.io/os: linux` |
-| postInstall.resources | The resource request/limits for the container image in postInstall hook jobs | `{}` |
-| postInstall.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| postUpgrade.labelNamespace.enabled | Add labels to the namespace during post upgrade hooks | `false` |
-| postUpgrade.labelNamespace.extraNamespaces | The extra namespaces that need to have the label during post upgrade hooks | `[]` |
-| postUpgrade.labelNamespace.extraAnnotations | Extra annotations added to the post upgrade Job | `{}` |
-| postUpgrade.labelNamespace.image.repository | Image with kubectl to label the namespace | `openpolicyagent/gatekeeper-crds` |
-| postUpgrade.labelNamespace.image.tag | Image tag | Current release version: `v3.12.0-beta.0` |
-| postUpgrade.labelNamespace.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
-| postUpgrade.labelNamespace.image.pullSecrets | Image pullSecrets | `[]`
-| postUpgrade.affinity | The affinity to use for pod scheduling in postUpgrade hook jobs | `{}` |
-| postUpgrade.tolerations | The tolerations to use for pod scheduling in postUpgrade hook jobs | `[]` |
-| postUpgrade.nodeSelector | The node selector to use for pod scheduling in postUpgrade hook jobs | `kubernetes.io/os: linux` |
-| postUpgrade.resources | The resource request/limits for the container image in postUpgrade hook jobs | `{}` |
-| postUpgrade.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| preUninstall.deleteWebhooks.enabled | Delete webhooks before gatekeeper itself is uninstalled | `false` |
-| preUninstall.deleteWebhooks.image.repository | Image with kubectl to delete the webhooks | `openpolicyagent/gatekeeper-crds` |
-| preUninstall.deleteWebhooks.image.tag | Image tag | Current release version: `v3.12.0-beta.0` |
-| preUninstall.deleteWebhooks.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
-| preUninstall.deleteWebhooks.image.pullSecrets | Image pullSecrets | `[]` |
-| preUninstall.deleteWebhooks.extraRules | Extra rules for the gatekeeper-delete-webhook-configs Role | `[]` |
-| preUninstall.affinity | The affinity to use for pod scheduling in preUninstall hook jobs | `{}` |
-| preUninstall.tolerations | The tolerations to use for pod scheduling in preUninstall hook jobs | `[]` |
-| preUninstall.nodeSelector | The node selector to use for pod scheduling in preUninstall hook jobs | `kubernetes.io/os: linux` |
-| preUninstall.resources | The resource request/limits for the container image in preUninstall hook jobs | `{}` |
-| preUninstall.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| psp.enabled | Enabled PodSecurityPolicy | `true` |
-| upgradeCRDs.enabled | Upgrade CRDs using pre-install/pre-upgrade hooks | `true` |
-| upgradeCRDs.extraRules | Extra rules for the gatekeeper-admin-upgrade-crds ClusterRole | `[]` |
-| crds.affinity | The affinity to use for pod scheduling in crds hook jobs | `{}` |
-| crds.tolerations | The tolerations to use for pod scheduling in crds hook jobs | `[]` |
-| crds.nodeSelector | The node selector to use for pod scheduling in crds hook jobs | `kubernetes.io/os: linux` |
-| crds.resources | The resource request/limits for the container image in crds hook jobs | `{}` |
-| crds.securityContext | Security context applied to the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 65532, "runAsNonRoot": true, "runAsUser": 65532 }` |
-| auditInterval | The frequency with which audit is run | `60` |
-| constraintViolationsLimit | The maximum # of audit violations reported on a constraint | `20` |
-| auditFromCache | Take the roster of resources to audit from the audit cache | `false` |
-| auditChunkSize | Chunk size for listing cluster resources for audit (alpha feature) | `500` |
-| auditMatchKindOnly | Only check resources of the kinds specified in all constraints defined in the cluster. | `false` |
-| disableValidatingWebhook | Disable the validating webhook | `false` |
-| disableMutation | Disable mutation | `false` |
-| validatingWebhookTimeoutSeconds | The timeout for the validating webhook in seconds | `3` |
-| validatingWebhookFailurePolicy | The failurePolicy for the validating webhook | `Ignore` |
-| validatingWebhookAnnotations | The annotations to add to the ValidatingWebhookConfiguration | `{}` |
-| validatingWebhookObjectSelector | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's validation webhook unless measures are taken to control how exemption labels can be set. | `{}` |
-| validatingWebhookCheckIgnoreFailurePolicy | The failurePolicy for the check-ignore-label validating webhook | `Fail` |
-| validatingWebhookExemptNamespacesLabels | Additional namespace labels that will be exempt from the validating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace. | `{}` |
-| validatingWebhookCustomRules | Custom rules for selecting which API resources trigger the webhook. Mutually exclusive with `enableDeleteOperations`. NOTE: If you change this, ensure all your constraints are still being enforced. | `{}` |
-| enableDeleteOperations | Enable validating webhook for delete operations. Does not work with `validatingWebhookCustomRules` | `false` |
-| enableExternalData | Enable external data | `true` |
-| enableGeneratorResourceExpansion | Enable generator resource expansion (alpha feature) | `false` |
-| enableTLSHealthcheck | Enable probing webhook API with certificate stored in certDir | `false` |
-| maxServingThreads | Limit the number of concurrent calls the validation backend made by the validation webhook. -1 limits this value to GOMAXPROCS. Configuring this value may lower max RAM usage and limit CPU throttling, Tuning it can optimize serving capacity. | `-1` |
-| metricsBackends | Metrics exporters to use. Valid exporters are: `prometheus`, `stackdriver`, and `opencensus` | `["prometheus"]` |
-| mutatingWebhookFailurePolicy | The failurePolicy for the mutating webhook | `Ignore` |
-| mutatingWebhookReinvocationPolicy | The reinvocationPolicy for the mutating webhook | `Never` |
-| mutatingWebhookAnnotations | The annotations to add to the MutatingWebhookConfiguration | `{}` |
-| mutatingWebhookExemptNamespacesLabels | Additional namespace labels that will be exempt from the mutating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace. | `{}` |
-| mutatingWebhookObjectSelector | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's mutation webhook unless measures are taken to control how exemption labels can be set. | `{}` |
-| mutatingWebhookTimeoutSeconds | The timeout for the mutating webhook in seconds | `3` |
-| mutatingWebhookCustomRules | Custom rules for selecting which API resources trigger the webhook. NOTE: If you change this, ensure all your constraints are still being enforced. | `{}` |
-| emitAdmissionEvents | Emit K8s events in gatekeeper namespace for admission violations (alpha feature) | `false` |
-| emitAuditEvents | Emit K8s events in gatekeeper namespace for audit violations (alpha feature) | `false` |
-| logDenies | Log detailed info on each deny | `false` |
-| logLevel | Minimum log level | `INFO` |
-| image.pullPolicy | The image pull policy | `IfNotPresent` |
-| image.repository | Image repository | `openpolicyagent/gatekeeper` |
-| image.release | The image release tag to use | Current release version: `v3.12.0-beta.0` |
-| image.pullSecrets | Specify an array of imagePullSecrets | `[]` |
-| resources | The resource request/limits for the container image | limits: 1 CPU, 512Mi, requests: 100mCPU, 256Mi |
-| nodeSelector | The node selector to use for pod scheduling | `kubernetes.io/os: linux` |
-| affinity | The node affinity to use for pod scheduling | `{}` |
-| topologySpreadConstraints | The topology spread constraints to use for pod scheduling | `[]` |
-| tolerations | The tolerations to use for pod scheduling | `[]` |
-| controllerManager.healthPort | Health port for controller manager | `9090` |
-| controllerManager.port | Webhook-server port for controller manager | `8443` |
-| controllerManager.metricsPort | Metrics port for controller manager | `8888` |
-| controllerManager.readinessTimeout | Timeout in seconds for the controller manager's readiness probe | `1` |
-| controllerManager.livenessTimeout | Timeout in seconds for the controller manager's liveness probe | `1` |
-| controllerManager.logLevel | The minimum log level for the controller manager, takes precedence over `logLevel` when specified | `null`
-| controllerManager.priorityClassName | Priority class name for controller manager | `system-cluster-critical` |
-| controllerManager.podSecurityContext | Security context on pod level for controller manager | {fsGroup: 999, suplementalGroups: [999]} |
-| controllerManager.exemptNamespaces | The exact namespaces to exempt by the admission webhook | `[]` |
-| controllerManager.exemptNamespacePrefixes | The namespace prefixes to exempt by the admission webhook | `[]` |
-| controllerManager.hostNetwork | Enables controllerManager to be deployed on hostNetwork | `false` |
-| controllerManager.dnsPolicy | Set the dnsPolicy for controllerManager pods | `ClusterFirst` |
-| controllerManager.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| controllerManager.tlsMinVersion | Set the minimum supported TLS version for validating and mutating webhook servers | `1.3` |
-| controllerManager.extraRules | Extra rules for the gatekeeper-manager-role Role | `[]` |
-| audit.priorityClassName | Priority class name for audit controller | `system-cluster-critical` |
-| audit.podSecurityContext | Security context for audit on pod level | {fsGroup: 999, suplementalGroups: [999]} |
-| audit.hostNetwork | Enables audit to be deployed on hostNetwork | `false` |
-| audit.dnsPolicy | Set the dnsPolicy for audit pods | `ClusterFirst` |
-| audit.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| audit.healthPort | Health port for audit | `9090` |
-| audit.metricsPort | Metrics port for audit | `8888` |
-| audit.readinessTimeout | Timeout in seconds for audit's readiness probe | `1` |
-| audit.livenessTimeout | Timeout in seconds for the audit's liveness probe | `1` |
-| audit.logLevel | The minimum log level for audit, takes precedence over `logLevel` when specified | `null`
-| replicas | The number of Gatekeeper replicas to deploy for the webhook | `3` |
-| podAnnotations | The annotations to add to the Gatekeeper pods | `container.seccomp.security.alpha.kubernetes.io/manager: runtime/default` |
-| podLabels | The labels to add to the Gatekeeper pods | `{}` |
-| podCountLimit | The maximum number of Gatekeeper pods to run | `100` |
-| secretAnnotations | The annotations to add to the Gatekeeper secrets | `{}` |
-| pdb.controllerManager.minAvailable | The number of controller manager pods that must still be available after an eviction | `1` |
-| service.type | Service type | `ClusterIP` |
-| service.loadBalancerIP | The IP address of LoadBalancer service | `` |
-| service.healthzPort | Service port to gatekeeper Webhook health port | `9090` |
-| rbac.create | Enable the creation of RBAC resources | `true` |
-| externalCertInjection.enabled | Enable the injection of an external certificate. This disables automatic certificate generation and rotation | `false` |
-| externalCertInjection.secretName | Name of secret for injected certificate | `gatekeeper-webhook-server-cert` |
+| Parameter | Description | Default |
+|:-----------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| postInstall.labelNamespace.enabled | Add labels to the namespace during post install hooks | `true` |
+| postInstall.labelNamespace.extraNamespaces | The extra namespaces that need to have the label during post install hooks | `[]` |
+| postInstall.labelNamespace.extraAnnotations | Extra annotations added to the post install Job | `{}` |
+| postInstall.labelNamespace.image.repository | Image with kubectl to label the namespace | `openpolicyagent/gatekeeper-crds` |
+| postInstall.labelNamespace.image.tag | Image tag | Current release version: `v3.14.0` |
+| postInstall.labelNamespace.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
+| postInstall.labelNamespace.image.pullSecrets | Image pullSecrets | `[]` |
+| postInstall.labelNamespace.extraRules | Extra rules for the gatekeeper-update-namespace-label Role | `[]` |
+| postInstall.labelNamespace.priorityClassName | Priority class name for gatekeeper-update-namespace-label Job | `` |
+| postInstall.probeWebhook.enabled | Probe webhook API post install. When enabled along with `postInstall.labelNamespace.enabled`, this probe will run as part of `postInstall.labelNamespace` Job as an initContainer | `true` |
+| postInstall.probeWebhook.image.repository | Image with curl to probe the webhook API | `curlimages/curl` |
+| postInstall.probeWebhook.image.tag | Image tag | `7.83.1` |
+| postInstall.probeWebhook.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
+| postInstall.probeWebhook.image.pullSecrets | Image pullSecrets | `[]` |
+| postInstall.probeWebhook.waitTimeout | Total time to wait for the webhook API to become available | `60` |
+| postInstall.probeWebhook.httpTimeout | HTTP client timeout | `2` |
+| postInstall.probeWebhook.insecureHTTPS | Ignore server SSL certificate | `false` |
+| postInstall.probeWebhook.priorityClassName | Priority class name for gatekeeper-probe-webhook-post-install Job | `` |
+| postInstall.affinity | The affinity to use for pod scheduling in postInstall hook jobs | `{}` |
+| postInstall.tolerations | The tolerations to use for pod scheduling in postInstall hook jobs | `[]` |
+| postInstall.nodeSelector | The node selector to use for pod scheduling in postInstall hook jobs | `kubernetes.io/os: linux` |
+| postInstall.resources | The resource request/limits for the container image in postInstall hook jobs | `{}` |
+| postInstall.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| postUpgrade.labelNamespace.enabled | Add labels to the namespace during post upgrade hooks | `false` |
+| postUpgrade.labelNamespace.extraNamespaces | The extra namespaces that need to have the label during post upgrade hooks | `[]` |
+| postUpgrade.labelNamespace.extraAnnotations | Extra annotations added to the post upgrade Job | `{}` |
+| postUpgrade.labelNamespace.image.repository | Image with kubectl to label the namespace | `openpolicyagent/gatekeeper-crds` |
+| postUpgrade.labelNamespace.image.tag | Image tag | Current release version: `v3.14.0` |
+| postUpgrade.labelNamespace.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
+| postUpgrade.labelNamespace.image.pullSecrets | Image pullSecrets | `[]` |
+| postUpgrade.labelNamespace.priorityClassName | Priority class name for gatekeeper-update-namespace-label-post-upgrade Job | `` |
+| postUpgrade.affinity | The affinity to use for pod scheduling in postUpgrade hook jobs | `{}` |
+| postUpgrade.tolerations | The tolerations to use for pod scheduling in postUpgrade hook jobs | `[]` |
+| postUpgrade.nodeSelector | The node selector to use for pod scheduling in postUpgrade hook jobs | `kubernetes.io/os: linux` |
+| postUpgrade.resources | The resource request/limits for the container image in postUpgrade hook jobs | `{}` |
+| postUpgrade.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| preInstall.crdRepository.image.repository | Image with kubectl to update the CRDs. If not set, the `image.crdRepository` is used instead. | `null` |
+| preInstall.crdRepository.image.tag | Image tag | Current release version: `v3.14.0` |
+| preUninstall.deleteWebhookConfigurations.enabled | Delete webhooks before gatekeeper itself is uninstalled | `false` |
+| preUninstall.deleteWebhookConfigurations.image.repository | Image with kubectl to delete the webhooks | `openpolicyagent/gatekeeper-crds` |
+| preUninstall.deleteWebhookConfigurations.image.tag | Image tag | Current release version: `v3.14.0` |
+| preUninstall.deleteWebhookConfigurations.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
+| preUninstall.deleteWebhookConfigurations.image.pullSecrets | Image pullSecrets | `[]` |
+| preUninstall.deleteWebhookConfigurations.extraRules | Extra rules for the gatekeeper-delete-webhook-configs Role | `[]` |
+| preUninstall.deleteWebhookConfigurations.priorityClassName | Priority class name for gatekeeper-delete-webhook-configs Job | `` |
+| preUninstall.affinity | The affinity to use for pod scheduling in preUninstall hook jobs | `{}` |
+| preUninstall.tolerations | The tolerations to use for pod scheduling in preUninstall hook jobs | `[]` |
+| preUninstall.nodeSelector | The node selector to use for pod scheduling in preUninstall hook jobs | `kubernetes.io/os: linux` |
+| preUninstall.resources | The resource request/limits for the container image in preUninstall hook jobs | `{}` |
+| preUninstall.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| psp.enabled | Enabled PodSecurityPolicy | `true` |
+| upgradeCRDs.enabled | Upgrade CRDs using pre-install/pre-upgrade hooks | `true` |
+| upgradeCRDs.extraRules | Extra rules for the gatekeeper-admin-upgrade-crds ClusterRole | `[]` |
+| upgradeCRDs.priorityClassName | Priority class name for gatekeeper-update-crds-hook Job | `` |
+| crds.affinity | The affinity to use for pod scheduling in crds hook jobs | `{}` |
+| crds.tolerations | The tolerations to use for pod scheduling in crds hook jobs | `[]` |
+| crds.nodeSelector | The node selector to use for pod scheduling in crds hook jobs | `kubernetes.io/os: linux` |
+| crds.resources | The resource request/limits for the container image in crds hook jobs | `{}` |
+| crds.securityContext | Security context applied to the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 65532, "runAsNonRoot": true, "runAsUser": 65532 }` |
+| auditInterval | The frequency with which audit is run | `60` |
+| constraintViolationsLimit | The maximum # of audit violations reported on a constraint | `20` |
+| auditFromCache | Take the roster of resources to audit from the audit cache | `false` |
+| auditChunkSize | Chunk size for listing cluster resources for audit (alpha feature) | `500` |
+| auditMatchKindOnly | Only check resources of the kinds specified in all constraints defined in the cluster. | `false` |
+| disableValidatingWebhook | Disable the validating webhook | `false` |
+| disableMutation | Disable mutation | `false` |
+| validatingWebhookName | The name of the `ValidatingWebhookConfiguration` | `gatekeeper-validating-webhook-configuration` |
+| validatingWebhookTimeoutSeconds | The timeout for the validating webhook in seconds | `3` |
+| validatingWebhookFailurePolicy | The failurePolicy for the validating webhook | `Ignore` |
+| validatingWebhookAnnotations | The annotations to add to the ValidatingWebhookConfiguration | `{}` |
+| validatingWebhookObjectSelector | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's validation webhook unless measures are taken to control how exemption labels can be set. | `{}` |
+| validatingWebhookCheckIgnoreFailurePolicy | The failurePolicy for the check-ignore-label validating webhook | `Fail` |
+| validatingWebhookExemptNamespacesLabels | Additional namespace labels that will be exempt from the validating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace. | `{}` |
+| validatingWebhookCustomRules | Custom rules for selecting which API resources trigger the webhook. Mutually exclusive with `enableDeleteOperations`. NOTE: If you change this, ensure all your constraints are still being enforced. | `{}` |
+| validatingWebhookURL | Custom URL for Kubernetes API server to use to reach the validating webhook pod. If not set, the default of connecting via the kubernetes service endpoint is used. | `null` |
+| enableDeleteOperations | Enable validating webhook for delete operations. Does not work with `validatingWebhookCustomRules` | `false` |
+| enableExternalData | Enable external data | `true` |
+| enableGeneratorResourceExpansion | Enable generator resource expansion (beta feature) | `true` |
+| enableTLSHealthcheck | Enable probing webhook API with certificate stored in certDir | `false` |
+| maxServingThreads | Limit the number of concurrent calls the validation backend made by the validation webhook. -1 limits this value to GOMAXPROCS. Configuring this value may lower max RAM usage and limit CPU throttling, Tuning it can optimize serving capacity. | `-1` |
+| metricsBackends | Metrics exporters to use. Valid exporters are: `prometheus`, `stackdriver`, and `opencensus` | `["prometheus"]` |
+| mutatingWebhookName | The name of the `MutatingWebhookConfiguration` | `gatekeeper-mutating-webhook-configuration` |
+| mutatingWebhookFailurePolicy | The failurePolicy for the mutating webhook | `Ignore` |
+| mutatingWebhookReinvocationPolicy | The reinvocationPolicy for the mutating webhook | `Never` |
+| mutatingWebhookAnnotations | The annotations to add to the MutatingWebhookConfiguration | `{}` |
+| mutatingWebhookExemptNamespacesLabels | Additional namespace labels that will be exempt from the mutating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace. | `{}` |
+| mutatingWebhookObjectSelector | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's mutation webhook unless measures are taken to control how exemption labels can be set. | `{}` |
+| mutatingWebhookTimeoutSeconds | The timeout for the mutating webhook in seconds | `3` |
+| mutatingWebhookCustomRules | Custom rules for selecting which API resources trigger the webhook. NOTE: If you change this, ensure all your constraints are still being enforced. | `{}` |
+| mutatingWebhookURL | Custom URL for Kubernetes API server to use to reach the mutating webhook pod. If not set, the default of connecting via the kubernetes service endpoint is used. | `null` |
+| emitAdmissionEvents | Emit K8s events in configurable namespace for admission violations (alpha feature) | `false` |
+| emitAuditEvents | Emit K8s events in configurable namespace for audit violations (alpha feature) | `false` |
+| auditEventsInvolvedNamespace | Emit audit events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Audit events from cluster-scoped resources will continue to generate events in the namespace that Gatekeeper is installed in | `false` |
+| admissionEventsInvolvedNamespace | Emit admission events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Admission events from cluster-scoped resources will continue to generate events in the namespace that Gatekeeper is installed in | `false` |
+| logDenies | Log detailed info on each deny | `false` |
+| logLevel | Minimum log level | `INFO` |
+| image.pullPolicy | The image pull policy | `IfNotPresent` |
+| image.repository | Image repository | `openpolicyagent/gatekeeper` |
+| image.release | The image release tag to use | Current release version: `v3.14.0` |
+| image.pullSecrets | Specify an array of imagePullSecrets | `[]` |
+| resources | The resource request/limits for the container image | limits: 1 CPU, 512Mi, requests: 100mCPU, 256Mi |
+| nodeSelector | The node selector to use for pod scheduling | `kubernetes.io/os: linux` |
+| controllerManager.affinity | The node affinity to use for controller manager pod scheduling | `{}` |
+| controllerManager.topologySpreadConstraints | The topology spread constraints to use for controller manager pod scheduling | `[]` |
+| controllerManager.tolerations | The tolerations to use for controller manager pod scheduling | `[]` |
+| controllerManager.healthPort | Health port for controller manager | `9090` |
+| controllerManager.port | Webhook-server port for controller manager | `8443` |
+| controllerManager.metricsPort | Metrics port for controller manager | `8888` |
+| controllerManager.readinessTimeout | Timeout in seconds for the controller manager's readiness probe | `1` |
+| controllerManager.livenessTimeout | Timeout in seconds for the controller manager's liveness probe | `1` |
+| controllerManager.logLevel | The minimum log level for the controller manager, takes precedence over `logLevel` when specified | `null` |
+| controllerManager.priorityClassName | Priority class name for controller manager | `system-cluster-critical` |
+| controllerManager.podSecurityContext | Security context on pod level for controller manager | {fsGroup: 999, suplementalGroups: [999]} |
+| controllerManager.exemptNamespaces | The exact namespaces to exempt by the admission webhook | `[]` |
+| controllerManager.exemptNamespacePrefixes | The namespace prefixes to exempt by the admission webhook | `[]` |
+| controllerManager.hostNetwork | Enables controllerManager to be deployed on hostNetwork | `false` |
+| controllerManager.dnsPolicy | Set the dnsPolicy for controllerManager pods | `ClusterFirst` |
+| controllerManager.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| controllerManager.tlsMinVersion | Set the minimum supported TLS version for validating and mutating webhook servers | `1.3` |
+| controllerManager.extraRules | Extra rules for the gatekeeper-manager-role Role | `[]` |
+| controllerManager.networkPolicy.enabled | Should a network policy for the controller manager be created | `false` |
+| controllerManager.networkPolicy.ingress | Additional ingress rules to be added to the controller manager network policy | `{}` |
+| controllerManager.strategyType | The strategy type to use for Controller Manager deployment | `RollingUpdate` |
+| audit.affinity | The node affinity to use for audit pod scheduling | `{}` |
+| audit.topologySpreadConstraints | The topology spread constraints to use for audit pod scheduling | `[]` |
+| audit.tolerations | The tolerations to use for audit pod scheduling | `[]` |
+| audit.priorityClassName | Priority class name for audit controller | `system-cluster-critical` |
+| audit.podSecurityContext | Security context for audit on pod level | {fsGroup: 999, suplementalGroups: [999]} |
+| audit.hostNetwork | Enables audit to be deployed on hostNetwork | `false` |
+| audit.dnsPolicy | Set the dnsPolicy for audit pods | `ClusterFirst` |
+| audit.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| audit.healthPort | Health port for audit | `9090` |
+| audit.metricsPort | Metrics port for audit | `8888` |
+| audit.readinessTimeout | Timeout in seconds for audit's readiness probe | `1` |
+| audit.livenessTimeout | Timeout in seconds for the audit's liveness probe | `1` |
+| audit.logLevel | The minimum log level for audit, takes precedence over `logLevel` when specified | `null` |
+| replicas | The number of Gatekeeper replicas to deploy for the webhook | `3` |
+| podAnnotations | The annotations to add to the Gatekeeper pods | `container.seccomp.security.alpha.kubernetes.io/manager: runtime/default` |
+| podLabels | The labels to add to the Gatekeeper pods | `{}` |
+| podCountLimit | The maximum number of Gatekeeper pods to run | `100` |
+| secretAnnotations | The annotations to add to the Gatekeeper secrets | `{}` |
+| pdb.controllerManager.minAvailable | The number of controller manager pods that must still be available after an eviction | `1` |
+| service.type | Service type | `ClusterIP` |
+| service.loadBalancerIP | The IP address of LoadBalancer service | `` |
+| service.healthzPort | Service port to gatekeeper Webhook health port | `9090` |
+| rbac.create | Enable the creation of RBAC resources | `true` |
+| externalCertInjection.enabled | Enable the injection of an external certificate. This disables automatic certificate generation and rotation | `false` |
+| externalCertInjection.secretName | Name of secret for injected certificate | `gatekeeper-webhook-server-cert` |
+| externaldataProviderResponseCacheTTL | TTL for the external data provider response cache. Specify the duration in 'h', 'm', or 's' for hours, minutes, or seconds respectively. | `3m` |
## Contributing Changes
-Please refer to [Contributing to Helm Chart](https://open-policy-agent.github.io/gatekeeper/website/docs/help#contributing-to-helm-chart) for modifying the Helm chart.
+Please refer
+to [Contributing to Helm Chart](https://open-policy-agent.github.io/gatekeeper/website/docs/help#contributing-to-helm-chart)
+for modifying the Helm chart.
diff --git a/charts/gatekeeper/crds/assign-customresourcedefinition.yaml b/charts/gatekeeper/crds/assign-customresourcedefinition.yaml
index ce98648baff..0221a194812 100644
--- a/charts/gatekeeper/crds/assign-customresourcedefinition.yaml
+++ b/charts/gatekeeper/crds/assign-customresourcedefinition.yaml
@@ -65,7 +65,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -115,7 +115,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -151,7 +151,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -310,7 +310,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -360,7 +360,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -396,7 +396,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -555,7 +555,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -605,7 +605,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -641,7 +641,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
diff --git a/charts/gatekeeper/crds/assignimage-customresourcedefinition.yaml b/charts/gatekeeper/crds/assignimage-customresourcedefinition.yaml
new file mode 100644
index 00000000000..197f2f17933
--- /dev/null
+++ b/charts/gatekeeper/crds/assignimage-customresourcedefinition.yaml
@@ -0,0 +1,237 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ labels:
+ gatekeeper.sh/system: "yes"
+ name: assignimage.mutations.gatekeeper.sh
+spec:
+ group: mutations.gatekeeper.sh
+ names:
+ kind: AssignImage
+ listKind: AssignImageList
+ plural: assignimage
+ singular: assignimage
+ preserveUnknownFields: false
+ scope: Cluster
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: AssignImage is the Schema for the assignimage 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:
+ properties:
+ name:
+ maxLength: 63
+ type: string
+ type: object
+ spec:
+ description: AssignImageSpec defines the desired state of AssignImage.
+ properties:
+ applyTo:
+ description: ApplyTo lists the specific groups, versions and kinds a mutation will be applied to. This is necessary because every mutation implies part of an object schema and object schemas are associated with specific GVKs.
+ items:
+ description: ApplyTo determines what GVKs items the mutation should apply to. Globs are not allowed.
+ properties:
+ groups:
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ versions:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ location:
+ description: 'Location describes the path to be mutated, for example: `spec.containers[name: main].image`.'
+ type: string
+ match:
+ description: Match allows the user to limit which resources get mutated. Individual match criteria are AND-ed together. An undefined match criteria matches everything.
+ properties:
+ excludedNamespaces:
+ description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
+ items:
+ description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ kinds:
+ items:
+ description: Kinds accepts a list of objects with apiGroups and kinds fields that list the groups/kinds of objects to which the mutation will apply. If multiple groups/kinds objects are specified, only one match is needed for the resource to be in scope.
+ properties:
+ apiGroups:
+ description: APIGroups is the API groups the resources belong to. '*' is all groups. If '*' is present, the length of the slice must be one. Required.
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ labelSelector:
+ description: 'LabelSelector is the combination of two optional fields: `matchLabels` and `matchExpressions`. These two fields provide different methods of selecting or excluding k8s objects based on the label keys and values included in object metadata. All selection expressions from both sections are ANDed to determine if an object meets the cumulative requirements of the selector.'
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ name:
+ description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ namespaceSelector:
+ description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ namespaces:
+ description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
+ items:
+ description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ scope:
+ description: Scope determines if cluster-scoped and/or namespaced-scoped resources are matched. Accepts `*`, `Cluster`, or `Namespaced`. (defaults to `*`)
+ type: string
+ source:
+ description: Source determines whether generated or original resources are matched. Accepts `Generated`|`Original`|`All` (defaults to `All`). A value of `Generated` will only match generated resources, while `Original` will only match regular resources.
+ enum:
+ - All
+ - Generated
+ - Original
+ type: string
+ type: object
+ parameters:
+ description: Parameters define the behavior of the mutator.
+ properties:
+ assignDomain:
+ description: AssignDomain sets the domain component on an image string. The trailing slash should not be included.
+ type: string
+ assignPath:
+ description: AssignPath sets the domain component on an image string.
+ type: string
+ assignTag:
+ description: AssignImage sets the image component on an image string. It must start with a `:` or `@`.
+ type: string
+ pathTests:
+ items:
+ description: "PathTest allows the user to customize how the mutation works if parent paths are missing. It traverses the list in order. All sub paths are tested against the provided condition, if the test fails, the mutation is not applied. All `subPath` entries must be a prefix of `location`. Any glob characters will take on the same value as was used to expand the matching glob in `location`. \n Available Tests: * MustExist - the path must exist or do not mutate * MustNotExist - the path must not exist or do not mutate."
+ properties:
+ condition:
+ description: Condition describes whether the path either MustExist or MustNotExist in the original object
+ enum:
+ - MustExist
+ - MustNotExist
+ type: string
+ subPath:
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ status:
+ description: AssignImageStatus defines the observed state of AssignImage.
+ properties:
+ byPod:
+ items:
+ description: MutatorPodStatusStatus defines the observed state of MutatorPodStatus.
+ properties:
+ enforced:
+ type: boolean
+ errors:
+ items:
+ description: MutatorError represents a single error caught while adding a mutator to a system.
+ properties:
+ message:
+ type: string
+ type:
+ description: Type indicates a specific class of error for use by controller code. If not present, the error should be treated as not matching any known type.
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ type: string
+ mutatorUID:
+ description: Storing the mutator UID allows us to detect drift, such as when a mutator has been recreated after its CRD was deleted out from under it, interrupting the watch
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/charts/gatekeeper/crds/assignmetadata-customresourcedefinition.yaml b/charts/gatekeeper/crds/assignmetadata-customresourcedefinition.yaml
index 3a63eef3cb3..65c17ed3ae1 100644
--- a/charts/gatekeeper/crds/assignmetadata-customresourcedefinition.yaml
+++ b/charts/gatekeeper/crds/assignmetadata-customresourcedefinition.yaml
@@ -39,13 +39,13 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -95,7 +95,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -131,7 +131,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -250,13 +250,13 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -306,7 +306,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -342,7 +342,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -461,13 +461,13 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -517,7 +517,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -553,7 +553,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
diff --git a/charts/gatekeeper/crds/config-customresourcedefinition.yaml b/charts/gatekeeper/crds/config-customresourcedefinition.yaml
index 57826ac09aa..269ca95f9a2 100644
--- a/charts/gatekeeper/crds/config-customresourcedefinition.yaml
+++ b/charts/gatekeeper/crds/config-customresourcedefinition.yaml
@@ -39,7 +39,7 @@ spec:
excludedNamespaces:
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
processes:
diff --git a/charts/gatekeeper/crds/constrainttemplate-customresourcedefinition.yaml b/charts/gatekeeper/crds/constrainttemplate-customresourcedefinition.yaml
index a4da4e9e90f..737e3aff15b 100644
--- a/charts/gatekeeper/crds/constrainttemplate-customresourcedefinition.yaml
+++ b/charts/gatekeeper/crds/constrainttemplate-customresourcedefinition.yaml
@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.10.0
+ controller-gen.kubebuilder.io/version: v0.11.3
labels:
gatekeeper.sh/system: "yes"
name: constrainttemplates.templates.gatekeeper.sh
@@ -61,6 +61,24 @@ spec:
targets:
items:
properties:
+ code:
+ description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
+ items:
+ properties:
+ engine:
+ description: 'The engine used to evaluate the code. Example: "Rego". Required.'
+ type: string
+ source:
+ description: The source code for the template. Required.
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - engine
+ - source
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - engine
+ x-kubernetes-list-type: map
libs:
items:
type: string
@@ -156,6 +174,24 @@ spec:
targets:
items:
properties:
+ code:
+ description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
+ items:
+ properties:
+ engine:
+ description: 'The engine used to evaluate the code. Example: "Rego". Required.'
+ type: string
+ source:
+ description: The source code for the template. Required.
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - engine
+ - source
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - engine
+ x-kubernetes-list-type: map
libs:
items:
type: string
@@ -251,6 +287,24 @@ spec:
targets:
items:
properties:
+ code:
+ description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
+ items:
+ properties:
+ engine:
+ description: 'The engine used to evaluate the code. Example: "Rego". Required.'
+ type: string
+ source:
+ description: The source code for the template. Required.
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - engine
+ - source
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - engine
+ x-kubernetes-list-type: map
libs:
items:
type: string
diff --git a/charts/gatekeeper/crds/expansiontemplate-customresourcedefinition.yaml b/charts/gatekeeper/crds/expansiontemplate-customresourcedefinition.yaml
index 042249cf102..9d248f2ccd2 100644
--- a/charts/gatekeeper/crds/expansiontemplate-customresourcedefinition.yaml
+++ b/charts/gatekeeper/crds/expansiontemplate-customresourcedefinition.yaml
@@ -68,6 +68,133 @@ spec:
description: TemplateSource specifies the source field on the generator resource to use as the base for expanded resource. For Pod-creating generators, this is usually spec.template
type: string
type: object
+ status:
+ description: ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+ properties:
+ byPod:
+ items:
+ description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
+ type: string
+ type: object
+ type: array
+ type: object
type: object
served: true
storage: true
+ subresources:
+ status: {}
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ description: ExpansionTemplate is the Schema for the ExpansionTemplate 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: ExpansionTemplateSpec defines the desired state of ExpansionTemplate.
+ properties:
+ applyTo:
+ description: ApplyTo lists the specific groups, versions and kinds of generator resources which will be expanded.
+ items:
+ description: ApplyTo determines what GVKs items the mutation should apply to. Globs are not allowed.
+ properties:
+ groups:
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ versions:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ enforcementAction:
+ description: EnforcementAction specifies the enforcement action to be used for resources matching the ExpansionTemplate. Specifying an empty value will use the enforcement action specified by the Constraint in violation.
+ type: string
+ generatedGVK:
+ description: GeneratedGVK specifies the GVK of the resources which the generator resource creates.
+ properties:
+ group:
+ type: string
+ kind:
+ type: string
+ version:
+ type: string
+ type: object
+ templateSource:
+ description: TemplateSource specifies the source field on the generator resource to use as the base for expanded resource. For Pod-creating generators, this is usually spec.template
+ type: string
+ type: object
+ status:
+ description: ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+ properties:
+ byPod:
+ items:
+ description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
diff --git a/charts/gatekeeper/crds/expansiontemplatepodstatus-customresourcedefinition.yaml b/charts/gatekeeper/crds/expansiontemplatepodstatus-customresourcedefinition.yaml
new file mode 100644
index 00000000000..8f49b4c5f7f
--- /dev/null
+++ b/charts/gatekeeper/crds/expansiontemplatepodstatus-customresourcedefinition.yaml
@@ -0,0 +1,62 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ labels:
+ gatekeeper.sh/system: "yes"
+ name: expansiontemplatepodstatuses.status.gatekeeper.sh
+spec:
+ group: status.gatekeeper.sh
+ names:
+ kind: ExpansionTemplatePodStatus
+ listKind: ExpansionTemplatePodStatusList
+ plural: expansiontemplatepodstatuses
+ singular: expansiontemplatepodstatus
+ preserveUnknownFields: false
+ scope: Namespaced
+ versions:
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ description: ExpansionTemplatePodStatus is the Schema for the expansiontemplatepodstatuses 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
+ status:
+ description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
+ type: string
+ type: object
+ type: object
+ served: true
+ storage: true
diff --git a/charts/gatekeeper/crds/modifyset-customresourcedefinition.yaml b/charts/gatekeeper/crds/modifyset-customresourcedefinition.yaml
index 1bb1933366d..46574fd369f 100644
--- a/charts/gatekeeper/crds/modifyset-customresourcedefinition.yaml
+++ b/charts/gatekeeper/crds/modifyset-customresourcedefinition.yaml
@@ -65,7 +65,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -115,7 +115,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -151,7 +151,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -283,7 +283,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -333,7 +333,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -369,7 +369,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -501,7 +501,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -551,7 +551,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -587,7 +587,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
diff --git a/charts/gatekeeper/crds/provider-customresourcedefinition.yaml b/charts/gatekeeper/crds/provider-customresourcedefinition.yaml
index 0deb6f630b1..95e66a8b8aa 100644
--- a/charts/gatekeeper/crds/provider-customresourcedefinition.yaml
+++ b/charts/gatekeeper/crds/provider-customresourcedefinition.yaml
@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.10.0
+ controller-gen.kubebuilder.io/version: v0.11.3
labels:
gatekeeper.sh/system: "yes"
name: providers.externaldata.gatekeeper.sh
@@ -41,12 +41,12 @@ spec:
description: Timeout is the timeout when querying the provider.
type: integer
url:
- description: URL is the url for the provider. URL is prefixed with http:// or https://.
+ description: URL is the url for the provider. URL is prefixed with https://.
type: string
type: object
type: object
served: true
- storage: true
+ storage: false
- name: v1beta1
schema:
openAPIV3Schema:
@@ -70,9 +70,9 @@ spec:
description: Timeout is the timeout when querying the provider.
type: integer
url:
- description: URL is the url for the provider. URL is prefixed with http:// or https://.
+ description: URL is the url for the provider. URL is prefixed with https://.
type: string
type: object
type: object
served: true
- storage: false
+ storage: true
diff --git a/charts/gatekeeper/templates/_helpers.tpl b/charts/gatekeeper/templates/_helpers.tpl
index 5ab6fe2b456..785d9912656 100644
--- a/charts/gatekeeper/templates/_helpers.tpl
+++ b/charts/gatekeeper/templates/_helpers.tpl
@@ -36,10 +36,44 @@ Adds additional pod labels to the common ones
*/}}
{{- define "gatekeeper.podLabels" -}}
{{- if .Values.podLabels }}
-{{- toYaml .Values.podLabels | nindent 8 }}
+{{- toYaml .Values.podLabels }}
{{- end }}
{{- end -}}
+{{/*
+Mandatory labels
+*/}}
+{{- define "gatekeeper.mandatoryLabels" -}}
+app: {{ include "gatekeeper.name" . }}
+chart: {{ include "gatekeeper.name" . }}
+gatekeeper.sh/system: "yes"
+heritage: {{ .Release.Service }}
+release: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "gatekeeper.commonLabels" -}}
+helm.sh/chart: {{ include "gatekeeper.chart" . }}
+{{ include "gatekeeper.selectorLabels" . }}
+{{- if .Chart.Version }}
+app.kubernetes.io/version: {{ .Chart.Version | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- if .Values.commonLabels }}
+{{ toYaml .Values.commonLabels }}
+{{- end }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "gatekeeper.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "gatekeeper.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
{{/*
Output post install webhook probe container entry
*/}}
@@ -47,10 +81,12 @@ Output post install webhook probe container entry
- name: webhook-probe-post
image: "{{ .Values.postInstall.probeWebhook.image.repository }}:{{ .Values.postInstall.probeWebhook.image.tag }}"
imagePullPolicy: {{ .Values.postInstall.probeWebhook.image.pullPolicy }}
- args:
+ command:
- "curl"
+ args:
- "--retry"
- "99999"
+ - "--retry-connrefused"
- "--retry-max-time"
- "{{ .Values.postInstall.probeWebhook.waitTimeout }}"
- "--retry-delay"
diff --git a/charts/gatekeeper/templates/gatekeeper-admin-podsecuritypolicy.yaml b/charts/gatekeeper/templates/gatekeeper-admin-podsecuritypolicy.yaml
index 398b1460077..8c02264b024 100644
--- a/charts/gatekeeper/templates/gatekeeper-admin-podsecuritypolicy.yaml
+++ b/charts/gatekeeper/templates/gatekeeper-admin-podsecuritypolicy.yaml
@@ -5,11 +5,8 @@ metadata:
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
name: gatekeeper-admin
spec:
allowPrivilegeEscalation: false
diff --git a/charts/gatekeeper/templates/gatekeeper-audit-deployment.yaml b/charts/gatekeeper/templates/gatekeeper-audit-deployment.yaml
index 3409d2f588e..1dc1ebac29c 100644
--- a/charts/gatekeeper/templates/gatekeeper-audit-deployment.yaml
+++ b/charts/gatekeeper/templates/gatekeeper-audit-deployment.yaml
@@ -13,6 +13,7 @@ metadata:
namespace: '{{ .Release.Namespace }}'
spec:
replicas: 1
+ revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
selector:
matchLabels:
app: '{{ template "gatekeeper.name" . }}'
@@ -28,6 +29,9 @@ spec:
{{- if .Values.podAnnotations }}
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
{{- end }}
+ {{- if .Values.auditPodAnnotations }}
+ {{- toYaml .Values.auditPodAnnotations | trim | nindent 8 }}
+ {{- end }}
labels:
{{- include "gatekeeper.podLabels" . }}
app: '{{ template "gatekeeper.name" . }}'
@@ -51,12 +55,20 @@ spec:
- --audit-interval={{ .Values.auditInterval }}
- --log-level={{ (.Values.audit.logLevel | empty | not) | ternary .Values.audit.logLevel .Values.logLevel }}
- --constraint-violations-limit={{ .Values.constraintViolationsLimit }}
+ - --validating-webhook-configuration-name={{ .Values.validatingWebhookName }}
+ - --mutating-webhook-configuration-name={{ .Values.mutatingWebhookName }}
- --audit-from-cache={{ .Values.auditFromCache }}
- --audit-chunk-size={{ .Values.auditChunkSize }}
- --audit-match-kind-only={{ .Values.auditMatchKindOnly }}
- --emit-audit-events={{ .Values.emitAuditEvents }}
+ - --audit-events-involved-namespace={{ .Values.auditEventsInvolvedNamespace }}
- --operation=audit
- --operation=status
+ {{ if .Values.audit.enablePubsub}}
+ - --enable-pub-sub={{ .Values.audit.enablePubsub }}
+ - --audit-connection={{ .Values.audit.connection }}
+ - --audit-channel={{ .Values.audit.channel }}
+ {{- end }}
{{ if not .Values.disableMutation}}- --operation=mutation-status{{- end }}
- --logtostderr
- --health-addr=:{{ .Values.audit.healthPort }}
@@ -67,7 +79,12 @@ spec:
{{- range .Values.metricsBackends}}
- --metrics-backend={{ . }}
{{- end }}
+
+ {{- if .Values.audit.logFile}}
+ - --log-file={{ .Values.audit.logFile }}
+ {{- end }}
- --disable-cert-rotation={{ or .Values.audit.disableCertRotation .Values.externalCertInjection.enabled }}
+ - --external-data-provider-response-cache-ttl={{ .Values.externaldataProviderResponseCacheTTL }}
command:
- /manager
env:
diff --git a/charts/gatekeeper/templates/gatekeeper-controller-manager-deployment.yaml b/charts/gatekeeper/templates/gatekeeper-controller-manager-deployment.yaml
index ebb1d2559e9..70c7571c2ce 100644
--- a/charts/gatekeeper/templates/gatekeeper-controller-manager-deployment.yaml
+++ b/charts/gatekeeper/templates/gatekeeper-controller-manager-deployment.yaml
@@ -13,6 +13,7 @@ metadata:
namespace: '{{ .Release.Namespace }}'
spec:
replicas: {{ .Values.replicas }}
+ revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
selector:
matchLabels:
app: '{{ template "gatekeeper.name" . }}'
@@ -22,6 +23,8 @@ spec:
gatekeeper.sh/system: "yes"
heritage: '{{ .Release.Service }}'
release: '{{ .Release.Name }}'
+ strategy:
+ type: {{ .Values.controllerManager.strategyType }}
template:
metadata:
annotations:
@@ -54,6 +57,7 @@ spec:
- --logtostderr
- --log-denies={{ .Values.logDenies }}
- --emit-admission-events={{ .Values.emitAdmissionEvents }}
+ - --admission-events-involved-namespace={{ .Values.admissionEventsInvolvedNamespace }}
- --log-level={{ (.Values.controllerManager.logLevel | empty | not) | ternary .Values.controllerManager.logLevel .Values.logLevel }}
- --exempt-namespace={{ .Release.Namespace }}
- --operation=webhook
@@ -64,6 +68,9 @@ spec:
- --disable-cert-rotation={{ .Values.controllerManager.disableCertRotation }}
- --max-serving-threads={{ .Values.maxServingThreads }}
- --tls-min-version={{ .Values.controllerManager.tlsMinVersion }}
+ - --validating-webhook-configuration-name={{ .Values.validatingWebhookName }}
+ - --mutating-webhook-configuration-name={{ .Values.mutatingWebhookName }}
+ - --external-data-provider-response-cache-ttl={{ .Values.externaldataProviderResponseCacheTTL }}
{{ if ne .Values.controllerManager.clientCertName "" }}- --client-cert-name={{ .Values.controllerManager.clientCertName }}{{- end }}
{{- range .Values.metricsBackends}}
@@ -83,6 +90,14 @@ spec:
{{- range .Values.controllerManager.exemptNamespacePrefixes}}
- --exempt-namespace-prefix={{ . }}
{{- end }}
+
+ {{- range .Values.controllerManager.exemptNamespaceSuffixes}}
+ - --exempt-namespace-suffix={{ . }}
+ {{- end }}
+
+ {{- if .Values.controllerManager.logFile}}
+ - --log-file={{ .Values.controllerManager.logFile }}
+ {{- end }}
command:
- /manager
env:
diff --git a/charts/gatekeeper/templates/gatekeeper-controller-manager-network-policy.yaml b/charts/gatekeeper/templates/gatekeeper-controller-manager-network-policy.yaml
new file mode 100644
index 00000000000..5ac3ca6c2c6
--- /dev/null
+++ b/charts/gatekeeper/templates/gatekeeper-controller-manager-network-policy.yaml
@@ -0,0 +1,26 @@
+{{- if .Values.controllerManager.networkPolicy.enabled -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+ labels:
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
+ name: gatekeeper-controller-manager
+spec:
+ ingress:
+ - from:
+ - podSelector:
+ matchLabels:
+ {{- include "gatekeeper.commonLabels" . | nindent 14 }}
+ app: '{{ template "gatekeeper.name" . }}'
+ release: '{{ .Release.Name }}'
+ {{- with .Values.controllerManager.networkPolicy.ingress }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ podSelector:
+ matchLabels:
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 6 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 6 }}
+ control-plane: controller-manager
+ gatekeeper.sh/operation: webhook
+{{- end -}}
diff --git a/charts/gatekeeper/templates/gatekeeper-manager-role-clusterrole.yaml b/charts/gatekeeper/templates/gatekeeper-manager-role-clusterrole.yaml
index 8b32f96014b..3e55923360c 100644
--- a/charts/gatekeeper/templates/gatekeeper-manager-role-clusterrole.yaml
+++ b/charts/gatekeeper/templates/gatekeeper-manager-role-clusterrole.yaml
@@ -11,6 +11,13 @@ metadata:
release: '{{ .Release.Name }}'
name: gatekeeper-manager-role
rules:
+- apiGroups:
+ - ""
+ resources:
+ - events
+ verbs:
+ - create
+ - patch
- apiGroups:
- '*'
resources:
@@ -22,7 +29,7 @@ rules:
- apiGroups:
- admissionregistration.k8s.io
resourceNames:
- - gatekeeper-mutating-webhook-configuration
+ - {{ .Values.mutatingWebhookName }}
resources:
- mutatingwebhookconfigurations
verbs:
@@ -75,6 +82,18 @@ rules:
- patch
- update
- watch
+- apiGroups:
+ - expansion.gatekeeper.sh
+ resources:
+ - '*'
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
- apiGroups:
- externaldata.gatekeeper.sh
resources:
@@ -153,7 +172,7 @@ rules:
- apiGroups:
- admissionregistration.k8s.io
resourceNames:
- - gatekeeper-validating-webhook-configuration
+ - {{ .Values.validatingWebhookName }}
resources:
- validatingwebhookconfigurations
verbs:
diff --git a/charts/gatekeeper/templates/gatekeeper-mutating-webhook-configuration-mutatingwebhookconfiguration.yaml b/charts/gatekeeper/templates/gatekeeper-mutating-webhook-configuration-mutatingwebhookconfiguration.yaml
index 30a23b4fb9d..ae85f8d08d3 100644
--- a/charts/gatekeeper/templates/gatekeeper-mutating-webhook-configuration-mutatingwebhookconfiguration.yaml
+++ b/charts/gatekeeper/templates/gatekeeper-mutating-webhook-configuration-mutatingwebhookconfiguration.yaml
@@ -9,16 +9,20 @@ metadata:
gatekeeper.sh/system: "yes"
heritage: '{{ .Release.Service }}'
release: '{{ .Release.Name }}'
- name: gatekeeper-mutating-webhook-configuration
+ name: '{{ .Values.mutatingWebhookName }}'
webhooks:
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
+ {{- if .Values.mutatingWebhookURL }}
+ url: https://{{ .Values.mutatingWebhookURL }}/v1/mutate
+ {{- else }}
service:
name: gatekeeper-webhook-service
namespace: '{{ .Release.Namespace }}'
path: /v1/mutate
+ {{- end }}
failurePolicy: {{ .Values.mutatingWebhookFailurePolicy }}
matchPolicy: Exact
name: mutation.gatekeeper.sh
diff --git a/charts/gatekeeper/templates/gatekeeper-validating-webhook-configuration-validatingwebhookconfiguration.yaml b/charts/gatekeeper/templates/gatekeeper-validating-webhook-configuration-validatingwebhookconfiguration.yaml
index a51dcef6bd6..933fbbd3c3e 100644
--- a/charts/gatekeeper/templates/gatekeeper-validating-webhook-configuration-validatingwebhookconfiguration.yaml
+++ b/charts/gatekeeper/templates/gatekeeper-validating-webhook-configuration-validatingwebhookconfiguration.yaml
@@ -9,16 +9,20 @@ metadata:
gatekeeper.sh/system: "yes"
heritage: '{{ .Release.Service }}'
release: '{{ .Release.Name }}'
- name: gatekeeper-validating-webhook-configuration
+ name: '{{ .Values.validatingWebhookName }}'
webhooks:
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
+ {{- if .Values.validatingWebhookURL }}
+ url: https://{{ .Values.validatingWebhookURL }}/v1/admit
+ {{- else }}
service:
name: gatekeeper-webhook-service
namespace: '{{ .Release.Namespace }}'
path: /v1/admit
+ {{- end }}
failurePolicy: {{ .Values.validatingWebhookFailurePolicy }}
matchPolicy: Exact
name: validation.gatekeeper.sh
diff --git a/charts/gatekeeper/templates/namespace-post-install.yaml b/charts/gatekeeper/templates/namespace-post-install.yaml
index 4f84b52b409..41232de4267 100644
--- a/charts/gatekeeper/templates/namespace-post-install.yaml
+++ b/charts/gatekeeper/templates/namespace-post-install.yaml
@@ -3,12 +3,10 @@ apiVersion: batch/v1
kind: Job
metadata:
name: gatekeeper-update-namespace-label
+ namespace: {{ .Release.Namespace | quote }}
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install
"helm.sh/hook-weight": "-5"
@@ -22,14 +20,14 @@ spec:
annotations:
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
restartPolicy: OnFailure
+ {{- if .Values.postInstall.labelNamespace.priorityClassName }}
+ priorityClassName: {{ .Values.postInstall.labelNamespace.priorityClassName }}
+ {{- end }}
{{- if .Values.postInstall.labelNamespace.image.pullSecrets }}
imagePullSecrets:
{{- .Values.postInstall.labelNamespace.image.pullSecrets | toYaml | nindent 12 }}
@@ -96,7 +94,9 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: gatekeeper-update-namespace-label
+ namespace: {{ .Release.Namespace | quote }}
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -110,6 +110,7 @@ kind: ClusterRole
metadata:
name: gatekeeper-update-namespace-label
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -141,6 +142,7 @@ kind: ClusterRoleBinding
metadata:
name: gatekeeper-update-namespace-label
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
diff --git a/charts/gatekeeper/templates/namespace-post-upgrade.yaml b/charts/gatekeeper/templates/namespace-post-upgrade.yaml
index 43a1dadd9fa..b26abab34e0 100644
--- a/charts/gatekeeper/templates/namespace-post-upgrade.yaml
+++ b/charts/gatekeeper/templates/namespace-post-upgrade.yaml
@@ -3,12 +3,10 @@ apiVersion: batch/v1
kind: Job
metadata:
name: gatekeeper-update-namespace-label-post-upgrade
+ namespace: {{ .Release.Namespace | quote }}
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-upgrade
"helm.sh/hook-weight": "-5"
@@ -20,12 +18,9 @@ spec:
template:
metadata:
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
restartPolicy: OnFailure
{{- if .Values.postUpgrade.labelNamespace.image.pullSecrets }}
@@ -33,6 +28,9 @@ spec:
{{- .Values.postUpgrade.labelNamespace.image.pullSecrets | toYaml | nindent 12 }}
{{- end }}
serviceAccount: gatekeeper-update-namespace-label-post-upgrade
+ {{- if .Values.postUpgrade.labelNamespace.priorityClassName }}
+ priorityClassName: {{ .Values.postUpgrade.labelNamespace.priorityClassName }}
+ {{- end }}
containers:
- name: kubectl-label
image: "{{ .Values.postUpgrade.labelNamespace.image.repository }}:{{ .Values.postUpgrade.labelNamespace.image.tag }}"
@@ -89,6 +87,7 @@ kind: ServiceAccount
metadata:
name: gatekeeper-update-namespace-label-post-upgrade
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -102,6 +101,7 @@ kind: ClusterRole
metadata:
name: gatekeeper-update-namespace-label-post-upgrade
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -130,6 +130,7 @@ kind: ClusterRoleBinding
metadata:
name: gatekeeper-update-namespace-label-post-upgrade
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
diff --git a/charts/gatekeeper/templates/probe-webhook-post-install.yaml b/charts/gatekeeper/templates/probe-webhook-post-install.yaml
index 5a140d31ce0..e6ef25b594c 100644
--- a/charts/gatekeeper/templates/probe-webhook-post-install.yaml
+++ b/charts/gatekeeper/templates/probe-webhook-post-install.yaml
@@ -5,11 +5,8 @@ kind: Job
metadata:
name: gatekeeper-probe-webhook-post-install
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install
"helm.sh/hook-weight": "-5"
@@ -20,14 +17,14 @@ spec:
annotations:
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
restartPolicy: Never
+ {{- if .Values.postInstall.probeWebhook.priorityClassName }}
+ priorityClassName: {{ .Values.postInstall.probeWebhook.priorityClassName }}
+ {{- end }}
{{- if .Values.postInstall.probeWebhook.image.pullSecrets }}
imagePullSecrets:
{{- .Values.postInstall.probeWebhook.image.pullSecrets | toYaml | nindent 12 }}
@@ -44,5 +41,6 @@ spec:
nodeSelector:
{{- toYaml .nodeSelector | nindent 8 }}
{{- end }}
+ backoffLimit: 3
{{- end }}
{{- end }}
diff --git a/charts/gatekeeper/templates/upgrade-crds-hook.yaml b/charts/gatekeeper/templates/upgrade-crds-hook.yaml
index cd57573f37a..f9347ad9c7b 100644
--- a/charts/gatekeeper/templates/upgrade-crds-hook.yaml
+++ b/charts/gatekeeper/templates/upgrade-crds-hook.yaml
@@ -5,6 +5,7 @@ kind: ClusterRole
metadata:
name: gatekeeper-admin-upgrade-crds
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -26,6 +27,7 @@ kind: ClusterRoleBinding
metadata:
name: gatekeeper-admin-upgrade-crds
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -46,6 +48,7 @@ apiVersion: v1
kind: ServiceAccount
metadata:
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
name: gatekeeper-admin-upgrade-crds
@@ -61,29 +64,23 @@ metadata:
name: gatekeeper-update-crds-hook
namespace: {{ .Release.Namespace }}
labels:
- app: {{ template "gatekeeper.name" . }}
- chart: {{ template "gatekeeper.name" . }}
- gatekeeper.sh/system: "yes"
- heritage: {{ .Release.Service }}
- release: {{ .Release.Name }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-weight: "1"
helm.sh/hook-delete-policy: "hook-succeeded,before-hook-creation"
spec:
- backoffLimit: 0
+ backoffLimit: 3
template:
metadata:
name: gatekeeper-update-crds-hook
annotations:
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
serviceAccountName: gatekeeper-admin-upgrade-crds
restartPolicy: Never
@@ -91,12 +88,23 @@ spec:
imagePullSecrets:
{{- toYaml .Values.image.pullSecrets | nindent 8 }}
{{- end }}
+ {{- if .Values.upgradeCRDs.priorityClassName }}
+ priorityClassName: {{ .Values.upgradeCRDs.priorityClassName }}
+ {{- end }}
containers:
- name: crds-upgrade
- {{- if not .Values.image.release }}
- image: '{{ .Values.image.crdRepository }}'
+ {{- if .Values.preInstall.crdRepository.image.repository }}
+ {{- if not .Values.preInstall.crdRepository.image.tag }}
+ image: '{{ .Values.preInstall.crdRepository.image.repository }}'
+ {{- else }}
+ image: '{{ .Values.preInstall.crdRepository.image.repository }}:{{ .Values.preInstall.crdRepository.image.tag }}'
+ {{- end }}
{{- else }}
+ {{- if not .Values.image.release }}
+ image: '{{ .Values.image.crdRepository }}'
+ {{- else }}
image: '{{ .Values.image.crdRepository }}:{{ .Values.image.release }}'
+ {{- end }}
{{- end }}
imagePullPolicy: '{{ .Values.image.pullPolicy }}'
args:
diff --git a/charts/gatekeeper/templates/webhook-configs-pre-delete.yaml b/charts/gatekeeper/templates/webhook-configs-pre-delete.yaml
index d610394de36..fb359b87e16 100644
--- a/charts/gatekeeper/templates/webhook-configs-pre-delete.yaml
+++ b/charts/gatekeeper/templates/webhook-configs-pre-delete.yaml
@@ -3,12 +3,10 @@ apiVersion: batch/v1
kind: Job
metadata:
name: gatekeeper-delete-webhook-configs
+ namespace: {{ .Release.Namespace | quote }}
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-5"
@@ -19,12 +17,9 @@ spec:
annotations:
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
restartPolicy: OnFailure
{{- if .Values.preUninstall.deleteWebhookConfigurations.image.pullSecrets }}
@@ -32,6 +27,9 @@ spec:
{{- .Values.preUninstall.deleteWebhookConfigurations.image.pullSecrets | toYaml | nindent 12 }}
{{- end }}
serviceAccount: gatekeeper-delete-webhook-configs
+ {{- if .Values.preUninstall.deleteWebhookConfigurations.priorityClassName }}
+ priorityClassName: {{ .Values.preUninstall.deleteWebhookConfigurations.priorityClassName }}
+ {{- end }}
containers:
- name: kubectl-delete
image: "{{ .Values.preUninstall.deleteWebhookConfigurations.image.repository }}:{{ .Values.preUninstall.deleteWebhookConfigurations.image.tag }}"
@@ -39,19 +37,19 @@ spec:
args:
- delete
{{- if not .Values.disableValidatingWebhook }}
- - validatingwebhookconfiguration/gatekeeper-validating-webhook-configuration
+ - validatingwebhookconfiguration/{{ .Values.validatingWebhookName }}
{{- end }}
{{- if not .Values.disableMutation }}
- - mutatingwebhookconfiguration/gatekeeper-mutating-webhook-configuration
+ - mutatingwebhookconfiguration/{{ .Values.mutatingWebhookName }}
{{- end }}
resources:
- {{- toYaml .Values.preUninstall.resources | nindent 10 }}
+ {{- toYaml .Values.preUninstall.resources | nindent 12 }}
securityContext:
{{- if .Values.enableRuntimeDefaultSeccompProfile }}
seccompProfile:
type: RuntimeDefault
{{- end }}
- {{- toYaml .Values.preUninstall.securityContext | nindent 10 }}
+ {{- toYaml .Values.preUninstall.securityContext | nindent 12 }}
{{- with .Values.preUninstall }}
nodeSelector:
{{- toYaml .nodeSelector | nindent 8 }}
@@ -65,7 +63,9 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: gatekeeper-delete-webhook-configs
+ namespace: {{ .Release.Namespace | quote }}
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -79,6 +79,7 @@ kind: ClusterRole
metadata:
name: gatekeeper-delete-webhook-configs
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -92,7 +93,7 @@ rules:
resources:
- validatingwebhookconfigurations
resourceNames:
- - gatekeeper-validating-webhook-configuration
+ - {{ .Values.validatingWebhookName }}
verbs:
- delete
{{- end }}
@@ -102,7 +103,7 @@ rules:
resources:
- mutatingwebhookconfigurations
resourceNames:
- - gatekeeper-mutating-webhook-configuration
+ - {{ .Values.mutatingWebhookName }}
verbs:
- delete
{{- end }}
@@ -117,6 +118,7 @@ kind: ClusterRoleBinding
metadata:
name: gatekeeper-delete-webhook-configs
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
diff --git a/charts/gatekeeper/values.yaml b/charts/gatekeeper/values.yaml
index 823dc06f364..2e4c3a8666f 100644
--- a/charts/gatekeeper/values.yaml
+++ b/charts/gatekeeper/values.yaml
@@ -1,4 +1,5 @@
replicas: 3
+revisionHistoryLimit: 10
auditInterval: 60
metricsBackends: ["prometheus"]
auditMatchKindOnly: false
@@ -6,6 +7,7 @@ constraintViolationsLimit: 20
auditFromCache: false
disableMutation: false
disableValidatingWebhook: false
+validatingWebhookName: gatekeeper-validating-webhook-configuration
validatingWebhookTimeoutSeconds: 3
validatingWebhookFailurePolicy: Ignore
validatingWebhookAnnotations: {}
@@ -13,11 +15,13 @@ validatingWebhookExemptNamespacesLabels: {}
validatingWebhookObjectSelector: {}
validatingWebhookCheckIgnoreFailurePolicy: Fail
validatingWebhookCustomRules: {}
+validatingWebhookURL: null
enableDeleteOperations: false
enableExternalData: true
-enableGeneratorResourceExpansion: false
+enableGeneratorResourceExpansion: true
enableTLSHealthcheck: false
maxServingThreads: -1
+mutatingWebhookName: gatekeeper-mutating-webhook-configuration
mutatingWebhookFailurePolicy: Ignore
mutatingWebhookReinvocationPolicy: Never
mutatingWebhookAnnotations: {}
@@ -25,6 +29,7 @@ mutatingWebhookExemptNamespacesLabels: {}
mutatingWebhookObjectSelector: {}
mutatingWebhookTimeoutSeconds: 1
mutatingWebhookCustomRules: {}
+mutatingWebhookURL: null
mutationAnnotations: false
auditChunkSize: 500
logLevel: INFO
@@ -32,13 +37,27 @@ logDenies: false
logMutations: false
emitAdmissionEvents: false
emitAuditEvents: false
+admissionEventsInvolvedNamespace: false
+auditEventsInvolvedNamespace: false
resourceQuota: true
+externaldataProviderResponseCacheTTL: 3m
+image:
+ repository: openpolicyagent/gatekeeper
+ crdRepository: openpolicyagent/gatekeeper-crds
+ release: v3.14.0
+ pullPolicy: IfNotPresent
+ pullSecrets: []
+preInstall:
+ crdRepository:
+ image:
+ repository: null
+ tag: v3.14.0
postUpgrade:
labelNamespace:
enabled: false
image:
repository: openpolicyagent/gatekeeper-crds
- tag: v3.12.0-beta.0
+ tag: v3.14.0
pullPolicy: IfNotPresent
pullSecrets: []
extraNamespaces: []
@@ -49,6 +68,7 @@ postUpgrade:
"pod-security.kubernetes.io/enforce=restricted",
"pod-security.kubernetes.io/enforce-version=v1.24"]
extraAnnotations: {}
+ priorityClassName: ""
affinity: {}
tolerations: []
nodeSelector: {kubernetes.io/os: linux}
@@ -68,7 +88,7 @@ postInstall:
extraRules: []
image:
repository: openpolicyagent/gatekeeper-crds
- tag: v3.12.0-beta.0
+ tag: v3.14.0
pullPolicy: IfNotPresent
pullSecrets: []
extraNamespaces: []
@@ -79,6 +99,7 @@ postInstall:
"pod-security.kubernetes.io/enforce=restricted",
"pod-security.kubernetes.io/enforce-version=v1.24"]
extraAnnotations: {}
+ priorityClassName: ""
probeWebhook:
enabled: true
image:
@@ -89,6 +110,7 @@ postInstall:
waitTimeout: 60
httpTimeout: 2
insecureHTTPS: false
+ priorityClassName: ""
affinity: {}
tolerations: []
nodeSelector: {kubernetes.io/os: linux}
@@ -107,9 +129,10 @@ preUninstall:
enabled: false
image:
repository: openpolicyagent/gatekeeper-crds
- tag: v3.12.0-beta.0
+ tag: v3.14.0
pullPolicy: IfNotPresent
pullSecrets: []
+ priorityClassName: ""
affinity: {}
tolerations: []
nodeSelector: {kubernetes.io/os: linux}
@@ -123,13 +146,8 @@ preUninstall:
runAsGroup: 999
runAsNonRoot: true
runAsUser: 1000
-image:
- repository: openpolicyagent/gatekeeper
- crdRepository: openpolicyagent/gatekeeper-crds
- release: v3.12.0-beta.0
- pullPolicy: IfNotPresent
- pullSecrets: []
podAnnotations: {}
+auditPodAnnotations: {}
podLabels: {}
podCountLimit: "100"
secretAnnotations: {}
@@ -146,8 +164,9 @@ controllerManager:
livenessTimeout: 1
priorityClassName: system-cluster-critical
disableCertRotation: false
- tlsMinVersion: 1.3
+ tlsMinVersion: 1.2
clientCertName: ""
+ strategyType: RollingUpdate
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
@@ -183,7 +202,14 @@ controllerManager:
supplementalGroups:
- 999
extraRules: []
+ networkPolicy:
+ enabled: false
+ ingress: { }
+ # - from:
+ # - ipBlock:
+ # cidr: 0.0.0.0/0
audit:
+ enablePubsub: false
hostNetwork: false
dnsPolicy: ClusterFirst
metricsPort: 8888
@@ -191,7 +217,7 @@ audit:
readinessTimeout: 1
livenessTimeout: 1
priorityClassName: system-cluster-critical
- disableCertRotation: true
+ disableCertRotation: false
affinity: {}
tolerations: []
nodeSelector: {kubernetes.io/os: linux}
@@ -240,6 +266,7 @@ psp:
upgradeCRDs:
enabled: true
extraRules: []
+ priorityClassName: ""
rbac:
create: true
externalCertInjection:
diff --git a/cmd/build/helmify/kustomization.yaml b/cmd/build/helmify/kustomization.yaml
index 2d94aad7994..1c1943f2874 100644
--- a/cmd/build/helmify/kustomization.yaml
+++ b/cmd/build/helmify/kustomization.yaml
@@ -34,18 +34,36 @@ patchesJson6902:
kind: CustomResourceDefinition
name: mutatorpodstatuses.status.gatekeeper.sh
path: labels_patch.yaml
+ - target:
+ group: apiextensions.k8s.io
+ version: v1
+ kind: CustomResourceDefinition
+ name: expansiontemplatepodstatuses.status.gatekeeper.sh
+ path: labels_patch.yaml
- target:
group: apiextensions.k8s.io
version: v1
kind: CustomResourceDefinition
name: configs.config.gatekeeper.sh
path: labels_patch.yaml
+ - target:
+ group: apiextensions.k8s.io
+ version: v1
+ kind: CustomResourceDefinition
+ name: syncsets.syncset.gatekeeper.sh
+ path: labels_patch.yaml
- target:
group: apiextensions.k8s.io
version: v1
kind: CustomResourceDefinition
name: assignmetadata.mutations.gatekeeper.sh
path: labels_patch.yaml
+ - target:
+ group: apiextensions.k8s.io
+ version: v1
+ kind: CustomResourceDefinition
+ name: assignimage.mutations.gatekeeper.sh
+ path: labels_patch.yaml
- target:
group: apiextensions.k8s.io
version: v1
@@ -131,3 +149,24 @@ patchesJson6902:
patch: |-
- op: remove
path: /spec/ports
+ - target:
+ kind: ValidatingWebhookConfiguration
+ name: gatekeeper-validating-webhook-configuration
+ patch: |-
+ - op: replace
+ path: /metadata/name
+ value: "{{ .Values.validatingWebhookName }}"
+ - op: replace
+ path: /webhooks/0/clientConfig
+ value: { "HELMSUBST_VALIDATING_WEBHOOK_CLIENT_CONFIG": "" }
+ - target:
+ kind: MutatingWebhookConfiguration
+ name: gatekeeper-mutating-webhook-configuration
+ patch: |-
+ - op: replace
+ path: /metadata/name
+ value: "{{ .Values.mutatingWebhookName }}"
+ - op: replace
+ path: /webhooks/0/clientConfig
+ value: { "HELMSUBST_MUTATING_WEBHOOK_CLIENT_CONFIG": "" }
+
diff --git a/cmd/build/helmify/kustomize-for-helm.yaml b/cmd/build/helmify/kustomize-for-helm.yaml
index 25ae92cf597..bd8847ac979 100644
--- a/cmd/build/helmify/kustomize-for-helm.yaml
+++ b/cmd/build/helmify/kustomize-for-helm.yaml
@@ -62,6 +62,9 @@ metadata:
namespace: gatekeeper-system
spec:
replicas: HELMSUBST_DEPLOYMENT_REPLICAS
+ revisionHistoryLimit: HELMSUBST_DEPLOYMENT_REVISION_HISTORY_LIMIT
+ strategy:
+ type: HELMSUBST_DEPLOYMENT_CONTROLLER_MANAGER_STRATEGY_TYPE
template:
metadata:
annotations:
@@ -76,6 +79,7 @@ spec:
- --logtostderr
- --log-denies={{ .Values.logDenies }}
- --emit-admission-events={{ .Values.emitAdmissionEvents }}
+ - --admission-events-involved-namespace={{ .Values.admissionEventsInvolvedNamespace }}
- --log-level={{ (.Values.controllerManager.logLevel | empty | not) | ternary .Values.controllerManager.logLevel .Values.logLevel }}
- --exempt-namespace={{ .Release.Namespace }}
- --operation=webhook
@@ -86,6 +90,9 @@ spec:
- --disable-cert-rotation={{ .Values.controllerManager.disableCertRotation }}
- --max-serving-threads={{ .Values.maxServingThreads }}
- --tls-min-version={{ .Values.controllerManager.tlsMinVersion }}
+ - --validating-webhook-configuration-name={{ .Values.validatingWebhookName }}
+ - --mutating-webhook-configuration-name={{ .Values.mutatingWebhookName }}
+ - --external-data-provider-response-cache-ttl={{ .Values.externaldataProviderResponseCacheTTL }}
- HELMBUST_ENABLE_TLS_APISERVER_AUTHENTICATION
- HELMSUBST_METRICS_BACKEND_ARG
- HELMSUBST_TLS_HEALTHCHECK_ENABLED_ARG
@@ -93,6 +100,7 @@ spec:
- HELMSUBST_DEPLOYMENT_CONTROLLER_MANAGER_DISABLED_BUILTIN
- HELMSUBST_DEPLOYMENT_CONTROLLER_MANAGER_EXEMPT_NAMESPACES
- HELMSUBST_DEPLOYMENT_CONTROLLER_MANAGER_EXEMPT_NAMESPACE_PREFIXES
+ - HELMSUBST_DEPLOYMENT_CONTROLLER_MANAGER_EXEMPT_NAMESPACE_SUFFIXES
- HELMSUBST_DEPLOYMENT_CONTROLLER_MANAGER_LOGFILE
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
HELMSUBST_AUDIT_CONTROLLER_MANAGER_DEPLOYMENT_IMAGE_RELEASE: ""
@@ -141,10 +149,12 @@ metadata:
name: gatekeeper-audit
namespace: gatekeeper-system
spec:
+ revisionHistoryLimit: HELMSUBST_DEPLOYMENT_REVISION_HISTORY_LIMIT
template:
metadata:
annotations:
HELMSUBST_ANNOTATIONS: ""
+ HELMSUBST_AUDIT_POD_ANNOTATIONS: ""
spec:
containers:
- name: manager
@@ -152,12 +162,16 @@ spec:
- --audit-interval={{ .Values.auditInterval }}
- --log-level={{ (.Values.audit.logLevel | empty | not) | ternary .Values.audit.logLevel .Values.logLevel }}
- --constraint-violations-limit={{ .Values.constraintViolationsLimit }}
+ - --validating-webhook-configuration-name={{ .Values.validatingWebhookName }}
+ - --mutating-webhook-configuration-name={{ .Values.mutatingWebhookName }}
- --audit-from-cache={{ .Values.auditFromCache }}
- --audit-chunk-size={{ .Values.auditChunkSize }}
- --audit-match-kind-only={{ .Values.auditMatchKindOnly }}
- --emit-audit-events={{ .Values.emitAuditEvents }}
+ - --audit-events-involved-namespace={{ .Values.auditEventsInvolvedNamespace }}
- --operation=audit
- --operation=status
+ - HELMSUBST_PUBSUB_ARGS
- HELMSUBST_MUTATION_STATUS_ENABLED_ARG
- --logtostderr
- --health-addr=:HELMSUBST_DEPLOYMENT_AUDIT_HEALTH_PORT
@@ -167,6 +181,7 @@ spec:
- HELMSUBST_METRICS_BACKEND_ARG
- HELMSUBST_DEPLOYMENT_AUDIT_LOGFILE
- --disable-cert-rotation={{ or .Values.audit.disableCertRotation .Values.externalCertInjection.enabled }}
+ - --external-data-provider-response-cache-ttl={{ .Values.externaldataProviderResponseCacheTTL }}
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
HELMSUBST_AUDIT_CONTROLLER_MANAGER_DEPLOYMENT_IMAGE_RELEASE: ""
ports:
diff --git a/cmd/build/helmify/main.go b/cmd/build/helmify/main.go
index 0a65cb53b8a..34f0d087026 100644
--- a/cmd/build/helmify/main.go
+++ b/cmd/build/helmify/main.go
@@ -101,18 +101,21 @@ func (ks *kindSet) Write() error {
if err != nil {
return err
}
+
fileName := fmt.Sprintf("%s-%s.yaml", strings.ToLower(name), strings.ToLower(kind))
- destFile := path.Join(*outputDir, subPath, fileName)
- fmt.Printf("Writing %s\n", destFile)
- if name == "gatekeeper-validating-webhook-configuration" {
+ if name == "validation.gatekeeper.sh" {
obj = "{{- if not .Values.disableValidatingWebhook }}\n" + obj + "{{- end }}\n"
+ fileName = fmt.Sprintf("gatekeeper-validating-webhook-configuration-%s.yaml", strings.ToLower(kind))
}
- if name == "gatekeeper-mutating-webhook-configuration" {
+ if name == "mutation.gatekeeper.sh" {
obj = "{{- if not .Values.disableMutation }}\n" + obj + "{{- end }}\n"
+ fileName = fmt.Sprintf("gatekeeper-mutating-webhook-configuration-%s.yaml", strings.ToLower(kind))
}
+ destFile := path.Join(*outputDir, subPath, fileName)
+
if name == "gatekeeper-webhook-server-cert" && kind == "Secret" {
obj = "{{- if not .Values.externalCertInjection.enabled }}\n" + obj + "{{- end }}\n"
}
@@ -151,8 +154,12 @@ func (ks *kindSet) Write() error {
if name == "gatekeeper-manager-role" && kind == "ClusterRole" {
obj = strings.Replace(obj, "- apiGroups:\n - policy\n resourceNames:\n - gatekeeper-admin\n resources:\n - podsecuritypolicies\n verbs:\n - use\n", "{{- if and .Values.psp.enabled (.Capabilities.APIVersions.Has \"policy/v1beta1/PodSecurityPolicy\") }}\n- apiGroups:\n - policy\n resourceNames:\n - gatekeeper-admin\n resources:\n - podsecuritypolicies\n verbs:\n - use\n{{- end }}\n", 1)
+ obj = strings.Replace(obj, "- gatekeeper-validating-webhook-configuration\n", "- {{ .Values.validatingWebhookName }}\n", 1)
+ obj = strings.Replace(obj, "- gatekeeper-mutating-webhook-configuration\n", "- {{ .Values.mutatingWebhookName }}\n", 1)
}
+ fmt.Printf("Writing %s\n", destFile)
+
if err := os.WriteFile(destFile, []byte(obj), 0o600); err != nil {
return err
}
diff --git a/cmd/build/helmify/replacements.go b/cmd/build/helmify/replacements.go
index e73c5359770..b849fb7352c 100644
--- a/cmd/build/helmify/replacements.go
+++ b/cmd/build/helmify/replacements.go
@@ -55,6 +55,8 @@ var replacements = map[string]string{
`HELMSUBST_DEPLOYMENT_CONTROLLER_MANAGER_AFFINITY: ""`: `{{- toYaml .Values.controllerManager.affinity | nindent 8 }}`,
+ "HELMSUBST_DEPLOYMENT_CONTROLLER_MANAGER_STRATEGY_TYPE": `{{ .Values.controllerManager.strategyType }}`,
+
`HELMSUBST_DEPLOYMENT_CONTROLLER_MANAGER_SECURITY_CONTEXT: ""`: `{{- if .Values.enableRuntimeDefaultSeccompProfile }}
seccompProfile:
type: RuntimeDefault
@@ -71,10 +73,16 @@ var replacements = map[string]string{
"HELMSUBST_DEPLOYMENT_REPLICAS": `{{ .Values.replicas }}`,
+ "HELMSUBST_DEPLOYMENT_REVISION_HISTORY_LIMIT": `{{ .Values.revisionHistoryLimit }}`,
+
`HELMSUBST_ANNOTATIONS: ""`: `{{- if .Values.podAnnotations }}
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
{{- end }}`,
+ `HELMSUBST_AUDIT_POD_ANNOTATIONS: ""`: `{{- if .Values.auditPodAnnotations }}
+ {{- toYaml .Values.auditPodAnnotations | trim | nindent 8 }}
+ {{- end }}`,
+
"HELMSUBST_SECRET_ANNOTATIONS": `{{- toYaml .Values.secretAnnotations | trim | nindent 4 }}`,
"- HELMSUBST_TLS_HEALTHCHECK_ENABLED_ARG": `{{ if .Values.enableTLSHealthcheck}}- --enable-tls-healthcheck{{- end }}`,
@@ -85,6 +93,12 @@ var replacements = map[string]string{
"- HELMSUBST_MUTATION_STATUS_ENABLED_ARG": `{{ if not .Values.disableMutation}}- --operation=mutation-status{{- end }}`,
+ "- HELMSUBST_PUBSUB_ARGS": `{{ if .Values.audit.enablePubsub}}
+ - --enable-pub-sub={{ .Values.audit.enablePubsub }}
+ - --audit-connection={{ .Values.audit.connection }}
+ - --audit-channel={{ .Values.audit.channel }}
+ {{- end }}`,
+
"HELMSUBST_MUTATING_WEBHOOK_FAILURE_POLICY": `{{ .Values.mutatingWebhookFailurePolicy }}`,
"HELMSUBST_MUTATING_WEBHOOK_REINVOCATION_POLICY": `{{ .Values.mutatingWebhookReinvocationPolicy }}`,
@@ -123,6 +137,15 @@ var replacements = map[string]string{
- '*'
{{- end }}`,
+ "HELMSUBST_MUTATING_WEBHOOK_CLIENT_CONFIG: \"\"": `{{- if .Values.mutatingWebhookURL }}
+ url: https://{{ .Values.mutatingWebhookURL }}/v1/mutate
+ {{- else }}
+ service:
+ name: gatekeeper-webhook-service
+ namespace: '{{ .Release.Namespace }}'
+ path: /v1/mutate
+ {{- end }}`,
+
"HELMSUBST_VALIDATING_WEBHOOK_TIMEOUT": `{{ .Values.validatingWebhookTimeoutSeconds }}`,
"HELMSUBST_VALIDATING_WEBHOOK_FAILURE_POLICY": `{{ .Values.validatingWebhookFailurePolicy }}`,
@@ -148,6 +171,15 @@ var replacements = map[string]string{
"HELMSUBST_VALIDATING_WEBHOOK_CHECK_IGNORE_FAILURE_POLICY": `{{ .Values.validatingWebhookCheckIgnoreFailurePolicy }}`,
+ "HELMSUBST_VALIDATING_WEBHOOK_CLIENT_CONFIG: \"\"": `{{- if .Values.validatingWebhookURL }}
+ url: https://{{ .Values.validatingWebhookURL }}/v1/admit
+ {{- else }}
+ service:
+ name: gatekeeper-webhook-service
+ namespace: '{{ .Release.Namespace }}'
+ path: /v1/admit
+ {{- end }}`,
+
"HELMSUBST_RESOURCEQUOTA_POD_LIMIT": `{{ .Values.podCountLimit }}`,
"- HELMSUBST_VALIDATING_WEBHOOK_OPERATION_RULES": `{{- if .Values.validatingWebhookCustomRules }}
@@ -232,6 +264,11 @@ var replacements = map[string]string{
- --exempt-namespace-prefix={{ . }}
{{- end }}`,
+ "- HELMSUBST_DEPLOYMENT_CONTROLLER_MANAGER_EXEMPT_NAMESPACE_SUFFIXES": `
+ {{- range .Values.controllerManager.exemptNamespaceSuffixes}}
+ - --exempt-namespace-suffix={{ . }}
+ {{- end }}`,
+
"- HELMSUBST_DEPLOYMENT_CONTROLLER_MANAGER_LOGFILE": `
{{- if .Values.controllerManager.logFile}}
- --log-file={{ .Values.controllerManager.logFile }}
diff --git a/cmd/build/helmify/static/Chart.yaml b/cmd/build/helmify/static/Chart.yaml
index 38a5497d03d..695bff1ac0d 100644
--- a/cmd/build/helmify/static/Chart.yaml
+++ b/cmd/build/helmify/static/Chart.yaml
@@ -4,8 +4,8 @@ name: gatekeeper
icon: https://open-policy-agent.github.io/gatekeeper/website/img/logo.svg
keywords:
- open policy agent
-version: 3.12.0-beta.0
+version: 3.14.0
home: https://github.com/open-policy-agent/gatekeeper
sources:
- https://github.com/open-policy-agent/gatekeeper.git
-appVersion: v3.12.0-beta.0
+appVersion: v3.14.0
diff --git a/cmd/build/helmify/static/README.md b/cmd/build/helmify/static/README.md
index 6e13a55b341..fe841a46a52 100644
--- a/cmd/build/helmify/static/README.md
+++ b/cmd/build/helmify/static/README.md
@@ -27,7 +27,8 @@ _See [helm install](https://helm.sh/docs/helm/helm_install/) for command documen
## Upgrade Chart
**Upgrading from < v3.4.0**
-Chart 3.4.0 deprecates support for Helm 2 and also removes the creation of the `gatekeeper-system` Namespace from within the chart. This follows Helm 3 Best Practices.
+Chart 3.4.0 deprecates support for Helm 2 and also removes the creation of the `gatekeeper-system` Namespace from within
+the chart. This follows Helm 3 Best Practices.
Option 1:
A simple way to upgrade is to uninstall first and re-install with 3.4.0 or greater.
@@ -39,7 +40,9 @@ $ helm install -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper --creat
```
Option 2:
-Run the `helm_migrate.sh` script before installing the 3.4.0 or greater chart. This will remove the Helm secret for the original release, while keeping all of the resources. It then updates the annotations of the resources so that the new chart can import and manage them.
+Run the `helm_migrate.sh` script before installing the 3.4.0 or greater chart. This will remove the Helm secret for the
+original release, while keeping all of the resources. It then updates the annotations of the resources so that the new
+chart can import and manage them.
```console
$ helm_migrate.sh
@@ -47,155 +50,178 @@ $ helm install -n gatekeeper-system gatekeeper gatekeeper/gatekeeper
```
**Upgrading from >= v3.4.0**
+
```console
$ helm upgrade -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper
```
_See [helm 2 to 3](https://helm.sh/docs/topics/v2_v3_migration/) for Helm 2 migration documentation._
-
## Exempting Namespace
-The Helm chart automatically sets the Gatekeeper flag `--exempt-namespace={{ .Release.Namespace }}` in order to exempt the namespace where the chart is installed, and adds the `admission.gatekeeper.sh/ignore` label to the namespace during a post-install hook.
+The Helm chart automatically sets the Gatekeeper flag `--exempt-namespace={{ .Release.Namespace }}` in order to exempt
+the namespace where the chart is installed, and adds the `admission.gatekeeper.sh/ignore` label to the namespace during
+a post-install hook.
-_See [Exempting Namespaces](https://open-policy-agent.github.io/gatekeeper/website/docs/exempt-namespaces) for more information._
+_See [Exempting Namespaces](https://open-policy-agent.github.io/gatekeeper/website/docs/exempt-namespaces) for more
+information._
## Parameters
-| Parameter | Description | Default |
-| :-------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------ |
-| postInstall.labelNamespace.enabled | Add labels to the namespace during post install hooks | `true` |
-| postInstall.labelNamespace.extraNamespaces | The extra namespaces that need to have the label during post install hooks | `[]` |
-| postInstall.labelNamespace.extraAnnotations | Extra annotations added to the post install Job | `{}` |
-| postInstall.labelNamespace.image.repository | Image with kubectl to label the namespace | `openpolicyagent/gatekeeper-crds` |
-| postInstall.labelNamespace.image.tag | Image tag | Current release version: `v3.12.0-beta.0` |
-| postInstall.labelNamespace.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
-| postInstall.labelNamespace.image.pullSecrets | Image pullSecrets | `[]` |
-| postInstall.labelNamespace.extraRules | Extra rules for the gatekeeper-update-namespace-label Role | `[]` |
-| postInstall.probeWebhook.enabled | Probe webhook API post install. When enabled along with `postInstall.labelNamespace.enabled`, this probe will run as part of `postInstall.labelNamespace` Job as an initContainer | `true` |
-| postInstall.probeWebhook.image.repository | Image with curl to probe the webhook API | `curlimages/curl` |
-| postInstall.probeWebhook.image.tag | Image tag | `7.83.1` |
-| postInstall.probeWebhook.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
-| postInstall.probeWebhook.image.pullSecrets | Image pullSecrets | `[]` |
-| postInstall.probeWebhook.waitTimeout | Total time to wait for the webhook API to become available | `60` |
-| postInstall.probeWebhook.httpTimeout | HTTP client timeout | `2` |
-| postInstall.probeWebhook.insecureHTTPS | Ignore server SSL certificate | `false` |
-| postInstall.affinity | The affinity to use for pod scheduling in postInstall hook jobs | `{}` |
-| postInstall.tolerations | The tolerations to use for pod scheduling in postInstall hook jobs | `[]` |
-| postInstall.nodeSelector | The node selector to use for pod scheduling in postInstall hook jobs | `kubernetes.io/os: linux` |
-| postInstall.resources | The resource request/limits for the container image in postInstall hook jobs | `{}` |
-| postInstall.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| postUpgrade.labelNamespace.enabled | Add labels to the namespace during post upgrade hooks | `false` |
-| postUpgrade.labelNamespace.extraNamespaces | The extra namespaces that need to have the label during post upgrade hooks | `[]` |
-| postUpgrade.labelNamespace.extraAnnotations | Extra annotations added to the post upgrade Job | `{}` |
-| postUpgrade.labelNamespace.image.repository | Image with kubectl to label the namespace | `openpolicyagent/gatekeeper-crds` |
-| postUpgrade.labelNamespace.image.tag | Image tag | Current release version: `v3.12.0-beta.0` |
-| postUpgrade.labelNamespace.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
-| postUpgrade.labelNamespace.image.pullSecrets | Image pullSecrets | `[]`
-| postUpgrade.affinity | The affinity to use for pod scheduling in postUpgrade hook jobs | `{}` |
-| postUpgrade.tolerations | The tolerations to use for pod scheduling in postUpgrade hook jobs | `[]` |
-| postUpgrade.nodeSelector | The node selector to use for pod scheduling in postUpgrade hook jobs | `kubernetes.io/os: linux` |
-| postUpgrade.resources | The resource request/limits for the container image in postUpgrade hook jobs | `{}` |
-| postUpgrade.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| preUninstall.deleteWebhooks.enabled | Delete webhooks before gatekeeper itself is uninstalled | `false` |
-| preUninstall.deleteWebhooks.image.repository | Image with kubectl to delete the webhooks | `openpolicyagent/gatekeeper-crds` |
-| preUninstall.deleteWebhooks.image.tag | Image tag | Current release version: `v3.12.0-beta.0` |
-| preUninstall.deleteWebhooks.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
-| preUninstall.deleteWebhooks.image.pullSecrets | Image pullSecrets | `[]` |
-| preUninstall.deleteWebhooks.extraRules | Extra rules for the gatekeeper-delete-webhook-configs Role | `[]` |
-| preUninstall.affinity | The affinity to use for pod scheduling in preUninstall hook jobs | `{}` |
-| preUninstall.tolerations | The tolerations to use for pod scheduling in preUninstall hook jobs | `[]` |
-| preUninstall.nodeSelector | The node selector to use for pod scheduling in preUninstall hook jobs | `kubernetes.io/os: linux` |
-| preUninstall.resources | The resource request/limits for the container image in preUninstall hook jobs | `{}` |
-| preUninstall.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| psp.enabled | Enabled PodSecurityPolicy | `true` |
-| upgradeCRDs.enabled | Upgrade CRDs using pre-install/pre-upgrade hooks | `true` |
-| upgradeCRDs.extraRules | Extra rules for the gatekeeper-admin-upgrade-crds ClusterRole | `[]` |
-| crds.affinity | The affinity to use for pod scheduling in crds hook jobs | `{}` |
-| crds.tolerations | The tolerations to use for pod scheduling in crds hook jobs | `[]` |
-| crds.nodeSelector | The node selector to use for pod scheduling in crds hook jobs | `kubernetes.io/os: linux` |
-| crds.resources | The resource request/limits for the container image in crds hook jobs | `{}` |
-| crds.securityContext | Security context applied to the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 65532, "runAsNonRoot": true, "runAsUser": 65532 }` |
-| auditInterval | The frequency with which audit is run | `60` |
-| constraintViolationsLimit | The maximum # of audit violations reported on a constraint | `20` |
-| auditFromCache | Take the roster of resources to audit from the audit cache | `false` |
-| auditChunkSize | Chunk size for listing cluster resources for audit (alpha feature) | `500` |
-| auditMatchKindOnly | Only check resources of the kinds specified in all constraints defined in the cluster. | `false` |
-| disableValidatingWebhook | Disable the validating webhook | `false` |
-| disableMutation | Disable mutation | `false` |
-| validatingWebhookTimeoutSeconds | The timeout for the validating webhook in seconds | `3` |
-| validatingWebhookFailurePolicy | The failurePolicy for the validating webhook | `Ignore` |
-| validatingWebhookAnnotations | The annotations to add to the ValidatingWebhookConfiguration | `{}` |
-| validatingWebhookObjectSelector | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's validation webhook unless measures are taken to control how exemption labels can be set. | `{}` |
-| validatingWebhookCheckIgnoreFailurePolicy | The failurePolicy for the check-ignore-label validating webhook | `Fail` |
-| validatingWebhookExemptNamespacesLabels | Additional namespace labels that will be exempt from the validating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace. | `{}` |
-| validatingWebhookCustomRules | Custom rules for selecting which API resources trigger the webhook. Mutually exclusive with `enableDeleteOperations`. NOTE: If you change this, ensure all your constraints are still being enforced. | `{}` |
-| enableDeleteOperations | Enable validating webhook for delete operations. Does not work with `validatingWebhookCustomRules` | `false` |
-| enableExternalData | Enable external data | `true` |
-| enableGeneratorResourceExpansion | Enable generator resource expansion (alpha feature) | `false` |
-| enableTLSHealthcheck | Enable probing webhook API with certificate stored in certDir | `false` |
-| maxServingThreads | Limit the number of concurrent calls the validation backend made by the validation webhook. -1 limits this value to GOMAXPROCS. Configuring this value may lower max RAM usage and limit CPU throttling, Tuning it can optimize serving capacity. | `-1` |
-| metricsBackends | Metrics exporters to use. Valid exporters are: `prometheus`, `stackdriver`, and `opencensus` | `["prometheus"]` |
-| mutatingWebhookFailurePolicy | The failurePolicy for the mutating webhook | `Ignore` |
-| mutatingWebhookReinvocationPolicy | The reinvocationPolicy for the mutating webhook | `Never` |
-| mutatingWebhookAnnotations | The annotations to add to the MutatingWebhookConfiguration | `{}` |
-| mutatingWebhookExemptNamespacesLabels | Additional namespace labels that will be exempt from the mutating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace. | `{}` |
-| mutatingWebhookObjectSelector | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's mutation webhook unless measures are taken to control how exemption labels can be set. | `{}` |
-| mutatingWebhookTimeoutSeconds | The timeout for the mutating webhook in seconds | `3` |
-| mutatingWebhookCustomRules | Custom rules for selecting which API resources trigger the webhook. NOTE: If you change this, ensure all your constraints are still being enforced. | `{}` |
-| emitAdmissionEvents | Emit K8s events in gatekeeper namespace for admission violations (alpha feature) | `false` |
-| emitAuditEvents | Emit K8s events in gatekeeper namespace for audit violations (alpha feature) | `false` |
-| logDenies | Log detailed info on each deny | `false` |
-| logLevel | Minimum log level | `INFO` |
-| image.pullPolicy | The image pull policy | `IfNotPresent` |
-| image.repository | Image repository | `openpolicyagent/gatekeeper` |
-| image.release | The image release tag to use | Current release version: `v3.12.0-beta.0` |
-| image.pullSecrets | Specify an array of imagePullSecrets | `[]` |
-| resources | The resource request/limits for the container image | limits: 1 CPU, 512Mi, requests: 100mCPU, 256Mi |
-| nodeSelector | The node selector to use for pod scheduling | `kubernetes.io/os: linux` |
-| affinity | The node affinity to use for pod scheduling | `{}` |
-| topologySpreadConstraints | The topology spread constraints to use for pod scheduling | `[]` |
-| tolerations | The tolerations to use for pod scheduling | `[]` |
-| controllerManager.healthPort | Health port for controller manager | `9090` |
-| controllerManager.port | Webhook-server port for controller manager | `8443` |
-| controllerManager.metricsPort | Metrics port for controller manager | `8888` |
-| controllerManager.readinessTimeout | Timeout in seconds for the controller manager's readiness probe | `1` |
-| controllerManager.livenessTimeout | Timeout in seconds for the controller manager's liveness probe | `1` |
-| controllerManager.logLevel | The minimum log level for the controller manager, takes precedence over `logLevel` when specified | `null`
-| controllerManager.priorityClassName | Priority class name for controller manager | `system-cluster-critical` |
-| controllerManager.podSecurityContext | Security context on pod level for controller manager | {fsGroup: 999, suplementalGroups: [999]} |
-| controllerManager.exemptNamespaces | The exact namespaces to exempt by the admission webhook | `[]` |
-| controllerManager.exemptNamespacePrefixes | The namespace prefixes to exempt by the admission webhook | `[]` |
-| controllerManager.hostNetwork | Enables controllerManager to be deployed on hostNetwork | `false` |
-| controllerManager.dnsPolicy | Set the dnsPolicy for controllerManager pods | `ClusterFirst` |
-| controllerManager.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| controllerManager.tlsMinVersion | Set the minimum supported TLS version for validating and mutating webhook servers | `1.3` |
-| controllerManager.extraRules | Extra rules for the gatekeeper-manager-role Role | `[]` |
-| controllerManager.networkPolicy.enabled | Should a network policy for the controller manager be created | `false` |
-| controllerManager.networkPolicy.ingress | Additional ingress rules to be added to the controller manager network policy | `{}` |
-| audit.priorityClassName | Priority class name for audit controller | `system-cluster-critical` |
-| audit.podSecurityContext | Security context for audit on pod level | {fsGroup: 999, suplementalGroups: [999]} |
-| audit.hostNetwork | Enables audit to be deployed on hostNetwork | `false` |
-| audit.dnsPolicy | Set the dnsPolicy for audit pods | `ClusterFirst` |
-| audit.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| audit.healthPort | Health port for audit | `9090` |
-| audit.metricsPort | Metrics port for audit | `8888` |
-| audit.readinessTimeout | Timeout in seconds for audit's readiness probe | `1` |
-| audit.livenessTimeout | Timeout in seconds for the audit's liveness probe | `1` |
-| audit.logLevel | The minimum log level for audit, takes precedence over `logLevel` when specified | `null`
-| replicas | The number of Gatekeeper replicas to deploy for the webhook | `3` |
-| podAnnotations | The annotations to add to the Gatekeeper pods | `container.seccomp.security.alpha.kubernetes.io/manager: runtime/default` |
-| podLabels | The labels to add to the Gatekeeper pods | `{}` |
-| podCountLimit | The maximum number of Gatekeeper pods to run | `100` |
-| secretAnnotations | The annotations to add to the Gatekeeper secrets | `{}` |
-| pdb.controllerManager.minAvailable | The number of controller manager pods that must still be available after an eviction | `1` |
-| service.type | Service type | `ClusterIP` |
-| service.loadBalancerIP | The IP address of LoadBalancer service | `` |
-| service.healthzPort | Service port to gatekeeper Webhook health port | `9090` |
-| rbac.create | Enable the creation of RBAC resources | `true` |
-| externalCertInjection.enabled | Enable the injection of an external certificate. This disables automatic certificate generation and rotation | `false` |
-| externalCertInjection.secretName | Name of secret for injected certificate | `gatekeeper-webhook-server-cert` |
+| Parameter | Description | Default |
+|:-----------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| postInstall.labelNamespace.enabled | Add labels to the namespace during post install hooks | `true` |
+| postInstall.labelNamespace.extraNamespaces | The extra namespaces that need to have the label during post install hooks | `[]` |
+| postInstall.labelNamespace.extraAnnotations | Extra annotations added to the post install Job | `{}` |
+| postInstall.labelNamespace.image.repository | Image with kubectl to label the namespace | `openpolicyagent/gatekeeper-crds` |
+| postInstall.labelNamespace.image.tag | Image tag | Current release version: `v3.14.0` |
+| postInstall.labelNamespace.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
+| postInstall.labelNamespace.image.pullSecrets | Image pullSecrets | `[]` |
+| postInstall.labelNamespace.extraRules | Extra rules for the gatekeeper-update-namespace-label Role | `[]` |
+| postInstall.labelNamespace.priorityClassName | Priority class name for gatekeeper-update-namespace-label Job | `` |
+| postInstall.probeWebhook.enabled | Probe webhook API post install. When enabled along with `postInstall.labelNamespace.enabled`, this probe will run as part of `postInstall.labelNamespace` Job as an initContainer | `true` |
+| postInstall.probeWebhook.image.repository | Image with curl to probe the webhook API | `curlimages/curl` |
+| postInstall.probeWebhook.image.tag | Image tag | `7.83.1` |
+| postInstall.probeWebhook.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
+| postInstall.probeWebhook.image.pullSecrets | Image pullSecrets | `[]` |
+| postInstall.probeWebhook.waitTimeout | Total time to wait for the webhook API to become available | `60` |
+| postInstall.probeWebhook.httpTimeout | HTTP client timeout | `2` |
+| postInstall.probeWebhook.insecureHTTPS | Ignore server SSL certificate | `false` |
+| postInstall.probeWebhook.priorityClassName | Priority class name for gatekeeper-probe-webhook-post-install Job | `` |
+| postInstall.affinity | The affinity to use for pod scheduling in postInstall hook jobs | `{}` |
+| postInstall.tolerations | The tolerations to use for pod scheduling in postInstall hook jobs | `[]` |
+| postInstall.nodeSelector | The node selector to use for pod scheduling in postInstall hook jobs | `kubernetes.io/os: linux` |
+| postInstall.resources | The resource request/limits for the container image in postInstall hook jobs | `{}` |
+| postInstall.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| postUpgrade.labelNamespace.enabled | Add labels to the namespace during post upgrade hooks | `false` |
+| postUpgrade.labelNamespace.extraNamespaces | The extra namespaces that need to have the label during post upgrade hooks | `[]` |
+| postUpgrade.labelNamespace.extraAnnotations | Extra annotations added to the post upgrade Job | `{}` |
+| postUpgrade.labelNamespace.image.repository | Image with kubectl to label the namespace | `openpolicyagent/gatekeeper-crds` |
+| postUpgrade.labelNamespace.image.tag | Image tag | Current release version: `v3.14.0` |
+| postUpgrade.labelNamespace.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
+| postUpgrade.labelNamespace.image.pullSecrets | Image pullSecrets | `[]` |
+| postUpgrade.labelNamespace.priorityClassName | Priority class name for gatekeeper-update-namespace-label-post-upgrade Job | `` |
+| postUpgrade.affinity | The affinity to use for pod scheduling in postUpgrade hook jobs | `{}` |
+| postUpgrade.tolerations | The tolerations to use for pod scheduling in postUpgrade hook jobs | `[]` |
+| postUpgrade.nodeSelector | The node selector to use for pod scheduling in postUpgrade hook jobs | `kubernetes.io/os: linux` |
+| postUpgrade.resources | The resource request/limits for the container image in postUpgrade hook jobs | `{}` |
+| postUpgrade.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| preInstall.crdRepository.image.repository | Image with kubectl to update the CRDs. If not set, the `image.crdRepository` is used instead. | `null` |
+| preInstall.crdRepository.image.tag | Image tag | Current release version: `v3.14.0` |
+| preUninstall.deleteWebhookConfigurations.enabled | Delete webhooks before gatekeeper itself is uninstalled | `false` |
+| preUninstall.deleteWebhookConfigurations.image.repository | Image with kubectl to delete the webhooks | `openpolicyagent/gatekeeper-crds` |
+| preUninstall.deleteWebhookConfigurations.image.tag | Image tag | Current release version: `v3.14.0` |
+| preUninstall.deleteWebhookConfigurations.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
+| preUninstall.deleteWebhookConfigurations.image.pullSecrets | Image pullSecrets | `[]` |
+| preUninstall.deleteWebhookConfigurations.extraRules | Extra rules for the gatekeeper-delete-webhook-configs Role | `[]` |
+| preUninstall.deleteWebhookConfigurations.priorityClassName | Priority class name for gatekeeper-delete-webhook-configs Job | `` |
+| preUninstall.affinity | The affinity to use for pod scheduling in preUninstall hook jobs | `{}` |
+| preUninstall.tolerations | The tolerations to use for pod scheduling in preUninstall hook jobs | `[]` |
+| preUninstall.nodeSelector | The node selector to use for pod scheduling in preUninstall hook jobs | `kubernetes.io/os: linux` |
+| preUninstall.resources | The resource request/limits for the container image in preUninstall hook jobs | `{}` |
+| preUninstall.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| psp.enabled | Enabled PodSecurityPolicy | `true` |
+| upgradeCRDs.enabled | Upgrade CRDs using pre-install/pre-upgrade hooks | `true` |
+| upgradeCRDs.extraRules | Extra rules for the gatekeeper-admin-upgrade-crds ClusterRole | `[]` |
+| upgradeCRDs.priorityClassName | Priority class name for gatekeeper-update-crds-hook Job | `` |
+| crds.affinity | The affinity to use for pod scheduling in crds hook jobs | `{}` |
+| crds.tolerations | The tolerations to use for pod scheduling in crds hook jobs | `[]` |
+| crds.nodeSelector | The node selector to use for pod scheduling in crds hook jobs | `kubernetes.io/os: linux` |
+| crds.resources | The resource request/limits for the container image in crds hook jobs | `{}` |
+| crds.securityContext | Security context applied to the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 65532, "runAsNonRoot": true, "runAsUser": 65532 }` |
+| auditInterval | The frequency with which audit is run | `60` |
+| constraintViolationsLimit | The maximum # of audit violations reported on a constraint | `20` |
+| auditFromCache | Take the roster of resources to audit from the audit cache | `false` |
+| auditChunkSize | Chunk size for listing cluster resources for audit (alpha feature) | `500` |
+| auditMatchKindOnly | Only check resources of the kinds specified in all constraints defined in the cluster. | `false` |
+| disableValidatingWebhook | Disable the validating webhook | `false` |
+| disableMutation | Disable mutation | `false` |
+| validatingWebhookName | The name of the `ValidatingWebhookConfiguration` | `gatekeeper-validating-webhook-configuration` |
+| validatingWebhookTimeoutSeconds | The timeout for the validating webhook in seconds | `3` |
+| validatingWebhookFailurePolicy | The failurePolicy for the validating webhook | `Ignore` |
+| validatingWebhookAnnotations | The annotations to add to the ValidatingWebhookConfiguration | `{}` |
+| validatingWebhookObjectSelector | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's validation webhook unless measures are taken to control how exemption labels can be set. | `{}` |
+| validatingWebhookCheckIgnoreFailurePolicy | The failurePolicy for the check-ignore-label validating webhook | `Fail` |
+| validatingWebhookExemptNamespacesLabels | Additional namespace labels that will be exempt from the validating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace. | `{}` |
+| validatingWebhookCustomRules | Custom rules for selecting which API resources trigger the webhook. Mutually exclusive with `enableDeleteOperations`. NOTE: If you change this, ensure all your constraints are still being enforced. | `{}` |
+| validatingWebhookURL | Custom URL for Kubernetes API server to use to reach the validating webhook pod. If not set, the default of connecting via the kubernetes service endpoint is used. | `null` |
+| enableDeleteOperations | Enable validating webhook for delete operations. Does not work with `validatingWebhookCustomRules` | `false` |
+| enableExternalData | Enable external data | `true` |
+| enableGeneratorResourceExpansion | Enable generator resource expansion (beta feature) | `true` |
+| enableTLSHealthcheck | Enable probing webhook API with certificate stored in certDir | `false` |
+| maxServingThreads | Limit the number of concurrent calls the validation backend made by the validation webhook. -1 limits this value to GOMAXPROCS. Configuring this value may lower max RAM usage and limit CPU throttling, Tuning it can optimize serving capacity. | `-1` |
+| metricsBackends | Metrics exporters to use. Valid exporters are: `prometheus`, `stackdriver`, and `opencensus` | `["prometheus"]` |
+| mutatingWebhookName | The name of the `MutatingWebhookConfiguration` | `gatekeeper-mutating-webhook-configuration` |
+| mutatingWebhookFailurePolicy | The failurePolicy for the mutating webhook | `Ignore` |
+| mutatingWebhookReinvocationPolicy | The reinvocationPolicy for the mutating webhook | `Never` |
+| mutatingWebhookAnnotations | The annotations to add to the MutatingWebhookConfiguration | `{}` |
+| mutatingWebhookExemptNamespacesLabels | Additional namespace labels that will be exempt from the mutating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace. | `{}` |
+| mutatingWebhookObjectSelector | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's mutation webhook unless measures are taken to control how exemption labels can be set. | `{}` |
+| mutatingWebhookTimeoutSeconds | The timeout for the mutating webhook in seconds | `3` |
+| mutatingWebhookCustomRules | Custom rules for selecting which API resources trigger the webhook. NOTE: If you change this, ensure all your constraints are still being enforced. | `{}` |
+| mutatingWebhookURL | Custom URL for Kubernetes API server to use to reach the mutating webhook pod. If not set, the default of connecting via the kubernetes service endpoint is used. | `null` |
+| emitAdmissionEvents | Emit K8s events in configurable namespace for admission violations (alpha feature) | `false` |
+| emitAuditEvents | Emit K8s events in configurable namespace for audit violations (alpha feature) | `false` |
+| auditEventsInvolvedNamespace | Emit audit events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Audit events from cluster-scoped resources will continue to generate events in the namespace that Gatekeeper is installed in | `false` |
+| admissionEventsInvolvedNamespace | Emit admission events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Admission events from cluster-scoped resources will continue to generate events in the namespace that Gatekeeper is installed in | `false` |
+| logDenies | Log detailed info on each deny | `false` |
+| logLevel | Minimum log level | `INFO` |
+| image.pullPolicy | The image pull policy | `IfNotPresent` |
+| image.repository | Image repository | `openpolicyagent/gatekeeper` |
+| image.release | The image release tag to use | Current release version: `v3.14.0` |
+| image.pullSecrets | Specify an array of imagePullSecrets | `[]` |
+| resources | The resource request/limits for the container image | limits: 1 CPU, 512Mi, requests: 100mCPU, 256Mi |
+| nodeSelector | The node selector to use for pod scheduling | `kubernetes.io/os: linux` |
+| controllerManager.affinity | The node affinity to use for controller manager pod scheduling | `{}` |
+| controllerManager.topologySpreadConstraints | The topology spread constraints to use for controller manager pod scheduling | `[]` |
+| controllerManager.tolerations | The tolerations to use for controller manager pod scheduling | `[]` |
+| controllerManager.healthPort | Health port for controller manager | `9090` |
+| controllerManager.port | Webhook-server port for controller manager | `8443` |
+| controllerManager.metricsPort | Metrics port for controller manager | `8888` |
+| controllerManager.readinessTimeout | Timeout in seconds for the controller manager's readiness probe | `1` |
+| controllerManager.livenessTimeout | Timeout in seconds for the controller manager's liveness probe | `1` |
+| controllerManager.logLevel | The minimum log level for the controller manager, takes precedence over `logLevel` when specified | `null` |
+| controllerManager.priorityClassName | Priority class name for controller manager | `system-cluster-critical` |
+| controllerManager.podSecurityContext | Security context on pod level for controller manager | {fsGroup: 999, suplementalGroups: [999]} |
+| controllerManager.exemptNamespaces | The exact namespaces to exempt by the admission webhook | `[]` |
+| controllerManager.exemptNamespacePrefixes | The namespace prefixes to exempt by the admission webhook | `[]` |
+| controllerManager.hostNetwork | Enables controllerManager to be deployed on hostNetwork | `false` |
+| controllerManager.dnsPolicy | Set the dnsPolicy for controllerManager pods | `ClusterFirst` |
+| controllerManager.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| controllerManager.tlsMinVersion | Set the minimum supported TLS version for validating and mutating webhook servers | `1.3` |
+| controllerManager.extraRules | Extra rules for the gatekeeper-manager-role Role | `[]` |
+| controllerManager.networkPolicy.enabled | Should a network policy for the controller manager be created | `false` |
+| controllerManager.networkPolicy.ingress | Additional ingress rules to be added to the controller manager network policy | `{}` |
+| controllerManager.strategyType | The strategy type to use for Controller Manager deployment | `RollingUpdate` |
+| audit.affinity | The node affinity to use for audit pod scheduling | `{}` |
+| audit.topologySpreadConstraints | The topology spread constraints to use for audit pod scheduling | `[]` |
+| audit.tolerations | The tolerations to use for audit pod scheduling | `[]` |
+| audit.priorityClassName | Priority class name for audit controller | `system-cluster-critical` |
+| audit.podSecurityContext | Security context for audit on pod level | {fsGroup: 999, suplementalGroups: [999]} |
+| audit.hostNetwork | Enables audit to be deployed on hostNetwork | `false` |
+| audit.dnsPolicy | Set the dnsPolicy for audit pods | `ClusterFirst` |
+| audit.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| audit.healthPort | Health port for audit | `9090` |
+| audit.metricsPort | Metrics port for audit | `8888` |
+| audit.readinessTimeout | Timeout in seconds for audit's readiness probe | `1` |
+| audit.livenessTimeout | Timeout in seconds for the audit's liveness probe | `1` |
+| audit.logLevel | The minimum log level for audit, takes precedence over `logLevel` when specified | `null` |
+| replicas | The number of Gatekeeper replicas to deploy for the webhook | `3` |
+| podAnnotations | The annotations to add to the Gatekeeper pods | `container.seccomp.security.alpha.kubernetes.io/manager: runtime/default` |
+| podLabels | The labels to add to the Gatekeeper pods | `{}` |
+| podCountLimit | The maximum number of Gatekeeper pods to run | `100` |
+| secretAnnotations | The annotations to add to the Gatekeeper secrets | `{}` |
+| pdb.controllerManager.minAvailable | The number of controller manager pods that must still be available after an eviction | `1` |
+| service.type | Service type | `ClusterIP` |
+| service.loadBalancerIP | The IP address of LoadBalancer service | `` |
+| service.healthzPort | Service port to gatekeeper Webhook health port | `9090` |
+| rbac.create | Enable the creation of RBAC resources | `true` |
+| externalCertInjection.enabled | Enable the injection of an external certificate. This disables automatic certificate generation and rotation | `false` |
+| externalCertInjection.secretName | Name of secret for injected certificate | `gatekeeper-webhook-server-cert` |
+| externaldataProviderResponseCacheTTL | TTL for the external data provider response cache. Specify the duration in 'h', 'm', or 's' for hours, minutes, or seconds respectively. | `3m` |
## Contributing Changes
-Please refer to [Contributing to Helm Chart](https://open-policy-agent.github.io/gatekeeper/website/docs/help#contributing-to-helm-chart) for modifying the Helm chart.
+Please refer
+to [Contributing to Helm Chart](https://open-policy-agent.github.io/gatekeeper/website/docs/help#contributing-to-helm-chart)
+for modifying the Helm chart.
diff --git a/cmd/build/helmify/static/templates/_helpers.tpl b/cmd/build/helmify/static/templates/_helpers.tpl
index 5ab6fe2b456..785d9912656 100644
--- a/cmd/build/helmify/static/templates/_helpers.tpl
+++ b/cmd/build/helmify/static/templates/_helpers.tpl
@@ -36,10 +36,44 @@ Adds additional pod labels to the common ones
*/}}
{{- define "gatekeeper.podLabels" -}}
{{- if .Values.podLabels }}
-{{- toYaml .Values.podLabels | nindent 8 }}
+{{- toYaml .Values.podLabels }}
{{- end }}
{{- end -}}
+{{/*
+Mandatory labels
+*/}}
+{{- define "gatekeeper.mandatoryLabels" -}}
+app: {{ include "gatekeeper.name" . }}
+chart: {{ include "gatekeeper.name" . }}
+gatekeeper.sh/system: "yes"
+heritage: {{ .Release.Service }}
+release: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "gatekeeper.commonLabels" -}}
+helm.sh/chart: {{ include "gatekeeper.chart" . }}
+{{ include "gatekeeper.selectorLabels" . }}
+{{- if .Chart.Version }}
+app.kubernetes.io/version: {{ .Chart.Version | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- if .Values.commonLabels }}
+{{ toYaml .Values.commonLabels }}
+{{- end }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "gatekeeper.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "gatekeeper.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
{{/*
Output post install webhook probe container entry
*/}}
@@ -47,10 +81,12 @@ Output post install webhook probe container entry
- name: webhook-probe-post
image: "{{ .Values.postInstall.probeWebhook.image.repository }}:{{ .Values.postInstall.probeWebhook.image.tag }}"
imagePullPolicy: {{ .Values.postInstall.probeWebhook.image.pullPolicy }}
- args:
+ command:
- "curl"
+ args:
- "--retry"
- "99999"
+ - "--retry-connrefused"
- "--retry-max-time"
- "{{ .Values.postInstall.probeWebhook.waitTimeout }}"
- "--retry-delay"
diff --git a/cmd/build/helmify/static/templates/gatekeeper-admin-podsecuritypolicy.yaml b/cmd/build/helmify/static/templates/gatekeeper-admin-podsecuritypolicy.yaml
index 398b1460077..8c02264b024 100644
--- a/cmd/build/helmify/static/templates/gatekeeper-admin-podsecuritypolicy.yaml
+++ b/cmd/build/helmify/static/templates/gatekeeper-admin-podsecuritypolicy.yaml
@@ -5,11 +5,8 @@ metadata:
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
name: gatekeeper-admin
spec:
allowPrivilegeEscalation: false
diff --git a/cmd/build/helmify/static/templates/gatekeeper-controller-manager-network-policy.yaml b/cmd/build/helmify/static/templates/gatekeeper-controller-manager-network-policy.yaml
index e05213feb46..5ac3ca6c2c6 100644
--- a/cmd/build/helmify/static/templates/gatekeeper-controller-manager-network-policy.yaml
+++ b/cmd/build/helmify/static/templates/gatekeeper-controller-manager-network-policy.yaml
@@ -3,16 +3,15 @@ kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
name: gatekeeper-controller-manager
spec:
ingress:
- from:
- podSelector:
matchLabels:
+ {{- include "gatekeeper.commonLabels" . | nindent 14 }}
app: '{{ template "gatekeeper.name" . }}'
release: '{{ .Release.Name }}'
{{- with .Values.controllerManager.networkPolicy.ingress }}
@@ -20,11 +19,8 @@ spec:
{{- end }}
podSelector:
matchLabels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 6 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 6 }}
control-plane: controller-manager
gatekeeper.sh/operation: webhook
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
{{- end -}}
diff --git a/cmd/build/helmify/static/templates/namespace-post-install.yaml b/cmd/build/helmify/static/templates/namespace-post-install.yaml
index 4f84b52b409..41232de4267 100644
--- a/cmd/build/helmify/static/templates/namespace-post-install.yaml
+++ b/cmd/build/helmify/static/templates/namespace-post-install.yaml
@@ -3,12 +3,10 @@ apiVersion: batch/v1
kind: Job
metadata:
name: gatekeeper-update-namespace-label
+ namespace: {{ .Release.Namespace | quote }}
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install
"helm.sh/hook-weight": "-5"
@@ -22,14 +20,14 @@ spec:
annotations:
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
restartPolicy: OnFailure
+ {{- if .Values.postInstall.labelNamespace.priorityClassName }}
+ priorityClassName: {{ .Values.postInstall.labelNamespace.priorityClassName }}
+ {{- end }}
{{- if .Values.postInstall.labelNamespace.image.pullSecrets }}
imagePullSecrets:
{{- .Values.postInstall.labelNamespace.image.pullSecrets | toYaml | nindent 12 }}
@@ -96,7 +94,9 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: gatekeeper-update-namespace-label
+ namespace: {{ .Release.Namespace | quote }}
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -110,6 +110,7 @@ kind: ClusterRole
metadata:
name: gatekeeper-update-namespace-label
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -141,6 +142,7 @@ kind: ClusterRoleBinding
metadata:
name: gatekeeper-update-namespace-label
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
diff --git a/cmd/build/helmify/static/templates/namespace-post-upgrade.yaml b/cmd/build/helmify/static/templates/namespace-post-upgrade.yaml
index 43a1dadd9fa..b26abab34e0 100644
--- a/cmd/build/helmify/static/templates/namespace-post-upgrade.yaml
+++ b/cmd/build/helmify/static/templates/namespace-post-upgrade.yaml
@@ -3,12 +3,10 @@ apiVersion: batch/v1
kind: Job
metadata:
name: gatekeeper-update-namespace-label-post-upgrade
+ namespace: {{ .Release.Namespace | quote }}
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-upgrade
"helm.sh/hook-weight": "-5"
@@ -20,12 +18,9 @@ spec:
template:
metadata:
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
restartPolicy: OnFailure
{{- if .Values.postUpgrade.labelNamespace.image.pullSecrets }}
@@ -33,6 +28,9 @@ spec:
{{- .Values.postUpgrade.labelNamespace.image.pullSecrets | toYaml | nindent 12 }}
{{- end }}
serviceAccount: gatekeeper-update-namespace-label-post-upgrade
+ {{- if .Values.postUpgrade.labelNamespace.priorityClassName }}
+ priorityClassName: {{ .Values.postUpgrade.labelNamespace.priorityClassName }}
+ {{- end }}
containers:
- name: kubectl-label
image: "{{ .Values.postUpgrade.labelNamespace.image.repository }}:{{ .Values.postUpgrade.labelNamespace.image.tag }}"
@@ -89,6 +87,7 @@ kind: ServiceAccount
metadata:
name: gatekeeper-update-namespace-label-post-upgrade
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -102,6 +101,7 @@ kind: ClusterRole
metadata:
name: gatekeeper-update-namespace-label-post-upgrade
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -130,6 +130,7 @@ kind: ClusterRoleBinding
metadata:
name: gatekeeper-update-namespace-label-post-upgrade
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
diff --git a/cmd/build/helmify/static/templates/probe-webhook-post-install.yaml b/cmd/build/helmify/static/templates/probe-webhook-post-install.yaml
index 5a140d31ce0..e6ef25b594c 100644
--- a/cmd/build/helmify/static/templates/probe-webhook-post-install.yaml
+++ b/cmd/build/helmify/static/templates/probe-webhook-post-install.yaml
@@ -5,11 +5,8 @@ kind: Job
metadata:
name: gatekeeper-probe-webhook-post-install
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install
"helm.sh/hook-weight": "-5"
@@ -20,14 +17,14 @@ spec:
annotations:
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
restartPolicy: Never
+ {{- if .Values.postInstall.probeWebhook.priorityClassName }}
+ priorityClassName: {{ .Values.postInstall.probeWebhook.priorityClassName }}
+ {{- end }}
{{- if .Values.postInstall.probeWebhook.image.pullSecrets }}
imagePullSecrets:
{{- .Values.postInstall.probeWebhook.image.pullSecrets | toYaml | nindent 12 }}
@@ -44,5 +41,6 @@ spec:
nodeSelector:
{{- toYaml .nodeSelector | nindent 8 }}
{{- end }}
+ backoffLimit: 3
{{- end }}
{{- end }}
diff --git a/cmd/build/helmify/static/templates/upgrade-crds-hook.yaml b/cmd/build/helmify/static/templates/upgrade-crds-hook.yaml
index cd57573f37a..f9347ad9c7b 100644
--- a/cmd/build/helmify/static/templates/upgrade-crds-hook.yaml
+++ b/cmd/build/helmify/static/templates/upgrade-crds-hook.yaml
@@ -5,6 +5,7 @@ kind: ClusterRole
metadata:
name: gatekeeper-admin-upgrade-crds
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -26,6 +27,7 @@ kind: ClusterRoleBinding
metadata:
name: gatekeeper-admin-upgrade-crds
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -46,6 +48,7 @@ apiVersion: v1
kind: ServiceAccount
metadata:
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
name: gatekeeper-admin-upgrade-crds
@@ -61,29 +64,23 @@ metadata:
name: gatekeeper-update-crds-hook
namespace: {{ .Release.Namespace }}
labels:
- app: {{ template "gatekeeper.name" . }}
- chart: {{ template "gatekeeper.name" . }}
- gatekeeper.sh/system: "yes"
- heritage: {{ .Release.Service }}
- release: {{ .Release.Name }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-weight: "1"
helm.sh/hook-delete-policy: "hook-succeeded,before-hook-creation"
spec:
- backoffLimit: 0
+ backoffLimit: 3
template:
metadata:
name: gatekeeper-update-crds-hook
annotations:
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
serviceAccountName: gatekeeper-admin-upgrade-crds
restartPolicy: Never
@@ -91,12 +88,23 @@ spec:
imagePullSecrets:
{{- toYaml .Values.image.pullSecrets | nindent 8 }}
{{- end }}
+ {{- if .Values.upgradeCRDs.priorityClassName }}
+ priorityClassName: {{ .Values.upgradeCRDs.priorityClassName }}
+ {{- end }}
containers:
- name: crds-upgrade
- {{- if not .Values.image.release }}
- image: '{{ .Values.image.crdRepository }}'
+ {{- if .Values.preInstall.crdRepository.image.repository }}
+ {{- if not .Values.preInstall.crdRepository.image.tag }}
+ image: '{{ .Values.preInstall.crdRepository.image.repository }}'
+ {{- else }}
+ image: '{{ .Values.preInstall.crdRepository.image.repository }}:{{ .Values.preInstall.crdRepository.image.tag }}'
+ {{- end }}
{{- else }}
+ {{- if not .Values.image.release }}
+ image: '{{ .Values.image.crdRepository }}'
+ {{- else }}
image: '{{ .Values.image.crdRepository }}:{{ .Values.image.release }}'
+ {{- end }}
{{- end }}
imagePullPolicy: '{{ .Values.image.pullPolicy }}'
args:
diff --git a/cmd/build/helmify/static/templates/webhook-configs-pre-delete.yaml b/cmd/build/helmify/static/templates/webhook-configs-pre-delete.yaml
index d610394de36..fb359b87e16 100644
--- a/cmd/build/helmify/static/templates/webhook-configs-pre-delete.yaml
+++ b/cmd/build/helmify/static/templates/webhook-configs-pre-delete.yaml
@@ -3,12 +3,10 @@ apiVersion: batch/v1
kind: Job
metadata:
name: gatekeeper-delete-webhook-configs
+ namespace: {{ .Release.Namespace | quote }}
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-5"
@@ -19,12 +17,9 @@ spec:
annotations:
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
restartPolicy: OnFailure
{{- if .Values.preUninstall.deleteWebhookConfigurations.image.pullSecrets }}
@@ -32,6 +27,9 @@ spec:
{{- .Values.preUninstall.deleteWebhookConfigurations.image.pullSecrets | toYaml | nindent 12 }}
{{- end }}
serviceAccount: gatekeeper-delete-webhook-configs
+ {{- if .Values.preUninstall.deleteWebhookConfigurations.priorityClassName }}
+ priorityClassName: {{ .Values.preUninstall.deleteWebhookConfigurations.priorityClassName }}
+ {{- end }}
containers:
- name: kubectl-delete
image: "{{ .Values.preUninstall.deleteWebhookConfigurations.image.repository }}:{{ .Values.preUninstall.deleteWebhookConfigurations.image.tag }}"
@@ -39,19 +37,19 @@ spec:
args:
- delete
{{- if not .Values.disableValidatingWebhook }}
- - validatingwebhookconfiguration/gatekeeper-validating-webhook-configuration
+ - validatingwebhookconfiguration/{{ .Values.validatingWebhookName }}
{{- end }}
{{- if not .Values.disableMutation }}
- - mutatingwebhookconfiguration/gatekeeper-mutating-webhook-configuration
+ - mutatingwebhookconfiguration/{{ .Values.mutatingWebhookName }}
{{- end }}
resources:
- {{- toYaml .Values.preUninstall.resources | nindent 10 }}
+ {{- toYaml .Values.preUninstall.resources | nindent 12 }}
securityContext:
{{- if .Values.enableRuntimeDefaultSeccompProfile }}
seccompProfile:
type: RuntimeDefault
{{- end }}
- {{- toYaml .Values.preUninstall.securityContext | nindent 10 }}
+ {{- toYaml .Values.preUninstall.securityContext | nindent 12 }}
{{- with .Values.preUninstall }}
nodeSelector:
{{- toYaml .nodeSelector | nindent 8 }}
@@ -65,7 +63,9 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: gatekeeper-delete-webhook-configs
+ namespace: {{ .Release.Namespace | quote }}
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -79,6 +79,7 @@ kind: ClusterRole
metadata:
name: gatekeeper-delete-webhook-configs
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -92,7 +93,7 @@ rules:
resources:
- validatingwebhookconfigurations
resourceNames:
- - gatekeeper-validating-webhook-configuration
+ - {{ .Values.validatingWebhookName }}
verbs:
- delete
{{- end }}
@@ -102,7 +103,7 @@ rules:
resources:
- mutatingwebhookconfigurations
resourceNames:
- - gatekeeper-mutating-webhook-configuration
+ - {{ .Values.mutatingWebhookName }}
verbs:
- delete
{{- end }}
@@ -117,6 +118,7 @@ kind: ClusterRoleBinding
metadata:
name: gatekeeper-delete-webhook-configs
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
diff --git a/cmd/build/helmify/static/values.yaml b/cmd/build/helmify/static/values.yaml
index 364f5ed4794..2e4c3a8666f 100644
--- a/cmd/build/helmify/static/values.yaml
+++ b/cmd/build/helmify/static/values.yaml
@@ -1,4 +1,5 @@
replicas: 3
+revisionHistoryLimit: 10
auditInterval: 60
metricsBackends: ["prometheus"]
auditMatchKindOnly: false
@@ -6,6 +7,7 @@ constraintViolationsLimit: 20
auditFromCache: false
disableMutation: false
disableValidatingWebhook: false
+validatingWebhookName: gatekeeper-validating-webhook-configuration
validatingWebhookTimeoutSeconds: 3
validatingWebhookFailurePolicy: Ignore
validatingWebhookAnnotations: {}
@@ -13,11 +15,13 @@ validatingWebhookExemptNamespacesLabels: {}
validatingWebhookObjectSelector: {}
validatingWebhookCheckIgnoreFailurePolicy: Fail
validatingWebhookCustomRules: {}
+validatingWebhookURL: null
enableDeleteOperations: false
enableExternalData: true
-enableGeneratorResourceExpansion: false
+enableGeneratorResourceExpansion: true
enableTLSHealthcheck: false
maxServingThreads: -1
+mutatingWebhookName: gatekeeper-mutating-webhook-configuration
mutatingWebhookFailurePolicy: Ignore
mutatingWebhookReinvocationPolicy: Never
mutatingWebhookAnnotations: {}
@@ -25,6 +29,7 @@ mutatingWebhookExemptNamespacesLabels: {}
mutatingWebhookObjectSelector: {}
mutatingWebhookTimeoutSeconds: 1
mutatingWebhookCustomRules: {}
+mutatingWebhookURL: null
mutationAnnotations: false
auditChunkSize: 500
logLevel: INFO
@@ -32,13 +37,27 @@ logDenies: false
logMutations: false
emitAdmissionEvents: false
emitAuditEvents: false
+admissionEventsInvolvedNamespace: false
+auditEventsInvolvedNamespace: false
resourceQuota: true
+externaldataProviderResponseCacheTTL: 3m
+image:
+ repository: openpolicyagent/gatekeeper
+ crdRepository: openpolicyagent/gatekeeper-crds
+ release: v3.14.0
+ pullPolicy: IfNotPresent
+ pullSecrets: []
+preInstall:
+ crdRepository:
+ image:
+ repository: null
+ tag: v3.14.0
postUpgrade:
labelNamespace:
enabled: false
image:
repository: openpolicyagent/gatekeeper-crds
- tag: v3.12.0-beta.0
+ tag: v3.14.0
pullPolicy: IfNotPresent
pullSecrets: []
extraNamespaces: []
@@ -49,6 +68,7 @@ postUpgrade:
"pod-security.kubernetes.io/enforce=restricted",
"pod-security.kubernetes.io/enforce-version=v1.24"]
extraAnnotations: {}
+ priorityClassName: ""
affinity: {}
tolerations: []
nodeSelector: {kubernetes.io/os: linux}
@@ -68,7 +88,7 @@ postInstall:
extraRules: []
image:
repository: openpolicyagent/gatekeeper-crds
- tag: v3.12.0-beta.0
+ tag: v3.14.0
pullPolicy: IfNotPresent
pullSecrets: []
extraNamespaces: []
@@ -79,6 +99,7 @@ postInstall:
"pod-security.kubernetes.io/enforce=restricted",
"pod-security.kubernetes.io/enforce-version=v1.24"]
extraAnnotations: {}
+ priorityClassName: ""
probeWebhook:
enabled: true
image:
@@ -89,6 +110,7 @@ postInstall:
waitTimeout: 60
httpTimeout: 2
insecureHTTPS: false
+ priorityClassName: ""
affinity: {}
tolerations: []
nodeSelector: {kubernetes.io/os: linux}
@@ -107,9 +129,10 @@ preUninstall:
enabled: false
image:
repository: openpolicyagent/gatekeeper-crds
- tag: v3.12.0-beta.0
+ tag: v3.14.0
pullPolicy: IfNotPresent
pullSecrets: []
+ priorityClassName: ""
affinity: {}
tolerations: []
nodeSelector: {kubernetes.io/os: linux}
@@ -123,13 +146,8 @@ preUninstall:
runAsGroup: 999
runAsNonRoot: true
runAsUser: 1000
-image:
- repository: openpolicyagent/gatekeeper
- crdRepository: openpolicyagent/gatekeeper-crds
- release: v3.12.0-beta.0
- pullPolicy: IfNotPresent
- pullSecrets: []
podAnnotations: {}
+auditPodAnnotations: {}
podLabels: {}
podCountLimit: "100"
secretAnnotations: {}
@@ -146,8 +164,9 @@ controllerManager:
livenessTimeout: 1
priorityClassName: system-cluster-critical
disableCertRotation: false
- tlsMinVersion: 1.3
+ tlsMinVersion: 1.2
clientCertName: ""
+ strategyType: RollingUpdate
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
@@ -190,6 +209,7 @@ controllerManager:
# - ipBlock:
# cidr: 0.0.0.0/0
audit:
+ enablePubsub: false
hostNetwork: false
dnsPolicy: ClusterFirst
metricsPort: 8888
@@ -197,7 +217,7 @@ audit:
readinessTimeout: 1
livenessTimeout: 1
priorityClassName: system-cluster-critical
- disableCertRotation: true
+ disableCertRotation: false
affinity: {}
tolerations: []
nodeSelector: {kubernetes.io/os: linux}
@@ -246,6 +266,7 @@ psp:
upgradeCRDs:
enabled: true
extraRules: []
+ priorityClassName: ""
rbac:
create: true
externalCertInjection:
diff --git a/cmd/gator/expand/expand.go b/cmd/gator/expand/expand.go
index 502abe0759e..feab47aa116 100644
--- a/cmd/gator/expand/expand.go
+++ b/cmd/gator/expand/expand.go
@@ -7,28 +7,26 @@ import (
"os"
"sort"
- "github.com/open-policy-agent/gatekeeper/pkg/gator/expand"
- "github.com/open-policy-agent/gatekeeper/pkg/gator/reader"
+ "github.com/open-policy-agent/gatekeeper/v3/cmd/gator/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/expand"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/reader"
"github.com/spf13/cobra"
-
- // yaml.v3 inserts a space before '-', which is inconsistent with standard
- // kubernetes and kubebuilder format. yaml.v2 does not insert these spaces.
- "gopkg.in/yaml.v2"
+ "gopkg.in/yaml.v2" // yaml.v3 inserts a space before '-', which is inconsistent with standard, kubernetes and kubebuilder format. yaml.v2 does not insert these spaces.
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
const (
- examples = ` # expand resources in a manifest
- gator expand --filename="manifest.yaml"
+ examples = `# expand resources in a manifest
+gator expand --filename="manifest.yaml"
- # expand a directory
- gator expand --filename="config-and-policies/"
+# expand a directory
+gator expand --filename="config-and-policies/"
- # Use multiple inputs
- gator expand --filename="manifest.yaml" --filename="templates-and-constraints/"
+# Use multiple inputs
+gator expand --filename="manifest.yaml" --filename="templates-and-constraints/"
- # Output JSON to file
- gator expand --filename="manifest.yaml" --format=json --outputfile=results.yaml `
+# Output JSON to file
+gator expand --filename="manifest.yaml" --format=json --outputfile=results.yaml`
)
var Cmd = &cobra.Command{
@@ -71,15 +69,15 @@ func init() {
func run(cmd *cobra.Command, args []string) {
unstrucs, err := reader.ReadSources(flagFilenames, flagImages, flagTempDir)
if err != nil {
- errFatalf("reading: %v\n", err)
+ util.ErrFatalf("reading: %v", err)
}
if len(unstrucs) == 0 {
- errFatalf("no input data identified\n")
+ util.ErrFatalf("no input data identified")
}
resultants, err := expand.Expand(unstrucs)
if err != nil {
- errFatalf("error expanding resources: %v", err)
+ util.ErrFatalf("error expanding resources: %v", err)
}
// Sort resultants for deterministic output
sortUnstructs(resultants)
@@ -89,7 +87,7 @@ func run(cmd *cobra.Command, args []string) {
fmt.Println(output)
} else {
fmt.Printf("Writing output to file: %s\n", flagOutput)
- stringToFile(output, flagOutput)
+ util.WriteToFile(output, flagOutput)
}
os.Exit(0)
@@ -98,19 +96,19 @@ func run(cmd *cobra.Command, args []string) {
func resourcetoYAMLString(resource *unstructured.Unstructured) string {
jsonb, err := json.Marshal(resource)
if err != nil {
- errFatalf("pre-marshaling results to json: %v", err)
+ util.ErrFatalf("pre-marshaling results to json: %v", err)
}
unmarshalled := map[string]interface{}{}
err = json.Unmarshal(jsonb, &unmarshalled)
if err != nil {
- errFatalf("pre-unmarshaling results from json: %v", err)
+ util.ErrFatalf("pre-unmarshaling results from json: %v", err)
}
var b bytes.Buffer
yamlEncoder := yaml.NewEncoder(&b)
if err := yamlEncoder.Encode(unmarshalled); err != nil {
- errFatalf("marshaling validation yaml results: %v", err)
+ util.ErrFatalf("marshaling validation yaml results: %v", err)
}
return b.String()
}
@@ -118,7 +116,7 @@ func resourcetoYAMLString(resource *unstructured.Unstructured) string {
func resourceToJSONString(resource *unstructured.Unstructured) string {
b, err := json.MarshalIndent(resource, "", " ")
if err != nil {
- errFatalf("marshaling validation json results: %v", err)
+ util.ErrFatalf("marshaling validation json results: %v", err)
}
return string(b)
}
@@ -131,7 +129,7 @@ func resourcesToString(resources []*unstructured.Unstructured, format string) st
case stringJSON:
conversionFunc = resourceToJSONString
default:
- errFatalf("unrecognized value for %s flag: %s", flagNameFormat, format)
+ util.ErrFatalf("unrecognized value for %s flag: %s", flagNameFormat, format)
}
output := ""
@@ -144,17 +142,6 @@ func resourcesToString(resources []*unstructured.Unstructured, format string) st
return output
}
-func stringToFile(s string, path string) {
- file, err := os.Create(path)
- if err != nil {
- errFatalf("error creating file at path %s: %v", path, err)
- }
-
- if _, err = fmt.Fprint(file, s); err != nil {
- errFatalf("error writing to file at path %s: %s", path, err)
- }
-}
-
func sortUnstructs(objs []*unstructured.Unstructured) {
sortKey := func(o *unstructured.Unstructured) string {
return o.GetName() + o.GetAPIVersion() + o.GetKind()
@@ -163,8 +150,3 @@ func sortUnstructs(objs []*unstructured.Unstructured) {
return sortKey(objs[i]) > sortKey(objs[j])
})
}
-
-func errFatalf(format string, a ...interface{}) {
- fmt.Fprintf(os.Stderr, format+"\n", a...)
- os.Exit(1)
-}
diff --git a/cmd/gator/gator.go b/cmd/gator/gator.go
index 079727820e0..be611a9713c 100644
--- a/cmd/gator/gator.go
+++ b/cmd/gator/gator.go
@@ -1,41 +1,31 @@
package main
import (
- "fmt"
"os"
- "github.com/open-policy-agent/gatekeeper/cmd/gator/expand"
- "github.com/open-policy-agent/gatekeeper/cmd/gator/test"
- "github.com/open-policy-agent/gatekeeper/cmd/gator/verify"
- "github.com/open-policy-agent/gatekeeper/pkg/version"
+ "github.com/open-policy-agent/gatekeeper/v3/cmd/gator/expand"
+ "github.com/open-policy-agent/gatekeeper/v3/cmd/gator/test"
+ "github.com/open-policy-agent/gatekeeper/v3/cmd/gator/verify"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/version"
"github.com/spf13/cobra"
-)
-
-const state = "beta"
-
-var (
- frameworksVersion string
-
- opaVersion string
+ k8sVersion "sigs.k8s.io/release-utils/version"
)
var commands = []*cobra.Command{
verify.Cmd,
test.Cmd,
expand.Cmd,
+ k8sVersion.WithFont("alligator2"),
}
func init() {
rootCmd.AddCommand(commands...)
+ rootCmd.Version = version.GetUserAgent("gator")
}
var rootCmd = &cobra.Command{
- Use: "gator subcommand",
- Short: "gator is a suite of authorship tools for Gatekeeper",
- Version: fmt.Sprintf("\nGator version: %s (Feature State: %s), OPA version: %s, Framework version: %s", version.Version, state, opaVersion, frameworksVersion),
- RunE: func(cmd *cobra.Command, args []string) error {
- return nil
- },
+ Use: "gator subcommand",
+ Short: "gator is a suite of authorship tools for Gatekeeper",
}
func main() {
diff --git a/cmd/gator/test/gatortest_test.go b/cmd/gator/test/gatortest_test.go
index d56b4531236..f2e573f1293 100644
--- a/cmd/gator/test/gatortest_test.go
+++ b/cmd/gator/test/gatortest_test.go
@@ -5,7 +5,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/open-policy-agent/frameworks/constraint/pkg/types"
- "github.com/open-policy-agent/gatekeeper/pkg/gator/test"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/test"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@@ -41,7 +41,7 @@ func Test_formatOutput(t *testing.T) {
ViolatingObject: barObject,
Trace: nil,
}},
- expectedOutput: `[""] Message: ""
+ expectedOutput: `/ : [""] Message: ""
`,
},
{
@@ -60,7 +60,6 @@ func Test_formatOutput(t *testing.T) {
object:
kind: kind
enforcementaction: ""
- evaluationmeta: null
violatingObject:
bar: xyz
trace: xyz
@@ -90,7 +89,7 @@ func Test_formatOutput(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- output := formatOutput(tc.inputFormat, tc.input)
+ output := formatOutput(tc.inputFormat, tc.input, nil)
if diff := cmp.Diff(tc.expectedOutput, output); diff != "" {
t.Fatal(diff)
}
diff --git a/cmd/gator/test/test.go b/cmd/gator/test/test.go
index 87dc4f769e4..6f3aae26954 100644
--- a/cmd/gator/test/test.go
+++ b/cmd/gator/test/test.go
@@ -7,32 +7,34 @@ import (
"os"
"strings"
- "github.com/open-policy-agent/gatekeeper/pkg/gator/reader"
- "github.com/open-policy-agent/gatekeeper/pkg/gator/test"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/instrumentation"
+ cmdutils "github.com/open-policy-agent/gatekeeper/v3/cmd/gator/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/reader"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/test"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)
const (
- examples = ` # test a manifest containing Kubernetes objects, Constraint Templates, and Constraints
- gator test --filename="manifest.yaml"
+ examples = `# test a manifest containing Kubernetes objects, Constraint Templates, and Constraints
+gator test --filename="manifest.yaml"
- # test a directory
- gator test --filename="config-and-policies/"
+# test a directory
+gator test --filename="config-and-policies/"
- # Use multiple inputs
- gator test --filename="manifest.yaml" --filename="templates-and-constraints/"
+# Use multiple inputs
+gator test --filename="manifest.yaml" --filename="templates-and-constraints/"
- # Receive input from stdin
- cat manifest.yaml | gator test
+# Receive input from stdin
+cat manifest.yaml | gator test
- # Output structured violations data
- gator test --filename="manifest.yaml" --output=json
+# Output structured violations data
+gator test --filename="manifest.yaml" --output=json
- Note: The alpha "gator test" has been renamed to "gator verify". "gator
- verify" verifies individual Constraint Templates against suites of tests, where "gator
- test" evaluates sets of resources against sets of Constraints and Templates.`
+Note: The alpha "gator test" has been renamed to "gator verify". "gator
+verify" verifies individual Constraint Templates against suites of tests, where "gator
+test" evaluates sets of resources against sets of Constraints and Templates.`
)
var Cmd = &cobra.Command{
@@ -47,8 +49,10 @@ var (
flagFilenames []string
flagOutput string
flagIncludeTrace bool
+ flagGatherStats bool
flagImages []string
flagTempDir string
+ flagEnableK8sCel bool
)
const (
@@ -60,12 +64,16 @@ const (
stringJSON = "json"
stringYAML = "yaml"
stringHumanFriendly = "default"
+
+ fourSpaceTab = " "
)
func init() {
Cmd.Flags().StringArrayVarP(&flagFilenames, flagNameFilename, "f", []string{}, "a file or directory containing Kubernetes resources. Can be specified multiple times.")
Cmd.Flags().StringVarP(&flagOutput, flagNameOutput, "o", "", fmt.Sprintf("Output format. One of: %s|%s.", stringJSON, stringYAML))
- Cmd.Flags().BoolVarP(&flagIncludeTrace, "trace", "t", false, `include a trace for the underlying constraint framework evaluation`)
+ Cmd.Flags().BoolVarP(&flagIncludeTrace, "trace", "t", false, "include a trace for the underlying Constraint Framework evaluation.")
+ Cmd.Flags().BoolVarP(&flagGatherStats, "stats", "", false, "include performance stats returned from the Constraint Framework.")
+ Cmd.Flags().BoolVarP(&flagEnableK8sCel, "experimental-enable-k8s-native-validation", "", false, "PROTOTYPE (not stable): enable the validating admission policy driver")
Cmd.Flags().StringArrayVarP(&flagImages, flagNameImage, "i", []string{}, "a URL to an OCI image containing policies. Can be specified multiple times.")
Cmd.Flags().StringVarP(&flagTempDir, flagNameTempDir, "d", "", fmt.Sprintf("Specifies the temporary directory to download and unpack images to, if using the --%s flag. Optional.", flagNameImage))
}
@@ -73,19 +81,19 @@ func init() {
func run(cmd *cobra.Command, args []string) {
unstrucs, err := reader.ReadSources(flagFilenames, flagImages, flagTempDir)
if err != nil {
- errFatalf("reading: %v", err)
+ cmdutils.ErrFatalf("reading: %v", err)
}
if len(unstrucs) == 0 {
- errFatalf("no input data identified")
+ cmdutils.ErrFatalf("no input data identified")
}
- responses, err := test.Test(unstrucs, flagIncludeTrace)
+ responses, err := test.Test(unstrucs, test.Opts{IncludeTrace: flagIncludeTrace, GatherStats: flagGatherStats, UseK8sCEL: flagEnableK8sCel})
if err != nil {
- errFatalf("auditing objects: %v\n", err)
+ cmdutils.ErrFatalf("auditing objects: %v", err)
}
results := responses.Results()
- fmt.Print(formatOutput(flagOutput, results))
+ fmt.Print(formatOutput(flagOutput, results, responses.StatsEntries))
// Whether or not we return non-zero depends on whether we have a `deny`
// enforcementAction on one of the violated constraints
@@ -96,38 +104,94 @@ func run(cmd *cobra.Command, args []string) {
os.Exit(exitCode)
}
-func formatOutput(flagOutput string, results []*test.GatorResult) string {
+func formatOutput(flagOutput string, results []*test.GatorResult, stats []*instrumentation.StatsEntry) string {
switch strings.ToLower(flagOutput) {
case stringJSON:
- b, err := json.MarshalIndent(results, "", " ")
- if err != nil {
- errFatalf("marshaling validation json results: %v", err)
+ var jsonB []byte
+ var err error
+
+ if stats != nil {
+ statsAndResults := map[string]interface{}{"results": results, "stats": stats}
+ jsonB, err = json.MarshalIndent(statsAndResults, "", fourSpaceTab)
+ if err != nil {
+ cmdutils.ErrFatalf("marshaling validation json results and stats: %v", err)
+ }
+ } else {
+ jsonB, err = json.MarshalIndent(results, "", fourSpaceTab)
+ if err != nil {
+ cmdutils.ErrFatalf("marshaling validation json results: %v", err)
+ }
}
- return string(b)
+
+ return string(jsonB)
case stringYAML:
yamlResults := test.GetYamlFriendlyResults(results)
- jsonb, err := json.Marshal(yamlResults)
- if err != nil {
- errFatalf("pre-marshaling results to json: %v", err)
- }
+ var yamlb []byte
- unmarshalled := []*test.YamlGatorResult{}
- err = json.Unmarshal(jsonb, &unmarshalled)
- if err != nil {
- errFatalf("pre-unmarshaling results from json: %v", err)
- }
+ if stats != nil {
+ statsAndResults := map[string]interface{}{"results": yamlResults, "stats": stats}
+
+ statsJSONB, err := json.Marshal(statsAndResults)
+ if err != nil {
+ cmdutils.ErrFatalf("pre-marshaling stats to json: %v", err)
+ }
+
+ statsAndResultsUnmarshalled := struct {
+ Results []*test.YamlGatorResult
+ Stats []*instrumentation.StatsEntry
+ }{}
+
+ err = json.Unmarshal(statsJSONB, &statsAndResultsUnmarshalled)
+ if err != nil {
+ cmdutils.ErrFatalf("pre-unmarshaling stats from json: %v", err)
+ }
- yamlb, err := yaml.Marshal(unmarshalled)
- if err != nil {
- errFatalf("marshaling validation yaml results: %v", err)
+ yamlb, err = yaml.Marshal(statsAndResultsUnmarshalled)
+ if err != nil {
+ cmdutils.ErrFatalf("marshaling validation yaml results and stats: %v", err)
+ }
+ } else {
+ jsonb, err := json.Marshal(yamlResults)
+ if err != nil {
+ cmdutils.ErrFatalf("pre-marshaling results to json: %v", err)
+ }
+
+ unmarshalled := []*test.YamlGatorResult{}
+ err = json.Unmarshal(jsonb, &unmarshalled)
+ if err != nil {
+ cmdutils.ErrFatalf("pre-unmarshaling results from json: %v", err)
+ }
+
+ yamlb, err = yaml.Marshal(unmarshalled)
+ if err != nil {
+ cmdutils.ErrFatalf("marshaling validation yaml results: %v", err)
+ }
}
+
return string(yamlb)
case stringHumanFriendly:
default:
var buf bytes.Buffer
if len(results) > 0 {
for _, result := range results {
- buf.WriteString(fmt.Sprintf("[%q] Message: %q \n", result.Constraint.GetName(), result.Msg))
+ obj := fmt.Sprintf("%s/%s %s",
+ result.ViolatingObject.GetAPIVersion(),
+ result.ViolatingObject.GetKind(),
+ result.ViolatingObject.GetName(),
+ )
+ if result.ViolatingObject.GetNamespace() != "" {
+ obj = fmt.Sprintf("%s/%s %s/%s",
+ result.ViolatingObject.GetAPIVersion(),
+ result.ViolatingObject.GetKind(),
+ result.ViolatingObject.GetNamespace(),
+ result.ViolatingObject.GetName(),
+ )
+ }
+ buf.WriteString(fmt.Sprintf("%s: [%q] Message: %q\n",
+ obj,
+ result.Constraint.GetName(),
+ result.Msg,
+ ))
if result.Trace != nil {
buf.WriteString(fmt.Sprintf("Trace: %v", *result.Trace))
@@ -149,8 +213,3 @@ func enforceableFailure(results []*test.GatorResult) bool {
return false
}
-
-func errFatalf(format string, a ...interface{}) {
- fmt.Fprintf(os.Stderr, format, a...)
- os.Exit(1)
-}
diff --git a/cmd/gator/util/util.go b/cmd/gator/util/util.go
new file mode 100644
index 00000000000..a87ab72f978
--- /dev/null
+++ b/cmd/gator/util/util.go
@@ -0,0 +1,22 @@
+package util
+
+import (
+ "fmt"
+ "os"
+)
+
+func ErrFatalf(format string, a ...interface{}) {
+ fmt.Fprintf(os.Stderr, format+"\n", a...)
+ os.Exit(1)
+}
+
+func WriteToFile(s string, path string) {
+ file, err := os.Create(path)
+ if err != nil {
+ ErrFatalf("error creating file at path %s: %v", path, err)
+ }
+
+ if _, err = fmt.Fprint(file, s); err != nil {
+ ErrFatalf("error writing to file at path %s: %s", path, err)
+ }
+}
diff --git a/cmd/gator/verify/verify.go b/cmd/gator/verify/verify.go
index 3b4ab49b39d..74c4b243911 100644
--- a/cmd/gator/verify/verify.go
+++ b/cmd/gator/verify/verify.go
@@ -10,33 +10,34 @@ import (
"runtime"
"strings"
- "github.com/open-policy-agent/gatekeeper/pkg/gator"
- "github.com/open-policy-agent/gatekeeper/pkg/gator/verify"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/verify"
"github.com/spf13/cobra"
)
const (
- examples = ` # Run all tests in label-tests.yaml
- gator verify label-tests.yaml
+ examples = `# Run all tests in label-tests.yaml
+gator verify label-tests.yaml
- # Run all tests whose names contain "forbid-labels".
- gator verify tests/... --run forbid-labels//
+# Run all tests whose names contain "forbid-labels".
+gator verify tests/... --run forbid-labels//
- # Run all cases whose names contain "nginx-deployment".
- gator verify tests/... --run //nginx-deployment
+# Run all cases whose names contain "nginx-deployment".
+gator verify tests/... --run //nginx-deployment
- # Run all cases whose names exactly match "nginx-deployment".
- gator verify tests/... --run '//^nginx-deployment$'
+# Run all cases whose names exactly match "nginx-deployment".
+gator verify tests/... --run '//^nginx-deployment$'
- # Run all cases that are either named "forbid-labels" or are
- # in tests named "forbid-labels".
- gator verify tests/... --run '^forbid-labels$'`
+# Run all cases that are either named "forbid-labels" or are
+# in tests named "forbid-labels".
+gator verify tests/... --run '^forbid-labels$'`
)
var (
- run string
- verbose bool
- includeTrace bool
+ run string
+ verbose bool
+ includeTrace bool
+ flagEnableK8sCel bool
)
func init() {
@@ -46,6 +47,8 @@ func init() {
`print extended test output`)
Cmd.Flags().BoolVarP(&includeTrace, "trace", "t", false,
`include a trace for the underlying constraint framework evaluation`)
+ Cmd.Flags().BoolVarP(&flagEnableK8sCel, "experimental-enable-k8s-native-validation", "", false,
+ `PROTOTYPE (not stable): enable the validating admission policy driver`)
}
// Cmd is the gator verify subcommand.
@@ -109,7 +112,7 @@ func runE(cmd *cobra.Command, args []string) error {
func runSuites(ctx context.Context, fileSystem fs.FS, suites []*verify.Suite, filter verify.Filter) error {
isFailure := false
- runner, err := verify.NewRunner(fileSystem, gator.NewOPAClient, verify.IncludeTrace(includeTrace))
+ runner, err := verify.NewRunner(fileSystem, gator.NewOPAClient, verify.IncludeTrace(includeTrace), verify.UseK8sCEL(flagEnableK8sCel))
if err != nil {
return err
}
diff --git a/config/crd/bases/config.gatekeeper.sh_configs.yaml b/config/crd/bases/config.gatekeeper.sh_configs.yaml
index 94c33b6ebbb..f9207c4dbab 100644
--- a/config/crd/bases/config.gatekeeper.sh_configs.yaml
+++ b/config/crd/bases/config.gatekeeper.sh_configs.yaml
@@ -45,7 +45,7 @@ spec:
or end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
processes:
diff --git a/config/crd/bases/expansion.gatekeeper.sh_expansiontemplate.yaml b/config/crd/bases/expansion.gatekeeper.sh_expansiontemplate.yaml
index 12f7f40d95e..e9a9298cb20 100644
--- a/config/crd/bases/expansion.gatekeeper.sh_expansiontemplate.yaml
+++ b/config/crd/bases/expansion.gatekeeper.sh_expansiontemplate.yaml
@@ -79,6 +79,155 @@ spec:
generators, this is usually spec.template
type: string
type: object
+ status:
+ description: ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+ properties:
+ byPod:
+ items:
+ description: ExpansionTemplatePodStatusStatus defines the observed
+ state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after
+ modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including
+ UUIDs. Because we don't ONLY use UUIDs, this is an alias
+ to string. Being a type captures intent and helps make sure
+ that UIDs and names do not get conflated.
+ type: string
+ type: object
+ type: array
+ type: object
type: object
served: true
storage: true
+ subresources:
+ status: {}
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ description: ExpansionTemplate is the Schema for the ExpansionTemplate 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: ExpansionTemplateSpec defines the desired state of ExpansionTemplate.
+ properties:
+ applyTo:
+ description: ApplyTo lists the specific groups, versions and kinds
+ of generator resources which will be expanded.
+ items:
+ description: ApplyTo determines what GVKs items the mutation should
+ apply to. Globs are not allowed.
+ properties:
+ groups:
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ versions:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ enforcementAction:
+ description: EnforcementAction specifies the enforcement action to
+ be used for resources matching the ExpansionTemplate. Specifying
+ an empty value will use the enforcement action specified by the
+ Constraint in violation.
+ type: string
+ generatedGVK:
+ description: GeneratedGVK specifies the GVK of the resources which
+ the generator resource creates.
+ properties:
+ group:
+ type: string
+ kind:
+ type: string
+ version:
+ type: string
+ type: object
+ templateSource:
+ description: TemplateSource specifies the source field on the generator
+ resource to use as the base for expanded resource. For Pod-creating
+ generators, this is usually spec.template
+ type: string
+ type: object
+ status:
+ description: ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+ properties:
+ byPod:
+ items:
+ description: ExpansionTemplatePodStatusStatus defines the observed
+ state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after
+ modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including
+ UUIDs. Because we don't ONLY use UUIDs, this is an alias
+ to string. Being a type captures intent and helps make sure
+ that UIDs and names do not get conflated.
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
diff --git a/config/crd/bases/match.gatekeeper.sh_matchcrd.yaml b/config/crd/bases/match.gatekeeper.sh_matchcrd.yaml
new file mode 100644
index 00000000000..1fd9983a63b
--- /dev/null
+++ b/config/crd/bases/match.gatekeeper.sh_matchcrd.yaml
@@ -0,0 +1,209 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ creationTimestamp: null
+ name: matchcrd.match.gatekeeper.sh
+spec:
+ group: match.gatekeeper.sh
+ names:
+ kind: DummyCRD
+ listKind: DummyCRDList
+ plural: matchcrd
+ singular: dummycrd
+ scope: Namespaced
+ versions:
+ - name: match
+ schema:
+ openAPIV3Schema:
+ description: DummyCRD is a "dummy" CRD to hold the Match object, which we
+ ultimately need to generate JSONSchemaProps. The TypeMeta and ObjectMeta
+ fields are required for controller-gen to generate the CRD.
+ 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
+ embeddedMatch:
+ description: Match selects which objects are in scope.
+ properties:
+ excludedNamespaces:
+ description: 'ExcludedNamespaces is a list of namespace names. If
+ defined, a constraint only applies to resources not in a listed
+ namespace. ExcludedNamespaces also supports a prefix or suffix based
+ glob. For example, `excludedNamespaces: [kube-*]` matches both
+ `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]`
+ matches both `kube-system` and `gatekeeper-system`.'
+ items:
+ description: 'A string that supports globbing at its front or end.
+ Ex: "kube-*" will match "kube-system" or "kube-public", "*-system"
+ will match "kube-system" or "gatekeeper-system". The asterisk
+ is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ kinds:
+ items:
+ description: Kinds accepts a list of objects with apiGroups and
+ kinds fields that list the groups/kinds of objects to which the
+ mutation will apply. If multiple groups/kinds objects are specified,
+ only one match is needed for the resource to be in scope.
+ properties:
+ apiGroups:
+ description: APIGroups is the API groups the resources belong
+ to. '*' is all groups. If '*' is present, the length of the
+ slice must be one. Required.
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ labelSelector:
+ description: 'LabelSelector is the combination of two optional fields:
+ `matchLabels` and `matchExpressions`. These two fields provide
+ different methods of selecting or excluding k8s objects based on
+ the label keys and values included in object metadata. All selection
+ expressions from both sections are ANDed to determine if an object
+ meets the cumulative requirements of the selector.'
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that
+ contains values, a key, and an operator that relates the key
+ and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies
+ to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to
+ a set of values. Valid operators are In, NotIn, Exists
+ and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the
+ operator is In or NotIn, the values array must be non-empty.
+ If the operator is Exists or DoesNotExist, the values
+ array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single
+ {key,value} in the matchLabels map is equivalent to an element
+ of matchExpressions, whose key field is "key", the operator
+ is "In", and the values array contains only "value". The requirements
+ are ANDed.
+ type: object
+ type: object
+ name:
+ description: 'Name is the name of an object. If defined, it will
+ match against objects with the specified name. Name also supports
+ a prefix or suffix glob. For example, `name: pod-*` would match
+ both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod`
+ and `b-pod`.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ namespaceSelector:
+ description: NamespaceSelector is a label selector against an object's
+ containing namespace or the object itself, if the object is a namespace.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that
+ contains values, a key, and an operator that relates the key
+ and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies
+ to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to
+ a set of values. Valid operators are In, NotIn, Exists
+ and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the
+ operator is In or NotIn, the values array must be non-empty.
+ If the operator is Exists or DoesNotExist, the values
+ array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single
+ {key,value} in the matchLabels map is equivalent to an element
+ of matchExpressions, whose key field is "key", the operator
+ is "In", and the values array contains only "value". The requirements
+ are ANDed.
+ type: object
+ type: object
+ namespaces:
+ description: 'Namespaces is a list of namespace names. If defined,
+ a constraint only applies to resources in a listed namespace. Namespaces
+ also supports a prefix or suffix based glob. For example, `namespaces:
+ [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces:
+ [*-system]` matches both `kube-system` and `gatekeeper-system`.'
+ items:
+ description: 'A string that supports globbing at its front or end.
+ Ex: "kube-*" will match "kube-system" or "kube-public", "*-system"
+ will match "kube-system" or "gatekeeper-system". The asterisk
+ is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ scope:
+ description: Scope determines if cluster-scoped and/or namespaced-scoped
+ resources are matched. Accepts `*`, `Cluster`, or `Namespaced`.
+ (defaults to `*`)
+ type: string
+ source:
+ description: Source determines whether generated or original resources
+ are matched. Accepts `Generated`|`Original`|`All` (defaults to `All`).
+ A value of `Generated` will only match generated resources, while
+ `Original` will only match regular resources.
+ enum:
+ - All
+ - Generated
+ - Original
+ type: string
+ type: object
+ 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
+ metadataDummy:
+ type: object
+ type: object
+ served: true
+ storage: true
diff --git a/config/crd/bases/mutations.gatekeeper.sh_assign.yaml b/config/crd/bases/mutations.gatekeeper.sh_assign.yaml
index 51ab6d565ac..42d3c1bc386 100644
--- a/config/crd/bases/mutations.gatekeeper.sh_assign.yaml
+++ b/config/crd/bases/mutations.gatekeeper.sh_assign.yaml
@@ -79,7 +79,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -158,7 +158,7 @@ spec:
a prefix or suffix glob. For example, `name: pod-*` would match
both `pod-a` and `pod-b`, and `name: *-pod` would match both
`a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an
@@ -217,7 +217,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -426,7 +426,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -505,7 +505,7 @@ spec:
a prefix or suffix glob. For example, `name: pod-*` would match
both `pod-a` and `pod-b`, and `name: *-pod` would match both
`a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an
@@ -564,7 +564,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -773,7 +773,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -852,7 +852,7 @@ spec:
a prefix or suffix glob. For example, `name: pod-*` would match
both `pod-a` and `pod-b`, and `name: *-pod` would match both
`a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an
@@ -911,7 +911,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
diff --git a/config/crd/bases/mutations.gatekeeper.sh_assignimage.yaml b/config/crd/bases/mutations.gatekeeper.sh_assignimage.yaml
new file mode 100644
index 00000000000..b472e067181
--- /dev/null
+++ b/config/crd/bases/mutations.gatekeeper.sh_assignimage.yaml
@@ -0,0 +1,326 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ creationTimestamp: null
+ name: assignimage.mutations.gatekeeper.sh
+spec:
+ group: mutations.gatekeeper.sh
+ names:
+ kind: AssignImage
+ listKind: AssignImageList
+ plural: assignimage
+ singular: assignimage
+ scope: Cluster
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: AssignImage is the Schema for the assignimage 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: AssignImageSpec defines the desired state of AssignImage.
+ properties:
+ applyTo:
+ description: ApplyTo lists the specific groups, versions and kinds
+ a mutation will be applied to. This is necessary because every mutation
+ implies part of an object schema and object schemas are associated
+ with specific GVKs.
+ items:
+ description: ApplyTo determines what GVKs items the mutation should
+ apply to. Globs are not allowed.
+ properties:
+ groups:
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ versions:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ location:
+ description: 'Location describes the path to be mutated, for example:
+ `spec.containers[name: main].image`.'
+ type: string
+ match:
+ description: Match allows the user to limit which resources get mutated.
+ Individual match criteria are AND-ed together. An undefined match
+ criteria matches everything.
+ properties:
+ excludedNamespaces:
+ description: 'ExcludedNamespaces is a list of namespace names.
+ If defined, a constraint only applies to resources not in a
+ listed namespace. ExcludedNamespaces also supports a prefix
+ or suffix based glob. For example, `excludedNamespaces: [kube-*]`
+ matches both `kube-system` and `kube-public`, and `excludedNamespaces:
+ [*-system]` matches both `kube-system` and `gatekeeper-system`.'
+ items:
+ description: 'A string that supports globbing at its front or
+ end. Ex: "kube-*" will match "kube-system" or "kube-public",
+ "*-system" will match "kube-system" or "gatekeeper-system". The
+ asterisk is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ kinds:
+ items:
+ description: Kinds accepts a list of objects with apiGroups
+ and kinds fields that list the groups/kinds of objects to
+ which the mutation will apply. If multiple groups/kinds objects
+ are specified, only one match is needed for the resource to
+ be in scope.
+ properties:
+ apiGroups:
+ description: APIGroups is the API groups the resources belong
+ to. '*' is all groups. If '*' is present, the length of
+ the slice must be one. Required.
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ labelSelector:
+ description: 'LabelSelector is the combination of two optional
+ fields: `matchLabels` and `matchExpressions`. These two fields
+ provide different methods of selecting or excluding k8s objects
+ based on the label keys and values included in object metadata. All
+ selection expressions from both sections are ANDed to determine
+ if an object meets the cumulative requirements of the selector.'
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector
+ requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector
+ that contains values, a key, and an operator that relates
+ the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship
+ to a set of values. Valid operators are In, NotIn,
+ Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If
+ the operator is In or NotIn, the values array must
+ be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced
+ during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A
+ single {key,value} in the matchLabels map is equivalent
+ to an element of matchExpressions, whose key field is "key",
+ the operator is "In", and the values array contains only
+ "value". The requirements are ANDed.
+ type: object
+ type: object
+ name:
+ description: 'Name is the name of an object. If defined, it will
+ match against objects with the specified name. Name also supports
+ a prefix or suffix glob. For example, `name: pod-*` would match
+ both `pod-a` and `pod-b`, and `name: *-pod` would match both
+ `a-pod` and `b-pod`.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ namespaceSelector:
+ description: NamespaceSelector is a label selector against an
+ object's containing namespace or the object itself, if the object
+ is a namespace.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector
+ requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector
+ that contains values, a key, and an operator that relates
+ the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship
+ to a set of values. Valid operators are In, NotIn,
+ Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If
+ the operator is In or NotIn, the values array must
+ be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced
+ during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A
+ single {key,value} in the matchLabels map is equivalent
+ to an element of matchExpressions, whose key field is "key",
+ the operator is "In", and the values array contains only
+ "value". The requirements are ANDed.
+ type: object
+ type: object
+ namespaces:
+ description: 'Namespaces is a list of namespace names. If defined,
+ a constraint only applies to resources in a listed namespace. Namespaces
+ also supports a prefix or suffix based glob. For example, `namespaces:
+ [kube-*]` matches both `kube-system` and `kube-public`, and
+ `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
+ items:
+ description: 'A string that supports globbing at its front or
+ end. Ex: "kube-*" will match "kube-system" or "kube-public",
+ "*-system" will match "kube-system" or "gatekeeper-system". The
+ asterisk is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ scope:
+ description: Scope determines if cluster-scoped and/or namespaced-scoped
+ resources are matched. Accepts `*`, `Cluster`, or `Namespaced`.
+ (defaults to `*`)
+ type: string
+ source:
+ description: Source determines whether generated or original resources
+ are matched. Accepts `Generated`|`Original`|`All` (defaults
+ to `All`). A value of `Generated` will only match generated
+ resources, while `Original` will only match regular resources.
+ enum:
+ - All
+ - Generated
+ - Original
+ type: string
+ type: object
+ parameters:
+ description: Parameters define the behavior of the mutator.
+ properties:
+ assignDomain:
+ description: AssignDomain sets the domain component on an image
+ string. The trailing slash should not be included.
+ type: string
+ assignPath:
+ description: AssignPath sets the domain component on an image
+ string.
+ type: string
+ assignTag:
+ description: AssignImage sets the image component on an image
+ string. It must start with a `:` or `@`.
+ type: string
+ pathTests:
+ items:
+ description: "PathTest allows the user to customize how the
+ mutation works if parent paths are missing. It traverses the
+ list in order. All sub paths are tested against the provided
+ condition, if the test fails, the mutation is not applied.
+ All `subPath` entries must be a prefix of `location`. Any
+ glob characters will take on the same value as was used to
+ expand the matching glob in `location`. \n Available Tests:
+ * MustExist - the path must exist or do not mutate * MustNotExist
+ - the path must not exist or do not mutate."
+ properties:
+ condition:
+ description: Condition describes whether the path either
+ MustExist or MustNotExist in the original object
+ enum:
+ - MustExist
+ - MustNotExist
+ type: string
+ subPath:
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ status:
+ description: AssignImageStatus defines the observed state of AssignImage.
+ properties:
+ byPod:
+ items:
+ description: MutatorPodStatusStatus defines the observed state of
+ MutatorPodStatus.
+ properties:
+ enforced:
+ type: boolean
+ errors:
+ items:
+ description: MutatorError represents a single error caught
+ while adding a mutator to a system.
+ properties:
+ message:
+ type: string
+ type:
+ description: Type indicates a specific class of error
+ for use by controller code. If not present, the error
+ should be treated as not matching any known type.
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ type: string
+ mutatorUID:
+ description: Storing the mutator UID allows us to detect drift,
+ such as when a mutator has been recreated after its CRD was
+ deleted out from under it, interrupting the watch
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/config/crd/bases/mutations.gatekeeper.sh_assignmetadata.yaml b/config/crd/bases/mutations.gatekeeper.sh_assignmetadata.yaml
index 895f3c44790..902aba1db61 100644
--- a/config/crd/bases/mutations.gatekeeper.sh_assignmetadata.yaml
+++ b/config/crd/bases/mutations.gatekeeper.sh_assignmetadata.yaml
@@ -38,7 +38,7 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names.
@@ -52,7 +52,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -131,7 +131,7 @@ spec:
a prefix or suffix glob. For example, `name: pod-*` would match
both `pod-a` and `pod-b`, and `name: *-pod` would match both
`a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an
@@ -190,7 +190,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -337,7 +337,7 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names.
@@ -351,7 +351,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -430,7 +430,7 @@ spec:
a prefix or suffix glob. For example, `name: pod-*` would match
both `pod-a` and `pod-b`, and `name: *-pod` would match both
`a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an
@@ -489,7 +489,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -636,7 +636,7 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names.
@@ -650,7 +650,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -729,7 +729,7 @@ spec:
a prefix or suffix glob. For example, `name: pod-*` would match
both `pod-a` and `pod-b`, and `name: *-pod` would match both
`a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an
@@ -788,7 +788,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
diff --git a/config/crd/bases/mutations.gatekeeper.sh_modifyset.yaml b/config/crd/bases/mutations.gatekeeper.sh_modifyset.yaml
index 44f24d1ef09..7e95583fb54 100644
--- a/config/crd/bases/mutations.gatekeeper.sh_modifyset.yaml
+++ b/config/crd/bases/mutations.gatekeeper.sh_modifyset.yaml
@@ -80,7 +80,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -159,7 +159,7 @@ spec:
a prefix or suffix glob. For example, `name: pod-*` would match
both `pod-a` and `pod-b`, and `name: *-pod` would match both
`a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an
@@ -218,7 +218,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -393,7 +393,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -472,7 +472,7 @@ spec:
a prefix or suffix glob. For example, `name: pod-*` would match
both `pod-a` and `pod-b`, and `name: *-pod` would match both
`a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an
@@ -531,7 +531,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -706,7 +706,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -785,7 +785,7 @@ spec:
a prefix or suffix glob. For example, `name: pod-*` would match
both `pod-a` and `pod-b`, and `name: *-pod` would match both
`a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an
@@ -844,7 +844,7 @@ spec:
end. Ex: "kube-*" will match "kube-system" or "kube-public",
"*-system" will match "kube-system" or "gatekeeper-system". The
asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
diff --git a/config/crd/bases/status.gatekeeper.sh_expansiontemplatepodstatuses.yaml b/config/crd/bases/status.gatekeeper.sh_expansiontemplatepodstatuses.yaml
new file mode 100644
index 00000000000..4335d45f5ca
--- /dev/null
+++ b/config/crd/bases/status.gatekeeper.sh_expansiontemplatepodstatuses.yaml
@@ -0,0 +1,71 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ creationTimestamp: null
+ name: expansiontemplatepodstatuses.status.gatekeeper.sh
+spec:
+ group: status.gatekeeper.sh
+ names:
+ kind: ExpansionTemplatePodStatus
+ listKind: ExpansionTemplatePodStatusList
+ plural: expansiontemplatepodstatuses
+ singular: expansiontemplatepodstatus
+ scope: Namespaced
+ versions:
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ description: ExpansionTemplatePodStatus is the Schema for the expansiontemplatepodstatuses
+ 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
+ status:
+ description: ExpansionTemplatePodStatusStatus defines the observed state
+ of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying
+ this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including
+ UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being
+ a type captures intent and helps make sure that UIDs and names do
+ not get conflated.
+ type: string
+ type: object
+ type: object
+ served: true
+ storage: true
diff --git a/config/crd/bases/syncset.gatekeeper.sh_syncsets.yaml b/config/crd/bases/syncset.gatekeeper.sh_syncsets.yaml
new file mode 100644
index 00000000000..790fb2a7436
--- /dev/null
+++ b/config/crd/bases/syncset.gatekeeper.sh_syncsets.yaml
@@ -0,0 +1,51 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ creationTimestamp: null
+ name: syncsets.syncset.gatekeeper.sh
+spec:
+ group: syncset.gatekeeper.sh
+ names:
+ kind: SyncSet
+ listKind: SyncSetList
+ plural: syncsets
+ singular: syncset
+ scope: Cluster
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: SyncSet is the Schema for the SyncSet 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:
+ properties:
+ gvks:
+ items:
+ properties:
+ group:
+ type: string
+ kind:
+ type: string
+ version:
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
index 2d096889dd6..9d6344716ec 100644
--- a/config/crd/kustomization.yaml
+++ b/config/crd/kustomization.yaml
@@ -3,10 +3,13 @@
# It should be run by config/default
resources:
- bases/config.gatekeeper.sh_configs.yaml
+#- bases/syncset.gatekeeper.sh_syncsets.yaml
- bases/status.gatekeeper.sh_constraintpodstatuses.yaml
- bases/status.gatekeeper.sh_constrainttemplatepodstatuses.yaml
- bases/status.gatekeeper.sh_mutatorpodstatuses.yaml
+- bases/status.gatekeeper.sh_expansiontemplatepodstatuses.yaml
- bases/mutations.gatekeeper.sh_assign.yaml
+- bases/mutations.gatekeeper.sh_assignimage.yaml
- bases/mutations.gatekeeper.sh_assignmetadata.yaml
- bases/mutations.gatekeeper.sh_modifyset.yaml
- bases/expansion.gatekeeper.sh_expansiontemplate.yaml
@@ -41,11 +44,18 @@ patchesJson6902:
kind: CustomResourceDefinition
name: modifyset.mutations.gatekeeper.sh
path: patches/max_name_size.yaml
+- target:
+ group: apiextensions.k8s.io
+ version: v1
+ kind: CustomResourceDefinition
+ name: assignimage.mutations.gatekeeper.sh
+ path: patches/max_name_size.yaml
patchesStrategicMerge:
#- patches/max_name_size_for_modifyset.yaml
#- patches/max_name_size_for_assign.yaml
#- patches/max_name_size_for_assignmetadata.yaml
+#- patches/max_name_size_for_assignimage.yaml
# [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_configs.yaml
diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml
index 5eeeee9022c..fb035f19865 100644
--- a/config/manager/manager.yaml
+++ b/config/manager/manager.yaml
@@ -56,7 +56,7 @@ spec:
- "--operation=webhook"
- "--operation=mutation-webhook"
- "--disable-opa-builtin={http.send}"
- image: openpolicyagent/gatekeeper:v3.12.0-beta.0
+ image: openpolicyagent/gatekeeper:v3.14.0
imagePullPolicy: Always
name: manager
ports:
@@ -148,7 +148,7 @@ spec:
- --disable-cert-rotation
command:
- /manager
- image: openpolicyagent/gatekeeper:v3.12.0-beta.0
+ image: openpolicyagent/gatekeeper:v3.14.0
env:
# used by Gatekeeper
- name: POD_NAMESPACE
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
index a7a893f5933..cb1aaf143ae 100644
--- a/config/rbac/role.yaml
+++ b/config/rbac/role.yaml
@@ -5,6 +5,13 @@ metadata:
creationTimestamp: null
name: manager-role
rules:
+- apiGroups:
+ - ""
+ resources:
+ - events
+ verbs:
+ - create
+ - patch
- apiGroups:
- '*'
resources:
@@ -69,6 +76,18 @@ rules:
- patch
- update
- watch
+- apiGroups:
+ - expansion.gatekeeper.sh
+ resources:
+ - '*'
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
- apiGroups:
- externaldata.gatekeeper.sh
resources:
diff --git a/crd.Dockerfile b/crd.Dockerfile
index 1abb6516972..c16bf18e4e3 100644
--- a/crd.Dockerfile
+++ b/crd.Dockerfile
@@ -1,15 +1,11 @@
-FROM alpine as builder
+FROM --platform=$TARGETPLATFORM registry.k8s.io/kubectl:v1.28.2 as builder
+ARG TARGETPLATFORM
ARG TARGETOS
ARG TARGETARCH
-ARG KUBE_VERSION
-
-RUN apk add --no-cache curl && \
- curl -LO https://storage.googleapis.com/kubernetes-release/release/v${KUBE_VERSION}/bin/${TARGETOS}/${TARGETARCH}/kubectl && \
- chmod +x kubectl
FROM scratch as build
USER 65532:65532
COPY --chown=65532:65532 * /crds/
-COPY --from=builder /kubectl /kubectl
+COPY --from=builder /bin/kubectl /kubectl
ENTRYPOINT ["/kubectl"]
diff --git a/demo/k8s-validating-admission-policy/README.md b/demo/k8s-validating-admission-policy/README.md
new file mode 100644
index 00000000000..63a65e98488
--- /dev/null
+++ b/demo/k8s-validating-admission-policy/README.md
@@ -0,0 +1,10 @@
+This is a demo of a prototype-stage feature and is subject to change.
+
+The demo will not work unless the `--experimental-enable-k8s-native-validation`` is
+set. Please set `--validate-template-rego` to `false` if using Gatekeeper version 3.13.1+ but before 3.16.0.
+
+Note that the contents of the constraint template have changed since cutting
+Gatekeeper's v3.13.0 release. To try this with the development build of
+Gatekeeper, use a [dev image](https://open-policy-agent.github.io/gatekeeper/website/docs/install/#deploying-a-release-using-development-image).
+
+
\ No newline at end of file
diff --git a/demo/k8s-validating-admission-policy/bad_namespace.yaml b/demo/k8s-validating-admission-policy/bad_namespace.yaml
new file mode 100644
index 00000000000..878ae205d71
--- /dev/null
+++ b/demo/k8s-validating-admission-policy/bad_namespace.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: bad-production
diff --git a/demo/k8s-validating-admission-policy/demo.gif b/demo/k8s-validating-admission-policy/demo.gif
new file mode 100644
index 00000000000..0656b750138
Binary files /dev/null and b/demo/k8s-validating-admission-policy/demo.gif differ
diff --git a/demo/k8s-validating-admission-policy/k8srequiredlabels_template.yaml b/demo/k8s-validating-admission-policy/k8srequiredlabels_template.yaml
new file mode 100644
index 00000000000..01f7644f5ef
--- /dev/null
+++ b/demo/k8s-validating-admission-policy/k8srequiredlabels_template.yaml
@@ -0,0 +1,35 @@
+apiVersion: templates.gatekeeper.sh/v1
+kind: ConstraintTemplate
+metadata:
+ name: k8srequiredlabels
+spec:
+ crd:
+ spec:
+ names:
+ kind: K8sRequiredLabels
+ validation:
+ # Schema for the `parameters` field
+ openAPIV3Schema:
+ type: object
+ properties:
+ message:
+ type: string
+ labels:
+ type: array
+ items:
+ type: object
+ properties:
+ key:
+ type: string
+ allowedRegex:
+ type: string
+ targets:
+ - target: admission.k8s.gatekeeper.sh
+ code:
+ - engine: K8sNativeValidation
+ source:
+ validations:
+ - expression: "variables.params.labels.all(entry, has(object.metadata.labels) && entry.key in object.metadata.labels)"
+ messageExpression: '"missing required label, requires all of: " + variables.params.labels.map(entry, entry.key).join(", ")'
+ - expression: "!variables.params.labels.exists(entry, has(object.metadata.labels) && entry.key in object.metadata.labels && !string(object.metadata.labels[entry.key]).matches(string(entry.allowedRegex)))"
+ message: "regex mismatch"
diff --git a/demo/k8s-validating-admission-policy/owner_must_be_provided.yaml b/demo/k8s-validating-admission-policy/owner_must_be_provided.yaml
new file mode 100644
index 00000000000..806e9862ffc
--- /dev/null
+++ b/demo/k8s-validating-admission-policy/owner_must_be_provided.yaml
@@ -0,0 +1,14 @@
+apiVersion: constraints.gatekeeper.sh/v1beta1
+kind: K8sRequiredLabels
+metadata:
+ name: all-must-have-owner
+spec:
+ match:
+ kinds:
+ - apiGroups: [""]
+ kinds: ["Namespace"]
+ parameters:
+ message: "All namespaces must have an `owner` label that points to your company username"
+ labels:
+ - key: owner
+ allowedRegex: "^[a-zA-Z]+.agilebank.demo$"
diff --git a/demo/mutation/assignimagedemo.yaml b/demo/mutation/assignimagedemo.yaml
new file mode 100644
index 00000000000..2f6e3c8162d
--- /dev/null
+++ b/demo/mutation/assignimagedemo.yaml
@@ -0,0 +1,18 @@
+apiVersion: mutations.gatekeeper.sh/v1alpha1
+kind: AssignImage
+metadata:
+ name: assign-container-image-registry
+spec:
+ applyTo:
+ - groups: [ "" ]
+ kinds: [ "Pod" ]
+ versions: [ "v1" ]
+ location: "spec.containers[name:*].image"
+ parameters:
+ assignDomain: "mycompany.registry.io"
+ match:
+ source: "All"
+ scope: Namespaced
+ kinds:
+ - apiGroups: [ "*" ]
+ kinds: [ "Pod" ]
diff --git a/demo/mutation/pod.yaml b/demo/mutation/pod.yaml
new file mode 100644
index 00000000000..5dc4087838b
--- /dev/null
+++ b/demo/mutation/pod.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: nginx
+spec:
+ containers:
+ - name: nginx
+ image: nginx
+ imagePullPolicy: IfNotPresent
diff --git a/deploy/gatekeeper.yaml b/deploy/gatekeeper.yaml
index 5b7d55b4d62..2bcb6b94eda 100644
--- a/deploy/gatekeeper.yaml
+++ b/deploy/gatekeeper.yaml
@@ -97,7 +97,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -147,7 +147,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -183,7 +183,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -342,7 +342,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -392,7 +392,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -428,7 +428,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -587,7 +587,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -637,7 +637,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -673,7 +673,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -790,6 +790,244 @@ spec:
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ labels:
+ gatekeeper.sh/system: "yes"
+ name: assignimage.mutations.gatekeeper.sh
+spec:
+ group: mutations.gatekeeper.sh
+ names:
+ kind: AssignImage
+ listKind: AssignImageList
+ plural: assignimage
+ singular: assignimage
+ preserveUnknownFields: false
+ scope: Cluster
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: AssignImage is the Schema for the assignimage 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:
+ properties:
+ name:
+ maxLength: 63
+ type: string
+ type: object
+ spec:
+ description: AssignImageSpec defines the desired state of AssignImage.
+ properties:
+ applyTo:
+ description: ApplyTo lists the specific groups, versions and kinds a mutation will be applied to. This is necessary because every mutation implies part of an object schema and object schemas are associated with specific GVKs.
+ items:
+ description: ApplyTo determines what GVKs items the mutation should apply to. Globs are not allowed.
+ properties:
+ groups:
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ versions:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ location:
+ description: 'Location describes the path to be mutated, for example: `spec.containers[name: main].image`.'
+ type: string
+ match:
+ description: Match allows the user to limit which resources get mutated. Individual match criteria are AND-ed together. An undefined match criteria matches everything.
+ properties:
+ excludedNamespaces:
+ description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
+ items:
+ description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ kinds:
+ items:
+ description: Kinds accepts a list of objects with apiGroups and kinds fields that list the groups/kinds of objects to which the mutation will apply. If multiple groups/kinds objects are specified, only one match is needed for the resource to be in scope.
+ properties:
+ apiGroups:
+ description: APIGroups is the API groups the resources belong to. '*' is all groups. If '*' is present, the length of the slice must be one. Required.
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ labelSelector:
+ description: 'LabelSelector is the combination of two optional fields: `matchLabels` and `matchExpressions`. These two fields provide different methods of selecting or excluding k8s objects based on the label keys and values included in object metadata. All selection expressions from both sections are ANDed to determine if an object meets the cumulative requirements of the selector.'
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ name:
+ description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ namespaceSelector:
+ description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ namespaces:
+ description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
+ items:
+ description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ scope:
+ description: Scope determines if cluster-scoped and/or namespaced-scoped resources are matched. Accepts `*`, `Cluster`, or `Namespaced`. (defaults to `*`)
+ type: string
+ source:
+ description: Source determines whether generated or original resources are matched. Accepts `Generated`|`Original`|`All` (defaults to `All`). A value of `Generated` will only match generated resources, while `Original` will only match regular resources.
+ enum:
+ - All
+ - Generated
+ - Original
+ type: string
+ type: object
+ parameters:
+ description: Parameters define the behavior of the mutator.
+ properties:
+ assignDomain:
+ description: AssignDomain sets the domain component on an image string. The trailing slash should not be included.
+ type: string
+ assignPath:
+ description: AssignPath sets the domain component on an image string.
+ type: string
+ assignTag:
+ description: AssignImage sets the image component on an image string. It must start with a `:` or `@`.
+ type: string
+ pathTests:
+ items:
+ description: "PathTest allows the user to customize how the mutation works if parent paths are missing. It traverses the list in order. All sub paths are tested against the provided condition, if the test fails, the mutation is not applied. All `subPath` entries must be a prefix of `location`. Any glob characters will take on the same value as was used to expand the matching glob in `location`. \n Available Tests: * MustExist - the path must exist or do not mutate * MustNotExist - the path must not exist or do not mutate."
+ properties:
+ condition:
+ description: Condition describes whether the path either MustExist or MustNotExist in the original object
+ enum:
+ - MustExist
+ - MustNotExist
+ type: string
+ subPath:
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ status:
+ description: AssignImageStatus defines the observed state of AssignImage.
+ properties:
+ byPod:
+ items:
+ description: MutatorPodStatusStatus defines the observed state of MutatorPodStatus.
+ properties:
+ enforced:
+ type: boolean
+ errors:
+ items:
+ description: MutatorError represents a single error caught while adding a mutator to a system.
+ properties:
+ message:
+ type: string
+ type:
+ description: Type indicates a specific class of error for use by controller code. If not present, the error should be treated as not matching any known type.
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ type: string
+ mutatorUID:
+ description: Storing the mutator UID allows us to detect drift, such as when a mutator has been recreated after its CRD was deleted out from under it, interrupting the watch
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.10.0
@@ -829,13 +1067,13 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -885,7 +1123,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -921,7 +1159,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -1040,13 +1278,13 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -1096,7 +1334,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -1132,7 +1370,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -1251,13 +1489,13 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -1307,7 +1545,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -1343,7 +1581,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -1485,7 +1723,7 @@ spec:
excludedNamespaces:
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
processes:
@@ -1689,7 +1927,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.10.0
+ controller-gen.kubebuilder.io/version: v0.11.3
labels:
gatekeeper.sh/system: "yes"
name: constrainttemplates.templates.gatekeeper.sh
@@ -1748,6 +1986,24 @@ spec:
targets:
items:
properties:
+ code:
+ description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
+ items:
+ properties:
+ engine:
+ description: 'The engine used to evaluate the code. Example: "Rego". Required.'
+ type: string
+ source:
+ description: The source code for the template. Required.
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - engine
+ - source
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - engine
+ x-kubernetes-list-type: map
libs:
items:
type: string
@@ -1843,6 +2099,24 @@ spec:
targets:
items:
properties:
+ code:
+ description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
+ items:
+ properties:
+ engine:
+ description: 'The engine used to evaluate the code. Example: "Rego". Required.'
+ type: string
+ source:
+ description: The source code for the template. Required.
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - engine
+ - source
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - engine
+ x-kubernetes-list-type: map
libs:
items:
type: string
@@ -1938,6 +2212,24 @@ spec:
targets:
items:
properties:
+ code:
+ description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
+ items:
+ properties:
+ engine:
+ description: 'The engine used to evaluate the code. Example: "Rego". Required.'
+ type: string
+ source:
+ description: The source code for the template. Required.
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - engine
+ - source
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - engine
+ x-kubernetes-list-type: map
libs:
items:
type: string
@@ -2059,6 +2351,196 @@ spec:
description: TemplateSource specifies the source field on the generator resource to use as the base for expanded resource. For Pod-creating generators, this is usually spec.template
type: string
type: object
+ status:
+ description: ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+ properties:
+ byPod:
+ items:
+ description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ description: ExpansionTemplate is the Schema for the ExpansionTemplate 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: ExpansionTemplateSpec defines the desired state of ExpansionTemplate.
+ properties:
+ applyTo:
+ description: ApplyTo lists the specific groups, versions and kinds of generator resources which will be expanded.
+ items:
+ description: ApplyTo determines what GVKs items the mutation should apply to. Globs are not allowed.
+ properties:
+ groups:
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ versions:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ enforcementAction:
+ description: EnforcementAction specifies the enforcement action to be used for resources matching the ExpansionTemplate. Specifying an empty value will use the enforcement action specified by the Constraint in violation.
+ type: string
+ generatedGVK:
+ description: GeneratedGVK specifies the GVK of the resources which the generator resource creates.
+ properties:
+ group:
+ type: string
+ kind:
+ type: string
+ version:
+ type: string
+ type: object
+ templateSource:
+ description: TemplateSource specifies the source field on the generator resource to use as the base for expanded resource. For Pod-creating generators, this is usually spec.template
+ type: string
+ type: object
+ status:
+ description: ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+ properties:
+ byPod:
+ items:
+ description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ labels:
+ gatekeeper.sh/system: "yes"
+ name: expansiontemplatepodstatuses.status.gatekeeper.sh
+spec:
+ group: status.gatekeeper.sh
+ names:
+ kind: ExpansionTemplatePodStatus
+ listKind: ExpansionTemplatePodStatusList
+ plural: expansiontemplatepodstatuses
+ singular: expansiontemplatepodstatus
+ preserveUnknownFields: false
+ scope: Namespaced
+ versions:
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ description: ExpansionTemplatePodStatus is the Schema for the expansiontemplatepodstatuses 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
+ status:
+ description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
+ type: string
+ type: object
type: object
served: true
storage: true
@@ -2130,7 +2612,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -2180,7 +2662,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -2216,7 +2698,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -2348,7 +2830,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -2398,7 +2880,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -2434,7 +2916,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -2566,7 +3048,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -2616,7 +3098,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -2652,7 +3134,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -2810,7 +3292,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.10.0
+ controller-gen.kubebuilder.io/version: v0.11.3
labels:
gatekeeper.sh/system: "yes"
name: providers.externaldata.gatekeeper.sh
@@ -2849,12 +3331,12 @@ spec:
description: Timeout is the timeout when querying the provider.
type: integer
url:
- description: URL is the url for the provider. URL is prefixed with http:// or https://.
+ description: URL is the url for the provider. URL is prefixed with https://.
type: string
type: object
type: object
served: true
- storage: true
+ storage: false
- name: v1beta1
schema:
openAPIV3Schema:
@@ -2878,12 +3360,12 @@ spec:
description: Timeout is the timeout when querying the provider.
type: integer
url:
- description: URL is the url for the provider. URL is prefixed with http:// or https://.
+ description: URL is the url for the provider. URL is prefixed with https://.
type: string
type: object
type: object
served: true
- storage: false
+ storage: true
---
apiVersion: v1
kind: ServiceAccount
@@ -2930,6 +3412,13 @@ metadata:
gatekeeper.sh/system: "yes"
name: gatekeeper-manager-role
rules:
+- apiGroups:
+ - ""
+ resources:
+ - events
+ verbs:
+ - create
+ - patch
- apiGroups:
- '*'
resources:
@@ -2994,6 +3483,18 @@ rules:
- patch
- update
- watch
+- apiGroups:
+ - expansion.gatekeeper.sh
+ resources:
+ - '*'
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
- apiGroups:
- externaldata.gatekeeper.sh
resources:
@@ -3189,7 +3690,7 @@ spec:
fieldPath: metadata.namespace
- name: CONTAINER_NAME
value: manager
- image: openpolicyagent/gatekeeper:v3.12.0-beta.0
+ image: openpolicyagent/gatekeeper:v3.14.0
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -3306,7 +3807,7 @@ spec:
fieldPath: metadata.namespace
- name: CONTAINER_NAME
value: manager
- image: openpolicyagent/gatekeeper:v3.12.0-beta.0
+ image: openpolicyagent/gatekeeper:v3.14.0
imagePullPolicy: Always
livenessProbe:
httpGet:
diff --git a/docs/Release_Management.md b/docs/Release_Management.md
index e5f35fd8b3e..85e23daf984 100644
--- a/docs/Release_Management.md
+++ b/docs/Release_Management.md
@@ -36,7 +36,7 @@ No plan to move to 4.0.0 unless there is a major design change like an incompati
- soak for ~ 2 weeks before cutting a stable release
- Release candidate release, cut from master branch
- X.Y.0 (Branch: master)
- - Released every ~ 2 months
+ - Released every ~ 3 months
- Stable release, cut from master when X.Y milestone is complete
**Patch Releases**
diff --git a/docs/design/README.md b/docs/design/README.md
index e846a5b1f44..b3dabf924c0 100644
--- a/docs/design/README.md
+++ b/docs/design/README.md
@@ -1,61 +1,65 @@
# Design Docs
Generally, design docs are on Google docs:
-## Conventions
-* [Versioning of Constraint Templates](https://docs.google.com/document/d/1vB_2wm60WCVLXoegMrupqwqKAuW6gbwEIxg3vBQj6cs/edit)
-
## In Development
## Proposed
-* [Template e2e Testing Design](https://docs.google.com/document/d/15nWc9TH97LF9o58CTVxYxFM9tYk8-seB5erIa2gouPo/edit)
-* [ByPod Status Design](https://docs.google.com/document/d/13xmVQuE9Q8CFDpL9pzpoAyH1nIzHndP0OfccXVShiPo/edit)
* [Namespace-Scoped Constraints](https://docs.google.com/document/d/1-pY7B5C6R0fjUbDu8izlcP7MSUDVDHv5XK16BFyTGRc/edit#heading=h.w8j68o8vjdts)
-* [Mutation Design - 4th Edition (current approach)](https://docs.google.com/document/d/1MdchNFz9guycX__QMGxpJviPaT_MZs8iXaAFqCvoXYQ/edit?ts=5f73fb77#
-)
- * [Mutation Interfaces (for the current approach)](https://docs.google.com/document/d/1c5Z3g6Zsfmga7xod4--t6RrXamdAaMaqYzPNujtZb10/edit)
- * [OPA Gatekeeper Mutation (alternate proposal)](https://docs.google.com/document/d/1LtNIxd-Y3oh0HPgPYdaVV7t2c6vBSwzYAFcTyxQYZjE/edit)
- * [Mutation Revised Design Doc (June 2019)](https://docs.google.com/document/d/1G7WgZKx1Y3VOTUjrqn7DjDaZgSKCIZowILm_I6psrw0/edit#heading=h.mtvdjag5uj9)
- * [Mutation Initial Design Doc (April 2019)](https://docs.google.com/document/d/1qTHwqoUX8AL2jodyWKB_2szrGDwhi14Ra_LlQ-ogtck/edit#heading=h.iu1ppjy7g7j)
-* [External Data](https://docs.google.com/document/d/1hPi86jdsCKg8puYT5_s_73mPGExUJeZfyKmvG-XWtPc/edit#)
-* [gator validate](https://docs.google.com/document/d/1B0hXDia8SExOkCVAEbPVHFJmnWeJgHziGvMxnzrENa0/edit)
+* [Sync Resource](https://docs.google.com/document/d/1ZbXaEh7v_HcgrRu7N-kEucU2pXyq1Rt7cSmmFOBN2q8/edit)
+* [External Data Response Cache](https://docs.google.com/document/d/1nl6iWMmh9CRT0A6cr-Nkfofv9wp210Bkf6ilLq9LLBo/edit)
+* [Gator SyncSet Support](https://docs.google.com/document/d/1mBvy6Y7TDyZswdYlFBHB3Mi2irLVqga_7ZoZvfPIU0A/edit)
## Implemented
-* [V3 Accepted Design](https://docs.google.com/document/d/1yC4wgpVoJj6ngYnSTtO-HeaIBl05gla562sD7qKPy3M/edit#heading=h.z0bjqzl81dpe)
- * [Initial v3 Design Proposal](https://docs.google.com/document/d/1S4C5BHZDoAqw5m5aVWrr8b8fe4H3I2jymmKitoTia2Y/edit#heading=h.p63jc1w6w88d)
- * [Initial v3 Design Proposal -- Detailed Design](https://docs.google.com/document/d/1oZR9b52z_EQkhit9A-ApFvz3tqsn9ckzvPyxKw1pBTo/edit)
-* [Dynamic Watch Design for OPA/Gatekeeper](https://docs.google.com/document/d/1Wi3LM3sG6Qgfzm--bWb6R0SEKCkQCCt-ene6cO62FlM/edit)
-* [Architecture Diagram](https://docs.google.com/document/d/1It-Mpz36ygqrElmh2hZ3DvDIqKYyKUZN6V4d7UTlEG8/edit#heading=h.rzuko1admjwd)
-* [Audit Design Doc](https://docs.google.com/document/d/1EnVOOaLZ_fWxo02ZmgnvTE2PtTRbyyhKjioPe-_In28/edit)
-* [Dry-Run Design Doc](https://docs.google.com/document/d/17nJDJxjY_XHV8zrMNdOi2hFgfm6XKGJi0QyznsbhQ70/edit#heading=h.z0bjqzl81dpe)
-* [Constraint Framework Client Interface](https://docs.google.com/document/d/1NDOgu8F_yQqrxRRVTDiCXGXMsajA3Jtp-lwGrZsDFcI/edit#)
-* [Logging Design Doc](https://docs.google.com/document/d/1ap7AKOupNcR_42s8mkSh5FV9eteXTd4VCqelKst73VY/edit)
-* [Namespace Exclusion Design doc](https://docs.google.com/document/d/1yHuXFs_HQL5N9yT9QVi6AMyflWPtZS4Pg-uXczdqgZ8/edit)
+* [Gatekeeper V3 Accepted Design](https://docs.google.com/document/d/1qsfeCx-Rx61Xm6JqJK-i67Gk_y__lNebdakmnhCdM7w/edit)
+ * [Initial v3 Design Proposal](https://docs.google.com/document/d/1GgebCUkQ6WiS_DFk24jAnS51hQz6kpIRjfkzVW3J2Cs/edit)
+ * [Initial v3 Design Proposal -- Detailed Design](https://docs.google.com/document/d/1VykioikDtcEtGIMQ_jsgCPEQDt5pecbEaDgA-hGryMo/edit)
+* [Dynamic Watch Design for OPA/Gatekeeper](https://docs.google.com/document/d/1WWtYajE-Vfr1TDetWktjpYeMarx2PTogmIr_2Gmhkt0/edit)
+* [Architecture Diagram](https://docs.google.com/document/d/1-0J8XV3Yavb7LiMkNIoyBp9MY021TrtKyu_GlpCNBU8/edit)
+* [Audit Design Doc](https://docs.google.com/document/d/1VGXXb9i3-CETJvuiskLMahGceFQZh1wUffMXHdqRtck/edit)
+* [Dry-Run Design Doc](https://docs.google.com/document/d/1H-JS4pJZvN_zpdfrwnu5Drsq8_qhHvk0El2s5a_SrWI/edit)
+* [Constraint Framework Client Interface](https://docs.google.com/document/d/1QwqRO0D5MQsNM1D6SuH8yWACa5nSZKjI7PGzl7F0a_g/edit)
+* [Logging Design Doc](https://docs.google.com/document/d/1jPl8sqZU2AEE-lxEQ-8Q2kKFS5OD93CuMm9y-htzUf8/edit)
+* [Namespace Exclusion Design doc](https://docs.google.com/document/d/1PjpFrhiQu2DNl3wFS5Ts-z8yx9EwQnafhNIp1PJvFQQ/edit)
* [Metrics Design Issue](https://github.com/open-policy-agent/gatekeeper/issues/157#issuecomment-553015292)
-* [Gatekeeper v1beta1 CRD Deprecation](https://docs.google.com/document/d/12TD9vk79X3y0RgNxURamW4tQOyd6YjA6WrwDAqcplwg/edit#)
-* [Compiler Sharding Design](https://docs.google.com/document/d/1ibCxaI-7HyWyDjQNL4iDRMHnrauufIMJ1D6LwIKdlsI/edit)
-* [External Data TLS Support](https://docs.google.com/document/d/1GjV3WeC2bgQ3j37_mMpY9hr7YOAqzSJ6jDSu-DVrcmU/edit)
+* [Gatekeeper v1beta1 CRD Deprecation](https://docs.google.com/document/d/1quP6ScoPiKDJrykOaReP8xRFdl66LO0586P_v5lfnQY/edit)
+* [Compiler Sharding Design](https://docs.google.com/document/d/1CV9HCp8TG-q_B6TltufHIkXcTrb03LTPWzD2Vr4R_ec/edit)
+* [Template e2e Testing Design](https://docs.google.com/document/d/1_DDhxDYjVxyZk090F-GznHTeT5jFMpwjEXLLhzR3AoU/edit)
+* [ByPod Status Design](https://docs.google.com/document/d/1kPb3B1I6FBsthpR6hp0Q3SEB11iXoSSuWbj9t1q-_58/edit)
+* [Mutation Design - 4th Edition (current approach)](https://docs.google.com/document/d/1FGJ8A9_JnGJu-pU0u6hh37JKWw7j7GhMfrvTFL9sfUA/edit)
+ * [Mutation Interfaces (for the current approach)](https://docs.google.com/document/d/1ihhUKly1YFJfvmTKjJLAOkQlrM1Oexr147IJbSHu5Ao/edit)
+ * [OPA Gatekeeper Mutation (alternate proposal)](https://docs.google.com/document/d/11V3zfQ75ugxUy_I2o6AqjWbhw1PKcMh8v3Cf8_uuwdU/edit)
+ * [Mutation Revised Design Doc (June 2019)](https://docs.google.com/document/d/1jluk3xL3dLxsE_9C69XWVOrSyLqzsySY0W7r9Yl0i68/edit&resourcekey=0-A4jzI3xwwxfggM9uvwctAw)
+ * [Mutation Initial Design Doc (April 2019)](https://docs.google.com/document/d/1-TRvdND3Q-HPzIg8pe2ZtYNkOBDnQ2CxC7SWhA0lP6g/edit)
+* [External Data](https://docs.google.com/document/d/1tXsoXWFzoCdWY8BqxXCNr5qXkTbGgEf2-sEpvGSE4ZQ/edit)
+* [gator validate](https://docs.google.com/document/d/1LG-GfOlXjWzz0wNCb8jdzIMplZqkyrkMmTLYx05CKY4/edit)
+* [External Data TLS Support](https://docs.google.com/document/d/1z43LI38twxPiUHPuktWPB1xMnsYr7SaVgczq-WsBhck/edit)
+* [Export violations using pub-sub](https://docs.google.com/document/d/1xu6c99m_qBOpztAc8uUnoY6ST8UiXyyJzrXOmMmJQ9I/edit)
+* [Versioning of Constraint Templates](https://docs.google.com/document/d/1Sg4HrNl9EYkNbn6wSGcyxULELrIrNbqS28djvNtHYoY/edit)
## Roadmap (in development)
* See [milestones](https://github.com/open-policy-agent/gatekeeper/milestones?direction=asc&sort=due_date)
## Roadmap (complete)
-* [GA Development Path](https://docs.google.com/document/d/1Lolr_jUkVlGSyk4iGhajx1LXWsWRXhLeu3L7s3lLDGY/edit#heading=h.9aae3wnhx5k3)
-* [Post-MVP Features Doc](https://docs.google.com/document/d/1t61-fcFdbNA0o1kTQd-oS2rkaUsouN4Kg6ImW8agfbk/edit#heading=h.57n2tr53h5l)
-* [MVP for Alpha](https://docs.google.com/document/d/1EPb3zg-hknAK7WqYh96XIXCEXG9mQqr_Cqn8VuEGoLI/edit#heading=h.vu8n6esi249)
+* [GA Development Path](https://docs.google.com/document/d/19iMT3CQ_DFKfSy9Ypxty4QEFyNH5U_ZO3RF056NtL00/edit)
+* [Post-MVP Features Doc](https://docs.google.com/document/d/1xtfrEGcA7MxRlMox-WSOQEpZ58gXWUU4S-Jeg47fQ6s/edit)
+* [MVP for Alpha](https://docs.google.com/document/d/18xonIGw5iM_U4wbgl18O6G4xSpShnZA3rM8vyRPGLfg/edit)
## Discussions
These docs may not be design docs in themselves, but seek to influence design
decisions
-* [Mutation Dynamics](https://docs.google.com/document/d/1WKj-9xYYVO9IckQVZHYVFCziRVS6zxCfvJxWbkbLcOM/view#)
+* [Mutation Convergence Proof](https://docs.google.com/document/d/1ZGV9H0xpafogtpMy_GnZVSHygwa01VsBtxyD3nWd_BA/edit)
+ * This looks at the elements of mutation that allow us to assert that any combination of mutators should converge
+ and should serve as a guide when considering changes in behavior to mutation.
+* [Mutation Dynamics](https://docs.google.com/document/d/1VkNIWPrHnaPbMRfkjyhyAPWoloiOq0lpTIHbTvBhVUA/edit)
* A dissection of the mutation problem space, attempting to break down the
salient behavioral elements and figure out what's needed for a
user-friendly set of mutation primitives.
-* [Mutation Transience](https://docs.google.com/document/d/1pyM3h5c8gh5W2eKP37qpge9jtEtRAs6Uv_sTyJttm3c/edit?ts=606f8bbf#)
+* [Mutation Transience](https://docs.google.com/document/d/1cKK1LQDm5LYu3Iqbi0HXrK5nacjEB88xGEJF8qwH708/edit)
* Looking at how a mutation webhook may behave during configuration changes and discussing what that might mean in terms
of necessary status fields and best practices for writing mutators.
-* [Finalizers in OPA Gatekeeper](https://docs.google.com/document/d/1lZZsHACi4LnPF4bBvjfg0qpbYGChkZd6mhaaRnvkx6M/view#)
+* [Finalizers in OPA Gatekeeper](https://docs.google.com/document/d/179uwLOU_t8TjUyxRagDN6qKJsJqJirIS7HDvg2ft1yw/edit)
* This doc discusses the impact the existence of finalizers has on running
OPA Gatekeeper. Its points have either been addressed or are on track
to being addressed.
diff --git a/gator.Dockerfile b/gator.Dockerfile
index a931d288ffe..20f9d66419c 100644
--- a/gator.Dockerfile
+++ b/gator.Dockerfile
@@ -1,5 +1,5 @@
ARG BUILDPLATFORM="linux/amd64"
-ARG BUILDERIMAGE="golang:1.19-bullseye"
+ARG BUILDERIMAGE="golang:1.21-bullseye"
# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
ARG BASEIMAGE="gcr.io/distroless/static:nonroot"
@@ -13,16 +13,15 @@ ARG TARGETVARIANT=""
ARG LDFLAGS
ENV GO111MODULE=on \
- CGO_ENABLED=0 \
+ CGO_ENABLED=1 \
GOOS=${TARGETOS} \
GOARCH=${TARGETARCH} \
GOARM=${TARGETVARIANT}
-COPY . /tmp/gatekeeper
+COPY . /go/src/github.com/open-policy-agent/gatekeeper
+WORKDIR /go/src/github.com/open-policy-agent/gatekeeper/cmd/gator
-WORKDIR /tmp/gatekeeper/cmd/gator
-
-RUN go build -mod vendor -a -ldflags "${LDFLAGS:--X github.com/open-policy-agent/gatekeeper/pkg/version.Version=latest -X main.frameworksVersion=latest -X main.opaVersion=latest}" -o /gator
+RUN go build -mod vendor -a -ldflags "${LDFLAGS}" -o /gator
FROM --platform=$BUILDPLATFORM $BASEIMAGE as build
USER 65532:65532
diff --git a/go.mod b/go.mod
index f4986218657..239c5123756 100644
--- a/go.mod
+++ b/go.mod
@@ -1,103 +1,110 @@
-module github.com/open-policy-agent/gatekeeper
+module github.com/open-policy-agent/gatekeeper/v3
-go 1.18
+go 1.20
-// Prevent otel dependencies from getting out of sync.
-replace (
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0
- go.opentelemetry.io/otel => go.opentelemetry.io/otel v0.20.0
- go.opentelemetry.io/otel/metric => go.opentelemetry.io/otel/metric v0.20.0
- go.opentelemetry.io/otel/sdk => go.opentelemetry.io/otel/sdk v0.20.0
- go.opentelemetry.io/otel/trace => go.opentelemetry.io/otel/trace v0.20.0
- go.opentelemetry.io/proto/otlp => go.opentelemetry.io/proto/otlp v0.7.0
-)
+// We are forking from commit 116a1b831fffe7ccc3c8145306c3e1a3b1b14ffa (tag: v0.15.0) to enable dynamic informer caching
+replace sigs.k8s.io/controller-runtime => ./third_party/sigs.k8s.io/controller-runtime
require (
- cloud.google.com/go/trace v1.2.0
+ cloud.google.com/go/trace v1.10.1
contrib.go.opencensus.io/exporter/ocagent v0.7.0
contrib.go.opencensus.io/exporter/prometheus v0.4.2
contrib.go.opencensus.io/exporter/stackdriver v0.13.14
+ github.com/dapr/go-sdk v1.8.0
github.com/davecgh/go-spew v1.1.1
- github.com/ghodss/yaml v1.0.0
- github.com/go-logr/logr v1.2.3
- github.com/go-logr/zapr v1.2.3
+ github.com/dominikbraun/graph v0.16.2
+ github.com/go-logr/logr v1.2.4
+ github.com/go-logr/zapr v1.2.4
+ github.com/golang/protobuf v1.5.3
github.com/google/go-cmp v0.5.9
- github.com/google/uuid v1.3.0
- github.com/onsi/ginkgo v1.16.5
- github.com/onsi/gomega v1.19.0
- github.com/open-policy-agent/cert-controller v0.4.0
- github.com/open-policy-agent/frameworks/constraint v0.0.0-20221214024800-b745745c4118
+ github.com/google/uuid v1.3.1
+ github.com/onsi/gomega v1.27.7
+ github.com/open-policy-agent/cert-controller v0.8.0
+ github.com/open-policy-agent/frameworks/constraint v0.0.0-20231030230613-2e0cb3d68575
github.com/pkg/errors v0.9.1
- github.com/prometheus/client_golang v1.14.0
- github.com/spf13/cobra v1.6.1
- github.com/stretchr/testify v1.8.1
- go.opencensus.io v0.23.0
- go.uber.org/automaxprocs v1.5.1
- go.uber.org/zap v1.21.0
- golang.org/x/net v0.4.0
- golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2
- golang.org/x/sync v0.1.0
- golang.org/x/time v0.0.0-20220609170525-579cf78fd858
+ github.com/prometheus/client_golang v1.16.0
+ github.com/spf13/cobra v1.7.0
+ github.com/stretchr/testify v1.8.4
+ go.opencensus.io v0.24.0
+ go.uber.org/automaxprocs v1.5.3
+ go.uber.org/zap v1.24.0
+ golang.org/x/net v0.17.0
+ golang.org/x/oauth2 v0.10.0
+ golang.org/x/sync v0.3.0
+ golang.org/x/time v0.3.0
+ google.golang.org/grpc v1.58.2
+ google.golang.org/protobuf v1.31.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
- k8s.io/api v0.24.9
- k8s.io/apiextensions-apiserver v0.24.7
- k8s.io/apimachinery v0.24.9
- k8s.io/client-go v0.24.9
- k8s.io/klog/v2 v2.70.1
- k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
- oras.land/oras-go v1.2.2
- sigs.k8s.io/controller-runtime v0.12.3
+ k8s.io/api v0.27.4
+ k8s.io/apiextensions-apiserver v0.27.4
+ k8s.io/apimachinery v0.27.4
+ k8s.io/client-go v0.27.4
+ k8s.io/klog/v2 v2.90.1
+ k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5
+ oras.land/oras-go v1.2.4
+ sigs.k8s.io/controller-runtime v0.15.0
+ sigs.k8s.io/release-utils v0.7.3
sigs.k8s.io/yaml v1.3.0
)
require (
- cloud.google.com/go/compute v1.6.1 // indirect
- cloud.google.com/go/monitoring v1.5.0 // indirect
+ cloud.google.com/go/compute v1.21.0 // indirect
+ cloud.google.com/go/compute/metadata v0.2.3 // indirect
+ cloud.google.com/go/monitoring v1.15.1 // indirect
+ github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
+ github.com/Microsoft/hcsshim v0.11.0 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
- github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e // indirect
+ github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
- github.com/aws/aws-sdk-go v1.44.23 // indirect
+ github.com/aws/aws-sdk-go v1.43.31 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
- github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
- github.com/cespare/xxhash/v2 v2.1.2 // indirect
- github.com/containerd/containerd v1.6.12 // indirect
- github.com/docker/cli v20.10.21+incompatible // indirect
- github.com/docker/distribution v2.8.1+incompatible // indirect
- github.com/docker/docker v20.10.21+incompatible // indirect
+ github.com/cenkalti/backoff/v4 v4.2.1 // indirect
+ github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
+ github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
+ github.com/containerd/containerd v1.7.6 // indirect
+ github.com/docker/cli v24.0.6+incompatible // indirect
+ github.com/docker/distribution v2.8.2+incompatible // indirect
+ github.com/docker/docker v24.0.6+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
- github.com/docker/go-units v0.4.0 // indirect
- github.com/emicklei/go-restful v2.16.0+incompatible // indirect
- github.com/evanphx/json-patch v5.6.0+incompatible // indirect
+ github.com/docker/go-units v0.5.0 // indirect
+ github.com/emicklei/go-restful/v3 v3.10.1 // indirect
+ github.com/evanphx/json-patch v4.12.0+incompatible // indirect
+ github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
+ github.com/go-chi/chi/v5 v5.0.8 // indirect
+ github.com/go-ini/ini v1.67.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // 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.21.1 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
+ github.com/go-openapi/jsonpointer v0.19.6 // indirect
+ github.com/go-openapi/jsonreference v0.20.1 // indirect
+ github.com/go-openapi/swag v0.22.3 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
- github.com/golang/glog v1.0.0 // indirect
+ github.com/golang/glog v1.1.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
- github.com/golang/protobuf v1.5.2 // indirect
- github.com/google/cel-go v0.10.2 // indirect
- github.com/google/gnostic v0.6.9 // indirect
+ github.com/google/cel-go v0.12.6 // indirect
+ github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/gofuzz v1.2.0 // indirect
- github.com/googleapis/gax-go/v2 v2.4.0 // indirect
+ github.com/google/s2a-go v0.1.4 // indirect
+ github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
+ github.com/googleapis/gax-go/v2 v2.11.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect
- github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/imdario/mergo v0.3.13 // indirect
- github.com/inconshreveable/mousetrap v1.0.1 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
- github.com/klauspost/compress v1.15.1 // indirect
+ github.com/klauspost/compress v1.16.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
@@ -107,51 +114,49 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
- github.com/nxadm/tail v1.4.8 // indirect
- github.com/open-policy-agent/opa v0.47.2 // indirect
+ github.com/open-policy-agent/opa v0.57.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
- github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
+ github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
github.com/pmezard/go-difflib v1.0.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/prometheus/client_model v0.4.0 // indirect
+ github.com/prometheus/common v0.42.0 // indirect
+ github.com/prometheus/procfs v0.10.1 // indirect
github.com/prometheus/prometheus v0.35.0 // indirect
github.com/prometheus/statsd_exporter v0.22.7 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
- github.com/sirupsen/logrus v1.9.0 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
- github.com/yashtewari/glob-intersection v0.1.0 // indirect
- go.opentelemetry.io/contrib v0.20.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 // indirect
- go.opentelemetry.io/otel v1.7.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp v0.20.0 // indirect
- go.opentelemetry.io/otel/metric v0.30.0 // indirect
- go.opentelemetry.io/otel/sdk v1.7.0 // indirect
- go.opentelemetry.io/otel/sdk/export/metric v0.20.0 // indirect
- go.opentelemetry.io/otel/sdk/metric v0.20.0 // indirect
- go.opentelemetry.io/otel/trace v1.7.0 // indirect
- go.opentelemetry.io/proto/otlp v0.16.0 // indirect
- go.uber.org/atomic v1.9.0 // indirect
- go.uber.org/multierr v1.8.0 // indirect
- golang.org/x/sys v0.3.0 // indirect
- golang.org/x/term v0.3.0 // indirect
- golang.org/x/text v0.5.0 // indirect
- gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
- google.golang.org/api v0.81.0 // indirect
+ github.com/yashtewari/glob-intersection v0.2.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
+ go.opentelemetry.io/otel v1.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect
+ go.opentelemetry.io/otel/metric v1.19.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.19.0 // indirect
+ go.opentelemetry.io/otel/trace v1.19.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.0.0 // indirect
+ go.uber.org/atomic v1.11.0 // indirect
+ go.uber.org/multierr v1.6.0 // indirect
+ golang.org/x/crypto v0.14.0 // indirect
+ golang.org/x/mod v0.10.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
+ golang.org/x/term v0.13.0 // indirect
+ golang.org/x/text v0.13.0 // indirect
+ gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
+ google.golang.org/api v0.126.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 // indirect
- google.golang.org/grpc v1.51.0 // indirect
- google.golang.org/protobuf v1.28.1 // indirect
+ google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
- gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
- k8s.io/apiserver v0.24.7 // indirect
- k8s.io/component-base v0.24.7 // indirect
- k8s.io/kube-openapi v0.0.0-20220413171646-5e7f5fdc6da6 // indirect
- sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.33 // indirect
- sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 // indirect
- sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
+ k8s.io/apiserver v0.27.4 // indirect
+ k8s.io/component-base v0.27.4 // indirect
+ k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
+ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 // indirect
+ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
)
diff --git a/go.sum b/go.sum
index 1a71e6e1ebf..d6dd4aefda2 100644
--- a/go.sum
+++ b/go.sum
@@ -28,7 +28,6 @@ cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+Y
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
-cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y=
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
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=
@@ -39,14 +38,15 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
-cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
-cloud.google.com/go/compute v1.6.1 h1:2sMmt8prCn7DPaG4Pmh0N3Inmc8cT8ae5k1M6VJ9Wqc=
-cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
+cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk=
+cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
+cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
+cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
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/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
-cloud.google.com/go/monitoring v1.5.0 h1:ZltYv8e69fJVga7RTthUBGdx4+Pwz6GRF1V3zylERl4=
-cloud.google.com/go/monitoring v1.5.0/go.mod h1:/o9y8NYX5j91JjD/JvGLYbi86kL11OjyJXq2XziLJu4=
+cloud.google.com/go/monitoring v1.15.1 h1:65JhLMd+JiYnXr6j5Z63dUYCuOg770p8a/VC+gil/58=
+cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM=
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=
@@ -56,8 +56,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-cloud.google.com/go/trace v1.2.0 h1:oIaB4KahkIUOpLSAAjEJ8y2desbjY/x/RfP4O3KAtTI=
-cloud.google.com/go/trace v1.2.0/go.mod h1:Wc8y/uYyOhPy12KEnXG9XGrvfMz5F5SrYecQlbW1rwM=
+cloud.google.com/go/trace v1.10.1 h1:EwGdOLCNfYOOPtgqo+D2sDLZmRCEO1AagRTJCU6ztdg=
+cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk=
contrib.go.opencensus.io/exporter/ocagent v0.7.0 h1:BEfdCTXfMV30tLZD8c9n64V/tIZX5+9sXiuFLnrr1k8=
contrib.go.opencensus.io/exporter/ocagent v0.7.0/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY=
contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg=
@@ -66,6 +66,8 @@ contrib.go.opencensus.io/exporter/stackdriver v0.13.14 h1:zBakwHardp9Jcb8sQHcHpX
contrib.go.opencensus.io/exporter/stackdriver v0.13.14/go.mod h1:5pSSGY0Bhuk7waTHuDf4aQ8D2DrhgETRo9fy6k3Xlzc=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v63.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
@@ -102,7 +104,7 @@ github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JP
github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
-github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
+github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
@@ -114,7 +116,8 @@ github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwT
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
-github.com/Microsoft/hcsshim v0.9.5 h1:AbV+VPfTrIVffukazHcpxmz/sRiE6YaMDzHWR9BXZHo=
+github.com/Microsoft/hcsshim v0.11.0 h1:7EFNIY4igHEXUdj1zXgAyU3fLc7QfOKHbkldRVTBdiM=
+github.com/Microsoft/hcsshim v0.11.0/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM=
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
@@ -139,8 +142,8 @@ github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8V
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e h1:GCzyKMDDjSGnlpl3clrdAK7I1AaVoaiKDOYkUzChZzg=
-github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
+github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
+github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -149,7 +152,6 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
@@ -157,9 +159,8 @@ github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:W
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go v1.43.11/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
+github.com/aws/aws-sdk-go v1.43.31 h1:yJZIr8nMV1hXjAvvOLUFqZRJcHV7udPQBfhJqawDzI0=
github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
-github.com/aws/aws-sdk-go v1.44.23 h1:oFvpKJk5qdprnCcuCWk2/CADdvfYtyduQ392bMXjlYI=
-github.com/aws/aws-sdk-go v1.44.23/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
@@ -190,16 +191,19 @@ github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3k
github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
+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/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk=
-github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
+github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.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/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
@@ -228,6 +232,8 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
+github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ=
+github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w=
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
@@ -242,8 +248,8 @@ github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4S
github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
-github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4=
github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8=
+github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
@@ -267,8 +273,8 @@ github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTV
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s=
github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE=
-github.com/containerd/containerd v1.6.12 h1:kJ9b3mOFKf8yqo05Ob+tMoxvt1pbVWhnB0re9Y+k+8c=
-github.com/containerd/containerd v1.6.12/go.mod h1:K4Bw7gjgh4TnkmQY+py/PYQGp4e7xgnHAeg87VeWb3A=
+github.com/containerd/containerd v1.7.6 h1:oNAVsnhPoy4BTPQivLgTzI9Oleml9l/+eYIDYXRCYo8=
+github.com/containerd/containerd v1.7.6/go.mod h1:SY6lrkkuJT40BVNO37tlYTSnKJnP5AXBc0fhx0q+TJ4=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@@ -277,6 +283,7 @@ github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR
github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk=
+github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
@@ -346,7 +353,6 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -358,12 +364,14 @@ github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1S
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
+github.com/dapr/go-sdk v1.8.0 h1:OEleeL3zUTqXxIZ7Vkk3PClAeCh1g8sZ1yR2JFZKfXM=
+github.com/dapr/go-sdk v1.8.0/go.mod h1:MBcTKXg8PmBc8A968tVWQg1Xt+DZtmeVR6zVVVGcmeA=
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/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
-github.com/dgraph-io/badger/v3 v3.2103.4 h1:WE1B07YNTTJTtG9xjBcSW2wn0RJLyiV99h959RKZqM4=
+github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg=
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
@@ -376,17 +384,17 @@ github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aB
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/cli v20.10.21+incompatible h1:qVkgyYUnOLQ98LtXBrwd/duVqPT2X4SHndOuGsfwyhU=
-github.com/docker/cli v20.10.21+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY=
+github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
-github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
+github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.14+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v20.10.21+incompatible h1:UTLdBmHk3bEY+w8qeO5KttOhy6OmXWsl/FEet9Uswog=
-github.com/docker/docker v20.10.21+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE=
+github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
@@ -398,12 +406,15 @@ github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6Uezg
github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
-github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4=
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
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/dominikbraun/graph v0.16.2 h1:EUndsCgHNQDHBdT4Q4M9GBePH3Tt0sV7DDPVWzfbEh4=
+github.com/dominikbraun/graph v0.16.2/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@@ -411,8 +422,8 @@ github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8E
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 v2.16.0+incompatible h1:rgqiKNjTnFQA6kkhFe16D8epTksy9HQ1MyrbDXSdYhM=
-github.com/emicklei/go-restful v2.16.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ=
+github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -422,27 +433,26 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ=
-github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
-github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
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.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/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
-github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
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/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
-github.com/foxcpp/go-mockdns v0.0.0-20210729171921-fb145fc6f897 h1:E52jfcE64UG42SwLmrW0QByONfGynWuzBvm86BoB9z8=
+github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
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=
@@ -454,12 +464,15 @@ github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYis
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
+github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
+github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
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=
@@ -475,13 +488,16 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7
github.com/go-logr/logr v0.2.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.1/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.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/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/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
-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-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
+github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY=
github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
@@ -489,15 +505,16 @@ github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpX
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
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/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.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
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.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
-github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
+github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
+github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g=
github.com/go-openapi/runtime v0.23.1/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
@@ -511,8 +528,9 @@ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
-github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
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-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
@@ -522,6 +540,7 @@ github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
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-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
@@ -569,8 +588,9 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
+github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw=
+github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
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=
@@ -586,6 +606,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
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/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
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=
@@ -603,8 +624,9 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
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.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
-github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
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/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
@@ -613,13 +635,11 @@ github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k
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/cel-go v0.10.2 h1:fJtfqBC/zg/+M0W32IemohwB6u5oFWv1iVGNpgUxan0=
-github.com/google/cel-go v0.10.2/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w=
-github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA=
-github.com/google/flatbuffers v2.0.6+incompatible h1:XHFReMv7nFFusa+CEokzWbzaYocKXI6C7hdU5Kgh9Lw=
+github.com/google/cel-go v0.12.6 h1:kjeKudqV0OygrAqA9fX6J55S8gj+Jre2tckIm5RoG4M=
+github.com/google/cel-go v0.12.6/go.mod h1:Jk7ljRzLBhkmiAwBoUxB1sZSCVBAzkqPF25olK/iRDw=
+github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw=
+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 v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0=
-github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -660,22 +680,26 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20220318212150-b2ab0324ddda h1:KdHPvlgeNEDs8rae032MqFG8LVwcSEivcCjNdVOXRmg=
github.com/google/pprof v0.0.0-20220318212150-b2ab0324ddda/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc=
+github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
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/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
+github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
+github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
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/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
-github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
-github.com/googleapis/gax-go/v2 v2.4.0 h1:dS9eYAjhrE2RjmzYw2XAPvcXfmcQLtFEQWn0CR82awk=
-github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
+github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4=
+github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
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=
@@ -699,8 +723,10 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
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/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
@@ -755,8 +781,8 @@ github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
-github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw=
@@ -796,8 +822,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
-github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
+github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
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.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -806,8 +832,8 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.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=
@@ -879,8 +905,8 @@ github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQ
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
-github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI=
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
+github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg=
github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs=
@@ -910,7 +936,6 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
-github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
@@ -926,10 +951,9 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
-github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
-github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc=
+github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -939,14 +963,14 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
-github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
-github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
-github.com/open-policy-agent/cert-controller v0.4.0 h1:AQntgNq7fsoHgnoKrOk0lpRyab1na09vibeJCX4YBCs=
-github.com/open-policy-agent/cert-controller v0.4.0/go.mod h1:uOQW+2tMU51vSxy1Yt162oVUTMdqLuotC0aObQxrh6k=
-github.com/open-policy-agent/frameworks/constraint v0.0.0-20221214024800-b745745c4118 h1:2i9k9I69KX48JTWxp+u4kfMRNgoP50A6uPPqo93uhow=
-github.com/open-policy-agent/frameworks/constraint v0.0.0-20221214024800-b745745c4118/go.mod h1:sN/YfAskVfaDy234+bETlOymFLDoLdJZvMdACwenxc8=
-github.com/open-policy-agent/opa v0.47.2 h1:9QmIumL6MRPYoXboBDSU/c1fG2PN5J4lo800RK36jrc=
-github.com/open-policy-agent/opa v0.47.2/go.mod h1:I5DbT677OGqfk9gvu5i54oIt0rrVf4B5pedpqDquAXo=
+github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
+github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
+github.com/open-policy-agent/cert-controller v0.8.0 h1:pao3WCLsKGz5dSWSlNUFrNFQdXtVTQ3lVDgk2IelH34=
+github.com/open-policy-agent/cert-controller v0.8.0/go.mod h1:alotCQRwX4M6VEwEgO53FB6nGLSlvah6L0pWxSRslIk=
+github.com/open-policy-agent/frameworks/constraint v0.0.0-20231030230613-2e0cb3d68575 h1:rhln22JjTgsJGL8gDK4qEM372Ei1PPQk4ZTIOKM9WvY=
+github.com/open-policy-agent/frameworks/constraint v0.0.0-20231030230613-2e0cb3d68575/go.mod h1:AaCd/gbQ31R7btHO450Kdp18/Zmvn7hjEt7Qbp+MfJM=
+github.com/open-policy-agent/opa v0.57.1 h1:LAa4Z0UkpjV94nRLy6XCvgOacQ6N1jf8TJLMUIzFRqc=
+github.com/open-policy-agent/opa v0.57.1/go.mod h1:YYcVsWcdOW47owR0zElx8HPYZK60vL0MOPsEmh13us4=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -957,8 +981,8 @@ github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034=
-github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
+github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
+github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
@@ -1012,15 +1036,15 @@ github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
-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_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
+github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.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/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
+github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
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=
@@ -1034,8 +1058,9 @@ github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE=
github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
-github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
+github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
+github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/common/assets v0.1.0/go.mod h1:D17UVUE12bHbim7HzwUvtqm6gwBEaDQ0F+hIGbFbccI=
github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI=
github.com/prometheus/exporter-toolkit v0.7.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g=
@@ -1051,8 +1076,9 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.2.0/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/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
+github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/prometheus/prometheus v0.35.0 h1:N93oX6BrJ2iP3UuE2Uz4Lt+5BkUpaFer3L9CbADzesc=
github.com/prometheus/prometheus v0.35.0/go.mod h1:7HaLx5kEPKJ0GDgbODG0fZgXbQ8K/XjZNJXQmbmgQlY=
github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0=
@@ -1065,6 +1091,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -1091,8 +1118,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
-github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
@@ -1102,7 +1129,6 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
-github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -1110,9 +1136,8 @@ github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKv
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/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
-github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
-github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
-github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
+github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
+github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/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-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -1140,8 +1165,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@@ -1180,12 +1206,11 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
-github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
-github.com/yashtewari/glob-intersection v0.1.0 h1:6gJvMYQlTDOL3dMsPF6J0+26vwX9MB8/1q3uAdhmTrg=
-github.com/yashtewari/glob-intersection v0.1.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok=
+github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg=
+github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -1193,6 +1218,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE=
@@ -1205,12 +1231,9 @@ go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
-go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
-go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
-go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q=
go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE=
go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc=
go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4=
@@ -1224,61 +1247,78 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
-go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
-go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0 h1:Q3C9yzW6I9jqEc8sawxzxZmY48fs9u220KXq6d5s3XU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
-go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0/go.mod h1:PFmBsWbldL1kiWZk9+0LBZz2brhByaGsvp6pRICMlPE=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q=
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
-go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg=
+go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs=
+go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ=
+go.opentelemetry.io/otel v1.6.1/go.mod h1:blzUabWHkX6LJewxvadmzafgh/wnvBSDBdOuwkAtrWQ=
+go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
+go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.1/go.mod h1:NEu79Xo32iVb+0gVNV8PMd7GoWqnyDXRlj04yFjqz40=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.1/go.mod h1:YJ/JbY5ag/tSQFXzH3mtDmHqzF3aFn3DI/aB1n7pt4w=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.1/go.mod h1:UJJXJj0rltNIemDMwkOJyggsvyMG9QHfJeFH0HS5JjM=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.1/go.mod h1:DAKwdo06hFLc0U88O10x4xnb5sc7dDRDqRuiN+io8JE=
-go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8=
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
-go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw=
+go.opentelemetry.io/otel/metric v0.28.0/go.mod h1:TrzsfQAmQaB1PDcdhBauLMk7nyyg9hm+GoQq/ekE9Iw=
+go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
+go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
-go.opentelemetry.io/otel/sdk v0.20.0 h1:JsxtGXd06J8jrnya7fdI/U/MR6yXA5DtbZy+qoHQlr8=
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
-go.opentelemetry.io/otel/sdk/export/metric v0.20.0 h1:c5VRjxCXdQlx1HjzwGdQHzZaVI82b5EbBgOu2ljD92g=
+go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs=
+go.opentelemetry.io/otel/sdk v1.6.1/go.mod h1:IVYrddmFZ+eJqu2k38qD3WezFR2pymCzm8tdxyh3R4E=
+go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
+go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
-go.opentelemetry.io/otel/sdk/metric v0.20.0 h1:7ao1wpzHRVKf0OQ7GIxiQJA6X7DLX9o14gmVon7mMK8=
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
-go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw=
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
-go.opentelemetry.io/proto/otlp v0.7.0 h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8=
+go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk=
+go.opentelemetry.io/otel/trace v1.6.0/go.mod h1:qs7BrU5cZ8dXQHBGxHMOxwME/27YH2qEp4/+tZLLwJE=
+go.opentelemetry.io/otel/trace v1.6.1/go.mod h1:RkFRM1m0puWIq10oxImnGEduNBzxiN7TXluRBtE+5j0=
+go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
+go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ=
+go.opentelemetry.io/proto/otlp v0.12.1/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
+go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
+go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
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.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
-go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
-go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk=
+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/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
+go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
+go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
-go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
-go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
+go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+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/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
-go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
-go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
-go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
-go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
+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-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -1304,8 +1344,9 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
+golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
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=
@@ -1344,7 +1385,9 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
+golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1404,7 +1447,6 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -1414,11 +1456,9 @@ golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qx
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.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
-golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1437,9 +1477,8 @@ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
-golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
-golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 h1:+jnHzr9VPj32ykQVai5DNahi9+NSp7yYuCsl5eAQtL0=
-golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
+golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
+golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
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=
@@ -1452,10 +1491,10 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
-golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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=
@@ -1549,6 +1588,7 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/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-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1578,21 +1618,20 @@ golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
-golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
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-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
-golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
+golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1602,8 +1641,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
-golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
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=
@@ -1612,10 +1652,9 @@ golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
-golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1689,17 +1728,15 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
-golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
-golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
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=
-golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
-gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
-gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
+gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc=
+gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@@ -1737,10 +1774,8 @@ google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQ
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
-google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
-google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
-google.golang.org/api v0.81.0 h1:o8WF5AvfidafWbFjsRyupxyEQJNUWxLZJCK5NXrxZZ8=
-google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko=
+google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o=
+google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw=
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=
@@ -1786,7 +1821,6 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
@@ -1817,7 +1851,6 @@ google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
@@ -1825,15 +1858,12 @@ google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
-google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
-google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
-google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
-google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
-google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
-google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
-google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
-google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 h1:a221mAAEAzq4Lz6ZWRkcS8ptb2mxoxYSt4N68aRyQHM=
-google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
+google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g=
+google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0=
+google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw=
+google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@@ -1868,10 +1898,8 @@ google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
-google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
-google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
+google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
+google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
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=
@@ -1887,8 +1915,9 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -1911,7 +1940,6 @@ gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/telebot.v3 v3.0.0/go.mod h1:7rExV8/0mDDNu9epSrDm/8j22KLaActH1Tbee6YjzWg=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
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=
@@ -1933,8 +1961,8 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
-gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
+gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
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=
@@ -1947,42 +1975,38 @@ k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ=
k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs=
k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8=
-k8s.io/api v0.24.7/go.mod h1:tt+TFsvj8um6tsywVsTdwGdPvQ4IDCMLZXFH5C2BRlU=
-k8s.io/api v0.24.9 h1:KKFyOydOohfc7EZrQ4u3kPUV14DgN4b2O85KxWV+yz0=
-k8s.io/api v0.24.9/go.mod h1:qQOu7t0mNvyvT5NE5rngeVHpBovp8Fd/FEI7CFZrlYY=
-k8s.io/apiextensions-apiserver v0.24.7 h1:bq8kg5Q1eR6/1OaZeE6R4Cj4lBwLRyP8Lsbdrwvys1s=
-k8s.io/apiextensions-apiserver v0.24.7/go.mod h1:BayNIvxdL4Fr78kGoy+nQYscNWaW4bJz8YTRvm9IqrA=
+k8s.io/api v0.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs=
+k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y=
+k8s.io/apiextensions-apiserver v0.27.4 h1:ie1yZG4nY/wvFMIR2hXBeSVq+HfNzib60FjnBYtPGSs=
+k8s.io/apiextensions-apiserver v0.27.4/go.mod h1:KHZaDr5H9IbGEnSskEUp/DsdXe1hMQ7uzpQcYUFt2bM=
k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U=
k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
-k8s.io/apimachinery v0.24.7/go.mod h1:WR5z9Lpw2mOAeDg20iSSrEBRQMY0p2YXVdYpUIgSr4o=
-k8s.io/apimachinery v0.24.9 h1:/oZ2GmA681mpKdt1WlLDIj0YzFRofIDZQZgSEPm7i7A=
-k8s.io/apimachinery v0.24.9/go.mod h1:f8XxPIMUqMHz3z8gD6dsTYIjg1Sy02y2YNaTYY2HEjk=
+k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs=
+k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ=
-k8s.io/apiserver v0.24.7 h1:J5X1BxF0hQ7Ssu5B1P5JikBA633LXsY98oshFSxSqek=
-k8s.io/apiserver v0.24.7/go.mod h1:0VDfpwku0fDEJGSGfmZN0CRy0YJ/3JG/qlNdd6aSc+w=
+k8s.io/apiserver v0.27.4 h1:ncZ0MBR9yQ/Gf34rtu1EK+HqT8In1YpfAUINu/Akvho=
+k8s.io/apiserver v0.27.4/go.mod h1:GDEFRfFZ4/l+pAvwYRnoSfz0K4j3TWiN4WsG2KnRteE=
k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k=
k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0=
k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y=
k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4=
-k8s.io/client-go v0.24.7/go.mod h1:UoQaKAGHRRE77THP0jGUehwqt5javBlv1AoKdpfz3JA=
-k8s.io/client-go v0.24.9 h1:iOTws1W4aUBbC6OROIQmx5qiRWgeyyqUITVQnPOEP4A=
-k8s.io/client-go v0.24.9/go.mod h1:be0fCcgenPyCTGJSFtexn+dMr4jJoUX36Y5UAb1vmls=
+k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk=
+k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc=
k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0=
-k8s.io/code-generator v0.24.7/go.mod h1:1B92gyaTHWnignKkQzbHIyV3hiyRlZ+prNqD6nbajPA=
k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI=
k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI=
-k8s.io/component-base v0.24.7 h1:zQ3SiqZucS1thDB/5UnRV3DQ71eXvmHaLY9GPB9YJYk=
-k8s.io/component-base v0.24.7/go.mod h1:ce5M3pIoOY3DoFbcQ+Y8BMEsRFd3KcrAEjrZIZf0xqw=
+k8s.io/component-base v0.27.4 h1:Wqc0jMKEDGjKXdae8hBXeskRP//vu1m6ypC+gwErj4c=
+k8s.io/component-base v0.27.4/go.mod h1:hoiEETnLc0ioLv6WPeDt8vD34DDeB35MfQnxCARq3kY=
k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
@@ -1992,7 +2016,6 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
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 v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
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=
@@ -2000,48 +2023,46 @@ k8s.io/klog/v2 v2.4.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.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ=
-k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/kube-aggregator v0.23.2 h1:6CoZZqNdFc9benrgSJJ0GQGgFtKjI0y3UwlBbioXtc8=
+k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
+k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-aggregator v0.27.2 h1:jfHoPip+qN/fn3OcrYs8/xMuVYvkJHKo0H0DYciqdns=
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
-k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk=
-k8s.io/kube-openapi v0.0.0-20220413171646-5e7f5fdc6da6 h1:nBQrWPlrNIiw0BsX6a6MKr1itkm0ZS0Nl97kNLitFfI=
-k8s.io/kube-openapi v0.0.0-20220413171646-5e7f5fdc6da6/go.mod h1:daOouuuwd9JXpv1L7Y34iV3yf6nxzipkKMWWlqlvK9M=
+k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
+k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/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-20210930125809-cb0fa318a74b/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-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc=
-k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
-oras.land/oras-go v1.2.2 h1:0E9tOHUfrNH7TCDk5KU0jVBEzCqbfdyuVfGmJ7ZeRPE=
-oras.land/oras-go v1.2.2/go.mod h1:Apa81sKoZPpP7CDciE006tSZ0x3Q3+dOoBcMZ/aNxvw=
+k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 h1:kmDqav+P+/5e1i9tFfHq1qcF3sOrDp+YEkVDAHu7Jwk=
+k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY=
+oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324=
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.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.33 h1:LYqFq+6Cj2D0gFfrJvL7iElD4ET6ir3VDdhDdTK7rgc=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.33/go.mod h1:soWkSNf2tZC7aMibXEqVhCd73GOY5fJikn8qbdzemB0=
-sigs.k8s.io/controller-runtime v0.12.3 h1:FCM8xeY/FI8hoAfh/V4XbbYMY20gElh9yh+A98usMio=
-sigs.k8s.io/controller-runtime v0.12.3/go.mod h1:qKsk4WE6zW2Hfj0G4v10EnNB2jMG1C+NTb8h+DwCoU0=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 h1:trsWhjU5jZrx6UvFu4WzQDrN7Pga4a7Qg+zcfcj64PA=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2/go.mod h1:+qG7ISXqCDVVcyO8hLn12AKVYYUjM7ftlqsqmrhMZE0=
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
-sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
-sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 h1:2sgAQQcY0dEW2SsQwTXhQV4vO6+rSslYx8K3XmM5hqQ=
-sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
+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/release-utils v0.7.3 h1:6pS8x6c5RmdUgR9qcg1LO6hjUzuE4Yo9TGZ3DemrZdM=
+sigs.k8s.io/release-utils v0.7.3/go.mod h1:n0mVez/1PZYZaZUTJmxewxH3RJ/Lf7JUDh7TG1CASOE=
sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.0.3/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.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/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/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
diff --git a/main.go b/main.go
index a94d0066007..18834fa4ed6 100644
--- a/main.go
+++ b/main.go
@@ -16,6 +16,8 @@ limitations under the License.
package main
import (
+ "context"
+ "crypto/tls"
"crypto/x509"
"errors"
"flag"
@@ -27,50 +29,52 @@ import (
"path/filepath"
"time"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- // set GOMAXPROCS to the number of container cores, if known.
- _ "go.uber.org/automaxprocs"
-
"github.com/go-logr/zapr"
"github.com/open-policy-agent/cert-controller/pkg/rotator"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
frameworksexternaldata "github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- api "github.com/open-policy-agent/gatekeeper/apis"
- configv1alpha1 "github.com/open-policy-agent/gatekeeper/apis/config/v1alpha1"
- mutationsv1alpha1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1alpha1"
- mutationsv1beta1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1beta1"
- statusv1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/audit"
- "github.com/open-policy-agent/gatekeeper/pkg/controller"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
- "github.com/open-policy-agent/gatekeeper/pkg/upgrade"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/open-policy-agent/gatekeeper/pkg/version"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
- "github.com/open-policy-agent/gatekeeper/pkg/webhook"
- "github.com/open-policy-agent/gatekeeper/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache"
+ api "github.com/open-policy-agent/gatekeeper/v3/apis"
+ configv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ expansionv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/v1alpha1"
+ expansionv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/v1beta1"
+ mutationsv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1alpha1"
+ mutationsv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1beta1"
+ statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/audit"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/externaldata"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/syncutil"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/upgrade"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/version"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/webhook"
+ _ "go.uber.org/automaxprocs" // set GOMAXPROCS to the number of container cores, if known.
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
- "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
- "k8s.io/client-go/rest"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/healthz"
crzap "sigs.k8s.io/controller-runtime/pkg/log/zap"
- // +kubebuilder:scaffold:imports
+ crWebhook "sigs.k8s.io/controller-runtime/pkg/webhook"
)
const (
@@ -93,21 +97,23 @@ var (
)
var (
- logFile = flag.String("log-file", "", "Log to file, if specified. Default is to log to stderr.")
- logLevel = flag.String("log-level", "INFO", "Minimum log level. For example, DEBUG, INFO, WARNING, ERROR. Defaulted to INFO if unspecified.")
- logLevelKey = flag.String("log-level-key", "level", "JSON key for the log level field, defaults to `level`")
- logLevelEncoder = flag.String("log-level-encoder", "lower", "Encoder for the value of the log level field. Valid values: [`lower`, `capital`, `color`, `capitalcolor`], default: `lower`")
- healthAddr = flag.String("health-addr", ":9090", "The address to which the health endpoint binds.")
- metricsAddr = flag.String("metrics-addr", "0", "The address the metric endpoint binds to.")
- port = flag.Int("port", 443, "port for the server. defaulted to 443 if unspecified ")
- host = flag.String("host", "", "the host address the webhook server listens on. defaults to all addresses.")
- certDir = flag.String("cert-dir", "/certs", "The directory where certs are stored, defaults to /certs")
- disableCertRotation = flag.Bool("disable-cert-rotation", false, "disable automatic generation and rotation of webhook TLS certificates/keys")
- enableProfile = flag.Bool("enable-pprof", false, "enable pprof profiling")
- profilePort = flag.Int("pprof-port", 6060, "port for pprof profiling. defaulted to 6060 if unspecified")
- certServiceName = flag.String("cert-service-name", "gatekeeper-webhook-service", "The service name used to generate the TLS cert's hostname. Defaults to gatekeeper-webhook-service")
- enableTLSHealthcheck = flag.Bool("enable-tls-healthcheck", false, "enable probing webhook API with certificate stored in certDir")
- disabledBuiltins = util.NewFlagSet()
+ logFile = flag.String("log-file", "", "Log to file, if specified. Default is to log to stderr.")
+ logLevel = flag.String("log-level", "INFO", "Minimum log level. For example, DEBUG, INFO, WARNING, ERROR. Defaulted to INFO if unspecified.")
+ logLevelKey = flag.String("log-level-key", "level", "JSON key for the log level field, defaults to `level`")
+ logLevelEncoder = flag.String("log-level-encoder", "lower", "Encoder for the value of the log level field. Valid values: [`lower`, `capital`, `color`, `capitalcolor`], default: `lower`")
+ healthAddr = flag.String("health-addr", ":9090", "The address to which the health endpoint binds.")
+ metricsAddr = flag.String("metrics-addr", "0", "The address the metric endpoint binds to.")
+ port = flag.Int("port", 443, "port for the server. defaulted to 443 if unspecified ")
+ host = flag.String("host", "", "the host address the webhook server listens on. defaults to all addresses.")
+ certDir = flag.String("cert-dir", "/certs", "The directory where certs are stored, defaults to /certs")
+ disableCertRotation = flag.Bool("disable-cert-rotation", false, "disable automatic generation and rotation of webhook TLS certificates/keys")
+ enableProfile = flag.Bool("enable-pprof", false, "enable pprof profiling")
+ profilePort = flag.Int("pprof-port", 6060, "port for pprof profiling. defaulted to 6060 if unspecified")
+ certServiceName = flag.String("cert-service-name", "gatekeeper-webhook-service", "The service name used to generate the TLS cert's hostname. Defaults to gatekeeper-webhook-service")
+ enableTLSHealthcheck = flag.Bool("enable-tls-healthcheck", false, "enable probing webhook API with certificate stored in certDir")
+ disabledBuiltins = util.NewFlagSet()
+ enableK8sCel = flag.Bool("experimental-enable-k8s-native-validation", false, "PROTOTYPE (not stable): enable the validating admission policy driver")
+ externaldataProviderResponseCacheTTL = flag.Duration("external-data-provider-response-cache-ttl", 3*time.Minute, "TTL for the external data provider response cache. Specify the duration in 'h', 'm', or 's' for hours, minutes, or seconds respectively. Defaults to 3 minutes if unspecified. Setting the TTL to 0 disables the cache.")
)
func init() {
@@ -119,6 +125,8 @@ func init() {
_ = statusv1beta1.AddToScheme(scheme)
_ = mutationsv1alpha1.AddToScheme(scheme)
_ = mutationsv1beta1.AddToScheme(scheme)
+ _ = expansionv1alpha1.AddToScheme(scheme)
+ _ = expansionv1beta1.AddToScheme(scheme)
// +kubebuilder:scaffold:scheme
flag.Var(disabledBuiltins, "disable-opa-builtin", "disable opa built-in function, this flag can be declared more than once.")
@@ -140,7 +148,11 @@ func innerMain() int {
setupLog.Info(fmt.Sprintf("Starting profiling on port %d", *profilePort))
go func() {
addr := fmt.Sprintf("%s:%d", "localhost", *profilePort)
- setupLog.Error(http.ListenAndServe(addr, nil), "unable to start profiling server")
+ server := http.Server{
+ Addr: addr,
+ ReadTimeout: 5 * time.Second,
+ }
+ setupLog.Error(server.ListenAndServe(), "unable to start profiling server")
}()
}
@@ -195,7 +207,8 @@ func innerMain() int {
}
config := ctrl.GetConfigOrDie()
- config.UserAgent = version.GetUserAgent()
+ config.UserAgent = version.GetUserAgent("gatekeeper")
+ setupLog.Info("setting up manager", "user agent", config.UserAgent)
var webhooks []rotator.WebhookInfo
webhooks = webhook.AppendValidationWebhookIfEnabled(webhooks)
@@ -205,18 +218,30 @@ func innerMain() int {
// Must be called before ctrl.NewManager!
metrics.DisableRESTClientMetrics()
+ serverOpts := crWebhook.Options{
+ Host: *host,
+ Port: *port,
+ CertDir: *certDir,
+ TLSMinVersion: *webhook.TLSMinVersion,
+ }
+ if *webhook.ClientCAName != "" {
+ serverOpts.ClientCAName = *webhook.ClientCAName
+ serverOpts.TLSOpts = []func(*tls.Config){
+ func(cfg *tls.Config) {
+ cfg.VerifyConnection = webhook.GetCertNameVerifier()
+ },
+ }
+ }
mgr, err := ctrl.NewManager(config, ctrl.Options{
- NewCache: dynamiccache.New,
Scheme: scheme,
MetricsBindAddress: *metricsAddr,
LeaderElection: false,
Port: *port,
Host: *host,
+ WebhookServer: crWebhook.NewServer(serverOpts),
CertDir: *certDir,
HealthProbeBindAddress: *healthAddr,
- MapperProvider: func(c *rest.Config) (meta.RESTMapper, error) {
- return apiutil.NewDynamicRESTMapper(c)
- },
+ MapperProvider: apiutil.NewDynamicRESTMapper,
})
if err != nil {
setupLog.Error(err, "unable to start manager")
@@ -258,7 +283,7 @@ func innerMain() int {
sw := watch.NewSwitch()
// Setup tracker and register readiness probe.
- tracker, err := readiness.SetupTracker(mgr, mutation.Enabled(), *externaldata.ExternalDataEnabled)
+ tracker, err := readiness.SetupTracker(mgr, mutation.Enabled(), *externaldata.ExternalDataEnabled, *expansion.ExpansionEnabled)
if err != nil {
setupLog.Error(err, "unable to register readiness tracker")
return 1
@@ -283,17 +308,19 @@ func innerMain() int {
// Setup controllers asynchronously, they will block for certificate generation if needed.
setupErr := make(chan error)
+ ctx := ctrl.SetupSignalHandler()
go func() {
- setupErr <- setupControllers(mgr, sw, tracker, setupFinished)
+ setupErr <- setupControllers(ctx, mgr, sw, tracker, setupFinished)
}()
setupLog.Info("starting manager")
mgrErr := make(chan error)
go func() {
- if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
+ if err := mgr.Start(ctx); err != nil {
setupLog.Error(err, "problem running manager")
mgrErr <- err
}
+ close(mgrErr)
}()
// block until either setupControllers or mgr has an error, or mgr exits.
@@ -328,18 +355,30 @@ blockingLoop:
return 0
}
-func setupControllers(mgr ctrl.Manager, sw *watch.ControllerSwitch, tracker *readiness.Tracker, setupFinished chan struct{}) error {
+func setupControllers(ctx context.Context, mgr ctrl.Manager, sw *watch.ControllerSwitch, tracker *readiness.Tracker, setupFinished chan struct{}) error {
// Block until the setup (certificate generation) finishes.
<-setupFinished
var providerCache *frameworksexternaldata.ProviderCache
- args := []local.Arg{local.Tracing(false), local.DisableBuiltins(disabledBuiltins.ToSlice()...)}
+ args := []rego.Arg{rego.Tracing(false), rego.DisableBuiltins(disabledBuiltins.ToSlice()...)}
mutationOpts := mutation.SystemOpts{Reporter: mutation.NewStatsReporter()}
if *externaldata.ExternalDataEnabled {
providerCache = frameworksexternaldata.NewCache()
- args = append(args, local.AddExternalDataProviderCache(providerCache))
+ args = append(args, rego.AddExternalDataProviderCache(providerCache))
mutationOpts.ProviderCache = providerCache
+ switch {
+ case *externaldataProviderResponseCacheTTL > 0:
+ providerResponseCache := frameworksexternaldata.NewProviderResponseCache(ctx, *externaldataProviderResponseCacheTTL)
+ args = append(args, rego.AddExternalDataProviderResponseCache(providerResponseCache))
+ case *externaldataProviderResponseCacheTTL == 0:
+ setupLog.Info("external data provider response cache is disabled")
+ default:
+ err := fmt.Errorf("invalid value for external-data-provider-response-cache-ttl: %d", *externaldataProviderResponseCacheTTL)
+ setupLog.Error(err, "unable to create external data provider response cache")
+ return err
+ }
+
certFile := filepath.Join(*certDir, certName)
keyFile := filepath.Join(*certDir, keyName)
@@ -357,19 +396,38 @@ func setupControllers(mgr ctrl.Manager, sw *watch.ControllerSwitch, tracker *rea
}
// register the client cert watcher to the driver
- args = append(args, local.EnableExternalDataClientAuth(), local.AddExternalDataClientCertWatcher(certWatcher))
+ args = append(args, rego.EnableExternalDataClientAuth(), rego.AddExternalDataClientCertWatcher(certWatcher))
// register the client cert watcher to the mutation system
mutationOpts.ClientCertWatcher = certWatcher
}
- // initialize OPA
- driver, err := local.New(args...)
+
+ cfArgs := []constraintclient.Opt{constraintclient.Targets(&target.K8sValidationTarget{})}
+
+ if *webhook.ValidateTemplateRego && *enableK8sCel {
+ err := fmt.Errorf("cannot validate template rego when K8s cel is enabled. Please disable K8s cel by setting --experimental-enable-k8s-native-validation=false or disable template rego validation by setting --validate-template-rego=false")
+ setupLog.Error(err, "unable to set up OPA and K8s native drivers")
+ return err
+ }
+
+ if *enableK8sCel {
+ // initialize K8sValidation
+ k8sDriver, err := k8scel.New()
+ if err != nil {
+ setupLog.Error(err, "unable to set up K8s native driver")
+ return err
+ }
+ cfArgs = append(cfArgs, constraintclient.Driver(k8sDriver))
+ }
+
+ driver, err := rego.New(args...)
if err != nil {
setupLog.Error(err, "unable to set up Driver")
return err
}
+ cfArgs = append(cfArgs, constraintclient.Driver(driver))
- client, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
+ client, err := constraintclient.NewClient(cfArgs...)
if err != nil {
setupLog.Error(err, "unable to set up OPA client")
return err
@@ -377,6 +435,7 @@ func setupControllers(mgr ctrl.Manager, sw *watch.ControllerSwitch, tracker *rea
mutationSystem := mutation.NewSystem(mutationOpts)
expansionSystem := expansion.NewSystem(mutationSystem)
+ pubsubSystem := pubsub.NewSystem()
c := mgr.GetCache()
dc, ok := c.(watch.RemovableCache)
@@ -401,17 +460,44 @@ func setupControllers(mgr ctrl.Manager, sw *watch.ControllerSwitch, tracker *rea
// Setup all Controllers
setupLog.Info("setting up controllers")
- watchSet := watch.NewSet()
+
+ // Events ch will be used to receive events from dynamic watches registered
+ // via the registrar below.
+ events := make(chan event.GenericEvent, 1024)
+ reg, err := wm.NewRegistrar(
+ cachemanager.RegistrarName,
+ events)
+ if err != nil {
+ setupLog.Error(err, "unable to set up watch registrar for cache manager")
+ return err
+ }
+
+ syncMetricsCache := syncutil.NewMetricsCache()
+ cm, err := cachemanager.NewCacheManager(&cachemanager.Config{
+ CfClient: client,
+ SyncMetricsCache: syncMetricsCache,
+ Tracker: tracker,
+ ProcessExcluder: processExcluder,
+ Registrar: reg,
+ Reader: mgr.GetCache(),
+ })
+ if err != nil {
+ setupLog.Error(err, "unable to create cache manager")
+ return err
+ }
+
opts := controller.Dependencies{
- Opa: client,
+ CFClient: client,
WatchManger: wm,
+ SyncEventsCh: events,
+ CacheMgr: cm,
ControllerSwitch: sw,
Tracker: tracker,
ProcessExcluder: processExcluder,
MutationSystem: mutationSystem,
ExpansionSystem: expansionSystem,
ProviderCache: providerCache,
- WatchSet: watchSet,
+ PubsubSystem: pubsubSystem,
}
if err := controller.AddToManager(mgr, &opts); err != nil {
@@ -435,12 +521,13 @@ func setupControllers(mgr ctrl.Manager, sw *watch.ControllerSwitch, tracker *rea
if operations.IsAssigned(operations.Audit) {
setupLog.Info("setting up audit")
- auditCache := audit.NewAuditCacheLister(mgr.GetCache(), watchSet)
+ auditCache := audit.NewAuditCacheLister(mgr.GetCache(), cm)
auditDeps := audit.Dependencies{
Client: client,
ProcessExcluder: processExcluder,
CacheLister: auditCache,
ExpansionSystem: expansionSystem,
+ PubSubSystem: pubsubSystem,
}
if err := audit.AddToManager(mgr, &auditDeps); err != nil {
setupLog.Error(err, "unable to register audit with the manager")
@@ -459,6 +546,7 @@ func setupControllers(mgr ctrl.Manager, sw *watch.ControllerSwitch, tracker *rea
setupLog.Error(err, "unable to register metrics with the manager")
return err
}
+
return nil
}
diff --git a/manifest_staging/charts/gatekeeper/Chart.yaml b/manifest_staging/charts/gatekeeper/Chart.yaml
index 38a5497d03d..695bff1ac0d 100644
--- a/manifest_staging/charts/gatekeeper/Chart.yaml
+++ b/manifest_staging/charts/gatekeeper/Chart.yaml
@@ -4,8 +4,8 @@ name: gatekeeper
icon: https://open-policy-agent.github.io/gatekeeper/website/img/logo.svg
keywords:
- open policy agent
-version: 3.12.0-beta.0
+version: 3.14.0
home: https://github.com/open-policy-agent/gatekeeper
sources:
- https://github.com/open-policy-agent/gatekeeper.git
-appVersion: v3.12.0-beta.0
+appVersion: v3.14.0
diff --git a/manifest_staging/charts/gatekeeper/README.md b/manifest_staging/charts/gatekeeper/README.md
index 6e13a55b341..fe841a46a52 100644
--- a/manifest_staging/charts/gatekeeper/README.md
+++ b/manifest_staging/charts/gatekeeper/README.md
@@ -27,7 +27,8 @@ _See [helm install](https://helm.sh/docs/helm/helm_install/) for command documen
## Upgrade Chart
**Upgrading from < v3.4.0**
-Chart 3.4.0 deprecates support for Helm 2 and also removes the creation of the `gatekeeper-system` Namespace from within the chart. This follows Helm 3 Best Practices.
+Chart 3.4.0 deprecates support for Helm 2 and also removes the creation of the `gatekeeper-system` Namespace from within
+the chart. This follows Helm 3 Best Practices.
Option 1:
A simple way to upgrade is to uninstall first and re-install with 3.4.0 or greater.
@@ -39,7 +40,9 @@ $ helm install -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper --creat
```
Option 2:
-Run the `helm_migrate.sh` script before installing the 3.4.0 or greater chart. This will remove the Helm secret for the original release, while keeping all of the resources. It then updates the annotations of the resources so that the new chart can import and manage them.
+Run the `helm_migrate.sh` script before installing the 3.4.0 or greater chart. This will remove the Helm secret for the
+original release, while keeping all of the resources. It then updates the annotations of the resources so that the new
+chart can import and manage them.
```console
$ helm_migrate.sh
@@ -47,155 +50,178 @@ $ helm install -n gatekeeper-system gatekeeper gatekeeper/gatekeeper
```
**Upgrading from >= v3.4.0**
+
```console
$ helm upgrade -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper
```
_See [helm 2 to 3](https://helm.sh/docs/topics/v2_v3_migration/) for Helm 2 migration documentation._
-
## Exempting Namespace
-The Helm chart automatically sets the Gatekeeper flag `--exempt-namespace={{ .Release.Namespace }}` in order to exempt the namespace where the chart is installed, and adds the `admission.gatekeeper.sh/ignore` label to the namespace during a post-install hook.
+The Helm chart automatically sets the Gatekeeper flag `--exempt-namespace={{ .Release.Namespace }}` in order to exempt
+the namespace where the chart is installed, and adds the `admission.gatekeeper.sh/ignore` label to the namespace during
+a post-install hook.
-_See [Exempting Namespaces](https://open-policy-agent.github.io/gatekeeper/website/docs/exempt-namespaces) for more information._
+_See [Exempting Namespaces](https://open-policy-agent.github.io/gatekeeper/website/docs/exempt-namespaces) for more
+information._
## Parameters
-| Parameter | Description | Default |
-| :-------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------ |
-| postInstall.labelNamespace.enabled | Add labels to the namespace during post install hooks | `true` |
-| postInstall.labelNamespace.extraNamespaces | The extra namespaces that need to have the label during post install hooks | `[]` |
-| postInstall.labelNamespace.extraAnnotations | Extra annotations added to the post install Job | `{}` |
-| postInstall.labelNamespace.image.repository | Image with kubectl to label the namespace | `openpolicyagent/gatekeeper-crds` |
-| postInstall.labelNamespace.image.tag | Image tag | Current release version: `v3.12.0-beta.0` |
-| postInstall.labelNamespace.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
-| postInstall.labelNamespace.image.pullSecrets | Image pullSecrets | `[]` |
-| postInstall.labelNamespace.extraRules | Extra rules for the gatekeeper-update-namespace-label Role | `[]` |
-| postInstall.probeWebhook.enabled | Probe webhook API post install. When enabled along with `postInstall.labelNamespace.enabled`, this probe will run as part of `postInstall.labelNamespace` Job as an initContainer | `true` |
-| postInstall.probeWebhook.image.repository | Image with curl to probe the webhook API | `curlimages/curl` |
-| postInstall.probeWebhook.image.tag | Image tag | `7.83.1` |
-| postInstall.probeWebhook.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
-| postInstall.probeWebhook.image.pullSecrets | Image pullSecrets | `[]` |
-| postInstall.probeWebhook.waitTimeout | Total time to wait for the webhook API to become available | `60` |
-| postInstall.probeWebhook.httpTimeout | HTTP client timeout | `2` |
-| postInstall.probeWebhook.insecureHTTPS | Ignore server SSL certificate | `false` |
-| postInstall.affinity | The affinity to use for pod scheduling in postInstall hook jobs | `{}` |
-| postInstall.tolerations | The tolerations to use for pod scheduling in postInstall hook jobs | `[]` |
-| postInstall.nodeSelector | The node selector to use for pod scheduling in postInstall hook jobs | `kubernetes.io/os: linux` |
-| postInstall.resources | The resource request/limits for the container image in postInstall hook jobs | `{}` |
-| postInstall.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| postUpgrade.labelNamespace.enabled | Add labels to the namespace during post upgrade hooks | `false` |
-| postUpgrade.labelNamespace.extraNamespaces | The extra namespaces that need to have the label during post upgrade hooks | `[]` |
-| postUpgrade.labelNamespace.extraAnnotations | Extra annotations added to the post upgrade Job | `{}` |
-| postUpgrade.labelNamespace.image.repository | Image with kubectl to label the namespace | `openpolicyagent/gatekeeper-crds` |
-| postUpgrade.labelNamespace.image.tag | Image tag | Current release version: `v3.12.0-beta.0` |
-| postUpgrade.labelNamespace.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
-| postUpgrade.labelNamespace.image.pullSecrets | Image pullSecrets | `[]`
-| postUpgrade.affinity | The affinity to use for pod scheduling in postUpgrade hook jobs | `{}` |
-| postUpgrade.tolerations | The tolerations to use for pod scheduling in postUpgrade hook jobs | `[]` |
-| postUpgrade.nodeSelector | The node selector to use for pod scheduling in postUpgrade hook jobs | `kubernetes.io/os: linux` |
-| postUpgrade.resources | The resource request/limits for the container image in postUpgrade hook jobs | `{}` |
-| postUpgrade.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| preUninstall.deleteWebhooks.enabled | Delete webhooks before gatekeeper itself is uninstalled | `false` |
-| preUninstall.deleteWebhooks.image.repository | Image with kubectl to delete the webhooks | `openpolicyagent/gatekeeper-crds` |
-| preUninstall.deleteWebhooks.image.tag | Image tag | Current release version: `v3.12.0-beta.0` |
-| preUninstall.deleteWebhooks.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
-| preUninstall.deleteWebhooks.image.pullSecrets | Image pullSecrets | `[]` |
-| preUninstall.deleteWebhooks.extraRules | Extra rules for the gatekeeper-delete-webhook-configs Role | `[]` |
-| preUninstall.affinity | The affinity to use for pod scheduling in preUninstall hook jobs | `{}` |
-| preUninstall.tolerations | The tolerations to use for pod scheduling in preUninstall hook jobs | `[]` |
-| preUninstall.nodeSelector | The node selector to use for pod scheduling in preUninstall hook jobs | `kubernetes.io/os: linux` |
-| preUninstall.resources | The resource request/limits for the container image in preUninstall hook jobs | `{}` |
-| preUninstall.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| psp.enabled | Enabled PodSecurityPolicy | `true` |
-| upgradeCRDs.enabled | Upgrade CRDs using pre-install/pre-upgrade hooks | `true` |
-| upgradeCRDs.extraRules | Extra rules for the gatekeeper-admin-upgrade-crds ClusterRole | `[]` |
-| crds.affinity | The affinity to use for pod scheduling in crds hook jobs | `{}` |
-| crds.tolerations | The tolerations to use for pod scheduling in crds hook jobs | `[]` |
-| crds.nodeSelector | The node selector to use for pod scheduling in crds hook jobs | `kubernetes.io/os: linux` |
-| crds.resources | The resource request/limits for the container image in crds hook jobs | `{}` |
-| crds.securityContext | Security context applied to the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 65532, "runAsNonRoot": true, "runAsUser": 65532 }` |
-| auditInterval | The frequency with which audit is run | `60` |
-| constraintViolationsLimit | The maximum # of audit violations reported on a constraint | `20` |
-| auditFromCache | Take the roster of resources to audit from the audit cache | `false` |
-| auditChunkSize | Chunk size for listing cluster resources for audit (alpha feature) | `500` |
-| auditMatchKindOnly | Only check resources of the kinds specified in all constraints defined in the cluster. | `false` |
-| disableValidatingWebhook | Disable the validating webhook | `false` |
-| disableMutation | Disable mutation | `false` |
-| validatingWebhookTimeoutSeconds | The timeout for the validating webhook in seconds | `3` |
-| validatingWebhookFailurePolicy | The failurePolicy for the validating webhook | `Ignore` |
-| validatingWebhookAnnotations | The annotations to add to the ValidatingWebhookConfiguration | `{}` |
-| validatingWebhookObjectSelector | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's validation webhook unless measures are taken to control how exemption labels can be set. | `{}` |
-| validatingWebhookCheckIgnoreFailurePolicy | The failurePolicy for the check-ignore-label validating webhook | `Fail` |
-| validatingWebhookExemptNamespacesLabels | Additional namespace labels that will be exempt from the validating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace. | `{}` |
-| validatingWebhookCustomRules | Custom rules for selecting which API resources trigger the webhook. Mutually exclusive with `enableDeleteOperations`. NOTE: If you change this, ensure all your constraints are still being enforced. | `{}` |
-| enableDeleteOperations | Enable validating webhook for delete operations. Does not work with `validatingWebhookCustomRules` | `false` |
-| enableExternalData | Enable external data | `true` |
-| enableGeneratorResourceExpansion | Enable generator resource expansion (alpha feature) | `false` |
-| enableTLSHealthcheck | Enable probing webhook API with certificate stored in certDir | `false` |
-| maxServingThreads | Limit the number of concurrent calls the validation backend made by the validation webhook. -1 limits this value to GOMAXPROCS. Configuring this value may lower max RAM usage and limit CPU throttling, Tuning it can optimize serving capacity. | `-1` |
-| metricsBackends | Metrics exporters to use. Valid exporters are: `prometheus`, `stackdriver`, and `opencensus` | `["prometheus"]` |
-| mutatingWebhookFailurePolicy | The failurePolicy for the mutating webhook | `Ignore` |
-| mutatingWebhookReinvocationPolicy | The reinvocationPolicy for the mutating webhook | `Never` |
-| mutatingWebhookAnnotations | The annotations to add to the MutatingWebhookConfiguration | `{}` |
-| mutatingWebhookExemptNamespacesLabels | Additional namespace labels that will be exempt from the mutating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace. | `{}` |
-| mutatingWebhookObjectSelector | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's mutation webhook unless measures are taken to control how exemption labels can be set. | `{}` |
-| mutatingWebhookTimeoutSeconds | The timeout for the mutating webhook in seconds | `3` |
-| mutatingWebhookCustomRules | Custom rules for selecting which API resources trigger the webhook. NOTE: If you change this, ensure all your constraints are still being enforced. | `{}` |
-| emitAdmissionEvents | Emit K8s events in gatekeeper namespace for admission violations (alpha feature) | `false` |
-| emitAuditEvents | Emit K8s events in gatekeeper namespace for audit violations (alpha feature) | `false` |
-| logDenies | Log detailed info on each deny | `false` |
-| logLevel | Minimum log level | `INFO` |
-| image.pullPolicy | The image pull policy | `IfNotPresent` |
-| image.repository | Image repository | `openpolicyagent/gatekeeper` |
-| image.release | The image release tag to use | Current release version: `v3.12.0-beta.0` |
-| image.pullSecrets | Specify an array of imagePullSecrets | `[]` |
-| resources | The resource request/limits for the container image | limits: 1 CPU, 512Mi, requests: 100mCPU, 256Mi |
-| nodeSelector | The node selector to use for pod scheduling | `kubernetes.io/os: linux` |
-| affinity | The node affinity to use for pod scheduling | `{}` |
-| topologySpreadConstraints | The topology spread constraints to use for pod scheduling | `[]` |
-| tolerations | The tolerations to use for pod scheduling | `[]` |
-| controllerManager.healthPort | Health port for controller manager | `9090` |
-| controllerManager.port | Webhook-server port for controller manager | `8443` |
-| controllerManager.metricsPort | Metrics port for controller manager | `8888` |
-| controllerManager.readinessTimeout | Timeout in seconds for the controller manager's readiness probe | `1` |
-| controllerManager.livenessTimeout | Timeout in seconds for the controller manager's liveness probe | `1` |
-| controllerManager.logLevel | The minimum log level for the controller manager, takes precedence over `logLevel` when specified | `null`
-| controllerManager.priorityClassName | Priority class name for controller manager | `system-cluster-critical` |
-| controllerManager.podSecurityContext | Security context on pod level for controller manager | {fsGroup: 999, suplementalGroups: [999]} |
-| controllerManager.exemptNamespaces | The exact namespaces to exempt by the admission webhook | `[]` |
-| controllerManager.exemptNamespacePrefixes | The namespace prefixes to exempt by the admission webhook | `[]` |
-| controllerManager.hostNetwork | Enables controllerManager to be deployed on hostNetwork | `false` |
-| controllerManager.dnsPolicy | Set the dnsPolicy for controllerManager pods | `ClusterFirst` |
-| controllerManager.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| controllerManager.tlsMinVersion | Set the minimum supported TLS version for validating and mutating webhook servers | `1.3` |
-| controllerManager.extraRules | Extra rules for the gatekeeper-manager-role Role | `[]` |
-| controllerManager.networkPolicy.enabled | Should a network policy for the controller manager be created | `false` |
-| controllerManager.networkPolicy.ingress | Additional ingress rules to be added to the controller manager network policy | `{}` |
-| audit.priorityClassName | Priority class name for audit controller | `system-cluster-critical` |
-| audit.podSecurityContext | Security context for audit on pod level | {fsGroup: 999, suplementalGroups: [999]} |
-| audit.hostNetwork | Enables audit to be deployed on hostNetwork | `false` |
-| audit.dnsPolicy | Set the dnsPolicy for audit pods | `ClusterFirst` |
-| audit.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
-| audit.healthPort | Health port for audit | `9090` |
-| audit.metricsPort | Metrics port for audit | `8888` |
-| audit.readinessTimeout | Timeout in seconds for audit's readiness probe | `1` |
-| audit.livenessTimeout | Timeout in seconds for the audit's liveness probe | `1` |
-| audit.logLevel | The minimum log level for audit, takes precedence over `logLevel` when specified | `null`
-| replicas | The number of Gatekeeper replicas to deploy for the webhook | `3` |
-| podAnnotations | The annotations to add to the Gatekeeper pods | `container.seccomp.security.alpha.kubernetes.io/manager: runtime/default` |
-| podLabels | The labels to add to the Gatekeeper pods | `{}` |
-| podCountLimit | The maximum number of Gatekeeper pods to run | `100` |
-| secretAnnotations | The annotations to add to the Gatekeeper secrets | `{}` |
-| pdb.controllerManager.minAvailable | The number of controller manager pods that must still be available after an eviction | `1` |
-| service.type | Service type | `ClusterIP` |
-| service.loadBalancerIP | The IP address of LoadBalancer service | `` |
-| service.healthzPort | Service port to gatekeeper Webhook health port | `9090` |
-| rbac.create | Enable the creation of RBAC resources | `true` |
-| externalCertInjection.enabled | Enable the injection of an external certificate. This disables automatic certificate generation and rotation | `false` |
-| externalCertInjection.secretName | Name of secret for injected certificate | `gatekeeper-webhook-server-cert` |
+| Parameter | Description | Default |
+|:-----------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| postInstall.labelNamespace.enabled | Add labels to the namespace during post install hooks | `true` |
+| postInstall.labelNamespace.extraNamespaces | The extra namespaces that need to have the label during post install hooks | `[]` |
+| postInstall.labelNamespace.extraAnnotations | Extra annotations added to the post install Job | `{}` |
+| postInstall.labelNamespace.image.repository | Image with kubectl to label the namespace | `openpolicyagent/gatekeeper-crds` |
+| postInstall.labelNamespace.image.tag | Image tag | Current release version: `v3.14.0` |
+| postInstall.labelNamespace.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
+| postInstall.labelNamespace.image.pullSecrets | Image pullSecrets | `[]` |
+| postInstall.labelNamespace.extraRules | Extra rules for the gatekeeper-update-namespace-label Role | `[]` |
+| postInstall.labelNamespace.priorityClassName | Priority class name for gatekeeper-update-namespace-label Job | `` |
+| postInstall.probeWebhook.enabled | Probe webhook API post install. When enabled along with `postInstall.labelNamespace.enabled`, this probe will run as part of `postInstall.labelNamespace` Job as an initContainer | `true` |
+| postInstall.probeWebhook.image.repository | Image with curl to probe the webhook API | `curlimages/curl` |
+| postInstall.probeWebhook.image.tag | Image tag | `7.83.1` |
+| postInstall.probeWebhook.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
+| postInstall.probeWebhook.image.pullSecrets | Image pullSecrets | `[]` |
+| postInstall.probeWebhook.waitTimeout | Total time to wait for the webhook API to become available | `60` |
+| postInstall.probeWebhook.httpTimeout | HTTP client timeout | `2` |
+| postInstall.probeWebhook.insecureHTTPS | Ignore server SSL certificate | `false` |
+| postInstall.probeWebhook.priorityClassName | Priority class name for gatekeeper-probe-webhook-post-install Job | `` |
+| postInstall.affinity | The affinity to use for pod scheduling in postInstall hook jobs | `{}` |
+| postInstall.tolerations | The tolerations to use for pod scheduling in postInstall hook jobs | `[]` |
+| postInstall.nodeSelector | The node selector to use for pod scheduling in postInstall hook jobs | `kubernetes.io/os: linux` |
+| postInstall.resources | The resource request/limits for the container image in postInstall hook jobs | `{}` |
+| postInstall.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| postUpgrade.labelNamespace.enabled | Add labels to the namespace during post upgrade hooks | `false` |
+| postUpgrade.labelNamespace.extraNamespaces | The extra namespaces that need to have the label during post upgrade hooks | `[]` |
+| postUpgrade.labelNamespace.extraAnnotations | Extra annotations added to the post upgrade Job | `{}` |
+| postUpgrade.labelNamespace.image.repository | Image with kubectl to label the namespace | `openpolicyagent/gatekeeper-crds` |
+| postUpgrade.labelNamespace.image.tag | Image tag | Current release version: `v3.14.0` |
+| postUpgrade.labelNamespace.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
+| postUpgrade.labelNamespace.image.pullSecrets | Image pullSecrets | `[]` |
+| postUpgrade.labelNamespace.priorityClassName | Priority class name for gatekeeper-update-namespace-label-post-upgrade Job | `` |
+| postUpgrade.affinity | The affinity to use for pod scheduling in postUpgrade hook jobs | `{}` |
+| postUpgrade.tolerations | The tolerations to use for pod scheduling in postUpgrade hook jobs | `[]` |
+| postUpgrade.nodeSelector | The node selector to use for pod scheduling in postUpgrade hook jobs | `kubernetes.io/os: linux` |
+| postUpgrade.resources | The resource request/limits for the container image in postUpgrade hook jobs | `{}` |
+| postUpgrade.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| preInstall.crdRepository.image.repository | Image with kubectl to update the CRDs. If not set, the `image.crdRepository` is used instead. | `null` |
+| preInstall.crdRepository.image.tag | Image tag | Current release version: `v3.14.0` |
+| preUninstall.deleteWebhookConfigurations.enabled | Delete webhooks before gatekeeper itself is uninstalled | `false` |
+| preUninstall.deleteWebhookConfigurations.image.repository | Image with kubectl to delete the webhooks | `openpolicyagent/gatekeeper-crds` |
+| preUninstall.deleteWebhookConfigurations.image.tag | Image tag | Current release version: `v3.14.0` |
+| preUninstall.deleteWebhookConfigurations.image.pullPolicy | Image pullPolicy | `IfNotPresent` |
+| preUninstall.deleteWebhookConfigurations.image.pullSecrets | Image pullSecrets | `[]` |
+| preUninstall.deleteWebhookConfigurations.extraRules | Extra rules for the gatekeeper-delete-webhook-configs Role | `[]` |
+| preUninstall.deleteWebhookConfigurations.priorityClassName | Priority class name for gatekeeper-delete-webhook-configs Job | `` |
+| preUninstall.affinity | The affinity to use for pod scheduling in preUninstall hook jobs | `{}` |
+| preUninstall.tolerations | The tolerations to use for pod scheduling in preUninstall hook jobs | `[]` |
+| preUninstall.nodeSelector | The node selector to use for pod scheduling in preUninstall hook jobs | `kubernetes.io/os: linux` |
+| preUninstall.resources | The resource request/limits for the container image in preUninstall hook jobs | `{}` |
+| preUninstall.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| psp.enabled | Enabled PodSecurityPolicy | `true` |
+| upgradeCRDs.enabled | Upgrade CRDs using pre-install/pre-upgrade hooks | `true` |
+| upgradeCRDs.extraRules | Extra rules for the gatekeeper-admin-upgrade-crds ClusterRole | `[]` |
+| upgradeCRDs.priorityClassName | Priority class name for gatekeeper-update-crds-hook Job | `` |
+| crds.affinity | The affinity to use for pod scheduling in crds hook jobs | `{}` |
+| crds.tolerations | The tolerations to use for pod scheduling in crds hook jobs | `[]` |
+| crds.nodeSelector | The node selector to use for pod scheduling in crds hook jobs | `kubernetes.io/os: linux` |
+| crds.resources | The resource request/limits for the container image in crds hook jobs | `{}` |
+| crds.securityContext | Security context applied to the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 65532, "runAsNonRoot": true, "runAsUser": 65532 }` |
+| auditInterval | The frequency with which audit is run | `60` |
+| constraintViolationsLimit | The maximum # of audit violations reported on a constraint | `20` |
+| auditFromCache | Take the roster of resources to audit from the audit cache | `false` |
+| auditChunkSize | Chunk size for listing cluster resources for audit (alpha feature) | `500` |
+| auditMatchKindOnly | Only check resources of the kinds specified in all constraints defined in the cluster. | `false` |
+| disableValidatingWebhook | Disable the validating webhook | `false` |
+| disableMutation | Disable mutation | `false` |
+| validatingWebhookName | The name of the `ValidatingWebhookConfiguration` | `gatekeeper-validating-webhook-configuration` |
+| validatingWebhookTimeoutSeconds | The timeout for the validating webhook in seconds | `3` |
+| validatingWebhookFailurePolicy | The failurePolicy for the validating webhook | `Ignore` |
+| validatingWebhookAnnotations | The annotations to add to the ValidatingWebhookConfiguration | `{}` |
+| validatingWebhookObjectSelector | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's validation webhook unless measures are taken to control how exemption labels can be set. | `{}` |
+| validatingWebhookCheckIgnoreFailurePolicy | The failurePolicy for the check-ignore-label validating webhook | `Fail` |
+| validatingWebhookExemptNamespacesLabels | Additional namespace labels that will be exempt from the validating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace. | `{}` |
+| validatingWebhookCustomRules | Custom rules for selecting which API resources trigger the webhook. Mutually exclusive with `enableDeleteOperations`. NOTE: If you change this, ensure all your constraints are still being enforced. | `{}` |
+| validatingWebhookURL | Custom URL for Kubernetes API server to use to reach the validating webhook pod. If not set, the default of connecting via the kubernetes service endpoint is used. | `null` |
+| enableDeleteOperations | Enable validating webhook for delete operations. Does not work with `validatingWebhookCustomRules` | `false` |
+| enableExternalData | Enable external data | `true` |
+| enableGeneratorResourceExpansion | Enable generator resource expansion (beta feature) | `true` |
+| enableTLSHealthcheck | Enable probing webhook API with certificate stored in certDir | `false` |
+| maxServingThreads | Limit the number of concurrent calls the validation backend made by the validation webhook. -1 limits this value to GOMAXPROCS. Configuring this value may lower max RAM usage and limit CPU throttling, Tuning it can optimize serving capacity. | `-1` |
+| metricsBackends | Metrics exporters to use. Valid exporters are: `prometheus`, `stackdriver`, and `opencensus` | `["prometheus"]` |
+| mutatingWebhookName | The name of the `MutatingWebhookConfiguration` | `gatekeeper-mutating-webhook-configuration` |
+| mutatingWebhookFailurePolicy | The failurePolicy for the mutating webhook | `Ignore` |
+| mutatingWebhookReinvocationPolicy | The reinvocationPolicy for the mutating webhook | `Never` |
+| mutatingWebhookAnnotations | The annotations to add to the MutatingWebhookConfiguration | `{}` |
+| mutatingWebhookExemptNamespacesLabels | Additional namespace labels that will be exempt from the mutating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace. | `{}` |
+| mutatingWebhookObjectSelector | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's mutation webhook unless measures are taken to control how exemption labels can be set. | `{}` |
+| mutatingWebhookTimeoutSeconds | The timeout for the mutating webhook in seconds | `3` |
+| mutatingWebhookCustomRules | Custom rules for selecting which API resources trigger the webhook. NOTE: If you change this, ensure all your constraints are still being enforced. | `{}` |
+| mutatingWebhookURL | Custom URL for Kubernetes API server to use to reach the mutating webhook pod. If not set, the default of connecting via the kubernetes service endpoint is used. | `null` |
+| emitAdmissionEvents | Emit K8s events in configurable namespace for admission violations (alpha feature) | `false` |
+| emitAuditEvents | Emit K8s events in configurable namespace for audit violations (alpha feature) | `false` |
+| auditEventsInvolvedNamespace | Emit audit events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Audit events from cluster-scoped resources will continue to generate events in the namespace that Gatekeeper is installed in | `false` |
+| admissionEventsInvolvedNamespace | Emit admission events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Admission events from cluster-scoped resources will continue to generate events in the namespace that Gatekeeper is installed in | `false` |
+| logDenies | Log detailed info on each deny | `false` |
+| logLevel | Minimum log level | `INFO` |
+| image.pullPolicy | The image pull policy | `IfNotPresent` |
+| image.repository | Image repository | `openpolicyagent/gatekeeper` |
+| image.release | The image release tag to use | Current release version: `v3.14.0` |
+| image.pullSecrets | Specify an array of imagePullSecrets | `[]` |
+| resources | The resource request/limits for the container image | limits: 1 CPU, 512Mi, requests: 100mCPU, 256Mi |
+| nodeSelector | The node selector to use for pod scheduling | `kubernetes.io/os: linux` |
+| controllerManager.affinity | The node affinity to use for controller manager pod scheduling | `{}` |
+| controllerManager.topologySpreadConstraints | The topology spread constraints to use for controller manager pod scheduling | `[]` |
+| controllerManager.tolerations | The tolerations to use for controller manager pod scheduling | `[]` |
+| controllerManager.healthPort | Health port for controller manager | `9090` |
+| controllerManager.port | Webhook-server port for controller manager | `8443` |
+| controllerManager.metricsPort | Metrics port for controller manager | `8888` |
+| controllerManager.readinessTimeout | Timeout in seconds for the controller manager's readiness probe | `1` |
+| controllerManager.livenessTimeout | Timeout in seconds for the controller manager's liveness probe | `1` |
+| controllerManager.logLevel | The minimum log level for the controller manager, takes precedence over `logLevel` when specified | `null` |
+| controllerManager.priorityClassName | Priority class name for controller manager | `system-cluster-critical` |
+| controllerManager.podSecurityContext | Security context on pod level for controller manager | {fsGroup: 999, suplementalGroups: [999]} |
+| controllerManager.exemptNamespaces | The exact namespaces to exempt by the admission webhook | `[]` |
+| controllerManager.exemptNamespacePrefixes | The namespace prefixes to exempt by the admission webhook | `[]` |
+| controllerManager.hostNetwork | Enables controllerManager to be deployed on hostNetwork | `false` |
+| controllerManager.dnsPolicy | Set the dnsPolicy for controllerManager pods | `ClusterFirst` |
+| controllerManager.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| controllerManager.tlsMinVersion | Set the minimum supported TLS version for validating and mutating webhook servers | `1.3` |
+| controllerManager.extraRules | Extra rules for the gatekeeper-manager-role Role | `[]` |
+| controllerManager.networkPolicy.enabled | Should a network policy for the controller manager be created | `false` |
+| controllerManager.networkPolicy.ingress | Additional ingress rules to be added to the controller manager network policy | `{}` |
+| controllerManager.strategyType | The strategy type to use for Controller Manager deployment | `RollingUpdate` |
+| audit.affinity | The node affinity to use for audit pod scheduling | `{}` |
+| audit.topologySpreadConstraints | The topology spread constraints to use for audit pod scheduling | `[]` |
+| audit.tolerations | The tolerations to use for audit pod scheduling | `[]` |
+| audit.priorityClassName | Priority class name for audit controller | `system-cluster-critical` |
+| audit.podSecurityContext | Security context for audit on pod level | {fsGroup: 999, suplementalGroups: [999]} |
+| audit.hostNetwork | Enables audit to be deployed on hostNetwork | `false` |
+| audit.dnsPolicy | Set the dnsPolicy for audit pods | `ClusterFirst` |
+| audit.securityContext | Security context applied on the container | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }` |
+| audit.healthPort | Health port for audit | `9090` |
+| audit.metricsPort | Metrics port for audit | `8888` |
+| audit.readinessTimeout | Timeout in seconds for audit's readiness probe | `1` |
+| audit.livenessTimeout | Timeout in seconds for the audit's liveness probe | `1` |
+| audit.logLevel | The minimum log level for audit, takes precedence over `logLevel` when specified | `null` |
+| replicas | The number of Gatekeeper replicas to deploy for the webhook | `3` |
+| podAnnotations | The annotations to add to the Gatekeeper pods | `container.seccomp.security.alpha.kubernetes.io/manager: runtime/default` |
+| podLabels | The labels to add to the Gatekeeper pods | `{}` |
+| podCountLimit | The maximum number of Gatekeeper pods to run | `100` |
+| secretAnnotations | The annotations to add to the Gatekeeper secrets | `{}` |
+| pdb.controllerManager.minAvailable | The number of controller manager pods that must still be available after an eviction | `1` |
+| service.type | Service type | `ClusterIP` |
+| service.loadBalancerIP | The IP address of LoadBalancer service | `` |
+| service.healthzPort | Service port to gatekeeper Webhook health port | `9090` |
+| rbac.create | Enable the creation of RBAC resources | `true` |
+| externalCertInjection.enabled | Enable the injection of an external certificate. This disables automatic certificate generation and rotation | `false` |
+| externalCertInjection.secretName | Name of secret for injected certificate | `gatekeeper-webhook-server-cert` |
+| externaldataProviderResponseCacheTTL | TTL for the external data provider response cache. Specify the duration in 'h', 'm', or 's' for hours, minutes, or seconds respectively. | `3m` |
## Contributing Changes
-Please refer to [Contributing to Helm Chart](https://open-policy-agent.github.io/gatekeeper/website/docs/help#contributing-to-helm-chart) for modifying the Helm chart.
+Please refer
+to [Contributing to Helm Chart](https://open-policy-agent.github.io/gatekeeper/website/docs/help#contributing-to-helm-chart)
+for modifying the Helm chart.
diff --git a/manifest_staging/charts/gatekeeper/crds/assign-customresourcedefinition.yaml b/manifest_staging/charts/gatekeeper/crds/assign-customresourcedefinition.yaml
index ce98648baff..0221a194812 100644
--- a/manifest_staging/charts/gatekeeper/crds/assign-customresourcedefinition.yaml
+++ b/manifest_staging/charts/gatekeeper/crds/assign-customresourcedefinition.yaml
@@ -65,7 +65,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -115,7 +115,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -151,7 +151,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -310,7 +310,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -360,7 +360,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -396,7 +396,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -555,7 +555,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -605,7 +605,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -641,7 +641,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
diff --git a/manifest_staging/charts/gatekeeper/crds/assignimage-customresourcedefinition.yaml b/manifest_staging/charts/gatekeeper/crds/assignimage-customresourcedefinition.yaml
new file mode 100644
index 00000000000..197f2f17933
--- /dev/null
+++ b/manifest_staging/charts/gatekeeper/crds/assignimage-customresourcedefinition.yaml
@@ -0,0 +1,237 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ labels:
+ gatekeeper.sh/system: "yes"
+ name: assignimage.mutations.gatekeeper.sh
+spec:
+ group: mutations.gatekeeper.sh
+ names:
+ kind: AssignImage
+ listKind: AssignImageList
+ plural: assignimage
+ singular: assignimage
+ preserveUnknownFields: false
+ scope: Cluster
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: AssignImage is the Schema for the assignimage 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:
+ properties:
+ name:
+ maxLength: 63
+ type: string
+ type: object
+ spec:
+ description: AssignImageSpec defines the desired state of AssignImage.
+ properties:
+ applyTo:
+ description: ApplyTo lists the specific groups, versions and kinds a mutation will be applied to. This is necessary because every mutation implies part of an object schema and object schemas are associated with specific GVKs.
+ items:
+ description: ApplyTo determines what GVKs items the mutation should apply to. Globs are not allowed.
+ properties:
+ groups:
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ versions:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ location:
+ description: 'Location describes the path to be mutated, for example: `spec.containers[name: main].image`.'
+ type: string
+ match:
+ description: Match allows the user to limit which resources get mutated. Individual match criteria are AND-ed together. An undefined match criteria matches everything.
+ properties:
+ excludedNamespaces:
+ description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
+ items:
+ description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ kinds:
+ items:
+ description: Kinds accepts a list of objects with apiGroups and kinds fields that list the groups/kinds of objects to which the mutation will apply. If multiple groups/kinds objects are specified, only one match is needed for the resource to be in scope.
+ properties:
+ apiGroups:
+ description: APIGroups is the API groups the resources belong to. '*' is all groups. If '*' is present, the length of the slice must be one. Required.
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ labelSelector:
+ description: 'LabelSelector is the combination of two optional fields: `matchLabels` and `matchExpressions`. These two fields provide different methods of selecting or excluding k8s objects based on the label keys and values included in object metadata. All selection expressions from both sections are ANDed to determine if an object meets the cumulative requirements of the selector.'
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ name:
+ description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ namespaceSelector:
+ description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ namespaces:
+ description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
+ items:
+ description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ scope:
+ description: Scope determines if cluster-scoped and/or namespaced-scoped resources are matched. Accepts `*`, `Cluster`, or `Namespaced`. (defaults to `*`)
+ type: string
+ source:
+ description: Source determines whether generated or original resources are matched. Accepts `Generated`|`Original`|`All` (defaults to `All`). A value of `Generated` will only match generated resources, while `Original` will only match regular resources.
+ enum:
+ - All
+ - Generated
+ - Original
+ type: string
+ type: object
+ parameters:
+ description: Parameters define the behavior of the mutator.
+ properties:
+ assignDomain:
+ description: AssignDomain sets the domain component on an image string. The trailing slash should not be included.
+ type: string
+ assignPath:
+ description: AssignPath sets the domain component on an image string.
+ type: string
+ assignTag:
+ description: AssignImage sets the image component on an image string. It must start with a `:` or `@`.
+ type: string
+ pathTests:
+ items:
+ description: "PathTest allows the user to customize how the mutation works if parent paths are missing. It traverses the list in order. All sub paths are tested against the provided condition, if the test fails, the mutation is not applied. All `subPath` entries must be a prefix of `location`. Any glob characters will take on the same value as was used to expand the matching glob in `location`. \n Available Tests: * MustExist - the path must exist or do not mutate * MustNotExist - the path must not exist or do not mutate."
+ properties:
+ condition:
+ description: Condition describes whether the path either MustExist or MustNotExist in the original object
+ enum:
+ - MustExist
+ - MustNotExist
+ type: string
+ subPath:
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ status:
+ description: AssignImageStatus defines the observed state of AssignImage.
+ properties:
+ byPod:
+ items:
+ description: MutatorPodStatusStatus defines the observed state of MutatorPodStatus.
+ properties:
+ enforced:
+ type: boolean
+ errors:
+ items:
+ description: MutatorError represents a single error caught while adding a mutator to a system.
+ properties:
+ message:
+ type: string
+ type:
+ description: Type indicates a specific class of error for use by controller code. If not present, the error should be treated as not matching any known type.
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ type: string
+ mutatorUID:
+ description: Storing the mutator UID allows us to detect drift, such as when a mutator has been recreated after its CRD was deleted out from under it, interrupting the watch
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/manifest_staging/charts/gatekeeper/crds/assignmetadata-customresourcedefinition.yaml b/manifest_staging/charts/gatekeeper/crds/assignmetadata-customresourcedefinition.yaml
index 3a63eef3cb3..65c17ed3ae1 100644
--- a/manifest_staging/charts/gatekeeper/crds/assignmetadata-customresourcedefinition.yaml
+++ b/manifest_staging/charts/gatekeeper/crds/assignmetadata-customresourcedefinition.yaml
@@ -39,13 +39,13 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -95,7 +95,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -131,7 +131,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -250,13 +250,13 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -306,7 +306,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -342,7 +342,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -461,13 +461,13 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -517,7 +517,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -553,7 +553,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
diff --git a/manifest_staging/charts/gatekeeper/crds/config-customresourcedefinition.yaml b/manifest_staging/charts/gatekeeper/crds/config-customresourcedefinition.yaml
index 57826ac09aa..269ca95f9a2 100644
--- a/manifest_staging/charts/gatekeeper/crds/config-customresourcedefinition.yaml
+++ b/manifest_staging/charts/gatekeeper/crds/config-customresourcedefinition.yaml
@@ -39,7 +39,7 @@ spec:
excludedNamespaces:
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
processes:
diff --git a/manifest_staging/charts/gatekeeper/crds/constrainttemplate-customresourcedefinition.yaml b/manifest_staging/charts/gatekeeper/crds/constrainttemplate-customresourcedefinition.yaml
index a4da4e9e90f..737e3aff15b 100644
--- a/manifest_staging/charts/gatekeeper/crds/constrainttemplate-customresourcedefinition.yaml
+++ b/manifest_staging/charts/gatekeeper/crds/constrainttemplate-customresourcedefinition.yaml
@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.10.0
+ controller-gen.kubebuilder.io/version: v0.11.3
labels:
gatekeeper.sh/system: "yes"
name: constrainttemplates.templates.gatekeeper.sh
@@ -61,6 +61,24 @@ spec:
targets:
items:
properties:
+ code:
+ description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
+ items:
+ properties:
+ engine:
+ description: 'The engine used to evaluate the code. Example: "Rego". Required.'
+ type: string
+ source:
+ description: The source code for the template. Required.
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - engine
+ - source
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - engine
+ x-kubernetes-list-type: map
libs:
items:
type: string
@@ -156,6 +174,24 @@ spec:
targets:
items:
properties:
+ code:
+ description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
+ items:
+ properties:
+ engine:
+ description: 'The engine used to evaluate the code. Example: "Rego". Required.'
+ type: string
+ source:
+ description: The source code for the template. Required.
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - engine
+ - source
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - engine
+ x-kubernetes-list-type: map
libs:
items:
type: string
@@ -251,6 +287,24 @@ spec:
targets:
items:
properties:
+ code:
+ description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
+ items:
+ properties:
+ engine:
+ description: 'The engine used to evaluate the code. Example: "Rego". Required.'
+ type: string
+ source:
+ description: The source code for the template. Required.
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - engine
+ - source
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - engine
+ x-kubernetes-list-type: map
libs:
items:
type: string
diff --git a/manifest_staging/charts/gatekeeper/crds/expansiontemplate-customresourcedefinition.yaml b/manifest_staging/charts/gatekeeper/crds/expansiontemplate-customresourcedefinition.yaml
index 042249cf102..9d248f2ccd2 100644
--- a/manifest_staging/charts/gatekeeper/crds/expansiontemplate-customresourcedefinition.yaml
+++ b/manifest_staging/charts/gatekeeper/crds/expansiontemplate-customresourcedefinition.yaml
@@ -68,6 +68,133 @@ spec:
description: TemplateSource specifies the source field on the generator resource to use as the base for expanded resource. For Pod-creating generators, this is usually spec.template
type: string
type: object
+ status:
+ description: ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+ properties:
+ byPod:
+ items:
+ description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
+ type: string
+ type: object
+ type: array
+ type: object
type: object
served: true
storage: true
+ subresources:
+ status: {}
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ description: ExpansionTemplate is the Schema for the ExpansionTemplate 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: ExpansionTemplateSpec defines the desired state of ExpansionTemplate.
+ properties:
+ applyTo:
+ description: ApplyTo lists the specific groups, versions and kinds of generator resources which will be expanded.
+ items:
+ description: ApplyTo determines what GVKs items the mutation should apply to. Globs are not allowed.
+ properties:
+ groups:
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ versions:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ enforcementAction:
+ description: EnforcementAction specifies the enforcement action to be used for resources matching the ExpansionTemplate. Specifying an empty value will use the enforcement action specified by the Constraint in violation.
+ type: string
+ generatedGVK:
+ description: GeneratedGVK specifies the GVK of the resources which the generator resource creates.
+ properties:
+ group:
+ type: string
+ kind:
+ type: string
+ version:
+ type: string
+ type: object
+ templateSource:
+ description: TemplateSource specifies the source field on the generator resource to use as the base for expanded resource. For Pod-creating generators, this is usually spec.template
+ type: string
+ type: object
+ status:
+ description: ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+ properties:
+ byPod:
+ items:
+ description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
diff --git a/manifest_staging/charts/gatekeeper/crds/expansiontemplatepodstatus-customresourcedefinition.yaml b/manifest_staging/charts/gatekeeper/crds/expansiontemplatepodstatus-customresourcedefinition.yaml
new file mode 100644
index 00000000000..8f49b4c5f7f
--- /dev/null
+++ b/manifest_staging/charts/gatekeeper/crds/expansiontemplatepodstatus-customresourcedefinition.yaml
@@ -0,0 +1,62 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ labels:
+ gatekeeper.sh/system: "yes"
+ name: expansiontemplatepodstatuses.status.gatekeeper.sh
+spec:
+ group: status.gatekeeper.sh
+ names:
+ kind: ExpansionTemplatePodStatus
+ listKind: ExpansionTemplatePodStatusList
+ plural: expansiontemplatepodstatuses
+ singular: expansiontemplatepodstatus
+ preserveUnknownFields: false
+ scope: Namespaced
+ versions:
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ description: ExpansionTemplatePodStatus is the Schema for the expansiontemplatepodstatuses 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
+ status:
+ description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
+ type: string
+ type: object
+ type: object
+ served: true
+ storage: true
diff --git a/manifest_staging/charts/gatekeeper/crds/modifyset-customresourcedefinition.yaml b/manifest_staging/charts/gatekeeper/crds/modifyset-customresourcedefinition.yaml
index 1bb1933366d..46574fd369f 100644
--- a/manifest_staging/charts/gatekeeper/crds/modifyset-customresourcedefinition.yaml
+++ b/manifest_staging/charts/gatekeeper/crds/modifyset-customresourcedefinition.yaml
@@ -65,7 +65,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -115,7 +115,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -151,7 +151,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -283,7 +283,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -333,7 +333,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -369,7 +369,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -501,7 +501,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -551,7 +551,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -587,7 +587,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
diff --git a/manifest_staging/charts/gatekeeper/crds/provider-customresourcedefinition.yaml b/manifest_staging/charts/gatekeeper/crds/provider-customresourcedefinition.yaml
index 0deb6f630b1..95e66a8b8aa 100644
--- a/manifest_staging/charts/gatekeeper/crds/provider-customresourcedefinition.yaml
+++ b/manifest_staging/charts/gatekeeper/crds/provider-customresourcedefinition.yaml
@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.10.0
+ controller-gen.kubebuilder.io/version: v0.11.3
labels:
gatekeeper.sh/system: "yes"
name: providers.externaldata.gatekeeper.sh
@@ -41,12 +41,12 @@ spec:
description: Timeout is the timeout when querying the provider.
type: integer
url:
- description: URL is the url for the provider. URL is prefixed with http:// or https://.
+ description: URL is the url for the provider. URL is prefixed with https://.
type: string
type: object
type: object
served: true
- storage: true
+ storage: false
- name: v1beta1
schema:
openAPIV3Schema:
@@ -70,9 +70,9 @@ spec:
description: Timeout is the timeout when querying the provider.
type: integer
url:
- description: URL is the url for the provider. URL is prefixed with http:// or https://.
+ description: URL is the url for the provider. URL is prefixed with https://.
type: string
type: object
type: object
served: true
- storage: false
+ storage: true
diff --git a/manifest_staging/charts/gatekeeper/templates/_helpers.tpl b/manifest_staging/charts/gatekeeper/templates/_helpers.tpl
index 5ab6fe2b456..785d9912656 100644
--- a/manifest_staging/charts/gatekeeper/templates/_helpers.tpl
+++ b/manifest_staging/charts/gatekeeper/templates/_helpers.tpl
@@ -36,10 +36,44 @@ Adds additional pod labels to the common ones
*/}}
{{- define "gatekeeper.podLabels" -}}
{{- if .Values.podLabels }}
-{{- toYaml .Values.podLabels | nindent 8 }}
+{{- toYaml .Values.podLabels }}
{{- end }}
{{- end -}}
+{{/*
+Mandatory labels
+*/}}
+{{- define "gatekeeper.mandatoryLabels" -}}
+app: {{ include "gatekeeper.name" . }}
+chart: {{ include "gatekeeper.name" . }}
+gatekeeper.sh/system: "yes"
+heritage: {{ .Release.Service }}
+release: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "gatekeeper.commonLabels" -}}
+helm.sh/chart: {{ include "gatekeeper.chart" . }}
+{{ include "gatekeeper.selectorLabels" . }}
+{{- if .Chart.Version }}
+app.kubernetes.io/version: {{ .Chart.Version | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- if .Values.commonLabels }}
+{{ toYaml .Values.commonLabels }}
+{{- end }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "gatekeeper.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "gatekeeper.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
{{/*
Output post install webhook probe container entry
*/}}
@@ -47,10 +81,12 @@ Output post install webhook probe container entry
- name: webhook-probe-post
image: "{{ .Values.postInstall.probeWebhook.image.repository }}:{{ .Values.postInstall.probeWebhook.image.tag }}"
imagePullPolicy: {{ .Values.postInstall.probeWebhook.image.pullPolicy }}
- args:
+ command:
- "curl"
+ args:
- "--retry"
- "99999"
+ - "--retry-connrefused"
- "--retry-max-time"
- "{{ .Values.postInstall.probeWebhook.waitTimeout }}"
- "--retry-delay"
diff --git a/manifest_staging/charts/gatekeeper/templates/gatekeeper-admin-podsecuritypolicy.yaml b/manifest_staging/charts/gatekeeper/templates/gatekeeper-admin-podsecuritypolicy.yaml
index 398b1460077..8c02264b024 100644
--- a/manifest_staging/charts/gatekeeper/templates/gatekeeper-admin-podsecuritypolicy.yaml
+++ b/manifest_staging/charts/gatekeeper/templates/gatekeeper-admin-podsecuritypolicy.yaml
@@ -5,11 +5,8 @@ metadata:
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
name: gatekeeper-admin
spec:
allowPrivilegeEscalation: false
diff --git a/manifest_staging/charts/gatekeeper/templates/gatekeeper-audit-deployment.yaml b/manifest_staging/charts/gatekeeper/templates/gatekeeper-audit-deployment.yaml
index 6088a432a3a..1dc1ebac29c 100644
--- a/manifest_staging/charts/gatekeeper/templates/gatekeeper-audit-deployment.yaml
+++ b/manifest_staging/charts/gatekeeper/templates/gatekeeper-audit-deployment.yaml
@@ -13,6 +13,7 @@ metadata:
namespace: '{{ .Release.Namespace }}'
spec:
replicas: 1
+ revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
selector:
matchLabels:
app: '{{ template "gatekeeper.name" . }}'
@@ -28,6 +29,9 @@ spec:
{{- if .Values.podAnnotations }}
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
{{- end }}
+ {{- if .Values.auditPodAnnotations }}
+ {{- toYaml .Values.auditPodAnnotations | trim | nindent 8 }}
+ {{- end }}
labels:
{{- include "gatekeeper.podLabels" . }}
app: '{{ template "gatekeeper.name" . }}'
@@ -51,12 +55,20 @@ spec:
- --audit-interval={{ .Values.auditInterval }}
- --log-level={{ (.Values.audit.logLevel | empty | not) | ternary .Values.audit.logLevel .Values.logLevel }}
- --constraint-violations-limit={{ .Values.constraintViolationsLimit }}
+ - --validating-webhook-configuration-name={{ .Values.validatingWebhookName }}
+ - --mutating-webhook-configuration-name={{ .Values.mutatingWebhookName }}
- --audit-from-cache={{ .Values.auditFromCache }}
- --audit-chunk-size={{ .Values.auditChunkSize }}
- --audit-match-kind-only={{ .Values.auditMatchKindOnly }}
- --emit-audit-events={{ .Values.emitAuditEvents }}
+ - --audit-events-involved-namespace={{ .Values.auditEventsInvolvedNamespace }}
- --operation=audit
- --operation=status
+ {{ if .Values.audit.enablePubsub}}
+ - --enable-pub-sub={{ .Values.audit.enablePubsub }}
+ - --audit-connection={{ .Values.audit.connection }}
+ - --audit-channel={{ .Values.audit.channel }}
+ {{- end }}
{{ if not .Values.disableMutation}}- --operation=mutation-status{{- end }}
- --logtostderr
- --health-addr=:{{ .Values.audit.healthPort }}
@@ -72,6 +84,7 @@ spec:
- --log-file={{ .Values.audit.logFile }}
{{- end }}
- --disable-cert-rotation={{ or .Values.audit.disableCertRotation .Values.externalCertInjection.enabled }}
+ - --external-data-provider-response-cache-ttl={{ .Values.externaldataProviderResponseCacheTTL }}
command:
- /manager
env:
diff --git a/manifest_staging/charts/gatekeeper/templates/gatekeeper-controller-manager-deployment.yaml b/manifest_staging/charts/gatekeeper/templates/gatekeeper-controller-manager-deployment.yaml
index b1e5ea7f737..70c7571c2ce 100644
--- a/manifest_staging/charts/gatekeeper/templates/gatekeeper-controller-manager-deployment.yaml
+++ b/manifest_staging/charts/gatekeeper/templates/gatekeeper-controller-manager-deployment.yaml
@@ -13,6 +13,7 @@ metadata:
namespace: '{{ .Release.Namespace }}'
spec:
replicas: {{ .Values.replicas }}
+ revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
selector:
matchLabels:
app: '{{ template "gatekeeper.name" . }}'
@@ -22,6 +23,8 @@ spec:
gatekeeper.sh/system: "yes"
heritage: '{{ .Release.Service }}'
release: '{{ .Release.Name }}'
+ strategy:
+ type: {{ .Values.controllerManager.strategyType }}
template:
metadata:
annotations:
@@ -54,6 +57,7 @@ spec:
- --logtostderr
- --log-denies={{ .Values.logDenies }}
- --emit-admission-events={{ .Values.emitAdmissionEvents }}
+ - --admission-events-involved-namespace={{ .Values.admissionEventsInvolvedNamespace }}
- --log-level={{ (.Values.controllerManager.logLevel | empty | not) | ternary .Values.controllerManager.logLevel .Values.logLevel }}
- --exempt-namespace={{ .Release.Namespace }}
- --operation=webhook
@@ -64,6 +68,9 @@ spec:
- --disable-cert-rotation={{ .Values.controllerManager.disableCertRotation }}
- --max-serving-threads={{ .Values.maxServingThreads }}
- --tls-min-version={{ .Values.controllerManager.tlsMinVersion }}
+ - --validating-webhook-configuration-name={{ .Values.validatingWebhookName }}
+ - --mutating-webhook-configuration-name={{ .Values.mutatingWebhookName }}
+ - --external-data-provider-response-cache-ttl={{ .Values.externaldataProviderResponseCacheTTL }}
{{ if ne .Values.controllerManager.clientCertName "" }}- --client-cert-name={{ .Values.controllerManager.clientCertName }}{{- end }}
{{- range .Values.metricsBackends}}
@@ -84,6 +91,10 @@ spec:
- --exempt-namespace-prefix={{ . }}
{{- end }}
+ {{- range .Values.controllerManager.exemptNamespaceSuffixes}}
+ - --exempt-namespace-suffix={{ . }}
+ {{- end }}
+
{{- if .Values.controllerManager.logFile}}
- --log-file={{ .Values.controllerManager.logFile }}
{{- end }}
diff --git a/manifest_staging/charts/gatekeeper/templates/gatekeeper-controller-manager-network-policy.yaml b/manifest_staging/charts/gatekeeper/templates/gatekeeper-controller-manager-network-policy.yaml
index e05213feb46..5ac3ca6c2c6 100644
--- a/manifest_staging/charts/gatekeeper/templates/gatekeeper-controller-manager-network-policy.yaml
+++ b/manifest_staging/charts/gatekeeper/templates/gatekeeper-controller-manager-network-policy.yaml
@@ -3,16 +3,15 @@ kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
name: gatekeeper-controller-manager
spec:
ingress:
- from:
- podSelector:
matchLabels:
+ {{- include "gatekeeper.commonLabels" . | nindent 14 }}
app: '{{ template "gatekeeper.name" . }}'
release: '{{ .Release.Name }}'
{{- with .Values.controllerManager.networkPolicy.ingress }}
@@ -20,11 +19,8 @@ spec:
{{- end }}
podSelector:
matchLabels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 6 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 6 }}
control-plane: controller-manager
gatekeeper.sh/operation: webhook
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
{{- end -}}
diff --git a/manifest_staging/charts/gatekeeper/templates/gatekeeper-manager-role-clusterrole.yaml b/manifest_staging/charts/gatekeeper/templates/gatekeeper-manager-role-clusterrole.yaml
index 8b32f96014b..3e55923360c 100644
--- a/manifest_staging/charts/gatekeeper/templates/gatekeeper-manager-role-clusterrole.yaml
+++ b/manifest_staging/charts/gatekeeper/templates/gatekeeper-manager-role-clusterrole.yaml
@@ -11,6 +11,13 @@ metadata:
release: '{{ .Release.Name }}'
name: gatekeeper-manager-role
rules:
+- apiGroups:
+ - ""
+ resources:
+ - events
+ verbs:
+ - create
+ - patch
- apiGroups:
- '*'
resources:
@@ -22,7 +29,7 @@ rules:
- apiGroups:
- admissionregistration.k8s.io
resourceNames:
- - gatekeeper-mutating-webhook-configuration
+ - {{ .Values.mutatingWebhookName }}
resources:
- mutatingwebhookconfigurations
verbs:
@@ -75,6 +82,18 @@ rules:
- patch
- update
- watch
+- apiGroups:
+ - expansion.gatekeeper.sh
+ resources:
+ - '*'
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
- apiGroups:
- externaldata.gatekeeper.sh
resources:
@@ -153,7 +172,7 @@ rules:
- apiGroups:
- admissionregistration.k8s.io
resourceNames:
- - gatekeeper-validating-webhook-configuration
+ - {{ .Values.validatingWebhookName }}
resources:
- validatingwebhookconfigurations
verbs:
diff --git a/manifest_staging/charts/gatekeeper/templates/gatekeeper-mutating-webhook-configuration-mutatingwebhookconfiguration.yaml b/manifest_staging/charts/gatekeeper/templates/gatekeeper-mutating-webhook-configuration-mutatingwebhookconfiguration.yaml
index 30a23b4fb9d..ae85f8d08d3 100644
--- a/manifest_staging/charts/gatekeeper/templates/gatekeeper-mutating-webhook-configuration-mutatingwebhookconfiguration.yaml
+++ b/manifest_staging/charts/gatekeeper/templates/gatekeeper-mutating-webhook-configuration-mutatingwebhookconfiguration.yaml
@@ -9,16 +9,20 @@ metadata:
gatekeeper.sh/system: "yes"
heritage: '{{ .Release.Service }}'
release: '{{ .Release.Name }}'
- name: gatekeeper-mutating-webhook-configuration
+ name: '{{ .Values.mutatingWebhookName }}'
webhooks:
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
+ {{- if .Values.mutatingWebhookURL }}
+ url: https://{{ .Values.mutatingWebhookURL }}/v1/mutate
+ {{- else }}
service:
name: gatekeeper-webhook-service
namespace: '{{ .Release.Namespace }}'
path: /v1/mutate
+ {{- end }}
failurePolicy: {{ .Values.mutatingWebhookFailurePolicy }}
matchPolicy: Exact
name: mutation.gatekeeper.sh
diff --git a/manifest_staging/charts/gatekeeper/templates/gatekeeper-validating-webhook-configuration-validatingwebhookconfiguration.yaml b/manifest_staging/charts/gatekeeper/templates/gatekeeper-validating-webhook-configuration-validatingwebhookconfiguration.yaml
index a51dcef6bd6..933fbbd3c3e 100644
--- a/manifest_staging/charts/gatekeeper/templates/gatekeeper-validating-webhook-configuration-validatingwebhookconfiguration.yaml
+++ b/manifest_staging/charts/gatekeeper/templates/gatekeeper-validating-webhook-configuration-validatingwebhookconfiguration.yaml
@@ -9,16 +9,20 @@ metadata:
gatekeeper.sh/system: "yes"
heritage: '{{ .Release.Service }}'
release: '{{ .Release.Name }}'
- name: gatekeeper-validating-webhook-configuration
+ name: '{{ .Values.validatingWebhookName }}'
webhooks:
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
+ {{- if .Values.validatingWebhookURL }}
+ url: https://{{ .Values.validatingWebhookURL }}/v1/admit
+ {{- else }}
service:
name: gatekeeper-webhook-service
namespace: '{{ .Release.Namespace }}'
path: /v1/admit
+ {{- end }}
failurePolicy: {{ .Values.validatingWebhookFailurePolicy }}
matchPolicy: Exact
name: validation.gatekeeper.sh
diff --git a/manifest_staging/charts/gatekeeper/templates/namespace-post-install.yaml b/manifest_staging/charts/gatekeeper/templates/namespace-post-install.yaml
index 4f84b52b409..41232de4267 100644
--- a/manifest_staging/charts/gatekeeper/templates/namespace-post-install.yaml
+++ b/manifest_staging/charts/gatekeeper/templates/namespace-post-install.yaml
@@ -3,12 +3,10 @@ apiVersion: batch/v1
kind: Job
metadata:
name: gatekeeper-update-namespace-label
+ namespace: {{ .Release.Namespace | quote }}
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install
"helm.sh/hook-weight": "-5"
@@ -22,14 +20,14 @@ spec:
annotations:
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
restartPolicy: OnFailure
+ {{- if .Values.postInstall.labelNamespace.priorityClassName }}
+ priorityClassName: {{ .Values.postInstall.labelNamespace.priorityClassName }}
+ {{- end }}
{{- if .Values.postInstall.labelNamespace.image.pullSecrets }}
imagePullSecrets:
{{- .Values.postInstall.labelNamespace.image.pullSecrets | toYaml | nindent 12 }}
@@ -96,7 +94,9 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: gatekeeper-update-namespace-label
+ namespace: {{ .Release.Namespace | quote }}
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -110,6 +110,7 @@ kind: ClusterRole
metadata:
name: gatekeeper-update-namespace-label
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -141,6 +142,7 @@ kind: ClusterRoleBinding
metadata:
name: gatekeeper-update-namespace-label
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
diff --git a/manifest_staging/charts/gatekeeper/templates/namespace-post-upgrade.yaml b/manifest_staging/charts/gatekeeper/templates/namespace-post-upgrade.yaml
index 43a1dadd9fa..b26abab34e0 100644
--- a/manifest_staging/charts/gatekeeper/templates/namespace-post-upgrade.yaml
+++ b/manifest_staging/charts/gatekeeper/templates/namespace-post-upgrade.yaml
@@ -3,12 +3,10 @@ apiVersion: batch/v1
kind: Job
metadata:
name: gatekeeper-update-namespace-label-post-upgrade
+ namespace: {{ .Release.Namespace | quote }}
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-upgrade
"helm.sh/hook-weight": "-5"
@@ -20,12 +18,9 @@ spec:
template:
metadata:
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
restartPolicy: OnFailure
{{- if .Values.postUpgrade.labelNamespace.image.pullSecrets }}
@@ -33,6 +28,9 @@ spec:
{{- .Values.postUpgrade.labelNamespace.image.pullSecrets | toYaml | nindent 12 }}
{{- end }}
serviceAccount: gatekeeper-update-namespace-label-post-upgrade
+ {{- if .Values.postUpgrade.labelNamespace.priorityClassName }}
+ priorityClassName: {{ .Values.postUpgrade.labelNamespace.priorityClassName }}
+ {{- end }}
containers:
- name: kubectl-label
image: "{{ .Values.postUpgrade.labelNamespace.image.repository }}:{{ .Values.postUpgrade.labelNamespace.image.tag }}"
@@ -89,6 +87,7 @@ kind: ServiceAccount
metadata:
name: gatekeeper-update-namespace-label-post-upgrade
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -102,6 +101,7 @@ kind: ClusterRole
metadata:
name: gatekeeper-update-namespace-label-post-upgrade
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -130,6 +130,7 @@ kind: ClusterRoleBinding
metadata:
name: gatekeeper-update-namespace-label-post-upgrade
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
diff --git a/manifest_staging/charts/gatekeeper/templates/probe-webhook-post-install.yaml b/manifest_staging/charts/gatekeeper/templates/probe-webhook-post-install.yaml
index 5a140d31ce0..e6ef25b594c 100644
--- a/manifest_staging/charts/gatekeeper/templates/probe-webhook-post-install.yaml
+++ b/manifest_staging/charts/gatekeeper/templates/probe-webhook-post-install.yaml
@@ -5,11 +5,8 @@ kind: Job
metadata:
name: gatekeeper-probe-webhook-post-install
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install
"helm.sh/hook-weight": "-5"
@@ -20,14 +17,14 @@ spec:
annotations:
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
restartPolicy: Never
+ {{- if .Values.postInstall.probeWebhook.priorityClassName }}
+ priorityClassName: {{ .Values.postInstall.probeWebhook.priorityClassName }}
+ {{- end }}
{{- if .Values.postInstall.probeWebhook.image.pullSecrets }}
imagePullSecrets:
{{- .Values.postInstall.probeWebhook.image.pullSecrets | toYaml | nindent 12 }}
@@ -44,5 +41,6 @@ spec:
nodeSelector:
{{- toYaml .nodeSelector | nindent 8 }}
{{- end }}
+ backoffLimit: 3
{{- end }}
{{- end }}
diff --git a/manifest_staging/charts/gatekeeper/templates/upgrade-crds-hook.yaml b/manifest_staging/charts/gatekeeper/templates/upgrade-crds-hook.yaml
index cd57573f37a..f9347ad9c7b 100644
--- a/manifest_staging/charts/gatekeeper/templates/upgrade-crds-hook.yaml
+++ b/manifest_staging/charts/gatekeeper/templates/upgrade-crds-hook.yaml
@@ -5,6 +5,7 @@ kind: ClusterRole
metadata:
name: gatekeeper-admin-upgrade-crds
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -26,6 +27,7 @@ kind: ClusterRoleBinding
metadata:
name: gatekeeper-admin-upgrade-crds
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -46,6 +48,7 @@ apiVersion: v1
kind: ServiceAccount
metadata:
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
name: gatekeeper-admin-upgrade-crds
@@ -61,29 +64,23 @@ metadata:
name: gatekeeper-update-crds-hook
namespace: {{ .Release.Namespace }}
labels:
- app: {{ template "gatekeeper.name" . }}
- chart: {{ template "gatekeeper.name" . }}
- gatekeeper.sh/system: "yes"
- heritage: {{ .Release.Service }}
- release: {{ .Release.Name }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-weight: "1"
helm.sh/hook-delete-policy: "hook-succeeded,before-hook-creation"
spec:
- backoffLimit: 0
+ backoffLimit: 3
template:
metadata:
name: gatekeeper-update-crds-hook
annotations:
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
serviceAccountName: gatekeeper-admin-upgrade-crds
restartPolicy: Never
@@ -91,12 +88,23 @@ spec:
imagePullSecrets:
{{- toYaml .Values.image.pullSecrets | nindent 8 }}
{{- end }}
+ {{- if .Values.upgradeCRDs.priorityClassName }}
+ priorityClassName: {{ .Values.upgradeCRDs.priorityClassName }}
+ {{- end }}
containers:
- name: crds-upgrade
- {{- if not .Values.image.release }}
- image: '{{ .Values.image.crdRepository }}'
+ {{- if .Values.preInstall.crdRepository.image.repository }}
+ {{- if not .Values.preInstall.crdRepository.image.tag }}
+ image: '{{ .Values.preInstall.crdRepository.image.repository }}'
+ {{- else }}
+ image: '{{ .Values.preInstall.crdRepository.image.repository }}:{{ .Values.preInstall.crdRepository.image.tag }}'
+ {{- end }}
{{- else }}
+ {{- if not .Values.image.release }}
+ image: '{{ .Values.image.crdRepository }}'
+ {{- else }}
image: '{{ .Values.image.crdRepository }}:{{ .Values.image.release }}'
+ {{- end }}
{{- end }}
imagePullPolicy: '{{ .Values.image.pullPolicy }}'
args:
diff --git a/manifest_staging/charts/gatekeeper/templates/webhook-configs-pre-delete.yaml b/manifest_staging/charts/gatekeeper/templates/webhook-configs-pre-delete.yaml
index d610394de36..fb359b87e16 100644
--- a/manifest_staging/charts/gatekeeper/templates/webhook-configs-pre-delete.yaml
+++ b/manifest_staging/charts/gatekeeper/templates/webhook-configs-pre-delete.yaml
@@ -3,12 +3,10 @@ apiVersion: batch/v1
kind: Job
metadata:
name: gatekeeper-delete-webhook-configs
+ namespace: {{ .Release.Namespace | quote }}
labels:
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 4 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-5"
@@ -19,12 +17,9 @@ spec:
annotations:
{{- toYaml .Values.podAnnotations | trim | nindent 8 }}
labels:
- {{- include "gatekeeper.podLabels" . }}
- app: '{{ template "gatekeeper.name" . }}'
- chart: '{{ template "gatekeeper.name" . }}'
- gatekeeper.sh/system: "yes"
- heritage: '{{ .Release.Service }}'
- release: '{{ .Release.Name }}'
+ {{- include "gatekeeper.podLabels" . | nindent 8 }}
+ {{- include "gatekeeper.mandatoryLabels" . | nindent 8 }}
+ {{- include "gatekeeper.commonLabels" . | nindent 8 }}
spec:
restartPolicy: OnFailure
{{- if .Values.preUninstall.deleteWebhookConfigurations.image.pullSecrets }}
@@ -32,6 +27,9 @@ spec:
{{- .Values.preUninstall.deleteWebhookConfigurations.image.pullSecrets | toYaml | nindent 12 }}
{{- end }}
serviceAccount: gatekeeper-delete-webhook-configs
+ {{- if .Values.preUninstall.deleteWebhookConfigurations.priorityClassName }}
+ priorityClassName: {{ .Values.preUninstall.deleteWebhookConfigurations.priorityClassName }}
+ {{- end }}
containers:
- name: kubectl-delete
image: "{{ .Values.preUninstall.deleteWebhookConfigurations.image.repository }}:{{ .Values.preUninstall.deleteWebhookConfigurations.image.tag }}"
@@ -39,19 +37,19 @@ spec:
args:
- delete
{{- if not .Values.disableValidatingWebhook }}
- - validatingwebhookconfiguration/gatekeeper-validating-webhook-configuration
+ - validatingwebhookconfiguration/{{ .Values.validatingWebhookName }}
{{- end }}
{{- if not .Values.disableMutation }}
- - mutatingwebhookconfiguration/gatekeeper-mutating-webhook-configuration
+ - mutatingwebhookconfiguration/{{ .Values.mutatingWebhookName }}
{{- end }}
resources:
- {{- toYaml .Values.preUninstall.resources | nindent 10 }}
+ {{- toYaml .Values.preUninstall.resources | nindent 12 }}
securityContext:
{{- if .Values.enableRuntimeDefaultSeccompProfile }}
seccompProfile:
type: RuntimeDefault
{{- end }}
- {{- toYaml .Values.preUninstall.securityContext | nindent 10 }}
+ {{- toYaml .Values.preUninstall.securityContext | nindent 12 }}
{{- with .Values.preUninstall }}
nodeSelector:
{{- toYaml .nodeSelector | nindent 8 }}
@@ -65,7 +63,9 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: gatekeeper-delete-webhook-configs
+ namespace: {{ .Release.Namespace | quote }}
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -79,6 +79,7 @@ kind: ClusterRole
metadata:
name: gatekeeper-delete-webhook-configs
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
@@ -92,7 +93,7 @@ rules:
resources:
- validatingwebhookconfigurations
resourceNames:
- - gatekeeper-validating-webhook-configuration
+ - {{ .Values.validatingWebhookName }}
verbs:
- delete
{{- end }}
@@ -102,7 +103,7 @@ rules:
resources:
- mutatingwebhookconfigurations
resourceNames:
- - gatekeeper-mutating-webhook-configuration
+ - {{ .Values.mutatingWebhookName }}
verbs:
- delete
{{- end }}
@@ -117,6 +118,7 @@ kind: ClusterRoleBinding
metadata:
name: gatekeeper-delete-webhook-configs
labels:
+ {{- include "gatekeeper.commonLabels" . | nindent 4 }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
diff --git a/manifest_staging/charts/gatekeeper/values.yaml b/manifest_staging/charts/gatekeeper/values.yaml
index 364f5ed4794..2e4c3a8666f 100644
--- a/manifest_staging/charts/gatekeeper/values.yaml
+++ b/manifest_staging/charts/gatekeeper/values.yaml
@@ -1,4 +1,5 @@
replicas: 3
+revisionHistoryLimit: 10
auditInterval: 60
metricsBackends: ["prometheus"]
auditMatchKindOnly: false
@@ -6,6 +7,7 @@ constraintViolationsLimit: 20
auditFromCache: false
disableMutation: false
disableValidatingWebhook: false
+validatingWebhookName: gatekeeper-validating-webhook-configuration
validatingWebhookTimeoutSeconds: 3
validatingWebhookFailurePolicy: Ignore
validatingWebhookAnnotations: {}
@@ -13,11 +15,13 @@ validatingWebhookExemptNamespacesLabels: {}
validatingWebhookObjectSelector: {}
validatingWebhookCheckIgnoreFailurePolicy: Fail
validatingWebhookCustomRules: {}
+validatingWebhookURL: null
enableDeleteOperations: false
enableExternalData: true
-enableGeneratorResourceExpansion: false
+enableGeneratorResourceExpansion: true
enableTLSHealthcheck: false
maxServingThreads: -1
+mutatingWebhookName: gatekeeper-mutating-webhook-configuration
mutatingWebhookFailurePolicy: Ignore
mutatingWebhookReinvocationPolicy: Never
mutatingWebhookAnnotations: {}
@@ -25,6 +29,7 @@ mutatingWebhookExemptNamespacesLabels: {}
mutatingWebhookObjectSelector: {}
mutatingWebhookTimeoutSeconds: 1
mutatingWebhookCustomRules: {}
+mutatingWebhookURL: null
mutationAnnotations: false
auditChunkSize: 500
logLevel: INFO
@@ -32,13 +37,27 @@ logDenies: false
logMutations: false
emitAdmissionEvents: false
emitAuditEvents: false
+admissionEventsInvolvedNamespace: false
+auditEventsInvolvedNamespace: false
resourceQuota: true
+externaldataProviderResponseCacheTTL: 3m
+image:
+ repository: openpolicyagent/gatekeeper
+ crdRepository: openpolicyagent/gatekeeper-crds
+ release: v3.14.0
+ pullPolicy: IfNotPresent
+ pullSecrets: []
+preInstall:
+ crdRepository:
+ image:
+ repository: null
+ tag: v3.14.0
postUpgrade:
labelNamespace:
enabled: false
image:
repository: openpolicyagent/gatekeeper-crds
- tag: v3.12.0-beta.0
+ tag: v3.14.0
pullPolicy: IfNotPresent
pullSecrets: []
extraNamespaces: []
@@ -49,6 +68,7 @@ postUpgrade:
"pod-security.kubernetes.io/enforce=restricted",
"pod-security.kubernetes.io/enforce-version=v1.24"]
extraAnnotations: {}
+ priorityClassName: ""
affinity: {}
tolerations: []
nodeSelector: {kubernetes.io/os: linux}
@@ -68,7 +88,7 @@ postInstall:
extraRules: []
image:
repository: openpolicyagent/gatekeeper-crds
- tag: v3.12.0-beta.0
+ tag: v3.14.0
pullPolicy: IfNotPresent
pullSecrets: []
extraNamespaces: []
@@ -79,6 +99,7 @@ postInstall:
"pod-security.kubernetes.io/enforce=restricted",
"pod-security.kubernetes.io/enforce-version=v1.24"]
extraAnnotations: {}
+ priorityClassName: ""
probeWebhook:
enabled: true
image:
@@ -89,6 +110,7 @@ postInstall:
waitTimeout: 60
httpTimeout: 2
insecureHTTPS: false
+ priorityClassName: ""
affinity: {}
tolerations: []
nodeSelector: {kubernetes.io/os: linux}
@@ -107,9 +129,10 @@ preUninstall:
enabled: false
image:
repository: openpolicyagent/gatekeeper-crds
- tag: v3.12.0-beta.0
+ tag: v3.14.0
pullPolicy: IfNotPresent
pullSecrets: []
+ priorityClassName: ""
affinity: {}
tolerations: []
nodeSelector: {kubernetes.io/os: linux}
@@ -123,13 +146,8 @@ preUninstall:
runAsGroup: 999
runAsNonRoot: true
runAsUser: 1000
-image:
- repository: openpolicyagent/gatekeeper
- crdRepository: openpolicyagent/gatekeeper-crds
- release: v3.12.0-beta.0
- pullPolicy: IfNotPresent
- pullSecrets: []
podAnnotations: {}
+auditPodAnnotations: {}
podLabels: {}
podCountLimit: "100"
secretAnnotations: {}
@@ -146,8 +164,9 @@ controllerManager:
livenessTimeout: 1
priorityClassName: system-cluster-critical
disableCertRotation: false
- tlsMinVersion: 1.3
+ tlsMinVersion: 1.2
clientCertName: ""
+ strategyType: RollingUpdate
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
@@ -190,6 +209,7 @@ controllerManager:
# - ipBlock:
# cidr: 0.0.0.0/0
audit:
+ enablePubsub: false
hostNetwork: false
dnsPolicy: ClusterFirst
metricsPort: 8888
@@ -197,7 +217,7 @@ audit:
readinessTimeout: 1
livenessTimeout: 1
priorityClassName: system-cluster-critical
- disableCertRotation: true
+ disableCertRotation: false
affinity: {}
tolerations: []
nodeSelector: {kubernetes.io/os: linux}
@@ -246,6 +266,7 @@ psp:
upgradeCRDs:
enabled: true
extraRules: []
+ priorityClassName: ""
rbac:
create: true
externalCertInjection:
diff --git a/manifest_staging/deploy/gatekeeper.yaml b/manifest_staging/deploy/gatekeeper.yaml
index 5b7d55b4d62..2bcb6b94eda 100644
--- a/manifest_staging/deploy/gatekeeper.yaml
+++ b/manifest_staging/deploy/gatekeeper.yaml
@@ -97,7 +97,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -147,7 +147,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -183,7 +183,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -342,7 +342,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -392,7 +392,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -428,7 +428,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -587,7 +587,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -637,7 +637,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -673,7 +673,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -790,6 +790,244 @@ spec:
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ labels:
+ gatekeeper.sh/system: "yes"
+ name: assignimage.mutations.gatekeeper.sh
+spec:
+ group: mutations.gatekeeper.sh
+ names:
+ kind: AssignImage
+ listKind: AssignImageList
+ plural: assignimage
+ singular: assignimage
+ preserveUnknownFields: false
+ scope: Cluster
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: AssignImage is the Schema for the assignimage 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:
+ properties:
+ name:
+ maxLength: 63
+ type: string
+ type: object
+ spec:
+ description: AssignImageSpec defines the desired state of AssignImage.
+ properties:
+ applyTo:
+ description: ApplyTo lists the specific groups, versions and kinds a mutation will be applied to. This is necessary because every mutation implies part of an object schema and object schemas are associated with specific GVKs.
+ items:
+ description: ApplyTo determines what GVKs items the mutation should apply to. Globs are not allowed.
+ properties:
+ groups:
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ versions:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ location:
+ description: 'Location describes the path to be mutated, for example: `spec.containers[name: main].image`.'
+ type: string
+ match:
+ description: Match allows the user to limit which resources get mutated. Individual match criteria are AND-ed together. An undefined match criteria matches everything.
+ properties:
+ excludedNamespaces:
+ description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
+ items:
+ description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ kinds:
+ items:
+ description: Kinds accepts a list of objects with apiGroups and kinds fields that list the groups/kinds of objects to which the mutation will apply. If multiple groups/kinds objects are specified, only one match is needed for the resource to be in scope.
+ properties:
+ apiGroups:
+ description: APIGroups is the API groups the resources belong to. '*' is all groups. If '*' is present, the length of the slice must be one. Required.
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ labelSelector:
+ description: 'LabelSelector is the combination of two optional fields: `matchLabels` and `matchExpressions`. These two fields provide different methods of selecting or excluding k8s objects based on the label keys and values included in object metadata. All selection expressions from both sections are ANDed to determine if an object meets the cumulative requirements of the selector.'
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ name:
+ description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ namespaceSelector:
+ description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ namespaces:
+ description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
+ items:
+ description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ scope:
+ description: Scope determines if cluster-scoped and/or namespaced-scoped resources are matched. Accepts `*`, `Cluster`, or `Namespaced`. (defaults to `*`)
+ type: string
+ source:
+ description: Source determines whether generated or original resources are matched. Accepts `Generated`|`Original`|`All` (defaults to `All`). A value of `Generated` will only match generated resources, while `Original` will only match regular resources.
+ enum:
+ - All
+ - Generated
+ - Original
+ type: string
+ type: object
+ parameters:
+ description: Parameters define the behavior of the mutator.
+ properties:
+ assignDomain:
+ description: AssignDomain sets the domain component on an image string. The trailing slash should not be included.
+ type: string
+ assignPath:
+ description: AssignPath sets the domain component on an image string.
+ type: string
+ assignTag:
+ description: AssignImage sets the image component on an image string. It must start with a `:` or `@`.
+ type: string
+ pathTests:
+ items:
+ description: "PathTest allows the user to customize how the mutation works if parent paths are missing. It traverses the list in order. All sub paths are tested against the provided condition, if the test fails, the mutation is not applied. All `subPath` entries must be a prefix of `location`. Any glob characters will take on the same value as was used to expand the matching glob in `location`. \n Available Tests: * MustExist - the path must exist or do not mutate * MustNotExist - the path must not exist or do not mutate."
+ properties:
+ condition:
+ description: Condition describes whether the path either MustExist or MustNotExist in the original object
+ enum:
+ - MustExist
+ - MustNotExist
+ type: string
+ subPath:
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ status:
+ description: AssignImageStatus defines the observed state of AssignImage.
+ properties:
+ byPod:
+ items:
+ description: MutatorPodStatusStatus defines the observed state of MutatorPodStatus.
+ properties:
+ enforced:
+ type: boolean
+ errors:
+ items:
+ description: MutatorError represents a single error caught while adding a mutator to a system.
+ properties:
+ message:
+ type: string
+ type:
+ description: Type indicates a specific class of error for use by controller code. If not present, the error should be treated as not matching any known type.
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ type: string
+ mutatorUID:
+ description: Storing the mutator UID allows us to detect drift, such as when a mutator has been recreated after its CRD was deleted out from under it, interrupting the watch
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.10.0
@@ -829,13 +1067,13 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -885,7 +1123,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -921,7 +1159,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -1040,13 +1278,13 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -1096,7 +1334,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -1132,7 +1370,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -1251,13 +1489,13 @@ spec:
location:
type: string
match:
- description: Match selects objects to apply mutations to.
+ description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -1307,7 +1545,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -1343,7 +1581,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -1485,7 +1723,7 @@ spec:
excludedNamespaces:
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
processes:
@@ -1689,7 +1927,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.10.0
+ controller-gen.kubebuilder.io/version: v0.11.3
labels:
gatekeeper.sh/system: "yes"
name: constrainttemplates.templates.gatekeeper.sh
@@ -1748,6 +1986,24 @@ spec:
targets:
items:
properties:
+ code:
+ description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
+ items:
+ properties:
+ engine:
+ description: 'The engine used to evaluate the code. Example: "Rego". Required.'
+ type: string
+ source:
+ description: The source code for the template. Required.
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - engine
+ - source
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - engine
+ x-kubernetes-list-type: map
libs:
items:
type: string
@@ -1843,6 +2099,24 @@ spec:
targets:
items:
properties:
+ code:
+ description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
+ items:
+ properties:
+ engine:
+ description: 'The engine used to evaluate the code. Example: "Rego". Required.'
+ type: string
+ source:
+ description: The source code for the template. Required.
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - engine
+ - source
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - engine
+ x-kubernetes-list-type: map
libs:
items:
type: string
@@ -1938,6 +2212,24 @@ spec:
targets:
items:
properties:
+ code:
+ description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
+ items:
+ properties:
+ engine:
+ description: 'The engine used to evaluate the code. Example: "Rego". Required.'
+ type: string
+ source:
+ description: The source code for the template. Required.
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - engine
+ - source
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - engine
+ x-kubernetes-list-type: map
libs:
items:
type: string
@@ -2059,6 +2351,196 @@ spec:
description: TemplateSource specifies the source field on the generator resource to use as the base for expanded resource. For Pod-creating generators, this is usually spec.template
type: string
type: object
+ status:
+ description: ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+ properties:
+ byPod:
+ items:
+ description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ description: ExpansionTemplate is the Schema for the ExpansionTemplate 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: ExpansionTemplateSpec defines the desired state of ExpansionTemplate.
+ properties:
+ applyTo:
+ description: ApplyTo lists the specific groups, versions and kinds of generator resources which will be expanded.
+ items:
+ description: ApplyTo determines what GVKs items the mutation should apply to. Globs are not allowed.
+ properties:
+ groups:
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ versions:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ enforcementAction:
+ description: EnforcementAction specifies the enforcement action to be used for resources matching the ExpansionTemplate. Specifying an empty value will use the enforcement action specified by the Constraint in violation.
+ type: string
+ generatedGVK:
+ description: GeneratedGVK specifies the GVK of the resources which the generator resource creates.
+ properties:
+ group:
+ type: string
+ kind:
+ type: string
+ version:
+ type: string
+ type: object
+ templateSource:
+ description: TemplateSource specifies the source field on the generator resource to use as the base for expanded resource. For Pod-creating generators, this is usually spec.template
+ type: string
+ type: object
+ status:
+ description: ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
+ properties:
+ byPod:
+ items:
+ description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ labels:
+ gatekeeper.sh/system: "yes"
+ name: expansiontemplatepodstatuses.status.gatekeeper.sh
+spec:
+ group: status.gatekeeper.sh
+ names:
+ kind: ExpansionTemplatePodStatus
+ listKind: ExpansionTemplatePodStatusList
+ plural: expansiontemplatepodstatuses
+ singular: expansiontemplatepodstatus
+ preserveUnknownFields: false
+ scope: Namespaced
+ versions:
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ description: ExpansionTemplatePodStatus is the Schema for the expansiontemplatepodstatuses 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
+ status:
+ description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
+ properties:
+ errors:
+ items:
+ properties:
+ message:
+ type: string
+ type:
+ type: string
+ required:
+ - message
+ type: object
+ type: array
+ id:
+ description: 'Important: Run "make" to regenerate code after modifying this file'
+ type: string
+ observedGeneration:
+ format: int64
+ type: integer
+ operations:
+ items:
+ type: string
+ type: array
+ templateUID:
+ description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
+ type: string
+ type: object
type: object
served: true
storage: true
@@ -2130,7 +2612,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -2180,7 +2662,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -2216,7 +2698,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -2348,7 +2830,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -2398,7 +2880,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -2434,7 +2916,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -2566,7 +3048,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@@ -2616,7 +3098,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@@ -2652,7 +3134,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
- pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@@ -2810,7 +3292,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.10.0
+ controller-gen.kubebuilder.io/version: v0.11.3
labels:
gatekeeper.sh/system: "yes"
name: providers.externaldata.gatekeeper.sh
@@ -2849,12 +3331,12 @@ spec:
description: Timeout is the timeout when querying the provider.
type: integer
url:
- description: URL is the url for the provider. URL is prefixed with http:// or https://.
+ description: URL is the url for the provider. URL is prefixed with https://.
type: string
type: object
type: object
served: true
- storage: true
+ storage: false
- name: v1beta1
schema:
openAPIV3Schema:
@@ -2878,12 +3360,12 @@ spec:
description: Timeout is the timeout when querying the provider.
type: integer
url:
- description: URL is the url for the provider. URL is prefixed with http:// or https://.
+ description: URL is the url for the provider. URL is prefixed with https://.
type: string
type: object
type: object
served: true
- storage: false
+ storage: true
---
apiVersion: v1
kind: ServiceAccount
@@ -2930,6 +3412,13 @@ metadata:
gatekeeper.sh/system: "yes"
name: gatekeeper-manager-role
rules:
+- apiGroups:
+ - ""
+ resources:
+ - events
+ verbs:
+ - create
+ - patch
- apiGroups:
- '*'
resources:
@@ -2994,6 +3483,18 @@ rules:
- patch
- update
- watch
+- apiGroups:
+ - expansion.gatekeeper.sh
+ resources:
+ - '*'
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
- apiGroups:
- externaldata.gatekeeper.sh
resources:
@@ -3189,7 +3690,7 @@ spec:
fieldPath: metadata.namespace
- name: CONTAINER_NAME
value: manager
- image: openpolicyagent/gatekeeper:v3.12.0-beta.0
+ image: openpolicyagent/gatekeeper:v3.14.0
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -3306,7 +3807,7 @@ spec:
fieldPath: metadata.namespace
- name: CONTAINER_NAME
value: manager
- image: openpolicyagent/gatekeeper:v3.12.0-beta.0
+ image: openpolicyagent/gatekeeper:v3.14.0
imagePullPolicy: Always
livenessProbe:
httpGet:
diff --git a/pkg/audit/audit_cache_lister.go b/pkg/audit/audit_cache_lister.go
index 64e53b11891..89220128e37 100644
--- a/pkg/audit/audit_cache_lister.go
+++ b/pkg/audit/audit_cache_lister.go
@@ -3,7 +3,6 @@ package audit
import (
"context"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -11,10 +10,10 @@ import (
// NewAuditCacheLister instantiates a new AuditCache which will read objects in
// watched from auditCache.
-func NewAuditCacheLister(auditCache client.Reader, watched *watch.Set) *CacheLister {
+func NewAuditCacheLister(auditCache client.Reader, lister WatchIterator) *CacheLister {
return &CacheLister{
- auditCache: auditCache,
- watched: watched,
+ auditCache: auditCache,
+ watchIterator: lister,
}
}
@@ -25,14 +24,22 @@ type CacheLister struct {
// Caution: only to be read from while watched is locked, such as through
// DoForEach.
auditCache client.Reader
- // watched is the set of objects watched by the audit cache.
- watched *watch.Set
+ // watchIterator is a delegate like CacheManager that we can use to query a watched set of GKVs.
+ // Passing our logic as a callback to a watched.Set allows us to take actions while
+ // holding the lock on the watched.Set. This prevents us from querying the API server
+ // for kinds that aren't currently being watched by the CacheManager.
+ watchIterator WatchIterator
+}
+
+// wraps DoForEach from a watch.Set.
+type WatchIterator interface {
+ DoForEach(listFunc func(gvk schema.GroupVersionKind) error) error
}
// ListObjects lists all objects from the audit cache.
func (l *CacheLister) ListObjects(ctx context.Context) ([]unstructured.Unstructured, error) {
var objs []unstructured.Unstructured
- err := l.watched.DoForEach(func(gvk schema.GroupVersionKind) error {
+ err := l.watchIterator.DoForEach(func(gvk schema.GroupVersionKind) error {
gvkObjects, err := listObjects(ctx, l.auditCache, gvk)
if err != nil {
return err
diff --git a/pkg/audit/controller.go b/pkg/audit/controller.go
index b0c76aa04e8..97f1bba7692 100644
--- a/pkg/audit/controller.go
+++ b/pkg/audit/controller.go
@@ -14,8 +14,9 @@ package audit
import (
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub"
"sigs.k8s.io/controller-runtime/pkg/manager"
)
@@ -24,6 +25,7 @@ type Dependencies struct {
ProcessExcluder *process.Excluder
CacheLister *CacheLister
ExpansionSystem *expansion.System
+ PubSubSystem *pubsub.System
}
// AddToManager adds audit manager to the Manager.
diff --git a/pkg/audit/manager.go b/pkg/audit/manager.go
index 0b3d8d9dbfa..3b12cadc55c 100644
--- a/pkg/audit/manager.go
+++ b/pkg/audit/manager.go
@@ -3,6 +3,7 @@ package audit
import (
"context"
"encoding/json"
+ "errors"
"flag"
"fmt"
"io"
@@ -14,13 +15,15 @@ import (
"github.com/go-logr/logr"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- mutationtypes "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/pkg/errors"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ pubsubController "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/pubsub"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ mutationtypes "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -50,17 +53,23 @@ const (
defaultConstraintViolationsLimit = 20
defaultListLimit = 500
defaultAPICacheDir = "/tmp/audit"
+ defaultConnection = "audit-connection"
+ defaultChannel = "audit-channel"
)
var (
- auditInterval = flag.Uint("audit-interval", defaultAuditInterval, "interval to run audit in seconds. defaulted to 60 secs if unspecified, 0 to disable")
- constraintViolationsLimit = flag.Uint("constraint-violations-limit", defaultConstraintViolationsLimit, "limit of number of violations per constraint. defaulted to 20 violations if unspecified")
- auditChunkSize = flag.Uint64("audit-chunk-size", defaultListLimit, "(alpha) Kubernetes API chunking List results when retrieving cluster resources using discovery client. defaulted to 500 if unspecified")
- auditFromCache = flag.Bool("audit-from-cache", false, "pull resources from audit cache when auditing")
- emitAuditEvents = flag.Bool("emit-audit-events", false, "(alpha) emit Kubernetes events in gatekeeper namespace with detailed info for each violation from an audit")
- auditMatchKindOnly = flag.Bool("audit-match-kind-only", false, "only use kinds specified in all constraints for auditing cluster resources. if kind is not specified in any of the constraints, it will audit all resources (same as setting this flag to false)")
- apiCacheDir = flag.String("api-cache-dir", defaultAPICacheDir, "The directory where audit from api server cache are stored, defaults to /tmp/audit")
- emptyAuditResults []updateListEntry
+ auditInterval = flag.Uint("audit-interval", defaultAuditInterval, "interval to run audit in seconds. defaulted to 60 secs if unspecified, 0 to disable")
+ constraintViolationsLimit = flag.Uint("constraint-violations-limit", defaultConstraintViolationsLimit, "limit of number of violations per constraint. defaulted to 20 violations if unspecified")
+ auditChunkSize = flag.Uint64("audit-chunk-size", defaultListLimit, "(alpha) Kubernetes API chunking List results when retrieving cluster resources using discovery client. defaulted to 500 if unspecified")
+ auditFromCache = flag.Bool("audit-from-cache", false, "audit synced resources from internal cache, bypassing direct queries to Kubernetes API server")
+ emitAuditEvents = flag.Bool("emit-audit-events", false, "(alpha) emit Kubernetes events with detailed info for each violation from an audit")
+ auditEventsInvolvedNamespace = flag.Bool("audit-events-involved-namespace", false, "emit audit events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Audit events from cluster-scoped resources will still follow the default behavior")
+ auditMatchKindOnly = flag.Bool("audit-match-kind-only", false, "only use kinds specified in all constraints for auditing cluster resources. if kind is not specified in any of the constraints, it will audit all resources (same as setting this flag to false)")
+ apiCacheDir = flag.String("api-cache-dir", defaultAPICacheDir, "The directory where audit from api server cache are stored, defaults to /tmp/audit")
+ auditConnection = flag.String("audit-connection", defaultConnection, "Connection name for publishing audit violation messages")
+ auditChannel = flag.String("audit-channel", defaultChannel, "Channel name for publishing audit violation messages")
+ emptyAuditResults []updateListEntry
+ logStatsAudit = flag.Bool("log-stats-audit", false, "(alpha) log stats metrics for the audit run")
)
// Manager allows us to audit resources periodically.
@@ -81,6 +90,7 @@ type Manager struct {
auditCache *CacheLister
expansionSystem *expansion.System
+ pubsubSystem *pubsub.System
}
// StatusViolation represents each violation under status.
@@ -94,6 +104,27 @@ type StatusViolation struct {
EnforcementAction string `json:"enforcementAction"`
}
+// ConstraintMsg represents publish message for each constraint.
+type PubsubMsg struct {
+ ID string `json:"id,omitempty"`
+ Details interface{} `json:"details,omitempty"`
+ EventType string `json:"eventType,omitempty"`
+ Group string `json:"group,omitempty"`
+ Version string `json:"version,omitempty"`
+ Kind string `json:"kind,omitempty"`
+ Name string `json:"name,omitempty"`
+ Namespace string `json:"namespace,omitempty"`
+ Message string `json:"message,omitempty"`
+ EnforcementAction string `json:"enforcementAction,omitempty"`
+ ConstraintAnnotations map[string]string `json:"constraintAnnotations,omitempty"`
+ ResourceGroup string `json:"resourceGroup,omitempty"`
+ ResourceAPIVersion string `json:"resourceAPIVersion,omitempty"`
+ ResourceKind string `json:"resourceKind,omitempty"`
+ ResourceNamespace string `json:"resourceNamespace,omitempty"`
+ ResourceName string `json:"resourceName,omitempty"`
+ ResourceLabels map[string]string `json:"resourceLabels,omitempty"`
+}
+
// updateListEntry holds the information necessary to update the
// audit results in the `status` field of the constraint template.
// Adding data to this struct has a large impact on memory usage.
@@ -154,6 +185,7 @@ func New(mgr manager.Manager, deps *Dependencies) (*Manager, error) {
gkNamespace: util.GetNamespace(),
auditCache: deps.CacheLister,
expansionSystem: deps.ExpansionSystem,
+ pubsubSystem: deps.PubSubSystem,
}
return am, nil
}
@@ -213,16 +245,12 @@ func (am *Manager) audit(ctx context.Context) error {
var res []Result
am.log.Info("Auditing from cache")
res, errs := am.auditFromCache(ctx)
-
am.log.Info("Audit from cache results", "violations", len(res))
for _, err := range errs {
am.log.Error(err, "Auditing")
}
- err := am.addAuditResponsesToUpdateLists(updateLists, res, totalViolationsPerConstraint, totalViolationsPerEnforcementAction, timestamp)
- if errs != nil {
- return err
- }
+ am.addAuditResponsesToUpdateLists(updateLists, res, totalViolationsPerConstraint, totalViolationsPerEnforcementAction, timestamp)
} else {
am.log.Info("Auditing via discovery client")
err := am.auditResources(ctx, constraintsGVKs, updateLists, totalViolationsPerConstraint, totalViolationsPerEnforcementAction, timestamp)
@@ -480,16 +508,36 @@ func (am *Manager) auditFromCache(ctx context.Context) ([]Result, []error) {
ns = nil
}
+ excluded, err := am.skipExcludedNamespace(&obj)
+ if err != nil {
+ am.log.Error(err, "Unable to exclude object namespace for audit from cache %v %s/%s", obj.GroupVersionKind().String(), obj.GetNamespace(), obj.GetName())
+ continue
+ }
+
+ if excluded {
+ am.log.V(logging.DebugLevel).Info("excluding object from audit from cache %v %s/%s", obj.GroupVersionKind().String(), obj.GetNamespace(), obj.GetName())
+ continue
+ }
+
au := &target.AugmentedUnstructured{
Object: obj,
Namespace: ns,
}
- resp, err := am.opa.Review(ctx, au)
+ resp, err := am.opa.Review(ctx, au, drivers.Stats(*logStatsAudit))
if err != nil {
am.log.Error(err, "Unable to review object from audit cache %v %s/%s", obj.GroupVersionKind().String(), obj.GetNamespace(), obj.GetName())
continue
}
+ if *logStatsAudit {
+ logging.LogStatsEntries(
+ am.opa,
+ am.log.WithValues(logging.EventType, "audit_cache_stats"),
+ resp.StatsEntries,
+ "audit from cache review request stats",
+ )
+ }
+
for _, r := range resp.Results() {
results = append(results, Result{
Result: r,
@@ -527,7 +575,6 @@ func (am *Manager) reviewObjects(ctx context.Context, kind string, folderCount i
totalViolationsPerEnforcementAction map[util.EnforcementAction]int64,
timestamp string,
) error {
- var errs []error
for i := 0; i < folderCount; i++ {
// cache directory structure:
// apiCacheDir/kind_folderIndex/fileIndex
@@ -565,7 +612,8 @@ func (am *Manager) reviewObjects(ctx context.Context, kind string, folderCount i
Namespace: ns,
Source: mutationtypes.SourceTypeOriginal,
}
- resp, err := am.opa.Review(ctx, augmentedObj)
+
+ resp, err := am.opa.Review(ctx, augmentedObj, drivers.Stats(*logStatsAudit))
if err != nil {
am.log.Error(err, "Unable to review object from file", "fileName", fileName, "objNs", objNs)
continue
@@ -589,29 +637,31 @@ func (am *Manager) reviewObjects(ctx context.Context, kind string, folderCount i
Namespace: ns,
Source: mutationtypes.SourceTypeGenerated,
}
- resultantResp, err := am.opa.Review(ctx, au)
+ resultantResp, err := am.opa.Review(ctx, au, drivers.Stats(*logStatsAudit))
if err != nil {
am.log.Error(err, "Unable to review expanded object", "objName", (*resultant.Obj).GetName(), "objNs", ns)
continue
}
expansion.OverrideEnforcementAction(resultant.EnforcementAction, resultantResp)
expansion.AggregateResponses(resultant.TemplateName, resp, resultantResp)
+ expansion.AggregateStats(resultant.TemplateName, resp, resultantResp)
+ }
+
+ if *logStatsAudit {
+ logging.LogStatsEntries(
+ am.opa,
+ am.log.WithValues(logging.EventType, "audit_stats"),
+ resp.StatsEntries,
+ "audit review request stats",
+ )
}
if len(resp.Results()) > 0 {
results := ToResults(&augmentedObj.Object, resp)
- err = am.addAuditResponsesToUpdateLists(updateLists, results, totalViolationsPerConstraint, totalViolationsPerEnforcementAction, timestamp)
- if err != nil {
- // updated to not return err immediately
- errs = append(errs, err)
- continue
- }
+ am.addAuditResponsesToUpdateLists(updateLists, results, totalViolationsPerConstraint, totalViolationsPerEnforcementAction, timestamp)
}
}
}
- if len(errs) > 0 {
- return mergeErrors(errs)
- }
return nil
}
@@ -728,7 +778,7 @@ func (am *Manager) addAuditResponsesToUpdateLists(
totalViolationsPerConstraint map[util.KindVersionName]int64,
totalViolationsPerEnforcementAction map[util.EnforcementAction]int64,
timestamp string,
-) error {
+) {
for _, r := range res {
key := util.GetUniqueKey(*r.Constraint)
totalViolationsPerConstraint[key]++
@@ -737,6 +787,8 @@ func (am *Manager) addAuditResponsesToUpdateLists(
gvk := r.obj.GroupVersionKind()
namespace := r.obj.GetNamespace()
name := r.obj.GetName()
+ uid := r.obj.GetUID()
+ rv := r.obj.GetResourceVersion()
ea := util.EnforcementAction(r.EnforcementAction)
// append audit results only if it is below violations limit
@@ -759,11 +811,16 @@ func (am *Manager) addAuditResponsesToUpdateLists(
totalViolationsPerEnforcementAction[ea]++
logViolation(am.log, r.Constraint, ea, gvk, namespace, name, r.Msg, details, r.obj.GetLabels())
+ if *pubsubController.PubsubEnabled {
+ err := am.pubsubSystem.Publish(context.Background(), *auditConnection, *auditChannel, violationMsg(r.Constraint, ea, gvk, namespace, name, r.Msg, details, r.obj.GetLabels(), timestamp))
+ if err != nil {
+ am.log.Error(err, "pubsub audit Publishing")
+ }
+ }
if *emitAuditEvents {
- emitEvent(r.Constraint, timestamp, ea, gvk, namespace, name, r.Msg, am.gkNamespace, am.eventRecorder)
+ emitEvent(r.Constraint, timestamp, ea, gvk, namespace, name, rv, r.Msg, am.gkNamespace, uid, am.eventRecorder)
}
}
- return nil
}
func (am *Manager) writeAuditResults(ctx context.Context, constraintsGVKs []schema.GroupVersionKind, updateLists map[util.KindVersionName][]updateListEntry, timestamp string, totalViolations map[util.KindVersionName]int64) {
@@ -1014,6 +1071,31 @@ func logConstraint(l logr.Logger, gvknn *util.KindVersionName, enforcementAction
)
}
+func violationMsg(constraint *unstructured.Unstructured, enforcementAction util.EnforcementAction, resourceGroupVersionKind schema.GroupVersionKind, rnamespace, rname, message string, details interface{}, rlabels map[string]string, timestamp string) interface{} {
+ userConstraintAnnotations := constraint.GetAnnotations()
+ delete(userConstraintAnnotations, "kubectl.kubernetes.io/last-applied-configuration")
+
+ return PubsubMsg{
+ Message: message,
+ Details: details,
+ ID: timestamp,
+ EventType: "violation_audited",
+ Group: constraint.GroupVersionKind().Group,
+ Version: constraint.GroupVersionKind().Version,
+ Kind: constraint.GetKind(),
+ Name: constraint.GetName(),
+ Namespace: constraint.GetNamespace(),
+ EnforcementAction: string(enforcementAction),
+ ConstraintAnnotations: userConstraintAnnotations,
+ ResourceGroup: resourceGroupVersionKind.Group,
+ ResourceAPIVersion: resourceGroupVersionKind.Version,
+ ResourceKind: resourceGroupVersionKind.Kind,
+ ResourceNamespace: rnamespace,
+ ResourceName: rname,
+ ResourceLabels: rlabels,
+ }
+}
+
func logViolation(l logr.Logger,
constraint *unstructured.Unstructured,
enforcementAction util.EnforcementAction, resourceGroupVersionKind schema.GroupVersionKind, rnamespace, rname, message string, details interface{}, rlabels map[string]string,
@@ -1042,7 +1124,7 @@ func logViolation(l logr.Logger,
}
func emitEvent(constraint *unstructured.Unstructured,
- timestamp string, enforcementAction util.EnforcementAction, resourceGroupVersionKind schema.GroupVersionKind, rnamespace, rname, message, gkNamespace string,
+ timestamp string, enforcementAction util.EnforcementAction, resourceGroupVersionKind schema.GroupVersionKind, rnamespace, rname, rrv, message, gkNamespace string, ruid types.UID,
eventRecorder record.EventRecorder,
) {
annotations := map[string]string{
@@ -1061,19 +1143,34 @@ func emitEvent(constraint *unstructured.Unstructured,
logging.ResourceNamespace: rnamespace,
logging.ResourceName: rname,
}
+
reason := "AuditViolation"
- ref := getViolationRef(gkNamespace, resourceGroupVersionKind.Kind, rname, rnamespace, constraint.GetKind(), constraint.GetName(), constraint.GetNamespace())
+ ref := getViolationRef(gkNamespace, resourceGroupVersionKind.Kind, rname, rnamespace, rrv, ruid, constraint.GetKind(), constraint.GetName(), constraint.GetNamespace(), *auditEventsInvolvedNamespace)
- eventRecorder.AnnotatedEventf(ref, annotations, corev1.EventTypeWarning, reason, "Timestamp: %s, Resource Namespace: %s, Constraint: %s, Message: %s", timestamp, rnamespace, constraint.GetName(), message)
+ if *auditEventsInvolvedNamespace {
+ eventRecorder.AnnotatedEventf(ref, annotations, corev1.EventTypeWarning, reason, "Constraint: %s, Message: %s", constraint.GetName(), message)
+ } else {
+ eventRecorder.AnnotatedEventf(ref, annotations, corev1.EventTypeWarning, reason, "Resource Namespace: %s, Constraint: %s, Message: %s", rnamespace, constraint.GetName(), message)
+ }
}
-func getViolationRef(gkNamespace, rkind, rname, rnamespace, ckind, cname, cnamespace string) *corev1.ObjectReference {
- return &corev1.ObjectReference{
+func getViolationRef(gkNamespace, rkind, rname, rnamespace, rrv string, ruid types.UID, ckind, cname, cnamespace string, emitInvolvedNamespace bool) *corev1.ObjectReference {
+ enamespace := gkNamespace
+ if emitInvolvedNamespace && len(rnamespace) > 0 {
+ enamespace = rnamespace
+ }
+ ref := &corev1.ObjectReference{
Kind: rkind,
Name: rname,
- UID: types.UID(rkind + "/" + rnamespace + "/" + rname + "/" + ckind + "/" + cnamespace + "/" + cname),
- Namespace: gkNamespace,
+ Namespace: enamespace,
+ }
+ if emitInvolvedNamespace && len(ruid) > 0 && len(rrv) > 0 {
+ ref.UID = ruid
+ ref.ResourceVersion = rrv
+ } else if !emitInvolvedNamespace {
+ ref.UID = types.UID(rkind + "/" + rnamespace + "/" + rname + "/" + ckind + "/" + cnamespace + "/" + cname)
}
+ return ref
}
// mergeErrors concatenates errs into a single error. None of the original errors
diff --git a/pkg/audit/manager_test.go b/pkg/audit/manager_test.go
index 38733e7d1d5..6ab50afc5b3 100644
--- a/pkg/audit/manager_test.go
+++ b/pkg/audit/manager_test.go
@@ -1,16 +1,115 @@
package audit
import (
+ "context"
"os"
"reflect"
"testing"
+ constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
+ configv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
"github.com/pkg/errors"
+ "github.com/stretchr/testify/require"
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/types"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/fake"
)
+func Test_auditFromCache(t *testing.T) {
+ podToReview := fakes.Pod(fakes.WithNamespace("test-namespace-1"))
+ podGVK := podToReview.GroupVersionKind()
+ testAuditCache := fakeCacheListerFor([]schema.GroupVersionKind{podGVK}, []client.Object{podToReview})
+
+ driver, err := rego.New()
+ require.NoError(t, err)
+ client, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
+ require.NoError(t, err)
+
+ _, err = client.AddTemplate(context.Background(), fakes.DenyAllRegoTemplate())
+ require.NoError(t, err, "adding denyall constraint template")
+ _, err = client.AddConstraint(context.Background(), fakes.DenyAllConstraint())
+ require.NoError(t, err, "adding denyall constraint")
+
+ tests := []struct {
+ name string
+ processExcluder *process.Excluder
+ wantViolation bool
+ }{
+ {
+ name: "obj excluded from audit",
+ processExcluder: processExcluderFor([]string{"test-namespace-1"}),
+ },
+ {
+ name: "obj not excluded from audit",
+ processExcluder: processExcluderFor([]string{}),
+ wantViolation: true,
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ am := &Manager{
+ processExcluder: tc.processExcluder,
+ auditCache: testAuditCache,
+ opa: client,
+ }
+
+ results, errs := am.auditFromCache(context.Background())
+ require.Len(t, errs, 0)
+
+ if tc.wantViolation {
+ require.Len(t, results, 1)
+ } else {
+ require.Len(t, results, 0)
+ }
+ })
+ }
+}
+
+func fakeCacheListerFor(gvks []schema.GroupVersionKind, objsToList []client.Object) *CacheLister {
+ k8sclient := fake.NewClientBuilder().WithObjects(objsToList...).Build()
+ fakeLister := fakeWatchIterator{gvksToList: gvks}
+
+ return NewAuditCacheLister(k8sclient, &fakeLister)
+}
+
+type fakeWatchIterator struct {
+ gvksToList []schema.GroupVersionKind
+}
+
+func (f *fakeWatchIterator) DoForEach(listFunc func(gvk schema.GroupVersionKind) error) error {
+ for _, gvk := range f.gvksToList {
+ if err := listFunc(gvk); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func processExcluderFor(ns []string) *process.Excluder {
+ processExcluder := process.New()
+ for _, n := range ns {
+ processExcluder.Add([]configv1alpha1.MatchEntry{
+ {
+ ExcludedNamespaces: []wildcard.Wildcard{wildcard.Wildcard(n)},
+ Processes: []string{"audit"},
+ },
+ })
+ }
+
+ return processExcluder
+}
+
func Test_newNSCache(t *testing.T) {
tests := []struct {
name string
@@ -187,9 +286,12 @@ func Test_getViolationRef(t *testing.T) {
rkind string
rname string
rnamespace string
+ rrv string
ckind string
cname string
cnamespace string
+ ruid types.UID
+ einvolved bool
}
tests := []struct {
name string
@@ -197,7 +299,7 @@ func Test_getViolationRef(t *testing.T) {
want *corev1.ObjectReference
}{
{
- name: "Test case 1",
+ name: "Test case 1 - Gatekeeper Namespace",
args: args{
gkNamespace: "default",
rkind: "Pod",
@@ -206,6 +308,7 @@ func Test_getViolationRef(t *testing.T) {
ckind: "LimitRange",
cname: "my-limit-range",
cnamespace: "default",
+ einvolved: false,
},
want: &corev1.ObjectReference{
Kind: "Pod",
@@ -215,7 +318,7 @@ func Test_getViolationRef(t *testing.T) {
},
},
{
- name: "Test case 2",
+ name: "Test case 2 - GK Namespace",
args: args{
gkNamespace: "kube-system",
rkind: "Service",
@@ -224,6 +327,7 @@ func Test_getViolationRef(t *testing.T) {
ckind: "PodSecurityPolicy",
cname: "my-pod-security-policy",
cnamespace: "kube-system",
+ einvolved: false,
},
want: &corev1.ObjectReference{
Kind: "Service",
@@ -232,10 +336,75 @@ func Test_getViolationRef(t *testing.T) {
Namespace: "kube-system",
},
},
+ {
+ name: "Test case 3 - Involved Namespace",
+ args: args{
+ gkNamespace: "kube-system",
+ rkind: "Pod",
+ rname: "my-pod",
+ rrv: "123456",
+ ruid: "abcde-123456",
+ rnamespace: "default",
+ ckind: "LimitRange",
+ cname: "my-limit-range",
+ cnamespace: "default",
+ einvolved: true,
+ },
+ want: &corev1.ObjectReference{
+ Kind: "Pod",
+ Name: "my-pod",
+ Namespace: "default",
+ ResourceVersion: "123456",
+ UID: "abcde-123456",
+ },
+ },
+ {
+ name: "Test case 4 - Involved Namespace Cluster Scoped",
+ args: args{
+ gkNamespace: "kube-system",
+ rkind: "Service",
+ rname: "my-service",
+ rrv: "123456",
+ ruid: "abcde-123456",
+ ckind: "PodSecurityPolicy",
+ cname: "my-pod-security-policy",
+ cnamespace: "kube-system",
+ einvolved: true,
+ },
+ want: &corev1.ObjectReference{
+ Kind: "Service",
+ Name: "my-service",
+ Namespace: "kube-system",
+ ResourceVersion: "123456",
+ UID: "abcde-123456",
+ },
+ },
+ {
+ name: "Test case 5 - Involved Namespace RV/UID",
+ args: args{
+ gkNamespace: "kube-system",
+ rkind: "Service",
+ rname: "my-service",
+ rrv: "",
+ ruid: "",
+ rnamespace: "default",
+ ckind: "PodSecurityPolicy",
+ cname: "my-pod-security-policy",
+ cnamespace: "kube-system",
+ einvolved: true,
+ },
+ want: &corev1.ObjectReference{
+ Kind: "Service",
+ Name: "my-service",
+ Namespace: "default",
+ ResourceVersion: "",
+ UID: "",
+ },
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- if got := getViolationRef(tt.args.gkNamespace, tt.args.rkind, tt.args.rname, tt.args.rnamespace, tt.args.ckind, tt.args.cname, tt.args.cnamespace); !reflect.DeepEqual(got, tt.want) {
+ if got := getViolationRef(tt.args.gkNamespace, tt.args.rkind, tt.args.rname, tt.args.rnamespace, tt.args.rrv, tt.args.ruid, tt.args.ckind, tt.args.cname, tt.args.cnamespace, tt.args.einvolved); !reflect.DeepEqual(got, tt.want) {
t.Errorf("getViolationRef() = %v, want %v", got, tt.want)
}
})
diff --git a/pkg/audit/stats_reporter.go b/pkg/audit/stats_reporter.go
index 8cfe9cd1645..43f2e32158a 100644
--- a/pkg/audit/stats_reporter.go
+++ b/pkg/audit/stats_reporter.go
@@ -4,8 +4,8 @@ import (
"context"
"time"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view"
"go.opencensus.io/tag"
diff --git a/pkg/cachemanager/aggregator/aggregator.go b/pkg/cachemanager/aggregator/aggregator.go
new file mode 100644
index 00000000000..b36b3cada13
--- /dev/null
+++ b/pkg/cachemanager/aggregator/aggregator.go
@@ -0,0 +1,178 @@
+package aggregator
+
+import (
+ "fmt"
+ gosync "sync"
+
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// Key defines a type, identifier tuple to store
+// in the GVKAggregator.
+type Key struct {
+ // Source specifies the type or where this Key comes from.
+ Source string
+ // ID specifies the name of the type that this Key is.
+ ID string
+}
+
+func NewGVKAggregator() *GVKAgreggator {
+ return &GVKAgreggator{
+ store: make(map[Key]map[schema.GroupVersionKind]struct{}),
+ reverseStore: make(map[schema.GroupVersionKind]map[Key]struct{}),
+ }
+}
+
+// GVKAgreggator is an implementation of a bi directional map
+// that stores associations between Key K and GVKs and reverse associations
+// between GVK g and Keys.
+type GVKAgreggator struct {
+ mu gosync.RWMutex
+
+ // store keeps track of associations between a Key type and a set of GVKs.
+ store map[Key]map[schema.GroupVersionKind]struct{}
+ // reverseStore keeps track of associations between a GVK and the set of Key types
+ // that references the GVK in the store map above. It is useful to have reverseStore
+ // in order for IsPresent() and ListGVKs() to run in optimal time.
+ reverseStore map[schema.GroupVersionKind]map[Key]struct{}
+}
+
+// IsPresent returns true if the given gvk is present in the GVKAggregator.
+func (b *GVKAgreggator) IsPresent(gvk schema.GroupVersionKind) bool {
+ b.mu.RLock()
+ defer b.mu.RUnlock()
+
+ _, found := b.reverseStore[gvk]
+ return found
+}
+
+// Remove deletes any associations that Key k has in the GVKAggregator.
+// For any GVK in the association k --> [GVKs], we also delete any associations
+// between the GVK and the Key k stored in the reverse map.
+func (b *GVKAgreggator) Remove(k Key) error {
+ b.mu.Lock()
+ defer b.mu.Unlock()
+
+ gvks, found := b.store[k]
+ if !found {
+ return nil
+ }
+
+ if err := b.pruneReverseStore(gvks, k); err != nil {
+ return err
+ }
+
+ delete(b.store, k)
+ return nil
+}
+
+// Upsert stores an association between Key k and the list of GVKs
+// and also the reverse associatoin between each GVK passed in and Key k.
+// Any old associations are dropped, unless they are included in the new list of
+// GVKs.
+// It errors out if there is an internal issue with remove the reverse Key links
+// for any GVKs that are being dropped as part of this Upsert call.
+func (b *GVKAgreggator) Upsert(k Key, gvks []schema.GroupVersionKind) error {
+ b.mu.Lock()
+ defer b.mu.Unlock()
+
+ oldGVKs, found := b.store[k]
+ if found {
+ // gvksToRemove contains old GKVs that are not included in the new gvks list
+ gvksToRemove := unreferencedOldGVKsToPrune(gvks, oldGVKs)
+ if err := b.pruneReverseStore(gvksToRemove, k); err != nil {
+ return fmt.Errorf("failed to prune entries on upsert: %w", err)
+ }
+ }
+
+ // protect against empty inputs
+ gvksSet := makeSet(gvks)
+ if len(gvksSet) == 0 {
+ return nil
+ }
+
+ b.store[k] = gvksSet
+ // add reverse links
+ for gvk := range gvksSet {
+ if _, found := b.reverseStore[gvk]; !found {
+ b.reverseStore[gvk] = make(map[Key]struct{})
+ }
+ b.reverseStore[gvk][k] = struct{}{}
+ }
+
+ return nil
+}
+
+// List returnes the gvk set for a given Key.
+func (b *GVKAgreggator) List(k Key) map[schema.GroupVersionKind]struct{} {
+ b.mu.RLock()
+ defer b.mu.RUnlock()
+
+ v := b.store[k]
+ cpy := make(map[schema.GroupVersionKind]struct{}, len(v))
+ for key, value := range v {
+ cpy[key] = value
+ }
+ return cpy
+}
+
+// GVKs returns a list of all of the schema.GroupVersionKind that are aggregated.
+func (b *GVKAgreggator) GVKs() []schema.GroupVersionKind {
+ b.mu.RLock()
+ defer b.mu.RUnlock()
+
+ allGVKs := []schema.GroupVersionKind{}
+ for gvk := range b.reverseStore {
+ allGVKs = append(allGVKs, gvk)
+ }
+ return allGVKs
+}
+
+func (b *GVKAgreggator) pruneReverseStore(gvks map[schema.GroupVersionKind]struct{}, k Key) error {
+ for gvk := range gvks {
+ keySet, found := b.reverseStore[gvk]
+ if !found || len(keySet) == 0 {
+ // this should not happen if we keep the two maps well defined
+ // but let's be defensive nonetheless.
+ return fmt.Errorf("internal aggregator error: gvks stores are corrupted for key: %s", k)
+ }
+
+ delete(keySet, k)
+
+ // remove GVK from reverseStore if it's not referenced by any Key anymore.
+ if len(keySet) == 0 {
+ delete(b.reverseStore, gvk)
+ } else {
+ b.reverseStore[gvk] = keySet
+ }
+ }
+
+ return nil
+}
+
+func makeSet(gvks []schema.GroupVersionKind) map[schema.GroupVersionKind]struct{} {
+ gvkSet := make(map[schema.GroupVersionKind]struct{})
+ for _, gvk := range gvks {
+ if !gvk.Empty() {
+ gvkSet[gvk] = struct{}{}
+ }
+ }
+
+ return gvkSet
+}
+
+func unreferencedOldGVKsToPrune(newGVKs []schema.GroupVersionKind, oldGVKs map[schema.GroupVersionKind]struct{}) map[schema.GroupVersionKind]struct{} {
+ // deep copy oldGVKs
+ oldGVKsCpy := make(map[schema.GroupVersionKind]struct{}, len(oldGVKs))
+ for k, v := range oldGVKs {
+ oldGVKsCpy[k] = v
+ }
+
+ // intersection: exclude the oldGVKs that are present in the new GVKs as well.
+ for _, newGVK := range newGVKs {
+ // don't prune what is being already added
+ delete(oldGVKsCpy, newGVK)
+ }
+
+ return oldGVKsCpy
+}
diff --git a/pkg/cachemanager/aggregator/aggregator_test.go b/pkg/cachemanager/aggregator/aggregator_test.go
new file mode 100644
index 00000000000..22dec711065
--- /dev/null
+++ b/pkg/cachemanager/aggregator/aggregator_test.go
@@ -0,0 +1,362 @@
+package aggregator
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+const (
+ // common test keys.
+ syncset = "TODOa"
+ configsync = "TODOb"
+)
+
+var (
+ // test gvks.
+ emptyGVK = schema.GroupVersionKind{Group: "", Version: "", Kind: ""}
+
+ g1v1k1 = schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "Kind1"}
+ g1v1k2 = schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "Kind2"}
+
+ g2v1k1 = schema.GroupVersionKind{Group: "group2", Version: "v1", Kind: "Kind1"}
+ g2v1k2 = schema.GroupVersionKind{Group: "group2", Version: "v1", Kind: "Kind2"}
+
+ g1v2k1 = schema.GroupVersionKind{Group: "group1", Version: "v2", Kind: "Kind1"}
+ g1v2k2 = schema.GroupVersionKind{Group: "group1", Version: "v2", Kind: "Kind2"}
+
+ g2v2k1 = schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "Kind1"}
+ g2v2k2 = schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "Kind2"}
+
+ g3v1k1 = schema.GroupVersionKind{Group: "group3", Version: "v1", Kind: "Kind1"}
+ g3v1k2 = schema.GroupVersionKind{Group: "group3", Version: "v1", Kind: "Kind2"}
+)
+
+type upsertKeyGVKs struct {
+ key Key
+ gvks []schema.GroupVersionKind
+}
+
+func Test_GVKAggregator_Upsert(t *testing.T) {
+ tests := []struct {
+ name string
+ // each entry in the list is a new Upsert call
+ keyGVKs []upsertKeyGVKs
+
+ expectData map[Key]map[schema.GroupVersionKind]struct{}
+ expectRev map[schema.GroupVersionKind]map[Key]struct{}
+ }{
+ {
+ name: "empty GVKs",
+ keyGVKs: []upsertKeyGVKs{
+ {
+ key: Key{
+ Source: syncset,
+ ID: "foo",
+ },
+ gvks: []schema.GroupVersionKind{emptyGVK, emptyGVK},
+ },
+ },
+ expectData: map[Key]map[schema.GroupVersionKind]struct{}{},
+ expectRev: map[schema.GroupVersionKind]map[Key]struct{}{},
+ },
+ {
+ name: "add one key and GVKs",
+ keyGVKs: []upsertKeyGVKs{
+ {
+ key: Key{
+ Source: syncset,
+ ID: "foo",
+ },
+ gvks: []schema.GroupVersionKind{g1v1k1, g1v1k2, emptyGVK},
+ },
+ },
+ expectData: map[Key]map[schema.GroupVersionKind]struct{}{
+ {
+ Source: syncset,
+ ID: "foo",
+ }: {
+ g1v1k1: {},
+ g1v1k2: {},
+ },
+ },
+ expectRev: map[schema.GroupVersionKind]map[Key]struct{}{
+ g1v1k1: {
+ {
+ Source: syncset,
+ ID: "foo",
+ }: {},
+ },
+ g1v1k2: {
+ {
+ Source: syncset,
+ ID: "foo",
+ }: {},
+ },
+ },
+ },
+ {
+ name: "add two keys and GVKs",
+ keyGVKs: []upsertKeyGVKs{
+ {
+ key: Key{
+ Source: syncset,
+ ID: "foo",
+ },
+ gvks: []schema.GroupVersionKind{g1v1k1, g1v1k2},
+ },
+ {
+ key: Key{
+ Source: configsync,
+ ID: "foo",
+ },
+ gvks: []schema.GroupVersionKind{g1v1k1, g1v1k2},
+ },
+ },
+ expectData: map[Key]map[schema.GroupVersionKind]struct{}{
+ {
+ Source: syncset,
+ ID: "foo",
+ }: {
+ g1v1k1: {},
+ g1v1k2: {},
+ },
+ {
+ Source: configsync,
+ ID: "foo",
+ }: {
+ g1v1k1: {},
+ g1v1k2: {},
+ },
+ },
+ expectRev: map[schema.GroupVersionKind]map[Key]struct{}{
+ g1v1k1: {
+ {
+ Source: syncset,
+ ID: "foo",
+ }: {},
+ {
+ Source: configsync,
+ ID: "foo",
+ }: {},
+ },
+ g1v1k2: {
+ {
+ Source: syncset,
+ ID: "foo",
+ }: {},
+ {
+ Source: configsync,
+ ID: "foo",
+ }: {},
+ },
+ },
+ },
+ {
+ name: "add one key and overwrite it",
+ keyGVKs: []upsertKeyGVKs{
+ {
+ key: Key{
+ Source: syncset,
+ ID: "foo",
+ },
+ gvks: []schema.GroupVersionKind{g1v1k1, g1v1k2},
+ },
+ {
+ key: Key{
+ Source: syncset,
+ ID: "foo",
+ },
+ gvks: []schema.GroupVersionKind{g3v1k1, g3v1k2},
+ },
+ },
+ expectData: map[Key]map[schema.GroupVersionKind]struct{}{
+ {
+ Source: syncset,
+ ID: "foo",
+ }: {
+ g3v1k1: {},
+ g3v1k2: {},
+ },
+ },
+ expectRev: map[schema.GroupVersionKind]map[Key]struct{}{
+ g3v1k1: {
+ {
+ Source: syncset,
+ ID: "foo",
+ }: {},
+ },
+ g3v1k2: {
+ {
+ Source: syncset,
+ ID: "foo",
+ }: {},
+ },
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ tt := tt
+ agg := NewGVKAggregator()
+
+ for _, keyGVKs := range tt.keyGVKs {
+ require.NoError(t, agg.Upsert(keyGVKs.key, keyGVKs.gvks))
+ }
+
+ // require all gvks added to be present in the aggregator
+ require.Equal(t, tt.expectData, agg.store, "data map did not match expected")
+ require.Equal(t, tt.expectRev, agg.reverseStore, "reverse store did not match expected")
+ })
+ }
+}
+
+func Test_GVKAgreggator_Remove(t *testing.T) {
+ t.Run("Remove on empty aggregator", func(t *testing.T) {
+ b := NewGVKAggregator()
+ key := Key{Source: "testSource", ID: "testID"}
+
+ require.NoError(t, b.Remove(key))
+ })
+
+ t.Run("Remove non-existing key", func(t *testing.T) {
+ b := NewGVKAggregator()
+ key1 := Key{Source: syncset, ID: "testID1"}
+ key2 := Key{Source: configsync, ID: "testID2"}
+ gvks := []schema.GroupVersionKind{g1v1k1, g1v1k2}
+ require.NoError(t, b.Upsert(key1, gvks))
+
+ require.NoError(t, b.Remove(key2))
+ })
+
+ t.Run("Remove existing key and verify reverseStore", func(t *testing.T) {
+ b := NewGVKAggregator()
+ key1 := Key{Source: syncset, ID: "testID"}
+ gvks := []schema.GroupVersionKind{g1v1k1, g1v1k2}
+ require.NoError(t, b.Upsert(key1, gvks))
+
+ require.NoError(t, b.Remove(key1))
+
+ for _, gvk := range gvks {
+ require.False(t, b.IsPresent(gvk))
+ }
+ })
+
+ t.Run("Remove existing 1 of existing keys referencing GVKs", func(t *testing.T) {
+ b := NewGVKAggregator()
+ key1 := Key{Source: syncset, ID: "testID"}
+ key2 := Key{Source: configsync, ID: "testID"}
+ gvks := []schema.GroupVersionKind{g1v1k1, g1v1k2}
+ require.NoError(t, b.Upsert(key1, gvks))
+ require.NoError(t, b.Upsert(key2, gvks))
+
+ require.NoError(t, b.Remove(key1))
+
+ for _, gvk := range gvks {
+ require.True(t, b.IsPresent(gvk))
+ }
+ })
+
+ t.Run("corrupted GVKAggregator error", func(t *testing.T) {
+ b := NewGVKAggregator()
+ key := Key{Source: syncset, ID: "testID"}
+
+ // simulate a corrupted aggreagator
+ require.NoError(t, b.Upsert(key, []schema.GroupVersionKind{g1v1k1}))
+ b.reverseStore[g1v1k1] = map[Key]struct{}{}
+
+ err2 := b.Remove(key)
+ require.EqualError(t, err2, fmt.Sprintf("internal aggregator error: gvks stores are corrupted for key: {%s %s}", key.Source, key.ID))
+ })
+}
+
+// Test_GVKAggreggator_E2E is a test that:
+// - Upserts two sources with different GVKs
+// - Upserts the two sources with some overlapping GVKs
+// - Remove one key, tests for correct output
+// - Overwrite an existing key with new data, and confirms correct re-calculation.
+func Test_GVKAggreggator_E2E(t *testing.T) {
+ b := NewGVKAggregator()
+
+ key1 := Key{Source: syncset, ID: "testID"}
+ key2 := Key{Source: configsync, ID: "testID"}
+
+ gvksKind1 := []schema.GroupVersionKind{g1v1k1, g2v1k1, g2v2k1}
+ gvksKind2 := []schema.GroupVersionKind{g1v1k2, g2v1k2, g2v2k2}
+
+ require.NoError(t, b.Upsert(key1, gvksKind1)) // key1 now has: g1v1k1, g2v1k1, g2v2k1
+ require.NoError(t, b.Upsert(key2, gvksKind2)) // key2 now has: g1v1k2, g2v1k2, g2v2k2
+
+ // require that every gvk that was just added to be present
+ gvksThatShouldBeTracked := map[schema.GroupVersionKind]interface{}{
+ g1v1k1: struct{}{}, g2v1k1: struct{}{}, g2v2k1: struct{}{},
+ g1v1k2: struct{}{}, g2v1k2: struct{}{}, g2v2k2: struct{}{},
+ }
+ for gvk := range gvksThatShouldBeTracked {
+ require.True(t, b.IsPresent(gvk))
+ }
+
+ // notice the overlap of with gvksKind1, gvksKind2
+ gvksVersion1 := []schema.GroupVersionKind{g1v1k1, g1v1k2, g2v1k1, g2v1k2} // overlaps key2 with g1v1k2, g1v1k2
+ gvksVersion2 := []schema.GroupVersionKind{g1v2k1, g1v2k2, g2v2k1, g2v2k2} // overlaps key1 with g2v2k1; overlaps key2 with g2v2k2
+
+ // new upserts
+ require.NoError(t, b.Upsert(key1, gvksVersion1)) // key1 no longer associates g2v2k1, but key2 does
+ require.NoError(t, b.Upsert(key2, gvksVersion2)) // key2 no longer associaates g1v1k2, but key1 does
+
+ // require that every gvk that was just added now and before to be present
+ for _, gvk := range append(append([]schema.GroupVersionKind{}, gvksVersion1...), gvksVersion2...) {
+ gvksThatShouldBeTracked[gvk] = struct{}{}
+
+ require.True(t, b.IsPresent(gvk), fmt.Sprintf("gvk %s should be present", gvk))
+ }
+
+ // At this point
+ // key1 has: g1v1k1, g2v1k1, g1v1k2, g2v1k2
+ // key2 has: g2v2k2, g1v2k1, g1v2k2, g2v2k1
+ // now remove key1
+ require.NoError(t, b.Remove(key1))
+
+ // untrack gvks that shouldn't exist in the
+ for _, gvk := range []schema.GroupVersionKind{g1v1k1, g2v1k1, g1v1k2, g2v1k2} {
+ delete(gvksThatShouldBeTracked, gvk)
+
+ // also require that this gvk not be present since it was removed
+ require.False(t, b.IsPresent(gvk), fmt.Sprintf("gvk %s shouldn't be present", gvk))
+ }
+
+ // require GVKs from un-removed keys that have GVK associations to still be present
+ for gvk := range gvksThatShouldBeTracked {
+ require.True(t, b.IsPresent(gvk), fmt.Sprintf("gvk %s should be present", gvk))
+ }
+
+ // overwrite key2
+ gvksGroup3 := []schema.GroupVersionKind{g3v1k1, g3v1k2}
+ require.NoError(t, b.Upsert(key2, gvksGroup3))
+
+ // require all previously added gvks to not be present:
+ testPresenceForGVK(t, false, b, gvksKind1...)
+ testPresenceForGVK(t, false, b, gvksKind2...)
+ testPresenceForGVK(t, false, b, gvksVersion1...)
+ testPresenceForGVK(t, false, b, gvksVersion2...)
+
+ // require newly added gvks to be present
+ testPresenceForGVK(t, true, b, gvksGroup3...)
+}
+
+func testPresenceForGVK(t *testing.T, requireTrue bool, b *GVKAgreggator, gvks ...schema.GroupVersionKind) {
+ t.Helper()
+
+ var msg string
+ if requireTrue {
+ msg = "%s should be present"
+ } else {
+ msg = "%s shouldn't be present"
+ }
+ for _, gvk := range gvks {
+ require.Equal(t, requireTrue, b.IsPresent(gvk), fmt.Sprintf(msg, gvk))
+ }
+}
diff --git a/pkg/cachemanager/cachemanager.go b/pkg/cachemanager/cachemanager.go
new file mode 100644
index 00000000000..00b1691d26a
--- /dev/null
+++ b/pkg/cachemanager/cachemanager.go
@@ -0,0 +1,442 @@
+package cachemanager
+
+import (
+ "context"
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/open-policy-agent/frameworks/constraint/pkg/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager/aggregator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/syncutil"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/util/wait"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+const RegistrarName = "cachemanager"
+
+var (
+ log = logf.Log.WithName("cache-manager")
+ backoff = wait.Backoff{
+ Duration: time.Second,
+ Factor: 2,
+ Jitter: 0.1,
+ Steps: 3,
+ }
+)
+
+type Config struct {
+ CfClient CFDataClient
+ SyncMetricsCache *syncutil.MetricsCache
+ Tracker *readiness.Tracker
+ ProcessExcluder *process.Excluder
+ Registrar *watch.Registrar
+ GVKAggregator *aggregator.GVKAgreggator
+ Reader client.Reader
+}
+
+type CacheManager struct {
+ watchedSet *watch.Set
+ processExcluder *process.Excluder
+ gvksToSync *aggregator.GVKAgreggator
+ needToList bool
+ gvksToDeleteFromCache *watch.Set
+ excluderChanged bool
+ // mu guards access to any of the fields above
+ mu sync.RWMutex
+
+ cfClient CFDataClient
+ syncMetricsCache *syncutil.MetricsCache
+ tracker *readiness.Tracker
+ registrar *watch.Registrar
+ backgroundManagementTicker time.Ticker
+ reader client.Reader
+}
+
+// CFDataClient is an interface for caching data.
+type CFDataClient interface {
+ AddData(ctx context.Context, data interface{}) (*types.Responses, error)
+ RemoveData(ctx context.Context, data interface{}) (*types.Responses, error)
+}
+
+func NewCacheManager(config *Config) (*CacheManager, error) {
+ if config.Registrar == nil {
+ return nil, fmt.Errorf("registrar must be non-nil")
+ }
+ if config.ProcessExcluder == nil {
+ return nil, fmt.Errorf("processExcluder must be non-nil")
+ }
+ if config.Tracker == nil {
+ return nil, fmt.Errorf("tracker must be non-nil")
+ }
+ if config.Reader == nil {
+ return nil, fmt.Errorf("reader must be non-nil")
+ }
+
+ if config.GVKAggregator == nil {
+ config.GVKAggregator = aggregator.NewGVKAggregator()
+ }
+
+ cm := &CacheManager{
+ cfClient: config.CfClient,
+ syncMetricsCache: config.SyncMetricsCache,
+ tracker: config.Tracker,
+ processExcluder: config.ProcessExcluder,
+ registrar: config.Registrar,
+ watchedSet: watch.NewSet(),
+ reader: config.Reader,
+ gvksToSync: config.GVKAggregator,
+ backgroundManagementTicker: *time.NewTicker(3 * time.Second),
+ gvksToDeleteFromCache: watch.NewSet(),
+ }
+
+ return cm, nil
+}
+
+func (c *CacheManager) Start(ctx context.Context) error {
+ go c.manageCache(ctx)
+
+ <-ctx.Done()
+ return nil
+}
+
+// UpsertSource adjusts the watched set of gvks according to the newGVKs passed in
+// for a given sourceKey. Callers are responsible for retrying on error.
+func (c *CacheManager) UpsertSource(ctx context.Context, sourceKey aggregator.Key, newGVKs []schema.GroupVersionKind) error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if len(newGVKs) > 0 {
+ if err := c.gvksToSync.Upsert(sourceKey, newGVKs); err != nil {
+ return fmt.Errorf("internal error adding source: %w", err)
+ }
+ } else {
+ if err := c.gvksToSync.Remove(sourceKey); err != nil {
+ return fmt.Errorf("internal error removing source: %w", err)
+ }
+ }
+
+ // as a result of upserting the new gvks for the source key, some gvks
+ // may become unreferenced and need to be deleted; this will be handled async
+ // in the manageCache loop.
+
+ if err := c.replaceWatchSet(ctx); err != nil {
+ return fmt.Errorf("error watching new gvks: %w", err)
+ }
+
+ return nil
+}
+
+// replaceWatchSet looks at the gvksToSync and makes changes to the registrar's watch set.
+// Assumes caller has lock. On error, actual watch state may not align with intended watch state.
+func (c *CacheManager) replaceWatchSet(ctx context.Context) error {
+ newWatchSet := watch.NewSet()
+ newWatchSet.Add(c.gvksToSync.GVKs()...)
+
+ diff := c.watchedSet.Difference(newWatchSet)
+ c.removeStaleExpectations(diff)
+
+ c.gvksToDeleteFromCache.AddSet(diff)
+
+ var innerError error
+ c.watchedSet.Replace(newWatchSet, func() {
+ // *Note the following steps are not transactional with respect to admission control
+
+ // Important: dynamic watches update must happen *after* updating our watchSet.
+ // Otherwise, the sync controller will drop events for the newly watched kinds.
+ innerError = c.registrar.ReplaceWatch(ctx, newWatchSet.Items())
+ })
+
+ return innerError
+}
+
+// removeStaleExpectations stops tracking data for any resources that are no longer watched.
+func (c *CacheManager) removeStaleExpectations(stale *watch.Set) {
+ for _, gvk := range stale.Items() {
+ c.tracker.CancelData(gvk)
+ }
+}
+
+// RemoveSource removes the watches of the GVKs for a given aggregator.Key. Callers are responsible for retrying on error.
+func (c *CacheManager) RemoveSource(ctx context.Context, sourceKey aggregator.Key) error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if err := c.gvksToSync.Remove(sourceKey); err != nil {
+ return fmt.Errorf("internal error removing source: %w", err)
+ }
+
+ if err := c.replaceWatchSet(ctx); err != nil {
+ return fmt.Errorf("error removing watches for source %v: %w", sourceKey, err)
+ }
+
+ return nil
+}
+
+// ExcludeProcesses swaps the current process excluder with the new *process.Excluder.
+// It's a no-op if the two excluders are equal.
+func (c *CacheManager) ExcludeProcesses(newExcluder *process.Excluder) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.processExcluder.Equals(newExcluder) {
+ return
+ }
+
+ c.processExcluder.Replace(newExcluder)
+ // there is a new excluder which means we need to schedule a wipe for any
+ // previously watched GVKs to be re-added to get a chance to be evaluated
+ // for this new process excluder.
+ c.excluderChanged = true
+}
+
+// DoForEach runs fn for each GVK that is being watched by the cache manager.
+// This is handy when we want to take actions while holding the lock on the watched.Set.
+func (c *CacheManager) DoForEach(fn func(gvk schema.GroupVersionKind) error) error {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+
+ err := c.watchedSet.DoForEach(fn)
+ return err
+}
+
+func (c *CacheManager) watchesGVK(gvk schema.GroupVersionKind) bool {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+
+ return c.watchedSet.Contains(gvk)
+}
+
+func (c *CacheManager) AddObject(ctx context.Context, instance *unstructured.Unstructured) error {
+ gvk := instance.GroupVersionKind()
+
+ isNamespaceExcluded, err := c.processExcluder.IsNamespaceExcluded(process.Sync, instance)
+ if err != nil {
+ return fmt.Errorf("error while excluding namespaces for gvk: %+v: %w", gvk, err)
+ }
+
+ if isNamespaceExcluded {
+ c.tracker.ForData(instance.GroupVersionKind()).CancelExpect(instance)
+ return nil
+ }
+
+ syncKey := syncutil.GetKeyForSyncMetrics(instance.GetNamespace(), instance.GetName())
+ if c.watchesGVK(gvk) {
+ _, err = c.cfClient.AddData(ctx, instance)
+ if err != nil {
+ c.syncMetricsCache.AddObject(
+ syncKey,
+ syncutil.Tags{
+ Kind: instance.GetKind(),
+ Status: metrics.ErrorStatus,
+ },
+ )
+
+ return err
+ }
+
+ c.syncMetricsCache.AddObject(syncKey, syncutil.Tags{
+ Kind: instance.GetKind(),
+ Status: metrics.ActiveStatus,
+ })
+ c.syncMetricsCache.AddKind(instance.GetKind())
+ }
+
+ c.tracker.ForData(instance.GroupVersionKind()).Observe(instance)
+
+ return nil
+}
+
+func (c *CacheManager) RemoveObject(ctx context.Context, instance *unstructured.Unstructured) error {
+ if _, err := c.cfClient.RemoveData(ctx, instance); err != nil {
+ return err
+ }
+
+ // only delete from metrics map if the data removal was successful
+ c.syncMetricsCache.DeleteObject(syncutil.GetKeyForSyncMetrics(instance.GetNamespace(), instance.GetName()))
+ c.tracker.ForData(instance.GroupVersionKind()).CancelExpect(instance)
+
+ return nil
+}
+
+func (c *CacheManager) wipeData(ctx context.Context) error {
+ if _, err := c.cfClient.RemoveData(ctx, target.WipeData()); err != nil {
+ return err
+ }
+
+ // reset sync cache before sending the metric
+ c.syncMetricsCache.ResetCache()
+ c.syncMetricsCache.ReportSync()
+
+ return nil
+}
+
+func (c *CacheManager) ReportSyncMetrics() {
+ c.syncMetricsCache.ReportSync()
+}
+
+func (c *CacheManager) syncGVK(ctx context.Context, gvk schema.GroupVersionKind) error {
+ u := &unstructured.UnstructuredList{}
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: gvk.Group,
+ Version: gvk.Version,
+ Kind: gvk.Kind + "List",
+ })
+
+ var err error
+ func() {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+
+ // only call List if we are still watching the gvk.
+ if c.watchedSet.Contains(gvk) {
+ err = c.reader.List(ctx, u)
+ }
+ }()
+
+ if err != nil {
+ return fmt.Errorf("listing data for %+v: %w", gvk, err)
+ }
+
+ for i := range u.Items {
+ if err := c.AddObject(ctx, &u.Items[i]); err != nil {
+ return fmt.Errorf("adding data for %+v: %w", gvk, err)
+ }
+ }
+
+ return nil
+}
+
+func (c *CacheManager) manageCache(ctx context.Context) {
+ // relistStopChan is used to stop any list operations still in progress
+ relistStopChan := make(chan struct{})
+ // waitToCloseChan is used to wait on the relist goroutine to end
+ // when needing to create another one. This ensures that we are essentially
+ // only using a singleton routine to relist gvks.
+ waitToCloseChan := make(chan struct{})
+
+ // edge case: the 0th relist goroutine is "stopped", by definition, so we close the wait channel
+ // but it's also "running" so we don't close the kill channel in order to do so in the for loop below.
+ close(waitToCloseChan)
+
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case <-c.backgroundManagementTicker.C:
+ func() {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ c.wipeCacheIfNeeded(ctx)
+
+ if !c.needToList {
+ // this means that there are no changes needed
+ // such that any gvks need to be relisted.
+ // any in flight goroutines can finish relisiting.
+ return
+ }
+
+ // otherwise, spin up new goroutines to relist gvks as there has been a wipe
+
+ // stop any goroutines that were relisting before
+ // as we may no longer be interested in those gvks
+ // and wait with a timeout for the child gorountine to stop.
+ close(relistStopChan)
+ select {
+ case <-waitToCloseChan:
+ // child goroutine exited gracefully
+ break
+ case <-time.After(time.Second * 10):
+ log.Error(fmt.Errorf("internal: background relist did not exit gracefully"), "possible goroutine leak")
+ // do not close waitToCloseChan as the goroutine may eventually exit and call close on the channel
+ break
+ }
+
+ // assume all gvks need to be relisted
+ // and while under lock, make a copy of
+ // all gvks so we can pass it in the goroutine
+ // without needing to read lock this data
+ gvksToRelist := c.gvksToSync.GVKs()
+
+ // clean state
+ c.needToList = false
+ relistStopChan = make(chan struct{})
+ waitToCloseChan = make(chan struct{})
+
+ go func() {
+ c.replayGVKs(ctx, gvksToRelist, relistStopChan)
+ close(waitToCloseChan)
+ }()
+ }()
+ }
+ }
+}
+
+func (c *CacheManager) replayGVKs(ctx context.Context, gvksToRelist []schema.GroupVersionKind, stopCh <-chan struct{}) {
+ gvksSet := watch.NewSet()
+ gvksSet.Add(gvksToRelist...)
+
+ for gvksSet.Size() != 0 {
+ gvkItems := gvksSet.Items()
+
+ for _, gvk := range gvkItems {
+ select {
+ case <-ctx.Done():
+ return
+ case <-stopCh:
+ return
+ default:
+ operation := func(ctx context.Context) (bool, error) {
+ select {
+ // make sure that the stop channel hasn't closed yet in order to stop
+ // the operation in the backoff retry-er earlier so we don't sync GVKs
+ // that we may not want to sync anymore. This also ensures that we exit
+ // the func as soon as possible.
+ case <-stopCh:
+ return true, nil
+ default:
+ if err := c.syncGVK(ctx, gvk); err != nil {
+ return false, err
+ }
+ return true, nil
+ }
+ }
+
+ if err := wait.ExponentialBackoffWithContext(ctx, backoff, operation); err != nil {
+ log.Error(err, "internal: error listings gvk cache data", "gvk", gvk)
+ } else {
+ gvksSet.Remove(gvk)
+ }
+ }
+ }
+
+ c.ReportSyncMetrics()
+ }
+}
+
+// wipeCacheIfNeeded performs a cache wipe if there are any gvks needing to be removed
+// from the cache or if the excluder has changed. It also marks which gvks need to be
+// re listed again in the cf data cache after the wipe. Assumes the caller has lock.
+func (c *CacheManager) wipeCacheIfNeeded(ctx context.Context) {
+ // remove any gvks not needing to be synced anymore
+ // or re evaluate all if the excluder changed.
+ if c.gvksToDeleteFromCache.Size() > 0 || c.excluderChanged {
+ if err := c.wipeData(ctx); err != nil {
+ log.Error(err, "internal: error wiping cache")
+ return
+ }
+
+ c.gvksToDeleteFromCache = watch.NewSet()
+ c.excluderChanged = false
+ c.needToList = true
+ }
+}
diff --git a/pkg/cachemanager/cachemanager_test.go b/pkg/cachemanager/cachemanager_test.go
new file mode 100644
index 00000000000..3e7fa9bbeec
--- /dev/null
+++ b/pkg/cachemanager/cachemanager_test.go
@@ -0,0 +1,539 @@
+package cachemanager
+
+import (
+ "context"
+ "testing"
+
+ configv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager/aggregator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/syncutil"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
+ testclient "github.com/open-policy-agent/gatekeeper/v3/test/clients"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
+ "github.com/stretchr/testify/require"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+)
+
+var cfg *rest.Config
+
+func TestMain(m *testing.M) {
+ testutils.StartControlPlane(m, &cfg, 2)
+}
+
+func makeCacheManager(t *testing.T) (*CacheManager, context.Context) {
+ mgr, wm := testutils.SetupManager(t, cfg)
+ c := testclient.NewRetryClient(mgr.GetClient())
+
+ ctx, cancelFunc := context.WithCancel(context.Background())
+
+ cfClient := &fakes.FakeCfClient{}
+ tracker, err := readiness.SetupTracker(mgr, false, false, false)
+ require.NoError(t, err)
+ processExcluder := process.Get()
+ processExcluder.Add([]configv1alpha1.MatchEntry{
+ {
+ ExcludedNamespaces: []wildcard.Wildcard{"kube-system"},
+ Processes: []string{"sync"},
+ },
+ })
+ events := make(chan event.GenericEvent, 1024)
+ reg, err := wm.NewRegistrar(
+ "test-cache-manager",
+ events)
+ require.NoError(t, err)
+
+ cacheManager, err := NewCacheManager(&Config{
+ CfClient: cfClient,
+ SyncMetricsCache: syncutil.NewMetricsCache(),
+ Tracker: tracker,
+ ProcessExcluder: processExcluder,
+ Registrar: reg,
+ Reader: c,
+ GVKAggregator: aggregator.NewGVKAggregator(),
+ })
+ require.NoError(t, err)
+
+ t.Cleanup(func() {
+ cancelFunc()
+ })
+
+ testutils.StartManager(ctx, t, mgr)
+
+ return cacheManager, ctx
+}
+
+func TestCacheManager_wipeCacheIfNeeded(t *testing.T) {
+ configMapGVK := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}
+ dataClientForTest := func() CFDataClient {
+ cfdc := &fakes.FakeCfClient{}
+
+ cm := unstructuredFor(configMapGVK, "config-test-1")
+ _, err := cfdc.AddData(context.Background(), cm)
+
+ require.NoError(t, err, "adding ConfigMap config-test-1 in cfClient")
+
+ return cfdc
+ }
+
+ tcs := []struct {
+ name string
+ cm *CacheManager
+ expectedData map[fakes.CfDataKey]interface{}
+ }{
+ {
+ name: "wipe cache if there are gvks to remove",
+ cm: &CacheManager{
+ cfClient: dataClientForTest(),
+ gvksToDeleteFromCache: func() *watch.Set {
+ gvksToDelete := watch.NewSet()
+ gvksToDelete.Add(configMapGVK)
+ return gvksToDelete
+ }(),
+ syncMetricsCache: syncutil.NewMetricsCache(),
+ },
+ expectedData: map[fakes.CfDataKey]interface{}{},
+ },
+ {
+ name: "wipe cache if there are excluder changes",
+ cm: &CacheManager{
+ cfClient: dataClientForTest(),
+ excluderChanged: true,
+ syncMetricsCache: syncutil.NewMetricsCache(),
+ gvksToDeleteFromCache: watch.NewSet(),
+ },
+ expectedData: map[fakes.CfDataKey]interface{}{},
+ },
+ {
+ name: "don't wipe cache if no excluder changes or no gvks to delete",
+ cm: &CacheManager{
+ cfClient: dataClientForTest(),
+ syncMetricsCache: syncutil.NewMetricsCache(),
+ gvksToDeleteFromCache: watch.NewSet(),
+ },
+ expectedData: map[fakes.CfDataKey]interface{}{{Gvk: configMapGVK, Key: "default/config-test-1"}: nil},
+ },
+ }
+
+ for _, tc := range tcs {
+ t.Run(tc.name, func(t *testing.T) {
+ cfClient, ok := tc.cm.cfClient.(*fakes.FakeCfClient)
+ require.True(t, ok)
+
+ tc.cm.wipeCacheIfNeeded(context.Background())
+ require.True(t, cfClient.Contains(tc.expectedData))
+ })
+ }
+}
+
+// TestCacheManager_AddObject tests that we can add objects in the cache.
+func TestCacheManager_AddObject(t *testing.T) {
+ pod := fakes.Pod(
+ fakes.WithNamespace("test-ns"),
+ fakes.WithName("test-name"),
+ )
+ unstructuredPod, err := runtime.DefaultUnstructuredConverter.ToUnstructured(pod)
+ require.NoError(t, err)
+
+ mgr, _ := testutils.SetupManager(t, cfg)
+
+ tcs := []struct {
+ name string
+ cm *CacheManager
+ expectSyncMetric bool
+ expectedMetricStatus metrics.Status
+ expectedData map[fakes.CfDataKey]interface{}
+ }{
+ {
+ name: "AddObject happy path",
+ cm: &CacheManager{
+ cfClient: &fakes.FakeCfClient{},
+ watchedSet: func() *watch.Set {
+ ws := watch.NewSet()
+ ws.Add(pod.GroupVersionKind())
+
+ return ws
+ }(),
+ tracker: readiness.NewTracker(mgr.GetAPIReader(), false, false, false),
+ syncMetricsCache: syncutil.NewMetricsCache(),
+ processExcluder: process.Get(),
+ },
+ expectedData: map[fakes.CfDataKey]interface{}{{Gvk: pod.GroupVersionKind(), Key: "test-ns/test-name"}: nil},
+ expectSyncMetric: true,
+ expectedMetricStatus: metrics.ActiveStatus,
+ },
+ {
+ name: "AddObject has no effect if GVK is not watched",
+ cm: &CacheManager{
+ cfClient: &fakes.FakeCfClient{},
+ watchedSet: watch.NewSet(),
+ tracker: readiness.NewTracker(mgr.GetAPIReader(), false, false, false),
+ syncMetricsCache: syncutil.NewMetricsCache(),
+ processExcluder: process.Get(),
+ },
+ expectedData: map[fakes.CfDataKey]interface{}{},
+ expectSyncMetric: false,
+ },
+ {
+ name: "AddObject has no effect if GVK is process excluded",
+ cm: &CacheManager{
+ cfClient: &fakes.FakeCfClient{},
+ watchedSet: func() *watch.Set {
+ ws := watch.NewSet()
+ ws.Add(pod.GroupVersionKind())
+
+ return ws
+ }(),
+ tracker: readiness.NewTracker(mgr.GetAPIReader(), false, false, false),
+ syncMetricsCache: syncutil.NewMetricsCache(),
+ processExcluder: func() *process.Excluder {
+ processExcluder := process.New()
+ processExcluder.Add([]configv1alpha1.MatchEntry{
+ {
+ ExcludedNamespaces: []wildcard.Wildcard{"test-ns"},
+ Processes: []string{"sync"},
+ },
+ })
+ return processExcluder
+ }(),
+ },
+ expectedData: map[fakes.CfDataKey]interface{}{},
+ expectSyncMetric: false,
+ },
+ {
+ name: "AddObject sets metrics on error from cfdataclient",
+ cm: &CacheManager{
+ cfClient: func() CFDataClient {
+ c := &fakes.FakeCfClient{}
+ c.SetErroring(true)
+ return c
+ }(),
+ watchedSet: func() *watch.Set {
+ ws := watch.NewSet()
+ ws.Add(pod.GroupVersionKind())
+
+ return ws
+ }(),
+ tracker: readiness.NewTracker(mgr.GetAPIReader(), false, false, false),
+ syncMetricsCache: syncutil.NewMetricsCache(),
+ processExcluder: process.Get(),
+ },
+ expectedData: map[fakes.CfDataKey]interface{}{},
+ expectSyncMetric: true,
+ expectedMetricStatus: metrics.ErrorStatus,
+ },
+ }
+
+ for _, tc := range tcs {
+ t.Run(tc.name, func(t *testing.T) {
+ err := tc.cm.AddObject(context.Background(), &unstructured.Unstructured{Object: unstructuredPod})
+ if tc.expectedMetricStatus == metrics.ActiveStatus {
+ require.NoError(t, err)
+ }
+
+ assertExpecations(t, tc.cm, &unstructured.Unstructured{Object: unstructuredPod}, tc.expectedData, tc.expectSyncMetric, &tc.expectedMetricStatus)
+ })
+ }
+}
+
+func assertExpecations(t *testing.T, cm *CacheManager, instance *unstructured.Unstructured, expectedData map[fakes.CfDataKey]interface{}, expectSyncMetric bool, expectedMetricStatus *metrics.Status) {
+ t.Helper()
+
+ cfClient, ok := cm.cfClient.(*fakes.FakeCfClient)
+ require.True(t, ok)
+
+ require.True(t, cfClient.Contains(expectedData))
+
+ syncKey := syncutil.GetKeyForSyncMetrics(instance.GetNamespace(), instance.GetName())
+
+ require.Equal(t, expectSyncMetric, cm.syncMetricsCache.HasObject(syncKey))
+
+ if expectSyncMetric {
+ require.Equal(t, *expectedMetricStatus, cm.syncMetricsCache.GetTags(syncKey).Status)
+ }
+}
+
+// TestCacheManager_RemoveObject tests that we can remove objects from the cache.
+func TestCacheManager_RemoveObject(t *testing.T) {
+ pod := fakes.Pod(
+ fakes.WithNamespace("test-ns"),
+ fakes.WithName("test-name"),
+ )
+ unstructuredPod, err := runtime.DefaultUnstructuredConverter.ToUnstructured(pod)
+ require.NoError(t, err)
+
+ mgr, _ := testutils.SetupManager(t, cfg)
+ tracker := readiness.NewTracker(mgr.GetAPIReader(), false, false, false)
+ makeDataClient := func() *fakes.FakeCfClient {
+ c := &fakes.FakeCfClient{}
+ _, err := c.AddData(context.Background(), &unstructured.Unstructured{Object: unstructuredPod})
+ require.NoError(t, err)
+
+ return c
+ }
+
+ tcs := []struct {
+ name string
+ cm *CacheManager
+ expectSyncMetric bool
+ expectedData map[fakes.CfDataKey]interface{}
+ }{
+ {
+ name: "RemoveObject happy path",
+ cm: &CacheManager{
+ cfClient: makeDataClient(),
+ watchedSet: func() *watch.Set {
+ ws := watch.NewSet()
+ ws.Add(pod.GroupVersionKind())
+
+ return ws
+ }(),
+ tracker: tracker,
+ syncMetricsCache: syncutil.NewMetricsCache(),
+ processExcluder: process.Get(),
+ },
+ expectedData: map[fakes.CfDataKey]interface{}{},
+ expectSyncMetric: false,
+ },
+ {
+ name: "RemoveObject succeeds even if GVK is not watched",
+ cm: &CacheManager{
+ cfClient: makeDataClient(),
+ watchedSet: watch.NewSet(),
+ tracker: tracker,
+ syncMetricsCache: syncutil.NewMetricsCache(),
+ processExcluder: process.Get(),
+ },
+ expectedData: map[fakes.CfDataKey]interface{}{},
+ expectSyncMetric: false,
+ },
+ {
+ name: "RemoveObject succeeds even if process excluded",
+ cm: &CacheManager{
+ cfClient: makeDataClient(),
+ watchedSet: func() *watch.Set {
+ ws := watch.NewSet()
+ ws.Add(pod.GroupVersionKind())
+
+ return ws
+ }(),
+ tracker: tracker,
+ syncMetricsCache: syncutil.NewMetricsCache(),
+ processExcluder: func() *process.Excluder {
+ processExcluder := process.New()
+ processExcluder.Add([]configv1alpha1.MatchEntry{
+ {
+ ExcludedNamespaces: []wildcard.Wildcard{"test-ns"},
+ Processes: []string{"sync"},
+ },
+ })
+ return processExcluder
+ }(),
+ },
+ expectedData: map[fakes.CfDataKey]interface{}{},
+ expectSyncMetric: false,
+ },
+ }
+
+ for _, tc := range tcs {
+ t.Run(tc.name, func(t *testing.T) {
+ require.NoError(t, tc.cm.RemoveObject(context.Background(), &unstructured.Unstructured{Object: unstructuredPod}))
+
+ assertExpecations(t, tc.cm, &unstructured.Unstructured{Object: unstructuredPod}, tc.expectedData, tc.expectSyncMetric, nil)
+ })
+ }
+}
+
+// TestCacheManager_UpsertSource tests that we can modify the gvk aggregator and watched set when adding a new source.
+func TestCacheManager_UpsertSource(t *testing.T) {
+ configMapGVK := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}
+ podGVK := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}
+ sourceA := aggregator.Key{Source: "a", ID: "source"}
+ sourceB := aggregator.Key{Source: "b", ID: "source"}
+
+ type sourcesAndGvk struct {
+ source aggregator.Key
+ gvks []schema.GroupVersionKind
+ }
+
+ tcs := []struct {
+ name string
+ sourcesAndGvks []sourcesAndGvk
+ expectedGVKs []schema.GroupVersionKind
+ }{
+ {
+ name: "add one source",
+ sourcesAndGvks: []sourcesAndGvk{
+ {
+ source: sourceA,
+ gvks: []schema.GroupVersionKind{configMapGVK},
+ },
+ },
+ expectedGVKs: []schema.GroupVersionKind{configMapGVK},
+ },
+ {
+ name: "overwrite source",
+ sourcesAndGvks: []sourcesAndGvk{
+ {
+ source: sourceA,
+ gvks: []schema.GroupVersionKind{configMapGVK},
+ },
+ {
+ source: sourceA,
+ gvks: []schema.GroupVersionKind{podGVK},
+ },
+ },
+ expectedGVKs: []schema.GroupVersionKind{podGVK},
+ },
+ {
+ name: "remove source by not specifying any gvk",
+ sourcesAndGvks: []sourcesAndGvk{
+ {
+ source: sourceA,
+ gvks: []schema.GroupVersionKind{configMapGVK},
+ },
+ {
+ source: sourceA,
+ gvks: []schema.GroupVersionKind{},
+ },
+ },
+ expectedGVKs: []schema.GroupVersionKind{},
+ },
+ {
+ name: "add two disjoing sources",
+ sourcesAndGvks: []sourcesAndGvk{
+ {
+ source: sourceA,
+ gvks: []schema.GroupVersionKind{configMapGVK},
+ },
+ {
+ source: sourceB,
+ gvks: []schema.GroupVersionKind{podGVK},
+ },
+ },
+ expectedGVKs: []schema.GroupVersionKind{configMapGVK, podGVK},
+ },
+ {
+ name: "add two sources with overlapping gvks",
+ sourcesAndGvks: []sourcesAndGvk{
+ {
+ source: sourceA,
+ gvks: []schema.GroupVersionKind{configMapGVK, podGVK},
+ },
+ {
+ source: sourceB,
+ gvks: []schema.GroupVersionKind{podGVK},
+ },
+ },
+ expectedGVKs: []schema.GroupVersionKind{configMapGVK, podGVK},
+ },
+ }
+
+ for _, tc := range tcs {
+ t.Run(tc.name, func(t *testing.T) {
+ cacheManager, ctx := makeCacheManager(t)
+
+ for _, sourceAndGVK := range tc.sourcesAndGvks {
+ require.NoError(t, cacheManager.UpsertSource(ctx, sourceAndGVK.source, sourceAndGVK.gvks))
+ }
+
+ require.ElementsMatch(t, cacheManager.watchedSet.Items(), tc.expectedGVKs)
+ require.ElementsMatch(t, cacheManager.gvksToSync.GVKs(), tc.expectedGVKs)
+ })
+ }
+}
+
+// TestCacheManager_RemoveSource tests that we can modify the gvk aggregator when removing a source.
+func TestCacheManager_RemoveSource(t *testing.T) {
+ configMapGVK := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}
+ podGVK := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}
+ sourceA := aggregator.Key{Source: "a", ID: "source"}
+ sourceB := aggregator.Key{Source: "b", ID: "source"}
+
+ tcs := []struct {
+ name string
+ seed func(c *CacheManager)
+ sourcesToRemove []aggregator.Key
+ expectedGVKs []schema.GroupVersionKind
+ }{
+ {
+ name: "remove disjoint source",
+ seed: func(c *CacheManager) {
+ require.NoError(t, c.gvksToSync.Upsert(sourceA, []schema.GroupVersionKind{podGVK}))
+ require.NoError(t, c.gvksToSync.Upsert(sourceB, []schema.GroupVersionKind{configMapGVK}))
+ },
+ sourcesToRemove: []aggregator.Key{sourceB},
+ expectedGVKs: []schema.GroupVersionKind{podGVK},
+ },
+ {
+ name: "remove overlapping source",
+ seed: func(c *CacheManager) {
+ require.NoError(t, c.gvksToSync.Upsert(sourceA, []schema.GroupVersionKind{podGVK}))
+ require.NoError(t, c.gvksToSync.Upsert(sourceB, []schema.GroupVersionKind{podGVK}))
+ },
+ sourcesToRemove: []aggregator.Key{sourceB},
+ expectedGVKs: []schema.GroupVersionKind{podGVK},
+ },
+ {
+ name: "remove non existing source",
+ seed: func(c *CacheManager) {
+ require.NoError(t, c.gvksToSync.Upsert(sourceA, []schema.GroupVersionKind{podGVK}))
+ },
+ sourcesToRemove: []aggregator.Key{sourceB},
+ expectedGVKs: []schema.GroupVersionKind{podGVK},
+ },
+ }
+
+ for _, tc := range tcs {
+ t.Run(tc.name, func(t *testing.T) {
+ cm, ctx := makeCacheManager(t)
+ tc.seed(cm)
+
+ for _, source := range tc.sourcesToRemove {
+ require.NoError(t, cm.RemoveSource(ctx, source))
+ }
+
+ require.ElementsMatch(t, cm.gvksToSync.GVKs(), tc.expectedGVKs)
+ })
+ }
+ cacheManager, ctx := makeCacheManager(t)
+
+ // seed the gvk aggregator
+ require.NoError(t, cacheManager.gvksToSync.Upsert(sourceA, []schema.GroupVersionKind{podGVK}))
+ require.NoError(t, cacheManager.gvksToSync.Upsert(sourceB, []schema.GroupVersionKind{podGVK, configMapGVK}))
+
+ // removing a source that is not the only one referencing a gvk ...
+ require.NoError(t, cacheManager.RemoveSource(ctx, sourceB))
+ // ... should not remove any gvks that are still referenced by other sources
+ require.True(t, cacheManager.gvksToSync.IsPresent(podGVK))
+ require.False(t, cacheManager.gvksToSync.IsPresent(configMapGVK))
+
+ require.NoError(t, cacheManager.RemoveSource(ctx, sourceA))
+ require.False(t, cacheManager.gvksToSync.IsPresent(podGVK))
+}
+
+func unstructuredFor(gvk schema.GroupVersionKind, name string) *unstructured.Unstructured {
+ u := &unstructured.Unstructured{}
+ u.SetGroupVersionKind(gvk)
+ u.SetName(name)
+ u.SetNamespace("default")
+ if gvk.Kind == "Pod" {
+ u.Object["spec"] = map[string]interface{}{
+ "containers": []map[string]interface{}{
+ {
+ "name": "foo-container",
+ "image": "foo-image",
+ },
+ },
+ }
+ }
+ return u
+}
diff --git a/pkg/cachemanager/cachemanager_test/cachemanager_integration_test.go b/pkg/cachemanager/cachemanager_test/cachemanager_integration_test.go
new file mode 100644
index 00000000000..7618c62bf45
--- /dev/null
+++ b/pkg/cachemanager/cachemanager_test/cachemanager_integration_test.go
@@ -0,0 +1,369 @@
+package cachemanager_test
+
+import (
+ "context"
+ "fmt"
+ "math/rand"
+ "sync"
+ "testing"
+ "time"
+
+ configv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager/aggregator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ syncc "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/sync"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/syncutil"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
+ testclient "github.com/open-policy-agent/gatekeeper/v3/test/clients"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+)
+
+const (
+ eventuallyTimeout = 10 * time.Second
+ eventuallyTicker = 2 * time.Second
+
+ jitterUpperBound = 100
+)
+
+var cfg *rest.Config
+
+var (
+ configMapGVK = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}
+ podGVK = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}
+
+ cm1Name = "config-test-1"
+ cm2Name = "config-test-2"
+
+ pod1Name = "pod-test-1"
+)
+
+func TestMain(m *testing.M) {
+ testutils.StartControlPlane(m, &cfg, 3)
+}
+
+// TestCacheManager_replay_retries tests that we can retry GVKs that error out in the replay goroutine.
+func TestCacheManager_replay_retries(t *testing.T) {
+ mgr, wm := testutils.SetupManager(t, cfg)
+ c := testclient.NewRetryClient(mgr.GetClient())
+
+ fi := fakes.NewFailureInjector()
+ reader := fakes.SpyReader{
+ Reader: c,
+ ListFunc: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
+ // return as many syntenthic failures as there are registered for this kind
+ if fi.CheckFailures(list.GetObjectKind().GroupVersionKind().Kind) {
+ return fmt.Errorf("synthetic failure")
+ }
+
+ return c.List(ctx, list, opts...)
+ },
+ }
+
+ testResources, ctx := makeTestResources(t, mgr, wm, reader)
+ cacheManager := testResources.CacheManager
+ dataStore := testResources.CFDataClient
+
+ cfClient, ok := dataStore.(*fakes.FakeCfClient)
+ require.True(t, ok)
+
+ cm := unstructuredFor(configMapGVK, cm1Name)
+ require.NoError(t, c.Create(ctx, cm), fmt.Sprintf("creating ConfigMap %s", cm1Name))
+ t.Cleanup(func() {
+ assert.NoError(t, deleteResource(ctx, c, cm), fmt.Sprintf("deleting resource %s", cm1Name))
+ })
+ cmKey, err := fakes.KeyFor(cm)
+ require.NoError(t, err)
+
+ pod := unstructuredFor(podGVK, pod1Name)
+ require.NoError(t, c.Create(ctx, pod), fmt.Sprintf("creating Pod %s", pod1Name))
+ t.Cleanup(func() {
+ assert.NoError(t, deleteResource(ctx, c, pod), fmt.Sprintf("deleting resource %s", pod1Name))
+ })
+ podKey, err := fakes.KeyFor(pod)
+ require.NoError(t, err)
+
+ syncSourceOne := aggregator.Key{Source: "source_a", ID: "ID_a"}
+ require.NoError(t, cacheManager.UpsertSource(ctx, syncSourceOne, []schema.GroupVersionKind{configMapGVK, podGVK}))
+
+ expected := map[fakes.CfDataKey]interface{}{
+ cmKey: nil,
+ podKey: nil,
+ }
+
+ require.Eventually(t, expectedCheck(cfClient, expected), eventuallyTimeout, eventuallyTicker)
+
+ fi.SetFailures("ConfigMapList", 5)
+
+ // this call should schedule a cache wipe and a replay for the configMapGVK
+ require.NoError(t, cacheManager.UpsertSource(ctx, syncSourceOne, []schema.GroupVersionKind{configMapGVK}))
+
+ expected2 := map[fakes.CfDataKey]interface{}{
+ cmKey: nil,
+ }
+ require.Eventually(t, expectedCheck(cfClient, expected2), eventuallyTimeout, eventuallyTicker)
+}
+
+// TestCacheManager_concurrent makes sure that we can add and remove multiple sources
+// from separate go routines and changes to the underlying cache are reflected.
+func TestCacheManager_concurrent(t *testing.T) {
+ r := rand.New(rand.NewSource(12345)) // #nosec G404: Using weak random number generator for determinism between calls
+
+ mgr, wm := testutils.SetupManager(t, cfg)
+ c := testclient.NewRetryClient(mgr.GetClient())
+ testResources, ctx := makeTestResources(t, mgr, wm, c)
+
+ cacheManager := testResources.CacheManager
+ dataStore := testResources.CFDataClient
+ agg := testResources.GVKAgreggator
+
+ // Create configMaps to test for
+ cm := unstructuredFor(configMapGVK, cm1Name)
+ require.NoError(t, c.Create(ctx, cm), fmt.Sprintf("creating ConfigMap %s", cm1Name))
+ t.Cleanup(func() {
+ assert.NoError(t, deleteResource(ctx, c, cm), fmt.Sprintf("deleting resource %s", cm1Name))
+ })
+ cmKey, err := fakes.KeyFor(cm)
+ require.NoError(t, err)
+
+ cm2 := unstructuredFor(configMapGVK, cm2Name)
+ require.NoError(t, c.Create(ctx, cm2), fmt.Sprintf("creating ConfigMap %s", cm2Name))
+ t.Cleanup(func() {
+ assert.NoError(t, deleteResource(ctx, c, cm2), fmt.Sprintf("deleting resource %s", cm2Name))
+ })
+ cm2Key, err := fakes.KeyFor(cm2)
+ require.NoError(t, err)
+
+ pod := unstructuredFor(podGVK, pod1Name)
+ require.NoError(t, c.Create(ctx, pod), fmt.Sprintf("creating Pod %s", pod1Name))
+ t.Cleanup(func() {
+ assert.NoError(t, deleteResource(ctx, c, pod), fmt.Sprintf("deleting resource %s", pod1Name))
+ })
+ podKey, err := fakes.KeyFor(pod)
+ require.NoError(t, err)
+
+ cfClient, ok := dataStore.(*fakes.FakeCfClient)
+ require.True(t, ok)
+
+ syncSourceOne := aggregator.Key{Source: "source_a", ID: "ID_a"}
+ syncSourceTwo := aggregator.Key{Source: "source_b", ID: "ID_b"}
+
+ wg := &sync.WaitGroup{}
+
+ // simulate a churn-y concurrent access by swapping the gvks for the sync sources repeatedly
+ // and removing sync sources, all from different go routines.
+ for i := 1; i < 100; i++ {
+ wg.Add(3)
+
+ // add some jitter between go func calls
+ time.Sleep(time.Duration(r.Intn(jitterUpperBound)) * time.Millisecond)
+ go func() {
+ defer wg.Done()
+
+ assert.NoError(t, cacheManager.UpsertSource(ctx, syncSourceOne, []schema.GroupVersionKind{configMapGVK}))
+ assert.NoError(t, cacheManager.UpsertSource(ctx, syncSourceTwo, []schema.GroupVersionKind{podGVK}))
+ }()
+
+ time.Sleep(time.Duration(r.Intn(jitterUpperBound)) * time.Millisecond)
+ go func() {
+ defer wg.Done()
+
+ assert.NoError(t, cacheManager.UpsertSource(ctx, syncSourceOne, []schema.GroupVersionKind{podGVK}))
+ assert.NoError(t, cacheManager.UpsertSource(ctx, syncSourceTwo, []schema.GroupVersionKind{configMapGVK}))
+ }()
+
+ time.Sleep(time.Duration(r.Intn(jitterUpperBound)) * time.Millisecond)
+ go func() {
+ defer wg.Done()
+
+ assert.NoError(t, cacheManager.RemoveSource(ctx, syncSourceTwo))
+ assert.NoError(t, cacheManager.RemoveSource(ctx, syncSourceOne))
+ }()
+ }
+
+ wg.Wait()
+
+ // final upsert for determinism
+ require.NoError(t, cacheManager.UpsertSource(ctx, syncSourceOne, []schema.GroupVersionKind{configMapGVK}))
+ require.NoError(t, cacheManager.UpsertSource(ctx, syncSourceTwo, []schema.GroupVersionKind{podGVK}))
+
+ expected := map[fakes.CfDataKey]interface{}{
+ cmKey: nil,
+ cm2Key: nil,
+ podKey: nil,
+ }
+
+ require.Eventually(t, expectedCheck(cfClient, expected), eventuallyTimeout, eventuallyTicker)
+ // now assert that the gvkAggregator looks as expected
+ agg.IsPresent(configMapGVK)
+ gvks := agg.List(syncSourceOne)
+ require.Len(t, gvks, 1)
+ _, foundConfigMap := gvks[configMapGVK]
+ require.True(t, foundConfigMap)
+ gvks = agg.List(syncSourceTwo)
+ require.Len(t, gvks, 1)
+ _, foundPod := gvks[podGVK]
+ require.True(t, foundPod)
+
+ // do a final remove and expect the cache to clear
+ require.NoError(t, cacheManager.RemoveSource(ctx, syncSourceOne))
+ require.NoError(t, cacheManager.RemoveSource(ctx, syncSourceTwo))
+
+ require.Eventually(t, expectedCheck(cfClient, map[fakes.CfDataKey]interface{}{}), eventuallyTimeout, eventuallyTicker)
+ require.True(t, len(agg.GVKs()) == 0)
+}
+
+// TestCacheManager_instance_updates tests that cache manager wires up dependencies correctly
+// such that updates to an instance of a watched gvks are reconciled in the sync_controller.
+func TestCacheManager_instance_updates(t *testing.T) {
+ mgr, wm := testutils.SetupManager(t, cfg)
+ c := testclient.NewRetryClient(mgr.GetClient())
+
+ testResources, ctx := makeTestResources(t, mgr, wm, c)
+
+ cacheManager := testResources.CacheManager
+ dataStore := testResources.CFDataClient
+
+ cfClient, ok := dataStore.(*fakes.FakeCfClient)
+ require.True(t, ok)
+
+ cm := unstructuredFor(configMapGVK, cm1Name)
+ require.NoError(t, c.Create(ctx, cm), fmt.Sprintf("creating ConfigMap %s", cm1Name))
+ t.Cleanup(func() {
+ assert.NoError(t, deleteResource(ctx, c, cm), fmt.Sprintf("deleting resource %s", cm1Name))
+ })
+ cmKey, err := fakes.KeyFor(cm)
+ require.NoError(t, err)
+
+ syncSourceOne := aggregator.Key{Source: "source_a", ID: "ID_a"}
+ require.NoError(t, cacheManager.UpsertSource(ctx, syncSourceOne, []schema.GroupVersionKind{configMapGVK}))
+
+ expected := map[fakes.CfDataKey]interface{}{
+ cmKey: nil,
+ }
+
+ require.Eventually(t, expectedCheck(cfClient, expected), eventuallyTimeout, eventuallyTicker)
+
+ cmUpdate := unstructuredFor(configMapGVK, cm1Name)
+ cmUpdate.SetLabels(map[string]string{"testlabel": "test"}) // trigger an instance update
+ require.NoError(t, c.Update(ctx, cmUpdate))
+
+ require.Eventually(t, func() bool {
+ instance := cfClient.GetData(cmKey)
+ unInstance, ok := instance.(*unstructured.Unstructured)
+ require.True(t, ok)
+
+ value, found, err := unstructured.NestedString(unInstance.Object, "metadata", "labels", "testlabel")
+ require.NoError(t, err)
+
+ return found && "test" == value
+ }, eventuallyTimeout, eventuallyTicker)
+}
+
+func deleteResource(ctx context.Context, c client.Client, resounce *unstructured.Unstructured) error {
+ err := c.Delete(ctx, resounce)
+ if apierrors.IsNotFound(err) {
+ // resource does not exist, this is good
+ return nil
+ }
+
+ return err
+}
+
+func expectedCheck(cfClient *fakes.FakeCfClient, expected map[fakes.CfDataKey]interface{}) func() bool {
+ return func() bool {
+ if cfClient.Len() != len(expected) {
+ return false
+ }
+ if cfClient.Contains(expected) {
+ return true
+ }
+
+ return false
+ }
+}
+
+func unstructuredFor(gvk schema.GroupVersionKind, name string) *unstructured.Unstructured {
+ u := &unstructured.Unstructured{}
+ u.SetGroupVersionKind(gvk)
+ u.SetName(name)
+ u.SetNamespace("default")
+ if gvk.Kind == "Pod" {
+ u.Object["spec"] = map[string]interface{}{
+ "containers": []map[string]interface{}{
+ {
+ "name": "foo-container",
+ "image": "foo-image",
+ },
+ },
+ }
+ }
+ return u
+}
+
+type testResources struct {
+ *cachemanager.CacheManager
+ cachemanager.CFDataClient
+ *aggregator.GVKAgreggator
+}
+
+func makeTestResources(t *testing.T, mgr manager.Manager, wm *watch.Manager, reader client.Reader) (testResources, context.Context) {
+ ctx, cancelFunc := context.WithCancel(context.Background())
+ t.Cleanup(func() {
+ cancelFunc()
+ })
+
+ cfClient := &fakes.FakeCfClient{}
+ tracker, err := readiness.SetupTracker(mgr, false, false, false)
+ require.NoError(t, err)
+ processExcluder := process.Get()
+ processExcluder.Add([]configv1alpha1.MatchEntry{
+ {
+ ExcludedNamespaces: []wildcard.Wildcard{"kube-system"},
+ Processes: []string{"sync"},
+ },
+ })
+ events := make(chan event.GenericEvent, 1024)
+ reg, err := wm.NewRegistrar(
+ "test-cache-manager",
+ events)
+ require.NoError(t, err)
+
+ aggregator := aggregator.NewGVKAggregator()
+ config := &cachemanager.Config{
+ CfClient: cfClient,
+ SyncMetricsCache: syncutil.NewMetricsCache(),
+ Tracker: tracker,
+ ProcessExcluder: processExcluder,
+ Registrar: reg,
+ Reader: reader,
+ GVKAggregator: aggregator,
+ }
+ cacheManager, err := cachemanager.NewCacheManager(config)
+ require.NoError(t, err)
+
+ syncAdder := syncc.Adder{
+ Events: events,
+ CacheManager: cacheManager,
+ }
+ require.NoError(t, syncAdder.Add(mgr), "registering sync controller")
+ go func() {
+ assert.NoError(t, cacheManager.Start(ctx))
+ }()
+
+ testutils.StartManager(ctx, t, mgr)
+
+ return testResources{cacheManager, cfClient, aggregator}, ctx
+}
diff --git a/pkg/cachemanager/parser/syncannotationreader.go b/pkg/cachemanager/parser/syncannotationreader.go
new file mode 100644
index 00000000000..ae22dac98d8
--- /dev/null
+++ b/pkg/cachemanager/parser/syncannotationreader.go
@@ -0,0 +1,87 @@
+package parser
+
+import (
+ "encoding/json"
+ "strings"
+
+ "github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// syncAnnotationName is the name of the annotation that stores
+// GVKS that are required to be synced.
+const SyncAnnotationName = "metadata.gatekeeper.sh/requires-sync-data"
+
+// SyncRequirements contains a list of ANDed requirements, each of which
+// contains an expanded set of equivalent (ORed) GVKs.
+type SyncRequirements []GVKEquivalenceSet
+
+// GVKEquivalenceSet is a set of GVKs that a template can use
+// interchangeably in its referential policy implementation.
+type GVKEquivalenceSet map[schema.GroupVersionKind]struct{}
+
+// CompactSyncRequirements contains a list of ANDed requirements, each of
+// which contains a list of equivalent (ORed) GVKs in compact form.
+type CompactSyncRequirements [][]CompactGVKEquivalenceSet
+
+// compactGVKEquivalenceSet contains a set of equivalent GVKs, expressed
+// in the compact form [groups, versions, kinds] where any combination of
+// items from these three fields can be considered a valid equivalent.
+// Used for unmarshalling as this is the form used in requiressync annotations.
+type CompactGVKEquivalenceSet struct {
+ Groups []string `json:"groups"`
+ Versions []string `json:"versions"`
+ Kinds []string `json:"kinds"`
+}
+
+// ReadSyncRequirements parses the sync requirements from a
+// constraint template.
+func ReadSyncRequirements(t *templates.ConstraintTemplate) (SyncRequirements, error) {
+ if t.ObjectMeta.Annotations != nil {
+ if annotation, exists := t.ObjectMeta.Annotations[SyncAnnotationName]; exists {
+ annotation = strings.Trim(annotation, "\n\"")
+ compactSyncRequirements := CompactSyncRequirements{}
+ decoder := json.NewDecoder(strings.NewReader(annotation))
+ decoder.DisallowUnknownFields()
+ err := decoder.Decode(&compactSyncRequirements)
+ if err != nil {
+ return nil, err
+ }
+ requirements, err := ExpandCompactRequirements(compactSyncRequirements)
+ if err != nil {
+ return nil, err
+ }
+ return requirements, nil
+ }
+ }
+ return SyncRequirements{}, nil
+}
+
+// Takes a compactGVKSet and expands it into a GVKEquivalenceSet.
+func ExpandCompactEquivalenceSet(compactEquivalenceSet CompactGVKEquivalenceSet) GVKEquivalenceSet {
+ equivalenceSet := GVKEquivalenceSet{}
+ for _, group := range compactEquivalenceSet.Groups {
+ for _, version := range compactEquivalenceSet.Versions {
+ for _, kind := range compactEquivalenceSet.Kinds {
+ equivalenceSet[schema.GroupVersionKind{Group: group, Version: version, Kind: kind}] = struct{}{}
+ }
+ }
+ }
+ return equivalenceSet
+}
+
+// Takes a CompactSyncRequirements (the json form provided in the template
+// annotation) and expands it into a SyncRequirements.
+func ExpandCompactRequirements(compactSyncRequirements CompactSyncRequirements) (SyncRequirements, error) {
+ syncRequirements := SyncRequirements{}
+ for _, compactRequirement := range compactSyncRequirements {
+ requirement := GVKEquivalenceSet{}
+ for _, compactEquivalenceSet := range compactRequirement {
+ for equivalentGVK := range ExpandCompactEquivalenceSet(compactEquivalenceSet) {
+ requirement[equivalentGVK] = struct{}{}
+ }
+ }
+ syncRequirements = append(syncRequirements, requirement)
+ }
+ return syncRequirements, nil
+}
diff --git a/pkg/cachemanager/parser/syncannotationreader_test.go b/pkg/cachemanager/parser/syncannotationreader_test.go
new file mode 100644
index 00000000000..aa26b076eaa
--- /dev/null
+++ b/pkg/cachemanager/parser/syncannotationreader_test.go
@@ -0,0 +1,196 @@
+package parser
+
+import (
+ "reflect"
+ "testing"
+
+ "github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func TestReadSyncRequirements(t *testing.T) {
+ tests := []struct {
+ name string
+ template *templates.ConstraintTemplate
+ want SyncRequirements
+ wantErr bool
+ }{
+ {
+ name: "test with basic valid annotation",
+ template: &templates.ConstraintTemplate{
+ ObjectMeta: metav1.ObjectMeta{
+ Annotations: map[string]string{
+ "metadata.gatekeeper.sh/requires-sync-data": "\n\"[[{\"groups\": [\"group1\"], \"versions\": [\"version1\"], \"kinds\": [\"kind1\"]}]]\"",
+ },
+ },
+ },
+ want: SyncRequirements{
+ {
+ {
+ Group: "group1",
+ Version: "version1",
+ Kind: "kind1",
+ }: struct{}{},
+ },
+ },
+ },
+ {
+ name: "test with valid annotation with multiple groups, versions, and kinds",
+ template: &templates.ConstraintTemplate{
+ ObjectMeta: metav1.ObjectMeta{
+ Annotations: map[string]string{
+ "metadata.gatekeeper.sh/requires-sync-data": "\n\"[[{\"groups\": [\"group1\", \"group2\"], \"versions\": [\"version1\", \"version2\"], \"kinds\": [\"kind1\", \"kind2\"]}]]\"",
+ },
+ },
+ },
+ want: SyncRequirements{
+ {
+ {
+ Group: "group1",
+ Version: "version1",
+ Kind: "kind1",
+ }: struct{}{},
+ {
+ Group: "group1",
+ Version: "version1",
+ Kind: "kind2",
+ }: struct{}{},
+ {
+ Group: "group1",
+ Version: "version2",
+ Kind: "kind1",
+ }: struct{}{},
+ {
+ Group: "group1",
+ Version: "version2",
+ Kind: "kind2",
+ }: struct{}{},
+ {
+ Group: "group2",
+ Version: "version1",
+ Kind: "kind1",
+ }: struct{}{},
+ {
+ Group: "group2",
+ Version: "version1",
+ Kind: "kind2",
+ }: struct{}{},
+ {
+ Group: "group2",
+ Version: "version2",
+ Kind: "kind1",
+ }: struct{}{},
+ {
+ Group: "group2",
+ Version: "version2",
+ Kind: "kind2",
+ }: struct{}{},
+ },
+ },
+ },
+ {
+ name: "test with valid annotation with multiple equivalence sets",
+ template: &templates.ConstraintTemplate{
+ ObjectMeta: metav1.ObjectMeta{
+ Annotations: map[string]string{
+ "metadata.gatekeeper.sh/requires-sync-data": "\n\"[[{\"groups\": [\"group1\"], \"versions\": [\"version1\"], \"kinds\": [\"kind1\"]}, {\"groups\": [\"group2\"], \"versions\": [\"version2\"], \"kinds\": [\"kind2\"]}]]\"",
+ },
+ },
+ },
+ want: SyncRequirements{
+ {
+ {
+ Group: "group1",
+ Version: "version1",
+ Kind: "kind1",
+ }: struct{}{},
+ {
+ Group: "group2",
+ Version: "version2",
+ Kind: "kind2",
+ }: struct{}{},
+ },
+ },
+ },
+ {
+ name: "test with valid annotation with multiple requirements",
+ template: &templates.ConstraintTemplate{
+ ObjectMeta: metav1.ObjectMeta{
+ Annotations: map[string]string{
+ "metadata.gatekeeper.sh/requires-sync-data": "\n\"[[{\"groups\": [\"group1\"], \"versions\": [\"version1\"], \"kinds\": [\"kind1\"]}], [{\"groups\": [\"group2\"], \"versions\": [\"version2\"], \"kinds\": [\"kind2\"]}]]\"",
+ },
+ },
+ },
+ want: SyncRequirements{
+ {
+ {
+ Group: "group1",
+ Version: "version1",
+ Kind: "kind1",
+ }: struct{}{},
+ },
+ {
+ {
+ Group: "group2",
+ Version: "version2",
+ Kind: "kind2",
+ }: struct{}{},
+ },
+ },
+ },
+ {
+ name: "test with no requires-sync-data annotation",
+ template: &templates.ConstraintTemplate{
+ ObjectMeta: metav1.ObjectMeta{
+ Annotations: map[string]string{},
+ },
+ },
+ want: SyncRequirements{},
+ },
+ {
+ name: "test with empty requires-sync-data annotation",
+ template: &templates.ConstraintTemplate{
+ ObjectMeta: metav1.ObjectMeta{
+ Annotations: map[string]string{
+ "metadata.gatekeeper.sh/requires-sync-data": "",
+ },
+ },
+ },
+ wantErr: true,
+ },
+ {
+ name: "test with invalid requires-sync-data annotation",
+ template: &templates.ConstraintTemplate{
+ ObjectMeta: metav1.ObjectMeta{
+ Annotations: map[string]string{
+ "metadata.gatekeeper.sh/requires-sync-data": "invalid",
+ },
+ },
+ },
+ wantErr: true,
+ },
+ {
+ name: "test with requires-sync-data annotation with invalid keys",
+ template: &templates.ConstraintTemplate{
+ ObjectMeta: metav1.ObjectMeta{
+ Annotations: map[string]string{
+ "metadata.gatekeeper.sh/requires-sync-data": "\n\"[[{\"group\": [\"group1\"], \"version\": [\"version1\"], \"kind\": [\"kind1\"]}]]\"",
+ },
+ },
+ },
+ wantErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := ReadSyncRequirements(tt.template)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("ReadSyncRequirements() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("ReadSyncRequirements() got = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
diff --git a/pkg/controller/add_config.go b/pkg/controller/add_config.go
index 650118903ae..1672a205f0d 100644
--- a/pkg/controller/add_config.go
+++ b/pkg/controller/add_config.go
@@ -16,7 +16,7 @@ limitations under the License.
package controller
import (
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config"
)
func init() {
diff --git a/pkg/controller/add_constrainttemplate.go b/pkg/controller/add_constrainttemplate.go
index ccd01bc9199..837bdf0f3f1 100644
--- a/pkg/controller/add_constrainttemplate.go
+++ b/pkg/controller/add_constrainttemplate.go
@@ -16,7 +16,7 @@ limitations under the License.
package controller
import (
- "github.com/open-policy-agent/gatekeeper/pkg/controller/constrainttemplate"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/constrainttemplate"
)
func init() {
diff --git a/pkg/controller/add_expansionstatus.go b/pkg/controller/add_expansionstatus.go
new file mode 100644
index 00000000000..288375d0429
--- /dev/null
+++ b/pkg/controller/add_expansionstatus.go
@@ -0,0 +1,24 @@
+/*
+
+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 controller
+
+import (
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/expansionstatus"
+)
+
+func init() {
+ Injectors = append(Injectors, &expansionstatus.Adder{})
+}
diff --git a/pkg/controller/add_expansiontemplate.go b/pkg/controller/add_expansiontemplate.go
index 6abdf4340ac..f917bb73472 100644
--- a/pkg/controller/add_expansiontemplate.go
+++ b/pkg/controller/add_expansiontemplate.go
@@ -16,7 +16,7 @@ limitations under the License.
package controller
import (
- "github.com/open-policy-agent/gatekeeper/pkg/controller/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/expansion"
)
func init() {
diff --git a/pkg/controller/add_externaldata.go b/pkg/controller/add_externaldata.go
index 2a637230498..425365c0b27 100644
--- a/pkg/controller/add_externaldata.go
+++ b/pkg/controller/add_externaldata.go
@@ -13,7 +13,7 @@ limitations under the License.
package controller
import (
- "github.com/open-policy-agent/gatekeeper/pkg/controller/externaldata"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/externaldata"
)
func init() {
diff --git a/pkg/controller/add_mutators.go b/pkg/controller/add_mutators.go
index b030cf82c86..5e6eef76e2c 100644
--- a/pkg/controller/add_mutators.go
+++ b/pkg/controller/add_mutators.go
@@ -16,7 +16,7 @@ limitations under the License.
package controller
import (
- "github.com/open-policy-agent/gatekeeper/pkg/controller/mutators/instances"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/mutators/instances"
)
func init() {
diff --git a/pkg/controller/add_mutatorstatus.go b/pkg/controller/add_mutatorstatus.go
index f47d4d7db1e..91b1a374b0a 100644
--- a/pkg/controller/add_mutatorstatus.go
+++ b/pkg/controller/add_mutatorstatus.go
@@ -16,7 +16,7 @@ limitations under the License.
package controller
import (
- "github.com/open-policy-agent/gatekeeper/pkg/controller/mutatorstatus"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/mutatorstatus"
)
func init() {
diff --git a/pkg/controller/add_pubsub.go b/pkg/controller/add_pubsub.go
new file mode 100644
index 00000000000..52904f36d50
--- /dev/null
+++ b/pkg/controller/add_pubsub.go
@@ -0,0 +1,24 @@
+/*
+
+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 controller
+
+import (
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/pubsub"
+)
+
+func init() {
+ Injectors = append(Injectors, &pubsub.Adder{})
+}
diff --git a/pkg/controller/config/config_controller.go b/pkg/controller/config/config_controller.go
index 81baf0c6876..59c2d9db3a4 100644
--- a/pkg/controller/config/config_controller.go
+++ b/pkg/controller/config/config_controller.go
@@ -19,25 +19,18 @@ import (
"context"
"fmt"
- constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- configv1alpha1 "github.com/open-policy-agent/gatekeeper/apis/config/v1alpha1"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- syncc "github.com/open-policy-agent/gatekeeper/pkg/controller/sync"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/keys"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
+ configv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ cm "github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager/aggregator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/keys"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
"k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
- "sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
@@ -53,21 +46,15 @@ const (
var log = logf.Log.WithName("controller").WithValues("kind", "Config")
type Adder struct {
- Opa *constraintclient.Client
- WatchManager *watch.Manager
ControllerSwitch *watch.ControllerSwitch
Tracker *readiness.Tracker
- ProcessExcluder *process.Excluder
- WatchSet *watch.Set
+ CacheManager *cm.CacheManager
}
// Add creates a new ConfigController and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
// and Start it when the Manager is Started.
func (a *Adder) Add(mgr manager.Manager) error {
- // Events will be used to receive events from dynamic watches registered
- // via the registrar below.
- events := make(chan event.GenericEvent, 1024)
- r, err := newReconciler(mgr, a.Opa, a.WatchManager, a.ControllerSwitch, a.Tracker, a.ProcessExcluder, events, a.WatchSet, events)
+ r, err := newReconciler(mgr, a.CacheManager, a.ControllerSwitch, a.Tracker)
if err != nil {
return err
}
@@ -75,14 +62,6 @@ func (a *Adder) Add(mgr manager.Manager) error {
return add(mgr, r)
}
-func (a *Adder) InjectOpa(o *constraintclient.Client) {
- a.Opa = o
-}
-
-func (a *Adder) InjectWatchManager(wm *watch.Manager) {
- a.WatchManager = wm
-}
-
func (a *Adder) InjectControllerSwitch(cs *watch.ControllerSwitch) {
a.ControllerSwitch = cs
}
@@ -91,62 +70,24 @@ func (a *Adder) InjectTracker(t *readiness.Tracker) {
a.Tracker = t
}
-func (a *Adder) InjectProcessExcluder(m *process.Excluder) {
- a.ProcessExcluder = m
+func (a *Adder) InjectCacheManager(cm *cm.CacheManager) {
+ a.CacheManager = cm
}
-func (a *Adder) InjectMutationSystem(mutationSystem *mutation.System) {}
-
-func (a *Adder) InjectExpansionSystem(expansionSystem *expansion.System) {}
-
-func (a *Adder) InjectProviderCache(providerCache *externaldata.ProviderCache) {}
-
-func (a *Adder) InjectWatchSet(watchSet *watch.Set) {
- a.WatchSet = watchSet
-}
-
-// newReconciler returns a new reconcile.Reconciler
-// events is the channel from which sync controller will receive the events
-// regEvents is the channel registered by Registrar to put the events in
-// events and regEvents point to same event channel except for testing.
-func newReconciler(mgr manager.Manager, opa syncc.OpaDataClient, wm *watch.Manager, cs *watch.ControllerSwitch, tracker *readiness.Tracker, processExcluder *process.Excluder, events <-chan event.GenericEvent, watchSet *watch.Set, regEvents chan<- event.GenericEvent) (*ReconcileConfig, error) {
- filteredOpa := syncc.NewFilteredOpaDataClient(opa, watchSet)
- syncMetricsCache := syncc.NewMetricsCache()
-
- syncAdder := syncc.Adder{
- Opa: filteredOpa,
- Events: events,
- MetricsCache: syncMetricsCache,
- Tracker: tracker,
- ProcessExcluder: processExcluder,
- }
- // Create subordinate controller - we will feed it events dynamically via watch
- if err := syncAdder.Add(mgr); err != nil {
- return nil, fmt.Errorf("registering sync controller: %w", err)
- }
-
- if watchSet == nil {
- return nil, fmt.Errorf("watchSet must be non-nil")
+// newReconciler returns a new reconcile.Reconciler.
+func newReconciler(mgr manager.Manager, cm *cm.CacheManager, cs *watch.ControllerSwitch, tracker *readiness.Tracker) (*ReconcileConfig, error) {
+ if cm == nil {
+ return nil, fmt.Errorf("cacheManager must be non-nil")
}
- w, err := wm.NewRegistrar(
- ctrlName,
- regEvents)
- if err != nil {
- return nil, err
- }
return &ReconcileConfig{
- reader: mgr.GetCache(),
- writer: mgr.GetClient(),
- statusClient: mgr.GetClient(),
- scheme: mgr.GetScheme(),
- opa: filteredOpa,
- cs: cs,
- watcher: w,
- watched: watchSet,
- syncMetricsCache: syncMetricsCache,
- tracker: tracker,
- processExcluder: processExcluder,
+ reader: mgr.GetCache(),
+ writer: mgr.GetClient(),
+ statusClient: mgr.GetClient(),
+ scheme: mgr.GetScheme(),
+ cs: cs,
+ cacheManager: cm,
+ tracker: tracker,
}, nil
}
@@ -159,7 +100,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
}
// Watch for changes to Config
- err = c.Watch(&source.Kind{Type: &configv1alpha1.Config{}}, &handler.EnqueueRequestForObject{})
+ err = c.Watch(source.Kind(mgr.GetCache(), &configv1alpha1.Config{}), &handler.EnqueueRequestForObject{})
if err != nil {
return err
}
@@ -175,24 +116,18 @@ type ReconcileConfig struct {
writer client.Writer
statusClient client.StatusClient
- scheme *runtime.Scheme
- opa syncc.OpaDataClient
- syncMetricsCache *syncc.MetricsCache
- cs *watch.ControllerSwitch
- watcher *watch.Registrar
-
- watched *watch.Set
+ scheme *runtime.Scheme
+ cacheManager *cm.CacheManager
+ cs *watch.ControllerSwitch
- needsReplay *watch.Set
- needsWipe bool
- tracker *readiness.Tracker
- processExcluder *process.Excluder
+ tracker *readiness.Tracker
}
// +kubebuilder:rbac:groups=*,resources=*,verbs=get;list;watch
// +kubebuilder:rbac:groups=policy,resources=podsecuritypolicies,resourceNames=gatekeeper-admin,verbs=use
// +kubebuilder:rbac:groups=config.gatekeeper.sh,resources=configs,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=config.gatekeeper.sh,resources=configs/status,verbs=get;update;patch
+// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch;
// Reconcile reads that state of the cluster for a Config object and makes changes based on the state read
// and what is in the Config.Spec
@@ -236,15 +171,15 @@ func (r *ReconcileConfig) Reconcile(ctx context.Context, request reconcile.Reque
}
}
- newSyncOnly := watch.NewSet()
newExcluder := process.New()
var statsEnabled bool
// If the config is being deleted the user is saying they don't want to
// sync anything
+ gvksToSync := []schema.GroupVersionKind{}
if exists && instance.GetDeletionTimestamp().IsZero() {
for _, entry := range instance.Spec.Sync.SyncOnly {
gvk := schema.GroupVersionKind{Group: entry.Group, Version: entry.Version, Kind: entry.Kind}
- newSyncOnly.Add(gvk)
+ gvksToSync = append(gvksToSync, gvk)
}
newExcluder.Add(instance.Spec.Match)
@@ -260,146 +195,15 @@ func (r *ReconcileConfig) Reconcile(ctx context.Context, request reconcile.Reque
r.tracker.DisableStats()
}
- // Remove expectations for resources we no longer watch.
- diff := r.watched.Difference(newSyncOnly)
- r.removeStaleExpectations(diff)
-
- // If the watch set has not changed, we're done here.
- if r.watched.Equals(newSyncOnly) && r.processExcluder.Equals(newExcluder) {
- // ...unless we have pending wipe / replay operations from a previous reconcile.
- if !(r.needsWipe || r.needsReplay != nil) {
- return reconcile.Result{}, nil
- }
-
- // If we reach here, the watch set hasn't changed since last reconcile, but we
- // have unfinished wipe/replay business from the last change.
- } else {
- // The watch set _has_ changed, so recalculate the replay set.
- r.needsReplay = nil
- r.needsWipe = true
- }
-
- // --- Start watching the new set ---
-
- // This must happen first - signals to the opa client in the sync controller
- // to drop events from no-longer-watched resources that may be in its queue.
- if r.needsReplay == nil {
- r.needsReplay = r.watched.Intersection(newSyncOnly)
- }
-
- // Wipe all data to avoid stale state if needed. Happens once per watch-set-change.
- if err := r.wipeCacheIfNeeded(ctx); err != nil {
- return reconcile.Result{}, fmt.Errorf("wiping opa data cache: %w", err)
- }
-
- r.watched.Replace(newSyncOnly, func() {
- // swapping with the new excluder
- r.processExcluder.Replace(newExcluder)
-
- // *Note the following steps are not transactional with respect to admission control*
-
- // Important: dynamic watches update must happen *after* updating our watchSet.
- // Otherwise, the sync controller will drop events for the newly watched kinds.
- // Defer error handling so object re-sync happens even if the watch is hard
- // errored due to a missing GVK in the watch set.
- err = r.watcher.ReplaceWatch(newSyncOnly.Items())
- })
- if err != nil {
- return reconcile.Result{}, err
- }
-
- // Replay cached data for any resources that were previously watched and still in the watch set.
- // This is necessary because we wipe their data from Opa above.
- // TODO(OREN): Improve later by selectively removing subtrees of data instead of a full wipe.
- if err := r.replayData(ctx); err != nil {
- return reconcile.Result{}, fmt.Errorf("replaying data: %w", err)
+ r.cacheManager.ExcludeProcesses(newExcluder)
+ configSourceKey := aggregator.Key{Source: "config", ID: request.NamespacedName.String()}
+ if err := r.cacheManager.UpsertSource(ctx, configSourceKey, gvksToSync); err != nil {
+ return reconcile.Result{Requeue: true}, fmt.Errorf("config-controller: error establishing watches for new syncOny: %w", err)
}
return reconcile.Result{}, nil
}
-func (r *ReconcileConfig) wipeCacheIfNeeded(ctx context.Context) error {
- if r.needsWipe {
- if _, err := r.opa.RemoveData(ctx, target.WipeData()); err != nil {
- return err
- }
-
- // reset sync cache before sending the metric
- r.syncMetricsCache.ResetCache()
- r.syncMetricsCache.ReportSync(&syncc.Reporter{})
-
- r.needsWipe = false
- }
- return nil
-}
-
-// replayData replays all watched and cached data into Opa following a config set change.
-// In the future we can rework this to avoid the full opa data cache wipe.
-func (r *ReconcileConfig) replayData(ctx context.Context) error {
- if r.needsReplay == nil {
- return nil
- }
- for _, gvk := range r.needsReplay.Items() {
- u := &unstructured.UnstructuredList{}
- u.SetGroupVersionKind(schema.GroupVersionKind{
- Group: gvk.Group,
- Version: gvk.Version,
- Kind: gvk.Kind + "List",
- })
- err := r.reader.List(ctx, u)
- if err != nil {
- return fmt.Errorf("replaying data for %+v: %w", gvk, err)
- }
-
- defer r.syncMetricsCache.ReportSync(&syncc.Reporter{})
-
- for i := range u.Items {
- syncKey := r.syncMetricsCache.GetSyncKey(u.Items[i].GetNamespace(), u.Items[i].GetName())
-
- isExcludedNamespace, err := r.skipExcludedNamespace(&u.Items[i])
- if err != nil {
- log.Error(err, "error while excluding namespaces")
- }
-
- if isExcludedNamespace {
- continue
- }
-
- if _, err := r.opa.AddData(ctx, &u.Items[i]); err != nil {
- r.syncMetricsCache.AddObject(syncKey, syncc.Tags{
- Kind: u.Items[i].GetKind(),
- Status: metrics.ErrorStatus,
- })
- return fmt.Errorf("adding data for %+v: %w", gvk, err)
- }
-
- r.syncMetricsCache.AddObject(syncKey, syncc.Tags{
- Kind: u.Items[i].GetKind(),
- Status: metrics.ActiveStatus,
- })
- }
- r.needsReplay.Remove(gvk)
- }
- r.needsReplay = nil
- return nil
-}
-
-// removeStaleExpectations stops tracking data for any resources that are no longer watched.
-func (r *ReconcileConfig) removeStaleExpectations(stale *watch.Set) {
- for _, gvk := range stale.Items() {
- r.tracker.CancelData(gvk)
- }
-}
-
-func (r *ReconcileConfig) skipExcludedNamespace(obj *unstructured.Unstructured) (bool, error) {
- isNamespaceExcluded, err := r.processExcluder.IsNamespaceExcluded(process.Sync, obj)
- if err != nil {
- return false, err
- }
-
- return isNamespaceExcluded, err
-}
-
func containsString(s string, items []string) bool {
for _, item := range items {
if item == s {
diff --git a/pkg/controller/config/config_controller_suite_test.go b/pkg/controller/config/config_controller_suite_test.go
index 7cc043985cf..3932f427015 100644
--- a/pkg/controller/config/config_controller_suite_test.go
+++ b/pkg/controller/config/config_controller_suite_test.go
@@ -20,18 +20,15 @@ import (
stdlog "log"
"os"
"path/filepath"
+ "sync"
"testing"
- v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "github.com/open-policy-agent/gatekeeper/v3/apis"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
-
- "github.com/open-policy-agent/gatekeeper/apis"
)
var cfg *rest.Config
@@ -53,7 +50,7 @@ func TestMain(m *testing.M) {
stdlog.Fatal(err)
}
- if err := createGatekeeperNamespace(cfg); err != nil {
+ if err := testutils.CreateGatekeeperNamespace(cfg); err != nil {
stdlog.Printf("creating namespace: %v", err)
}
@@ -66,31 +63,12 @@ func TestMain(m *testing.M) {
// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and
// writes the request to requests after Reconcile is finished.
-func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) {
- requests := make(chan reconcile.Request)
+func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, *sync.Map) {
+ var requests sync.Map
fn := reconcile.Func(func(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
result, err := inner.Reconcile(ctx, req)
- requests <- req
+ requests.Store(req, struct{}{})
return result, err
})
- return fn, requests
-}
-
-// Bootstrap the gatekeeper-system namespace for use in tests.
-func createGatekeeperNamespace(cfg *rest.Config) error {
- c, err := client.New(cfg, client.Options{})
- if err != nil {
- return err
- }
-
- // Create gatekeeper namespace
- ns := &v1.Namespace{
- ObjectMeta: metav1.ObjectMeta{
- Name: "gatekeeper-system",
- },
- }
-
- ctx := context.Background()
- _, err = controllerutil.CreateOrUpdate(ctx, c, ns, func() error { return nil })
- return err
+ return fn, &requests
}
diff --git a/pkg/controller/config/config_controller_test.go b/pkg/controller/config/config_controller_test.go
index c2161eee819..ce6538ac2dc 100644
--- a/pkg/controller/config/config_controller_test.go
+++ b/pkg/controller/config/config_controller_test.go
@@ -17,34 +17,36 @@ package config
import (
"fmt"
- gosync "sync"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/onsi/gomega"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
- configv1alpha1 "github.com/open-policy-agent/gatekeeper/apis/config/v1alpha1"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
- testclient "github.com/open-policy-agent/gatekeeper/test/clients"
- "github.com/open-policy-agent/gatekeeper/test/testutils"
- "github.com/open-policy-agent/gatekeeper/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
+ configv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ syncc "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/sync"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/syncutil"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
+ testclient "github.com/open-policy-agent/gatekeeper/v3/test/clients"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
"github.com/prometheus/client_golang/prometheus"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"golang.org/x/net/context"
corev1 "k8s.io/api/core/v1"
+ v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/api/meta"
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/types"
- "k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
@@ -56,11 +58,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
-var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{
- Name: "config",
- Namespace: "gatekeeper-system",
-}}
-
const timeout = time.Second * 20
// setupManager sets up a controller-runtime manager with registered watch manager.
@@ -71,10 +68,7 @@ func setupManager(t *testing.T) (manager.Manager, *watch.Manager) {
metrics.Registry = prometheus.NewRegistry()
mgr, err := manager.New(cfg, manager.Options{
MetricsBindAddress: "0",
- NewCache: dynamiccache.New,
- MapperProvider: func(c *rest.Config) (meta.RESTMapper, error) {
- return apiutil.NewDynamicRESTMapper(c)
- },
+ MapperProvider: apiutil.NewDynamicRESTMapper,
})
if err != nil {
t.Fatalf("setting up controller manager: %s", err)
@@ -95,7 +89,11 @@ func setupManager(t *testing.T) (manager.Manager, *watch.Manager) {
}
func TestReconcile(t *testing.T) {
+ ctx, cancelFunc := context.WithCancel(context.Background())
+ defer cancelFunc()
+
g := gomega.NewGomegaWithT(t)
+
instance := &configv1alpha1.Config{
ObjectMeta: metav1.ObjectMeta{
Name: "config",
@@ -110,60 +108,57 @@ func TestReconcile(t *testing.T) {
},
Match: []configv1alpha1.MatchEntry{
{
- ExcludedNamespaces: []util.Wildcard{"foo"},
+ ExcludedNamespaces: []wildcard.Wildcard{"foo"},
Processes: []string{"*"},
},
{
- ExcludedNamespaces: []util.Wildcard{"bar"},
+ ExcludedNamespaces: []wildcard.Wildcard{"bar"},
Processes: []string{"audit", "webhook"},
},
},
},
}
-
- // Set up the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a
- // channel when it is finished.
mgr, wm := setupManager(t)
c := testclient.NewRetryClient(mgr.GetClient())
- // initialize OPA
- driver, err := local.New(local.Tracing(true))
- if err != nil {
- t.Fatalf("unable to set up Driver: %v", err)
- }
-
- opaClient, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
- if err != nil {
- t.Fatalf("unable to set up OPA client: %s", err)
- }
+ dataClient := &fakes.FakeCfClient{}
cs := watch.NewSwitch()
- tracker, err := readiness.SetupTracker(mgr, false, false)
+ tracker, err := readiness.SetupTracker(mgr, false, false, false)
if err != nil {
t.Fatal(err)
}
processExcluder := process.Get()
processExcluder.Add(instance.Spec.Match)
events := make(chan event.GenericEvent, 1024)
- watchSet := watch.NewSet()
- rec, _ := newReconciler(mgr, opaClient, wm, cs, tracker, processExcluder, events, watchSet, events)
+ syncMetricsCache := syncutil.NewMetricsCache()
+ reg, err := wm.NewRegistrar(
+ cachemanager.RegistrarName,
+ events)
+ require.NoError(t, err)
+ cacheManager, err := cachemanager.NewCacheManager(&cachemanager.Config{
+ CfClient: dataClient,
+ SyncMetricsCache: syncMetricsCache,
+ Tracker: tracker,
+ ProcessExcluder: processExcluder,
+ Registrar: reg,
+ Reader: c,
+ })
+ require.NoError(t, err)
+
+ // start the cache manager
+ go func() {
+ assert.NoError(t, cacheManager.Start(ctx))
+ }()
+
+ rec, err := newReconciler(mgr, cacheManager, cs, tracker)
+ require.NoError(t, err)
+ // Wrap the Controller Reconcile function so it writes each request to a map when it is finished reconciling.
recFn, requests := SetupTestReconcile(rec)
- err = add(mgr, recFn)
- if err != nil {
- t.Fatal(err)
- }
+ require.NoError(t, add(mgr, recFn))
- ctx, cancelFunc := context.WithCancel(context.Background())
testutils.StartManager(ctx, t, mgr)
- once := gosync.Once{}
- testMgrStopped := func() {
- once.Do(func() {
- cancelFunc()
- })
- }
-
- defer testMgrStopped()
// Create the Config object and expect the Reconcile to be created
err = c.Create(ctx, instance)
@@ -178,10 +173,20 @@ func TestReconcile(t *testing.T) {
t.Fatal(err)
}
}()
- g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))
+ g.Eventually(func() bool {
+ expectedReq := reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: "config",
+ Namespace: "gatekeeper-system",
+ }}
+ _, ok := requests.Load(expectedReq)
+ return ok
+ }).WithTimeout(timeout).Should(gomega.BeTrue())
+
+ g.Eventually(func() int {
+ return len(wm.GetManagedGVK())
+ }).WithTimeout(timeout).ShouldNot(gomega.Equal(0))
gvks := wm.GetManagedGVK()
- g.Eventually(len(gvks), timeout).ShouldNot(gomega.Equal(0))
wantGVKs := []schema.GroupVersionKind{
{Group: "", Version: "v1", Kind: "Namespace"},
@@ -257,7 +262,28 @@ func TestReconcile(t *testing.T) {
t.Fatal(err)
}
- testMgrStopped()
+ fooNs := &v1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "foo",
+ },
+ }
+ require.NoError(t, c.Create(ctx, fooNs))
+ fooPod.Object["spec"] = map[string]interface{}{
+ "containers": []map[string]interface{}{
+ {
+ "name": "foo-container",
+ "image": "foo-image",
+ },
+ },
+ }
+
+ // directly call cacheManager to avoid any race condition
+ // between adding the pod and the sync_controller calling AddObject
+ require.NoError(t, cacheManager.AddObject(ctx, fooPod))
+
+ // fooPod should be namespace excluded, hence not added to the cache
+ require.False(t, dataClient.Contains(map[fakes.CfDataKey]interface{}{{Gvk: fooPod.GroupVersionKind(), Key: "default"}: struct{}{}}))
+
cs.Stop()
}
@@ -287,7 +313,10 @@ func TestConfig_DeleteSyncResources(t *testing.T) {
},
},
}
- ctx := context.Background()
+
+ ctx, cancelFunc := context.WithCancel(context.Background())
+ defer cancelFunc()
+
err := c.Create(ctx, instance)
if err != nil {
t.Fatal(err)
@@ -321,7 +350,7 @@ func TestConfig_DeleteSyncResources(t *testing.T) {
}
// set up tracker
- tracker, err := readiness.SetupTracker(mgr, false, false)
+ tracker, err := readiness.SetupTracker(mgr, false, false, false)
if err != nil {
t.Fatal(err)
}
@@ -330,20 +359,12 @@ func TestConfig_DeleteSyncResources(t *testing.T) {
events := make(chan event.GenericEvent, 1024)
// set up controller and add it to the manager
- err = setupController(mgr, wm, tracker, events)
- if err != nil {
- t.Fatal(err)
- }
+ _, err = setupController(ctx, mgr, wm, tracker, events, c, false)
+ require.NoError(t, err, "failed to set up controller")
// start manager that will start tracker and controller
- ctx, cancelFunc := context.WithCancel(context.Background())
testutils.StartManager(ctx, t, mgr)
- once := gosync.Once{}
- defer func() {
- once.Do(func() {
- cancelFunc()
- })
- }()
+
gvk := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}
// get the object tracker for the synconly pod resource
@@ -380,35 +401,77 @@ func TestConfig_DeleteSyncResources(t *testing.T) {
}, timeout).Should(gomega.BeTrue())
}
-func setupController(mgr manager.Manager, wm *watch.Manager, tracker *readiness.Tracker, events <-chan event.GenericEvent) error {
- // initialize OPA
- driver, err := local.New(local.Tracing(true))
- if err != nil {
- return fmt.Errorf("unable to set up Driver: %v", err)
- }
+func setupController(ctx context.Context, mgr manager.Manager, wm *watch.Manager, tracker *readiness.Tracker, events chan event.GenericEvent, reader client.Reader, useFakeClient bool) (cachemanager.CFDataClient, error) {
+ // initialize constraint framework data client
+ var client cachemanager.CFDataClient
+ if useFakeClient {
+ client = &fakes.FakeCfClient{}
+ } else {
+ driver, err := rego.New(rego.Tracing(true))
+ if err != nil {
+ return nil, fmt.Errorf("unable to set up Driver: %w", err)
+ }
- opaClient, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
- if err != nil {
- return fmt.Errorf("unable to set up OPA backend client: %w", err)
+ client, err = constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
+ if err != nil {
+ return nil, fmt.Errorf("unable to set up constraint framework data client: %w", err)
+ }
}
// ControllerSwitch will be used to disable controllers during our teardown process,
// avoiding conflicts in finalizer cleanup.
cs := watch.NewSwitch()
-
processExcluder := process.Get()
+ syncMetricsCache := syncutil.NewMetricsCache()
+ reg, err := wm.NewRegistrar(
+ cachemanager.RegistrarName,
+ events)
+ if err != nil {
+ return nil, fmt.Errorf("cannot create registrar: %w", err)
+ }
+ cacheManager, err := cachemanager.NewCacheManager(&cachemanager.Config{
+ CfClient: client,
+ SyncMetricsCache: syncMetricsCache,
+ Tracker: tracker,
+ ProcessExcluder: processExcluder,
+ Registrar: reg,
+ Reader: reader,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("error creating cache manager: %w", err)
+ }
+ go func() {
+ _ = cacheManager.Start(ctx)
+ }()
- watchSet := watch.NewSet()
- rec, _ := newReconciler(mgr, opaClient, wm, cs, tracker, processExcluder, events, watchSet, nil)
+ rec, err := newReconciler(mgr, cacheManager, cs, tracker)
+ if err != nil {
+ return nil, fmt.Errorf("creating reconciler: %w", err)
+ }
err = add(mgr, rec)
if err != nil {
- return fmt.Errorf("adding reconciler to manager: %w", err)
+ return nil, fmt.Errorf("adding reconciler to manager: %w", err)
}
- return nil
+
+ syncAdder := syncc.Adder{
+ Events: events,
+ CacheManager: cacheManager,
+ }
+ err = syncAdder.Add(mgr)
+ if err != nil {
+ return nil, fmt.Errorf("registering sync controller: %w", err)
+ }
+ return client, nil
}
-// Verify the Opa cache is populated based on the config resource.
+// Verify the constraint framework cache is populated based on the config resource.
func TestConfig_CacheContents(t *testing.T) {
+ ctx, cancelFunc := context.WithCancel(context.Background())
+ defer cancelFunc()
+
+ // Setup the Manager and Controller.
+ mgr, wm := setupManager(t)
+ c := testclient.NewRetryClient(mgr.GetClient())
g := gomega.NewGomegaWithT(t)
nsGVK := schema.GroupVersionKind{
Group: "",
@@ -420,157 +483,96 @@ func TestConfig_CacheContents(t *testing.T) {
Version: "v1",
Kind: "ConfigMap",
}
- instance := configFor([]schema.GroupVersionKind{
- nsGVK,
- configMapGVK,
+ // Create a configMap to test for
+ cm := unstructuredFor(configMapGVK, "config-test-1")
+ cm.SetNamespace("default")
+ require.NoError(t, c.Create(ctx, cm), "creating configMap config-test-1")
+ t.Cleanup(func() {
+ assert.NoError(t, deleteResource(ctx, c, cm), "deleting configMap config-test-1")
})
+ cmKey, err := fakes.KeyFor(cm)
+ require.NoError(t, err)
- // Setup the Manager and Controller.
- mgr, wm := setupManager(t)
- c := testclient.NewRetryClient(mgr.GetClient())
+ cm2 := unstructuredFor(configMapGVK, "config-test-2")
+ cm2.SetNamespace("kube-system")
+ require.NoError(t, c.Create(ctx, cm2), "creating configMap config-test-2")
+ t.Cleanup(func() {
+ assert.NoError(t, deleteResource(ctx, c, cm2), "deleting configMap config-test-2")
+ })
+ cm2Key, err := fakes.KeyFor(cm2)
+ require.NoError(t, err)
- opaClient := &fakeOpa{}
- cs := watch.NewSwitch()
- tracker, err := readiness.SetupTracker(mgr, false, false)
- if err != nil {
- t.Fatal(err)
- }
- processExcluder := process.Get()
- processExcluder.Add(instance.Spec.Match)
+ tracker, err := readiness.SetupTracker(mgr, false, false, false)
+ require.NoError(t, err)
events := make(chan event.GenericEvent, 1024)
- watchSet := watch.NewSet()
- rec, _ := newReconciler(mgr, opaClient, wm, cs, tracker, processExcluder, events, watchSet, events)
- err = add(mgr, rec)
- if err != nil {
- t.Fatal(err)
- }
+ dataClient, err := setupController(ctx, mgr, wm, tracker, events, c, true)
+ require.NoError(t, err, "failed to set up controller")
- ctx, cancelFunc := context.WithCancel(context.Background())
- testutils.StartManager(ctx, t, mgr)
- once := gosync.Once{}
- testMgrStopped := func() {
- once.Do(func() {
- cancelFunc()
- })
- }
+ fakeClient, ok := dataClient.(*fakes.FakeCfClient)
+ require.True(t, ok)
- defer testMgrStopped()
+ testutils.StartManager(ctx, t, mgr)
// Create the Config object and expect the Reconcile to be created
- ctx = context.Background()
-
- instance = configFor([]schema.GroupVersionKind{nsGVK, configMapGVK})
+ config := configFor([]schema.GroupVersionKind{nsGVK, configMapGVK})
+ require.NoError(t, c.Create(ctx, config), "creating Config config")
- // Since we're reusing instance between tests, we must wait for it to be fully
- // deleted. We also can't reuse the same instance without introducing
- // flakiness as client.Client methods modify their input.
- g.Eventually(ensureDeleted(ctx, c, instance), timeout).
- ShouldNot(gomega.HaveOccurred())
- g.Eventually(ensureCreated(ctx, c, instance), timeout).
- ShouldNot(gomega.HaveOccurred())
-
- t.Cleanup(func() {
- err = c.Delete(ctx, instance)
- if !apierrors.IsNotFound(err) {
- t.Errorf("got Delete(instance) error %v, want IsNotFound", err)
- }
- })
-
- // Create a configMap to test for
- cm := unstructuredFor(configMapGVK, "config-test-1")
- cm.SetNamespace("default")
- err = c.Create(ctx, cm)
- if err != nil {
- t.Fatalf("creating configMap config-test-1: %v", err)
- }
-
- cm2 := unstructuredFor(configMapGVK, "config-test-2")
- cm2.SetNamespace("kube-system")
- err = c.Create(ctx, cm2)
- if err != nil {
- t.Fatalf("creating configMap config-test-2: %v", err)
- }
-
- defer func() {
- err = c.Delete(ctx, cm)
- if err != nil {
- t.Fatal(err)
- }
- err = c.Delete(ctx, cm2)
- if err != nil {
- t.Fatal(err)
- }
- }()
-
- expected := map[opaKey]interface{}{
- {gvk: nsGVK, key: "default"}: nil,
- {gvk: configMapGVK, key: "default/config-test-1"}: nil,
- // kube-system namespace is being excluded, it should not be in opa cache
+ expected := map[fakes.CfDataKey]interface{}{
+ {Gvk: nsGVK, Key: "default"}: nil,
+ cmKey: nil,
+ // kube-system namespace is being excluded, it should not be in the cache
}
g.Eventually(func() bool {
- return opaClient.Contains(expected)
- }, 10*time.Second).Should(gomega.BeTrue(), "checking initial opa cache contents")
-
- // Sanity
- if !opaClient.HasGVK(nsGVK) {
- t.Fatal("want opaClient.HasGVK(nsGVK) to be true but got false")
- }
+ return fakeClient.Contains(expected)
+ }, 10*time.Second).Should(gomega.BeTrue(), "checking initial cache contents")
+ require.True(t, fakeClient.HasGVK(nsGVK), "want fakeClient.HasGVK(nsGVK) to be true but got false")
// Reconfigure to drop the namespace watches
- instance = configFor([]schema.GroupVersionKind{configMapGVK})
- forUpdate := instance.DeepCopy()
- _, err = controllerutil.CreateOrUpdate(ctx, c, forUpdate, func() error {
- forUpdate.Spec = instance.Spec
- return nil
- })
- if err != nil {
- t.Fatalf("updating Config resource: %v", err)
- }
+ config = configFor([]schema.GroupVersionKind{configMapGVK})
+ configUpdate := config.DeepCopy()
+
+ require.NoError(t, c.Get(ctx, client.ObjectKeyFromObject(configUpdate), configUpdate))
+ configUpdate.Spec = config.Spec
+ require.NoError(t, c.Update(ctx, configUpdate), "updating Config config")
// Expect namespaces to go away from cache
g.Eventually(func() bool {
- return opaClient.HasGVK(nsGVK)
+ return fakeClient.HasGVK(nsGVK)
}, 10*time.Second).Should(gomega.BeFalse())
// Expect our configMap to return at some point
// TODO: In the future it will remain instead of having to repopulate.
- expected = map[opaKey]interface{}{
- {
- gvk: configMapGVK,
- key: "default/config-test-1",
- }: nil,
+ expected = map[fakes.CfDataKey]interface{}{
+ cmKey: nil,
}
g.Eventually(func() bool {
- return opaClient.Contains(expected)
+ return fakeClient.Contains(expected)
}, 10*time.Second).Should(gomega.BeTrue(), "waiting for ConfigMap to repopulate in cache")
- expected = map[opaKey]interface{}{
- {
- gvk: configMapGVK,
- key: "kube-system/config-test-2",
- }: nil,
+ expected = map[fakes.CfDataKey]interface{}{
+ cm2Key: nil,
}
g.Eventually(func() bool {
- return !opaClient.Contains(expected)
- }, 10*time.Second).Should(gomega.BeTrue(), "kube-system namespace is excluded. kube-system/config-test-2 should not be in opa cache")
+ return !fakeClient.Contains(expected)
+ }, 10*time.Second).Should(gomega.BeTrue(), "kube-system namespace is excluded. kube-system/config-test-2 should not be in the cache")
- // Delete the config resource - expect opa to empty out.
- if opaClient.Len() == 0 {
+ // Delete the config resource - expect cache to empty out.
+ if fakeClient.Len() == 0 {
t.Fatal("sanity")
}
- err = c.Delete(ctx, instance)
- if err != nil {
- t.Fatalf("deleting Config resource: %v", err)
- }
+ require.NoError(t, c.Delete(ctx, config), "deleting Config resource")
// The cache will be cleared out.
g.Eventually(func() int {
- return opaClient.Len()
+ return fakeClient.Len()
}, 10*time.Second).Should(gomega.BeZero(), "waiting for cache to empty")
}
func TestConfig_Retries(t *testing.T) {
+ ctx, cancelFunc := context.WithCancel(context.Background())
+ defer cancelFunc()
+
g := gomega.NewGomegaWithT(t)
nsGVK := schema.GroupVersionKind{
Group: "",
@@ -582,17 +584,15 @@ func TestConfig_Retries(t *testing.T) {
Version: "v1",
Kind: "ConfigMap",
}
- instance := configFor([]schema.GroupVersionKind{
- configMapGVK,
- })
+ instance := configFor([]schema.GroupVersionKind{nsGVK, configMapGVK})
// Setup the Manager and Controller.
mgr, wm := setupManager(t)
c := testclient.NewRetryClient(mgr.GetClient())
- opaClient := &fakeOpa{}
+ dataClient := &fakes.FakeCfClient{}
cs := watch.NewSwitch()
- tracker, err := readiness.SetupTracker(mgr, false, false)
+ tracker, err := readiness.SetupTracker(mgr, false, false, false)
if err != nil {
t.Fatal(err)
}
@@ -600,44 +600,52 @@ func TestConfig_Retries(t *testing.T) {
processExcluder.Add(instance.Spec.Match)
events := make(chan event.GenericEvent, 1024)
- watchSet := watch.NewSet()
- rec, _ := newReconciler(mgr, opaClient, wm, cs, tracker, processExcluder, events, watchSet, events)
+ syncMetricsCache := syncutil.NewMetricsCache()
+ reg, err := wm.NewRegistrar(
+ cachemanager.RegistrarName,
+ events)
+ require.NoError(t, err)
+ cacheManager, err := cachemanager.NewCacheManager(&cachemanager.Config{
+ CfClient: dataClient,
+ SyncMetricsCache: syncMetricsCache,
+ Tracker: tracker,
+ ProcessExcluder: processExcluder,
+ Registrar: reg,
+ Reader: c,
+ })
+ require.NoError(t, err)
+ go func() {
+ assert.NoError(t, cacheManager.Start(ctx))
+ }()
+
+ rec, _ := newReconciler(mgr, cacheManager, cs, tracker)
err = add(mgr, rec)
if err != nil {
t.Fatal(err)
}
+ syncAdder := syncc.Adder{
+ Events: events,
+ CacheManager: cacheManager,
+ }
+ require.NoError(t, syncAdder.Add(mgr), "registering sync controller")
- // Use our special hookReader to inject controlled failures
- failPlease := make(chan string, 1)
- rec.reader = hookReader{
+ // Use our special reader interceptor to inject controlled failures
+ fi := fakes.NewFailureInjector()
+ rec.reader = fakes.SpyReader{
Reader: mgr.GetCache(),
ListFunc: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
- // Return an error the first go-around.
- var failKind string
- select {
- case failKind = <-failPlease:
- default:
- }
- if failKind != "" && list.GetObjectKind().GroupVersionKind().Kind == failKind {
+ // return as many syntenthic failures as there are registered for this kind
+ if fi.CheckFailures(list.GetObjectKind().GroupVersionKind().Kind) {
return fmt.Errorf("synthetic failure")
}
+
return mgr.GetCache().List(ctx, list, opts...)
},
}
- ctx, cancelFunc := context.WithCancel(context.Background())
testutils.StartManager(ctx, t, mgr)
- once := gosync.Once{}
- testMgrStopped := func() {
- once.Do(func() {
- cancelFunc()
- })
- }
-
- defer testMgrStopped()
// Create the Config object and expect the Reconcile to be created
- ctx = context.Background()
g.Eventually(func() error {
return c.Create(ctx, instance.DeepCopy())
}, timeout).Should(gomega.BeNil())
@@ -664,28 +672,20 @@ func TestConfig_Retries(t *testing.T) {
t.Error(err)
}
}()
+ cmKey, err := fakes.KeyFor(cm)
+ require.NoError(t, err)
- expected := map[opaKey]interface{}{
- {gvk: configMapGVK, key: "default/config-test-1"}: nil,
+ expected := map[fakes.CfDataKey]interface{}{
+ cmKey: nil,
}
g.Eventually(func() bool {
- return opaClient.Contains(expected)
- }, 10*time.Second).Should(gomega.BeTrue(), "checking initial opa cache contents")
+ return dataClient.Contains(expected)
+ }, 10*time.Second).Should(gomega.BeTrue(), "checking initial cache contents")
- // Wipe the opa cache, we want to see it repopulate despite transient replay errors below.
- _, err = opaClient.RemoveData(ctx, target.WipeData())
- if err != nil {
- t.Fatalf("wiping opa cache: %v", err)
- }
- if opaClient.Contains(expected) {
- t.Fatal("wipe failed")
- }
+ fi.SetFailures("ConfigMapList", 2)
- // Make List fail once for ConfigMaps as the replay occurs following the reconfig below.
- failPlease <- "ConfigMapList"
-
- // Reconfigure to add a namespace watch.
- instance = configFor([]schema.GroupVersionKind{nsGVK, configMapGVK})
+ // Reconfigure to force an internal replay.
+ instance = configFor([]schema.GroupVersionKind{configMapGVK})
forUpdate := instance.DeepCopy()
_, err = controllerutil.CreateOrUpdate(ctx, c, forUpdate, func() error {
forUpdate.Spec = instance.Spec
@@ -697,8 +697,8 @@ func TestConfig_Retries(t *testing.T) {
// Despite the transient error, we expect the cache to eventually be repopulated.
g.Eventually(func() bool {
- return opaClient.Contains(expected)
- }, 10*time.Second).Should(gomega.BeTrue(), "checking final opa cache contents")
+ return dataClient.Contains(expected)
+ }, 10*time.Second).Should(gomega.BeTrue(), "checking final cache contents")
}
// configFor returns a config resource that watches the requested set of resources.
@@ -725,7 +725,7 @@ func configFor(kinds []schema.GroupVersionKind) *configv1alpha1.Config {
},
Match: []configv1alpha1.MatchEntry{
{
- ExcludedNamespaces: []util.Wildcard{"kube-system"},
+ ExcludedNamespaces: []wildcard.Wildcard{"kube-system"},
Processes: []string{"sync"},
},
},
@@ -746,65 +746,15 @@ type testExpectations interface {
IsExpecting(gvk schema.GroupVersionKind, nsName types.NamespacedName) bool
}
-// ensureDeleted
-//
-// This package uses the same API server process across multiple test functions.
-// The residual state from a previous test function can cause flakes.
-//
-// To ensure a clean slate, we must verify that any previously applied Config object
-// has been fully removed before applying our new object.
-func ensureDeleted(ctx context.Context, c client.Client, toDelete client.Object) func() error {
- gvk := toDelete.GetObjectKind().GroupVersionKind()
- key := client.ObjectKeyFromObject(toDelete)
-
- return func() error {
- u := &unstructured.Unstructured{}
- u.SetGroupVersionKind(gvk)
-
- err := c.Get(ctx, key, u)
- if apierrors.IsNotFound(err) {
- return nil
- } else if err != nil {
- return err
- }
-
- if !u.GetDeletionTimestamp().IsZero() {
- return fmt.Errorf("waiting for deletion: %v %v", gvk, key)
- }
-
- err = c.Delete(ctx, u)
- if err != nil {
- return fmt.Errorf("deleting %v %v: %w", gvk, key, err)
- }
-
- return fmt.Errorf("queued %v %v for deletion", gvk, key)
+func deleteResource(ctx context.Context, c client.Client, resounce *unstructured.Unstructured) error {
+ if ctx.Err() != nil {
+ ctx = context.Background()
}
-}
-
-// ensureCreated attempts to create toCreate in Client c as toCreate existed when ensureCreated was called.
-func ensureCreated(ctx context.Context, c client.Client, toCreate client.Object) func() error {
- gvk := toCreate.GetObjectKind().GroupVersionKind()
- key := client.ObjectKeyFromObject(toCreate)
-
- // As ensureCreated returns a closure, it is possible that the value toCreate will be modified after ensureCreated
- // is called but before the closure is called. Creating a copy here ensures the object to be created is consistent
- // with the way it existed when ensureCreated was called.
- toCreateCopy := toCreate.DeepCopyObject()
-
- return func() error {
- instance, ok := toCreateCopy.(client.Object)
- if !ok {
- return fmt.Errorf("instance was %T which is not a client.Object", instance)
- }
-
- err := c.Create(ctx, instance)
- if apierrors.IsAlreadyExists(err) {
- return fmt.Errorf("a copy of %v %v already exists - run ensureDeleted to ensure a fresh copy exists for testing",
- gvk, key)
- } else if err != nil {
- return fmt.Errorf("creating %v %v: %v", gvk, key, err)
- }
-
+ err := c.Delete(ctx, resounce)
+ if apierrors.IsNotFound(err) {
+ // resource does not exist, this is good
return nil
}
+
+ return err
}
diff --git a/pkg/controller/config/fakes_test.go b/pkg/controller/config/fakes_test.go
deleted file mode 100644
index d1bda58deb3..00000000000
--- a/pkg/controller/config/fakes_test.go
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
-
-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 (
- "context"
- "fmt"
- gosync "sync"
-
- constraintTypes "github.com/open-policy-agent/frameworks/constraint/pkg/types"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-type opaKey struct {
- gvk schema.GroupVersionKind
- key string
-}
-
-// fakeOpa is an OpaDataClient for testing.
-type fakeOpa struct {
- mu gosync.Mutex
- data map[opaKey]interface{}
-}
-
-// keyFor returns an opaKey for the provided resource.
-// Returns error if the resource is not a runtime.Object w/ metadata.
-func (f *fakeOpa) keyFor(obj interface{}) (opaKey, error) {
- o, ok := obj.(client.Object)
- if !ok {
- return opaKey{}, fmt.Errorf("expected runtime.Object, got: %T", obj)
- }
- gvk := o.GetObjectKind().GroupVersionKind()
- ns := o.GetNamespace()
- if ns == "" {
- return opaKey{gvk: gvk, key: o.GetName()}, nil
- }
-
- return opaKey{gvk: gvk, key: fmt.Sprintf("%s/%s", ns, o.GetName())}, nil
-}
-
-func (f *fakeOpa) AddData(ctx context.Context, data interface{}) (*constraintTypes.Responses, error) {
- f.mu.Lock()
- defer f.mu.Unlock()
-
- key, err := f.keyFor(data)
- if err != nil {
- return nil, err
- }
-
- if f.data == nil {
- f.data = make(map[opaKey]interface{})
- }
-
- f.data[key] = data
- return &constraintTypes.Responses{}, nil
-}
-
-func (f *fakeOpa) RemoveData(ctx context.Context, data interface{}) (*constraintTypes.Responses, error) {
- f.mu.Lock()
- defer f.mu.Unlock()
-
- if target.IsWipeData(data) {
- f.data = make(map[opaKey]interface{})
- return &constraintTypes.Responses{}, nil
- }
-
- key, err := f.keyFor(data)
- if err != nil {
- return nil, err
- }
-
- delete(f.data, key)
- return &constraintTypes.Responses{}, nil
-}
-
-// Contains returns true if all expected resources are in the cache.
-func (f *fakeOpa) Contains(expected map[opaKey]interface{}) bool {
- f.mu.Lock()
- defer f.mu.Unlock()
-
- for k := range expected {
- if _, ok := f.data[k]; !ok {
- return false
- }
- }
- return true
-}
-
-// HasGVK returns true if the cache has any data of the requested kind.
-func (f *fakeOpa) HasGVK(gvk schema.GroupVersionKind) bool {
- f.mu.Lock()
- defer f.mu.Unlock()
-
- for k := range f.data {
- if k.gvk == gvk {
- return true
- }
- }
- return false
-}
-
-// Len returns the number of items in the cache.
-func (f *fakeOpa) Len() int {
- f.mu.Lock()
- defer f.mu.Unlock()
- return len(f.data)
-}
-
-// hookReader is a client.Reader with overrideable methods.
-type hookReader struct {
- client.Reader
- ListFunc func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error
-}
-
-func (r hookReader) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
- if r.ListFunc != nil {
- return r.ListFunc(ctx, list, opts...)
- }
- return r.Reader.List(ctx, list, opts...)
-}
diff --git a/pkg/controller/config/process/excluder.go b/pkg/controller/config/process/excluder.go
index c5ee340e82d..60e3f3c0cd2 100644
--- a/pkg/controller/config/process/excluder.go
+++ b/pkg/controller/config/process/excluder.go
@@ -4,8 +4,8 @@ import (
"reflect"
"sync"
- configv1alpha1 "github.com/open-policy-agent/gatekeeper/apis/config/v1alpha1"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ configv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
"sigs.k8s.io/controller-runtime/pkg/client"
)
@@ -23,7 +23,7 @@ const (
type Excluder struct {
mux sync.RWMutex
- excludedNamespaces map[Process]map[util.Wildcard]bool
+ excludedNamespaces map[Process]map[wildcard.Wildcard]bool
}
var allProcesses = []Process{
@@ -34,7 +34,7 @@ var allProcesses = []Process{
}
var processExcluder = &Excluder{
- excludedNamespaces: make(map[Process]map[util.Wildcard]bool),
+ excludedNamespaces: make(map[Process]map[wildcard.Wildcard]bool),
}
func Get() *Excluder {
@@ -43,7 +43,7 @@ func Get() *Excluder {
func New() *Excluder {
return &Excluder{
- excludedNamespaces: make(map[Process]map[util.Wildcard]bool),
+ excludedNamespaces: make(map[Process]map[wildcard.Wildcard]bool),
}
}
@@ -58,13 +58,13 @@ func (s *Excluder) Add(entry []configv1alpha1.MatchEntry) {
if Process(op) == Star {
for _, o := range allProcesses {
if s.excludedNamespaces[o] == nil {
- s.excludedNamespaces[o] = make(map[util.Wildcard]bool)
+ s.excludedNamespaces[o] = make(map[wildcard.Wildcard]bool)
}
s.excludedNamespaces[o][ns] = true
}
} else {
if s.excludedNamespaces[Process(op)] == nil {
- s.excludedNamespaces[Process(op)] = make(map[util.Wildcard]bool)
+ s.excludedNamespaces[Process(op)] = make(map[wildcard.Wildcard]bool)
}
s.excludedNamespaces[Process(op)][ns] = true
}
@@ -96,7 +96,7 @@ func (s *Excluder) IsNamespaceExcluded(process Process, obj client.Object) (bool
return exactOrWildcardMatch(s.excludedNamespaces[process], obj.GetNamespace()), nil
}
-func exactOrWildcardMatch(boolMap map[util.Wildcard]bool, ns string) bool {
+func exactOrWildcardMatch(boolMap map[wildcard.Wildcard]bool, ns string) bool {
for k := range boolMap {
if k.Matches(ns) {
return true
diff --git a/pkg/controller/config/process/excluder_test.go b/pkg/controller/config/process/excluder_test.go
index 40015179ebe..b2fbbf68eac 100644
--- a/pkg/controller/config/process/excluder_test.go
+++ b/pkg/controller/config/process/excluder_test.go
@@ -3,19 +3,19 @@ package process
import (
"testing"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
)
func TestExactOrWildcardMatch(t *testing.T) {
tcs := []struct {
name string
- nsMap map[util.Wildcard]bool
+ nsMap map[wildcard.Wildcard]bool
ns string
excluded bool
}{
{
name: "exact text match",
- nsMap: map[util.Wildcard]bool{
+ nsMap: map[wildcard.Wildcard]bool{
"kube-system": true,
"foobar": true,
},
@@ -24,7 +24,7 @@ func TestExactOrWildcardMatch(t *testing.T) {
},
{
name: "wildcard prefix match",
- nsMap: map[util.Wildcard]bool{
+ nsMap: map[wildcard.Wildcard]bool{
"kube-*": true,
"foobar": true,
},
@@ -33,7 +33,7 @@ func TestExactOrWildcardMatch(t *testing.T) {
},
{
name: "wildcard suffix match",
- nsMap: map[util.Wildcard]bool{
+ nsMap: map[wildcard.Wildcard]bool{
"*-system": true,
"foobar": true,
},
@@ -42,7 +42,7 @@ func TestExactOrWildcardMatch(t *testing.T) {
},
{
name: "lack of asterisk prevents globbing",
- nsMap: map[util.Wildcard]bool{
+ nsMap: map[wildcard.Wildcard]bool{
"kube-": true,
},
ns: "kube-system",
diff --git a/pkg/controller/constraint/constraint_controller.go b/pkg/controller/constraint/constraint_controller.go
index 706005c04ac..95443753d4d 100644
--- a/pkg/controller/constraint/constraint_controller.go
+++ b/pkg/controller/constraint/constraint_controller.go
@@ -24,17 +24,15 @@ import (
"github.com/go-logr/logr"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/constraints"
- constraintstatusv1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/constraintstatus"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
+ constraintstatusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/constraintstatus"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
@@ -59,7 +57,7 @@ const (
)
type Adder struct {
- Opa *constraintclient.Client
+ CFClient *constraintclient.Client
ConstraintsCache *ConstraintsCache
WatchManager *watch.Manager
ControllerSwitch *watch.ControllerSwitch
@@ -74,8 +72,8 @@ type Adder struct {
IfWatching func(schema.GroupVersionKind, func() error) (bool, error)
}
-func (a *Adder) InjectOpa(o *constraintclient.Client) {
- a.Opa = o
+func (a *Adder) InjectCFClient(c *constraintclient.Client) {
+ a.CFClient = c
}
func (a *Adder) InjectWatchManager(w *watch.Manager) {
@@ -90,10 +88,6 @@ func (a *Adder) InjectTracker(t *readiness.Tracker) {
a.Tracker = t
}
-func (a *Adder) InjectMutationSystem(mutationSystem *mutation.System) {}
-
-func (a *Adder) InjectExpansionSystem(expansionSystem *expansion.System) {}
-
// Add creates a new Constraint Controller and adds it to the Manager. The Manager will set fields on the Controller
// and Start it when the Manager is Started.
func (a *Adder) Add(mgr manager.Manager) error {
@@ -106,7 +100,7 @@ func (a *Adder) Add(mgr manager.Manager) error {
return err
}
- r := newReconciler(mgr, a.Opa, a.ControllerSwitch, reporter, a.ConstraintsCache, a.Tracker)
+ r := newReconciler(mgr, a.CFClient, a.ControllerSwitch, reporter, a.ConstraintsCache, a.Tracker)
if a.GetPod != nil {
r.getPod = a.GetPod
}
@@ -129,7 +123,7 @@ type tags struct {
// newReconciler returns a new reconcile.Reconciler.
func newReconciler(
mgr manager.Manager,
- opa *constraintclient.Client,
+ cfClient *constraintclient.Client,
cs *watch.ControllerSwitch,
reporter StatsReporter,
constraintsCache *ConstraintsCache,
@@ -143,7 +137,7 @@ func newReconciler(
cs: cs,
scheme: mgr.GetScheme(),
- opa: opa,
+ cfClient: cfClient,
log: log,
reporter: reporter,
constraintsCache: constraintsCache,
@@ -177,7 +171,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler, events <-chan event.Generi
// Watch for changes to ConstraintStatus
err = c.Watch(
- &source.Kind{Type: &constraintstatusv1beta1.ConstraintPodStatus{}},
+ source.Kind(mgr.GetCache(), &constraintstatusv1beta1.ConstraintPodStatus{}),
handler.EnqueueRequestsFromMapFunc(constraintstatus.PodStatusToConstraintMapper(true, util.EventPackerMapFunc())),
)
if err != nil {
@@ -196,7 +190,7 @@ type ReconcileConstraint struct {
cs *watch.ControllerSwitch
scheme *runtime.Scheme
- opa *constraintclient.Client
+ cfClient *constraintclient.Client
log logr.Logger
reporter StatsReporter
constraintsCache *ConstraintsCache
@@ -291,7 +285,7 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R
status.Status.ConstraintUID = instance.GetUID()
status.Status.ObservedGeneration = instance.GetGeneration()
status.Status.Errors = nil
- if c, err := r.opa.GetConstraint(instance); err != nil || !constraints.SemanticEqual(instance, c) {
+ if c, err := r.cfClient.GetConstraint(instance); err != nil || !constraints.SemanticEqual(instance, c) {
if err := r.cacheConstraint(ctx, instance); err != nil {
r.constraintsCache.addConstraintKey(constraintKey, tags{
enforcementAction: enforcementAction,
@@ -320,7 +314,7 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R
reportMetrics = true
} else {
r.log.Info("handling constraint delete", "instance", instance)
- if _, err := r.opa.RemoveConstraint(ctx, instance); err != nil {
+ if _, err := r.cfClient.RemoveConstraint(ctx, instance); err != nil {
if errors.Is(err, constraintclient.ErrMissingConstraint) {
return reconcile.Result{}, err
}
@@ -414,9 +408,9 @@ func (r *ReconcileConstraint) cacheConstraint(ctx context.Context, instance *uns
t := r.tracker.For(instance.GroupVersionKind())
obj := instance.DeepCopy()
- // Remove the status field since we do not need it for OPA
+ // Remove the status field since we do not need it
unstructured.RemoveNestedField(obj.Object, "status")
- _, err := r.opa.AddConstraint(ctx, obj)
+ _, err := r.cfClient.AddConstraint(ctx, obj)
if err != nil {
t.TryCancelExpect(obj)
return err
@@ -424,7 +418,6 @@ func (r *ReconcileConstraint) cacheConstraint(ctx context.Context, instance *uns
// Track for readiness
t.Observe(instance)
- log.Info("[readiness] observed Constraint", "name", instance.GetName())
return nil
}
diff --git a/pkg/controller/constraint/constraint_controller_test.go b/pkg/controller/constraint/constraint_controller_test.go
index 6d81dc6e210..b50e3e7beef 100644
--- a/pkg/controller/constraint/constraint_controller_test.go
+++ b/pkg/controller/constraint/constraint_controller_test.go
@@ -4,8 +4,8 @@ import (
"testing"
"github.com/davecgh/go-spew/spew"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
)
func TestTotalConstraintsCache(t *testing.T) {
diff --git a/pkg/controller/constraint/stats_reporter.go b/pkg/controller/constraint/stats_reporter.go
index 37e180a3de6..b5cdd629a85 100644
--- a/pkg/controller/constraint/stats_reporter.go
+++ b/pkg/controller/constraint/stats_reporter.go
@@ -3,7 +3,7 @@ package constraint
import (
"context"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view"
"go.opencensus.io/tag"
diff --git a/pkg/controller/constraint/stats_reporter_test.go b/pkg/controller/constraint/stats_reporter_test.go
index 8583c43a902..debe186b205 100644
--- a/pkg/controller/constraint/stats_reporter_test.go
+++ b/pkg/controller/constraint/stats_reporter_test.go
@@ -4,7 +4,7 @@ import (
"context"
"testing"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
"go.opencensus.io/stats/view"
)
diff --git a/pkg/controller/constraintstatus/constraintstatus_controller.go b/pkg/controller/constraintstatus/constraintstatus_controller.go
index 5bfcb664c64..3095cccb95e 100644
--- a/pkg/controller/constraintstatus/constraintstatus_controller.go
+++ b/pkg/controller/constraintstatus/constraintstatus_controller.go
@@ -23,10 +23,10 @@ import (
"github.com/go-logr/logr"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
@@ -44,7 +44,7 @@ import (
var log = logf.Log.WithName("controller").WithValues(logging.Process, "constraint_status_controller")
type Adder struct {
- Opa *constraintclient.Client
+ CFClient *constraintclient.Client
WatchManager *watch.Manager
ControllerSwitch *watch.ControllerSwitch
Events <-chan event.GenericEvent
@@ -84,7 +84,7 @@ type PackerMap func(obj client.Object) []reconcile.Request
// PodStatusToConstraintMapper correlates a ConstraintPodStatus with its corresponding constraint
// `selfOnly` tells the mapper to only map statuses corresponding to the current pod.
func PodStatusToConstraintMapper(selfOnly bool, packerMap handler.MapFunc) handler.MapFunc {
- return func(obj client.Object) []reconcile.Request {
+ return func(ctx context.Context, obj client.Object) []reconcile.Request {
labels := obj.GetLabels()
name, ok := labels[v1beta1.ConstraintNameLabel]
if !ok {
@@ -109,7 +109,7 @@ func PodStatusToConstraintMapper(selfOnly bool, packerMap handler.MapFunc) handl
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(schema.GroupVersionKind{Group: v1beta1.ConstraintsGroup, Version: "v1beta1", Kind: kind})
u.SetName(name)
- return packerMap(u)
+ return packerMap(ctx, u)
}
}
@@ -123,7 +123,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler, events <-chan event.Generi
// Watch for changes to ConstraintStatus
err = c.Watch(
- &source.Kind{Type: &v1beta1.ConstraintPodStatus{}},
+ source.Kind(mgr.GetCache(), &v1beta1.ConstraintPodStatus{}),
handler.EnqueueRequestsFromMapFunc(PodStatusToConstraintMapper(false, util.EventPackerMapFunc())),
)
if err != nil {
diff --git a/pkg/controller/constrainttemplate/constrainttemplate_controller.go b/pkg/controller/constrainttemplate/constrainttemplate_controller.go
index 00f69467840..a8c23c559c6 100644
--- a/pkg/controller/constrainttemplate/constrainttemplate_controller.go
+++ b/pkg/controller/constrainttemplate/constrainttemplate_controller.go
@@ -24,19 +24,16 @@ import (
"github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
- "github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- statusv1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/constraint"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/constraintstatus"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/constrainttemplatestatus"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
+ statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/constraint"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/constraintstatus"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/constrainttemplatestatus"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
errorpkg "github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -69,7 +66,7 @@ var gvkConstraintTemplate = schema.GroupVersionKind{
}
type Adder struct {
- Opa *constraintclient.Client
+ CFClient *constraintclient.Client
WatchManager *watch.Manager
ControllerSwitch *watch.ControllerSwitch
Tracker *readiness.Tracker
@@ -84,15 +81,15 @@ func (a *Adder) Add(mgr manager.Manager) error {
}
// events will be used to receive events from dynamic watches registered
events := make(chan event.GenericEvent, 1024)
- r, err := newReconciler(mgr, a.Opa, a.WatchManager, a.ControllerSwitch, a.Tracker, events, events, a.GetPod)
+ r, err := newReconciler(mgr, a.CFClient, a.WatchManager, a.ControllerSwitch, a.Tracker, events, events, a.GetPod)
if err != nil {
return err
}
return add(mgr, r)
}
-func (a *Adder) InjectOpa(o *constraintclient.Client) {
- a.Opa = o
+func (a *Adder) InjectCFClient(c *constraintclient.Client) {
+ a.CFClient = c
}
func (a *Adder) InjectWatchManager(wm *watch.Manager) {
@@ -111,17 +108,11 @@ func (a *Adder) InjectGetPod(getPod func(context.Context) (*corev1.Pod, error))
a.GetPod = getPod
}
-func (a *Adder) InjectMutationSystem(_ *mutation.System) {}
-
-func (a *Adder) InjectExpansionSystem(_ *expansion.System) {}
-
-func (a *Adder) InjectProviderCache(_ *externaldata.ProviderCache) {}
-
// newReconciler returns a new reconcile.Reconciler
// cstrEvents is the channel from which constraint controller will receive the events
// regEvents is the channel registered by Registrar to put the events in
// cstrEvents and regEvents point to same event channel except for testing.
-func newReconciler(mgr manager.Manager, opa *constraintclient.Client, wm *watch.Manager, cs *watch.ControllerSwitch, tracker *readiness.Tracker, cstrEvents <-chan event.GenericEvent, regEvents chan<- event.GenericEvent, getPod func(context.Context) (*corev1.Pod, error)) (*ReconcileConstraintTemplate, error) {
+func newReconciler(mgr manager.Manager, cfClient *constraintclient.Client, wm *watch.Manager, cs *watch.ControllerSwitch, tracker *readiness.Tracker, cstrEvents <-chan event.GenericEvent, regEvents chan<- event.GenericEvent, getPod func(context.Context) (*corev1.Pod, error)) (*ReconcileConstraintTemplate, error) {
// constraintsCache contains total number of constraints and shared mutex
constraintsCache := constraint.NewConstraintsCache()
@@ -136,7 +127,7 @@ func newReconciler(mgr manager.Manager, opa *constraintclient.Client, wm *watch.
// via the registrar below.
constraintAdder := constraint.Adder{
- Opa: opa,
+ CFClient: cfClient,
ConstraintsCache: constraintsCache,
WatchManager: wm,
ControllerSwitch: cs,
@@ -155,7 +146,7 @@ func newReconciler(mgr manager.Manager, opa *constraintclient.Client, wm *watch.
// via the registrar below.
statusEvents := make(chan event.GenericEvent, 1024)
csAdder := constraintstatus.Adder{
- Opa: opa,
+ CFClient: cfClient,
WatchManager: wm,
ControllerSwitch: cs,
Events: statusEvents,
@@ -166,7 +157,7 @@ func newReconciler(mgr manager.Manager, opa *constraintclient.Client, wm *watch.
}
ctsAdder := constrainttemplatestatus.Adder{
- Opa: opa,
+ CfClient: cfClient,
WatchManager: wm,
ControllerSwitch: cs,
}
@@ -179,7 +170,7 @@ func newReconciler(mgr manager.Manager, opa *constraintclient.Client, wm *watch.
reconciler := &ReconcileConstraintTemplate{
Client: mgr.GetClient(),
scheme: mgr.GetScheme(),
- opa: opa,
+ cfClient: cfClient,
watcher: w,
statusWatcher: statusW,
cs: cs,
@@ -203,14 +194,14 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
}
// Watch for changes to ConstraintTemplate
- err = c.Watch(&source.Kind{Type: &v1beta1.ConstraintTemplate{}}, &handler.EnqueueRequestForObject{})
+ err = c.Watch(source.Kind(mgr.GetCache(), &v1beta1.ConstraintTemplate{}), &handler.EnqueueRequestForObject{})
if err != nil {
return err
}
// Watch for changes to ConstraintTemplateStatus
err = c.Watch(
- &source.Kind{Type: &statusv1beta1.ConstraintTemplatePodStatus{}},
+ source.Kind(mgr.GetCache(), &statusv1beta1.ConstraintTemplatePodStatus{}),
handler.EnqueueRequestsFromMapFunc(constrainttemplatestatus.PodStatusToConstraintTemplateMapper(true)),
)
if err != nil {
@@ -219,11 +210,13 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
// Watch for changes to Constraint CRDs
err = c.Watch(
- &source.Kind{Type: &apiextensionsv1.CustomResourceDefinition{}},
- &handler.EnqueueRequestForOwner{
- OwnerType: &v1beta1.ConstraintTemplate{},
- IsController: true,
- },
+ source.Kind(mgr.GetCache(), &apiextensionsv1.CustomResourceDefinition{}),
+ handler.EnqueueRequestForOwner(
+ mgr.GetScheme(),
+ mgr.GetRESTMapper(),
+ &v1beta1.ConstraintTemplate{},
+ handler.OnlyControllerOwner(),
+ ),
)
if err != nil {
return err
@@ -240,7 +233,7 @@ type ReconcileConstraintTemplate struct {
scheme *runtime.Scheme
watcher *watch.Registrar
statusWatcher *watch.Registrar
- opa *constraintclient.Client
+ cfClient *constraintclient.Client
cs *watch.ControllerSwitch
metrics *reporter
tracker *readiness.Tracker
@@ -297,7 +290,7 @@ func (r *ReconcileConstraintTemplate) Reconcile(ctx context.Context, request rec
ctRef := &templates.ConstraintTemplate{}
ctRef.SetNamespace(request.Namespace)
ctRef.SetName(request.Name)
- ctUnversioned, err := r.opa.GetTemplate(ctRef)
+ ctUnversioned, err := r.cfClient.GetTemplate(ctRef)
result := reconcile.Result{}
if err != nil {
logger.Info("missing constraint template in OPA cache, no deletion necessary")
@@ -336,7 +329,7 @@ func (r *ReconcileConstraintTemplate) Reconcile(ctx context.Context, request rec
return reconcile.Result{}, err
}
- unversionedProposedCRD, err := r.opa.CreateCRD(ctx, unversionedCT)
+ unversionedProposedCRD, err := r.cfClient.CreateCRD(ctx, unversionedCT)
if err != nil {
logger.Error(err, "CRD creation error")
r.tracker.TryCancelTemplate(unversionedCT) // Don't track templates that failed compilation
@@ -422,10 +415,10 @@ func (r *ReconcileConstraintTemplate) handleUpdate(
logger.Info("loading code into OPA")
beginCompile := time.Now()
- // It's important that opa.AddTemplate() is called first. That way we can
+ // It's important that cfClient.AddTemplate() is called first. That way we can
// rely on a template's existence in OPA to know whether a watch needs
// to be removed
- if _, err := r.opa.AddTemplate(ctx, unversionedCT); err != nil {
+ if _, err := r.cfClient.AddTemplate(ctx, unversionedCT); err != nil {
if err := r.metrics.reportIngestDuration(ctx, metrics.ErrorStatus, time.Since(beginCompile)); err != nil {
logger.Error(err, "failed to report constraint template ingestion duration")
}
@@ -441,7 +434,6 @@ func (r *ReconcileConstraintTemplate) handleUpdate(
// Mark for readiness tracking
t := r.tracker.For(gvkConstraintTemplate)
t.Observe(unversionedCT)
- logger.Info("[readiness] observed ConstraintTemplate", "name", unversionedCT.GetName())
var newCRD *apiextensionsv1.CustomResourceDefinition
if currentCRD == nil {
@@ -470,7 +462,7 @@ func (r *ReconcileConstraintTemplate) handleUpdate(
}
// This must go after CRD creation/update as otherwise AddWatch will always fail
logger.Info("making sure constraint is in watcher registry")
- if err := r.addWatch(makeGvk(ct.Spec.CRD.Spec.Names.Kind)); err != nil {
+ if err := r.addWatch(ctx, makeGvk(ct.Spec.CRD.Spec.Names.Kind)); err != nil {
logger.Error(err, "error adding template to watch registry")
return reconcile.Result{}, err
}
@@ -488,14 +480,14 @@ func (r *ReconcileConstraintTemplate) handleDelete(
logger := logger.WithValues("name", ct.GetName())
logger.Info("removing from watcher registry")
gvk := makeGvk(ct.Spec.CRD.Spec.Names.Kind)
- if err := r.removeWatch(gvk); err != nil {
+ if err := r.removeWatch(ctx, gvk); err != nil {
return reconcile.Result{}, err
}
r.tracker.CancelTemplate(ct)
// removing the template from the OPA cache must go last as we are relying
// on that cache to derive the Kind to remove from the watch
- if _, err := r.opa.RemoveTemplate(ctx, ct); err != nil {
+ if _, err := r.cfClient.RemoveTemplate(ctx, ct); err != nil {
return reconcile.Result{}, err
}
return reconcile.Result{}, nil
@@ -567,18 +559,18 @@ func (r *ReconcileConstraintTemplate) getOrCreatePodStatus(ctx context.Context,
return statusObj, nil
}
-func (r *ReconcileConstraintTemplate) addWatch(kind schema.GroupVersionKind) error {
- if err := r.watcher.AddWatch(kind); err != nil {
+func (r *ReconcileConstraintTemplate) addWatch(ctx context.Context, kind schema.GroupVersionKind) error {
+ if err := r.watcher.AddWatch(ctx, kind); err != nil {
return err
}
- return r.statusWatcher.AddWatch(kind)
+ return r.statusWatcher.AddWatch(ctx, kind)
}
-func (r *ReconcileConstraintTemplate) removeWatch(kind schema.GroupVersionKind) error {
- if err := r.watcher.RemoveWatch(kind); err != nil {
+func (r *ReconcileConstraintTemplate) removeWatch(ctx context.Context, kind schema.GroupVersionKind) error {
+ if err := r.watcher.RemoveWatch(ctx, kind); err != nil {
return err
}
- return r.statusWatcher.RemoveWatch(kind)
+ return r.statusWatcher.RemoveWatch(ctx, kind)
}
type action string
diff --git a/pkg/controller/constrainttemplate/constrainttemplate_controller_suite_test.go b/pkg/controller/constrainttemplate/constrainttemplate_controller_suite_test.go
index b61197fd038..d3dfad6b28e 100644
--- a/pkg/controller/constrainttemplate/constrainttemplate_controller_suite_test.go
+++ b/pkg/controller/constrainttemplate/constrainttemplate_controller_suite_test.go
@@ -16,64 +16,14 @@ limitations under the License.
package constrainttemplate
import (
- "context"
- "log"
- "os"
- "path/filepath"
"testing"
- "github.com/open-policy-agent/gatekeeper/apis"
- v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/client-go/kubernetes/scheme"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
"k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
- "sigs.k8s.io/controller-runtime/pkg/envtest"
)
var cfg *rest.Config
func TestMain(m *testing.M) {
- t := &envtest.Environment{
- CRDDirectoryPaths: []string{
- filepath.Join("..", "..", "..", "vendor", "github.com", "open-policy-agent", "frameworks", "constraint", "deploy", "crds.yaml"),
- filepath.Join("..", "..", "..", "config", "crd", "bases"),
- },
- ErrorIfCRDPathMissing: true,
- }
- if err := apis.AddToScheme(scheme.Scheme); err != nil {
- log.Fatal(err)
- }
-
- var err error
- if cfg, err = t.Start(); err != nil {
- log.Fatal(err)
- }
- log.Print("STARTED")
-
- code := m.Run()
- if err = t.Stop(); err != nil {
- log.Printf("error while trying to stop server: %v", err)
- }
- os.Exit(code)
-}
-
-// Bootstrap the gatekeeper-system namespace for use in tests.
-func createGatekeeperNamespace(cfg *rest.Config) error {
- c, err := client.New(cfg, client.Options{})
- if err != nil {
- return err
- }
-
- // Create gatekeeper namespace
- ns := &v1.Namespace{
- ObjectMeta: metav1.ObjectMeta{
- Name: "gatekeeper-system",
- },
- }
-
- ctx := context.Background()
- _, err = controllerutil.CreateOrUpdate(ctx, c, ns, func() error { return nil })
- return err
+ testutils.StartControlPlane(m, &cfg, 3)
}
diff --git a/pkg/controller/constrainttemplate/constrainttemplate_controller_test.go b/pkg/controller/constrainttemplate/constrainttemplate_controller_test.go
index a6724c98f2e..e9abc8dbd76 100644
--- a/pkg/controller/constrainttemplate/constrainttemplate_controller_test.go
+++ b/pkg/controller/constrainttemplate/constrainttemplate_controller_test.go
@@ -21,84 +21,36 @@ import (
"fmt"
"strings"
"testing"
- "time"
templatesv1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1"
"github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
- statusv1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
- testclient "github.com/open-policy-agent/gatekeeper/test/clients"
- "github.com/open-policy-agent/gatekeeper/test/testutils"
- "github.com/open-policy-agent/gatekeeper/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache"
- "github.com/prometheus/client_golang/prometheus"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
+ statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ testclient "github.com/open-policy-agent/gatekeeper/v3/test/clients"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
"golang.org/x/net/context"
admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
- "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
- "k8s.io/client-go/rest"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
"sigs.k8s.io/controller-runtime/pkg/event"
- "sigs.k8s.io/controller-runtime/pkg/manager"
- "sigs.k8s.io/controller-runtime/pkg/metrics"
)
-// constantRetry makes 3,000 attempts at a rate of 100 per second. Since this
-// is a test instance and not a "real" cluster, this is fine and there's no need
-// to increase the wait time each iteration.
-var constantRetry = wait.Backoff{
- Steps: 3000,
- Duration: 10 * time.Millisecond,
-}
-
-// setupManager sets up a controller-runtime manager with registered watch manager.
-func setupManager(t *testing.T) (manager.Manager, *watch.Manager) {
- t.Helper()
-
- metrics.Registry = prometheus.NewRegistry()
- mgr, err := manager.New(cfg, manager.Options{
- MetricsBindAddress: "0",
- NewCache: dynamiccache.New,
- MapperProvider: func(c *rest.Config) (meta.RESTMapper, error) {
- return apiutil.NewDynamicRESTMapper(c)
- },
- Logger: testutils.NewLogger(t),
- })
- if err != nil {
- t.Fatalf("setting up controller manager: %s", err)
- }
- c := mgr.GetCache()
- dc, ok := c.(watch.RemovableCache)
- if !ok {
- t.Fatalf("expected dynamic cache, got: %T", c)
- }
- wm, err := watch.New(dc)
- if err != nil {
- t.Fatalf("could not create watch manager: %s", err)
- }
- if err := mgr.Add(wm); err != nil {
- t.Fatalf("could not add watch manager to manager: %s", err)
- }
- return mgr, wm
-}
-
func makeReconcileConstraintTemplate(suffix string) *v1beta1.ConstraintTemplate {
return &v1beta1.ConstraintTemplate{
TypeMeta: metav1.TypeMeta{
@@ -151,31 +103,30 @@ func TestReconcile(t *testing.T) {
// Setup the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a
// channel when it is finished.
- mgr, wm := setupManager(t)
+ mgr, wm := testutils.SetupManager(t, cfg)
c := testclient.NewRetryClient(mgr.GetClient())
// creating the gatekeeper-system namespace is necessary because that's where
// status resources live by default
- err := createGatekeeperNamespace(mgr.GetConfig())
+ err := testutils.CreateGatekeeperNamespace(mgr.GetConfig())
if err != nil {
t.Fatal(err)
}
- // initialize OPA
- driver, err := local.New(local.Tracing(true))
+ driver, err := rego.New(rego.Tracing(true))
if err != nil {
t.Fatalf("unable to set up Driver: %v", err)
}
- opaClient, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
+ cfClient, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
if err != nil {
- t.Fatalf("unable to set up OPA client: %s", err)
+ t.Fatalf("unable to set up constraint framework client: %s", err)
}
testutils.Setenv(t, "POD_NAME", "no-pod")
cs := watch.NewSwitch()
- tracker, err := readiness.SetupTracker(mgr, false, false)
+ tracker, err := readiness.SetupTracker(mgr, false, false, false)
if err != nil {
t.Fatal(err)
}
@@ -187,7 +138,7 @@ func TestReconcile(t *testing.T) {
// events will be used to receive events from dynamic watches registered
events := make(chan event.GenericEvent, 1024)
- rec, err := newReconciler(mgr, opaClient, wm, cs, tracker, events, events, func(context.Context) (*corev1.Pod, error) { return pod, nil })
+ rec, err := newReconciler(mgr, cfClient, wm, cs, tracker, events, events, func(context.Context) (*corev1.Pod, error) { return pod, nil })
if err != nil {
t.Fatal(err)
}
@@ -205,11 +156,11 @@ func TestReconcile(t *testing.T) {
logger.Info("Running test: CRD Gets Created")
constraintTemplate := makeReconcileConstraintTemplate(suffix)
- t.Cleanup(deleteObjectAndConfirm(ctx, t, c, expectedCRD(suffix)))
- createThenCleanup(ctx, t, c, constraintTemplate)
+ t.Cleanup(testutils.DeleteObjectAndConfirm(ctx, t, c, expectedCRD(suffix)))
+ testutils.CreateThenCleanup(ctx, t, c, constraintTemplate)
clientset := kubernetes.NewForConfigOrDie(cfg)
- err = retry.OnError(constantRetry, func(err error) bool {
+ err = retry.OnError(testutils.ConstantRetry, func(err error) bool {
return true
}, func() error {
crd := &apiextensionsv1.CustomResourceDefinition{}
@@ -239,11 +190,11 @@ func TestReconcile(t *testing.T) {
constraintTemplate := makeReconcileConstraintTemplate(suffix)
cstr := newDenyAllCstr(suffix)
- t.Cleanup(deleteObjectAndConfirm(ctx, t, c, cstr))
- t.Cleanup(deleteObjectAndConfirm(ctx, t, c, expectedCRD(suffix)))
- createThenCleanup(ctx, t, c, constraintTemplate)
+ t.Cleanup(testutils.DeleteObjectAndConfirm(ctx, t, c, cstr))
+ t.Cleanup(testutils.DeleteObjectAndConfirm(ctx, t, c, expectedCRD(suffix)))
+ testutils.CreateThenCleanup(ctx, t, c, constraintTemplate)
- err = retry.OnError(constantRetry, func(error) bool {
+ err = retry.OnError(testutils.ConstantRetry, func(error) bool {
return true
}, func() error {
return c.Create(ctx, cstr)
@@ -272,7 +223,7 @@ func TestReconcile(t *testing.T) {
Name: "FooNamespace",
Object: runtime.RawExtension{Object: ns},
}
- resp, err := opaClient.Review(ctx, req)
+ resp, err := cfClient.Review(ctx, req)
if err != nil {
t.Fatal(err)
}
@@ -280,7 +231,7 @@ func TestReconcile(t *testing.T) {
gotResults := resp.Results()
if len(gotResults) != 1 {
t.Log(resp.TraceDump())
- t.Log(opaClient.Dump(ctx))
+ t.Log(cfClient.Dump(ctx))
t.Fatalf("want 1 result, got %v", gotResults)
}
})
@@ -293,12 +244,12 @@ func TestReconcile(t *testing.T) {
constraintTemplate := makeReconcileConstraintTemplate(suffix)
cstr := newDenyAllCstr(suffix)
- t.Cleanup(deleteObjectAndConfirm(ctx, t, c, cstr))
- t.Cleanup(deleteObjectAndConfirm(ctx, t, c, expectedCRD(suffix)))
- createThenCleanup(ctx, t, c, constraintTemplate)
+ t.Cleanup(testutils.DeleteObjectAndConfirm(ctx, t, c, cstr))
+ t.Cleanup(testutils.DeleteObjectAndConfirm(ctx, t, c, expectedCRD(suffix)))
+ testutils.CreateThenCleanup(ctx, t, c, constraintTemplate)
var crd *apiextensionsv1.CustomResourceDefinition
- err = retry.OnError(constantRetry, func(err error) bool {
+ err = retry.OnError(testutils.ConstantRetry, func(err error) bool {
return true
}, func() error {
crd = &apiextensionsv1.CustomResourceDefinition{}
@@ -315,7 +266,7 @@ func TestReconcile(t *testing.T) {
t.Fatal(err)
}
- err = retry.OnError(constantRetry, func(err error) bool {
+ err = retry.OnError(testutils.ConstantRetry, func(err error) bool {
return true
}, func() error {
crd := &apiextensionsv1.CustomResourceDefinition{}
@@ -339,7 +290,7 @@ func TestReconcile(t *testing.T) {
t.Fatal(err)
}
- err = retry.OnError(constantRetry, func(err error) bool {
+ err = retry.OnError(testutils.ConstantRetry, func(err error) bool {
return true
}, func() error {
sList := &statusv1beta1.ConstraintPodStatusList{}
@@ -355,7 +306,7 @@ func TestReconcile(t *testing.T) {
t.Fatal(err)
}
- err = retry.OnError(constantRetry, func(err error) bool {
+ err = retry.OnError(testutils.ConstantRetry, func(err error) bool {
return true
}, func() error {
return c.Create(ctx, newDenyAllCstr(suffix))
@@ -409,7 +360,7 @@ func TestReconcile(t *testing.T) {
// https://github.com/open-policy-agent/gatekeeper/pull/1595#discussion_r722819552
t.Cleanup(testutils.DeleteObject(t, c, instanceInvalidRego))
- err = retry.OnError(constantRetry, func(err error) bool {
+ err = retry.OnError(testutils.ConstantRetry, func(err error) bool {
return true
}, func() error {
ct := &v1beta1.ConstraintTemplate{}
@@ -466,7 +417,7 @@ func TestReconcile(t *testing.T) {
Name: "FooNamespace",
Object: runtime.RawExtension{Object: ns},
}
- resp, err := opaClient.Review(ctx, req)
+ resp, err := cfClient.Review(ctx, req)
if err != nil {
t.Fatal(err)
}
@@ -474,7 +425,7 @@ func TestReconcile(t *testing.T) {
gotResults := resp.Results()
if len(resp.Results()) != 0 {
t.Log(resp.TraceDump())
- t.Log(opaClient.Dump(ctx))
+ t.Log(cfClient.Dump(ctx))
t.Fatalf("did not get 0 results: %v", gotResults)
}
@@ -484,16 +435,16 @@ func TestReconcile(t *testing.T) {
t.Fatal(err)
}
- err = retry.OnError(constantRetry, func(err error) bool {
+ err = retry.OnError(testutils.ConstantRetry, func(err error) bool {
return true
}, func() error {
- resp, err := opaClient.Review(ctx, req)
+ resp, err := cfClient.Review(ctx, req)
if err != nil {
return err
}
if len(resp.Results()) != 0 {
- dump, _ := opaClient.Dump(ctx)
- return fmt.Errorf("Results not yet zero\nOPA DUMP:\n%s", dump)
+ dump, _ := cfClient.Dump(ctx)
+ return fmt.Errorf("Results not yet zero\nDUMP:\n%s", dump)
}
return nil
})
@@ -508,7 +459,7 @@ func TestReconcile_DeleteConstraintResources(t *testing.T) {
logger.Info("Running test: Cancel the expectations when constraint gets deleted")
// Setup the Manager
- mgr, wm := setupManager(t)
+ mgr, wm := testutils.SetupManager(t, cfg)
c := testclient.NewRetryClient(mgr.GetClient())
// start manager that will start tracker and controller
@@ -573,26 +524,25 @@ violation[{"msg": "denied!"}] {
// creating the gatekeeper-system namespace is necessary because that's where
// status resources live by default
- err = createGatekeeperNamespace(mgr.GetConfig())
+ err = testutils.CreateGatekeeperNamespace(mgr.GetConfig())
if err != nil {
t.Fatal(err)
}
// Set up tracker
- tracker, err := readiness.SetupTracker(mgr, false, false)
+ tracker, err := readiness.SetupTrackerNoReadyz(mgr, false, false, false)
if err != nil {
t.Fatal(err)
}
- // initialize OPA
- driver, err := local.New(local.Tracing(true))
+ driver, err := rego.New(rego.Tracing(true))
if err != nil {
t.Fatalf("unable to set up Driver: %v", err)
}
- opaClient, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
+ cfClient, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
if err != nil {
- t.Fatalf("unable to set up OPA client: %s", err)
+ t.Fatalf("unable to set up constraint framework client: %s", err)
}
testutils.Setenv(t, "POD_NAME", "no-pod")
@@ -605,7 +555,7 @@ violation[{"msg": "denied!"}] {
// events will be used to receive events from dynamic watches registered
events := make(chan event.GenericEvent, 1024)
- rec, err := newReconciler(mgr, opaClient, wm, cs, tracker, events, nil, func(context.Context) (*corev1.Pod, error) { return pod, nil })
+ rec, err := newReconciler(mgr, cfClient, wm, cs, tracker, events, nil, func(context.Context) (*corev1.Pod, error) { return pod, nil })
if err != nil {
t.Fatal(err)
}
@@ -622,7 +572,7 @@ violation[{"msg": "denied!"}] {
t.Fatalf("unexpected tracker, got %T", ot)
}
// ensure that expectations are set for the constraint gvk
- err = retry.OnError(constantRetry, func(err error) bool {
+ err = retry.OnError(testutils.ConstantRetry, func(err error) bool {
return true
}, func() error {
gotExpected := tr.IsExpecting(gvk, types.NamespacedName{Name: "denyallconstraint"})
@@ -648,7 +598,7 @@ violation[{"msg": "denied!"}] {
}
// Check readiness tracker is satisfied post-reconcile
- err = retry.OnError(constantRetry, func(err error) bool {
+ err = retry.OnError(testutils.ConstantRetry, func(err error) bool {
return true
}, func() error {
satisfied := tracker.For(gvk).Satisfied()
@@ -663,7 +613,7 @@ violation[{"msg": "denied!"}] {
}
func constraintEnforced(ctx context.Context, c client.Client, suffix string) error {
- return retry.OnError(constantRetry, func(err error) bool {
+ return retry.OnError(testutils.ConstantRetry, func(err error) bool {
return true
}, func() error {
cstr := newDenyAllCstr(suffix)
@@ -778,7 +728,7 @@ func applyCRD(ctx context.Context, client client.Client, gvk schema.GroupVersion
u := &unstructured.UnstructuredList{}
u.SetGroupVersionKind(gvk)
- return retry.OnError(constantRetry, func(err error) bool {
+ return retry.OnError(testutils.ConstantRetry, func(err error) bool {
return true
}, func() error {
if ctx.Err() != nil {
@@ -788,99 +738,7 @@ func applyCRD(ctx context.Context, client client.Client, gvk schema.GroupVersion
})
}
-// deleteObjectAndConfirm returns a callback which deletes obj from the passed
-// Client. Does result in mutations to obj. The callback includes a cached copy
-// of all information required to delete obj in the callback, so it is safe to
-// mutate obj afterwards. Similarly - client.Delete mutates its input, but
-// the callback does not call client.Delete on obj. Instead, it creates a
-// single-purpose Unstructured for this purpose. Thus, obj is not mutated after
-// the callback is run.
-func deleteObjectAndConfirm(ctx context.Context, t *testing.T, c client.Client, obj client.Object) func() {
- t.Helper()
-
- // Cache the identifying information from obj. We refer to this cached
- // information in the callback, and not obj itself.
- gvk := obj.GetObjectKind().GroupVersionKind()
- namespace := obj.GetNamespace()
- name := obj.GetName()
-
- if gvk.Empty() {
- // We can't send a proper delete request with an Unstructured without
- // filling in GVK. The alternative would be to require tests to construct
- // a valid Scheme or provide a factory method for the type to delete - this
- // is easier.
- t.Fatalf("gvk for %v/%v %T is empty",
- namespace, name, obj)
- }
-
- return func() {
- t.Helper()
-
- // Construct a single-use Unstructured to send the Delete request.
- toDelete := makeUnstructured(gvk, namespace, name)
- err := c.Delete(ctx, toDelete)
- if apierrors.IsNotFound(err) {
- return
- } else if err != nil {
- t.Fatal(err)
- }
-
- err = retry.OnError(constantRetry, func(err error) bool {
- return true
- }, func() error {
- // Construct a single-use Unstructured to send the Get request. It isn't
- // safe to reuse Unstructureds for each retry as Get modifies its input.
- toGet := makeUnstructured(gvk, namespace, name)
- key := client.ObjectKey{Namespace: namespace, Name: name}
- err2 := c.Get(ctx, key, toGet)
- if apierrors.IsGone(err2) || apierrors.IsNotFound(err2) {
- return nil
- }
-
- // Marshal the currently-gotten object, so it can be printed in test
- // failure output.
- s, _ := json.MarshalIndent(toGet, "", " ")
- return fmt.Errorf("found %v %v:\n%s", gvk, key, string(s))
- })
-
- if err != nil {
- t.Fatal(err)
- }
- }
-}
-
// This interface is getting used by tests to check the private objects of objectTracker.
type testExpectations interface {
IsExpecting(gvk schema.GroupVersionKind, nsName types.NamespacedName) bool
}
-
-// createThenCleanup creates obj in Client, and then registers obj to be deleted
-// at the end of the test. The passed obj is safely deepcopied before being
-// passed to client.Create, so it is not mutated by this call.
-func createThenCleanup(ctx context.Context, t *testing.T, c client.Client, obj client.Object) {
- t.Helper()
- cpy := obj.DeepCopyObject()
- cpyObj, ok := cpy.(client.Object)
- if !ok {
- t.Fatalf("got obj.DeepCopyObject() type = %T, want %T", cpy, client.Object(nil))
- }
-
- err := c.Create(ctx, cpyObj)
- if err != nil {
- t.Fatal(err)
- }
-
- // It is unnecessary to deepcopy obj as deleteObjectAndConfirm does not pass
- // obj to any Client calls.
- t.Cleanup(deleteObjectAndConfirm(ctx, t, c, obj))
-}
-
-func makeUnstructured(gvk schema.GroupVersionKind, namespace, name string) *unstructured.Unstructured {
- u := &unstructured.Unstructured{
- Object: make(map[string]interface{}),
- }
- u.SetGroupVersionKind(gvk)
- u.SetNamespace(namespace)
- u.SetName(name)
- return u
-}
diff --git a/pkg/controller/constrainttemplate/stats_reporter.go b/pkg/controller/constrainttemplate/stats_reporter.go
index 20a90d5b285..3d451694ae2 100644
--- a/pkg/controller/constrainttemplate/stats_reporter.go
+++ b/pkg/controller/constrainttemplate/stats_reporter.go
@@ -4,7 +4,7 @@ import (
"context"
"time"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view"
"go.opencensus.io/tag"
diff --git a/pkg/controller/constrainttemplate/stats_reporter_test.go b/pkg/controller/constrainttemplate/stats_reporter_test.go
index 86e43efe0d3..0f0f9615fce 100644
--- a/pkg/controller/constrainttemplate/stats_reporter_test.go
+++ b/pkg/controller/constrainttemplate/stats_reporter_test.go
@@ -5,7 +5,7 @@ import (
"testing"
"time"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
"go.opencensus.io/stats/view"
)
diff --git a/pkg/controller/constrainttemplatestatus/constrainttemplatestatus_controller.go b/pkg/controller/constrainttemplatestatus/constrainttemplatestatus_controller.go
index ab66940d6db..c1d44bf196b 100644
--- a/pkg/controller/constrainttemplatestatus/constrainttemplatestatus_controller.go
+++ b/pkg/controller/constrainttemplatestatus/constrainttemplatestatus_controller.go
@@ -24,10 +24,10 @@ import (
"github.com/go-logr/logr"
constrainttemplatev1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
@@ -44,7 +44,7 @@ import (
var log = logf.Log.WithName("controller").WithValues(logging.Process, "constraint_template_status_controller")
type Adder struct {
- Opa *constraintclient.Client
+ CfClient *constraintclient.Client
WatchManager *watch.Manager
ControllerSwitch *watch.ControllerSwitch
}
@@ -76,7 +76,7 @@ func newReconciler(
// PodStatusToConstraintTemplateMapper correlates a ConstraintTemplatePodStatus with its corresponding constraint template
// `selfOnly` tells the mapper to only map statuses corresponding to the current pod.
func PodStatusToConstraintTemplateMapper(selfOnly bool) handler.MapFunc {
- return func(obj client.Object) []reconcile.Request {
+ return func(ctx context.Context, obj client.Object) []reconcile.Request {
labels := obj.GetLabels()
name, ok := labels[v1beta1.ConstraintTemplateNameLabel]
if !ok {
@@ -107,7 +107,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
// Watch for changes to ConstraintTemplateStatus
err = c.Watch(
- &source.Kind{Type: &v1beta1.ConstraintTemplatePodStatus{}},
+ source.Kind(mgr.GetCache(), &v1beta1.ConstraintTemplatePodStatus{}),
handler.EnqueueRequestsFromMapFunc(PodStatusToConstraintTemplateMapper(false)),
)
if err != nil {
@@ -116,7 +116,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
// Watch for changes to the provided constraint
// Watch for changes to ConstraintTemplate
- err = c.Watch(&source.Kind{Type: &constrainttemplatev1beta1.ConstraintTemplate{}}, &handler.EnqueueRequestForObject{})
+ err = c.Watch(source.Kind(mgr.GetCache(), &constrainttemplatev1beta1.ConstraintTemplate{}), &handler.EnqueueRequestForObject{})
if err != nil {
return err
}
diff --git a/pkg/controller/constrainttemplatestatus/constrainttemplatestatus_controller_suite_test.go b/pkg/controller/constrainttemplatestatus/constrainttemplatestatus_controller_suite_test.go
index 64ea69a73ef..67772d2cdd1 100644
--- a/pkg/controller/constrainttemplatestatus/constrainttemplatestatus_controller_suite_test.go
+++ b/pkg/controller/constrainttemplatestatus/constrainttemplatestatus_controller_suite_test.go
@@ -16,65 +16,14 @@ limitations under the License.
package constrainttemplatestatus_test
import (
- "context"
- stdlog "log"
- "os"
- "path/filepath"
"testing"
- "github.com/open-policy-agent/gatekeeper/apis"
- v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/client-go/kubernetes/scheme"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
"k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
- "sigs.k8s.io/controller-runtime/pkg/envtest"
)
var cfg *rest.Config
func TestMain(m *testing.M) {
- var err error
-
- t := &envtest.Environment{
- CRDDirectoryPaths: []string{
- filepath.Join("..", "..", "..", "vendor", "github.com", "open-policy-agent", "frameworks", "constraint", "deploy", "crds.yaml"),
- filepath.Join("..", "..", "..", "config", "crd", "bases"),
- },
- ErrorIfCRDPathMissing: true,
- }
- if err := apis.AddToScheme(scheme.Scheme); err != nil {
- stdlog.Fatal(err)
- }
-
- if cfg, err = t.Start(); err != nil {
- stdlog.Fatal(err)
- }
- stdlog.Print("STARTED")
-
- code := m.Run()
- if err = t.Stop(); err != nil {
- stdlog.Printf("error while trying to stop server: %v", err)
- }
- os.Exit(code)
-}
-
-// Bootstrap the gatekeeper-system namespace for use in tests.
-func createGatekeeperNamespace(cfg *rest.Config) error {
- c, err := client.New(cfg, client.Options{})
- if err != nil {
- return err
- }
-
- // Create gatekeeper namespace
- ns := &v1.Namespace{
- ObjectMeta: metav1.ObjectMeta{
- Name: "gatekeeper-system",
- },
- }
-
- ctx := context.Background()
- _, err = controllerutil.CreateOrUpdate(ctx, c, ns, func() error { return nil })
- return err
+ testutils.StartControlPlane(m, &cfg, 3)
}
diff --git a/pkg/controller/constrainttemplatestatus/constrainttemplatestatus_controller_test.go b/pkg/controller/constrainttemplatestatus/constrainttemplatestatus_controller_test.go
index cd8944f09b1..58ac3be5d7b 100644
--- a/pkg/controller/constrainttemplatestatus/constrainttemplatestatus_controller_test.go
+++ b/pkg/controller/constrainttemplatestatus/constrainttemplatestatus_controller_test.go
@@ -9,23 +9,20 @@ import (
"github.com/onsi/gomega"
"github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
- podstatus "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/constrainttemplate"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
- testclient "github.com/open-policy-agent/gatekeeper/test/clients"
- "github.com/open-policy-agent/gatekeeper/test/testutils"
- "github.com/open-policy-agent/gatekeeper/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
+ podstatus "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/constrainttemplate"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ testclient "github.com/open-policy-agent/gatekeeper/v3/test/clients"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/meta"
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/types"
- "k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
"sigs.k8s.io/controller-runtime/pkg/manager"
@@ -44,11 +41,8 @@ func setupManager(t *testing.T) (manager.Manager, *watch.Manager) {
mgr, err := manager.New(cfg, manager.Options{
MetricsBindAddress: "0",
- NewCache: dynamiccache.New,
- MapperProvider: func(c *rest.Config) (meta.RESTMapper, error) {
- return apiutil.NewDynamicRESTMapper(c)
- },
- Logger: testutils.NewLogger(t),
+ MapperProvider: apiutil.NewDynamicRESTMapper,
+ Logger: testutils.NewLogger(t),
})
if err != nil {
t.Fatalf("setting up controller manager: %s", err)
@@ -108,25 +102,24 @@ violation[{"msg": "denied!"}] {
// creating the gatekeeper-system namespace is necessary because that's where
// status resources live by default
- if err := createGatekeeperNamespace(mgr.GetConfig()); err != nil {
+ if err := testutils.CreateGatekeeperNamespace(mgr.GetConfig()); err != nil {
t.Fatalf("want createGatekeeperNamespace(mgr.GetConfig()) error = nil, got %v", err)
}
- // initialize OPA
- driver, err := local.New(local.Tracing(true))
+ driver, err := rego.New(rego.Tracing(true))
if err != nil {
t.Fatalf("unable to set up Driver: %v", err)
}
- opaClient, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
+ cfClient, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
if err != nil {
- t.Fatalf("unable to set up OPA client: %s", err)
+ t.Fatalf("unable to set up constraint framework client: %s", err)
}
testutils.Setenv(t, "POD_NAME", "no-pod")
cs := watch.NewSwitch()
- tracker, err := readiness.SetupTracker(mgr, false, false)
+ tracker, err := readiness.SetupTracker(mgr, false, false, false)
if err != nil {
t.Fatal(err)
}
@@ -136,7 +129,7 @@ violation[{"msg": "denied!"}] {
)
adder := constrainttemplate.Adder{
- Opa: opaClient,
+ CFClient: cfClient,
WatchManager: wm,
ControllerSwitch: cs,
Tracker: tracker,
diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go
index 002d0625ee1..3076b5fba02 100644
--- a/pkg/controller/controller.go
+++ b/pkg/controller/controller.go
@@ -18,37 +18,38 @@ package controller
import (
"context"
"flag"
+ "fmt"
"os"
"sync"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
"github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
+ cm "github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ syncc "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/sync"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/manager"
)
var debugUseFakePod = flag.Bool("debug-use-fake-pod", false, "Use a fake pod name so the Gatekeeper executable can be run outside of Kubernetes")
type Injector interface {
- InjectOpa(*constraintclient.Client)
- InjectWatchManager(*watch.Manager)
InjectControllerSwitch(*watch.ControllerSwitch)
InjectTracker(tracker *readiness.Tracker)
- InjectMutationSystem(mutationSystem *mutation.System)
- InjectExpansionSystem(expansionSystem *expansion.System)
- InjectProviderCache(providerCache *externaldata.ProviderCache)
+
Add(mgr manager.Manager) error
}
@@ -56,12 +57,32 @@ type GetPodInjector interface {
InjectGetPod(func(context.Context) (*corev1.Pod, error))
}
-type GetProcessExcluderInjector interface {
- InjectProcessExcluder(processExcluder *process.Excluder)
+type PubsubInjector interface {
+ InjectPubsubSystem(pubsubSystem *pubsub.System)
+}
+
+type DataClientInjector interface {
+ InjectCFClient(*constraintclient.Client)
+}
+
+type WatchManagerInjector interface {
+ InjectWatchManager(*watch.Manager)
+}
+
+type MutationSystemInjector interface {
+ InjectMutationSystem(mutationSystem *mutation.System)
+}
+
+type ExpansionSystemInjector interface {
+ InjectExpansionSystem(expansionSystem *expansion.System)
+}
+
+type ProviderCacheInjector interface {
+ InjectProviderCache(providerCache *externaldata.ProviderCache)
}
-type WatchSetInjector interface {
- InjectWatchSet(watchSet *watch.Set)
+type CacheManagerInjector interface {
+ InjectCacheManager(cm *cm.CacheManager)
}
// Injectors is a list of adder structs that need injection. We can convert this
@@ -73,7 +94,7 @@ var AddToManagerFuncs []func(manager.Manager) error
// Dependencies are dependencies that can be injected into controllers.
type Dependencies struct {
- Opa *constraintclient.Client
+ CFClient *constraintclient.Client
WatchManger *watch.Manager
ControllerSwitch *watch.ControllerSwitch
Tracker *readiness.Tracker
@@ -82,7 +103,9 @@ type Dependencies struct {
MutationSystem *mutation.System
ExpansionSystem *expansion.System
ProviderCache *externaldata.ProviderCache
- WatchSet *watch.Set
+ PubsubSystem *pubsub.System
+ SyncEventsCh chan event.GenericEvent
+ CacheMgr *cm.CacheManager
}
type defaultPodGetter struct {
@@ -154,23 +177,52 @@ func AddToManager(m manager.Manager, deps *Dependencies) error {
}
deps.GetPod = fakePodGetter
}
+
+ // Adding the CacheManager as a runnable;
+ // manager will start CacheManager.
+ if err := m.Add(deps.CacheMgr); err != nil {
+ return fmt.Errorf("error adding cache manager as a runnable: %w", err)
+ }
+
+ syncAdder := syncc.Adder{
+ Events: deps.SyncEventsCh,
+ CacheManager: deps.CacheMgr,
+ }
+ // Create subordinate controller - we will feed it events dynamically via watch
+ if err := syncAdder.Add(m); err != nil {
+ return fmt.Errorf("registering sync controller: %w", err)
+ }
+
for _, a := range Injectors {
- a.InjectOpa(deps.Opa)
- a.InjectWatchManager(deps.WatchManger)
a.InjectControllerSwitch(deps.ControllerSwitch)
a.InjectTracker(deps.Tracker)
- a.InjectMutationSystem(deps.MutationSystem)
- a.InjectExpansionSystem(deps.ExpansionSystem)
- a.InjectProviderCache(deps.ProviderCache)
+
+ if a2, ok := a.(DataClientInjector); ok {
+ a2.InjectCFClient(deps.CFClient)
+ }
+ if a2, ok := a.(WatchManagerInjector); ok {
+ a2.InjectWatchManager(deps.WatchManger)
+ }
+ if a2, ok := a.(MutationSystemInjector); ok {
+ a2.InjectMutationSystem(deps.MutationSystem)
+ }
+ if a2, ok := a.(ExpansionSystemInjector); ok {
+ a2.InjectExpansionSystem(deps.ExpansionSystem)
+ }
+ if a2, ok := a.(ProviderCacheInjector); ok {
+ a2.InjectProviderCache(deps.ProviderCache)
+ }
if a2, ok := a.(GetPodInjector); ok {
a2.InjectGetPod(deps.GetPod)
}
- if a2, ok := a.(GetProcessExcluderInjector); ok {
- a2.InjectProcessExcluder(deps.ProcessExcluder)
+ if a2, ok := a.(PubsubInjector); ok {
+ a2.InjectPubsubSystem(deps.PubsubSystem)
}
- if a2, ok := a.(WatchSetInjector); ok {
- a2.InjectWatchSet(deps.WatchSet)
+ if a2, ok := a.(CacheManagerInjector); ok {
+ // this is used by the config controller to sync
+ a2.InjectCacheManager(deps.CacheMgr)
}
+
if err := a.Add(m); err != nil {
return err
}
diff --git a/pkg/controller/expansion/expansion_controller.go b/pkg/controller/expansion/expansion_controller.go
index 6a1d0cf6aa0..08b73ca2608 100644
--- a/pkg/controller/expansion/expansion_controller.go
+++ b/pkg/controller/expansion/expansion_controller.go
@@ -2,22 +2,25 @@ package expansion
import (
"context"
- "flag"
-
- constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/apis/expansion/unversioned"
- "github.com/open-policy-agent/gatekeeper/apis/expansion/v1alpha1"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
- "k8s.io/apimachinery/pkg/api/errors"
+ "fmt"
+
+ "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/unversioned"
+ expansionv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/v1beta1"
+ statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ corev1 "k8s.io/api/core/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
@@ -25,109 +28,250 @@ import (
"sigs.k8s.io/controller-runtime/pkg/source"
)
-var (
- expansionEnabled = flag.Bool("enable-generator-resource-expansion", false, "(alpha) Enable the expansion of generator resources")
+var log = logf.Log.WithName("controller").WithValues("kind", "ExpansionTemplate", logging.Process, "template_expansion_controller")
- log = logf.Log.WithName("controller").WithValues("kind", "ExpansionTemplate", logging.Process, "template_expansion_controller")
-)
+// eventQueueSize is how many events to queue before blocking.
+const eventQueueSize = 1024
type Adder struct {
WatchManager *watch.Manager
ExpansionSystem *expansion.System
+ Tracker *readiness.Tracker
+ // GetPod returns an instance of the currently running Gatekeeper pod
+ GetPod func(context.Context) (*corev1.Pod, error)
}
func (a *Adder) Add(mgr manager.Manager) error {
- if !*expansionEnabled {
+ if !*expansion.ExpansionEnabled {
return nil
}
- r := newReconciler(mgr, a.ExpansionSystem)
+ r := newReconciler(mgr, a.ExpansionSystem, a.GetPod, a.Tracker)
return add(mgr, r)
}
-func (a *Adder) InjectOpa(_ *constraintclient.Client) {}
-
-func (a *Adder) InjectWatchManager(_ *watch.Manager) {}
-
func (a *Adder) InjectControllerSwitch(_ *watch.ControllerSwitch) {}
-func (a *Adder) InjectTracker(_ *readiness.Tracker) {}
-
-func (a *Adder) InjectMutationSystem(_ *mutation.System) {}
+func (a *Adder) InjectTracker(tracker *readiness.Tracker) {
+ a.Tracker = tracker
+}
func (a *Adder) InjectExpansionSystem(expansionSystem *expansion.System) {
a.ExpansionSystem = expansionSystem
}
-func (a *Adder) InjectProviderCache(_ *externaldata.ProviderCache) {}
+func (a *Adder) InjectGetPod(getPod func(ctx context.Context) (*corev1.Pod, error)) {
+ a.GetPod = getPod
+}
type Reconciler struct {
client.Client
- system *expansion.System
- scheme *runtime.Scheme
- registry *etRegistry
+ system *expansion.System
+ scheme *runtime.Scheme
+ registry *etRegistry
+ statusClient client.StatusClient
+ tracker *readiness.Tracker
+ events chan event.GenericEvent
+ eventSource source.Source
+
+ getPod func(context.Context) (*corev1.Pod, error)
}
-func newReconciler(mgr manager.Manager, system *expansion.System) *Reconciler {
+func newReconciler(mgr manager.Manager,
+ system *expansion.System,
+ getPod func(ctx context.Context) (*corev1.Pod, error),
+ tracker *readiness.Tracker,
+) *Reconciler {
+ ev := make(chan event.GenericEvent, eventQueueSize)
return &Reconciler{
- Client: mgr.GetClient(),
- system: system,
- scheme: mgr.GetScheme(),
- registry: newRegistry(),
+ Client: mgr.GetClient(),
+ system: system,
+ scheme: mgr.GetScheme(),
+ registry: newRegistry(),
+ statusClient: mgr.GetClient(),
+ getPod: getPod,
+ tracker: tracker,
+ events: ev,
+ eventSource: &source.Channel{Source: ev, DestBufferSize: 1024},
}
}
-func add(mgr manager.Manager, r reconcile.Reconciler) error {
+func add(mgr manager.Manager, r *Reconciler) error {
c, err := controller.New("expansion-template-controller", mgr, controller.Options{Reconciler: r})
if err != nil {
return err
}
+ // Watch for enqueued events
+ if r.eventSource != nil {
+ err = c.Watch(
+ r.eventSource,
+ &handler.EnqueueRequestForObject{})
+ if err != nil {
+ return err
+ }
+ }
+
+ // Watch for changes to ExpansionTemplates
return c.Watch(
- &source.Kind{Type: &v1alpha1.ExpansionTemplate{}},
+ source.Kind(mgr.GetCache(), &expansionv1beta1.ExpansionTemplate{}),
&handler.EnqueueRequestForObject{})
}
func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
- log.Info("Reconcile", "request", request, "namespace", request.Namespace, "name", request.Name)
+ defer r.registry.report(ctx)
+ log.V(logging.DebugLevel).Info("Reconcile", "request", request, "namespace", request.Namespace, "name", request.Name)
deleted := false
- te := &v1alpha1.ExpansionTemplate{}
- err := r.Get(ctx, request.NamespacedName, te)
+ versionedET := &expansionv1beta1.ExpansionTemplate{}
+ err := r.Get(ctx, request.NamespacedName, versionedET)
if err != nil {
- if !errors.IsNotFound(err) {
+ if !apierrors.IsNotFound(err) {
return reconcile.Result{}, err
}
deleted = true
}
- unversionedTE := &unversioned.ExpansionTemplate{}
- if err := r.scheme.Convert(te, unversionedTE, nil); err != nil {
+ et := &unversioned.ExpansionTemplate{}
+ if err := r.scheme.Convert(versionedET, et, nil); err != nil {
return reconcile.Result{}, err
}
- nsName := types.NamespacedName{
- Namespace: unversionedTE.GetNamespace(),
- Name: unversionedTE.GetName(),
+ oldConflicts := r.system.GetConflicts()
+
+ if !et.GetDeletionTimestamp().IsZero() {
+ deleted = true
}
+
if deleted {
- // unversionedTE will be an empty struct. We set the metadata name, which is
+ // et will be an empty struct. We set the metadata name, which is
// used as a key to delete it from the expansion system
- unversionedTE.ObjectMeta.Name = request.Name
- if err := r.system.RemoveTemplate(unversionedTE); err != nil {
+ et.Name = request.Name
+ if err := r.system.RemoveTemplate(et); err != nil {
+ r.getTracker().TryCancelExpect(versionedET)
return reconcile.Result{}, err
}
- log.Info("removed template expansion", "template name", unversionedTE.ObjectMeta.Name)
- r.registry.remove(nsName)
+ log.V(logging.DebugLevel).Info("removed expansion template", "template name", et.GetName())
+ r.registry.remove(request.NamespacedName)
+ r.getTracker().CancelExpect(versionedET)
+ r.queueConflicts(oldConflicts)
+ return reconcile.Result{}, r.deleteStatus(ctx, request.NamespacedName.Name)
+ }
+
+ upsertErr := r.system.UpsertTemplate(et)
+ if upsertErr == nil {
+ r.getTracker().Observe(versionedET)
+ r.registry.add(request.NamespacedName, metrics.ActiveStatus)
} else {
- if err := r.system.UpsertTemplate(unversionedTE); err != nil {
- return reconcile.Result{}, err
+ r.getTracker().TryCancelExpect(versionedET)
+ r.registry.add(request.NamespacedName, metrics.ErrorStatus)
+ log.Error(upsertErr, "upserting template", "template_name", et.GetName())
+ }
+
+ r.queueConflicts(oldConflicts)
+ return reconcile.Result{}, r.updateOrCreatePodStatus(ctx, et, upsertErr)
+}
+
+func (r *Reconciler) queueConflicts(old expansion.IDSet) {
+ for tID := range symmetricDiff(old, r.system.GetConflicts()) {
+ u := &unstructured.Unstructured{}
+ u.SetGroupVersionKind(expansionv1beta1.GroupVersion.WithKind("ExpansionTemplate"))
+ // ExpansionTemplate is cluster-scoped, so we do not set namespace
+ u.SetName(string(tID))
+
+ r.events <- event.GenericEvent{Object: u}
+ }
+}
+
+func symmetricDiff(x, y expansion.IDSet) expansion.IDSet {
+ sDiff := make(expansion.IDSet)
+
+ for id := range x {
+ if _, exists := y[id]; !exists {
+ sDiff[id] = true
+ }
+ }
+ for id := range y {
+ if _, exists := x[id]; !exists {
+ sDiff[id] = true
+ }
+ }
+
+ return sDiff
+}
+
+func (r *Reconciler) deleteStatus(ctx context.Context, etName string) error {
+ status := &statusv1beta1.ExpansionTemplatePodStatus{}
+ pod, err := r.getPod(ctx)
+ if err != nil {
+ return fmt.Errorf("getting reconciler pod: %w", err)
+ }
+ sName, err := statusv1beta1.KeyForExpansionTemplate(pod.Name, etName)
+ if err != nil {
+ return fmt.Errorf("getting key for expansiontemplate: %w", err)
+ }
+ status.SetName(sName)
+ status.SetNamespace(util.GetNamespace())
+ if err := r.Delete(ctx, status); err != nil && !apierrors.IsNotFound(err) {
+ return err
+ }
+ return nil
+}
+
+func (r *Reconciler) updateOrCreatePodStatus(ctx context.Context, et *unversioned.ExpansionTemplate, etErr error) error {
+ pod, err := r.getPod(ctx)
+ if err != nil {
+ return fmt.Errorf("getting reconciler pod: %w", err)
+ }
+
+ // Check if it exists already
+ sNS := pod.Namespace
+ sName, err := statusv1beta1.KeyForExpansionTemplate(pod.Name, et.GetName())
+ if err != nil {
+ return fmt.Errorf("getting key for expansiontemplate: %w", err)
+ }
+ shouldCreate := true
+ status := &statusv1beta1.ExpansionTemplatePodStatus{}
+
+ err = r.Get(ctx, types.NamespacedName{Namespace: sNS, Name: sName}, status)
+ switch {
+ case err == nil:
+ shouldCreate = false
+ case apierrors.IsNotFound(err):
+ if status, err = r.newETStatus(pod, et); err != nil {
+ return fmt.Errorf("creating new expansiontemplate status: %w", err)
}
- log.Info("upserted template expansion", "template name", unversionedTE.ObjectMeta.Name)
- r.registry.add(nsName)
+ default:
+ return fmt.Errorf("getting expansion status in name %s, namespace %s: %w", et.GetName(), et.GetNamespace(), err)
+ }
+
+ setStatusError(status, etErr)
+ status.Status.ObservedGeneration = et.GetGeneration()
+
+ if shouldCreate {
+ return r.Create(ctx, status)
+ }
+ return r.Update(ctx, status)
+}
+
+func (r *Reconciler) newETStatus(pod *corev1.Pod, et *unversioned.ExpansionTemplate) (*statusv1beta1.ExpansionTemplatePodStatus, error) {
+ status, err := statusv1beta1.NewExpansionTemplateStatusForPod(pod, et.GetName(), r.scheme)
+ if err != nil {
+ return nil, fmt.Errorf("creating status for pod: %w", err)
}
+ status.Status.TemplateUID = et.GetUID()
+
+ return status, nil
+}
+
+func (r *Reconciler) getTracker() readiness.Expectations {
+ return r.tracker.For(expansionv1beta1.GroupVersion.WithKind("ExpansionTemplate"))
+}
- if err := r.registry.report(ctx); err != nil {
- log.Error(err, "error reporting template expansion metrics", "namespacedName", nsName)
+func setStatusError(status *statusv1beta1.ExpansionTemplatePodStatus, etErr error) {
+ if etErr == nil {
+ status.Status.Errors = nil
+ return
}
- return reconcile.Result{}, nil
+ e := &statusv1beta1.ExpansionTemplateError{Message: etErr.Error()}
+ status.Status.Errors = []*statusv1beta1.ExpansionTemplateError{e}
}
diff --git a/pkg/controller/expansion/expansion_controller_test.go b/pkg/controller/expansion/expansion_controller_test.go
new file mode 100644
index 00000000000..8b7c1311d0a
--- /dev/null
+++ b/pkg/controller/expansion/expansion_controller_test.go
@@ -0,0 +1,204 @@
+package expansion
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/v1beta1"
+ statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ testclient "github.com/open-policy-agent/gatekeeper/v3/test/clients"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
+ corev1 "k8s.io/api/core/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/util/retry"
+)
+
+var cfg *rest.Config
+
+func TestMain(m *testing.M) {
+ testutils.StartControlPlane(m, &cfg, 3)
+}
+
+func TestReconcile(t *testing.T) {
+ // Uncommenting the below enables logging of K8s internals like watch.
+ // fs := flag.NewFlagSet("", flag.PanicOnError)
+ // klog.InitFlags(fs)
+ // fs.Parse([]string{"--alsologtostderr", "-v=10"})
+ // klog.SetOutput(os.Stderr)
+
+ mgr, _ := testutils.SetupManager(t, cfg)
+ c := testclient.NewRetryClient(mgr.GetClient())
+
+ // creating the gatekeeper-system namespace is necessary because that's where
+ // status resources live by default
+ err := testutils.CreateGatekeeperNamespace(mgr.GetConfig())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ mutSystem := mutation.NewSystem(mutation.SystemOpts{})
+ expSystem := expansion.NewSystem(mutSystem)
+
+ testutils.Setenv(t, "POD_NAME", "no-pod")
+
+ tracker, err := readiness.SetupTracker(mgr, false, false, true)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ pod := fakes.Pod(
+ fakes.WithNamespace("gatekeeper-system"),
+ fakes.WithName("no-pod"),
+ )
+
+ r := newReconciler(mgr, expSystem, func(context.Context) (*corev1.Pod, error) { return pod, nil }, tracker)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = add(mgr, r)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ctx := context.Background()
+ testutils.StartManager(ctx, t, mgr)
+
+ t.Run("creating ET creates status obj, deleting ET deletes status", func(t *testing.T) {
+ t.Log("running test: creating ET creates ETPodStatus, deleting ET deletes status")
+
+ etName := "default-et"
+ et := newET(etName)
+
+ sName, err := statusv1beta1.KeyForExpansionTemplate("no-pod", etName)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t.Cleanup(testutils.DeleteObjectAndConfirm(ctx, t, c, et))
+ testutils.CreateThenCleanup(ctx, t, c, et)
+
+ err = retry.OnError(testutils.ConstantRetry, func(err error) bool {
+ return true
+ }, func() error {
+ // First, get the ET
+ et := &v1beta1.ExpansionTemplate{}
+ nsName := types.NamespacedName{Name: etName}
+ if err := c.Get(ctx, nsName, et); err != nil {
+ return err
+ }
+ if err != nil {
+ return fmt.Errorf("error fetching ET: %w", err)
+ }
+
+ // Get the ETPodStatus
+ status := &statusv1beta1.ExpansionTemplatePodStatus{}
+ nsName = types.NamespacedName{
+ Name: sName,
+ Namespace: "gatekeeper-system",
+ }
+ if err := c.Get(ctx, nsName, status); err != nil {
+ return err
+ }
+ if err != nil {
+ return fmt.Errorf("error fetching ET status: %w", err)
+ }
+ if status.Status.TemplateUID == et.GetUID() {
+ return nil
+ }
+ return fmt.Errorf("ExpansionTemplatePodStatus.Status.TemplateUID %q does not match ExpansionTemplate.GetUID() %q", status.Status.TemplateUID, et.GetUID())
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err := c.Delete(ctx, et); err != nil {
+ t.Fatalf("error deleting ET: %s", err)
+ }
+
+ err = retry.OnError(testutils.ConstantRetry, func(err error) bool {
+ return true
+ }, func() error {
+ // Get the ETPodStatus
+ status := &statusv1beta1.ExpansionTemplatePodStatus{}
+ nsName := types.NamespacedName{
+ Name: sName,
+ Namespace: "gatekeeper-system",
+ }
+ if err := c.Get(ctx, nsName, status); err != nil && apierrors.IsNotFound(err) {
+ return nil
+ }
+ return fmt.Errorf("expected IsNotFound when fetching status, but got: %w", err)
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ })
+}
+
+func TestAddStatusError(t *testing.T) {
+ tests := []struct {
+ name string
+ inputStatus statusv1beta1.ExpansionTemplatePodStatus
+ etErr error
+ wantStatus statusv1beta1.ExpansionTemplatePodStatus
+ }{
+ {
+ name: "no err",
+ inputStatus: statusv1beta1.ExpansionTemplatePodStatus{},
+ etErr: nil,
+ wantStatus: statusv1beta1.ExpansionTemplatePodStatus{Status: statusv1beta1.ExpansionTemplatePodStatusStatus{}},
+ },
+ {
+ name: "with err",
+ inputStatus: statusv1beta1.ExpansionTemplatePodStatus{},
+ etErr: errors.New("big problem"),
+ wantStatus: statusv1beta1.ExpansionTemplatePodStatus{
+ Status: statusv1beta1.ExpansionTemplatePodStatusStatus{
+ Errors: []*statusv1beta1.ExpansionTemplateError{{Message: "big problem"}},
+ },
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ setStatusError(&tc.inputStatus, tc.etErr)
+ if diff := cmp.Diff(tc.inputStatus, tc.wantStatus); diff != "" {
+ t.Errorf("got: %v\nwant: %v\ndiff: %s", tc.inputStatus, tc.wantStatus, diff)
+ }
+ })
+ }
+}
+
+func newET(name string) *v1beta1.ExpansionTemplate {
+ et := &v1beta1.ExpansionTemplate{
+ ObjectMeta: v1.ObjectMeta{Name: name},
+ Spec: v1beta1.ExpansionTemplateSpec{
+ ApplyTo: []match.ApplyTo{{
+ Groups: []string{"apps"},
+ Kinds: []string{"Deployment"},
+ Versions: []string{"v1"},
+ }},
+ TemplateSource: "spec.template",
+ GeneratedGVK: v1beta1.GeneratedGVK{
+ Kind: "Pod",
+ Version: "v1",
+ },
+ },
+ }
+ et.SetGroupVersionKind(v1alpha1.GroupVersion.WithKind("ExpansionTemplate"))
+ return et
+}
diff --git a/pkg/controller/expansion/stats_reporter.go b/pkg/controller/expansion/stats_reporter.go
index 91bf1c45076..623886c174e 100644
--- a/pkg/controller/expansion/stats_reporter.go
+++ b/pkg/controller/expansion/stats_reporter.go
@@ -3,9 +3,10 @@ package expansion
import (
"context"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view"
+ "go.opencensus.io/tag"
"k8s.io/apimachinery/pkg/types"
)
@@ -15,7 +16,8 @@ const (
)
var (
- etM = stats.Int64(etMetricName, etDesc, stats.UnitDimensionless)
+ etM = stats.Int64(etMetricName, etDesc, stats.UnitDimensionless)
+ statusKey = tag.MustNewKey("status")
views = []*view.View{
{
@@ -23,6 +25,7 @@ var (
Measure: etM,
Description: etDesc,
Aggregation: view.LastValue(),
+ TagKeys: []tag.Key{statusKey},
},
}
)
@@ -38,33 +41,50 @@ func register() error {
}
func newRegistry() *etRegistry {
- return &etRegistry{cache: make(map[types.NamespacedName]bool)}
+ return &etRegistry{cache: make(map[types.NamespacedName]metrics.Status)}
}
type etRegistry struct {
- cache map[types.NamespacedName]bool
+ cache map[types.NamespacedName]metrics.Status
dirty bool
}
-func (r *etRegistry) add(key types.NamespacedName) {
- r.cache[key] = true
+func (r *etRegistry) add(key types.NamespacedName, status metrics.Status) {
+ v, ok := r.cache[key]
+ if ok && v == status {
+ return
+ }
+ r.cache[key] = status
r.dirty = true
}
func (r *etRegistry) remove(key types.NamespacedName) {
+ if _, exists := r.cache[key]; !exists {
+ return
+ }
delete(r.cache, key)
r.dirty = true
}
-func (r *etRegistry) report(ctx context.Context) error {
+func (r *etRegistry) report(ctx context.Context) {
if !r.dirty {
- return nil
+ return
}
- if err := metrics.Record(ctx, etM.M(int64(len(r.cache)))); err != nil {
- r.dirty = false
- return err
+ totals := make(map[metrics.Status]int64)
+ for _, status := range r.cache {
+ totals[status]++
}
- return nil
+ for _, s := range metrics.AllStatuses {
+ ctx, err := tag.New(ctx, tag.Insert(statusKey, string(s)))
+ if err != nil {
+ log.Error(err, "failed to create status tag for expansion templates")
+ continue
+ }
+ err = metrics.Record(ctx, etM.M(totals[s]))
+ if err != nil {
+ log.Error(err, "failed to record total expansion templates")
+ }
+ }
}
diff --git a/pkg/controller/expansionstatus/expansionstatus_controller.go b/pkg/controller/expansionstatus/expansionstatus_controller.go
new file mode 100644
index 00000000000..1cd19b67ea0
--- /dev/null
+++ b/pkg/controller/expansionstatus/expansionstatus_controller.go
@@ -0,0 +1,201 @@
+/*
+
+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 expansionstatus
+
+import (
+ "context"
+ "fmt"
+ "sort"
+
+ "github.com/go-logr/logr"
+ constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
+ expansionv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+var log = logf.Log.WithName("controller").WithValues(logging.Process, "expansion_template_status_controller")
+
+type Adder struct {
+ CFClient *constraintclient.Client
+ WatchManager *watch.Manager
+}
+
+func (a *Adder) InjectControllerSwitch(cs *watch.ControllerSwitch) {}
+
+func (a *Adder) InjectTracker(t *readiness.Tracker) {}
+
+// Add creates a new Constraint Status Controller and adds it to the Manager. The Manager will set fields on the Controller
+// and Start it when the Manager is Started.
+func (a *Adder) Add(mgr manager.Manager) error {
+ if !*expansion.ExpansionEnabled {
+ return nil
+ }
+ r := newReconciler(mgr)
+ return add(mgr, r)
+}
+
+// newReconciler returns a new reconcile.Reconciler.
+func newReconciler(mgr manager.Manager) reconcile.Reconciler {
+ return &ReconcileExpansionStatus{
+ // Separate reader and writer because manager's default client bypasses the cache for unstructured resources.
+ writer: mgr.GetClient(),
+ statusClient: mgr.GetClient(),
+ reader: mgr.GetCache(),
+
+ scheme: mgr.GetScheme(),
+ log: log,
+ }
+}
+
+// PodStatusToExpansionTemplateMapper correlates a ExpansionTemplatePodStatus with its corresponding expansion template.
+// `selfOnly` tells the mapper to only map statuses corresponding to the current pod.
+func PodStatusToExpansionTemplateMapper(selfOnly bool) handler.MapFunc {
+ return func(ctx context.Context, obj client.Object) []reconcile.Request {
+ labels := obj.GetLabels()
+ name, ok := labels[v1beta1.ExpansionTemplateNameLabel]
+ if !ok {
+ log.Error(fmt.Errorf("expansion template status resource with no mapping label: %s", obj.GetName()), "missing label while attempting to map a expansion template status resource")
+ return nil
+ }
+ if selfOnly {
+ pod, ok := labels[v1beta1.PodLabel]
+ if !ok {
+ log.Error(fmt.Errorf("expansion template status resource with no pod label: %s", obj.GetName()), "missing label while attempting to map a expansion template status resource")
+ }
+ // Do not attempt to reconcile the resource when other pods have changed their status
+ if pod != util.GetPodName() {
+ return nil
+ }
+ }
+ return []reconcile.Request{{NamespacedName: types.NamespacedName{Name: name}}}
+ }
+}
+
+// add adds a new Controller to mgr with r as the reconcile.Reconciler.
+func add(mgr manager.Manager, r reconcile.Reconciler) error {
+ // Create a new controller
+ c, err := controller.New("expansion-template-status-controller", mgr, controller.Options{Reconciler: r})
+ if err != nil {
+ return err
+ }
+
+ // Watch for changes to ExpansionTemplateStatus
+ err = c.Watch(
+ source.Kind(mgr.GetCache(), &v1beta1.ExpansionTemplatePodStatus{}),
+ handler.EnqueueRequestsFromMapFunc(PodStatusToExpansionTemplateMapper(false)),
+ )
+ if err != nil {
+ return err
+ }
+
+ // Watch for changes to ExpansionTemplate
+ err = c.Watch(source.Kind(mgr.GetCache(), &expansionv1beta1.ExpansionTemplate{}), &handler.EnqueueRequestForObject{})
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+var _ reconcile.Reconciler = &ReconcileExpansionStatus{}
+
+// ReconcileExpansionStatus reconciles an arbitrary constraint object described by Kind.
+type ReconcileExpansionStatus struct {
+ reader client.Reader
+ writer client.Writer
+ statusClient client.StatusClient
+
+ scheme *runtime.Scheme
+ log logr.Logger
+}
+
+// +kubebuilder:rbac:groups=expansion.gatekeeper.sh,resources=*,verbs=get;list;watch;create;update;patch;delete
+// +kubebuilder:rbac:groups=status.gatekeeper.sh,resources=*,verbs=get;list;watch;create;update;patch;delete
+
+// Reconcile reads that state of the cluster for a constraint object and makes changes based on the state read
+// and what is in the constraint.Spec.
+func (r *ReconcileExpansionStatus) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
+ et := &expansionv1beta1.ExpansionTemplate{}
+ err := r.reader.Get(ctx, request.NamespacedName, et)
+ if err != nil {
+ // If the ExpansionTemplate does not exist then we are done
+ if errors.IsNotFound(err) {
+ return reconcile.Result{}, nil
+ }
+ return reconcile.Result{}, err
+ }
+
+ sObjs := &v1beta1.ExpansionTemplatePodStatusList{}
+ if err := r.reader.List(
+ ctx,
+ sObjs,
+ client.MatchingLabels{v1beta1.ExpansionTemplateNameLabel: request.Name},
+ client.InNamespace(util.GetNamespace()),
+ ); err != nil {
+ return reconcile.Result{}, err
+ }
+ statusObjs := make(sortableStatuses, len(sObjs.Items))
+ copy(statusObjs, sObjs.Items)
+ sort.Sort(statusObjs)
+
+ var s []v1beta1.ExpansionTemplatePodStatusStatus
+ // created is true if at least one Pod hasn't reported any errors
+
+ for i := range statusObjs {
+ // Don't report status if it's not for the correct object. This can happen
+ // if a watch gets interrupted, causing the constraint status to be deleted
+ // out from underneath it
+ if statusObjs[i].Status.TemplateUID != et.GetUID() {
+ continue
+ }
+ s = append(s, statusObjs[i].Status)
+ }
+
+ et.Status.ByPod = s
+
+ if err := r.statusClient.Status().Update(ctx, et); err != nil {
+ return reconcile.Result{Requeue: true}, nil
+ }
+ return reconcile.Result{}, nil
+}
+
+type sortableStatuses []v1beta1.ExpansionTemplatePodStatus
+
+func (s sortableStatuses) Len() int {
+ return len(s)
+}
+
+func (s sortableStatuses) Less(i, j int) bool {
+ return s[i].Status.ID < s[j].Status.ID
+}
+
+func (s sortableStatuses) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
diff --git a/pkg/controller/externaldata/externaldata_controller.go b/pkg/controller/externaldata/externaldata_controller.go
index 42180ed7613..941965bd72b 100644
--- a/pkg/controller/externaldata/externaldata_controller.go
+++ b/pkg/controller/externaldata/externaldata_controller.go
@@ -7,12 +7,10 @@ import (
externaldatav1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/externaldata/v1beta1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
frameworksexternaldata "github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/externaldata"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -38,23 +36,17 @@ var (
)
type Adder struct {
- Opa *constraintclient.Client
+ CFClient *constraintclient.Client
ProviderCache *frameworksexternaldata.ProviderCache
Tracker *readiness.Tracker
}
-func (a *Adder) InjectOpa(o *constraintclient.Client) {
- a.Opa = o
+func (a *Adder) InjectCFClient(c *constraintclient.Client) {
+ a.CFClient = c
}
-func (a *Adder) InjectWatchManager(w *watch.Manager) {}
-
func (a *Adder) InjectControllerSwitch(cs *watch.ControllerSwitch) {}
-func (a *Adder) InjectMutationSystem(mutationSystem *mutation.System) {}
-
-func (a *Adder) InjectExpansionSystem(expansionSystem *expansion.System) {}
-
func (a *Adder) InjectTracker(t *readiness.Tracker) {
a.Tracker = t
}
@@ -66,23 +58,23 @@ func (a *Adder) InjectProviderCache(providerCache *frameworksexternaldata.Provid
// Add creates a new ExternalData Controller and adds it to the Manager. The Manager will set fields on the Controller
// and Start it when the Manager is Started.
func (a *Adder) Add(mgr manager.Manager) error {
- r := newReconciler(mgr, a.Opa, a.ProviderCache, a.Tracker)
+ r := newReconciler(mgr, a.CFClient, a.ProviderCache, a.Tracker)
return add(mgr, r)
}
// Reconciler reconciles a ExternalData object.
type Reconciler struct {
client.Client
- opa *constraintclient.Client
+ cfClient *constraintclient.Client
providerCache *frameworksexternaldata.ProviderCache
tracker *readiness.Tracker
scheme *runtime.Scheme
}
// newReconciler returns a new reconcile.Reconciler.
-func newReconciler(mgr manager.Manager, opa *constraintclient.Client, providerCache *frameworksexternaldata.ProviderCache, tracker *readiness.Tracker) *Reconciler {
+func newReconciler(mgr manager.Manager, client *constraintclient.Client, providerCache *frameworksexternaldata.ProviderCache, tracker *readiness.Tracker) *Reconciler {
r := &Reconciler{
- opa: opa,
+ cfClient: client,
providerCache: providerCache,
Client: mgr.GetClient(),
scheme: mgr.GetScheme(),
@@ -105,7 +97,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
// Watch for changes to Provider
return c.Watch(
- &source.Kind{Type: &externaldatav1beta1.Provider{}},
+ source.Kind(mgr.GetCache(), &externaldatav1beta1.Provider{}),
&handler.EnqueueRequestForObject{})
}
diff --git a/pkg/controller/externaldata/externaldata_controller_suite_test.go b/pkg/controller/externaldata/externaldata_controller_suite_test.go
index 35169bc3357..5fc5c39ca45 100644
--- a/pkg/controller/externaldata/externaldata_controller_suite_test.go
+++ b/pkg/controller/externaldata/externaldata_controller_suite_test.go
@@ -17,44 +17,17 @@ package externaldata
import (
"context"
- stdlog "log"
- "os"
- "path/filepath"
"testing"
- "github.com/open-policy-agent/gatekeeper/apis"
- "k8s.io/client-go/kubernetes/scheme"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
"k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/envtest"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
var cfg *rest.Config
func TestMain(m *testing.M) {
- var err error
-
- t := &envtest.Environment{
- CRDDirectoryPaths: []string{
- filepath.Join("..", "..", "..", "vendor", "github.com", "open-policy-agent", "frameworks", "constraint", "deploy", "crds.yaml"),
- filepath.Join("..", "..", "..", "config", "crd", "bases"),
- },
- ErrorIfCRDPathMissing: true,
- }
- if err := apis.AddToScheme(scheme.Scheme); err != nil {
- stdlog.Fatal(err)
- }
-
- if cfg, err = t.Start(); err != nil {
- stdlog.Fatal(err)
- }
- stdlog.Print("STARTED")
-
- code := m.Run()
- if err = t.Stop(); err != nil {
- stdlog.Printf("error while trying to stop server: %v", err)
- }
- os.Exit(code)
+ testutils.StartControlPlane(m, &cfg, 3)
}
// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and
diff --git a/pkg/controller/externaldata/externaldata_controller_test.go b/pkg/controller/externaldata/externaldata_controller_test.go
index 1347a2b099c..88e2a036b8b 100644
--- a/pkg/controller/externaldata/externaldata_controller_test.go
+++ b/pkg/controller/externaldata/externaldata_controller_test.go
@@ -11,20 +11,18 @@ import (
externaldataUnversioned "github.com/open-policy-agent/frameworks/constraint/pkg/apis/externaldata/unversioned"
externaldatav1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/externaldata/v1beta1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
frameworksexternaldata "github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
- testclient "github.com/open-policy-agent/gatekeeper/test/clients"
- "github.com/open-policy-agent/gatekeeper/test/testutils"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/externaldata"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ testclient "github.com/open-policy-agent/gatekeeper/v3/test/clients"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
"github.com/prometheus/client_golang/prometheus"
- "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
- "k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
@@ -47,9 +45,7 @@ func setupManager(t *testing.T) manager.Manager {
metrics.Registry = prometheus.NewRegistry()
mgr, err := manager.New(cfg, manager.Options{
MetricsBindAddress: "0",
- MapperProvider: func(c *rest.Config) (meta.RESTMapper, error) {
- return apiutil.NewDynamicRESTMapper(c)
- },
+ MapperProvider: apiutil.NewDynamicRESTMapper,
})
if err != nil {
t.Fatalf("setting up controller manager: %s", err)
@@ -83,25 +79,24 @@ func TestReconcile(t *testing.T) {
*externaldata.ExternalDataEnabled = true
pc := frameworksexternaldata.NewCache()
- // initialize OPA
- args := []local.Arg{local.Tracing(false), local.AddExternalDataProviderCache(pc)}
- driver, err := local.New(args...)
+ args := []rego.Arg{rego.Tracing(false), rego.AddExternalDataProviderCache(pc)}
+ driver, err := rego.New(args...)
if err != nil {
t.Fatalf("unable to set up Driver: %v", err)
}
- opa, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
+ cfClient, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
if err != nil {
- t.Fatalf("unable to set up OPA client: %s", err)
+ t.Fatalf("unable to set up constraint framework client: %s", err)
}
cs := watch.NewSwitch()
- tracker, err := readiness.SetupTracker(mgr, false, true)
+ tracker, err := readiness.SetupTracker(mgr, false, true, false)
if err != nil {
t.Fatal(err)
}
- rec := newReconciler(mgr, opa, pc, tracker)
+ rec := newReconciler(mgr, cfClient, pc, tracker)
recFn, requests := SetupTestReconcile(rec)
err = add(mgr, recFn)
diff --git a/pkg/controller/mutators/cache.go b/pkg/controller/mutators/cache.go
index f6274bb2cce..d853ccc3d25 100644
--- a/pkg/controller/mutators/cache.go
+++ b/pkg/controller/mutators/cache.go
@@ -3,7 +3,7 @@ package mutators
import (
"sync"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
type mutatorStatus struct {
diff --git a/pkg/controller/mutators/cache_test.go b/pkg/controller/mutators/cache_test.go
index de7c6a3ff07..ce48276a975 100644
--- a/pkg/controller/mutators/cache_test.go
+++ b/pkg/controller/mutators/cache_test.go
@@ -5,7 +5,7 @@ import (
"sync"
"testing"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
func TestCache_TallyStatus(t *testing.T) {
diff --git a/pkg/controller/mutators/core/adder.go b/pkg/controller/mutators/core/adder.go
index fe55c99a2dc..6dbb2dd3e3f 100644
--- a/pkg/controller/mutators/core/adder.go
+++ b/pkg/controller/mutators/core/adder.go
@@ -5,11 +5,11 @@ import (
"fmt"
"strings"
- statusv1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/mutatorstatus"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
+ statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/mutatorstatus"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
corev1 "k8s.io/api/core/v1"
apitypes "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -67,7 +67,7 @@ func (a *Adder) add(mgr manager.Manager, r *Reconciler) error {
// Watch for changes to Mutators.
err = c.Watch(
- &source.Kind{Type: r.newMutationObj()},
+ source.Kind(mgr.GetCache(), r.newMutationObj()),
&handler.EnqueueRequestForObject{})
if err != nil {
return err
@@ -75,8 +75,8 @@ func (a *Adder) add(mgr manager.Manager, r *Reconciler) error {
// Watch for changes to MutatorPodStatuses.
err = c.Watch(
- &source.Kind{Type: &statusv1beta1.MutatorPodStatus{}},
- handler.EnqueueRequestsFromMapFunc(mutatorstatus.PodStatusToMutatorMapper(true, r.gvk.Kind, func(obj client.Object) []reconcile.Request {
+ source.Kind(mgr.GetCache(), &statusv1beta1.MutatorPodStatus{}),
+ handler.EnqueueRequestsFromMapFunc(mutatorstatus.PodStatusToMutatorMapper(true, r.gvk.Kind, func(ctx context.Context, obj client.Object) []reconcile.Request {
return []reconcile.Request{{
NamespacedName: apitypes.NamespacedName{
Namespace: obj.GetNamespace(),
@@ -93,7 +93,7 @@ func (a *Adder) add(mgr manager.Manager, r *Reconciler) error {
// Watch for enqueued events.
err = c.Watch(
a.EventsSource,
- handler.EnqueueRequestsFromMapFunc(func(obj client.Object) []reconcile.Request {
+ handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
if obj.GetObjectKind().GroupVersionKind().Kind != r.gvk.Kind {
return nil
}
diff --git a/pkg/controller/mutators/core/controller_suite_test.go b/pkg/controller/mutators/core/controller_suite_test.go
index 510170ad405..0600f80994e 100644
--- a/pkg/controller/mutators/core/controller_suite_test.go
+++ b/pkg/controller/mutators/core/controller_suite_test.go
@@ -16,19 +16,14 @@ limitations under the License.
package core
import (
- "context"
"log"
"os"
"path/filepath"
"testing"
- "github.com/open-policy-agent/gatekeeper/apis"
- v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "github.com/open-policy-agent/gatekeeper/v3/apis"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/envtest"
)
@@ -57,22 +52,3 @@ func TestMain(m *testing.M) {
}
os.Exit(code)
}
-
-// Bootstrap the gatekeeper-system namespace for use in tests.
-func createGatekeeperNamespace(cfg *rest.Config) error {
- c, err := client.New(cfg, client.Options{})
- if err != nil {
- return err
- }
-
- // Create gatekeeper namespace
- ns := &v1.Namespace{
- ObjectMeta: metav1.ObjectMeta{
- Name: "gatekeeper-system",
- },
- }
-
- ctx := context.Background()
- _, err = controllerutil.CreateOrUpdate(ctx, c, ns, func() error { return nil })
- return err
-}
diff --git a/pkg/controller/mutators/core/controller_test.go b/pkg/controller/mutators/core/controller_test.go
index 6e9985715f8..de7755a8c28 100644
--- a/pkg/controller/mutators/core/controller_test.go
+++ b/pkg/controller/mutators/core/controller_test.go
@@ -23,28 +23,26 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/onsi/gomega"
- mutationsinternal "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- mutationsv1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1"
- podstatus "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/mutatorstatus"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators"
- mutationschema "github.com/open-policy-agent/gatekeeper/pkg/mutation/schema"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/test/testutils"
+ mutationsinternal "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ mutationsv1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1"
+ podstatus "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/mutatorstatus"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators"
+ mutationschema "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/schema"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/net/context"
corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
apiTypes "k8s.io/apimachinery/pkg/types"
- "k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
"sigs.k8s.io/controller-runtime/pkg/event"
@@ -66,10 +64,8 @@ func setupManager(t *testing.T) manager.Manager {
metrics.Registry = prometheus.NewRegistry()
mgr, err := manager.New(cfg, manager.Options{
MetricsBindAddress: "0",
- MapperProvider: func(c *rest.Config) (meta.RESTMapper, error) {
- return apiutil.NewDynamicRESTMapper(c)
- },
- Logger: testutils.NewLogger(t),
+ MapperProvider: apiutil.NewDynamicRESTMapper,
+ Logger: testutils.NewLogger(t),
})
if err != nil {
t.Fatalf("setting up controller manager: %s", err)
@@ -117,13 +113,13 @@ func TestReconcile(t *testing.T) {
// creating the gatekeeper-system namespace is necessary because that's where
// status resources live by default
- if err := createGatekeeperNamespace(mgr.GetConfig()); err != nil {
+ if err := testutils.CreateGatekeeperNamespace(mgr.GetConfig()); err != nil {
t.Fatalf("want createGatekeeperNamespace(mgr.GetConfig()) error = nil, got %v", err)
}
mSys := mutation.NewSystem(mutation.SystemOpts{})
- tracker, err := readiness.SetupTracker(mgr, true, false)
+ tracker, err := readiness.SetupTracker(mgr, true, false, false)
if err != nil {
t.Fatal(err)
}
diff --git a/pkg/controller/mutators/core/reconciler.go b/pkg/controller/mutators/core/reconciler.go
index d3490c71817..cfc2d6aae21 100644
--- a/pkg/controller/mutators/core/reconciler.go
+++ b/pkg/controller/mutators/core/reconciler.go
@@ -23,14 +23,14 @@ import (
"time"
"github.com/go-logr/logr"
- mutationsv1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1"
- statusv1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- ctrlmutators "github.com/open-policy-agent/gatekeeper/pkg/controller/mutators"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- mutationschema "github.com/open-policy-agent/gatekeeper/pkg/mutation/schema"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
+ mutationsv1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1"
+ statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ ctrlmutators "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/mutators"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ mutationschema "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/schema"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
diff --git a/pkg/controller/mutators/core/reconciler_test.go b/pkg/controller/mutators/core/reconciler_test.go
index 1cdc07cd59a..7430f1aabaf 100644
--- a/pkg/controller/mutators/core/reconciler_test.go
+++ b/pkg/controller/mutators/core/reconciler_test.go
@@ -11,14 +11,14 @@ import (
"github.com/go-logr/logr"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
- mutationsv1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1"
- statusv1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/mutators"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- mutationschema "github.com/open-policy-agent/gatekeeper/pkg/mutation/schema"
- mutationtypes "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ mutationsv1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1"
+ statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/mutators"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ mutationschema "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/schema"
+ mutationtypes "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -92,7 +92,7 @@ func newFakeClient() *fakeClient {
var _ client.Client = &fakeClient{}
-func (c *fakeClient) Get(_ context.Context, key client.ObjectKey, obj client.Object) error {
+func (c *fakeClient) Get(_ context.Context, key client.ObjectKey, obj client.Object, _ ...client.GetOption) error {
got, found := c.objects[key]
if !found {
return apierrors.NewNotFound(schema.GroupResource{}, key.Name)
@@ -254,7 +254,7 @@ func (m *fakeMutator) HasDiff(right mutationtypes.Mutator) bool {
m.path.String() != other.path.String()
}
-func (m *fakeMutator) UsesExternalData() bool {
+func (m *fakeMutator) MustTerminate() bool {
return false
}
@@ -263,7 +263,8 @@ type errSome struct{ id int }
func newErrSome(id int) error { return &errSome{id: id} }
func (e *errSome) Is(target error) bool {
- if t, ok := target.(*errSome); ok {
+ var t *errSome
+ if errors.As(target, &t) {
return t.id == e.id
}
@@ -401,7 +402,7 @@ func TestReconciler_Reconcile(t *testing.T) {
},
Status: statusv1beta1.MutatorPodStatusStatus{
ID: "no-pod",
- Operations: []string{"audit", "mutation-status", "mutation-webhook", "status", "webhook"},
+ Operations: []string{"audit", "mutation-controller", "mutation-status", "mutation-webhook", "status", "webhook"},
Enforced: true,
Errors: nil,
},
@@ -433,7 +434,7 @@ func TestReconciler_Reconcile(t *testing.T) {
},
Status: statusv1beta1.MutatorPodStatusStatus{
ID: "no-pod",
- Operations: []string{"audit", "mutation-status", "mutation-webhook", "status", "webhook"},
+ Operations: []string{"audit", "mutation-controller", "mutation-status", "mutation-webhook", "status", "webhook"},
Enforced: true,
Errors: nil,
},
@@ -493,7 +494,7 @@ func TestReconciler_Reconcile(t *testing.T) {
},
Status: statusv1beta1.MutatorPodStatusStatus{
ID: "no-pod",
- Operations: []string{"audit", "mutation-status", "mutation-webhook", "status", "webhook"},
+ Operations: []string{"audit", "mutation-controller", "mutation-status", "mutation-webhook", "status", "webhook"},
Enforced: false,
Errors: []statusv1beta1.MutatorError{{Message: newErrSome(1).Error()}},
},
@@ -534,7 +535,7 @@ func TestReconciler_Reconcile(t *testing.T) {
},
Status: statusv1beta1.MutatorPodStatusStatus{
ID: "no-pod",
- Operations: []string{"audit", "mutation-status", "mutation-webhook", "status", "webhook"},
+ Operations: []string{"audit", "mutation-controller", "mutation-status", "mutation-webhook", "status", "webhook"},
Enforced: false,
Errors: []statusv1beta1.MutatorError{
{
@@ -633,7 +634,7 @@ func TestReconciler_Reconcile(t *testing.T) {
},
Status: statusv1beta1.MutatorPodStatusStatus{
ID: "no-pod",
- Operations: []string{"audit", "mutation-status", "mutation-webhook", "status", "webhook"},
+ Operations: []string{"audit", "mutation-controller", "mutation-status", "mutation-webhook", "status", "webhook"},
Enforced: false,
Errors: []statusv1beta1.MutatorError{
{
@@ -684,7 +685,7 @@ func TestReconciler_Reconcile(t *testing.T) {
},
Status: statusv1beta1.MutatorPodStatusStatus{
ID: "no-pod",
- Operations: []string{"audit", "mutation-status", "mutation-webhook", "status", "webhook"},
+ Operations: []string{"audit", "mutation-controller", "mutation-status", "mutation-webhook", "status", "webhook"},
Enforced: true,
Errors: nil,
},
@@ -939,7 +940,7 @@ func TestReconciler_Reconcile_DeletePodStatus(t *testing.T) {
},
Status: statusv1beta1.MutatorPodStatusStatus{
ID: "no-pod",
- Operations: []string{"audit", "mutation-status", "mutation-webhook", "status", "webhook"},
+ Operations: []string{"audit", "mutation-controller", "mutation-status", "mutation-webhook", "status", "webhook"},
Enforced: true,
},
}
diff --git a/pkg/controller/mutators/core/status.go b/pkg/controller/mutators/core/status.go
index 72cd841b219..2472bb91032 100644
--- a/pkg/controller/mutators/core/status.go
+++ b/pkg/controller/mutators/core/status.go
@@ -1,8 +1,10 @@
package core
import (
- statusv1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/schema"
+ "errors"
+
+ statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/schema"
apiTypes "k8s.io/apimachinery/pkg/types"
)
@@ -23,15 +25,16 @@ func setGeneration(generation int64) statusUpdate {
func setErrors(err error) statusUpdate {
return func(status *statusv1beta1.MutatorPodStatus) {
// Replaces any existing errors, if there was one.
- switch err.(type) {
- case nil:
+ if err == nil {
status.Status.Errors = nil
- case schema.ErrConflictingSchema:
+ return
+ }
+ if errors.As(err, &schema.ErrConflictingSchema{}) {
status.Status.Errors = []statusv1beta1.MutatorError{{
Type: schema.ErrConflictingSchemaType,
Message: err.Error(),
}}
- default:
+ } else {
status.Status.Errors = []statusv1beta1.MutatorError{{Message: err.Error()}}
}
}
diff --git a/pkg/controller/mutators/instances/mutator_controllers.go b/pkg/controller/mutators/instances/mutator_controllers.go
index b5074ea380c..f790cd83d93 100644
--- a/pkg/controller/mutators/instances/mutator_controllers.go
+++ b/pkg/controller/mutators/instances/mutator_controllers.go
@@ -3,17 +3,15 @@ package instances
import (
"context"
- constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- mutationsv1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/mutators/core"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ mutationsv1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/mutators/core"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
@@ -82,11 +80,34 @@ func (a *Adder) Add(mgr manager.Manager) error {
Events: events,
EventsSource: eventsSource,
}
-
if err := modifySet.Add(mgr); err != nil {
return err
}
+ assignImage := core.Adder{
+ Tracker: a.Tracker,
+ GetPod: a.GetPod,
+ MutationSystem: a.MutationSystem,
+ Kind: "AssignImage",
+ NewMutationObj: func() client.Object { return &v1alpha1.AssignImage{} },
+ MutatorFor: func(obj client.Object) (types.Mutator, error) {
+ // The type is provided by the `NewObj` function above. If we
+ // are fed the wrong type, this is a non-recoverable error and we
+ // may as well crash for visibility
+ assignImage := obj.(*v1alpha1.AssignImage) // nolint:forcetypeassert
+ unversioned := &mutationsunversioned.AssignImage{}
+ if err := scheme.Convert(assignImage, unversioned, nil); err != nil {
+ return nil, err
+ }
+ return mutators.MutatorForAssignImage(unversioned)
+ },
+ Events: events,
+ EventsSource: eventsSource,
+ }
+ if err := assignImage.Add(mgr); err != nil {
+ return err
+ }
+
assignMetadata := core.Adder{
Tracker: a.Tracker,
GetPod: a.GetPod,
@@ -108,10 +129,6 @@ func (a *Adder) Add(mgr manager.Manager) error {
return assignMetadata.Add(mgr)
}
-func (a *Adder) InjectOpa(o *constraintclient.Client) {}
-
-func (a *Adder) InjectWatchManager(w *watch.Manager) {}
-
func (a *Adder) InjectControllerSwitch(cs *watch.ControllerSwitch) {}
func (a *Adder) InjectTracker(t *readiness.Tracker) {
@@ -125,7 +142,3 @@ func (a *Adder) InjectGetPod(getPod func(ctx context.Context) (*corev1.Pod, erro
func (a *Adder) InjectMutationSystem(mutationSystem *mutation.System) {
a.MutationSystem = mutationSystem
}
-
-func (a *Adder) InjectExpansionSystem(expansionSystem *expansion.System) {}
-
-func (a *Adder) InjectProviderCache(providerCache *externaldata.ProviderCache) {}
diff --git a/pkg/controller/mutators/stats_reporter.go b/pkg/controller/mutators/stats_reporter.go
index c279a8cbf3b..63603a0d037 100644
--- a/pkg/controller/mutators/stats_reporter.go
+++ b/pkg/controller/mutators/stats_reporter.go
@@ -4,7 +4,7 @@ import (
"context"
"time"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view"
"go.opencensus.io/tag"
diff --git a/pkg/controller/mutators/stats_reporter_test.go b/pkg/controller/mutators/stats_reporter_test.go
index 39111cbd6d5..5d08d6c06e8 100644
--- a/pkg/controller/mutators/stats_reporter_test.go
+++ b/pkg/controller/mutators/stats_reporter_test.go
@@ -181,7 +181,7 @@ func getRow(rows []*view.Row, tagValue string) (*view.Row, error) {
func checkData(name string, rowLength int) ([]*view.Row, error) {
rows, err := view.RetrieveData(name)
if err != nil {
- return nil, fmt.Errorf("got RetrieveData error %v from %v, want nil", err, name)
+ return nil, fmt.Errorf("got RetrieveData error %w from %v, want nil", err, name)
}
if len(rows) != rowLength {
return nil, fmt.Errorf("got %q row length %v, want %v", name, len(rows), rowLength)
diff --git a/pkg/controller/mutatorstatus/mutatorstatus_controller.go b/pkg/controller/mutatorstatus/mutatorstatus_controller.go
index bb1b422fc16..824cc097b2d 100644
--- a/pkg/controller/mutatorstatus/mutatorstatus_controller.go
+++ b/pkg/controller/mutatorstatus/mutatorstatus_controller.go
@@ -22,17 +22,14 @@ import (
"sort"
"github.com/go-logr/logr"
- constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- mutationsv1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1"
- "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
+ mutationsv1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1"
+ mutationsv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
@@ -53,20 +50,10 @@ type Adder struct {
ControllerSwitch *watch.ControllerSwitch
}
-func (a *Adder) InjectOpa(o *constraintclient.Client) {}
-
-func (a *Adder) InjectWatchManager(w *watch.Manager) {}
-
func (a *Adder) InjectControllerSwitch(cs *watch.ControllerSwitch) {}
func (a *Adder) InjectTracker(t *readiness.Tracker) {}
-func (a *Adder) InjectMutationSystem(mutationSystem *mutation.System) {}
-
-func (a *Adder) InjectExpansionSystem(expansionSystem *expansion.System) {}
-
-func (a *Adder) InjectProviderCache(providerCache *externaldata.ProviderCache) {}
-
// Add creates a new Mutator Status Controller and adds it to the Manager. The Manager will set fields on the Controller
// and Start it when the Manager is Started.
func (a *Adder) Add(mgr manager.Manager) error {
@@ -98,7 +85,7 @@ type PackerMap func(obj client.Object) []reconcile.Request
// PodStatusToMutatorMapper correlates a MutatorPodStatus with its corresponding mutator.
func PodStatusToMutatorMapper(selfOnly bool, kindMatch string, packerMap handler.MapFunc) handler.MapFunc {
- return func(obj client.Object) []reconcile.Request {
+ return func(ctx context.Context, obj client.Object) []reconcile.Request {
labels := obj.GetLabels()
name, ok := labels[v1beta1.MutatorNameLabel]
if !ok {
@@ -124,9 +111,14 @@ func PodStatusToMutatorMapper(selfOnly bool, kindMatch string, packerMap handler
}
}
u := &unstructured.Unstructured{}
- u.SetGroupVersionKind(schema.GroupVersionKind{Group: v1beta1.MutationsGroup, Version: "v1", Kind: kind})
+ // AssignImage is the only mutator in v1alpha1 still
+ v := "v1"
+ if kind == "AssignImage" {
+ v = "v1alpha1"
+ }
+ u.SetGroupVersionKind(schema.GroupVersionKind{Group: v1beta1.MutationsGroup, Version: v, Kind: kind})
u.SetName(name)
- return packerMap(u)
+ return packerMap(ctx, u)
}
}
@@ -140,7 +132,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
// Watch for changes to MutatorStatus
err = c.Watch(
- &source.Kind{Type: &v1beta1.MutatorPodStatus{}},
+ source.Kind(mgr.GetCache(), &v1beta1.MutatorPodStatus{}),
handler.EnqueueRequestsFromMapFunc(PodStatusToMutatorMapper(false, "", util.EventPackerMapFunc())),
)
if err != nil {
@@ -149,21 +141,28 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
// Watch for changes to mutators
err = c.Watch(
- &source.Kind{Type: &mutationsv1.Assign{}},
+ source.Kind(mgr.GetCache(), &mutationsv1.Assign{}),
handler.EnqueueRequestsFromMapFunc(util.EventPackerMapFuncHardcodeGVK(schema.GroupVersionKind{Group: v1beta1.MutationsGroup, Version: "v1", Kind: "Assign"})),
)
if err != nil {
return err
}
err = c.Watch(
- &source.Kind{Type: &mutationsv1.AssignMetadata{}},
+ source.Kind(mgr.GetCache(), &mutationsv1.AssignMetadata{}),
handler.EnqueueRequestsFromMapFunc(util.EventPackerMapFuncHardcodeGVK(schema.GroupVersionKind{Group: v1beta1.MutationsGroup, Version: "v1", Kind: "AssignMetadata"})),
)
if err != nil {
return err
}
+ err = c.Watch(
+ source.Kind(mgr.GetCache(), &mutationsv1alpha1.AssignImage{}),
+ handler.EnqueueRequestsFromMapFunc(util.EventPackerMapFuncHardcodeGVK(schema.GroupVersionKind{Group: v1beta1.MutationsGroup, Version: "v1alpha1", Kind: "AssignImage"})),
+ )
+ if err != nil {
+ return err
+ }
return c.Watch(
- &source.Kind{Type: &mutationsv1.ModifySet{}},
+ source.Kind(mgr.GetCache(), &mutationsv1.ModifySet{}),
handler.EnqueueRequestsFromMapFunc(util.EventPackerMapFuncHardcodeGVK(schema.GroupVersionKind{Group: v1beta1.MutationsGroup, Version: "v1", Kind: "ModifySet"})),
)
}
diff --git a/pkg/controller/pubsub/pubsub_config_controller.go b/pkg/controller/pubsub/pubsub_config_controller.go
new file mode 100644
index 00000000000..e70ac499587
--- /dev/null
+++ b/pkg/controller/pubsub/pubsub_config_controller.go
@@ -0,0 +1,134 @@
+package pubsub
+
+import (
+ "context"
+ "encoding/json"
+ "flag"
+ "fmt"
+
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+var (
+ PubsubEnabled = flag.Bool("enable-pub-sub", false, "Enabled pubsub to publish messages")
+ log = logf.Log.WithName("controller").WithValues(logging.Process, "pubsub_controller")
+)
+
+type Adder struct {
+ PubsubSystem *pubsub.System
+}
+
+func (a *Adder) Add(mgr manager.Manager) error {
+ if !*PubsubEnabled {
+ return nil
+ }
+ r := newReconciler(mgr, a.PubsubSystem)
+ return add(mgr, r)
+}
+
+func (a *Adder) InjectControllerSwitch(_ *watch.ControllerSwitch) {}
+
+func (a *Adder) InjectTracker(_ *readiness.Tracker) {}
+
+func (a *Adder) InjectPubsubSystem(pubsubSystem *pubsub.System) {
+ a.PubsubSystem = pubsubSystem
+}
+
+type Reconciler struct {
+ client.Client
+ scheme *runtime.Scheme
+ system *pubsub.System
+}
+
+func newReconciler(mgr manager.Manager, system *pubsub.System) *Reconciler {
+ return &Reconciler{
+ Client: mgr.GetClient(),
+ scheme: mgr.GetScheme(),
+ system: system,
+ }
+}
+
+func add(mgr manager.Manager, r reconcile.Reconciler) error {
+ c, err := controller.New("pubsub-config-controller", mgr, controller.Options{Reconciler: r})
+ if err != nil {
+ return err
+ }
+
+ return c.Watch(
+ source.Kind(mgr.GetCache(), &corev1.ConfigMap{}),
+ &handler.EnqueueRequestForObject{},
+ predicate.Funcs{
+ CreateFunc: func(e event.CreateEvent) bool {
+ return e.Object.GetNamespace() == util.GetNamespace()
+ },
+ UpdateFunc: func(e event.UpdateEvent) bool {
+ return e.ObjectNew.GetNamespace() == util.GetNamespace()
+ },
+ DeleteFunc: func(e event.DeleteEvent) bool {
+ return e.Object.GetNamespace() == util.GetNamespace()
+ },
+ GenericFunc: func(e event.GenericEvent) bool {
+ return e.Object.GetNamespace() == util.GetNamespace()
+ },
+ },
+ )
+}
+
+func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
+ log.Info("Reconcile", "request", request, "namespace", request.Namespace, "name", request.Name)
+
+ deleted := false
+ cfg := &corev1.ConfigMap{}
+ err := r.Get(ctx, request.NamespacedName, cfg)
+ if err != nil {
+ if !errors.IsNotFound(err) {
+ return reconcile.Result{}, err
+ }
+ deleted = true
+ }
+
+ if deleted {
+ err := r.system.CloseConnection(request.Name)
+ if err != nil {
+ return reconcile.Result{Requeue: true}, err
+ }
+ log.Info("removed connection", "name", request.Name)
+ return reconcile.Result{}, nil
+ }
+
+ if len(cfg.Data) == 0 {
+ return reconcile.Result{}, fmt.Errorf(fmt.Sprintf("data missing in configmap %s, unable to configure respective pubsub", request.NamespacedName))
+ }
+ if _, ok := cfg.Data["provider"]; !ok {
+ return reconcile.Result{}, fmt.Errorf(fmt.Sprintf("missing provider field in configmap %s, unable to configure respective pubsub", request.NamespacedName))
+ }
+ var config interface{}
+ err = json.Unmarshal([]byte(cfg.Data["config"]), &config)
+ if err != nil {
+ return reconcile.Result{}, err
+ }
+
+ err = r.system.UpsertConnection(ctx, config, request.Name, cfg.Data["provider"])
+ if err != nil {
+ return reconcile.Result{}, err
+ }
+
+ log.Info("Connection upsert successful", "name", request.Name, "provider", cfg.Data["provider"])
+ return reconcile.Result{}, nil
+}
diff --git a/pkg/controller/pubsub/pubsub_config_controller_test.go b/pkg/controller/pubsub/pubsub_config_controller_test.go
new file mode 100644
index 00000000000..258b092c309
--- /dev/null
+++ b/pkg/controller/pubsub/pubsub_config_controller_test.go
@@ -0,0 +1,68 @@
+package pubsub
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "testing"
+
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/dapr"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/stretchr/testify/assert"
+ corev1 "k8s.io/api/core/v1"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
+ "sigs.k8s.io/controller-runtime/pkg/client/fake"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+func TestReconcile(t *testing.T) {
+ // Create a fake client with some data
+ scheme := runtime.NewScheme()
+ err := corev1.AddToScheme(scheme)
+ if err != nil {
+ t.Fatalf("Unexpected error parsing flag: %v", err)
+ }
+
+ err = flag.CommandLine.Parse([]string{"--enable-pub-sub", "true"})
+ if err != nil {
+ t.Fatalf("Unexpected error parsing flag: %v", err)
+ }
+
+ request := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: util.GetNamespace(), Name: dapr.Name}}
+
+ ctx := context.Background()
+ testCases := []struct {
+ name string
+ config *corev1.ConfigMap
+ wantErr bool
+ errorMsg string
+ }{
+ {
+ name: "invalid configmap",
+ config: &corev1.ConfigMap{
+ ObjectMeta: v1.ObjectMeta{
+ Name: dapr.Name,
+ Namespace: util.GetNamespace(),
+ },
+ },
+ wantErr: true,
+ errorMsg: fmt.Sprintf("data missing in configmap %s, unable to configure respective pubsub", request.NamespacedName),
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(tc.config).Build()
+ r := &Reconciler{
+ Client: client,
+ scheme: scheme,
+ }
+
+ _, err := r.Reconcile(ctx, request)
+ if tc.wantErr {
+ assert.Equal(t, err.Error(), tc.errorMsg)
+ }
+ })
+ }
+}
diff --git a/pkg/controller/sync/opadataclient.go b/pkg/controller/sync/opadataclient.go
deleted file mode 100644
index 76120e4ad5e..00000000000
--- a/pkg/controller/sync/opadataclient.go
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-
-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 sync
-
-import (
- "context"
-
- "github.com/open-policy-agent/frameworks/constraint/pkg/types"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-// OpaDataClient is an interface for caching data.
-type OpaDataClient interface {
- AddData(ctx context.Context, data interface{}) (*types.Responses, error)
- RemoveData(ctx context.Context, data interface{}) (*types.Responses, error)
-}
-
-// FilteredDataClient is an OpaDataClient which drops any unwatched resources.
-type FilteredDataClient struct {
- watched *watch.Set
- opa OpaDataClient
-}
-
-func NewFilteredOpaDataClient(opa OpaDataClient, watchSet *watch.Set) *FilteredDataClient {
- return &FilteredDataClient{
- watched: watchSet,
- opa: opa,
- }
-}
-
-// AddData adds data to the opa cache if that data is currently being watched.
-// Unwatched data is silently dropped with no error.
-func (f *FilteredDataClient) AddData(ctx context.Context, data interface{}) (*types.Responses, error) {
- if obj, ok := data.(client.Object); ok {
- gvk := obj.GetObjectKind().GroupVersionKind()
- if !f.watched.Contains(gvk) {
- return &types.Responses{}, nil
- }
- }
-
- return f.opa.AddData(ctx, data)
-}
-
-// RemoveData removes data from the opa cache if that data is currently being watched.
-// Unwatched data is silently dropped with no error.
-func (f *FilteredDataClient) RemoveData(ctx context.Context, data interface{}) (*types.Responses, error) {
- if obj, ok := data.(client.Object); ok {
- gvk := obj.GetObjectKind().GroupVersionKind()
- if !f.watched.Contains(gvk) {
- return &types.Responses{}, nil
- }
- }
-
- return f.opa.RemoveData(ctx, data)
-}
diff --git a/pkg/controller/sync/stats_reporter.go b/pkg/controller/sync/stats_reporter.go
deleted file mode 100644
index 9d8f3262c3f..00000000000
--- a/pkg/controller/sync/stats_reporter.go
+++ /dev/null
@@ -1,94 +0,0 @@
-package sync
-
-import (
- "context"
- "time"
-
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
- "go.opencensus.io/stats"
- "go.opencensus.io/stats/view"
- "go.opencensus.io/tag"
-)
-
-const (
- syncMetricName = "sync"
- syncDurationMetricName = "sync_duration_seconds"
- lastRunTimeMetricName = "sync_last_run_time"
-)
-
-var (
- syncM = stats.Int64(syncMetricName, "Total number of resources of each kind being cached", stats.UnitDimensionless)
- syncDurationM = stats.Float64(syncDurationMetricName, "Latency of sync operation in seconds", stats.UnitSeconds)
- lastRunSyncM = stats.Float64(lastRunTimeMetricName, "Timestamp of last sync operation", stats.UnitSeconds)
-
- kindKey = tag.MustNewKey("kind")
- statusKey = tag.MustNewKey("status")
-
- views = []*view.View{
- {
- Name: syncM.Name(),
- Measure: syncM,
- Description: syncM.Description(),
- Aggregation: view.LastValue(),
- TagKeys: []tag.Key{kindKey, statusKey},
- },
- {
- Name: syncDurationM.Name(),
- Measure: syncDurationM,
- Description: syncDurationM.Description(),
- Aggregation: view.Distribution(0.0001, 0.0002, 0.0003, 0.0004, 0.0005, 0.0006, 0.0007, 0.0008, 0.0009, 0.001, 0.002, 0.003, 0.004, 0.005, 0.01, 0.02, 0.03, 0.04, 0.05),
- },
- {
- Name: lastRunSyncM.Name(),
- Measure: lastRunSyncM,
- Description: lastRunSyncM.Description(),
- Aggregation: view.LastValue(),
- },
- }
-)
-
-func init() {
- if err := register(); err != nil {
- panic(err)
- }
-}
-
-func register() error {
- return view.Register(views...)
-}
-
-type Reporter struct {
- now func() float64
-}
-
-// NewStatsReporter creates a reporter for sync metrics.
-func NewStatsReporter() (*Reporter, error) {
- return &Reporter{now: now}, nil
-}
-
-func (r *Reporter) reportSyncDuration(d time.Duration) error {
- ctx := context.Background()
- return metrics.Record(ctx, syncDurationM.M(d.Seconds()))
-}
-
-func (r *Reporter) reportLastSync() error {
- ctx := context.Background()
- return metrics.Record(ctx, lastRunSyncM.M(r.now()))
-}
-
-func (r *Reporter) reportSync(t Tags, v int64) error {
- ctx, err := tag.New(
- context.Background(),
- tag.Insert(kindKey, t.Kind),
- tag.Insert(statusKey, string(t.Status)))
- if err != nil {
- return err
- }
-
- return metrics.Record(ctx, syncM.M(v))
-}
-
-// now returns the timestamp as a second-denominated float.
-func now() float64 {
- return float64(time.Now().UnixNano()) / 1e9
-}
diff --git a/pkg/controller/sync/sync_controller.go b/pkg/controller/sync/sync_controller.go
index 2d792caa24e..a74655c2135 100644
--- a/pkg/controller/sync/sync_controller.go
+++ b/pkg/controller/sync/sync_controller.go
@@ -17,17 +17,14 @@ package sync
import (
"context"
- "strings"
- "sync"
"time"
"github.com/go-logr/logr"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/syncutil"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
@@ -44,11 +41,8 @@ import (
var log = logf.Log.WithName("controller").WithValues("metaKind", "Sync")
type Adder struct {
- Opa OpaDataClient
- Events <-chan event.GenericEvent
- MetricsCache *MetricsCache
- Tracker *readiness.Tracker
- ProcessExcluder *process.Excluder
+ CacheManager *cachemanager.CacheManager
+ Events <-chan event.GenericEvent
}
// Add creates a new Sync Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
@@ -57,34 +51,28 @@ func (a *Adder) Add(mgr manager.Manager) error {
if !operations.HasValidationOperations() {
return nil
}
- reporter, err := NewStatsReporter()
+ reporter, err := syncutil.NewStatsReporter()
if err != nil {
log.Error(err, "Sync metrics reporter could not start")
return err
}
- r := newReconciler(mgr, a.Opa, *reporter, a.MetricsCache, a.Tracker, a.ProcessExcluder)
+ r := newReconciler(mgr, *reporter, a.CacheManager)
return add(mgr, r, a.Events)
}
// newReconciler returns a new reconcile.Reconciler.
func newReconciler(
mgr manager.Manager,
- opa OpaDataClient,
- reporter Reporter,
- metricsCache *MetricsCache,
- tracker *readiness.Tracker,
- processExcluder *process.Excluder,
+ reporter syncutil.Reporter,
+ cm *cachemanager.CacheManager,
) reconcile.Reconciler {
return &ReconcileSync{
- reader: mgr.GetCache(),
- scheme: mgr.GetScheme(),
- opa: opa,
- log: log,
- reporter: reporter,
- metricsCache: metricsCache,
- tracker: tracker,
- processExcluder: processExcluder,
+ reader: mgr.GetCache(),
+ scheme: mgr.GetScheme(),
+ log: log,
+ reporter: reporter,
+ cm: cm,
}
}
@@ -108,28 +96,14 @@ func add(mgr manager.Manager, r reconcile.Reconciler, events <-chan event.Generi
var _ reconcile.Reconciler = &ReconcileSync{}
-type MetricsCache struct {
- mux sync.RWMutex
- Cache map[string]Tags
- KnownKinds map[string]bool
-}
-
-type Tags struct {
- Kind string
- Status metrics.Status
-}
-
// ReconcileSync reconciles an arbitrary object described by Kind.
type ReconcileSync struct {
reader client.Reader
- scheme *runtime.Scheme
- opa OpaDataClient
- log logr.Logger
- reporter Reporter
- metricsCache *MetricsCache
- tracker *readiness.Tracker
- processExcluder *process.Excluder
+ scheme *runtime.Scheme
+ log logr.Logger
+ reporter syncutil.Reporter
+ cm *cachemanager.CacheManager
}
// +kubebuilder:rbac:groups=constraints.gatekeeper.sh,resources=*,verbs=get;list;watch;create;update;patch;delete
@@ -147,17 +121,16 @@ func (r *ReconcileSync) Reconcile(ctx context.Context, request reconcile.Request
return reconcile.Result{}, nil
}
- syncKey := r.metricsCache.GetSyncKey(unpackedRequest.Namespace, unpackedRequest.Name)
reportMetrics := false
defer func() {
if reportMetrics {
- if err := r.reporter.reportSyncDuration(time.Since(timeStart)); err != nil {
+ if err := r.reporter.ReportSyncDuration(time.Since(timeStart)); err != nil {
log.Error(err, "failed to report sync duration")
}
- r.metricsCache.ReportSync(&r.reporter)
+ r.cm.ReportSyncMetrics()
- if err := r.reporter.reportLastSync(); err != nil {
+ if err := r.reporter.ReportLastSync(); err != nil {
log.Error(err, "failed to report last sync timestamp")
}
}
@@ -171,15 +144,10 @@ func (r *ReconcileSync) Reconcile(ctx context.Context, request reconcile.Request
// This is a deletion; remove the data
instance.SetNamespace(unpackedRequest.Namespace)
instance.SetName(unpackedRequest.Name)
- if _, err := r.opa.RemoveData(ctx, instance); err != nil {
+ if err := r.cm.RemoveObject(ctx, instance); err != nil {
return reconcile.Result{}, err
}
- // cancel expectations
- t := r.tracker.ForData(instance.GroupVersionKind())
- t.CancelExpect(instance)
-
- r.metricsCache.DeleteObject(syncKey)
reportMetrics = true
return reconcile.Result{}, nil
}
@@ -187,29 +155,11 @@ func (r *ReconcileSync) Reconcile(ctx context.Context, request reconcile.Request
return reconcile.Result{}, err
}
- // namespace is excluded from sync
- isExcludedNamespace, err := r.skipExcludedNamespace(instance)
- if err != nil {
- log.Error(err, "error while excluding namespaces")
- }
-
- if isExcludedNamespace {
- // cancel expectations
- t := r.tracker.ForData(instance.GroupVersionKind())
- t.CancelExpect(instance)
- return reconcile.Result{}, nil
- }
-
if !instance.GetDeletionTimestamp().IsZero() {
- if _, err := r.opa.RemoveData(ctx, instance); err != nil {
+ if err := r.cm.RemoveObject(ctx, instance); err != nil {
return reconcile.Result{}, err
}
- // cancel expectations
- t := r.tracker.ForData(instance.GroupVersionKind())
- t.CancelExpect(instance)
-
- r.metricsCache.DeleteObject(syncKey)
reportMetrics = true
return reconcile.Result{}, nil
}
@@ -222,106 +172,10 @@ func (r *ReconcileSync) Reconcile(ctx context.Context, request reconcile.Request
logging.ResourceName, instance.GetName(),
)
- if _, err := r.opa.AddData(ctx, instance); err != nil {
- r.metricsCache.AddObject(syncKey, Tags{
- Kind: instance.GetKind(),
- Status: metrics.ErrorStatus,
- })
- reportMetrics = true
-
+ reportMetrics = true
+ if err := r.cm.AddObject(ctx, instance); err != nil {
return reconcile.Result{}, err
}
- r.tracker.ForData(gvk).Observe(instance)
- log.V(1).Info("[readiness] observed data", "gvk", gvk, "namespace", instance.GetNamespace(), "name", instance.GetName())
-
- r.metricsCache.AddObject(syncKey, Tags{
- Kind: instance.GetKind(),
- Status: metrics.ActiveStatus,
- })
-
- r.metricsCache.addKind(instance.GetKind())
-
- reportMetrics = true
return reconcile.Result{}, nil
}
-
-func (r *ReconcileSync) skipExcludedNamespace(obj *unstructured.Unstructured) (bool, error) {
- isNamespaceExcluded, err := r.processExcluder.IsNamespaceExcluded(process.Sync, obj)
- if err != nil {
- return false, err
- }
-
- return isNamespaceExcluded, err
-}
-
-func NewMetricsCache() *MetricsCache {
- return &MetricsCache{
- Cache: make(map[string]Tags),
- KnownKinds: make(map[string]bool),
- }
-}
-
-func (c *MetricsCache) GetSyncKey(namespace string, name string) string {
- return strings.Join([]string{namespace, name}, "/")
-}
-
-// need to know encountered kinds to reset metrics for that kind
-// this is a known memory leak
-// footprint should naturally reset on Pod upgrade b/c the container restarts.
-func (c *MetricsCache) addKind(key string) {
- c.mux.Lock()
- defer c.mux.Unlock()
-
- c.KnownKinds[key] = true
-}
-
-func (c *MetricsCache) ResetCache() {
- c.mux.Lock()
- defer c.mux.Unlock()
-
- c.Cache = make(map[string]Tags)
-}
-
-func (c *MetricsCache) AddObject(key string, t Tags) {
- c.mux.Lock()
- defer c.mux.Unlock()
-
- c.Cache[key] = Tags{
- Kind: t.Kind,
- Status: t.Status,
- }
-}
-
-func (c *MetricsCache) DeleteObject(key string) {
- c.mux.Lock()
- defer c.mux.Unlock()
-
- delete(c.Cache, key)
-}
-
-func (c *MetricsCache) ReportSync(reporter *Reporter) {
- c.mux.RLock()
- defer c.mux.RUnlock()
-
- totals := make(map[Tags]int)
- for _, v := range c.Cache {
- totals[v]++
- }
-
- for kind := range c.KnownKinds {
- for _, status := range metrics.AllStatuses {
- if err := reporter.reportSync(
- Tags{
- Kind: kind,
- Status: status,
- },
- int64(totals[Tags{
- Kind: kind,
- Status: status,
- }])); err != nil {
- log.Error(err, "failed to report sync")
- }
- }
- }
-}
diff --git a/pkg/expansion/aggregate.go b/pkg/expansion/aggregate.go
index 2e95f8c389b..2967a08ef17 100644
--- a/pkg/expansion/aggregate.go
+++ b/pkg/expansion/aggregate.go
@@ -3,10 +3,15 @@ package expansion
import (
"fmt"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/instrumentation"
"github.com/open-policy-agent/frameworks/constraint/pkg/types"
)
-const childMsgPrefix = "[Implied by %s]"
+const (
+ childMsgPrefix = "[Implied by %s]"
+
+ ChildStatLabel = "Implied by"
+)
// AggregateResponses aggregates all responses from children into the parent.
// Child result messages will be prefixed with a string to indicate the msg
@@ -22,6 +27,22 @@ func AggregateResponses(templateName string, parent *types.Responses, child *typ
}
}
+// AggregateStats aggregates all stats from the child Responses.StatsEntry
+// into the parent Responses.StatsEntry. Child Stats will have a label to
+// indicate that they come from an ExpansionTemplate usage.
+func AggregateStats(templateName string, parent *types.Responses, child *types.Responses) {
+ childStatsEntries := child.StatsEntries
+
+ for _, se := range childStatsEntries {
+ se.Labels = append(se.Labels, []*instrumentation.Label{{
+ Name: ChildStatLabel,
+ Value: templateName,
+ }}...)
+ }
+
+ parent.StatsEntries = append(parent.StatsEntries, child.StatsEntries...)
+}
+
func OverrideEnforcementAction(action string, resps *types.Responses) {
// If the enforcement action is empty, do not override
if action == "" {
diff --git a/pkg/expansion/aggregate_test.go b/pkg/expansion/aggregate_test.go
index 8278a39db6c..549a420ce65 100644
--- a/pkg/expansion/aggregate_test.go
+++ b/pkg/expansion/aggregate_test.go
@@ -5,7 +5,9 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/instrumentation"
"github.com/open-policy-agent/frameworks/constraint/pkg/types"
+ "github.com/stretchr/testify/require"
)
// addFn is used to easily build types.Responses within the tests.
@@ -91,6 +93,82 @@ func TestAggregateResponses(t *testing.T) {
}
}
+// Test_AggregateStats is meant to show that StatsEntry objects are properly added
+// fron child to parent when using the AggregateStats function. IT IS NOT meant to
+// test StatsEntry objects themselves.
+func Test_AggregateStats(t *testing.T) {
+ tests := []struct {
+ name string
+ templateName string
+ parent *types.Responses
+ child *types.Responses
+ expectedStats int
+ }{
+ {
+ name: "empty parent and child",
+ templateName: "testTemplate1",
+ parent: &types.Responses{},
+ child: &types.Responses{},
+ expectedStats: 0,
+ },
+ {
+ name: "empty parent, single child",
+ templateName: "testTemplate2",
+ parent: &types.Responses{},
+ child: &types.Responses{
+ StatsEntries: []*instrumentation.StatsEntry{
+ {Labels: []*instrumentation.Label{}},
+ },
+ },
+ expectedStats: 1,
+ },
+ {
+ name: "multiple children",
+ templateName: "testTemplate3",
+ parent: &types.Responses{
+ StatsEntries: []*instrumentation.StatsEntry{
+ {Labels: []*instrumentation.Label{}},
+ },
+ },
+ child: &types.Responses{
+ StatsEntries: []*instrumentation.StatsEntry{
+ {Labels: []*instrumentation.Label{}},
+ {Labels: []*instrumentation.Label{}},
+ },
+ },
+ expectedStats: 3,
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ parent := tc.parent
+ child := tc.child
+ AggregateStats(tc.templateName, parent, child)
+
+ require.Len(t, parent.StatsEntries, tc.expectedStats)
+
+ for _, se := range tc.parent.StatsEntries {
+ labelFound := false
+ for _, label := range se.Labels {
+ if label.Name == ChildStatLabel && label.Value == tc.templateName {
+ labelFound = true
+ break
+ }
+ }
+
+ // note that, in practice, we shouldn't care for the len of se.Labels
+ // we only add the check in here to distinguish between the parent labels,
+ // which are 0, and the child labels which should have at least one element,
+ // the label that is added thru AggregateStats
+ if !labelFound && len(se.Labels) > 0 {
+ t.Errorf("expected label %s not found", ChildStatLabel)
+ }
+ }
+ })
+ }
+}
+
func TestOverrideEnforcementAction(t *testing.T) {
tests := []struct {
name string
diff --git a/pkg/expansion/db.go b/pkg/expansion/db.go
new file mode 100644
index 00000000000..b8eab62b98d
--- /dev/null
+++ b/pkg/expansion/db.go
@@ -0,0 +1,290 @@
+package expansion
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/dominikbraun/graph"
+ expansionunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/unversioned"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+type templateDB interface {
+ upsert(*expansionunversioned.ExpansionTemplate) error
+ remove(*expansionunversioned.ExpansionTemplate)
+ templatesForGVK(gvk schema.GroupVersionKind) []*expansionunversioned.ExpansionTemplate
+ getConflicts() IDSet
+}
+
+var _ templateDB = &db{}
+
+type adjList map[schema.GroupVersionKind]IDSet
+
+// hashID is passed to the graphing package.
+var hashID = func(id TemplateID) string {
+ return string(id)
+}
+
+type templateState struct {
+ template *expansionunversioned.ExpansionTemplate
+ hasConflicts bool
+}
+
+type edge struct {
+ x TemplateID
+ y TemplateID
+}
+
+type db struct {
+ store map[TemplateID]*templateState
+
+ // graph stores a graph of ExpansionTemplate. A directed edge from template A
+ // to B means that the template A's `generatedGVK` matches template B's `applyTo`.
+ graph graph.Graph[string, TemplateID]
+
+ // `matchers` and `generators` creates the necessary mappings to be able to
+ // determine the inbound and outbound edges of a given template in O(1).
+ // matchers is a mapping of GVKs to templates that match (applyTo) that GVK.
+ matchers adjList
+ // generators is a mapping of GVKs to templates that generate that GVK.
+ generators adjList
+}
+
+func newDB() *db {
+ return &db{
+ store: make(map[TemplateID]*templateState),
+ graph: graph.New(hashID, graph.Directed()),
+ matchers: make(adjList),
+ generators: make(adjList),
+ }
+}
+
+func (d *db) getConflicts() IDSet {
+ confs := make(IDSet)
+ for tID, tState := range d.store {
+ if tState.hasConflicts {
+ confs[tID] = true
+ }
+ }
+ return confs
+}
+
+// handleAdd adds the template to the DB, returning true if a cycle was created.
+// The template is added even if a cycle was found.
+func (d *db) handleAdd(template *expansionunversioned.ExpansionTemplate) (bool, error) {
+ id := keyForTemplate(template)
+
+ // We should always remove the old template before handleAdd. If we
+ // didn't, that's a bug.
+ if _, exists := d.store[id]; exists {
+ panic(fmt.Errorf("tried to add template %q that already exists", id))
+ }
+
+ // Update storage
+ d.store[id] = &templateState{template: template.DeepCopy(), hasConflicts: false}
+
+ // Update generators
+ genGVK := genGVKToSchemaGVK(template.Spec.GeneratedGVK)
+ if _, exists := d.generators[genGVK]; !exists {
+ d.generators[genGVK] = make(map[TemplateID]bool)
+ }
+ d.generators[genGVK][id] = true
+
+ // Update matchers
+ matches := applyToGVKs(template)
+ for _, m := range matches {
+ if _, exists := d.matchers[m]; !exists {
+ d.matchers[m] = make(map[TemplateID]bool)
+ }
+ d.matchers[m][id] = true
+ }
+
+ // Add vertex if DNE
+ if _, err := d.graph.Vertex(hashID(id)); err != nil {
+ if errors.Is(err, graph.ErrVertexNotFound) {
+ if err := d.graph.AddVertex(id); err != nil {
+ return false, fmt.Errorf("adding vertex to graph: %w", err)
+ }
+ } else {
+ return false, fmt.Errorf("unexpected error getting vertex for template %s: %w", id, err)
+ }
+ }
+
+ // Add edges
+ edges := d.edgesForTemplate(template)
+ cycle := false
+ for _, e := range edges {
+ from := hashID(e.x)
+ to := hashID(e.y)
+
+ createsCycle, err := graph.CreatesCycle(d.graph, from, to)
+ if err != nil {
+ return false, fmt.Errorf("checking cycle for template %s: %w", id, err)
+ }
+ cycle = createsCycle || cycle
+
+ if err = d.graph.AddEdge(from, to); err != nil {
+ return false, fmt.Errorf("adding edge for template %s: %w", id, err)
+ }
+ }
+
+ return cycle, nil
+}
+
+func (d *db) edgesForTemplate(template *expansionunversioned.ExpansionTemplate) []edge {
+ var edges []edge
+ id := keyForTemplate(template)
+ genGVK := genGVKToSchemaGVK(template.Spec.GeneratedGVK)
+
+ // Add out-bound edges (from this template's generated GVK to other
+ // templates' matched GVKs)
+ for t := range d.matchers[genGVK] {
+ edges = append(edges, edge{id, t})
+ }
+
+ // Add in-bound edges (from other templates' generated GVK to this template's
+ // matched GVK)
+ for _, gen := range applyToGVKs(template) {
+ for t := range d.generators[gen] {
+ edges = append(edges, edge{t, id})
+ }
+ }
+
+ return edges
+}
+
+func (d *db) handleRemove(id TemplateID) {
+ // The template must exist. Existence checks should be done upstream.
+ if _, exists := d.store[id]; !exists {
+ panic(fmt.Errorf("called handleRemove for template %q, but template DNE in store", id))
+ }
+ template := d.store[id].template
+
+ // Update storage
+ delete(d.store, id)
+
+ // Update generators
+ genGVK := genGVKToSchemaGVK(template.Spec.GeneratedGVK)
+ if _, exists := d.generators[genGVK]; exists {
+ delete(d.generators[genGVK], id)
+ if len(d.generators[genGVK]) == 0 {
+ delete(d.generators, genGVK)
+ }
+ } else {
+ panic(fmt.Errorf("[template %q] inconsistent db - expected key %s to exist in generators", id, genGVK))
+ }
+
+ // Update matchers
+ matches := applyToGVKs(template)
+ for _, m := range matches {
+ if _, exists := d.matchers[m]; exists {
+ delete(d.matchers[m], id)
+ if len(d.matchers[m]) == 0 {
+ delete(d.matchers, m)
+ }
+ } else {
+ panic(fmt.Errorf("[template %q] inconsistent db - expected key %s to exist in matches", id, m))
+ }
+ }
+
+ // Remove edges
+ edges := d.edgesForTemplate(template)
+ for _, e := range edges {
+ from := hashID(e.x)
+ to := hashID(e.y)
+ if err := d.graph.RemoveEdge(from, to); err != nil {
+ panic(fmt.Errorf("[template %q] unexpected error removing edge: %w", id, err))
+ }
+ }
+}
+
+func (d *db) updateCycles() {
+ // First reset all conflicts
+ for _, ts := range d.store {
+ ts.hasConflicts = false
+ }
+
+ conflicts, err := graph.StronglyConnectedComponents(d.graph)
+ if err != nil {
+ panic(fmt.Errorf("error getting SCCs: %w", err))
+ }
+ // All strongly connect components containing more than 1 vertex are a cycle
+ for _, scc := range conflicts {
+ if len(scc) <= 1 {
+ continue
+ }
+ for _, id := range scc {
+ d.store[TemplateID(id)].hasConflicts = true
+ }
+ }
+}
+
+func (d *db) upsert(template *expansionunversioned.ExpansionTemplate) error {
+ id := keyForTemplate(template)
+ old, hasOld := d.store[id]
+ if hasOld {
+ d.handleRemove(id)
+ }
+
+ newCycle, err := d.handleAdd(template)
+ if err != nil {
+ return fmt.Errorf("adding template to db: %w", err)
+ }
+ // If the new/updated template caused a cycle, or the previous template belonged
+ // to a cycle, then we need to re-check the graph for cycles
+ if newCycle || (hasOld && old.hasConflicts) {
+ d.updateCycles()
+ }
+
+ if newCycle {
+ return fmt.Errorf("template forms expansion cycle")
+ }
+ return nil
+}
+
+func (d *db) remove(template *expansionunversioned.ExpansionTemplate) {
+ id := keyForTemplate(template)
+ old, exists := d.store[id]
+ if !exists {
+ return
+ }
+
+ d.handleRemove(id)
+ // If the removed template was part of a cycle, we need to recheck the graph
+ // in case that cycle was resolved
+ if old.hasConflicts {
+ d.updateCycles()
+ }
+}
+
+func (d *db) templatesForGVK(gvk schema.GroupVersionKind) []*expansionunversioned.ExpansionTemplate {
+ var tset []*expansionunversioned.ExpansionTemplate
+ for tID := range d.matchers[gvk] {
+ // Sanity check. In theory, this should never happen, but if it does, we
+ // can't recover.
+ if _, exists := d.store[tID]; !exists {
+ panic(fmt.Errorf("inconsistent db - key %s exists in matchers but not cache", tID))
+ }
+
+ tState := d.store[tID]
+ if !tState.hasConflicts {
+ tset = append(tset, tState.template)
+ }
+ }
+
+ return tset
+}
+
+func applyToGVKs(template *expansionunversioned.ExpansionTemplate) []schema.GroupVersionKind {
+ var gvks []schema.GroupVersionKind
+ for _, apply := range template.Spec.ApplyTo {
+ for _, g := range apply.Groups {
+ for _, v := range apply.Versions {
+ for _, k := range apply.Kinds {
+ gvks = append(gvks, schema.GroupVersionKind{Group: g, Version: v, Kind: k})
+ }
+ }
+ }
+ }
+ return gvks
+}
diff --git a/pkg/expansion/db_test.go b/pkg/expansion/db_test.go
new file mode 100644
index 00000000000..0ea713f6eca
--- /dev/null
+++ b/pkg/expansion/db_test.go
@@ -0,0 +1,799 @@
+package expansion
+
+import (
+ "sort"
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion/fixtures"
+ "github.com/stretchr/testify/require"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+const (
+ addOp = "UPSERT"
+ rmOp = "REMOVE"
+)
+
+type templateOperation struct {
+ op string
+ template unversioned.ExpansionTemplate
+
+ // wantErr is only relevant for add operations.
+ wantErr bool
+}
+
+func TestDB(t *testing.T) {
+ tests := []struct {
+ name string
+ ops []templateOperation
+ wantMatchers adjList
+ wantGenerators adjList
+ wantStore map[TemplateID]*templateState
+ }{
+ {
+ name: "add 1 template",
+ ops: []templateOperation{
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("foo", 1, 2),
+ wantErr: false,
+ },
+ },
+ wantStore: map[TemplateID]*templateState{
+ keyForTemplate(fixtures.TestTemplate("foo", 1, 2)): {
+ template: fixtures.TestTemplate("foo", 1, 2),
+ hasConflicts: false,
+ },
+ },
+ wantMatchers: adjList{
+ schema.GroupVersionKind{
+ Group: "group1",
+ Version: "v1",
+ Kind: "kind1",
+ }: {
+ keyForTemplate(fixtures.TestTemplate("foo", 1, 2)): true,
+ },
+ },
+ wantGenerators: adjList{
+ schema.GroupVersionKind{
+ Group: "group2",
+ Version: "v2",
+ Kind: "kind2",
+ }: {
+ keyForTemplate(fixtures.TestTemplate("foo", 1, 2)): true,
+ },
+ },
+ },
+ {
+ name: "add 1 template that has many applyTo",
+ ops: []templateOperation{
+ {
+ op: addOp,
+ template: *fixtures.TempMultApply(),
+ wantErr: false,
+ },
+ },
+ wantStore: map[TemplateID]*templateState{
+ keyForTemplate(fixtures.TempMultApply()): {
+ template: fixtures.TempMultApply(),
+ hasConflicts: false,
+ },
+ },
+ wantMatchers: adjList{
+ schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "kind1"}: {
+ keyForTemplate(fixtures.TempMultApply()): true,
+ },
+ schema.GroupVersionKind{Group: "group11", Version: "v11", Kind: "kind11"}: {
+ keyForTemplate(fixtures.TempMultApply()): true,
+ },
+ schema.GroupVersionKind{Group: "group11", Version: "v22", Kind: "kind11"}: {
+ keyForTemplate(fixtures.TempMultApply()): true,
+ },
+ },
+ wantGenerators: adjList{
+ schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "kind2"}: {
+ keyForTemplate(fixtures.TempMultApply()): true,
+ },
+ },
+ },
+ {
+ name: "add 2 templates with same applyTo and genGVK",
+ ops: []templateOperation{
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t1", 1, 2),
+ },
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t2", 1, 2),
+ },
+ },
+ wantStore: map[TemplateID]*templateState{
+ keyForTemplate(fixtures.TestTemplate("t1", 1, 2)): {
+ template: fixtures.TestTemplate("t1", 1, 2),
+ hasConflicts: false,
+ },
+ keyForTemplate(fixtures.TestTemplate("t2", 1, 2)): {
+ template: fixtures.TestTemplate("t2", 1, 2),
+ hasConflicts: false,
+ },
+ },
+ wantMatchers: adjList{
+ schema.GroupVersionKind{
+ Group: "group1",
+ Version: "v1",
+ Kind: "kind1",
+ }: {
+ keyForTemplate(fixtures.TestTemplate("t1", 1, 2)): true,
+ keyForTemplate(fixtures.TestTemplate("t2", 1, 2)): true,
+ },
+ },
+ wantGenerators: adjList{
+ schema.GroupVersionKind{
+ Group: "group2",
+ Version: "v2",
+ Kind: "kind2",
+ }: {
+ keyForTemplate(fixtures.TestTemplate("t1", 1, 2)): true,
+ keyForTemplate(fixtures.TestTemplate("t2", 1, 2)): true,
+ },
+ },
+ },
+ {
+ name: "removing non-existing template does nothing",
+ ops: []templateOperation{
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("foo", 1, 2),
+ },
+ {
+ op: rmOp,
+ template: *fixtures.TestTemplate("DNE", 1, 2),
+ },
+ },
+ wantStore: map[TemplateID]*templateState{
+ keyForTemplate(fixtures.TestTemplate("foo", 1, 2)): {
+ template: fixtures.TestTemplate("foo", 1, 2),
+ hasConflicts: false,
+ },
+ },
+ wantMatchers: adjList{
+ schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "kind1"}: {
+ keyForTemplate(fixtures.TestTemplate("foo", 1, 2)): true,
+ },
+ },
+ wantGenerators: adjList{
+ schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "kind2"}: {
+ keyForTemplate(fixtures.TestTemplate("foo", 1, 2)): true,
+ },
+ },
+ },
+ {
+ name: "update existing template",
+ ops: []templateOperation{
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("foo", 1, 2),
+ },
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("foo", 3, 4),
+ },
+ },
+ wantStore: map[TemplateID]*templateState{
+ keyForTemplate(fixtures.TestTemplate("foo", 3, 4)): {
+ template: fixtures.TestTemplate("foo", 3, 4),
+ hasConflicts: false,
+ },
+ },
+ wantMatchers: adjList{
+ schema.GroupVersionKind{Group: "group3", Version: "v3", Kind: "kind3"}: {
+ keyForTemplate(fixtures.TestTemplate("foo", 3, 4)): true,
+ },
+ },
+ wantGenerators: adjList{
+ schema.GroupVersionKind{Group: "group4", Version: "v4", Kind: "kind4"}: {
+ keyForTemplate(fixtures.TestTemplate("foo", 3, 4)): true,
+ },
+ },
+ },
+ {
+ name: "adding cycle disables cyclic templates and leaves non-cyclic enabled",
+ ops: []templateOperation{
+ // t1 -> t2 -> t3 -> t1 -> ... forms cycle
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t1-2", 1, 2),
+ },
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t2-3", 2, 3),
+ },
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t3-1", 3, 1),
+ wantErr: true,
+ },
+ // t2-8 is "touching" the cycle, but not part of it
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t2-8", 2, 8),
+ },
+ // t5 is completely disjoint from rest of graph
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t5", 5, 6),
+ },
+ },
+ wantStore: map[TemplateID]*templateState{
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): {
+ template: fixtures.TestTemplate("t1-2", 1, 2),
+ hasConflicts: true,
+ },
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): {
+ template: fixtures.TestTemplate("t2-3", 2, 3),
+ hasConflicts: true,
+ },
+ keyForTemplate(fixtures.TestTemplate("t3-1", 3, 1)): {
+ template: fixtures.TestTemplate("t3-1", 3, 1),
+ hasConflicts: true,
+ },
+ keyForTemplate(fixtures.TestTemplate("t2-8", 2, 8)): {
+ template: fixtures.TestTemplate("t2-8", 2, 8),
+ hasConflicts: false,
+ },
+ keyForTemplate(fixtures.TestTemplate("t5", 5, 6)): {
+ template: fixtures.TestTemplate("t5", 5, 6),
+ hasConflicts: false,
+ },
+ },
+ wantMatchers: adjList{
+ schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "kind1"}: {
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): true,
+ },
+ schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "kind2"}: {
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): true,
+ keyForTemplate(fixtures.TestTemplate("t2-8", 2, 8)): true,
+ },
+ schema.GroupVersionKind{Group: "group3", Version: "v3", Kind: "kind3"}: {
+ keyForTemplate(fixtures.TestTemplate("t3-1", 3, 1)): true,
+ },
+ schema.GroupVersionKind{Group: "group5", Version: "v5", Kind: "kind5"}: {
+ keyForTemplate(fixtures.TestTemplate("t5", 5, 6)): true,
+ },
+ },
+ wantGenerators: adjList{
+ schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "kind2"}: {
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): true,
+ },
+ schema.GroupVersionKind{Group: "group3", Version: "v3", Kind: "kind3"}: {
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): true,
+ },
+ schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "kind1"}: {
+ keyForTemplate(fixtures.TestTemplate("t3-1", 3, 1)): true,
+ },
+ schema.GroupVersionKind{Group: "group6", Version: "v6", Kind: "kind6"}: {
+ keyForTemplate(fixtures.TestTemplate("t5", 5, 6)): true,
+ },
+ schema.GroupVersionKind{Group: "group8", Version: "v8", Kind: "kind8"}: {
+ keyForTemplate(fixtures.TestTemplate("t2-8", 2, 8)): true,
+ },
+ },
+ },
+ {
+ name: "update template to produce cycle",
+ ops: []templateOperation{
+ // t5 is completely disjoint from rest of graph
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t5", 5, 6),
+ },
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t3-4", 3, 4),
+ },
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t1-2", 1, 2),
+ },
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t2-3", 2, 3),
+ },
+ // update 3-4 to form a cycle
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t3-4", 3, 1),
+ wantErr: true,
+ },
+ },
+ wantStore: map[TemplateID]*templateState{
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): {
+ template: fixtures.TestTemplate("t1-2", 1, 2),
+ hasConflicts: true,
+ },
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): {
+ template: fixtures.TestTemplate("t2-3", 2, 3),
+ hasConflicts: true,
+ },
+ keyForTemplate(fixtures.TestTemplate("t3-4", 1, 1)): {
+ template: fixtures.TestTemplate("t3-4", 3, 1),
+ hasConflicts: true,
+ },
+ keyForTemplate(fixtures.TestTemplate("t5", 5, 6)): {
+ template: fixtures.TestTemplate("t5", 5, 6),
+ hasConflicts: false,
+ },
+ },
+ wantMatchers: adjList{
+ schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "kind1"}: {
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): true,
+ },
+ schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "kind2"}: {
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): true,
+ },
+ schema.GroupVersionKind{Group: "group3", Version: "v3", Kind: "kind3"}: {
+ keyForTemplate(fixtures.TestTemplate("t3-4", 3, 4)): true,
+ },
+ schema.GroupVersionKind{Group: "group5", Version: "v5", Kind: "kind5"}: {
+ keyForTemplate(fixtures.TestTemplate("t5", 5, 6)): true,
+ },
+ },
+ wantGenerators: adjList{
+ schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "kind2"}: {
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): true,
+ },
+ schema.GroupVersionKind{Group: "group3", Version: "v3", Kind: "kind3"}: {
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): true,
+ },
+ schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "kind1"}: {
+ keyForTemplate(fixtures.TestTemplate("t3-4", 3, 1)): true,
+ },
+ schema.GroupVersionKind{Group: "group6", Version: "v6", Kind: "kind6"}: {
+ keyForTemplate(fixtures.TestTemplate("t5", 5, 6)): true,
+ },
+ },
+ },
+ {
+ name: "fixing cycle re-enables templates but existing cycles still disabled",
+ ops: []templateOperation{
+ // t7-8 and t8-7 form a cycle unconnected to the t1-t2-t3 cycle
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t7-8", 7, 8),
+ },
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t8-7", 8, 7),
+ wantErr: true,
+ },
+ // t1 -> t2 -> t3 -> t1 -> ... forms cycle
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t1-2", 1, 2),
+ },
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t2-3", 2, 3),
+ },
+ // t3-1 produces cycle
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t3-1", 3, 1),
+ wantErr: true,
+ },
+ // fix t3-1 to behavior like t3-4, thus fixing cycle
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t3-1", 3, 4),
+ },
+ },
+ wantStore: map[TemplateID]*templateState{
+ keyForTemplate(fixtures.TestTemplate("t7-8", 7, 8)): {
+ template: fixtures.TestTemplate("t7-8", 7, 8),
+ hasConflicts: true,
+ },
+ keyForTemplate(fixtures.TestTemplate("t8-7", 8, 7)): {
+ template: fixtures.TestTemplate("t8-7", 8, 7),
+ hasConflicts: true,
+ },
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): {
+ template: fixtures.TestTemplate("t1-2", 1, 2),
+ hasConflicts: false,
+ },
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): {
+ template: fixtures.TestTemplate("t2-3", 2, 3),
+ hasConflicts: false,
+ },
+ keyForTemplate(fixtures.TestTemplate("t3-1", 3, 4)): {
+ template: fixtures.TestTemplate("t3-1", 3, 4),
+ hasConflicts: false,
+ },
+ },
+ wantMatchers: adjList{
+ schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "kind1"}: {
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): true,
+ },
+ schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "kind2"}: {
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): true,
+ },
+ schema.GroupVersionKind{Group: "group3", Version: "v3", Kind: "kind3"}: {
+ keyForTemplate(fixtures.TestTemplate("t3-1", 3, 1)): true,
+ },
+ schema.GroupVersionKind{Group: "group7", Version: "v7", Kind: "kind7"}: {
+ keyForTemplate(fixtures.TestTemplate("t7-8", 7, 8)): true,
+ },
+ schema.GroupVersionKind{Group: "group8", Version: "v8", Kind: "kind8"}: {
+ keyForTemplate(fixtures.TestTemplate("t8-7", 8, 7)): true,
+ },
+ },
+ wantGenerators: adjList{
+ schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "kind2"}: {
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): true,
+ },
+ schema.GroupVersionKind{Group: "group3", Version: "v3", Kind: "kind3"}: {
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): true,
+ },
+ schema.GroupVersionKind{Group: "group4", Version: "v4", Kind: "kind4"}: {
+ keyForTemplate(fixtures.TestTemplate("t3-1", 3, 4)): true,
+ },
+ schema.GroupVersionKind{Group: "group8", Version: "v8", Kind: "kind8"}: {
+ keyForTemplate(fixtures.TestTemplate("t7-8", 7, 8)): true,
+ },
+ schema.GroupVersionKind{Group: "group7", Version: "v7", Kind: "kind7"}: {
+ keyForTemplate(fixtures.TestTemplate("t8-7", 8, 7)): true,
+ },
+ },
+ },
+ {
+ name: "removing cycle re-enables templates but existing cycles still disabled",
+ ops: []templateOperation{
+ // t7-8 and t8-7 form a cycle unconnected to the t1-t2-t3 cycle
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t7-8", 7, 8),
+ },
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t8-7", 8, 7),
+ wantErr: true,
+ },
+ // t1 -> t2 -> t3 -> t1 -> ... forms cycle
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t1-2", 1, 2),
+ },
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t2-3", 2, 3),
+ },
+ // t3-1 produces cycle
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t3-1", 3, 1),
+ wantErr: true,
+ },
+ // remove t3-1 to fix cycle
+ {
+ op: rmOp,
+ template: *fixtures.TestTemplate("t3-1", 3, 1),
+ },
+ },
+ wantStore: map[TemplateID]*templateState{
+ keyForTemplate(fixtures.TestTemplate("t7-8", 7, 8)): {
+ template: fixtures.TestTemplate("t7-8", 7, 8),
+ hasConflicts: true,
+ },
+ keyForTemplate(fixtures.TestTemplate("t8-7", 8, 7)): {
+ template: fixtures.TestTemplate("t8-7", 8, 7),
+ hasConflicts: true,
+ },
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): {
+ template: fixtures.TestTemplate("t1-2", 1, 2),
+ hasConflicts: false,
+ },
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): {
+ template: fixtures.TestTemplate("t2-3", 2, 3),
+ hasConflicts: false,
+ },
+ },
+ wantMatchers: adjList{
+ schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "kind1"}: {
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): true,
+ },
+ schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "kind2"}: {
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): true,
+ },
+ schema.GroupVersionKind{Group: "group7", Version: "v7", Kind: "kind7"}: {
+ keyForTemplate(fixtures.TestTemplate("t7-8", 7, 8)): true,
+ },
+ schema.GroupVersionKind{Group: "group8", Version: "v8", Kind: "kind8"}: {
+ keyForTemplate(fixtures.TestTemplate("t8-7", 8, 7)): true,
+ },
+ },
+ wantGenerators: adjList{
+ schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "kind2"}: {
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): true,
+ },
+ schema.GroupVersionKind{Group: "group3", Version: "v3", Kind: "kind3"}: {
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): true,
+ },
+ schema.GroupVersionKind{Group: "group8", Version: "v8", Kind: "kind8"}: {
+ keyForTemplate(fixtures.TestTemplate("t7-8", 7, 8)): true,
+ },
+ schema.GroupVersionKind{Group: "group7", Version: "v7", Kind: "kind7"}: {
+ keyForTemplate(fixtures.TestTemplate("t8-7", 8, 7)): true,
+ },
+ },
+ },
+ {
+ name: "removing 1 edge from double-edged cycle does not re-enable templates",
+ ops: []templateOperation{
+ // t1 -> t2 -> t3 -> t1 -> ... forms cycle
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t1-2", 1, 2),
+ },
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t2-3", 2, 3),
+ },
+ // t3-1 produces cycle
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("t3-1", 3, 1),
+ wantErr: true,
+ },
+ // ta3-1 produces double-edged cycle
+ {
+ op: addOp,
+ template: *fixtures.TestTemplate("ta3-1", 3, 1),
+ wantErr: true,
+ },
+ // remove t3-1, but cycle still exists with ta3-1
+ {
+ op: rmOp,
+ template: *fixtures.TestTemplate("t3-1", 3, 1),
+ },
+ },
+ wantStore: map[TemplateID]*templateState{
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): {
+ template: fixtures.TestTemplate("t1-2", 1, 2),
+ hasConflicts: true,
+ },
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): {
+ template: fixtures.TestTemplate("t2-3", 2, 3),
+ hasConflicts: true,
+ },
+ keyForTemplate(fixtures.TestTemplate("ta3-1", 3, 1)): {
+ template: fixtures.TestTemplate("ta3-1", 3, 1),
+ hasConflicts: true,
+ },
+ },
+ wantMatchers: adjList{
+ schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "kind1"}: {
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): true,
+ },
+ schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "kind2"}: {
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): true,
+ },
+ schema.GroupVersionKind{Group: "group3", Version: "v3", Kind: "kind3"}: {
+ keyForTemplate(fixtures.TestTemplate("ta3-1", 3, 1)): true,
+ },
+ },
+ wantGenerators: adjList{
+ schema.GroupVersionKind{Group: "group2", Version: "v2", Kind: "kind2"}: {
+ keyForTemplate(fixtures.TestTemplate("t1-2", 1, 2)): true,
+ },
+ schema.GroupVersionKind{Group: "group3", Version: "v3", Kind: "kind3"}: {
+ keyForTemplate(fixtures.TestTemplate("t2-3", 2, 3)): true,
+ },
+ schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "kind1"}: {
+ keyForTemplate(fixtures.TestTemplate("ta3-1", 3, 1)): true,
+ },
+ },
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ d := newDB()
+
+ // Execute all the upsert/remove calls
+ executeOps(d, tc.ops, t)
+
+ if df := cmp.Diff(d.matchers, tc.wantMatchers); df != "" {
+ t.Errorf("got matchers: %v\nbut want: %v\ndiff: %s", d.matchers, tc.wantMatchers, df)
+ }
+
+ if df := cmp.Diff(d.generators, tc.wantGenerators); df != "" {
+ t.Errorf("got generators: %v\nbut want: %v\ndiff: %s", d.generators, tc.wantGenerators, df)
+ }
+
+ if df := cmp.Diff(d.store, tc.wantStore, cmp.AllowUnexported(templateState{})); df != "" {
+ t.Errorf("got store: %v\nbut want: %v\ndiff: %s", d.generators, tc.wantGenerators, df)
+ }
+ })
+ }
+}
+
+func executeOps(db templateDB, ops []templateOperation, t *testing.T) {
+ for i := 0; i < len(ops); i++ {
+ op := ops[i]
+ switch op.op {
+ case addOp:
+ gotErr := db.upsert(&op.template)
+ if op.wantErr {
+ require.Error(t, gotErr, "want err: %t, got: %s", op.wantErr, gotErr)
+ } else if gotErr != nil {
+ t.Errorf("unexpected err upserting: %v", gotErr)
+ }
+ case rmOp:
+ if op.wantErr {
+ t.Fatalf("cannot set errFn for remove operation")
+ }
+ db.remove(&op.template)
+ default:
+ t.Fatalf("unrecognized operation: %s", op.op)
+ }
+ }
+}
+
+func sortTemplates(temps []*unversioned.ExpansionTemplate) {
+ sort.Slice(temps, func(i, j int) bool {
+ return keyForTemplate(temps[i]) > keyForTemplate(temps[j])
+ })
+}
+
+func TestTemplatesForGVK(t *testing.T) {
+ tests := []struct {
+ name string
+ add []*unversioned.ExpansionTemplate
+ gvk schema.GroupVersionKind
+ want []*unversioned.ExpansionTemplate
+ }{
+ {
+ name: "no templates in db returns nothing",
+ gvk: schema.GroupVersionKind{Group: "a", Version: "b", Kind: "c"},
+ },
+ {
+ name: "2 templates no cycles",
+ gvk: schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "kind1"},
+ add: []*unversioned.ExpansionTemplate{
+ fixtures.TestTemplate("t1-2", 1, 2),
+ fixtures.TestTemplate("t2-3", 2, 3),
+ },
+ want: []*unversioned.ExpansionTemplate{
+ fixtures.TestTemplate("t1-2", 1, 2),
+ },
+ },
+ {
+ name: "cycle not returned",
+ gvk: schema.GroupVersionKind{Group: "group1", Version: "v1", Kind: "kind1"},
+ add: []*unversioned.ExpansionTemplate{
+ fixtures.TestTemplate("t1-2", 1, 2),
+ fixtures.TestTemplate("t2-3", 2, 3),
+ fixtures.TestTemplate("t3-1", 3, 1),
+ },
+ },
+ {
+ name: "cycle not returned but non-cyclics are",
+ gvk: schema.GroupVersionKind{Group: "group4", Version: "v4", Kind: "kind4"},
+ add: []*unversioned.ExpansionTemplate{
+ fixtures.TestTemplate("t1-2", 1, 2),
+ fixtures.TestTemplate("t2-3", 2, 3),
+ fixtures.TestTemplate("t3-1", 3, 1),
+ fixtures.TestTemplate("t4-5", 4, 5),
+ fixtures.TestTemplate("t4-6", 4, 6),
+ },
+ want: []*unversioned.ExpansionTemplate{
+ fixtures.TestTemplate("t4-5", 4, 5),
+ fixtures.TestTemplate("t4-6", 4, 6),
+ },
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ d := newDB()
+ for _, t := range tc.add {
+ _ = d.upsert(t)
+ }
+
+ got := d.templatesForGVK(tc.gvk)
+ sortTemplates(got)
+ sortTemplates(tc.want)
+
+ require.Len(t, got, len(tc.want))
+ for i := 0; i < len(got); i++ {
+ if diff := cmp.Diff(got[i], tc.want[i]); diff != "" {
+ t.Errorf("got template %v\nwanted: %v\ndiff: %s", got[i], tc.want[i], diff)
+ }
+ }
+ })
+ }
+}
+
+func TestGetConflicts(t *testing.T) {
+ tests := []struct {
+ name string
+ seed []templateState
+ want map[TemplateID]bool
+ }{
+ {
+ name: "empty db, empty conflicts",
+ },
+ {
+ name: "2 conflicts",
+ seed: []templateState{
+ {
+ hasConflicts: true,
+ template: fixtures.TestTemplate("t1-2", 1, 2),
+ },
+ {
+ hasConflicts: true,
+ template: fixtures.TestTemplate("t2-1", 2, 1),
+ },
+ },
+ want: map[TemplateID]bool{
+ "t1-2": true,
+ "t2-1": true,
+ },
+ },
+ {
+ name: "2 conflicts, 1 non",
+ seed: []templateState{
+ {
+ hasConflicts: true,
+ template: fixtures.TestTemplate("t1-2", 1, 2),
+ },
+ {
+ hasConflicts: true,
+ template: fixtures.TestTemplate("t2-1", 2, 1),
+ },
+ {
+ hasConflicts: false,
+ template: fixtures.TestTemplate("t4-5", 4, 5),
+ },
+ },
+ want: map[TemplateID]bool{
+ "t1-2": true,
+ "t2-1": true,
+ },
+ },
+ {
+ name: "no conflicts",
+ seed: []templateState{
+ {
+ hasConflicts: false,
+ template: fixtures.TestTemplate("t1-2", 1, 2),
+ },
+ {
+ hasConflicts: false,
+ template: fixtures.TestTemplate("t2-3", 2, 3),
+ },
+ {
+ hasConflicts: false,
+ template: fixtures.TestTemplate("t4-5", 4, 5),
+ },
+ },
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ d := newDB()
+ for i := range tc.seed {
+ d.store[keyForTemplate(tc.seed[i].template)] = &tc.seed[i]
+ }
+
+ got := d.getConflicts()
+
+ require.Len(t, got, len(tc.want))
+ for k := range tc.want {
+ if _, exists := got[k]; !exists {
+ t.Errorf("wanted template ID %s, but not returned", k)
+ }
+ }
+ })
+ }
+}
diff --git a/pkg/expansion/fixtures/fixtures.go b/pkg/expansion/fixtures/fixtures.go
index 94dbafb6649..088f4a1a18d 100644
--- a/pkg/expansion/fixtures/fixtures.go
+++ b/pkg/expansion/fixtures/fixtures.go
@@ -2,7 +2,7 @@ package fixtures
const (
TempExpDeploymentExpandsPods = `
-apiVersion: expansion.gatekeeper.sh/v1alpha1
+apiVersion: expansion.gatekeeper.sh/v1beta1
kind: ExpansionTemplate
metadata:
name: expand-deployments
@@ -18,8 +18,79 @@ spec:
version: "v1"
`
+ TempExpReplicaDeploymentExpandsPods = `
+apiVersion: expansion.gatekeeper.sh/v1beta1
+kind: ExpansionTemplate
+metadata:
+ name: expand-deployments-replicas
+spec:
+ applyTo:
+ - groups: ["apps"]
+ kinds: ["Deployment", "ReplicaSet"]
+ versions: ["v1"]
+ templateSource: "spec.template"
+ generatedGVK:
+ kind: "Pod"
+ group: ""
+ version: "v1"
+`
+
+ TempExpMultipleApplyTo = `
+apiVersion: expansion.gatekeeper.sh/v1beta1
+kind: ExpansionTemplate
+metadata:
+ name: expand-many-things
+spec:
+ applyTo:
+ - groups: ["apps", "traps"]
+ kinds: ["Deployment", "ReplicaSet"]
+ versions: ["v1", "v1beta1"]
+ - groups: [""]
+ kinds: ["CoreKind"]
+ versions: ["v1"]
+ templateSource: "spec.template"
+ generatedGVK:
+ kind: "Pod"
+ group: ""
+ version: "v1"
+`
+
+ TempExpCronJob = `
+apiVersion: expansion.gatekeeper.sh/v1beta1
+kind: ExpansionTemplate
+metadata:
+ name: expand-cronjobs
+spec:
+ applyTo:
+ - groups: ["batch"]
+ kinds: ["CronJob"]
+ versions: ["v1"]
+ templateSource: "spec.jobTemplate"
+ generatedGVK:
+ kind: "Job"
+ group: "batch"
+ version: "v1"
+`
+
+ TempExpJob = `
+apiVersion: expansion.gatekeeper.sh/v1beta1
+kind: ExpansionTemplate
+metadata:
+ name: expand-jobs
+spec:
+ applyTo:
+ - groups: ["batch"]
+ kinds: ["Job"]
+ versions: ["v1"]
+ templateSource: "spec.template"
+ generatedGVK:
+ kind: "Pod"
+ group: ""
+ version: "v1"
+`
+
TempExpDeploymentExpandsPodsEnforceDryrun = `
-apiVersion: expansion.gatekeeper.sh/v1alpha1
+apiVersion: expansion.gatekeeper.sh/v1beta1
kind: ExpansionTemplate
metadata:
name: expand-deployments
@@ -62,6 +133,33 @@ spec:
- "/bin/sh"
`
+ DeploymentNginxWithNs = `
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: nginx-deployment
+ labels:
+ app: nginx
+ namespace: not-default
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: nginx
+ template:
+ metadata:
+ labels:
+ app: nginx
+ spec:
+ containers:
+ - name: nginx
+ image: nginx:1.14.2
+ ports:
+ - containerPort: '80'
+ args:
+ - "/bin/sh"
+`
+
DeploymentNoGVK = `
metadata:
name: nginx-deployment
@@ -91,6 +189,7 @@ kind: Pod
metadata:
labels:
app: nginx
+ name: nginx-deployment-pod
namespace: default
spec:
containers:
@@ -108,6 +207,7 @@ kind: Pod
metadata:
labels:
app: nginx
+ name: nginx-deployment-pod
namespace: default
spec:
containers:
@@ -120,6 +220,43 @@ spec:
- containerPort: '80'
`
+ PodImagePullMutateWithNs = `
+apiVersion: v1
+kind: Pod
+metadata:
+ labels:
+ app: nginx
+ name: nginx-deployment-pod
+ namespace: not-default
+spec:
+ containers:
+ - args:
+ - "/bin/sh"
+ image: nginx:1.14.2
+ imagePullPolicy: Always
+ name: nginx
+ ports:
+ - containerPort: '80'
+`
+
+ PodMutateImage = `
+apiVersion: v1
+kind: Pod
+metadata:
+ labels:
+ app: nginx
+ name: nginx-deployment-pod
+ namespace: default
+spec:
+ containers:
+ - args:
+ - "/bin/sh"
+ image: nginx:v2
+ name: nginx
+ ports:
+ - containerPort: '80'
+`
+
PodImagePullMutateAnnotated = `
apiVersion: v1
kind: Pod
@@ -128,6 +265,7 @@ metadata:
app: nginx
annotations:
owner: admin
+ name: nginx-deployment-pod
namespace: default
spec:
containers:
@@ -160,6 +298,33 @@ spec:
kinds:
- apiGroups: []
kinds: []
+`
+
+ AssignPullImageWithNsSelector = `
+apiVersion: mutations.gatekeeper.sh/v1alpha1
+kind: Assign
+metadata:
+ name: always-pull-image
+spec:
+ applyTo:
+ - groups: [""]
+ kinds: ["Pod"]
+ versions: ["v1"]
+ location: "spec.containers[name: *].imagePullPolicy"
+ parameters:
+ assign:
+ value: "Always"
+ match:
+ source: "Generated"
+ scope: Namespaced
+ kinds:
+ - apiGroups: []
+ kinds: []
+ namespaceSelector:
+ matchExpressions:
+ - key: admission.gatekeeper.sh/ignore
+ operator: DoesNotExist
+
`
AssignPullImageSourceAll = `
@@ -205,6 +370,21 @@ spec:
kinds: []
`
+ AssignImage = `
+apiVersion: mutations.gatekeeper.sh/v1alpha1
+kind: AssignImage
+metadata:
+ name: tag-v2
+spec:
+ applyTo:
+ - groups: [""]
+ kinds: ["Pod"]
+ versions: ["v1"]
+ location: "spec.containers[name:nginx].image"
+ parameters:
+ assignTag: ":v2"
+`
+
AssignHostnameSourceOriginal = `
apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
@@ -263,7 +443,7 @@ spec:
`
TemplateCatExpandsKitten = `
-apiVersion: expansion.gatekeeper.sh/v1alpha1
+apiVersion: expansion.gatekeeper.sh/v1beta1
kind: ExpansionTemplate
metadata:
name: expand-cats-kitten
@@ -281,7 +461,7 @@ spec:
`
TemplateCatExpandsPurr = `
-apiVersion: expansion.gatekeeper.sh/v1alpha1
+apiVersion: expansion.gatekeeper.sh/v1beta1
kind: ExpansionTemplate
metadata:
name: expand-cats-purr
@@ -364,6 +544,7 @@ metadata:
sound: meow
labels:
fluffy: extremely
+ name: big-chungus-kitten
namespace: default
spec:
breed: calico
@@ -377,8 +558,68 @@ kind: Purr
metadata:
annotations:
shouldPet: manytimes
+ name: big-chungus-purr
namespace: default
spec:
loud: very
`
+
+ GeneratorCronJob = `
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: my-cronjob
+spec:
+ schedule: "* * * * *"
+ jobTemplate:
+ spec:
+ template:
+ spec:
+ containers:
+ - args:
+ - "/bin/sh"
+ image: nginx:1.14.2
+ imagePullPolicy: Always
+ name: nginx
+ ports:
+ - containerPort: '80'
+`
+
+ ResultantJob = `
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: my-cronjob-job
+ namespace: default
+spec:
+ template:
+ spec:
+ containers:
+ - args:
+ - "/bin/sh"
+ image: nginx:1.14.2
+ imagePullPolicy: Always
+ name: nginx
+ ports:
+ - containerPort: '80'
+`
+
+ ResultantRecursivePod = `
+apiVersion: v1
+kind: Pod
+metadata:
+ annotations:
+ owner: admin
+ name: my-cronjob-job-pod
+ namespace: default
+spec:
+ containers:
+ - args:
+ - "/bin/sh"
+ image: nginx:1.14.2
+ imagePullPolicy: Always
+ name: nginx
+ ports:
+ - containerPort: '80'
+`
)
diff --git a/pkg/expansion/fixtures/load.go b/pkg/expansion/fixtures/load.go
new file mode 100644
index 00000000000..672986e2991
--- /dev/null
+++ b/pkg/expansion/fixtures/load.go
@@ -0,0 +1,166 @@
+package fixtures
+
+import (
+ "encoding/json"
+ "fmt"
+ "testing"
+
+ expansionunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/unversioned"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assign"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assignimage"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assignmeta"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "gopkg.in/yaml.v3"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+type TemplateData struct {
+ Name string
+ Apply []match.ApplyTo
+ Source string
+ GenGVK expansionunversioned.GeneratedGVK
+ EnforcementAction string
+}
+
+func NewTemplate(data *TemplateData) *expansionunversioned.ExpansionTemplate {
+ return &expansionunversioned.ExpansionTemplate{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ExpansionTemplate",
+ APIVersion: "expansiontemplates.gatekeeper.sh/v1beta1",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: data.Name,
+ },
+ Spec: expansionunversioned.ExpansionTemplateSpec{
+ ApplyTo: data.Apply,
+ TemplateSource: data.Source,
+ GeneratedGVK: data.GenGVK,
+ EnforcementAction: data.EnforcementAction,
+ },
+ }
+}
+
+func LoadFixture(f string, t *testing.T) *unstructured.Unstructured {
+ obj := make(map[string]interface{})
+ if err := yaml.Unmarshal([]byte(f), obj); err != nil {
+ t.Fatalf("error unmarshaling yaml for fixture: %s\n%s", err, f)
+ }
+
+ jsonBytes, err := json.Marshal(obj)
+ if err != nil {
+ t.Fatalf("error marshaling json for fixture: %s", err)
+ }
+
+ if err = json.Unmarshal(jsonBytes, &obj); err != nil {
+ t.Fatalf("error unmarshaling json for fixture: %s", err)
+ }
+
+ u := unstructured.Unstructured{}
+ u.SetUnstructuredContent(obj)
+ return &u
+}
+
+func LoadTemplate(f string, t *testing.T) *expansionunversioned.ExpansionTemplate {
+ u := LoadFixture(f, t)
+ te := &expansionunversioned.ExpansionTemplate{}
+ err := convertUnstructuredToTyped(u, te)
+ if err != nil {
+ t.Fatalf("error converting template expansion: %s", err)
+ }
+ return te
+}
+
+func LoadAssign(f string, t *testing.T) types.Mutator {
+ u := LoadFixture(f, t)
+ a := &mutationsunversioned.Assign{}
+ err := convertUnstructuredToTyped(u, a)
+ if err != nil {
+ t.Fatalf("error converting assign: %s", err)
+ }
+ mut, err := assign.MutatorForAssign(a)
+ if err != nil {
+ t.Fatalf("error creating assign: %s", err)
+ }
+ return mut
+}
+
+func LoadAssignImage(f string, t *testing.T) types.Mutator {
+ u := LoadFixture(f, t)
+ a := &mutationsunversioned.AssignImage{}
+ err := convertUnstructuredToTyped(u, a)
+ if err != nil {
+ t.Fatalf("error converting assignImage: %s", err)
+ }
+ mut, err := assignimage.MutatorForAssignImage(a)
+ if err != nil {
+ t.Fatalf("error creating assignimage: %s", err)
+ }
+ return mut
+}
+
+func LoadAssignMeta(f string, t *testing.T) types.Mutator {
+ u := LoadFixture(f, t)
+ a := &mutationsunversioned.AssignMetadata{}
+ err := convertUnstructuredToTyped(u, a)
+ if err != nil {
+ t.Fatalf("error converting assignmeta: %s", err)
+ }
+ mut, err := assignmeta.MutatorForAssignMetadata(a)
+ if err != nil {
+ t.Fatalf("error creating assignmeta: %s", err)
+ }
+ return mut
+}
+
+func convertUnstructuredToTyped(u *unstructured.Unstructured, obj interface{}) error {
+ if u == nil {
+ return fmt.Errorf("cannot convert nil unstructured to type")
+ }
+ err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.UnstructuredContent(), obj)
+ return err
+}
+
+func TestTemplate(name string, applyID, genID int) *expansionunversioned.ExpansionTemplate {
+ return NewTemplate(&TemplateData{
+ Name: name,
+ Apply: []match.ApplyTo{{
+ Groups: []string{fmt.Sprintf("group%d", applyID)},
+ Versions: []string{fmt.Sprintf("v%d", applyID)},
+ Kinds: []string{fmt.Sprintf("kind%d", applyID)},
+ }},
+ Source: "spec.template",
+ GenGVK: expansionunversioned.GeneratedGVK{
+ Group: fmt.Sprintf("group%d", genID),
+ Version: fmt.Sprintf("v%d", genID),
+ Kind: fmt.Sprintf("kind%d", genID),
+ },
+ })
+}
+
+func TempMultApply() *expansionunversioned.ExpansionTemplate {
+ return NewTemplate(&TemplateData{
+ Name: "t2",
+ Apply: []match.ApplyTo{
+ {
+ Groups: []string{"group1"},
+ Versions: []string{"v1"},
+ Kinds: []string{"kind1"},
+ },
+ {
+ Groups: []string{"group11"},
+ Versions: []string{"v11", "v22"},
+ Kinds: []string{"kind11"},
+ },
+ },
+ Source: "spec.template",
+ GenGVK: expansionunversioned.GeneratedGVK{
+ Group: "group2",
+ Version: "v2",
+ Kind: "kind2",
+ },
+ })
+}
diff --git a/pkg/expansion/system.go b/pkg/expansion/system.go
index 59818172fd9..5287b159726 100644
--- a/pkg/expansion/system.go
+++ b/pkg/expansion/system.go
@@ -2,22 +2,39 @@ package expansion
import (
"encoding/json"
+ "flag"
"fmt"
"strings"
"sync"
- expansionunversioned "github.com/open-policy-agent/gatekeeper/apis/expansion/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- mutationtypes "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ expansionunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ mutationtypes "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
)
+var (
+ ExpansionEnabled *bool
+ log = logf.Log.WithName("expansion").WithValues(logging.Process, "expansion")
+)
+
+// maxRecursionDepth specifies the maximum call depth for recursive expansion.
+// Theoretically, it should be impossible for a cycle to be created but this
+// measure is put in place as a safeguard.
+const maxRecursionDepth = 30
+
+func init() {
+ ExpansionEnabled = flag.Bool("enable-generator-resource-expansion", true, "(beta) Enable the expansion of generator resources")
+}
+
type System struct {
lock sync.RWMutex
- templates map[string]*expansionunversioned.ExpansionTemplate
mutationSystem *mutation.System
+ db templateDB
}
type Resultant struct {
@@ -26,20 +43,24 @@ type Resultant struct {
EnforcementAction string
}
-func keyForTemplate(template *expansionunversioned.ExpansionTemplate) string {
- return template.ObjectMeta.Name
+type TemplateID string
+
+type IDSet map[TemplateID]bool
+
+func keyForTemplate(template *expansionunversioned.ExpansionTemplate) TemplateID {
+ return TemplateID(template.ObjectMeta.Name)
}
func (s *System) UpsertTemplate(template *expansionunversioned.ExpansionTemplate) error {
s.lock.Lock()
defer s.lock.Unlock()
+ log.V(1).Info("upserting ExpansionTemplate", "template name", template.GetName())
- if err := validateTemplate(template); err != nil {
+ if err := ValidateTemplate(template); err != nil {
return err
}
- s.templates[keyForTemplate(template)] = template.DeepCopy()
- return nil
+ return s.db.upsert(template)
}
func (s *System) RemoveTemplate(template *expansionunversioned.ExpansionTemplate) error {
@@ -51,11 +72,15 @@ func (s *System) RemoveTemplate(template *expansionunversioned.ExpansionTemplate
return fmt.Errorf("cannot remove template with empty name")
}
- delete(s.templates, k)
+ s.db.remove(template)
return nil
}
-func validateTemplate(template *expansionunversioned.ExpansionTemplate) error {
+func (s *System) GetConflicts() IDSet {
+ return s.db.getConflicts()
+}
+
+func ValidateTemplate(template *expansionunversioned.ExpansionTemplate) error {
k := keyForTemplate(template)
if k == "" {
return fmt.Errorf("ExpansionTemplate has empty name field")
@@ -66,6 +91,18 @@ func validateTemplate(template *expansionunversioned.ExpansionTemplate) error {
if template.Spec.GeneratedGVK == (expansionunversioned.GeneratedGVK{}) {
return fmt.Errorf("ExpansionTemplate %s has empty generatedGVK field", k)
}
+ if len(template.Spec.ApplyTo) == 0 {
+ return fmt.Errorf("ExpansionTemplate %s must specify ApplyTo", k)
+ }
+ // Make sure template does not form a self-edge (i.e. a template configured
+ // to expand its own output)
+ genGVK := genGVKToSchemaGVK(template.Spec.GeneratedGVK)
+ for _, apply := range template.Spec.ApplyTo {
+ if apply.Matches(genGVK) {
+ return fmt.Errorf("ExpansionTemplate %s generates GVK %v, but also applies to that same GVK", k, genGVK)
+ }
+ }
+
return nil
}
@@ -89,34 +126,54 @@ func genGVKToSchemaGVK(gvk expansionunversioned.GeneratedGVK) schema.GroupVersio
}
}
-// templatesForGVK returns a slice of ExpansionTemplates that match a given gvk.
-func (s *System) templatesForGVK(gvk schema.GroupVersionKind) []*expansionunversioned.ExpansionTemplate {
+// Expand expands `base` into resultant resources, and applies any applicable
+// mutators. If no ExpansionTemplates match `base`, an empty slice
+// will be returned. If `s.mutationSystem` is nil, no mutations will be applied.
+func (s *System) Expand(base *mutationtypes.Mutable) ([]*Resultant, error) {
s.lock.RLock()
defer s.lock.RUnlock()
- var templates []*expansionunversioned.ExpansionTemplate
- for _, t := range s.templates {
- for _, apply := range t.Spec.ApplyTo {
- if apply.Matches(gvk) {
- templates = append(templates, t)
- }
+ var res []*Resultant
+ if err := s.expandRecursive(base, &res, 0); err != nil {
+ return nil, err
+ }
+ return res, nil
+}
+
+func (s *System) expandRecursive(base *mutationtypes.Mutable, resultants *[]*Resultant, depth int) error {
+ if depth >= maxRecursionDepth {
+ return fmt.Errorf("maximum recursion depth of %d reached", maxRecursionDepth)
+ }
+
+ res, err := s.expand(base)
+ if err != nil {
+ return err
+ }
+
+ for _, r := range res {
+ mut := &mutationtypes.Mutable{
+ Object: r.Obj,
+ Namespace: base.Namespace,
+ Username: base.Username,
+ Source: base.Source,
+ }
+ if err := s.expandRecursive(mut, resultants, depth+1); err != nil {
+ return err
}
}
- return templates
+ *resultants = append(*resultants, res...)
+ return nil
}
-// Expand expands `base` into resultant resources, and applies any applicable
-// mutators. If no ExpansionTemplates match `base`, an empty slice
-// will be returned. If `s.mutationSystem` is nil, no mutations will be applied.
-func (s *System) Expand(base *mutationtypes.Mutable) ([]*Resultant, error) {
+func (s *System) expand(base *mutationtypes.Mutable) ([]*Resultant, error) {
gvk := base.Object.GroupVersionKind()
if gvk == (schema.GroupVersionKind{}) {
return nil, fmt.Errorf("cannot expand resource %s with empty GVK", base.Object.GetName())
}
var resultants []*Resultant
- templates := s.templatesForGVK(gvk)
+ templates := s.db.templatesForGVK(gvk)
for _, te := range templates {
res, err := expandResource(base.Object, base.Namespace, te)
@@ -143,7 +200,7 @@ func (s *System) Expand(base *mutationtypes.Mutable) ([]*Resultant, error) {
}
_, err := s.mutationSystem.Mutate(mutable)
if err != nil {
- return nil, fmt.Errorf("failed to mutate resultant resource %s: %s", res.Obj.GetName(), err)
+ return nil, fmt.Errorf("failed to mutate resultant resource %s: %w", res.Obj.GetName(), err)
}
}
@@ -151,10 +208,6 @@ func (s *System) Expand(base *mutationtypes.Mutable) ([]*Resultant, error) {
}
func expandResource(obj *unstructured.Unstructured, ns *corev1.Namespace, template *expansionunversioned.ExpansionTemplate) (*unstructured.Unstructured, error) {
- if ns == nil {
- return nil, fmt.Errorf("cannot expand resource with nil namespace")
- }
-
srcPath := template.Spec.TemplateSource
if srcPath == "" {
return nil, fmt.Errorf("cannot expand resource using a template with no source")
@@ -166,24 +219,52 @@ func expandResource(obj *unstructured.Unstructured, ns *corev1.Namespace, templa
src, ok, err := unstructured.NestedMap(obj.Object, sourcePath(srcPath)...)
if err != nil {
- return nil, fmt.Errorf("could not extract source field from unstructured: %s", err)
+ return nil, fmt.Errorf("could not extract source field from unstructured: %w", err)
}
if !ok {
- return nil, fmt.Errorf("could not find source field %q in Obj", srcPath)
+ return nil, fmt.Errorf("could not find source field %q in resource %s", srcPath, obj.GetName())
}
resource := &unstructured.Unstructured{}
resource.SetUnstructuredContent(src)
resource.SetGroupVersionKind(resultantGVK)
- resource.SetNamespace(ns.Name)
+ if ns != nil {
+ resource.SetNamespace(ns.Name)
+ } else {
+ nsFromUn, found, err := unstructured.NestedString(obj.Object, "metadata", "namespace")
+ if err != nil {
+ return nil, fmt.Errorf("could not extract namespace field %q in parent resource %s", srcPath, obj.GetName())
+ }
+
+ if found {
+ resource.SetNamespace(nsFromUn)
+ }
+ // if not found, then the resulting resource may be cluster scoped.
+ }
+
+ resource.SetName(mockNameForResource(obj, resultantGVK))
return resource, nil
}
+// mockNameForResource returns a mock name for a resultant resource created
+// from expanding `gen`. The name will be of the form:
+// "-". For example, a deployment named
+// `nginx-deployment` will produce a resultant named `nginx-deployment-pod`.
+func mockNameForResource(gen *unstructured.Unstructured, gvk schema.GroupVersionKind) string {
+ name := gen.GetName()
+ if gvk.Kind != "" {
+ name += "-"
+ }
+ name += gvk.Kind
+
+ return strings.ToLower(name)
+}
+
func NewSystem(mutationSystem *mutation.System) *System {
return &System{
lock: sync.RWMutex{},
- templates: map[string]*expansionunversioned.ExpansionTemplate{},
mutationSystem: mutationSystem,
+ db: newDB(),
}
}
diff --git a/pkg/expansion/system_test.go b/pkg/expansion/system_test.go
index 92696217f04..9eaf394b6e6 100644
--- a/pkg/expansion/system_test.go
+++ b/pkg/expansion/system_test.go
@@ -1,588 +1,21 @@
package expansion
import (
- "encoding/json"
- "fmt"
"sort"
+ "strings"
"testing"
"github.com/google/go-cmp/cmp"
- expansionunversioned "github.com/open-policy-agent/gatekeeper/apis/expansion/unversioned"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion/fixtures"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/assign"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/assignmeta"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "gopkg.in/yaml.v3"
+ expansionunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion/fixtures"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
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"
)
-type templateData struct {
- name string
- apply []match.ApplyTo
- source string
- generatedGVK expansionunversioned.GeneratedGVK
- enforcementAction string
-}
-
-func newTemplate(data *templateData) *expansionunversioned.ExpansionTemplate {
- return &expansionunversioned.ExpansionTemplate{
- TypeMeta: metav1.TypeMeta{
- Kind: "ExpansionTemplate",
- APIVersion: "expansiontemplates.gatekeeper.sh/v1beta1",
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: data.name,
- },
- Spec: expansionunversioned.ExpansionTemplateSpec{
- ApplyTo: data.apply,
- TemplateSource: data.source,
- GeneratedGVK: data.generatedGVK,
- EnforcementAction: data.enforcementAction,
- },
- }
-}
-
-func TestUpsertRemoveTemplate(t *testing.T) {
- tests := []struct {
- name string
- add []*expansionunversioned.ExpansionTemplate
- remove []*expansionunversioned.ExpansionTemplate
- check []*expansionunversioned.ExpansionTemplate
- wantAddErr bool
- wantRemoveErr bool
- }{
- {
- name: "adding 2 valid templates",
- add: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- newTemplate(&templateData{
- name: "test2",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Foo"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Bar",
- },
- }),
- },
- check: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- newTemplate(&templateData{
- name: "test2",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Foo"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Bar",
- },
- }),
- },
- wantAddErr: false,
- },
- {
- name: "adding template with empty name returns error",
- add: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- },
- check: []*expansionunversioned.ExpansionTemplate{},
- wantAddErr: true,
- },
- {
- name: "adding template with empty source returns error",
- add: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "hello",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- },
- check: []*expansionunversioned.ExpansionTemplate{},
- wantAddErr: true,
- },
- {
- name: "adding template with empty GVK returns error",
- add: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "hello",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{},
- }),
- },
- check: []*expansionunversioned.ExpansionTemplate{},
- wantAddErr: true,
- },
- {
- name: "removing a template with empty name returns error",
- add: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- },
- remove: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- },
- check: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- },
- wantAddErr: false,
- wantRemoveErr: true,
- },
- {
- name: "adding 2 templates, removing 1",
- add: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- newTemplate(&templateData{
- name: "test2",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- },
- remove: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test2",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- },
- check: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- },
- wantAddErr: false,
- wantRemoveErr: false,
- },
- {
- name: "updating an existing template",
- add: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"Baz"},
- Kinds: []string{"Foo"},
- Versions: []string{"v9000"},
- }},
- source: "spec.something",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v9000",
- Kind: "Bar",
- },
- }),
- },
- check: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"Baz"},
- Kinds: []string{"Foo"},
- Versions: []string{"v9000"},
- }},
- source: "spec.something",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v9000",
- Kind: "Bar",
- },
- }),
- },
- wantAddErr: false,
- },
- }
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- ec := NewSystem(mutation.NewSystem(mutation.SystemOpts{}))
-
- for _, templ := range tc.add {
- err := ec.UpsertTemplate(templ)
- if tc.wantAddErr && err == nil {
- t.Errorf("expected error, got nil")
- } else if !tc.wantAddErr && err != nil {
- t.Errorf("failed to add template: %s", err)
- }
- }
-
- for _, templ := range tc.remove {
- err := ec.RemoveTemplate(templ)
- if tc.wantRemoveErr && err == nil {
- t.Errorf("expected error, got nil")
- } else if !tc.wantRemoveErr && err != nil {
- t.Errorf("failed to remove template: %s", err)
- }
- }
-
- if len(ec.templates) != len(tc.check) {
- t.Errorf("incorrect number of templates in cache, got %d, want %d", len(ec.templates), len(tc.check))
- }
- for _, templ := range tc.check {
- k := templ.ObjectMeta.Name
- got, exists := ec.templates[k]
- if !exists {
- t.Errorf("could not find template with key %q", k)
- }
- if cmp.Diff(got, templ) != "" {
- t.Errorf("got value: \n%s\n, wanted: \n%s\n\n diff: \n%s", prettyResource(got), prettyResource(templ), cmp.Diff(got, templ))
- }
- }
- })
- }
-}
-
-func TestTemplatesForGVK(t *testing.T) {
- tests := []struct {
- name string
- gvk expansionunversioned.GeneratedGVK
- addTemplates []*expansionunversioned.ExpansionTemplate
- want []*expansionunversioned.ExpansionTemplate
- }{
- {
- name: "adding 2 templates, 1 match",
- gvk: expansionunversioned.GeneratedGVK{
- Group: "apps",
- Version: "v1",
- Kind: "Deployment",
- },
- addTemplates: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- newTemplate(&templateData{
- name: "test2",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Foo"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Bar",
- },
- }),
- },
- want: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- },
- },
- {
- name: "adding 2 templates, 2 matches",
- gvk: expansionunversioned.GeneratedGVK{
- Group: "apps",
- Version: "v1",
- Kind: "Deployment",
- },
- addTemplates: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- newTemplate(&templateData{
- name: "test2",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Bar",
- },
- }),
- },
- want: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- newTemplate(&templateData{
- name: "test2",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Bar",
- },
- }),
- },
- },
- {
- name: "adding 1 templates, 0 match",
- addTemplates: []*expansionunversioned.ExpansionTemplate{
- newTemplate(&templateData{
- name: "test1",
- apply: []match.ApplyTo{{
- Groups: []string{"apps"},
- Kinds: []string{"Deployment"},
- Versions: []string{"v1"},
- }},
- source: "spec.template",
- generatedGVK: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- }),
- },
- want: []*expansionunversioned.ExpansionTemplate{},
- gvk: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v9000",
- Kind: "CronJob",
- },
- },
- {
- name: "no templates, no matches",
- addTemplates: []*expansionunversioned.ExpansionTemplate{},
- want: []*expansionunversioned.ExpansionTemplate{},
- gvk: expansionunversioned.GeneratedGVK{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- },
- },
- }
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- ec := NewSystem(mutation.NewSystem(mutation.SystemOpts{}))
- for _, te := range tc.addTemplates {
- if err := ec.UpsertTemplate(te); err != nil {
- t.Fatalf("error upserting template: %s", err)
- }
- }
-
- got := ec.templatesForGVK(genGVKToSchemaGVK(tc.gvk))
- sortTemplates(got)
- wantSorted := make([]*expansionunversioned.ExpansionTemplate, len(tc.want))
- copy(wantSorted, tc.want)
- sortTemplates(wantSorted)
-
- if len(got) != len(wantSorted) {
- t.Errorf("want %d templates, got %d", len(wantSorted), len(got))
- }
- for i := 0; i < len(got); i++ {
- diff := cmp.Diff(got[i], wantSorted[i])
- if diff != "" {
- t.Errorf("got = \n%s\n, want = \n%s\n\n diff \n%s", prettyResource(got[i]), prettyResource(wantSorted[i]), diff)
- }
- }
- })
- }
-}
-
func TestExpand(t *testing.T) {
tests := []struct {
name string
@@ -595,179 +28,224 @@ func TestExpand(t *testing.T) {
}{
{
name: "generator with no templates or mutators",
- generator: loadFixture(fixtures.GeneratorCat, t),
+ generator: fixtures.LoadFixture(fixtures.GeneratorCat, t),
},
{
name: "generator with no gvk returns error",
- generator: loadFixture(fixtures.DeploymentNoGVK, t),
+ generator: fixtures.LoadFixture(fixtures.DeploymentNoGVK, t),
expectErr: true,
},
{
name: "generator with non-matching template",
- generator: loadFixture(fixtures.GeneratorCat, t),
+ generator: fixtures.LoadFixture(fixtures.GeneratorCat, t),
templates: []*expansionunversioned.ExpansionTemplate{
- loadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
},
want: []*Resultant{},
},
{
name: "no mutators basic deployment expands pod",
- generator: loadFixture(fixtures.DeploymentNginx, t),
+ generator: fixtures.LoadFixture(fixtures.DeploymentNginx, t),
ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
mutators: []types.Mutator{},
templates: []*expansionunversioned.ExpansionTemplate{
- loadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
},
want: []*Resultant{
- {Obj: loadFixture(fixtures.PodNoMutate, t), EnforcementAction: "", TemplateName: "expand-deployments"},
+ {Obj: fixtures.LoadFixture(fixtures.PodNoMutate, t), EnforcementAction: "", TemplateName: "expand-deployments"},
},
},
{
name: "deployment expands pod with enforcement action override",
- generator: loadFixture(fixtures.DeploymentNginx, t),
+ generator: fixtures.LoadFixture(fixtures.DeploymentNginx, t),
ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
mutators: []types.Mutator{},
templates: []*expansionunversioned.ExpansionTemplate{
- loadTemplate(fixtures.TempExpDeploymentExpandsPodsEnforceDryrun, t),
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPodsEnforceDryrun, t),
},
want: []*Resultant{
- {Obj: loadFixture(fixtures.PodNoMutate, t), EnforcementAction: "dryrun", TemplateName: "expand-deployments"},
+ {Obj: fixtures.LoadFixture(fixtures.PodNoMutate, t), EnforcementAction: "dryrun", TemplateName: "expand-deployments"},
},
},
{
name: "1 mutator basic deployment expands pod",
- generator: loadFixture(fixtures.DeploymentNginx, t),
+ generator: fixtures.LoadFixture(fixtures.DeploymentNginx, t),
ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
mutators: []types.Mutator{
- loadAssign(fixtures.AssignPullImage, t),
+ fixtures.LoadAssign(fixtures.AssignPullImage, t),
},
templates: []*expansionunversioned.ExpansionTemplate{
- loadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
},
want: []*Resultant{
- {Obj: loadFixture(fixtures.PodImagePullMutate, t), EnforcementAction: "", TemplateName: "expand-deployments"},
+ {Obj: fixtures.LoadFixture(fixtures.PodImagePullMutate, t), EnforcementAction: "", TemplateName: "expand-deployments"},
},
},
{
- name: "expand with nil namespace returns error",
- generator: loadFixture(fixtures.DeploymentNginx, t),
+ name: "expand with nil namespace returns error bc the namespace selector errs out",
+ generator: fixtures.LoadFixture(fixtures.DeploymentNginxWithNs, t),
ns: nil,
mutators: []types.Mutator{
- loadAssign(fixtures.AssignPullImage, t),
+ fixtures.LoadAssign(fixtures.AssignPullImageWithNsSelector, t),
},
templates: []*expansionunversioned.ExpansionTemplate{
- loadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
},
expectErr: true,
},
+ {
+ name: "expand with nil namespace does not error out if no namespace selectors",
+ generator: fixtures.LoadFixture(fixtures.DeploymentNginxWithNs, t),
+ ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "not-default"}},
+ mutators: []types.Mutator{
+ fixtures.LoadAssign(fixtures.AssignPullImage, t),
+ },
+ templates: []*expansionunversioned.ExpansionTemplate{
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
+ },
+ expectErr: false,
+ want: []*Resultant{
+ {Obj: fixtures.LoadFixture(fixtures.PodImagePullMutateWithNs, t), EnforcementAction: "", TemplateName: "expand-deployments"},
+ },
+ },
{
name: "1 mutator source All deployment expands pod and mutates",
- generator: loadFixture(fixtures.DeploymentNginx, t),
+ generator: fixtures.LoadFixture(fixtures.DeploymentNginx, t),
ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
mutators: []types.Mutator{
- loadAssign(fixtures.AssignPullImageSourceAll, t),
+ fixtures.LoadAssign(fixtures.AssignPullImageSourceAll, t),
},
templates: []*expansionunversioned.ExpansionTemplate{
- loadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
},
want: []*Resultant{
- {Obj: loadFixture(fixtures.PodImagePullMutate, t), EnforcementAction: "", TemplateName: "expand-deployments"},
+ {Obj: fixtures.LoadFixture(fixtures.PodImagePullMutate, t), EnforcementAction: "", TemplateName: "expand-deployments"},
},
},
{
name: "1 mutator source empty deployment expands pod and mutates",
- generator: loadFixture(fixtures.DeploymentNginx, t),
+ generator: fixtures.LoadFixture(fixtures.DeploymentNginx, t),
ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
mutators: []types.Mutator{
- loadAssign(fixtures.AssignPullImageSourceEmpty, t),
+ fixtures.LoadAssign(fixtures.AssignPullImageSourceEmpty, t),
},
templates: []*expansionunversioned.ExpansionTemplate{
- loadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
},
want: []*Resultant{
- {Obj: loadFixture(fixtures.PodImagePullMutate, t), EnforcementAction: "", TemplateName: "expand-deployments"},
+ {Obj: fixtures.LoadFixture(fixtures.PodImagePullMutate, t), EnforcementAction: "", TemplateName: "expand-deployments"},
},
},
{
name: "1 mutator source Original deployment expands pod but does not mutate",
- generator: loadFixture(fixtures.DeploymentNginx, t),
+ generator: fixtures.LoadFixture(fixtures.DeploymentNginx, t),
ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
mutators: []types.Mutator{
- loadAssign(fixtures.AssignHostnameSourceOriginal, t),
+ fixtures.LoadAssign(fixtures.AssignHostnameSourceOriginal, t),
},
templates: []*expansionunversioned.ExpansionTemplate{
- loadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
},
want: []*Resultant{
- {Obj: loadFixture(fixtures.PodNoMutate, t), EnforcementAction: "", TemplateName: "expand-deployments"},
+ {Obj: fixtures.LoadFixture(fixtures.PodNoMutate, t), EnforcementAction: "", TemplateName: "expand-deployments"},
},
},
{
name: "2 mutators, only 1 match, basic deployment expands pod",
- generator: loadFixture(fixtures.DeploymentNginx, t),
+ generator: fixtures.LoadFixture(fixtures.DeploymentNginx, t),
ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
mutators: []types.Mutator{
- loadAssign(fixtures.AssignPullImage, t),
- loadAssignMeta(fixtures.AssignMetaAnnotateKitten, t), // should not match
+ fixtures.LoadAssign(fixtures.AssignPullImage, t),
+ fixtures.LoadAssignMeta(fixtures.AssignMetaAnnotateKitten, t), // should not match
},
templates: []*expansionunversioned.ExpansionTemplate{
- loadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
},
want: []*Resultant{
- {Obj: loadFixture(fixtures.PodImagePullMutate, t), EnforcementAction: "", TemplateName: "expand-deployments"},
+ {Obj: fixtures.LoadFixture(fixtures.PodImagePullMutate, t), EnforcementAction: "", TemplateName: "expand-deployments"},
},
},
{
name: "2 mutators, 2 matches, basic deployment expands pod",
- generator: loadFixture(fixtures.DeploymentNginx, t),
+ generator: fixtures.LoadFixture(fixtures.DeploymentNginx, t),
ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
mutators: []types.Mutator{
- loadAssign(fixtures.AssignPullImage, t),
- loadAssignMeta(fixtures.AssignMetaAnnotatePod, t),
+ fixtures.LoadAssign(fixtures.AssignPullImage, t),
+ fixtures.LoadAssignMeta(fixtures.AssignMetaAnnotatePod, t),
},
templates: []*expansionunversioned.ExpansionTemplate{
- loadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
},
want: []*Resultant{
- {Obj: loadFixture(fixtures.PodImagePullMutateAnnotated, t), EnforcementAction: "", TemplateName: "expand-deployments"},
+ {Obj: fixtures.LoadFixture(fixtures.PodImagePullMutateAnnotated, t), EnforcementAction: "", TemplateName: "expand-deployments"},
},
},
{
name: "custom CR with 2 different resultant kinds, with mutators",
- generator: loadFixture(fixtures.GeneratorCat, t),
+ generator: fixtures.LoadFixture(fixtures.GeneratorCat, t),
ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
mutators: []types.Mutator{
- loadAssign(fixtures.AssignKittenAge, t),
- loadAssignMeta(fixtures.AssignMetaAnnotatePurr, t),
- loadAssignMeta(fixtures.AssignMetaAnnotateKitten, t),
+ fixtures.LoadAssign(fixtures.AssignKittenAge, t),
+ fixtures.LoadAssignMeta(fixtures.AssignMetaAnnotatePurr, t),
+ fixtures.LoadAssignMeta(fixtures.AssignMetaAnnotateKitten, t),
},
templates: []*expansionunversioned.ExpansionTemplate{
- loadTemplate(fixtures.TemplateCatExpandsKitten, t),
- loadTemplate(fixtures.TemplateCatExpandsPurr, t),
+ fixtures.LoadTemplate(fixtures.TemplateCatExpandsKitten, t),
+ fixtures.LoadTemplate(fixtures.TemplateCatExpandsPurr, t),
},
want: []*Resultant{
- {Obj: loadFixture(fixtures.ResultantKitten, t), EnforcementAction: "dryrun", TemplateName: "expand-cats-kitten"},
- {Obj: loadFixture(fixtures.ResultantPurr, t), EnforcementAction: "warn", TemplateName: "expand-cats-purr"},
+ {Obj: fixtures.LoadFixture(fixtures.ResultantKitten, t), EnforcementAction: "dryrun", TemplateName: "expand-cats-kitten"},
+ {Obj: fixtures.LoadFixture(fixtures.ResultantPurr, t), EnforcementAction: "warn", TemplateName: "expand-cats-purr"},
},
},
{
name: "custom CR with 2 different resultant kinds, with mutators and non-matching configs",
- generator: loadFixture(fixtures.GeneratorCat, t),
+ generator: fixtures.LoadFixture(fixtures.GeneratorCat, t),
ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
mutators: []types.Mutator{
- loadAssign(fixtures.AssignKittenAge, t),
- loadAssignMeta(fixtures.AssignMetaAnnotatePurr, t),
- loadAssignMeta(fixtures.AssignMetaAnnotateKitten, t),
- loadAssign(fixtures.AssignPullImage, t), // should not match
+ fixtures.LoadAssign(fixtures.AssignKittenAge, t),
+ fixtures.LoadAssignMeta(fixtures.AssignMetaAnnotatePurr, t),
+ fixtures.LoadAssignMeta(fixtures.AssignMetaAnnotateKitten, t),
+ fixtures.LoadAssign(fixtures.AssignPullImage, t), // should not match
},
templates: []*expansionunversioned.ExpansionTemplate{
- loadTemplate(fixtures.TemplateCatExpandsKitten, t),
- loadTemplate(fixtures.TemplateCatExpandsPurr, t),
- loadTemplate(fixtures.TempExpDeploymentExpandsPods, t), // should not match
+ fixtures.LoadTemplate(fixtures.TemplateCatExpandsKitten, t),
+ fixtures.LoadTemplate(fixtures.TemplateCatExpandsPurr, t),
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPods, t), // should not match
},
want: []*Resultant{
- {Obj: loadFixture(fixtures.ResultantKitten, t), EnforcementAction: "dryrun", TemplateName: "expand-cats-kitten"},
- {Obj: loadFixture(fixtures.ResultantPurr, t), EnforcementAction: "warn", TemplateName: "expand-cats-purr"},
+ {Obj: fixtures.LoadFixture(fixtures.ResultantKitten, t), EnforcementAction: "dryrun", TemplateName: "expand-cats-kitten"},
+ {Obj: fixtures.LoadFixture(fixtures.ResultantPurr, t), EnforcementAction: "warn", TemplateName: "expand-cats-purr"},
+ },
+ },
+ {
+ name: "1 mutator deployment expands pod with AssignImage",
+ generator: fixtures.LoadFixture(fixtures.DeploymentNginx, t),
+ ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
+ mutators: []types.Mutator{
+ fixtures.LoadAssignImage(fixtures.AssignImage, t),
+ },
+ templates: []*expansionunversioned.ExpansionTemplate{
+ fixtures.LoadTemplate(fixtures.TempExpDeploymentExpandsPods, t),
+ },
+ want: []*Resultant{
+ {Obj: fixtures.LoadFixture(fixtures.PodMutateImage, t), EnforcementAction: "", TemplateName: "expand-deployments"},
+ },
+ },
+ {
+ name: "recursive expansion with mutators",
+ generator: fixtures.LoadFixture(fixtures.GeneratorCronJob, t),
+ ns: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
+ mutators: []types.Mutator{
+ fixtures.LoadAssignMeta(fixtures.AssignMetaAnnotatePod, t),
+ },
+ templates: []*expansionunversioned.ExpansionTemplate{
+ fixtures.LoadTemplate(fixtures.TempExpCronJob, t),
+ fixtures.LoadTemplate(fixtures.TempExpJob, t),
+ },
+ want: []*Resultant{
+ {Obj: fixtures.LoadFixture(fixtures.ResultantJob, t), EnforcementAction: "", TemplateName: "expand-cronjobs"},
+ {Obj: fixtures.LoadFixture(fixtures.ResultantRecursivePod, t), EnforcementAction: "", TemplateName: "expand-jobs"},
},
},
}
@@ -811,8 +289,8 @@ func compareResults(got []*Resultant, want []*Resultant, t *testing.T) {
return
}
- sortReusultants(got)
- sortReusultants(want)
+ sortResultants(got)
+ sortResultants(want)
for i := 0; i < len(got); i++ {
if diff := cmp.Diff(got[i], want[i]); diff != "" {
@@ -821,7 +299,7 @@ func compareResults(got []*Resultant, want []*Resultant, t *testing.T) {
}
}
-func sortReusultants(objs []*Resultant) {
+func sortResultants(objs []*Resultant) {
sortKey := func(r *Resultant) string {
return r.Obj.GetName() + r.Obj.GetAPIVersion()
}
@@ -830,74 +308,118 @@ func sortReusultants(objs []*Resultant) {
})
}
-func loadFixture(f string, t *testing.T) *unstructured.Unstructured {
- obj := make(map[string]interface{})
- if err := yaml.Unmarshal([]byte(f), obj); err != nil {
- t.Fatalf("error unmarshaling yaml for fixture: %s", err)
- }
-
- jsonBytes, err := json.Marshal(obj)
- if err != nil {
- t.Fatalf("error marshaling json for fixture: %s", err)
- }
-
- if err = json.Unmarshal(jsonBytes, &obj); err != nil {
- t.Fatalf("error unmarshaling json for fixture: %s", err)
+func TestValidateTemplate(t *testing.T) {
+ tests := []struct {
+ name string
+ errFn func(e error, t *testing.T)
+ temp expansionunversioned.ExpansionTemplate
+ }{
+ {
+ name: "valid expansion template",
+ errFn: noError,
+ temp: *fixtures.TestTemplate("foo", 1, 2),
+ },
+ {
+ name: "missing name",
+ temp: *fixtures.NewTemplate(&fixtures.TemplateData{
+ Apply: []match.ApplyTo{{
+ Groups: []string{"apps"},
+ Kinds: []string{"Deployment"},
+ Versions: []string{"v1"},
+ }},
+ Source: "spec.template",
+ GenGVK: expansionunversioned.GeneratedGVK{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ },
+ }),
+ errFn: matchErr("empty name"),
+ },
+ {
+ name: "missing source",
+ temp: *fixtures.NewTemplate(&fixtures.TemplateData{
+ Name: "test1",
+ Apply: []match.ApplyTo{{
+ Groups: []string{"apps"},
+ Kinds: []string{"Deployment"},
+ Versions: []string{"v1"},
+ }},
+ GenGVK: expansionunversioned.GeneratedGVK{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ },
+ }),
+ errFn: matchErr("empty source"),
+ },
+ {
+ name: "missing generated GVK",
+ temp: *fixtures.NewTemplate(&fixtures.TemplateData{
+ Name: "test1",
+ Apply: []match.ApplyTo{{
+ Groups: []string{"apps"},
+ Kinds: []string{"Deployment"},
+ Versions: []string{"v1"},
+ }},
+ Source: "spec.template",
+ }),
+ errFn: matchErr("empty generatedGVK"),
+ },
+ {
+ name: "missing applyTo",
+ temp: *fixtures.NewTemplate(&fixtures.TemplateData{
+ Name: "test1",
+ Source: "spec.template",
+ GenGVK: expansionunversioned.GeneratedGVK{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ },
+ }),
+ errFn: matchErr("specify ApplyTo"),
+ },
+ {
+ name: "loop",
+ temp: *fixtures.NewTemplate(&fixtures.TemplateData{
+ Name: "test1",
+ Apply: []match.ApplyTo{{
+ Groups: []string{""},
+ Kinds: []string{"Pod"},
+ Versions: []string{"v1"},
+ }},
+ Source: "spec.template",
+ GenGVK: expansionunversioned.GeneratedGVK{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ },
+ }),
+ errFn: matchErr("also applies to that same GVK"),
+ },
}
-
- u := unstructured.Unstructured{}
- u.SetUnstructuredContent(obj)
- return &u
-}
-
-func loadTemplate(f string, t *testing.T) *expansionunversioned.ExpansionTemplate {
- u := loadFixture(f, t)
- te := &expansionunversioned.ExpansionTemplate{}
- err := convertUnstructuredToTyped(u, te)
- if err != nil {
- t.Fatalf("error converting template expansion: %s", err)
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ tc.errFn(ValidateTemplate(&tc.temp), t)
+ })
}
- return te
}
-func loadAssign(f string, t *testing.T) types.Mutator {
- u := loadFixture(f, t)
- a := &mutationsunversioned.Assign{}
- err := convertUnstructuredToTyped(u, a)
- if err != nil {
- t.Fatalf("error converting assign: %s", err)
- }
- mut, err := assign.MutatorForAssign(a)
- if err != nil {
- t.Fatalf("error creating assign: %s", err)
+func noError(e error, t *testing.T) {
+ if e != nil {
+ t.Errorf("did want want error, but got %s", e)
}
- return mut
}
-func loadAssignMeta(f string, t *testing.T) types.Mutator {
- u := loadFixture(f, t)
- a := &mutationsunversioned.AssignMetadata{}
- err := convertUnstructuredToTyped(u, a)
- if err != nil {
- t.Fatalf("error converting assignmeta: %s", err)
- }
- mut, err := assignmeta.MutatorForAssignMetadata(a)
- if err != nil {
- t.Fatalf("error creating assignmeta: %s", err)
- }
- return mut
-}
+func matchErr(substr string) func(error, *testing.T) {
+ return func(err error, t *testing.T) {
+ if err == nil {
+ t.Error("expected err but got nil")
+ return
+ }
-func convertUnstructuredToTyped(u *unstructured.Unstructured, obj interface{}) error {
- if u == nil {
- return fmt.Errorf("cannot convert nil unstructured to type")
+ if !strings.Contains(err.Error(), substr) {
+ t.Errorf("expected error to contain %q, but got %q", substr, err.Error())
+ }
}
- err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.UnstructuredContent(), obj)
- return err
-}
-
-func sortTemplates(templates []*expansionunversioned.ExpansionTemplate) {
- sort.SliceStable(templates, func(x, y int) bool {
- return templates[x].Name < templates[y].Name
- })
}
diff --git a/pkg/fakes/fakecfdataclient.go b/pkg/fakes/fakecfdataclient.go
new file mode 100644
index 00000000000..ba81b4fe255
--- /dev/null
+++ b/pkg/fakes/fakecfdataclient.go
@@ -0,0 +1,146 @@
+/*
+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 fakes
+
+import (
+ "context"
+ "fmt"
+ gosync "sync"
+
+ constraintTypes "github.com/open-policy-agent/frameworks/constraint/pkg/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+type CfDataKey struct {
+ Gvk schema.GroupVersionKind
+ Key string
+}
+
+// FakeCfClient is an CfDataClient for testing.
+type FakeCfClient struct {
+ mu gosync.Mutex
+ data map[CfDataKey]interface{}
+ needsToError bool
+}
+
+// KeyFor returns a CfDataKey for the provided resource.
+// Returns error if the resource is not a runtime.Object w/ metadata.
+func KeyFor(obj interface{}) (CfDataKey, error) {
+ o, ok := obj.(client.Object)
+ if !ok {
+ return CfDataKey{}, fmt.Errorf("expected runtime.Object, got: %T", obj)
+ }
+ gvk := o.GetObjectKind().GroupVersionKind()
+ ns := o.GetNamespace()
+ if ns == "" {
+ return CfDataKey{Gvk: gvk, Key: o.GetName()}, nil
+ }
+
+ return CfDataKey{Gvk: gvk, Key: fmt.Sprintf("%s/%s", ns, o.GetName())}, nil
+}
+
+func (f *FakeCfClient) AddData(ctx context.Context, data interface{}) (*constraintTypes.Responses, error) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+
+ if f.needsToError {
+ return nil, fmt.Errorf("test error")
+ }
+
+ key, err := KeyFor(data)
+ if err != nil {
+ return nil, err
+ }
+
+ if f.data == nil {
+ f.data = make(map[CfDataKey]interface{})
+ }
+
+ f.data[key] = data
+ return &constraintTypes.Responses{}, nil
+}
+
+func (f *FakeCfClient) RemoveData(ctx context.Context, data interface{}) (*constraintTypes.Responses, error) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+
+ if f.needsToError {
+ return nil, fmt.Errorf("test error")
+ }
+
+ if target.IsWipeData(data) {
+ f.data = make(map[CfDataKey]interface{})
+ return &constraintTypes.Responses{}, nil
+ }
+
+ key, err := KeyFor(data)
+ if err != nil {
+ return nil, err
+ }
+
+ delete(f.data, key)
+ return &constraintTypes.Responses{}, nil
+}
+
+// GetData returns data for a CfDataKey. It assumes that the
+// key is present in the FakeCfClient. Also the data returned is not copied
+// and it's meant only for assertions not modifications.
+func (f *FakeCfClient) GetData(key CfDataKey) interface{} {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+
+ return f.data[key]
+}
+
+// Contains returns true if all expected resources are in the cache.
+func (f *FakeCfClient) Contains(expected map[CfDataKey]interface{}) bool {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+
+ for k := range expected {
+ if _, ok := f.data[k]; !ok {
+ return false
+ }
+ }
+ return true
+}
+
+// HasGVK returns true if the cache has any data of the requested kind.
+func (f *FakeCfClient) HasGVK(gvk schema.GroupVersionKind) bool {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+
+ for k := range f.data {
+ if k.Gvk == gvk {
+ return true
+ }
+ }
+ return false
+}
+
+// Len returns the number of items in the cache.
+func (f *FakeCfClient) Len() int {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ return len(f.data)
+}
+
+// SetErroring will error out on AddObject or RemoveObject.
+func (f *FakeCfClient) SetErroring(enabled bool) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ f.needsToError = enabled
+}
diff --git a/pkg/fakes/fixtures.go b/pkg/fakes/fixtures.go
new file mode 100644
index 00000000000..29f5cff9ed1
--- /dev/null
+++ b/pkg/fakes/fixtures.go
@@ -0,0 +1,63 @@
+package fakes
+
+import (
+ "github.com/open-policy-agent/frameworks/constraint/pkg/apis/constraints"
+ templatesv1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+func DenyAllRegoTemplate() *templates.ConstraintTemplate {
+ return &templates.ConstraintTemplate{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: templatesv1beta1.SchemeGroupVersion.String(),
+ Kind: "ConstraintTemplate",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "denyall",
+ },
+ Spec: templates.ConstraintTemplateSpec{
+ CRD: templates.CRD{
+ Spec: templates.CRDSpec{
+ Names: templates.Names{
+ Kind: "denyall",
+ },
+ },
+ },
+ Targets: []templates.Target{{
+ Target: target.Name,
+ Code: []templates.Code{{
+ Engine: "Rego",
+ Source: &templates.Anything{
+ Value: map[string]interface{}{"rego": `
+package goodrego
+
+violation[{"msg": msg}] {
+ msg := "denyall"
+}`},
+ },
+ }},
+ }},
+ },
+ }
+}
+
+func DenyAllConstraint() *unstructured.Unstructured {
+ return ConstraintFor("denyall")
+}
+
+func ConstraintFor(kind string) *unstructured.Unstructured {
+ u := &unstructured.Unstructured{}
+
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: constraints.Group,
+ Version: "v1beta1",
+ Kind: kind,
+ })
+ u.SetName("constraint")
+
+ return u
+}
diff --git a/pkg/fakes/provider_cache.go b/pkg/fakes/provider_cache.go
index 7d795ef23ea..236395a0fba 100644
--- a/pkg/fakes/provider_cache.go
+++ b/pkg/fakes/provider_cache.go
@@ -3,7 +3,7 @@ package fakes
import (
externaldataUnversioned "github.com/open-policy-agent/frameworks/constraint/pkg/apis/externaldata/unversioned"
frameworksexternaldata "github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
diff --git a/pkg/fakes/reader.go b/pkg/fakes/reader.go
new file mode 100644
index 00000000000..2acd81d19da
--- /dev/null
+++ b/pkg/fakes/reader.go
@@ -0,0 +1,60 @@
+package fakes
+
+import (
+ "context"
+ "sync"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+type SpyReader struct {
+ client.Reader
+ ListFunc func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error
+}
+
+func (r SpyReader) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
+ if r.ListFunc != nil {
+ return r.ListFunc(ctx, list, opts...)
+ }
+ return r.Reader.List(ctx, list, opts...)
+}
+
+// FailureInjector can be used in combination with the SpyReader to simulate transient
+// failures for network calls.
+type FailureInjector struct {
+ mu sync.Mutex
+ failures map[string]int // registers GVK.Kind and how many times to fail
+}
+
+func (f *FailureInjector) SetFailures(kind string, failures int) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+
+ f.failures[kind] = failures
+}
+
+// CheckFailures looks at the count of failures and returns true
+// if there are still failures for the kind to consume, false otherwise.
+func (f *FailureInjector) CheckFailures(kind string) bool {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+
+ v, ok := f.failures[kind]
+ if !ok {
+ return false
+ }
+
+ if v == 0 {
+ return false
+ }
+
+ f.failures[kind] = v - 1
+
+ return true
+}
+
+func NewFailureInjector() *FailureInjector {
+ return &FailureInjector{
+ failures: make(map[string]int),
+ }
+}
diff --git a/pkg/gator/expand/expand.go b/pkg/gator/expand/expand.go
index 74084b9ae99..7d372506b8c 100644
--- a/pkg/gator/expand/expand.go
+++ b/pkg/gator/expand/expand.go
@@ -3,16 +3,17 @@ package expand
import (
"fmt"
- "github.com/open-policy-agent/gatekeeper/apis/expansion/unversioned"
- expansionv1 "github.com/open-policy-agent/gatekeeper/apis/expansion/v1alpha1"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- mutationsv1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1alpha1"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/assign"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/assignmeta"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/modifyset"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/unversioned"
+ expansionv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/v1alpha1"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ mutationsv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assign"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assignimage"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assignmeta"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/modifyset"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -23,6 +24,7 @@ var mutatorKinds = map[string]bool{
"Assign": true,
"AssignMetadata": true,
"ModifySet": true,
+ "AssignImage": true,
}
type Expander struct {
@@ -63,18 +65,18 @@ func NewExpander(resources []*unstructured.Unstructured) (*Expander, error) {
}
if err := er.addResources(resources); err != nil {
- return nil, fmt.Errorf("error parsing resources: %s", err)
+ return nil, fmt.Errorf("error parsing resources: %w", err)
}
for _, te := range er.templateExpansions {
if err := er.expSystem.UpsertTemplate(te); err != nil {
- return nil, fmt.Errorf("error upserting template %s: %s", te.Name, err)
+ return nil, fmt.Errorf("error upserting template %s: %w", te.Name, err)
}
}
for _, m := range er.mutators {
if err := er.mutSystem.Upsert(m); err != nil {
- return nil, fmt.Errorf("error upserting mutator: %s", err)
+ return nil, fmt.Errorf("error upserting mutator: %w", err)
}
}
@@ -92,12 +94,12 @@ func (er *Expander) Expand(resource *unstructured.Unstructured) ([]*expansion.Re
Source: types.SourceTypeOriginal,
}
if _, err := er.mutSystem.Mutate(base); err != nil {
- return nil, fmt.Errorf("error mutating base resource %s: %s", resource.GetName(), err)
+ return nil, fmt.Errorf("error mutating base resource %s: %w", resource.GetName(), err)
}
resultants, err := er.expSystem.Expand(base)
if err != nil {
- return nil, fmt.Errorf("error expanding resource %s: %s", resource.GetName(), err)
+ return nil, fmt.Errorf("error expanding resource %s: %w", resource.GetName(), err)
}
return resultants, nil
@@ -151,6 +153,12 @@ func (er *Expander) addMutator(mut *unstructured.Unstructured) error {
return err
}
m, mutErr = modifyset.MutatorForModifySet(ms)
+ case "AssignImage":
+ a, err := convertAssignImage(mut)
+ if err != nil {
+ return err
+ }
+ m, mutErr = assignimage.MutatorForAssignImage(a)
default:
return fmt.Errorf("cannot convert mutator of kind %q", mut.GetKind())
}
@@ -172,7 +180,6 @@ func (er *Expander) add(u *unstructured.Unstructured) error {
case isNamespace(u):
err = er.addNamespace(u)
}
-
if err == nil {
// Any resource can technically be a generator
er.objects = append(er.objects, u)
@@ -200,14 +207,14 @@ func (er *Expander) addNamespace(u *unstructured.Unstructured) error {
}
func isExpansion(u *unstructured.Unstructured) bool {
- return u.GroupVersionKind().Group == expansionv1.GroupVersion.Group && u.GetKind() == "ExpansionTemplate"
+ return u.GroupVersionKind().Group == expansionv1alpha1.GroupVersion.Group && u.GetKind() == "ExpansionTemplate"
}
func isMutator(obj *unstructured.Unstructured) bool {
if _, exists := mutatorKinds[obj.GetKind()]; !exists {
return false
}
- return obj.GroupVersionKind().Group == mutationsv1.GroupVersion.Group
+ return obj.GroupVersionKind().Group == mutationsv1alpha1.GroupVersion.Group
}
func isNamespace(obj *unstructured.Unstructured) bool {
@@ -246,6 +253,12 @@ func convertModifySet(u *unstructured.Unstructured) (*mutationsunversioned.Modif
return ms, err
}
+func convertAssignImage(u *unstructured.Unstructured) (*mutationsunversioned.AssignImage, error) {
+ ai := &mutationsunversioned.AssignImage{}
+ err := convertUnstructuredToTyped(u, ai)
+ return ai, err
+}
+
func convertNamespace(u *unstructured.Unstructured) (*corev1.Namespace, error) {
ns := &corev1.Namespace{}
err := convertUnstructuredToTyped(u, ns)
diff --git a/pkg/gator/opa.go b/pkg/gator/opa.go
index 952dce8931f..3871e131ce7 100644
--- a/pkg/gator/opa.go
+++ b/pkg/gator/opa.go
@@ -2,17 +2,30 @@ package gator
import (
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
)
-func NewOPAClient(includeTrace bool) (Client, error) {
- driver, err := local.New(local.Tracing(includeTrace))
+func NewOPAClient(includeTrace bool, k8sCEL bool) (Client, error) {
+ args := []constraintclient.Opt{constraintclient.Targets(&target.K8sValidationTarget{})}
+
+ if k8sCEL {
+ k8sDriver, err := k8scel.New()
+ if err != nil {
+ return nil, err
+ }
+ args = append(args, constraintclient.Driver(k8sDriver))
+ }
+
+ driver, err := rego.New(rego.Tracing(includeTrace))
if err != nil {
return nil, err
}
- c, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
+ args = append(args, constraintclient.Driver(driver))
+
+ c, err := constraintclient.NewClient(args...)
if err != nil {
return nil, err
}
diff --git a/pkg/gator/reader/filereader.go b/pkg/gator/reader/filereader.go
index 867bd211e52..6c1f1a7d78e 100644
--- a/pkg/gator/reader/filereader.go
+++ b/pkg/gator/reader/filereader.go
@@ -6,7 +6,7 @@ import (
"os"
"path/filepath"
- "github.com/open-policy-agent/gatekeeper/pkg/oci"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/oci"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@@ -148,7 +148,8 @@ func readStdin() ([]*unstructured.Unstructured, error) {
return nil, fmt.Errorf("getting stdin info: %w", err)
}
- if stdinfo.Size() == 0 {
+ // check if data is being piped or redirected to stdin
+ if (stdinfo.Mode() & os.ModeCharDevice) != 0 {
return nil, nil
}
diff --git a/pkg/gator/reader/read_constraints.go b/pkg/gator/reader/read_constraints.go
index 33963dfcff8..09623dbc695 100644
--- a/pkg/gator/reader/read_constraints.go
+++ b/pkg/gator/reader/read_constraints.go
@@ -10,7 +10,7 @@ import (
templatesv1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
- "github.com/open-policy-agent/gatekeeper/pkg/gator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/yaml"
@@ -60,7 +60,7 @@ func ReadUnstructureds(bytes []byte) ([]*unstructured.Unstructured, error) {
u, err := readUnstructured([]byte(split))
if err != nil {
- return nil, fmt.Errorf("%w: %v", gator.ErrInvalidYAML, err)
+ return nil, fmt.Errorf("%w: %w", gator.ErrInvalidYAML, err)
}
result = append(result, u)
@@ -91,7 +91,7 @@ func ReadTemplate(scheme *runtime.Scheme, f fs.FS, path string) (*templates.Cons
u, err := readUnstructured(bytes)
if err != nil {
- return nil, fmt.Errorf("%w: parsing ConstraintTemplate YAML from %q: %v", gator.ErrAddingTemplate, path, err)
+ return nil, fmt.Errorf("%w: parsing ConstraintTemplate YAML from %q: %w", gator.ErrAddingTemplate, path, err)
}
template, err := ToTemplate(scheme, u)
@@ -115,7 +115,7 @@ func ToTemplate(scheme *runtime.Scheme, u *unstructured.Unstructured) (*template
t, err := scheme.New(gvk)
if err != nil {
// The type isn't registered in the scheme.
- return nil, fmt.Errorf("%w: %v", gator.ErrAddingTemplate, err)
+ return nil, fmt.Errorf("%w: %w", gator.ErrAddingTemplate, err)
}
// YAML parsing doesn't properly handle ObjectMeta, so we must
@@ -128,7 +128,7 @@ func ToTemplate(scheme *runtime.Scheme, u *unstructured.Unstructured) (*template
}
err = json.Unmarshal(jsonBytes, t)
if err != nil {
- return nil, fmt.Errorf("%w: %v", gator.ErrAddingTemplate, err)
+ return nil, fmt.Errorf("%w: %w", gator.ErrAddingTemplate, err)
}
v, isVersionless := t.(versionless)
@@ -140,7 +140,7 @@ func ToTemplate(scheme *runtime.Scheme, u *unstructured.Unstructured) (*template
if err != nil {
// This shouldn't happen unless there's a bug in the conversion functions.
// Most likely it means the conversion functions weren't generated.
- return nil, fmt.Errorf("%w: %v", gator.ErrConvertingTemplate, err)
+ return nil, fmt.Errorf("%w: %w", gator.ErrConvertingTemplate, err)
}
return template, nil
@@ -157,7 +157,7 @@ func ReadObject(f fs.FS, path string) (*unstructured.Unstructured, error) {
u, err := readUnstructured(bytes)
if err != nil {
- return nil, fmt.Errorf("%w: parsing Constraint from %q: %v", gator.ErrAddingConstraint, path, err)
+ return nil, fmt.Errorf("%w: parsing Constraint from %q: %w", gator.ErrAddingConstraint, path, err)
}
return u, nil
diff --git a/pkg/gator/test/test.go b/pkg/gator/test/test.go
index df1b084f4f5..d09aafcb616 100644
--- a/pkg/gator/test/test.go
+++ b/pkg/gator/test/test.go
@@ -7,12 +7,13 @@ import (
"github.com/open-policy-agent/frameworks/constraint/pkg/apis"
templatesv1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/gator/expand"
- "github.com/open-policy-agent/gatekeeper/pkg/gator/reader"
- mutationtypes "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/expand"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/reader"
+ mutationtypes "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
)
@@ -27,15 +28,29 @@ func init() {
}
}
-func Test(objs []*unstructured.Unstructured, includeTrace bool) (*GatorResponses, error) {
- // create the client
+// options for the Test func.
+type Opts struct {
+ // Driver specific options
+ IncludeTrace bool
+ GatherStats bool
+ UseK8sCEL bool
+}
+
+func Test(objs []*unstructured.Unstructured, tOpts Opts) (*GatorResponses, error) {
+ args := []constraintclient.Opt{constraintclient.Targets(&target.K8sValidationTarget{})}
+ k8sDriver, err := k8scel.New()
+ if err != nil {
+ return nil, fmt.Errorf("creating K8s native driver: %w", err)
+ }
+ args = append(args, constraintclient.Driver(k8sDriver))
- driver, err := local.New(local.Tracing(includeTrace))
+ driver, err := makeRegoDriver(tOpts)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("creating Rego driver: %w", err)
}
+ args = append(args, constraintclient.Driver(driver))
- client, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
+ client, err := constraintclient.NewClient(args...)
if err != nil {
return nil, fmt.Errorf("creating OPA client: %w", err)
}
@@ -82,7 +97,7 @@ func Test(objs []*unstructured.Unstructured, includeTrace bool) (*GatorResponses
// create the expander
er, err := expand.NewExpander(objs)
if err != nil {
- return nil, fmt.Errorf("error creating expander: %s", err)
+ return nil, fmt.Errorf("error creating expander: %w", err)
}
// now audit all objects
@@ -100,14 +115,14 @@ func Test(objs []*unstructured.Unstructured, includeTrace bool) (*GatorResponses
review, err := client.Review(ctx, au)
if err != nil {
- return nil, fmt.Errorf("reviewing %v %s/%s: %v",
+ return nil, fmt.Errorf("reviewing %v %s/%s: %w",
obj.GroupVersionKind(), obj.GetNamespace(), obj.GetName(), err)
}
// Attempt to expand the obj and review resultant resources (if any)
resultants, err := er.Expand(obj)
if err != nil {
- return nil, fmt.Errorf("expanding resource %s: %s", obj.GetName(), err)
+ return nil, fmt.Errorf("expanding resource %s: %w", obj.GetName(), err)
}
for _, resultant := range resultants {
au := target.AugmentedUnstructured{
@@ -117,11 +132,12 @@ func Test(objs []*unstructured.Unstructured, includeTrace bool) (*GatorResponses
}
resultantReview, err := client.Review(ctx, au)
if err != nil {
- return nil, fmt.Errorf("reviewing expanded resource %v %s/%s: %v",
+ return nil, fmt.Errorf("reviewing expanded resource %v %s/%s: %w",
resultant.Obj.GroupVersionKind(), resultant.Obj.GetNamespace(), resultant.Obj.GetName(), err)
}
expansion.OverrideEnforcementAction(resultant.EnforcementAction, resultantReview)
expansion.AggregateResponses(resultant.TemplateName, review, resultantReview)
+ expansion.AggregateStats(resultant.TemplateName, review, resultantReview)
}
for targetName, r := range review.ByTarget {
@@ -148,9 +164,10 @@ func Test(objs []*unstructured.Unstructured, includeTrace bool) (*GatorResponses
trace = trace + "\n\n" + *r.Trace
targetResponse.Trace = &trace
}
-
responses.ByTarget[targetName] = targetResponse
}
+
+ responses.StatsEntries = append(responses.StatsEntries, review.StatsEntries...)
}
return responses, nil
@@ -165,3 +182,15 @@ func isConstraint(u *unstructured.Unstructured) bool {
gvk := u.GroupVersionKind()
return gvk.Group == "constraints.gatekeeper.sh"
}
+
+func makeRegoDriver(tOpts Opts) (*rego.Driver, error) {
+ var args []rego.Arg
+ if tOpts.GatherStats {
+ args = append(args, rego.GatherStats())
+ }
+ if tOpts.IncludeTrace {
+ args = append(args, rego.Tracing(tOpts.IncludeTrace))
+ }
+
+ return rego.New(args...)
+}
diff --git a/pkg/gator/test/test_test.go b/pkg/gator/test/test_test.go
index 0fd4ec900b4..95a0d18ac39 100644
--- a/pkg/gator/test/test_test.go
+++ b/pkg/gator/test/test_test.go
@@ -1,15 +1,17 @@
package test
import (
- "errors"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/instrumentation"
"github.com/open-policy-agent/frameworks/constraint/pkg/types"
- "github.com/open-policy-agent/gatekeeper/pkg/gator/fixtures"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/fixtures"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/yaml"
)
@@ -56,12 +58,27 @@ func init() {
}
}
+func ignoreGatorResultFields() cmp.Option {
+ return cmp.FilterPath(
+ func(p cmp.Path) bool {
+ switch p.String() {
+ // ignore these fields
+ case "Result.Metadata", "Result.EvaluationMeta", "Result.EnforcementAction", "ViolatingObject":
+ return true
+ default:
+ return false
+ }
+ },
+ cmp.Ignore())
+}
+
func TestTest(t *testing.T) {
tcs := []struct {
- name string
- inputs []string
- want []*GatorResult
- err error
+ name string
+ inputs []string
+ want []*GatorResult
+ cmpOption cmp.Option
+ err error
}{
{
name: "basic no violation",
@@ -70,6 +87,7 @@ func TestTest(t *testing.T) {
fixtures.ConstraintAlwaysValidate,
fixtures.Object,
},
+ cmpOption: ignoreGatorResultFields(),
},
{
name: "basic violation",
@@ -101,6 +119,7 @@ func TestTest(t *testing.T) {
},
},
},
+ cmpOption: ignoreGatorResultFields(),
},
{
name: "referential constraint with violation",
@@ -126,6 +145,7 @@ func TestTest(t *testing.T) {
},
},
},
+ cmpOption: ignoreGatorResultFields(),
},
{
name: "referential constraint without violation",
@@ -168,27 +188,26 @@ func TestTest(t *testing.T) {
var objs []*unstructured.Unstructured
for _, input := range tc.inputs {
u, err := readUnstructured([]byte(input))
- if err != nil {
- t.Fatalf("readUnstructured for input %q: %v", input, err)
- }
+ require.NoError(t, err)
objs = append(objs, u)
}
- resps, err := Test(objs, false)
+ resps, err := Test(objs, Opts{})
if tc.err != nil {
- if err == nil {
- t.Errorf("got nil err, want %v", tc.err)
- }
- if !errors.Is(err, tc.err) {
- t.Errorf("got err %q, want %q", err, tc.err)
- }
+ require.ErrorIs(t, err, tc.err)
} else if err != nil {
- t.Errorf("got err '%v', want nil", err)
+ require.NoError(t, err)
}
got := resps.Results()
- diff := cmp.Diff(tc.want, got, cmpopts.IgnoreFields(GatorResult{}, "Metadata", "EvaluationMeta", "EnforcementAction", "ViolatingObject"))
+ var diff string
+ if tc.cmpOption != nil {
+ diff = cmp.Diff(tc.want, got, tc.cmpOption)
+ } else {
+ diff = cmp.Diff(tc.want, got)
+ }
+
if diff != "" {
t.Errorf("diff in GatorResult objects (-want +got):\n%s", diff)
}
@@ -213,7 +232,7 @@ func Test_Test_withTrace(t *testing.T) {
objs = append(objs, u)
}
- resps, err := Test(objs, true)
+ resps, err := Test(objs, Opts{IncludeTrace: true})
if err != nil {
t.Errorf("got err '%v', want nil", err)
}
@@ -244,12 +263,8 @@ func Test_Test_withTrace(t *testing.T) {
},
}
- diff := cmp.Diff(want, got, cmpopts.IgnoreFields(
+ diff := cmp.Diff(want, got, ignoreGatorResultFields(), cmpopts.IgnoreFields(
GatorResult{},
- "Metadata",
- "EvaluationMeta",
- "EnforcementAction",
- "ViolatingObject",
"Trace", // ignore Trace for now, we will assert non nil further down
))
if diff != "" {
@@ -263,6 +278,87 @@ func Test_Test_withTrace(t *testing.T) {
}
}
+// Test_Test_withStats proves that we can get a stats populated when we ask for it.
+func Test_Test_withStats(t *testing.T) {
+ inputs := []string{
+ fixtures.TemplateNeverValidate,
+ fixtures.ConstraintNeverValidate,
+ fixtures.Object,
+ }
+
+ var objs []*unstructured.Unstructured
+ for _, input := range inputs {
+ u, err := readUnstructured([]byte(input))
+ assert.NoErrorf(t, err, "readUnstructured for input %q: %v", input, err)
+ objs = append(objs, u)
+ }
+
+ resps, err := Test(objs, Opts{GatherStats: true})
+ assert.NoError(t, err)
+
+ actualStats := resps.StatsEntries
+ expectesSE := &instrumentation.StatsEntry{
+ Scope: "template",
+ StatsFor: "NeverValidate",
+ Stats: []*instrumentation.Stat{
+ {
+ Name: "templateRunTimeNS",
+ // Value: 0, // will be checked later
+ Source: instrumentation.Source{
+ Type: "engine",
+ Value: "Rego",
+ },
+ },
+ {
+ Name: "constraintCount",
+ Value: 1,
+ Source: instrumentation.Source{
+ Type: "engine",
+ Value: "Rego",
+ },
+ },
+ },
+ Labels: []*instrumentation.Label{
+ {
+ Name: "TracingEnabled",
+ Value: false,
+ },
+ {
+ Name: "PrintEnabled",
+ Value: false,
+ },
+ {
+ Name: "target",
+ Value: "admission.k8s.gatekeeper.sh",
+ },
+ },
+ }
+
+ // test.go calls review on all 3 objects (template, constraint, objToReview)
+ // so we need 3 "almost" copies of the stat entry above.
+ expectedStats := []*instrumentation.StatsEntry{}
+ expectedStats = append(expectedStats, expectesSE, expectesSE, expectesSE)
+
+ diff := cmp.Diff(actualStats, expectedStats, cmpopts.IgnoreFields(
+ instrumentation.Stat{}, "Value",
+ ))
+ if diff != "" {
+ t.Errorf("diff in StatsEntries (-want +got):\n%s", diff)
+ }
+
+ // there should be at least 3 stats entry with two stats each
+ assert.Len(t, actualStats, len(expectedStats))
+ assert.Len(t, actualStats[0].Stats, 2)
+ for _, stat := range actualStats[0].Stats {
+ if stat.Name == "templateRunTimeNS" {
+ require.NotZero(t, stat.Value)
+ }
+ if stat.Name == "constraintCount" {
+ require.Equal(t, stat.Value, 1)
+ }
+ }
+}
+
func readUnstructured(bytes []byte) (*unstructured.Unstructured, error) {
u := &unstructured.Unstructured{
Object: make(map[string]interface{}),
diff --git a/pkg/gator/test/types.go b/pkg/gator/test/types.go
index 36f98ab90cf..33db9b4451b 100644
--- a/pkg/gator/test/types.go
+++ b/pkg/gator/test/types.go
@@ -3,6 +3,7 @@ package test
import (
"sort"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/instrumentation"
"github.com/open-policy-agent/frameworks/constraint/pkg/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@@ -41,8 +42,9 @@ type GatorResponse struct {
}
type GatorResponses struct {
- ByTarget map[string]*GatorResponse
- Handled map[string]bool
+ ByTarget map[string]*GatorResponse
+ Handled map[string]bool
+ StatsEntries []*instrumentation.StatsEntry
}
func (r *GatorResponses) Results() []*GatorResult {
diff --git a/pkg/gator/verify/assertion.go b/pkg/gator/verify/assertion.go
index ce8314e038e..9d050d17a12 100644
--- a/pkg/gator/verify/assertion.go
+++ b/pkg/gator/verify/assertion.go
@@ -6,7 +6,7 @@ import (
"sync"
"github.com/open-policy-agent/frameworks/constraint/pkg/types"
- "github.com/open-policy-agent/gatekeeper/pkg/gator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator"
"k8s.io/apimachinery/pkg/util/intstr"
)
@@ -150,7 +150,7 @@ func (a *Assertion) getMsgRegex() (*regexp.Regexp, error) {
a.msgRegex, err = regexp.Compile(*a.Message)
})
if err != nil {
- return nil, fmt.Errorf("%w: %v", gator.ErrInvalidRegex, err)
+ return nil, fmt.Errorf("%w: %w", gator.ErrInvalidRegex, err)
}
return a.msgRegex, nil
diff --git a/pkg/gator/verify/assertion_test.go b/pkg/gator/verify/assertion_test.go
index 20257f48628..974ad7314be 100644
--- a/pkg/gator/verify/assertion_test.go
+++ b/pkg/gator/verify/assertion_test.go
@@ -5,7 +5,7 @@ import (
"testing"
"github.com/open-policy-agent/frameworks/constraint/pkg/types"
- "github.com/open-policy-agent/gatekeeper/pkg/gator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator"
"k8s.io/utils/pointer"
)
@@ -38,7 +38,7 @@ func TestAssertion_Run(t *testing.T) {
name: "violation with message",
assertion: &Assertion{
Violations: gator.IntStrFromInt(1),
- Message: pointer.StringPtr("message"),
+ Message: pointer.String("message"),
},
results: nil,
wantErr: gator.ErrNumViolations,
@@ -46,7 +46,7 @@ func TestAssertion_Run(t *testing.T) {
name: "no violations with message",
assertion: &Assertion{
Violations: gator.IntStrFromStr("no"),
- Message: pointer.StringPtr("message"),
+ Message: pointer.String("message"),
},
results: nil,
wantErr: nil,
@@ -54,7 +54,7 @@ func TestAssertion_Run(t *testing.T) {
name: "fail no violations with message",
assertion: &Assertion{
Violations: gator.IntStrFromStr("no"),
- Message: pointer.StringPtr("message"),
+ Message: pointer.String("message"),
},
results: []*types.Result{{
Msg: "message",
diff --git a/pkg/gator/verify/filter.go b/pkg/gator/verify/filter.go
index d98d4fb5bff..e1b6ad138ec 100644
--- a/pkg/gator/verify/filter.go
+++ b/pkg/gator/verify/filter.go
@@ -5,7 +5,7 @@ import (
"regexp"
"strings"
- "github.com/open-policy-agent/gatekeeper/pkg/gator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator"
)
type Filter interface {
@@ -87,7 +87,7 @@ type orFilter struct {
func newOrFilter(filter string) (Filter, error) {
regex, err := regexp.Compile(filter)
if err != nil {
- return nil, fmt.Errorf("%w: %v", gator.ErrInvalidFilter, err)
+ return nil, fmt.Errorf("%w: %w", gator.ErrInvalidFilter, err)
}
return &orFilter{regex: regex}, nil
@@ -123,12 +123,12 @@ var _ Filter = &andFilter{}
func newAndFilter(testFilter, caseFilter string) (Filter, error) {
testRegex, err := regexp.Compile(testFilter)
if err != nil {
- return nil, fmt.Errorf("%w: %v", gator.ErrInvalidFilter, err)
+ return nil, fmt.Errorf("%w: %w", gator.ErrInvalidFilter, err)
}
caseRegex, err := regexp.Compile(caseFilter)
if err != nil {
- return nil, fmt.Errorf("%w: %v", gator.ErrInvalidFilter, err)
+ return nil, fmt.Errorf("%w: %w", gator.ErrInvalidFilter, err)
}
return &andFilter{testRegex: testRegex, caseRegex: caseRegex}, nil
diff --git a/pkg/gator/verify/filter_test.go b/pkg/gator/verify/filter_test.go
index b25f8a603ee..7d251dceddf 100644
--- a/pkg/gator/verify/filter_test.go
+++ b/pkg/gator/verify/filter_test.go
@@ -4,7 +4,7 @@ import (
"errors"
"testing"
- "github.com/open-policy-agent/gatekeeper/pkg/gator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator"
)
func TestFilter_Error(t *testing.T) {
diff --git a/pkg/gator/verify/printer_go.go b/pkg/gator/verify/printer_go.go
index 41e6ccb7f35..35cc4cabe84 100644
--- a/pkg/gator/verify/printer_go.go
+++ b/pkg/gator/verify/printer_go.go
@@ -53,18 +53,18 @@ func (p PrinterGo) PrintSuite(w StringWriter, r *SuiteResult, verbose bool) erro
if r.IsFailure() {
_, err := w.WriteString(fmt.Sprintf("FAIL\t%s\t%v\n", r.Path, r.Runtime))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
if r.Error != nil {
_, err = w.WriteString(fmt.Sprintf(" %v\n", r.Error))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
}
} else {
_, err := w.WriteString(fmt.Sprintf("ok\t%s\t%v\n", r.Path, r.Runtime))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
}
return nil
@@ -75,39 +75,39 @@ func (p PrinterGo) PrintTest(w StringWriter, r *TestResult, verbose bool) error
if r.Skipped {
_, err := w.WriteString(fmt.Sprintf("=== SKIP %s\n", r.Name))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
return nil
}
_, err := w.WriteString(fmt.Sprintf("=== RUN %s\n", r.Name))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
}
for i := range r.CaseResults {
err := p.PrintCase(w, &r.CaseResults[i], verbose)
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
}
if r.IsFailure() {
_, err := w.WriteString(fmt.Sprintf("--- FAIL: %s\t(%v)\n", r.Name, r.Runtime))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
if r.Error != nil {
_, err = w.WriteString(fmt.Sprintf(" %v\n", r.Error))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
}
} else if verbose {
_, err := w.WriteString(fmt.Sprintf("--- PASS: %s\t(%v)\n", r.Name, r.Runtime))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
}
return nil
@@ -118,26 +118,26 @@ func (p PrinterGo) PrintCase(w StringWriter, r *CaseResult, verbose bool) error
if r.Skipped {
_, err := w.WriteString(fmt.Sprintf(" === SKIP %s\n", r.Name))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
return nil
}
_, err := w.WriteString(fmt.Sprintf(" === RUN %s\n", r.Name))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
}
if r.Error != nil {
_, err := w.WriteString(fmt.Sprintf(" --- FAIL: %s\t(%v)\n %v\n", r.Name, r.Runtime, r.Error))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
} else if verbose {
_, err := w.WriteString(fmt.Sprintf(" --- PASS: %s\t(%v)\n", r.Name, r.Runtime))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
}
@@ -149,7 +149,7 @@ func (p PrinterGo) PrintCase(w StringWriter, r *CaseResult, verbose bool) error
}
_, err := w.WriteString(fmt.Sprintf("%sTRACE: %s\t%s\n", prefix, r.Name, strings.ReplaceAll(*r.Trace, "\n", "\n"+prefix)))
if err != nil {
- return fmt.Errorf("%w: %v", ErrWritingString, err)
+ return fmt.Errorf("%w: %w", ErrWritingString, err)
}
}
diff --git a/pkg/gator/verify/printer_go_test.go b/pkg/gator/verify/printer_go_test.go
index d49ae0f67d3..0be62381696 100644
--- a/pkg/gator/verify/printer_go_test.go
+++ b/pkg/gator/verify/printer_go_test.go
@@ -282,7 +282,7 @@ PASS
CaseResults: []CaseResult{{
Name: "case name",
Runtime: Duration(100 * time.Millisecond),
- Trace: pointer.StringPtr("this is a trace"),
+ Trace: pointer.String("this is a trace"),
}},
},
},
diff --git a/pkg/gator/verify/read_suites.go b/pkg/gator/verify/read_suites.go
index bdbaf8a1c6d..684d7ecc359 100644
--- a/pkg/gator/verify/read_suites.go
+++ b/pkg/gator/verify/read_suites.go
@@ -8,7 +8,7 @@ import (
"sort"
"strings"
- "github.com/open-policy-agent/gatekeeper/pkg/gator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator"
"gopkg.in/yaml.v3"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@@ -186,7 +186,7 @@ func readSuite(f fs.FS, path string) (*Suite, error) {
}
err = yaml.Unmarshal(bytes, u.Object)
if err != nil {
- return nil, fmt.Errorf("%w: parsing yaml file %q: %v", gator.ErrInvalidYAML, path, err)
+ return nil, fmt.Errorf("%w: parsing yaml file %q: %w", gator.ErrInvalidYAML, path, err)
}
gvk := u.GroupVersionKind()
if gvk.Group != Group || gvk.Kind != Kind {
@@ -198,7 +198,7 @@ func readSuite(f fs.FS, path string) (*Suite, error) {
err = gator.ParseYaml(bytes, &suite)
if err != nil {
- return nil, fmt.Errorf("%w: %v", gator.ErrInvalidYAML, err)
+ return nil, fmt.Errorf("%w: %w", gator.ErrInvalidYAML, err)
}
return &suite, nil
diff --git a/pkg/gator/verify/read_suites_test.go b/pkg/gator/verify/read_suites_test.go
index e0943932034..95784ddd947 100644
--- a/pkg/gator/verify/read_suites_test.go
+++ b/pkg/gator/verify/read_suites_test.go
@@ -8,7 +8,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
- "github.com/open-policy-agent/gatekeeper/pkg/gator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator"
"k8s.io/utils/pointer"
)
@@ -369,7 +369,7 @@ tests:
Object: "deny.yaml",
Assertions: []Assertion{{
Violations: gator.IntStrFromInt(2),
- Message: pointer.StringPtr("some message"),
+ Message: pointer.String("some message"),
}},
}},
}},
@@ -410,7 +410,7 @@ tests:
Object: "deny.yaml",
Assertions: []Assertion{{
Violations: gator.IntStrFromInt(2),
- Message: pointer.StringPtr("some message"),
+ Message: pointer.String("some message"),
}},
}},
}},
@@ -451,7 +451,7 @@ tests:
Object: "deny.yaml",
Assertions: []Assertion{{
Violations: gator.IntStrFromInt(2),
- Message: pointer.StringPtr("some message"),
+ Message: pointer.String("some message"),
}},
}},
}},
@@ -492,7 +492,7 @@ tests:
Object: "deny.yaml",
Assertions: []Assertion{{
Violations: gator.IntStrFromInt(2),
- Message: pointer.StringPtr("some message"),
+ Message: pointer.String("some message"),
}},
}},
}},
diff --git a/pkg/gator/verify/runner.go b/pkg/gator/verify/runner.go
index 3a240adbcdd..64255204036 100644
--- a/pkg/gator/verify/runner.go
+++ b/pkg/gator/verify/runner.go
@@ -10,12 +10,12 @@ import (
"github.com/open-policy-agent/frameworks/constraint/pkg/apis/constraints"
"github.com/open-policy-agent/frameworks/constraint/pkg/types"
- "github.com/open-policy-agent/gatekeeper/apis"
- "github.com/open-policy-agent/gatekeeper/pkg/gator"
- "github.com/open-policy-agent/gatekeeper/pkg/gator/reader"
- mutationtypes "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/apis"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/reader"
+ mutationtypes "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
admissionv1 "k8s.io/api/admission/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
@@ -31,14 +31,16 @@ type Runner struct {
// newClient instantiates a Client for compiling Templates/Constraints, and
// validating objects against them.
- newClient func(includeTrace bool) (gator.Client, error)
+ newClient func(includeTrace bool, useK8sCEL bool) (gator.Client, error)
scheme *runtime.Scheme
includeTrace bool
+
+ useK8sCEL bool
}
-func NewRunner(filesystem fs.FS, newClient func(includeTrace bool) (gator.Client, error), opts ...RunnerOptions) (*Runner, error) {
+func NewRunner(filesystem fs.FS, newClient func(includeTrace bool, useK8sCEL bool) (gator.Client, error), opts ...RunnerOptions) (*Runner, error) {
s := runtime.NewScheme()
err := apis.AddToScheme(s)
if err != nil {
@@ -66,6 +68,12 @@ func IncludeTrace(includeTrace bool) RunnerOptions {
}
}
+func UseK8sCEL(useK8sCEL bool) RunnerOptions {
+ return func(r *Runner) {
+ r.useK8sCEL = useK8sCEL
+ }
+}
+
// Run executes all Tests in the Suite and returns the results.
func (r *Runner) Run(ctx context.Context, filter Filter, s *Suite) SuiteResult {
start := time.Now()
@@ -118,7 +126,7 @@ func (r *Runner) runTest(ctx context.Context, suiteDir string, filter Filter, t
if errors.Is(err, constraints.ErrSchema) {
err = nil
} else {
- err = fmt.Errorf("%w: got error %v but want %v", gator.ErrValidConstraint, err, constraints.ErrSchema)
+ err = fmt.Errorf("%w: got error %w but want %w", gator.ErrValidConstraint, err, constraints.ErrSchema)
}
} else if err == nil {
results, err = r.runCases(ctx, suiteDir, filter, t)
@@ -133,9 +141,9 @@ func (r *Runner) runTest(ctx context.Context, suiteDir string, filter Filter, t
}
func (r *Runner) tryAddConstraint(ctx context.Context, suiteDir string, t Test) error {
- client, err := r.newClient(r.includeTrace)
+ client, err := r.newClient(r.includeTrace, r.useK8sCEL)
if err != nil {
- return fmt.Errorf("%w: %v", gator.ErrCreatingClient, err)
+ return fmt.Errorf("%w: %w", gator.ErrCreatingClient, err)
}
err = r.addTemplate(suiteDir, t.Template, client)
@@ -188,9 +196,9 @@ func (r *Runner) skipCase(tc *Case) CaseResult {
}
func (r *Runner) makeTestClient(ctx context.Context, suiteDir string, t Test) (gator.Client, error) {
- client, err := r.newClient(r.includeTrace)
+ client, err := r.newClient(r.includeTrace, r.useK8sCEL)
if err != nil {
- return nil, fmt.Errorf("%w: %v", gator.ErrCreatingClient, err)
+ return nil, fmt.Errorf("%w: %w", gator.ErrCreatingClient, err)
}
err = r.addTemplate(suiteDir, t.Template, client)
@@ -218,7 +226,7 @@ func (r *Runner) addConstraint(ctx context.Context, suiteDir, constraintPath str
_, err = client.AddConstraint(ctx, cObj)
if err != nil {
- return fmt.Errorf("%w: %v", gator.ErrAddingConstraint, err)
+ return fmt.Errorf("%w: %w", gator.ErrAddingConstraint, err)
}
return nil
}
@@ -235,7 +243,7 @@ func (r *Runner) addTemplate(suiteDir, templatePath string, client gator.Client)
_, err = client.AddTemplate(context.Background(), template)
if err != nil {
- return fmt.Errorf("%w: %v", gator.ErrAddingTemplate, err)
+ return fmt.Errorf("%w: %w", gator.ErrAddingTemplate, err)
}
return nil
@@ -271,7 +279,7 @@ func (r *Runner) checkCase(ctx context.Context, newClient func() (gator.Client,
results := review.Results()
if r.includeTrace {
- trace = pointer.StringPtr(review.TraceDump())
+ trace = pointer.String(review.TraceDump())
}
for i := range tc.Assertions {
err = tc.Assertions[i].Run(results)
@@ -324,7 +332,7 @@ func (r *Runner) validateAndReviewAdmissionReviewRequest(ctx context.Context, c
// convert unstructured into AdmissionReview, don't allow unknown fields
var ar admissionv1.AdmissionReview
if err := runtime.DefaultUnstructuredConverter.FromUnstructuredWithValidation(toReview.UnstructuredContent(), &ar, true); err != nil {
- return nil, fmt.Errorf("%w: unable to convert to an AdmissionReview object, error: %v", gator.ErrInvalidK8sAdmissionReview, err)
+ return nil, fmt.Errorf("%w: unable to convert to an AdmissionReview object, error: %w", gator.ErrInvalidK8sAdmissionReview, err)
}
if ar.Request == nil { // then this admission review did not actually pass in an AdmissionRequest
@@ -341,19 +349,19 @@ func (r *Runner) validateAndReviewAdmissionReviewRequest(ctx context.Context, c
obj := &unstructured.Unstructured{}
if ar.Request.Object.Raw != nil {
if err := obj.UnmarshalJSON(ar.Request.Object.Raw); err != nil {
- return nil, fmt.Errorf("%w: %v", gator.ErrUnmarshallObject, err.Error())
+ return nil, fmt.Errorf("%w: %w", gator.ErrUnmarshallObject, err)
}
}
if ar.Request.OldObject.Raw != nil {
if err := obj.UnmarshalJSON(ar.Request.OldObject.Raw); err != nil {
- return nil, fmt.Errorf("%w: %v", gator.ErrUnmarshallObject, err.Error())
+ return nil, fmt.Errorf("%w: %w", gator.ErrUnmarshallObject, err)
}
}
// parse into webhook/admission type
req := &admission.Request{AdmissionRequest: *ar.Request}
if err := util.SetObjectOnDelete(req); err != nil {
- return nil, fmt.Errorf("%w: %v", gator.ErrNilOldObject, err.Error())
+ return nil, fmt.Errorf("%w: %w", gator.ErrNilOldObject, err)
}
arr := target.AugmentedReview{
@@ -375,7 +383,7 @@ func (r *Runner) addInventory(ctx context.Context, c gator.Client, suiteDir, inv
for _, obj := range inventory {
_, err = c.AddData(ctx, obj)
if err != nil {
- return fmt.Errorf("%w: %v %v/%v: %v",
+ return fmt.Errorf("%w: %v %v/%v: %w",
gator.ErrAddInventory, obj.GroupVersionKind(), obj.GetNamespace(), obj.GetName(), err)
}
}
diff --git a/pkg/gator/verify/runner_integer_test.go b/pkg/gator/verify/runner_integer_test.go
index b3915b64a3b..9868b984f34 100644
--- a/pkg/gator/verify/runner_integer_test.go
+++ b/pkg/gator/verify/runner_integer_test.go
@@ -6,7 +6,7 @@ import (
"testing"
"testing/fstest"
- "github.com/open-policy-agent/gatekeeper/pkg/gator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator"
)
const templateV1Beta1Integer = `
diff --git a/pkg/gator/verify/runner_test.go b/pkg/gator/verify/runner_test.go
index c2d232660ad..ca55fb8e74a 100644
--- a/pkg/gator/verify/runner_test.go
+++ b/pkg/gator/verify/runner_test.go
@@ -10,8 +10,8 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/gatekeeper/pkg/gator"
- "github.com/open-policy-agent/gatekeeper/pkg/gator/fixtures"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/fixtures"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/pointer"
)
@@ -983,7 +983,7 @@ func TestRunner_Run(t *testing.T) {
}, {
Name: "missing-namespace",
Object: "object.yaml",
- Assertions: []Assertion{{Violations: gator.IntStrFromStr("yes"), Message: pointer.StringPtr("missing Namespace")}},
+ Assertions: []Assertion{{Violations: gator.IntStrFromStr("yes"), Message: pointer.String("missing Namespace")}},
}},
}},
},
@@ -1034,7 +1034,7 @@ func TestRunner_Run(t *testing.T) {
{
Name: "user doesn't begin with \"system:\"",
Object: "non-system-ar.yaml",
- Assertions: []Assertion{{Violations: gator.IntStrFromStr("yes"), Message: pointer.StringPtr("username is not allowed to perform this operation")}},
+ Assertions: []Assertion{{Violations: gator.IntStrFromStr("yes"), Message: pointer.String("username is not allowed to perform this operation")}},
},
},
},
@@ -1207,7 +1207,7 @@ func TestRunner_Run_ClientError(t *testing.T) {
TestResults: []TestResult{{Error: gator.ErrCreatingClient}},
}
- runner, err := NewRunner(fstest.MapFS{}, func(includeTrace bool) (gator.Client, error) {
+ runner, err := NewRunner(fstest.MapFS{}, func(includeTrace bool, useK8sCEL bool) (gator.Client, error) {
return nil, errors.New("error")
})
if err != nil {
@@ -1306,7 +1306,7 @@ func TestRunner_RunCase(t *testing.T) {
constraint: fixtures.ConstraintAlwaysValidate,
object: fixtures.Object,
assertions: []Assertion{{
- Message: pointer.StringPtr("first message"),
+ Message: pointer.String("first message"),
}},
want: CaseResult{
Error: gator.ErrNumViolations,
@@ -1381,7 +1381,7 @@ func TestRunner_RunCase(t *testing.T) {
constraint: fixtures.ConstraintAlwaysValidate,
object: fixtures.Object,
assertions: []Assertion{{
- Message: pointer.StringPtr("never validate"),
+ Message: pointer.String("never validate"),
}},
want: CaseResult{
Error: gator.ErrNumViolations,
@@ -1393,7 +1393,7 @@ func TestRunner_RunCase(t *testing.T) {
constraint: fixtures.ConstraintNeverValidate,
object: fixtures.Object,
assertions: []Assertion{{
- Message: pointer.StringPtr("[enrv]+ [adeiltv]+"),
+ Message: pointer.String("[enrv]+ [adeiltv]+"),
}},
want: CaseResult{},
},
@@ -1403,7 +1403,7 @@ func TestRunner_RunCase(t *testing.T) {
constraint: fixtures.ConstraintNeverValidate,
object: fixtures.Object,
assertions: []Assertion{{
- Message: pointer.StringPtr("never validate [("),
+ Message: pointer.String("never validate [("),
}},
want: CaseResult{
Error: gator.ErrInvalidRegex,
@@ -1415,7 +1415,7 @@ func TestRunner_RunCase(t *testing.T) {
constraint: fixtures.ConstraintNeverValidate,
object: fixtures.Object,
assertions: []Assertion{{
- Message: pointer.StringPtr("[enrv]+x [adeiltv]+"),
+ Message: pointer.String("[enrv]+x [adeiltv]+"),
}},
want: CaseResult{
Error: gator.ErrNumViolations,
@@ -1438,9 +1438,9 @@ func TestRunner_RunCase(t *testing.T) {
constraint: fixtures.ConstraintNeverValidateTwice,
object: fixtures.Object,
assertions: []Assertion{{
- Message: pointer.StringPtr("first message"),
+ Message: pointer.String("first message"),
}, {
- Message: pointer.StringPtr("second message"),
+ Message: pointer.String("second message"),
}},
want: CaseResult{},
},
@@ -1451,10 +1451,10 @@ func TestRunner_RunCase(t *testing.T) {
object: fixtures.Object,
assertions: []Assertion{{
Violations: gator.IntStrFromInt(1),
- Message: pointer.StringPtr("first message"),
+ Message: pointer.String("first message"),
}, {
Violations: gator.IntStrFromInt(1),
- Message: pointer.StringPtr("second message"),
+ Message: pointer.String("second message"),
}},
want: CaseResult{},
},
@@ -1464,7 +1464,7 @@ func TestRunner_RunCase(t *testing.T) {
constraint: fixtures.ConstraintNeverValidateTwice,
object: fixtures.Object,
assertions: []Assertion{{
- Message: pointer.StringPtr("[cdefinorst]+ [aegms]+"),
+ Message: pointer.String("[cdefinorst]+ [aegms]+"),
}},
want: CaseResult{},
},
@@ -1475,7 +1475,7 @@ func TestRunner_RunCase(t *testing.T) {
object: fixtures.Object,
assertions: []Assertion{{
Violations: gator.IntStrFromInt(2),
- Message: pointer.StringPtr("[cdefinorst]+ [aegms]+"),
+ Message: pointer.String("[cdefinorst]+ [aegms]+"),
}},
want: CaseResult{},
},
@@ -1485,9 +1485,9 @@ func TestRunner_RunCase(t *testing.T) {
constraint: fixtures.ConstraintNeverValidateTwice,
object: fixtures.Object,
assertions: []Assertion{{
- Message: pointer.StringPtr("first message"),
+ Message: pointer.String("first message"),
}, {
- Message: pointer.StringPtr("third message"),
+ Message: pointer.String("third message"),
}},
want: CaseResult{
Error: gator.ErrNumViolations,
diff --git a/pkg/instrumentation/types.go b/pkg/instrumentation/types.go
new file mode 100644
index 00000000000..a9ca3103ac4
--- /dev/null
+++ b/pkg/instrumentation/types.go
@@ -0,0 +1,59 @@
+package instrumentation
+
+import (
+ constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
+ cfinstr "github.com/open-policy-agent/frameworks/constraint/pkg/instrumentation"
+)
+
+// StatWithDesc mirrors constraint framework instrumentation.Stat.
+type StatWithDesc struct {
+ cfinstr.Stat
+ Description string `json:"description"`
+}
+
+// StatsEntryWithDesc mirrors constraint framework instrumentation.StatsEntry.
+type StatsEntryWithDesc struct {
+ // Scope is the level of granularity that the Stats
+ // were created at.
+ Scope string `json:"scope"`
+ // StatsFor is the specific kind of Scope type that Stats
+ // were created for.
+ StatsFor string `json:"statsFor"`
+ Stats []*StatWithDesc `json:"stats"`
+ Labels []*cfinstr.Label `json:"labels,omitempty"`
+}
+
+// ToStatsEntriesWithDesc will use the client passed in to adorn constraint framework instrumentation.StatsEntry structs
+// with a description and returns an array of StatsEntryWithDesc.
+func ToStatsEntriesWithDesc(client *constraintclient.Client, cfentries []*cfinstr.StatsEntry) []*StatsEntryWithDesc {
+ var entriesWithDesc []*StatsEntryWithDesc
+ for _, se := range cfentries {
+ sewd := &StatsEntryWithDesc{
+ Scope: se.Scope,
+ StatsFor: se.StatsFor,
+ Labels: se.Labels,
+ }
+
+ var stats []*StatWithDesc
+ for _, stat := range se.Stats {
+ swd := &StatWithDesc{
+ Stat: *stat,
+ }
+
+ var desc string
+ if client != nil {
+ desc = client.GetDescriptionForStat(stat.Source, stat.Name)
+ } else {
+ desc = cfinstr.UnknownDescription
+ }
+
+ swd.Description = desc
+ stats = append(stats, swd)
+ }
+
+ sewd.Stats = stats
+ entriesWithDesc = append(entriesWithDesc, sewd)
+ }
+
+ return entriesWithDesc
+}
diff --git a/pkg/instrumentation/types_test.go b/pkg/instrumentation/types_test.go
new file mode 100644
index 00000000000..b5b9bea7bd0
--- /dev/null
+++ b/pkg/instrumentation/types_test.go
@@ -0,0 +1,154 @@
+package instrumentation
+
+import (
+ "testing"
+
+ constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
+ cfinstr "github.com/open-policy-agent/frameworks/constraint/pkg/instrumentation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func Test_ToStatsEntriesWithDesc(t *testing.T) {
+ driver, err := rego.New()
+ assert.NoError(t, err)
+
+ actualClient, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
+ assert.NoError(t, err)
+
+ testCases := []struct {
+ name string
+ client *constraintclient.Client
+ cfentries []*cfinstr.StatsEntry
+ expected []*StatsEntryWithDesc
+ }{
+ {
+ name: "Empty input",
+ client: nil,
+ cfentries: []*cfinstr.StatsEntry{},
+ expected: nil,
+ },
+ {
+ name: "Single entry with one stat, unknown description",
+ client: nil,
+ cfentries: []*cfinstr.StatsEntry{
+ {
+ Scope: "scope1",
+ StatsFor: "statsFor1",
+ Stats: []*cfinstr.Stat{
+ {
+ Name: "stat1",
+ Value: "value1",
+ },
+ },
+ Labels: []*cfinstr.Label{
+ {
+ Name: "label1",
+ Value: "lvalue1",
+ },
+ },
+ },
+ },
+ expected: []*StatsEntryWithDesc{
+ {
+ Scope: "scope1",
+ StatsFor: "statsFor1",
+ Stats: []*StatWithDesc{
+ {
+ Stat: cfinstr.Stat{
+ Name: "stat1",
+ Value: "value1",
+ },
+ Description: cfinstr.UnknownDescription,
+ },
+ },
+ Labels: []*cfinstr.Label{
+ {
+ Name: "label1",
+ Value: "lvalue1",
+ },
+ },
+ },
+ },
+ },
+ {
+ name: "actual client, stat",
+ client: actualClient,
+ cfentries: []*cfinstr.StatsEntry{
+ {
+ Scope: "scope1",
+ StatsFor: "statsFor1",
+ Stats: []*cfinstr.Stat{
+ {
+ Name: "templateRunTimeNS",
+ Value: "value1",
+ Source: cfinstr.Source{
+ Type: cfinstr.EngineSourceType,
+ Value: "Rego",
+ },
+ },
+ {
+ Name: "constraintCount",
+ Value: "value1",
+ Source: cfinstr.Source{
+ Type: cfinstr.EngineSourceType,
+ Value: "Rego",
+ },
+ },
+ },
+ Labels: []*cfinstr.Label{
+ {
+ Name: "label1",
+ Value: "lvalue1",
+ },
+ },
+ },
+ },
+ expected: []*StatsEntryWithDesc{
+ {
+ Scope: "scope1",
+ StatsFor: "statsFor1",
+ Stats: []*StatWithDesc{
+ {
+ Stat: cfinstr.Stat{
+ Name: "templateRunTimeNS",
+ Value: "value1",
+ Source: cfinstr.Source{
+ Type: cfinstr.EngineSourceType,
+ Value: "Rego",
+ },
+ },
+ Description: "the number of nanoseconds it took to evaluate all constraints for a template",
+ },
+ {
+ Stat: cfinstr.Stat{
+ Name: "constraintCount",
+ Value: "value1",
+ Source: cfinstr.Source{
+ Type: cfinstr.EngineSourceType,
+ Value: "Rego",
+ },
+ },
+ Description: "the number of constraints that were evaluated for the given constraint kind",
+ },
+ },
+ Labels: []*cfinstr.Label{
+ {
+ Name: "label1",
+ Value: "lvalue1",
+ },
+ },
+ },
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ result := ToStatsEntriesWithDesc(tc.client, tc.cfentries)
+ require.Equal(t, tc.expected, result)
+ })
+ }
+}
diff --git a/pkg/keys/config.go b/pkg/keys/config.go
index 2959ccd5aa3..015f57ad3ef 100644
--- a/pkg/keys/config.go
+++ b/pkg/keys/config.go
@@ -16,7 +16,7 @@ limitations under the License.
package keys
import (
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
"k8s.io/apimachinery/pkg/types"
)
diff --git a/pkg/logging/logging.go b/pkg/logging/logging.go
index 48040680896..d9f4ec81b13 100644
--- a/pkg/logging/logging.go
+++ b/pkg/logging/logging.go
@@ -1,5 +1,12 @@
package logging
+import (
+ "github.com/go-logr/logr"
+ constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/instrumentation"
+ gkinstr "github.com/open-policy-agent/gatekeeper/v3/pkg/instrumentation"
+)
+
// Log keys.
const (
Process = "process"
@@ -22,8 +29,18 @@ const (
ResourceAPIVersion = "resource_api_version"
ResourceNamespace = "resource_namespace"
ResourceName = "resource_name"
+ ResourceSourceType = "resource_source_type"
RequestUsername = "request_username"
MutationApplied = "mutation_applied"
Mutator = "mutator"
- DebugLevel = 2 // r.log.Debug(foo) == r.log.V(logging.DebugLevel).Info(foo)
+ DebugLevel = 1 // r.log.Debug(foo) == r.log.V(logging.DebugLevel).Info(foo)
+ ExecutionStats = "execution_stats"
)
+
+func LogStatsEntries(client *constraintclient.Client, logger logr.Logger, entries []*instrumentation.StatsEntry, msg string) {
+ if len(entries) == 0 {
+ return
+ }
+
+ logger.WithValues(ExecutionStats, gkinstr.ToStatsEntriesWithDesc(client, entries)).Info(msg)
+}
diff --git a/pkg/logging/logging_test.go b/pkg/logging/logging_test.go
new file mode 100644
index 00000000000..17ea7f3b120
--- /dev/null
+++ b/pkg/logging/logging_test.go
@@ -0,0 +1,128 @@
+package logging
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+
+ "github.com/go-logr/zapr"
+ constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/instrumentation"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+)
+
+func Test_LogStatsEntries(t *testing.T) {
+ testBuf := &bytes.Buffer{}
+
+ encCfg := zap.NewProductionEncoderConfig()
+ enc := zapcore.NewJSONEncoder(encCfg)
+
+ core := &fakeCore{
+ LevelEnabler: zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
+ return lvl >= zapcore.InfoLevel
+ }),
+ enc: enc,
+ buffer: testBuf,
+ }
+
+ zapLogger := zap.New(core)
+ defer require.NoError(t, zapLogger.Sync())
+ testLogger := zapr.NewLogger(zapLogger)
+
+ // test log lines show up
+ LogStatsEntries(
+ &constraintclient.Client{},
+ testLogger,
+ []*instrumentation.StatsEntry{
+ {
+ Scope: "someScope",
+ StatsFor: "someConstranint",
+ Stats: []*instrumentation.Stat{
+ {
+ Name: "someStat",
+ Value: "someValue",
+ Source: instrumentation.Source{
+ Type: "someType",
+ Value: "someValue",
+ },
+ },
+ },
+ Labels: []*instrumentation.Label{
+ {
+ Name: "someLabel",
+ Value: "someLabelValue",
+ },
+ },
+ },
+ },
+ "test message",
+ )
+
+ expectedLogLine := fmt.Sprintf("\"msg\":\"test message\",\"execution_stats\":[{\"scope\":\"someScope\","+
+ "\"statsFor\":\"someConstranint\",\"stats\":[{\"name\":\"someStat\",\"value\":\"someValue\","+
+ "\"source\":{\"type\":\"someType\",\"value\":\"someValue\"},\"description\":\"%s\"}],"+
+ "\"labels\":[{\"name\":\"someLabel\",\"value\":\"someLabelValue\"}]}]}\n", instrumentation.UnknownDescription)
+ require.Contains(t, testBuf.String(), expectedLogLine)
+
+ // test that empty stats don't log
+ LogStatsEntries(
+ &constraintclient.Client{},
+ testLogger,
+ []*instrumentation.StatsEntry{},
+ "this message should not be logged",
+ )
+ require.NotContains(t, testBuf.String(), "this message should not be logged")
+}
+
+//// logging utilities for testing below /////
+
+// Testing zapcore.Core implementation to intercept log entries in a buffer by choice.
+// Consumers can inspect contents of the buffer to see if it matches expectations.
+// Reusing buffers or loggers not encouraged since this implementation is not focused
+// on thread safety, concurrency or reusability.
+type fakeCore struct {
+ zapcore.LevelEnabler
+ enc zapcore.Encoder
+ buffer *bytes.Buffer
+}
+
+func (c *fakeCore) With(fields []zapcore.Field) zapcore.Core {
+ clone := c.clone()
+ for _, f := range fields {
+ f.AddTo(clone.enc)
+ }
+ return clone
+}
+
+func (c *fakeCore) Check(e zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { //nolint:gocritic
+ if c.Enabled(e.Level) {
+ return ce.AddCore(e, c)
+ }
+ return ce
+}
+
+func (c *fakeCore) Write(e zapcore.Entry, fields []zapcore.Field) error { //nolint:gocritic
+ for _, f := range fields {
+ f.AddTo(c.enc)
+ }
+ buf, err := c.enc.EncodeEntry(e, fields)
+ if err != nil {
+ return err
+ }
+ _, err = c.buffer.Write(buf.Bytes())
+ return err
+}
+
+func (c *fakeCore) Sync() error {
+ return nil // TODO(acpana): revisit implementation for GC / https://github.com/open-policy-agent/gatekeeper/issues/2748
+}
+
+func (c *fakeCore) clone() *fakeCore {
+ return &fakeCore{
+ LevelEnabler: c.LevelEnabler,
+ enc: c.enc.Clone(),
+ buffer: c.buffer,
+ }
+}
diff --git a/pkg/metrics/exporter.go b/pkg/metrics/exporter.go
index 79fd8e44234..d85691272d1 100644
--- a/pkg/metrics/exporter.go
+++ b/pkg/metrics/exporter.go
@@ -3,7 +3,7 @@ package metrics
import (
"context"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics/registry"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics/registry"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
)
diff --git a/pkg/metrics/registry/registry.go b/pkg/metrics/registry/registry.go
index 002806b5950..cd43aeb64fe 100644
--- a/pkg/metrics/registry/registry.go
+++ b/pkg/metrics/registry/registry.go
@@ -9,9 +9,9 @@ import (
"strings"
// register exporters with the registry.
- "github.com/open-policy-agent/gatekeeper/pkg/metrics/exporters/opencensus"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics/exporters/prometheus"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics/exporters/stackdriver"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics/exporters/opencensus"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics/exporters/prometheus"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics/exporters/stackdriver"
)
func init() {
@@ -60,7 +60,7 @@ func newExporterSet(exporters map[string]StartExporter) *exporterSet {
func (es *exporterSet) String() string {
contents := make([]string, 0)
for k := range es.assignedExporters {
- contents = append(contents, string(k))
+ contents = append(contents, k)
}
return fmt.Sprintf("%s", contents)
}
diff --git a/pkg/metrics/registry/registry_test.go b/pkg/metrics/registry/registry_test.go
index ea1812f76fa..392dadf2295 100644
--- a/pkg/metrics/registry/registry_test.go
+++ b/pkg/metrics/registry/registry_test.go
@@ -6,7 +6,7 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics/exporters/prometheus"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics/exporters/prometheus"
)
// Validates flags parsing for metrics reporters.
diff --git a/pkg/mutation/annotations.go b/pkg/mutation/annotations.go
index 72b88156339..cba9b919624 100644
--- a/pkg/mutation/annotations.go
+++ b/pkg/mutation/annotations.go
@@ -5,7 +5,7 @@ import (
"strings"
"github.com/google/uuid"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
diff --git a/pkg/mutation/logging.go b/pkg/mutation/logging.go
index 64dc0e02b1c..f95e4b8cf41 100644
--- a/pkg/mutation/logging.go
+++ b/pkg/mutation/logging.go
@@ -5,12 +5,12 @@ import (
"strings"
"github.com/google/uuid"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
-func logAppliedMutations(message string, mutationUUID uuid.UUID, obj *unstructured.Unstructured, allAppliedMutations [][]types.Mutator) {
+func logAppliedMutations(message string, mutationUUID uuid.UUID, obj *unstructured.Unstructured, allAppliedMutations [][]types.Mutator, source types.SourceType) {
iterations := make([]interface{}, 0, 2*len(allAppliedMutations))
for i, appliedMutations := range allAppliedMutations {
if len(appliedMutations) == 0 {
@@ -33,9 +33,22 @@ func logAppliedMutations(message string, mutationUUID uuid.UUID, obj *unstructur
logging.ResourceKind, obj.GroupVersionKind().Kind,
logging.ResourceAPIVersion, obj.GroupVersionKind().Version,
logging.ResourceNamespace, obj.GetNamespace(),
- logging.ResourceName, obj.GetName(),
+ logging.ResourceName, getNameOrGenerateName(obj),
+ logging.ResourceSourceType, source,
+ logging.ResourceLabels, obj.GetLabels(),
}
logDetails = append(logDetails, iterations...)
log.Info(message, logDetails...)
}
}
+
+func getNameOrGenerateName(obj *unstructured.Unstructured) string {
+ resourceName := obj.GetName()
+ // for generated resources on CREATE, like a pod from a deployment,
+ // the name has not been populated yet, so we use the GeneratedName instead.
+ if resourceName == "" {
+ resourceName = obj.GetGenerateName()
+ }
+
+ return resourceName
+}
diff --git a/pkg/mutation/match/match.go b/pkg/mutation/match/match.go
index a65af53fc18..f0f935479a6 100644
--- a/pkg/mutation/match/match.go
+++ b/pkg/mutation/match/match.go
@@ -5,8 +5,7 @@ import (
"fmt"
"reflect"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -20,62 +19,8 @@ var ErrMatch = errors.New("failed to run Match criteria")
// Only for use in Match, not ApplyTo.
const Wildcard = "*"
-// Match selects objects to apply mutations to.
-// +kubebuilder:object:generate=true
-type Match struct {
- // Source determines whether generated or original resources are matched.
- // Accepts `Generated`|`Original`|`All` (defaults to `All`). A value of
- // `Generated` will only match generated resources, while `Original` will only
- // match regular resources.
- // +kubebuilder:validation:Enum=All;Generated;Original
- Source string `json:"source,omitempty"`
- Kinds []Kinds `json:"kinds,omitempty"`
- // Scope determines if cluster-scoped and/or namespaced-scoped resources
- // are matched. Accepts `*`, `Cluster`, or `Namespaced`. (defaults to `*`)
- Scope apiextensionsv1.ResourceScope `json:"scope,omitempty"`
- // Namespaces is a list of namespace names. If defined, a constraint only
- // applies to resources in a listed namespace. Namespaces also supports a
- // prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both
- // `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both
- // `kube-system` and `gatekeeper-system`.
- Namespaces []util.Wildcard `json:"namespaces,omitempty"`
- // ExcludedNamespaces is a list of namespace names. If defined, a
- // constraint only applies to resources not in a listed namespace.
- // ExcludedNamespaces also supports a prefix or suffix based glob. For example,
- // `excludedNamespaces: [kube-*]` matches both `kube-system` and
- // `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and
- // `gatekeeper-system`.
- ExcludedNamespaces []util.Wildcard `json:"excludedNamespaces,omitempty"`
- // LabelSelector is the combination of two optional fields: `matchLabels`
- // and `matchExpressions`. These two fields provide different methods of
- // selecting or excluding k8s objects based on the label keys and values
- // included in object metadata. All selection expressions from both
- // sections are ANDed to determine if an object meets the cumulative
- // requirements of the selector.
- LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"`
- // NamespaceSelector is a label selector against an object's containing
- // namespace or the object itself, if the object is a namespace.
- NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"`
- // Name is the name of an object. If defined, it will match against objects with the specified
- // name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match
- // both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.
- Name util.Wildcard `json:"name,omitempty"`
-}
-
-// Kinds accepts a list of objects with apiGroups and kinds fields
-// that list the groups/kinds of objects to which the mutation will apply.
-// If multiple groups/kinds objects are specified,
-// only one match is needed for the resource to be in scope.
-// +kubebuilder:object:generate=true
-type Kinds struct {
- // APIGroups is the API groups the resources belong to. '*' is all groups.
- // If '*' is present, the length of the slice must be one.
- // Required.
- APIGroups []string `json:"apiGroups,omitempty" protobuf:"bytes,1,rep,name=apiGroups"`
- Kinds []string `json:"kinds,omitempty"`
-}
-
// Matchable represent an object to be matched along with its metadata.
+// +kubebuilder:object:generate=false
type Matchable struct {
Object client.Object
Namespace *corev1.Namespace
@@ -107,7 +52,7 @@ func Matches(match *Match, target *Matchable) (bool, error) {
for _, fn := range topLevelMatchers {
matches, err := fn(match, target)
if err != nil {
- return false, fmt.Errorf("%w: %v", ErrMatch, err)
+ return false, fmt.Errorf("%w: %w", ErrMatch, err)
}
if !matches {
@@ -263,7 +208,7 @@ func namesMatch(match *Match, target *Matchable) (bool, error) {
return true, nil
}
- return match.Name.Matches(target.Object.GetName()), nil
+ return match.Name.Matches(target.Object.GetName()) || match.Name.MatchesGenerateName(target.Object.GetGenerateName()), nil
}
func scopeMatch(match *Match, target *Matchable) (bool, error) {
diff --git a/pkg/mutation/match/match_test.go b/pkg/mutation/match/match_test.go
index 71b586d0d7d..5a5382fb4f2 100644
--- a/pkg/mutation/match/match_test.go
+++ b/pkg/mutation/match/match_test.go
@@ -4,8 +4,8 @@ import (
"errors"
"testing"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -188,7 +188,7 @@ func TestMatch(t *testing.T) {
name: "namespace matches",
object: makeObject(schema.GroupVersionKind{Kind: "kind", Group: "group"}, "namespace", "name"),
matcher: Match{
- Namespaces: []util.Wildcard{"nonmatching", "namespace"},
+ Namespaces: []wildcard.Wildcard{"nonmatching", "namespace"},
},
namespace: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "namespace"}},
source: types.SourceTypeOriginal,
@@ -198,7 +198,7 @@ func TestMatch(t *testing.T) {
name: "is a matching Namespace",
object: makeNamespace("matching"),
matcher: Match{
- Namespaces: []util.Wildcard{"matching"},
+ Namespaces: []wildcard.Wildcard{"matching"},
},
namespace: nil,
source: types.SourceTypeOriginal,
@@ -208,7 +208,7 @@ func TestMatch(t *testing.T) {
name: "is not a matching Namespace",
object: makeNamespace("non-matching"),
matcher: Match{
- Namespaces: []util.Wildcard{"matching"},
+ Namespaces: []wildcard.Wildcard{"matching"},
},
namespace: nil,
source: types.SourceTypeOriginal,
@@ -219,7 +219,7 @@ func TestMatch(t *testing.T) {
name: "namespaces configured, but cluster scoped",
object: makeObject(schema.GroupVersionKind{Kind: "kind", Group: "group"}, "", "name"),
matcher: Match{
- Namespaces: []util.Wildcard{"nonmatching", "namespace"},
+ Namespaces: []wildcard.Wildcard{"nonmatching", "namespace"},
},
namespace: nil,
source: types.SourceTypeOriginal,
@@ -229,7 +229,7 @@ func TestMatch(t *testing.T) {
name: "namespace prefix matches",
object: makeObject(schema.GroupVersionKind{Kind: "kind", Group: "group"}, "kube-system", "name"),
matcher: Match{
- Namespaces: []util.Wildcard{"nonmatching", "kube-*"},
+ Namespaces: []wildcard.Wildcard{"nonmatching", "kube-*"},
},
namespace: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "kube-system"}},
source: types.SourceTypeOriginal,
@@ -239,7 +239,7 @@ func TestMatch(t *testing.T) {
name: "namespace is not in the matches list",
object: makeObject(schema.GroupVersionKind{Kind: "kind", Group: "group"}, "namespace2", "name"),
matcher: Match{
- Namespaces: []util.Wildcard{"nonmatching", "notmatchingeither"},
+ Namespaces: []wildcard.Wildcard{"nonmatching", "notmatchingeither"},
},
namespace: nil,
source: types.SourceTypeOriginal,
@@ -319,7 +319,7 @@ func TestMatch(t *testing.T) {
name: "object's namespace is excluded",
object: makeObject(schema.GroupVersionKind{Kind: "kind", Group: "group"}, "namespace", "name"),
matcher: Match{
- ExcludedNamespaces: []util.Wildcard{"namespace"},
+ ExcludedNamespaces: []wildcard.Wildcard{"namespace"},
},
namespace: nil,
source: types.SourceTypeOriginal,
@@ -329,7 +329,7 @@ func TestMatch(t *testing.T) {
name: "object is an excluded Namespace",
object: makeNamespace("excluded"),
matcher: Match{
- ExcludedNamespaces: []util.Wildcard{"excluded"},
+ ExcludedNamespaces: []wildcard.Wildcard{"excluded"},
},
namespace: nil,
source: types.SourceTypeOriginal,
@@ -339,7 +339,7 @@ func TestMatch(t *testing.T) {
name: "object is not an excluded Namespace",
object: makeNamespace("not-excluded"),
matcher: Match{
- ExcludedNamespaces: []util.Wildcard{"excluded"},
+ ExcludedNamespaces: []wildcard.Wildcard{"excluded"},
},
namespace: nil,
source: types.SourceTypeOriginal,
@@ -350,7 +350,7 @@ func TestMatch(t *testing.T) {
name: "a namespace is excluded, but object is cluster scoped",
object: makeObject(schema.GroupVersionKind{Kind: "kind", Group: "group"}, "", "name"),
matcher: Match{
- ExcludedNamespaces: []util.Wildcard{"namespace"},
+ ExcludedNamespaces: []wildcard.Wildcard{"namespace"},
},
namespace: nil,
source: types.SourceTypeOriginal,
@@ -360,7 +360,7 @@ func TestMatch(t *testing.T) {
name: "namespace is excluded by wildcard match",
object: makeObject(schema.GroupVersionKind{Kind: "kind", Group: "group"}, "kube-system", "name"),
matcher: Match{
- ExcludedNamespaces: []util.Wildcard{"kube-*"},
+ ExcludedNamespaces: []wildcard.Wildcard{"kube-*"},
},
namespace: &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "kube-system"}},
source: types.SourceTypeOriginal,
@@ -598,7 +598,7 @@ func TestMatch(t *testing.T) {
object: makeObject(schema.GroupVersionKind{Kind: "kind", Group: "group"}, "namespace", "name-foo"),
matcher: Match{
Name: "name-foo",
- Namespaces: []util.Wildcard{"other-namespace"},
+ Namespaces: []wildcard.Wildcard{"other-namespace"},
},
namespace: nil,
source: types.SourceTypeOriginal,
@@ -609,7 +609,7 @@ func TestMatch(t *testing.T) {
object: makeObject(schema.GroupVersionKind{Kind: "kind", Group: "group"}, "namespace", "name-foo"),
matcher: Match{
Name: "name-foo",
- Namespaces: []util.Wildcard{"my-ns"},
+ Namespaces: []wildcard.Wildcard{"my-ns"},
Source: string(types.SourceTypeGenerated),
},
source: types.SourceTypeGenerated,
@@ -625,7 +625,7 @@ func TestMatch(t *testing.T) {
object: makeObject(schema.GroupVersionKind{Kind: "kind", Group: "group"}, "namespace", "name-foo"),
matcher: Match{
Name: "name-foo",
- Namespaces: []util.Wildcard{"my-ns"},
+ Namespaces: []wildcard.Wildcard{"my-ns"},
},
source: types.SourceTypeGenerated,
namespace: &corev1.Namespace{
@@ -640,7 +640,7 @@ func TestMatch(t *testing.T) {
object: makeObject(schema.GroupVersionKind{Kind: "kind", Group: "group"}, "namespace", "name-foo"),
matcher: Match{
Name: "name-foo",
- Namespaces: []util.Wildcard{"my-ns"},
+ Namespaces: []wildcard.Wildcard{"my-ns"},
Source: string(types.SourceTypeOriginal),
},
source: types.SourceTypeGenerated,
@@ -656,7 +656,7 @@ func TestMatch(t *testing.T) {
object: makeObject(schema.GroupVersionKind{Kind: "kind", Group: "group"}, "namespace", "name-foo"),
matcher: Match{
Name: "name-foo",
- Namespaces: []util.Wildcard{"my-ns"},
+ Namespaces: []wildcard.Wildcard{"my-ns"},
Source: string(types.SourceTypeOriginal),
},
namespace: &corev1.Namespace{
@@ -831,3 +831,210 @@ func TestApplyTo(t *testing.T) {
})
}
}
+
+func makeObjectWithGenerateName(gvk schema.GroupVersionKind, namespace, name string, options ...func(*unstructured.Unstructured)) *unstructured.Unstructured {
+ obj := &unstructured.Unstructured{Object: make(map[string]interface{})}
+ obj.SetGroupVersionKind(gvk)
+ obj.SetNamespace(namespace)
+ obj.SetGenerateName(name)
+
+ for _, o := range options {
+ o(obj)
+ }
+ return obj
+}
+
+func Test_namesMatch(t *testing.T) {
+ type args struct {
+ match *Match
+ target *Matchable
+ }
+
+ tests := []struct {
+ name string
+ args args
+ want bool
+ wantErr bool
+ }{
+ {
+ name: "match name with wild card",
+ args: args{
+ match: &Match{
+ Name: "foo*",
+ Kinds: []Kinds{
+ {
+ Kinds: []string{"Pod"},
+ APIGroups: []string{"*"},
+ },
+ },
+ },
+ target: &Matchable{
+ Object: makeObject(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "foo-bar"),
+ Namespace: &corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-ns",
+ },
+ },
+ },
+ },
+ want: true,
+ wantErr: false,
+ },
+ {
+ name: "match generate name with wild card",
+ args: args{
+ match: &Match{
+ Name: "foo*",
+ Kinds: []Kinds{
+ {
+ Kinds: []string{"Pod"},
+ APIGroups: []string{"*"},
+ },
+ },
+ },
+ target: &Matchable{
+ Object: makeObjectWithGenerateName(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "foo-bar-"),
+ Namespace: &corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-ns",
+ },
+ },
+ },
+ },
+ want: true,
+ wantErr: false,
+ },
+ {
+ name: "match different name with wild card",
+ args: args{
+ match: &Match{
+ Name: "foo*",
+ Kinds: []Kinds{
+ {
+ Kinds: []string{"Pod"},
+ APIGroups: []string{"*"},
+ },
+ },
+ },
+ target: &Matchable{
+ Object: makeObject(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "fob"),
+ Namespace: &corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-ns",
+ },
+ },
+ },
+ },
+ want: false,
+ wantErr: false,
+ },
+ {
+ name: "match different generate name with wild card",
+ args: args{
+ match: &Match{
+ Name: "foo*",
+ Kinds: []Kinds{
+ {
+ Kinds: []string{"Pod"},
+ APIGroups: []string{"*"},
+ },
+ },
+ },
+ target: &Matchable{
+ Object: makeObjectWithGenerateName(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "fob-bar-"),
+ Namespace: &corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-ns",
+ },
+ },
+ },
+ },
+ want: false,
+ wantErr: false,
+ },
+ {
+ name: "match whole name with generate name",
+ args: args{
+ match: &Match{
+ Name: "foo",
+ Kinds: []Kinds{
+ {
+ Kinds: []string{"Pod"},
+ APIGroups: []string{"*"},
+ },
+ },
+ },
+ target: &Matchable{
+ Object: makeObjectWithGenerateName(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "foo"),
+ Namespace: &corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-ns",
+ },
+ },
+ },
+ },
+ want: false,
+ wantErr: false,
+ },
+ {
+ name: "match prefix wildcard with generate name",
+ args: args{
+ match: &Match{
+ Name: "*foo",
+ Kinds: []Kinds{
+ {
+ Kinds: []string{"Pod"},
+ APIGroups: []string{"*"},
+ },
+ },
+ },
+ target: &Matchable{
+ Object: makeObjectWithGenerateName(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "foo"),
+ Namespace: &corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-ns",
+ },
+ },
+ },
+ },
+ want: false,
+ wantErr: false,
+ },
+ {
+ name: "match later half of the name with wild card with generate name",
+ args: args{
+ match: &Match{
+ Name: "*-bar*",
+ Kinds: []Kinds{
+ {
+ Kinds: []string{"Pod"},
+ APIGroups: []string{"*"},
+ },
+ },
+ },
+ target: &Matchable{
+ Object: makeObjectWithGenerateName(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "fob-bar"),
+ Namespace: &corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-ns",
+ },
+ },
+ },
+ },
+ want: true,
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := namesMatch(tt.args.match, tt.args.target)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("namesMatch() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if got != tt.want {
+ t.Errorf("namesMatch() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
diff --git a/pkg/mutation/match/match_types.go b/pkg/mutation/match/match_types.go
new file mode 100644
index 00000000000..9bc66540d16
--- /dev/null
+++ b/pkg/mutation/match/match_types.go
@@ -0,0 +1,75 @@
+// +kubebuilder:object:generate=true
+// +groupName=match.gatekeeper.sh
+package match
+
+import (
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// Match selects which objects are in scope.
+// +kubebuilder:object:generate=true
+type Match struct {
+ // Source determines whether generated or original resources are matched.
+ // Accepts `Generated`|`Original`|`All` (defaults to `All`). A value of
+ // `Generated` will only match generated resources, while `Original` will only
+ // match regular resources.
+ // +kubebuilder:validation:Enum=All;Generated;Original
+ Source string `json:"source,omitempty"`
+ Kinds []Kinds `json:"kinds,omitempty"`
+ // Scope determines if cluster-scoped and/or namespaced-scoped resources
+ // are matched. Accepts `*`, `Cluster`, or `Namespaced`. (defaults to `*`)
+ Scope apiextensionsv1.ResourceScope `json:"scope,omitempty"`
+ // Namespaces is a list of namespace names. If defined, a constraint only
+ // applies to resources in a listed namespace. Namespaces also supports a
+ // prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both
+ // `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both
+ // `kube-system` and `gatekeeper-system`.
+ Namespaces []wildcard.Wildcard `json:"namespaces,omitempty"`
+ // ExcludedNamespaces is a list of namespace names. If defined, a
+ // constraint only applies to resources not in a listed namespace.
+ // ExcludedNamespaces also supports a prefix or suffix based glob. For example,
+ // `excludedNamespaces: [kube-*]` matches both `kube-system` and
+ // `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and
+ // `gatekeeper-system`.
+ ExcludedNamespaces []wildcard.Wildcard `json:"excludedNamespaces,omitempty"`
+ // LabelSelector is the combination of two optional fields: `matchLabels`
+ // and `matchExpressions`. These two fields provide different methods of
+ // selecting or excluding k8s objects based on the label keys and values
+ // included in object metadata. All selection expressions from both
+ // sections are ANDed to determine if an object meets the cumulative
+ // requirements of the selector.
+ LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"`
+ // NamespaceSelector is a label selector against an object's containing
+ // namespace or the object itself, if the object is a namespace.
+ NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"`
+ // Name is the name of an object. If defined, it will match against objects with the specified
+ // name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match
+ // both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.
+ Name wildcard.Wildcard `json:"name,omitempty"`
+}
+
+// Kinds accepts a list of objects with apiGroups and kinds fields
+// that list the groups/kinds of objects to which the mutation will apply.
+// If multiple groups/kinds objects are specified,
+// only one match is needed for the resource to be in scope.
+// +kubebuilder:object:generate=true
+type Kinds struct {
+ // APIGroups is the API groups the resources belong to. '*' is all groups.
+ // If '*' is present, the length of the slice must be one.
+ // Required.
+ APIGroups []string `json:"apiGroups,omitempty" protobuf:"bytes,1,rep,name=apiGroups"`
+ Kinds []string `json:"kinds,omitempty"`
+}
+
+// DummyCRD is a "dummy" CRD to hold the Match object, which we ultimately
+// need to generate JSONSchemaProps. The TypeMeta and ObjectMeta fields are
+// required for controller-gen to generate the CRD.
+// +kubebuilder:resource:path="matchcrd"
+type DummyCRD struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadataDummy,omitempty"`
+
+ Match `json:"embeddedMatch,omitempty"`
+}
diff --git a/pkg/mutation/match/zz_generated.deepcopy.go b/pkg/mutation/match/zz_generated.deepcopy.go
index 88cf2894ff7..26213f1e2d5 100644
--- a/pkg/mutation/match/zz_generated.deepcopy.go
+++ b/pkg/mutation/match/zz_generated.deepcopy.go
@@ -21,7 +21,7 @@ limitations under the License.
package match
import (
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
"k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -55,6 +55,24 @@ func (in *ApplyTo) DeepCopy() *ApplyTo {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *DummyCRD) DeepCopyInto(out *DummyCRD) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Match.DeepCopyInto(&out.Match)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DummyCRD.
+func (in *DummyCRD) DeepCopy() *DummyCRD {
+ if in == nil {
+ return nil
+ }
+ out := new(DummyCRD)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Kinds) DeepCopyInto(out *Kinds) {
*out = *in
@@ -92,12 +110,12 @@ func (in *Match) DeepCopyInto(out *Match) {
}
if in.Namespaces != nil {
in, out := &in.Namespaces, &out.Namespaces
- *out = make([]util.Wildcard, len(*in))
+ *out = make([]wildcard.Wildcard, len(*in))
copy(*out, *in)
}
if in.ExcludedNamespaces != nil {
in, out := &in.ExcludedNamespaces, &out.ExcludedNamespaces
- *out = make([]util.Wildcard, len(*in))
+ *out = make([]wildcard.Wildcard, len(*in))
copy(*out, *in)
}
if in.LabelSelector != nil {
diff --git a/pkg/mutation/mutation.go b/pkg/mutation/mutation.go
index f2997c1594a..ad468b9afa2 100644
--- a/pkg/mutation/mutation.go
+++ b/pkg/mutation/mutation.go
@@ -15,8 +15,8 @@ package mutation
import (
"flag"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
@@ -34,5 +34,5 @@ func init() {
// Enabled indicates if the mutation feature is enabled.
func Enabled() bool {
- return operations.IsAssigned(operations.MutationStatus) || operations.IsAssigned(operations.MutationWebhook)
+ return operations.IsAssigned(operations.MutationStatus) || operations.IsAssigned(operations.MutationWebhook) || operations.IsAssigned(operations.MutationController)
}
diff --git a/pkg/mutation/mutators/assign/assign_mutator.go b/pkg/mutation/mutators/assign/assign_mutator.go
index e06fee11cea..4315deb3ee3 100644
--- a/pkg/mutation/mutators/assign/assign_mutator.go
+++ b/pkg/mutation/mutators/assign/assign_mutator.go
@@ -3,18 +3,16 @@ package assign
import (
"fmt"
"reflect"
- "sort"
"github.com/google/go-cmp/cmp"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- mutationsv1beta1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/core"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- patht "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/schema"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ mutationsv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/core"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ patht "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/schema"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"github.com/pkg/errors"
runtimeschema "k8s.io/apimachinery/pkg/runtime/schema"
logf "sigs.k8s.io/controller-runtime/pkg/log"
@@ -38,22 +36,12 @@ type Mutator struct {
// Mutator implements mutatorWithSchema.
var _ schema.MutatorWithSchema = &Mutator{}
-func (m *Mutator) Matches(mutable *types.Mutable) bool {
- gvk := mutable.Object.GetObjectKind().GroupVersionKind()
- if !match.AppliesTo(m.assign.Spec.ApplyTo, gvk) {
- return false
- }
- target := &match.Matchable{
- Object: mutable.Object,
- Namespace: mutable.Namespace,
- Source: mutable.Source,
- }
- matches, err := match.Matches(&m.assign.Spec.Match, target)
+func (m *Mutator) Matches(mutable *types.Mutable) (bool, error) {
+ res, err := core.MatchWithApplyTo(mutable, m.assign.Spec.ApplyTo, &m.assign.Spec.Match)
if err != nil {
log.Error(err, "Matches failed for assign", "assign", m.assign.Name)
- return false
}
- return matches
+ return res, err
}
func (m *Mutator) TerminalType() parser.NodeType {
@@ -68,7 +56,7 @@ func (m *Mutator) Mutate(mutable *types.Mutable) (bool, error) {
return core.Mutate(m.Path(), m.tester, core.NewDefaultSetter(value), mutable.Object)
}
-func (m *Mutator) UsesExternalData() bool {
+func (m *Mutator) MustTerminate() bool {
return m.assign.Spec.Parameters.Assign.ExternalData != nil
}
@@ -128,8 +116,7 @@ func (m *Mutator) String() string {
return fmt.Sprintf("%s/%s/%s:%d", m.id.Kind, m.id.Namespace, m.id.Name, m.assign.GetGeneration())
}
-// MutatorForAssign returns an mutator built from
-// the given assign instance.
+// MutatorForAssign returns a mutator built from the given assign instance.
func MutatorForAssign(assign *mutationsunversioned.Assign) (*Mutator, error) {
// This is not always set by the kubernetes API server
assign.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: mutationsv1beta1.GroupVersion.Group, Kind: "Assign"})
@@ -143,7 +130,7 @@ func MutatorForAssign(assign *mutationsunversioned.Assign) (*Mutator, error) {
return nil, fmt.Errorf("assign %s can't change metadata", assign.GetName())
}
- err = checkKeyNotChanged(path)
+ err = core.CheckKeyNotChanged(path)
if err != nil {
return nil, err
}
@@ -168,29 +155,17 @@ func MutatorForAssign(assign *mutationsunversioned.Assign) (*Mutator, error) {
}
}
- id := types.MakeID(assign)
-
- pathTests, err := gatherPathTests(assign)
+ tester, err := core.NewTester(assign.GetName(), "Assign", path, assign.Spec.Parameters.PathTests)
if err != nil {
return nil, err
}
- tester, err := patht.New(path, pathTests)
+ gvks, err := core.NewValidatedBindings(assign.GetName(), "Assign", assign.Spec.ApplyTo)
if err != nil {
return nil, err
}
- for _, applyTo := range assign.Spec.ApplyTo {
- if len(applyTo.Groups) == 0 || len(applyTo.Versions) == 0 || len(applyTo.Kinds) == 0 {
- return nil, fmt.Errorf("invalid applyTo for Assign mutator %s, all of group, version and kind must be specified", assign.GetName())
- }
- }
-
- gvks := getSortedGVKs(assign.Spec.ApplyTo)
- if len(gvks) == 0 {
- return nil, fmt.Errorf("applyTo required for Assign mutator %s", assign.GetName())
- }
return &Mutator{
- id: id,
+ id: types.MakeID(assign),
assign: assign.DeepCopy(),
bindings: gvks,
path: path,
@@ -198,19 +173,6 @@ func MutatorForAssign(assign *mutationsunversioned.Assign) (*Mutator, error) {
}, nil
}
-func gatherPathTests(assign *mutationsunversioned.Assign) ([]patht.Test, error) {
- pts := assign.Spec.Parameters.PathTests
- var pathTests []patht.Test
- for _, pt := range pts {
- p, err := parser.Parse(pt.SubPath)
- if err != nil {
- return nil, errors.Wrap(err, fmt.Sprintf("problem parsing sub path `%s` for Assign %s", pt.SubPath, assign.GetName()))
- }
- pathTests = append(pathTests, patht.Test{SubPath: p, Condition: pt.Condition})
- }
- return pathTests, nil
-}
-
// IsValidAssign returns an error if the given assign object is not
// semantically valid.
func IsValidAssign(assign *mutationsunversioned.Assign) error {
@@ -231,39 +193,6 @@ func hasMetadataRoot(path parser.Path) bool {
return false
}
-// checkKeyNotChanged does not allow to change the key field of
-// a list element. A path like foo[name: bar].name is rejected.
-func checkKeyNotChanged(p parser.Path) error {
- if len(p.Nodes) == 0 {
- return errors.New("empty path")
- }
- if len(p.Nodes) < 2 {
- return nil
- }
- lastNode := p.Nodes[len(p.Nodes)-1]
- secondLastNode := p.Nodes[len(p.Nodes)-2]
-
- if secondLastNode.Type() != parser.ListNode {
- return nil
- }
- if lastNode.Type() != parser.ObjectNode {
- return fmt.Errorf("invalid path format: child of a list can't be a list")
- }
- addedObject, ok := lastNode.(*parser.Object)
- if !ok {
- return errors.New("failed converting an ObjectNodeType to Object")
- }
- listNode, ok := secondLastNode.(*parser.List)
- if !ok {
- return errors.New("failed converting a ListNodeType to List")
- }
-
- if addedObject.Reference == listNode.KeyField {
- return fmt.Errorf("invalid path format: changing the item key is not allowed")
- }
- return nil
-}
-
func validateObjectAssignedToList(p parser.Path, value interface{}) error {
if len(p.Nodes) == 0 {
return errors.New("empty path")
@@ -291,24 +220,3 @@ func validateObjectAssignedToList(p parser.Path, value interface{}) error {
return nil
}
-
-func getSortedGVKs(bindings []match.ApplyTo) []runtimeschema.GroupVersionKind {
- // deduplicate GVKs
- gvksMap := map[runtimeschema.GroupVersionKind]struct{}{}
- for _, binding := range bindings {
- for _, gvk := range binding.Flatten() {
- gvksMap[gvk] = struct{}{}
- }
- }
-
- var gvks []runtimeschema.GroupVersionKind
- for gvk := range gvksMap {
- gvks = append(gvks, gvk)
- }
-
- // we iterate over the map in a stable order so that
- // unit tests won't be flaky.
- sort.Slice(gvks, func(i, j int) bool { return gvks[i].String() < gvks[j].String() })
-
- return gvks
-}
diff --git a/pkg/mutation/mutators/assign/assign_mutator_benchmark_test.go b/pkg/mutation/mutators/assign/assign_mutator_benchmark_test.go
index d113862afd5..74deef1c5d6 100644
--- a/pkg/mutation/mutators/assign/assign_mutator_benchmark_test.go
+++ b/pkg/mutation/mutators/assign/assign_mutator_benchmark_test.go
@@ -5,10 +5,10 @@ import (
"strings"
"testing"
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
diff --git a/pkg/mutation/mutators/assign/assign_mutator_test.go b/pkg/mutation/mutators/assign/assign_mutator_test.go
index a9d460ba50f..af4a19ef071 100644
--- a/pkg/mutation/mutators/assign/assign_mutator_test.go
+++ b/pkg/mutation/mutators/assign/assign_mutator_test.go
@@ -8,11 +8,12 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/google/go-cmp/cmp"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- path "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/externaldata"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ path "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -91,7 +92,7 @@ func newPod(pod *corev1.Pod) *unstructured.Unstructured {
func ensureObj(u *unstructured.Unstructured, expected interface{}, path ...string) error {
v, exists, err := unstructured.NestedFieldNoCopy(u.Object, path...)
if err != nil {
- return fmt.Errorf("could not retrieve value: %v", err)
+ return fmt.Errorf("could not retrieve value: %w", err)
}
if !exists {
return fmt.Errorf("value does not exist at %+v: %s", path, spew.Sdump(u.Object))
@@ -105,7 +106,7 @@ func ensureObj(u *unstructured.Unstructured, expected interface{}, path ...strin
func ensureMissing(u *unstructured.Unstructured, path ...string) error {
v, exists, err := unstructured.NestedFieldNoCopy(u.Object, path...)
if err != nil {
- return fmt.Errorf("could not retrieve value: %v", err)
+ return fmt.Errorf("could not retrieve value: %w", err)
}
if exists {
return fmt.Errorf("value exists at %+v as %v, expected missing: %s", path, v, spew.Sdump(u.Object))
@@ -774,7 +775,8 @@ func TestApplyTo(t *testing.T) {
Version: test.version,
Kind: test.kind,
})
- matches := mutator.Matches(&types.Mutable{Object: obj, Source: types.SourceTypeDefault})
+ matches, err := mutator.Matches(&types.Mutable{Object: obj, Source: types.SourceTypeDefault})
+ require.NoError(t, err)
if matches != test.matchExpected {
t.Errorf("Matches() = %t, expected %t", matches, test.matchExpected)
}
@@ -1070,3 +1072,12 @@ func nestedMapSlice(u map[string]interface{}, fields ...string) ([]map[string]in
}
return out, nil
}
+
+// Tests the Assign mutator MutatorForAssign call with an empty spec for graceful handling.
+func Test_Assign_emptySpec(t *testing.T) {
+ assign := &mutationsunversioned.Assign{}
+ mutator, err := MutatorForAssign(assign)
+
+ require.ErrorContains(t, err, "empty path")
+ require.Nil(t, mutator)
+}
diff --git a/pkg/mutation/mutators/assignimage/assignimage_mutator.go b/pkg/mutation/mutators/assignimage/assignimage_mutator.go
new file mode 100644
index 00000000000..d0862538a15
--- /dev/null
+++ b/pkg/mutation/mutators/assignimage/assignimage_mutator.go
@@ -0,0 +1,206 @@
+package assignimage
+
+import (
+ "fmt"
+
+ "github.com/google/go-cmp/cmp"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ mutationsv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/core"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ patht "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/schema"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/pkg/errors"
+ runtimeschema "k8s.io/apimachinery/pkg/runtime/schema"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+var log = logf.Log.WithName("mutation").WithValues(logging.Process, "mutation", logging.Mutator, "assignimage")
+
+// Mutator is a mutator object built out of an AssignImage instance.
+type Mutator struct {
+ id types.ID
+ assignImage *mutationsunversioned.AssignImage
+
+ path parser.Path
+
+ // bindings are the set of GVKs this Mutator applies to.
+ bindings []runtimeschema.GroupVersionKind
+ tester *patht.Tester
+}
+
+// Mutator implements mutatorWithSchema.
+var _ schema.MutatorWithSchema = &Mutator{}
+
+func (m *Mutator) Matches(mutable *types.Mutable) (bool, error) {
+ res, err := core.MatchWithApplyTo(mutable, m.assignImage.Spec.ApplyTo, &m.assignImage.Spec.Match)
+ if err != nil {
+ log.Error(err, "Matches failed for assign image", "assignImage", m.assignImage.Name)
+ }
+ return res, err
+}
+
+func (m *Mutator) TerminalType() parser.NodeType {
+ return schema.String
+}
+
+func (m *Mutator) Mutate(mutable *types.Mutable) (bool, error) {
+ p := m.assignImage.Spec.Parameters
+ s := setter{tag: p.AssignTag, domain: p.AssignDomain, path: p.AssignPath}
+ return core.Mutate(m.Path(), m.tester, s, mutable.Object)
+}
+
+func (m *Mutator) MustTerminate() bool {
+ return true
+}
+
+func (m *Mutator) ID() types.ID {
+ return m.id
+}
+
+func (m *Mutator) SchemaBindings() []runtimeschema.GroupVersionKind {
+ return m.bindings
+}
+
+func (m *Mutator) HasDiff(mutator types.Mutator) bool {
+ toCheck, ok := mutator.(*Mutator)
+ if !ok { // different types, different
+ return true
+ }
+
+ if !cmp.Equal(toCheck.id, m.id) {
+ return true
+ }
+ if !cmp.Equal(toCheck.path, m.path) {
+ return true
+ }
+ if !cmp.Equal(toCheck.bindings, m.bindings) {
+ return true
+ }
+
+ // any difference in spec may be enough
+ if !cmp.Equal(toCheck.assignImage.Spec, m.assignImage.Spec) {
+ return true
+ }
+
+ return false
+}
+
+func (m *Mutator) Path() parser.Path {
+ return m.path
+}
+
+func (m *Mutator) DeepCopy() types.Mutator {
+ res := &Mutator{
+ id: m.id,
+ assignImage: m.assignImage.DeepCopy(),
+ path: parser.Path{
+ Nodes: make([]parser.Node, len(m.path.Nodes)),
+ },
+ bindings: make([]runtimeschema.GroupVersionKind, len(m.bindings)),
+ }
+
+ copy(res.path.Nodes, m.path.Nodes)
+ copy(res.bindings, m.bindings)
+ res.tester = m.tester.DeepCopy()
+ return res
+}
+
+func (m *Mutator) String() string {
+ return fmt.Sprintf("%s/%s/%s:%d", m.id.Kind, m.id.Namespace, m.id.Name, m.assignImage.GetGeneration())
+}
+
+// MutatorForAssignImage returns a mutator built from
+// the given assignImage instance.
+func MutatorForAssignImage(assignImage *mutationsunversioned.AssignImage) (*Mutator, error) {
+ // This is not always set by the kubernetes API server
+ assignImage.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: mutationsv1beta1.GroupVersion.Group, Kind: "AssignImage"})
+
+ path, err := parser.Parse(assignImage.Spec.Location)
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid location format `%s` for assignImage %s", assignImage.Spec.Location, assignImage.GetName())
+ }
+
+ if core.HasMetadataRoot(path) {
+ return nil, newMetadataRootError(assignImage.GetName())
+ }
+
+ if hasListTerminal(path) {
+ return nil, newListTerminalError(assignImage.GetName())
+ }
+
+ err = core.CheckKeyNotChanged(path)
+ if err != nil {
+ return nil, err
+ }
+
+ p := assignImage.Spec.Parameters
+ if err := validateImageParts(p.AssignDomain, p.AssignPath, p.AssignTag); err != nil {
+ return nil, fmt.Errorf("assignImage %s has invalid parameters: %w", assignImage.GetName(), err)
+ }
+
+ tester, err := core.NewTester(assignImage.GetName(), "AssignImage", path, p.PathTests)
+ if err != nil {
+ return nil, err
+ }
+
+ gvks, err := core.NewValidatedBindings(assignImage.GetName(), "AssignImage", assignImage.Spec.ApplyTo)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Mutator{
+ id: types.MakeID(assignImage),
+ assignImage: assignImage.DeepCopy(),
+ bindings: gvks,
+ path: path,
+ tester: tester,
+ }, nil
+}
+
+func hasListTerminal(path parser.Path) bool {
+ if len(path.Nodes) == 0 {
+ return false
+ }
+ return path.Nodes[len(path.Nodes)-1].Type() == parser.ListNode
+}
+
+var _ core.Setter = setter{}
+
+type setter struct {
+ tag string
+ domain string
+ path string
+}
+
+func (s setter) KeyedListOkay() bool { return false }
+
+func (s setter) KeyedListValue() (map[string]interface{}, error) {
+ panic("assignimage setter does not handle keyed lists")
+}
+
+func (s setter) SetValue(obj map[string]interface{}, key string) error {
+ val, exists := obj[key]
+ strVal := ""
+ if exists {
+ val, ok := val.(string)
+ if !ok {
+ return fmt.Errorf("expected value at AssignImage location to be a string, got %v of type %T", val, val)
+ }
+ strVal = val
+ }
+
+ obj[key] = mutateImage(s.domain, s.path, s.tag, strVal)
+ return nil
+}
+
+// IsValidAssignImage returns an error if the given assignImage object is not
+// semantically valid.
+func IsValidAssignImage(assignImage *mutationsunversioned.AssignImage) error {
+ if _, err := MutatorForAssignImage(assignImage); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/pkg/mutation/mutators/assignimage/assignimage_mutator_benchmark_test.go b/pkg/mutation/mutators/assignimage/assignimage_mutator_benchmark_test.go
new file mode 100644
index 00000000000..80a47cb1fba
--- /dev/null
+++ b/pkg/mutation/mutators/assignimage/assignimage_mutator_benchmark_test.go
@@ -0,0 +1,104 @@
+package assignimage
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+)
+
+func assignImage(domain, path, tag, location string) *unversioned.AssignImage {
+ result := &unversioned.AssignImage{
+ Spec: unversioned.AssignImageSpec{
+ ApplyTo: []match.ApplyTo{{
+ Groups: []string{"*"},
+ Versions: []string{"*"},
+ Kinds: []string{"*"},
+ }},
+ Location: location,
+ Parameters: unversioned.AssignImageParameters{
+ AssignDomain: domain,
+ AssignPath: path,
+ AssignTag: tag,
+ },
+ },
+ }
+
+ return result
+}
+
+func benchmarkAssignImageMutator(b *testing.B, n int) {
+ ai := assignImage("a.b.c", "lib/repo", ":latest", "spec"+strings.Repeat(".spec", n-1))
+ mutator, err := MutatorForAssignImage(ai)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ obj := &unstructured.Unstructured{
+ Object: make(map[string]interface{}),
+ }
+ p := make([]string, n)
+ for i := 0; i < n; i++ {
+ p[i] = "spec"
+ }
+ _, err = mutator.Mutate(&types.Mutable{Object: obj})
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, _ = mutator.Mutate(&types.Mutable{Object: obj})
+ }
+}
+
+func benchmarkNoAssignImageMutator(b *testing.B, n int) {
+ location := "spec" + strings.Repeat(".spec", n-1)
+ a := assignImage("a.b.c", "lib/repo", ":latest", location)
+ a.Spec.Parameters.PathTests = []unversioned.PathTest{{
+ SubPath: location,
+ Condition: tester.MustNotExist,
+ }}
+ mutator, err := MutatorForAssignImage(a)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ obj := &unstructured.Unstructured{
+ Object: make(map[string]interface{}),
+ }
+ p := make([]string, n)
+ for i := 0; i < n; i++ {
+ p[i] = "spec"
+ }
+ _, err = mutator.Mutate(&types.Mutable{Object: obj})
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, _ = mutator.Mutate(&types.Mutable{Object: obj})
+ }
+}
+
+func BenchmarkAssignImageMutator_Mutate(b *testing.B) {
+ ns := []int{1, 2, 5, 10, 20}
+
+ for _, n := range ns {
+ b.Run(fmt.Sprintf("always mutate %d-depth", n), func(b *testing.B) {
+ benchmarkAssignImageMutator(b, n)
+ })
+ }
+
+ for _, n := range ns {
+ b.Run(fmt.Sprintf("never mutate %d-depth", n), func(b *testing.B) {
+ benchmarkNoAssignImageMutator(b, n)
+ })
+ }
+}
diff --git a/pkg/mutation/mutators/assignimage/assignimage_mutator_test.go b/pkg/mutation/mutators/assignimage/assignimage_mutator_test.go
new file mode 100644
index 00000000000..854637146a8
--- /dev/null
+++ b/pkg/mutation/mutators/assignimage/assignimage_mutator_test.go
@@ -0,0 +1,394 @@
+package assignimage
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+ "testing"
+
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ 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"
+)
+
+type aiTestConfig struct {
+ domain string
+ path string
+ tag string
+
+ location string
+ pathTests []mutationsunversioned.PathTest
+ applyTo []match.ApplyTo
+}
+
+func newAIMutator(cfg *aiTestConfig) *Mutator {
+ m := newAI(cfg)
+ m2, err := MutatorForAssignImage(m)
+ if err != nil {
+ panic(err)
+ }
+ return m2
+}
+
+func newAI(cfg *aiTestConfig) *mutationsunversioned.AssignImage {
+ m := &mutationsunversioned.AssignImage{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "Foo",
+ },
+ }
+ m.Spec.Parameters.AssignDomain = cfg.domain
+ m.Spec.Parameters.AssignPath = cfg.path
+ m.Spec.Parameters.AssignTag = cfg.tag
+ m.Spec.Location = cfg.location
+ m.Spec.Parameters.PathTests = cfg.pathTests
+ m.Spec.ApplyTo = cfg.applyTo
+ return m
+}
+
+func newPod(imageVal, name string) *unstructured.Unstructured {
+ pod := &corev1.Pod{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Pod",
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: name,
+ Image: imageVal,
+ },
+ },
+ },
+ }
+
+ u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(pod)
+ if err != nil {
+ panic(fmt.Sprintf("converting pod to unstructured: %v", err))
+ }
+ return &unstructured.Unstructured{Object: u}
+}
+
+func newPodNoImage() *unstructured.Unstructured {
+ pod := &corev1.Pod{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Pod",
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "foo",
+ },
+ },
+ },
+ }
+
+ u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(pod)
+ if err != nil {
+ panic(fmt.Sprintf("converting pod to unstructured: %v", err))
+ }
+ return &unstructured.Unstructured{Object: u}
+}
+
+func podTest(wantImage string) func(*unstructured.Unstructured) error {
+ return func(u *unstructured.Unstructured) error {
+ var pod corev1.Pod
+ err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &pod)
+ if err != nil {
+ return err
+ }
+
+ if len(pod.Spec.Containers) != 1 {
+ return fmt.Errorf("incorrect number of containers: %d", len(pod.Spec.Containers))
+ }
+
+ c := pod.Spec.Containers[0]
+ if c.Image != wantImage {
+ return fmt.Errorf("image incorrect, got: %q wanted %v", c.Image, wantImage)
+ }
+
+ return nil
+ }
+}
+
+func TestMutate(t *testing.T) {
+ tests := []struct {
+ name string
+ obj *unstructured.Unstructured
+ cfg *aiTestConfig
+ fn func(*unstructured.Unstructured) error
+ }{
+ {
+ name: "mutate tag",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ tag: ":new",
+ },
+ obj: newPod("library/busybox:v1", "foo"),
+ fn: podTest("library/busybox:new"),
+ },
+ {
+ name: "mutate path and tag with empty image",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ path: "library/busybox",
+ tag: ":new",
+ },
+ obj: newPod("", "foo"),
+ fn: podTest("library/busybox:new"),
+ },
+ {
+ name: "mutate path and tag with missing image",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ path: "library/busybox",
+ tag: ":new",
+ },
+ obj: newPodNoImage(),
+ fn: podTest("library/busybox:new"),
+ },
+ {
+ name: "mutate path",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ path: "new/repo",
+ },
+ obj: newPod("library/busybox:v1", "foo"),
+ fn: podTest("new/repo:v1"),
+ },
+ {
+ name: "mutate domain",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ domain: "myreg.io",
+ },
+ obj: newPod("docker.io/library/busybox:v1", "foo"),
+ fn: podTest("myreg.io/library/busybox:v1"),
+ },
+ {
+ name: "add domain",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ domain: "myreg.io",
+ },
+ obj: newPod("library/busybox:v1", "foo"),
+ fn: podTest("myreg.io/library/busybox:v1"),
+ },
+ {
+ name: "add tag",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ tag: ":latest",
+ },
+ obj: newPod("myreg.io/library/busybox", "foo"),
+ fn: podTest("myreg.io/library/busybox:latest"),
+ },
+ {
+ name: "add digest",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ tag: "@sha256:12345678901234567890123456789012",
+ },
+ obj: newPod("myreg.io/library/busybox", "foo"),
+ fn: podTest("myreg.io/library/busybox@sha256:12345678901234567890123456789012"),
+ },
+ {
+ name: "mutate all field",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ domain: "myreg.io",
+ path: "newlib/newbox",
+ tag: ":v2",
+ },
+ obj: newPod("docker.io/library/busybox:v1", "foo"),
+ fn: podTest("myreg.io/newlib/newbox:v2"),
+ },
+ {
+ name: "mutate path, domain not set",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ path: "newlib/newbox",
+ },
+ obj: newPod("library/busybox:v1", "foo"),
+ fn: podTest("newlib/newbox:v1"),
+ },
+ {
+ name: "mutate path and tag, no domain set",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ path: "newlib/newbox",
+ tag: ":latest",
+ },
+ obj: newPod("library/busybox:v1", "foo"),
+ fn: podTest("newlib/newbox:latest"),
+ },
+ {
+ name: "mutate tag to digest",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ tag: "@sha256:12345678901234567890123456789012",
+ },
+ obj: newPod("library/busybox:v1", "foo"),
+ fn: podTest("library/busybox@sha256:12345678901234567890123456789012"),
+ },
+ {
+ name: "mutate domain with bad imageref with no domain still converges",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ domain: "myreg.io",
+ },
+ obj: newPod("this/not.good:ABC123_//lib.com.repo//localhost@blah101", "foo"),
+ fn: podTest("myreg.io/this/not.good:ABC123_//lib.com.repo//localhost@blah101"),
+ },
+ {
+ name: "mutate domain with bad imageref with domain still converges",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ domain: "myreg.io",
+ },
+ obj: newPod("a.b.c:5000//not.good:ABC123_//lib.com.repo//localhost@blah101", "foo"),
+ fn: podTest("myreg.io//not.good:ABC123_//lib.com.repo//localhost@blah101"),
+ },
+ {
+ name: "mutate path and tag colon in imageref's domain still converges",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ path: "repo/app",
+ tag: ":latest",
+ },
+ obj: newPod("a.b.c:/not.good:ABC123_//lib.com.repo//localhost@blah101", "foo"),
+ fn: podTest("a.b.c:/repo/app:latest"),
+ },
+ {
+ name: "mutate path to domain-like string with domain set",
+ cfg: &aiTestConfig{
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ location: `spec.containers[name:foo].image`,
+ domain: "myreg.io",
+ path: "my.special.repo/a.b/c",
+ },
+ obj: newPod("a.b:latest", "foo"),
+ fn: podTest("myreg.io/my.special.repo/a.b/c:latest"),
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ mutator := newAIMutator(test.cfg)
+ obj := test.obj.DeepCopy()
+ _, err := mutator.Mutate(&types.Mutable{Object: obj})
+ if err != nil {
+ t.Fatalf("failed mutation: %s", err)
+ }
+ if err := test.fn(obj); err != nil {
+ t.Errorf("failed test: %v", err)
+ }
+ })
+ }
+}
+
+func TestMutatorForAssignImage(t *testing.T) {
+ tests := []struct {
+ name string
+ cfg *aiTestConfig
+ errFn func(error) bool
+ }{
+ {
+ name: "valid assignImage",
+ cfg: &aiTestConfig{
+ domain: "a.b.c",
+ path: "new/app",
+ tag: ":latest",
+ location: "spec.containers[name:foo].image",
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ },
+ },
+ {
+ name: "metadata root returns err",
+ cfg: &aiTestConfig{
+ domain: "a.b.c",
+ path: "new/app",
+ tag: ":latest",
+ location: "metadata.labels.image",
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ },
+ errFn: func(err error) bool {
+ return errors.As(err, &metadataRootError{})
+ },
+ },
+ {
+ name: "terminal list returns err",
+ cfg: &aiTestConfig{
+ domain: "a.b.c",
+ path: "new/app",
+ tag: ":latest",
+ location: "spec.containers[name:foo]",
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ },
+ errFn: func(err error) bool {
+ return errors.As(err, &listTerminalError{})
+ },
+ },
+ {
+ name: "syntactically invalid location returns err",
+ cfg: &aiTestConfig{
+ domain: "a.b.c",
+ path: "new/app",
+ tag: ":latest",
+ location: "/x/y/zx[)",
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ },
+ errFn: func(err error) bool {
+ return strings.Contains(err.Error(), "invalid location format")
+ },
+ },
+ {
+ name: "bad assigns return err",
+ cfg: &aiTestConfig{
+ domain: "",
+ path: "a.b.c/repo",
+ tag: ":latest",
+ location: "spec.containers[name:foo].image",
+ applyTo: []match.ApplyTo{{Groups: []string{""}, Versions: []string{"v1"}, Kinds: []string{"Foo"}}},
+ },
+ errFn: func(err error) bool {
+ return errors.As(err, &domainLikePathError{})
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ mut, err := MutatorForAssignImage(newAI(tc.cfg))
+ if err != nil && mut != nil {
+ t.Errorf("returned non-nil mutator but got err: %s", err)
+ }
+ if tc.errFn != nil {
+ if err == nil {
+ t.Errorf("wanted err but got nil")
+ } else if !tc.errFn(err) {
+ t.Errorf("got error of unexpected type: %s", err)
+ }
+ }
+ })
+ }
+}
diff --git a/pkg/mutation/mutators/assignimage/errors.go b/pkg/mutation/mutators/assignimage/errors.go
new file mode 100644
index 00000000000..7418d62b024
--- /dev/null
+++ b/pkg/mutation/mutators/assignimage/errors.go
@@ -0,0 +1,83 @@
+package assignimage
+
+import "fmt"
+
+type baseError struct {
+ s string
+}
+
+func (e baseError) Error() string {
+ return e.s
+}
+
+// Component field (domain|path|tag) errors.
+type invalidDomainError struct{ baseError }
+
+type (
+ invalidPathError struct{ baseError }
+ invalidTagError struct{ baseError }
+ missingComponentsError struct{ baseError }
+ domainLikePathError struct{ baseError }
+)
+
+// Location field errors.
+type (
+ listTerminalError struct{ baseError }
+ metadataRootError struct{ baseError }
+)
+
+func newInvalidDomainError(domain string) invalidDomainError {
+ return invalidDomainError{
+ baseError{
+ fmt.Sprintf("assignDomain %q must be a fully-qualified domain name or localhost", domain),
+ },
+ }
+}
+
+func newInvalidPathError(path string) invalidPathError {
+ return invalidPathError{
+ baseError{
+ fmt.Sprintf("assignPath %q must be a valid docker image path", path),
+ },
+ }
+}
+
+func newInvalidTagError(tag string) invalidTagError {
+ return invalidTagError{
+ baseError{
+ fmt.Sprintf("assignTag %q must be a valid docker image tag or digest starting with ':' or '@'", tag),
+ },
+ }
+}
+
+func newMissingComponentsError() missingComponentsError {
+ return missingComponentsError{
+ baseError{
+ "at least one of [assignDomain, assignPath, assignTag] must be set",
+ },
+ }
+}
+
+func newDomainLikePathError(path string) domainLikePathError {
+ return domainLikePathError{
+ baseError{
+ fmt.Sprintf("assignDomain must be set if the first part of assignPath %q can be interpretted as part of a domain", path),
+ },
+ }
+}
+
+func newListTerminalError(name string) listTerminalError {
+ return listTerminalError{
+ baseError{
+ fmt.Sprintf("assignImage %s cannot mutate list-type fields", name),
+ },
+ }
+}
+
+func newMetadataRootError(name string) metadataRootError {
+ return metadataRootError{
+ baseError{
+ fmt.Sprintf("assignImage %s can't change metadata", name),
+ },
+ }
+}
diff --git a/pkg/mutation/mutators/assignimage/imageparser.go b/pkg/mutation/mutators/assignimage/imageparser.go
new file mode 100644
index 00000000000..df00f15718d
--- /dev/null
+++ b/pkg/mutation/mutators/assignimage/imageparser.go
@@ -0,0 +1,165 @@
+package assignimage
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+var (
+ // We perform validation on the components of an image string to ensure that
+ // the user cannot define a mutator which does not converge. This would
+ // otherwise be possible by injecting tokens we use to split an image string,
+ // [@:/], into components that would cause that component to be split the next
+ // time the mutation is applied and "leak" to its neighbor. Some validation is
+ // done as regex on individual components, and other validation which looks at
+ // multiple components together is done in code. All validation for domain and
+ // tag must be put in validateDomain and validateTag respectively.
+
+ // domainRegexp defines a schema for a domain component.
+ domainRegexp = regexp.MustCompile(`(^\w[\w\-_]*\.[\w\-_\.]*[\w](:\d+)?$)|(^localhost(:\d+)?$)`)
+
+ // pathRegexp defines a schema for a location component. It follows the convention
+ // specified in the docker distribution reference. The regex restricts
+ // location-components to start with an alphanumeric character, with following
+ // parts able to be separated by a separator (one period, one or two
+ // underscore and multiple dashes).
+ pathRegexp = regexp.MustCompile(`^[a-z0-9]+(?:(?:(?:[._/]|__|[-]*)[a-z0-9]+)+)?`)
+
+ // tagRegexp defines a schema for a tag component. It must start with `:` or `@`.
+ tagRegexp = regexp.MustCompile(`(^:[\w][\w.-]{0,127}$)|(^@[A-Za-z][A-Za-z0-9]*([-_+.][A-Za-z][A-Za-z0-9]*)*[:][0-9A-Fa-f]{32,}$)`)
+)
+
+type image struct {
+ domain string
+ path string
+ tag string
+}
+
+func mutateImage(domain, path, tag, mutableImgRef string) string {
+ oldImg := newImage(mutableImgRef)
+ newImg := oldImg.newMutatedImage(domain, path, tag)
+ return newImg.fullRef()
+}
+
+func newImage(imageRef string) image {
+ domain, remainder := splitDomain(imageRef)
+ path, tag := splitTag(remainder)
+ return image{domain: domain, path: path, tag: tag}
+}
+
+// splitTag separates the path and tag components from a string.
+func splitTag(remainder string) (string, string) {
+ var path string
+ tag := ""
+ if tagSep := strings.IndexAny(remainder, ":@"); tagSep > -1 {
+ path = remainder[:tagSep]
+ tag = remainder[tagSep:]
+ } else {
+ path = remainder
+ }
+
+ return path, tag
+}
+
+func (img image) newMutatedImage(domain, path, tag string) image {
+ return image{
+ domain: ignoreUnset(img.domain, domain),
+ path: ignoreUnset(img.path, path),
+ tag: ignoreUnset(img.tag, tag),
+ }
+}
+
+// ignoreUnset returns `new` if `new` is set, otherwise it returns `old`.
+func ignoreUnset(old, new string) string {
+ if new != "" {
+ return new
+ }
+ return old
+}
+
+func (img image) fullRef() string {
+ domain := img.domain
+ if domain != "" {
+ domain += "/"
+ }
+ return domain + img.path + img.tag
+}
+
+func splitDomain(name string) (domain, remainder string) {
+ i := strings.IndexRune(name, '/')
+ if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
+ return "", name
+ }
+ return name[:i], name[i+1:]
+}
+
+func validateDomain(domain string) error {
+ if domain == "" {
+ return nil
+ }
+
+ if !domainRegexp.MatchString(domain) {
+ return newInvalidDomainError(domain)
+ }
+
+ // The error below should theoretically be unreachable, as the regex
+ // validation should preclude this from happening. This check is included
+ // anyway to prevent code drift, and ensure that if a domain is validated
+ // it can also be recognized as a domain.
+ if d, r := splitDomain(domain + "/"); d != domain || r != "" {
+ return fmt.Errorf("domain %q could not be recognized as a valid domain", domain)
+ }
+
+ return nil
+}
+
+func validateTag(tag string) error {
+ if tag == "" {
+ return nil
+ }
+
+ if !tagRegexp.MatchString(tag) {
+ return newInvalidTagError(tag)
+ }
+
+ // This error should never happen because the regex above prevents it, but the
+ // check is included to prevent drift. Splitting the tag should return itself,
+ // and splitting a valid tag should never return a path.
+ if p, t := splitTag(tag); t != tag || p != "" {
+ return fmt.Errorf("tag %q could not be recognized as a valid tag or digest", tag)
+ }
+
+ return nil
+}
+
+func validateImageParts(domain, path, tag string) error {
+ if domain == "" && path == "" && tag == "" {
+ return newMissingComponentsError()
+ }
+ if err := validateDomain(domain); err != nil {
+ return err
+ }
+ // match the whole string for path (anchoring with `$` is tricky here)
+ if path != "" && path != pathRegexp.FindString(path) {
+ return newInvalidPathError(path)
+ }
+ if err := validateTag(tag); err != nil {
+ return err
+ }
+
+ // Check if the path looks like a domain string, and the domain is not set.
+ // This prevents part of the path field from "leaking" to the domain, causing
+ // non convergent behavior.
+ // For example, suppose: domain="", path="gcr.io/repo", tag=""
+ // Suppose no value is currently set on the mutable, so the result is
+ // just "gcr.io/repo". When this value mutated again, "gcr.io" is parsed into
+ // the domain component, so the result would be "gcr.io/gcr.io/repo" and so on.
+ if domain == "" {
+ if d, _ := splitDomain(path); d != "" {
+ return newDomainLikePathError(path)
+ }
+ }
+
+ return nil
+}
diff --git a/pkg/mutation/mutators/assignimage/imageparser_test.go b/pkg/mutation/mutators/assignimage/imageparser_test.go
new file mode 100644
index 00000000000..22d63c9e971
--- /dev/null
+++ b/pkg/mutation/mutators/assignimage/imageparser_test.go
@@ -0,0 +1,468 @@
+package assignimage
+
+import (
+ "errors"
+ "strings"
+ "testing"
+)
+
+func TestNewImage(t *testing.T) {
+ tests := []struct {
+ name string
+ imageRef string
+ want image
+ }{
+ {
+ name: "full image with tag",
+ imageRef: "gcr.io/some-image/hello:latest",
+ want: image{
+ domain: "gcr.io",
+ path: "some-image/hello",
+ tag: ":latest",
+ },
+ },
+ {
+ name: "all empty components",
+ imageRef: "",
+ want: image{
+ domain: "",
+ path: "",
+ tag: "",
+ },
+ },
+ {
+ name: "full image with hash",
+ imageRef: "some-image/hello@sha256:abcde",
+ want: image{
+ domain: "",
+ path: "some-image/hello",
+ tag: "@sha256:abcde",
+ },
+ },
+ {
+ name: "slash in location with tag",
+ imageRef: "some-image/hello:latest",
+ want: image{
+ domain: "",
+ path: "some-image/hello",
+ tag: ":latest",
+ },
+ },
+ {
+ name: "only location",
+ imageRef: "some-image/hello",
+ want: image{
+ domain: "",
+ path: "some-image/hello",
+ tag: "",
+ },
+ },
+ {
+ name: "no slash in location",
+ imageRef: "some-image:tag123",
+ want: image{
+ domain: "",
+ path: "some-image",
+ tag: ":tag123",
+ },
+ },
+ {
+ name: "just location",
+ imageRef: "alpine",
+ want: image{
+ domain: "",
+ path: "alpine",
+ tag: "",
+ },
+ },
+ {
+ name: "leading underscore",
+ imageRef: "_/alpine",
+ want: image{
+ domain: "",
+ path: "_/alpine",
+ tag: "",
+ },
+ },
+ {
+ name: "leading underscore with tag",
+ imageRef: "_/alpine:latest",
+ want: image{
+ domain: "",
+ path: "_/alpine",
+ tag: ":latest",
+ },
+ },
+ {
+ name: "no domain, location has /",
+ imageRef: "library/busybox:v9",
+ want: image{
+ domain: "",
+ path: "library/busybox",
+ tag: ":v9",
+ },
+ },
+ {
+ name: "dots in domain",
+ imageRef: "this.that.com/repo/alpine:1.23",
+ want: image{
+ domain: "this.that.com",
+ path: "repo/alpine",
+ tag: ":1.23",
+ },
+ },
+ {
+ name: "port and dots in domain",
+ imageRef: "this.that.com:5000/repo/alpine:latest",
+ want: image{
+ domain: "this.that.com:5000",
+ path: "repo/alpine",
+ tag: ":latest",
+ },
+ },
+ {
+ name: "localhost with port",
+ imageRef: "localhost:5000/repo/alpine:latest",
+ want: image{
+ domain: "localhost:5000",
+ path: "repo/alpine",
+ tag: ":latest",
+ },
+ },
+ {
+ name: "dots in location",
+ imageRef: "x.y.z/gcr.io/repo:latest",
+ want: image{
+ domain: "x.y.z",
+ path: "gcr.io/repo",
+ tag: ":latest",
+ },
+ },
+ {
+ name: "dot in domain",
+ imageRef: "gcr.io/repo:latest",
+ want: image{
+ domain: "gcr.io",
+ path: "repo",
+ tag: ":latest",
+ },
+ },
+ {
+ name: "invalid ref still parses",
+ imageRef: "x.io/get/ready4.//this/not.good:404@yikes/bad/string",
+ want: image{
+ domain: "x.io",
+ path: "get/ready4.//this/not.good",
+ tag: ":404@yikes/bad/string",
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ got := newImage(tc.imageRef)
+ if got != tc.want {
+ t.Errorf("got: %v, want %v", got, tc.want)
+ }
+ })
+ }
+}
+
+func isDomainError(domain string) func(error) bool {
+ return func(err error) bool {
+ return errors.As(err, &invalidDomainError{}) && strings.Contains(err.Error(), domain)
+ }
+}
+
+func isPathError(path string) func(error) bool {
+ return func(err error) bool {
+ return errors.As(err, &invalidPathError{}) && strings.Contains(err.Error(), path)
+ }
+}
+
+func isTagError(tag string) func(error) bool {
+ return func(err error) bool {
+ return errors.As(err, &invalidTagError{}) && strings.Contains(err.Error(), tag)
+ }
+}
+
+func isEmptyArgsError() func(error) bool {
+ return func(err error) bool {
+ return errors.As(err, &missingComponentsError{})
+ }
+}
+
+func isPathlikeDomainError() func(error) bool {
+ return func(err error) bool {
+ return errors.As(err, &domainLikePathError{})
+ }
+}
+
+func TestValidateImageParts(t *testing.T) {
+ tests := []struct {
+ name string
+ domain string
+ path string
+ tag string
+ errFn func(error) bool
+ }{
+ {
+ name: "all valid components",
+ domain: "my.register.io:5000",
+ path: "lib/stuff/app",
+ tag: ":latest",
+ },
+ {
+ name: "no fields set returns err",
+ errFn: isEmptyArgsError(),
+ },
+ {
+ name: "valid domain with port",
+ domain: "localhost:5000",
+ },
+ {
+ name: "valid domain no port",
+ domain: "localhost",
+ },
+ {
+ name: "valid domain with .",
+ domain: "a.b.c",
+ },
+ {
+ name: "valid domain with - . and port",
+ domain: "a-b-c.com:5000",
+ },
+ {
+ name: "valid domain with . and port",
+ domain: "a.b.c:123",
+ },
+ {
+ name: "invalid domain no .",
+ domain: "foobar",
+ errFn: isDomainError("foobar"),
+ },
+ {
+ name: "invalid domain leading .",
+ domain: ".foobar",
+ errFn: isDomainError(".foobar"),
+ },
+ {
+ name: "invalid domain trailing .",
+ domain: "foobar.",
+ errFn: isDomainError("foobar."),
+ },
+ {
+ name: "invalid domain . before port",
+ domain: "foobar.:5000",
+ errFn: isDomainError("foobar.:5000"),
+ },
+ {
+ name: "invalid domain / before port",
+ domain: "foobar/:5000",
+ errFn: isDomainError("foobar/:5000"),
+ },
+ {
+ name: "invalid domain leading and trailing .",
+ domain: ".foobar.",
+ errFn: isDomainError(".foobar."),
+ },
+ {
+ name: "invalid domain with _ and port but no .",
+ domain: "a_b_c:123",
+ errFn: isDomainError("a_b_c:123"),
+ },
+ {
+ name: "invalid domain with leading /",
+ domain: "/not.ok.io:2000",
+ errFn: isDomainError("/not.ok.io:2000"),
+ },
+ {
+ name: "invalid domain with trailing /",
+ domain: "not.ok.io:2000/",
+ errFn: isDomainError("not.ok.io:2000/"),
+ },
+ {
+ name: "invalid domain with middle /",
+ domain: "not/ok/io",
+ errFn: isDomainError("not/ok/io"),
+ },
+ {
+ name: "invalid domain port start with alpha",
+ domain: "my.reg.io:abc2000",
+ errFn: isDomainError("my.reg.io:abc2000"),
+ },
+ {
+ name: "invalid domain with multiple :",
+ domain: "my.reg.io:2000:",
+ errFn: isDomainError("my.reg.io:2000:"),
+ },
+ {
+ name: "invalid domain with repeat :",
+ domain: "my.reg.io::2000",
+ errFn: isDomainError("my.reg.io::2000"),
+ },
+ {
+ name: "invalid domain with tag",
+ domain: "my.reg.io:latest",
+ errFn: isDomainError("my.reg.io:latest"),
+ },
+ {
+ name: "invalid domain with digest",
+ domain: "my.reg.io@sha256:abcde123456789",
+ errFn: isDomainError("my.reg.io@sha256:abcde123456789"),
+ },
+ {
+ name: "invalid domain with bad character",
+ domain: ";!234.com",
+ errFn: isDomainError(";!234.com"),
+ },
+ {
+ name: "valid path",
+ path: "lib/stuff",
+ },
+ {
+ name: "domain-like path with domain",
+ domain: "my.reg.io:5000",
+ path: "a.b.c/stuff",
+ },
+ {
+ name: "domain-like path without domain returns err",
+ path: "a.b.c/stuff",
+ tag: ":latest",
+ errFn: isPathlikeDomainError(),
+ },
+ {
+ name: "valid path . and -",
+ path: "lib/stuff-app__thing/a/b--c/e",
+ },
+ {
+ name: "invalid path ending / returns err",
+ path: "lib/stuff/app/",
+ errFn: isPathError("lib/stuff/app/"),
+ },
+ {
+ name: "invalid path with leading / returns err",
+ path: "/lib/stuff/app",
+ errFn: isPathError("/lib/stuff/app"),
+ },
+ {
+ name: "invalid path with leading : returns err",
+ domain: "my.register.io:5000",
+ path: ":lib/stuff/app",
+ errFn: isPathError(":lib/stuff/app"),
+ },
+ {
+ name: "invalid path with leading @ returns err",
+ domain: "my.register.io:5000",
+ path: "@lib/stuff/app",
+ errFn: isPathError("@lib/stuff/app"),
+ },
+ {
+ name: "invalid path with trailing : returns err",
+ domain: "my.register.io:5000",
+ path: "lib/stuff/app:",
+ errFn: isPathError("lib/stuff/app:"),
+ },
+ {
+ name: "invalid path with trailing @ returns err",
+ domain: "my.register.io:5000",
+ path: "lib/stuff/app@",
+ errFn: isPathError("lib/stuff/app@"),
+ },
+ {
+ name: "invalid path : in middle returns err",
+ domain: "my.register.io:5000",
+ path: "lib/stuff:things/app",
+ errFn: isPathError("lib/stuff:things/app"),
+ },
+ {
+ name: "test valid tag",
+ tag: ":latest",
+ },
+ {
+ name: "test valid digest",
+ tag: "@sha256:12345678901234567890123456789012",
+ },
+ {
+ name: "invalid tag no leading :",
+ tag: "latest",
+ errFn: isTagError("latest"),
+ },
+ {
+ name: "invalid digest no leading @",
+ tag: "sha256:12345678901234567890123456789012",
+ errFn: isTagError("sha256:12345678901234567890123456789012"),
+ },
+ {
+ name: "invalid digest hash too short",
+ tag: "@sha256:123456",
+ errFn: isTagError("@sha256:123456"),
+ },
+ {
+ name: "invalid digest not base 16",
+ tag: "@sha256:1XYZ5678901234567890123456789012",
+ errFn: isTagError("@sha256:1XYZ5678901234567890123456789012"),
+ },
+ {
+ name: "invalid tag leading /",
+ tag: "/:latest",
+ errFn: isTagError("/:latest"),
+ },
+ {
+ name: "invalid tag trailing /",
+ tag: ":latest/",
+ errFn: isTagError(":latest/"),
+ },
+ {
+ name: "invalid tag trailing :",
+ tag: ":latest:",
+ errFn: isTagError(":latest:"),
+ },
+ {
+ name: "invalid tag trailing @",
+ tag: ":latest@",
+ errFn: isTagError(":latest@"),
+ },
+ {
+ name: "invalid tag : inside",
+ tag: ":lat:est",
+ errFn: isTagError(":lat:est"),
+ },
+ {
+ name: "invalid tag @ inside",
+ tag: "@sha256:12345678901234567890123456789012@sha256:12345678901234567890123456789012",
+ errFn: isTagError("@sha256:12345678901234567890123456789012@sha256:12345678901234567890123456789012"),
+ },
+ {
+ name: "invalid tag double :",
+ tag: "::latest",
+ errFn: isTagError("::latest"),
+ },
+ {
+ name: "invalid digest double @",
+ tag: "@@sha256:1XYZ5678901234567890123456789012",
+ errFn: isTagError("@@sha256:1XYZ5678901234567890123456789012"),
+ },
+ {
+ name: "invalid tag @ and :",
+ tag: "@:latest",
+ errFn: isTagError("@:latest"),
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ err := validateImageParts(tc.domain, tc.path, tc.tag)
+ if tc.errFn == nil && err != nil {
+ t.Errorf("(domain=%s, path=%s, tag=%s) did not want error but got: %v", tc.domain, tc.path, tc.tag, err)
+ }
+ if tc.errFn != nil {
+ if err == nil {
+ t.Errorf("(domain=%s, path=%s, tag=%s) wanted error but got nil", tc.domain, tc.path, tc.tag)
+ } else if !tc.errFn(err) {
+ t.Errorf("got error of unexpected type: %s", err)
+ }
+ }
+ })
+ }
+}
diff --git a/pkg/mutation/mutators/assignmeta/assignmeta_mutator.go b/pkg/mutation/mutators/assignmeta/assignmeta_mutator.go
index 21ee16902aa..634ec643231 100644
--- a/pkg/mutation/mutators/assignmeta/assignmeta_mutator.go
+++ b/pkg/mutation/mutators/assignmeta/assignmeta_mutator.go
@@ -5,14 +5,14 @@ import (
"reflect"
"github.com/google/go-cmp/cmp"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- mutationsv1beta1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/core"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ mutationsv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/core"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"github.com/pkg/errors"
runtimeschema "k8s.io/apimachinery/pkg/runtime/schema"
logf "sigs.k8s.io/controller-runtime/pkg/log"
@@ -54,7 +54,7 @@ type Mutator struct {
// Mutator implements mutator.
var _ types.Mutator = &Mutator{}
-func (m *Mutator) Matches(mutable *types.Mutable) bool {
+func (m *Mutator) Matches(mutable *types.Mutable) (bool, error) {
target := &match.Matchable{
Object: mutable.Object,
Namespace: mutable.Namespace,
@@ -63,9 +63,8 @@ func (m *Mutator) Matches(mutable *types.Mutable) bool {
matches, err := match.Matches(&m.assignMetadata.Spec.Match, target)
if err != nil {
log.Error(err, "Matches failed for assign metadata", "assignMeta", m.assignMetadata.Name)
- return false
}
- return matches
+ return matches, err
}
func (m *Mutator) Mutate(mutable *types.Mutable) (bool, error) {
@@ -80,7 +79,7 @@ func (m *Mutator) Mutate(mutable *types.Mutable) (bool, error) {
return core.Mutate(m.path, m.tester, core.NewDefaultSetter(value), mutable.Object)
}
-func (m *Mutator) UsesExternalData() bool {
+func (m *Mutator) MustTerminate() bool {
return m.assignMetadata.Spec.Parameters.Assign.ExternalData != nil
}
@@ -123,7 +122,7 @@ func (m *Mutator) String() string {
return fmt.Sprintf("%s/%s/%s:%d", m.id.Kind, m.id.Namespace, m.id.Name, m.assignMetadata.GetGeneration())
}
-// MutatorForAssignMetadata builds an Mutator from the given AssignMetadata object.
+// MutatorForAssignMetadata builds a Mutator from the given AssignMetadata object.
func MutatorForAssignMetadata(assignMeta *mutationsunversioned.AssignMetadata) (*Mutator, error) {
// This is not always set by the kubernetes API server
assignMeta.SetGroupVersionKind(runtimeschema.GroupVersionKind{Group: mutationsv1beta1.GroupVersion.Group, Kind: "AssignMetadata"})
diff --git a/pkg/mutation/mutators/assignmeta/assignmeta_mutator_benchmark_test.go b/pkg/mutation/mutators/assignmeta/assignmeta_mutator_benchmark_test.go
index c9261d4afda..fe7f0b242ef 100644
--- a/pkg/mutation/mutators/assignmeta/assignmeta_mutator_benchmark_test.go
+++ b/pkg/mutation/mutators/assignmeta/assignmeta_mutator_benchmark_test.go
@@ -3,8 +3,8 @@ package assignmeta
import (
"testing"
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
diff --git a/pkg/mutation/mutators/assignmeta/assignmeta_mutator_test.go b/pkg/mutation/mutators/assignmeta/assignmeta_mutator_test.go
index 6fca949d1ad..5ab99f73be6 100644
--- a/pkg/mutation/mutators/assignmeta/assignmeta_mutator_test.go
+++ b/pkg/mutation/mutators/assignmeta/assignmeta_mutator_test.go
@@ -4,10 +4,10 @@ import (
"reflect"
"testing"
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/externaldata"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@@ -26,8 +26,8 @@ func newFoo(spec map[string]interface{}) *unstructured.Unstructured {
return &unstructured.Unstructured{Object: data}
}
-func newAssignMetadataMutator(t *testing.T, path string, value mutationsunversioned.AssignField) *Mutator {
- m := &mutationsunversioned.AssignMetadata{
+func newAssignMetadataMutator(t *testing.T, path string, value unversioned.AssignField) *Mutator {
+ m := &unversioned.AssignMetadata{
ObjectMeta: metav1.ObjectMeta{
Name: "Foo",
},
@@ -47,13 +47,13 @@ func TestAssignMetadata(t *testing.T) {
name string
obj *unstructured.Unstructured
path string
- value mutationsunversioned.AssignField
+ value unversioned.AssignField
expected interface{}
}{
{
name: "metadata value",
path: "metadata.labels.foo",
- value: mutationsunversioned.AssignField{FromMetadata: &mutationsunversioned.FromMetadata{Field: mutationsunversioned.ObjName}},
+ value: unversioned.AssignField{FromMetadata: &unversioned.FromMetadata{Field: unversioned.ObjName}},
obj: newFoo(map[string]interface{}{}),
expected: map[string]interface{}{
"name": "my-foo",
@@ -65,7 +65,7 @@ func TestAssignMetadata(t *testing.T) {
{
name: "external data placeholder",
path: "metadata.labels.foo",
- value: mutationsunversioned.AssignField{
+ value: unversioned.AssignField{
ExternalData: &unversioned.ExternalData{
Provider: "some-provider",
DataSource: types.DataSourceUsername,
@@ -108,3 +108,12 @@ func TestAssignMetadata(t *testing.T) {
})
}
}
+
+// Tests the AssignMeta mutator MutatorForAssignMetadata call with an empty spec for graceful handling.
+func Test_AssignMeta_emptySpec(t *testing.T) {
+ assignMeta := &unversioned.AssignMetadata{}
+ mutator, err := MutatorForAssignMetadata(assignMeta)
+
+ require.ErrorContains(t, err, "invalid location for assignmetadat")
+ require.Nil(t, mutator)
+}
diff --git a/pkg/mutation/mutators/conversion.go b/pkg/mutation/mutators/conversion.go
index b421c06e15f..8e57f9a99d5 100644
--- a/pkg/mutation/mutators/conversion.go
+++ b/pkg/mutation/mutators/conversion.go
@@ -1,10 +1,11 @@
package mutators
import (
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/assign"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/assignmeta"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/modifyset"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assign"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assignimage"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assignmeta"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/modifyset"
)
// MutatorForAssign returns an AssignMutator built from
@@ -18,7 +19,13 @@ func MutatorForAssignMetadata(assignMeta *mutationsunversioned.AssignMetadata) (
return assignmeta.MutatorForAssignMetadata(assignMeta)
}
-// MutatorForModifySet builds an AssignMetadataMutator from the given ModifySet object.
+// MutatorForModifySet builds a ModifySetMutator from the given ModifySet object.
func MutatorForModifySet(modifySet *mutationsunversioned.ModifySet) (*modifyset.Mutator, error) {
return modifyset.MutatorForModifySet(modifySet)
}
+
+// MutatorForAssignImage builds an AssignImageMutator from the given AssignImage
+// object.
+func MutatorForAssignImage(assignImage *mutationsunversioned.AssignImage) (*assignimage.Mutator, error) {
+ return assignimage.MutatorForAssignImage(assignImage)
+}
diff --git a/pkg/mutation/mutators/conversion_test.go b/pkg/mutation/mutators/conversion_test.go
index 514923279c8..46006f389f9 100644
--- a/pkg/mutation/mutators/conversion_test.go
+++ b/pkg/mutation/mutators/conversion_test.go
@@ -5,11 +5,11 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
@@ -241,7 +241,7 @@ func TestAssignMetadataHasDiff(t *testing.T) {
{
"differentMatch",
func(a *mutationsunversioned.AssignMetadata) {
- a.Spec.Match.Namespaces = []util.Wildcard{"foo", "bar"}
+ a.Spec.Match.Namespaces = []wildcard.Wildcard{"foo", "bar"}
},
true,
},
diff --git a/pkg/mutation/mutators/core/mutation_function.go b/pkg/mutation/mutators/core/mutation_function.go
index 12b98834ffb..dbc67efaacc 100644
--- a/pkg/mutation/mutators/core/mutation_function.go
+++ b/pkg/mutation/mutators/core/mutation_function.go
@@ -4,9 +4,9 @@ import (
"errors"
"fmt"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- path "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ path "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"
)
diff --git a/pkg/mutation/mutators/core/mutation_function_setter_test.go b/pkg/mutation/mutators/core/mutation_function_setter_test.go
index 443adb1ee35..8ee1aba2ebe 100644
--- a/pkg/mutation/mutators/core/mutation_function_setter_test.go
+++ b/pkg/mutation/mutators/core/mutation_function_setter_test.go
@@ -1,10 +1,11 @@
package core
import (
+ "errors"
"testing"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@@ -27,7 +28,7 @@ func TestKeyedListIncompatible(t *testing.T) {
}
obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
m, err := Mutate(path, &tester.Tester{}, ¬KeyedSetter{}, obj)
- if err != ErrNonKeyedSetter {
+ if !errors.Is(err, ErrNonKeyedSetter) {
t.Errorf("wanted err = %+v, got %+v", ErrNonKeyedSetter, err)
}
if m != false {
diff --git a/pkg/mutation/mutators/core/mutation_function_test.go b/pkg/mutation/mutators/core/mutation_function_test.go
index 62c157f2093..6295fdb17a4 100644
--- a/pkg/mutation/mutators/core/mutation_function_test.go
+++ b/pkg/mutation/mutators/core/mutation_function_test.go
@@ -4,12 +4,12 @@ import (
"encoding/json"
"testing"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/testhelpers"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/testhelpers"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
diff --git a/pkg/mutation/mutators/core/mutator.go b/pkg/mutation/mutators/core/mutator.go
new file mode 100644
index 00000000000..507448d28c5
--- /dev/null
+++ b/pkg/mutation/mutators/core/mutator.go
@@ -0,0 +1,143 @@
+package core
+
+import (
+ "fmt"
+ "reflect"
+ "sort"
+
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ patht "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/pkg/errors"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// NewTester returns a patht.Tester for the given object name, kind path and
+// pathtests.
+func NewTester(name string, kind string, path parser.Path, ptests []unversioned.PathTest) (*patht.Tester, error) {
+ pathTests, err := gatherPathTests(name, kind, ptests)
+ if err != nil {
+ return nil, err
+ }
+ tester, err := patht.New(path, pathTests)
+ if err != nil {
+ return nil, err
+ }
+
+ return tester, nil
+}
+
+// NewValidatedBindings returns a slice of gvks from the given applies, or an
+// error if the applies are invalid.
+func NewValidatedBindings(name string, kind string, applies []match.ApplyTo) ([]schema.GroupVersionKind, error) {
+ for _, applyTo := range applies {
+ if len(applyTo.Groups) == 0 || len(applyTo.Versions) == 0 || len(applyTo.Kinds) == 0 {
+ return nil, fmt.Errorf("invalid applyTo for %s mutator %s, all of group, version and kind must be specified", kind, name)
+ }
+ }
+
+ gvks := getSortedGVKs(applies)
+ if len(gvks) == 0 {
+ return nil, fmt.Errorf("applyTo required for %s mutator %s", kind, name)
+ }
+
+ return gvks, nil
+}
+
+func gatherPathTests(mutName string, mutKind string, pts []unversioned.PathTest) ([]patht.Test, error) {
+ var pathTests []patht.Test
+ for _, pt := range pts {
+ p, err := parser.Parse(pt.SubPath)
+ if err != nil {
+ return nil, errors.Wrap(err, fmt.Sprintf("problem parsing sub path `%s` for %s %s", pt.SubPath, mutKind, mutName))
+ }
+ pathTests = append(pathTests, patht.Test{SubPath: p, Condition: pt.Condition})
+ }
+
+ return pathTests, nil
+}
+
+func getSortedGVKs(bindings []match.ApplyTo) []schema.GroupVersionKind {
+ // deduplicate GVKs
+ gvksMap := map[schema.GroupVersionKind]struct{}{}
+ for _, binding := range bindings {
+ for _, gvk := range binding.Flatten() {
+ gvksMap[gvk] = struct{}{}
+ }
+ }
+
+ var gvks []schema.GroupVersionKind
+ for gvk := range gvksMap {
+ gvks = append(gvks, gvk)
+ }
+
+ // we iterate over the map in a stable order so that
+ // unit tests won't be flaky.
+ sort.Slice(gvks, func(i, j int) bool { return gvks[i].String() < gvks[j].String() })
+
+ return gvks
+}
+
+// HasMetadataRoot returns true if the root node at given path references the
+// metadata field.
+func HasMetadataRoot(path parser.Path) bool {
+ if len(path.Nodes) == 0 {
+ return false
+ }
+ return reflect.DeepEqual(path.Nodes[0], &parser.Object{Reference: "metadata"})
+}
+
+// CheckKeyNotChanged does not allow to change the key field of
+// a list element. A path like foo[name: bar].name is rejected.
+func CheckKeyNotChanged(p parser.Path) error {
+ if len(p.Nodes) == 0 {
+ return errors.New("empty path")
+ }
+ if len(p.Nodes) < 2 {
+ return nil
+ }
+ lastNode := p.Nodes[len(p.Nodes)-1]
+ secondLastNode := p.Nodes[len(p.Nodes)-2]
+
+ if secondLastNode.Type() != parser.ListNode {
+ return nil
+ }
+ if lastNode.Type() != parser.ObjectNode {
+ return fmt.Errorf("invalid path format: child of a list can't be a list")
+ }
+ addedObject, ok := lastNode.(*parser.Object)
+ if !ok {
+ return errors.New("failed converting an ObjectNodeType to Object")
+ }
+ listNode, ok := secondLastNode.(*parser.List)
+ if !ok {
+ return errors.New("failed converting a ListNodeType to List")
+ }
+
+ if addedObject.Reference == listNode.KeyField {
+ return fmt.Errorf("invalid path format: changing the item key is not allowed")
+ }
+
+ return nil
+}
+
+func MatchWithApplyTo(mut *types.Mutable, applies []match.ApplyTo, mat *match.Match) (bool, error) {
+ gvk := mut.Object.GetObjectKind().GroupVersionKind()
+ if !match.AppliesTo(applies, gvk) {
+ return false, nil
+ }
+
+ target := &match.Matchable{
+ Object: mut.Object,
+ Namespace: mut.Namespace,
+ Source: mut.Source,
+ }
+ matches, err := match.Matches(mat, target)
+ if err != nil {
+ return false, err
+ }
+
+ return matches, nil
+}
diff --git a/pkg/mutation/mutators/core/setter.go b/pkg/mutation/mutators/core/setter.go
index a5e183d6e08..b264ca0d88c 100644
--- a/pkg/mutation/mutators/core/setter.go
+++ b/pkg/mutation/mutators/core/setter.go
@@ -3,7 +3,7 @@ package core
import (
"fmt"
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
)
// Setter tells the mutate function what to do once we have found the
diff --git a/pkg/mutation/mutators/modifyset/modify_set_mutator.go b/pkg/mutation/mutators/modifyset/modify_set_mutator.go
index ee7aa845c26..590d1920ea4 100644
--- a/pkg/mutation/mutators/modifyset/modify_set_mutator.go
+++ b/pkg/mutation/mutators/modifyset/modify_set_mutator.go
@@ -2,19 +2,16 @@ package modifyset
import (
"fmt"
- "reflect"
- "sort"
"github.com/google/go-cmp/cmp"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- mutationsv1beta1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1beta1"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/core"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- patht "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/schema"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ mutationsv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1beta1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/core"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ patht "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/schema"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime"
runtimeschema "k8s.io/apimachinery/pkg/runtime/schema"
@@ -39,22 +36,12 @@ type Mutator struct {
// Mutator implements mutatorWithSchema.
var _ schema.MutatorWithSchema = &Mutator{}
-func (m *Mutator) Matches(mutable *types.Mutable) bool {
- gvk := mutable.Object.GetObjectKind().GroupVersionKind()
- if !match.AppliesTo(m.modifySet.Spec.ApplyTo, gvk) {
- return false
- }
- target := &match.Matchable{
- Object: mutable.Object,
- Namespace: mutable.Namespace,
- Source: mutable.Source,
- }
- matches, err := match.Matches(&m.modifySet.Spec.Match, target)
+func (m *Mutator) Matches(mutable *types.Mutable) (bool, error) {
+ res, err := core.MatchWithApplyTo(mutable, m.modifySet.Spec.ApplyTo, &m.modifySet.Spec.Match)
if err != nil {
log.Error(err, "Matches failed for modify set", "modifyset", m.modifySet.Name)
- return false
}
- return matches
+ return res, err
}
func (m *Mutator) TerminalType() parser.NodeType {
@@ -75,7 +62,7 @@ func (m *Mutator) Mutate(mutable *types.Mutable) (bool, error) {
)
}
-func (m *Mutator) UsesExternalData() bool {
+func (m *Mutator) MustTerminate() bool {
// modify set doesn't use external data
return false
}
@@ -147,37 +134,25 @@ func MutatorForModifySet(modifySet *mutationsunversioned.ModifySet) (*Mutator, e
return nil, errors.Wrapf(err, "invalid location format `%s` for ModifySet %s", modifySet.Spec.Location, modifySet.GetName())
}
- if hasMetadataRoot(path) {
+ if core.HasMetadataRoot(path) {
return nil, fmt.Errorf("modifyset %s can't change metadata", modifySet.GetName())
}
- if path.Nodes[len(path.Nodes)-1].Type() == parser.ListNode {
+ if len(path.Nodes) > 0 && path.Nodes[len(path.Nodes)-1].Type() == parser.ListNode {
return nil, fmt.Errorf("final node in a modifyset location cannot be a keyed list")
}
- id := types.MakeID(modifySet)
-
- pathTests, err := gatherPathTests(modifySet)
+ tester, err := core.NewTester(modifySet.GetName(), "ModifySet", path, modifySet.Spec.Parameters.PathTests)
if err != nil {
return nil, err
}
- tester, err := patht.New(path, pathTests)
+ gvks, err := core.NewValidatedBindings(modifySet.GetName(), "ModifySet", modifySet.Spec.ApplyTo)
if err != nil {
return nil, err
}
- for _, applyTo := range modifySet.Spec.ApplyTo {
- if len(applyTo.Groups) == 0 || len(applyTo.Versions) == 0 || len(applyTo.Kinds) == 0 {
- return nil, fmt.Errorf("invalid applyTo for ModifySet mutator %s, all of group, version and kind must be specified", modifySet.GetName())
- }
- }
-
- gvks := getSortedGVKs(modifySet.Spec.ApplyTo)
- if len(gvks) == 0 {
- return nil, fmt.Errorf("applyTo required for ModifySet mutator %s", modifySet.GetName())
- }
return &Mutator{
- id: id,
+ id: types.MakeID(modifySet),
modifySet: modifySet.DeepCopy(),
bindings: gvks,
path: path,
@@ -185,19 +160,6 @@ func MutatorForModifySet(modifySet *mutationsunversioned.ModifySet) (*Mutator, e
}, nil
}
-func gatherPathTests(modifySet *mutationsunversioned.ModifySet) ([]patht.Test, error) {
- pts := modifySet.Spec.Parameters.PathTests
- var pathTests []patht.Test
- for _, pt := range pts {
- p, err := parser.Parse(pt.SubPath)
- if err != nil {
- return nil, errors.Wrap(err, fmt.Sprintf("problem parsing sub path `%s` for ModifySet %s", pt.SubPath, modifySet.GetName()))
- }
- pathTests = append(pathTests, patht.Test{SubPath: p, Condition: pt.Condition})
- }
- return pathTests, nil
-}
-
// IsValidModifySet returns an error if the given modifyset object is not
// semantically valid.
func IsValidModifySet(modifySet *mutationsunversioned.ModifySet) error {
@@ -207,38 +169,6 @@ func IsValidModifySet(modifySet *mutationsunversioned.ModifySet) error {
return nil
}
-func hasMetadataRoot(path parser.Path) bool {
- if len(path.Nodes) == 0 {
- return false
- }
-
- if reflect.DeepEqual(path.Nodes[0], &parser.Object{Reference: "metadata"}) {
- return true
- }
- return false
-}
-
-func getSortedGVKs(bindings []match.ApplyTo) []runtimeschema.GroupVersionKind {
- // deduplicate GVKs
- gvksMap := map[runtimeschema.GroupVersionKind]struct{}{}
- for _, binding := range bindings {
- for _, gvk := range binding.Flatten() {
- gvksMap[gvk] = struct{}{}
- }
- }
-
- var gvks []runtimeschema.GroupVersionKind
- for gvk := range gvksMap {
- gvks = append(gvks, gvk)
- }
-
- // we iterate over the map in a stable order so that
- // unit tests won't be flaky.
- sort.Slice(gvks, func(i, j int) bool { return gvks[i].String() < gvks[j].String() })
-
- return gvks
-}
-
var _ core.Setter = setter{}
type setter struct {
diff --git a/pkg/mutation/mutators/modifyset/modify_set_mutator_benchmark_test.go b/pkg/mutation/mutators/modifyset/modify_set_mutator_benchmark_test.go
index bb15d688017..c4793833556 100644
--- a/pkg/mutation/mutators/modifyset/modify_set_mutator_benchmark_test.go
+++ b/pkg/mutation/mutators/modifyset/modify_set_mutator_benchmark_test.go
@@ -5,15 +5,15 @@ import (
"strings"
"testing"
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func modifyset(value interface{}, location string) *unversioned.ModifySet {
- result := &unversioned.ModifySet{
+ return &unversioned.ModifySet{
Spec: unversioned.ModifySetSpec{
ApplyTo: []match.ApplyTo{{
Groups: []string{"*"},
@@ -29,8 +29,6 @@ func modifyset(value interface{}, location string) *unversioned.ModifySet {
},
},
}
-
- return result
}
func benchmarkModifySetMutator(b *testing.B, n int) {
diff --git a/pkg/mutation/mutators/modifyset/modify_set_mutator_test.go b/pkg/mutation/mutators/modifyset/modify_set_mutator_test.go
new file mode 100644
index 00000000000..473e214e241
--- /dev/null
+++ b/pkg/mutation/mutators/modifyset/modify_set_mutator_test.go
@@ -0,0 +1,17 @@
+package modifyset
+
+import (
+ "testing"
+
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/stretchr/testify/require"
+)
+
+// Tests the ModifySet mutator MutatorForModifySet call with an empty spec for graceful handling.
+func Test_ModifySet_emptySpec(t *testing.T) {
+ modifySet := &mutationsunversioned.ModifySet{}
+ mutator, err := MutatorForModifySet(modifySet)
+
+ require.ErrorContains(t, err, "applyTo required for ModifySet mutator")
+ require.Nil(t, mutator)
+}
diff --git a/pkg/mutation/mutators/modifyset/modify_set_test.go b/pkg/mutation/mutators/modifyset/modify_set_test.go
index 2938eba269e..30c18ae6ecf 100644
--- a/pkg/mutation/mutators/modifyset/modify_set_test.go
+++ b/pkg/mutation/mutators/modifyset/modify_set_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
)
func TestSetterMerge(t *testing.T) {
diff --git a/pkg/mutation/mutators/testhelpers/dummy_mutator.go b/pkg/mutation/mutators/testhelpers/dummy_mutator.go
index 12cc4b79745..bd5c0219205 100644
--- a/pkg/mutation/mutators/testhelpers/dummy_mutator.go
+++ b/pkg/mutation/mutators/testhelpers/dummy_mutator.go
@@ -3,11 +3,11 @@ package testhelpers
import (
"reflect"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/core"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- path "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/core"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ path "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/tester"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
var _ types.Mutator = &DummyMutator{}
@@ -36,13 +36,13 @@ func (d *DummyMutator) Path() parser.Path {
return d.path
}
-func (d *DummyMutator) Matches(mutable *types.Mutable) bool {
+func (d *DummyMutator) Matches(mutable *types.Mutable) (bool, error) {
m := &match.Matchable{Object: mutable.Object, Namespace: mutable.Namespace}
matches, err := match.Matches(&d.match, m)
if err != nil {
- return false
+ return false, err
}
- return matches
+ return matches, nil
}
func (d *DummyMutator) Mutate(mutable *types.Mutable) (bool, error) {
@@ -50,7 +50,7 @@ func (d *DummyMutator) Mutate(mutable *types.Mutable) (bool, error) {
return core.Mutate(d.Path(), t, core.NewDefaultSetter(d.value), mutable.Object)
}
-func (d *DummyMutator) UsesExternalData() bool {
+func (d *DummyMutator) MustTerminate() bool {
return false
}
diff --git a/pkg/mutation/ordered_ids.go b/pkg/mutation/ordered_ids.go
index 5e38cd6d1ae..4902481f9e3 100644
--- a/pkg/mutation/ordered_ids.go
+++ b/pkg/mutation/ordered_ids.go
@@ -3,7 +3,7 @@ package mutation
import (
"sort"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
type orderedIDs struct {
diff --git a/pkg/mutation/ordered_ids_test.go b/pkg/mutation/ordered_ids_test.go
index b01af2348cf..813135e3a80 100644
--- a/pkg/mutation/ordered_ids_test.go
+++ b/pkg/mutation/ordered_ids_test.go
@@ -5,7 +5,7 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
func fake(id types.ID) types.Mutator {
diff --git a/pkg/mutation/path/parser/errors.go b/pkg/mutation/path/parser/errors.go
index e4ae81ffce5..65924e7e35c 100644
--- a/pkg/mutation/path/parser/errors.go
+++ b/pkg/mutation/path/parser/errors.go
@@ -38,6 +38,5 @@ func (e invalidIntegerError) Error() string {
}
func (e invalidIntegerError) Is(target error) bool {
- _, ok := target.(invalidIntegerError)
- return ok
+ return errors.As(target, &invalidIntegerError{})
}
diff --git a/pkg/mutation/path/parser/parser.go b/pkg/mutation/path/parser/parser.go
index 580fd46d51c..b39f1a5fefa 100644
--- a/pkg/mutation/path/parser/parser.go
+++ b/pkg/mutation/path/parser/parser.go
@@ -18,7 +18,7 @@ package parser
import (
"fmt"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/token"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/token"
)
type parser struct {
diff --git a/pkg/mutation/path/tester/tester.go b/pkg/mutation/path/tester/tester.go
index e1de460e0f5..512219ec234 100644
--- a/pkg/mutation/path/tester/tester.go
+++ b/pkg/mutation/path/tester/tester.go
@@ -6,7 +6,7 @@ import (
"math"
"reflect"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
)
// Condition describes whether the path either MustExist or MustNotExist in the original object
diff --git a/pkg/mutation/path/tester/tester_test.go b/pkg/mutation/path/tester/tester_test.go
index 74b01fc9edc..ce27a92e378 100644
--- a/pkg/mutation/path/tester/tester_test.go
+++ b/pkg/mutation/path/tester/tester_test.go
@@ -5,7 +5,7 @@ import (
"fmt"
"testing"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
)
func TestPrefix(t *testing.T) {
diff --git a/pkg/mutation/schema/errors.go b/pkg/mutation/schema/errors.go
index 699ce314f6a..242762349d3 100644
--- a/pkg/mutation/schema/errors.go
+++ b/pkg/mutation/schema/errors.go
@@ -1,9 +1,10 @@
package schema
import (
+ "errors"
"fmt"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
)
// ErrNilMutator reports that a method which expected an actual Mutator was
@@ -28,8 +29,8 @@ func (e ErrConflictingSchema) Error() string {
}
func (e ErrConflictingSchema) Is(other error) bool {
- o, ok := other.(ErrConflictingSchema)
- if !ok {
+ var o ErrConflictingSchema
+ if !errors.As(other, &o) {
return false
}
diff --git a/pkg/mutation/schema/id_set.go b/pkg/mutation/schema/id_set.go
index b283fdbbc7f..67236159c1b 100644
--- a/pkg/mutation/schema/id_set.go
+++ b/pkg/mutation/schema/id_set.go
@@ -5,7 +5,7 @@ import (
"sort"
"strings"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
)
type IDSet map[types.ID]bool
diff --git a/pkg/mutation/schema/node.go b/pkg/mutation/schema/node.go
index b68515b7982..ba05b1a6838 100644
--- a/pkg/mutation/schema/node.go
+++ b/pkg/mutation/schema/node.go
@@ -3,9 +3,9 @@ package schema
import (
"fmt"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
)
// node is an element of an implicit schema.
@@ -14,7 +14,7 @@ type node struct {
// ReferencedBy tracks the Mutations which reference this part of the schema tree.
ReferencedBy IDSet
- // Children is the set of child Nodes a this location in the schema.
+ // Children is the set of child Nodes at this location in the schema.
// Each node defines a distinct child definition. If multiple Nodes are defined
// for the same child, then there is a schema conflict.
Children map[string]map[parser.NodeType]node
diff --git a/pkg/mutation/schema/node_test.go b/pkg/mutation/schema/node_test.go
index 2ddcd0f38e6..cbb6dd8666f 100644
--- a/pkg/mutation/schema/node_test.go
+++ b/pkg/mutation/schema/node_test.go
@@ -6,8 +6,8 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/runtime/schema"
)
@@ -132,6 +132,28 @@ func TestNode_Add(t *testing.T) {
id("set"): true,
},
},
+ {
+ name: "string vs. set conflict",
+ before: []idPath{
+ ipt("set", "spec.containers[name: foo].images", Set),
+ },
+ add: ipt("string", "spec.containers[name: foo].images", String),
+ want: IDSet{
+ id("set"): true,
+ id("string"): true,
+ },
+ },
+ {
+ name: "string vs. set conflict at nonterminal node",
+ before: []idPath{
+ ipt("string", "spec.containers.image", String),
+ },
+ add: ipt("set", "spec.containers", Set),
+ want: IDSet{
+ id("set"): true,
+ id("string"): true,
+ },
+ },
{
name: "obj vs. set conflict",
before: []idPath{
diff --git a/pkg/mutation/schema/schema.go b/pkg/mutation/schema/schema.go
index bb1b5b130ac..f0a6b227c71 100644
--- a/pkg/mutation/schema/schema.go
+++ b/pkg/mutation/schema/schema.go
@@ -4,8 +4,8 @@ import (
"fmt"
"sync"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/runtime/schema"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
@@ -106,7 +106,7 @@ func (db *DB) upsert(mutator MutatorWithSchema) error {
s = &node{}
db.schemas[gvk] = s
}
- newConflicts := s.Add(id, path.Nodes, mutator.TerminalType(), mutator.UsesExternalData())
+ newConflicts := s.Add(id, path.Nodes, mutator.TerminalType(), mutator.MustTerminate())
conflicts = merge(conflicts, newConflicts)
}
@@ -143,7 +143,7 @@ func (db *DB) remove(id types.ID) {
log.Error(nil, "mutator associated with missing schema", "mutator", id, "schema", gvk)
panic(fmt.Sprintf("mutator %v associated with missing schema %v", id, gvk))
}
- s.Remove(id, cachedMutator.Path().Nodes, cachedMutator.TerminalType(), cachedMutator.UsesExternalData())
+ s.Remove(id, cachedMutator.Path().Nodes, cachedMutator.TerminalType(), cachedMutator.MustTerminate())
db.schemas[gvk] = s
if len(s.ReferencedBy) == 0 {
diff --git a/pkg/mutation/schema/schema_test.go b/pkg/mutation/schema/schema_test.go
index 82063d7d575..c10a4bd227c 100644
--- a/pkg/mutation/schema/schema_test.go
+++ b/pkg/mutation/schema/schema_test.go
@@ -5,8 +5,8 @@ import (
"fmt"
"testing"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/runtime/schema"
)
@@ -34,7 +34,7 @@ func newFakeMutator(id types.ID, pathStr string, usesExternalData bool, bindings
}
}
-func (m *fakeMutator) Matches(*types.Mutable) bool {
+func (m *fakeMutator) Matches(*types.Mutable) (bool, error) {
panic("should not be called")
}
@@ -42,7 +42,7 @@ func (m *fakeMutator) Mutate(*types.Mutable) (bool, error) {
panic("should not be called")
}
-func (m *fakeMutator) UsesExternalData() bool {
+func (m *fakeMutator) MustTerminate() bool {
return m.usesExternalData
}
diff --git a/pkg/mutation/schema/terminal_types.go b/pkg/mutation/schema/terminal_types.go
index c535af4cf00..f161089d065 100644
--- a/pkg/mutation/schema/terminal_types.go
+++ b/pkg/mutation/schema/terminal_types.go
@@ -1,6 +1,6 @@
package schema
-import "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
+import "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
// Unknown represents a path element we do not know the type of.
// Elements of type unknown do not conflict with path elements of known types.
@@ -8,3 +8,6 @@ const Unknown = parser.NodeType("Unknown")
// Set represents a list populated by unique values.
const Set = parser.NodeType("Set")
+
+// String represents a string element.
+const String = parser.NodeType("String")
diff --git a/pkg/mutation/stats_reporter.go b/pkg/mutation/stats_reporter.go
index d12f2e00e5f..661b70cf739 100644
--- a/pkg/mutation/stats_reporter.go
+++ b/pkg/mutation/stats_reporter.go
@@ -3,7 +3,7 @@ package mutation
import (
"context"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view"
"go.opencensus.io/tag"
diff --git a/pkg/mutation/system.go b/pkg/mutation/system.go
index d24da2c06d8..da5dbfe1c01 100644
--- a/pkg/mutation/system.go
+++ b/pkg/mutation/system.go
@@ -7,9 +7,9 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/uuid"
"github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/schema"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/schema"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
@@ -183,7 +183,12 @@ func (s *System) mutate(mutable *types.Mutable) (int, error) {
}
mutator := s.mutatorsMap[id]
- if mutator.Matches(mutable) {
+ matches, err := mutator.Matches(mutable)
+ if err != nil {
+ return iteration, matchesErr(err, mutator.ID(), mutable.Object)
+ }
+
+ if matches {
mutated, err := mutator.Mutate(mutable)
if mutated {
appliedMutations = append(appliedMutations, mutator)
@@ -207,7 +212,7 @@ func (s *System) mutate(mutable *types.Mutable) (int, error) {
}
if *MutationLoggingEnabled {
- logAppliedMutations("Mutation applied", mutationUUID, original, allAppliedMutations)
+ logAppliedMutations("Mutation applied", mutationUUID, original, allAppliedMutations, mutable.Source)
}
if *MutationAnnotationsEnabled {
@@ -223,7 +228,7 @@ func (s *System) mutate(mutable *types.Mutable) (int, error) {
}
if *MutationLoggingEnabled {
- logAppliedMutations("Mutation not converging", mutationUUID, original, allAppliedMutations)
+ logAppliedMutations("Mutation not converging", mutationUUID, original, allAppliedMutations, mutable.Source)
}
return maxIterations, fmt.Errorf("%w: mutation %s not converging for %s %s %s %s",
@@ -232,7 +237,7 @@ func (s *System) mutate(mutable *types.Mutable) (int, error) {
mutable.Object.GroupVersionKind().Group,
mutable.Object.GroupVersionKind().Kind,
mutable.Object.GetNamespace(),
- mutable.Object.GetName())
+ getNameOrGenerateName(mutable.Object))
}
func mutateErr(err error, uid uuid.UUID, mID types.ID, obj *unstructured.Unstructured) error {
@@ -242,5 +247,14 @@ func mutateErr(err error, uid uuid.UUID, mID types.ID, obj *unstructured.Unstruc
obj.GroupVersionKind().Group,
obj.GroupVersionKind().Kind,
obj.GetNamespace(),
- obj.GetName())
+ getNameOrGenerateName(obj))
+}
+
+func matchesErr(err error, mID types.ID, obj *unstructured.Unstructured) error {
+ return errors.Wrapf(err, "matching for mutator %v failed for %s %s %s %s",
+ mID,
+ obj.GroupVersionKind().Group,
+ obj.GroupVersionKind().Kind,
+ obj.GetNamespace(),
+ getNameOrGenerateName(obj))
}
diff --git a/pkg/mutation/system_annotations_test.go b/pkg/mutation/system_annotations_test.go
index 80097d6929c..261831b0724 100644
--- a/pkg/mutation/system_annotations_test.go
+++ b/pkg/mutation/system_annotations_test.go
@@ -5,15 +5,15 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/uuid"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/utils/pointer"
)
func TestSystem_Mutate_Annotations(t *testing.T) {
- MutationAnnotationsEnabled = pointer.BoolPtr(true)
+ MutationAnnotationsEnabled = pointer.Bool(true)
t.Cleanup(func() {
- MutationAnnotationsEnabled = pointer.BoolPtr(false)
+ MutationAnnotationsEnabled = pointer.Bool(false)
})
m := &fakeMutator{
diff --git a/pkg/mutation/system_benchmark_test.go b/pkg/mutation/system_benchmark_test.go
index a6ac9858cfd..8e8bb998095 100644
--- a/pkg/mutation/system_benchmark_test.go
+++ b/pkg/mutation/system_benchmark_test.go
@@ -3,10 +3,10 @@ package mutation
import (
"testing"
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
diff --git a/pkg/mutation/system_errors_test.go b/pkg/mutation/system_errors_test.go
index ce50a2e4847..a541a00eb5f 100644
--- a/pkg/mutation/system_errors_test.go
+++ b/pkg/mutation/system_errors_test.go
@@ -5,8 +5,8 @@ import (
"fmt"
"testing"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@@ -38,15 +38,15 @@ type errorMutator struct {
var _ types.Mutator = &errorMutator{}
-func (e errorMutator) Matches(*types.Mutable) bool {
- return true
+func (e errorMutator) Matches(*types.Mutable) (bool, error) {
+ return true, nil
}
func (e errorMutator) Mutate(*types.Mutable) (bool, error) {
return false, e.err
}
-func (e errorMutator) UsesExternalData() bool {
+func (e errorMutator) MustTerminate() bool {
return false
}
diff --git a/pkg/mutation/system_external_data.go b/pkg/mutation/system_external_data.go
index 3f537f2e204..ea906f337dd 100644
--- a/pkg/mutation/system_external_data.go
+++ b/pkg/mutation/system_external_data.go
@@ -9,8 +9,8 @@ import (
externaldataUnversioned "github.com/open-policy-agent/frameworks/constraint/pkg/apis/externaldata/unversioned"
"github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
errorsutil "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
@@ -18,7 +18,7 @@ import (
// resolvePlaceholders resolves all external data placeholders in the given object.
func (s *System) resolvePlaceholders(obj *unstructured.Unstructured) error {
- providerKeys := make(map[string]sets.String)
+ providerKeys := make(map[string]sets.Set[string])
// recurse object to find all existing external data placeholders
var recurse func(object interface{})
@@ -26,7 +26,7 @@ func (s *System) resolvePlaceholders(obj *unstructured.Unstructured) error {
switch obj := object.(type) {
case *unversioned.ExternalDataPlaceholder:
if _, ok := providerKeys[obj.Ref.Provider]; !ok {
- providerKeys[obj.Ref.Provider] = sets.NewString()
+ providerKeys[obj.Ref.Provider] = sets.New[string]()
}
// gather and de-duplicate all keys for this
// provider so we can resolve them in batch
@@ -62,7 +62,7 @@ func (s *System) resolvePlaceholders(obj *unstructured.Unstructured) error {
}
// sendRequests sends requests to all providers in parallel.
-func (s *System) sendRequests(providerKeys map[string]sets.String, clientCert *tls.Certificate) (map[string]map[string]*externaldata.Item, map[string]error) {
+func (s *System) sendRequests(providerKeys map[string]sets.Set[string], clientCert *tls.Certificate) (map[string]map[string]*externaldata.Item, map[string]error) {
var (
wg sync.WaitGroup
mutex sync.RWMutex
@@ -108,7 +108,7 @@ func (s *System) sendRequests(providerKeys map[string]sets.String, clientCert *t
item := item // for scoping
responses[provider.Name][item.Key] = &item
}
- }(&provider, keys.List())
+ }(&provider, keys.UnsortedList())
wg.Wait()
}
diff --git a/pkg/mutation/system_external_data_test.go b/pkg/mutation/system_external_data_test.go
index 77b83d1b427..4bf374f904d 100644
--- a/pkg/mutation/system_external_data_test.go
+++ b/pkg/mutation/system_external_data_test.go
@@ -11,9 +11,9 @@ import (
externaldataUnversioned "github.com/open-policy-agent/frameworks/constraint/pkg/apis/externaldata/unversioned"
"github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
)
diff --git a/pkg/mutation/system_test.go b/pkg/mutation/system_test.go
index 438977e1735..5f7db49fa0d 100644
--- a/pkg/mutation/system_test.go
+++ b/pkg/mutation/system_test.go
@@ -7,10 +7,10 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
- mutationschema "github.com/open-policy-agent/gatekeeper/pkg/mutation/schema"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
+ mutationschema "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/schema"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -36,8 +36,8 @@ type fakeMutator struct {
Default *types.Anything
}
-func (m *fakeMutator) Matches(*types.Mutable) bool {
- return true // always matches
+func (m *fakeMutator) Matches(*types.Mutable) (bool, error) {
+ return true, nil // always matches
}
func (m *fakeMutator) Mutate(mutable *types.Mutable) (bool, error) {
@@ -65,7 +65,7 @@ func (m *fakeMutator) Mutate(mutable *types.Mutable) (bool, error) {
return true, nil
}
-func (m *fakeMutator) UsesExternalData() bool {
+func (m *fakeMutator) MustTerminate() bool {
return false
}
diff --git a/pkg/mutation/types/mutator.go b/pkg/mutation/types/mutator.go
index 0bfaafd69b4..c3fc665b82e 100644
--- a/pkg/mutation/types/mutator.go
+++ b/pkg/mutation/types/mutator.go
@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/path/parser"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -48,11 +48,11 @@ func IsValidSource(src SourceType) bool {
// Mutator represent a mutation object.
type Mutator interface {
// Matches tells if the given object is eligible for this mutation.
- Matches(mutable *Mutable) bool
+ Matches(mutable *Mutable) (bool, error)
// Mutate applies the mutation to the given object
Mutate(mutable *Mutable) (bool, error)
- // UsesExternalData returns true if the mutation uses external data.
- UsesExternalData() bool
+ // MustTerminate returns true if the mutator requires its path to terminate
+ MustTerminate() bool
// ID returns the id of the current mutator.
ID() ID
// HasDiff tells if the mutator has meaningful differences
diff --git a/pkg/mutation/types/mutator_test.go b/pkg/mutation/types/mutator_test.go
index af08ed779fb..d6ced6e904d 100644
--- a/pkg/mutation/types/mutator_test.go
+++ b/pkg/mutation/types/mutator_test.go
@@ -4,8 +4,8 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
- configv1alpha1 "github.com/open-policy-agent/gatekeeper/apis/config/v1alpha1"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ configv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
diff --git a/pkg/operations/operations.go b/pkg/operations/operations.go
index 1de48cf9cb6..d51496d2c50 100644
--- a/pkg/operations/operations.go
+++ b/pkg/operations/operations.go
@@ -15,22 +15,23 @@ type Operation string
// All defined Operations.
const (
- Audit = Operation("audit")
- Status = Operation("status")
- MutationStatus = Operation("mutation-status")
- MutationWebhook = Operation("mutation-webhook")
- Webhook = Operation("webhook")
+ Audit = Operation("audit")
+ MutationController = Operation("mutation-controller")
+ MutationStatus = Operation("mutation-status")
+ MutationWebhook = Operation("mutation-webhook")
+ Status = Operation("status")
+ Webhook = Operation("webhook")
)
var (
// allOperations is a list of all possible Operations that can be assigned to
- // a pod. It is NOT intended to be mutated. It should be kept in alphabetical
- // order so that it can be readily compared to the results from AssignedOperations.
+ // a pod. It is NOT intended to be mutated.
allOperations = []Operation{
Audit,
- Status,
+ MutationController,
MutationStatus,
MutationWebhook,
+ Status,
Webhook,
}
@@ -85,18 +86,6 @@ func init() {
flag.Var(operations, "operation", "The operation to be performed by this instance. e.g. audit, webhook. This flag can be declared more than once. Omitting will default to supporting all operations.")
}
-// AssignedOperations returns a map of operations assigned to the pod.
-func AssignedOperations() map[Operation]bool {
- ret := make(map[Operation]bool)
- operationsMtx.RLock()
- defer operationsMtx.RUnlock()
-
- for k, v := range operations.assignedOperations {
- ret[k] = v
- }
- return ret
-}
-
// IsAssigned returns true when the provided operation is assigned to the pod.
func IsAssigned(op Operation) bool {
operationsMtx.RLock()
diff --git a/pkg/operations/operations_test.go b/pkg/operations/operations_test.go
index 07da739ae9e..1865a6c630e 100644
--- a/pkg/operations/operations_test.go
+++ b/pkg/operations/operations_test.go
@@ -15,7 +15,7 @@ func Test_Flags(t *testing.T) {
}{
"default": {
input: []string{},
- expected: map[Operation]bool{Audit: true, Webhook: true, Status: true, MutationStatus: true, MutationWebhook: true},
+ expected: map[Operation]bool{Audit: true, Webhook: true, Status: true, MutationStatus: true, MutationWebhook: true, MutationController: true},
},
"multiple": {
input: []string{"-operation", "audit", "-operation", "webhook"},
diff --git a/pkg/pubsub/connection/connection.go b/pkg/pubsub/connection/connection.go
new file mode 100644
index 00000000000..0edb6a74daf
--- /dev/null
+++ b/pkg/pubsub/connection/connection.go
@@ -0,0 +1,17 @@
+package connection
+
+import (
+ "context"
+)
+
+// PubSub is the interface that wraps pubsub methods.
+type Connection interface {
+ // Publish single message over a specific topic/channel
+ Publish(ctx context.Context, data interface{}, topic string) error
+
+ // Close connections
+ CloseConnection() error
+
+ // Update connection
+ UpdateConnection(ctx context.Context, data interface{}) error
+}
diff --git a/pkg/pubsub/dapr/dapr.go b/pkg/pubsub/dapr/dapr.go
new file mode 100644
index 00000000000..ae20be72c64
--- /dev/null
+++ b/pkg/pubsub/dapr/dapr.go
@@ -0,0 +1,83 @@
+package dapr
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+
+ daprClient "github.com/dapr/go-sdk/client"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/connection"
+)
+
+type ClientConfig struct {
+ // Name of the component to be used for pub sub messaging
+ Component string `json:"component"`
+}
+
+// Dapr represents driver for interacting with pub sub using dapr.
+type Dapr struct {
+ // Array of clients to talk to different endpoints
+ client daprClient.Client
+
+ // Name of the pubsub component
+ pubSubComponent string
+}
+
+const (
+ Name = "dapr"
+)
+
+func (r *Dapr) Publish(ctx context.Context, data interface{}, topic string) error {
+ jsonData, err := json.Marshal(data)
+ if err != nil {
+ return fmt.Errorf("error marshaling data: %w", err)
+ }
+
+ err = r.client.PublishEvent(context.Background(), r.pubSubComponent, topic, jsonData)
+ if err != nil {
+ return fmt.Errorf("error publishing message to dapr: %w", err)
+ }
+
+ return nil
+}
+
+func (r *Dapr) CloseConnection() error {
+ return nil
+}
+
+func (r *Dapr) UpdateConnection(_ context.Context, config interface{}) error {
+ var cfg ClientConfig
+ m, ok := config.(map[string]interface{})
+ if !ok {
+ return fmt.Errorf("invalid type assertion, config is not in expected format")
+ }
+ cfg.Component, ok = m["component"].(string)
+ if !ok {
+ return fmt.Errorf("failed to get value of component")
+ }
+ r.pubSubComponent = cfg.Component
+ return nil
+}
+
+// Returns a new client for dapr.
+func NewConnection(_ context.Context, config interface{}) (connection.Connection, error) {
+ var cfg ClientConfig
+ m, ok := config.(map[string]interface{})
+ if !ok {
+ return nil, fmt.Errorf("invalid type assertion, config is not in expected format")
+ }
+ cfg.Component, ok = m["component"].(string)
+ if !ok {
+ return nil, fmt.Errorf("failed to get value of component")
+ }
+
+ tmp, err := daprClient.NewClient()
+ if err != nil {
+ return nil, err
+ }
+
+ return &Dapr{
+ client: tmp,
+ pubSubComponent: cfg.Component,
+ }, nil
+}
diff --git a/pkg/pubsub/dapr/dapr_test.go b/pkg/pubsub/dapr/dapr_test.go
new file mode 100644
index 00000000000..5a2e72615b1
--- /dev/null
+++ b/pkg/pubsub/dapr/dapr_test.go
@@ -0,0 +1,151 @@
+package dapr
+
+import (
+ "context"
+ "os"
+ "testing"
+
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/connection"
+ "github.com/stretchr/testify/assert"
+)
+
+var testClient connection.Connection
+
+func TestMain(m *testing.M) {
+ c, f := FakeConnection()
+ testClient = c
+ r := m.Run()
+ f()
+
+ if r != 0 {
+ os.Exit(r)
+ }
+}
+
+func TestNewConnection(t *testing.T) {
+ tests := []struct {
+ name string
+ config interface{}
+ expected connection.Connection
+ errorMsg string
+ }{
+ {
+ name: "invalid config",
+ config: "test",
+ expected: nil,
+ errorMsg: "invalid type assertion, config is not in expected format",
+ },
+ {
+ name: "config with missing component",
+ config: map[string]interface{}{"enableBatching": true},
+ expected: nil,
+ errorMsg: "failed to get value of component",
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ ret, err := NewConnection(context.TODO(), tc.config)
+ assert.Equal(t, ret, tc.expected)
+ assert.EqualError(t, err, tc.errorMsg)
+ })
+ }
+}
+
+func TestDapr_Publish(t *testing.T) {
+ ctx := context.Background()
+
+ type args struct {
+ ctx context.Context
+ data interface{}
+ topic string
+ }
+
+ tests := []struct {
+ name string
+ args args
+ wantErr bool
+ }{
+ {
+ name: "test publish",
+ args: args{
+ ctx: ctx,
+ data: map[string]interface{}{
+ "test": "test",
+ },
+ topic: "test",
+ },
+ wantErr: false,
+ },
+ {
+ name: "test publish without data",
+ args: args{
+ ctx: ctx,
+ data: nil,
+ topic: "test",
+ },
+ wantErr: false,
+ },
+ {
+ name: "test publish without topic",
+ args: args{
+ ctx: ctx,
+ data: map[string]interface{}{
+ "test": "test",
+ },
+ topic: "",
+ },
+ wantErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ r := testClient
+ if err := r.Publish(tt.args.ctx, tt.args.data, tt.args.topic); (err != nil) != tt.wantErr {
+ t.Errorf("Dapr.Publish() error = %v, wantErr %v", err, tt.wantErr)
+ }
+ })
+ }
+}
+
+func TestDapr_UpdateConnection(t *testing.T) {
+ tests := []struct {
+ name string
+ config interface{}
+ wantErr bool
+ }{
+ {
+ name: "test update connection",
+ config: map[string]interface{}{
+ "component": "foo",
+ },
+ wantErr: false,
+ },
+ {
+ name: "test update connection with invalid config",
+ config: map[string]interface{}{
+ "foo": "bar",
+ },
+ wantErr: true,
+ },
+ {
+ name: "test update connection with nil config",
+ config: nil,
+ wantErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ r := testClient
+ if err := r.UpdateConnection(context.Background(), tt.config); (err != nil) != tt.wantErr {
+ t.Errorf("Dapr.UpdateConnection() error = %v, wantErr %v", err, tt.wantErr)
+ }
+ if !tt.wantErr {
+ cmp, ok := tt.config.(map[string]interface{})["component"].(string)
+ assert.True(t, ok)
+ tmp, ok := r.(*Dapr)
+ assert.True(t, ok)
+ assert.Equal(t, cmp, tmp.pubSubComponent)
+ }
+ })
+ }
+}
diff --git a/pkg/pubsub/dapr/fake_dapr_client.go b/pkg/pubsub/dapr/fake_dapr_client.go
new file mode 100644
index 00000000000..322fccd269f
--- /dev/null
+++ b/pkg/pubsub/dapr/fake_dapr_client.go
@@ -0,0 +1,387 @@
+package dapr
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "log"
+ "net"
+ "os"
+ "sync"
+ "time"
+
+ daprClient "github.com/dapr/go-sdk/client"
+ commonv1pb "github.com/dapr/go-sdk/dapr/proto/common/v1"
+ pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
+ "github.com/golang/protobuf/ptypes/empty"
+ "github.com/google/uuid"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/connection"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
+ "google.golang.org/grpc/test/bufconn"
+ "google.golang.org/protobuf/types/known/anypb"
+)
+
+const (
+ testBufSize = 1024 * 1024
+ testSocket = "/tmp/dapr.socket"
+ valueSuffix = "_value"
+)
+
+var logger = log.New(os.Stdout, "", 0)
+
+func getTestClient(ctx context.Context) (client daprClient.Client, closer func()) {
+ s := grpc.NewServer()
+ pb.RegisterDaprServer(s, &testDaprServer{
+ state: make(map[string][]byte),
+ configurationSubscriptionID: map[string]chan struct{}{},
+ })
+
+ l := bufconn.Listen(testBufSize)
+ go func() {
+ if err := s.Serve(l); err != nil && err.Error() != "closed" {
+ logger.Fatalf("test server exited with error: %v", err)
+ }
+ }()
+
+ d := grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) {
+ return l.Dial()
+ })
+
+ c, err := grpc.DialContext(ctx, "", d, grpc.WithTransportCredentials(insecure.NewCredentials()))
+ if err != nil {
+ logger.Fatalf("failed to dial test context: %v", err)
+ }
+
+ closer = func() {
+ l.Close()
+ s.Stop()
+ }
+
+ client = daprClient.NewClientWithConnection(c)
+ return
+}
+
+type testDaprServer struct {
+ pb.UnimplementedDaprServer
+ state map[string][]byte
+ configurationSubscriptionIDMapLoc sync.Mutex
+ configurationSubscriptionID map[string]chan struct{}
+}
+
+func (s *testDaprServer) TryLockAlpha1(ctx context.Context, req *pb.TryLockRequest) (*pb.TryLockResponse, error) {
+ return &pb.TryLockResponse{
+ Success: true,
+ }, nil
+}
+
+func (s *testDaprServer) UnlockAlpha1(ctx context.Context, req *pb.UnlockRequest) (*pb.UnlockResponse, error) {
+ return &pb.UnlockResponse{
+ Status: pb.UnlockResponse_SUCCESS,
+ }, nil
+}
+
+func (s *testDaprServer) InvokeService(ctx context.Context, req *pb.InvokeServiceRequest) (*commonv1pb.InvokeResponse, error) {
+ if req.Message == nil {
+ return &commonv1pb.InvokeResponse{
+ ContentType: "text/plain",
+ Data: &anypb.Any{
+ Value: []byte("pong"),
+ },
+ }, nil
+ }
+ return &commonv1pb.InvokeResponse{
+ ContentType: req.Message.ContentType,
+ Data: req.Message.Data,
+ }, nil
+}
+
+func (s *testDaprServer) GetState(ctx context.Context, req *pb.GetStateRequest) (*pb.GetStateResponse, error) {
+ return &pb.GetStateResponse{
+ Data: s.state[req.Key],
+ Etag: "1",
+ }, nil
+}
+
+func (s *testDaprServer) GetBulkState(ctx context.Context, in *pb.GetBulkStateRequest) (*pb.GetBulkStateResponse, error) {
+ items := make([]*pb.BulkStateItem, 0)
+ for _, k := range in.GetKeys() {
+ if v, found := s.state[k]; found {
+ item := &pb.BulkStateItem{
+ Key: k,
+ Etag: "1",
+ Data: v,
+ }
+ items = append(items, item)
+ }
+ }
+ return &pb.GetBulkStateResponse{
+ Items: items,
+ }, nil
+}
+
+func (s *testDaprServer) SaveState(ctx context.Context, req *pb.SaveStateRequest) (*empty.Empty, error) {
+ for _, item := range req.States {
+ s.state[item.Key] = item.Value
+ }
+ return &empty.Empty{}, nil
+}
+
+func (s *testDaprServer) QueryStateAlpha1(ctx context.Context, req *pb.QueryStateRequest) (*pb.QueryStateResponse, error) {
+ var v map[string]interface{}
+ if err := json.Unmarshal([]byte(req.Query), &v); err != nil {
+ return nil, err
+ }
+
+ ret := &pb.QueryStateResponse{
+ Results: make([]*pb.QueryStateItem, 0, len(s.state)),
+ }
+ for key, value := range s.state {
+ ret.Results = append(ret.Results, &pb.QueryStateItem{Key: key, Data: value})
+ }
+ return ret, nil
+}
+
+func (s *testDaprServer) DeleteState(ctx context.Context, req *pb.DeleteStateRequest) (*empty.Empty, error) {
+ delete(s.state, req.Key)
+ return &empty.Empty{}, nil
+}
+
+func (s *testDaprServer) DeleteBulkState(ctx context.Context, req *pb.DeleteBulkStateRequest) (*empty.Empty, error) {
+ for _, item := range req.States {
+ delete(s.state, item.Key)
+ }
+ return &empty.Empty{}, nil
+}
+
+func (s *testDaprServer) ExecuteStateTransaction(ctx context.Context, in *pb.ExecuteStateTransactionRequest) (*empty.Empty, error) {
+ for _, op := range in.GetOperations() {
+ item := op.GetRequest()
+ switch opType := op.GetOperationType(); opType {
+ case "upsert":
+ s.state[item.Key] = item.Value
+ case "delete":
+ delete(s.state, item.Key)
+ default:
+ return &empty.Empty{}, fmt.Errorf("invalid operation type: %s", opType)
+ }
+ }
+ return &empty.Empty{}, nil
+}
+
+func (s *testDaprServer) PublishEvent(ctx context.Context, req *pb.PublishEventRequest) (*empty.Empty, error) {
+ return &empty.Empty{}, nil
+}
+
+func (s *testDaprServer) InvokeBinding(ctx context.Context, req *pb.InvokeBindingRequest) (*pb.InvokeBindingResponse, error) {
+ if req.Data == nil {
+ return &pb.InvokeBindingResponse{
+ Data: []byte("test"),
+ Metadata: map[string]string{"k1": "v1", "k2": "v2"},
+ }, nil
+ }
+ return &pb.InvokeBindingResponse{
+ Data: req.Data,
+ Metadata: req.Metadata,
+ }, nil
+}
+
+func (s *testDaprServer) GetSecret(ctx context.Context, req *pb.GetSecretRequest) (*pb.GetSecretResponse, error) {
+ d := make(map[string]string)
+ d["test"] = "value"
+ return &pb.GetSecretResponse{
+ Data: d,
+ }, nil
+}
+
+func (s *testDaprServer) GetBulkSecret(ctx context.Context, req *pb.GetBulkSecretRequest) (*pb.GetBulkSecretResponse, error) {
+ d := make(map[string]*pb.SecretResponse)
+ d["test"] = &pb.SecretResponse{
+ Secrets: map[string]string{
+ "test": "value",
+ },
+ }
+ return &pb.GetBulkSecretResponse{
+ Data: d,
+ }, nil
+}
+
+func (s *testDaprServer) RegisterActorReminder(ctx context.Context, req *pb.RegisterActorReminderRequest) (*empty.Empty, error) {
+ return &empty.Empty{}, nil
+}
+
+func (s *testDaprServer) UnregisterActorReminder(ctx context.Context, req *pb.UnregisterActorReminderRequest) (*empty.Empty, error) {
+ return &empty.Empty{}, nil
+}
+
+func (s *testDaprServer) RenameActorReminder(ctx context.Context, req *pb.RenameActorReminderRequest) (*empty.Empty, error) {
+ return &empty.Empty{}, nil
+}
+
+func (s *testDaprServer) InvokeActor(context.Context, *pb.InvokeActorRequest) (*pb.InvokeActorResponse, error) {
+ return &pb.InvokeActorResponse{
+ Data: []byte("mockValue"),
+ }, nil
+}
+
+func (s *testDaprServer) RegisterActorTimer(context.Context, *pb.RegisterActorTimerRequest) (*empty.Empty, error) {
+ return &empty.Empty{}, nil
+}
+
+func (s *testDaprServer) UnregisterActorTimer(context.Context, *pb.UnregisterActorTimerRequest) (*empty.Empty, error) {
+ return &empty.Empty{}, nil
+}
+
+func (s *testDaprServer) Shutdown(ctx context.Context, req *empty.Empty) (*empty.Empty, error) {
+ return &empty.Empty{}, nil
+}
+
+func (s *testDaprServer) GetConfiguration(ctx context.Context, in *pb.GetConfigurationRequest) (*pb.GetConfigurationResponse, error) {
+ if in.GetStoreName() == "" {
+ return &pb.GetConfigurationResponse{}, errors.New("store name notfound")
+ }
+ items := make(map[string]*commonv1pb.ConfigurationItem)
+ for _, v := range in.GetKeys() {
+ items[v] = &commonv1pb.ConfigurationItem{
+ Value: v + valueSuffix,
+ }
+ }
+ return &pb.GetConfigurationResponse{
+ Items: items,
+ }, nil
+}
+
+func (s *testDaprServer) SubscribeConfiguration(in *pb.SubscribeConfigurationRequest, server pb.Dapr_SubscribeConfigurationServer) error {
+ stopCh := make(chan struct{})
+ id, _ := uuid.NewUUID()
+ s.configurationSubscriptionIDMapLoc.Lock()
+ s.configurationSubscriptionID[id.String()] = stopCh
+ s.configurationSubscriptionIDMapLoc.Unlock()
+
+ // Send subscription ID in the first response.
+ if err := server.Send(&pb.SubscribeConfigurationResponse{
+ Id: id.String(),
+ }); err != nil {
+ return err
+ }
+
+ for i := 0; i < 5; i++ {
+ select {
+ case <-stopCh:
+ return nil
+ default:
+ }
+ items := make(map[string]*commonv1pb.ConfigurationItem)
+ for _, v := range in.GetKeys() {
+ items[v] = &commonv1pb.ConfigurationItem{
+ Value: v + valueSuffix,
+ }
+ }
+ if err := server.Send(&pb.SubscribeConfigurationResponse{
+ Id: id.String(),
+ Items: items,
+ }); err != nil {
+ return err
+ }
+ time.Sleep(time.Second)
+ }
+ return nil
+}
+
+func (s *testDaprServer) UnsubscribeConfiguration(ctx context.Context, in *pb.UnsubscribeConfigurationRequest) (*pb.UnsubscribeConfigurationResponse, error) {
+ s.configurationSubscriptionIDMapLoc.Lock()
+ defer s.configurationSubscriptionIDMapLoc.Unlock()
+ ch, ok := s.configurationSubscriptionID[in.Id]
+ if !ok {
+ return &pb.UnsubscribeConfigurationResponse{Ok: true}, nil
+ }
+ close(ch)
+ delete(s.configurationSubscriptionID, in.Id)
+ return &pb.UnsubscribeConfigurationResponse{Ok: true}, nil
+}
+
+// BulkPublishEventAlpha1 mocks the BulkPublishEventAlpha1 API.
+// It will fail to publish events that start with "fail".
+// It will fail the entire request if an event starts with "failall".
+func (s *testDaprServer) BulkPublishEventAlpha1(ctx context.Context, req *pb.BulkPublishRequest) (*pb.BulkPublishResponse, error) {
+ failedEntries := make([]*pb.BulkPublishResponseFailedEntry, 0)
+ for _, entry := range req.Entries {
+ if bytes.HasPrefix(entry.Event, []byte("failall")) {
+ // fail the entire request
+ return nil, errors.New("failed to publish events")
+ } else if bytes.HasPrefix(entry.Event, []byte("fail")) {
+ // fail this entry
+ failedEntries = append(failedEntries, &pb.BulkPublishResponseFailedEntry{
+ EntryId: entry.EntryId,
+ Error: "failed to publish events",
+ })
+ }
+ }
+ return &pb.BulkPublishResponse{FailedEntries: failedEntries}, nil
+}
+
+func FakeConnection() (connection.Connection, func()) {
+ ctx := context.Background()
+ c, f := getTestClient(ctx)
+ return &Dapr{
+ client: c,
+ pubSubComponent: "test",
+ }, f
+}
+
+type FakeDapr struct {
+ // Array of clients to talk to different endpoints
+ client daprClient.Client
+
+ // Name of the pubsub component
+ pubSubComponent string
+
+ // closing function
+ f func()
+}
+
+func (r *FakeDapr) Publish(ctx context.Context, data interface{}, topic string) error {
+ return nil
+}
+
+func (r *FakeDapr) CloseConnection() error {
+ r.f()
+ return nil
+}
+
+func (r *FakeDapr) UpdateConnection(_ context.Context, config interface{}) error {
+ var cfg ClientConfig
+ m, ok := config.(map[string]interface{})
+ if !ok {
+ return fmt.Errorf("invalid type assertion, config is not in expected format")
+ }
+ cfg.Component, ok = m["component"].(string)
+ if !ok {
+ return fmt.Errorf("failed to get value of component")
+ }
+ r.pubSubComponent = cfg.Component
+ return nil
+}
+
+// Returns a fake client for dapr.
+func FakeNewConnection(ctx context.Context, config interface{}) (connection.Connection, error) {
+ var cfg ClientConfig
+ m, ok := config.(map[string]interface{})
+ if !ok {
+ return nil, fmt.Errorf("invalid type assertion, config is not in expected format")
+ }
+ cfg.Component, ok = m["component"].(string)
+ if !ok {
+ return nil, fmt.Errorf("failed to get value of component")
+ }
+
+ c, f := getTestClient(ctx)
+
+ return &FakeDapr{
+ client: c,
+ pubSubComponent: cfg.Component,
+ f: f,
+ }, nil
+}
diff --git a/pkg/pubsub/provider/fake_provider.go b/pkg/pubsub/provider/fake_provider.go
new file mode 100644
index 00000000000..6e1173eb9b7
--- /dev/null
+++ b/pkg/pubsub/provider/fake_provider.go
@@ -0,0 +1,11 @@
+package provider
+
+import (
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/dapr"
+)
+
+func FakeProviders() {
+ pubSubs = newPubSubSet(map[string]InitiateConnection{
+ dapr.Name: dapr.FakeNewConnection,
+ })
+}
diff --git a/pkg/pubsub/provider/provider.go b/pkg/pubsub/provider/provider.go
new file mode 100644
index 00000000000..5e1d0601014
--- /dev/null
+++ b/pkg/pubsub/provider/provider.go
@@ -0,0 +1,39 @@
+package provider
+
+import (
+ "context"
+
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/connection"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/dapr"
+)
+
+var pubSubs = newPubSubSet(map[string]InitiateConnection{
+ dapr.Name: dapr.NewConnection,
+},
+)
+
+type pubSubSet struct {
+ supportedPubSub map[string]InitiateConnection
+}
+
+// returns new client for pub sub tool.
+type InitiateConnection func(ctx context.Context, config interface{}) (connection.Connection, error)
+
+func newPubSubSet(pubSubs map[string]InitiateConnection) *pubSubSet {
+ supported := make(map[string]InitiateConnection)
+ set := &pubSubSet{
+ supportedPubSub: supported,
+ }
+ for name := range pubSubs {
+ set.supportedPubSub[name] = pubSubs[name]
+ }
+ return set
+}
+
+func List() map[string]InitiateConnection {
+ ret := make(map[string]InitiateConnection)
+ for name, new := range pubSubs.supportedPubSub {
+ ret[name] = new
+ }
+ return ret
+}
diff --git a/pkg/pubsub/provider/provider_test.go b/pkg/pubsub/provider/provider_test.go
new file mode 100644
index 00000000000..c81602525ac
--- /dev/null
+++ b/pkg/pubsub/provider/provider_test.go
@@ -0,0 +1,51 @@
+package provider
+
+import (
+ "testing"
+
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/dapr"
+)
+
+func Test_newPubSubSet(t *testing.T) {
+ tests := []struct {
+ name string
+ pubSubs map[string]InitiateConnection
+ wantKey string
+ }{
+ {
+ name: "only one provider is available",
+ pubSubs: map[string]InitiateConnection{
+ dapr.Name: dapr.NewConnection,
+ },
+ wantKey: dapr.Name,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := newPubSubSet(tt.pubSubs)
+ if _, ok := got.supportedPubSub[tt.wantKey]; !ok {
+ t.Errorf("newPubSubSet() = %#v, want key %#v", got.supportedPubSub, tt.wantKey)
+ }
+ })
+ }
+}
+
+func TestList(t *testing.T) {
+ tests := []struct {
+ name string
+ wantKey string
+ }{
+ {
+ name: "only one provider is available",
+ wantKey: dapr.Name,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := List()
+ if _, ok := got[tt.wantKey]; !ok {
+ t.Errorf("List() = %#v, want key %#v", got, tt.wantKey)
+ }
+ })
+ }
+}
diff --git a/pkg/pubsub/system.go b/pkg/pubsub/system.go
new file mode 100644
index 00000000000..48216735cd9
--- /dev/null
+++ b/pkg/pubsub/system.go
@@ -0,0 +1,87 @@
+package pubsub
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/connection"
+ prvd "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/provider"
+)
+
+type System struct {
+ mux sync.RWMutex
+ connections map[string]connection.Connection
+ providers map[string]string
+}
+
+func NewSystem() *System {
+ return &System{}
+}
+
+func (s *System) Publish(ctx context.Context, connection string, topic string, msg interface{}) error {
+ s.mux.RLock()
+ defer s.mux.RUnlock()
+ if len(s.connections) > 0 {
+ if c, ok := s.connections[connection]; ok {
+ return c.Publish(context.Background(), msg, topic)
+ }
+ return fmt.Errorf("connection is not initialized, name: %s ", connection)
+ }
+ return fmt.Errorf("No connections are established")
+}
+
+func (s *System) UpsertConnection(ctx context.Context, config interface{}, name string, provider string) error {
+ s.mux.Lock()
+ defer s.mux.Unlock()
+ // Check if the connection already exists.
+ if conn, ok := s.connections[name]; ok {
+ // If the provider is the same, update the existing connection.
+ if s.providers[name] == provider {
+ return conn.UpdateConnection(ctx, config)
+ }
+ }
+ // Check if the provider is supported.
+ if newConnFunc, ok := prvd.List()[provider]; ok {
+ newConn, err := newConnFunc(ctx, config)
+ if err != nil {
+ return err
+ }
+
+ // Close the existing connection after successfully creating the new one.
+ if err := s.closeConnection(name); err != nil {
+ return err
+ }
+ // Add the new connection and provider to the maps.
+ if s.connections == nil {
+ s.connections = map[string]connection.Connection{}
+ }
+ if s.providers == nil {
+ s.providers = map[string]string{}
+ }
+ s.connections[name] = newConn
+ s.providers[name] = provider
+ return nil
+ }
+ return fmt.Errorf("pub-sub provider %s is not supported", provider)
+}
+
+func (s *System) CloseConnection(connection string) error {
+ s.mux.Lock()
+ defer s.mux.Unlock()
+ return s.closeConnection(connection)
+}
+
+func (s *System) closeConnection(connection string) error {
+ if len(s.connections) > 0 {
+ if c, ok := s.connections[connection]; ok {
+ err := c.CloseConnection()
+ if err != nil {
+ return err
+ }
+ delete(s.connections, connection)
+ delete(s.providers, connection)
+ }
+ }
+ return nil
+}
diff --git a/pkg/pubsub/system_test.go b/pkg/pubsub/system_test.go
new file mode 100644
index 00000000000..a58e43c8cb7
--- /dev/null
+++ b/pkg/pubsub/system_test.go
@@ -0,0 +1,256 @@
+package pubsub
+
+import (
+ "context"
+ "os"
+ "sync"
+ "testing"
+
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/connection"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/dapr"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub/provider"
+ "github.com/stretchr/testify/assert"
+)
+
+var testSystem *System
+
+func TestMain(m *testing.M) {
+ ctx := context.Background()
+ provider.FakeProviders()
+ tmp := provider.List()
+ testSystem = NewSystem()
+ testSystem.connections = make(map[string]connection.Connection)
+ testSystem.providers = make(map[string]string)
+ cfg := map[string]interface{}{
+ dapr.Name: map[string]interface{}{
+ "component": "pubsub",
+ },
+ }
+ for name, fakeConn := range tmp {
+ testSystem.providers[name] = name
+ testSystem.connections[name], _ = fakeConn(ctx, cfg[name])
+ }
+ r := m.Run()
+ for _, fakeConn := range testSystem.connections {
+ _ = fakeConn.CloseConnection()
+ }
+
+ if r != 0 {
+ os.Exit(r)
+ }
+}
+
+func TestNewSystem(t *testing.T) {
+ tests := []struct {
+ name string
+ input string
+ want *System
+ }{
+ {
+ name: "requesting system",
+ want: &System{},
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ ret := NewSystem()
+ assert.Equal(t, ret, tc.want)
+ })
+ }
+}
+
+func TestSystem_UpsertConnection(t *testing.T) {
+ type fields struct {
+ connections map[string]connection.Connection
+ providers map[string]string
+ s *System
+ }
+ type args struct {
+ ctx context.Context
+ config interface{}
+ name string
+ provider string
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ wantErr bool
+ match bool
+ }{
+ {
+ name: "Create a new connection with dapr provider",
+ fields: fields{
+ connections: testSystem.connections,
+ providers: testSystem.providers,
+ s: &System{},
+ },
+ args: args{
+ ctx: context.Background(),
+ config: map[string]interface{}{
+ "component": "pubsub",
+ },
+ name: "dapr",
+ provider: "dapr",
+ },
+ wantErr: false,
+ match: true,
+ },
+ {
+ name: "Update a connection to use test provider",
+ fields: fields{
+ connections: nil,
+ providers: map[string]string{"audit": "dapr"},
+ s: &System{
+ mux: sync.RWMutex{},
+ providers: map[string]string{"audit": "dapr"},
+ },
+ },
+ args: args{
+ ctx: context.Background(),
+ config: map[string]interface{}{
+ "component": "pubsub",
+ },
+ name: "audit",
+ provider: "test",
+ },
+ wantErr: true,
+ match: true,
+ },
+ {
+ name: "Update a connection using same provider",
+ fields: fields{
+ connections: testSystem.connections,
+ providers: map[string]string{"dapr": "dapr"},
+ s: &System{
+ mux: sync.RWMutex{},
+ providers: testSystem.providers,
+ connections: testSystem.connections,
+ },
+ },
+ args: args{
+ ctx: context.Background(),
+ config: map[string]interface{}{
+ "component": "test",
+ },
+ name: "audit",
+ provider: "dapr",
+ },
+ wantErr: false,
+ match: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if err := tt.fields.s.UpsertConnection(tt.args.ctx, tt.args.config, tt.args.name, tt.args.provider); (err != nil) != tt.wantErr {
+ t.Errorf("System.UpsertConnection() error = %v, wantErr %v", err, tt.wantErr)
+ }
+ assert.NotEqual(t, nil, tt.fields.s.connections)
+ if tt.match {
+ assert.Equal(t, tt.fields.providers, tt.fields.s.providers)
+ } else {
+ assert.NotEqual(t, tt.fields.providers, tt.fields.s.providers)
+ }
+ })
+ }
+}
+
+func TestSystem_CloseConnection(t *testing.T) {
+ type fields struct {
+ connections map[string]connection.Connection
+ providers map[string]string
+ }
+ type args struct {
+ connection string
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ wantErr bool
+ }{
+ {
+ name: "closing connection",
+ fields: fields{
+ connections: map[string]connection.Connection{"audit": &dapr.Dapr{}},
+ providers: map[string]string{"audit": "dapr"},
+ },
+ args: args{connection: "audit"},
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ s := &System{
+ mux: sync.RWMutex{},
+ connections: tt.fields.connections,
+ providers: tt.fields.providers,
+ }
+ if err := s.CloseConnection(tt.args.connection); (err != nil) != tt.wantErr {
+ t.Errorf("System.CloseConnection() error = %v, wantErr %v", err, tt.wantErr)
+ _, ok := s.connections[tt.args.connection]
+ assert.False(t, ok)
+ }
+ })
+ }
+}
+
+func TestSystem_Publish(t *testing.T) {
+ type fields struct {
+ connections map[string]connection.Connection
+ providers map[string]string
+ }
+ type args struct {
+ ctx context.Context
+ connection string
+ topic string
+ msg interface{}
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ wantErr bool
+ }{
+ {
+ name: "There are no connections established",
+ fields: fields{
+ connections: nil,
+ providers: nil,
+ },
+ args: args{ctx: context.Background(), connection: "audit", topic: "test", msg: nil},
+ wantErr: true,
+ },
+ {
+ name: "Publishing to a connection that does not exist",
+ fields: fields{
+ connections: map[string]connection.Connection{"audit": &dapr.Dapr{}},
+ providers: map[string]string{"audit": "dapr"},
+ },
+ args: args{ctx: context.Background(), connection: "test", topic: "test", msg: nil},
+ wantErr: true,
+ },
+ {
+ name: "Publishing to a connection that does exist",
+ fields: fields{
+ connections: testSystem.connections,
+ providers: testSystem.providers,
+ },
+ args: args{ctx: context.Background(), connection: "dapr", topic: "test", msg: nil},
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ s := &System{
+ mux: sync.RWMutex{},
+ connections: tt.fields.connections,
+ providers: tt.fields.providers,
+ }
+ if err := s.Publish(tt.args.ctx, tt.args.connection, tt.args.topic, tt.args.msg); (err != nil) != tt.wantErr {
+ t.Errorf("System.Publish() error = %v, wantErr %v", err, tt.wantErr)
+ }
+ })
+ }
+}
diff --git a/pkg/readiness/integration_suite_test.go b/pkg/readiness/integration_suite_test.go
index ae3aff5767e..1fedd4961b4 100644
--- a/pkg/readiness/integration_suite_test.go
+++ b/pkg/readiness/integration_suite_test.go
@@ -22,7 +22,7 @@ import (
"path/filepath"
"testing"
- "github.com/open-policy-agent/gatekeeper/apis"
+ "github.com/open-policy-agent/gatekeeper/v3/apis"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/scheme"
diff --git a/pkg/readiness/list.go b/pkg/readiness/list.go
index 38d754aadb4..514c8692eba 100644
--- a/pkg/readiness/list.go
+++ b/pkg/readiness/list.go
@@ -20,7 +20,7 @@ import (
"errors"
"time"
- "github.com/open-policy-agent/gatekeeper/pkg/syncutil"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/syncutil"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
diff --git a/pkg/readiness/object_tracker.go b/pkg/readiness/object_tracker.go
index 4ec9cf39fde..674824106a5 100644
--- a/pkg/readiness/object_tracker.go
+++ b/pkg/readiness/object_tracker.go
@@ -22,6 +22,7 @@ import (
"github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -107,6 +108,11 @@ func (t *objectTracker) Expect(o runtime.Object) {
return
}
+ // Satisfied objects cannot be expected again.
+ if _, ok := t.satisfied[k]; ok {
+ return
+ }
+
// We may have seen it before starting to expect it
if _, ok := t.seen[k]; ok {
delete(t.seen, k)
@@ -250,6 +256,8 @@ func (t *objectTracker) Observe(o runtime.Object) {
// Track for future expectation.
t.seen[k] = struct{}{}
+
+ log.V(logging.DebugLevel).Info("[readiness] observed data", "gvk", o.GetObjectKind().GroupVersionKind())
}
func (t *objectTracker) Populated() bool {
diff --git a/pkg/readiness/object_tracker_test.go b/pkg/readiness/object_tracker_test.go
index 951f3151307..e6e601cd417 100644
--- a/pkg/readiness/object_tracker_test.go
+++ b/pkg/readiness/object_tracker_test.go
@@ -178,6 +178,28 @@ func Test_ObjectTracker_Duplicate_Expectations(t *testing.T) {
}
}
+// Verify that that satisfied expectations cannot be re-established.
+func Test_ObjectTracker_Satisfaction_Final(t *testing.T) {
+ ot := newObjTracker(schema.GroupVersionKind{}, nil)
+
+ const count = 10
+ ct := makeCTSlice("ct-", count)
+ for i := 0; i < len(ct); i++ {
+ ot.Expect(ct[i])
+ ot.Observe(ct[i])
+ ot.Expect(ct[i])
+ }
+ if ot.Satisfied() {
+ t.Fatal("should not be satisfied before ExpectationsDone")
+ }
+
+ ot.ExpectationsDone()
+
+ if !ot.Satisfied() {
+ t.Fatal("should be satisfied")
+ }
+}
+
// Verify that an expectation can be canceled before it's first expected.
func Test_ObjectTracker_CancelBeforeExpect(t *testing.T) {
ot := newObjTracker(schema.GroupVersionKind{}, nil)
diff --git a/pkg/readiness/ready_tracker.go b/pkg/readiness/ready_tracker.go
index 184ac1b0bc1..a2eeab4658b 100644
--- a/pkg/readiness/ready_tracker.go
+++ b/pkg/readiness/ready_tracker.go
@@ -25,11 +25,13 @@ import (
externaldatav1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/externaldata/v1beta1"
"github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
- configv1alpha1 "github.com/open-policy-agent/gatekeeper/apis/config/v1alpha1"
- mutationv1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1"
- "github.com/open-policy-agent/gatekeeper/pkg/keys"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/pkg/syncutil"
+ configv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ expansionv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/v1alpha1"
+ mutationv1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1"
+ mutationsv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/keys"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/syncutil"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
"k8s.io/apimachinery/pkg/api/meta"
@@ -64,7 +66,9 @@ type Tracker struct {
assignMetadata *objectTracker
assign *objectTracker
modifySet *objectTracker
+ assignImage *objectTracker
externalDataProvider *objectTracker
+ expansions *objectTracker
constraints *trackerMap
data *trackerMap
@@ -73,14 +77,15 @@ type Tracker struct {
statsEnabled syncutil.SyncBool
mutationEnabled bool
externalDataEnabled bool
+ expansionEnabled bool
}
// NewTracker creates a new Tracker and initializes the internal trackers.
-func NewTracker(lister Lister, mutationEnabled bool, externalDataEnabled bool) *Tracker {
- return newTracker(lister, mutationEnabled, externalDataEnabled, nil)
+func NewTracker(lister Lister, mutationEnabled, externalDataEnabled, expansionEnabled bool) *Tracker {
+ return newTracker(lister, mutationEnabled, externalDataEnabled, expansionEnabled, nil)
}
-func newTracker(lister Lister, mutationEnabled bool, externalDataEnabled bool, fn objDataFactory) *Tracker {
+func newTracker(lister Lister, mutationEnabled, externalDataEnabled, expansionEnabled bool, fn objDataFactory) *Tracker {
tracker := Tracker{
lister: lister,
templates: newObjTracker(v1beta1.SchemeGroupVersion.WithKind("ConstraintTemplate"), fn),
@@ -92,15 +97,20 @@ func newTracker(lister Lister, mutationEnabled bool, externalDataEnabled bool, f
mutationEnabled: mutationEnabled,
externalDataEnabled: externalDataEnabled,
+ expansionEnabled: expansionEnabled,
}
if mutationEnabled {
tracker.assignMetadata = newObjTracker(mutationv1.GroupVersion.WithKind("AssignMetadata"), fn)
tracker.assign = newObjTracker(mutationv1.GroupVersion.WithKind("Assign"), fn)
tracker.modifySet = newObjTracker(mutationv1.GroupVersion.WithKind("ModifySet"), fn)
+ tracker.assignImage = newObjTracker(mutationsv1alpha1.GroupVersion.WithKind("AssignImage"), fn)
}
if externalDataEnabled {
tracker.externalDataProvider = newObjTracker(externaldatav1beta1.SchemeGroupVersion.WithKind("Provider"), fn)
}
+ if expansionEnabled {
+ tracker.expansions = newObjTracker(expansionv1alpha1.GroupVersion.WithKind("ExpansionTemplate"), fn)
+ }
return &tracker
}
@@ -119,31 +129,42 @@ func (t *Tracker) For(gvk schema.GroupVersionKind) Expectations {
return noopExpectations{}
}
+ // Do not compare versions. Internally, we index trackers by GroupKind
switch {
- case gvk.GroupVersion() == v1beta1.SchemeGroupVersion && gvk.Kind == "ConstraintTemplate":
+ case gvk.Group == v1beta1.SchemeGroupVersion.Group && gvk.Kind == "ConstraintTemplate":
if operations.HasValidationOperations() {
return t.templates
}
return noopExpectations{}
- case gvk.GroupVersion() == configv1alpha1.GroupVersion && gvk.Kind == "Config":
+ case gvk.Group == configv1alpha1.GroupVersion.Group && gvk.Kind == "Config":
return t.config
- case gvk.GroupVersion() == externaldatav1beta1.SchemeGroupVersion && gvk.Kind == "Provider":
+ case gvk.Group == externaldatav1beta1.SchemeGroupVersion.Group && gvk.Kind == "Provider":
return t.externalDataProvider
- case gvk.GroupVersion() == mutationv1.GroupVersion && gvk.Kind == "AssignMetadata":
+ case gvk.Group == mutationv1.GroupVersion.Group && gvk.Kind == "AssignMetadata":
if t.mutationEnabled {
return t.assignMetadata
}
return noopExpectations{}
- case gvk.GroupVersion() == mutationv1.GroupVersion && gvk.Kind == "Assign":
+ case gvk.Group == mutationv1.GroupVersion.Group && gvk.Kind == "Assign":
if t.mutationEnabled {
return t.assign
}
return noopExpectations{}
- case gvk.GroupVersion() == mutationv1.GroupVersion && gvk.Kind == "ModifySet":
+ case gvk.Group == mutationv1.GroupVersion.Group && gvk.Kind == "ModifySet":
if t.mutationEnabled {
return t.modifySet
}
return noopExpectations{}
+ case gvk.Group == mutationsv1alpha1.GroupVersion.Group && gvk.Kind == "AssignImage":
+ if t.mutationEnabled {
+ return t.assignImage
+ }
+ return noopExpectations{}
+ case gvk.Group == expansionv1alpha1.GroupVersion.Group && gvk.Kind == "ExpansionTemplate":
+ if t.expansionEnabled {
+ return t.expansions
+ }
+ return noopExpectations{}
}
// Avoid new constraint trackers after templates have been populated.
@@ -207,12 +228,13 @@ func (t *Tracker) Satisfied() bool {
}
if t.mutationEnabled {
- if !t.assignMetadata.Satisfied() || !t.assign.Satisfied() || !t.modifySet.Satisfied() {
+ if !t.assignMetadata.Satisfied() || !t.assign.Satisfied() || !t.modifySet.Satisfied() || !t.assignImage.Satisfied() {
return false
}
log.V(1).Info("all expectations satisfied", "tracker", "assignMetadata")
log.V(1).Info("all expectations satisfied", "tracker", "assign")
log.V(1).Info("all expectations satisfied", "tracker", "modifySet")
+ log.V(1).Info("all expectations satisfied", "tracker", "assignImage")
}
if t.externalDataEnabled {
@@ -222,6 +244,13 @@ func (t *Tracker) Satisfied() bool {
log.V(1).Info("all expectations satisfied", "tracker", "provider")
}
+ if t.expansionEnabled {
+ if !t.expansions.Satisfied() {
+ return false
+ }
+ log.V(1).Info("all expectations satisfied", "tracker", "expansiontemplates")
+ }
+
if operations.HasValidationOperations() {
if !t.templates.Satisfied() {
return false
@@ -275,12 +304,20 @@ func (t *Tracker) Run(ctx context.Context) error {
grp.Go(func() error {
return t.trackModifySet(gctx)
})
+ grp.Go(func() error {
+ return t.trackAssignImage(gctx)
+ })
}
if t.externalDataEnabled {
grp.Go(func() error {
return t.trackExternalDataProvider(gctx)
})
}
+ if t.expansionEnabled {
+ grp.Go(func() error {
+ return t.trackExpansionTemplates(gctx)
+ })
+ }
if operations.HasValidationOperations() {
grp.Go(func() error {
return t.trackConstraintTemplates(gctx)
@@ -331,7 +368,7 @@ func (t *Tracker) Populated() bool {
mutationPopulated := true
if t.mutationEnabled {
// If !t.mutationEnabled and we call this, it yields a null pointer exception
- mutationPopulated = t.assignMetadata.Populated() && t.assign.Populated() && t.modifySet.Populated()
+ mutationPopulated = t.assignMetadata.Populated() && t.assign.Populated() && t.modifySet.Populated() && t.assignImage.Populated()
}
externalDataProviderPopulated := true
if t.externalDataEnabled {
@@ -529,6 +566,56 @@ func (t *Tracker) trackModifySet(ctx context.Context) error {
return nil
}
+func (t *Tracker) trackAssignImage(ctx context.Context) error {
+ defer func() {
+ t.assignImage.ExpectationsDone()
+ log.V(1).Info("AssignImage expectations populated")
+ _ = t.constraintTrackers.Wait()
+ }()
+
+ if !t.mutationEnabled {
+ return nil
+ }
+
+ assignImageList := &mutationsv1alpha1.AssignImageList{}
+ lister := retryLister(t.lister, retryAll)
+ if err := lister.List(ctx, assignImageList); err != nil {
+ return fmt.Errorf("listing AssignImage: %w", err)
+ }
+ log.V(1).Info("setting expectations for AssignImage", "AssignImage Count", len(assignImageList.Items))
+
+ for index := range assignImageList.Items {
+ log.V(1).Info("expecting AssignImage", "name", assignImageList.Items[index].GetName())
+ t.assignImage.Expect(&assignImageList.Items[index])
+ }
+ return nil
+}
+
+func (t *Tracker) trackExpansionTemplates(ctx context.Context) error {
+ defer func() {
+ t.expansions.ExpectationsDone()
+ log.V(1).Info("ExpansionTemplate expectations populated")
+ _ = t.constraintTrackers.Wait()
+ }()
+
+ if !t.expansionEnabled {
+ return nil
+ }
+
+ expansionList := &expansionv1alpha1.ExpansionTemplateList{}
+ lister := retryLister(t.lister, retryAll)
+ if err := lister.List(ctx, expansionList); err != nil {
+ return fmt.Errorf("listing ExpansionTemplate: %w", err)
+ }
+ log.V(1).Info("setting expectations for ExpansionTemplate", "ExpansionTemplate Count", len(expansionList.Items))
+
+ for index := range expansionList.Items {
+ log.V(1).Info("expecting ExpansionTemplate", "name", expansionList.Items[index].GetName())
+ t.expansions.Expect(&expansionList.Items[index])
+ }
+ return nil
+}
+
func (t *Tracker) trackExternalDataProvider(ctx context.Context) error {
defer func() {
t.externalDataProvider.ExpectationsDone()
@@ -815,10 +902,14 @@ func (t *Tracker) statsPrinter(ctx context.Context) {
logUnsatisfiedAssignMetadata(t)
logUnsatisfiedAssign(t)
logUnsatisfiedModifySet(t)
+ logUnsatisfiedAssignImage(t)
}
if t.externalDataEnabled {
logUnsatisfiedExternalDataProvider(t)
}
+ if t.expansionEnabled {
+ logUnsatisfiedExpansions(t)
+ }
}
}
@@ -840,6 +931,18 @@ func logUnsatisfiedModifySet(t *Tracker) {
}
}
+func logUnsatisfiedAssignImage(t *Tracker) {
+ for _, amKey := range t.assignImage.unsatisfied() {
+ log.Info("unsatisfied AssignImage", "name", amKey.namespacedName)
+ }
+}
+
+func logUnsatisfiedExpansions(t *Tracker) {
+ for _, et := range t.expansions.unsatisfied() {
+ log.Info("unsatisfied ExpansionTemplate", "name", et.namespacedName)
+ }
+}
+
func logUnsatisfiedExternalDataProvider(t *Tracker) {
for _, amKey := range t.externalDataProvider.unsatisfied() {
log.Info("unsatisfied Provider", "name", amKey.namespacedName)
diff --git a/pkg/readiness/ready_tracker_test.go b/pkg/readiness/ready_tracker_test.go
index 3bcff8e9f63..a31e47d2f74 100644
--- a/pkg/readiness/ready_tracker_test.go
+++ b/pkg/readiness/ready_tracker_test.go
@@ -28,27 +28,30 @@ import (
externaldataUnversioned "github.com/open-policy-agent/frameworks/constraint/pkg/apis/externaldata/unversioned"
"github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
frameworksexternaldata "github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
- "github.com/open-policy-agent/gatekeeper/pkg/controller"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- mutationtypes "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/readiness"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
- "github.com/open-policy-agent/gatekeeper/test/testutils"
- "github.com/open-policy-agent/gatekeeper/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ mutationtypes "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/syncutil"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
"github.com/prometheus/client_golang/prometheus"
corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/client-go/rest"
+ ctrl "sigs.k8s.io/controller-runtime"
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/metrics"
@@ -59,15 +62,13 @@ func setupManager(t *testing.T) (manager.Manager, *watch.Manager) {
t.Helper()
logger := zap.New(zap.UseDevMode(true), zap.WriteTo(testutils.NewTestWriter(t)))
+ ctrl.SetLogger(logger)
metrics.Registry = prometheus.NewRegistry()
mgr, err := manager.New(cfg, manager.Options{
HealthProbeBindAddress: "127.0.0.1:29090",
MetricsBindAddress: "0",
- NewCache: dynamiccache.New,
- MapperProvider: func(c *rest.Config) (meta.RESTMapper, error) {
- return apiutil.NewDynamicRESTMapper(c)
- },
- Logger: logger,
+ MapperProvider: apiutil.NewDynamicRESTMapper,
+ Logger: logger,
})
if err != nil {
t.Fatalf("setting up controller manager: %s", err)
@@ -87,16 +88,15 @@ func setupManager(t *testing.T) (manager.Manager, *watch.Manager) {
return mgr, wm
}
-func setupOpa(t *testing.T) *constraintclient.Client {
- // initialize OPA
- driver, err := local.New(local.Tracing(false))
+func setupDataClient(t *testing.T) *constraintclient.Client {
+ driver, err := rego.New(rego.Tracing(false))
if err != nil {
t.Fatalf("setting up Driver: %v", err)
}
client, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
if err != nil {
- t.Fatalf("setting up OPA client: %v", err)
+ t.Fatalf("setting up constraint framework client: %v", err)
}
return client
}
@@ -104,11 +104,14 @@ func setupOpa(t *testing.T) *constraintclient.Client {
func setupController(
mgr manager.Manager,
wm *watch.Manager,
- opa *constraintclient.Client,
+ cfClient *constraintclient.Client,
mutationSystem *mutation.System,
+ expansionSystem *expansion.System,
providerCache *frameworksexternaldata.ProviderCache,
) error {
- tracker, err := readiness.SetupTracker(mgr, mutationSystem != nil, providerCache != nil)
+ *expansion.ExpansionEnabled = expansionSystem != nil
+
+ tracker, err := readiness.SetupTracker(mgr, mutationSystem != nil, providerCache != nil, expansionSystem != nil)
if err != nil {
return fmt.Errorf("setting up tracker: %w", err)
}
@@ -124,17 +127,39 @@ func setupController(
processExcluder := process.Get()
+ events := make(chan event.GenericEvent, 1024)
+ syncMetricsCache := syncutil.NewMetricsCache()
+ reg, err := wm.NewRegistrar(
+ cachemanager.RegistrarName,
+ events)
+ if err != nil {
+ return fmt.Errorf("setting up watch manager: %w", err)
+ }
+ cacheManager, err := cachemanager.NewCacheManager(&cachemanager.Config{
+ CfClient: cfClient,
+ SyncMetricsCache: syncMetricsCache,
+ Tracker: tracker,
+ ProcessExcluder: processExcluder,
+ Registrar: reg,
+ Reader: mgr.GetCache(),
+ })
+ if err != nil {
+ return fmt.Errorf("setting up cache manager: %w", err)
+ }
+
// Setup all Controllers
opts := controller.Dependencies{
- Opa: opa,
+ CFClient: cfClient,
WatchManger: wm,
ControllerSwitch: sw,
Tracker: tracker,
GetPod: func(ctx context.Context) (*corev1.Pod, error) { return pod, nil },
ProcessExcluder: processExcluder,
MutationSystem: mutationSystem,
+ ExpansionSystem: expansionSystem,
ProviderCache: providerCache,
- WatchSet: watch.NewSet(),
+ CacheMgr: cacheManager,
+ SyncEventsCh: events,
}
if err := controller.AddToManager(mgr, &opts); err != nil {
return fmt.Errorf("registering controllers: %w", err)
@@ -153,12 +178,13 @@ func Test_AssignMetadata(t *testing.T) {
// Wire up the rest.
mgr, wm := setupManager(t)
- opaClient := setupOpa(t)
+ cfClient := setupDataClient(t)
mutationSystem := mutation.NewSystem(mutation.SystemOpts{})
+ expansionSystem := expansion.NewSystem(mutationSystem)
providerCache := frameworksexternaldata.NewCache()
- if err := setupController(mgr, wm, opaClient, mutationSystem, providerCache); err != nil {
+ if err := setupController(mgr, wm, cfClient, mutationSystem, expansionSystem, providerCache); err != nil {
t.Fatalf("setupControllers: %v", err)
}
@@ -196,12 +222,13 @@ func Test_ModifySet(t *testing.T) {
// Wire up the rest.
mgr, wm := setupManager(t)
- opaClient := setupOpa(t)
+ cfClient := setupDataClient(t)
mutationSystem := mutation.NewSystem(mutation.SystemOpts{})
+ expansionSystem := expansion.NewSystem(mutationSystem)
providerCache := frameworksexternaldata.NewCache()
- if err := setupController(mgr, wm, opaClient, mutationSystem, providerCache); err != nil {
+ if err := setupController(mgr, wm, cfClient, mutationSystem, expansionSystem, providerCache); err != nil {
t.Fatalf("setupControllers: %v", err)
}
@@ -224,6 +251,48 @@ func Test_ModifySet(t *testing.T) {
}
}
+func Test_AssignImage(t *testing.T) {
+ g := gomega.NewWithT(t)
+
+ testutils.Setenv(t, "POD_NAME", "no-pod")
+
+ // Apply fixtures *before* the controllers are set up.
+ err := applyFixtures("testdata")
+ if err != nil {
+ t.Fatalf("applying fixtures: %v", err)
+ }
+
+ // Wire up the rest.
+ mgr, wm := setupManager(t)
+ cfClient := setupDataClient(t)
+
+ mutationSystem := mutation.NewSystem(mutation.SystemOpts{})
+ expansionSystem := expansion.NewSystem(mutationSystem)
+ providerCache := frameworksexternaldata.NewCache()
+
+ if err := setupController(mgr, wm, cfClient, mutationSystem, expansionSystem, providerCache); err != nil {
+ t.Fatalf("setupControllers: %v", err)
+ }
+
+ ctx := context.Background()
+ testutils.StartManager(ctx, t, mgr)
+
+ g.Eventually(func() (bool, error) {
+ ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
+ defer cancel()
+ return probeIsReady(ctx)
+ }, 20*time.Second, 1*time.Second).Should(gomega.BeTrue())
+
+ // Verify that the AssignImage is present in the cache
+ for _, am := range testAssignImage {
+ id := mutationtypes.MakeID(am)
+ expectedMutator := mutationSystem.Get(id)
+ if expectedMutator == nil {
+ t.Fatal("want expectedMutator != nil but got nil")
+ }
+ }
+}
+
func Test_Assign(t *testing.T) {
g := gomega.NewWithT(t)
@@ -237,12 +306,13 @@ func Test_Assign(t *testing.T) {
// Wire up the rest.
mgr, wm := setupManager(t)
- opaClient := setupOpa(t)
+ cfClient := setupDataClient(t)
mutationSystem := mutation.NewSystem(mutation.SystemOpts{})
+ expansionSystem := expansion.NewSystem(mutationSystem)
providerCache := frameworksexternaldata.NewCache()
- if err := setupController(mgr, wm, opaClient, mutationSystem, providerCache); err != nil {
+ if err := setupController(mgr, wm, cfClient, mutationSystem, expansionSystem, providerCache); err != nil {
t.Fatalf("setupControllers: %v", err)
}
@@ -265,6 +335,61 @@ func Test_Assign(t *testing.T) {
}
}
+func Test_ExpansionTemplate(t *testing.T) {
+ g := gomega.NewWithT(t)
+
+ testutils.Setenv(t, "POD_NAME", "no-pod")
+
+ // Apply fixtures *before* the controllers are setup.
+ err := applyFixtures("testdata")
+ if err != nil {
+ t.Fatalf("applying fixtures: %v", err)
+ }
+
+ // Wire up the rest.
+ mgr, wm := setupManager(t)
+ cfClient := setupDataClient(t)
+
+ mutationSystem := mutation.NewSystem(mutation.SystemOpts{})
+ expansionSystem := expansion.NewSystem(mutationSystem)
+ providerCache := frameworksexternaldata.NewCache()
+
+ if err := setupController(mgr, wm, cfClient, mutationSystem, expansionSystem, providerCache); err != nil {
+ t.Fatalf("setupControllers: %v", err)
+ }
+
+ ctx := context.Background()
+ testutils.StartManager(ctx, t, mgr)
+
+ g.Eventually(func() (bool, error) {
+ ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
+ defer cancel()
+ return probeIsReady(ctx)
+ }, 20*time.Second, 1*time.Second).Should(gomega.BeTrue())
+
+ // Verify that the ExpansionTemplate is registered by expanding a demo deployment
+ // and checking that the resulting Pod is non-nil
+ deployment := makeDeployment("demo-deployment")
+ o, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deployment)
+ if err != nil {
+ panic(fmt.Errorf("error converting deployment to unstructured: %w", err))
+ }
+ u := unstructured.Unstructured{Object: o}
+ m := mutationtypes.Mutable{
+ Object: &u,
+ Namespace: testNS,
+ Username: "",
+ Source: "All",
+ }
+ res, err := expansionSystem.Expand(&m)
+ if err != nil {
+ panic(fmt.Errorf("error expanding: %w", err))
+ }
+ if len(res) != 1 {
+ t.Fatal("expected generator to expand into 1 pod, but got 0 resultants")
+ }
+}
+
func Test_Provider(t *testing.T) {
g := gomega.NewWithT(t)
@@ -282,12 +407,13 @@ func Test_Provider(t *testing.T) {
// Wire up the rest.
mgr, wm := setupManager(t)
- opaClient := setupOpa(t)
+ cfClient := setupDataClient(t)
if err := setupController(mgr,
wm,
- opaClient,
+ cfClient,
mutation.NewSystem(mutation.SystemOpts{}),
+ nil,
providerCache); err != nil {
t.Fatalf("setupControllers: %v", err)
}
@@ -339,10 +465,10 @@ func Test_Tracker(t *testing.T) {
// Wire up the rest.
mgr, wm := setupManager(t)
- opaClient := setupOpa(t)
+ cfClient := setupDataClient(t)
providerCache := frameworksexternaldata.NewCache()
- if err := setupController(mgr, wm, opaClient, mutation.NewSystem(mutation.SystemOpts{}), providerCache); err != nil {
+ if err := setupController(mgr, wm, cfClient, mutation.NewSystem(mutation.SystemOpts{}), nil, providerCache); err != nil {
t.Fatalf("setupControllers: %v", err)
}
@@ -363,20 +489,20 @@ func Test_Tracker(t *testing.T) {
// Verify cache (tracks testdata fixtures)
for _, ct := range testTemplates {
- _, err := opaClient.GetTemplate(ct)
+ _, err := cfClient.GetTemplate(ct)
if err != nil {
t.Fatalf("checking cache for template: %v", err)
}
}
for _, c := range testConstraints {
- _, err := opaClient.GetConstraint(c)
+ _, err := cfClient.GetConstraint(c)
if err != nil {
t.Fatalf("checking cache for constraint: %v", err)
}
}
- // TODO: Verify data if we add the corresponding API to opa.Client.
+ // TODO: Verify data if we add the corresponding API to cf.Client.
// for _, d := range testData {
- // _, err := opaClient.GetData(ctx, c)
+ // _, err := cfClient.GetData(ctx, c)
// if err != nil {
// t.Fatalf("checking cache for constraint: %v", err)
// }
@@ -390,13 +516,13 @@ func Test_Tracker(t *testing.T) {
g.Eventually(func() (bool, error) {
// Verify cache (tracks testdata/post fixtures)
for _, ct := range postTemplates {
- _, err := opaClient.GetTemplate(ct)
+ _, err := cfClient.GetTemplate(ct)
if err != nil {
return false, err
}
}
for _, c := range postConstraints {
- _, err := opaClient.GetConstraint(c)
+ _, err := cfClient.GetConstraint(c)
if err != nil {
return false, err
}
@@ -437,10 +563,10 @@ func Test_Tracker_UnregisteredCachedData(t *testing.T) {
// Wire up the rest.
mgr, wm := setupManager(t)
- opaClient := setupOpa(t)
+ cfClient := setupDataClient(t)
providerCache := frameworksexternaldata.NewCache()
- if err := setupController(mgr, wm, opaClient, mutation.NewSystem(mutation.SystemOpts{}), providerCache); err != nil {
+ if err := setupController(mgr, wm, cfClient, mutation.NewSystem(mutation.SystemOpts{}), nil, providerCache); err != nil {
t.Fatalf("setupControllers: %v", err)
}
@@ -463,7 +589,7 @@ func Test_CollectDeleted(t *testing.T) {
type test struct {
description string
gvk schema.GroupVersionKind
- tracker readiness.Expectations
+ tracker *readiness.Expectations
}
g := gomega.NewWithT(t)
@@ -480,7 +606,7 @@ func Test_CollectDeleted(t *testing.T) {
lister: mgr.GetAPIReader(),
namespace: "gatekeeper-system",
}
- tracker := readiness.NewTracker(lister, false, false)
+ tracker := readiness.NewTracker(lister, false, false, false)
err = mgr.Add(manager.RunnableFunc(func(ctx context.Context) error {
return tracker.Run(ctx)
}))
@@ -521,7 +647,7 @@ func Test_CollectDeleted(t *testing.T) {
// between them to keep the test short. Trackers are mostly independent per GVK.
tests := []test{
{description: "constraints", gvk: cgvk},
- {description: "data (configmaps)", gvk: cmgvk, tracker: cmtracker},
+ {description: "data (configmaps)", gvk: cmgvk, tracker: &cmtracker},
{description: "templates", gvk: ctgvk},
// no need to check Config here since it is not actually Expected for readiness
// (the objects identified in a Config's syncOnly are Expected, tested in data case above)
@@ -531,7 +657,7 @@ func Test_CollectDeleted(t *testing.T) {
t.Run(tc.description, func(t *testing.T) {
var tt readiness.Expectations
if tc.tracker != nil {
- tt = tc.tracker
+ tt = *tc.tracker
} else {
tt = tracker.For(tc.gvk)
}
diff --git a/pkg/readiness/ready_tracker_unit_test.go b/pkg/readiness/ready_tracker_unit_test.go
index b732400f321..bfdc38fc1e5 100644
--- a/pkg/readiness/ready_tracker_unit_test.go
+++ b/pkg/readiness/ready_tracker_unit_test.go
@@ -72,7 +72,7 @@ func Test_ReadyTracker_TryCancelTemplate_No_Retries(t *testing.T) {
g := gomega.NewWithT(t)
l := dummyLister{}
- rt := newTracker(l, false, false, func() objData {
+ rt := newTracker(l, false, false, false, func() objData {
return objData{retries: 0}
})
@@ -114,7 +114,7 @@ func Test_ReadyTracker_TryCancelTemplate_Retries(t *testing.T) {
g := gomega.NewWithT(t)
l := dummyLister{}
- rt := newTracker(l, false, false, func() objData {
+ rt := newTracker(l, false, false, false, func() objData {
return objData{retries: 2}
})
diff --git a/pkg/readiness/setup.go b/pkg/readiness/setup.go
index 8882959ac91..47e2b3721ce 100644
--- a/pkg/readiness/setup.go
+++ b/pkg/readiness/setup.go
@@ -25,8 +25,23 @@ import (
// SetupTracker sets up a readiness tracker and registers it to run under control of the
// provided Manager object.
// NOTE: Must be called _before_ the manager is started.
-func SetupTracker(mgr manager.Manager, mutationEnabled bool, externalDataEnabled bool) (*Tracker, error) {
- tracker := NewTracker(mgr.GetAPIReader(), mutationEnabled, externalDataEnabled)
+func SetupTracker(mgr manager.Manager, mutationEnabled, externalDataEnabled, expansionEnabled bool) (*Tracker, error) {
+ tracker, err := SetupTrackerNoReadyz(mgr, mutationEnabled, externalDataEnabled, expansionEnabled)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := mgr.AddReadyzCheck("tracker", tracker.CheckSatisfied); err != nil {
+ return nil, fmt.Errorf("registering readiness check: %w", err)
+ }
+
+ return tracker, nil
+}
+
+// SetupTrackerNoReadyz sets up a readiness tracker and registers it to run under control of the
+// provided Manager object without instantiating /readyz (used for testing).
+func SetupTrackerNoReadyz(mgr manager.Manager, mutationEnabled, externalDataEnabled, expansionEnabled bool) (*Tracker, error) {
+ tracker := NewTracker(mgr.GetAPIReader(), mutationEnabled, externalDataEnabled, expansionEnabled)
err := mgr.Add(manager.RunnableFunc(func(ctx context.Context) error {
return tracker.Run(ctx)
@@ -35,9 +50,5 @@ func SetupTracker(mgr manager.Manager, mutationEnabled bool, externalDataEnabled
return nil, fmt.Errorf("adding tracker to manager: %w", err)
}
- if err := mgr.AddReadyzCheck("tracker", tracker.CheckSatisfied); err != nil {
- return nil, fmt.Errorf("registering readiness check: %w", err)
- }
-
return tracker, nil
}
diff --git a/pkg/readiness/testdata/99-assignimage.yaml b/pkg/readiness/testdata/99-assignimage.yaml
new file mode 100644
index 00000000000..54b65084178
--- /dev/null
+++ b/pkg/readiness/testdata/99-assignimage.yaml
@@ -0,0 +1,21 @@
+apiVersion: mutations.gatekeeper.sh/v1alpha1
+kind: AssignImage
+metadata:
+ name: demo
+spec:
+ applyTo:
+ - groups: [ "" ]
+ kinds: [ "Pod" ]
+ versions: [ "v1" ]
+ location: "spec.containers[name:*].image"
+ parameters:
+ assignDomain: "barcorp.org"
+ assignTag: ":latest"
+ assignPath: "newpath/newrepo"
+ match:
+ source: "All"
+ scope: Namespaced
+ kinds:
+ - apiGroups: [ "*" ]
+ kinds: [ "Pod" ]
+
diff --git a/pkg/readiness/testdata/99-expansion-template.yaml b/pkg/readiness/testdata/99-expansion-template.yaml
new file mode 100644
index 00000000000..716a48456d4
--- /dev/null
+++ b/pkg/readiness/testdata/99-expansion-template.yaml
@@ -0,0 +1,15 @@
+apiVersion: expansion.gatekeeper.sh/v1alpha1
+kind: ExpansionTemplate
+metadata:
+ name: demo
+spec:
+ applyTo:
+ - groups: [ "apps" ]
+ kinds: [ "Deployment", "ReplicaSet" ]
+ versions: [ "v1" ]
+ templateSource: "spec.template"
+ enforcementAction: "deny"
+ generatedGVK:
+ kind: "Pod"
+ group: ""
+ version: "v1"
diff --git a/pkg/readiness/testdata_test.go b/pkg/readiness/testdata_test.go
index 845e1feac36..5439cc4f547 100644
--- a/pkg/readiness/testdata_test.go
+++ b/pkg/readiness/testdata_test.go
@@ -18,7 +18,9 @@ package readiness_test
import (
externaldatav1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/externaldata/v1beta1"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
- mutationsv1alpha1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1alpha1"
+ mutationsv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/v1alpha1"
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@@ -51,6 +53,10 @@ var testModifySet = []*mutationsv1alpha1.ModifySet{
makeModifySet("demo"),
}
+var testAssignImage = []*mutationsv1alpha1.AssignImage{
+ makeAssignImage("demo"),
+}
+
var testAssign = []*mutationsv1alpha1.Assign{
makeAssign("demo"),
}
@@ -59,6 +65,8 @@ var testProvider = []*externaldatav1beta1.Provider{
makeProvider("demo"),
}
+var testNS = makeNS("demo")
+
func makeTemplate(name string) *templates.ConstraintTemplate {
return &templates.ConstraintTemplate{
ObjectMeta: metav1.ObjectMeta{
@@ -105,6 +113,21 @@ func makeModifySet(name string) *mutationsv1alpha1.ModifySet {
}
}
+func makeAssignImage(name string) *mutationsv1alpha1.AssignImage {
+ return &mutationsv1alpha1.AssignImage{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "mutations.gatekeeper.sh/v1alpha1",
+ Kind: "AssignImage",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: name,
+ },
+ Spec: mutationsv1alpha1.AssignImageSpec{
+ Location: "spec.containers[name:*].image",
+ },
+ }
+}
+
func makeAssign(name string) *mutationsv1alpha1.Assign {
return &mutationsv1alpha1.Assign{
TypeMeta: metav1.TypeMeta{
@@ -135,3 +158,39 @@ func makeProvider(name string) *externaldatav1beta1.Provider {
},
}
}
+
+func makeDeployment(name string) *appsv1.Deployment {
+ return &appsv1.Deployment{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "Deployment",
+ APIVersion: "apps/v1",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: name,
+ },
+ Spec: appsv1.DeploymentSpec{
+ Template: corev1.PodTemplateSpec{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx:latest",
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func makeNS(name string) *corev1.Namespace {
+ return &corev1.Namespace{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "Namespace",
+ APIVersion: "v1",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: name,
+ },
+ }
+}
diff --git a/pkg/readiness/tracker_map.go b/pkg/readiness/tracker_map.go
index f18fb86b932..57a596eaae1 100644
--- a/pkg/readiness/tracker_map.go
+++ b/pkg/readiness/tracker_map.go
@@ -66,6 +66,10 @@ func (t *trackerMap) Get(gvk schema.GroupVersionKind) Expectations {
t.mu.Lock()
defer t.mu.Unlock()
+ // re-retrieve map entry in case it was added after releasing the read lock.
+ if e, ok := t.m[gvk]; ok {
+ return e
+ }
entry := newObjTracker(gvk, t.fn)
t.m[gvk] = entry
return entry
diff --git a/pkg/syncutil/backoff.go b/pkg/syncutil/backoff.go
index c9898d12f1e..44f34f55e25 100644
--- a/pkg/syncutil/backoff.go
+++ b/pkg/syncutil/backoff.go
@@ -17,6 +17,7 @@ package syncutil
import (
"context"
+ "errors"
"time"
"k8s.io/apimachinery/pkg/util/wait"
@@ -31,7 +32,7 @@ import (
// 1. the condition check returns true or an error, or
// 2. the context is canceled.
// In case (1) the returned error is what the condition function returned.
-// In all other cases, ErrWaitTimeout is returned.
+// In all other cases, wait.ErrorInterrupted is returned.
//
// Adapted from wait.ExponentialBackoff in https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/util/wait/wait.go
func BackoffWithContext(ctx context.Context, backoff wait.Backoff, condition wait.ConditionFunc) error {
@@ -42,8 +43,8 @@ func BackoffWithContext(ctx context.Context, backoff wait.Backoff, condition wai
select {
case <-time.After(backoff.Step()):
case <-ctx.Done():
- return wait.ErrWaitTimeout
+ return wait.ErrorInterrupted(errors.New("context canceled during backoff"))
}
}
- return wait.ErrWaitTimeout
+ return wait.ErrorInterrupted(errors.New("maximum backoff retries exceeded"))
}
diff --git a/pkg/syncutil/stats_reporter.go b/pkg/syncutil/stats_reporter.go
new file mode 100644
index 00000000000..42a1b8f2f32
--- /dev/null
+++ b/pkg/syncutil/stats_reporter.go
@@ -0,0 +1,209 @@
+package syncutil
+
+import (
+ "context"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
+ "go.opencensus.io/stats"
+ "go.opencensus.io/stats/view"
+ "go.opencensus.io/tag"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+var log = logf.Log.WithName("reporter").WithValues("metaKind", "Sync")
+
+const (
+ syncMetricName = "sync"
+ syncDurationMetricName = "sync_duration_seconds"
+ lastRunTimeMetricName = "sync_last_run_time"
+)
+
+var (
+ syncM = stats.Int64(syncMetricName, "Total number of resources of each kind being cached", stats.UnitDimensionless)
+ syncDurationM = stats.Float64(syncDurationMetricName, "Latency of sync operation in seconds", stats.UnitSeconds)
+ lastRunSyncM = stats.Float64(lastRunTimeMetricName, "Timestamp of last sync operation", stats.UnitSeconds)
+
+ kindKey = tag.MustNewKey("kind")
+ statusKey = tag.MustNewKey("status")
+
+ views = []*view.View{
+ {
+ Name: syncM.Name(),
+ Measure: syncM,
+ Description: syncM.Description(),
+ Aggregation: view.LastValue(),
+ TagKeys: []tag.Key{kindKey, statusKey},
+ },
+ {
+ Name: syncDurationM.Name(),
+ Measure: syncDurationM,
+ Description: syncDurationM.Description(),
+ Aggregation: view.Distribution(0.0001, 0.0002, 0.0003, 0.0004, 0.0005, 0.0006, 0.0007, 0.0008, 0.0009, 0.001, 0.002, 0.003, 0.004, 0.005, 0.01, 0.02, 0.03, 0.04, 0.05),
+ },
+ {
+ Name: lastRunSyncM.Name(),
+ Measure: lastRunSyncM,
+ Description: lastRunSyncM.Description(),
+ Aggregation: view.LastValue(),
+ },
+ }
+)
+
+type MetricsCache struct {
+ mux sync.RWMutex
+ Cache map[string]Tags
+ KnownKinds map[string]bool
+}
+
+type Tags struct {
+ Kind string
+ Status metrics.Status
+}
+
+func NewMetricsCache() *MetricsCache {
+ return &MetricsCache{
+ Cache: make(map[string]Tags),
+ KnownKinds: make(map[string]bool),
+ }
+}
+
+func GetKeyForSyncMetrics(namespace string, name string) string {
+ return strings.Join([]string{namespace, name}, "/")
+}
+
+// need to know encountered kinds to reset metrics for that kind
+// this is a known memory leak
+// footprint should naturally reset on Pod upgrade b/c the container restarts.
+func (c *MetricsCache) AddKind(key string) {
+ c.mux.Lock()
+ defer c.mux.Unlock()
+
+ c.KnownKinds[key] = true
+}
+
+func (c *MetricsCache) ResetCache() {
+ c.mux.Lock()
+ defer c.mux.Unlock()
+
+ c.Cache = make(map[string]Tags)
+}
+
+func (c *MetricsCache) AddObject(key string, t Tags) {
+ c.mux.Lock()
+ defer c.mux.Unlock()
+
+ c.Cache[key] = Tags{
+ Kind: t.Kind,
+ Status: t.Status,
+ }
+}
+
+func (c *MetricsCache) DeleteObject(key string) {
+ c.mux.Lock()
+ defer c.mux.Unlock()
+
+ delete(c.Cache, key)
+}
+
+func (c *MetricsCache) GetTags(key string) *Tags {
+ c.mux.RLock()
+ defer c.mux.RUnlock()
+
+ cpy := &Tags{}
+ v, ok := c.Cache[key]
+ if ok {
+ cpy.Kind = v.Kind
+ cpy.Status = v.Status
+ }
+
+ return cpy
+}
+
+func (c *MetricsCache) HasObject(key string) bool {
+ c.mux.RLock()
+ defer c.mux.RUnlock()
+
+ _, ok := c.Cache[key]
+ return ok
+}
+
+func (c *MetricsCache) ReportSync() {
+ c.mux.RLock()
+ defer c.mux.RUnlock()
+
+ reporter, err := NewStatsReporter()
+ if err != nil {
+ log.Error(err, "failed to initialize reporter")
+ return
+ }
+
+ totals := make(map[Tags]int)
+ for _, v := range c.Cache {
+ totals[v]++
+ }
+
+ for kind := range c.KnownKinds {
+ for _, status := range metrics.AllStatuses {
+ if err := reporter.ReportSync(
+ Tags{
+ Kind: kind,
+ Status: status,
+ },
+ int64(totals[Tags{
+ Kind: kind,
+ Status: status,
+ }])); err != nil {
+ log.Error(err, "failed to report sync")
+ }
+ }
+ }
+}
+
+func init() {
+ if err := register(); err != nil {
+ panic(err)
+ }
+}
+
+func register() error {
+ return view.Register(views...)
+}
+
+type Reporter struct {
+ now func() float64
+}
+
+// NewStatsReporter creates a reporter for sync metrics.
+func NewStatsReporter() (*Reporter, error) {
+ return &Reporter{now: now}, nil
+}
+
+func (r *Reporter) ReportSyncDuration(d time.Duration) error {
+ ctx := context.Background()
+ return metrics.Record(ctx, syncDurationM.M(d.Seconds()))
+}
+
+func (r *Reporter) ReportLastSync() error {
+ ctx := context.Background()
+ return metrics.Record(ctx, lastRunSyncM.M(r.now()))
+}
+
+func (r *Reporter) ReportSync(t Tags, v int64) error {
+ ctx, err := tag.New(
+ context.Background(),
+ tag.Insert(kindKey, t.Kind),
+ tag.Insert(statusKey, string(t.Status)))
+ if err != nil {
+ return err
+ }
+
+ return metrics.Record(ctx, syncM.M(v))
+}
+
+// now returns the timestamp as a second-denominated float.
+func now() float64 {
+ return float64(time.Now().UnixNano()) / 1e9
+}
diff --git a/pkg/controller/sync/stats_reporter_test.go b/pkg/syncutil/stats_reporter_test.go
similarity index 94%
rename from pkg/controller/sync/stats_reporter_test.go
rename to pkg/syncutil/stats_reporter_test.go
index 252f84849b1..828c5856ced 100644
--- a/pkg/controller/sync/stats_reporter_test.go
+++ b/pkg/syncutil/stats_reporter_test.go
@@ -1,10 +1,10 @@
-package sync
+package syncutil
import (
"testing"
"time"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
"go.opencensus.io/stats/view"
"go.opencensus.io/tag"
)
@@ -22,7 +22,7 @@ func TestReportSync(t *testing.T) {
t.Errorf("newStatsReporter() error %v", err)
}
- err = r.reportSync(wantTags, wantValue)
+ err = r.ReportSync(wantTags, wantValue)
if err != nil {
t.Fatalf("got reportSync() error %v", err)
}
@@ -62,12 +62,12 @@ func TestReportSyncLatency(t *testing.T) {
t.Fatalf("got newStatsReporter() error %v, want nil", err)
}
- err = r.reportSyncDuration(minLatency)
+ err = r.ReportSyncDuration(minLatency)
if err != nil {
t.Fatalf("got reportSyncDuration() error %v, want nil", err)
}
- err = r.reportSyncDuration(maxLatency)
+ err = r.ReportSyncDuration(maxLatency)
if err != nil {
t.Fatalf("got reportSyncDuration error %v, want nil", err)
}
@@ -105,7 +105,7 @@ func TestLastRunSync(t *testing.T) {
}
r.now = fakeNow
- err = r.reportLastSync()
+ err = r.ReportLastSync()
if err != nil {
t.Fatalf("got reportLastSync() error %v, want nil", err)
}
diff --git a/pkg/syncutil/syncbool_test.go b/pkg/syncutil/syncbool_test.go
index f5e5931efe3..75606c50233 100644
--- a/pkg/syncutil/syncbool_test.go
+++ b/pkg/syncutil/syncbool_test.go
@@ -16,10 +16,11 @@ limitations under the License.
package syncutil_test
import (
+ "context"
"testing"
"time"
- "github.com/open-policy-agent/gatekeeper/pkg/syncutil"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/syncutil"
"k8s.io/apimachinery/pkg/util/wait"
)
@@ -36,7 +37,7 @@ func Test_SyncBool(t *testing.T) {
b.Set(true)
}()
- waitErr := wait.Poll(10*time.Millisecond, 5*time.Second, func() (done bool, err error) {
+ waitErr := wait.PollUntilContextTimeout(context.Background(), 10*time.Millisecond, 5*time.Second, false, func(ctx context.Context) (done bool, err error) {
return b.Get(), nil
})
diff --git a/pkg/target/data.go b/pkg/target/data.go
index 35fa7df9574..de9af6ece8d 100644
--- a/pkg/target/data.go
+++ b/pkg/target/data.go
@@ -1,7 +1,7 @@
package target
import (
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
diff --git a/pkg/target/match_schema.go b/pkg/target/match_schema.go
index 314815e5e76..e3ed2e7b876 100644
--- a/pkg/target/match_schema.go
+++ b/pkg/target/match_schema.go
@@ -1,130 +1,49 @@
package target
-import "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
+import (
+ "fmt"
-// This pattern is meant to match:
-//
-// REGULAR NAMESPACES
-// - These are defined by this pattern: [a-z0-9]([-a-z0-9]*[a-z0-9])?
-// - You'll see that this is the first two-thirds or so of the pattern below
-//
-// PREFIX OR SUFFIX BASED WILDCARDS
-// - A typical namespace must end in an alphanumeric character. A prefixed wildcard
-// can end in "*" (like `kube*`) or "-*" (like `kube-*`), and a suffixed wildcard
-// can start with "*" (like `*system`) or "*-" (like `*-system`).
-// - To implement this, we add either (\*|\*-)? as a prefix or (\*|-\*)? as a suffix.
-// Using both prefixed wildcards and suffixed wildcards at once is not supported. Therefore,
-// this _does not_ allow the value to start _and_ end in a wildcard (like `*-*`).
-// - Crucially, this _does not_ allow the value to start or end in a dash (like `-system` or `kube-`).
-// That is not a valid namespace and not a wildcard, so it's disallowed.
-//
-// Notably, this disallows other uses of the "*" character like:
-// - *
-// - k*-system
-//
-// See the following regexr to test this regex: https://regexr.com/6dgdj
-const wildcardNSPattern = `^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$`
+ "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "sigs.k8s.io/yaml"
+)
-func matchSchema() apiextensions.JSONSchemaProps {
- // Define some repeatedly used sections
- wildcardNSList := apiextensions.JSONSchemaProps{
- Type: "array",
- Items: &apiextensions.JSONSchemaPropsOrArray{
- Schema: &apiextensions.JSONSchemaProps{Type: "string", Pattern: wildcardNSPattern},
- },
+var matchJSONSchemaProps apiextensions.JSONSchemaProps
+
+func init() {
+ matchCRD := &apiextensionsv1.CustomResourceDefinition{}
+ if err := yaml.Unmarshal([]byte(matchYAML), matchCRD); err != nil {
+ panic(fmt.Errorf("failed to unmarshal match yaml: %w", err))
}
- nullableStringList := apiextensions.JSONSchemaProps{
- Type: "array",
- Items: &apiextensions.JSONSchemaPropsOrArray{
- Schema: &apiextensions.JSONSchemaProps{Type: "string", Nullable: true},
- },
+ // Sanity checks to ensure the CRD was generated properly
+ if len(matchCRD.Spec.Versions) != 1 {
+ panic(fmt.Errorf("generated match CRD does not contain any versions"))
+ }
+ if matchCRD.Spec.Versions[0].Schema.OpenAPIV3Schema == nil {
+ panic(fmt.Errorf("generated match CRD has nil OpenAPIV3Schema"))
}
- trueBool := true
- labelSelectorSchema := apiextensions.JSONSchemaProps{
- Type: "object",
- Properties: map[string]apiextensions.JSONSchemaProps{
- "matchLabels": {
- Type: "object",
- Description: "A mapping of label keys to sets of allowed label values for those keys. A selected resource will match all of these expressions.",
- AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
- Allows: true,
- Schema: &apiextensions.JSONSchemaProps{Type: "string"},
- },
- XPreserveUnknownFields: &trueBool,
- },
- "matchExpressions": {
- Type: "array",
- Description: "a list of label selection expressions. A selected resource will match all of these expressions.",
- Items: &apiextensions.JSONSchemaPropsOrArray{
- Schema: &apiextensions.JSONSchemaProps{
- Type: "object",
- Description: "a selector that specifies a label key, a set of label values, an operator that defines the relationship between the two that will match the selector.",
- Properties: map[string]apiextensions.JSONSchemaProps{
- "key": {
- Description: "the label key that the selector applies to.",
- Type: "string",
- },
- "operator": {
- Type: "string",
- Description: "the relationship between the label and value set that defines a matching selection.",
- Enum: []apiextensions.JSON{
- "In",
- "NotIn",
- "Exists",
- "DoesNotExist",
- },
- },
- "values": {
- Type: "array",
- Description: "a set of label values.",
- Items: &apiextensions.JSONSchemaPropsOrArray{
- Schema: &apiextensions.JSONSchemaProps{Type: "string"},
- },
- },
- },
- },
- },
- },
- },
+ // Convert v1 JSONSchemaProps to versionless
+ rt := runtime.NewScheme()
+ if err := apiextensions.AddToScheme(rt); err != nil {
+ panic(fmt.Errorf("could not add apiextensions to scheme: %w", err))
+ }
+ if err := apiextensionsv1.AddToScheme(rt); err != nil {
+ panic(fmt.Errorf("could not add apiextensionsv1 to scheme: %w", err))
+ }
+ embedded := matchCRD.Spec.Versions[0].Schema.OpenAPIV3Schema.Properties["embeddedMatch"]
+ if err := rt.Convert(&embedded, &matchJSONSchemaProps, nil); err != nil {
+ panic(fmt.Errorf("could not convert match JSONSchemaProps from v1 to versionless: %w", err))
}
- // Make sure to copy description changes into pkg/mutation/match/match.go's `Match` struct.
- return apiextensions.JSONSchemaProps{
- Type: "object",
- Properties: map[string]apiextensions.JSONSchemaProps{
- "kinds": {
- Type: "array",
- Items: &apiextensions.JSONSchemaPropsOrArray{
- Schema: &apiextensions.JSONSchemaProps{
- Type: "object",
- Description: "The Group and Kind of objects that should be matched. If multiple groups/kinds combinations are specified, an incoming resource need only match one to be in scope.",
- Properties: map[string]apiextensions.JSONSchemaProps{
- "apiGroups": nullableStringList,
- "kinds": nullableStringList,
- },
- },
- },
- },
- "namespaces": *propsWithDescription(&wildcardNSList, "`namespaces` is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix-based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`."),
- "excludedNamespaces": *propsWithDescription(&wildcardNSList, "`excludedNamespaces` is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix-based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`."),
- "labelSelector": *propsWithDescription(&labelSelectorSchema, "`labelSelector` is the combination of two optional fields: `matchLabels` and `matchExpressions`. These two fields provide different methods of selecting or excluding k8s objects based on the label keys and values included in object metadata. All selection expressions from both sections are ANDed to determine if an object meets the cumulative requirements of the selector."),
- "namespaceSelector": *propsWithDescription(&labelSelectorSchema, "`namespaceSelector` is a label selector against an object's containing namespace or the object itself, if the object is a namespace."),
- "scope": {
- Type: "string",
- Description: "`scope` determines if cluster-scoped and/or namespaced-scoped resources are matched. Accepts `*`, `Cluster`, or `Namespaced`. (defaults to `*`)",
- Enum: []apiextensions.JSON{
- "*",
- "Cluster",
- "Namespaced",
- },
- },
- "name": {
- Type: "string",
- Description: "`name` is the name of an object. If defined, it matches against objects with the specified name. Name also supports a prefix-based glob. For example, `name: pod-*` matches both `pod-a` and `pod-b`.",
- Pattern: wildcardNSPattern,
- },
- },
+ // Verify conversion worked by checking properties field
+ if _, exists := matchJSONSchemaProps.Properties["kinds"]; !exists {
+ panic("converted match schema does not have 'kinds' field")
}
}
+
+func matchSchema() apiextensions.JSONSchemaProps {
+ return *matchJSONSchemaProps.DeepCopy()
+}
diff --git a/pkg/target/matchcrd_constant.go b/pkg/target/matchcrd_constant.go
new file mode 100644
index 00000000000..fd454258514
--- /dev/null
+++ b/pkg/target/matchcrd_constant.go
@@ -0,0 +1,216 @@
+package target
+
+// DO NOT MODIFY THIS FILE DIRECTLY!
+// This file is generated from ./pkg/mutation/match/match_types.go via "make manifests".
+
+const matchYAML = `
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.10.0
+ creationTimestamp: null
+ name: matchcrd.match.gatekeeper.sh
+spec:
+ group: match.gatekeeper.sh
+ names:
+ kind: DummyCRD
+ listKind: DummyCRDList
+ plural: matchcrd
+ singular: dummycrd
+ scope: Namespaced
+ versions:
+ - name: match
+ schema:
+ openAPIV3Schema:
+ description: DummyCRD is a "dummy" CRD to hold the Match object, which we
+ ultimately need to generate JSONSchemaProps. The TypeMeta and ObjectMeta
+ fields are required for controller-gen to generate the CRD.
+ 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
+ embeddedMatch:
+ description: Match selects which objects are in scope.
+ properties:
+ excludedNamespaces:
+ description: 'ExcludedNamespaces is a list of namespace names. If
+ defined, a constraint only applies to resources not in a listed
+ namespace. ExcludedNamespaces also supports a prefix or suffix based
+ glob. For example, `+"`"+`excludedNamespaces: [kube-*]`+"`"+` matches both
+ `+"`"+`kube-system`+"`"+` and `+"`"+`kube-public`+"`"+`, and `+"`"+`excludedNamespaces: [*-system]`+"`"+`
+ matches both `+"`"+`kube-system`+"`"+` and `+"`"+`gatekeeper-system`+"`"+`.'
+ items:
+ description: 'A string that supports globbing at its front or end.
+ Ex: "kube-*" will match "kube-system" or "kube-public", "*-system"
+ will match "kube-system" or "gatekeeper-system". The asterisk
+ is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ kinds:
+ items:
+ description: Kinds accepts a list of objects with apiGroups and
+ kinds fields that list the groups/kinds of objects to which the
+ mutation will apply. If multiple groups/kinds objects are specified,
+ only one match is needed for the resource to be in scope.
+ properties:
+ apiGroups:
+ description: APIGroups is the API groups the resources belong
+ to. '*' is all groups. If '*' is present, the length of the
+ slice must be one. Required.
+ items:
+ type: string
+ type: array
+ kinds:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ labelSelector:
+ description: 'LabelSelector is the combination of two optional fields:
+ `+"`"+`matchLabels`+"`"+` and `+"`"+`matchExpressions`+"`"+`. These two fields provide
+ different methods of selecting or excluding k8s objects based on
+ the label keys and values included in object metadata. All selection
+ expressions from both sections are ANDed to determine if an object
+ meets the cumulative requirements of the selector.'
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that
+ contains values, a key, and an operator that relates the key
+ and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies
+ to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to
+ a set of values. Valid operators are In, NotIn, Exists
+ and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the
+ operator is In or NotIn, the values array must be non-empty.
+ If the operator is Exists or DoesNotExist, the values
+ array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single
+ {key,value} in the matchLabels map is equivalent to an element
+ of matchExpressions, whose key field is "key", the operator
+ is "In", and the values array contains only "value". The requirements
+ are ANDed.
+ type: object
+ type: object
+ name:
+ description: 'Name is the name of an object. If defined, it will
+ match against objects with the specified name. Name also supports
+ a prefix or suffix glob. For example, `+"`"+`name: pod-*`+"`"+` would match
+ both `+"`"+`pod-a`+"`"+` and `+"`"+`pod-b`+"`"+`, and `+"`"+`name: *-pod`+"`"+` would match both `+"`"+`a-pod`+"`"+`
+ and `+"`"+`b-pod`+"`"+`.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ namespaceSelector:
+ description: NamespaceSelector is a label selector against an object's
+ containing namespace or the object itself, if the object is a namespace.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: A label selector requirement is a selector that
+ contains values, a key, and an operator that relates the key
+ and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies
+ to.
+ type: string
+ operator:
+ description: operator represents a key's relationship to
+ a set of values. Valid operators are In, NotIn, Exists
+ and DoesNotExist.
+ type: string
+ values:
+ description: values is an array of string values. If the
+ operator is In or NotIn, the values array must be non-empty.
+ If the operator is Exists or DoesNotExist, the values
+ array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: matchLabels is a map of {key,value} pairs. A single
+ {key,value} in the matchLabels map is equivalent to an element
+ of matchExpressions, whose key field is "key", the operator
+ is "In", and the values array contains only "value". The requirements
+ are ANDed.
+ type: object
+ type: object
+ namespaces:
+ description: 'Namespaces is a list of namespace names. If defined,
+ a constraint only applies to resources in a listed namespace. Namespaces
+ also supports a prefix or suffix based glob. For example, `+"`"+`namespaces:
+ [kube-*]`+"`"+` matches both `+"`"+`kube-system`+"`"+` and `+"`"+`kube-public`+"`"+`, and `+"`"+`namespaces:
+ [*-system]`+"`"+` matches both `+"`"+`kube-system`+"`"+` and `+"`"+`gatekeeper-system`+"`"+`.'
+ items:
+ description: 'A string that supports globbing at its front or end.
+ Ex: "kube-*" will match "kube-system" or "kube-public", "*-system"
+ will match "kube-system" or "gatekeeper-system". The asterisk
+ is required for wildcard matching.'
+ pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
+ type: string
+ type: array
+ scope:
+ description: Scope determines if cluster-scoped and/or namespaced-scoped
+ resources are matched. Accepts `+"`"+`*`+"`"+`, `+"`"+`Cluster`+"`"+`, or `+"`"+`Namespaced`+"`"+`.
+ (defaults to `+"`"+`*`+"`"+`)
+ type: string
+ source:
+ description: Source determines whether generated or original resources
+ are matched. Accepts `+"`"+`Generated`+"`"+`|`+"`"+`Original`+"`"+`|`+"`"+`All`+"`"+` (defaults to `+"`"+`All`+"`"+`).
+ A value of `+"`"+`Generated`+"`"+` will only match generated resources, while
+ `+"`"+`Original`+"`"+` will only match regular resources.
+ enum:
+ - All
+ - Generated
+ - Original
+ type: string
+ type: object
+ 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
+ metadataDummy:
+ type: object
+ type: object
+ served: true
+ storage: true
+`
diff --git a/pkg/target/matcher.go b/pkg/target/matcher.go
index eaa7591ff11..ad199713fe9 100644
--- a/pkg/target/matcher.go
+++ b/pkg/target/matcher.go
@@ -4,8 +4,8 @@ import (
"fmt"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/constraints"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@@ -56,7 +56,7 @@ func matchAny(m *Matcher, ns *corev1.Namespace, source types.SourceType, objs ..
}
matched, err := match.Matches(m.match, t)
if err != nil {
- return false, fmt.Errorf("%w: %v", ErrMatching, err)
+ return false, fmt.Errorf("%w: %v :%w", ErrMatching, obj.GetName(), err)
}
if matched {
diff --git a/pkg/target/review.go b/pkg/target/review.go
index f814c337efb..f2fbe1fa60b 100644
--- a/pkg/target/review.go
+++ b/pkg/target/review.go
@@ -1,7 +1,7 @@
package target
import (
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
)
@@ -17,3 +17,7 @@ type gkReview struct {
namespace *corev1.Namespace
source types.SourceType
}
+
+func (g *gkReview) GetAdmissionRequest() *admissionv1.AdmissionRequest {
+ return &g.AdmissionRequest
+}
diff --git a/pkg/target/target.go b/pkg/target/target.go
index c93c16d5c3e..e6c14c7ca1d 100644
--- a/pkg/target/target.go
+++ b/pkg/target/target.go
@@ -6,7 +6,7 @@ import (
"github.com/open-policy-agent/frameworks/constraint/pkg/core/constraints"
"github.com/open-policy-agent/frameworks/constraint/pkg/handler"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
"github.com/pkg/errors"
admissionv1 "k8s.io/api/admission/v1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
@@ -162,12 +162,6 @@ func unstructuredToAdmissionRequest(obj *unstructured.Unstructured) (*gkReview,
return &gkReview{AdmissionRequest: req}, nil
}
-func propsWithDescription(props *apiextensions.JSONSchemaProps, description string) *apiextensions.JSONSchemaProps {
- propCopy := props.DeepCopy()
- propCopy.Description = description
- return propCopy
-}
-
func (h *K8sValidationTarget) MatchSchema() apiextensions.JSONSchemaProps {
return matchSchema()
}
@@ -183,7 +177,7 @@ func (h *K8sValidationTarget) ValidateConstraint(u *unstructured.Unstructured) e
if err != nil {
return err
}
- errorList := validation.ValidateLabelSelector(labelSelectorObj, field.NewPath("spec", "labelSelector"))
+ errorList := validation.ValidateLabelSelector(labelSelectorObj, validation.LabelSelectorValidationOptions{}, field.NewPath("spec", "labelSelector"))
if len(errorList) > 0 {
return errorList.ToAggregate()
}
@@ -199,7 +193,7 @@ func (h *K8sValidationTarget) ValidateConstraint(u *unstructured.Unstructured) e
if err != nil {
return err
}
- errorList := validation.ValidateLabelSelector(namespaceSelectorObj, field.NewPath("spec", "labelSelector"))
+ errorList := validation.ValidateLabelSelector(namespaceSelectorObj, validation.LabelSelectorValidationOptions{}, field.NewPath("spec", "labelSelector"))
if len(errorList) > 0 {
return errorList.ToAggregate()
}
@@ -236,13 +230,13 @@ func convertToMatch(object map[string]interface{}) (*match.Match, error) {
func (h *K8sValidationTarget) ToMatcher(u *unstructured.Unstructured) (constraints.Matcher, error) {
obj, found, err := unstructured.NestedMap(u.Object, "spec", "match")
if err != nil {
- return nil, fmt.Errorf("%w: %v", ErrCreatingMatcher, err)
+ return nil, fmt.Errorf("%w: %w", ErrCreatingMatcher, err)
}
if found && obj != nil {
m, err := convertToMatch(obj)
if err != nil {
- return nil, fmt.Errorf("%w: %v", ErrCreatingMatcher, err)
+ return nil, fmt.Errorf("%w: %w", ErrCreatingMatcher, err)
}
return &Matcher{match: m, cache: &h.cache}, nil
}
diff --git a/pkg/target/target_integration_test.go b/pkg/target/target_integration_test.go
index 20f8b189d8d..dee7d32558e 100644
--- a/pkg/target/target_integration_test.go
+++ b/pkg/target/target_integration_test.go
@@ -5,17 +5,19 @@ import (
"encoding/json"
"testing"
- "github.com/ghodss/yaml"
+ templatesv1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
"github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers"
- "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
+ api "github.com/open-policy-agent/gatekeeper/v3/apis"
admissionv1 "k8s.io/api/admission/v1"
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"
"k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/yaml"
)
const (
@@ -412,10 +414,15 @@ func TestConstraintEnforcement(t *testing.T) {
},
}
+ scheme := runtime.NewScheme()
+ if err := api.AddToScheme(scheme); err != nil {
+ t.Fatalf("could not initialize scheme: %s", err)
+ }
+
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
target := &K8sValidationTarget{}
- driver, err := local.New(local.Tracing(true))
+ driver, err := rego.New(rego.Tracing(true))
if err != nil {
t.Fatalf("unable to set up Driver: %v", err)
}
@@ -425,10 +432,14 @@ func TestConstraintEnforcement(t *testing.T) {
t.Fatalf("unable to set up OPA client: %s", err)
}
- tmpl := &templates.ConstraintTemplate{}
- if err := yaml.Unmarshal([]byte(testTemplate), tmpl); err != nil {
+ versionedTmpl := &templatesv1beta1.ConstraintTemplate{}
+ if err := yaml.Unmarshal([]byte(testTemplate), versionedTmpl); err != nil {
t.Fatalf("unable to unmarshal template: %s", err)
}
+ tmpl := &templates.ConstraintTemplate{}
+ if err := scheme.Convert(versionedTmpl, tmpl, nil); err != nil {
+ t.Fatalf("could not convert template: %s", err)
+ }
ctx := context.Background()
if _, err := c.AddTemplate(ctx, tmpl); err != nil {
t.Fatalf("unable to add template: %s", err)
diff --git a/pkg/target/target_test.go b/pkg/target/target_test.go
index 33fececaeee..83f507465bd 100644
--- a/pkg/target/target_test.go
+++ b/pkg/target/target_test.go
@@ -10,12 +10,12 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/constraints"
- "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -26,7 +26,7 @@ import (
func TestFrameworkInjection(t *testing.T) {
target := &K8sValidationTarget{}
- driver, err := local.New(local.Tracing(true))
+ driver, err := rego.New(rego.Tracing(true))
if err != nil {
t.Fatal(err)
}
@@ -54,6 +54,7 @@ func TestValidateConstraint(t *testing.T) {
},
"spec": {
"match": {
+ "source": "All",
"kinds": [
{
"apiGroups": [""],
@@ -80,6 +81,7 @@ func TestValidateConstraint(t *testing.T) {
},
"spec": {
"match": {
+ "source": "Original",
"kinds": [
{
"apiGroups": [""],
@@ -90,7 +92,7 @@ func TestValidateConstraint(t *testing.T) {
"matchExpressions": [{
"key": "someKey",
"operator": "NotIn",
- "values": ["some value"]
+ "values": ["some-value"]
}]
}
},
@@ -130,7 +132,7 @@ func TestValidateConstraint(t *testing.T) {
ErrorExpected: true,
},
{
- Name: "Invalid LabelSelector MatchLels",
+ Name: "Invalid LabelSelector MatchLabels",
Constraint: `
{
"apiVersion": "constraints.gatekeeper.sh/v1beta1",
@@ -202,6 +204,7 @@ func TestValidateConstraint(t *testing.T) {
},
"spec": {
"match": {
+ "source": "Generated",
"kinds": [
{
"apiGroups": [""],
@@ -212,7 +215,7 @@ func TestValidateConstraint(t *testing.T) {
"matchExpressions": [{
"key": "someKey",
"operator": "In",
- "values": ["some value"]
+ "values": ["some-value"]
}]
}
},
@@ -245,7 +248,7 @@ func TestValidateConstraint(t *testing.T) {
"matchExpressions": [{
"key": "someKey",
"operator": "In",
- "values": ["some value"]
+ "values": ["some-value"]
}]
}
},
@@ -509,7 +512,7 @@ func fooMatch() *match.Match {
},
},
Scope: "Namespaced",
- Namespaces: []util.Wildcard{"my-ns"},
+ Namespaces: []wildcard.Wildcard{"my-ns"},
ExcludedNamespaces: nil,
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
diff --git a/pkg/upgrade/manager.go b/pkg/upgrade/manager.go
index b50e4a14a3e..6b4f1eccf55 100644
--- a/pkg/upgrade/manager.go
+++ b/pkg/upgrade/manager.go
@@ -8,7 +8,7 @@ import (
"strings"
"time"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/pkg/util/enforcement_action.go b/pkg/util/enforcement_action.go
index 39c49781bb6..555fbe2d2e4 100644
--- a/pkg/util/enforcement_action.go
+++ b/pkg/util/enforcement_action.go
@@ -43,7 +43,7 @@ func ValidateEnforcementAction(input EnforcementAction) error {
func GetEnforcementAction(item map[string]interface{}) (EnforcementAction, error) {
enforcementActionSpec, _, err := unstructured.NestedString(item, "spec", "enforcementAction")
if err != nil {
- return "", fmt.Errorf("%w: %v", ErrInvalidSpecEnforcementAction, err)
+ return "", fmt.Errorf("%w: %w", ErrInvalidSpecEnforcementAction, err)
}
enforcementAction := EnforcementAction(enforcementActionSpec)
// default enforcementAction is deny
diff --git a/pkg/util/pack.go b/pkg/util/pack.go
index fdb7ba85747..720a9be71c0 100644
--- a/pkg/util/pack.go
+++ b/pkg/util/pack.go
@@ -1,6 +1,7 @@
package util
import (
+ "context"
"errors"
"fmt"
"strings"
@@ -41,7 +42,7 @@ func UnpackRequest(r reconcile.Request) (schema.GroupVersionKind, reconcile.Requ
// EventPackerMapFunc maps an event into a reconcile.Request with embedded GVK information. Must
// be unpacked with UnpackRequest() before use.
func EventPackerMapFunc() handler.MapFunc {
- return func(obj client.Object) []reconcile.Request {
+ return func(_ context.Context, obj client.Object) []reconcile.Request {
if obj == nil {
return nil
}
@@ -67,11 +68,11 @@ func EventPackerMapFunc() handler.MapFunc {
// no GVK associated with them by allowing the caller to set the expected GVK.
func EventPackerMapFuncHardcodeGVK(gvk schema.GroupVersionKind) handler.MapFunc {
mf := EventPackerMapFunc()
- return func(obj client.Object) []reconcile.Request {
+ return func(ctx context.Context, obj client.Object) []reconcile.Request {
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(gvk)
u.SetNamespace(obj.GetNamespace())
u.SetName(obj.GetName())
- return mf(u)
+ return mf(ctx, u)
}
}
diff --git a/pkg/util/pack_test.go b/pkg/util/pack_test.go
index 61aec95286b..e623b30f8b9 100644
--- a/pkg/util/pack_test.go
+++ b/pkg/util/pack_test.go
@@ -1,6 +1,7 @@
package util
import (
+ "context"
"errors"
"testing"
@@ -91,7 +92,7 @@ func TestEventPackerMapFunc(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- got := EventPackerMapFunc()(tc.obj)
+ got := EventPackerMapFunc()(context.Background(), tc.obj)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("got EventPackerMapFunc()(obj) diff: %v", diff)
}
diff --git a/pkg/util/wildcard.go b/pkg/util/wildcard.go
deleted file mode 100644
index 5235ee66f34..00000000000
--- a/pkg/util/wildcard.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package util
-
-import "strings"
-
-// +kubebuilder:validation:Pattern=`^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$`
-
-// A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or
-// "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is
-// required for wildcard matching.
-//
-//nolint:revive
-type Wildcard string
-
-// Matches returns true if the candidate parameter is either an exact match of the Wildcard,
-// or if the Wildcard is a valid glob-match for the candidate. The Wildcard must start or end
-// in a "*" to be considered a glob.
-func (w Wildcard) Matches(candidate string) bool {
- wStr := string(w)
- switch {
- case strings.HasPrefix(wStr, "*") && strings.HasSuffix(wStr, "*"):
- return strings.Contains(candidate, strings.TrimSuffix(strings.TrimPrefix(wStr, "*"), "*"))
- case strings.HasPrefix(wStr, "*"):
- return strings.HasSuffix(candidate, strings.TrimPrefix(wStr, "*"))
- case strings.HasSuffix(wStr, "*"):
- return strings.HasPrefix(candidate, strings.TrimSuffix(wStr, "*"))
- default:
- return wStr == candidate
- }
-}
diff --git a/pkg/util/wildcard_test.go b/pkg/util/wildcard_test.go
deleted file mode 100644
index 695260c4ed8..00000000000
--- a/pkg/util/wildcard_test.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package util
-
-import "testing"
-
-func TestMatches(t *testing.T) {
- tcs := []struct {
- name string
- w Wildcard
- candidate string
- matches bool
- }{
- {
- name: "exact text match",
- w: Wildcard("kube-system"),
- candidate: "kube-system",
- matches: true,
- },
- {
- name: "no glob, wrong text",
- w: Wildcard("kube-system"),
- candidate: "gatekeeper-system",
- matches: false,
- },
- {
- name: "wildcard prefix match",
- w: Wildcard("kube-*"),
- candidate: "kube-system",
- matches: true,
- },
- {
- name: "wildcard prefix doesn't match",
- w: Wildcard("kube-*"),
- candidate: "gatekeeper-system",
- matches: false,
- },
- {
- name: "wildcard suffix match",
- w: Wildcard("*-system"),
- candidate: "kube-system",
- matches: true,
- },
- {
- name: "wildcard suffix doesn't match",
- w: Wildcard("*-system"),
- candidate: "kube-public",
- matches: false,
- },
- {
- name: "missing asterisk yields no wildcard support",
- w: Wildcard("kube-"),
- candidate: "kube-system",
- matches: false,
- },
- {
- name: "wildcard suffix and prefix match",
- w: Wildcard("*-kube-*"),
- candidate: "test-kube-test",
- matches: true,
- },
- {
- name: "no wildcard, only hypens at suffix and prefix",
- w: Wildcard("-kube-"),
- candidate: "test-kube-test",
- matches: false,
- },
- {
- name: "wild card at suffix and prefix, multiple hyphens",
- w: Wildcard("*-kube-*"),
- candidate: "test-dev-kube-dev-test",
- matches: true,
- },
- {
- name: "wild card at suffid and end, multiple hypens, no match",
- w: Wildcard("*-kube-*"),
- candidate: "my-kub-controller",
- matches: false,
- },
- {
- name: "wild card at suffix and prefix, multiple hyphens, no match",
- w: Wildcard("*-kube-*"),
- candidate: "my-controller-manager",
- matches: false,
- },
- }
-
- for _, tc := range tcs {
- t.Run(tc.name, func(t *testing.T) {
- if tc.w.Matches(tc.candidate) != tc.matches {
- if tc.matches {
- t.Errorf("Expected candidate '%v' to match wildcard '%v'", tc.candidate, tc.w)
- } else {
- t.Errorf("Candidate '%v' unexpectedly matched wildcard '%v'", tc.candidate, tc.w)
- }
- }
- })
- }
-}
diff --git a/pkg/version/version.go b/pkg/version/version.go
index 52531b3049d..4907d50cb9b 100644
--- a/pkg/version/version.go
+++ b/pkg/version/version.go
@@ -3,18 +3,60 @@ package version
import (
"fmt"
"runtime"
+ "runtime/debug"
)
-// Vcs is is the commit hash for the binary build.
-var Vcs string
-
-// Timestamp is the date for the binary build.
-var Timestamp string
+const (
+ gatorState = "beta"
+ unknown = "unknown"
+)
// Version is the gatekeeper version.
var Version string
-// GetUserAgent returns a user agent of the format: gatekeeper/ (/) /.
-func GetUserAgent() string {
- return fmt.Sprintf("gatekeeper/%s (%s/%s) %s/%s", Version, runtime.GOOS, runtime.GOARCH, Vcs, Timestamp)
+// GetUserAgent returns Gatekeeper and Gator version information.
+func GetUserAgent(name string) string {
+ vcsrevision := unknown
+ vcstimestamp := unknown
+ vcsdirty := ""
+ opaVersion := unknown
+ frameworksVersion := unknown
+
+ if info, ok := debug.ReadBuildInfo(); ok {
+ for _, v := range info.Settings {
+ switch v.Key {
+ case "vcs.revision":
+ vcsrevision = v.Value
+ case "vcs.modified":
+ if v.Value == "true" {
+ vcsdirty = "-dirty"
+ }
+ case "vcs.time":
+ vcstimestamp = v.Value
+ }
+ }
+
+ for _, v := range info.Deps {
+ switch v.Path {
+ case "github.com/open-policy-agent/opa":
+ opaVersion = v.Version
+ case "github.com/open-policy-agent/frameworks/constraint":
+ frameworksVersion = v.Version
+ }
+ }
+ }
+
+ // OPA and Frameworks version used by Gatekeeper and Gator
+ opaFrameworksVersion := fmt.Sprintf("opa/%s, frameworks/%s", opaVersion, frameworksVersion)
+
+ // if LDFLAGS are not set, use revision info
+ if Version == "" {
+ Version = fmt.Sprintf("devel (%s)", vcsrevision)
+ }
+
+ if name == "gator" {
+ return fmt.Sprintf("%s (Feature State: %s), %s", Version, gatorState, opaFrameworksVersion)
+ }
+
+ return fmt.Sprintf("%s/%s (%s/%s) %s%s/%s, %s", name, Version, runtime.GOOS, runtime.GOARCH, vcsrevision, vcsdirty, vcstimestamp, opaFrameworksVersion)
}
diff --git a/pkg/watch/manager.go b/pkg/watch/manager.go
index cd8a7a0e60c..7858fa42d78 100644
--- a/pkg/watch/manager.go
+++ b/pkg/watch/manager.go
@@ -62,7 +62,7 @@ type AddFunction func(manager.Manager) error
// It supports non-blocking calls to get informers, as well as the
// ability to remove an informer dynamically.
type RemovableCache interface {
- GetInformerNonBlocking(obj client.Object) (cache.Informer, error)
+ GetInformer(_ context.Context, obj client.Object, opts ...cache.InformerGetOption) (cache.Informer, error)
List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error
Remove(obj client.Object) error
}
@@ -138,13 +138,13 @@ func (wm *Manager) GetManagedGVK() []schema.GroupVersionKind {
return wm.managedKinds.GetGVK()
}
-func (wm *Manager) addWatch(r *Registrar, gvk schema.GroupVersionKind) error {
+func (wm *Manager) addWatch(ctx context.Context, r *Registrar, gvk schema.GroupVersionKind) error {
wm.watchedMux.Lock()
defer wm.watchedMux.Unlock()
- return wm.doAddWatch(r, gvk)
+ return wm.doAddWatch(ctx, r, gvk)
}
-func (wm *Manager) doAddWatch(r *Registrar, gvk schema.GroupVersionKind) error {
+func (wm *Manager) doAddWatch(ctx context.Context, r *Registrar, gvk schema.GroupVersionKind) error {
// lock acquired by caller
if r == nil {
@@ -177,14 +177,16 @@ func (wm *Manager) doAddWatch(r *Registrar, gvk schema.GroupVersionKind) error {
default:
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(gvk)
- informer, err := wm.cache.GetInformerNonBlocking(u)
+ informer, err := wm.cache.GetInformer(ctx, u, cache.InformerGetOption(cache.BlockUntilSynced(false)))
if err != nil || informer == nil {
// This is expected to fail if a CRD is unregistered.
return fmt.Errorf("getting informer for kind: %+v %w", gvk, err)
}
// First watcher gets a fresh informer, register for events.
- informer.AddEventHandler(wm)
+ if _, err := informer.AddEventHandler(wm); err != nil {
+ return err
+ }
}
// Mark it as watched.
@@ -199,13 +201,13 @@ func (wm *Manager) doAddWatch(r *Registrar, gvk schema.GroupVersionKind) error {
return nil
}
-func (wm *Manager) removeWatch(r *Registrar, gvk schema.GroupVersionKind) error {
+func (wm *Manager) removeWatch(ctx context.Context, r *Registrar, gvk schema.GroupVersionKind) error {
wm.watchedMux.Lock()
defer wm.watchedMux.Unlock()
- return wm.doRemoveWatch(r, gvk)
+ return wm.doRemoveWatch(ctx, r, gvk)
}
-func (wm *Manager) doRemoveWatch(r *Registrar, gvk schema.GroupVersionKind) error {
+func (wm *Manager) doRemoveWatch(ctx context.Context, r *Registrar, gvk schema.GroupVersionKind) error {
// lock acquired by caller
v, ok := wm.watchedKinds[gvk]
@@ -248,7 +250,7 @@ func (wm *Manager) doRemoveWatch(r *Registrar, gvk schema.GroupVersionKind) erro
}
// replaceWatches ensures all and only desired watches are running.
-func (wm *Manager) replaceWatches(r *Registrar) error {
+func (wm *Manager) replaceWatches(ctx context.Context, r *Registrar) error {
wm.watchedMux.Lock()
defer wm.watchedMux.Unlock()
@@ -260,7 +262,7 @@ func (wm *Manager) replaceWatches(r *Registrar) error {
// This registrar still desires this gvk, skip.
continue
}
- if err := wm.doRemoveWatch(r, gvk); err != nil {
+ if err := wm.doRemoveWatch(ctx, r, gvk); err != nil {
errlist = append(errlist, fmt.Errorf("removing watch for %+v %w", gvk, err))
}
}
@@ -270,7 +272,7 @@ func (wm *Manager) replaceWatches(r *Registrar) error {
if !v.registrars[r] {
continue
}
- if err := wm.doAddWatch(r, gvk); err != nil {
+ if err := wm.doAddWatch(ctx, r, gvk); err != nil {
errlist = append(errlist, fmt.Errorf("adding watch for %+v %w", gvk, err))
}
}
@@ -286,7 +288,7 @@ func (wm *Manager) replaceWatches(r *Registrar) error {
}
// OnAdd implements cache.ResourceEventHandler. Called by informers.
-func (wm *Manager) OnAdd(obj interface{}) {
+func (wm *Manager) OnAdd(obj interface{}, _ bool) {
// Send event to eventLoop() for processing
select {
case wm.events <- obj:
diff --git a/pkg/watch/manager_integration_test.go b/pkg/watch/manager_integration_test.go
index 1c8ea1d3983..582f1b2085f 100644
--- a/pkg/watch/manager_integration_test.go
+++ b/pkg/watch/manager_integration_test.go
@@ -25,19 +25,17 @@ import (
"github.com/go-logr/logr"
"github.com/onsi/gomega"
- "github.com/open-policy-agent/gatekeeper/pkg/fakes"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- "github.com/open-policy-agent/gatekeeper/pkg/watch"
- testclient "github.com/open-policy-agent/gatekeeper/test/clients"
- "github.com/open-policy-agent/gatekeeper/test/testutils"
- "github.com/open-policy-agent/gatekeeper/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ testclient "github.com/open-policy-agent/gatekeeper/v3/test/clients"
+ "github.com/open-policy-agent/gatekeeper/v3/test/testutils"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/sync/errgroup"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
apierrors "k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -62,11 +60,8 @@ func setupManager(t *testing.T) (manager.Manager, *watch.Manager) {
metrics.Registry = prometheus.NewRegistry()
mgr, err := manager.New(cfg, manager.Options{
MetricsBindAddress: "0",
- NewCache: dynamiccache.New,
- MapperProvider: func(c *rest.Config) (meta.RESTMapper, error) {
- return apiutil.NewDynamicRESTMapper(c)
- },
- Logger: testutils.NewLogger(t),
+ MapperProvider: apiutil.NewDynamicRESTMapper,
+ Logger: testutils.NewLogger(t),
})
if err != nil {
t.Fatalf("setting up controller manager: %s", err)
@@ -121,7 +116,7 @@ func TestRegistrar_AddUnknown(t *testing.T) {
t.Fatalf("creating registrar: %v", err)
}
- err = r.AddWatch(schema.GroupVersionKind{
+ err = r.AddWatch(ctx, schema.GroupVersionKind{
Group: "i",
Version: "donot",
Kind: "exist",
@@ -197,7 +192,7 @@ func Test_ReconcileErrorDoesNotBlockController(t *testing.T) {
// Setup another watch. Show that both the error resource (in a backoff-requeue loop)
// and other resources can reconcile in an interleaving fashion.
err = c.Watch(
- &source.Kind{Type: &corev1.Namespace{}},
+ source.Kind(mgr.GetCache(), &corev1.Namespace{}),
&handler.EnqueueRequestForObject{},
)
if err != nil {
@@ -273,7 +268,7 @@ func TestRegistrar_Reconnect(t *testing.T) {
t.Fatalf("applying CRD: %v", err)
}
- err = r.AddWatch(gvk)
+ err = r.AddWatch(ctx, gvk)
if err != nil {
t.Fatalf("adding watch: %v", err)
}
@@ -371,7 +366,7 @@ func Test_Registrar_Replay(t *testing.T) {
t.Fatal(err)
}
- err = r.AddWatch(gvk)
+ err = r.AddWatch(ctx, gvk)
if err != nil {
t.Fatal(err)
}
diff --git a/pkg/watch/manager_suite_test.go b/pkg/watch/manager_suite_test.go
index f1771820643..e70d09f0ab7 100644
--- a/pkg/watch/manager_suite_test.go
+++ b/pkg/watch/manager_suite_test.go
@@ -20,7 +20,7 @@ import (
"os"
"testing"
- "github.com/open-policy-agent/gatekeeper/apis"
+ "github.com/open-policy-agent/gatekeeper/v3/apis"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/envtest"
diff --git a/pkg/watch/manager_test.go b/pkg/watch/manager_test.go
index 713dcc2009b..35b6d8c543b 100644
--- a/pkg/watch/manager_test.go
+++ b/pkg/watch/manager_test.go
@@ -40,17 +40,22 @@ type fakeCacheInformer struct {
handlers map[kcache.ResourceEventHandler]int
}
-func (f *fakeCacheInformer) AddEventHandler(h kcache.ResourceEventHandler) {
+func (f *fakeCacheInformer) AddEventHandler(h kcache.ResourceEventHandler) (kcache.ResourceEventHandlerRegistration, error) {
f.mu.Lock()
defer f.mu.Unlock()
if f.handlers == nil {
f.handlers = make(map[kcache.ResourceEventHandler]int)
}
f.handlers[h]++
+ return nil, nil
}
-func (f *fakeCacheInformer) AddEventHandlerWithResyncPeriod(h kcache.ResourceEventHandler, resyncPeriod time.Duration) {
- f.AddEventHandler(h)
+func (f *fakeCacheInformer) RemoveEventHandler(handle kcache.ResourceEventHandlerRegistration) error {
+ return nil
+}
+
+func (f *fakeCacheInformer) AddEventHandlerWithResyncPeriod(h kcache.ResourceEventHandler, resyncPeriod time.Duration) (kcache.ResourceEventHandlerRegistration, error) {
+ return f.AddEventHandler(h)
}
func (f *fakeCacheInformer) AddIndexers(indexers kcache.Indexers) error {
@@ -80,7 +85,7 @@ type fakeRemovableCache struct {
removeCounter int
}
-func (f *fakeRemovableCache) GetInformerNonBlocking(obj client.Object) (cache.Informer, error) {
+func (f *fakeRemovableCache) GetInformer(_ context.Context, obj client.Object, opts ...cache.InformerGetOption) (cache.Informer, error) {
return f.informer, nil
}
@@ -109,12 +114,12 @@ func (f *fakeRemovableCache) removeCount() int {
type funcCache struct {
ListFunc func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error
- GetInformerNonBlockingFunc func(obj client.Object) (cache.Informer, error)
+ GetInformerNonBlockingFunc func(ctx context.Context, obj client.Object) (cache.Informer, error)
}
-func (f *funcCache) GetInformerNonBlocking(obj client.Object) (cache.Informer, error) {
+func (f *funcCache) GetInformer(ctx context.Context, obj client.Object, opts ...cache.InformerGetOption) (cache.Informer, error) {
if f.GetInformerNonBlockingFunc != nil {
- return f.GetInformerNonBlockingFunc(obj)
+ return f.GetInformerNonBlockingFunc(ctx, obj)
}
return &fakeCacheInformer{}, nil
}
@@ -152,6 +157,7 @@ func setupWatchManager(c RemovableCache) (*Manager, context.CancelFunc, error) {
// Verifies that redundant calls to AddWatch (even across registrars) will be idempotent
// and only register a single event handler on the respective informer.
func TestRegistrar_AddWatch_Idempotent(t *testing.T) {
+ ctx := context.Background()
informer := &fakeCacheInformer{}
c := &fakeRemovableCache{informer: informer}
wm, cancel, err := setupWatchManager(c)
@@ -178,11 +184,11 @@ func TestRegistrar_AddWatch_Idempotent(t *testing.T) {
}
for _, r := range []*Registrar{r1, r2} {
- if err := r.AddWatch(gvk); err != nil {
+ if err := r.AddWatch(ctx, gvk); err != nil {
t.Errorf("setting initial watch: %v", err)
return
}
- if err := r.AddWatch(gvk); err != nil {
+ if err := r.AddWatch(ctx, gvk); err != nil {
t.Errorf("setting redundant watch: %v", err)
return
}
@@ -204,6 +210,7 @@ func TestRegistrar_AddWatch_Idempotent(t *testing.T) {
}
func TestRegistrar_RemoveWatch_Idempotent(t *testing.T) {
+ ctx := context.Background()
informer := &fakeCacheInformer{}
c := &fakeRemovableCache{informer: informer}
wm, cancel, err := setupWatchManager(c)
@@ -230,7 +237,7 @@ func TestRegistrar_RemoveWatch_Idempotent(t *testing.T) {
}
for _, r := range []*Registrar{r1, r2} {
- if err := r.AddWatch(gvk); err != nil {
+ if err := r.AddWatch(ctx, gvk); err != nil {
t.Errorf("setting initial watch: %v", err)
return
}
@@ -242,7 +249,7 @@ func TestRegistrar_RemoveWatch_Idempotent(t *testing.T) {
return
}
- if err := r1.RemoveWatch(gvk); err != nil {
+ if err := r1.RemoveWatch(ctx, gvk); err != nil {
t.Errorf("removing first watch: %v", err)
return
}
@@ -259,7 +266,7 @@ func TestRegistrar_RemoveWatch_Idempotent(t *testing.T) {
return
}
- if err := r2.RemoveWatch(gvk); err != nil {
+ if err := r2.RemoveWatch(ctx, gvk); err != nil {
t.Errorf("removing second watch: %v", err)
return
}
@@ -278,7 +285,7 @@ func TestRegistrar_RemoveWatch_Idempotent(t *testing.T) {
}
// Extra removes are fine.
- if err := r2.RemoveWatch(gvk); err != nil {
+ if err := r2.RemoveWatch(ctx, gvk); err != nil {
t.Errorf("redundant remove: %v", err)
return
}
@@ -324,7 +331,7 @@ func TestRegistrar_Replay(t *testing.T) {
}
for _, entry := range registrars {
- if err := entry.r.AddWatch(gvk); err != nil {
+ if err := entry.r.AddWatch(ctx, gvk); err != nil {
t.Errorf("setting initial watch: %v", err)
return
}
@@ -392,7 +399,7 @@ func TestRegistrar_Replay_Retry(t *testing.T) {
}
return nil
},
- GetInformerNonBlockingFunc: func(obj client.Object) (cache.Informer, error) {
+ GetInformerNonBlockingFunc: func(_ context.Context, obj client.Object) (cache.Informer, error) {
return informer, nil
},
}
@@ -417,7 +424,7 @@ func TestRegistrar_Replay_Retry(t *testing.T) {
}
for _, r := range []*Registrar{r1, r2} {
- if err := r.AddWatch(gvk); err != nil {
+ if err := r.AddWatch(ctx, gvk); err != nil {
t.Errorf("setting initial watch: %v", err)
return
}
@@ -502,7 +509,7 @@ func TestRegistrar_Replay_Async(t *testing.T) {
Kind: "Pod",
}
for _, r := range []*Registrar{r1, r2} {
- if err := r.AddWatch(gvk); err != nil {
+ if err := r.AddWatch(ctx, gvk); err != nil {
t.Errorf("setting initial watch: %v", err)
return
}
@@ -517,7 +524,7 @@ func TestRegistrar_Replay_Async(t *testing.T) {
}
// Ensure we can cancel a pending replay
- if err := r2.RemoveWatch(gvk); err != nil {
+ if err := r2.RemoveWatch(ctx, gvk); err != nil {
t.Errorf("removing watch: %v", err)
}
@@ -529,7 +536,7 @@ func TestRegistrar_Replay_Async(t *testing.T) {
}
// [Scenario 2] - Verify that pending replays are canceled during watch manager shutdown.
- if err := r2.AddWatch(gvk); err != nil {
+ if err := r2.AddWatch(ctx, gvk); err != nil {
t.Errorf("adding watch: %v", err)
}
select {
@@ -575,6 +582,7 @@ func TestRegistrar_Duplicates_Rejected(t *testing.T) {
// Verify ReplaceWatch replaces the set of watched resources for a registrar. New watches will be added,
// unneeded watches will be removed, and watches that haven't changed will remain unchanged.
func TestRegistrar_ReplaceWatch(t *testing.T) {
+ ctx := context.Background()
g := gomega.NewWithT(t)
var mu sync.Mutex
listCalls := make(map[schema.GroupVersionKind]int)
@@ -588,7 +596,7 @@ func TestRegistrar_ReplaceWatch(t *testing.T) {
listCalls[gvk]++
return nil
},
- GetInformerNonBlockingFunc: func(obj client.Object) (cache.Informer, error) {
+ GetInformerNonBlockingFunc: func(_ context.Context, obj client.Object) (cache.Informer, error) {
mu.Lock()
defer mu.Unlock()
gvk := obj.GetObjectKind().GroupVersionKind()
@@ -619,28 +627,28 @@ func TestRegistrar_ReplaceWatch(t *testing.T) {
service := schema.GroupVersionKind{Version: "v1", Kind: "Service"}
secret := schema.GroupVersionKind{Version: "v1", Kind: "Secret"}
- err = r1.AddWatch(pod)
+ err = r1.AddWatch(ctx, pod)
if err != nil {
t.Fatalf("initial pod watch: %v", err)
}
- err = r1.AddWatch(volume)
+ err = r1.AddWatch(ctx, volume)
if err != nil {
t.Fatalf("initial volume watch: %v", err)
}
- err = r1.AddWatch(deploy)
+ err = r1.AddWatch(ctx, deploy)
if err != nil {
t.Fatalf("initial deployment watch: %v", err)
}
- err = r2.AddWatch(volume)
+ err = r2.AddWatch(ctx, volume)
if err != nil {
t.Fatalf("initial volume watch: %v", err)
}
- err = r2.AddWatch(configMap)
+ err = r2.AddWatch(ctx, configMap)
if err != nil {
t.Fatalf("initial configmap watch: %v", err)
}
- err = r2.AddWatch(secret)
+ err = r2.AddWatch(ctx, secret)
if err != nil {
t.Fatalf("initial secret watch: %v", err)
}
@@ -677,7 +685,7 @@ func TestRegistrar_ReplaceWatch(t *testing.T) {
// Pod overlaps between r1 and r2. Secret is retained. ConfigMap is swapped for Service.
// Volume originally overlapped between r1 and r2, but will be removed from r2.
- err = r2.ReplaceWatch([]schema.GroupVersionKind{pod, service, secret})
+ err = r2.ReplaceWatch(ctx, []schema.GroupVersionKind{pod, service, secret})
if err != nil {
t.Fatalf("calling replaceWatch: %v", err)
}
diff --git a/pkg/watch/registrar.go b/pkg/watch/registrar.go
index 79b080ac967..c1f90c4cd22 100644
--- a/pkg/watch/registrar.go
+++ b/pkg/watch/registrar.go
@@ -16,6 +16,7 @@ limitations under the License.
package watch
import (
+ "context"
"fmt"
"sort"
"sync"
@@ -84,7 +85,7 @@ func (r *recordKeeper) RemoveRegistrar(parentName string) error {
if registrar == nil {
return nil
}
- if err := registrar.ReplaceWatch(nil); err != nil {
+ if err := registrar.ReplaceWatch(context.Background(), nil); err != nil {
return err
}
@@ -227,7 +228,7 @@ type Registrar struct {
// - The consumer of the channel does not receive any unbuffered events.
//
// XXXX also may block if the watch manager has not been started.
-func (r *Registrar) AddWatch(gvk schema.GroupVersionKind) error {
+func (r *Registrar) AddWatch(ctx context.Context, gvk schema.GroupVersionKind) error {
r.mux.Lock()
defer r.mux.Unlock()
wv := vitals{
@@ -235,11 +236,11 @@ func (r *Registrar) AddWatch(gvk schema.GroupVersionKind) error {
registrars: map[*Registrar]bool{r: true},
}
r.managedKinds.Update(r.parentName, vitalsByGVK{gvk: wv})
- return r.mgr.addWatch(r, gvk)
+ return r.mgr.addWatch(ctx, r, gvk)
}
// ReplaceWatch replaces the set of watched resources.
-func (r *Registrar) ReplaceWatch(gvks []schema.GroupVersionKind) error {
+func (r *Registrar) ReplaceWatch(ctx context.Context, gvks []schema.GroupVersionKind) error {
r.mux.Lock()
defer r.mux.Unlock()
roster := make(vitalsByGVK)
@@ -251,16 +252,16 @@ func (r *Registrar) ReplaceWatch(gvks []schema.GroupVersionKind) error {
roster[gvk] = wv
}
r.managedKinds.ReplaceRegistrarRoster(r, roster)
- return r.mgr.replaceWatches(r)
+ return r.mgr.replaceWatches(ctx, r)
}
// RemoveWatch removes a watch for the given kind.
// Ignores the request if the kind was not previously watched.
-func (r *Registrar) RemoveWatch(gvk schema.GroupVersionKind) error {
+func (r *Registrar) RemoveWatch(ctx context.Context, gvk schema.GroupVersionKind) error {
r.mux.Lock()
defer r.mux.Unlock()
r.managedKinds.Remove(r.parentName, gvk)
- return r.mgr.removeWatch(r, gvk)
+ return r.mgr.removeWatch(ctx, r, gvk)
}
// IfWatching executes the passed function if the provided GVK is being watched
diff --git a/pkg/watch/stats_reporter.go b/pkg/watch/stats_reporter.go
index be4c25fe3b8..baa60da2526 100644
--- a/pkg/watch/stats_reporter.go
+++ b/pkg/watch/stats_reporter.go
@@ -3,7 +3,7 @@ package watch
import (
"context"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view"
"go.opencensus.io/tag"
diff --git a/pkg/webhook/common.go b/pkg/webhook/common.go
index 63f255b1519..0d7dc24b272 100644
--- a/pkg/webhook/common.go
+++ b/pkg/webhook/common.go
@@ -8,11 +8,11 @@ import (
"fmt"
"strings"
- "github.com/open-policy-agent/gatekeeper/apis"
- "github.com/open-policy-agent/gatekeeper/apis/config/v1alpha1"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/keys"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/apis"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/keys"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
admissionv1 "k8s.io/api/admission/v1"
authenticationv1 "k8s.io/api/authentication/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -21,7 +21,6 @@ import (
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
- "sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)
@@ -38,13 +37,6 @@ const (
var log = logf.Log.WithName("webhook")
-var (
- // VwhName is the metadata.name of the Gatekeeper ValidatingWebhookConfiguration.
- VwhName = "gatekeeper-validating-webhook-configuration"
- // MwhName is the metadata.name of the Gatekeeper MutatingWebhookConfiguration.
- MwhName = "gatekeeper-mutating-webhook-configuration"
-)
-
const (
serviceAccountName = "gatekeeper-admin"
mutationsGroup = "mutations.gatekeeper.sh"
@@ -58,12 +50,16 @@ var (
deserializer = codecs.UniversalDeserializer()
disableEnforcementActionValidation = flag.Bool("disable-enforcementaction-validation", false, "disable validation of the enforcementAction field of a constraint")
logDenies = flag.Bool("log-denies", false, "log detailed info on each deny")
- emitAdmissionEvents = flag.Bool("emit-admission-events", false, "(alpha) emit Kubernetes events in gatekeeper namespace for each admission violation")
- tlsMinVersion = flag.String("tls-min-version", "1.3", "minimum version of TLS supported")
+ emitAdmissionEvents = flag.Bool("emit-admission-events", false, "(alpha) emit Kubernetes events for each admission violation")
+ admissionEventsInvolvedNamespace = flag.Bool("admission-events-involved-namespace", false, "emit admission events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Admission events from cluster-scoped resources will still follow the default behavior")
+ logStatsAdmission = flag.Bool("log-stats-admission", false, "(alpha) log stats for admission webhook")
+ tlsMinVersion = flag.String("tls-min-version", "1.2", "minimum version of TLS supported")
serviceaccount = fmt.Sprintf("system:serviceaccount:%s:%s", util.GetNamespace(), serviceAccountName)
- clientCAName = flag.String("client-ca-name", "", "name of the certificate authority bundle to authenticate the Kubernetes API server requests against")
- certCNName = flag.String("client-cn-name", "kube-apiserver", "expected CN name on the client certificate attached by apiserver in requests to the webhook")
- // webhookName is deprecated, set this on the manifest YAML if needed".
+ VwhName = flag.String("validating-webhook-configuration-name", "gatekeeper-validating-webhook-configuration", "name of the ValidatingWebhookConfiguration")
+ MwhName = flag.String("mutating-webhook-configuration-name", "gatekeeper-mutating-webhook-configuration", "name of the MutatingWebhookConfiguration")
+ TLSMinVersion = flag.String("tls-min-version", "1.3", "minimum version of TLS supported")
+ ClientCAName = flag.String("client-ca-name", "", "name of the certificate authority bundle to authenticate the Kubernetes API server requests against")
+ CertCNName = flag.String("client-cn-name", "kube-apiserver", "expected CN name on the client certificate attached by apiserver in requests to the webhook")
)
func init() {
@@ -149,24 +145,11 @@ func (h *webhookHandler) skipExcludedNamespace(req *admissionv1.AdmissionRequest
return isNamespaceExcluded, err
}
-func congifureWebhookServer(server *webhook.Server) *webhook.Server {
- server.TLSMinVersion = *tlsMinVersion
- if *clientCAName != "" {
- server.ClientCAName = *clientCAName
- server.TLSOpts = []func(*tls.Config){
- func(cfg *tls.Config) {
- cfg.VerifyConnection = getCertNameVerifier()
- },
- }
- }
- return server
-}
-
-func getCertNameVerifier() func(cs tls.ConnectionState) error {
+func GetCertNameVerifier() func(cs tls.ConnectionState) error {
return func(cs tls.ConnectionState) error {
if len(cs.PeerCertificates) > 0 {
- if cs.PeerCertificates[0].Subject.CommonName != *certCNName {
- return fmt.Errorf("x509: subject with cn=%s do not identify as %s", cs.PeerCertificates[0].Subject.CommonName, *certCNName)
+ if cs.PeerCertificates[0].Subject.CommonName != *CertCNName {
+ return fmt.Errorf("x509: subject with cn=%s do not identify as %s", cs.PeerCertificates[0].Subject.CommonName, *CertCNName)
}
return nil
}
diff --git a/pkg/webhook/common_test.go b/pkg/webhook/common_test.go
index c80e21e93cf..1d7ebc5b2ca 100644
--- a/pkg/webhook/common_test.go
+++ b/pkg/webhook/common_test.go
@@ -33,7 +33,7 @@ func (w chanWriter) Write(p []byte) (n int, err error) {
func TestCongifureWebhookServer(t *testing.T) {
expectedServer := &webhook.Server{
- TLSMinVersion: "1.3",
+ TLSMinVersion: "1.2",
}
if *clientCAName != "" {
@@ -65,7 +65,7 @@ func TestCongifureWebhookServer(t *testing.T) {
}
func TestTLSConfig(t *testing.T) {
- ca, caPEM, caPrivKey, err := getCA(*certCNName)
+ ca, caPEM, caPrivKey, err := getCA(*CertCNName)
if err != nil {
t.Fatal(err)
}
@@ -73,7 +73,7 @@ func TestTLSConfig(t *testing.T) {
certpool := x509.NewCertPool()
certpool.AppendCertsFromPEM(caPEM.Bytes())
- serverTLSConf, err := serverCertSetup(*certCNName, ca, caPrivKey, certpool)
+ serverTLSConf, err := serverCertSetup(*CertCNName, ca, caPrivKey, certpool)
if err != nil {
t.Fatal(err)
}
@@ -87,7 +87,7 @@ func TestTLSConfig(t *testing.T) {
ts.StartTLS()
defer ts.Close()
- goodHTTPClient, err := getClient(*certCNName, ca, caPrivKey, certpool)
+ goodHTTPClient, err := getClient(*CertCNName, ca, caPrivKey, certpool)
if err != nil {
t.Fatal(err)
}
@@ -97,7 +97,7 @@ func TestTLSConfig(t *testing.T) {
t.Fatal(err)
}
- diffCa, diffCaPEM, diffCaPrivKey, err := getCA(*certCNName)
+ diffCa, diffCaPEM, diffCaPrivKey, err := getCA(*CertCNName)
if err != nil {
t.Fatal(err)
}
@@ -105,7 +105,7 @@ func TestTLSConfig(t *testing.T) {
diffCertpool := x509.NewCertPool()
diffCertpool.AppendCertsFromPEM(diffCaPEM.Bytes())
- diffHTTPClient, err := getClient(*certCNName, diffCa, diffCaPrivKey, diffCertpool)
+ diffHTTPClient, err := getClient(*CertCNName, diffCa, diffCaPrivKey, diffCertpool)
if err != nil {
t.Fatal(err)
}
@@ -160,8 +160,8 @@ func TestTLSConfig(t *testing.T) {
select {
case v := <-errc:
- if !strings.Contains(v, fmt.Sprintf("x509: subject with cn=test do not identify as %s", *certCNName)) {
- t.Errorf("expected an error log message containing '%s'; got %q", fmt.Sprintf("x509: subject with cn=test do not identify as %s", *certCNName), v)
+ if !strings.Contains(v, fmt.Sprintf("x509: subject with cn=test do not identify as %s", *CertCNName)) {
+ t.Errorf("expected an error log message containing '%s'; got %q", fmt.Sprintf("x509: subject with cn=test do not identify as %s", *CertCNName), v)
}
case <-time.After(5 * time.Second):
t.Errorf("timeout waiting for logged error")
@@ -269,7 +269,7 @@ func serverCertSetup(s string, ca *x509.Certificate, caPrivKey *rsa.PrivateKey,
serverTLSConf = &tls.Config{
Certificates: []tls.Certificate{serverCert},
- VerifyConnection: getCertNameVerifier(),
+ VerifyConnection: GetCertNameVerifier(),
ClientCAs: certPool,
ClientAuth: tls.RequireAndVerifyClientCert,
MinVersion: tls.VersionTLS13,
diff --git a/pkg/webhook/health_check.go b/pkg/webhook/health_check.go
index b0dd29f2c71..e0960f681dd 100644
--- a/pkg/webhook/health_check.go
+++ b/pkg/webhook/health_check.go
@@ -4,23 +4,27 @@ import (
"bytes"
"crypto/tls"
"fmt"
+ "io"
"net/http"
"path/filepath"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
-// disabling gosec linting here as the http client used in this checking is intended to skip CA verification
-//
-//nolint:gosec
-var tr = &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
-}
-var insecureClient = &http.Client{Transport: tr}
-
var tlsCheckerLog = logf.Log.WithName("webhook-tls-checker")
func NewTLSChecker(certDir string, port int) func(*http.Request) error {
+ //nolint:forcetypeassert
+ tr := http.DefaultTransport.(*http.Transport).Clone()
+ // disabling gosec linting here as the http client used in this checking is intended to skip CA verification
+ //
+ //nolint:gosec
+ tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
+ // disable keep alives to ensure that http connection aren't reused, otherwise the check may
+ // fail if the cert was rotated in between
+ tr.DisableKeepAlives = true
+ insecureClient := &http.Client{Transport: tr}
+
returnFunc := func(_ *http.Request) error {
resp, err := insecureClient.Get(fmt.Sprintf("https://127.0.0.1:%d", port))
if err != nil {
@@ -28,6 +32,10 @@ func NewTLSChecker(certDir string, port int) func(*http.Request) error {
tlsCheckerLog.Error(newErr, "error in connecting to webhook server with https")
return newErr
}
+ defer resp.Body.Close()
+ // explicitly discard the body to avoid any memory leak
+ _, _ = io.Copy(io.Discard, resp.Body)
+
if len(resp.TLS.PeerCertificates) == 0 {
newErr := fmt.Errorf("webhook does not serve TLS certificate")
tlsCheckerLog.Error(newErr, "error in connecting to webhook server with https")
diff --git a/pkg/webhook/mutation.go b/pkg/webhook/mutation.go
index f1ead452a6d..91a07fb6973 100644
--- a/pkg/webhook/mutation.go
+++ b/pkg/webhook/mutation.go
@@ -18,13 +18,14 @@ import (
"net/http"
"time"
+ "github.com/go-logr/logr"
"github.com/open-policy-agent/cert-controller/pkg/rotator"
- "github.com/open-policy-agent/gatekeeper/apis"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- mutationtypes "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/apis"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ mutationtypes "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -63,6 +64,7 @@ func AddMutatingWebhook(mgr manager.Manager, deps Dependencies) error {
eventBroadcaster := record.NewBroadcaster()
kubeClient := kubernetes.NewForConfigOrDie(mgr.GetConfig())
+ log := log.WithValues("hookType", "mutation")
eventBroadcaster.StartRecordingToSink(&clientcorev1.EventSinkImpl{Interface: kubeClient.CoreV1().Events("")})
recorder := eventBroadcaster.NewRecorder(
scheme.Scheme,
@@ -80,15 +82,11 @@ func AddMutatingWebhook(mgr manager.Manager, deps Dependencies) error {
},
mutationSystem: deps.MutationSystem,
deserializer: codecs.UniversalDeserializer(),
+ log: log,
},
}
- // TODO(https://github.com/open-policy-agent/gatekeeper/issues/661): remove log injection if the race condition in the cited bug is eliminated.
- // Otherwise we risk having unstable logger names for the webhook.
- if err := wh.InjectLogger(log); err != nil {
- return err
- }
- congifureWebhookServer(mgr.GetWebhookServer()).Register("/v1/mutate", wh)
+ mgr.GetWebhookServer().Register("/v1/mutate", wh)
return nil
}
@@ -99,12 +97,12 @@ type mutationHandler struct {
webhookHandler
mutationSystem *mutation.System
deserializer runtime.Decoder
+ log logr.Logger
}
// Handle the mutation request
// nolint: gocritic // Must accept admission.Request to satisfy interface.
func (h *mutationHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
- log := log.WithValues("hookType", "mutation")
timeStart := time.Now()
if isGkServiceAccount(req.AdmissionRequest.UserInfo) {
@@ -124,7 +122,7 @@ func (h *mutationHandler) Handle(ctx context.Context, req admission.Request) adm
defer func() {
if h.reporter != nil {
if err := h.reporter.ReportMutationRequest(ctx, requestResponse, time.Since(timeStart)); err != nil {
- log.Error(err, "failed to report request")
+ h.log.Error(err, "failed to report request")
}
}
}()
@@ -132,7 +130,7 @@ func (h *mutationHandler) Handle(ctx context.Context, req admission.Request) adm
// namespace is excluded from webhook using config
isExcludedNamespace, err := h.skipExcludedNamespace(&req.AdmissionRequest, process.Mutation)
if err != nil {
- log.Error(err, "error while excluding namespace")
+ h.log.Error(err, "error while excluding namespace")
}
if isExcludedNamespace {
@@ -164,13 +162,13 @@ func (h *mutationHandler) mutateRequest(ctx context.Context, req *admission.Requ
case req.AdmissionRequest.Namespace != "":
if err := h.client.Get(ctx, types.NamespacedName{Name: req.AdmissionRequest.Namespace}, ns); err != nil {
if !k8serrors.IsNotFound(err) {
- log.Error(err, "error retrieving namespace", "name", req.AdmissionRequest.Namespace)
+ h.log.Error(err, "error retrieving namespace", "name", req.AdmissionRequest.Namespace)
return admission.Errored(int32(http.StatusInternalServerError), err)
}
// bypass cached client and ask api-server directly
err = h.reader.Get(ctx, types.NamespacedName{Name: req.AdmissionRequest.Namespace}, ns)
if err != nil {
- log.Error(err, "error retrieving namespace from API server", "name", req.AdmissionRequest.Namespace)
+ h.log.Error(err, "error retrieving namespace from API server", "name", req.AdmissionRequest.Namespace)
return admission.Errored(int32(http.StatusInternalServerError), err)
}
}
@@ -180,7 +178,7 @@ func (h *mutationHandler) mutateRequest(ctx context.Context, req *admission.Requ
obj := unstructured.Unstructured{}
err := obj.UnmarshalJSON(req.Object.Raw)
if err != nil {
- log.Error(err, "failed to unmarshal", "object", string(req.Object.Raw))
+ h.log.Error(err, "failed to unmarshal", "object", string(req.Object.Raw))
return admission.Errored(int32(http.StatusInternalServerError), err)
}
@@ -198,7 +196,7 @@ func (h *mutationHandler) mutateRequest(ctx context.Context, req *admission.Requ
}
mutated, err := h.mutationSystem.Mutate(mutable)
if err != nil {
- log.Error(err, "failed to mutate object", "object", string(req.Object.Raw))
+ h.log.Error(err, "failed to mutate object", "object", string(req.Object.Raw))
return admission.Errored(int32(http.StatusInternalServerError), err)
}
if !mutated {
@@ -209,7 +207,7 @@ func (h *mutationHandler) mutateRequest(ctx context.Context, req *admission.Requ
newJSON, err := mutable.Object.MarshalJSON()
if err != nil {
- log.Error(err, "failed to marshal mutated object", "object", obj)
+ h.log.Error(err, "failed to marshal mutated object", "object", obj)
return admission.Errored(int32(http.StatusInternalServerError), err)
}
resp := admission.PatchResponseFromRaw(req.Object.Raw, newJSON)
@@ -219,7 +217,7 @@ func (h *mutationHandler) mutateRequest(ctx context.Context, req *admission.Requ
func AppendMutationWebhookIfEnabled(webhooks []rotator.WebhookInfo) []rotator.WebhookInfo {
if operations.IsAssigned(operations.MutationWebhook) {
return append(webhooks, rotator.WebhookInfo{
- Name: MwhName,
+ Name: *MwhName,
Type: rotator.Mutating,
})
}
diff --git a/pkg/webhook/mutation_test.go b/pkg/webhook/mutation_test.go
index 86a0ef9ad9d..de25e294478 100644
--- a/pkg/webhook/mutation_test.go
+++ b/pkg/webhook/mutation_test.go
@@ -5,15 +5,15 @@ import (
"reflect"
"testing"
- configv1alpha1 "github.com/open-policy-agent/gatekeeper/apis/config/v1alpha1"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/assign"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/assignmeta"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
+ configv1alpha1 "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/match"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assign"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assignmeta"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
admissionv1 "k8s.io/api/admission/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -64,6 +64,7 @@ func TestWebhookAssign(t *testing.T) {
},
mutationSystem: sys,
deserializer: codecs.UniversalDeserializer(),
+ log: log,
}
raw := []byte(`{"apiVersion": "v1", "kind": "Pod", "metadata": {"name": "acbd","namespace": "ns1"}}`)
@@ -130,6 +131,7 @@ func TestWebhookAssignMetadata(t *testing.T) {
},
mutationSystem: sys,
deserializer: codecs.UniversalDeserializer(),
+ log: log,
}
raw := []byte(`{"apiVersion": "v1", "kind": "Pod", "metadata": {"name": "acbd","namespace": "ns1"}}`)
diff --git a/pkg/webhook/mutator_validation_test.go b/pkg/webhook/mutator_validation_test.go
index 7a4a4cf3724..ac222cf8402 100644
--- a/pkg/webhook/mutator_validation_test.go
+++ b/pkg/webhook/mutator_validation_test.go
@@ -4,11 +4,11 @@ import (
"context"
"testing"
- "github.com/ghodss/yaml"
admissionv1 "k8s.io/api/admission/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
atypes "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+ "sigs.k8s.io/yaml"
)
func TestAssignMetaValidation(t *testing.T) {
@@ -97,7 +97,7 @@ spec:
}
for _, tt := range tc {
t.Run(tt.Name, func(t *testing.T) {
- handler := validationHandler{webhookHandler: webhookHandler{}}
+ handler := validationHandler{webhookHandler: webhookHandler{}, log: log}
b, err := yaml.YAMLToJSON([]byte(tt.AssignMeta))
if err != nil {
t.Fatalf("Error parsing yaml: %s", err)
@@ -348,7 +348,7 @@ spec:
}
for _, tt := range tc {
t.Run(tt.Name, func(t *testing.T) {
- handler := validationHandler{webhookHandler: webhookHandler{}}
+ handler := validationHandler{webhookHandler: webhookHandler{}, log: log}
b, err := yaml.YAMLToJSON([]byte(tt.Assign))
if err != nil {
t.Fatalf("Error parsing yaml: %s", err)
diff --git a/pkg/webhook/namespacelabel.go b/pkg/webhook/namespacelabel.go
index 20d5d2fc13b..e63745b1ab8 100644
--- a/pkg/webhook/namespacelabel.go
+++ b/pkg/webhook/namespacelabel.go
@@ -8,7 +8,7 @@ import (
"net/http"
"strings"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
"github.com/pkg/errors"
admissionv1 "k8s.io/api/admission/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -19,12 +19,14 @@ import (
var (
exemptNamespace = util.NewFlagSet()
exemptNamespacePrefix = util.NewFlagSet()
+ exemptNamespaceSuffix = util.NewFlagSet()
)
func init() {
AddToManagerFuncs = append(AddToManagerFuncs, AddLabelWebhook)
flag.Var(exemptNamespace, "exempt-namespace", "The specified namespace is allowed to set the admission.gatekeeper.sh/ignore label. To exempt multiple namespaces, this flag can be declared more than once.")
flag.Var(exemptNamespacePrefix, "exempt-namespace-prefix", "A namespace with the specified prefix is allowed to set the admission.gatekeeper.sh/ignore label. To exempt multiple prefixes, this flag can be declared more than once.")
+ flag.Var(exemptNamespaceSuffix, "exempt-namespace-suffix", "A namespace with the specified suffix is allowed to set the admission.gatekeeper.sh/ignore label. To exempt multiple suffixes, this flag can be declared more than once.")
}
const ignoreLabel = "admission.gatekeeper.sh/ignore"
@@ -34,12 +36,7 @@ const ignoreLabel = "admission.gatekeeper.sh/ignore"
// AddLabelWebhook registers the label webhook server with the manager.
func AddLabelWebhook(mgr manager.Manager, _ Dependencies) error {
wh := &admission.Webhook{Handler: &namespaceLabelHandler{}}
- // TODO(https://github.com/open-policy-agent/gatekeeper/issues/661): remove log injection if the race condition in the cited bug is eliminated.
- // Otherwise we risk having unstable logger names for the webhook.
- if err := wh.InjectLogger(log); err != nil {
- return err
- }
- congifureWebhookServer(mgr.GetWebhookServer()).Register("/v1/admitlabel", wh)
+ mgr.GetWebhookServer().Register("/v1/admitlabel", wh)
return nil
}
@@ -47,7 +44,7 @@ var _ admission.Handler = &namespaceLabelHandler{}
type namespaceLabelHandler struct{}
-// nolint: gocritic // Must accept admission.Request as a struct to satisfy Handler interface.
+//nolint:gocritic // Must accept admission.Request as a struct to satisfy Handler interface.
func (h *namespaceLabelHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
if req.Operation == admissionv1.Delete {
return admission.Allowed("Delete is always allowed")
@@ -61,7 +58,7 @@ func (h *namespaceLabelHandler) Handle(ctx context.Context, req admission.Reques
r.Result.Code = http.StatusInternalServerError
return r
}
- if exemptNamespace[obj.GetName()] || matchesPrefix(obj.GetName()) {
+ if exemptNamespace[obj.GetName()] || matchesPrefix(obj.GetName()) || matchesSuffix(obj.GetName()) {
return admission.Allowed(fmt.Sprintf("Namespace %s is allowed to set %s", obj.GetName(), ignoreLabel))
}
for label := range obj.GetLabels() {
@@ -80,3 +77,12 @@ func matchesPrefix(s string) bool {
}
return false
}
+
+func matchesSuffix(s string) bool {
+ for p := range exemptNamespaceSuffix {
+ if strings.HasSuffix(s, p) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/pkg/webhook/namespacelabel_test.go b/pkg/webhook/namespacelabel_test.go
index 967804b4d83..75381516c2e 100644
--- a/pkg/webhook/namespacelabel_test.go
+++ b/pkg/webhook/namespacelabel_test.go
@@ -139,6 +139,10 @@ func TestAdmission(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
+ t.Cleanup(func() {
+ exemptNamespace = nil
+ })
+
exemptNamespace = map[string]bool{"random-allowed-ns": true}
gvk := tt.obj.GetObjectKind()
gvk.SetGroupVersionKind(schema.GroupVersionKind{Group: tt.kind.Group, Version: tt.kind.Version, Kind: tt.kind.Kind})
@@ -226,6 +230,10 @@ func TestAdmissionPrefix(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
+ t.Cleanup(func() {
+ exemptNamespacePrefix = nil
+ })
+
exemptNamespacePrefix = map[string]bool{}
for _, p := range tt.prefixes {
exemptNamespacePrefix[p] = true
@@ -252,6 +260,100 @@ func TestAdmissionPrefix(t *testing.T) {
}
}
+func TestAdmissionSuffix(t *testing.T) {
+ tests := []struct {
+ name string
+ suffixes []string
+ kind metav1.GroupVersionKind
+ obj client.Object
+ op admissionv1.Operation
+ expectAllowed bool
+ }{
+ {
+ name: "Exempt Namespace create allowed",
+ suffixes: []string{"-random"},
+ kind: gvk("", "v1", "Namespace"),
+ obj: &corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "allowed-ns-random",
+ Labels: map[string]string{ignoreLabel: "true"},
+ },
+ },
+ op: admissionv1.Create,
+ expectAllowed: true,
+ },
+ {
+ name: "Exempt Namespace update allowed",
+ suffixes: []string{"-random"},
+ kind: gvk("", "v1", "Namespace"),
+ obj: &corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "allowed-ns-random",
+ Labels: map[string]string{ignoreLabel: "true"},
+ },
+ },
+ op: admissionv1.Update,
+ expectAllowed: true,
+ },
+ {
+ name: "Exempt Namespace delete allowed",
+ suffixes: []string{"-random"},
+ kind: gvk("", "v1", "Namespace"),
+ obj: &corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "allowed-ns-random",
+ Labels: map[string]string{ignoreLabel: "true"},
+ },
+ },
+ op: admissionv1.Delete,
+ expectAllowed: true,
+ },
+ {
+ name: "Bad Namespace create rejected",
+ suffixes: []string{"-random"},
+ kind: gvk("", "v1", "Namespace"),
+ obj: &corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "random-namespace-wrongsuffix",
+ Labels: map[string]string{ignoreLabel: "true"},
+ },
+ },
+ op: admissionv1.Create,
+ expectAllowed: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ t.Cleanup(func() {
+ exemptNamespaceSuffix = nil
+ })
+
+ exemptNamespaceSuffix = map[string]bool{}
+ for _, p := range tt.suffixes {
+ exemptNamespaceSuffix[p] = true
+ }
+ gvk := tt.obj.GetObjectKind()
+ gvk.SetGroupVersionKind(schema.GroupVersionKind{Group: tt.kind.Group, Version: tt.kind.Version, Kind: tt.kind.Kind})
+ bytes, err := json.Marshal(tt.obj)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req := admission.Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Kind: tt.kind,
+ Object: runtime.RawExtension{Raw: bytes},
+ Operation: tt.op,
+ },
+ }
+ handler := &namespaceLabelHandler{}
+ resp := handler.Handle(context.Background(), req)
+ if resp.Allowed != tt.expectAllowed {
+ t.Errorf("resp.Allowed = %v, expected %v. Reason: %s", resp.Allowed, tt.expectAllowed, resp.Result.Reason)
+ }
+ })
+ }
+}
+
func TestBadSerialization(t *testing.T) {
req := admission.Request{
AdmissionRequest: admissionv1.AdmissionRequest{
diff --git a/pkg/webhook/policy.go b/pkg/webhook/policy.go
index 95663e692e1..be6830957a2 100644
--- a/pkg/webhook/policy.go
+++ b/pkg/webhook/policy.go
@@ -25,28 +25,31 @@ import (
"strings"
"time"
+ "github.com/go-logr/logr"
"github.com/open-policy-agent/cert-controller/pkg/rotator"
externaldataUnversioned "github.com/open-policy-agent/frameworks/constraint/pkg/apis/externaldata/unversioned"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
"github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers"
- "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
"github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
rtypes "github.com/open-policy-agent/frameworks/constraint/pkg/types"
- "github.com/open-policy-agent/gatekeeper/apis"
- mutationsunversioned "github.com/open-policy-agent/gatekeeper/apis/mutations/unversioned"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/keys"
- "github.com/open-policy-agent/gatekeeper/pkg/logging"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/assign"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/assignmeta"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation/mutators/modifyset"
- mutationtypes "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
- "github.com/open-policy-agent/gatekeeper/pkg/operations"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
+ "github.com/open-policy-agent/gatekeeper/v3/apis"
+ expansionunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/expansion/unversioned"
+ mutationsunversioned "github.com/open-policy-agent/gatekeeper/v3/apis/mutations/unversioned"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/keys"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/logging"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assign"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assignimage"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/assignmeta"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/mutators/modifyset"
+ mutationtypes "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/util"
admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -66,7 +69,10 @@ import (
// https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#response
const httpStatusWarning = 299
-var maxServingThreads = flag.Int("max-serving-threads", -1, "cap the number of threads handling non-trivial requests, -1 caps the number of threads to GOMAXPROCS. Defaults to -1.")
+var (
+ ValidateTemplateRego = flag.Bool("validate-template-rego", true, "validate Rego code for constraint templates. Defaults to true. This flag will be removed in Gatekeeper v3.16 and cannot be used if `experimental-enable-k8s-native-validation` flag is set. Use Gator to validate in shift left manner to avoid impact with this behavior change.). Use Gator to validate in shift left manner to avoid impact with this behavior change.")
+ maxServingThreads = flag.Int("max-serving-threads", -1, "cap the number of threads handling non-trivial requests, -1 caps the number of threads to GOMAXPROCS. Defaults to -1.")
+)
func init() {
AddToManagerFuncs = append(AddToManagerFuncs, AddPolicyWebhook)
@@ -90,6 +96,7 @@ func AddPolicyWebhook(mgr manager.Manager, deps Dependencies) error {
if err != nil {
return err
}
+ log := log.WithValues("hookType", "validation")
eventBroadcaster := record.NewBroadcaster()
kubeClient := kubernetes.NewForConfigOrDie(mgr.GetConfig())
eventBroadcaster.StartRecordingToSink(&clientcorev1.EventSinkImpl{Interface: kubeClient.CoreV1().Events("")})
@@ -108,6 +115,7 @@ func AddPolicyWebhook(mgr manager.Manager, deps Dependencies) error {
eventRecorder: recorder,
gkNamespace: util.GetNamespace(),
},
+ log: log,
}
threadCount := *maxServingThreads
if threadCount < 1 {
@@ -115,12 +123,7 @@ func AddPolicyWebhook(mgr manager.Manager, deps Dependencies) error {
}
handler.semaphore = make(chan struct{}, threadCount)
wh := &admission.Webhook{Handler: handler}
- // TODO(https://github.com/open-policy-agent/gatekeeper/issues/661): remove log injection if the race condition in the cited bug is eliminated.
- // Otherwise we risk having unstable logger names for the webhook.
- if err := wh.InjectLogger(log); err != nil {
- return err
- }
- congifureWebhookServer(mgr.GetWebhookServer()).Register("/v1/admit", wh)
+ mgr.GetWebhookServer().Register("/v1/admit", wh)
return nil
}
@@ -132,13 +135,12 @@ type validationHandler struct {
mutationSystem *mutation.System
expansionSystem *expansion.System
semaphore chan struct{}
+ log logr.Logger
}
// Handle the validation request
// nolint: gocritic // Must accept admission.Request as a struct to satisfy Handler interface.
func (h *validationHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
- log := log.WithValues("hookType", "validation")
-
timeStart := time.Now()
if isGkServiceAccount(req.AdmissionRequest.UserInfo) {
@@ -169,7 +171,7 @@ func (h *validationHandler) Handle(ctx context.Context, req admission.Request) a
isDryRun = "true"
}
if err := h.reporter.ReportValidationRequest(ctx, requestResponse, isDryRun, time.Since(timeStart)); err != nil {
- log.Error(err, "failed to report request")
+ h.log.Error(err, "failed to report request")
}
}
}()
@@ -177,7 +179,7 @@ func (h *validationHandler) Handle(ctx context.Context, req admission.Request) a
// namespace is excluded from webhook using config
isExcludedNamespace, err := h.skipExcludedNamespace(&req.AdmissionRequest, process.Webhook)
if err != nil {
- log.Error(err, "error while excluding namespace")
+ h.log.Error(err, "error while excluding namespace")
}
if isExcludedNamespace {
@@ -187,11 +189,27 @@ func (h *validationHandler) Handle(ctx context.Context, req admission.Request) a
resp, err := h.reviewRequest(ctx, &req)
if err != nil {
- log.Error(err, "error executing query")
+ h.log.Error(err, "error executing query")
requestResponse = errorResponse
return admission.Errored(http.StatusInternalServerError, err)
}
+ if *logStatsAdmission {
+ logging.LogStatsEntries(
+ h.opa,
+ h.log.WithValues(
+ logging.Process, "admission",
+ logging.EventType, "review_response_stats",
+ logging.ResourceGroup, req.AdmissionRequest.Kind.Group,
+ logging.ResourceAPIVersion, req.AdmissionRequest.Kind.Version,
+ logging.ResourceKind, req.AdmissionRequest.Kind.Kind,
+ logging.ResourceNamespace, req.AdmissionRequest.Namespace,
+ logging.RequestUsername, req.AdmissionRequest.UserInfo.Username,
+ ),
+ resp.StatsEntries, "admission review request stats",
+ )
+ }
+
res := resp.Results()
denyMsgs, warnMsgs := h.getValidationMessages(res, &req)
@@ -229,14 +247,17 @@ func (h *validationHandler) Handle(ctx context.Context, req admission.Request) a
func (h *validationHandler) getValidationMessages(res []*rtypes.Result, req *admission.Request) ([]string, []string) {
var denyMsgs, warnMsgs []string
var resourceName string
+ obj := &unstructured.Unstructured{}
+
if len(res) > 0 && (*logDenies || *emitAdmissionEvents) {
resourceName = req.AdmissionRequest.Name
- if len(resourceName) == 0 && req.AdmissionRequest.Object.Raw != nil {
- // On a CREATE operation, the client may omit name and
- // rely on the server to generate the name.
- obj := &unstructured.Unstructured{}
+ if req.AdmissionRequest.Object.Raw != nil {
if _, _, err := deserializer.Decode(req.AdmissionRequest.Object.Raw, nil, obj); err == nil {
- resourceName = obj.GetName()
+ // On a CREATE operation, the client may omit name and
+ // rely on the server to generate the name.
+ if len(resourceName) == 0 {
+ resourceName = obj.GetName()
+ }
}
}
}
@@ -245,8 +266,9 @@ func (h *validationHandler) getValidationMessages(res []*rtypes.Result, req *adm
continue
}
if *logDenies {
- log.WithValues(
+ h.log.WithValues(
logging.Process, "admission",
+ logging.Details, r.Metadata["details"],
logging.EventType, "violation",
logging.ConstraintName, r.Constraint.GetName(),
logging.ConstraintGroup, r.Constraint.GroupVersionKind().Group,
@@ -259,7 +281,8 @@ func (h *validationHandler) getValidationMessages(res []*rtypes.Result, req *adm
logging.ResourceNamespace, req.AdmissionRequest.Namespace,
logging.ResourceName, resourceName,
logging.RequestUsername, req.AdmissionRequest.UserInfo.Username,
- ).Info(fmt.Sprintf("denied admission: %s", r.Msg))
+ ).Info(
+ fmt.Sprintf("denied admission: %s", r.Msg))
}
if *emitAdmissionEvents {
annotations := map[string]string{
@@ -289,24 +312,14 @@ func (h *validationHandler) getValidationMessages(res []*rtypes.Result, req *adm
eventMsg = "Admission webhook \"validation.gatekeeper.sh\" denied request"
reason = "FailedAdmission"
}
- ref := getViolationRef(
- h.gkNamespace,
- req.AdmissionRequest.Kind.Kind,
- resourceName,
- req.AdmissionRequest.Namespace,
- r.Constraint.GetKind(),
- r.Constraint.GetName(),
- r.Constraint.GetNamespace())
- h.eventRecorder.AnnotatedEventf(
- ref,
- annotations,
- corev1.EventTypeWarning,
- reason,
- "%s, Resource Namespace: %s, Constraint: %s, Message: %s",
- eventMsg,
- req.AdmissionRequest.Namespace,
- r.Constraint.GetName(),
- r.Msg)
+
+ ref := getViolationRef(h.gkNamespace, req.AdmissionRequest.Kind.Kind, resourceName, obj.GetNamespace(), obj.GetResourceVersion(), obj.GetUID(), r.Constraint.GetKind(), r.Constraint.GetName(), r.Constraint.GetNamespace(), *admissionEventsInvolvedNamespace)
+
+ if *admissionEventsInvolvedNamespace {
+ h.eventRecorder.AnnotatedEventf(ref, annotations, corev1.EventTypeWarning, reason, "%s, Constraint: %s, Message: %s", eventMsg, r.Constraint.GetName(), r.Msg)
+ } else {
+ h.eventRecorder.AnnotatedEventf(ref, annotations, corev1.EventTypeWarning, reason, "%s, Resource Namespace: %s, Constraint: %s, Message: %s", eventMsg, req.AdmissionRequest.Namespace, r.Constraint.GetName(), r.Msg)
+ }
}
if r.EnforcementAction == string(util.Deny) {
@@ -328,6 +341,8 @@ func (h *validationHandler) validateGatekeeperResources(ctx context.Context, req
switch {
case gvk.Group == "templates.gatekeeper.sh" && gvk.Kind == "ConstraintTemplate":
return h.validateTemplate(ctx, req)
+ case gvk.Group == "expansion.gatekeeper.sh" && gvk.Kind == "ExpansionTemplate":
+ return h.validateExpansionTemplate(req)
case gvk.Group == "constraints.gatekeeper.sh":
return h.validateConstraint(req)
case gvk.Group == "config.gatekeeper.sh" && gvk.Kind == "Config":
@@ -340,6 +355,8 @@ func (h *validationHandler) validateGatekeeperResources(ctx context.Context, req
return h.validateAssign(req)
case req.AdmissionRequest.Kind.Group == mutationsGroup && req.AdmissionRequest.Kind.Kind == "ModifySet":
return h.validateModifySet(req)
+ case req.AdmissionRequest.Kind.Group == mutationsGroup && req.AdmissionRequest.Kind.Kind == "AssignImage":
+ return h.validateAssignImage(req)
case req.AdmissionRequest.Kind.Group == externalDataGroup && req.AdmissionRequest.Kind.Kind == "Provider":
return h.validateProvider(req)
}
@@ -369,16 +386,19 @@ func (h *validationHandler) validateTemplate(ctx context.Context, req *admission
return true, err
}
- // Create a temporary Driver and attempt to add the Template to it. This
- // ensures the Rego code both parses and compiles.
- d, err := local.New()
- if err != nil {
- return false, fmt.Errorf("unable to create Driver: %v", err)
- }
+ // TODO: This is a temporary check for rego to give enough time to users to migrate to gator for validation. To be removed before 3.16.
+ if *ValidateTemplateRego {
+ // Create a temporary Driver and attempt to add the Template to it. This
+ // ensures the Rego code both parses and compiles.
+ d, err := rego.New()
+ if err != nil {
+ return false, fmt.Errorf("unable to create Driver: %w", err)
+ }
- err = d.AddTemplate(ctx, unversioned)
- if err != nil {
- return true, err
+ err = d.AddTemplate(ctx, unversioned)
+ if err != nil {
+ return true, err
+ }
}
return false, nil
@@ -411,6 +431,23 @@ func (h *validationHandler) validateConstraint(req *admission.Request) (bool, er
return false, nil
}
+func (h *validationHandler) validateExpansionTemplate(req *admission.Request) (bool, error) {
+ obj, _, err := deserializer.Decode(req.AdmissionRequest.Object.Raw, nil, nil)
+ if err != nil {
+ return false, err
+ }
+ unversioned := &expansionunversioned.ExpansionTemplate{}
+ if err := runtimeScheme.Convert(obj, unversioned, nil); err != nil {
+ return false, err
+ }
+ err = expansion.ValidateTemplate(unversioned)
+ if err != nil {
+ return true, err
+ }
+
+ return false, nil
+}
+
func (h *validationHandler) validateConfigResource(req *admission.Request) error {
if req.Name != keys.Config.Name {
return fmt.Errorf("config resource must have name 'config'")
@@ -452,6 +489,23 @@ func (h *validationHandler) validateAssign(req *admission.Request) (bool, error)
return false, nil
}
+func (h *validationHandler) validateAssignImage(req *admission.Request) (bool, error) {
+ obj, _, err := deserializer.Decode(req.AdmissionRequest.Object.Raw, nil, nil)
+ if err != nil {
+ return false, err
+ }
+ unversioned := &mutationsunversioned.AssignImage{}
+ if err := runtimeScheme.Convert(obj, unversioned, nil); err != nil {
+ return false, err
+ }
+ err = assignimage.IsValidAssignImage(unversioned)
+ if err != nil {
+ return true, err
+ }
+
+ return false, nil
+}
+
func (h *validationHandler) validateModifySet(req *admission.Request) (bool, error) {
obj, _, err := deserializer.Decode(req.AdmissionRequest.Object.Raw, nil, nil)
if err != nil {
@@ -504,13 +558,13 @@ func (h *validationHandler) reviewRequest(ctx context.Context, req *admission.Re
review, err := h.createReviewForRequest(ctx, req)
if err != nil {
- return nil, fmt.Errorf("failed to create augmentedReview: %s", err)
+ return nil, fmt.Errorf("failed to create augmentedReview: %w", err)
}
// Convert the request's generator resource to unstructured for expansion
obj := &unstructured.Unstructured{}
if _, _, err := deserializer.Decode(req.Object.Raw, nil, obj); err != nil {
- return nil, fmt.Errorf("error decoding generator resource %s: %v", req.Name, err)
+ return nil, fmt.Errorf("error decoding generator resource %s: %w", req.Name, err)
}
obj.SetNamespace(req.Namespace)
obj.SetGroupVersionKind(
@@ -529,38 +583,39 @@ func (h *validationHandler) reviewRequest(ctx context.Context, req *admission.Re
}
resultants, err := h.expansionSystem.Expand(base)
if err != nil {
- return nil, fmt.Errorf("unable to expand object: %s", err)
+ return nil, fmt.Errorf("unable to expand object: %w", err)
}
trace, dump := h.tracingLevel(ctx, req)
resp, err := h.review(ctx, review, trace, dump)
if err != nil {
- return nil, fmt.Errorf("error reviewing resource %s: %s", req.Name, err)
+ return nil, fmt.Errorf("error reviewing resource %s: %w", req.Name, err)
}
for _, res := range resultants {
resultantResp, err := h.review(ctx, createReviewForResultant(res.Obj, review.Namespace), trace, dump)
if err != nil {
- return nil, fmt.Errorf("error reviewing resultant resource: %s", err)
+ return nil, fmt.Errorf("error reviewing resultant resource: %w", err)
}
expansion.OverrideEnforcementAction(res.EnforcementAction, resultantResp)
expansion.AggregateResponses(res.TemplateName, resp, resultantResp)
+ expansion.AggregateStats(res.TemplateName, resp, resultantResp)
}
return resp, nil
}
func (h *validationHandler) review(ctx context.Context, review interface{}, trace bool, dump bool) (*rtypes.Responses, error) {
- resp, err := h.opa.Review(ctx, review, drivers.Tracing(trace))
+ resp, err := h.opa.Review(ctx, review, drivers.Tracing(trace), drivers.Stats(*logStatsAdmission))
if resp != nil && trace {
- log.Info(resp.TraceDump())
+ h.log.Info(resp.TraceDump())
}
if dump {
dump, err := h.opa.Dump(ctx)
if err != nil {
- log.Error(err, "dump error")
+ h.log.Error(err, "dump error")
} else {
- log.Info(dump)
+ h.log.Info(dump)
}
}
@@ -604,19 +659,29 @@ func createReviewForResultant(obj *unstructured.Unstructured, ns *corev1.Namespa
}
}
-func getViolationRef(gkNamespace, rkind, rname, rnamespace, ckind, cname, cnamespace string) *corev1.ObjectReference {
- return &corev1.ObjectReference{
+func getViolationRef(gkNamespace, rkind, rname, rnamespace, rrv string, ruid types.UID, ckind, cname, cnamespace string, emitInvolvedNamespace bool) *corev1.ObjectReference {
+ enamespace := gkNamespace
+ if emitInvolvedNamespace && len(rnamespace) > 0 {
+ enamespace = rnamespace
+ }
+ ref := &corev1.ObjectReference{
Kind: rkind,
Name: rname,
- UID: types.UID(rkind + "/" + rnamespace + "/" + rname + "/" + ckind + "/" + cnamespace + "/" + cname),
- Namespace: gkNamespace,
+ Namespace: enamespace,
+ }
+ if emitInvolvedNamespace && len(ruid) > 0 && len(rrv) > 0 {
+ ref.UID = ruid
+ ref.ResourceVersion = rrv
+ } else if !emitInvolvedNamespace {
+ ref.UID = types.UID(rkind + "/" + rnamespace + "/" + rname + "/" + ckind + "/" + cnamespace + "/" + cname)
}
+ return ref
}
func AppendValidationWebhookIfEnabled(webhooks []rotator.WebhookInfo) []rotator.WebhookInfo {
if operations.IsAssigned(operations.Webhook) {
return append(webhooks, rotator.WebhookInfo{
- Name: VwhName,
+ Name: *VwhName,
Type: rotator.Validating,
})
}
diff --git a/pkg/webhook/policy_benchmark_test.go b/pkg/webhook/policy_benchmark_test.go
index d96ac3a4cdd..4100e8f1f1a 100644
--- a/pkg/webhook/policy_benchmark_test.go
+++ b/pkg/webhook/policy_benchmark_test.go
@@ -24,16 +24,15 @@ import (
"path/filepath"
"strconv"
"testing"
- "time"
templv1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
- "github.com/open-policy-agent/gatekeeper/apis/config/v1alpha1"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- testclient "github.com/open-policy-agent/gatekeeper/test/clients"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ testclient "github.com/open-policy-agent/gatekeeper/v3/test/clients"
"github.com/pkg/errors"
admissionv1 "k8s.io/api/admission/v1"
authenticationv1 "k8s.io/api/authentication/v1"
@@ -42,6 +41,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/uuid"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -77,7 +77,19 @@ func getFiles(dir string) ([]string, error) {
return filePaths, nil
}
-func (f *fakeNsGetter) Get(_ context.Context, key client.ObjectKey, obj client.Object) error {
+func (f *fakeNsGetter) IsObjectNamespaced(obj runtime.Object) (bool, error) {
+ return false, nil
+}
+
+func (f *fakeNsGetter) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
+ return schema.GroupVersionKind{}, nil
+}
+
+func (f *fakeNsGetter) SubResource(_ string) client.SubResourceClient {
+ return nil
+}
+
+func (f *fakeNsGetter) Get(_ context.Context, key client.ObjectKey, obj client.Object, _ ...client.GetOption) error {
if ns, ok := obj.(*corev1.Namespace); ok {
ns.ObjectMeta = metav1.ObjectMeta{
Name: key.Name,
@@ -305,11 +317,9 @@ func BenchmarkValidationHandler(b *testing.B) {
client: c,
injectedConfig: cfg,
},
+ log: log,
}
- // seed random generator
- rand.Seed(time.Now().UnixNano())
-
// create T templates
err = addTemplates(ctx, opaClient, ctList)
if err != nil {
diff --git a/pkg/webhook/policy_test.go b/pkg/webhook/policy_test.go
index 5798554d3d0..d3c87f8ede7 100644
--- a/pkg/webhook/policy_test.go
+++ b/pkg/webhook/policy_test.go
@@ -2,23 +2,21 @@ package webhook
import (
"context"
- "encoding/json"
"testing"
- "github.com/ghodss/yaml"
"github.com/open-policy-agent/frameworks/constraint/pkg/apis/constraints"
templatesv1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
+ "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
rtypes "github.com/open-policy-agent/frameworks/constraint/pkg/types"
- "github.com/open-policy-agent/gatekeeper/apis/config/v1alpha1"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
- "github.com/open-policy-agent/gatekeeper/pkg/target"
- "github.com/open-policy-agent/gatekeeper/pkg/util"
- testclients "github.com/open-policy-agent/gatekeeper/test/clients"
+ "github.com/open-policy-agent/gatekeeper/v3/apis/config/v1alpha1"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/target"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
+ testclients "github.com/open-policy-agent/gatekeeper/v3/test/clients"
admissionv1 "k8s.io/api/admission/v1"
authenticationv1 "k8s.io/api/authentication/v1"
corev1 "k8s.io/api/core/v1"
@@ -29,7 +27,7 @@ import (
k8schema "k8s.io/apimachinery/pkg/runtime/schema"
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
- atypes "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+ "sigs.k8s.io/yaml"
)
const (
@@ -166,12 +164,17 @@ func validRegoTemplate() *templates.ConstraintTemplate {
},
Targets: []templates.Target{{
Target: target.Name,
- Rego: `
+ Code: []templates.Code{{
+ Engine: "Rego",
+ Source: &templates.Anything{
+ Value: map[string]interface{}{"rego": `
package goodrego
- violation[{"msg": msg}] {
- msg := "Maybe this will work?"
- }`,
+violation[{"msg": msg}] {
+ msg := "Maybe this will work?"
+}`},
+ },
+ }},
}},
},
}
@@ -190,20 +193,9 @@ func validRegoTemplateConstraint() *unstructured.Unstructured {
return u
}
-func invalidRegoTemplate() *templates.ConstraintTemplate {
- template := validRegoTemplate()
-
- template.Spec.Targets[0].Rego = `package badrego
-
- violation[{"msg": msg}] {
- msg := "I'm sure this will work"`
-
- return template
-}
-
func makeOpaClient() (*constraintclient.Client, error) {
t := &target.K8sValidationTarget{}
- driver, err := local.New(local.Tracing(false))
+ driver, err := rego.New(rego.Tracing(false))
if err != nil {
return nil, err
}
@@ -215,67 +207,23 @@ func makeOpaClient() (*constraintclient.Client, error) {
return c, nil
}
-func TestTemplateValidation(t *testing.T) {
- tc := []struct {
- Name string
- Template *templates.ConstraintTemplate
- ErrorExpected bool
- }{
- {
- Name: "Valid Template",
- Template: validRegoTemplate(),
- ErrorExpected: false,
- },
- {
- Name: "Invalid Template",
- Template: invalidRegoTemplate(),
- ErrorExpected: true,
- },
- }
- for _, tt := range tc {
- t.Run(tt.Name, func(t *testing.T) {
- opa, err := makeOpaClient()
- if err != nil {
- t.Fatalf("Could not initialize OPA: %s", err)
- }
- handler := validationHandler{opa: opa, webhookHandler: webhookHandler{}}
-
- b, err := json.Marshal(tt.Template)
- if err != nil {
- t.Fatalf("Error parsing yaml: %s", err)
- }
-
- review := &atypes.Request{
- AdmissionRequest: admissionv1.AdmissionRequest{
- Kind: metav1.GroupVersionKind{
- Group: "templates.gatekeeper.sh",
- Version: "v1beta1",
- Kind: "ConstraintTemplate",
- },
- Object: runtime.RawExtension{
- Raw: b,
- },
- },
- }
+type nsGetter struct {
+ testclients.NoopClient
+}
- ctx := context.Background()
- _, err = handler.validateGatekeeperResources(ctx, review)
- if err != nil && !tt.ErrorExpected {
- t.Errorf("err = %s; want nil", err)
- }
+func (f *nsGetter) IsObjectNamespaced(obj runtime.Object) (bool, error) {
+ return false, nil
+}
- if err == nil && tt.ErrorExpected {
- t.Error("err = nil; want non-nil")
- }
- })
- }
+func (f *nsGetter) GroupVersionKindFor(obj runtime.Object) (k8schema.GroupVersionKind, error) {
+ return k8schema.GroupVersionKind{}, nil
}
-type nsGetter struct {
- testclients.NoopClient
+func (f *nsGetter) SubResource(_ string) ctrlclient.SubResourceClient {
+ return nil
}
-func (f *nsGetter) Get(_ context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object) error {
+func (f *nsGetter) Get(_ context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, _ ...ctrlclient.GetOption) error {
if ns, ok := obj.(*corev1.Namespace); ok {
ns.ObjectMeta = metav1.ObjectMeta{
Name: key.Name,
@@ -290,7 +238,19 @@ type errorNSGetter struct {
testclients.NoopClient
}
-func (f *errorNSGetter) Get(_ context.Context, key ctrlclient.ObjectKey, _ ctrlclient.Object) error {
+func (f *errorNSGetter) IsObjectNamespaced(obj runtime.Object) (bool, error) {
+ return false, nil
+}
+
+func (f *errorNSGetter) GroupVersionKindFor(obj runtime.Object) (k8schema.GroupVersionKind, error) {
+ return k8schema.GroupVersionKind{}, nil
+}
+
+func (f *errorNSGetter) SubResource(_ string) ctrlclient.SubResourceClient {
+ return nil
+}
+
+func (f *errorNSGetter) Get(_ context.Context, key ctrlclient.ObjectKey, _ ctrlclient.Object, _ ...ctrlclient.GetOption) error {
return k8serrors.NewNotFound(k8schema.GroupResource{Resource: "namespaces"}, key.Name)
}
@@ -347,11 +307,12 @@ func TestReviewRequest(t *testing.T) {
client: tt.CachedClient,
reader: tt.APIReader,
},
+ log: log,
}
if maxThreads > 0 {
handler.semaphore = make(chan struct{}, maxThreads)
}
- review := &atypes.Request{
+ review := &admission.Request{
AdmissionRequest: admissionv1.AdmissionRequest{
Kind: metav1.GroupVersionKind{
Group: "",
@@ -385,7 +346,7 @@ func TestReviewDefaultNS(t *testing.T) {
Spec: v1alpha1.ConfigSpec{
Match: []v1alpha1.MatchEntry{
{
- ExcludedNamespaces: []util.Wildcard{"default"},
+ ExcludedNamespaces: []wildcard.Wildcard{"default"},
Processes: []string{"*"},
},
},
@@ -419,6 +380,7 @@ func TestReviewDefaultNS(t *testing.T) {
reader: &nsGetter{},
processExcluder: pe,
},
+ log: log,
}
if maxThreads > 0 {
handler.semaphore = make(chan struct{}, maxThreads)
@@ -510,12 +472,13 @@ func TestConstraintValidation(t *testing.T) {
opa: opa,
expansionSystem: expansion.NewSystem(mutation.NewSystem(mutation.SystemOpts{})),
webhookHandler: webhookHandler{},
+ log: log,
}
b, err := yaml.YAMLToJSON([]byte(tt.Constraint))
if err != nil {
t.Fatalf("Error parsing yaml: %s", err)
}
- review := &atypes.Request{
+ review := &admission.Request{
AdmissionRequest: admissionv1.AdmissionRequest{
Kind: metav1.GroupVersionKind{
Group: "constraints.gatekeeper.sh",
@@ -637,12 +600,13 @@ func TestTracing(t *testing.T) {
opa: opa,
expansionSystem: expansion.NewSystem(mutation.NewSystem(mutation.SystemOpts{})),
webhookHandler: webhookHandler{injectedConfig: tt.Cfg},
+ log: log,
}
if maxThreads > 0 {
handler.semaphore = make(chan struct{}, maxThreads)
}
- review := &atypes.Request{
+ review := &admission.Request{
AdmissionRequest: admissionv1.AdmissionRequest{
Kind: metav1.GroupVersionKind{
Group: "",
@@ -813,11 +777,12 @@ func TestGetValidationMessages(t *testing.T) {
opa: opa,
expansionSystem: expansion.NewSystem(mutation.NewSystem(mutation.SystemOpts{})),
webhookHandler: webhookHandler{},
+ log: log,
}
if maxThreads > 0 {
handler.semaphore = make(chan struct{}, maxThreads)
}
- review := &atypes.Request{
+ review := &admission.Request{
AdmissionRequest: admissionv1.AdmissionRequest{
Kind: metav1.GroupVersionKind{
Group: "",
@@ -863,8 +828,8 @@ func TestValidateConfigResource(t *testing.T) {
for _, tt := range tc {
t.Run(tt.TestName, func(t *testing.T) {
- handler := validationHandler{}
- req := &atypes.Request{
+ handler := validationHandler{log: log}
+ req := &admission.Request{
AdmissionRequest: admissionv1.AdmissionRequest{
Name: tt.Name,
},
@@ -910,13 +875,13 @@ func TestValidateProvider(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- h := &validationHandler{}
+ h := &validationHandler{log: log}
b, err := yaml.YAMLToJSON([]byte(tt.provider))
if err != nil {
t.Fatalf("Error parsing yaml: %s", err)
}
- req := &atypes.Request{
+ req := &admission.Request{
AdmissionRequest: admissionv1.AdmissionRequest{
Object: runtime.RawExtension{
Raw: b,
diff --git a/pkg/webhook/stats_reporter.go b/pkg/webhook/stats_reporter.go
index ce727dfb3b6..ea0b2b77e58 100644
--- a/pkg/webhook/stats_reporter.go
+++ b/pkg/webhook/stats_reporter.go
@@ -4,7 +4,7 @@ import (
"context"
"time"
- "github.com/open-policy-agent/gatekeeper/pkg/metrics"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view"
"go.opencensus.io/tag"
diff --git a/pkg/webhook/webhook.go b/pkg/webhook/webhook.go
index ef651e0fa5a..bc1367cb64c 100644
--- a/pkg/webhook/webhook.go
+++ b/pkg/webhook/webhook.go
@@ -17,9 +17,9 @@ package webhook
import (
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
- "github.com/open-policy-agent/gatekeeper/pkg/controller/config/process"
- "github.com/open-policy-agent/gatekeeper/pkg/expansion"
- "github.com/open-policy-agent/gatekeeper/pkg/mutation"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
"sigs.k8s.io/controller-runtime/pkg/manager"
)
diff --git a/pkg/wildcard/wildcard.go b/pkg/wildcard/wildcard.go
new file mode 100644
index 00000000000..36df10bfa7c
--- /dev/null
+++ b/pkg/wildcard/wildcard.go
@@ -0,0 +1,41 @@
+package wildcard
+
+import "strings"
+
+// +kubebuilder:validation:Pattern=`^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$`
+
+// A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or
+// "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is
+// required for wildcard matching.
+//
+//nolint:revive
+type Wildcard string
+
+// Matches returns true if the candidate parameter is either an exact match of the Wildcard,
+// or if the Wildcard is a valid glob-match for the candidate. The Wildcard must start or end
+// in a "*" to be considered a glob.
+func (w Wildcard) Matches(candidate string) bool {
+ wStr := string(w)
+ switch {
+ case strings.HasPrefix(wStr, "*") && strings.HasSuffix(wStr, "*"):
+ return strings.Contains(candidate, strings.TrimSuffix(strings.TrimPrefix(wStr, "*"), "*"))
+ case strings.HasPrefix(wStr, "*"):
+ return strings.HasSuffix(candidate, strings.TrimPrefix(wStr, "*"))
+ case strings.HasSuffix(wStr, "*"):
+ return strings.HasPrefix(candidate, strings.TrimSuffix(wStr, "*"))
+ default:
+ return wStr == candidate
+ }
+}
+
+func (w Wildcard) MatchesGenerateName(candidate string) bool {
+ wStr := string(w)
+ switch {
+ case strings.HasPrefix(wStr, "*") && strings.HasSuffix(wStr, "*"):
+ return strings.Contains(candidate, strings.TrimSuffix(strings.TrimPrefix(wStr, "*"), "*"))
+ case strings.HasSuffix(wStr, "*"):
+ return strings.HasPrefix(candidate, strings.TrimSuffix(wStr, "*"))
+ default:
+ return false
+ }
+}
diff --git a/pkg/wildcard/wildcard_test.go b/pkg/wildcard/wildcard_test.go
new file mode 100644
index 00000000000..d3853eebae8
--- /dev/null
+++ b/pkg/wildcard/wildcard_test.go
@@ -0,0 +1,193 @@
+package wildcard
+
+import (
+ "testing"
+)
+
+func TestMatches(t *testing.T) {
+ tcs := []struct {
+ name string
+ w Wildcard
+ candidate string
+ matches bool
+ }{
+ {
+ name: "exact text match",
+ w: Wildcard("kube-system"),
+ candidate: "kube-system",
+ matches: true,
+ },
+ {
+ name: "no glob, wrong text",
+ w: Wildcard("kube-system"),
+ candidate: "gatekeeper-system",
+ matches: false,
+ },
+ {
+ name: "wildcard prefix match",
+ w: Wildcard("kube-*"),
+ candidate: "kube-system",
+ matches: true,
+ },
+ {
+ name: "wildcard prefix doesn't match",
+ w: Wildcard("kube-*"),
+ candidate: "gatekeeper-system",
+ matches: false,
+ },
+ {
+ name: "wildcard suffix match",
+ w: Wildcard("*-system"),
+ candidate: "kube-system",
+ matches: true,
+ },
+ {
+ name: "wildcard suffix doesn't match",
+ w: Wildcard("*-system"),
+ candidate: "kube-public",
+ matches: false,
+ },
+ {
+ name: "missing asterisk yields no wildcard support",
+ w: Wildcard("kube-"),
+ candidate: "kube-system",
+ matches: false,
+ },
+ {
+ name: "wildcard suffix and prefix match",
+ w: Wildcard("*-kube-*"),
+ candidate: "test-kube-test",
+ matches: true,
+ },
+ {
+ name: "no wildcard, only hypens at suffix and prefix",
+ w: Wildcard("-kube-"),
+ candidate: "test-kube-test",
+ matches: false,
+ },
+ {
+ name: "wild card at suffix and prefix, multiple hyphens",
+ w: Wildcard("*-kube-*"),
+ candidate: "test-dev-kube-dev-test",
+ matches: true,
+ },
+ {
+ name: "wild card at suffid and end, multiple hypens, no match",
+ w: Wildcard("*-kube-*"),
+ candidate: "my-kub-controller",
+ matches: false,
+ },
+ {
+ name: "wild card at suffix and prefix, multiple hyphens, no match",
+ w: Wildcard("*-kube-*"),
+ candidate: "my-controller-manager",
+ matches: false,
+ },
+ }
+
+ for _, tc := range tcs {
+ t.Run(tc.name, func(t *testing.T) {
+ if tc.w.Matches(tc.candidate) != tc.matches {
+ if tc.matches {
+ t.Errorf("Expected candidate '%v' to match wildcard '%v'", tc.candidate, tc.w)
+ } else {
+ t.Errorf("Candidate '%v' unexpectedly matched wildcard '%v'", tc.candidate, tc.w)
+ }
+ }
+ })
+ }
+}
+
+func TestWildcard_MatchesGenerateName(t *testing.T) {
+ tcs := []struct {
+ name string
+ w Wildcard
+ candidate string
+ matches bool
+ }{
+ {
+ name: "exact text match",
+ w: Wildcard("kube-system"),
+ candidate: "kube-system",
+ matches: false,
+ },
+ {
+ name: "no glob, wrong text",
+ w: Wildcard("kube-system"),
+ candidate: "gatekeeper-system",
+ matches: false,
+ },
+ {
+ name: "wildcard prefix match",
+ w: Wildcard("kube-*"),
+ candidate: "kube-system",
+ matches: true,
+ },
+ {
+ name: "wildcard prefix doesn't match",
+ w: Wildcard("kube-*"),
+ candidate: "gatekeeper-system",
+ matches: false,
+ },
+ {
+ name: "wildcard suffix match",
+ w: Wildcard("*-system"),
+ candidate: "kube-system",
+ matches: false,
+ },
+ {
+ name: "wildcard suffix doesn't match",
+ w: Wildcard("*-system"),
+ candidate: "kube-public",
+ matches: false,
+ },
+ {
+ name: "missing asterisk yields no wildcard support",
+ w: Wildcard("kube-"),
+ candidate: "kube-system",
+ matches: false,
+ },
+ {
+ name: "wildcard suffix and prefix match",
+ w: Wildcard("*-kube-*"),
+ candidate: "test-kube-test",
+ matches: true,
+ },
+ {
+ name: "no wildcard, only hypens at suffix and prefix",
+ w: Wildcard("-kube-"),
+ candidate: "test-kube-test",
+ matches: false,
+ },
+ {
+ name: "wild card at suffix and prefix, multiple hyphens",
+ w: Wildcard("*-kube-*"),
+ candidate: "test-dev-kube-dev-test",
+ matches: true,
+ },
+ {
+ name: "wild card at suffid and end, multiple hypens, no match",
+ w: Wildcard("*-kube-*"),
+ candidate: "my-kub-controller",
+ matches: false,
+ },
+ {
+ name: "wild card at suffix and prefix, multiple hyphens, no match",
+ w: Wildcard("*-kube-*"),
+ candidate: "my-controller-manager",
+ matches: false,
+ },
+ }
+
+ for _, tc := range tcs {
+ t.Run(tc.name, func(t *testing.T) {
+ if tc.w.MatchesGenerateName(tc.candidate) != tc.matches {
+ if tc.matches {
+ t.Errorf("Expected candidate '%v' to match wildcard '%v'", tc.candidate, tc.w)
+ } else {
+ t.Errorf("Candidate '%v' unexpectedly matched wildcard '%v'", tc.candidate, tc.w)
+ }
+ }
+ })
+ }
+}
diff --git a/test/bats/helpers.bash b/test/bats/helpers.bash
index 75535abca06..e2acb9e1205 100644
--- a/test/bats/helpers.bash
+++ b/test/bats/helpers.bash
@@ -137,4 +137,11 @@ mutator_enforced() {
local ready_count=$(echo "${cstr}" | jq '.metadata.generation as $generation | [.status.byPod[] | select( .operations[] == "mutation-webhook" and .observedGeneration == $generation)] | length')
echo "ready: ${ready_count}, expected: ${pod_count}"
[[ "${ready_count}" -eq "${pod_count}" ]]
-}
\ No newline at end of file
+}
+
+total_violations() {
+ ct_total_violations="$(kubectl get k8srequiredlabels pod-must-have-test -n gatekeeper-system -ojson | jq '.status.totalViolations')"
+ audit_id="$(kubectl get k8srequiredlabels pod-must-have-test -n gatekeeper-system -ojson | jq '.status.auditTimestamp')"
+ violations="$(kubectl logs -n fake-subscriber -l app=sub -c go-sub --tail=-1 | grep $audit_id | grep violation_audited | wc -l)"
+ [[ "${ct_total_violations}" -eq "${violations}" ]]
+}
diff --git a/test/bats/test.bats b/test/bats/test.bats
index 24bf49a8720..dc7ef017afa 100644
--- a/test/bats/test.bats
+++ b/test/bats/test.bats
@@ -52,6 +52,8 @@ teardown_file() {
@test "mutation crds are established" {
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl wait --for condition=established --timeout=60s crd/assign.mutations.gatekeeper.sh"
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl wait --for condition=established --timeout=60s crd/assignmetadata.mutations.gatekeeper.sh"
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl wait --for condition=established --timeout=60s crd/modifyset.mutations.gatekeeper.sh"
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl wait --for condition=established --timeout=60s crd/assignimage.mutations.gatekeeper.sh"
}
@test "waiting for validating webhook" {
@@ -82,9 +84,25 @@ teardown_file() {
run kubectl get svc mutate-svc -o jsonpath="{.metadata.annotations.gatekeeper\.sh\/mutations}"
assert_equal 'Assign//k8sexternalip:1' "${output}"
+ # Test AssignImage
+ kubectl apply -f ${BATS_TESTS_DIR}/mutations/assign_image.yaml
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "mutator_enforced AssignImage add-domain-digest"
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl apply -f ${BATS_TESTS_DIR}/mutations/nginx_pod.yaml"
+ run kubectl get pod nginx-test-pod -o jsonpath="{.spec.containers[0].image}"
+ assert_equal "foocorp.org/nginx@sha256:abcde67890123456789abc345678901a" "${output}"
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl delete pod nginx-test-pod"
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl delete assignimage add-domain-digest"
+
+ # Test removing the AssignImage does not apply mutation
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl apply -f ${BATS_TESTS_DIR}/mutations/nginx_pod.yaml"
+ run kubectl get pod nginx-test-pod -o jsonpath="{.spec.containers[0].image}"
+ assert_equal "nginx:latest" "${output}"
+
kubectl delete --ignore-not-found svc mutate-svc
kubectl delete --ignore-not-found assignmetadata k8sownerlabel
kubectl delete --ignore-not-found assign k8sexternalip
+ kubectl delete --ignore-not-found assignimage add-domain-digest
+ kubectl delete --ignore-not-found pod nginx-test-pod
}
@test "applying sync config" {
@@ -210,14 +228,14 @@ __required_labels_audit_test() {
@test "emit events test" {
# list events for easy debugging
- kubectl get events -n ${GATEKEEPER_NAMESPACE}
- events=$(kubectl get events -n ${GATEKEEPER_NAMESPACE} --field-selector reason=FailedAdmission -o json | jq -r '.items[] | select(.metadata.annotations.constraint_kind=="K8sRequiredLabels" )' | jq -s '. | length')
+ kubectl get events -n gatekeeper-test-playground
+ events=$(kubectl get events -n gatekeeper-test-playground --field-selector reason=FailedAdmission -o json | jq -r '.items[] | select(.metadata.annotations.constraint_kind=="K8sRequiredLabels" )' | jq -s '. | length')
[[ "$events" -ge 1 ]]
- events=$(kubectl get events -n ${GATEKEEPER_NAMESPACE} --field-selector reason=DryrunViolation -o json | jq -r '.items[] | select(.metadata.annotations.constraint_kind=="K8sRequiredLabels" )' | jq -s '. | length')
+ events=$(kubectl get events -n gatekeeper-test-playground --field-selector reason=DryrunViolation -o json | jq -r '.items[] | select(.metadata.annotations.constraint_kind=="K8sRequiredLabels" )' | jq -s '. | length')
[[ "$events" -ge 1 ]]
- events=$(kubectl get events -n ${GATEKEEPER_NAMESPACE} --field-selector reason=AuditViolation -o json | jq -r '.items[] | select(.metadata.annotations.constraint_kind=="K8sRequiredLabels" )' | jq -s '. | length')
+ events=$(kubectl get events -n gatekeeper-test-playground --field-selector reason=AuditViolation -o json | jq -r '.items[] | select(.metadata.annotations.constraint_kind=="K8sRequiredLabels" )' | jq -s '. | length')
[[ "$events" -ge 1 ]]
}
@@ -399,6 +417,12 @@ __expansion_audit_test() {
run kubectl apply -f test/expansion/loadbalancers_must_have_env.yaml
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "constraint_enforced k8srequiredlabels loadbalancers-must-have-env"
+ # check status resource on expansion template
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl get -f test/expansion/expand_deployments.yaml -ojson | jq -r -e '.status.byPod[0]'"
+ local temp_uid=$(kubectl get -f test/expansion/expand_deployments.yaml -o jsonpath='{.metadata.uid}')
+ local byPod_uid=$(kubectl get -f test/expansion/expand_deployments.yaml -o jsonpath='{.status.byPod[0].templateUID}')
+ assert_match ${temp_uid} ${byPod_uid}
+
# assert that creating deployment without 'env' label is rejected
run kubectl apply -f test/expansion/deployment_no_label.yaml
assert_failure
@@ -426,6 +450,38 @@ __expansion_audit_test() {
assert_success
# with a violating deployment on cluster, test that audit produces expansion violations
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "__expansion_audit_test"
+ run kubectl delete -f test/expansion/warn_expand_deployments
+ run kubectl delete -f test/expansion/deployment_no_label.yaml
+
+ # test source field on Constraints
+ run kubectl apply -f test/expansion/expand_deployments.yaml
+ run kubectl delete --ignore-not-found -f test/expansion/loadbalancers_must_have_env.yaml
+ run kubectl apply -f test/expansion/loadbalancers_must_have_env_source_gen.yaml
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "constraint_enforced k8srequiredlabels loadbalancers-must-have-env-gen"
+ # a generated pod should be denied
+ run kubectl apply -f test/expansion/deployment_no_label.yaml
+ assert_failure
+ # an original pod should be accepted, as the constraint only matches generated pods
+ run kubectl run nginx --image=nginx --dry-run=server --output json
+ assert_success
+
+ # test recursive expansion cronjob->job->pod triggers pod violation when creating cronjob
+ run kubectl apply -f test/expansion/expand_cronjob_job_pod.yaml
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl get expansiontemplate expand-cronjobs -ojson | jq -r -e '.status.byPod[0]'"
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl get expansiontemplate expand-jobs -ojson | jq -r -e '.status.byPod[0]'"
+ run kubectl apply -f test/expansion/cronjob.yaml
+ assert_failure
+
+ # test adding a ExpansionTemplate that creates a cycle updates template's status
+ run kubectl apply -f test/expansion/expand_pod_cronjob.yaml
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl get -f test/expansion/expand_pod_cronjob.yaml -ojson | jq -r -e '.status.byPod[0]'"
+ # expand-cronjobs, expand-jobs, and expand_pod_cronjob should each have an error set in their status
+ local status_err=$(kubectl get -f test/expansion/expand_pod_cronjob.yaml -o jsonpath='{.status.byPod[0].errors}' | grep "template forms expansion cycle" | wc -l)
+ assert_match "${status_err}" "1"
+ local status_err2=$(kubectl get expansiontemplate expand-cronjobs -o jsonpath='{.status.byPod[0].errors}' | grep "template forms expansion cycle" | wc -l)
+ assert_match "${status_err2}" "1"
+ local status_err3=$(kubectl get expansiontemplate expand-jobs -o jsonpath='{.status.byPod[0].errors}' | grep "template forms expansion cycle" | wc -l)
+ assert_match "${status_err3}" "1"
# cleanup
run kubectl delete --ignore-not-found namespace loadbalancers
@@ -433,7 +489,32 @@ __expansion_audit_test() {
run kubectl delete --ignore-not-found -f test/expansion/warn_expand_deployments.yaml
run kubectl delete --ignore-not-found -f test/expansion/k8srequiredlabels_ct.yaml
run kubectl delete --ignore-not-found -f test/expansion/loadbalancers_must_have_env.yaml
+ run kubectl delete --ignore-not-found -f test/expansion/loadbalancers_must_have_env_source_gen.yaml
run kubectl delete --ignore-not-found -f test/expansion/assignmeta_env.yaml
run kubectl delete --ignore-not-found -f test/expansion/deployment_no_label.yaml
run kubectl delete --ignore-not-found -f test/expansion/deployment_with_label.yaml
+ run kubectl delete --ignore-not-found -f test/expansion/cronjob.yaml
+ run kubectl delete --ignore-not-found -f test/expansion/expand_cronjob_job_pod.yaml
+ run kubectl delete --ignore-not-found -f test/expansion/expand_pod_cronjob.yaml
+}
+
+@test "gatekeeper pubsub test" {
+ if [ -z $ENABLE_PUBSUB_TESTS ]; then
+ skip "skipping pubsub tests"
+ fi
+
+ run kubectl create ns nginx
+ run kubectl create -f test/pubsub/nginx_deployment.yaml
+
+ run kubectl apply -f test/pubsub/k8srequiredlabels_ct.yaml
+ run kubectl apply -f test/pubsub/pod_must_have_test.yaml
+
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "constraint_enforced k8srequiredlabels pod-must-have-test"
+
+ wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "total_violations"
+
+ run kubectl delete -f test/pubsub/k8srequiredlabels_ct.yaml --ignore-not-found
+ run kubectl delete -f test/pubsub/pod_must_have_test.yaml --ignore-not-found
+ run kubectl delete -f test/pubsub/nginx_deployment.yaml --ignore-not-found
+ run kubectl delete ns nginx --ignore-not-found
}
diff --git a/test/bats/tests/mutations/assign_image.yaml b/test/bats/tests/mutations/assign_image.yaml
new file mode 100644
index 00000000000..c2d2af4ef23
--- /dev/null
+++ b/test/bats/tests/mutations/assign_image.yaml
@@ -0,0 +1,19 @@
+apiVersion: mutations.gatekeeper.sh/v1alpha1
+kind: AssignImage
+metadata:
+ name: add-domain-digest
+spec:
+ applyTo:
+ - groups: [ "" ]
+ kinds: [ "Pod" ]
+ versions: [ "v1" ]
+ location: "spec.containers[name:*].image"
+ parameters:
+ assignDomain: "foocorp.org"
+ assignTag: "@sha256:abcde67890123456789abc345678901a"
+ match:
+ source: "All"
+ scope: Namespaced
+ kinds:
+ - apiGroups: [ "*" ]
+ kinds: [ "Pod" ]
diff --git a/test/bats/tests/mutations/nginx_pod.yaml b/test/bats/tests/mutations/nginx_pod.yaml
new file mode 100644
index 00000000000..b90135fdc97
--- /dev/null
+++ b/test/bats/tests/mutations/nginx_pod.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: nginx-test-pod
+ labels:
+ role: myrole
+spec:
+ containers:
+ - name: test
+ image: nginx:latest
diff --git a/test/clients/noop_client.go b/test/clients/noop_client.go
index d9950a9294d..6cff301cba1 100644
--- a/test/clients/noop_client.go
+++ b/test/clients/noop_client.go
@@ -54,7 +54,7 @@ func (f *NoopClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ..
}
func (f *NoopClient) Status() client.StatusWriter {
- return f
+ return &SubResourceNoopClient{}
}
func (f *NoopClient) RESTMapper() meta.RESTMapper {
@@ -64,3 +64,17 @@ func (f *NoopClient) RESTMapper() meta.RESTMapper {
func (f *NoopClient) Scheme() *runtime.Scheme {
return nil
}
+
+type SubResourceNoopClient struct{}
+
+func (f *SubResourceNoopClient) Create(ctx context.Context, obj, subResource client.Object, opts ...client.SubResourceCreateOption) error {
+ return nil
+}
+
+func (f *SubResourceNoopClient) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
+ return nil
+}
+
+func (f *SubResourceNoopClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error {
+ return nil
+}
diff --git a/test/clients/retry_client.go b/test/clients/retry_client.go
index 67200ce9bcb..743a8ee5db4 100644
--- a/test/clients/retry_client.go
+++ b/test/clients/retry_client.go
@@ -68,7 +68,7 @@ func retry(ctx context.Context, limiter *rate.Limiter, f func() error) error {
}
}
-func (c *RetryClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
+func (c *RetryClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
return retry(ctx, c.Limiter, func() error {
return c.Client.Get(ctx, key, obj)
})
@@ -119,13 +119,13 @@ type RetryStatusWriter struct {
Limiter *rate.Limiter
}
-func (c *RetryStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+func (c *RetryStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
return retry(ctx, c.Limiter, func() error {
return c.StatusWriter.Update(ctx, obj, opts...)
})
}
-func (c *RetryStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+func (c *RetryStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error {
return retry(ctx, c.Limiter, func() error {
return c.StatusWriter.Patch(ctx, obj, patch, opts...)
})
diff --git a/test/expansion/cronjob.yaml b/test/expansion/cronjob.yaml
new file mode 100644
index 00000000000..4f7db934506
--- /dev/null
+++ b/test/expansion/cronjob.yaml
@@ -0,0 +1,23 @@
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: my-cronjob
+ namespace: "loadbalancers"
+spec:
+ schedule: "* * * * *"
+ jobTemplate:
+ spec:
+ template:
+ metadata:
+ namespace: "loadbalancers"
+ spec:
+ containers:
+ - args:
+ - "/bin/sh"
+ image: nginx:1.14.2
+ imagePullPolicy: Always
+ name: nginx
+ ports:
+ - containerPort: 80
+ restartPolicy: OnFailure
+
diff --git a/test/expansion/expand_cronjob_job_pod.yaml b/test/expansion/expand_cronjob_job_pod.yaml
new file mode 100644
index 00000000000..b8b3b7e3381
--- /dev/null
+++ b/test/expansion/expand_cronjob_job_pod.yaml
@@ -0,0 +1,29 @@
+apiVersion: expansion.gatekeeper.sh/v1beta1
+kind: ExpansionTemplate
+metadata:
+ name: expand-cronjobs
+spec:
+ applyTo:
+ - groups: [ "batch" ]
+ kinds: [ "CronJob" ]
+ versions: [ "v1" ]
+ templateSource: "spec.jobTemplate"
+ generatedGVK:
+ kind: "Job"
+ group: "batch"
+ version: "v1"
+---
+apiVersion: expansion.gatekeeper.sh/v1beta1
+kind: ExpansionTemplate
+metadata:
+ name: expand-jobs
+spec:
+ applyTo:
+ - groups: [ "batch" ]
+ kinds: [ "Job" ]
+ versions: [ "v1" ]
+ templateSource: "spec.template"
+ generatedGVK:
+ kind: "Pod"
+ group: ""
+ version: "v1"
diff --git a/test/expansion/expand_deployments.yaml b/test/expansion/expand_deployments.yaml
index e6447220471..dd04af0366a 100644
--- a/test/expansion/expand_deployments.yaml
+++ b/test/expansion/expand_deployments.yaml
@@ -1,4 +1,4 @@
-apiVersion: expansion.gatekeeper.sh/v1alpha1
+apiVersion: expansion.gatekeeper.sh/v1beta1
kind: ExpansionTemplate
metadata:
name: expand-deployments
diff --git a/test/expansion/expand_pod_cronjob.yaml b/test/expansion/expand_pod_cronjob.yaml
new file mode 100644
index 00000000000..123a5ce57a6
--- /dev/null
+++ b/test/expansion/expand_pod_cronjob.yaml
@@ -0,0 +1,14 @@
+apiVersion: expansion.gatekeeper.sh/v1beta1
+kind: ExpansionTemplate
+metadata:
+ name: expand-pods
+spec:
+ applyTo:
+ - groups: [ "" ]
+ kinds: [ "Pod" ]
+ versions: [ "v1" ]
+ templateSource: "spec.foo"
+ generatedGVK:
+ kind: "CronJob"
+ group: "batch"
+ version: "v1"
diff --git a/test/expansion/loadbalancers_must_have_env_source_gen.yaml b/test/expansion/loadbalancers_must_have_env_source_gen.yaml
new file mode 100644
index 00000000000..5d9060b8586
--- /dev/null
+++ b/test/expansion/loadbalancers_must_have_env_source_gen.yaml
@@ -0,0 +1,14 @@
+apiVersion: constraints.gatekeeper.sh/v1beta1
+kind: K8sRequiredLabels
+metadata:
+ name: loadbalancers-must-have-env-gen
+spec:
+ match:
+ scope: "Namespaced"
+ namespaces: [ "loadbalancers" ]
+ kinds:
+ - apiGroups: [ "" ]
+ kinds: [ "Pod" ]
+ source: "Generated"
+ parameters:
+ labels: [ "env" ]
diff --git a/test/expansion/warn_expand_deployments.yaml b/test/expansion/warn_expand_deployments.yaml
index 3b9cf7a3672..e61a29988b0 100644
--- a/test/expansion/warn_expand_deployments.yaml
+++ b/test/expansion/warn_expand_deployments.yaml
@@ -1,4 +1,4 @@
-apiVersion: expansion.gatekeeper.sh/v1alpha1
+apiVersion: expansion.gatekeeper.sh/v1beta1
kind: ExpansionTemplate
metadata:
name: expand-deployments
diff --git a/test/externaldata/dummy-provider/Dockerfile b/test/externaldata/dummy-provider/Dockerfile
index ef1521e67cc..001880610c9 100644
--- a/test/externaldata/dummy-provider/Dockerfile
+++ b/test/externaldata/dummy-provider/Dockerfile
@@ -1,5 +1,5 @@
ARG BUILDPLATFORM="linux/amd64"
-ARG BUILDERIMAGE="golang:1.19-bullseye"
+ARG BUILDERIMAGE="golang:1.21-bullseye"
ARG BASEIMAGE="gcr.io/distroless/static:nonroot"
FROM --platform=$BUILDPLATFORM $BUILDERIMAGE as builder
diff --git a/test/gator/expand/fixtures/basic-expansion-nonmatching-configs/output/output.yaml b/test/gator/expand/fixtures/basic-expansion-nonmatching-configs/output/output.yaml
index daa0fc09b9f..e2151b5fe47 100644
--- a/test/gator/expand/fixtures/basic-expansion-nonmatching-configs/output/output.yaml
+++ b/test/gator/expand/fixtures/basic-expansion-nonmatching-configs/output/output.yaml
@@ -3,6 +3,7 @@ kind: Pod
metadata:
labels:
app: nginx
+ name: nginx-deployment-pod
spec:
containers:
- args:
diff --git a/test/gator/expand/fixtures/basic-expansion/input/assignimage_mutator.yaml b/test/gator/expand/fixtures/basic-expansion/input/assignimage_mutator.yaml
new file mode 100644
index 00000000000..8043daf3485
--- /dev/null
+++ b/test/gator/expand/fixtures/basic-expansion/input/assignimage_mutator.yaml
@@ -0,0 +1,18 @@
+apiVersion: mutations.gatekeeper.sh/v1alpha1
+kind: AssignImage
+metadata:
+ name: add-tag-latest
+spec:
+ applyTo:
+ - groups: [ "" ]
+ kinds: [ "Pod" ]
+ versions: [ "v1" ]
+ location: "spec.containers[name:*].image"
+ parameters:
+ assignTag: ":latest"
+ match:
+ source: "All"
+ scope: Namespaced
+ kinds:
+ - apiGroups: [ "*" ]
+ kinds: [ "Pod" ]
diff --git a/test/gator/expand/fixtures/basic-expansion/output/output.yaml b/test/gator/expand/fixtures/basic-expansion/output/output.yaml
index 676c973a671..58941d6ba97 100644
--- a/test/gator/expand/fixtures/basic-expansion/output/output.yaml
+++ b/test/gator/expand/fixtures/basic-expansion/output/output.yaml
@@ -5,11 +5,12 @@ metadata:
owner: admin
labels:
app: nginx
+ name: nginx-deployment-pod
spec:
containers:
- args:
- /bin/sh
- image: nginx:1.14.2
+ image: nginx:latest
imagePullPolicy: Always
name: nginx
ports:
diff --git a/test/gator/expand/fixtures/expand-cr/output/output.yaml b/test/gator/expand/fixtures/expand-cr/output/output.yaml
index fefe29f02aa..aabede74d33 100644
--- a/test/gator/expand/fixtures/expand-cr/output/output.yaml
+++ b/test/gator/expand/fixtures/expand-cr/output/output.yaml
@@ -3,6 +3,7 @@ kind: Purr
metadata:
annotations:
shouldPet: manytimes
+ name: big-chungus-purr
spec:
loud: very
---
@@ -13,6 +14,7 @@ metadata:
sound: meow
labels:
fluffy: extremely
+ name: big-chungus-kitten
spec:
age: 10
breed: calico
diff --git a/test/gator/expand/fixtures/expand-with-missing-ns/input/manifest.yaml b/test/gator/expand/fixtures/expand-with-missing-ns/input/manifest.yaml
index b0144e715de..30b53f025d9 100644
--- a/test/gator/expand/fixtures/expand-with-missing-ns/input/manifest.yaml
+++ b/test/gator/expand/fixtures/expand-with-missing-ns/input/manifest.yaml
@@ -38,3 +38,6 @@ spec:
args:
- "/bin/sh"
---
+# while this is missing the "my-ns" namespace
+# since there are no namespace selectors
+# this test will pass.
diff --git a/test/gator/expand/fixtures/expand-with-ns/output/output.yaml b/test/gator/expand/fixtures/expand-with-ns/output/output.yaml
index 1a0fc80a699..d4cf89ebb9a 100644
--- a/test/gator/expand/fixtures/expand-with-ns/output/output.yaml
+++ b/test/gator/expand/fixtures/expand-with-ns/output/output.yaml
@@ -3,6 +3,7 @@ kind: Pod
metadata:
labels:
app: nginx
+ name: nginx-deployment-pod
namespace: my-ns
spec:
containers:
diff --git a/test/gator/expand/test.bats b/test/gator/expand/test.bats
index 363815578f1..9475f635a01 100644
--- a/test/gator/expand/test.bats
+++ b/test/gator/expand/test.bats
@@ -12,9 +12,9 @@ match_yaml_in_dir () {
want=$(cat "${BATS_TEST_DIRNAME}"/fixtures/"${match_dir}"/output/output.yaml)
if [[ ${yaml_output} != *"$want"* ]]; then
- printf "ERROR: resource not found in output\n"
- printf "WANT:\n%s\n\n" "$want"
- printf "GOT:\n%s\n" "$yaml_output"
+ echo "ERROR: resource not found in output"
+ echo "WANT: ${want}"
+ echo "GOT: ${yaml_output}"
echo "DIFF: "
diff <( echo "$want" ) <( echo "$yaml_output" )
exit 1
@@ -52,8 +52,10 @@ test_dir () {
test_dir "expand-with-ns" 0
}
+# the matching system will not err out when the namespace for
+# a resource is not defined but we DON'T use a namespace selector.
@test "generator with a custom namespace but namespace config missing" {
- test_dir "expand-with-missing-ns" 1
+ test_dir "expand-with-missing-ns" 0
}
@test "expand into 2 resultants and write to file" {
diff --git a/test/gator/test/fixtures/manifests/expansion/expansion-w-ns-selector.yaml b/test/gator/test/fixtures/manifests/expansion/expansion-w-ns-selector.yaml
new file mode 100644
index 00000000000..3c9c3942d68
--- /dev/null
+++ b/test/gator/test/fixtures/manifests/expansion/expansion-w-ns-selector.yaml
@@ -0,0 +1,128 @@
+apiVersion: expansion.gatekeeper.sh/v1alpha1
+kind: ExpansionTemplate
+metadata:
+ name: expand-deployments
+spec:
+ applyTo:
+ - groups: [ "apps" ]
+ kinds: [ "Deployment" ]
+ versions: [ "v1" ]
+ templateSource: "spec.template"
+ generatedGVK:
+ kind: "Pod"
+ group: ""
+ version: "v1"
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: nginx-deployment
+ namespace: my-ns
+ labels:
+ app: nginx
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: nginx
+ template:
+ metadata:
+ labels:
+ app: nginx
+ spec:
+ containers:
+ - name: nginx
+ image: nginx:1.14.2
+ ports:
+ - containerPort: 80
+ args:
+ - "/bin/sh"
+---
+apiVersion: constraints.gatekeeper.sh/v1beta1
+kind: K8sRequiredLabels
+metadata:
+ name: all-must-have-owner
+spec:
+ match:
+ kinds:
+ - apiGroups: [""]
+ kinds: ["Pod"]
+ namespaceSelector:
+ matchExpressions:
+ - key: admission.gatekeeper.sh/ignore
+ operator: DoesNotExist
+ parameters:
+ message: "All pods must have an `owner` label that points to your company username"
+ labels:
+ - key: owner
+ allowedRegex: "^[a-zA-Z]+.agilebank.demo$"
+---
+apiVersion: templates.gatekeeper.sh/v1
+kind: ConstraintTemplate
+metadata:
+ name: k8srequiredlabels
+ annotations:
+ description: >-
+ Requires resources to contain specified labels, with values matching
+ provided regular expressions.
+spec:
+ crd:
+ spec:
+ names:
+ kind: K8sRequiredLabels
+ validation:
+ openAPIV3Schema:
+ type: object
+ properties:
+ message:
+ type: string
+ labels:
+ type: array
+ description: >-
+ A list of labels and values the object must specify.
+ items:
+ type: object
+ properties:
+ key:
+ type: string
+ description: >-
+ The required label.
+ allowedRegex:
+ type: string
+ description: >-
+ If specified, a regular expression the annotation's value
+ must match. The value must contain at least one match for
+ the regular expression.
+ targets:
+ - target: admission.k8s.gatekeeper.sh
+ rego: |
+ package k8srequiredlabels
+
+ get_message(parameters, _default) = msg {
+ not parameters.message
+ msg := _default
+ }
+
+ get_message(parameters, _default) = msg {
+ msg := parameters.message
+ }
+
+ violation[{"msg": msg, "details": {"missing_labels": missing}}] {
+ provided := {label | input.review.object.metadata.labels[label]}
+ required := {label | label := input.parameters.labels[_].key}
+ missing := required - provided
+ count(missing) > 0
+ def_msg := sprintf("you must provide labels: %v", [missing])
+ msg := get_message(input.parameters, def_msg)
+ }
+
+ violation[{"msg": msg}] {
+ value := input.review.object.metadata.labels[key]
+ expected := input.parameters.labels[_]
+ expected.key == key
+ # do not match if allowedRegex is not defined, or is an empty string
+ expected.allowedRegex != ""
+ not re_match(expected.allowedRegex, value)
+ def_msg := sprintf("Label <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex])
+ msg := get_message(input.parameters, def_msg)
+ }
diff --git a/test/gator/test/fixtures/manifests/expansion/ns.yaml b/test/gator/test/fixtures/manifests/expansion/ns.yaml
new file mode 100644
index 00000000000..fe784865e8f
--- /dev/null
+++ b/test/gator/test/fixtures/manifests/expansion/ns.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: my-ns
diff --git a/test/gator/test/fixtures/manifests/with-policies/with-violations-and-defaults.yaml b/test/gator/test/fixtures/manifests/with-policies/with-violations-and-defaults.yaml
new file mode 100644
index 00000000000..c7a087b8c7f
--- /dev/null
+++ b/test/gator/test/fixtures/manifests/with-policies/with-violations-and-defaults.yaml
@@ -0,0 +1,75 @@
+apiVersion: templates.gatekeeper.sh/v1
+kind: ConstraintTemplate
+metadata:
+ name: k8srequiredlabelsdefault
+spec:
+ crd:
+ spec:
+ names:
+ kind: K8sRequiredLabelsDefault
+ validation:
+ legacySchema: false
+ openAPIV3Schema:
+ properties:
+ labels:
+ description: A list of labels and values the object must specify.
+ default:
+ - key: "aRequiredLabel"
+ items:
+ properties:
+ key:
+ description: The required label.
+ type: string
+ type: object
+ type: array
+ message:
+ default: "aRequiredMessage"
+ type: string
+ placeholder: # needed to showcase defaulting of the other two props above.
+ type: string
+ type: object
+ targets:
+ - rego: |
+ package k8srequiredlabels
+
+ get_message(parameters, _default) = msg {
+ not parameters.message
+ msg := _default
+ }
+
+ get_message(parameters, _default) = msg {
+ msg := parameters.message
+ }
+
+ violation[{"msg": msg, "details": {"missing_labels": missing}}] {
+ provided := {label | input.review.object.metadata.labels[label]}
+ required := {label | label := input.parameters.labels[_].key}
+ missing := required - provided
+ count(missing) > 0
+
+ msg := input.parameters.message
+ }
+
+ target: admission.k8s.gatekeeper.sh
+---
+apiVersion: constraints.gatekeeper.sh/v1beta1
+kind: K8sRequiredLabelsDefault
+metadata:
+ name: all-must-have-owner
+spec:
+ match:
+ kinds:
+ - apiGroups: [""]
+ kinds: ["Namespace"]
+ parameters:
+ placeholder: "placeholder"
+# notice no parameters that are used in the validaiton code are defined,
+# the defaults are applied from the ConstraintTemplate's open api v3 schema definition
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: my-ns
+# Missing owner label
+# labels:
+# owner: user.agilebank.demo
diff --git a/test/gator/test/test.bats b/test/gator/test/test.bats
index d03ae84736a..fd19c308eae 100755
--- a/test/gator/test/test.bats
+++ b/test/gator/test/test.bats
@@ -46,6 +46,11 @@ match_yaml_msg () {
# END OF HELPER FUNCTIONS
####################################################################################################
+@test "gator test doesn't wait on stdin input" {
+ # this should fail with "no input data identified"
+ ! bin/gator test
+}
+
@test "manifest with no violations piped to stdin returns 0 exit status" {
bin/gator test < "$BATS_TEST_DIRNAME/fixtures/manifests/with-policies/no-violations.yaml"
if [ "$?" -ne 0 ]; then
@@ -54,10 +59,20 @@ match_yaml_msg () {
fi
}
-@test "manifest with violations piped to stdin returns 1 exit status" {
+@test "manifest with violations redirected to stdin returns 1 exit status" {
! bin/gator test < "$BATS_TEST_DIRNAME/fixtures/manifests/with-policies/with-violations.yaml"
}
+@test "manifest with violations piped to stdin returns 1 exit status" {
+ # first test that we fail the command
+ ! cat "$BATS_TEST_DIRNAME/fixtures/manifests/with-policies/with-violations.yaml" | bin/gator test
+
+ output=$(! cat "$BATS_TEST_DIRNAME/fixtures/manifests/with-policies/with-violations.yaml" | bin/gator test)
+
+ # now test that the failure reason is a violation
+ match_substring "${output[*]}" "Container in your has no "
+}
+
@test "manifest with no violations included as flag returns 0 exit status" {
bin/gator test --filename="$BATS_TEST_DIRNAME/fixtures/manifests/with-policies/no-violations.yaml"
if [ "$?" -ne 0 ]; then
@@ -230,3 +245,41 @@ match_yaml_msg () {
want_msg="you must provide labels: {\"geo\"}"
match_yaml_msg "${output[*]}" "${want_msg}"
}
+
+@test "observe open api v3 defaults being applied" {
+ run bin/gator test \
+ -f="$BATS_TEST_DIRNAME/fixtures/manifests/with-policies/with-violations-and-defaults.yaml" \
+ -o=yaml
+
+ [ "$status" -eq 1 ]
+
+ # these are defined in the template's default fields for the parameters
+ want_msg_1="aRequiredLabel"
+ want_msg_2="aRequiredMessage"
+
+ match_substring "${output[*]}" "${want_msg_1}"
+ match_substring "${output[*]}" "${want_msg_2}"
+}
+
+@test "expansion with namespace selector" {
+ # First run without the namespace and expect an err
+ run bin/gator test \
+ -f="$BATS_TEST_DIRNAME/fixtures/manifests/expansion/expansion-w-ns-selector.yaml" \
+ -o=yaml
+
+ [ "$status" -eq 1 ]
+
+ want_msg="Implied by expand-deployments] unable to match constraints: error matching the requested object: nginx-deployment-pod :failed to run Match criteria: namespace selector for namespace-scoped object but missing Namespace"
+ match_substring "${output[*]}" "${want_msg}"
+
+ # Now expect a violation
+ run bin/gator test \
+ -f="$BATS_TEST_DIRNAME/fixtures/manifests/expansion/expansion-w-ns-selector.yaml" \
+ -f="$BATS_TEST_DIRNAME/fixtures/manifests/expansion/ns.yaml" \
+ -o=yaml
+
+ [ "$status" -eq 1 ]
+
+ want_msg="[Implied by expand-deployments] All pods must have an \`owner\` label that points to your company username"
+ match_substring "${output[*]}" "${want_msg}"
+}
diff --git a/test/image/Dockerfile b/test/image/Dockerfile
index 86f791fad22..7db376df488 100644
--- a/test/image/Dockerfile
+++ b/test/image/Dockerfile
@@ -1,21 +1,16 @@
-# Build the manager binary
-FROM golang:1.19-bullseye as builder
+FROM golang:1.21-bullseye@sha256:26c7537d6ac3827eb4638034d16edc64de57bb011c8cc8fe301ac13a6568f6f4 as builder
ARG BATS_VERSION
ARG ORAS_VERSION
ARG YQ_VERSION
ARG KUSTOMIZE_VERSION
-ARG KUBEBUILDER_VERSION
+
ARG TARGETARCH
-RUN apt-get update &&\
- apt-get install -y apt-utils make
+RUN git config --global --add safe.directory "*"
-# Install kubebuilder
-WORKDIR /scratch
-RUN curl -L -O "https://github.com/kubernetes-sigs/kubebuilder/releases/download/v${KUBEBUILDER_VERSION}/kubebuilder_linux_${TARGETARCH}" &&\
- mv kubebuilder_linux_${TARGETARCH} /usr/local/kubebuilder
-ENV PATH=$PATH:/usr/local/kubebuilder/bin:/usr/bin
+RUN apt-get update && \
+ apt-get install -y make jq apt-utils
# Install kustomize
RUN curl -L -O "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${KUSTOMIZE_VERSION}/kustomize_v${KUSTOMIZE_VERSION}_linux_${TARGETARCH}.tar.gz" &&\
@@ -37,9 +32,6 @@ RUN curl -SsLO https://github.com/oras-project/oras/releases/download/v${ORAS_VE
RUN curl -LsS https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_${TARGETARCH} -o /usr/local/bin/yq \
&& chmod +x /usr/local/bin/yq
-# Install jq
-RUN apt-get update && yes | apt-get install jq
-
# Install docker
RUN curl -fsSL https://get.docker.com | sh
diff --git a/test/pubsub/fake-subscriber/Dockerfile b/test/pubsub/fake-subscriber/Dockerfile
new file mode 100644
index 00000000000..fa389e7c05d
--- /dev/null
+++ b/test/pubsub/fake-subscriber/Dockerfile
@@ -0,0 +1,35 @@
+ARG BUILDPLATFORM="linux/amd64"
+ARG BUILDERIMAGE="golang:1.21-bullseye"
+ARG BASEIMAGE="gcr.io/distroless/static:nonroot"
+
+FROM --platform=$BUILDPLATFORM $BUILDERIMAGE as builder
+
+ARG TARGETPLATFORM
+ARG TARGETOS
+ARG TARGETARCH
+ARG TARGETVARIANT=""
+ARG LDFLAGS
+
+ENV GO111MODULE=on \
+ CGO_ENABLED=0 \
+ GOOS=${TARGETOS} \
+ GOARCH=${TARGETARCH} \
+ GOARM=${TARGETVARIANT}
+
+WORKDIR /go/src/github.com/open-policy-agent/gatekeeper/test/pubsub/fake-subscriber
+
+COPY . .
+
+RUN go mod init && go mod tidy && go mod vendor
+
+RUN go build -o main
+
+FROM $BASEIMAGE
+
+WORKDIR /
+
+COPY --from=builder /go/src/github.com/open-policy-agent/gatekeeper/test/pubsub/fake-subscriber/main .
+
+USER 65532:65532
+
+ENTRYPOINT ["/main"]
diff --git a/test/pubsub/fake-subscriber/main.go b/test/pubsub/fake-subscriber/main.go
new file mode 100644
index 00000000000..9831cbe2b2b
--- /dev/null
+++ b/test/pubsub/fake-subscriber/main.go
@@ -0,0 +1,62 @@
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "log"
+ "strconv"
+
+ "github.com/dapr/go-sdk/service/common"
+ daprd "github.com/dapr/go-sdk/service/http"
+)
+
+type PubsubMsg struct {
+ ID string `json:"id,omitempty"`
+ Details interface{} `json:"details,omitempty"`
+ EventType string `json:"eventType,omitempty"`
+ Group string `json:"group,omitempty"`
+ Version string `json:"version,omitempty"`
+ Kind string `json:"kind,omitempty"`
+ Name string `json:"name,omitempty"`
+ Namespace string `json:"namespace,omitempty"`
+ Message string `json:"message,omitempty"`
+ EnforcementAction string `json:"enforcementAction,omitempty"`
+ ConstraintAnnotations map[string]string `json:"constraintAnnotations,omitempty"`
+ ResourceGroup string `json:"resourceGroup,omitempty"`
+ ResourceAPIVersion string `json:"resourceAPIVersion,omitempty"`
+ ResourceKind string `json:"resourceKind,omitempty"`
+ ResourceNamespace string `json:"resourceNamespace,omitempty"`
+ ResourceName string `json:"resourceName,omitempty"`
+ ResourceLabels map[string]string `json:"resourceLabels,omitempty"`
+}
+
+var sub = &common.Subscription{
+ PubsubName: "pubsub",
+ Topic: "audit",
+ Route: "/checkout",
+}
+
+func main() {
+ s := daprd.NewService(":6002")
+ log.Printf("Listening...")
+ if err := s.AddTopicEventHandler(sub, eventHandler); err != nil {
+ log.Fatalf("error adding topic subscription: %v", err)
+ }
+ if err := s.Start(); err != nil {
+ log.Fatalf("error listening: %v", err)
+ }
+}
+
+func eventHandler(_ context.Context, e *common.TopicEvent) (retry bool, err error) {
+ var msg PubsubMsg
+ jsonInput, err := strconv.Unquote(string(e.RawData))
+ if err != nil {
+ log.Fatalf("error unquoting %v", err)
+ }
+ if err := json.Unmarshal([]byte(jsonInput), &msg); err != nil {
+ log.Fatalf("error %v", err)
+ }
+
+ log.Printf("%#v", msg)
+ return false, nil
+}
diff --git a/test/pubsub/fake-subscriber/manifest/subscriber.yaml b/test/pubsub/fake-subscriber/manifest/subscriber.yaml
new file mode 100644
index 00000000000..d0372ed6350
--- /dev/null
+++ b/test/pubsub/fake-subscriber/manifest/subscriber.yaml
@@ -0,0 +1,43 @@
+---
+apiVersion: dapr.io/v1alpha1
+kind: Component
+metadata:
+ name: pubsub
+ namespace: fake-subscriber
+spec:
+ type: pubsub.redis
+ version: v1
+ metadata:
+ - name: redisHost
+ value: redis-master.default.svc.cluster.local:6379
+ - name: redisPassword
+ secretKeyRef:
+ name: redis
+ key: redis-password
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: sub
+ namespace: fake-subscriber
+ labels:
+ app: sub
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: sub
+ template:
+ metadata:
+ labels:
+ app: sub
+ annotations:
+ dapr.io/enabled: "true"
+ dapr.io/app-id: "subscriber"
+ dapr.io/enable-api-logging: "true"
+ dapr.io/app-port: "6002"
+ spec:
+ containers:
+ - name: go-sub
+ image: fake-subscriber:latest
+ imagePullPolicy: Never
diff --git a/test/pubsub/k8srequiredlabels_ct.yaml b/test/pubsub/k8srequiredlabels_ct.yaml
new file mode 100644
index 00000000000..4437a1a19cb
--- /dev/null
+++ b/test/pubsub/k8srequiredlabels_ct.yaml
@@ -0,0 +1,29 @@
+apiVersion: templates.gatekeeper.sh/v1
+kind: ConstraintTemplate
+metadata:
+ name: k8srequiredlabels
+spec:
+ crd:
+ spec:
+ names:
+ kind: K8sRequiredLabels
+ validation:
+ # Schema for the `parameters` field
+ openAPIV3Schema:
+ type: object
+ properties:
+ labels:
+ type: array
+ items:
+ type: string
+ targets:
+ - target: admission.k8s.gatekeeper.sh
+ rego: |
+ package k8srequiredlabels
+ violation[{"msg": msg, "details": {"missing_labels": missing}}] {
+ provided := {label | input.review.object.metadata.labels[label]}
+ required := {label | label := input.parameters.labels[_]}
+ missing := required - provided
+ count(missing) > 0
+ msg := sprintf("you must provide labels: %v", [missing])
+ }
diff --git a/test/pubsub/nginx_deployment.yaml b/test/pubsub/nginx_deployment.yaml
new file mode 100644
index 00000000000..f3bdc4befc4
--- /dev/null
+++ b/test/pubsub/nginx_deployment.yaml
@@ -0,0 +1,22 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: nginx-deployment
+ namespace: nginx
+ labels:
+ app: nginx
+spec:
+ replicas: 4
+ selector:
+ matchLabels:
+ app: nginx
+ template:
+ metadata:
+ labels:
+ app: nginx
+ spec:
+ containers:
+ - name: nginx
+ image: nginx:latest
+ ports:
+ - containerPort: 80
diff --git a/test/pubsub/pod_must_have_test.yaml b/test/pubsub/pod_must_have_test.yaml
new file mode 100644
index 00000000000..3143283304a
--- /dev/null
+++ b/test/pubsub/pod_must_have_test.yaml
@@ -0,0 +1,13 @@
+apiVersion: constraints.gatekeeper.sh/v1beta1
+kind: K8sRequiredLabels
+metadata:
+ name: pod-must-have-test
+spec:
+ match:
+ scope: "Namespaced"
+ namespaces: [ "nginx" ]
+ kinds:
+ - apiGroups: [ "" ]
+ kinds: [ "Pod" ]
+ parameters:
+ labels: [ "test" ]
diff --git a/test/pubsub/publish-components.yaml b/test/pubsub/publish-components.yaml
new file mode 100644
index 00000000000..9686935dd01
--- /dev/null
+++ b/test/pubsub/publish-components.yaml
@@ -0,0 +1,28 @@
+---
+apiVersion: dapr.io/v1alpha1
+kind: Component
+metadata:
+ name: pubsub
+ namespace: gatekeeper-system
+spec:
+ type: pubsub.redis
+ version: v1
+ metadata:
+ - name: redisHost
+ value: redis-master.default.svc.cluster.local:6379
+ - name: redisPassword
+ secretKeyRef:
+ name: redis
+ key: redis-password
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: audit
+ namespace: gatekeeper-system
+data:
+ provider: "dapr"
+ config: |
+ {
+ "component": "pubsub"
+ }
diff --git a/test/testutils/controller.go b/test/testutils/controller.go
new file mode 100644
index 00000000000..ddcd9f8c9a7
--- /dev/null
+++ b/test/testutils/controller.go
@@ -0,0 +1,179 @@
+package testutils
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "github.com/open-policy-agent/gatekeeper/v3/apis"
+ v1 "k8s.io/api/core/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/util/wait"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/util/retry"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+)
+
+var (
+ vendorCRDPath = []string{"vendor", "github.com", "open-policy-agent", "frameworks", "constraint", "deploy", "crds.yaml"}
+ gkCRDPath = []string{"config", "crd", "bases"}
+)
+
+// ConstantRetry makes 3,000 attempts at a rate of 100 per second. Since this
+// is a test instance and not a "real" cluster, this is fine and there's no need
+// to increase the wait time each iteration.
+var ConstantRetry = wait.Backoff{
+ Steps: 3000,
+ Duration: 10 * time.Millisecond,
+}
+
+// CreateGatekeeperNamespace bootstraps the gatekeeper-system namespace for use in tests.
+func CreateGatekeeperNamespace(cfg *rest.Config) error {
+ c, err := client.New(cfg, client.Options{})
+ if err != nil {
+ return err
+ }
+
+ // Create gatekeeper namespace
+ ns := &v1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "gatekeeper-system",
+ },
+ }
+
+ ctx := context.Background()
+ _, err = controllerutil.CreateOrUpdate(ctx, c, ns, func() error { return nil })
+ return err
+}
+
+// DeleteObjectAndConfirm returns a callback which deletes obj from the passed
+// Client. Does result in mutations to obj. The callback includes a cached copy
+// of all information required to delete obj in the callback, so it is safe to
+// mutate obj afterwards. Similarly - client.Delete mutates its input, but
+// the callback does not call client.Delete on obj. Instead, it creates a
+// single-purpose Unstructured for this purpose. Thus, obj is not mutated after
+// the callback is run.
+func DeleteObjectAndConfirm(ctx context.Context, t *testing.T, c client.Client, obj client.Object) func() {
+ t.Helper()
+
+ // Cache the identifying information from obj. We refer to this cached
+ // information in the callback, and not obj itself.
+ gvk := obj.GetObjectKind().GroupVersionKind()
+ namespace := obj.GetNamespace()
+ name := obj.GetName()
+
+ if gvk.Empty() {
+ // We can't send a proper delete request with an Unstructured without
+ // filling in GVK. The alternative would be to require tests to construct
+ // a valid Scheme or provide a factory method for the type to delete - this
+ // is easier.
+ t.Fatalf("gvk for %v/%v %T is empty",
+ namespace, name, obj)
+ }
+
+ return func() {
+ t.Helper()
+
+ // Construct a single-use Unstructured to send the Delete request.
+ toDelete := makeUnstructured(gvk, namespace, name)
+ err := c.Delete(ctx, toDelete)
+ if apierrors.IsNotFound(err) {
+ return
+ } else if err != nil {
+ t.Fatal(err)
+ }
+
+ err = retry.OnError(ConstantRetry, func(err error) bool {
+ return true
+ }, func() error {
+ // Construct a single-use Unstructured to send the Get request. It isn't
+ // safe to reuse Unstructureds for each retry as Get modifies its input.
+ toGet := makeUnstructured(gvk, namespace, name)
+ key := client.ObjectKey{Namespace: namespace, Name: name}
+ err2 := c.Get(ctx, key, toGet)
+ if apierrors.IsGone(err2) || apierrors.IsNotFound(err2) {
+ return nil
+ }
+
+ // Marshal the currently-gotten object, so it can be printed in test
+ // failure output.
+ s, _ := json.MarshalIndent(toGet, "", " ")
+ return fmt.Errorf("found %v %v:\n%s", gvk, key, string(s))
+ })
+
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+}
+
+func StartControlPlane(m *testing.M, cfg **rest.Config, testerDepth int) {
+ walkbacks := make([]string, testerDepth)
+ for i := 0; i < testerDepth; i++ {
+ walkbacks[i] = ".."
+ }
+ t := &envtest.Environment{
+ CRDDirectoryPaths: []string{
+ filepath.Join(append(walkbacks, vendorCRDPath...)...),
+ filepath.Join(append(walkbacks, gkCRDPath...)...),
+ },
+ ErrorIfCRDPathMissing: true,
+ }
+ if err := apis.AddToScheme(scheme.Scheme); err != nil {
+ log.Fatal(err)
+ }
+
+ var err error
+ if *cfg, err = t.Start(); err != nil {
+ log.Fatal(err)
+ }
+ log.Print("STARTED")
+
+ code := m.Run()
+ if err = t.Stop(); err != nil {
+ log.Printf("error while trying to stop server: %v", err)
+ }
+ os.Exit(code)
+}
+
+// CreateThenCleanup creates obj in Client, and then registers obj to be deleted
+// at the end of the test. The passed obj is safely deepcopied before being
+// passed to client.Create, so it is not mutated by this call.
+func CreateThenCleanup(ctx context.Context, t *testing.T, c client.Client, obj client.Object) {
+ t.Helper()
+ cpy := obj.DeepCopyObject()
+ cpyObj, ok := cpy.(client.Object)
+ if !ok {
+ t.Fatalf("got obj.DeepCopyObject() type = %T, want %T", cpy, client.Object(nil))
+ }
+
+ err := c.Create(ctx, cpyObj)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // It is unnecessary to deepcopy obj as deleteObjectAndConfirm does not pass
+ // obj to any Client calls.
+ t.Cleanup(DeleteObjectAndConfirm(ctx, t, c, obj))
+}
+
+func makeUnstructured(gvk schema.GroupVersionKind, namespace, name string) *unstructured.Unstructured {
+ u := &unstructured.Unstructured{
+ Object: make(map[string]interface{}),
+ }
+ u.SetGroupVersionKind(gvk)
+ u.SetNamespace(namespace)
+ u.SetName(name)
+ return u
+}
diff --git a/test/testutils/manager.go b/test/testutils/manager.go
index bc5ded5b27a..8bfb377ea06 100644
--- a/test/testutils/manager.go
+++ b/test/testutils/manager.go
@@ -5,7 +5,14 @@ import (
"sync"
"testing"
+ "github.com/open-policy-agent/gatekeeper/v3/pkg/watch"
+ "github.com/prometheus/client_golang/prometheus"
+ "k8s.io/client-go/rest"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
)
// StartManager starts mgr. Registers a cleanup function to stop the manager at the completion of the test.
@@ -30,3 +37,32 @@ func StartManager(ctx context.Context, t *testing.T, mgr manager.Manager) {
}
})
}
+
+// SetupManager sets up a controller-runtime manager with registered watch manager.
+func SetupManager(t *testing.T, cfg *rest.Config) (manager.Manager, *watch.Manager) {
+ t.Helper()
+
+ ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
+ metrics.Registry = prometheus.NewRegistry()
+ mgr, err := manager.New(cfg, manager.Options{
+ MetricsBindAddress: "0",
+ MapperProvider: apiutil.NewDynamicRESTMapper,
+ Logger: NewLogger(t),
+ })
+ if err != nil {
+ t.Fatalf("setting up controller manager: %s", err)
+ }
+ c := mgr.GetCache()
+ dc, ok := c.(watch.RemovableCache)
+ if !ok {
+ t.Fatalf("expected dynamic cache, got: %T", c)
+ }
+ wm, err := watch.New(dc)
+ if err != nil {
+ t.Fatalf("could not create watch manager: %s", err)
+ }
+ if err := mgr.Add(wm); err != nil {
+ t.Fatalf("could not add watch manager to manager: %s", err)
+ }
+ return mgr, wm
+}
diff --git a/third_party/k8s.io/README.md b/third_party/k8s.io/README.md
new file mode 100644
index 00000000000..d1ddd4c7802
--- /dev/null
+++ b/third_party/k8s.io/README.md
@@ -0,0 +1,7 @@
+# k8s.io/kubernetes
+
+Forked from k8s.io/kubernetes@124fd62ad253f8362d78d5710d8d363aa1b376df
+
+This is a light fork to use scripts from kubernetes/kubernetes for gatekeeper's use cases.
+
+The original code can be found at https://github.com/kubernetes/kubernetes/tree/124fd62ad253f8362d78d5710d8d363aa1b376df .
diff --git a/third_party/k8s.io/kubernetes/hack/verify-licenses.sh b/third_party/k8s.io/kubernetes/hack/verify-licenses.sh
new file mode 100755
index 00000000000..7aec68fd5f2
--- /dev/null
+++ b/third_party/k8s.io/kubernetes/hack/verify-licenses.sh
@@ -0,0 +1,161 @@
+#!/usr/bin/env bash
+
+# Copyright 2016 The Kubernetes Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Usage: `hack/verify-licenses.sh`.
+
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+KUBE_TEMP=$(mktemp -d 2>/dev/null || mktemp -d -t kubernetes.XXXXXX)
+
+
+# Creating a new repository tree
+# Deleting vendor directory to make go-licenses fetch license URLs from go-packages source repository
+git worktree add -f "${KUBE_TEMP}"/tmp_test_licenses/gatekeeper HEAD >/dev/null 2>&1 || true
+cd "${KUBE_TEMP}"/tmp_test_licenses/gatekeeper && rm -rf vendor
+
+
+# Explicitly opt into go modules, even though we're inside a GOPATH directory
+export GO111MODULE=on
+
+
+allowed_licenses=()
+packages_flagged=()
+packages_url_missing=()
+exit_code=0
+
+# Install go-licenses
+echo '[INFO] Installing go-licenses...'
+go install github.com/google/go-licenses@latest
+
+# Fetching CNCF Approved List Of Licenses
+# Refer: https://github.com/cncf/foundation/blob/main/allowed-third-party-license-policy.md
+curl -s 'https://spdx.org/licenses/licenses.json' -o "${KUBE_TEMP}"/licenses.json
+
+number_of_licenses=$(jq '.licenses | length' "${KUBE_TEMP}"/licenses.json)
+loop_index_length=$(( number_of_licenses - 1 ))
+
+
+echo '[INFO] Fetching current list of CNCF approved licenses...'
+for index in $(seq 0 $loop_index_length);
+do
+ licenseID=$(jq ".licenses[$index] .licenseId" "${KUBE_TEMP}"/licenses.json)
+ if [[ $(jq ".licenses[$index] .isDeprecatedLicenseId" "${KUBE_TEMP}"/licenses.json) == false ]]
+ then
+ allowed_licenses+=("${licenseID}")
+ fi
+done
+
+
+# Scanning go-packages under the project & verifying against the CNCF approved list of licenses
+echo '[INFO] Starting license scan on go-packages...'
+go-licenses report ./... --include_tests >> "${KUBE_TEMP}"/licenses.csv
+
+echo -e 'PACKAGE_NAME LICENSE_NAME LICENSE_URL\n' >> "${KUBE_TEMP}"/approved_licenses.dump
+while IFS=, read -r GO_PACKAGE LICENSE_URL LICENSE_NAME
+do
+ FORMATTED_LICENSE_URL=
+ if [[ " ${allowed_licenses[*]} " == *"${LICENSE_NAME}"* ]];
+ then
+ if [[ "${LICENSE_URL}" == 'Unknown' ]];
+ then
+ if [[ "${GO_PACKAGE}" != k8s.io/* ]];
+ then
+ echo "${GO_PACKAGE} ${LICENSE_NAME} ${LICENSE_URL}" >> "${KUBE_TEMP}"/approved_licenses_with_missing_urls.dump
+ packages_url_missing+=("${GO_PACKAGE}")
+ else
+ LICENSE_URL='https://github.com/kubernetes/kubernetes/blob/master/LICENSE'
+ echo "${GO_PACKAGE} ${LICENSE_NAME} ${LICENSE_URL}" >> "${KUBE_TEMP}"/approved_licenses.dump
+ fi
+ elif curl -Is "${LICENSE_URL}" | head -1 | grep -q 404;
+ then
+ # For gatekeeper, the script won't find the constraint frameworks's license atm.
+ if [[ "${GO_PACKAGE}" == github.com/open-policy-agent/frameworks/* ]];
+ then
+ LICENSE_URL='https://github.com/open-policy-agent/frameworks/blob/master/LICENSE'
+ echo "${GO_PACKAGE} ${LICENSE_NAME} ${LICENSE_URL}" >> "${KUBE_TEMP}"/approved_licenses.dump
+ continue
+ fi
+
+ # Check whether the License URL is incorrectly formed
+ # TODO: Remove this workaround check once PR https://github.com/google/go-licenses/pull/110 is merged
+ IFS='/' read -r -a split_license_url <<< ${LICENSE_URL}
+ for part_of_url in "${split_license_url[@]}"
+ do
+ if [[ ${part_of_url} == '' ]]
+ then
+ continue
+ elif [[ ${part_of_url} == 'https:' ]]
+ then
+ FORMATTED_LICENSE_URL+='https://'
+ else
+ if [[ ${part_of_url} =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]
+ then
+ FORMATTED_LICENSE_URL+="${part_of_url}/${split_license_url[-1]}"
+ break
+ else
+ FORMATTED_LICENSE_URL+="${part_of_url}/"
+ fi
+ fi
+ done
+ if curl -Is "${FORMATTED_LICENSE_URL}" | head -1 | grep -q 404;
+ then
+ packages_url_missing+=("${GO_PACKAGE}")
+ echo "${GO_PACKAGE} ${LICENSE_NAME} ${LICENSE_URL}" >> "${KUBE_TEMP}"/approved_licenses_with_missing_urls.dump
+ else
+ echo "${GO_PACKAGE} ${LICENSE_NAME} ${FORMATTED_LICENSE_URL}" >> "${KUBE_TEMP}"/approved_licenses.dump
+ fi
+ else
+ echo "${GO_PACKAGE} ${LICENSE_NAME} ${LICENSE_URL}" >> "${KUBE_TEMP}"/approved_licenses.dump
+ fi
+ else
+ # Not all packages at this point should go to the not approved dump.
+ # there are a few exceptions approved by CNCF as per: https://github.com/cncf/foundation/tree/main/license-exceptions
+ # Currently gatekeeper uses just one of those so we are not going to do a general solution.
+
+ if [[ "${GO_PACKAGE}" == "github.com/rcrowley/go-metrics" ]] && [[ "${LICENSE_NAME}" == "BSD-2-Clause-FreeBSD" ]];
+ then
+ # as per https://github.com/cncf/foundation/blob/main/license-exceptions/cncf-exceptions-2019-11-01.json#L723-L726
+ echo "${GO_PACKAGE} ${LICENSE_NAME} ${LICENSE_URL}" >> "${KUBE_TEMP}"/approved_licenses.dump
+ else
+ echo "${GO_PACKAGE} ${LICENSE_NAME} ${LICENSE_URL}" >> "${KUBE_TEMP}"/notapproved_licenses.dump
+ packages_flagged+=("${GO_PACKAGE}")
+ fi
+ fi
+done < "${KUBE_TEMP}"/licenses.csv
+awk '{ printf "%-100s : %-20s : %s\n", $1, $2, $3 }' "${KUBE_TEMP}"/approved_licenses.dump
+
+
+if [[ ${#packages_url_missing[@]} -gt 0 ]]; then
+ echo -e '\n[ERROR] The following go-packages in the project have unknown or unreachable license URL:'
+ awk '{ printf "%-100s : %-20s : %s\n", $1, $2, $3 }' "${KUBE_TEMP}"/approved_licenses_with_missing_urls.dump
+ exit_code=1
+fi
+
+
+if [[ ${#packages_flagged[@]} -gt 0 ]]; then
+ echo "[ERROR] The following go-packages in the project are using non-CNCF approved licenses. Please refer to the CNCF's approved licence list for further information: https://github.com/cncf/foundation/blob/main/allowed-third-party-license-policy.md"
+ awk '{ printf "%-100s : %-20s : %s\n", $1, $2, $3 }' "${KUBE_TEMP}"/notapproved_licenses.dump
+ exit_code=1
+elif [[ "${exit_code}" -eq 1 ]]; then
+ echo "[ERROR] Project is using go-packages with unknown or unreachable license URLs. Please refer to the CNCF's approved licence list for further information: https://github.com/cncf/foundation/blob/main/allowed-third-party-license-policy.md"
+else
+ echo "[SUCCESS] Scan complete! All go-packages under the project are using current CNCF approved licenses!"
+fi
+
+exit "${exit_code}"
diff --git a/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/breaking_change.md b/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/breaking_change.md
new file mode 100644
index 00000000000..b15c979a173
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/breaking_change.md
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/bug_fix.md b/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/bug_fix.md
new file mode 100644
index 00000000000..84c58c71e16
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/bug_fix.md
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/compat_feature.md b/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/compat_feature.md
new file mode 100644
index 00000000000..3ad61bba834
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/compat_feature.md
@@ -0,0 +1,3 @@
+
+
+
diff --git a/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/docs.md b/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/docs.md
new file mode 100644
index 00000000000..c99ec61c2d4
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/docs.md
@@ -0,0 +1,3 @@
+
+
+
diff --git a/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/other.md b/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/other.md
new file mode 100644
index 00000000000..eec7cbf6ee6
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/.github/PULL_REQUEST_TEMPLATE/other.md
@@ -0,0 +1,3 @@
+
+
+
diff --git a/third_party/sigs.k8s.io/controller-runtime/.github/dependabot.yml b/third_party/sigs.k8s.io/controller-runtime/.github/dependabot.yml
new file mode 100644
index 00000000000..f3eba9f073f
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/.github/dependabot.yml
@@ -0,0 +1,36 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+
+ # Maintain dependencies for GitHub Actions
+ - package-ecosystem: "github-actions"
+ # Workflow files stored in the
+ # default location of `.github/workflows`
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: ":seedling:"
+ labels:
+ - "ok-to-test"
+
+ # Maintain dependencies for go
+ - package-ecosystem: "gomod"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: ":seedling:"
+ # Ignore K8 packages as these are done manually
+ ignore:
+ - dependency-name: "k8s.io/api"
+ - dependency-name: "k8s.io/apiextensions-apiserver"
+ - dependency-name: "k8s.io/apimachinery"
+ - dependency-name: "k8s.io/client-go"
+ - dependency-name: "k8s.io/component-base"
+ labels:
+ - "ok-to-test"
diff --git a/third_party/sigs.k8s.io/controller-runtime/.github/pull_request_template.md b/third_party/sigs.k8s.io/controller-runtime/.github/pull_request_template.md
new file mode 100644
index 00000000000..f6b8370e57f
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/.github/pull_request_template.md
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/third_party/sigs.k8s.io/controller-runtime/.github/workflows/golangci-lint.yml b/third_party/sigs.k8s.io/controller-runtime/.github/workflows/golangci-lint.yml
new file mode 100644
index 00000000000..bcc3b26eb9e
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/.github/workflows/golangci-lint.yml
@@ -0,0 +1,26 @@
+name: golangci-lint
+on:
+ pull_request:
+ types: [opened, edited, synchronize, reopened]
+ branches:
+ - main
+jobs:
+ golangci:
+ name: lint
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ working-directory:
+ - ""
+ - tools/setup-envtest
+ steps:
+ - uses: actions/setup-go@v4
+ with:
+ go-version: '1.20'
+ cache: false
+ - uses: actions/checkout@v3
+ - name: golangci-lint
+ uses: golangci/golangci-lint-action@v3
+ with:
+ version: v1.52.1
+ working-directory: ${{matrix.working-directory}}
diff --git a/third_party/sigs.k8s.io/controller-runtime/.github/workflows/verify.yml b/third_party/sigs.k8s.io/controller-runtime/.github/workflows/verify.yml
new file mode 100644
index 00000000000..51bb083ed5a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/.github/workflows/verify.yml
@@ -0,0 +1,14 @@
+on:
+ pull_request_target:
+ types: [opened, edited, reopened, synchronize]
+
+jobs:
+ verify:
+ runs-on: ubuntu-latest
+ name: verify PR contents
+ steps:
+ - name: Verifier action
+ id: verifier
+ uses: kubernetes-sigs/kubebuilder-release-tools@v0.3.0
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/third_party/sigs.k8s.io/controller-runtime/.gitignore b/third_party/sigs.k8s.io/controller-runtime/.gitignore
new file mode 100644
index 00000000000..294685952b8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/.gitignore
@@ -0,0 +1,27 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# editor and IDE paraphernalia
+.idea
+*.swp
+*.swo
+*~
+
+# Vscode files
+.vscode
+
+# Tools binaries.
+hack/tools/bin
+
+junit-report.xml
+/artifacts
\ No newline at end of file
diff --git a/third_party/sigs.k8s.io/controller-runtime/.golangci.yml b/third_party/sigs.k8s.io/controller-runtime/.golangci.yml
new file mode 100644
index 00000000000..817c2c723bd
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/.golangci.yml
@@ -0,0 +1,174 @@
+linters:
+ disable-all: true
+ enable:
+ - asasalint
+ - asciicheck
+ - bidichk
+ - bodyclose
+ - depguard
+ - dogsled
+ - dupl
+ - errcheck
+ - errchkjson
+ - errorlint
+ - exhaustive
+ - exportloopref
+ - goconst
+ - gocritic
+ - gocyclo
+ - gofmt
+ - goimports
+ - goprintffuncname
+ - gosec
+ - gosimple
+ - govet
+ - importas
+ - ineffassign
+ - makezero
+ - misspell
+ - nakedret
+ - nilerr
+ - nolintlint
+ - prealloc
+ - revive
+ - staticcheck
+ - stylecheck
+ - tagliatelle
+ - typecheck
+ - unconvert
+ - unparam
+ - unused
+ - whitespace
+
+linters-settings:
+ importas:
+ no-unaliased: true
+ alias:
+ # Kubernetes
+ - pkg: k8s.io/api/core/v1
+ alias: corev1
+ - pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
+ alias: apiextensionsv1
+ - pkg: k8s.io/apimachinery/pkg/apis/meta/v1
+ alias: metav1
+ - pkg: k8s.io/apimachinery/pkg/api/errors
+ alias: apierrors
+ - pkg: k8s.io/apimachinery/pkg/util/errors
+ alias: kerrors
+ # Controller Runtime
+ - pkg: sigs.k8s.io/controller-runtime
+ alias: ctrl
+ staticcheck:
+ go: "1.20"
+ stylecheck:
+ go: "1.20"
+ depguard:
+ include-go-root: true
+ packages:
+ - io/ioutil # https://go.dev/doc/go1.16#ioutil
+ revive:
+ rules:
+ # The following rules are recommended https://github.com/mgechev/revive#recommended-configuration
+ - name: blank-imports
+ - name: context-as-argument
+ - name: context-keys-type
+ - name: dot-imports
+ - name: error-return
+ - name: error-strings
+ - name: error-naming
+ - name: exported
+ - name: if-return
+ - name: increment-decrement
+ - name: var-naming
+ - name: var-declaration
+ - name: range
+ - name: receiver-naming
+ - name: time-naming
+ - name: unexported-return
+ - name: indent-error-flow
+ - name: errorf
+ - name: superfluous-else
+ - name: unreachable-code
+ - name: redefines-builtin-id
+ #
+ # Rules in addition to the recommended configuration above.
+ #
+ - name: bool-literal-in-expr
+ - name: constant-logical-expr
+
+issues:
+ max-same-issues: 0
+ max-issues-per-linter: 0
+ # We are disabling default golangci exclusions because we want to help reviewers to focus on reviewing the most relevant
+ # changes in PRs and avoid nitpicking.
+ exclude-use-default: false
+ # List of regexps of issue texts to exclude, empty list by default.
+ exclude:
+ # The following are being worked on to remove their exclusion. This list should be reduced or go away all together over time.
+ # If it is decided they will not be addressed they should be moved above this comment.
+ - Subprocess launch(ed with variable|ing should be audited)
+ - (G204|G104|G307)
+ - "ST1000: at least one file in a package should have a package comment"
+ exclude-rules:
+ - linters:
+ - gosec
+ text: "G108: Profiling endpoint is automatically exposed on /debug/pprof"
+ - linters:
+ - revive
+ text: "exported: exported method .*\\.(Reconcile|SetupWithManager|SetupWebhookWithManager) should have comment or be unexported"
+ - linters:
+ - errcheck
+ text: Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). is not checked
+ - linters:
+ - staticcheck
+ text: "SA1019: .*The component config package has been deprecated and will be removed in a future release."
+ # With Go 1.16, the new embed directive can be used with an un-named import,
+ # revive (previously, golint) only allows these to be imported in a main.go, which wouldn't work for us.
+ # This directive allows the embed package to be imported with an underscore everywhere.
+ - linters:
+ - revive
+ source: _ "embed"
+ # Exclude some packages or code to require comments, for example test code, or fake clients.
+ - linters:
+ - revive
+ text: exported (method|function|type|const) (.+) should have comment or be unexported
+ source: (func|type).*Fake.*
+ - linters:
+ - revive
+ text: exported (method|function|type|const) (.+) should have comment or be unexported
+ path: fake_\.go
+ # Disable unparam "always receives" which might not be really
+ # useful when building libraries.
+ - linters:
+ - unparam
+ text: always receives
+ # Dot imports for gomega and ginkgo are allowed
+ # within test files.
+ - path: _test\.go
+ text: should not use dot imports
+ - path: _test\.go
+ text: cyclomatic complexity
+ - path: _test\.go
+ text: "G107: Potential HTTP request made with variable url"
+ # Append should be able to assign to a different var/slice.
+ - linters:
+ - gocritic
+ text: "appendAssign: append result not assigned to the same slice"
+ - linters:
+ - gocritic
+ text: "singleCaseSwitch: should rewrite switch statement to if statement"
+ # It considers all file access to a filename that comes from a variable problematic,
+ # which is naiv at best.
+ - linters:
+ - gosec
+ text: "G304: Potential file inclusion via variable"
+ - linters:
+ - dupl
+ path: _test\.go
+
+run:
+ timeout: 10m
+ skip-files:
+ - "zz_generated.*\\.go$"
+ - ".*conversion.*\\.go$"
+ allow-parallel-runners: true
diff --git a/third_party/sigs.k8s.io/controller-runtime/CONTRIBUTING.md b/third_party/sigs.k8s.io/controller-runtime/CONTRIBUTING.md
new file mode 100644
index 00000000000..2c0ea1f6674
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/CONTRIBUTING.md
@@ -0,0 +1,19 @@
+# Contributing guidelines
+
+## Sign the CLA
+
+Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests.
+
+Please see https://git.k8s.io/community/CLA.md for more info
+
+## Contributing steps
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The [repo owners](OWNERS) will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Submit a pull request.
+
+## Test locally
+
+Run the command `make test` to test the changes locally.
diff --git a/third_party/sigs.k8s.io/controller-runtime/FAQ.md b/third_party/sigs.k8s.io/controller-runtime/FAQ.md
new file mode 100644
index 00000000000..c21b29e287a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/FAQ.md
@@ -0,0 +1,81 @@
+# FAQ
+
+### Q: How do I know which type of object a controller references?
+
+**A**: Each controller should only reconcile one object type. Other
+affected objects should be mapped to a single type of root object, using
+the `EnqueueRequestForOwner` or `EnqueueRequestsFromMapFunc` event
+handlers, and potentially indices. Then, your Reconcile method should
+attempt to reconcile *all* state for that given root objects.
+
+### Q: How do I have different logic in my reconciler for different types of events (e.g. create, update, delete)?
+
+**A**: You should not. Reconcile functions should be idempotent, and
+should always reconcile state by reading all the state it needs, then
+writing updates. This allows your reconciler to correctly respond to
+generic events, adjust to skipped or coalesced events, and easily deal
+with application startup. The controller will enqueue reconcile requests
+for both old and new objects if a mapping changes, but it's your
+responsibility to make sure you have enough information to be able clean
+up state that's no longer referenced.
+
+### Q: My cache might be stale if I read from a cache! How should I deal with that?
+
+**A**: There are several different approaches that can be taken, depending
+on your situation.
+
+- When you can, take advantage of optimistic locking: use deterministic
+ names for objects you create, so that the Kubernetes API server will
+ warn you if the object already exists. Many controllers in Kubernetes
+ take this approach: the StatefulSet controller appends a specific number
+ to each pod that it creates, while the Deployment controller hashes the
+ pod template spec and appends that.
+
+- In the few cases when you cannot take advantage of deterministic names
+ (e.g. when using generateName), it may be useful in to track which
+ actions you took, and assume that they need to be repeated if they don't
+ occur after a given time (e.g. using a requeue result). This is what
+ the ReplicaSet controller does.
+
+In general, write your controller with the assumption that information
+will eventually be correct, but may be slightly out of date. Make sure
+that your reconcile function enforces the entire state of the world each
+time it runs. If none of this works for you, you can always construct
+a client that reads directly from the API server, but this is generally
+considered to be a last resort, and the two approaches above should
+generally cover most circumstances.
+
+### Q: Where's the fake client? How do I use it?
+
+**A**: The fake client
+[exists](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/client/fake),
+but we generally recommend using
+[envtest.Environment](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest#Environment)
+to test against a real API server. In our experience, tests using fake
+clients gradually re-implement poorly-written impressions of a real API
+server, which leads to hard-to-maintain, complex test code.
+
+### Q: How should I write tests? Any suggestions for getting started?
+
+- Use the aforementioned
+ [envtest.Environment](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest#Environment)
+ to spin up a real API server instead of trying to mock one out.
+
+- Structure your tests to check that the state of the world is as you
+ expect it, *not* that a particular set of API calls were made, when
+ working with Kubernetes APIs. This will allow you to more easily
+ refactor and improve the internals of your controllers without changing
+ your tests.
+
+- Remember that any time you're interacting with the API server, changes
+ may have some delay between write time and reconcile time.
+
+### Q: What are these errors about no Kind being registered for a type?
+
+**A**: You're probably missing a fully-set-up Scheme. Schemes record the
+mapping between Go types and group-version-kinds in Kubernetes. In
+general, your application should have its own Scheme containing the types
+from the API groups that it needs (be they Kubernetes types or your own).
+See the [scheme builder
+docs](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/scheme) for
+more information.
diff --git a/third_party/sigs.k8s.io/controller-runtime/FORK_INFO.md b/third_party/sigs.k8s.io/controller-runtime/FORK_INFO.md
new file mode 100644
index 00000000000..d6f185c930f
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/FORK_INFO.md
@@ -0,0 +1,3 @@
+This is a fork of controller runtime made from the following commit:
+
+commit 116a1b831fffe7ccc3c8145306c3e1a3b1b14ffa (HEAD, tag: v0.15.0)
diff --git a/third_party/sigs.k8s.io/controller-runtime/Makefile b/third_party/sigs.k8s.io/controller-runtime/Makefile
new file mode 100644
index 00000000000..71ec644de02
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/Makefile
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+
+# Copyright 2020 The Kubernetes Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# If you update this file, please follow
+# https://suva.sh/posts/well-documented-makefiles
+
+## --------------------------------------
+## General
+## --------------------------------------
+
+SHELL:=/usr/bin/env bash
+.DEFAULT_GOAL:=help
+
+# Use GOPROXY environment variable if set
+GOPROXY := $(shell go env GOPROXY)
+ifeq ($(GOPROXY),)
+GOPROXY := https://proxy.golang.org
+endif
+export GOPROXY
+
+# Active module mode, as we use go modules to manage dependencies
+export GO111MODULE=on
+
+# Tools.
+TOOLS_DIR := hack/tools
+TOOLS_BIN_DIR := $(TOOLS_DIR)/bin
+GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/golangci-lint)
+GO_APIDIFF := $(TOOLS_BIN_DIR)/go-apidiff
+CONTROLLER_GEN := $(TOOLS_BIN_DIR)/controller-gen
+ENVTEST_DIR := $(abspath tools/setup-envtest)
+
+# The help will print out all targets with their descriptions organized bellow their categories. The categories are represented by `##@` and the target descriptions by `##`.
+# The awk commands is responsible to read the entire set of makefiles included in this invocation, looking for lines of the file as xyz: ## something, and then pretty-format the target and help. Then, if there's a line with ##@ something, that gets pretty-printed as a category.
+# More info over the usage of ANSI control characters for terminal formatting: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
+# More info over awk command: http://linuxcommand.org/lc3_adv_awk.php
+.PHONY: help
+help: ## Display this help
+ @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
+
+## --------------------------------------
+## Testing
+## --------------------------------------
+
+.PHONY: test
+test: test-tools ## Run the script check-everything.sh which will check all.
+ TRACE=1 ./hack/check-everything.sh
+
+.PHONY: test-tools
+test-tools: ## tests the tools codebase (setup-envtest)
+ cd tools/setup-envtest && go test ./...
+
+## --------------------------------------
+## Binaries
+## --------------------------------------
+
+$(GO_APIDIFF): $(TOOLS_DIR)/go.mod # Build go-apidiff from tools folder.
+ cd $(TOOLS_DIR) && go build -tags=tools -o bin/go-apidiff github.com/joelanford/go-apidiff
+
+$(CONTROLLER_GEN): $(TOOLS_DIR)/go.mod # Build controller-gen from tools folder.
+ cd $(TOOLS_DIR) && go build -tags=tools -o bin/controller-gen sigs.k8s.io/controller-tools/cmd/controller-gen
+
+$(GOLANGCI_LINT): .github/workflows/golangci-lint.yml # Download golanci-lint using hack script into tools folder.
+ hack/ensure-golangci-lint.sh \
+ -b $(TOOLS_BIN_DIR) \
+ $(shell cat .github/workflows/golangci-lint.yml | grep "version: v" | sed 's/.*version: //')
+
+## --------------------------------------
+## Linting
+## --------------------------------------
+
+.PHONY: lint
+lint: $(GOLANGCI_LINT) ## Lint codebase
+ $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS)
+ cd tools/setup-envtest; $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS)
+
+.PHONY: lint-fix
+lint-fix: $(GOLANGCI_LINT) ## Lint the codebase and run auto-fixers if supported by the linter.
+ GOLANGCI_LINT_EXTRA_ARGS=--fix $(MAKE) lint
+
+## --------------------------------------
+## Generate
+## --------------------------------------
+
+.PHONY: modules
+modules: ## Runs go mod to ensure modules are up to date.
+ go mod tidy
+ cd $(TOOLS_DIR); go mod tidy
+ cd $(ENVTEST_DIR); go mod tidy
+
+.PHONY: generate
+generate: $(CONTROLLER_GEN) ## Runs controller-gen for internal types for config file
+ $(CONTROLLER_GEN) object paths="./pkg/config/v1alpha1/...;./examples/configfile/custom/v1alpha1/..."
+
+## --------------------------------------
+## Cleanup / Verification
+## --------------------------------------
+
+.PHONY: clean
+clean: ## Cleanup.
+ $(MAKE) clean-bin
+
+.PHONY: clean-bin
+clean-bin: ## Remove all generated binaries.
+ rm -rf hack/tools/bin
+
+.PHONY: verify-modules
+verify-modules: modules ## Verify go modules are up to date
+ @if !(git diff --quiet HEAD -- go.sum go.mod $(TOOLS_DIR)/go.mod $(TOOLS_DIR)/go.sum $(ENVTEST_DIR)/go.mod $(ENVTEST_DIR)/go.sum); then \
+ git diff; \
+ echo "go module files are out of date, please run 'make modules'"; exit 1; \
+ fi
+
+.PHONY: verify-generate
+verify-generate: generate ## Verify generated files are up to date
+ @if !(git diff --quiet HEAD); then \
+ git diff; \
+ echo "generated files are out of date, run make generate"; exit 1; \
+ fi
diff --git a/third_party/sigs.k8s.io/controller-runtime/OWNERS b/third_party/sigs.k8s.io/controller-runtime/OWNERS
new file mode 100644
index 00000000000..4b1fa044bf7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/OWNERS
@@ -0,0 +1,10 @@
+# See the OWNERS docs: https://git.k8s.io/community/contributors/guide/owners.md
+
+approvers:
+ - controller-runtime-admins
+ - controller-runtime-maintainers
+ - controller-runtime-approvers
+reviewers:
+ - controller-runtime-admins
+ - controller-runtime-reviewers
+ - controller-runtime-approvers
diff --git a/third_party/sigs.k8s.io/controller-runtime/OWNERS_ALIASES b/third_party/sigs.k8s.io/controller-runtime/OWNERS_ALIASES
new file mode 100644
index 00000000000..7848941d534
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/OWNERS_ALIASES
@@ -0,0 +1,41 @@
+# See the OWNERS docs: https://git.k8s.io/community/contributors/guide/owners.md
+
+aliases:
+ # active folks who can be contacted to perform admin-related
+ # tasks on the repo, or otherwise approve any PRS.
+ controller-runtime-admins:
+ - vincepri
+ - joelanford
+
+ # non-admin folks who have write-access and can approve any PRs in the repo
+ controller-runtime-maintainers:
+ - alvaroaleman
+ - joelanford
+ - sbueringer
+ - vincepri
+
+ # non-admin folks who can approve any PRs in the repo
+ controller-runtime-approvers:
+ - fillzpp
+
+ # folks who can review and LGTM any PRs in the repo (doesn't
+ # include approvers & admins -- those count too via the OWNERS
+ # file)
+ controller-runtime-reviewers:
+ - varshaprasad96
+ - inteon
+
+ # folks to can approve things in the directly-ported
+ # testing_frameworks portions of the codebase
+ testing-integration-approvers:
+ - apelisse
+ - hoegaarden
+
+ # folks who may have context on ancient history,
+ # but are no longer directly involved
+ controller-runtime-emeritus-maintainers:
+ - directxman12
+ controller-runtime-emeritus-admins:
+ - droot
+ - mengqiy
+ - pwittrock
diff --git a/third_party/sigs.k8s.io/controller-runtime/README.md b/third_party/sigs.k8s.io/controller-runtime/README.md
index 1e6f62398f3..e785abdd77b 100644
--- a/third_party/sigs.k8s.io/controller-runtime/README.md
+++ b/third_party/sigs.k8s.io/controller-runtime/README.md
@@ -1,10 +1,66 @@
-# sigs.k8s.io/controller-runtime
+[](https://goreportcard.com/report/sigs.k8s.io/controller-runtime)
+[](https://pkg.go.dev/sigs.k8s.io/controller-runtime)
-Forked from sigs.k8s.io/controller-runtime@a8c19c49e49cfba2aa486ff322cbe5222d6da533 (v0.8.2).
+# Kubernetes controller-runtime Project
-This fork adds the ability to dynamically
-remove informers from the informer cache. Additionally, non-blocking APIs were added to fetch informers
-without waiting for cache sync. `pkg/cache` was renamed to `pkg/dynamiccache` for clarity.
+The Kubernetes controller-runtime Project is a set of go libraries for building
+Controllers. It is leveraged by [Kubebuilder](https://book.kubebuilder.io/) and
+[Operator SDK](https://github.com/operator-framework/operator-sdk). Both are
+a great place to start for new projects. See
+[Kubebuilder's Quick Start](https://book.kubebuilder.io/quick-start.html) to
+see how it can be used.
-The original code can be found at https://github.com/kubernetes-sigs/controller-runtime/tree/v0.8.2/pkg/cache.
+Documentation:
+- [Package overview](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg)
+- [Basic controller using builder](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/builder#example-Builder)
+- [Creating a manager](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#example-New)
+- [Creating a controller](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/controller#example-New)
+- [Examples](https://github.com/kubernetes-sigs/controller-runtime/blob/main/examples)
+- [Designs](https://github.com/kubernetes-sigs/controller-runtime/blob/main/designs)
+
+# Versioning, Maintenance, and Compatibility
+
+The full documentation can be found at [VERSIONING.md](VERSIONING.md), but TL;DR:
+
+Users:
+
+- We follow [Semantic Versioning (semver)](https://semver.org)
+- Use releases with your dependency management to ensure that you get compatible code
+- The main branch contains all the latest code, some of which may break compatibility (so "normal" `go get` is not recommended)
+
+Contributors:
+
+- All code PR must be labeled with :bug: (patch fixes), :sparkles: (backwards-compatible features), or :warning: (breaking changes)
+- Breaking changes will find their way into the next major release, other changes will go into an semi-immediate patch or minor release
+- For a quick PR template suggesting the right information, use one of these PR templates:
+ * [Breaking Changes/Features](/.github/PULL_REQUEST_TEMPLATE/breaking_change.md)
+ * [Backwards-Compatible Features](/.github/PULL_REQUEST_TEMPLATE/compat_feature.md)
+ * [Bug fixes](/.github/PULL_REQUEST_TEMPLATE/bug_fix.md)
+ * [Documentation Changes](/.github/PULL_REQUEST_TEMPLATE/docs.md)
+ * [Test/Build/Other Changes](/.github/PULL_REQUEST_TEMPLATE/other.md)
+
+## FAQ
+
+See [FAQ.md](FAQ.md)
+
+## Community, discussion, contribution, and support
+
+Learn how to engage with the Kubernetes community on the [community page](http://kubernetes.io/community/).
+
+controller-runtime is a subproject of the [kubebuilder](https://github.com/kubernetes-sigs/kubebuilder) project
+in sig apimachinery.
+
+You can reach the maintainers of this project at:
+
+- Slack channel: [#controller-runtime](https://kubernetes.slack.com/archives/C02MRBMN00Z)
+- Google Group: [kubebuilder@googlegroups.com](https://groups.google.com/forum/#!forum/kubebuilder)
+
+## Contributing
+Contributions are greatly appreciated. The maintainers actively manage the issues list, and try to highlight issues suitable for newcomers.
+The project follows the typical GitHub pull request model. See [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
+Before starting any work, please either comment on an existing issue, or file a new one.
+
+## Code of conduct
+
+Participation in the Kubernetes community is governed by the [Kubernetes Code of Conduct](code-of-conduct.md).
diff --git a/third_party/sigs.k8s.io/controller-runtime/RELEASE.md b/third_party/sigs.k8s.io/controller-runtime/RELEASE.md
new file mode 100644
index 00000000000..f234494fe1c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/RELEASE.md
@@ -0,0 +1,47 @@
+# Release Process
+
+The Kubernetes controller-runtime Project is released on an as-needed basis. The process is as follows:
+
+**Note:** Releases are done from the `release-MAJOR.MINOR` branches. For PATCH releases is not required
+to create a new branch you will just need to ensure that all big fixes are cherry-picked into the respective
+`release-MAJOR.MINOR` branch. To know more about versioning check https://semver.org/.
+
+## How to do a release
+
+### Create the new branch and the release tag
+
+1. Create a new branch `git checkout -b release-` from main
+2. Push the new branch to the remote repository
+
+### Now, let's generate the changelog
+
+1. Create the changelog from the new branch `release-` (`git checkout release-`).
+You will need to use the [kubebuilder-release-tools][kubebuilder-release-tools] to generate the notes. See [here][release-notes-generation]
+
+> **Note**
+> - You will need to have checkout locally from the remote repository the previous branch
+> - Also, ensure that you fetch all tags from the remote `git fetch --all --tags`
+
+### Draft a new release from GitHub
+
+1. Create a new tag with the correct version from the new `release-` branch
+2. Add the changelog on it and publish. Now, the code source is released !
+
+### Add a new Prow test the for the new branch release
+
+1. Create a new prow test under [github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/controller-runtime](https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/controller-runtime)
+for the new `release-` branch. (i.e. for the `0.11.0` release see the PR: https://github.com/kubernetes/test-infra/pull/25205)
+2. Ping the infra PR in the controller-runtime slack channel for reviews.
+
+### Announce the new release:
+
+1. Publish on the Slack channel the new release, i.e:
+
+````
+:announce: Controller-Runtime v0.12.0 has been released!
+This release includes a Kubernetes dependency bump to v1.24.
+For more info, see the release page: https://github.com/kubernetes-sigs/controller-runtime/releases.
+ :tada: Thanks to all our contributors!
+````
+
+2. An announcement email is sent to `kubebuilder@googlegroups.com` with the subject `[ANNOUNCE] Controller-Runtime $VERSION is released`
diff --git a/third_party/sigs.k8s.io/controller-runtime/SECURITY_CONTACTS b/third_party/sigs.k8s.io/controller-runtime/SECURITY_CONTACTS
new file mode 100644
index 00000000000..9c5241c6b42
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/SECURITY_CONTACTS
@@ -0,0 +1,15 @@
+# Defined below are the security contacts for this repo.
+#
+# They are the contact point for the Product Security Team to reach out
+# to for triaging and handling of incoming issues.
+#
+# The below names agree to abide by the
+# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy)
+# and will be removed and replaced if they violate that agreement.
+#
+# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
+# INSTRUCTIONS AT https://kubernetes.io/security/
+
+alvaroaleman
+sbueringer
+vincepri
diff --git a/third_party/sigs.k8s.io/controller-runtime/TMP-LOGGING.md b/third_party/sigs.k8s.io/controller-runtime/TMP-LOGGING.md
new file mode 100644
index 00000000000..97e091fd48a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/TMP-LOGGING.md
@@ -0,0 +1,169 @@
+Logging Guidelines
+==================
+
+controller-runtime uses a kind of logging called *structured logging*. If
+you've used a library like Zap or logrus before, you'll be familiar with
+the concepts we use. If you've only used a logging library like the "log"
+package (in the Go standard library) or "glog" (in Kubernetes), you'll
+need to adjust how you think about logging a bit.
+
+### Getting Started With Structured Logging
+
+With structured logging, we associate a *constant* log message with some
+variable key-value pairs. For instance, suppose we wanted to log that we
+were starting reconciliation on a pod. In the Go standard library logger,
+we might write:
+
+```go
+log.Printf("starting reconciliation for pod %s/%s", podNamespace, podName)
+```
+
+In controller-runtime, we'd instead write:
+
+```go
+logger.Info("starting reconciliation", "pod", req.NamespacedName)
+```
+
+or even write
+
+```go
+func (r *Reconciler) Reconcile(req reconcile.Request) (reconcile.Response, error) {
+ logger := logger.WithValues("pod", req.NamespacedName)
+ // do some stuff
+ logger.Info("starting reconciliation")
+}
+```
+
+Notice how we've broken out the information that we want to convey into
+a constant message (`"starting reconciliation"`) and some key-value pairs
+that convey variable information (`"pod", req.NamespacedName`). We've
+there-by added "structure" to our logs, which makes them easier to save
+and search later, as well as correlate with metrics and events.
+
+All of controller-runtime's logging is done via
+[logr](https://github.com/go-logr/logr), a generic interface for
+structured logging. You can use whichever logging library you want to
+implement the actual mechanics of the logging. controller-runtime
+provides some helpers to make it easy to use
+[Zap](https://go.uber.org/zap) as the implementation.
+
+You can configure the logging implementation using
+`"sigs.k8s.io/controller-runtime/pkg/log".SetLogger`. That
+package also contains the convenience functions for setting up Zap.
+
+You can get a handle to the "root" logger using
+`"sigs.k8s.io/controller-runtime/pkg/log".Log`, and can then call
+`WithName` to create individual named loggers. You can call `WithName`
+repeatedly to chain names together:
+
+```go
+logger := log.Log.WithName("controller").WithName("replicaset")
+// in reconcile...
+logger = logger.WithValues("replicaset", req.NamespacedName)
+// later on in reconcile...
+logger.Info("doing things with pods", "pod", newPod)
+```
+
+As seen above, you can also call `WithValue` to create a new sub-logger
+that always attaches some key-value pairs to a logger.
+
+Finally, you can use `V(1)` to mark a particular log line as "debug" logs:
+
+```go
+logger.V(1).Info("this is particularly verbose!", "state of the world",
+allKubernetesObjectsEverywhere)
+```
+
+While it's possible to use higher log levels, it's recommended that you
+stick with `V(1)` or `V(0)` (which is equivalent to not specifying `V`),
+and then filter later based on key-value pairs or messages; different
+numbers tend to lose meaning easily over time, and you'll be left
+wondering why particular logs lines are at `V(5)` instead of `V(7)`.
+
+## Logging errors
+
+Errors should *always* be logged with `log.Error`, which allows logr
+implementations to provide special handling of errors (for instance,
+providing stack traces in debug mode).
+
+It's acceptable to log call `log.Error` with a nil error object. This
+conveys that an error occurred in some capacity, but that no actual
+`error` object was involved.
+
+Errors returned by the `Reconcile` implementation of the `Reconciler` interface are commonly logged as a `Reconciler error`.
+It's a developer choice to create an additional error log in the `Reconcile` implementation so a more specific file name and line for the error are returned.
+
+## Logging messages
+
+- Don't put variable content in your messages -- use key-value pairs for
+ that. Never use `fmt.Sprintf` in your message.
+
+- Try to match the terminology in your messages with your key-value pairs
+ -- for instance, if you have a key-value pairs `api version`, use the
+ term `APIVersion` instead of `GroupVersion` in your message.
+
+## Logging Kubernetes Objects
+
+Kubernetes objects should be logged directly, like `log.Info("this is
+a Kubernetes object", "pod", somePod)`. controller-runtime provides
+a special encoder for Zap that will transform Kubernetes objects into
+`name, namespace, apiVersion, kind` objects, when available and not in
+development mode. Other logr implementations should implement similar
+logic.
+
+## Logging Structured Values (Key-Value pairs)
+
+- Use lower-case, space separated keys. For example `object` for objects,
+ `api version` for `APIVersion`
+
+- Be consistent across your application, and with controller-runtime when
+ possible.
+
+- Try to be brief but descriptive.
+
+- Match terminology in keys with terminology in the message.
+
+- Be careful logging non-Kubernetes objects verbatim if they're very
+ large.
+
+### Groups, Versions, and Kinds
+
+- Kinds should not be logged alone (they're meaningless alone). Use
+ a `GroupKind` object to log them instead, or a `GroupVersionKind` when
+ version is relevant.
+
+- If you need to log an API version string, use `api version` as the key
+ (formatted as with a `GroupVersion`, or as received directly from API
+ discovery).
+
+### Objects and Types
+
+- If code works with a generic Kubernetes `runtime.Object`, use the
+ `object` key. For specific objects, prefer the resource name as the key
+ (e.g. `pod` for `v1.Pod` objects).
+
+- For non-Kubernetes objects, the `object` key may also be used, if you
+ accept a generic interface.
+
+- When logging a raw type, log it using the `type` key, with a value of
+ `fmt.Sprintf("%T", typ)`
+
+- If there's specific context around a type, the key may be more specific,
+ but should end with `type` -- for instance, `OwnerType` should be logged
+ as `owner` in the context of `log.Error(err, "Could not get ObjectKinds
+ for OwnerType", `owner type`, fmt.Sprintf("%T"))`. When possible, favor
+ communicating kind instead.
+
+### Multiple things
+
+- When logging multiple things, simply pluralize the key.
+
+### controller-runtime Specifics
+
+- Reconcile requests should be logged as `request`, although normal code
+ should favor logging the key.
+
+- Reconcile keys should be logged as with the same key as if you were
+ logging the object directly (e.g. `log.Info("reconciling pod", "pod",
+ req.NamespacedName)`). This ends up having a similar effect to logging
+ the object directly.
diff --git a/third_party/sigs.k8s.io/controller-runtime/VERSIONING.md b/third_party/sigs.k8s.io/controller-runtime/VERSIONING.md
new file mode 100644
index 00000000000..18779000ec2
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/VERSIONING.md
@@ -0,0 +1,30 @@
+# Versioning and Branching in controller-runtime
+
+We follow the [common KubeBuilder versioning guidelines][guidelines], and
+use the corresponding tooling.
+
+For the purposes of the aforementioned guidelines, controller-runtime
+counts as a "library project", but otherwise follows the guidelines
+exactly.
+
+[guidelines]: https://sigs.k8s.io/kubebuilder-release-tools/VERSIONING.md
+
+## Compatiblity and Release Support
+
+For release branches, we generally tend to support backporting one (1)
+major release (`release-{X-1}` or `release-0.{Y-1}`), but may go back
+further if the need arises and is very pressing (e.g. security updates).
+
+### Dependency Support
+
+Note the [guidelines on dependency versions][dep-versions]. Particularly:
+
+- We **DO** guarantee Kubernetes REST API compability -- if a given
+ version of controller-runtime stops working with what should be
+ a supported version of Kubernetes, this is almost certainly a bug.
+
+- We **DO NOT** guarantee any particular compability matrix between
+ kubernetes library dependencies (client-go, apimachinery, etc); Such
+ compability is infeasible due to the way those libraries are versioned.
+
+[dep-versions]: https://sigs.k8s.io/kubebuilder-release-tools/VERSIONING.md#kubernetes-version-compatibility
diff --git a/third_party/sigs.k8s.io/controller-runtime/alias.go b/third_party/sigs.k8s.io/controller-runtime/alias.go
new file mode 100644
index 00000000000..237963889c7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/alias.go
@@ -0,0 +1,156 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controllerruntime
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/builder"
+ "sigs.k8s.io/controller-runtime/pkg/client/config"
+ cfg "sigs.k8s.io/controller-runtime/pkg/config"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/manager/signals"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+// Builder builds an Application ControllerManagedBy (e.g. Operator) and returns a manager.Manager to start it.
+type Builder = builder.Builder
+
+// Request contains the information necessary to reconcile a Kubernetes object. This includes the
+// information to uniquely identify the object - its Name and Namespace. It does NOT contain information about
+// any specific Event or the object contents itself.
+type Request = reconcile.Request
+
+// Result contains the result of a Reconciler invocation.
+type Result = reconcile.Result
+
+// Manager initializes shared dependencies such as Caches and Clients, and provides them to Runnables.
+// A Manager is required to create Controllers.
+type Manager = manager.Manager
+
+// Options are the arguments for creating a new Manager.
+type Options = manager.Options
+
+// SchemeBuilder builds a new Scheme for mapping go types to Kubernetes GroupVersionKinds.
+type SchemeBuilder = scheme.Builder
+
+// GroupVersion contains the "group" and the "version", which uniquely identifies the API.
+type GroupVersion = schema.GroupVersion
+
+// GroupResource specifies a Group and a Resource, but does not force a version. This is useful for identifying
+// concepts during lookup stages without having partially valid types.
+type GroupResource = schema.GroupResource
+
+// TypeMeta describes an individual object in an API response or request
+// with strings representing the type of the object and its API schema version.
+// Structures that are versioned or persisted should inline TypeMeta.
+//
+// +k8s:deepcopy-gen=false
+type TypeMeta = metav1.TypeMeta
+
+// ObjectMeta is metadata that all persisted resources must have, which includes all objects
+// users must create.
+type ObjectMeta = metav1.ObjectMeta
+
+var (
+ // RegisterFlags registers flag variables to the given FlagSet if not already registered.
+ // It uses the default command line FlagSet, if none is provided. Currently, it only registers the kubeconfig flag.
+ RegisterFlags = config.RegisterFlags
+
+ // GetConfigOrDie creates a *rest.Config for talking to a Kubernetes apiserver.
+ // If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running
+ // in cluster and use the cluster provided kubeconfig.
+ //
+ // Will log an error and exit if there is an error creating the rest.Config.
+ GetConfigOrDie = config.GetConfigOrDie
+
+ // GetConfig creates a *rest.Config for talking to a Kubernetes apiserver.
+ // If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running
+ // in cluster and use the cluster provided kubeconfig.
+ //
+ // Config precedence
+ //
+ // * --kubeconfig flag pointing at a file
+ //
+ // * KUBECONFIG environment variable pointing at a file
+ //
+ // * In-cluster config if running in cluster
+ //
+ // * $HOME/.kube/config if exists.
+ GetConfig = config.GetConfig
+
+ // ConfigFile returns the cfg.File function for deferred config file loading,
+ // this is passed into Options{}.From() to populate the Options fields for
+ // the manager.
+ //
+ // Deprecated: This is deprecated in favor of using Options directly.
+ ConfigFile = cfg.File
+
+ // NewControllerManagedBy returns a new controller builder that will be started by the provided Manager.
+ NewControllerManagedBy = builder.ControllerManagedBy
+
+ // NewWebhookManagedBy returns a new webhook builder that will be started by the provided Manager.
+ NewWebhookManagedBy = builder.WebhookManagedBy
+
+ // NewManager returns a new Manager for creating Controllers.
+ NewManager = manager.New
+
+ // CreateOrUpdate creates or updates the given object obj in the Kubernetes
+ // cluster. The object's desired state should be reconciled with the existing
+ // state using the passed in ReconcileFn. obj must be a struct pointer so that
+ // obj can be updated with the content returned by the Server.
+ //
+ // It returns the executed operation and an error.
+ CreateOrUpdate = controllerutil.CreateOrUpdate
+
+ // SetControllerReference sets owner as a Controller OwnerReference on owned.
+ // This is used for garbage collection of the owned object and for
+ // reconciling the owner object on changes to owned (with a Watch + EnqueueRequestForOwner).
+ // Since only one OwnerReference can be a controller, it returns an error if
+ // there is another OwnerReference with Controller flag set.
+ SetControllerReference = controllerutil.SetControllerReference
+
+ // SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned
+ // which is closed on one of these signals. If a second signal is caught, the program
+ // is terminated with exit code 1.
+ SetupSignalHandler = signals.SetupSignalHandler
+
+ // Log is the base logger used by controller-runtime. It delegates
+ // to another logr.Logger. You *must* call SetLogger to
+ // get any actual logging.
+ Log = log.Log
+
+ // LoggerFrom returns a logger with predefined values from a context.Context.
+ // The logger, when used with controllers, can be expected to contain basic information about the object
+ // that's being reconciled like:
+ // - `reconciler group` and `reconciler kind` coming from the For(...) object passed in when building a controller.
+ // - `name` and `namespace` from the reconciliation request.
+ //
+ // This is meant to be used with the context supplied in a struct that satisfies the Reconciler interface.
+ LoggerFrom = log.FromContext
+
+ // LoggerInto takes a context and sets the logger as one of its keys.
+ //
+ // This is meant to be used in reconcilers to enrich the logger within a context with additional values.
+ LoggerInto = log.IntoContext
+
+ // SetLogger sets a concrete logging implementation for all deferred Loggers.
+ SetLogger = log.SetLogger
+)
diff --git a/third_party/sigs.k8s.io/controller-runtime/code-of-conduct.md b/third_party/sigs.k8s.io/controller-runtime/code-of-conduct.md
new file mode 100644
index 00000000000..0d15c00cf32
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/code-of-conduct.md
@@ -0,0 +1,3 @@
+# Kubernetes Community Code of Conduct
+
+Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)
diff --git a/third_party/sigs.k8s.io/controller-runtime/designs/README.md b/third_party/sigs.k8s.io/controller-runtime/designs/README.md
new file mode 100644
index 00000000000..bf8b5000a9a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/designs/README.md
@@ -0,0 +1,36 @@
+Designs
+=======
+
+These are the design documents for changes to Controller Runtime. They
+exist to help document the design processes that go into writing
+Controller Runtime, but may not be up-to-date (more below).
+
+Not all changes to Controller Runtime need a design document -- only major
+ones. Use your best judgement.
+
+When submitting a design document, we encourage having written
+a proof-of-concept, and it's perfectly acceptable to submit the
+proof-of-concept PR simultaneously with the design document, as the
+proof-of-concept process can help iron out wrinkles and can help with the
+`Example` section of the template.
+
+## Out-of-Date Designs
+
+**Controller Runtime documentation
+[GoDoc](https://pkg.go.dev/sigs.k8s.io/controller-runtime) should be
+considered the canonical, update-to-date reference and architectural
+documentation** for Controller Runtime.
+
+However, if you see an out-of-date design document, feel free to submit
+a PR marking it as such, and add an addendum linking to issues documenting
+why things changed. For example:
+
+```markdown
+
+# Out of Date
+
+This change is out of date. It turns out curly braces are frustrating to
+type, so we had to abandon functions entirely, and have users specify
+custom functionality using strings of Common LISP instead. See #000 for
+more information.
+```
diff --git a/third_party/sigs.k8s.io/controller-runtime/designs/component-config.md b/third_party/sigs.k8s.io/controller-runtime/designs/component-config.md
new file mode 100644
index 00000000000..8aebec4f960
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/designs/component-config.md
@@ -0,0 +1,320 @@
+# ComponentConfig Controller Runtime Support
+Author: @christopherhein
+
+Last Updated on: 03/02/2020
+
+## Table of Contents
+
+
+ * [ComponentConfig Controller Runtime Support](#componentconfig-controller-runtime-support)
+ * [Table of Contents](#table-of-contents)
+ * [Summary](#summary)
+ * [Motivation](#motivation)
+ * [Links to Open Issues](#links-to-open-issues)
+ * [Goals](#goals)
+ * [Non-Goals/Future Work](#non-goalsfuture-work)
+ * [Proposal](#proposal)
+ * [ComponentConfig Load Order](#componentconfig-load-order)
+ * [Embeddable ComponentConfig Type](#embeddable-componentconfig-type)
+ * [Default ComponentConfig Type](#default-componentconfig-type)
+ * [Using Flags w/ ComponentConfig](#using-flags-w-componentconfig)
+ * [Kubebuilder Scaffolding Example](#kubebuilder-scaffolding-example)
+ * [User Stories](#user-stories)
+ * [Controller Author with controller-runtime and default type](#controller-author-with-controller-runtime-and-default-type)
+ * [Controller Author with controller-runtime and custom type](#controller-author-with-controller-runtime-and-custom-type)
+ * [Controller Author with kubebuilder (tbd proposal for kubebuilder)](#controller-author-with-kubebuilder-tbd-proposal-for-kubebuilder)
+ * [Controller User without modifications to config](#controller-user-without-modifications-to-config)
+ * [Controller User with modifications to config](#controller-user-with-modifications-to-config)
+ * [Risks and Mitigations](#risks-and-mitigations)
+ * [Alternatives](#alternatives)
+ * [Implementation History](#implementation-history)
+
+
+
+## Summary
+
+Currently controllers that use `controller-runtime` need to configure the `ctrl.Manager` by using flags or hardcoding values into the initialization methods. Core Kubernetes has started to move away from using flags as a mechanism for configuring components and standardized on [`ComponentConfig` or Versioned Component Configuration Files](https://docs.google.com/document/d/1FdaEJUEh091qf5B98HM6_8MS764iXrxxigNIdwHYW9c/edit). This proposal is to bring `ComponentConfig` to `controller-runtime` to allow controller authors to make `go` types backed by `apimachinery` to unmarshal and configure the `ctrl.Manager{}` reducing the flags and allowing code based tools to easily configure controllers instead of requiring them to mutate CLI args.
+
+## Motivation
+
+This change is important because:
+- it will help make it easier for controllers to be configured by other machine processes
+- it will reduce the required flags required to start a controller
+- allow for configuration types which aren't natively supported by flags
+- allow using and upgrading older configurations avoiding breaking changes in flags
+
+### Links to Open Issues
+
+- [#518 Provide a ComponentConfig to tweak the Manager](https://github.com/kubernetes-sigs/controller-runtime/issues/518)
+- [#207 Reduce command line flag boilerplate](https://github.com/kubernetes-sigs/controller-runtime/issues/207)
+- [#722 Implement ComponentConfig by default & stop using (most) flags](https://github.com/kubernetes-sigs/kubebuilder/issues/722)
+
+### Goals
+
+- Provide an interface for pulling configuration data out of exposed `ComponentConfig` types (see below for implementation)
+- Provide a new `ctrl.NewFromComponentConfig()` function for initializing a manager
+- Provide an embeddable `ControllerManagerConfiguration` type for easily authoring `ComponentConfig` types
+- Provide an `DefaultControllerConfig` to make the switching easier for clients
+
+### Non-Goals/Future Work
+
+- `kubebuilder` implementation and design in another PR
+- Changing the default `controller-runtime` implementation
+- Dynamically reloading `ComponentConfig` object
+- Providing `flags` interface and overrides
+
+## Proposal
+
+The `ctrl.Manager` _SHOULD_ support loading configurations from `ComponentConfig` like objects.
+An interface for that object with getters for the specific configuration parameters is created to bridge existing patterns.
+
+Without breaking the current `ctrl.NewManager` which uses an exported `ctrl.Options{}` the `manager.go` can expose a new func, `NewFromComponentConfig()` this would be able to loop through the getters to populate an internal `ctrl.Options{}` and pass that into `New()`.
+
+```golang
+//pkg/manager/manager.go
+
+// ManagerConfiguration defines what the ComponentConfig object for ControllerRuntime needs to support
+type ManagerConfiguration interface {
+ GetSyncPeriod() *time.Duration
+
+ GetLeaderElection() bool
+ GetLeaderElectionNamespace() string
+ GetLeaderElectionID() string
+
+ GetLeaseDuration() *time.Duration
+ GetRenewDeadline() *time.Duration
+ GetRetryPeriod() *time.Duration
+
+ GetNamespace() string
+ GetMetricsBindAddress() string
+ GetHealthProbeBindAddress() string
+
+ GetReadinessEndpointName() string
+ GetLivenessEndpointName() string
+
+ GetPort() int
+ GetHost() string
+
+ GetCertDir() string
+}
+
+func NewFromComponentConfig(config *rest.Config, scheme *runtime.Scheme, filename string, managerconfig ManagerConfiguration) (Manager, error) {
+ codecs := serializer.NewCodecFactory(scheme)
+ if err := decodeComponentConfigFileInto(codecs, filename, managerconfig); err != nil {
+
+ }
+ options := Options{}
+
+ if scheme != nil {
+ options.Scheme = scheme
+ }
+
+ // Loop through getters
+ if managerconfig.GetLeaderElection() {
+ options.LeaderElection = managerconfig.GetLeaderElection()
+ }
+ // ...
+
+ return New(config, options)
+}
+```
+
+#### ComponentConfig Load Order
+
+
+
+#### Embeddable ComponentConfig Type
+
+To make this easier for Controller authors `controller-runtime` can expose a set of `config.ControllerConfiguration` type that can be embedded similar to the way that `k8s.io/apimachinery/pkg/apis/meta/v1` works for `TypeMeta` and `ObjectMeta` these could live in `pkg/api/config/v1alpha1/types.go`. See the `DefaultComponentConfig` type below for and example implementation.
+
+```golang
+// pkg/api/config/v1alpha1/types.go
+package v1alpha1
+
+import (
+ "time"
+
+ configv1alpha1 "k8s.io/component-base/config/v1alpha1"
+)
+
+// ControllerManagerConfiguration defines the embedded RuntimeConfiguration for controller-runtime clients.
+type ControllerManagerConfiguration struct {
+ Namespace string `json:"namespace,omitempty"`
+
+ SyncPeriod *time.Duration `json:"syncPeriod,omitempty"`
+
+ LeaderElection configv1alpha1.LeaderElectionConfiguration `json:"leaderElection,omitempty"`
+
+ MetricsBindAddress string `json:"metricsBindAddress,omitempty"`
+
+ Health ControllerManagerConfigurationHealth `json:"health,omitempty"`
+
+ Port *int `json:"port,omitempty"`
+ Host string `json:"host,omitempty"`
+
+ CertDir string `json:"certDir,omitempty"`
+}
+
+// ControllerManagerConfigurationHealth defines the health configs
+type ControllerManagerConfigurationHealth struct {
+ HealthProbeBindAddress string `json:"healthProbeBindAddress,omitempty"`
+
+ ReadinessEndpointName string `json:"readinessEndpointName,omitempty"`
+ LivenessEndpointName string `json:"livenessEndpointName,omitempty"`
+}
+```
+
+
+
+#### Default ComponentConfig Type
+
+To enable `controller-runtime` to have a default `ComponentConfig` struct which can be used instead of requiring each controller or extension to build its own `ComponentConfig` type, we can create a `DefaultControllerConfiguration` type which can exist in `pkg/api/config/v1alpha1/types.go`. This will allow the controller authors to use this before needing to implement their own type with additional configs.
+
+```golang
+// pkg/api/config/v1alpha1/types.go
+package v1alpha1
+
+import (
+ "time"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ configv1alpha1 "sigs.k8s.io/controller-runtime/pkg/apis/config/v1alpha1"
+)
+
+// DefaultControllerManagerConfiguration is the Schema for the DefaultControllerManagerConfigurations API
+type DefaultControllerManagerConfiguration struct {
+ metav1.TypeMeta `json:",inline"`
+
+ Spec configv1alpha1.ControllerManagerConfiguration `json:"spec,omitempty"`
+}
+```
+
+This would allow a controller author to use this struct with any config that supports the json/yaml structure. For example a controller author could define their `Kind` as `FoobarControllerConfiguration` and have it defined as the following.
+
+```yaml
+# config.yaml
+apiVersion: config.somedomain.io/v1alpha1
+kind: FoobarControllerManagerConfiguration
+spec:
+ port: 9443
+ metricsBindAddress: ":8080"
+ leaderElection:
+ leaderElect: false
+```
+
+Given the following config and `DefaultControllerManagerConfiguration` we'd be able to initialize the controller using the following.
+
+
+```golang
+mgr, err := ctrl.NewManagerFromComponentConfig(ctrl.GetConfigOrDie(), scheme, configname, &defaultv1alpha1.DefaultControllerManagerConfiguration{})
+if err != nil {
+ // ...
+}
+```
+
+The above example uses `configname` which is the name of the file to load the configuration from and uses `scheme` to get the specific serializer, eg `serializer.NewCodecFactory(scheme)`. This will allow the configuration to be unmarshalled into the `runtime.Object` type and passed into the
+`ctrl.NewManagerFromComponentConfig()` as a `ManagerConfiguration` interface.
+
+#### Using Flags w/ ComponentConfig
+
+Since this design still requires setting up the initial `ComponentConfig` type and passing in a pointer to `ctrl.NewFromComponentConfig()` if you want to allow for the use of flags, your controller can use any of the different flagging interfaces. eg [`flag`](https://golang.org/pkg/flag/), [`pflag`](https://pkg.go.dev/github.com/spf13/pflag), [`flagnum`](https://pkg.go.dev/github.com/luci/luci-go/common/flag/flagenum) and set values on the `ComponentConfig` type prior to passing the pointer into the `ctrl.NewFromComponentConfig()`, example below.
+
+```golang
+leaderElect := true
+
+config := &defaultv1alpha1.DefaultControllerManagerConfiguration{
+ Spec: configv1alpha1.ControllerManagerConfiguration{
+ LeaderElection: configv1alpha1.LeaderElectionConfiguration{
+ LeaderElect: &leaderElect,
+ },
+ },
+}
+mgr, err := ctrl.NewManagerFromComponentConfig(ctrl.GetConfigOrDie(), scheme, configname, config)
+if err != nil {
+ // ...
+}
+```
+
+#### Kubebuilder Scaffolding Example
+
+Within expanded in a separate design _(link once created)_ this will allow controller authors to generate a type that implements the `ManagerConfiguration` interface. The following is a sample of what this looks like:
+
+```golang
+package config
+
+import (
+ "time"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ configv1alpha1 "sigs.k8s.io/controller-runtime/pkg/apis/config/v1alpha1"
+)
+
+type ControllerNameConfigurationSpec struct {
+ configv1alpha1.ControllerManagerConfiguration `json:",inline"`
+}
+
+type ControllerNameConfiguration struct {
+ metav1.TypeMeta
+
+ Spec ControllerNameConfigurationSpec `json:"spec"`
+}
+```
+
+Usage of this custom `ComponentConfig` type would require then changing the `ctrl.NewFromComponentConfig()` to use the new struct vs the `DefaultControllerManagerConfiguration`.
+
+## User Stories
+
+### Controller Author with `controller-runtime` and default type
+
+- Mount `ConfigMap`
+- Initialize `ctrl.Manager` with `NewFromComponentConfig` with config name and `DefaultControllerManagerConfiguration` type
+- Build custom controller as usual
+
+### Controller Author with `controller-runtime` and custom type
+
+- Implement `ComponentConfig` type
+- Embed `ControllerManagerConfiguration` type
+- Mount `ConfigMap`
+- Initialize `ctrl.Manager` with `NewFromComponentConfig` with config name and `ComponentConfig` type
+- Build custom controller as usual
+
+### Controller Author with `kubebuilder` (tbd proposal for `kubebuilder`)
+
+- Initialize `kubebuilder` project using `--component-config-name=XYZConfiguration`
+- Build custom controller as usual
+
+### Controller User without modifications to config
+
+_Provided that the controller provides manifests_
+
+- Apply the controller to the cluster
+- Deploy custom resources
+
+### Controller User with modifications to config
+
+- _Following from previous example without changes_
+- Create a new `ConfigMap` for changes
+- Modify the `controller-runtime` pod to use the new `ConfigMap`
+- Apply the controller to the cluster
+- Deploy custom resources
+
+
+## Risks and Mitigations
+
+- Given that this isn't changing the core Manager initialization for `controller-runtime` it's fairly low risk
+
+## Alternatives
+
+* `NewFromComponentConfig()` could load the object from disk based on the file name and hydrate the `ComponentConfig` type.
+
+## Implementation History
+
+- [x] 02/19/2020: Proposed idea in an issue or [community meeting]
+- [x] 02/24/2020: Proposal submitted to `controller-runtime`
+- [x] 03/02/2020: Updated with default `DefaultControllerManagerConfiguration`
+- [x] 03/04/2020: Updated with embeddable `RuntimeConfig`
+- [x] 03/10/2020: Updated embeddable name to `ControllerManagerConfiguration`
+
+
+
+[community meeting]: https://docs.google.com/document/d/1Ih-2cgg1bUrLwLVTB9tADlPcVdgnuMNBGbUl4D-0TIk
diff --git a/third_party/sigs.k8s.io/controller-runtime/designs/images/component-config-load.png b/third_party/sigs.k8s.io/controller-runtime/designs/images/component-config-load.png
new file mode 100644
index 00000000000..04619779dad
Binary files /dev/null and b/third_party/sigs.k8s.io/controller-runtime/designs/images/component-config-load.png differ
diff --git a/third_party/sigs.k8s.io/controller-runtime/designs/move-cluster-specific-code-out-of-manager.md b/third_party/sigs.k8s.io/controller-runtime/designs/move-cluster-specific-code-out-of-manager.md
new file mode 100644
index 00000000000..67b7a419a54
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/designs/move-cluster-specific-code-out-of-manager.md
@@ -0,0 +1,228 @@
+Move cluster-specific code out of the manager
+===================
+
+## Motivation
+
+Today, it is already possible to use controller-runtime to build controllers that act on
+more than one cluster. However, this is undocumented and not straight-forward, requiring
+users to look into the implementation details to figure out how to make this work.
+
+## Goals
+
+* Provide an easy-to-discover way to build controllers that act on multiple clusters
+* Decouple the management of `Runnables` from the construction of "things that require a kubeconfig"
+* Do not introduce changes for users that build controllers that act on one cluster only
+
+## Non-Goals
+
+## Proposal
+
+Currently, the `./pkg/manager.Manager` has two purposes:
+
+* Handle running controllers/other runnables and managing their lifecycle
+* Setting up various things to interact with the Kubernetes cluster,
+ for example a `Client` and a `Cache`
+
+This works very well when building controllers that talk to a single cluster,
+however some use-cases require controllers that interact with more than
+one cluster. This multi-cluster usecase is very awkward today, because it
+requires to construct one manager per cluster and adding all subsequent
+managers to the first one.
+
+This document proposes to move all cluster-specific code out of the manager
+and into a new package and interface, that then gets embedded into the manager.
+This allows to keep the usage for single-cluster cases the same and introduce
+this change in a backwards-compatible manner.
+
+Furthermore, the manager gets extended to start all caches before any other
+`runnables` are started.
+
+
+The new `Cluster` interface will look like this:
+
+```go
+type Cluster interface {
+ // SetFields will set cluster-specific dependencies on an object for which the object has implemented the inject
+ // interface, specifically inject.Client, inject.Cache, inject.Scheme, inject.Config and inject.APIReader
+ SetFields(interface{}) error
+
+ // GetConfig returns an initialized Config
+ GetConfig() *rest.Config
+
+ // GetClient returns a client configured with the Config. This client may
+ // not be a fully "direct" client -- it may read from a cache, for
+ // instance. See Options.NewClient for more information on how the default
+ // implementation works.
+ GetClient() client.Client
+
+ // GetFieldIndexer returns a client.FieldIndexer configured with the client
+ GetFieldIndexer() client.FieldIndexer
+
+ // GetCache returns a cache.Cache
+ GetCache() cache.Cache
+
+ // GetEventRecorderFor returns a new EventRecorder for the provided name
+ GetEventRecorderFor(name string) record.EventRecorder
+
+ // GetRESTMapper returns a RESTMapper
+ GetRESTMapper() meta.RESTMapper
+
+ // GetAPIReader returns a reader that will be configured to use the API server.
+ // This should be used sparingly and only when the client does not fit your
+ // use case.
+ GetAPIReader() client.Reader
+
+ // GetScheme returns an initialized Scheme
+ GetScheme() *runtime.Scheme
+
+ // Start starts the connection tothe Cluster
+ Start(<-chan struct{}) error
+}
+```
+
+And the current `Manager` interface will change to look like this:
+
+```go
+type Manager interface {
+ // Cluster holds objects to connect to a cluster
+ cluser.Cluster
+
+ // Add will set requested dependencies on the component, and cause the component to be
+ // started when Start is called. Add will inject any dependencies for which the argument
+ // implements the inject interface - e.g. inject.Client.
+ // Depending on if a Runnable implements LeaderElectionRunnable interface, a Runnable can be run in either
+ // non-leaderelection mode (always running) or leader election mode (managed by leader election if enabled).
+ Add(Runnable) error
+
+ // Elected is closed when this manager is elected leader of a group of
+ // managers, either because it won a leader election or because no leader
+ // election was configured.
+ Elected() <-chan struct{}
+
+ // SetFields will set any dependencies on an object for which the object has implemented the inject
+ // interface - e.g. inject.Client.
+ SetFields(interface{}) error
+
+ // AddMetricsExtraHandler adds an extra handler served on path to the http server that serves metrics.
+ // Might be useful to register some diagnostic endpoints e.g. pprof. Note that these endpoints meant to be
+ // sensitive and shouldn't be exposed publicly.
+ // If the simple path -> handler mapping offered here is not enough, a new http server/listener should be added as
+ // Runnable to the manager via Add method.
+ AddMetricsExtraHandler(path string, handler http.Handler) error
+
+ // AddHealthzCheck allows you to add Healthz checker
+ AddHealthzCheck(name string, check healthz.Checker) error
+
+ // AddReadyzCheck allows you to add Readyz checker
+ AddReadyzCheck(name string, check healthz.Checker) error
+
+ // Start starts all registered Controllers and blocks until the Stop channel is closed.
+ // Returns an error if there is an error starting any controller.
+ // If LeaderElection is used, the binary must be exited immediately after this returns,
+ // otherwise components that need leader election might continue to run after the leader
+ // lock was lost.
+ Start(<-chan struct{}) error
+
+ // GetWebhookServer returns a webhook.Server
+ GetWebhookServer() *webhook.Server
+}
+```
+
+Furthermore, during startup, the `Manager` will use type assertion to find `Cluster`s
+to be able to start their caches before anything else:
+
+```go
+type HasCaches interface {
+ GetCache()
+}
+if getter, hasCaches := runnable.(HasCaches); hasCaches {
+ m.caches = append(m.caches, getter())
+}
+```
+
+```go
+for idx := range cm.caches {
+ go func(idx int) {cm.caches[idx].Start(cm.internalStop)}
+}
+
+for _, cache := range cm.caches {
+ cache.WaitForCacheSync(cm.internalStop)
+}
+
+// Start all other runnables
+```
+
+## Example
+
+Below is a sample `reconciler` that will create a secret in a `mirrorCluster` for each
+secret found in `referenceCluster` if none of that name already exists. To keep the sample
+short, it won't compare the contents of the secrets.
+
+```go
+type secretMirrorReconciler struct {
+ referenceClusterClient, mirrorClusterClient client.Client
+}
+
+func (r *secretMirrorReconciler) Reconcile(r reconcile.Request)(reconcile.Result, error){
+ s := &corev1.Secret{}
+ if err := r.referenceClusterClient.Get(context.TODO(), r.NamespacedName, s); err != nil {
+ if kerrors.IsNotFound{ return reconcile.Result{}, nil }
+ return reconcile.Result, err
+ }
+
+ if err := r.mirrorClusterClient.Get(context.TODO(), r.NamespacedName, &corev1.Secret); err != nil {
+ if !kerrors.IsNotFound(err) {
+ return reconcile.Result{}, err
+ }
+
+ mirrorSecret := &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{Namespace: s.Namespace, Name: s.Name},
+ Data: s.Data,
+ }
+ return reconcile.Result{}, r.mirrorClusterClient.Create(context.TODO(), mirrorSecret)
+ }
+
+ return nil
+}
+
+func NewSecretMirrorReconciler(mgr manager.Manager, mirrorCluster cluster.Cluster) error {
+ return ctrl.NewControllerManagedBy(mgr).
+ // Watch Secrets in the reference cluster
+ For(&corev1.Secret{}).
+ // Watch Secrets in the mirror cluster
+ Watches(
+ source.NewKindWithCache(&corev1.Secret{}, mirrorCluster.GetCache()),
+ &handler.EnqueueRequestForObject{},
+ ).
+ Complete(&secretMirrorReconciler{
+ referenceClusterClient: mgr.GetClient(),
+ mirrorClusterClient: mirrorCluster.GetClient(),
+ })
+ }
+}
+
+func main(){
+
+ mgr, err := manager.New( cfg1, manager.Options{})
+ if err != nil {
+ panic(err)
+ }
+
+ mirrorCluster, err := cluster.New(cfg2)
+ if err != nil {
+ panic(err)
+ }
+
+ if err := mgr.Add(mirrorCluster); err != nil {
+ panic(err)
+ }
+
+ if err := NewSecretMirrorReconciler(mgr, mirrorCluster); err != nil {
+ panic(err)
+ }
+
+ if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+ panic(err)
+ }
+}
+```
diff --git a/third_party/sigs.k8s.io/controller-runtime/designs/template.md b/third_party/sigs.k8s.io/controller-runtime/designs/template.md
new file mode 100644
index 00000000000..c04d6e0c71d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/designs/template.md
@@ -0,0 +1,21 @@
+Title of the Design
+===================
+
+
+
+## Example
+
+
\ No newline at end of file
diff --git a/third_party/sigs.k8s.io/controller-runtime/designs/use-selectors-at-cache.md b/third_party/sigs.k8s.io/controller-runtime/designs/use-selectors-at-cache.md
new file mode 100644
index 00000000000..1d7ec6ecfb5
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/designs/use-selectors-at-cache.md
@@ -0,0 +1,122 @@
+# Filter cache ListWatch using selectors
+
+## Motivation
+
+Controller-Runtime controllers use a cache to subscribe to events from
+Kubernetes objects and to read those objects more efficiently by avoiding
+to call out to the API. This cache is backed by Kubernetes informers.
+
+The only way to filter this cache is by namespace and resource type.
+In cases where a controller is only interested in a small subset of objects
+(for example all pods on a node), this might end up not being efficient enough.
+
+Requests to a client backed by a filtered cache for objects that do not match
+the filter will never return anything, so we need to make sure that we properly
+warn users to only use this when they are sure they know what they are doing.
+
+This proposal sidesteps the issue of "How to we plug this into the cache-backed
+client so that users get feedback when they request something that is
+not matching the caches filter" by only implementing the filter logic in the
+cache package. This allows advanced users to combine a filtered cache with the
+already existing `NewCacheFunc` option in the manager and cluster package,
+while simultaneously hiding it from newer users that might not be aware of the
+implications and the associated foot-shoot potential.
+
+The only alternative today to get a filtered cache with controller-runtime is
+to build it out-of tree. Because such a cache would mostly copy the existing
+cache and add just some options, this is not great for consumers.
+
+This proposal is related to the following issue [2]
+
+## Proposal
+
+Add a new selector code at `pkg/cache/internal/selector.go` with common structs
+and helpers
+
+```golang
+package internal
+
+...
+
+// SelectorsByObject associate a runtime.Object to a field/label selector
+type SelectorsByObject map[client.Object]Selector
+
+// SelectorsByGVK associate a GroupVersionResource to a field/label selector
+type SelectorsByGVK map[schema.GroupVersionKind]Selector
+
+// Selector specify the label/field selector to fill in ListOptions
+type Selector struct {
+ Label labels.Selector
+ Field fields.Selector
+}
+
+// ApplyToList fill in ListOptions LabelSelector and FieldSelector if needed
+func (s Selector) ApplyToList(listOpts *metav1.ListOptions) {
+...
+}
+```
+
+Add a type alias to `pkg/cache/cache.go` to internal
+
+```golang
+type SelectorsByObject internal.SelectorsByObject
+```
+
+Extend `cache.Options` as follows:
+
+```golang
+type Options struct {
+ Scheme *runtime.Scheme
+ Mapper meta.RESTMapper
+ Resync *time.Duration
+ Namespace string
+ SelectorsByObject SelectorsByObject
+}
+```
+
+Add new builder function that will return a cache constructor using the passed
+cache.Options, users can set SelectorsByObject there to filter out cache, it
+will convert SelectorByObject to SelectorsByGVK
+
+```golang
+func BuilderWithOptions(options cache.Options) NewCacheFunc {
+...
+}
+```
+
+is passed to informer's ListWatch and add the filtering option:
+
+```golang
+
+# At pkg/cache/internal/informers_map.go
+
+ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
+ ip.selectors[gvk].ApplyToList(&opts)
+...
+```
+
+Here is a PR with the implementatin at the `pkg/cache` part [3]
+
+## Example
+
+User will override `NewCache` function to make clear that they know exactly the
+implications of using a different cache than the default one
+
+```golang
+ ctrl.Options.NewCache = cache.BuilderWithOptions(cache.Options{
+ SelectorsByObject: cache.SelectorsByObject{
+ &corev1.Node{}: {
+ Field: fields.SelectorFromSet(fields.Set{"metadata.name": "node01"}),
+ }
+ &v1beta1.NodeNetworkState{}: {
+ Field: fields.SelectorFromSet(fields.Set{"metadata.name": "node01"}),
+ Label: labels.SelectorFromSet(labels.Set{"app": "kubernetes-nmstate})",
+ }
+ }
+ }
+ )
+```
+
+[1] https://github.com/nmstate/kubernetes-nmstate/pull/687
+[2] https://github.com/kubernetes-sigs/controller-runtime/issues/244
+[3] https://github.com/kubernetes-sigs/controller-runtime/pull/1404
diff --git a/third_party/sigs.k8s.io/controller-runtime/doc.go b/third_party/sigs.k8s.io/controller-runtime/doc.go
new file mode 100644
index 00000000000..0319bc3ff86
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/doc.go
@@ -0,0 +1,128 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package controllerruntime provides tools to construct Kubernetes-style
+// controllers that manipulate both Kubernetes CRDs and aggregated/built-in
+// Kubernetes APIs.
+//
+// It defines easy helpers for the common use cases when building CRDs, built
+// on top of customizable layers of abstraction. Common cases should be easy,
+// and uncommon cases should be possible. In general, controller-runtime tries
+// to guide users towards Kubernetes controller best-practices.
+//
+// # Getting Started
+//
+// The main entrypoint for controller-runtime is this root package, which
+// contains all of the common types needed to get started building controllers:
+//
+// import (
+// ctrl "sigs.k8s.io/controller-runtime"
+// )
+//
+// The examples in this package walk through a basic controller setup. The
+// kubebuilder book (https://book.kubebuilder.io) has some more in-depth
+// walkthroughs.
+//
+// controller-runtime favors structs with sane defaults over constructors, so
+// it's fairly common to see structs being used directly in controller-runtime.
+//
+// # Organization
+//
+// A brief-ish walkthrough of the layout of this library can be found below. Each
+// package contains more information about how to use it.
+//
+// Frequently asked questions about using controller-runtime and designing
+// controllers can be found at
+// https://github.com/kubernetes-sigs/controller-runtime/blob/main/FAQ.md.
+//
+// # Managers
+//
+// Every controller and webhook is ultimately run by a Manager (pkg/manager). A
+// manager is responsible for running controllers and webhooks, and setting up
+// common dependencies, like shared caches and clients, as
+// well as managing leader election (pkg/leaderelection). Managers are
+// generally configured to gracefully shut down controllers on pod termination
+// by wiring up a signal handler (pkg/manager/signals).
+//
+// # Controllers
+//
+// Controllers (pkg/controller) use events (pkg/event) to eventually trigger
+// reconcile requests. They may be constructed manually, but are often
+// constructed with a Builder (pkg/builder), which eases the wiring of event
+// sources (pkg/source), like Kubernetes API object changes, to event handlers
+// (pkg/handler), like "enqueue a reconcile request for the object owner".
+// Predicates (pkg/predicate) can be used to filter which events actually
+// trigger reconciles. There are pre-written utilities for the common cases, and
+// interfaces and helpers for advanced cases.
+//
+// # Reconcilers
+//
+// Controller logic is implemented in terms of Reconcilers (pkg/reconcile). A
+// Reconciler implements a function which takes a reconcile Request containing
+// the name and namespace of the object to reconcile, reconciles the object,
+// and returns a Response or an error indicating whether to requeue for a
+// second round of processing.
+//
+// # Clients and Caches
+//
+// Reconcilers use Clients (pkg/client) to access API objects. The default
+// client provided by the manager reads from a local shared cache (pkg/cache)
+// and writes directly to the API server, but clients can be constructed that
+// only talk to the API server, without a cache. The Cache will auto-populate
+// with watched objects, as well as when other structured objects are
+// requested. The default split client does not promise to invalidate the cache
+// during writes (nor does it promise sequential create/get coherence), and code
+// should not assume a get immediately following a create/update will return
+// the updated resource. Caches may also have indexes, which can be created via
+// a FieldIndexer (pkg/client) obtained from the manager. Indexes can used to
+// quickly and easily look up all objects with certain fields set. Reconcilers
+// may retrieve event recorders (pkg/recorder) to emit events using the
+// manager.
+//
+// # Schemes
+//
+// Clients, Caches, and many other things in Kubernetes use Schemes
+// (pkg/scheme) to associate Go types to Kubernetes API Kinds
+// (Group-Version-Kinds, to be specific).
+//
+// # Webhooks
+//
+// Similarly, webhooks (pkg/webhook/admission) may be implemented directly, but
+// are often constructed using a builder (pkg/webhook/admission/builder). They
+// are run via a server (pkg/webhook) which is managed by a Manager.
+//
+// # Logging and Metrics
+//
+// Logging (pkg/log) in controller-runtime is done via structured logs, using a
+// log set of interfaces called logr
+// (https://pkg.go.dev/github.com/go-logr/logr). While controller-runtime
+// provides easy setup for using Zap (https://go.uber.org/zap, pkg/log/zap),
+// you can provide any implementation of logr as the base logger for
+// controller-runtime.
+//
+// Metrics (pkg/metrics) provided by controller-runtime are registered into a
+// controller-runtime-specific Prometheus metrics registry. The manager can
+// serve these by an HTTP endpoint, and additional metrics may be registered to
+// this Registry as normal.
+//
+// # Testing
+//
+// You can easily build integration and unit tests for your controllers and
+// webhooks using the test Environment (pkg/envtest). This will automatically
+// stand up a copy of etcd and kube-apiserver, and provide the correct options
+// to connect to the API server. It's designed to work well with the Ginkgo
+// testing framework, but should work with any testing setup.
+package controllerruntime
diff --git a/third_party/sigs.k8s.io/controller-runtime/example_test.go b/third_party/sigs.k8s.io/controller-runtime/example_test.go
new file mode 100644
index 00000000000..381959d5bb5
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/example_test.go
@@ -0,0 +1,145 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controllerruntime_test
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "time"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ // since we invoke tests with -ginkgo.junit-report we need to import ginkgo.
+ _ "github.com/onsi/ginkgo/v2"
+)
+
+// This example creates a simple application Controller that is configured for ReplicaSets and Pods.
+//
+// * Create a new application for ReplicaSets that manages Pods owned by the ReplicaSet and calls into
+// ReplicaSetReconciler.
+//
+// * Start the application.
+func Example() {
+ var log = ctrl.Log.WithName("builder-examples")
+
+ manager, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{})
+ if err != nil {
+ log.Error(err, "could not create manager")
+ os.Exit(1)
+ }
+
+ err = ctrl.
+ NewControllerManagedBy(manager). // Create the Controller
+ For(&appsv1.ReplicaSet{}). // ReplicaSet is the Application API
+ Owns(&corev1.Pod{}). // ReplicaSet owns Pods created by it
+ Complete(&ReplicaSetReconciler{Client: manager.GetClient()})
+ if err != nil {
+ log.Error(err, "could not create controller")
+ os.Exit(1)
+ }
+
+ if err := manager.Start(ctrl.SetupSignalHandler()); err != nil {
+ log.Error(err, "could not start manager")
+ os.Exit(1)
+ }
+}
+
+// This example creates a simple application Controller that is configured for ReplicaSets and Pods.
+// This application controller will be running leader election with the provided configuration in the manager options.
+// If leader election configuration is not provided, controller runs leader election with default values.
+// Default values taken from: https://github.com/kubernetes/component-base/blob/master/config/v1alpha1/defaults.go
+// * defaultLeaseDuration = 15 * time.Second
+// * defaultRenewDeadline = 10 * time.Second
+// * defaultRetryPeriod = 2 * time.Second
+//
+// * Create a new application for ReplicaSets that manages Pods owned by the ReplicaSet and calls into
+// ReplicaSetReconciler.
+//
+// * Start the application.
+func Example_updateLeaderElectionDurations() {
+ var log = ctrl.Log.WithName("builder-examples")
+ leaseDuration := 100 * time.Second
+ renewDeadline := 80 * time.Second
+ retryPeriod := 20 * time.Second
+ manager, err := ctrl.NewManager(
+ ctrl.GetConfigOrDie(),
+ ctrl.Options{
+ LeaseDuration: &leaseDuration,
+ RenewDeadline: &renewDeadline,
+ RetryPeriod: &retryPeriod,
+ })
+ if err != nil {
+ log.Error(err, "could not create manager")
+ os.Exit(1)
+ }
+
+ err = ctrl.
+ NewControllerManagedBy(manager). // Create the Controller
+ For(&appsv1.ReplicaSet{}). // ReplicaSet is the Application API
+ Owns(&corev1.Pod{}). // ReplicaSet owns Pods created by it
+ Complete(&ReplicaSetReconciler{Client: manager.GetClient()})
+ if err != nil {
+ log.Error(err, "could not create controller")
+ os.Exit(1)
+ }
+
+ if err := manager.Start(ctrl.SetupSignalHandler()); err != nil {
+ log.Error(err, "could not start manager")
+ os.Exit(1)
+ }
+}
+
+// ReplicaSetReconciler is a simple Controller example implementation.
+type ReplicaSetReconciler struct {
+ client.Client
+}
+
+// Implement the business logic:
+// This function will be called when there is a change to a ReplicaSet or a Pod with an OwnerReference
+// to a ReplicaSet.
+//
+// * Read the ReplicaSet
+// * Read the Pods
+// * Set a Label on the ReplicaSet with the Pod count.
+func (a *ReplicaSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+ // Read the ReplicaSet
+ rs := &appsv1.ReplicaSet{}
+ err := a.Get(ctx, req.NamespacedName, rs)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ // List the Pods matching the PodTemplate Labels
+ pods := &corev1.PodList{}
+ err = a.List(ctx, pods, client.InNamespace(req.Namespace), client.MatchingLabels(rs.Spec.Template.Labels))
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ // Update the ReplicaSet
+ rs.Labels["pod-count"] = fmt.Sprintf("%v", len(pods.Items))
+ err = a.Update(ctx, rs)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ return ctrl.Result{}, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/README.md b/third_party/sigs.k8s.io/controller-runtime/examples/README.md
new file mode 100644
index 00000000000..2110ae214ea
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/README.md
@@ -0,0 +1,36 @@
+# Examples
+
+These two examples represent the usage of `controller-runtime` libraries for built-in Kubernetes resources as well as custom resources.
+
+### builtins/
+
+This example implements a custom controller and webhooks for the *existing* ReplicaSet resource.
+
+* `controller.go`: implements a reconciler for ReplicaSets
+* `mutatingwebhook.go`: implements a mutating webhook that adds an annotation to every incoming Pod ("example-mutating-admission-webhook" = "foo")
+* `validatingwebhook.go`: implements a validating webhook that checks to see if a Pod has the aforementioned annotation
+* `main.go`
+ 1. Creates a new manager
+ 2. Creates a new controller that watches both ReplicaSets and Pods and reconciles the objects with the implemented reconciler
+ 3. Registers the mutating and validating webhooks with the manager
+ 4. Starts the manager
+
+### crd/
+
+This example implements a *new* Kubernetes resource, ChaosPod, and creates a custom controller that watches it and webhooks that mutate and validate.
+
+* `pkg/`
+ * `resource.go`: defines the schema for the ChaosPod API and implements validate and mutate webhooks
+ * `groupversion_info.go`: specifies the Group and Version for the ChaosPod API
+ * `zz_generated.deepcopy.go`: deep copy functions generated by kubebuilder
+* `main.go`
+ 1. Creates a new manager
+ 2. Adds ChaosPod resource to the manager's schema
+ 3. Implements a reconciler to execute the desired behavior of the ChaosPod API
+ 4. Creates a new controller that watches ChaosPods and reconciles the objects with the implemented reconciler
+ 5. Adds ChaosPod webhooks to manager
+ 6. Starts the manager
+
+## Deploying and Running
+
+To install and run the provided examples, see the Kubebuilder [Quick Start](https://book.kubebuilder.io/quick-start.html).
\ No newline at end of file
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/builtins/controller.go b/third_party/sigs.k8s.io/controller-runtime/examples/builtins/controller.go
new file mode 100644
index 00000000000..6c8c5d935ff
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/builtins/controller.go
@@ -0,0 +1,74 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "context"
+ "fmt"
+
+ appsv1 "k8s.io/api/apps/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+// reconcileReplicaSet reconciles ReplicaSets
+type reconcileReplicaSet struct {
+ // client can be used to retrieve objects from the APIServer.
+ client client.Client
+}
+
+// Implement reconcile.Reconciler so the controller can reconcile objects
+var _ reconcile.Reconciler = &reconcileReplicaSet{}
+
+func (r *reconcileReplicaSet) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
+ // set up a convenient log object so we don't have to type request over and over again
+ log := log.FromContext(ctx)
+
+ // Fetch the ReplicaSet from the cache
+ rs := &appsv1.ReplicaSet{}
+ err := r.client.Get(ctx, request.NamespacedName, rs)
+ if errors.IsNotFound(err) {
+ log.Error(nil, "Could not find ReplicaSet")
+ return reconcile.Result{}, nil
+ }
+
+ if err != nil {
+ return reconcile.Result{}, fmt.Errorf("could not fetch ReplicaSet: %+v", err)
+ }
+
+ // Print the ReplicaSet
+ log.Info("Reconciling ReplicaSet", "container name", rs.Spec.Template.Spec.Containers[0].Name)
+
+ // Set the label if it is missing
+ if rs.Labels == nil {
+ rs.Labels = map[string]string{}
+ }
+ if rs.Labels["hello"] == "world" {
+ return reconcile.Result{}, nil
+ }
+
+ // Update the ReplicaSet
+ rs.Labels["hello"] = "world"
+ err = r.client.Update(ctx, rs)
+ if err != nil {
+ return reconcile.Result{}, fmt.Errorf("could not write ReplicaSet: %+v", err)
+ }
+
+ return reconcile.Result{}, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/builtins/main.go b/third_party/sigs.k8s.io/controller-runtime/examples/builtins/main.go
new file mode 100644
index 00000000000..8ea173b2486
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/builtins/main.go
@@ -0,0 +1,88 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "os"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
+ "sigs.k8s.io/controller-runtime/pkg/builder"
+ "sigs.k8s.io/controller-runtime/pkg/client/config"
+ "sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/manager/signals"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+func init() {
+ log.SetLogger(zap.New())
+}
+
+func main() {
+ entryLog := log.Log.WithName("entrypoint")
+
+ // Setup a Manager
+ entryLog.Info("setting up manager")
+ mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{})
+ if err != nil {
+ entryLog.Error(err, "unable to set up overall controller manager")
+ os.Exit(1)
+ }
+
+ // Setup a new controller to reconcile ReplicaSets
+ entryLog.Info("Setting up controller")
+ c, err := controller.New("foo-controller", mgr, controller.Options{
+ Reconciler: &reconcileReplicaSet{client: mgr.GetClient()},
+ })
+ if err != nil {
+ entryLog.Error(err, "unable to set up individual controller")
+ os.Exit(1)
+ }
+
+ // Watch ReplicaSets and enqueue ReplicaSet object key
+ if err := c.Watch(source.Kind(mgr.GetCache(), &appsv1.ReplicaSet{}), &handler.EnqueueRequestForObject{}); err != nil {
+ entryLog.Error(err, "unable to watch ReplicaSets")
+ os.Exit(1)
+ }
+
+ // Watch Pods and enqueue owning ReplicaSet key
+ if err := c.Watch(source.Kind(mgr.GetCache(), &corev1.Pod{}),
+ handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &appsv1.ReplicaSet{}, handler.OnlyControllerOwner())); err != nil {
+ entryLog.Error(err, "unable to watch Pods")
+ os.Exit(1)
+ }
+
+ if err := builder.WebhookManagedBy(mgr).
+ For(&corev1.Pod{}).
+ WithDefaulter(&podAnnotator{}).
+ WithValidator(&podValidator{}).
+ Complete(); err != nil {
+ entryLog.Error(err, "unable to create webhook", "webhook", "Pod")
+ os.Exit(1)
+ }
+
+ entryLog.Info("starting manager")
+ if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+ entryLog.Error(err, "unable to run manager")
+ os.Exit(1)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/builtins/mutatingwebhook.go b/third_party/sigs.k8s.io/controller-runtime/examples/builtins/mutatingwebhook.go
new file mode 100644
index 00000000000..a588eba8f9c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/builtins/mutatingwebhook.go
@@ -0,0 +1,48 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "context"
+ "fmt"
+
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+// +kubebuilder:webhook:path=/mutate--v1-pod,mutating=true,failurePolicy=fail,groups="",resources=pods,verbs=create;update,versions=v1,name=mpod.kb.io
+
+// podAnnotator annotates Pods
+type podAnnotator struct{}
+
+func (a *podAnnotator) Default(ctx context.Context, obj runtime.Object) error {
+ log := logf.FromContext(ctx)
+ pod, ok := obj.(*corev1.Pod)
+ if !ok {
+ return fmt.Errorf("expected a Pod but got a %T", obj)
+ }
+
+ if pod.Annotations == nil {
+ pod.Annotations = map[string]string{}
+ }
+ pod.Annotations["example-mutating-admission-webhook"] = "foo"
+ log.Info("Annotated Pod")
+
+ return nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/builtins/validatingwebhook.go b/third_party/sigs.k8s.io/controller-runtime/examples/builtins/validatingwebhook.go
new file mode 100644
index 00000000000..1bee7f7c848
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/builtins/validatingwebhook.go
@@ -0,0 +1,66 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "context"
+ "fmt"
+
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+// +kubebuilder:webhook:path=/validate--v1-pod,mutating=false,failurePolicy=fail,groups="",resources=pods,verbs=create;update,versions=v1,name=vpod.kb.io
+
+// podValidator validates Pods
+type podValidator struct{}
+
+// validate admits a pod if a specific annotation exists.
+func (v *podValidator) validate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
+ log := logf.FromContext(ctx)
+ pod, ok := obj.(*corev1.Pod)
+ if !ok {
+ return nil, fmt.Errorf("expected a Pod but got a %T", obj)
+ }
+
+ log.Info("Validating Pod")
+ key := "example-mutating-admission-webhook"
+ anno, found := pod.Annotations[key]
+ if !found {
+ return nil, fmt.Errorf("missing annotation %s", key)
+ }
+ if anno != "foo" {
+ return nil, fmt.Errorf("annotation %s did not have value %q", key, "foo")
+ }
+
+ return nil, nil
+}
+
+func (v *podValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
+ return v.validate(ctx, obj)
+}
+
+func (v *podValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
+ return v.validate(ctx, newObj)
+}
+
+func (v *podValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
+ return v.validate(ctx, obj)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/configfile/builtin/config.yaml b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/builtin/config.yaml
new file mode 100644
index 00000000000..39ac86ce60e
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/builtin/config.yaml
@@ -0,0 +1,7 @@
+apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
+kind: ControllerManagerConfiguration
+cacheNamespace: default
+metrics:
+ bindAddress: :9091
+leaderElection:
+ leaderElect: false
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/configfile/builtin/controller.go b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/builtin/controller.go
new file mode 100644
index 00000000000..8349bcd5aa8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/builtin/controller.go
@@ -0,0 +1,74 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "context"
+ "fmt"
+
+ appsv1 "k8s.io/api/apps/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+// reconcileReplicaSet reconciles ReplicaSets
+type reconcileReplicaSet struct {
+ // client can be used to retrieve objects from the APIServer.
+ client client.Client
+}
+
+// Implement reconcile.Reconciler so the controller can reconcile objects
+var _ reconcile.Reconciler = &reconcileReplicaSet{}
+
+func (r *reconcileReplicaSet) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
+ // set up a convenient log object so we don't have to type request over and over again
+ log := log.FromContext(ctx)
+
+ // Fetch the ReplicaSet from the cache
+ rs := &appsv1.ReplicaSet{}
+ err := r.client.Get(context.TODO(), request.NamespacedName, rs)
+ if errors.IsNotFound(err) {
+ log.Error(nil, "Could not find ReplicaSet")
+ return reconcile.Result{}, nil
+ }
+
+ if err != nil {
+ return reconcile.Result{}, fmt.Errorf("could not fetch ReplicaSet: %+v", err)
+ }
+
+ // Print the ReplicaSet
+ log.Info("Reconciling ReplicaSet", "container name", rs.Spec.Template.Spec.Containers[0].Name)
+
+ // Set the label if it is missing
+ if rs.Labels == nil {
+ rs.Labels = map[string]string{}
+ }
+ if rs.Labels["hello"] == "world" {
+ return reconcile.Result{}, nil
+ }
+
+ // Update the ReplicaSet
+ rs.Labels["hello"] = "world"
+ err = r.client.Update(context.TODO(), rs)
+ if err != nil {
+ return reconcile.Result{}, fmt.Errorf("could not write ReplicaSet: %+v", err)
+ }
+
+ return reconcile.Result{}, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/configfile/builtin/main.go b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/builtin/main.go
new file mode 100644
index 00000000000..abd6180d191
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/builtin/main.go
@@ -0,0 +1,72 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "os"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+ _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client/config"
+ cfg "sigs.k8s.io/controller-runtime/pkg/config"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+ "sigs.k8s.io/controller-runtime/pkg/manager/signals"
+)
+
+var scheme = runtime.NewScheme()
+
+func init() {
+ log.SetLogger(zap.New())
+ clientgoscheme.AddToScheme(scheme)
+}
+
+func main() {
+ entryLog := log.Log.WithName("entrypoint")
+
+ // Setup a Manager
+ entryLog.Info("setting up manager")
+ mgr, err := ctrl.NewManager(config.GetConfigOrDie(), ctrl.Options{
+ Scheme: scheme,
+ }.AndFromOrDie(cfg.File()))
+ if err != nil {
+ entryLog.Error(err, "unable to set up overall controller manager")
+ os.Exit(1)
+ }
+
+ // Setup a new controller to reconcile ReplicaSets
+ err = ctrl.NewControllerManagedBy(mgr).
+ For(&appsv1.ReplicaSet{}).
+ Owns(&corev1.Pod{}).
+ Complete(&reconcileReplicaSet{
+ client: mgr.GetClient(),
+ })
+ if err != nil {
+ entryLog.Error(err, "unable to create controller")
+ os.Exit(1)
+ }
+
+ entryLog.Info("starting manager")
+ if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+ entryLog.Error(err, "unable to run manager")
+ os.Exit(1)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/config.yaml b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/config.yaml
new file mode 100644
index 00000000000..bf9ac044b4d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/config.yaml
@@ -0,0 +1,8 @@
+apiVersion: examples.x-k8s.io/v1alpha1
+kind: CustomControllerManagerConfiguration
+clusterName: example-test
+cacheNamespace: default
+metrics:
+ bindAddress: :8081
+leaderElection:
+ leaderElect: false
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/controller.go b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/controller.go
new file mode 100644
index 00000000000..8349bcd5aa8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/controller.go
@@ -0,0 +1,74 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "context"
+ "fmt"
+
+ appsv1 "k8s.io/api/apps/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+// reconcileReplicaSet reconciles ReplicaSets
+type reconcileReplicaSet struct {
+ // client can be used to retrieve objects from the APIServer.
+ client client.Client
+}
+
+// Implement reconcile.Reconciler so the controller can reconcile objects
+var _ reconcile.Reconciler = &reconcileReplicaSet{}
+
+func (r *reconcileReplicaSet) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
+ // set up a convenient log object so we don't have to type request over and over again
+ log := log.FromContext(ctx)
+
+ // Fetch the ReplicaSet from the cache
+ rs := &appsv1.ReplicaSet{}
+ err := r.client.Get(context.TODO(), request.NamespacedName, rs)
+ if errors.IsNotFound(err) {
+ log.Error(nil, "Could not find ReplicaSet")
+ return reconcile.Result{}, nil
+ }
+
+ if err != nil {
+ return reconcile.Result{}, fmt.Errorf("could not fetch ReplicaSet: %+v", err)
+ }
+
+ // Print the ReplicaSet
+ log.Info("Reconciling ReplicaSet", "container name", rs.Spec.Template.Spec.Containers[0].Name)
+
+ // Set the label if it is missing
+ if rs.Labels == nil {
+ rs.Labels = map[string]string{}
+ }
+ if rs.Labels["hello"] == "world" {
+ return reconcile.Result{}, nil
+ }
+
+ // Update the ReplicaSet
+ rs.Labels["hello"] = "world"
+ err = r.client.Update(context.TODO(), rs)
+ if err != nil {
+ return reconcile.Result{}, fmt.Errorf("could not write ReplicaSet: %+v", err)
+ }
+
+ return reconcile.Result{}, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/main.go b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/main.go
new file mode 100644
index 00000000000..e0fc95e3378
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/main.go
@@ -0,0 +1,78 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "os"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+ _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/examples/configfile/custom/v1alpha1"
+ "sigs.k8s.io/controller-runtime/pkg/client/config"
+ cfg "sigs.k8s.io/controller-runtime/pkg/config"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+ "sigs.k8s.io/controller-runtime/pkg/manager/signals"
+)
+
+var scheme = runtime.NewScheme()
+
+func init() {
+ log.SetLogger(zap.New())
+ clientgoscheme.AddToScheme(scheme)
+ v1alpha1.AddToScheme(scheme)
+}
+
+func main() {
+ entryLog := log.Log.WithName("entrypoint")
+
+ // Setup a Manager
+ entryLog.Info("setting up manager")
+ ctrlConfig := v1alpha1.CustomControllerManagerConfiguration{}
+
+ mgr, err := ctrl.NewManager(config.GetConfigOrDie(), ctrl.Options{
+ Scheme: scheme,
+ }.AndFromOrDie(cfg.File().OfKind(&ctrlConfig)))
+ if err != nil {
+ entryLog.Error(err, "unable to set up overall controller manager")
+ os.Exit(1)
+ }
+
+ entryLog.Info("setting up cluster", "name", ctrlConfig.ClusterName)
+
+ // Watch ReplicaSets and enqueue ReplicaSet object key
+ err = ctrl.NewControllerManagedBy(mgr).
+ For(&appsv1.ReplicaSet{}).
+ Owns(&corev1.Pod{}).
+ Complete(&reconcileReplicaSet{
+ client: mgr.GetClient(),
+ })
+ if err != nil {
+ entryLog.Error(err, "unable to create controller")
+ os.Exit(1)
+ }
+
+ entryLog.Info("starting manager")
+ if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+ entryLog.Error(err, "unable to run manager")
+ os.Exit(1)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/v1alpha1/types.go b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/v1alpha1/types.go
new file mode 100644
index 00000000000..79e8422c5c9
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/v1alpha1/types.go
@@ -0,0 +1,54 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package v1alpha1 provides the CustomControllerManagerConfiguration used for
+// demoing componentconfig
+// +kubebuilder:object:generate=true
+package v1alpha1
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ cfg "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+ // GroupVersion is group version used to register these objects
+ GroupVersion = schema.GroupVersion{Group: "examples.x-k8s.io", Version: "v1alpha1"}
+
+ // SchemeBuilder is used to add go types to the GroupVersionKind scheme
+ SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+ // AddToScheme adds the types in this group-version to the given scheme.
+ AddToScheme = SchemeBuilder.AddToScheme
+)
+
+// +kubebuilder:object:root=true
+
+// CustomControllerManagerConfiguration is the Schema for the CustomControllerManagerConfigurations API
+type CustomControllerManagerConfiguration struct {
+ metav1.TypeMeta `json:",inline"`
+
+ // ControllerManagerConfigurationSpec returns the contfigurations for controllers
+ cfg.ControllerManagerConfigurationSpec `json:",inline"`
+
+ ClusterName string `json:"clusterName,omitempty"`
+}
+
+func init() {
+ SchemeBuilder.Register(&CustomControllerManagerConfiguration{})
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/v1alpha1/zz_generated.deepcopy.go b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/v1alpha1/zz_generated.deepcopy.go
new file mode 100644
index 00000000000..b9d3b6b4b94
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/configfile/custom/v1alpha1/zz_generated.deepcopy.go
@@ -0,0 +1,35 @@
+//go:build !ignore_autogenerated
+// +build !ignore_autogenerated
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CustomControllerManagerConfiguration) DeepCopyInto(out *CustomControllerManagerConfiguration) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ControllerManagerConfigurationSpec.DeepCopyInto(&out.ControllerManagerConfigurationSpec)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomControllerManagerConfiguration.
+func (in *CustomControllerManagerConfiguration) DeepCopy() *CustomControllerManagerConfiguration {
+ if in == nil {
+ return nil
+ }
+ out := new(CustomControllerManagerConfiguration)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *CustomControllerManagerConfiguration) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/crd/main.go b/third_party/sigs.k8s.io/controller-runtime/examples/crd/main.go
new file mode 100644
index 00000000000..1f6cd5fac2e
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/crd/main.go
@@ -0,0 +1,145 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "context"
+ "math/rand"
+ "os"
+ "time"
+
+ corev1 "k8s.io/api/core/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+ _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
+ ctrl "sigs.k8s.io/controller-runtime"
+ api "sigs.k8s.io/controller-runtime/examples/crd/pkg"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+var (
+ setupLog = ctrl.Log.WithName("setup")
+)
+
+type reconciler struct {
+ client.Client
+ scheme *runtime.Scheme
+}
+
+func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+ log := log.FromContext(ctx).WithValues("chaospod", req.NamespacedName)
+ log.V(1).Info("reconciling chaos pod")
+
+ var chaospod api.ChaosPod
+ if err := r.Get(ctx, req.NamespacedName, &chaospod); err != nil {
+ log.Error(err, "unable to get chaosctl")
+ return ctrl.Result{}, err
+ }
+
+ var pod corev1.Pod
+ podFound := true
+ if err := r.Get(ctx, req.NamespacedName, &pod); err != nil {
+ if !apierrors.IsNotFound(err) {
+ log.Error(err, "unable to get pod")
+ return ctrl.Result{}, err
+ }
+ podFound = false
+ }
+
+ if podFound {
+ shouldStop := chaospod.Spec.NextStop.Time.Before(time.Now())
+ if !shouldStop {
+ return ctrl.Result{RequeueAfter: chaospod.Spec.NextStop.Sub(time.Now()) + 1*time.Second}, nil
+ }
+
+ if err := r.Delete(ctx, &pod); err != nil {
+ log.Error(err, "unable to delete pod")
+ return ctrl.Result{}, err
+ }
+
+ return ctrl.Result{Requeue: true}, nil
+ }
+
+ templ := chaospod.Spec.Template.DeepCopy()
+ pod.ObjectMeta = templ.ObjectMeta
+ pod.Name = req.Name
+ pod.Namespace = req.Namespace
+ pod.Spec = templ.Spec
+
+ if err := ctrl.SetControllerReference(&chaospod, &pod, r.scheme); err != nil {
+ log.Error(err, "unable to set pod's owner reference")
+ return ctrl.Result{}, err
+ }
+
+ if err := r.Create(ctx, &pod); err != nil {
+ log.Error(err, "unable to create pod")
+ return ctrl.Result{}, err
+ }
+
+ chaospod.Spec.NextStop.Time = time.Now().Add(time.Duration(10*(rand.Int63n(2)+1)) * time.Second)
+ chaospod.Status.LastRun = pod.CreationTimestamp
+ if err := r.Update(ctx, &chaospod); err != nil {
+ log.Error(err, "unable to update chaosctl status")
+ return ctrl.Result{}, err
+ }
+ return ctrl.Result{}, nil
+}
+
+func main() {
+ ctrl.SetLogger(zap.New())
+
+ mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{})
+ if err != nil {
+ setupLog.Error(err, "unable to start manager")
+ os.Exit(1)
+ }
+
+ // in a real controller, we'd create a new scheme for this
+ err = api.AddToScheme(mgr.GetScheme())
+ if err != nil {
+ setupLog.Error(err, "unable to add scheme")
+ os.Exit(1)
+ }
+
+ err = ctrl.NewControllerManagedBy(mgr).
+ For(&api.ChaosPod{}).
+ Owns(&corev1.Pod{}).
+ Complete(&reconciler{
+ Client: mgr.GetClient(),
+ scheme: mgr.GetScheme(),
+ })
+ if err != nil {
+ setupLog.Error(err, "unable to create controller")
+ os.Exit(1)
+ }
+
+ err = ctrl.NewWebhookManagedBy(mgr).
+ For(&api.ChaosPod{}).
+ Complete()
+ if err != nil {
+ setupLog.Error(err, "unable to create webhook")
+ os.Exit(1)
+ }
+
+ setupLog.Info("starting manager")
+ if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
+ setupLog.Error(err, "problem running manager")
+ os.Exit(1)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/crd/pkg/groupversion_info.go b/third_party/sigs.k8s.io/controller-runtime/examples/crd/pkg/groupversion_info.go
new file mode 100644
index 00000000000..04953dd9398
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/crd/pkg/groupversion_info.go
@@ -0,0 +1,38 @@
+/*
+Copyright 2018 The Kubernetes authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// +kubebuilder:object:generate=true
+// +groupName=chaosapps.metamagical.io
+package pkg
+
+import (
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+ log = logf.Log.WithName("chaospod-resource")
+
+ // SchemeGroupVersion is group version used to register these objects
+ SchemeGroupVersion = schema.GroupVersion{Group: "chaosapps.metamagical.io", Version: "v1"}
+
+ // SchemeBuilder is used to add go types to the GroupVersionKind scheme
+ SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
+
+ // AddToScheme is required by pkg/client/...
+ AddToScheme = SchemeBuilder.AddToScheme
+)
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/crd/pkg/resource.go b/third_party/sigs.k8s.io/controller-runtime/examples/crd/pkg/resource.go
new file mode 100644
index 00000000000..555029f5de7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/crd/pkg/resource.go
@@ -0,0 +1,122 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package pkg
+
+import (
+ "fmt"
+ "time"
+
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+// ChaosPodSpec defines the desired state of ChaosPod
+type ChaosPodSpec struct {
+ Template corev1.PodTemplateSpec `json:"template"`
+ // +optional
+ NextStop metav1.Time `json:"nextStop,omitempty"`
+}
+
+// ChaosPodStatus defines the observed state of ChaosPod.
+// It should always be reconstructable from the state of the cluster and/or outside world.
+type ChaosPodStatus struct {
+ LastRun metav1.Time `json:"lastRun,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ChaosPod is the Schema for the randomjobs API
+// +kubebuilder:printcolumn:name="next stop",type="string",JSONPath=".spec.nextStop",format="date"
+// +kubebuilder:printcolumn:name="last run",type="string",JSONPath=".status.lastRun",format="date"
+type ChaosPod struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec ChaosPodSpec `json:"spec,omitempty"`
+ Status ChaosPodStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ChaosPodList contains a list of ChaosPod
+type ChaosPodList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []ChaosPod `json:"items"`
+}
+
+// +kubebuilder:webhook:path=/validate-chaosapps-metamagical-io-v1-chaospod,mutating=false,failurePolicy=fail,groups=chaosapps.metamagical.io,resources=chaospods,verbs=create;update,versions=v1,name=vchaospod.kb.io
+
+var _ webhook.Validator = &ChaosPod{}
+
+// ValidateCreate implements webhookutil.validator so a webhook will be registered for the type
+func (c *ChaosPod) ValidateCreate() (admission.Warnings, error) {
+ log.Info("validate create", "name", c.Name)
+
+ if c.Spec.NextStop.Before(&metav1.Time{Time: time.Now()}) {
+ return nil, fmt.Errorf(".spec.nextStop must be later than current time")
+ }
+ return nil, nil
+}
+
+// ValidateUpdate implements webhookutil.validator so a webhook will be registered for the type
+func (c *ChaosPod) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
+ log.Info("validate update", "name", c.Name)
+
+ if c.Spec.NextStop.Before(&metav1.Time{Time: time.Now()}) {
+ return nil, fmt.Errorf(".spec.nextStop must be later than current time")
+ }
+
+ oldC, ok := old.(*ChaosPod)
+ if !ok {
+ return nil, fmt.Errorf("expect old object to be a %T instead of %T", oldC, old)
+ }
+ if c.Spec.NextStop.After(oldC.Spec.NextStop.Add(time.Hour)) {
+ return nil, fmt.Errorf("it is not allowed to delay.spec.nextStop for more than 1 hour")
+ }
+ return nil, nil
+}
+
+// ValidateDelete implements webhookutil.validator so a webhook will be registered for the type
+func (c *ChaosPod) ValidateDelete() (admission.Warnings, error) {
+ log.Info("validate delete", "name", c.Name)
+
+ if c.Spec.NextStop.Before(&metav1.Time{Time: time.Now()}) {
+ return nil, fmt.Errorf(".spec.nextStop must be later than current time")
+ }
+ return nil, nil
+}
+
+// +kubebuilder:webhook:path=/mutate-chaosapps-metamagical-io-v1-chaospod,mutating=true,failurePolicy=fail,groups=chaosapps.metamagical.io,resources=chaospods,verbs=create;update,versions=v1,name=mchaospod.kb.io
+
+var _ webhook.Defaulter = &ChaosPod{}
+
+// Default implements webhookutil.defaulter so a webhook will be registered for the type
+func (c *ChaosPod) Default() {
+ log.Info("default", "name", c.Name)
+
+ if c.Spec.NextStop.Before(&metav1.Time{Time: time.Now()}) {
+ c.Spec.NextStop = metav1.Time{Time: time.Now().Add(time.Minute)}
+ }
+}
+
+func init() {
+ SchemeBuilder.Register(&ChaosPod{}, &ChaosPodList{})
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/crd/pkg/zz_generated.deepcopy.go b/third_party/sigs.k8s.io/controller-runtime/examples/crd/pkg/zz_generated.deepcopy.go
new file mode 100644
index 00000000000..cd506a87c07
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/crd/pkg/zz_generated.deepcopy.go
@@ -0,0 +1,121 @@
+// +build !ignore_autogenerated
+
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by main. DO NOT EDIT.
+
+package pkg
+
+import (
+ runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (c *ChaosPod) DeepCopyInto(out *ChaosPod) {
+ *out = *c
+ out.TypeMeta = c.TypeMeta
+ c.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ c.Spec.DeepCopyInto(&out.Spec)
+ c.Status.DeepCopyInto(&out.Status)
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChaosPod.
+func (c *ChaosPod) DeepCopy() *ChaosPod {
+ if c == nil {
+ return nil
+ }
+ out := new(ChaosPod)
+ c.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (c *ChaosPod) DeepCopyObject() runtime.Object {
+ if c := c.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 *ChaosPodList) DeepCopyInto(out *ChaosPodList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ out.ListMeta = in.ListMeta
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]ChaosPod, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChaosPodList.
+func (in *ChaosPodList) DeepCopy() *ChaosPodList {
+ if in == nil {
+ return nil
+ }
+ out := new(ChaosPodList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ChaosPodList) 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 *ChaosPodSpec) DeepCopyInto(out *ChaosPodSpec) {
+ *out = *in
+ in.Template.DeepCopyInto(&out.Template)
+ in.NextStop.DeepCopyInto(&out.NextStop)
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChaosPodSpec.
+func (in *ChaosPodSpec) DeepCopy() *ChaosPodSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ChaosPodSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ChaosPodStatus) DeepCopyInto(out *ChaosPodStatus) {
+ *out = *in
+ in.LastRun.DeepCopyInto(&out.LastRun)
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChaosPodStatus.
+func (in *ChaosPodStatus) DeepCopy() *ChaosPodStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ChaosPodStatus)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/scratch-env/go.mod b/third_party/sigs.k8s.io/controller-runtime/examples/scratch-env/go.mod
new file mode 100644
index 00000000000..59da6b3d9ec
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/scratch-env/go.mod
@@ -0,0 +1,10 @@
+module sigs.k8s.io/controller-runtime/examples/scratch-env
+
+go 1.15
+
+require (
+ github.com/spf13/pflag v1.0.5
+ sigs.k8s.io/controller-runtime v0.0.0-00010101000000-000000000000
+)
+
+replace sigs.k8s.io/controller-runtime => ../..
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/scratch-env/go.sum b/third_party/sigs.k8s.io/controller-runtime/examples/scratch-env/go.sum
new file mode 100644
index 00000000000..ffafe857816
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/scratch-env/go.sum
@@ -0,0 +1,840 @@
+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.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/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/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/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+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/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=
+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 v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
+github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+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/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
+github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
+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/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
+github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
+github.com/cespare/xxhash/v2 v2.1.1/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/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.13+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-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+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/creack/pty v1.1.11/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 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/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/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+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/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
+github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
+github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+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/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
+github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-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/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
+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-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.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
+github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM=
+github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
+github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
+github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
+github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
+github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
+github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-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 h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/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/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.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+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/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.5.0/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 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+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/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/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/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.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
+github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
+github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+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/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+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 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+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/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+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/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+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.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/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.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/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/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
+github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
+github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+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/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+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 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+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-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
+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 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+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/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
+github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
+github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
+github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+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/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+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/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.7.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.16.2 h1:HFB2fbVIlhIfCfOW81bZFbiC/RvnpXSdhbF2/DJr134=
+github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.4.3/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.12.0 h1:p4oGGk2M2UJc0wWN4lHFvIB71lxsh0T/UiKCCgFADY8=
+github.com/onsi/gomega v1.12.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
+github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
+github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
+github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+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/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+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-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
+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.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg=
+github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+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.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.18.0 h1:WCVKW7aL6LEe1uryfI9dnEc2ZqNB1Fn0ok930v0iL1Y=
+github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/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.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+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/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
+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/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.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
+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.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
+github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
+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/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 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+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/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/yuin/goldmark v1.1.27/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.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
+go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+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.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.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
+go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+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/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/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 h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
+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/mod v0.3.1-0.20200828183125-ce943fd02449 h1:xUIPaMhvROX9dhPvRCenIJtU78+lbEenGbgqB5hfHCQ=
+golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+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-20181023162649-9b4f9f5ad519/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-20181201002055-351d144fa1fc/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-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-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-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-20200520004742-59133d7f0dd7/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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+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-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-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+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-20181026203630-95b1ffbd15a5/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-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-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-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-20191220142924-d4481acd189f/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-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+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-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
+golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/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-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/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-20191112195655-aa38f8e97acc/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-20200103221440-774c71fcf114/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-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+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-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+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.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+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.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+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.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-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+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-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
+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.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+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/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+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 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+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=
+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 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
+gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+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 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+k8s.io/api v0.21.1 h1:94bbZ5NTjdINJEdzOkpS4vdPhkb1VFpTYC9zh43f75c=
+k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s=
+k8s.io/apiextensions-apiserver v0.21.1 h1:AA+cnsb6w7SZ1vD32Z+zdgfXdXY8X9uGX5bN6EoPEIo=
+k8s.io/apiextensions-apiserver v0.21.1/go.mod h1:KESQFCGjqVcVsZ9g0xX5bacMjyX5emuWcS2arzdEouA=
+k8s.io/apimachinery v0.21.1 h1:Q6XuHGlj2xc+hlMCvqyYfbv3H7SRGn2c8NycxJquDVs=
+k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY=
+k8s.io/apiserver v0.21.1/go.mod h1:nLLYZvMWn35glJ4/FZRhzLG/3MPxAaZTgV4FJZdr+tY=
+k8s.io/client-go v0.21.1 h1:bhblWYLZKUu+pm50plvQF8WpY6TXdRRtcS/K9WauOj4=
+k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs=
+k8s.io/code-generator v0.21.1/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q=
+k8s.io/component-base v0.21.1 h1:iLpj2btXbR326s/xNQWmPNGu0gaYSjzn7IN/5i28nQw=
+k8s.io/component-base v0.21.1/go.mod h1:NgzFZ2qu4m1juby4TnrmpR8adRk6ka62YdH5DkIIyKA=
+k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/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.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts=
+k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
+k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0=
+k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
+k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20210517184530-5a248b5acedc h1:cIS13bDBZaWqngldgGuDypv4z+zjcYgTKv72k6bMAn0=
+k8s.io/utils v0.0.0-20210517184530-5a248b5acedc/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+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.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8=
+sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
+sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/scratch-env/main.go b/third_party/sigs.k8s.io/controller-runtime/examples/scratch-env/main.go
new file mode 100644
index 00000000000..b8305ffed39
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/scratch-env/main.go
@@ -0,0 +1,132 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ goflag "flag"
+ "os"
+
+ flag "github.com/spf13/pflag"
+ "go.uber.org/zap"
+
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+ logzap "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+var (
+ crdPaths = flag.StringSlice("crd-paths", nil, "paths to files or directories containing CRDs to install on start")
+ webhookPaths = flag.StringSlice("webhook-paths", nil, "paths to files or directories containing webhook configurations to install on start")
+ attachControlPlaneOut = flag.Bool("debug-env", false, "attach to test env (apiserver & etcd) output -- just a convinience flag to force KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT=true")
+)
+
+// have a separate function so we can return an exit code w/o skipping defers
+func runMain() int {
+ loggerOpts := &logzap.Options{
+ Development: true, // a sane default
+ ZapOpts: []zap.Option{zap.AddCaller()},
+ }
+ {
+ var goFlagSet goflag.FlagSet
+ loggerOpts.BindFlags(&goFlagSet)
+ flag.CommandLine.AddGoFlagSet(&goFlagSet)
+ }
+ flag.Parse()
+ ctrl.SetLogger(logzap.New(logzap.UseFlagOptions(loggerOpts)))
+ ctrl.Log.Info("Starting...")
+
+ log := ctrl.Log.WithName("main")
+
+ env := &envtest.Environment{}
+ env.CRDInstallOptions.Paths = *crdPaths
+ env.WebhookInstallOptions.Paths = *webhookPaths
+
+ if *attachControlPlaneOut {
+ os.Setenv("KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT", "true")
+ }
+
+ log.Info("Starting apiserver & etcd")
+ cfg, err := env.Start()
+ if err != nil {
+ log.Error(err, "unable to start the test environment")
+ // shut down the environment in case we started it and failed while
+ // installing CRDs or provisioning users.
+ if err := env.Stop(); err != nil {
+ log.Error(err, "unable to stop the test environment after an error (this might be expected, but just though you should know)")
+ }
+ return 1
+ }
+
+ log.Info("apiserver running", "host", cfg.Host)
+
+ // NB(directxman12): this group is unfortunately named, but various
+ // kubernetes versions require us to use it to get "admin" access.
+ user, err := env.ControlPlane.AddUser(envtest.User{
+ Name: "envtest-admin",
+ Groups: []string{"system:masters"},
+ }, nil)
+ if err != nil {
+ log.Error(err, "unable to provision admin user, continuing on without it")
+ return 1
+ }
+
+ // TODO(directxman12): add support for writing to a new context in an existing file
+ kubeconfigFile, err := os.CreateTemp("", "scratch-env-kubeconfig-")
+ if err != nil {
+ log.Error(err, "unable to create kubeconfig file, continuing on without it")
+ return 1
+ }
+ defer os.Remove(kubeconfigFile.Name())
+
+ {
+ log := log.WithValues("path", kubeconfigFile.Name())
+ log.V(1).Info("Writing kubeconfig")
+
+ kubeConfig, err := user.KubeConfig()
+ if err != nil {
+ log.Error(err, "unable to create kubeconfig")
+ }
+
+ if _, err := kubeconfigFile.Write(kubeConfig); err != nil {
+ log.Error(err, "unable to save kubeconfig")
+ return 1
+ }
+
+ log.Info("Wrote kubeconfig")
+ }
+
+ if opts := env.WebhookInstallOptions; opts.LocalServingPort != 0 {
+ log.Info("webhooks configured for", "host", opts.LocalServingHost, "port", opts.LocalServingPort, "dir", opts.LocalServingCertDir)
+ }
+
+ ctx := ctrl.SetupSignalHandler()
+ <-ctx.Done()
+
+ log.Info("Shutting down apiserver & etcd")
+ err = env.Stop()
+ if err != nil {
+ log.Error(err, "unable to stop the test environment")
+ return 1
+ }
+
+ log.Info("Shutdown successful")
+ return 0
+}
+
+func main() {
+ os.Exit(runMain())
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/tokenreview/main.go b/third_party/sigs.k8s.io/controller-runtime/examples/tokenreview/main.go
new file mode 100644
index 00000000000..d018956f960
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/tokenreview/main.go
@@ -0,0 +1,58 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "os"
+
+ _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
+ "sigs.k8s.io/controller-runtime/pkg/client/config"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/manager/signals"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/authentication"
+)
+
+func init() {
+ log.SetLogger(zap.New())
+}
+
+func main() {
+ entryLog := log.Log.WithName("entrypoint")
+
+ // Setup a Manager
+ entryLog.Info("setting up manager")
+ mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{})
+ if err != nil {
+ entryLog.Error(err, "unable to set up overall controller manager")
+ os.Exit(1)
+ }
+
+ // Setup webhooks
+ entryLog.Info("setting up webhook server")
+ hookServer := mgr.GetWebhookServer()
+
+ entryLog.Info("registering webhooks to the webhook server")
+ hookServer.Register("/validate-v1-tokenreview", &authentication.Webhook{Handler: &authenticator{}})
+
+ entryLog.Info("starting manager")
+ if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+ entryLog.Error(err, "unable to run manager")
+ os.Exit(1)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/examples/tokenreview/tokenreview.go b/third_party/sigs.k8s.io/controller-runtime/examples/tokenreview/tokenreview.go
new file mode 100644
index 00000000000..cc64545e160
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/examples/tokenreview/tokenreview.go
@@ -0,0 +1,37 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "context"
+
+ v1 "k8s.io/api/authentication/v1"
+
+ "sigs.k8s.io/controller-runtime/pkg/webhook/authentication"
+)
+
+// authenticator validates tokenreviews
+type authenticator struct {
+}
+
+// authenticator admits a request by the token.
+func (a *authenticator) Handle(ctx context.Context, req authentication.Request) authentication.Response {
+ if req.Spec.Token == "invalid" {
+ return authentication.Unauthenticated("invalid is an invalid token", v1.UserInfo{})
+ }
+ return authentication.Authenticated("", v1.UserInfo{})
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/go.mod b/third_party/sigs.k8s.io/controller-runtime/go.mod
new file mode 100644
index 00000000000..d5deefaa598
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/go.mod
@@ -0,0 +1,74 @@
+module sigs.k8s.io/controller-runtime
+
+go 1.20
+
+require (
+ github.com/evanphx/json-patch v4.12.0+incompatible
+ github.com/evanphx/json-patch/v5 v5.6.0
+ github.com/fsnotify/fsnotify v1.6.0
+ github.com/go-logr/logr v1.2.4
+ github.com/go-logr/zapr v1.2.4
+ github.com/google/go-cmp v0.5.9
+ github.com/onsi/ginkgo/v2 v2.9.5
+ github.com/onsi/gomega v1.27.7
+ github.com/prometheus/client_golang v1.15.1
+ github.com/prometheus/client_model v0.4.0
+ go.uber.org/goleak v1.2.1
+ go.uber.org/zap v1.24.0
+ golang.org/x/sys v0.8.0
+ gomodules.xyz/jsonpatch/v2 v2.3.0
+ k8s.io/api v0.27.2
+ k8s.io/apiextensions-apiserver v0.27.2
+ k8s.io/apimachinery v0.27.2
+ k8s.io/client-go v0.27.2
+ k8s.io/component-base v0.27.2
+ k8s.io/klog/v2 v2.90.1
+ k8s.io/utils v0.0.0-20230209194617-a36077c30491
+ sigs.k8s.io/yaml v1.3.0
+)
+
+require (
+ github.com/beorn7/perks v1.0.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/go-openapi/jsonpointer v0.19.6 // indirect
+ github.com/go-openapi/jsonreference v0.20.1 // 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/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/gofuzz v1.1.0 // indirect
+ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
+ github.com/google/uuid v1.3.0 // indirect
+ github.com/imdario/mergo v0.3.6 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.4 // 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/pkg/errors v0.9.1 // indirect
+ github.com/prometheus/common v0.42.0 // indirect
+ github.com/prometheus/procfs v0.9.0 // 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.10.0 // indirect
+ golang.org/x/oauth2 v0.5.0 // indirect
+ golang.org/x/term v0.8.0 // indirect
+ golang.org/x/text v0.9.0 // indirect
+ golang.org/x/time v0.3.0 // indirect
+ golang.org/x/tools v0.9.1 // indirect
+ google.golang.org/appengine v1.6.7 // indirect
+ google.golang.org/protobuf v1.30.0 // indirect
+ gopkg.in/inf.v0 v0.9.1 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
+ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
+)
diff --git a/third_party/sigs.k8s.io/controller-runtime/go.sum b/third_party/sigs.k8s.io/controller-runtime/go.sum
new file mode 100644
index 00000000000..fd1d80d30e9
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/go.sum
@@ -0,0 +1,284 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+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 v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+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/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/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+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.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
+github.com/evanphx/json-patch v4.12.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/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
+github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
+github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
+github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
+github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
+github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
+github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
+github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-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 v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-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/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.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.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/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
+github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
+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.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 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/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.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
+github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+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/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/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
+github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+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 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-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
+github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
+github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
+github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
+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/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
+github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
+github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
+github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
+github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
+github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
+github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.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.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.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 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+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.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
+go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
+go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
+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/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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
+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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
+golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
+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-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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
+golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc=
+gomodules.xyz/jsonpatch/v2 v2.3.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.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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+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.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.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.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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
+google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo=
+k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4=
+k8s.io/apiextensions-apiserver v0.27.2 h1:iwhyoeS4xj9Y7v8YExhUwbVuBhMr3Q4bd/laClBV6Bo=
+k8s.io/apiextensions-apiserver v0.27.2/go.mod h1:Oz9UdvGguL3ULgRdY9QMUzL2RZImotgxvGjdWRq6ZXQ=
+k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg=
+k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
+k8s.io/client-go v0.27.2 h1:vDLSeuYvCHKeoQRhCXjxXO45nHVv2Ip4Fe0MfioMrhE=
+k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ=
+k8s.io/component-base v0.27.2 h1:neju+7s/r5O4x4/txeUONNTS9r1HsPbyoPBAtHsDCpo=
+k8s.io/component-base v0.27.2/go.mod h1:5UPk7EjfgrfgRIuDBFtsEFAe4DAvP3U+M8RTzoSJkpo=
+k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
+k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
+k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
+k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
+k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+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.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
+sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
+sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
diff --git a/third_party/sigs.k8s.io/controller-runtime/hack/apidiff.sh b/third_party/sigs.k8s.io/controller-runtime/hack/apidiff.sh
new file mode 100755
index 00000000000..0167486da1d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/hack/apidiff.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+
+# Copyright 2018 The Kubernetes Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+source $(dirname ${BASH_SOURCE})/common.sh
+
+REPO_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
+cd "${REPO_ROOT}"
+
+APIDIFF="hack/tools/bin/go-apidiff"
+
+header_text "fetching and building go-apidiff"
+make "${APIDIFF}"
+
+git status
+
+header_text "verifying api diff"
+header_text "invoking: '${APIDIFF} ${PULL_BASE_SHA} --print-compatible'"
+"${APIDIFF}" "${PULL_BASE_SHA}" --print-compatible
diff --git a/third_party/sigs.k8s.io/controller-runtime/hack/check-everything.sh b/third_party/sigs.k8s.io/controller-runtime/hack/check-everything.sh
new file mode 100755
index 00000000000..09f2a901d4a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/hack/check-everything.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+# Copyright 2018 The Kubernetes Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+hack_dir=$(dirname ${BASH_SOURCE})
+source ${hack_dir}/common.sh
+
+tmp_root=/tmp
+kb_root_dir=$tmp_root/kubebuilder
+
+# Run verification scripts.
+${hack_dir}/verify.sh
+
+# Envtest.
+ENVTEST_K8S_VERSION=${ENVTEST_K8S_VERSION:-"1.24.2"}
+
+header_text "installing envtest tools@${ENVTEST_K8S_VERSION} with setup-envtest if necessary"
+tmp_bin=/tmp/cr-tests-bin
+(
+ # don't presume to install for the user
+ cd ${hack_dir}/../tools/setup-envtest
+ GOBIN=${tmp_bin} go install .
+)
+export KUBEBUILDER_ASSETS="$(${tmp_bin}/setup-envtest use --use-env -p path "${ENVTEST_K8S_VERSION}")"
+
+# Run tests.
+${hack_dir}/test-all.sh
+
+header_text "confirming examples compile (via go install)"
+go install ${MOD_OPT} ./examples/builtins
+go install ${MOD_OPT} ./examples/crd
+go install ${MOD_OPT} ./examples/configfile/builtin
+go install ${MOD_OPT} ./examples/configfile/custom
+
+echo "passed"
+exit 0
diff --git a/third_party/sigs.k8s.io/controller-runtime/hack/ci-check-everything.sh b/third_party/sigs.k8s.io/controller-runtime/hack/ci-check-everything.sh
new file mode 100755
index 00000000000..39b85e91d81
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/hack/ci-check-everything.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+# Copyright 2018 The Kubernetes Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+export TRACE=1
+
+# Not included or existing by default in Prow
+export PATH=$(go env GOPATH)/bin:$PATH
+mkdir -p $(go env GOPATH)/bin
+
+$(dirname ${BASH_SOURCE})/check-everything.sh
diff --git a/third_party/sigs.k8s.io/controller-runtime/hack/common.sh b/third_party/sigs.k8s.io/controller-runtime/hack/common.sh
new file mode 100755
index 00000000000..eff91ba7b76
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/hack/common.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+
+# Copyright 2018 The Kubernetes Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+# Enable tracing in this script off by setting the TRACE variable in your
+# environment to any value:
+#
+# $ TRACE=1 test.sh
+TRACE=${TRACE:-""}
+if [ -n "$TRACE" ]; then
+ set -x
+fi
+
+# check if modules are enabled
+(go mod edit -json &>/dev/null)
+MODULES_ENABLED=$?
+
+MOD_OPT=""
+MODULES_OPT=${MODULES_OPT:-""}
+if [[ -n "${MODULES_OPT}" && $MODULES_ENABLED ]]; then
+ MOD_OPT="-mod=${MODULES_OPT}"
+fi
+
+# Turn colors in this script off by setting the NO_COLOR variable in your
+# environment to any value:
+#
+# $ NO_COLOR=1 test.sh
+NO_COLOR=${NO_COLOR:-""}
+if [ -z "$NO_COLOR" ]; then
+ header=$'\e[1;33m'
+ reset=$'\e[0m'
+else
+ header=''
+ reset=''
+fi
+
+function header_text {
+ echo "$header$*$reset"
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/hack/ensure-golangci-lint.sh b/third_party/sigs.k8s.io/controller-runtime/hack/ensure-golangci-lint.sh
new file mode 100755
index 00000000000..9210f959b00
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/hack/ensure-golangci-lint.sh
@@ -0,0 +1,432 @@
+#!/usr/bin/env bash
+
+# Copyright 2021 The Kubernetes Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# NOTE: This script is copied from from https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh.
+
+set -e
+
+usage() {
+ this=$1
+ cat </dev/null
+}
+echoerr() {
+ echo "$@" 1>&2
+}
+log_prefix() {
+ echo "$0"
+}
+_logp=6
+log_set_priority() {
+ _logp="$1"
+}
+log_priority() {
+ if test -z "$1"; then
+ echo "$_logp"
+ return
+ fi
+ [ "$1" -le "$_logp" ]
+}
+log_tag() {
+ case $1 in
+ 0) echo "emerg" ;;
+ 1) echo "alert" ;;
+ 2) echo "crit" ;;
+ 3) echo "err" ;;
+ 4) echo "warning" ;;
+ 5) echo "notice" ;;
+ 6) echo "info" ;;
+ 7) echo "debug" ;;
+ *) echo "$1" ;;
+ esac
+}
+log_debug() {
+ log_priority 7 || return 0
+ echoerr "$(log_prefix)" "$(log_tag 7)" "$@"
+}
+log_info() {
+ log_priority 6 || return 0
+ echoerr "$(log_prefix)" "$(log_tag 6)" "$@"
+}
+log_err() {
+ log_priority 3 || return 0
+ echoerr "$(log_prefix)" "$(log_tag 3)" "$@"
+}
+log_crit() {
+ log_priority 2 || return 0
+ echoerr "$(log_prefix)" "$(log_tag 2)" "$@"
+}
+uname_os() {
+ os=$(uname -s | tr '[:upper:]' '[:lower:]')
+ case "$os" in
+ msys*) os="windows" ;;
+ mingw*) os="windows" ;;
+ cygwin*) os="windows" ;;
+ win*) os="windows" ;;
+ esac
+ echo "$os"
+}
+uname_arch() {
+ arch=$(uname -m)
+ case $arch in
+ x86_64) arch="amd64" ;;
+ x86) arch="386" ;;
+ i686) arch="386" ;;
+ i386) arch="386" ;;
+ aarch64) arch="arm64" ;;
+ armv5*) arch="armv5" ;;
+ armv6*) arch="armv6" ;;
+ armv7*) arch="armv7" ;;
+ esac
+ echo ${arch}
+}
+uname_os_check() {
+ os=$(uname_os)
+ case "$os" in
+ darwin) return 0 ;;
+ dragonfly) return 0 ;;
+ freebsd) return 0 ;;
+ linux) return 0 ;;
+ android) return 0 ;;
+ nacl) return 0 ;;
+ netbsd) return 0 ;;
+ openbsd) return 0 ;;
+ plan9) return 0 ;;
+ solaris) return 0 ;;
+ windows) return 0 ;;
+ esac
+ log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value."
+ return 1
+}
+uname_arch_check() {
+ arch=$(uname_arch)
+ case "$arch" in
+ 386) return 0 ;;
+ amd64) return 0 ;;
+ arm64) return 0 ;;
+ armv5) return 0 ;;
+ armv6) return 0 ;;
+ armv7) return 0 ;;
+ ppc64) return 0 ;;
+ ppc64le) return 0 ;;
+ mips) return 0 ;;
+ mipsle) return 0 ;;
+ mips64) return 0 ;;
+ mips64le) return 0 ;;
+ s390x) return 0 ;;
+ riscv64) return 0 ;;
+ amd64p32) return 0 ;;
+ esac
+ log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value."
+ return 1
+}
+untar() {
+ tarball=$1
+ case "${tarball}" in
+ *.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;;
+ *.tar) tar --no-same-owner -xf "${tarball}" ;;
+ *.zip) unzip "${tarball}" ;;
+ *)
+ log_err "untar unknown archive format for ${tarball}"
+ return 1
+ ;;
+ esac
+}
+http_download_curl() {
+ local_file=$1
+ source_url=$2
+ header=$3
+ if [ -z "$header" ]; then
+ code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url")
+ else
+ code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url")
+ fi
+ if [ "$code" != "200" ]; then
+ log_debug "http_download_curl received HTTP status $code"
+ return 1
+ fi
+ return 0
+}
+http_download_wget() {
+ local_file=$1
+ source_url=$2
+ header=$3
+ if [ -z "$header" ]; then
+ wget -q -O "$local_file" "$source_url"
+ else
+ wget -q --header "$header" -O "$local_file" "$source_url"
+ fi
+}
+http_download() {
+ log_debug "http_download $2"
+ if is_command curl; then
+ http_download_curl "$@"
+ return
+ elif is_command wget; then
+ http_download_wget "$@"
+ return
+ fi
+ log_crit "http_download unable to find wget or curl"
+ return 1
+}
+http_copy() {
+ tmp=$(mktemp)
+ http_download "${tmp}" "$1" "$2" || return 1
+ body=$(cat "$tmp")
+ rm -f "${tmp}"
+ echo "$body"
+}
+github_release() {
+ owner_repo=$1
+ version=$2
+ if [ -z "$version" ]; then
+ giturl="https://api.github.com/repos/${owner_repo}/releases/latest"
+ else
+ giturl="https://api.github.com/repos/${owner_repo}/releases/tags/${version}"
+ fi
+ json=$(http_copy "$giturl" "Accept:application/json")
+ test -z "$json" && return 1
+ version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name": "//' | sed 's/".*//')
+ test -z "$version" && return 1
+ echo "$version"
+}
+hash_sha256() {
+ TARGET=${1:-/dev/stdin}
+ if is_command gsha256sum; then
+ hash=$(gsha256sum "$TARGET") || return 1
+ echo "$hash" | cut -d ' ' -f 1
+ elif is_command sha256sum; then
+ hash=$(sha256sum "$TARGET") || return 1
+ echo "$hash" | cut -d ' ' -f 1
+ elif is_command shasum; then
+ hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
+ echo "$hash" | cut -d ' ' -f 1
+ elif is_command openssl; then
+ hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
+ echo "$hash" | cut -d ' ' -f a
+ else
+ log_crit "hash_sha256 unable to find command to compute sha-256 hash"
+ return 1
+ fi
+}
+hash_sha256_verify() {
+ TARGET=$1
+ checksums=$2
+ if [ -z "$checksums" ]; then
+ log_err "hash_sha256_verify checksum file not specified in arg2"
+ return 1
+ fi
+ BASENAME=${TARGET##*/}
+ want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
+ if [ -z "$want" ]; then
+ log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
+ return 1
+ fi
+ got=$(hash_sha256 "$TARGET")
+ if [ "$want" != "$got" ]; then
+ log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got"
+ return 1
+ fi
+}
+cat /dev/null < 0 && blder.forInput.object == nil {
+ return errors.New("Owns() can only be used together with For()")
+ }
+ for _, own := range blder.ownsInput {
+ obj, err := blder.project(own.object, own.objectProjection)
+ if err != nil {
+ return err
+ }
+ src := source.Kind(blder.mgr.GetCache(), obj)
+ opts := []handler.OwnerOption{}
+ if !own.matchEveryOwner {
+ opts = append(opts, handler.OnlyControllerOwner())
+ }
+ hdler := handler.EnqueueRequestForOwner(
+ blder.mgr.GetScheme(), blder.mgr.GetRESTMapper(),
+ blder.forInput.object,
+ opts...,
+ )
+ allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
+ allPredicates = append(allPredicates, own.predicates...)
+ if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil {
+ return err
+ }
+ }
+
+ // Do the watch requests
+ if len(blder.watchesInput) == 0 && blder.forInput.object == nil {
+ return errors.New("there are no watches configured, controller will never get triggered. Use For(), Owns() or Watches() to set them up")
+ }
+ for _, w := range blder.watchesInput {
+ allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
+ allPredicates = append(allPredicates, w.predicates...)
+
+ // If the source of this watch is of type Kind, project it.
+ if srckind, ok := w.src.(*internalsource.Kind); ok {
+ typeForSrc, err := blder.project(srckind.Type, w.objectProjection)
+ if err != nil {
+ return err
+ }
+ srckind.Type = typeForSrc
+ }
+
+ if err := blder.ctrl.Watch(w.src, w.eventhandler, allPredicates...); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (blder *Builder) getControllerName(gvk schema.GroupVersionKind, hasGVK bool) (string, error) {
+ if blder.name != "" {
+ return blder.name, nil
+ }
+ if !hasGVK {
+ return "", errors.New("one of For() or Named() must be called")
+ }
+ return strings.ToLower(gvk.Kind), nil
+}
+
+func (blder *Builder) doController(r reconcile.Reconciler) error {
+ globalOpts := blder.mgr.GetControllerOptions()
+
+ ctrlOptions := blder.ctrlOptions
+ if ctrlOptions.Reconciler == nil {
+ ctrlOptions.Reconciler = r
+ }
+
+ // Retrieve the GVK from the object we're reconciling
+ // to prepopulate logger information, and to optionally generate a default name.
+ var gvk schema.GroupVersionKind
+ hasGVK := blder.forInput.object != nil
+ if hasGVK {
+ var err error
+ gvk, err = getGvk(blder.forInput.object, blder.mgr.GetScheme())
+ if err != nil {
+ return err
+ }
+ }
+
+ // Setup concurrency.
+ if ctrlOptions.MaxConcurrentReconciles == 0 && hasGVK {
+ groupKind := gvk.GroupKind().String()
+
+ if concurrency, ok := globalOpts.GroupKindConcurrency[groupKind]; ok && concurrency > 0 {
+ ctrlOptions.MaxConcurrentReconciles = concurrency
+ }
+ }
+
+ // Setup cache sync timeout.
+ if ctrlOptions.CacheSyncTimeout == 0 && globalOpts.CacheSyncTimeout > 0 {
+ ctrlOptions.CacheSyncTimeout = globalOpts.CacheSyncTimeout
+ }
+
+ controllerName, err := blder.getControllerName(gvk, hasGVK)
+ if err != nil {
+ return err
+ }
+
+ // Setup the logger.
+ if ctrlOptions.LogConstructor == nil {
+ log := blder.mgr.GetLogger().WithValues(
+ "controller", controllerName,
+ )
+ if hasGVK {
+ log = log.WithValues(
+ "controllerGroup", gvk.Group,
+ "controllerKind", gvk.Kind,
+ )
+ }
+
+ ctrlOptions.LogConstructor = func(req *reconcile.Request) logr.Logger {
+ log := log
+ if req != nil {
+ if hasGVK {
+ log = log.WithValues(gvk.Kind, klog.KRef(req.Namespace, req.Name))
+ }
+ log = log.WithValues(
+ "namespace", req.Namespace, "name", req.Name,
+ )
+ }
+ return log
+ }
+ }
+
+ // Build the controller and return.
+ blder.ctrl, err = newController(controllerName, blder.mgr, ctrlOptions)
+ return err
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/builder/controller_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/controller_test.go
new file mode 100644
index 00000000000..dd98c2e5657
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/controller_test.go
@@ -0,0 +1,697 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package builder
+
+import (
+ "context"
+ "fmt"
+ "strings"
+ "sync/atomic"
+
+ "github.com/go-logr/logr"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/util/workqueue"
+ "k8s.io/utils/pointer"
+
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/config"
+ "sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+type typedNoop struct{}
+
+func (typedNoop) Reconcile(context.Context, reconcile.Request) (reconcile.Result, error) {
+ return reconcile.Result{}, nil
+}
+
+type testLogger struct {
+ logr.Logger
+}
+
+func (l *testLogger) Init(logr.RuntimeInfo) {
+}
+
+func (l *testLogger) Enabled(int) bool {
+ return true
+}
+
+func (l *testLogger) Info(level int, msg string, keysAndValues ...interface{}) {
+}
+
+func (l *testLogger) WithValues(keysAndValues ...interface{}) logr.LogSink {
+ return l
+}
+
+func (l *testLogger) WithName(name string) logr.LogSink {
+ return l
+}
+
+var _ = Describe("application", func() {
+ BeforeEach(func() {
+ newController = controller.New
+ })
+
+ noop := reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
+ return reconcile.Result{}, nil
+ })
+
+ Describe("New", func() {
+ It("should return success if given valid objects", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ instance, err := ControllerManagedBy(m).
+ For(&appsv1.ReplicaSet{}).
+ Owns(&appsv1.ReplicaSet{}).
+ Build(noop)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(instance).NotTo(BeNil())
+ })
+
+ It("should return error if given two apiType objects in For function", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ instance, err := ControllerManagedBy(m).
+ For(&appsv1.ReplicaSet{}).
+ For(&appsv1.Deployment{}).
+ Owns(&appsv1.ReplicaSet{}).
+ Build(noop)
+ Expect(err).To(MatchError(ContainSubstring("For(...) should only be called once, could not assign multiple objects for reconciliation")))
+ Expect(instance).To(BeNil())
+ })
+
+ It("should return an error if For and Named function are not called", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ instance, err := ControllerManagedBy(m).
+ Watches(&appsv1.ReplicaSet{}, &handler.EnqueueRequestForObject{}).
+ Build(noop)
+ Expect(err).To(MatchError(ContainSubstring("one of For() or Named() must be called")))
+ Expect(instance).To(BeNil())
+ })
+
+ It("should return an error when using Owns without For", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ instance, err := ControllerManagedBy(m).
+ Named("my_controller").
+ Owns(&appsv1.ReplicaSet{}).
+ Build(noop)
+ Expect(err).To(MatchError(ContainSubstring("Owns() can only be used together with For()")))
+ Expect(instance).To(BeNil())
+
+ })
+
+ It("should return an error when there are no watches", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ instance, err := ControllerManagedBy(m).
+ Named("my_controller").
+ Build(noop)
+ Expect(err).To(MatchError(ContainSubstring("there are no watches configured, controller will never get triggered. Use For(), Owns() or Watches() to set them up")))
+ Expect(instance).To(BeNil())
+ })
+
+ It("should allow creating a controllerw without calling For", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ instance, err := ControllerManagedBy(m).
+ Named("my_controller").
+ Watches(&appsv1.ReplicaSet{}, &handler.EnqueueRequestForObject{}).
+ Build(noop)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(instance).NotTo(BeNil())
+ })
+
+ It("should return an error if there is no GVK for an object, and thus we can't default the controller name", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a controller with a bad For type")
+ instance, err := ControllerManagedBy(m).
+ For(&fakeType{}).
+ Owns(&appsv1.ReplicaSet{}).
+ Build(noop)
+ Expect(err).To(MatchError(ContainSubstring("no kind is registered for the type builder.fakeType")))
+ Expect(instance).To(BeNil())
+
+ // NB(directxman12): we don't test non-for types, since errors for
+ // them now manifest on controller.Start, not controller.Watch. Errors on the For type
+ // manifest when we try to default the controller name, which is good to double check.
+ })
+
+ It("should return an error if it cannot create the controller", func() {
+ newController = func(name string, mgr manager.Manager, options controller.Options) (
+ controller.Controller, error) {
+ return nil, fmt.Errorf("expected error")
+ }
+
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ instance, err := ControllerManagedBy(m).
+ For(&appsv1.ReplicaSet{}).
+ Owns(&appsv1.ReplicaSet{}).
+ Build(noop)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("expected error"))
+ Expect(instance).To(BeNil())
+ })
+
+ It("should override max concurrent reconcilers during creation of controller", func() {
+ const maxConcurrentReconciles = 5
+ newController = func(name string, mgr manager.Manager, options controller.Options) (
+ controller.Controller, error) {
+ if options.MaxConcurrentReconciles == maxConcurrentReconciles {
+ return controller.New(name, mgr, options)
+ }
+ return nil, fmt.Errorf("max concurrent reconcilers expected %d but found %d", maxConcurrentReconciles, options.MaxConcurrentReconciles)
+ }
+
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ instance, err := ControllerManagedBy(m).
+ For(&appsv1.ReplicaSet{}).
+ Owns(&appsv1.ReplicaSet{}).
+ WithOptions(controller.Options{MaxConcurrentReconciles: maxConcurrentReconciles}).
+ Build(noop)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(instance).NotTo(BeNil())
+ })
+
+ It("should override max concurrent reconcilers during creation of controller, when using", func() {
+ const maxConcurrentReconciles = 10
+ newController = func(name string, mgr manager.Manager, options controller.Options) (
+ controller.Controller, error) {
+ if options.MaxConcurrentReconciles == maxConcurrentReconciles {
+ return controller.New(name, mgr, options)
+ }
+ return nil, fmt.Errorf("max concurrent reconcilers expected %d but found %d", maxConcurrentReconciles, options.MaxConcurrentReconciles)
+ }
+
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{
+ Controller: config.Controller{
+ GroupKindConcurrency: map[string]int{
+ "ReplicaSet.apps": maxConcurrentReconciles,
+ },
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ instance, err := ControllerManagedBy(m).
+ For(&appsv1.ReplicaSet{}).
+ Owns(&appsv1.ReplicaSet{}).
+ Build(noop)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(instance).NotTo(BeNil())
+ })
+
+ It("should override rate limiter during creation of controller", func() {
+ rateLimiter := workqueue.DefaultItemBasedRateLimiter()
+ newController = func(name string, mgr manager.Manager, options controller.Options) (controller.Controller, error) {
+ if options.RateLimiter == rateLimiter {
+ return controller.New(name, mgr, options)
+ }
+ return nil, fmt.Errorf("rate limiter expected %T but found %T", rateLimiter, options.RateLimiter)
+ }
+
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ instance, err := ControllerManagedBy(m).
+ For(&appsv1.ReplicaSet{}).
+ Owns(&appsv1.ReplicaSet{}).
+ WithOptions(controller.Options{RateLimiter: rateLimiter}).
+ Build(noop)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(instance).NotTo(BeNil())
+ })
+
+ It("should override logger during creation of controller", func() {
+
+ logger := &testLogger{}
+ newController = func(name string, mgr manager.Manager, options controller.Options) (controller.Controller, error) {
+ if options.LogConstructor(nil).GetSink() == logger {
+ return controller.New(name, mgr, options)
+ }
+ return nil, fmt.Errorf("logger expected %T but found %T", logger, options.LogConstructor)
+ }
+
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ instance, err := ControllerManagedBy(m).
+ For(&appsv1.ReplicaSet{}).
+ Owns(&appsv1.ReplicaSet{}).
+ WithLogConstructor(func(request *reconcile.Request) logr.Logger {
+ return logr.New(logger)
+ }).
+ Build(noop)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(instance).NotTo(BeNil())
+ })
+
+ It("should prefer reconciler from options during creation of controller", func() {
+ newController = func(name string, mgr manager.Manager, options controller.Options) (controller.Controller, error) {
+ if options.Reconciler != (typedNoop{}) {
+ return nil, fmt.Errorf("Custom reconciler expected %T but found %T", typedNoop{}, options.Reconciler)
+ }
+ return controller.New(name, mgr, options)
+ }
+
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ instance, err := ControllerManagedBy(m).
+ For(&appsv1.ReplicaSet{}).
+ Owns(&appsv1.ReplicaSet{}).
+ WithOptions(controller.Options{Reconciler: typedNoop{}}).
+ Build(noop)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(instance).NotTo(BeNil())
+ })
+
+ It("should allow multiple controllers for the same kind", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("registering the type in the Scheme")
+ builder := scheme.Builder{GroupVersion: testDefaultValidatorGVK.GroupVersion()}
+ builder.Register(&TestDefaultValidator{}, &TestDefaultValidatorList{})
+ err = builder.AddToScheme(m.GetScheme())
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating the 1st controller")
+ ctrl1, err := ControllerManagedBy(m).
+ For(&TestDefaultValidator{}).
+ Owns(&appsv1.ReplicaSet{}).
+ Build(noop)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(ctrl1).NotTo(BeNil())
+
+ By("creating the 2nd controller")
+ ctrl2, err := ControllerManagedBy(m).
+ For(&TestDefaultValidator{}).
+ Owns(&appsv1.ReplicaSet{}).
+ Build(noop)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(ctrl2).NotTo(BeNil())
+ })
+ })
+
+ Describe("Start with ControllerManagedBy", func() {
+ It("should Reconcile Owns objects", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ bldr := ControllerManagedBy(m).
+ For(&appsv1.Deployment{}).
+ Owns(&appsv1.ReplicaSet{})
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ doReconcileTest(ctx, "3", m, false, bldr)
+ })
+
+ It("should Reconcile Owns objects for every owner", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ bldr := ControllerManagedBy(m).
+ For(&appsv1.Deployment{}).
+ Owns(&appsv1.ReplicaSet{}, MatchEveryOwner)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ doReconcileTest(ctx, "12", m, false, bldr)
+ })
+
+ It("should Reconcile Watches objects", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ bldr := ControllerManagedBy(m).
+ For(&appsv1.Deployment{}).
+ Watches( // Equivalent of Owns
+ &appsv1.ReplicaSet{},
+ handler.EnqueueRequestForOwner(m.GetScheme(), m.GetRESTMapper(), &appsv1.Deployment{}, handler.OnlyControllerOwner()),
+ )
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ doReconcileTest(ctx, "4", m, true, bldr)
+ })
+
+ It("should Reconcile without For", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ bldr := ControllerManagedBy(m).
+ Named("Deployment").
+ Watches( // Equivalent of For
+ &appsv1.Deployment{}, &handler.EnqueueRequestForObject{}).
+ Watches( // Equivalent of Owns
+ &appsv1.ReplicaSet{},
+ handler.EnqueueRequestForOwner(m.GetScheme(), m.GetRESTMapper(), &appsv1.Deployment{}, handler.OnlyControllerOwner()),
+ )
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ doReconcileTest(ctx, "9", m, true, bldr)
+ })
+ })
+
+ Describe("Set custom predicates", func() {
+ It("should execute registered predicates only for assigned kind", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ var (
+ deployPrctExecuted = false
+ replicaSetPrctExecuted = false
+ allPrctExecuted = int64(0)
+ )
+
+ deployPrct := predicate.Funcs{
+ CreateFunc: func(e event.CreateEvent) bool {
+ defer GinkgoRecover()
+ // check that it was called only for deployment
+ Expect(e.Object).To(BeAssignableToTypeOf(&appsv1.Deployment{}))
+ deployPrctExecuted = true
+ return true
+ },
+ }
+
+ replicaSetPrct := predicate.Funcs{
+ CreateFunc: func(e event.CreateEvent) bool {
+ defer GinkgoRecover()
+ // check that it was called only for replicaset
+ Expect(e.Object).To(BeAssignableToTypeOf(&appsv1.ReplicaSet{}))
+ replicaSetPrctExecuted = true
+ return true
+ },
+ }
+
+ allPrct := predicate.Funcs{
+ CreateFunc: func(e event.CreateEvent) bool {
+ defer GinkgoRecover()
+ // check that it was called for all registered kinds
+ Expect(e.Object).Should(Or(
+ BeAssignableToTypeOf(&appsv1.Deployment{}),
+ BeAssignableToTypeOf(&appsv1.ReplicaSet{}),
+ ))
+
+ atomic.AddInt64(&allPrctExecuted, 1)
+ return true
+ },
+ }
+
+ bldr := ControllerManagedBy(m).
+ For(&appsv1.Deployment{}, WithPredicates(deployPrct)).
+ Owns(&appsv1.ReplicaSet{}, WithPredicates(replicaSetPrct)).
+ WithEventFilter(allPrct)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ doReconcileTest(ctx, "5", m, true, bldr)
+
+ Expect(deployPrctExecuted).To(BeTrue(), "Deploy predicated should be called at least once")
+ Expect(replicaSetPrctExecuted).To(BeTrue(), "ReplicaSet predicated should be called at least once")
+ Expect(allPrctExecuted).To(BeNumerically(">=", 2), "Global Predicated should be called at least twice")
+ })
+ })
+
+ Describe("watching with projections", func() {
+ var mgr manager.Manager
+ BeforeEach(func() {
+ // use a cache that intercepts requests for fully typed objects to
+ // ensure we use the projected versions
+ var err error
+ mgr, err = manager.New(cfg, manager.Options{NewCache: newNonTypedOnlyCache})
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ It("should support multiple controllers watching the same metadata kind", func() {
+ bldr1 := ControllerManagedBy(mgr).For(&appsv1.Deployment{}, OnlyMetadata)
+ bldr2 := ControllerManagedBy(mgr).For(&appsv1.Deployment{}, OnlyMetadata)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ doReconcileTest(ctx, "6", mgr, true, bldr1, bldr2)
+ })
+
+ It("should support watching For, Owns, and Watch as metadata", func() {
+ statefulSetMaps := make(chan *metav1.PartialObjectMetadata)
+
+ bldr := ControllerManagedBy(mgr).
+ For(&appsv1.Deployment{}, OnlyMetadata).
+ Owns(&appsv1.ReplicaSet{}, OnlyMetadata).
+ Watches(&appsv1.StatefulSet{},
+ handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, o client.Object) []reconcile.Request {
+ defer GinkgoRecover()
+
+ ometa := o.(*metav1.PartialObjectMetadata)
+ statefulSetMaps <- ometa
+
+ // Validate that the GVK is not empty when dealing with PartialObjectMetadata objects.
+ Expect(o.GetObjectKind().GroupVersionKind()).To(Equal(schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "StatefulSet",
+ }))
+ return nil
+ }),
+ OnlyMetadata)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ doReconcileTest(ctx, "8", mgr, true, bldr)
+
+ By("Creating a new stateful set")
+ set := &appsv1.StatefulSet{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: "test1",
+ Labels: map[string]string{
+ "foo": "bar",
+ },
+ },
+ Spec: appsv1.StatefulSetSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx",
+ },
+ },
+ },
+ },
+ },
+ }
+ err := mgr.GetClient().Create(context.TODO(), set)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Checking that the mapping function has been called")
+ Eventually(func() bool {
+ metaSet := <-statefulSetMaps
+ Expect(metaSet.Name).To(Equal(set.Name))
+ Expect(metaSet.Namespace).To(Equal(set.Namespace))
+ Expect(metaSet.Labels).To(Equal(set.Labels))
+ return true
+ }).Should(BeTrue())
+ })
+ })
+})
+
+// newNonTypedOnlyCache returns a new cache that wraps the normal cache,
+// returning an error if normal, typed objects have informers requested.
+func newNonTypedOnlyCache(config *rest.Config, opts cache.Options) (cache.Cache, error) {
+ normalCache, err := cache.New(config, opts)
+ if err != nil {
+ return nil, err
+ }
+ return &nonTypedOnlyCache{
+ Cache: normalCache,
+ }, nil
+}
+
+// nonTypedOnlyCache is a cache.Cache that only provides metadata &
+// unstructured informers.
+type nonTypedOnlyCache struct {
+ cache.Cache
+}
+
+func (c *nonTypedOnlyCache) GetInformer(ctx context.Context, obj client.Object) (cache.Informer, error) {
+ switch obj.(type) {
+ case (*metav1.PartialObjectMetadata):
+ return c.Cache.GetInformer(ctx, obj)
+ default:
+ return nil, fmt.Errorf("did not want to provide an informer for normal type %T", obj)
+ }
+}
+func (c *nonTypedOnlyCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (cache.Informer, error) {
+ return nil, fmt.Errorf("don't try to sidestep the restriction on informer types by calling GetInformerForKind")
+}
+
+// TODO(directxman12): this function has too many arguments, and the whole
+// "nameSuffix" think is a bit of a hack It should be cleaned up significantly by someone with a bit of time.
+func doReconcileTest(ctx context.Context, nameSuffix string, mgr manager.Manager, complete bool, blders ...*Builder) {
+ deployName := "deploy-name-" + nameSuffix
+ rsName := "rs-name-" + nameSuffix
+
+ By("Creating the application")
+ ch := make(chan reconcile.Request)
+ fn := reconcile.Func(func(_ context.Context, req reconcile.Request) (reconcile.Result, error) {
+ defer GinkgoRecover()
+ if !strings.HasSuffix(req.Name, nameSuffix) {
+ // From different test, ignore this request. Etcd is shared across tests.
+ return reconcile.Result{}, nil
+ }
+ ch <- req
+ return reconcile.Result{}, nil
+ })
+
+ for _, blder := range blders {
+ if complete {
+ err := blder.Complete(fn)
+ Expect(err).NotTo(HaveOccurred())
+ } else {
+ var err error
+ var c controller.Controller
+ c, err = blder.Build(fn)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(c).NotTo(BeNil())
+ }
+ }
+
+ By("Starting the application")
+ go func() {
+ defer GinkgoRecover()
+ Expect(mgr.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ By("Creating a Deployment")
+ // Expect a Reconcile when the Deployment is managedObjects.
+ dep := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: deployName,
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx",
+ },
+ },
+ },
+ },
+ },
+ }
+ err := mgr.GetClient().Create(ctx, dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Waiting for the Deployment Reconcile")
+ Eventually(ch).Should(Receive(Equal(reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: "default", Name: deployName}})))
+
+ By("Creating a ReplicaSet")
+ // Expect a Reconcile when an Owned object is managedObjects.
+ rs := &appsv1.ReplicaSet{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: rsName,
+ Labels: dep.Spec.Selector.MatchLabels,
+ OwnerReferences: []metav1.OwnerReference{
+ {
+ Name: deployName,
+ Kind: "Deployment",
+ APIVersion: "apps/v1",
+ Controller: pointer.Bool(true),
+ UID: dep.UID,
+ },
+ },
+ },
+ Spec: appsv1.ReplicaSetSpec{
+ Selector: dep.Spec.Selector,
+ Template: dep.Spec.Template,
+ },
+ }
+ err = mgr.GetClient().Create(ctx, rs)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Waiting for the ReplicaSet Reconcile")
+ Eventually(ch).Should(Receive(Equal(reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: "default", Name: deployName}})))
+}
+
+var _ runtime.Object = &fakeType{}
+
+type fakeType struct {
+ metav1.TypeMeta
+ metav1.ObjectMeta
+}
+
+func (*fakeType) GetObjectKind() schema.ObjectKind { return nil }
+func (*fakeType) DeepCopyObject() runtime.Object { return nil }
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/builder/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/doc.go
new file mode 100644
index 00000000000..e4df1b709f2
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/doc.go
@@ -0,0 +1,28 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package builder wraps other controller-runtime libraries and exposes simple
+// patterns for building common Controllers.
+//
+// Projects built with the builder package can trivially be rebased on top of the underlying
+// packages if the project requires more customized behavior in the future.
+package builder
+
+import (
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("builder")
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/builder/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/example_test.go
new file mode 100644
index 00000000000..652c9b58334
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/example_test.go
@@ -0,0 +1,159 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package builder_test
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "sigs.k8s.io/controller-runtime/pkg/builder"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/config"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/manager/signals"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+func ExampleBuilder_metadata_only() {
+ logf.SetLogger(zap.New())
+
+ var log = logf.Log.WithName("builder-examples")
+
+ mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{})
+ if err != nil {
+ log.Error(err, "could not create manager")
+ os.Exit(1)
+ }
+
+ cl := mgr.GetClient()
+ err = builder.
+ ControllerManagedBy(mgr). // Create the ControllerManagedBy
+ For(&appsv1.ReplicaSet{}). // ReplicaSet is the Application API
+ Owns(&corev1.Pod{}, builder.OnlyMetadata). // ReplicaSet owns Pods created by it, and caches them as metadata only
+ Complete(reconcile.Func(func(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
+ // Read the ReplicaSet
+ rs := &appsv1.ReplicaSet{}
+ err := cl.Get(ctx, req.NamespacedName, rs)
+ if err != nil {
+ return reconcile.Result{}, client.IgnoreNotFound(err)
+ }
+
+ // List the Pods matching the PodTemplate Labels, but only their metadata
+ var podsMeta metav1.PartialObjectMetadataList
+ err = cl.List(ctx, &podsMeta, client.InNamespace(req.Namespace), client.MatchingLabels(rs.Spec.Template.Labels))
+ if err != nil {
+ return reconcile.Result{}, client.IgnoreNotFound(err)
+ }
+
+ // Update the ReplicaSet
+ rs.Labels["pod-count"] = fmt.Sprintf("%v", len(podsMeta.Items))
+ err = cl.Update(ctx, rs)
+ if err != nil {
+ return reconcile.Result{}, err
+ }
+
+ return reconcile.Result{}, nil
+ }))
+ if err != nil {
+ log.Error(err, "could not create controller")
+ os.Exit(1)
+ }
+
+ if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+ log.Error(err, "could not start manager")
+ os.Exit(1)
+ }
+}
+
+// This example creates a simple application ControllerManagedBy that is configured for ReplicaSets and Pods.
+//
+// * Create a new application for ReplicaSets that manages Pods owned by the ReplicaSet and calls into
+// ReplicaSetReconciler.
+//
+// * Start the application.
+func ExampleBuilder() {
+ logf.SetLogger(zap.New())
+
+ var log = logf.Log.WithName("builder-examples")
+
+ mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{})
+ if err != nil {
+ log.Error(err, "could not create manager")
+ os.Exit(1)
+ }
+
+ err = builder.
+ ControllerManagedBy(mgr). // Create the ControllerManagedBy
+ For(&appsv1.ReplicaSet{}). // ReplicaSet is the Application API
+ Owns(&corev1.Pod{}). // ReplicaSet owns Pods created by it
+ Complete(&ReplicaSetReconciler{
+ Client: mgr.GetClient(),
+ })
+ if err != nil {
+ log.Error(err, "could not create controller")
+ os.Exit(1)
+ }
+
+ if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+ log.Error(err, "could not start manager")
+ os.Exit(1)
+ }
+}
+
+// ReplicaSetReconciler is a simple ControllerManagedBy example implementation.
+type ReplicaSetReconciler struct {
+ client.Client
+}
+
+// Implement the business logic:
+// This function will be called when there is a change to a ReplicaSet or a Pod with an OwnerReference
+// to a ReplicaSet.
+//
+// * Read the ReplicaSet
+// * Read the Pods
+// * Set a Label on the ReplicaSet with the Pod count.
+func (a *ReplicaSetReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
+ // Read the ReplicaSet
+ rs := &appsv1.ReplicaSet{}
+ err := a.Get(ctx, req.NamespacedName, rs)
+ if err != nil {
+ return reconcile.Result{}, err
+ }
+
+ // List the Pods matching the PodTemplate Labels
+ pods := &corev1.PodList{}
+ err = a.List(ctx, pods, client.InNamespace(req.Namespace), client.MatchingLabels(rs.Spec.Template.Labels))
+ if err != nil {
+ return reconcile.Result{}, err
+ }
+
+ // Update the ReplicaSet
+ rs.Labels["pod-count"] = fmt.Sprintf("%v", len(pods.Items))
+ err = a.Update(ctx, rs)
+ if err != nil {
+ return reconcile.Result{}, err
+ }
+
+ return reconcile.Result{}, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/builder/example_webhook_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/example_webhook_test.go
new file mode 100644
index 00000000000..63333a24782
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/example_webhook_test.go
@@ -0,0 +1,61 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package builder_test
+
+import (
+ "os"
+
+ "sigs.k8s.io/controller-runtime/pkg/builder"
+ "sigs.k8s.io/controller-runtime/pkg/client/config"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/manager/signals"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+
+ examplegroup "sigs.k8s.io/controller-runtime/examples/crd/pkg"
+)
+
+// examplegroup.ChaosPod has implemented both admission.Defaulter and
+// admission.Validator interfaces.
+var _ admission.Defaulter = &examplegroup.ChaosPod{}
+var _ admission.Validator = &examplegroup.ChaosPod{}
+
+// This example use webhook builder to create a simple webhook that is managed
+// by a manager for CRD ChaosPod. And then start the manager.
+func ExampleWebhookBuilder() {
+ var log = logf.Log.WithName("webhookbuilder-example")
+
+ mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{})
+ if err != nil {
+ log.Error(err, "could not create manager")
+ os.Exit(1)
+ }
+
+ err = builder.
+ WebhookManagedBy(mgr). // Create the WebhookManagedBy
+ For(&examplegroup.ChaosPod{}). // ChaosPod is a CRD.
+ Complete()
+ if err != nil {
+ log.Error(err, "could not create webhook")
+ os.Exit(1)
+ }
+
+ if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+ log.Error(err, "could not start manager")
+ os.Exit(1)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/builder/options.go b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/options.go
new file mode 100644
index 00000000000..bce2065efaf
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/options.go
@@ -0,0 +1,156 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package builder
+
+import (
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+)
+
+// {{{ "Functional" Option Interfaces
+
+// ForOption is some configuration that modifies options for a For request.
+type ForOption interface {
+ // ApplyToFor applies this configuration to the given for input.
+ ApplyToFor(*ForInput)
+}
+
+// OwnsOption is some configuration that modifies options for a owns request.
+type OwnsOption interface {
+ // ApplyToOwns applies this configuration to the given owns input.
+ ApplyToOwns(*OwnsInput)
+}
+
+// WatchesOption is some configuration that modifies options for a watches request.
+type WatchesOption interface {
+ // ApplyToWatches applies this configuration to the given watches options.
+ ApplyToWatches(*WatchesInput)
+}
+
+// }}}
+
+// {{{ Multi-Type Options
+
+// WithPredicates sets the given predicates list.
+func WithPredicates(predicates ...predicate.Predicate) Predicates {
+ return Predicates{
+ predicates: predicates,
+ }
+}
+
+// Predicates filters events before enqueuing the keys.
+type Predicates struct {
+ predicates []predicate.Predicate
+}
+
+// ApplyToFor applies this configuration to the given ForInput options.
+func (w Predicates) ApplyToFor(opts *ForInput) {
+ opts.predicates = w.predicates
+}
+
+// ApplyToOwns applies this configuration to the given OwnsInput options.
+func (w Predicates) ApplyToOwns(opts *OwnsInput) {
+ opts.predicates = w.predicates
+}
+
+// ApplyToWatches applies this configuration to the given WatchesInput options.
+func (w Predicates) ApplyToWatches(opts *WatchesInput) {
+ opts.predicates = w.predicates
+}
+
+var _ ForOption = &Predicates{}
+var _ OwnsOption = &Predicates{}
+var _ WatchesOption = &Predicates{}
+
+// }}}
+
+// {{{ For & Owns Dual-Type options
+
+// asProjection configures the projection (currently only metadata) on the input.
+// Currently only metadata is supported. We might want to expand
+// this to arbitrary non-special local projections in the future.
+type projectAs objectProjection
+
+// ApplyToFor applies this configuration to the given ForInput options.
+func (p projectAs) ApplyToFor(opts *ForInput) {
+ opts.objectProjection = objectProjection(p)
+}
+
+// ApplyToOwns applies this configuration to the given OwnsInput options.
+func (p projectAs) ApplyToOwns(opts *OwnsInput) {
+ opts.objectProjection = objectProjection(p)
+}
+
+// ApplyToWatches applies this configuration to the given WatchesInput options.
+func (p projectAs) ApplyToWatches(opts *WatchesInput) {
+ opts.objectProjection = objectProjection(p)
+}
+
+var (
+ // OnlyMetadata tells the controller to *only* cache metadata, and to watch
+ // the API server in metadata-only form. This is useful when watching
+ // lots of objects, really big objects, or objects for which you only know
+ // the GVK, but not the structure. You'll need to pass
+ // metav1.PartialObjectMetadata to the client when fetching objects in your
+ // reconciler, otherwise you'll end up with a duplicate structured or
+ // unstructured cache.
+ //
+ // When watching a resource with OnlyMetadata, for example the v1.Pod, you
+ // should not Get and List using the v1.Pod type. Instead, you should use
+ // the special metav1.PartialObjectMetadata type.
+ //
+ // ❌ Incorrect:
+ //
+ // pod := &v1.Pod{}
+ // mgr.GetClient().Get(ctx, nsAndName, pod)
+ //
+ // ✅ Correct:
+ //
+ // pod := &metav1.PartialObjectMetadata{}
+ // pod.SetGroupVersionKind(schema.GroupVersionKind{
+ // Group: "",
+ // Version: "v1",
+ // Kind: "Pod",
+ // })
+ // mgr.GetClient().Get(ctx, nsAndName, pod)
+ //
+ // In the first case, controller-runtime will create another cache for the
+ // concrete type on top of the metadata cache; this increases memory
+ // consumption and leads to race conditions as caches are not in sync.
+ OnlyMetadata = projectAs(projectAsMetadata)
+
+ _ ForOption = OnlyMetadata
+ _ OwnsOption = OnlyMetadata
+ _ WatchesOption = OnlyMetadata
+)
+
+// }}}
+
+// MatchEveryOwner determines whether the watch should be filtered based on
+// controller ownership. As in, when the OwnerReference.Controller field is set.
+//
+// If passed as an option,
+// the handler receives notification for every owner of the object with the given type.
+// If unset (default), the handler receives notification only for the first
+// OwnerReference with `Controller: true`.
+var MatchEveryOwner = &matchEveryOwner{}
+
+type matchEveryOwner struct{}
+
+// ApplyToOwns applies this configuration to the given OwnsInput options.
+func (o matchEveryOwner) ApplyToOwns(opts *OwnsInput) {
+ opts.matchEveryOwner = true
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go
new file mode 100644
index 00000000000..82fac4d8fa6
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go
@@ -0,0 +1,251 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package builder
+
+import (
+ "errors"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/go-logr/logr"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/rest"
+ "k8s.io/klog/v2"
+
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/conversion"
+)
+
+// WebhookBuilder builds a Webhook.
+type WebhookBuilder struct {
+ apiType runtime.Object
+ withDefaulter admission.CustomDefaulter
+ withValidator admission.CustomValidator
+ gvk schema.GroupVersionKind
+ mgr manager.Manager
+ config *rest.Config
+ recoverPanic bool
+ logConstructor func(base logr.Logger, req *admission.Request) logr.Logger
+}
+
+// WebhookManagedBy allows inform its manager.Manager.
+func WebhookManagedBy(m manager.Manager) *WebhookBuilder {
+ return &WebhookBuilder{mgr: m}
+}
+
+// TODO(droot): update the GoDoc for conversion.
+
+// For takes a runtime.Object which should be a CR.
+// If the given object implements the admission.Defaulter interface, a MutatingWebhook will be wired for this type.
+// If the given object implements the admission.Validator interface, a ValidatingWebhook will be wired for this type.
+func (blder *WebhookBuilder) For(apiType runtime.Object) *WebhookBuilder {
+ blder.apiType = apiType
+ return blder
+}
+
+// WithDefaulter takes a admission.WithDefaulter interface, a MutatingWebhook will be wired for this type.
+func (blder *WebhookBuilder) WithDefaulter(defaulter admission.CustomDefaulter) *WebhookBuilder {
+ blder.withDefaulter = defaulter
+ return blder
+}
+
+// WithValidator takes a admission.WithValidator interface, a ValidatingWebhook will be wired for this type.
+func (blder *WebhookBuilder) WithValidator(validator admission.CustomValidator) *WebhookBuilder {
+ blder.withValidator = validator
+ return blder
+}
+
+// WithLogConstructor overrides the webhook's LogConstructor.
+func (blder *WebhookBuilder) WithLogConstructor(logConstructor func(base logr.Logger, req *admission.Request) logr.Logger) *WebhookBuilder {
+ blder.logConstructor = logConstructor
+ return blder
+}
+
+// RecoverPanic indicates whether the panic caused by webhook should be recovered.
+func (blder *WebhookBuilder) RecoverPanic() *WebhookBuilder {
+ blder.recoverPanic = true
+ return blder
+}
+
+// Complete builds the webhook.
+func (blder *WebhookBuilder) Complete() error {
+ // Set the Config
+ blder.loadRestConfig()
+
+ // Configure the default LogConstructor
+ blder.setLogConstructor()
+
+ // Set the Webhook if needed
+ return blder.registerWebhooks()
+}
+
+func (blder *WebhookBuilder) loadRestConfig() {
+ if blder.config == nil {
+ blder.config = blder.mgr.GetConfig()
+ }
+}
+
+func (blder *WebhookBuilder) setLogConstructor() {
+ if blder.logConstructor == nil {
+ blder.logConstructor = func(base logr.Logger, req *admission.Request) logr.Logger {
+ log := base.WithValues(
+ "webhookGroup", blder.gvk.Group,
+ "webhookKind", blder.gvk.Kind,
+ )
+ if req != nil {
+ return log.WithValues(
+ blder.gvk.Kind, klog.KRef(req.Namespace, req.Name),
+ "namespace", req.Namespace, "name", req.Name,
+ "resource", req.Resource, "user", req.UserInfo.Username,
+ "requestID", req.UID,
+ )
+ }
+ return log
+ }
+ }
+}
+
+func (blder *WebhookBuilder) registerWebhooks() error {
+ typ, err := blder.getType()
+ if err != nil {
+ return err
+ }
+
+ // Create webhook(s) for each type
+ blder.gvk, err = apiutil.GVKForObject(typ, blder.mgr.GetScheme())
+ if err != nil {
+ return err
+ }
+
+ blder.registerDefaultingWebhook()
+ blder.registerValidatingWebhook()
+
+ err = blder.registerConversionWebhook()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// registerDefaultingWebhook registers a defaulting webhook if th.
+func (blder *WebhookBuilder) registerDefaultingWebhook() {
+ mwh := blder.getDefaultingWebhook()
+ if mwh != nil {
+ mwh.LogConstructor = blder.logConstructor
+ path := generateMutatePath(blder.gvk)
+
+ // Checking if the path is already registered.
+ // If so, just skip it.
+ if !blder.isAlreadyHandled(path) {
+ log.Info("Registering a mutating webhook",
+ "GVK", blder.gvk,
+ "path", path)
+ blder.mgr.GetWebhookServer().Register(path, mwh)
+ }
+ }
+}
+
+func (blder *WebhookBuilder) getDefaultingWebhook() *admission.Webhook {
+ if defaulter := blder.withDefaulter; defaulter != nil {
+ return admission.WithCustomDefaulter(blder.mgr.GetScheme(), blder.apiType, defaulter).WithRecoverPanic(blder.recoverPanic)
+ }
+ if defaulter, ok := blder.apiType.(admission.Defaulter); ok {
+ return admission.DefaultingWebhookFor(blder.mgr.GetScheme(), defaulter).WithRecoverPanic(blder.recoverPanic)
+ }
+ log.Info(
+ "skip registering a mutating webhook, object does not implement admission.Defaulter or WithDefaulter wasn't called",
+ "GVK", blder.gvk)
+ return nil
+}
+
+func (blder *WebhookBuilder) registerValidatingWebhook() {
+ vwh := blder.getValidatingWebhook()
+ if vwh != nil {
+ vwh.LogConstructor = blder.logConstructor
+ path := generateValidatePath(blder.gvk)
+
+ // Checking if the path is already registered.
+ // If so, just skip it.
+ if !blder.isAlreadyHandled(path) {
+ log.Info("Registering a validating webhook",
+ "GVK", blder.gvk,
+ "path", path)
+ blder.mgr.GetWebhookServer().Register(path, vwh)
+ }
+ }
+}
+
+func (blder *WebhookBuilder) getValidatingWebhook() *admission.Webhook {
+ if validator := blder.withValidator; validator != nil {
+ return admission.WithCustomValidator(blder.mgr.GetScheme(), blder.apiType, validator).WithRecoverPanic(blder.recoverPanic)
+ }
+ if validator, ok := blder.apiType.(admission.Validator); ok {
+ return admission.ValidatingWebhookFor(blder.mgr.GetScheme(), validator).WithRecoverPanic(blder.recoverPanic)
+ }
+ log.Info(
+ "skip registering a validating webhook, object does not implement admission.Validator or WithValidator wasn't called",
+ "GVK", blder.gvk)
+ return nil
+}
+
+func (blder *WebhookBuilder) registerConversionWebhook() error {
+ ok, err := conversion.IsConvertible(blder.mgr.GetScheme(), blder.apiType)
+ if err != nil {
+ log.Error(err, "conversion check failed", "GVK", blder.gvk)
+ return err
+ }
+ if ok {
+ if !blder.isAlreadyHandled("/convert") {
+ blder.mgr.GetWebhookServer().Register("/convert", conversion.NewWebhookHandler(blder.mgr.GetScheme()))
+ }
+ log.Info("Conversion webhook enabled", "GVK", blder.gvk)
+ }
+
+ return nil
+}
+
+func (blder *WebhookBuilder) getType() (runtime.Object, error) {
+ if blder.apiType != nil {
+ return blder.apiType, nil
+ }
+ return nil, errors.New("For() must be called with a valid object")
+}
+
+func (blder *WebhookBuilder) isAlreadyHandled(path string) bool {
+ if blder.mgr.GetWebhookServer().WebhookMux() == nil {
+ return false
+ }
+ h, p := blder.mgr.GetWebhookServer().WebhookMux().Handler(&http.Request{URL: &url.URL{Path: path}})
+ if p == path && h != nil {
+ return true
+ }
+ return false
+}
+
+func generateMutatePath(gvk schema.GroupVersionKind) string {
+ return "/mutate-" + strings.ReplaceAll(gvk.Group, ".", "-") + "-" +
+ gvk.Version + "-" + strings.ToLower(gvk.Kind)
+}
+
+func generateValidatePath(gvk schema.GroupVersionKind) string {
+ return "/validate-" + strings.ReplaceAll(gvk.Group, ".", "-") + "-" +
+ gvk.Version + "-" + strings.ToLower(gvk.Kind)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/builder/webhook_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/webhook_test.go
new file mode 100644
index 00000000000..54df3919cc0
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/builder/webhook_test.go
@@ -0,0 +1,930 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package builder
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "strings"
+
+ "github.com/go-logr/logr"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/onsi/gomega/gbytes"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+
+ "sigs.k8s.io/controller-runtime/pkg/controller"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+var _ = Describe("webhook", func() {
+ Describe("New", func() {
+ Context("v1 AdmissionReview", func() {
+ runTests("v1")
+ })
+ Context("v1beta1 AdmissionReview", func() {
+ runTests("v1beta1")
+ })
+ })
+})
+
+func runTests(admissionReviewVersion string) {
+ var (
+ stop chan struct{}
+ logBuffer *gbytes.Buffer
+ testingLogger logr.Logger
+ )
+
+ BeforeEach(func() {
+ stop = make(chan struct{})
+ newController = controller.New
+ logBuffer = gbytes.NewBuffer()
+ testingLogger = zap.New(zap.JSONEncoder(), zap.WriteTo(io.MultiWriter(logBuffer, GinkgoWriter)))
+ })
+
+ AfterEach(func() {
+ close(stop)
+ })
+
+ It("should scaffold a defaulting webhook if the type implements the Defaulter interface", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ By("registering the type in the Scheme")
+ builder := scheme.Builder{GroupVersion: testDefaulterGVK.GroupVersion()}
+ builder.Register(&TestDefaulter{}, &TestDefaulterList{})
+ err = builder.AddToScheme(m.GetScheme())
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ err = WebhookManagedBy(m).
+ For(&TestDefaulter{}).
+ Complete()
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ svr := m.GetWebhookServer()
+ ExpectWithOffset(1, svr).NotTo(BeNil())
+
+ reader := strings.NewReader(`{
+ "kind":"AdmissionReview",
+ "apiVersion":"admission.k8s.io/` + admissionReviewVersion + `",
+ "request":{
+ "uid":"07e52e8d-4513-11e9-a716-42010a800270",
+ "kind":{
+ "group":"",
+ "version":"v1",
+ "kind":"TestDefaulter"
+ },
+ "resource":{
+ "group":"",
+ "version":"v1",
+ "resource":"testdefaulter"
+ },
+ "namespace":"default",
+ "operation":"CREATE",
+ "object":{
+ "replica":1
+ },
+ "oldObject":null
+ }
+}`)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ err = svr.Start(ctx)
+ if err != nil && !os.IsNotExist(err) {
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ }
+
+ By("sending a request to a mutating webhook path")
+ path := generateMutatePath(testDefaulterGVK)
+ req := httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusOK))
+ By("sanity checking the response contains reasonable fields")
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"allowed":true`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"patch":`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"code":200`))
+
+ By("sending a request to a validating webhook path that doesn't exist")
+ path = generateValidatePath(testDefaulterGVK)
+ _, err = reader.Seek(0, 0)
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ req = httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w = httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusNotFound))
+ })
+
+ It("should scaffold a defaulting webhook which recovers from panics", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ By("registering the type in the Scheme")
+ builder := scheme.Builder{GroupVersion: testDefaulterGVK.GroupVersion()}
+ builder.Register(&TestDefaulter{}, &TestDefaulterList{})
+ err = builder.AddToScheme(m.GetScheme())
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ err = WebhookManagedBy(m).
+ For(&TestDefaulter{Panic: true}).
+ RecoverPanic().
+ Complete()
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ svr := m.GetWebhookServer()
+ ExpectWithOffset(1, svr).NotTo(BeNil())
+
+ reader := strings.NewReader(`{
+ "kind":"AdmissionReview",
+ "apiVersion":"admission.k8s.io/` + admissionReviewVersion + `",
+ "request":{
+ "uid":"07e52e8d-4513-11e9-a716-42010a800270",
+ "kind":{
+ "group":"",
+ "version":"v1",
+ "kind":"TestDefaulter"
+ },
+ "resource":{
+ "group":"",
+ "version":"v1",
+ "resource":"testdefaulter"
+ },
+ "namespace":"default",
+ "operation":"CREATE",
+ "object":{
+ "replica":1,
+ "panic":true
+ },
+ "oldObject":null
+ }
+}`)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ err = svr.Start(ctx)
+ if err != nil && !os.IsNotExist(err) {
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ }
+
+ By("sending a request to a mutating webhook path")
+ path := generateMutatePath(testDefaulterGVK)
+ req := httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusOK))
+ By("sanity checking the response contains reasonable fields")
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"allowed":false`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"code":500`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"message":"panic: fake panic test [recovered]`))
+ })
+
+ It("should scaffold a defaulting webhook with a custom defaulter", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ By("registering the type in the Scheme")
+ builder := scheme.Builder{GroupVersion: testDefaulterGVK.GroupVersion()}
+ builder.Register(&TestDefaulter{}, &TestDefaulterList{})
+ err = builder.AddToScheme(m.GetScheme())
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ err = WebhookManagedBy(m).
+ WithDefaulter(&TestCustomDefaulter{}).
+ For(&TestDefaulter{}).
+ WithLogConstructor(func(base logr.Logger, req *admission.Request) logr.Logger {
+ return admission.DefaultLogConstructor(testingLogger, req)
+ }).
+ Complete()
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ svr := m.GetWebhookServer()
+ ExpectWithOffset(1, svr).NotTo(BeNil())
+
+ reader := strings.NewReader(`{
+ "kind":"AdmissionReview",
+ "apiVersion":"admission.k8s.io/` + admissionReviewVersion + `",
+ "request":{
+ "uid":"07e52e8d-4513-11e9-a716-42010a800270",
+ "kind":{
+ "group":"foo.test.org",
+ "version":"v1",
+ "kind":"TestDefaulter"
+ },
+ "resource":{
+ "group":"foo.test.org",
+ "version":"v1",
+ "resource":"testdefaulter"
+ },
+ "namespace":"default",
+ "name":"foo",
+ "operation":"CREATE",
+ "object":{
+ "replica":1
+ },
+ "oldObject":null
+ }
+}`)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ err = svr.Start(ctx)
+ if err != nil && !os.IsNotExist(err) {
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ }
+
+ By("sending a request to a mutating webhook path")
+ path := generateMutatePath(testDefaulterGVK)
+ req := httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusOK))
+ By("sanity checking the response contains reasonable fields")
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"allowed":true`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"patch":`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"code":200`))
+ EventuallyWithOffset(1, logBuffer).Should(gbytes.Say(`"msg":"Defaulting object","object":{"name":"foo","namespace":"default"},"namespace":"default","name":"foo","resource":{"group":"foo.test.org","version":"v1","resource":"testdefaulter"},"user":"","requestID":"07e52e8d-4513-11e9-a716-42010a800270"`))
+
+ By("sending a request to a validating webhook path that doesn't exist")
+ path = generateValidatePath(testDefaulterGVK)
+ _, err = reader.Seek(0, 0)
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ req = httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w = httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusNotFound))
+ })
+
+ It("should scaffold a validating webhook if the type implements the Validator interface", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ By("registering the type in the Scheme")
+ builder := scheme.Builder{GroupVersion: testValidatorGVK.GroupVersion()}
+ builder.Register(&TestValidator{}, &TestValidatorList{})
+ err = builder.AddToScheme(m.GetScheme())
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ err = WebhookManagedBy(m).
+ For(&TestValidator{}).
+ Complete()
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ svr := m.GetWebhookServer()
+ ExpectWithOffset(1, svr).NotTo(BeNil())
+
+ reader := strings.NewReader(`{
+ "kind":"AdmissionReview",
+ "apiVersion":"admission.k8s.io/` + admissionReviewVersion + `",
+ "request":{
+ "uid":"07e52e8d-4513-11e9-a716-42010a800270",
+ "kind":{
+ "group":"",
+ "version":"v1",
+ "kind":"TestValidator"
+ },
+ "resource":{
+ "group":"",
+ "version":"v1",
+ "resource":"testvalidator"
+ },
+ "namespace":"default",
+ "operation":"UPDATE",
+ "object":{
+ "replica":1
+ },
+ "oldObject":{
+ "replica":2
+ }
+ }
+}`)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ err = svr.Start(ctx)
+ if err != nil && !os.IsNotExist(err) {
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ }
+
+ By("sending a request to a mutating webhook path that doesn't exist")
+ path := generateMutatePath(testValidatorGVK)
+ req := httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusNotFound))
+
+ By("sending a request to a validating webhook path")
+ path = generateValidatePath(testValidatorGVK)
+ _, err = reader.Seek(0, 0)
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ req = httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w = httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusOK))
+ By("sanity checking the response contains reasonable field")
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"allowed":false`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"code":403`))
+ })
+
+ It("should scaffold a validating webhook which recovers from panics", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ By("registering the type in the Scheme")
+ builder := scheme.Builder{GroupVersion: testValidatorGVK.GroupVersion()}
+ builder.Register(&TestValidator{}, &TestValidatorList{})
+ err = builder.AddToScheme(m.GetScheme())
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ err = WebhookManagedBy(m).
+ For(&TestValidator{Panic: true}).
+ RecoverPanic().
+ Complete()
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ svr := m.GetWebhookServer()
+ ExpectWithOffset(1, svr).NotTo(BeNil())
+
+ reader := strings.NewReader(`{
+ "kind":"AdmissionReview",
+ "apiVersion":"admission.k8s.io/` + admissionReviewVersion + `",
+ "request":{
+ "uid":"07e52e8d-4513-11e9-a716-42010a800270",
+ "kind":{
+ "group":"",
+ "version":"v1",
+ "kind":"TestValidator"
+ },
+ "resource":{
+ "group":"",
+ "version":"v1",
+ "resource":"testvalidator"
+ },
+ "namespace":"default",
+ "operation":"CREATE",
+ "object":{
+ "replica":2,
+ "panic":true
+ }
+ }
+}`)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ err = svr.Start(ctx)
+ if err != nil && !os.IsNotExist(err) {
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ }
+
+ By("sending a request to a validating webhook path")
+ path := generateValidatePath(testValidatorGVK)
+ _, err = reader.Seek(0, 0)
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ req := httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusOK))
+ By("sanity checking the response contains reasonable field")
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"allowed":false`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"code":500`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"message":"panic: fake panic test [recovered]`))
+ })
+
+ It("should scaffold a validating webhook with a custom validator", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ By("registering the type in the Scheme")
+ builder := scheme.Builder{GroupVersion: testValidatorGVK.GroupVersion()}
+ builder.Register(&TestValidator{}, &TestValidatorList{})
+ err = builder.AddToScheme(m.GetScheme())
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ err = WebhookManagedBy(m).
+ WithValidator(&TestCustomValidator{}).
+ For(&TestValidator{}).
+ WithLogConstructor(func(base logr.Logger, req *admission.Request) logr.Logger {
+ return admission.DefaultLogConstructor(testingLogger, req)
+ }).
+ Complete()
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ svr := m.GetWebhookServer()
+ ExpectWithOffset(1, svr).NotTo(BeNil())
+
+ reader := strings.NewReader(`{
+ "kind":"AdmissionReview",
+ "apiVersion":"admission.k8s.io/` + admissionReviewVersion + `",
+ "request":{
+ "uid":"07e52e8d-4513-11e9-a716-42010a800270",
+ "kind":{
+ "group":"foo.test.org",
+ "version":"v1",
+ "kind":"TestValidator"
+ },
+ "resource":{
+ "group":"foo.test.org",
+ "version":"v1",
+ "resource":"testvalidator"
+ },
+ "namespace":"default",
+ "name":"foo",
+ "operation":"UPDATE",
+ "object":{
+ "replica":1
+ },
+ "oldObject":{
+ "replica":2
+ }
+ }
+}`)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ err = svr.Start(ctx)
+ if err != nil && !os.IsNotExist(err) {
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ }
+
+ By("sending a request to a mutating webhook path that doesn't exist")
+ path := generateMutatePath(testValidatorGVK)
+ req := httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusNotFound))
+
+ By("sending a request to a validating webhook path")
+ path = generateValidatePath(testValidatorGVK)
+ _, err = reader.Seek(0, 0)
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ req = httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w = httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusOK))
+ By("sanity checking the response contains reasonable field")
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"allowed":false`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"code":403`))
+ EventuallyWithOffset(1, logBuffer).Should(gbytes.Say(`"msg":"Validating object","object":{"name":"foo","namespace":"default"},"namespace":"default","name":"foo","resource":{"group":"foo.test.org","version":"v1","resource":"testvalidator"},"user":"","requestID":"07e52e8d-4513-11e9-a716-42010a800270"`))
+ })
+
+ It("should scaffold defaulting and validating webhooks if the type implements both Defaulter and Validator interfaces", func() {
+ By("creating a controller manager")
+ m, err := manager.New(cfg, manager.Options{})
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ By("registering the type in the Scheme")
+ builder := scheme.Builder{GroupVersion: testDefaultValidatorGVK.GroupVersion()}
+ builder.Register(&TestDefaultValidator{}, &TestDefaultValidatorList{})
+ err = builder.AddToScheme(m.GetScheme())
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ err = WebhookManagedBy(m).
+ For(&TestDefaultValidator{}).
+ Complete()
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ svr := m.GetWebhookServer()
+ ExpectWithOffset(1, svr).NotTo(BeNil())
+
+ reader := strings.NewReader(`{
+ "kind":"AdmissionReview",
+ "apiVersion":"admission.k8s.io/` + admissionReviewVersion + `",
+ "request":{
+ "uid":"07e52e8d-4513-11e9-a716-42010a800270",
+ "kind":{
+ "group":"",
+ "version":"v1",
+ "kind":"TestDefaultValidator"
+ },
+ "resource":{
+ "group":"",
+ "version":"v1",
+ "resource":"testdefaultvalidator"
+ },
+ "namespace":"default",
+ "operation":"CREATE",
+ "object":{
+ "replica":1
+ },
+ "oldObject":null
+ }
+}`)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ err = svr.Start(ctx)
+ if err != nil && !os.IsNotExist(err) {
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ }
+
+ By("sending a request to a mutating webhook path")
+ path := generateMutatePath(testDefaultValidatorGVK)
+ req := httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusOK))
+ By("sanity checking the response contains reasonable field")
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"allowed":true`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"patch":`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"code":200`))
+
+ By("sending a request to a validating webhook path")
+ path = generateValidatePath(testDefaultValidatorGVK)
+ _, err = reader.Seek(0, 0)
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ req = httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w = httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusOK))
+ By("sanity checking the response contains reasonable field")
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"allowed":true`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"code":200`))
+ })
+
+ It("should scaffold a validating webhook if the type implements the Validator interface to validate deletes", func() {
+ By("creating a controller manager")
+ ctx, cancel := context.WithCancel(context.Background())
+
+ m, err := manager.New(cfg, manager.Options{})
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ By("registering the type in the Scheme")
+ builder := scheme.Builder{GroupVersion: testValidatorGVK.GroupVersion()}
+ builder.Register(&TestValidator{}, &TestValidatorList{})
+ err = builder.AddToScheme(m.GetScheme())
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+
+ err = WebhookManagedBy(m).
+ For(&TestValidator{}).
+ Complete()
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ svr := m.GetWebhookServer()
+ ExpectWithOffset(1, svr).NotTo(BeNil())
+
+ reader := strings.NewReader(`{
+ "kind":"AdmissionReview",
+ "apiVersion":"admission.k8s.io/` + admissionReviewVersion + `",
+ "request":{
+ "uid":"07e52e8d-4513-11e9-a716-42010a800270",
+ "kind":{
+ "group":"",
+ "version":"v1",
+ "kind":"TestValidator"
+ },
+ "resource":{
+ "group":"",
+ "version":"v1",
+ "resource":"testvalidator"
+ },
+ "namespace":"default",
+ "operation":"DELETE",
+ "object":null,
+ "oldObject":{
+ "replica":1
+ }
+ }
+}`)
+
+ cancel()
+ err = svr.Start(ctx)
+ if err != nil && !os.IsNotExist(err) {
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ }
+
+ By("sending a request to a validating webhook path to check for failed delete")
+ path := generateValidatePath(testValidatorGVK)
+ req := httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusOK))
+ By("sanity checking the response contains reasonable field")
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"allowed":false`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"code":403`))
+
+ reader = strings.NewReader(`{
+ "kind":"AdmissionReview",
+ "apiVersion":"admission.k8s.io/` + admissionReviewVersion + `",
+ "request":{
+ "uid":"07e52e8d-4513-11e9-a716-42010a800270",
+ "kind":{
+ "group":"",
+ "version":"v1",
+ "kind":"TestValidator"
+ },
+ "resource":{
+ "group":"",
+ "version":"v1",
+ "resource":"testvalidator"
+ },
+ "namespace":"default",
+ "operation":"DELETE",
+ "object":null,
+ "oldObject":{
+ "replica":0
+ }
+ }
+}`)
+ By("sending a request to a validating webhook path with correct request")
+ path = generateValidatePath(testValidatorGVK)
+ req = httptest.NewRequest("POST", "http://svc-name.svc-ns.svc"+path, reader)
+ req.Header.Add("Content-Type", "application/json")
+ w = httptest.NewRecorder()
+ svr.WebhookMux().ServeHTTP(w, req)
+ ExpectWithOffset(1, w.Code).To(Equal(http.StatusOK))
+ By("sanity checking the response contains reasonable field")
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"allowed":true`))
+ ExpectWithOffset(1, w.Body).To(ContainSubstring(`"code":200`))
+ })
+}
+
+// TestDefaulter.
+var _ runtime.Object = &TestDefaulter{}
+
+const testDefaulterKind = "TestDefaulter"
+
+type TestDefaulter struct {
+ Replica int `json:"replica,omitempty"`
+ Panic bool `json:"panic,omitempty"`
+}
+
+var testDefaulterGVK = schema.GroupVersionKind{Group: "foo.test.org", Version: "v1", Kind: testDefaulterKind}
+
+func (d *TestDefaulter) GetObjectKind() schema.ObjectKind { return d }
+func (d *TestDefaulter) DeepCopyObject() runtime.Object {
+ return &TestDefaulter{
+ Replica: d.Replica,
+ }
+}
+
+func (d *TestDefaulter) GroupVersionKind() schema.GroupVersionKind {
+ return testDefaulterGVK
+}
+
+func (d *TestDefaulter) SetGroupVersionKind(gvk schema.GroupVersionKind) {}
+
+var _ runtime.Object = &TestDefaulterList{}
+
+type TestDefaulterList struct{}
+
+func (*TestDefaulterList) GetObjectKind() schema.ObjectKind { return nil }
+func (*TestDefaulterList) DeepCopyObject() runtime.Object { return nil }
+
+func (d *TestDefaulter) Default() {
+ if d.Panic {
+ panic("fake panic test")
+ }
+ if d.Replica < 2 {
+ d.Replica = 2
+ }
+}
+
+// TestValidator.
+var _ runtime.Object = &TestValidator{}
+
+const testValidatorKind = "TestValidator"
+
+type TestValidator struct {
+ Replica int `json:"replica,omitempty"`
+ Panic bool `json:"panic,omitempty"`
+}
+
+var testValidatorGVK = schema.GroupVersionKind{Group: "foo.test.org", Version: "v1", Kind: testValidatorKind}
+
+func (v *TestValidator) GetObjectKind() schema.ObjectKind { return v }
+func (v *TestValidator) DeepCopyObject() runtime.Object {
+ return &TestValidator{
+ Replica: v.Replica,
+ }
+}
+
+func (v *TestValidator) GroupVersionKind() schema.GroupVersionKind {
+ return testValidatorGVK
+}
+
+func (v *TestValidator) SetGroupVersionKind(gvk schema.GroupVersionKind) {}
+
+var _ runtime.Object = &TestValidatorList{}
+
+type TestValidatorList struct{}
+
+func (*TestValidatorList) GetObjectKind() schema.ObjectKind { return nil }
+func (*TestValidatorList) DeepCopyObject() runtime.Object { return nil }
+
+var _ admission.Validator = &TestValidator{}
+
+func (v *TestValidator) ValidateCreate() (admission.Warnings, error) {
+ if v.Panic {
+ panic("fake panic test")
+ }
+ if v.Replica < 0 {
+ return nil, errors.New("number of replica should be greater than or equal to 0")
+ }
+ return nil, nil
+}
+
+func (v *TestValidator) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
+ if v.Panic {
+ panic("fake panic test")
+ }
+ if v.Replica < 0 {
+ return nil, errors.New("number of replica should be greater than or equal to 0")
+ }
+ if oldObj, ok := old.(*TestValidator); !ok {
+ return nil, fmt.Errorf("the old object is expected to be %T", oldObj)
+ } else if v.Replica < oldObj.Replica {
+ return nil, fmt.Errorf("new replica %v should not be fewer than old replica %v", v.Replica, oldObj.Replica)
+ }
+ return nil, nil
+}
+
+func (v *TestValidator) ValidateDelete() (admission.Warnings, error) {
+ if v.Panic {
+ panic("fake panic test")
+ }
+ if v.Replica > 0 {
+ return nil, errors.New("number of replica should be less than or equal to 0 to delete")
+ }
+ return nil, nil
+}
+
+// TestDefaultValidator.
+var _ runtime.Object = &TestDefaultValidator{}
+
+type TestDefaultValidator struct {
+ metav1.TypeMeta
+ metav1.ObjectMeta
+
+ Replica int `json:"replica,omitempty"`
+}
+
+var testDefaultValidatorGVK = schema.GroupVersionKind{Group: "foo.test.org", Version: "v1", Kind: "TestDefaultValidator"}
+
+func (dv *TestDefaultValidator) GetObjectKind() schema.ObjectKind { return dv }
+func (dv *TestDefaultValidator) DeepCopyObject() runtime.Object {
+ return &TestDefaultValidator{
+ Replica: dv.Replica,
+ }
+}
+
+func (dv *TestDefaultValidator) GroupVersionKind() schema.GroupVersionKind {
+ return testDefaultValidatorGVK
+}
+
+func (dv *TestDefaultValidator) SetGroupVersionKind(gvk schema.GroupVersionKind) {}
+
+var _ runtime.Object = &TestDefaultValidatorList{}
+
+type TestDefaultValidatorList struct{}
+
+func (*TestDefaultValidatorList) GetObjectKind() schema.ObjectKind { return nil }
+func (*TestDefaultValidatorList) DeepCopyObject() runtime.Object { return nil }
+
+func (dv *TestDefaultValidator) Default() {
+ if dv.Replica < 2 {
+ dv.Replica = 2
+ }
+}
+
+var _ admission.Validator = &TestDefaultValidator{}
+
+func (dv *TestDefaultValidator) ValidateCreate() (admission.Warnings, error) {
+ if dv.Replica < 0 {
+ return nil, errors.New("number of replica should be greater than or equal to 0")
+ }
+ return nil, nil
+}
+
+func (dv *TestDefaultValidator) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
+ if dv.Replica < 0 {
+ return nil, errors.New("number of replica should be greater than or equal to 0")
+ }
+ return nil, nil
+}
+
+func (dv *TestDefaultValidator) ValidateDelete() (admission.Warnings, error) {
+ if dv.Replica > 0 {
+ return nil, errors.New("number of replica should be less than or equal to 0 to delete")
+ }
+ return nil, nil
+}
+
+// TestCustomDefaulter.
+
+type TestCustomDefaulter struct{}
+
+func (*TestCustomDefaulter) Default(ctx context.Context, obj runtime.Object) error {
+ logf.FromContext(ctx).Info("Defaulting object")
+ req, err := admission.RequestFromContext(ctx)
+ if err != nil {
+ return fmt.Errorf("expected admission.Request in ctx: %w", err)
+ }
+ if req.Kind.Kind != testDefaulterKind {
+ return fmt.Errorf("expected Kind TestDefaulter got %q", req.Kind.Kind)
+ }
+
+ d := obj.(*TestDefaulter) //nolint:ifshort
+ if d.Replica < 2 {
+ d.Replica = 2
+ }
+ return nil
+}
+
+var _ admission.CustomDefaulter = &TestCustomDefaulter{}
+
+// TestCustomValidator.
+
+type TestCustomValidator struct{}
+
+func (*TestCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
+ logf.FromContext(ctx).Info("Validating object")
+ req, err := admission.RequestFromContext(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("expected admission.Request in ctx: %w", err)
+ }
+ if req.Kind.Kind != testValidatorKind {
+ return nil, fmt.Errorf("expected Kind TestValidator got %q", req.Kind.Kind)
+ }
+
+ v := obj.(*TestValidator) //nolint:ifshort
+ if v.Replica < 0 {
+ return nil, errors.New("number of replica should be greater than or equal to 0")
+ }
+ return nil, nil
+}
+
+func (*TestCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
+ logf.FromContext(ctx).Info("Validating object")
+ req, err := admission.RequestFromContext(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("expected admission.Request in ctx: %w", err)
+ }
+ if req.Kind.Kind != testValidatorKind {
+ return nil, fmt.Errorf("expected Kind TestValidator got %q", req.Kind.Kind)
+ }
+
+ v := newObj.(*TestValidator)
+ old := oldObj.(*TestValidator)
+ if v.Replica < 0 {
+ return nil, errors.New("number of replica should be greater than or equal to 0")
+ }
+ if v.Replica < old.Replica {
+ return nil, fmt.Errorf("new replica %v should not be fewer than old replica %v", v.Replica, old.Replica)
+ }
+ return nil, nil
+}
+
+func (*TestCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
+ logf.FromContext(ctx).Info("Validating object")
+ req, err := admission.RequestFromContext(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("expected admission.Request in ctx: %w", err)
+ }
+ if req.Kind.Kind != testValidatorKind {
+ return nil, fmt.Errorf("expected Kind TestValidator got %q", req.Kind.Kind)
+ }
+
+ v := obj.(*TestValidator) //nolint:ifshort
+ if v.Replica > 0 {
+ return nil, errors.New("number of replica should be less than or equal to 0 to delete")
+ }
+ return nil, nil
+}
+
+var _ admission.CustomValidator = &TestCustomValidator{}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cache/cache.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
new file mode 100644
index 00000000000..57e6eb61883
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
@@ -0,0 +1,308 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cache
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "time"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/fields"
+ "k8s.io/apimachinery/pkg/labels"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ toolscache "k8s.io/client-go/tools/cache"
+
+ "sigs.k8s.io/controller-runtime/pkg/cache/internal"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var (
+ log = logf.RuntimeLog.WithName("object-cache")
+ defaultSyncPeriod = 10 * time.Hour
+
+ // BlockUntilSynced determines whether a get request for an informer should block
+ // until the informer's cache has synced.
+ BlockUntilSynced = internal.BlockUntilSynced
+)
+
+// InformerGetOption defines an option that alters the behavior of how informers are retrieved.
+type InformerGetOption internal.InformerGetOption
+
+func castInformerGetOptions(opts []InformerGetOption) []internal.InformerGetOption {
+ out := make([]internal.InformerGetOption, len(opts))
+ for i := range opts {
+ out[i] = internal.InformerGetOption(opts[i])
+ }
+ return out
+}
+
+// Cache knows how to load Kubernetes objects, fetch informers to request
+// to receive events for Kubernetes objects (at a low-level),
+// and add indices to fields on the objects stored in the cache.
+type Cache interface {
+ // Cache acts as a client to objects stored in the cache.
+ client.Reader
+
+ // Cache loads informers and adds field indices.
+ Informers
+}
+
+// Informers knows how to create or fetch informers for different
+// group-version-kinds, and add indices to those informers. It's safe to call
+// GetInformer from multiple threads.
+type Informers interface {
+ // GetInformer fetches or constructs an informer for the given object that corresponds to a single
+ // API kind and resource.
+ GetInformer(ctx context.Context, obj client.Object, opts ...InformerGetOption) (Informer, error)
+
+ // GetInformerForKind is similar to GetInformer, except that it takes a group-version-kind, instead
+ // of the underlying object.
+ GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind, opts ...InformerGetOption) (Informer, error)
+
+ // Start runs all the informers known to this cache until the context is closed.
+ // It blocks.
+ Start(ctx context.Context) error
+
+ // WaitForCacheSync waits for all the caches to sync. Returns false if it could not sync a cache.
+ WaitForCacheSync(ctx context.Context) bool
+
+ // Informers knows how to add indices to the caches (informers) that it manages.
+ client.FieldIndexer
+}
+
+// Informer - informer allows you interact with the underlying informer.
+type Informer interface {
+ // AddEventHandler adds an event handler to the shared informer using the shared informer's resync
+ // period. Events to a single handler are delivered sequentially, but there is no coordination
+ // between different handlers.
+ // It returns a registration handle for the handler that can be used to remove
+ // the handler again.
+ AddEventHandler(handler toolscache.ResourceEventHandler) (toolscache.ResourceEventHandlerRegistration, error)
+ // AddEventHandlerWithResyncPeriod adds an event handler to the shared informer using the
+ // specified resync period. Events to a single handler are delivered sequentially, but there is
+ // no coordination between different handlers.
+ // It returns a registration handle for the handler that can be used to remove
+ // the handler again and an error if the handler cannot be added.
+ AddEventHandlerWithResyncPeriod(handler toolscache.ResourceEventHandler, resyncPeriod time.Duration) (toolscache.ResourceEventHandlerRegistration, error)
+ // RemoveEventHandler removes a formerly added event handler given by
+ // its registration handle.
+ // This function is guaranteed to be idempotent, and thread-safe.
+ RemoveEventHandler(handle toolscache.ResourceEventHandlerRegistration) error
+ // AddIndexers adds more indexers to this store. If you call this after you already have data
+ // in the store, the results are undefined.
+ AddIndexers(indexers toolscache.Indexers) error
+ // HasSynced return true if the informers underlying store has synced.
+ HasSynced() bool
+}
+
+// Options are the optional arguments for creating a new InformersMap object.
+type Options struct {
+ // HTTPClient is the http client to use for the REST client
+ HTTPClient *http.Client
+
+ // Scheme is the scheme to use for mapping objects to GroupVersionKinds
+ Scheme *runtime.Scheme
+
+ // Mapper is the RESTMapper to use for mapping GroupVersionKinds to Resources
+ Mapper meta.RESTMapper
+
+ // SyncPeriod determines the minimum frequency at which watched resources are
+ // reconciled. A lower period will correct entropy more quickly, but reduce
+ // responsiveness to change if there are many watched resources. Change this
+ // value only if you know what you are doing. Defaults to 10 hours if unset.
+ // there will a 10 percent jitter between the SyncPeriod of all controllers
+ // so that all controllers will not send list requests simultaneously.
+ //
+ // This applies to all controllers.
+ //
+ // A period sync happens for two reasons:
+ // 1. To insure against a bug in the controller that causes an object to not
+ // be requeued, when it otherwise should be requeued.
+ // 2. To insure against an unknown bug in controller-runtime, or its dependencies,
+ // that causes an object to not be requeued, when it otherwise should be
+ // requeued, or to be removed from the queue, when it otherwise should not
+ // be removed.
+ //
+ // If you want
+ // 1. to insure against missed watch events, or
+ // 2. to poll services that cannot be watched,
+ // then we recommend that, instead of changing the default period, the
+ // controller requeue, with a constant duration `t`, whenever the controller
+ // is "done" with an object, and would otherwise not requeue it, i.e., we
+ // recommend the `Reconcile` function return `reconcile.Result{RequeueAfter: t}`,
+ // instead of `reconcile.Result{}`.
+ SyncPeriod *time.Duration
+
+ // Namespaces restricts the cache's ListWatch to the desired namespaces
+ // Default watches all namespaces
+ Namespaces []string
+
+ // DefaultLabelSelector will be used as a label selectors for all object types
+ // unless they have a more specific selector set in ByObject.
+ DefaultLabelSelector labels.Selector
+
+ // DefaultFieldSelector will be used as a field selectors for all object types
+ // unless they have a more specific selector set in ByObject.
+ DefaultFieldSelector fields.Selector
+
+ // DefaultTransform will be used as transform for all object types
+ // unless they have a more specific transform set in ByObject.
+ DefaultTransform toolscache.TransformFunc
+
+ // ByObject restricts the cache's ListWatch to the desired fields per GVK at the specified object.
+ ByObject map[client.Object]ByObject
+
+ // UnsafeDisableDeepCopy indicates not to deep copy objects during get or
+ // list objects for EVERY object.
+ // Be very careful with this, when enabled you must DeepCopy any object before mutating it,
+ // otherwise you will mutate the object in the cache.
+ //
+ // This is a global setting for all objects, and can be overridden by the ByObject setting.
+ UnsafeDisableDeepCopy *bool
+}
+
+// ByObject offers more fine-grained control over the cache's ListWatch by object.
+type ByObject struct {
+ // Label represents a label selector for the object.
+ Label labels.Selector
+
+ // Field represents a field selector for the object.
+ Field fields.Selector
+
+ // Transform is a map from objects to transformer functions which
+ // get applied when objects of the transformation are about to be committed
+ // to cache.
+ //
+ // This function is called both for new objects to enter the cache,
+ // and for updated objects.
+ Transform toolscache.TransformFunc
+
+ // UnsafeDisableDeepCopy indicates not to deep copy objects during get or
+ // list objects per GVK at the specified object.
+ // Be very careful with this, when enabled you must DeepCopy any object before mutating it,
+ // otherwise you will mutate the object in the cache.
+ UnsafeDisableDeepCopy *bool
+}
+
+// NewCacheFunc - Function for creating a new cache from the options and a rest config.
+type NewCacheFunc func(config *rest.Config, opts Options) (Cache, error)
+
+// New initializes and returns a new Cache.
+func New(config *rest.Config, opts Options) (Cache, error) {
+ if len(opts.Namespaces) == 0 {
+ opts.Namespaces = []string{metav1.NamespaceAll}
+ }
+ if len(opts.Namespaces) > 1 {
+ return newMultiNamespaceCache(config, opts)
+ }
+
+ opts, err := defaultOpts(config, opts)
+ if err != nil {
+ return nil, err
+ }
+
+ byGVK, err := convertToInformerOptsByGVK(opts.ByObject, opts.Scheme)
+ if err != nil {
+ return nil, err
+ }
+ // Set the default selector and transform.
+ byGVK[schema.GroupVersionKind{}] = internal.InformersOptsByGVK{
+ Selector: internal.Selector{
+ Label: opts.DefaultLabelSelector,
+ Field: opts.DefaultFieldSelector,
+ },
+ Transform: opts.DefaultTransform,
+ UnsafeDisableDeepCopy: opts.UnsafeDisableDeepCopy,
+ }
+
+ return &informerCache{
+ scheme: opts.Scheme,
+ Informers: internal.NewInformers(config, &internal.InformersOpts{
+ HTTPClient: opts.HTTPClient,
+ Scheme: opts.Scheme,
+ Mapper: opts.Mapper,
+ ResyncPeriod: *opts.SyncPeriod,
+ Namespace: opts.Namespaces[0],
+ ByGVK: byGVK,
+ }),
+ }, nil
+}
+
+func defaultOpts(config *rest.Config, opts Options) (Options, error) {
+ logger := log.WithName("setup")
+
+ // Use the rest HTTP client for the provided config if unset
+ if opts.HTTPClient == nil {
+ var err error
+ opts.HTTPClient, err = rest.HTTPClientFor(config)
+ if err != nil {
+ logger.Error(err, "Failed to get HTTP client")
+ return opts, fmt.Errorf("could not create HTTP client from config: %w", err)
+ }
+ }
+
+ // Use the default Kubernetes Scheme if unset
+ if opts.Scheme == nil {
+ opts.Scheme = scheme.Scheme
+ }
+
+ // Construct a new Mapper if unset
+ if opts.Mapper == nil {
+ var err error
+ opts.Mapper, err = apiutil.NewDiscoveryRESTMapper(config, opts.HTTPClient)
+ if err != nil {
+ logger.Error(err, "Failed to get API Group-Resources")
+ return opts, fmt.Errorf("could not create RESTMapper from config: %w", err)
+ }
+ }
+
+ // Default the resync period to 10 hours if unset
+ if opts.SyncPeriod == nil {
+ opts.SyncPeriod = &defaultSyncPeriod
+ }
+ return opts, nil
+}
+
+func convertToInformerOptsByGVK(in map[client.Object]ByObject, scheme *runtime.Scheme) (map[schema.GroupVersionKind]internal.InformersOptsByGVK, error) {
+ out := map[schema.GroupVersionKind]internal.InformersOptsByGVK{}
+ for object, byObject := range in {
+ gvk, err := apiutil.GVKForObject(object, scheme)
+ if err != nil {
+ return nil, err
+ }
+ if _, ok := out[gvk]; ok {
+ return nil, fmt.Errorf("duplicate cache options for GVK %v, cache.Options.ByObject has multiple types with the same GroupVersionKind", gvk)
+ }
+ out[gvk] = internal.InformersOptsByGVK{
+ Selector: internal.Selector{
+ Field: byObject.Field,
+ Label: byObject.Label,
+ },
+ Transform: byObject.Transform,
+ UnsafeDisableDeepCopy: byObject.UnsafeDisableDeepCopy,
+ }
+ }
+ return out, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/cache_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/cache_suite_test.go
similarity index 76%
rename from third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/cache_suite_test.go
rename to third_party/sigs.k8s.io/controller-runtime/pkg/cache/cache_suite_test.go
index 0f603cb2e61..a9a5152ce85 100644
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/cache_suite_test.go
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/cache_suite_test.go
@@ -14,28 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
-package dynamiccache_test
+package cache_test
import (
"testing"
- . "github.com/onsi/ginkgo"
+ . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/envtest"
- "sigs.k8s.io/controller-runtime/pkg/envtest/printer"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)
func TestSource(t *testing.T) {
RegisterFailHandler(Fail)
- suiteName := "Cache Suite"
- RunSpecsWithDefaultAndCustomReporters(t, suiteName, []Reporter{printer.NewlineReporter{}, printer.NewProwReporter(suiteName)})
+ RunSpecs(t, "Cache Suite")
}
var testenv *envtest.Environment
@@ -53,7 +48,7 @@ var _ = BeforeSuite(func() {
clientset, err = kubernetes.NewForConfig(cfg)
Expect(err).NotTo(HaveOccurred())
-}, 60)
+})
var _ = AfterSuite(func() {
Expect(testenv.Stop()).To(Succeed())
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cache/cache_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/cache_test.go
new file mode 100644
index 00000000000..7f9ed975d6d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/cache_test.go
@@ -0,0 +1,1817 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cache_test
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ corev1 "k8s.io/api/core/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/fields"
+ "k8s.io/apimachinery/pkg/labels"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ kscheme "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ kcache "k8s.io/client-go/tools/cache"
+ "k8s.io/utils/pointer"
+
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+const testNodeOne = "test-node-1"
+const testNamespaceOne = "test-namespace-1"
+const testNamespaceTwo = "test-namespace-2"
+const testNamespaceThree = "test-namespace-3"
+
+// TODO(community): Pull these helper functions into testenv.
+// Restart policy is included to allow indexing on that field.
+func createPodWithLabels(name, namespace string, restartPolicy corev1.RestartPolicy, labels map[string]string) client.Object {
+ three := int64(3)
+ if labels == nil {
+ labels = map[string]string{}
+ }
+ labels["test-label"] = name
+ pod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: name,
+ Namespace: namespace,
+ Labels: labels,
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}},
+ RestartPolicy: restartPolicy,
+ ActiveDeadlineSeconds: &three,
+ },
+ }
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ err = cl.Create(context.Background(), pod)
+ Expect(err).NotTo(HaveOccurred())
+ return pod
+}
+
+func createSvc(name, namespace string, cl client.Client) client.Object {
+ svc := &corev1.Service{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: name,
+ Namespace: namespace,
+ },
+ Spec: corev1.ServiceSpec{
+ Ports: []corev1.ServicePort{{Port: 1}},
+ },
+ }
+ err := cl.Create(context.Background(), svc)
+ Expect(err).NotTo(HaveOccurred())
+ return svc
+}
+
+func createSA(name, namespace string, cl client.Client) client.Object {
+ sa := &corev1.ServiceAccount{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: name,
+ Namespace: namespace,
+ },
+ }
+ err := cl.Create(context.Background(), sa)
+ Expect(err).NotTo(HaveOccurred())
+ return sa
+}
+
+func createPod(name, namespace string, restartPolicy corev1.RestartPolicy) client.Object {
+ return createPodWithLabels(name, namespace, restartPolicy, nil)
+}
+
+func deletePod(pod client.Object) {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ err = cl.Delete(context.Background(), pod)
+ Expect(err).NotTo(HaveOccurred())
+}
+
+var _ = Describe("Informer Cache", func() {
+ CacheTest(cache.New, cache.Options{})
+})
+var _ = Describe("Multi-Namespace Informer Cache", func() {
+ CacheTest(cache.MultiNamespacedCacheBuilder([]string{testNamespaceOne, testNamespaceTwo, "default"}), cache.Options{})
+})
+
+var _ = Describe("Informer Cache without global DeepCopy", func() {
+ CacheTest(cache.New, cache.Options{
+ UnsafeDisableDeepCopy: pointer.Bool(true),
+ })
+})
+
+var _ = Describe("Cache with transformers", func() {
+ var (
+ informerCache cache.Cache
+ informerCacheCtx context.Context
+ informerCacheCancel context.CancelFunc
+ knownPod1 client.Object
+ knownPod2 client.Object
+ knownPod3 client.Object
+ knownPod4 client.Object
+ knownPod5 client.Object
+ knownPod6 client.Object
+ )
+
+ getTransformValue := func(obj client.Object) string {
+ accessor, err := meta.Accessor(obj)
+ if err == nil {
+ annotations := accessor.GetAnnotations()
+ if val, exists := annotations["transformed"]; exists {
+ return val
+ }
+ }
+ return ""
+ }
+
+ BeforeEach(func() {
+ informerCacheCtx, informerCacheCancel = context.WithCancel(context.Background())
+ Expect(cfg).NotTo(BeNil())
+
+ By("creating three pods")
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ err = ensureNode(testNodeOne, cl)
+ Expect(err).NotTo(HaveOccurred())
+ err = ensureNamespace(testNamespaceOne, cl)
+ Expect(err).NotTo(HaveOccurred())
+ err = ensureNamespace(testNamespaceTwo, cl)
+ Expect(err).NotTo(HaveOccurred())
+ err = ensureNamespace(testNamespaceThree, cl)
+ Expect(err).NotTo(HaveOccurred())
+ // Includes restart policy since these objects are indexed on this field.
+ knownPod1 = createPod("test-pod-1", testNamespaceOne, corev1.RestartPolicyNever)
+ knownPod2 = createPod("test-pod-2", testNamespaceTwo, corev1.RestartPolicyAlways)
+ knownPod3 = createPodWithLabels("test-pod-3", testNamespaceTwo, corev1.RestartPolicyOnFailure, map[string]string{"common-label": "common"})
+ knownPod4 = createPodWithLabels("test-pod-4", testNamespaceThree, corev1.RestartPolicyNever, map[string]string{"common-label": "common"})
+ knownPod5 = createPod("test-pod-5", testNamespaceOne, corev1.RestartPolicyNever)
+ knownPod6 = createPod("test-pod-6", testNamespaceTwo, corev1.RestartPolicyAlways)
+
+ podGVK := schema.GroupVersionKind{
+ Kind: "Pod",
+ Version: "v1",
+ }
+
+ knownPod1.GetObjectKind().SetGroupVersionKind(podGVK)
+ knownPod2.GetObjectKind().SetGroupVersionKind(podGVK)
+ knownPod3.GetObjectKind().SetGroupVersionKind(podGVK)
+ knownPod4.GetObjectKind().SetGroupVersionKind(podGVK)
+ knownPod5.GetObjectKind().SetGroupVersionKind(podGVK)
+ knownPod6.GetObjectKind().SetGroupVersionKind(podGVK)
+
+ By("creating the informer cache")
+ informerCache, err = cache.New(cfg, cache.Options{
+ DefaultTransform: func(i interface{}) (interface{}, error) {
+ obj := i.(runtime.Object)
+ Expect(obj).NotTo(BeNil())
+
+ accessor, err := meta.Accessor(obj)
+ Expect(err).To(BeNil())
+ annotations := accessor.GetAnnotations()
+
+ if _, exists := annotations["transformed"]; exists {
+ // Avoid performing transformation multiple times.
+ return i, nil
+ }
+
+ if annotations == nil {
+ annotations = make(map[string]string)
+ }
+ annotations["transformed"] = "default"
+ accessor.SetAnnotations(annotations)
+ return i, nil
+ },
+ ByObject: map[client.Object]cache.ByObject{
+ &corev1.Pod{}: {
+ Transform: func(i interface{}) (interface{}, error) {
+ obj := i.(runtime.Object)
+ Expect(obj).NotTo(BeNil())
+ accessor, err := meta.Accessor(obj)
+ Expect(err).To(BeNil())
+
+ annotations := accessor.GetAnnotations()
+ if _, exists := annotations["transformed"]; exists {
+ // Avoid performing transformation multiple times.
+ return i, nil
+ }
+
+ if annotations == nil {
+ annotations = make(map[string]string)
+ }
+ annotations["transformed"] = "explicit"
+ accessor.SetAnnotations(annotations)
+ return i, nil
+ },
+ },
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ By("running the cache and waiting for it to sync")
+ // pass as an arg so that we don't race between close and re-assign
+ go func(ctx context.Context) {
+ defer GinkgoRecover()
+ Expect(informerCache.Start(ctx)).To(Succeed())
+ }(informerCacheCtx)
+ Expect(informerCache.WaitForCacheSync(informerCacheCtx)).To(BeTrue())
+ })
+
+ AfterEach(func() {
+ By("cleaning up created pods")
+ deletePod(knownPod1)
+ deletePod(knownPod2)
+ deletePod(knownPod3)
+ deletePod(knownPod4)
+ deletePod(knownPod5)
+ deletePod(knownPod6)
+
+ informerCacheCancel()
+ })
+
+ Context("with structured objects", func() {
+ It("should apply transformers to explicitly specified GVKS", func() {
+ By("listing pods")
+ out := corev1.PodList{}
+ Expect(informerCache.List(context.Background(), &out)).To(Succeed())
+
+ By("verifying that the returned pods were transformed")
+ for i := 0; i < len(out.Items); i++ {
+ Expect(getTransformValue(&out.Items[i])).To(BeIdenticalTo("explicit"))
+ }
+ })
+
+ It("should apply default transformer to objects when none is specified", func() {
+ By("getting the Kubernetes service")
+ svc := &corev1.Service{}
+ svcKey := client.ObjectKey{Namespace: "default", Name: "kubernetes"}
+ Expect(informerCache.Get(context.Background(), svcKey, svc)).To(Succeed())
+
+ By("verifying that the returned service was transformed")
+ Expect(getTransformValue(svc)).To(BeIdenticalTo("default"))
+ })
+ })
+
+ Context("with unstructured objects", func() {
+ It("should apply transformers to explicitly specified GVKS", func() {
+ By("listing pods")
+ out := unstructured.UnstructuredList{}
+ out.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ Expect(informerCache.List(context.Background(), &out)).To(Succeed())
+
+ By("verifying that the returned pods were transformed")
+ for i := 0; i < len(out.Items); i++ {
+ Expect(getTransformValue(&out.Items[i])).To(BeIdenticalTo("explicit"))
+ }
+ })
+
+ It("should apply default transformer to objects when none is specified", func() {
+ By("getting the Kubernetes service")
+ svc := &unstructured.Unstructured{}
+ svc.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Service",
+ })
+ svcKey := client.ObjectKey{Namespace: "default", Name: "kubernetes"}
+ Expect(informerCache.Get(context.Background(), svcKey, svc)).To(Succeed())
+
+ By("verifying that the returned service was transformed")
+ Expect(getTransformValue(svc)).To(BeIdenticalTo("default"))
+ })
+ })
+
+ Context("with metadata-only objects", func() {
+ It("should apply transformers to explicitly specified GVKS", func() {
+ By("listing pods")
+ out := metav1.PartialObjectMetadataList{}
+ out.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ Expect(informerCache.List(context.Background(), &out)).To(Succeed())
+
+ By("verifying that the returned pods were transformed")
+ for i := 0; i < len(out.Items); i++ {
+ Expect(getTransformValue(&out.Items[i])).To(BeIdenticalTo("explicit"))
+ }
+ })
+ It("should apply default transformer to objects when none is specified", func() {
+ By("getting the Kubernetes service")
+ svc := &metav1.PartialObjectMetadata{}
+ svc.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Service",
+ })
+ svcKey := client.ObjectKey{Namespace: "default", Name: "kubernetes"}
+ Expect(informerCache.Get(context.Background(), svcKey, svc)).To(Succeed())
+
+ By("verifying that the returned service was transformed")
+ Expect(getTransformValue(svc)).To(BeIdenticalTo("default"))
+ })
+ })
+})
+
+var _ = Describe("Cache with selectors", func() {
+ defer GinkgoRecover()
+ var (
+ informerCache cache.Cache
+ informerCacheCtx context.Context
+ informerCacheCancel context.CancelFunc
+ )
+
+ BeforeEach(func() {
+ informerCacheCtx, informerCacheCancel = context.WithCancel(context.Background())
+ Expect(cfg).NotTo(BeNil())
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ err = ensureNamespace(testNamespaceOne, cl)
+ Expect(err).NotTo(HaveOccurred())
+ err = ensureNamespace(testNamespaceTwo, cl)
+ Expect(err).NotTo(HaveOccurred())
+ for idx, namespace := range []string{testNamespaceOne, testNamespaceTwo} {
+ _ = createSA("test-sa-"+strconv.Itoa(idx), namespace, cl)
+ _ = createSvc("test-svc-"+strconv.Itoa(idx), namespace, cl)
+ }
+
+ opts := cache.Options{
+ DefaultFieldSelector: fields.OneTermEqualSelector("metadata.namespace", testNamespaceTwo),
+ ByObject: map[client.Object]cache.ByObject{
+ &corev1.ServiceAccount{}: {Field: fields.OneTermEqualSelector("metadata.namespace", testNamespaceOne)},
+ },
+ }
+
+ By("creating the informer cache")
+ informerCache, err = cache.New(cfg, opts)
+ Expect(err).NotTo(HaveOccurred())
+ By("running the cache and waiting for it to sync")
+ // pass as an arg so that we don't race between close and re-assign
+ go func(ctx context.Context) {
+ defer GinkgoRecover()
+ Expect(informerCache.Start(ctx)).To(Succeed())
+ }(informerCacheCtx)
+ Expect(informerCache.WaitForCacheSync(informerCacheCtx)).To(BeTrue())
+ })
+
+ AfterEach(func() {
+ ctx := context.Background()
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ for idx, namespace := range []string{testNamespaceOne, testNamespaceTwo} {
+ err = cl.Delete(ctx, &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: "test-sa-" + strconv.Itoa(idx)}})
+ Expect(err).NotTo(HaveOccurred())
+ err = cl.Delete(ctx, &corev1.Service{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: "test-svc-" + strconv.Itoa(idx)}})
+ Expect(err).NotTo(HaveOccurred())
+ }
+ informerCacheCancel()
+ })
+
+ It("Should list serviceaccounts and find exactly one in namespace "+testNamespaceOne, func() {
+ var sas corev1.ServiceAccountList
+ err := informerCache.List(informerCacheCtx, &sas)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(len(sas.Items)).To(Equal(1))
+ Expect(sas.Items[0].Namespace).To(Equal(testNamespaceOne))
+ })
+
+ It("Should list services and find exactly one in namespace "+testNamespaceTwo, func() {
+ var svcs corev1.ServiceList
+ err := informerCache.List(informerCacheCtx, &svcs)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(len(svcs.Items)).To(Equal(1))
+ Expect(svcs.Items[0].Namespace).To(Equal(testNamespaceTwo))
+ })
+})
+
+func CacheTest(createCacheFunc func(config *rest.Config, opts cache.Options) (cache.Cache, error), opts cache.Options) {
+ Describe("Cache test", func() {
+ var (
+ informerCache cache.Cache
+ informerCacheCtx context.Context
+ informerCacheCancel context.CancelFunc
+ knownPod1 client.Object
+ knownPod2 client.Object
+ knownPod3 client.Object
+ knownPod4 client.Object
+ knownPod5 client.Object
+ knownPod6 client.Object
+ )
+
+ BeforeEach(func() {
+ informerCacheCtx, informerCacheCancel = context.WithCancel(context.Background())
+ Expect(cfg).NotTo(BeNil())
+
+ By("creating three pods")
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ err = ensureNode(testNodeOne, cl)
+ Expect(err).NotTo(HaveOccurred())
+ err = ensureNamespace(testNamespaceOne, cl)
+ Expect(err).NotTo(HaveOccurred())
+ err = ensureNamespace(testNamespaceTwo, cl)
+ Expect(err).NotTo(HaveOccurred())
+ err = ensureNamespace(testNamespaceThree, cl)
+ Expect(err).NotTo(HaveOccurred())
+ // Includes restart policy since these objects are indexed on this field.
+ knownPod1 = createPod("test-pod-1", testNamespaceOne, corev1.RestartPolicyNever)
+ knownPod2 = createPod("test-pod-2", testNamespaceTwo, corev1.RestartPolicyAlways)
+ knownPod3 = createPodWithLabels("test-pod-3", testNamespaceTwo, corev1.RestartPolicyOnFailure, map[string]string{"common-label": "common"})
+ knownPod4 = createPodWithLabels("test-pod-4", testNamespaceThree, corev1.RestartPolicyNever, map[string]string{"common-label": "common"})
+ knownPod5 = createPod("test-pod-5", testNamespaceOne, corev1.RestartPolicyNever)
+ knownPod6 = createPod("test-pod-6", testNamespaceTwo, corev1.RestartPolicyAlways)
+
+ podGVK := schema.GroupVersionKind{
+ Kind: "Pod",
+ Version: "v1",
+ }
+
+ knownPod1.GetObjectKind().SetGroupVersionKind(podGVK)
+ knownPod2.GetObjectKind().SetGroupVersionKind(podGVK)
+ knownPod3.GetObjectKind().SetGroupVersionKind(podGVK)
+ knownPod4.GetObjectKind().SetGroupVersionKind(podGVK)
+ knownPod5.GetObjectKind().SetGroupVersionKind(podGVK)
+ knownPod6.GetObjectKind().SetGroupVersionKind(podGVK)
+
+ By("creating the informer cache")
+ informerCache, err = createCacheFunc(cfg, opts)
+ Expect(err).NotTo(HaveOccurred())
+ By("running the cache and waiting for it to sync")
+ // pass as an arg so that we don't race between close and re-assign
+ go func(ctx context.Context) {
+ defer GinkgoRecover()
+ Expect(informerCache.Start(ctx)).To(Succeed())
+ }(informerCacheCtx)
+ Expect(informerCache.WaitForCacheSync(informerCacheCtx)).To(BeTrue())
+ })
+
+ AfterEach(func() {
+ By("cleaning up created pods")
+ deletePod(knownPod1)
+ deletePod(knownPod2)
+ deletePod(knownPod3)
+ deletePod(knownPod4)
+ deletePod(knownPod5)
+ deletePod(knownPod6)
+
+ informerCacheCancel()
+ })
+
+ Describe("as a Reader", func() {
+ Context("with structured objects", func() {
+ It("should be able to list objects that haven't been watched previously", func() {
+ By("listing all services in the cluster")
+ listObj := &corev1.ServiceList{}
+ Expect(informerCache.List(context.Background(), listObj)).To(Succeed())
+
+ By("verifying that the returned list contains the Kubernetes service")
+ // NB: kubernetes default service is automatically created in testenv.
+ Expect(listObj.Items).NotTo(BeEmpty())
+ hasKubeService := false
+ for i := range listObj.Items {
+ svc := &listObj.Items[i]
+ if isKubeService(svc) {
+ hasKubeService = true
+ break
+ }
+ }
+ Expect(hasKubeService).To(BeTrue())
+ })
+
+ It("should be able to get objects that haven't been watched previously", func() {
+ By("getting the Kubernetes service")
+ svc := &corev1.Service{}
+ svcKey := client.ObjectKey{Namespace: "default", Name: "kubernetes"}
+ Expect(informerCache.Get(context.Background(), svcKey, svc)).To(Succeed())
+
+ By("verifying that the returned service looks reasonable")
+ Expect(svc.Name).To(Equal("kubernetes"))
+ Expect(svc.Namespace).To(Equal("default"))
+ })
+
+ It("should support filtering by labels in a single namespace", func() {
+ By("listing pods with a particular label")
+ // NB: each pod has a "test-label":
+ out := corev1.PodList{}
+ Expect(informerCache.List(context.Background(), &out,
+ client.InNamespace(testNamespaceTwo),
+ client.MatchingLabels(map[string]string{"test-label": "test-pod-2"}))).To(Succeed())
+
+ By("verifying the returned pods have the correct label")
+ Expect(out.Items).NotTo(BeEmpty())
+ Expect(out.Items).Should(HaveLen(1))
+ actual := out.Items[0]
+ Expect(actual.Labels["test-label"]).To(Equal("test-pod-2"))
+ })
+
+ It("should support filtering by labels from multiple namespaces", func() {
+ By("creating another pod with the same label but different namespace")
+ anotherPod := createPod("test-pod-2", testNamespaceOne, corev1.RestartPolicyAlways)
+ defer deletePod(anotherPod)
+
+ By("listing pods with a particular label")
+ // NB: each pod has a "test-label":
+ out := corev1.PodList{}
+ labels := map[string]string{"test-label": "test-pod-2"}
+ Expect(informerCache.List(context.Background(), &out, client.MatchingLabels(labels))).To(Succeed())
+
+ By("verifying multiple pods with the same label in different namespaces are returned")
+ Expect(out.Items).NotTo(BeEmpty())
+ Expect(out.Items).Should(HaveLen(2))
+ for _, actual := range out.Items {
+ Expect(actual.Labels["test-label"]).To(Equal("test-pod-2"))
+ }
+ })
+
+ if !isPodDisableDeepCopy(opts) {
+ It("should be able to list objects with GVK populated", func() {
+ By("listing pods")
+ out := &corev1.PodList{}
+ Expect(informerCache.List(context.Background(), out)).To(Succeed())
+
+ By("verifying that the returned pods have GVK populated")
+ Expect(out.Items).NotTo(BeEmpty())
+ Expect(out.Items).Should(SatisfyAny(HaveLen(5), HaveLen(6)))
+ for _, p := range out.Items {
+ Expect(p.GroupVersionKind()).To(Equal(corev1.SchemeGroupVersion.WithKind("Pod")))
+ }
+ })
+ }
+
+ It("should be able to list objects by namespace", func() {
+ By("listing pods in test-namespace-1")
+ listObj := &corev1.PodList{}
+ Expect(informerCache.List(context.Background(), listObj,
+ client.InNamespace(testNamespaceOne))).To(Succeed())
+
+ By("verifying that the returned pods are in test-namespace-1")
+ Expect(listObj.Items).NotTo(BeEmpty())
+ Expect(listObj.Items).Should(HaveLen(2))
+ for _, item := range listObj.Items {
+ Expect(item.Namespace).To(Equal(testNamespaceOne))
+ }
+ })
+
+ if !isPodDisableDeepCopy(opts) {
+ It("should deep copy the object unless told otherwise", func() {
+ By("retrieving a specific pod from the cache")
+ out := &corev1.Pod{}
+ podKey := client.ObjectKey{Name: "test-pod-2", Namespace: testNamespaceTwo}
+ Expect(informerCache.Get(context.Background(), podKey, out)).To(Succeed())
+
+ By("verifying the retrieved pod is equal to a known pod")
+ Expect(out).To(Equal(knownPod2))
+
+ By("altering a field in the retrieved pod")
+ *out.Spec.ActiveDeadlineSeconds = 4
+
+ By("verifying the pods are no longer equal")
+ Expect(out).NotTo(Equal(knownPod2))
+ })
+ } else {
+ It("should not deep copy the object if UnsafeDisableDeepCopy is enabled", func() {
+ By("getting a specific pod from the cache twice")
+ podKey := client.ObjectKey{Name: "test-pod-2", Namespace: testNamespaceTwo}
+ out1 := &corev1.Pod{}
+ Expect(informerCache.Get(context.Background(), podKey, out1)).To(Succeed())
+ out2 := &corev1.Pod{}
+ Expect(informerCache.Get(context.Background(), podKey, out2)).To(Succeed())
+
+ By("verifying the pointer fields in pod have the same addresses")
+ Expect(out1).To(Equal(out2))
+ Expect(reflect.ValueOf(out1.Labels).Pointer()).To(BeIdenticalTo(reflect.ValueOf(out2.Labels).Pointer()))
+
+ By("listing pods from the cache twice")
+ outList1 := &corev1.PodList{}
+ Expect(informerCache.List(context.Background(), outList1, client.InNamespace(testNamespaceOne))).To(Succeed())
+ outList2 := &corev1.PodList{}
+ Expect(informerCache.List(context.Background(), outList2, client.InNamespace(testNamespaceOne))).To(Succeed())
+
+ By("verifying the pointer fields in pod have the same addresses")
+ Expect(len(outList1.Items)).To(Equal(len(outList2.Items)))
+ sort.SliceStable(outList1.Items, func(i, j int) bool { return outList1.Items[i].Name <= outList1.Items[j].Name })
+ sort.SliceStable(outList2.Items, func(i, j int) bool { return outList2.Items[i].Name <= outList2.Items[j].Name })
+ for i := range outList1.Items {
+ a := &outList1.Items[i]
+ b := &outList2.Items[i]
+ Expect(a).To(Equal(b))
+ Expect(reflect.ValueOf(a.Labels).Pointer()).To(BeIdenticalTo(reflect.ValueOf(b.Labels).Pointer()))
+ }
+ })
+ }
+
+ It("should return an error if the object is not found", func() {
+ By("getting a service that does not exists")
+ svc := &corev1.Service{}
+ svcKey := client.ObjectKey{Namespace: testNamespaceOne, Name: "unknown"}
+
+ By("verifying that an error is returned")
+ err := informerCache.Get(context.Background(), svcKey, svc)
+ Expect(err).To(HaveOccurred())
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+
+ It("should return an error if getting object in unwatched namespace", func() {
+ By("getting a service that does not exists")
+ svc := &corev1.Service{}
+ svcKey := client.ObjectKey{Namespace: "unknown", Name: "unknown"}
+
+ By("verifying that an error is returned")
+ err := informerCache.Get(context.Background(), svcKey, svc)
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should return an error when context is cancelled", func() {
+ By("cancelling the context")
+ informerCacheCancel()
+
+ By("listing pods in test-namespace-1 with a cancelled context")
+ listObj := &corev1.PodList{}
+ err := informerCache.List(informerCacheCtx, listObj, client.InNamespace(testNamespaceOne))
+
+ By("verifying that an error is returned")
+ Expect(err).To(HaveOccurred())
+ Expect(apierrors.IsTimeout(err)).To(BeTrue())
+ })
+
+ It("should set the Limit option and limit number of objects to Limit when List is called", func() {
+ opts := &client.ListOptions{Limit: int64(3)}
+ By("verifying that only Limit (3) number of objects are retrieved from the cache")
+ listObj := &corev1.PodList{}
+ Expect(informerCache.List(context.Background(), listObj, opts)).To(Succeed())
+ Expect(listObj.Items).Should(HaveLen(3))
+ })
+
+ It("should return a limited result set matching the correct label", func() {
+ listObj := &corev1.PodList{}
+ labelOpt := client.MatchingLabels(map[string]string{"common-label": "common"})
+ limitOpt := client.Limit(1)
+ By("verifying that only Limit (1) number of objects are retrieved from the cache")
+ Expect(informerCache.List(context.Background(), listObj, labelOpt, limitOpt)).To(Succeed())
+ Expect(listObj.Items).Should(HaveLen(1))
+ })
+ })
+
+ Context("with unstructured objects", func() {
+ It("should be able to list objects that haven't been watched previously", func() {
+ By("listing all services in the cluster")
+ listObj := &unstructured.UnstructuredList{}
+ listObj.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "ServiceList",
+ })
+ err := informerCache.List(context.Background(), listObj)
+ Expect(err).To(Succeed())
+
+ By("verifying that the returned list contains the Kubernetes service")
+ // NB: kubernetes default service is automatically created in testenv.
+ Expect(listObj.Items).NotTo(BeEmpty())
+ hasKubeService := false
+ for i := range listObj.Items {
+ svc := &listObj.Items[i]
+ if isKubeService(svc) {
+ hasKubeService = true
+ break
+ }
+ }
+ Expect(hasKubeService).To(BeTrue())
+ })
+ It("should be able to get objects that haven't been watched previously", func() {
+ By("getting the Kubernetes service")
+ svc := &unstructured.Unstructured{}
+ svc.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Service",
+ })
+ svcKey := client.ObjectKey{Namespace: "default", Name: "kubernetes"}
+ Expect(informerCache.Get(context.Background(), svcKey, svc)).To(Succeed())
+
+ By("verifying that the returned service looks reasonable")
+ Expect(svc.GetName()).To(Equal("kubernetes"))
+ Expect(svc.GetNamespace()).To(Equal("default"))
+ })
+
+ It("should support filtering by labels in a single namespace", func() {
+ By("listing pods with a particular label")
+ // NB: each pod has a "test-label":
+ out := unstructured.UnstructuredList{}
+ out.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ err := informerCache.List(context.Background(), &out,
+ client.InNamespace(testNamespaceTwo),
+ client.MatchingLabels(map[string]string{"test-label": "test-pod-2"}))
+ Expect(err).To(Succeed())
+
+ By("verifying the returned pods have the correct label")
+ Expect(out.Items).NotTo(BeEmpty())
+ Expect(out.Items).Should(HaveLen(1))
+ actual := out.Items[0]
+ Expect(actual.GetLabels()["test-label"]).To(Equal("test-pod-2"))
+ })
+
+ It("should support filtering by labels from multiple namespaces", func() {
+ By("creating another pod with the same label but different namespace")
+ anotherPod := createPod("test-pod-2", testNamespaceOne, corev1.RestartPolicyAlways)
+ defer deletePod(anotherPod)
+
+ By("listing pods with a particular label")
+ // NB: each pod has a "test-label":
+ out := unstructured.UnstructuredList{}
+ out.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ labels := map[string]string{"test-label": "test-pod-2"}
+ err := informerCache.List(context.Background(), &out, client.MatchingLabels(labels))
+ Expect(err).To(Succeed())
+
+ By("verifying multiple pods with the same label in different namespaces are returned")
+ Expect(out.Items).NotTo(BeEmpty())
+ Expect(out.Items).Should(HaveLen(2))
+ for _, actual := range out.Items {
+ Expect(actual.GetLabels()["test-label"]).To(Equal("test-pod-2"))
+ }
+ })
+
+ It("should be able to list objects by namespace", func() {
+ By("listing pods in test-namespace-1")
+ listObj := &unstructured.UnstructuredList{}
+ listObj.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ err := informerCache.List(context.Background(), listObj, client.InNamespace(testNamespaceOne))
+ Expect(err).To(Succeed())
+
+ By("verifying that the returned pods are in test-namespace-1")
+ Expect(listObj.Items).NotTo(BeEmpty())
+ Expect(listObj.Items).Should(HaveLen(2))
+ for _, item := range listObj.Items {
+ Expect(item.GetNamespace()).To(Equal(testNamespaceOne))
+ }
+ })
+
+ It("should be able to restrict cache to a namespace", func() {
+ By("creating a namespaced cache")
+ namespacedCache, err := cache.New(cfg, cache.Options{Namespaces: []string{testNamespaceOne}})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("running the cache and waiting for it to sync")
+ go func() {
+ defer GinkgoRecover()
+ Expect(namespacedCache.Start(informerCacheCtx)).To(Succeed())
+ }()
+ Expect(namespacedCache.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
+
+ By("listing pods in all namespaces")
+ out := &unstructured.UnstructuredList{}
+ out.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ Expect(namespacedCache.List(context.Background(), out)).To(Succeed())
+
+ By("verifying the returned pod is from the watched namespace")
+ Expect(out.Items).NotTo(BeEmpty())
+ Expect(out.Items).Should(HaveLen(2))
+ for _, item := range out.Items {
+ Expect(item.GetNamespace()).To(Equal(testNamespaceOne))
+ }
+ By("listing all nodes - should still be able to list a cluster-scoped resource")
+ nodeList := &unstructured.UnstructuredList{}
+ nodeList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "NodeList",
+ })
+ Expect(namespacedCache.List(context.Background(), nodeList)).To(Succeed())
+
+ By("verifying the node list is not empty")
+ Expect(nodeList.Items).NotTo(BeEmpty())
+
+ By("getting a node - should still be able to get a cluster-scoped resource")
+ node := &unstructured.Unstructured{}
+ node.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Node",
+ })
+
+ By("verifying that getting the node works with an empty namespace")
+ key1 := client.ObjectKey{Namespace: "", Name: testNodeOne}
+ Expect(namespacedCache.Get(context.Background(), key1, node)).To(Succeed())
+
+ By("verifying that the namespace is ignored when getting a cluster-scoped resource")
+ key2 := client.ObjectKey{Namespace: "random", Name: testNodeOne}
+ Expect(namespacedCache.Get(context.Background(), key2, node)).To(Succeed())
+ })
+
+ if !isPodDisableDeepCopy(opts) {
+ It("should deep copy the object unless told otherwise", func() {
+ By("retrieving a specific pod from the cache")
+ out := &unstructured.Unstructured{}
+ out.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ })
+ uKnownPod2 := &unstructured.Unstructured{}
+ Expect(kscheme.Scheme.Convert(knownPod2, uKnownPod2, nil)).To(Succeed())
+
+ podKey := client.ObjectKey{Name: "test-pod-2", Namespace: testNamespaceTwo}
+ Expect(informerCache.Get(context.Background(), podKey, out)).To(Succeed())
+
+ By("verifying the retrieved pod is equal to a known pod")
+ Expect(out).To(Equal(uKnownPod2))
+
+ By("altering a field in the retrieved pod")
+ m, _ := out.Object["spec"].(map[string]interface{})
+ m["activeDeadlineSeconds"] = 4
+
+ By("verifying the pods are no longer equal")
+ Expect(out).NotTo(Equal(knownPod2))
+ })
+ } else {
+ It("should not deep copy the object if UnsafeDisableDeepCopy is enabled", func() {
+ By("getting a specific pod from the cache twice")
+ podKey := client.ObjectKey{Name: "test-pod-2", Namespace: testNamespaceTwo}
+ out1 := &unstructured.Unstructured{}
+ out1.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"})
+ Expect(informerCache.Get(context.Background(), podKey, out1)).To(Succeed())
+ out2 := &unstructured.Unstructured{}
+ out2.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"})
+ Expect(informerCache.Get(context.Background(), podKey, out2)).To(Succeed())
+
+ By("verifying the pointer fields in pod have the same addresses")
+ Expect(out1).To(Equal(out2))
+ Expect(reflect.ValueOf(out1.Object).Pointer()).To(BeIdenticalTo(reflect.ValueOf(out2.Object).Pointer()))
+
+ By("listing pods from the cache twice")
+ outList1 := &unstructured.UnstructuredList{}
+ outList1.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PodList"})
+ Expect(informerCache.List(context.Background(), outList1, client.InNamespace(testNamespaceOne))).To(Succeed())
+ outList2 := &unstructured.UnstructuredList{}
+ outList2.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PodList"})
+ Expect(informerCache.List(context.Background(), outList2, client.InNamespace(testNamespaceOne))).To(Succeed())
+
+ By("verifying the pointer fields in pod have the same addresses")
+ Expect(len(outList1.Items)).To(Equal(len(outList2.Items)))
+ sort.SliceStable(outList1.Items, func(i, j int) bool { return outList1.Items[i].GetName() <= outList1.Items[j].GetName() })
+ sort.SliceStable(outList2.Items, func(i, j int) bool { return outList2.Items[i].GetName() <= outList2.Items[j].GetName() })
+ for i := range outList1.Items {
+ a := &outList1.Items[i]
+ b := &outList2.Items[i]
+ Expect(a).To(Equal(b))
+ Expect(reflect.ValueOf(a.Object).Pointer()).To(BeIdenticalTo(reflect.ValueOf(b.Object).Pointer()))
+ }
+ })
+ }
+
+ It("should return an error if the object is not found", func() {
+ By("getting a service that does not exists")
+ svc := &unstructured.Unstructured{}
+ svc.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Service",
+ })
+ svcKey := client.ObjectKey{Namespace: testNamespaceOne, Name: "unknown"}
+
+ By("verifying that an error is returned")
+ err := informerCache.Get(context.Background(), svcKey, svc)
+ Expect(err).To(HaveOccurred())
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+ It("should return an error if getting object in unwatched namespace", func() {
+ By("getting a service that does not exists")
+ svc := &corev1.Service{}
+ svcKey := client.ObjectKey{Namespace: "unknown", Name: "unknown"}
+
+ By("verifying that an error is returned")
+ err := informerCache.Get(context.Background(), svcKey, svc)
+ Expect(err).To(HaveOccurred())
+ })
+ It("test multinamespaced cache for cluster scoped resources", func() {
+ By("creating a multinamespaced cache to watch specific namespaces")
+ multi := cache.MultiNamespacedCacheBuilder([]string{"default", testNamespaceOne})
+ m, err := multi(cfg, cache.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("running the cache and waiting it for sync")
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(informerCacheCtx)).To(Succeed())
+ }()
+ Expect(m.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
+
+ By("should be able to fetch cluster scoped resource")
+ node := &corev1.Node{}
+
+ By("verifying that getting the node works with an empty namespace")
+ key1 := client.ObjectKey{Namespace: "", Name: testNodeOne}
+ Expect(m.Get(context.Background(), key1, node)).To(Succeed())
+
+ By("verifying if the cluster scoped resources are not duplicated")
+ nodeList := &unstructured.UnstructuredList{}
+ nodeList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "NodeList",
+ })
+ Expect(m.List(context.Background(), nodeList)).To(Succeed())
+
+ By("verifying the node list is not empty")
+ Expect(nodeList.Items).NotTo(BeEmpty())
+ Expect(len(nodeList.Items)).To(BeEquivalentTo(1))
+ })
+ })
+ Context("with metadata-only objects", func() {
+ It("should be able to list objects that haven't been watched previously", func() {
+ By("listing all services in the cluster")
+ listObj := &metav1.PartialObjectMetadataList{}
+ listObj.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "ServiceList",
+ })
+ err := informerCache.List(context.Background(), listObj)
+ Expect(err).To(Succeed())
+
+ By("verifying that the returned list contains the Kubernetes service")
+ // NB: kubernetes default service is automatically created in testenv.
+ Expect(listObj.Items).NotTo(BeEmpty())
+ hasKubeService := false
+ for i := range listObj.Items {
+ svc := &listObj.Items[i]
+ if isKubeService(svc) {
+ hasKubeService = true
+ break
+ }
+ }
+ Expect(hasKubeService).To(BeTrue())
+ })
+ It("should be able to get objects that haven't been watched previously", func() {
+ By("getting the Kubernetes service")
+ svc := &metav1.PartialObjectMetadata{}
+ svc.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Service",
+ })
+ svcKey := client.ObjectKey{Namespace: "default", Name: "kubernetes"}
+ Expect(informerCache.Get(context.Background(), svcKey, svc)).To(Succeed())
+
+ By("verifying that the returned service looks reasonable")
+ Expect(svc.GetName()).To(Equal("kubernetes"))
+ Expect(svc.GetNamespace()).To(Equal("default"))
+ })
+
+ It("should support filtering by labels in a single namespace", func() {
+ By("listing pods with a particular label")
+ // NB: each pod has a "test-label":
+ out := metav1.PartialObjectMetadataList{}
+ out.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ err := informerCache.List(context.Background(), &out,
+ client.InNamespace(testNamespaceTwo),
+ client.MatchingLabels(map[string]string{"test-label": "test-pod-2"}))
+ Expect(err).To(Succeed())
+
+ By("verifying the returned pods have the correct label")
+ Expect(out.Items).NotTo(BeEmpty())
+ Expect(out.Items).Should(HaveLen(1))
+ actual := out.Items[0]
+ Expect(actual.GetLabels()["test-label"]).To(Equal("test-pod-2"))
+ })
+
+ It("should support filtering by labels from multiple namespaces", func() {
+ By("creating another pod with the same label but different namespace")
+ anotherPod := createPod("test-pod-2", testNamespaceOne, corev1.RestartPolicyAlways)
+ defer deletePod(anotherPod)
+
+ By("listing pods with a particular label")
+ // NB: each pod has a "test-label":
+ out := metav1.PartialObjectMetadataList{}
+ out.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ labels := map[string]string{"test-label": "test-pod-2"}
+ err := informerCache.List(context.Background(), &out, client.MatchingLabels(labels))
+ Expect(err).To(Succeed())
+
+ By("verifying multiple pods with the same label in different namespaces are returned")
+ Expect(out.Items).NotTo(BeEmpty())
+ Expect(out.Items).Should(HaveLen(2))
+ for _, actual := range out.Items {
+ Expect(actual.GetLabels()["test-label"]).To(Equal("test-pod-2"))
+ }
+ })
+
+ It("should be able to list objects by namespace", func() {
+ By("listing pods in test-namespace-1")
+ listObj := &metav1.PartialObjectMetadataList{}
+ listObj.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ err := informerCache.List(context.Background(), listObj, client.InNamespace(testNamespaceOne))
+ Expect(err).To(Succeed())
+
+ By("verifying that the returned pods are in test-namespace-1")
+ Expect(listObj.Items).NotTo(BeEmpty())
+ Expect(listObj.Items).Should(HaveLen(2))
+ for _, item := range listObj.Items {
+ Expect(item.Namespace).To(Equal(testNamespaceOne))
+ }
+ })
+
+ It("should be able to restrict cache to a namespace", func() {
+ By("creating a namespaced cache")
+ namespacedCache, err := cache.New(cfg, cache.Options{Namespaces: []string{testNamespaceOne}})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("running the cache and waiting for it to sync")
+ go func() {
+ defer GinkgoRecover()
+ Expect(namespacedCache.Start(informerCacheCtx)).To(Succeed())
+ }()
+ Expect(namespacedCache.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
+
+ By("listing pods in all namespaces")
+ out := &metav1.PartialObjectMetadataList{}
+ out.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ Expect(namespacedCache.List(context.Background(), out)).To(Succeed())
+
+ By("verifying the returned pod is from the watched namespace")
+ Expect(out.Items).NotTo(BeEmpty())
+ Expect(out.Items).Should(HaveLen(2))
+ for _, item := range out.Items {
+ Expect(item.Namespace).To(Equal(testNamespaceOne))
+ }
+ By("listing all nodes - should still be able to list a cluster-scoped resource")
+ nodeList := &metav1.PartialObjectMetadataList{}
+ nodeList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "NodeList",
+ })
+ Expect(namespacedCache.List(context.Background(), nodeList)).To(Succeed())
+
+ By("verifying the node list is not empty")
+ Expect(nodeList.Items).NotTo(BeEmpty())
+
+ By("getting a node - should still be able to get a cluster-scoped resource")
+ node := &metav1.PartialObjectMetadata{}
+ node.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Node",
+ })
+
+ By("verifying that getting the node works with an empty namespace")
+ key1 := client.ObjectKey{Namespace: "", Name: testNodeOne}
+ Expect(namespacedCache.Get(context.Background(), key1, node)).To(Succeed())
+
+ By("verifying that the namespace is ignored when getting a cluster-scoped resource")
+ key2 := client.ObjectKey{Namespace: "random", Name: testNodeOne}
+ Expect(namespacedCache.Get(context.Background(), key2, node)).To(Succeed())
+ })
+
+ if !isPodDisableDeepCopy(opts) {
+ It("should deep copy the object unless told otherwise", func() {
+ By("retrieving a specific pod from the cache")
+ out := &metav1.PartialObjectMetadata{}
+ out.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ })
+ uKnownPod2 := &metav1.PartialObjectMetadata{}
+ knownPod2.(*corev1.Pod).ObjectMeta.DeepCopyInto(&uKnownPod2.ObjectMeta)
+ uKnownPod2.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ })
+
+ podKey := client.ObjectKey{Name: "test-pod-2", Namespace: testNamespaceTwo}
+ Expect(informerCache.Get(context.Background(), podKey, out)).To(Succeed())
+
+ By("verifying the retrieved pod is equal to a known pod")
+ Expect(out).To(Equal(uKnownPod2))
+
+ By("altering a field in the retrieved pod")
+ out.Labels["foo"] = "bar"
+
+ By("verifying the pods are no longer equal")
+ Expect(out).NotTo(Equal(knownPod2))
+ })
+ } else {
+ It("should not deep copy the object if UnsafeDisableDeepCopy is enabled", func() {
+ By("getting a specific pod from the cache twice")
+ podKey := client.ObjectKey{Name: "test-pod-2", Namespace: testNamespaceTwo}
+ out1 := &metav1.PartialObjectMetadata{}
+ out1.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"})
+ Expect(informerCache.Get(context.Background(), podKey, out1)).To(Succeed())
+ out2 := &metav1.PartialObjectMetadata{}
+ out2.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"})
+ Expect(informerCache.Get(context.Background(), podKey, out2)).To(Succeed())
+
+ By("verifying the pods have the same pointer addresses")
+ By("verifying the pointer fields in pod have the same addresses")
+ Expect(out1).To(Equal(out2))
+ Expect(reflect.ValueOf(out1.Labels).Pointer()).To(BeIdenticalTo(reflect.ValueOf(out2.Labels).Pointer()))
+
+ By("listing pods from the cache twice")
+ outList1 := &metav1.PartialObjectMetadataList{}
+ outList1.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PodList"})
+ Expect(informerCache.List(context.Background(), outList1, client.InNamespace(testNamespaceOne))).To(Succeed())
+ outList2 := &metav1.PartialObjectMetadataList{}
+ outList2.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PodList"})
+ Expect(informerCache.List(context.Background(), outList2, client.InNamespace(testNamespaceOne))).To(Succeed())
+
+ By("verifying the pointer fields in pod have the same addresses")
+ Expect(len(outList1.Items)).To(Equal(len(outList2.Items)))
+ sort.SliceStable(outList1.Items, func(i, j int) bool { return outList1.Items[i].Name <= outList1.Items[j].Name })
+ sort.SliceStable(outList2.Items, func(i, j int) bool { return outList2.Items[i].Name <= outList2.Items[j].Name })
+ for i := range outList1.Items {
+ a := &outList1.Items[i]
+ b := &outList2.Items[i]
+ Expect(a).To(Equal(b))
+ Expect(reflect.ValueOf(a.Labels).Pointer()).To(BeIdenticalTo(reflect.ValueOf(b.Labels).Pointer()))
+ }
+ })
+ }
+
+ It("should return an error if the object is not found", func() {
+ By("getting a service that does not exists")
+ svc := &metav1.PartialObjectMetadata{}
+ svc.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Service",
+ })
+ svcKey := client.ObjectKey{Namespace: testNamespaceOne, Name: "unknown"}
+
+ By("verifying that an error is returned")
+ err := informerCache.Get(context.Background(), svcKey, svc)
+ Expect(err).To(HaveOccurred())
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+ It("should return an error if getting object in unwatched namespace", func() {
+ By("getting a service that does not exists")
+ svc := &corev1.Service{}
+ svcKey := client.ObjectKey{Namespace: "unknown", Name: "unknown"}
+
+ By("verifying that an error is returned")
+ err := informerCache.Get(context.Background(), svcKey, svc)
+ Expect(err).To(HaveOccurred())
+ })
+ })
+ type selectorsTestCase struct {
+ fieldSelectors map[string]string
+ labelSelectors map[string]string
+ expectedPods []string
+ }
+ DescribeTable(" and cache with selectors", func(tc selectorsTestCase) {
+ By("creating the cache")
+ informer, err := cache.New(cfg, cache.Options{
+ ByObject: map[client.Object]cache.ByObject{
+ &corev1.Pod{}: {
+ Label: labels.Set(tc.labelSelectors).AsSelector(),
+ Field: fields.Set(tc.fieldSelectors).AsSelector(),
+ },
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ By("running the cache and waiting for it to sync")
+ go func() {
+ defer GinkgoRecover()
+ Expect(informer.Start(informerCacheCtx)).To(Succeed())
+ }()
+ Expect(informer.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
+
+ By("Checking with structured")
+ obtainedStructuredPodList := corev1.PodList{}
+ Expect(informer.List(context.Background(), &obtainedStructuredPodList)).To(Succeed())
+ Expect(obtainedStructuredPodList.Items).Should(WithTransform(func(pods []corev1.Pod) []string {
+ obtainedPodNames := []string{}
+ for _, pod := range pods {
+ obtainedPodNames = append(obtainedPodNames, pod.Name)
+ }
+ return obtainedPodNames
+ }, ConsistOf(tc.expectedPods)))
+
+ By("Checking with unstructured")
+ obtainedUnstructuredPodList := unstructured.UnstructuredList{}
+ obtainedUnstructuredPodList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ err = informer.List(context.Background(), &obtainedUnstructuredPodList)
+ Expect(err).To(Succeed())
+ Expect(obtainedUnstructuredPodList.Items).Should(WithTransform(func(pods []unstructured.Unstructured) []string {
+ obtainedPodNames := []string{}
+ for _, pod := range pods {
+ obtainedPodNames = append(obtainedPodNames, pod.GetName())
+ }
+ return obtainedPodNames
+ }, ConsistOf(tc.expectedPods)))
+
+ By("Checking with metadata")
+ obtainedMetadataPodList := metav1.PartialObjectMetadataList{}
+ obtainedMetadataPodList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ err = informer.List(context.Background(), &obtainedMetadataPodList)
+ Expect(err).To(Succeed())
+ Expect(obtainedMetadataPodList.Items).Should(WithTransform(func(pods []metav1.PartialObjectMetadata) []string {
+ obtainedPodNames := []string{}
+ for _, pod := range pods {
+ obtainedPodNames = append(obtainedPodNames, pod.Name)
+ }
+ return obtainedPodNames
+ }, ConsistOf(tc.expectedPods)))
+ },
+ Entry("when selectors are empty it has to inform about all the pods", selectorsTestCase{
+ fieldSelectors: map[string]string{},
+ labelSelectors: map[string]string{},
+ expectedPods: []string{"test-pod-1", "test-pod-2", "test-pod-3", "test-pod-4", "test-pod-5", "test-pod-6"},
+ }),
+ Entry("when field matches one pod it has to inform about it", selectorsTestCase{
+ fieldSelectors: map[string]string{"metadata.name": "test-pod-2"},
+ expectedPods: []string{"test-pod-2"},
+ }),
+ Entry("when field matches multiple pods it has to inform about all of them", selectorsTestCase{
+ fieldSelectors: map[string]string{"metadata.namespace": testNamespaceTwo},
+ expectedPods: []string{"test-pod-2", "test-pod-3", "test-pod-6"},
+ }),
+ Entry("when label matches one pod it has to inform about it", selectorsTestCase{
+ labelSelectors: map[string]string{"test-label": "test-pod-4"},
+ expectedPods: []string{"test-pod-4"},
+ }),
+ Entry("when label matches multiple pods it has to inform about all of them", selectorsTestCase{
+ labelSelectors: map[string]string{"common-label": "common"},
+ expectedPods: []string{"test-pod-3", "test-pod-4"},
+ }),
+ Entry("when label and field matches one pod it has to inform about about it", selectorsTestCase{
+ labelSelectors: map[string]string{"common-label": "common"},
+ fieldSelectors: map[string]string{"metadata.namespace": testNamespaceTwo},
+ expectedPods: []string{"test-pod-3"},
+ }),
+ Entry("when label does not match it does not has to inform", selectorsTestCase{
+ labelSelectors: map[string]string{"new-label": "new"},
+ expectedPods: []string{},
+ }),
+ Entry("when field does not match it does not has to inform", selectorsTestCase{
+ fieldSelectors: map[string]string{"metadata.namespace": "new"},
+ expectedPods: []string{},
+ }),
+ )
+ })
+ Describe("as an Informer", func() {
+ Context("with structured objects", func() {
+ It("should be able to get informer for the object", func() {
+ By("getting a shared index informer for a pod")
+ pod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "informer-obj",
+ Namespace: "default",
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx",
+ },
+ },
+ },
+ }
+ sii, err := informerCache.GetInformer(context.TODO(), pod)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(sii).NotTo(BeNil())
+ Expect(sii.HasSynced()).To(BeTrue())
+
+ By("adding an event handler listening for object creation which sends the object to a channel")
+ out := make(chan interface{})
+ addFunc := func(obj interface{}) {
+ out <- obj
+ }
+ _, _ = sii.AddEventHandler(kcache.ResourceEventHandlerFuncs{AddFunc: addFunc})
+
+ By("adding an object")
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl.Create(context.Background(), pod)).To(Succeed())
+ defer deletePod(pod)
+
+ By("verifying the object is received on the channel")
+ Eventually(out).Should(Receive(Equal(pod)))
+ })
+ It("should be able to get an informer by group/version/kind", func() {
+ By("getting an shared index informer for gvk = core/v1/pod")
+ gvk := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}
+ sii, err := informerCache.GetInformerForKind(context.TODO(), gvk)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(sii).NotTo(BeNil())
+ Expect(sii.HasSynced()).To(BeTrue())
+
+ By("adding an event handler listening for object creation which sends the object to a channel")
+ out := make(chan interface{})
+ addFunc := func(obj interface{}) {
+ out <- obj
+ }
+ _, _ = sii.AddEventHandler(kcache.ResourceEventHandlerFuncs{AddFunc: addFunc})
+
+ By("adding an object")
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ pod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "informer-gvk",
+ Namespace: "default",
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx",
+ },
+ },
+ },
+ }
+ Expect(cl.Create(context.Background(), pod)).To(Succeed())
+ defer deletePod(pod)
+
+ By("verifying the object is received on the channel")
+ Eventually(out).Should(Receive(Equal(pod)))
+ })
+ It("should be able to index an object field then retrieve objects by that field", func() {
+ By("creating the cache")
+ informer, err := cache.New(cfg, cache.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("indexing the restartPolicy field of the Pod object before starting")
+ pod := &corev1.Pod{}
+ indexFunc := func(obj client.Object) []string {
+ return []string{string(obj.(*corev1.Pod).Spec.RestartPolicy)}
+ }
+ Expect(informer.IndexField(context.TODO(), pod, "spec.restartPolicy", indexFunc)).To(Succeed())
+
+ By("running the cache and waiting for it to sync")
+ go func() {
+ defer GinkgoRecover()
+ Expect(informer.Start(informerCacheCtx)).To(Succeed())
+ }()
+ Expect(informer.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
+
+ By("listing Pods with restartPolicyOnFailure")
+ listObj := &corev1.PodList{}
+ Expect(informer.List(context.Background(), listObj,
+ client.MatchingFields{"spec.restartPolicy": "OnFailure"})).To(Succeed())
+ By("verifying that the returned pods have correct restart policy")
+ Expect(listObj.Items).NotTo(BeEmpty())
+ Expect(listObj.Items).Should(HaveLen(1))
+ actual := listObj.Items[0]
+ Expect(actual.Name).To(Equal("test-pod-3"))
+ })
+
+ It("should allow for get informer to be cancelled", func() {
+ By("creating a context and cancelling it")
+ informerCacheCancel()
+
+ By("getting a shared index informer for a pod with a cancelled context")
+ pod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "informer-obj",
+ Namespace: "default",
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx",
+ },
+ },
+ },
+ }
+ sii, err := informerCache.GetInformer(informerCacheCtx, pod)
+ Expect(err).To(HaveOccurred())
+ Expect(sii).To(BeNil())
+ Expect(apierrors.IsTimeout(err)).To(BeTrue())
+ })
+
+ It("should allow getting an informer by group/version/kind to be cancelled", func() {
+ By("creating a context and cancelling it")
+ informerCacheCancel()
+
+ By("getting an shared index informer for gvk = core/v1/pod with a cancelled context")
+ gvk := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}
+ sii, err := informerCache.GetInformerForKind(informerCacheCtx, gvk)
+ Expect(err).To(HaveOccurred())
+ Expect(sii).To(BeNil())
+ Expect(apierrors.IsTimeout(err)).To(BeTrue())
+ })
+
+ It("should be able not to change indexer values after indexing cluster-scope objects", func() {
+ By("creating the cache")
+ informer, err := cache.New(cfg, cache.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("indexing the Namespace objects with fixed values before starting")
+ pod := &corev1.Namespace{}
+ indexerValues := []string{"a", "b", "c"}
+ fieldName := "fixedValues"
+ indexFunc := func(obj client.Object) []string {
+ return indexerValues
+ }
+ Expect(informer.IndexField(context.TODO(), pod, fieldName, indexFunc)).To(Succeed())
+
+ By("running the cache and waiting for it to sync")
+ go func() {
+ defer GinkgoRecover()
+ Expect(informer.Start(informerCacheCtx)).To(Succeed())
+ }()
+ Expect(informer.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
+
+ By("listing Namespaces with fixed indexer")
+ listObj := &corev1.NamespaceList{}
+ Expect(informer.List(context.Background(), listObj,
+ client.MatchingFields{fieldName: "a"})).To(Succeed())
+ Expect(listObj.Items).NotTo(BeZero())
+
+ By("verifying the indexing does not change fixed returned values")
+ Expect(indexerValues).Should(HaveLen(3))
+ Expect(indexerValues[0]).To(Equal("a"))
+ Expect(indexerValues[1]).To(Equal("b"))
+ Expect(indexerValues[2]).To(Equal("c"))
+ })
+ })
+ Context("with unstructured objects", func() {
+ It("should be able to get informer for the object", func() {
+ By("getting a shared index informer for a pod")
+
+ pod := &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "containers": []map[string]interface{}{
+ {
+ "name": "nginx",
+ "image": "nginx",
+ },
+ },
+ },
+ },
+ }
+ pod.SetName("informer-obj2")
+ pod.SetNamespace("default")
+ pod.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ })
+ sii, err := informerCache.GetInformer(context.TODO(), pod)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(sii).NotTo(BeNil())
+ Expect(sii.HasSynced()).To(BeTrue())
+
+ By("adding an event handler listening for object creation which sends the object to a channel")
+ out := make(chan interface{})
+ addFunc := func(obj interface{}) {
+ out <- obj
+ }
+ _, _ = sii.AddEventHandler(kcache.ResourceEventHandlerFuncs{AddFunc: addFunc})
+
+ By("adding an object")
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl.Create(context.Background(), pod)).To(Succeed())
+ defer deletePod(pod)
+
+ By("verifying the object is received on the channel")
+ Eventually(out).Should(Receive(Equal(pod)))
+ })
+
+ It("should be able to index an object field then retrieve objects by that field", func() {
+ By("creating the cache")
+ informer, err := cache.New(cfg, cache.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("indexing the restartPolicy field of the Pod object before starting")
+ pod := &unstructured.Unstructured{}
+ pod.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ })
+ indexFunc := func(obj client.Object) []string {
+ s, ok := obj.(*unstructured.Unstructured).Object["spec"]
+ if !ok {
+ return []string{}
+ }
+ m, ok := s.(map[string]interface{})
+ if !ok {
+ return []string{}
+ }
+ return []string{fmt.Sprintf("%v", m["restartPolicy"])}
+ }
+ Expect(informer.IndexField(context.TODO(), pod, "spec.restartPolicy", indexFunc)).To(Succeed())
+
+ By("running the cache and waiting for it to sync")
+ go func() {
+ defer GinkgoRecover()
+ Expect(informer.Start(informerCacheCtx)).To(Succeed())
+ }()
+ Expect(informer.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
+
+ By("listing Pods with restartPolicyOnFailure")
+ listObj := &unstructured.UnstructuredList{}
+ listObj.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ })
+ err = informer.List(context.Background(), listObj,
+ client.MatchingFields{"spec.restartPolicy": "OnFailure"})
+ Expect(err).To(Succeed())
+
+ By("verifying that the returned pods have correct restart policy")
+ Expect(listObj.Items).NotTo(BeEmpty())
+ Expect(listObj.Items).Should(HaveLen(1))
+ actual := listObj.Items[0]
+ Expect(actual.GetName()).To(Equal("test-pod-3"))
+ })
+
+ It("should allow for get informer to be cancelled", func() {
+ By("cancelling the context")
+ informerCacheCancel()
+
+ By("getting a shared index informer for a pod with a cancelled context")
+ pod := &unstructured.Unstructured{}
+ pod.SetName("informer-obj2")
+ pod.SetNamespace("default")
+ pod.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ })
+ sii, err := informerCache.GetInformer(informerCacheCtx, pod)
+ Expect(err).To(HaveOccurred())
+ Expect(sii).To(BeNil())
+ Expect(apierrors.IsTimeout(err)).To(BeTrue())
+ })
+ })
+ Context("with metadata-only objects", func() {
+ It("should be able to get informer for the object", func() {
+ By("getting a shared index informer for a pod")
+
+ pod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "informer-obj",
+ Namespace: "default",
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx",
+ },
+ },
+ },
+ }
+
+ podMeta := &metav1.PartialObjectMetadata{}
+ pod.ObjectMeta.DeepCopyInto(&podMeta.ObjectMeta)
+ podMeta.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ })
+
+ sii, err := informerCache.GetInformer(context.TODO(), podMeta)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(sii).NotTo(BeNil())
+ Expect(sii.HasSynced()).To(BeTrue())
+
+ By("adding an event handler listening for object creation which sends the object to a channel")
+ out := make(chan interface{})
+ addFunc := func(obj interface{}) {
+ out <- obj
+ }
+ _, _ = sii.AddEventHandler(kcache.ResourceEventHandlerFuncs{AddFunc: addFunc})
+
+ By("adding an object")
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl.Create(context.Background(), pod)).To(Succeed())
+ defer deletePod(pod)
+ // re-copy the result in so that we can match on it properly
+ pod.ObjectMeta.DeepCopyInto(&podMeta.ObjectMeta)
+
+ By("verifying the object's metadata is received on the channel")
+ Eventually(out).Should(Receive(Equal(podMeta)))
+ })
+
+ It("should be able to index an object field then retrieve objects by that field", func() {
+ By("creating the cache")
+ informer, err := cache.New(cfg, cache.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("indexing the restartPolicy field of the Pod object before starting")
+ pod := &metav1.PartialObjectMetadata{}
+ pod.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ })
+ indexFunc := func(obj client.Object) []string {
+ metadata := obj.(*metav1.PartialObjectMetadata)
+ return []string{metadata.Labels["test-label"]}
+ }
+ Expect(informer.IndexField(context.TODO(), pod, "metadata.labels.test-label", indexFunc)).To(Succeed())
+
+ By("running the cache and waiting for it to sync")
+ go func() {
+ defer GinkgoRecover()
+ Expect(informer.Start(informerCacheCtx)).To(Succeed())
+ }()
+ Expect(informer.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
+
+ By("listing Pods with restartPolicyOnFailure")
+ listObj := &metav1.PartialObjectMetadataList{}
+ gvk := schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "PodList",
+ }
+ listObj.SetGroupVersionKind(gvk)
+ err = informer.List(context.Background(), listObj,
+ client.MatchingFields{"metadata.labels.test-label": "test-pod-3"})
+ Expect(err).To(Succeed())
+
+ By("verifying that the GVK has been preserved for the list object")
+ Expect(listObj.GroupVersionKind()).To(Equal(gvk))
+
+ By("verifying that the returned pods have correct restart policy")
+ Expect(listObj.Items).NotTo(BeEmpty())
+ Expect(listObj.Items).Should(HaveLen(1))
+ actual := listObj.Items[0]
+ Expect(actual.GetName()).To(Equal("test-pod-3"))
+
+ By("verifying that the GVK has been preserved for the item in the list")
+ Expect(actual.GroupVersionKind()).To(Equal(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ }))
+ })
+
+ It("should allow for get informer to be cancelled", func() {
+ By("creating a context and cancelling it")
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+
+ By("getting a shared index informer for a pod with a cancelled context")
+ pod := &metav1.PartialObjectMetadata{}
+ pod.SetName("informer-obj2")
+ pod.SetNamespace("default")
+ pod.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ })
+ sii, err := informerCache.GetInformer(ctx, pod)
+ Expect(err).To(HaveOccurred())
+ Expect(sii).To(BeNil())
+ Expect(apierrors.IsTimeout(err)).To(BeTrue())
+ })
+ })
+ })
+ Describe("use UnsafeDisableDeepCopy list options", func() {
+ It("should be able to change object in informer cache", func() {
+ By("listing pods")
+ out := corev1.PodList{}
+ Expect(informerCache.List(context.Background(), &out, client.UnsafeDisableDeepCopy)).To(Succeed())
+ for _, item := range out.Items {
+ if strings.Compare(item.Name, "test-pod-3") == 0 { // test-pod-3 has labels
+ item.Labels["UnsafeDisableDeepCopy"] = "true"
+ break
+ }
+ }
+
+ By("verifying that the returned pods were changed")
+ out2 := corev1.PodList{}
+ Expect(informerCache.List(context.Background(), &out, client.UnsafeDisableDeepCopy)).To(Succeed())
+ for _, item := range out2.Items {
+ if strings.Compare(item.Name, "test-pod-3") == 0 {
+ Expect(item.Labels["UnsafeDisableDeepCopy"]).To(Equal("true"))
+ break
+ }
+ }
+ })
+ })
+ })
+}
+
+// ensureNamespace installs namespace of a given name if not exists.
+func ensureNamespace(namespace string, client client.Client) error {
+ ns := corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespace,
+ },
+ TypeMeta: metav1.TypeMeta{
+ Kind: "Namespace",
+ APIVersion: "v1",
+ },
+ }
+ err := client.Create(context.TODO(), &ns)
+ if apierrors.IsAlreadyExists(err) {
+ return nil
+ }
+ return err
+}
+
+func ensureNode(name string, client client.Client) error {
+ node := corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: name,
+ },
+ TypeMeta: metav1.TypeMeta{
+ Kind: "Node",
+ APIVersion: "v1",
+ },
+ }
+ err := client.Create(context.TODO(), &node)
+ if apierrors.IsAlreadyExists(err) {
+ return nil
+ }
+ return err
+}
+
+//nolint:interfacer
+func isKubeService(svc metav1.Object) bool {
+ // grumble grumble linters grumble grumble
+ return svc.GetNamespace() == "default" && svc.GetName() == "kubernetes"
+}
+
+func isPodDisableDeepCopy(opts cache.Options) bool {
+ if opts.ByObject[&corev1.Pod{}].UnsafeDisableDeepCopy != nil {
+ return *opts.ByObject[&corev1.Pod{}].UnsafeDisableDeepCopy
+ }
+ if opts.UnsafeDisableDeepCopy != nil {
+ return *opts.UnsafeDisableDeepCopy
+ }
+ return false
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cache/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/doc.go
new file mode 100644
index 00000000000..e1742ac0f32
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/doc.go
@@ -0,0 +1,19 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package cache provides object caches that act as caching client.Reader
+// instances and help drive Kubernetes-object-based event handlers.
+package cache
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go
new file mode 100644
index 00000000000..e070dbeb606
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go
@@ -0,0 +1,222 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cache
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ apimeta "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/tools/cache"
+ "sigs.k8s.io/controller-runtime/pkg/cache/internal"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+)
+
+var (
+ _ Informers = &informerCache{}
+ _ client.Reader = &informerCache{}
+ _ Cache = &informerCache{}
+)
+
+// ErrCacheNotStarted is returned when trying to read from the cache that wasn't started.
+type ErrCacheNotStarted struct{}
+
+func (*ErrCacheNotStarted) Error() string {
+ return "the cache is not started, can not read objects"
+}
+
+// informerCache is a Kubernetes Object cache populated from internal.Informers.
+// informerCache wraps internal.Informers.
+type informerCache struct {
+ scheme *runtime.Scheme
+ *internal.Informers
+}
+
+// Get implements Reader.
+func (ic *informerCache) Get(ctx context.Context, key client.ObjectKey, out client.Object, opts ...client.GetOption) error {
+ gvk, err := apiutil.GVKForObject(out, ic.scheme)
+ if err != nil {
+ return err
+ }
+
+ started, cache, err := ic.Informers.Get(ctx, gvk, out)
+ if err != nil {
+ return err
+ }
+
+ if !started {
+ return &ErrCacheNotStarted{}
+ }
+ return cache.Reader.Get(ctx, key, out)
+}
+
+// List implements Reader.
+func (ic *informerCache) List(ctx context.Context, out client.ObjectList, opts ...client.ListOption) error {
+ gvk, cacheTypeObj, err := ic.objectTypeForListObject(out)
+ if err != nil {
+ return err
+ }
+
+ started, cache, err := ic.Informers.Get(ctx, *gvk, cacheTypeObj)
+ if err != nil {
+ return err
+ }
+
+ if !started {
+ return &ErrCacheNotStarted{}
+ }
+
+ return cache.Reader.List(ctx, out, opts...)
+}
+
+// objectTypeForListObject tries to find the runtime.Object and associated GVK
+// for a single object corresponding to the passed-in list type. We need them
+// because they are used as cache map key.
+func (ic *informerCache) objectTypeForListObject(list client.ObjectList) (*schema.GroupVersionKind, runtime.Object, error) {
+ gvk, err := apiutil.GVKForObject(list, ic.scheme)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // We need the non-list GVK, so chop off the "List" from the end of the kind.
+ gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
+
+ // Handle unstructured.UnstructuredList.
+ if _, isUnstructured := list.(runtime.Unstructured); isUnstructured {
+ u := &unstructured.Unstructured{}
+ u.SetGroupVersionKind(gvk)
+ return &gvk, u, nil
+ }
+ // Handle metav1.PartialObjectMetadataList.
+ if _, isPartialObjectMetadata := list.(*metav1.PartialObjectMetadataList); isPartialObjectMetadata {
+ pom := &metav1.PartialObjectMetadata{}
+ pom.SetGroupVersionKind(gvk)
+ return &gvk, pom, nil
+ }
+
+ // Any other list type should have a corresponding non-list type registered
+ // in the scheme. Use that to create a new instance of the non-list type.
+ cacheTypeObj, err := ic.scheme.New(gvk)
+ if err != nil {
+ return nil, nil, err
+ }
+ return &gvk, cacheTypeObj, nil
+}
+
+// GetInformerForKind returns the informer for the GroupVersionKind.
+func (ic *informerCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind, opts ...InformerGetOption) (Informer, error) {
+ // Map the gvk to an object
+ obj, err := ic.scheme.New(gvk)
+ if err != nil {
+ return nil, err
+ }
+
+ _, i, err := ic.Informers.Get(ctx, gvk, obj, castInformerGetOptions(opts)...)
+ if err != nil {
+ return nil, err
+ }
+ return i.Informer, err
+}
+
+// GetInformer returns the informer for the obj.
+func (ic *informerCache) GetInformer(ctx context.Context, obj client.Object, opts ...InformerGetOption) (Informer, error) {
+ gvk, err := apiutil.GVKForObject(obj, ic.scheme)
+ if err != nil {
+ return nil, err
+ }
+
+ _, i, err := ic.Informers.Get(ctx, gvk, obj, castInformerGetOptions(opts)...)
+ if err != nil {
+ return nil, err
+ }
+ return i.Informer, err
+}
+
+// NeedLeaderElection implements the LeaderElectionRunnable interface
+// to indicate that this can be started without requiring the leader lock.
+func (ic *informerCache) NeedLeaderElection() bool {
+ return false
+}
+
+// IndexField adds an indexer to the underlying cache, using extraction function to get
+// value(s) from the given field. This index can then be used by passing a field selector
+// to List. For one-to-one compatibility with "normal" field selectors, only return one value.
+// The values may be anything. They will automatically be prefixed with the namespace of the
+// given object, if present. The objects passed are guaranteed to be objects of the correct type.
+func (ic *informerCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error {
+ informer, err := ic.GetInformer(ctx, obj)
+ if err != nil {
+ return err
+ }
+ return indexByField(informer, field, extractValue)
+}
+
+// Remove removes an informer specified by the obj argument from the cache and stops it if it existed.
+func (ic *informerCache) Remove(obj client.Object) error {
+ gvk, err := apiutil.GVKForObject(obj, ic.scheme)
+ if err != nil {
+ return err
+ }
+
+ ic.Informers.Remove(gvk, obj)
+ return nil
+}
+
+func indexByField(indexer Informer, field string, extractor client.IndexerFunc) error {
+ indexFunc := func(objRaw interface{}) ([]string, error) {
+ // TODO(directxman12): check if this is the correct type?
+ obj, isObj := objRaw.(client.Object)
+ if !isObj {
+ return nil, fmt.Errorf("object of type %T is not an Object", objRaw)
+ }
+ meta, err := apimeta.Accessor(obj)
+ if err != nil {
+ return nil, err
+ }
+ ns := meta.GetNamespace()
+
+ rawVals := extractor(obj)
+ var vals []string
+ if ns == "" {
+ // if we're not doubling the keys for the namespaced case, just create a new slice with same length
+ vals = make([]string, len(rawVals))
+ } else {
+ // if we need to add non-namespaced versions too, double the length
+ vals = make([]string, len(rawVals)*2)
+ }
+ for i, rawVal := range rawVals {
+ // save a namespaced variant, so that we can ask
+ // "what are all the object matching a given index *in a given namespace*"
+ vals[i] = internal.KeyToNamespacedKey(ns, rawVal)
+ if ns != "" {
+ // if we have a namespace, also inject a special index key for listing
+ // regardless of the object namespace
+ vals[i+len(rawVals)] = internal.KeyToNamespacedKey("", rawVal)
+ }
+ }
+
+ return vals, nil
+ }
+
+ return indexer.AddIndexers(cache.Indexers{internal.FieldIndexName(field): indexFunc})
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache_test.go
new file mode 100644
index 00000000000..617e74c4e50
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache_test.go
@@ -0,0 +1,46 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cache_test
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ "k8s.io/client-go/rest"
+
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+)
+
+var _ = Describe("informerCache", func() {
+ It("should not require LeaderElection", func() {
+ cfg := &rest.Config{}
+
+ httpClient, err := rest.HTTPClientFor(cfg)
+ Expect(err).ToNot(HaveOccurred())
+ mapper, err := apiutil.NewDynamicRESTMapper(cfg, httpClient)
+ Expect(err).ToNot(HaveOccurred())
+
+ c, err := cache.New(cfg, cache.Options{Mapper: mapper})
+ Expect(err).ToNot(HaveOccurred())
+
+ leaderElectionRunnable, ok := c.(manager.LeaderElectionRunnable)
+ Expect(ok).To(BeTrue())
+ Expect(leaderElectionRunnable.NeedLeaderElection()).To(BeFalse())
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/informer_cache_unit_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache_unit_test.go
similarity index 75%
rename from third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/informer_cache_unit_test.go
rename to third_party/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache_unit_test.go
index d0f7470d648..130059bc409 100644
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/informer_cache_unit_test.go
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache_unit_test.go
@@ -14,22 +14,20 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
-package dynamiccache
+package cache
import (
- . "github.com/onsi/ginkgo"
+ . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
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"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes/scheme"
- "github.com/open-policy-agent/gatekeeper/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal"
+ "sigs.k8s.io/controller-runtime/pkg/cache/internal"
"sigs.k8s.io/controller-runtime/pkg/controller/controllertest"
crscheme "sigs.k8s.io/controller-runtime/pkg/scheme"
)
@@ -40,8 +38,9 @@ const (
)
var _ = Describe("ip.objectTypeForListObject", func() {
- ip := &dynamicInformerCache{
- InformersMap: &internal.InformersMap{Scheme: scheme.Scheme},
+ ip := &informerCache{
+ scheme: scheme.Scheme,
+ Informers: &internal.Informers{},
}
It("should find the object type for unstructured lists", func() {
@@ -57,7 +56,21 @@ var _ = Describe("ip.objectTypeForListObject", func() {
referenceUnstructured := &unstructured.Unstructured{}
referenceUnstructured.SetGroupVersionKind(*gvk)
Expect(obj).To(Equal(referenceUnstructured))
+ })
+ It("should find the object type for partial object metadata lists", func() {
+ partialList := &metav1.PartialObjectMetadataList{}
+ partialList.APIVersion = ("v1")
+ partialList.Kind = "PodList"
+
+ gvk, obj, err := ip.objectTypeForListObject(partialList)
+ Expect(err).ToNot(HaveOccurred())
+ Expect(gvk.Group).To(Equal(""))
+ Expect(gvk.Version).To(Equal("v1"))
+ Expect(gvk.Kind).To(Equal("Pod"))
+ referencePartial := &metav1.PartialObjectMetadata{}
+ referencePartial.SetGroupVersionKind(*gvk)
+ Expect(obj).To(Equal(referencePartial))
})
It("should find the object type of a list with a slice of literals items field", func() {
@@ -66,21 +79,20 @@ var _ = Describe("ip.objectTypeForListObject", func() {
Expect(gvk.Group).To(Equal(""))
Expect(gvk.Version).To(Equal("v1"))
Expect(gvk.Kind).To(Equal("Pod"))
- var referencePod *corev1.Pod
+ referencePod := &corev1.Pod{}
Expect(obj).To(Equal(referencePod))
-
})
It("should find the object type of a list with a slice of pointers items field", func() {
By("registering the type", func() {
- ip.Scheme = runtime.NewScheme()
+ ip.scheme = runtime.NewScheme()
err := (&crscheme.Builder{
GroupVersion: schema.GroupVersion{Group: itemPointerSliceTypeGroupName, Version: itemPointerSliceTypeVersion},
}).
Register(
&controllertest.UnconventionalListType{},
&controllertest.UnconventionalListTypeList{},
- ).AddToScheme(ip.Scheme)
+ ).AddToScheme(ip.scheme)
Expect(err).To(BeNil())
})
@@ -90,7 +102,7 @@ var _ = Describe("ip.objectTypeForListObject", func() {
Expect(gvk.Group).To(Equal(itemPointerSliceTypeGroupName))
Expect(gvk.Version).To(Equal(itemPointerSliceTypeVersion))
Expect(gvk.Kind).To(Equal("UnconventionalListType"))
- var referenceObject *controllertest.UnconventionalListType
+ referenceObject := &controllertest.UnconventionalListType{}
Expect(obj).To(Equal(referenceObject))
})
})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/informertest/fake_cache.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/informertest/fake_cache.go
similarity index 95%
rename from third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/informertest/fake_cache.go
rename to third_party/sigs.k8s.io/controller-runtime/pkg/cache/informertest/fake_cache.go
index 6124a08d032..da3bf8e0d42 100644
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/informertest/fake_cache.go
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/informertest/fake_cache.go
@@ -14,9 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
package informertest
import (
@@ -134,7 +131,7 @@ func (c *FakeInformers) IndexField(ctx context.Context, obj client.Object, field
}
// Get implements Cache.
-func (c *FakeInformers) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
+func (c *FakeInformers) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
return nil
}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/cache_reader.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go
similarity index 81%
rename from third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/cache_reader.go
rename to third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go
index 6bb23bd493e..3c8355bbde5 100644
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/cache_reader.go
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go
@@ -14,9 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
package internal
import (
@@ -26,14 +23,13 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
- "k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/apimachinery/pkg/selection"
"k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/internal/field/selector"
)
// CacheReader is a client.Reader.
@@ -49,10 +45,15 @@ type CacheReader struct {
// scopeName is the scope of the resource (namespaced or cluster-scoped).
scopeName apimeta.RESTScopeName
+
+ // disableDeepCopy indicates not to deep copy objects during get or list objects.
+ // Be very careful with this, when enabled you must DeepCopy any object before mutating it,
+ // otherwise you will mutate the object in the cache.
+ disableDeepCopy bool
}
// Get checks the indexer for the object and writes a copy of it if found.
-func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Object) error {
+func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Object, opts ...client.GetOption) error {
if c.scopeName == apimeta.RESTScopeNameRoot {
key.Namespace = ""
}
@@ -79,9 +80,13 @@ func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Ob
return fmt.Errorf("cache contained %T, which is not an Object", obj)
}
- // deep copy to avoid mutating cache
- // TODO(directxman12): revisit the decision to always deepcopy
- obj = obj.(runtime.Object).DeepCopyObject()
+ if c.disableDeepCopy {
+ // skip deep copy which might be unsafe
+ // you must DeepCopy any object before mutating it outside
+ } else {
+ // deep copy to avoid mutating cache
+ obj = obj.(runtime.Object).DeepCopyObject()
+ }
// Copy the value of the item in the cache to the returned value
// TODO(directxman12): this is a terrible hack, pls fix (we should have deepcopyinto)
@@ -91,7 +96,9 @@ func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Ob
return fmt.Errorf("cache had type %s, but %s was asked for", objVal.Type(), outVal.Type())
}
reflect.Indirect(outVal).Set(reflect.Indirect(objVal))
- out.GetObjectKind().SetGroupVersionKind(c.groupVersionKind)
+ if !c.disableDeepCopy {
+ out.GetObjectKind().SetGroupVersionKind(c.groupVersionKind)
+ }
return nil
}
@@ -108,7 +115,7 @@ func (c *CacheReader) List(_ context.Context, out client.ObjectList, opts ...cli
case listOpts.FieldSelector != nil:
// TODO(directxman12): support more complicated field selectors by
// combining multiple indices, GetIndexers, etc
- field, val, requiresExact := requiresExactMatch(listOpts.FieldSelector)
+ field, val, requiresExact := selector.RequiresExactMatch(listOpts.FieldSelector)
if !requiresExact {
return fmt.Errorf("non-exact field matches are not supported by the cache")
}
@@ -132,15 +139,15 @@ func (c *CacheReader) List(_ context.Context, out client.ObjectList, opts ...cli
limitSet := listOpts.Limit > 0
runtimeObjs := make([]runtime.Object, 0, len(objs))
- for i, item := range objs {
+ for _, item := range objs {
// if the Limit option is set and the number of items
// listed exceeds this limit, then stop reading.
- if limitSet && int64(i) >= listOpts.Limit {
+ if limitSet && int64(len(runtimeObjs)) >= listOpts.Limit {
break
}
obj, isObj := item.(runtime.Object)
if !isObj {
- return fmt.Errorf("cache contained %T, which is not an Object", obj)
+ return fmt.Errorf("cache contained %T, which is not an Object", item)
}
meta, err := apimeta.Accessor(obj)
if err != nil {
@@ -153,8 +160,15 @@ func (c *CacheReader) List(_ context.Context, out client.ObjectList, opts ...cli
}
}
- outObj := obj.DeepCopyObject()
- outObj.GetObjectKind().SetGroupVersionKind(c.groupVersionKind)
+ var outObj runtime.Object
+ if c.disableDeepCopy || (listOpts.UnsafeDisableDeepCopy != nil && *listOpts.UnsafeDisableDeepCopy) {
+ // skip deep copy which might be unsafe
+ // you must DeepCopy any object before mutating it outside
+ outObj = obj
+ } else {
+ outObj = obj.DeepCopyObject()
+ outObj.GetObjectKind().SetGroupVersionKind(c.groupVersionKind)
+ }
runtimeObjs = append(runtimeObjs, outObj)
}
return apimeta.SetList(out, runtimeObjs)
@@ -171,19 +185,6 @@ func objectKeyToStoreKey(k client.ObjectKey) string {
return k.Namespace + "/" + k.Name
}
-// requiresExactMatch checks if the given field selector is of the form `k=v` or `k==v`.
-func requiresExactMatch(sel fields.Selector) (field, val string, required bool) {
- reqs := sel.Requirements()
- if len(reqs) != 1 {
- return "", "", false
- }
- req := reqs[0]
- if req.Operator != selection.Equals && req.Operator != selection.DoubleEquals {
- return "", "", false
- }
- return req.Field, req.Value, true
-}
-
// FieldIndexName constructs the name of the index over the given field,
// for use with an indexer.
func FieldIndexName(field string) string {
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers.go
new file mode 100644
index 00000000000..bb3a454f1c4
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers.go
@@ -0,0 +1,615 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package internal
+
+import (
+ "context"
+ "fmt"
+ "math/rand"
+ "net/http"
+ "sync"
+ "time"
+
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ "k8s.io/apimachinery/pkg/watch"
+ "k8s.io/client-go/dynamic"
+ "k8s.io/client-go/metadata"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/internal/syncs"
+)
+
+// InformersOpts configures an InformerMap.
+type InformersOpts struct {
+ HTTPClient *http.Client
+ Scheme *runtime.Scheme
+ Mapper meta.RESTMapper
+ ResyncPeriod time.Duration
+ Namespace string
+ ByGVK map[schema.GroupVersionKind]InformersOptsByGVK
+}
+
+// InformersOptsByGVK configured additional by group version kind (or object)
+// in an InformerMap.
+type InformersOptsByGVK struct {
+ Selector Selector
+ Transform cache.TransformFunc
+ UnsafeDisableDeepCopy *bool
+}
+
+// NewInformers creates a new InformersMap that can create informers under the hood.
+func NewInformers(config *rest.Config, options *InformersOpts) *Informers {
+ return &Informers{
+ config: config,
+ httpClient: options.HTTPClient,
+ scheme: options.Scheme,
+ mapper: options.Mapper,
+ tracker: tracker{
+ Structured: make(map[schema.GroupVersionKind]*Cache),
+ Unstructured: make(map[schema.GroupVersionKind]*Cache),
+ Metadata: make(map[schema.GroupVersionKind]*Cache),
+ },
+ codecs: serializer.NewCodecFactory(options.Scheme),
+ paramCodec: runtime.NewParameterCodec(options.Scheme),
+ resync: options.ResyncPeriod,
+ startWait: make(chan struct{}),
+ namespace: options.Namespace,
+ byGVK: options.ByGVK,
+ }
+}
+
+// Cache contains the cached data for an Cache.
+type Cache struct {
+ // Informer is the cached informer
+ Informer cache.SharedIndexInformer
+
+ // CacheReader wraps Informer and implements the CacheReader interface for a single type
+ Reader CacheReader
+
+ // Stop can be used to stop this individual informer.
+ stop chan struct{}
+}
+
+// Start starts the informer managed by a MapEntry.
+// Blocks until the informer stops. The informer can be stopped
+// either individually (via the entry's stop channel) or globally
+// via the provided stop argument.
+func (c *Cache) Start(stop <-chan struct{}) {
+ // Stop on either the whole map stopping or just this informer being removed.
+ internalStop, cancel := syncs.MergeChans(stop, c.stop)
+ defer cancel()
+ c.Informer.Run(internalStop)
+}
+
+type tracker struct {
+ Structured map[schema.GroupVersionKind]*Cache
+ Unstructured map[schema.GroupVersionKind]*Cache
+ Metadata map[schema.GroupVersionKind]*Cache
+}
+
+// GetOptions provides configuration to customize the behavior when
+// getting an informer.
+type GetOptions struct {
+ // DoNotBlockUntilSynced tells Get() to return the informer immediately,
+ // without waiting for its cache to sync.
+ DoNotBlockUntilSynced bool
+}
+
+// InformerGetOption defines an option that alters the behavior of how informers are retrieved.
+type InformerGetOption func(*GetOptions)
+
+// BlockUntilSynced determines whether a get request for an informer should block
+// until the informer's cache has synced.
+func BlockUntilSynced(shouldBlock bool) InformerGetOption {
+ return func(opts *GetOptions) {
+ opts.DoNotBlockUntilSynced = !shouldBlock
+ }
+}
+
+// Informers create and caches Informers for (runtime.Object, schema.GroupVersionKind) pairs.
+// It uses a standard parameter codec constructed based on the given generated Scheme.
+type Informers struct {
+ // httpClient is used to create a new REST client
+ httpClient *http.Client
+
+ // scheme maps runtime.Objects to GroupVersionKinds
+ scheme *runtime.Scheme
+
+ // config is used to talk to the apiserver
+ config *rest.Config
+
+ // mapper maps GroupVersionKinds to Resources
+ mapper meta.RESTMapper
+
+ // tracker tracks informers keyed by their type and groupVersionKind
+ tracker tracker
+
+ // codecs is used to create a new REST client
+ codecs serializer.CodecFactory
+
+ // paramCodec is used by list and watch
+ paramCodec runtime.ParameterCodec
+
+ // resync is the base frequency the informers are resynced
+ // a 10 percent jitter will be added to the resync period between informers
+ // so that all informers will not send list requests simultaneously.
+ resync time.Duration
+
+ // mu guards access to the map
+ mu sync.RWMutex
+
+ // started is true if the informers have been started
+ started bool
+
+ // startWait is a channel that is closed after the
+ // informer has been started.
+ startWait chan struct{}
+
+ // waitGroup is the wait group that is used to wait for all informers to stop
+ waitGroup sync.WaitGroup
+
+ // stopped is true if the informers have been stopped
+ stopped bool
+
+ // ctx is the context to stop informers
+ ctx context.Context
+
+ // namespace is the namespace that all ListWatches are restricted to
+ // default or empty string means all namespaces
+ namespace string
+
+ byGVK map[schema.GroupVersionKind]InformersOptsByGVK
+}
+
+func (ip *Informers) getSelector(gvk schema.GroupVersionKind) Selector {
+ if ip.byGVK == nil {
+ return Selector{}
+ }
+ if res, ok := ip.byGVK[gvk]; ok {
+ return res.Selector
+ }
+ if res, ok := ip.byGVK[schema.GroupVersionKind{}]; ok {
+ return res.Selector
+ }
+ return Selector{}
+}
+
+func (ip *Informers) getTransform(gvk schema.GroupVersionKind) cache.TransformFunc {
+ if ip.byGVK == nil {
+ return nil
+ }
+ if res, ok := ip.byGVK[gvk]; ok {
+ return res.Transform
+ }
+ if res, ok := ip.byGVK[schema.GroupVersionKind{}]; ok {
+ return res.Transform
+ }
+ return nil
+}
+
+func (ip *Informers) getDisableDeepCopy(gvk schema.GroupVersionKind) bool {
+ if ip.byGVK == nil {
+ return false
+ }
+ if res, ok := ip.byGVK[gvk]; ok && res.UnsafeDisableDeepCopy != nil {
+ return *res.UnsafeDisableDeepCopy
+ }
+ if res, ok := ip.byGVK[schema.GroupVersionKind{}]; ok && res.UnsafeDisableDeepCopy != nil {
+ return *res.UnsafeDisableDeepCopy
+ }
+ return false
+}
+
+// Start calls Run on each of the informers and sets started to true. Blocks on the context.
+// It doesn't return start because it can't return an error, and it's not a runnable directly.
+func (ip *Informers) Start(ctx context.Context) error {
+ func() {
+ ip.mu.Lock()
+ defer ip.mu.Unlock()
+
+ // Set the context so it can be passed to informers that are added later
+ ip.ctx = ctx
+
+ // Start each informer
+ for _, i := range ip.tracker.Structured {
+ ip.startInformerLocked(i)
+ }
+ for _, i := range ip.tracker.Unstructured {
+ ip.startInformerLocked(i)
+ }
+ for _, i := range ip.tracker.Metadata {
+ ip.startInformerLocked(i)
+ }
+
+ // Set started to true so we immediately start any informers added later.
+ ip.started = true
+ close(ip.startWait)
+ }()
+ <-ctx.Done() // Block until the context is done
+ ip.mu.Lock()
+ ip.stopped = true // Set stopped to true so we don't start any new informers
+ ip.mu.Unlock()
+ ip.waitGroup.Wait() // Block until all informers have stopped
+ return nil
+}
+
+func (ip *Informers) startInformerLocked(cacheEntry *Cache) {
+ // Don't start the informer in case we are already waiting for the items in
+ // the waitGroup to finish, since waitGroups don't support waiting and adding
+ // at the same time.
+ if ip.stopped {
+ return
+ }
+
+ ip.waitGroup.Add(1)
+ go func() {
+ defer ip.waitGroup.Done()
+ cacheEntry.Start(ip.ctx.Done())
+ }()
+}
+
+func (ip *Informers) waitForStarted(ctx context.Context) bool {
+ select {
+ case <-ip.startWait:
+ return true
+ case <-ctx.Done():
+ return false
+ }
+}
+
+// getHasSyncedFuncs returns all the HasSynced functions for the informers in this map.
+func (ip *Informers) getHasSyncedFuncs() []cache.InformerSynced {
+ ip.mu.RLock()
+ defer ip.mu.RUnlock()
+
+ res := make([]cache.InformerSynced, 0,
+ len(ip.tracker.Structured)+len(ip.tracker.Unstructured)+len(ip.tracker.Metadata),
+ )
+ for _, i := range ip.tracker.Structured {
+ res = append(res, i.Informer.HasSynced)
+ }
+ for _, i := range ip.tracker.Unstructured {
+ res = append(res, i.Informer.HasSynced)
+ }
+ for _, i := range ip.tracker.Metadata {
+ res = append(res, i.Informer.HasSynced)
+ }
+ return res
+}
+
+// WaitForCacheSync waits until all the caches have been started and synced.
+func (ip *Informers) WaitForCacheSync(ctx context.Context) bool {
+ if !ip.waitForStarted(ctx) {
+ return false
+ }
+ return cache.WaitForCacheSync(ctx.Done(), ip.getHasSyncedFuncs()...)
+}
+
+func (ip *Informers) get(gvk schema.GroupVersionKind, obj runtime.Object) (res *Cache, started bool, ok bool) {
+ ip.mu.RLock()
+ defer ip.mu.RUnlock()
+ i, ok := ip.informersByType(obj)[gvk]
+ return i, ip.started, ok
+}
+
+// Get will create a new Informer and add it to the map of specificInformersMap if none exists. Returns
+// the Informer from the map.
+func (ip *Informers) Get(ctx context.Context, gvk schema.GroupVersionKind, obj runtime.Object, opts ...InformerGetOption) (bool, *Cache, error) {
+ // Return the informer if it is found
+ i, started, ok := ip.get(gvk, obj)
+ if !ok {
+ var err error
+ if i, started, err = ip.addInformerToMap(gvk, obj); err != nil {
+ return started, nil, err
+ }
+ }
+
+ cfg := &GetOptions{}
+ for _, opt := range opts {
+ opt(cfg)
+ }
+
+ if started && !i.Informer.HasSynced() && !cfg.DoNotBlockUntilSynced {
+ // Wait for it to sync before returning the Informer so that folks don't read from a stale cache.
+ if !cache.WaitForCacheSync(ctx.Done(), i.Informer.HasSynced) {
+ return started, nil, apierrors.NewTimeoutError(fmt.Sprintf("failed waiting for %T Informer to sync", obj), 0)
+ }
+ }
+
+ return started, i, nil
+}
+
+// Remove removes an informer entry and stops it if it was running.
+func (ip *Informers) Remove(gvk schema.GroupVersionKind, obj runtime.Object) {
+ ip.mu.Lock()
+ defer ip.mu.Unlock()
+
+ informerMap := ip.informersByType(obj)
+
+ entry, ok := informerMap[gvk]
+ if !ok {
+ return
+ }
+ close(entry.stop)
+ delete(informerMap, gvk)
+}
+
+func (ip *Informers) informersByType(obj runtime.Object) map[schema.GroupVersionKind]*Cache {
+ switch obj.(type) {
+ case runtime.Unstructured:
+ return ip.tracker.Unstructured
+ case *metav1.PartialObjectMetadata, *metav1.PartialObjectMetadataList:
+ return ip.tracker.Metadata
+ default:
+ return ip.tracker.Structured
+ }
+}
+
+func (ip *Informers) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.Object) (*Cache, bool, error) {
+ ip.mu.Lock()
+ defer ip.mu.Unlock()
+
+ // Check the cache to see if we already have an Informer. If we do, return the Informer.
+ // This is for the case where 2 routines tried to get the informer when it wasn't in the map
+ // so neither returned early, but the first one created it.
+ if i, ok := ip.informersByType(obj)[gvk]; ok {
+ return i, ip.started, nil
+ }
+
+ // Create a NewSharedIndexInformer and add it to the map.
+ listWatcher, err := ip.makeListWatcher(gvk, obj)
+ if err != nil {
+ return nil, false, err
+ }
+ sharedIndexInformer := cache.NewSharedIndexInformer(&cache.ListWatch{
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
+ ip.getSelector(gvk).ApplyToList(&opts)
+ return listWatcher.ListFunc(opts)
+ },
+ WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
+ ip.getSelector(gvk).ApplyToList(&opts)
+ opts.Watch = true // Watch needs to be set to true separately
+ return listWatcher.WatchFunc(opts)
+ },
+ }, obj, calculateResyncPeriod(ip.resync), cache.Indexers{
+ cache.NamespaceIndex: cache.MetaNamespaceIndexFunc,
+ })
+
+ // Check to see if there is a transformer for this gvk
+ if err := sharedIndexInformer.SetTransform(ip.getTransform(gvk)); err != nil {
+ return nil, false, err
+ }
+
+ mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
+ if err != nil {
+ return nil, false, err
+ }
+
+ // Create the new entry and set it in the map.
+ i := &Cache{
+ Informer: sharedIndexInformer,
+ Reader: CacheReader{
+ indexer: sharedIndexInformer.GetIndexer(),
+ groupVersionKind: gvk,
+ scopeName: mapping.Scope.Name(),
+ disableDeepCopy: ip.getDisableDeepCopy(gvk),
+ },
+ stop: make(chan struct{}),
+ }
+ ip.informersByType(obj)[gvk] = i
+
+ // Start the informer in case the InformersMap has started, otherwise it will be
+ // started when the InformersMap starts.
+ if ip.started {
+ ip.startInformerLocked(i)
+ }
+ return i, ip.started, nil
+}
+
+func (ip *Informers) makeListWatcher(gvk schema.GroupVersionKind, obj runtime.Object) (*cache.ListWatch, error) {
+ // Kubernetes APIs work against Resources, not GroupVersionKinds. Map the
+ // groupVersionKind to the Resource API we will use.
+ mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
+ if err != nil {
+ return nil, err
+ }
+
+ // Figure out if the GVK we're dealing with is global, or namespace scoped.
+ var namespace string
+ if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
+ namespace = restrictNamespaceBySelector(ip.namespace, ip.getSelector(gvk))
+ }
+
+ switch obj.(type) {
+ //
+ // Unstructured
+ //
+ case runtime.Unstructured:
+ // If the rest configuration has a negotiated serializer passed in,
+ // we should remove it and use the one that the dynamic client sets for us.
+ cfg := rest.CopyConfig(ip.config)
+ cfg.NegotiatedSerializer = nil
+ dynamicClient, err := dynamic.NewForConfigAndClient(cfg, ip.httpClient)
+ if err != nil {
+ return nil, err
+ }
+ resources := dynamicClient.Resource(mapping.Resource)
+ return &cache.ListWatch{
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
+ if namespace != "" {
+ return resources.Namespace(namespace).List(ip.ctx, opts)
+ }
+ return resources.List(ip.ctx, opts)
+ },
+ // Setup the watch function
+ WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
+ if namespace != "" {
+ return resources.Namespace(namespace).Watch(ip.ctx, opts)
+ }
+ return resources.Watch(ip.ctx, opts)
+ },
+ }, nil
+ //
+ // Metadata
+ //
+ case *metav1.PartialObjectMetadata, *metav1.PartialObjectMetadataList:
+ // Always clear the negotiated serializer and use the one
+ // set from the metadata client.
+ cfg := rest.CopyConfig(ip.config)
+ cfg.NegotiatedSerializer = nil
+
+ // Grab the metadata metadataClient.
+ metadataClient, err := metadata.NewForConfigAndClient(cfg, ip.httpClient)
+ if err != nil {
+ return nil, err
+ }
+ resources := metadataClient.Resource(mapping.Resource)
+
+ return &cache.ListWatch{
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
+ var (
+ list *metav1.PartialObjectMetadataList
+ err error
+ )
+ if namespace != "" {
+ list, err = resources.Namespace(namespace).List(ip.ctx, opts)
+ } else {
+ list, err = resources.List(ip.ctx, opts)
+ }
+ if list != nil {
+ for i := range list.Items {
+ list.Items[i].SetGroupVersionKind(gvk)
+ }
+ }
+ return list, err
+ },
+ // Setup the watch function
+ WatchFunc: func(opts metav1.ListOptions) (watcher watch.Interface, err error) {
+ if namespace != "" {
+ watcher, err = resources.Namespace(namespace).Watch(ip.ctx, opts)
+ } else {
+ watcher, err = resources.Watch(ip.ctx, opts)
+ }
+ if err != nil {
+ return nil, err
+ }
+ return newGVKFixupWatcher(gvk, watcher), nil
+ },
+ }, nil
+ //
+ // Structured.
+ //
+ default:
+ client, err := apiutil.RESTClientForGVK(gvk, false, ip.config, ip.codecs, ip.httpClient)
+ if err != nil {
+ return nil, err
+ }
+ listGVK := gvk.GroupVersion().WithKind(gvk.Kind + "List")
+ listObj, err := ip.scheme.New(listGVK)
+ if err != nil {
+ return nil, err
+ }
+ return &cache.ListWatch{
+ ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
+ // Build the request.
+ req := client.Get().Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec)
+ if namespace != "" {
+ req.Namespace(namespace)
+ }
+
+ // Create the resulting object, and execute the request.
+ res := listObj.DeepCopyObject()
+ if err := req.Do(ip.ctx).Into(res); err != nil {
+ return nil, err
+ }
+ return res, nil
+ },
+ // Setup the watch function
+ WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
+ // Build the request.
+ req := client.Get().Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec)
+ if namespace != "" {
+ req.Namespace(namespace)
+ }
+ // Call the watch.
+ return req.Watch(ip.ctx)
+ },
+ }, nil
+ }
+}
+
+// newGVKFixupWatcher adds a wrapper that preserves the GVK information when
+// events come in.
+//
+// This works around a bug where GVK information is not passed into mapping
+// functions when using the OnlyMetadata option in the builder.
+// This issue is most likely caused by kubernetes/kubernetes#80609.
+// See kubernetes-sigs/controller-runtime#1484.
+//
+// This was originally implemented as a cache.ResourceEventHandler wrapper but
+// that contained a data race which was resolved by setting the GVK in a watch
+// wrapper, before the objects are written to the cache.
+// See kubernetes-sigs/controller-runtime#1650.
+//
+// The original watch wrapper was found to be incompatible with
+// k8s.io/client-go/tools/cache.Reflector so it has been re-implemented as a
+// watch.Filter which is compatible.
+// See kubernetes-sigs/controller-runtime#1789.
+func newGVKFixupWatcher(gvk schema.GroupVersionKind, watcher watch.Interface) watch.Interface {
+ return watch.Filter(
+ watcher,
+ func(in watch.Event) (watch.Event, bool) {
+ in.Object.GetObjectKind().SetGroupVersionKind(gvk)
+ return in, true
+ },
+ )
+}
+
+// calculateResyncPeriod returns a duration based on the desired input
+// this is so that multiple controllers don't get into lock-step and all
+// hammer the apiserver with list requests simultaneously.
+func calculateResyncPeriod(resync time.Duration) time.Duration {
+ // the factor will fall into [0.9, 1.1)
+ factor := rand.Float64()/5.0 + 0.9 //nolint:gosec
+ return time.Duration(float64(resync.Nanoseconds()) * factor)
+}
+
+// restrictNamespaceBySelector returns either a global restriction for all ListWatches
+// if not default/empty, or the namespace that a ListWatch for the specific resource
+// is restricted to, based on a specified field selector for metadata.namespace field.
+func restrictNamespaceBySelector(namespaceOpt string, s Selector) string {
+ if namespaceOpt != "" {
+ // namespace is already restricted
+ return namespaceOpt
+ }
+ fieldSelector := s.Field
+ if fieldSelector == nil || fieldSelector.Empty() {
+ return ""
+ }
+ // check whether a selector includes the namespace field
+ value, found := fieldSelector.RequiresExactMatch("metadata.namespace")
+ if found {
+ return value
+ }
+ return ""
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_test.go
new file mode 100644
index 00000000000..854a39c1f1c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_test.go
@@ -0,0 +1,94 @@
+/*
+Copyright 2022 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package internal
+
+import (
+ "fmt"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/watch"
+)
+
+// Test that gvkFixupWatcher behaves like watch.FakeWatcher
+// and that it overrides the GVK.
+// These tests are adapted from the watch.FakeWatcher tests in:
+// https://github.com/kubernetes/kubernetes/blob/adbda068c1808fcc8a64a94269e0766b5c46ec41/staging/src/k8s.io/apimachinery/pkg/watch/watch_test.go#L33-L78
+var _ = Describe("gvkFixupWatcher", func() {
+ It("behaves like watch.FakeWatcher", func() {
+ newTestType := func(name string) runtime.Object {
+ return &metav1.PartialObjectMetadata{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: name,
+ },
+ }
+ }
+
+ f := watch.NewFake()
+ // This is the GVK which we expect the wrapper to set on all the events
+ expectedGVK := schema.GroupVersionKind{
+ Group: "testgroup",
+ Version: "v1test2",
+ Kind: "TestKind",
+ }
+ gvkfw := newGVKFixupWatcher(expectedGVK, f)
+
+ table := []struct {
+ t watch.EventType
+ s runtime.Object
+ }{
+ {watch.Added, newTestType("foo")},
+ {watch.Modified, newTestType("qux")},
+ {watch.Modified, newTestType("bar")},
+ {watch.Deleted, newTestType("bar")},
+ {watch.Error, newTestType("error: blah")},
+ }
+
+ consumer := func(w watch.Interface) {
+ for _, expect := range table {
+ By(fmt.Sprintf("Fixing up watch.EventType: %v and passing it on", expect.t))
+ got, ok := <-w.ResultChan()
+ Expect(ok).To(BeTrue(), "closed early")
+ Expect(expect.t).To(Equal(got.Type), "unexpected Event.Type or out-of-order Event")
+ Expect(got.Object).To(BeAssignableToTypeOf(&metav1.PartialObjectMetadata{}), "unexpected Event.Object type")
+ a := got.Object.(*metav1.PartialObjectMetadata)
+ Expect(got.Object.GetObjectKind().GroupVersionKind()).To(Equal(expectedGVK), "GVK was not fixed up")
+ expected := expect.s.DeepCopyObject()
+ expected.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{})
+ actual := a.DeepCopyObject()
+ actual.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{})
+ Expect(actual).To(Equal(expected), "unexpected change to the Object")
+ }
+ Eventually(w.ResultChan()).Should(BeClosed())
+ }
+
+ sender := func() {
+ f.Add(newTestType("foo"))
+ f.Action(watch.Modified, newTestType("qux"))
+ f.Modify(newTestType("bar"))
+ f.Delete(newTestType("bar"))
+ f.Error(newTestType("error: blah"))
+ f.Stop()
+ }
+
+ go sender()
+ consumer(gvkfw)
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/internal_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/internal_suite_test.go
new file mode 100644
index 00000000000..25ec0f1dbce
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/internal_suite_test.go
@@ -0,0 +1,29 @@
+/*
+Copyright 2022 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package internal
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Cache Internal Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/selector.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go
similarity index 86%
rename from third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/selector.go
rename to third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go
index cd9c5800080..c674379b992 100644
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/selector.go
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go
@@ -20,12 +20,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
- "k8s.io/apimachinery/pkg/runtime/schema"
)
-// SelectorsByGVK associate a GroupVersionKind to a field/label selector.
-type SelectorsByGVK map[schema.GroupVersionKind]Selector
-
// Selector specify the label/field selector to fill in ListOptions.
type Selector struct {
Label labels.Selector
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/transformers.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/transformers.go
new file mode 100644
index 00000000000..0725f550c5e
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/internal/transformers.go
@@ -0,0 +1,55 @@
+package internal
+
+import (
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/tools/cache"
+
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+)
+
+// TransformFuncByGVK provides access to the correct transform function for
+// any given GVK.
+type TransformFuncByGVK interface {
+ Set(runtime.Object, *runtime.Scheme, cache.TransformFunc) error
+ Get(schema.GroupVersionKind) cache.TransformFunc
+ SetDefault(transformer cache.TransformFunc)
+}
+
+type transformFuncByGVK struct {
+ defaultTransform cache.TransformFunc
+ transformers map[schema.GroupVersionKind]cache.TransformFunc
+}
+
+// TransformFuncByGVKFromMap creates a TransformFuncByGVK from a map that
+// maps GVKs to TransformFuncs.
+func TransformFuncByGVKFromMap(in map[schema.GroupVersionKind]cache.TransformFunc) TransformFuncByGVK {
+ byGVK := &transformFuncByGVK{}
+ if defaultFunc, hasDefault := in[schema.GroupVersionKind{}]; hasDefault {
+ byGVK.defaultTransform = defaultFunc
+ }
+ delete(in, schema.GroupVersionKind{})
+ byGVK.transformers = in
+ return byGVK
+}
+
+func (t *transformFuncByGVK) SetDefault(transformer cache.TransformFunc) {
+ t.defaultTransform = transformer
+}
+
+func (t *transformFuncByGVK) Set(obj runtime.Object, scheme *runtime.Scheme, transformer cache.TransformFunc) error {
+ gvk, err := apiutil.GVKForObject(obj, scheme)
+ if err != nil {
+ return err
+ }
+
+ t.transformers[gvk] = transformer
+ return nil
+}
+
+func (t transformFuncByGVK) Get(gvk schema.GroupVersionKind) cache.TransformFunc {
+ if val, ok := t.transformers[gvk]; ok {
+ return val
+ }
+ return t.defaultTransform
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go
new file mode 100644
index 00000000000..ff617beab0c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go
@@ -0,0 +1,391 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cache
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ corev1 "k8s.io/api/core/v1"
+ apimeta "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/rest"
+ toolscache "k8s.io/client-go/tools/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+)
+
+// a new global namespaced cache to handle cluster scoped resources.
+const globalCache = "_cluster-scope"
+
+// MultiNamespacedCacheBuilder - Builder function to create a new multi-namespaced cache.
+// This will scope the cache to a list of namespaces. Listing for all namespaces
+// will list for all the namespaces that this knows about. By default this will create
+// a global cache for cluster scoped resource. Note that this is not intended
+// to be used for excluding namespaces, this is better done via a Predicate. Also note that
+// you may face performance issues when using this with a high number of namespaces.
+//
+// Deprecated: Use cache.Options.Namespaces instead.
+func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
+ return func(config *rest.Config, opts Options) (Cache, error) {
+ opts.Namespaces = namespaces
+ return newMultiNamespaceCache(config, opts)
+ }
+}
+
+func newMultiNamespaceCache(config *rest.Config, opts Options) (Cache, error) {
+ if len(opts.Namespaces) < 2 {
+ return nil, fmt.Errorf("must specify more than one namespace to use multi-namespace cache")
+ }
+ opts, err := defaultOpts(config, opts)
+ if err != nil {
+ return nil, err
+ }
+
+ // Create every namespace cache.
+ caches := map[string]Cache{}
+ for _, ns := range opts.Namespaces {
+ opts.Namespaces = []string{ns}
+ c, err := New(config, opts)
+ if err != nil {
+ return nil, err
+ }
+ caches[ns] = c
+ }
+
+ // Create a cache for cluster scoped resources.
+ opts.Namespaces = []string{}
+ gCache, err := New(config, opts)
+ if err != nil {
+ return nil, fmt.Errorf("error creating global cache: %w", err)
+ }
+
+ return &multiNamespaceCache{namespaceToCache: caches, Scheme: opts.Scheme, RESTMapper: opts.Mapper, clusterCache: gCache}, nil
+}
+
+// multiNamespaceCache knows how to handle multiple namespaced caches
+// Use this feature when scoping permissions for your
+// operator to a list of namespaces instead of watching every namespace
+// in the cluster.
+type multiNamespaceCache struct {
+ namespaceToCache map[string]Cache
+ Scheme *runtime.Scheme
+ RESTMapper apimeta.RESTMapper
+ clusterCache Cache
+}
+
+var _ Cache = &multiNamespaceCache{}
+
+// Methods for multiNamespaceCache to conform to the Informers interface.
+func (c *multiNamespaceCache) GetInformer(ctx context.Context, obj client.Object, opts ...InformerGetOption) (Informer, error) {
+ informers := map[string]Informer{}
+
+ // If the object is clusterscoped, get the informer from clusterCache,
+ // if not use the namespaced caches.
+ isNamespaced, err := apiutil.IsObjectNamespaced(obj, c.Scheme, c.RESTMapper)
+ if err != nil {
+ return nil, err
+ }
+ if !isNamespaced {
+ clusterCacheInf, err := c.clusterCache.GetInformer(ctx, obj, opts...)
+ if err != nil {
+ return nil, err
+ }
+ informers[globalCache] = clusterCacheInf
+
+ return &multiNamespaceInformer{namespaceToInformer: informers}, nil
+ }
+
+ for ns, cache := range c.namespaceToCache {
+ informer, err := cache.GetInformer(ctx, obj)
+ if err != nil {
+ return nil, err
+ }
+ informers[ns] = informer
+ }
+
+ return &multiNamespaceInformer{namespaceToInformer: informers}, nil
+}
+
+func (c *multiNamespaceCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind, opts ...InformerGetOption) (Informer, error) {
+ informers := map[string]Informer{}
+
+ // If the object is clusterscoped, get the informer from clusterCache,
+ // if not use the namespaced caches.
+ isNamespaced, err := apiutil.IsGVKNamespaced(gvk, c.RESTMapper)
+ if err != nil {
+ return nil, err
+ }
+ if !isNamespaced {
+ clusterCacheInf, err := c.clusterCache.GetInformerForKind(ctx, gvk, opts...)
+ if err != nil {
+ return nil, err
+ }
+ informers[globalCache] = clusterCacheInf
+
+ return &multiNamespaceInformer{namespaceToInformer: informers}, nil
+ }
+
+ for ns, cache := range c.namespaceToCache {
+ informer, err := cache.GetInformerForKind(ctx, gvk, opts...)
+ if err != nil {
+ return nil, err
+ }
+ informers[ns] = informer
+ }
+
+ return &multiNamespaceInformer{namespaceToInformer: informers}, nil
+}
+
+func (c *multiNamespaceCache) Start(ctx context.Context) error {
+ // start global cache
+ go func() {
+ err := c.clusterCache.Start(ctx)
+ if err != nil {
+ log.Error(err, "cluster scoped cache failed to start")
+ }
+ }()
+
+ // start namespaced caches
+ for ns, cache := range c.namespaceToCache {
+ go func(ns string, cache Cache) {
+ err := cache.Start(ctx)
+ if err != nil {
+ log.Error(err, "multinamespace cache failed to start namespaced informer", "namespace", ns)
+ }
+ }(ns, cache)
+ }
+
+ <-ctx.Done()
+ return nil
+}
+
+func (c *multiNamespaceCache) WaitForCacheSync(ctx context.Context) bool {
+ synced := true
+ for _, cache := range c.namespaceToCache {
+ if s := cache.WaitForCacheSync(ctx); !s {
+ synced = s
+ }
+ }
+
+ // check if cluster scoped cache has synced
+ if !c.clusterCache.WaitForCacheSync(ctx) {
+ synced = false
+ }
+ return synced
+}
+
+func (c *multiNamespaceCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error {
+ isNamespaced, err := apiutil.IsObjectNamespaced(obj, c.Scheme, c.RESTMapper)
+ if err != nil {
+ return err
+ }
+
+ if !isNamespaced {
+ return c.clusterCache.IndexField(ctx, obj, field, extractValue)
+ }
+
+ for _, cache := range c.namespaceToCache {
+ if err := cache.IndexField(ctx, obj, field, extractValue); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
+ isNamespaced, err := apiutil.IsObjectNamespaced(obj, c.Scheme, c.RESTMapper)
+ if err != nil {
+ return err
+ }
+
+ if !isNamespaced {
+ // Look into the global cache to fetch the object
+ return c.clusterCache.Get(ctx, key, obj)
+ }
+
+ cache, ok := c.namespaceToCache[key.Namespace]
+ if !ok {
+ return fmt.Errorf("unable to get: %v because of unknown namespace for the cache", key)
+ }
+ return cache.Get(ctx, key, obj)
+}
+
+// List multi namespace cache will get all the objects in the namespaces that the cache is watching if asked for all namespaces.
+func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
+ listOpts := client.ListOptions{}
+ listOpts.ApplyOptions(opts)
+
+ isNamespaced, err := apiutil.IsObjectNamespaced(list, c.Scheme, c.RESTMapper)
+ if err != nil {
+ return err
+ }
+
+ if !isNamespaced {
+ // Look at the global cache to get the objects with the specified GVK
+ return c.clusterCache.List(ctx, list, opts...)
+ }
+
+ if listOpts.Namespace != corev1.NamespaceAll {
+ cache, ok := c.namespaceToCache[listOpts.Namespace]
+ if !ok {
+ return fmt.Errorf("unable to get: %v because of unknown namespace for the cache", listOpts.Namespace)
+ }
+ return cache.List(ctx, list, opts...)
+ }
+
+ listAccessor, err := apimeta.ListAccessor(list)
+ if err != nil {
+ return err
+ }
+
+ allItems, err := apimeta.ExtractList(list)
+ if err != nil {
+ return err
+ }
+
+ limitSet := listOpts.Limit > 0
+
+ var resourceVersion string
+ for _, cache := range c.namespaceToCache {
+ listObj := list.DeepCopyObject().(client.ObjectList)
+ err = cache.List(ctx, listObj, &listOpts)
+ if err != nil {
+ return err
+ }
+ items, err := apimeta.ExtractList(listObj)
+ if err != nil {
+ return err
+ }
+ accessor, err := apimeta.ListAccessor(listObj)
+ if err != nil {
+ return fmt.Errorf("object: %T must be a list type", list)
+ }
+ allItems = append(allItems, items...)
+ // The last list call should have the most correct resource version.
+ resourceVersion = accessor.GetResourceVersion()
+ if limitSet {
+ // decrement Limit by the number of items
+ // fetched from the current namespace.
+ listOpts.Limit -= int64(len(items))
+ // if a Limit was set and the number of
+ // items read has reached this set limit,
+ // then stop reading.
+ if listOpts.Limit == 0 {
+ break
+ }
+ }
+ }
+ listAccessor.SetResourceVersion(resourceVersion)
+
+ return apimeta.SetList(list, allItems)
+}
+
+// multiNamespaceInformer knows how to handle interacting with the underlying informer across multiple namespaces.
+type multiNamespaceInformer struct {
+ namespaceToInformer map[string]Informer
+}
+
+type handlerRegistration struct {
+ handles map[string]toolscache.ResourceEventHandlerRegistration
+}
+
+type syncer interface {
+ HasSynced() bool
+}
+
+// HasSynced asserts that the handler has been called for the full initial state of the informer.
+// This uses syncer to be compatible between client-go 1.27+ and older versions when the interface changed.
+func (h handlerRegistration) HasSynced() bool {
+ for _, reg := range h.handles {
+ if s, ok := reg.(syncer); ok {
+ if !s.HasSynced() {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+var _ Informer = &multiNamespaceInformer{}
+
+// AddEventHandler adds the handler to each namespaced informer.
+func (i *multiNamespaceInformer) AddEventHandler(handler toolscache.ResourceEventHandler) (toolscache.ResourceEventHandlerRegistration, error) {
+ handles := handlerRegistration{handles: make(map[string]toolscache.ResourceEventHandlerRegistration, len(i.namespaceToInformer))}
+ for ns, informer := range i.namespaceToInformer {
+ registration, err := informer.AddEventHandler(handler)
+ if err != nil {
+ return nil, err
+ }
+ handles.handles[ns] = registration
+ }
+ return handles, nil
+}
+
+// AddEventHandlerWithResyncPeriod adds the handler with a resync period to each namespaced informer.
+func (i *multiNamespaceInformer) AddEventHandlerWithResyncPeriod(handler toolscache.ResourceEventHandler, resyncPeriod time.Duration) (toolscache.ResourceEventHandlerRegistration, error) {
+ handles := handlerRegistration{handles: make(map[string]toolscache.ResourceEventHandlerRegistration, len(i.namespaceToInformer))}
+ for ns, informer := range i.namespaceToInformer {
+ registration, err := informer.AddEventHandlerWithResyncPeriod(handler, resyncPeriod)
+ if err != nil {
+ return nil, err
+ }
+ handles.handles[ns] = registration
+ }
+ return handles, nil
+}
+
+// RemoveEventHandler removes a formerly added event handler given by its registration handle.
+func (i *multiNamespaceInformer) RemoveEventHandler(h toolscache.ResourceEventHandlerRegistration) error {
+ handles, ok := h.(handlerRegistration)
+ if !ok {
+ return fmt.Errorf("it is not the registration returned by multiNamespaceInformer")
+ }
+ for ns, informer := range i.namespaceToInformer {
+ registration, ok := handles.handles[ns]
+ if !ok {
+ continue
+ }
+ if err := informer.RemoveEventHandler(registration); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// AddIndexers adds the indexer for each namespaced informer.
+func (i *multiNamespaceInformer) AddIndexers(indexers toolscache.Indexers) error {
+ for _, informer := range i.namespaceToInformer {
+ err := informer.AddIndexers(indexers)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// HasSynced checks if each namespaced informer has synced.
+func (i *multiNamespaceInformer) HasSynced() bool {
+ for _, informer := range i.namespaceToInformer {
+ if ok := informer.HasSynced(); !ok {
+ return ok
+ }
+ }
+ return true
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go
new file mode 100644
index 00000000000..2b9b60d8d77
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go
@@ -0,0 +1,204 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package certwatcher
+
+import (
+ "context"
+ "crypto/tls"
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/fsnotify/fsnotify"
+ kerrors "k8s.io/apimachinery/pkg/util/errors"
+ "k8s.io/apimachinery/pkg/util/sets"
+ "k8s.io/apimachinery/pkg/util/wait"
+ "sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("certwatcher")
+
+// CertWatcher watches certificate and key files for changes. When either file
+// changes, it reads and parses both and calls an optional callback with the new
+// certificate.
+type CertWatcher struct {
+ sync.RWMutex
+
+ currentCert *tls.Certificate
+ watcher *fsnotify.Watcher
+
+ certPath string
+ keyPath string
+
+ // callback is a function to be invoked when the certificate changes.
+ callback func(tls.Certificate)
+}
+
+// New returns a new CertWatcher watching the given certificate and key.
+func New(certPath, keyPath string) (*CertWatcher, error) {
+ var err error
+
+ cw := &CertWatcher{
+ certPath: certPath,
+ keyPath: keyPath,
+ }
+
+ // Initial read of certificate and key.
+ if err := cw.ReadCertificate(); err != nil {
+ return nil, err
+ }
+
+ cw.watcher, err = fsnotify.NewWatcher()
+ if err != nil {
+ return nil, err
+ }
+
+ return cw, nil
+}
+
+// RegisterCallback registers a callback to be invoked when the certificate changes.
+func (cw *CertWatcher) RegisterCallback(callback func(tls.Certificate)) {
+ cw.Lock()
+ defer cw.Unlock()
+ // If the current certificate is not nil, invoke the callback immediately.
+ if cw.currentCert != nil {
+ callback(*cw.currentCert)
+ }
+ cw.callback = callback
+}
+
+// GetCertificate fetches the currently loaded certificate, which may be nil.
+func (cw *CertWatcher) GetCertificate(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
+ cw.RLock()
+ defer cw.RUnlock()
+ return cw.currentCert, nil
+}
+
+// Start starts the watch on the certificate and key files.
+func (cw *CertWatcher) Start(ctx context.Context) error {
+ files := sets.New(cw.certPath, cw.keyPath)
+
+ {
+ var watchErr error
+ if err := wait.PollUntilContextTimeout(ctx, 1*time.Second, 10*time.Second, true, func(ctx context.Context) (done bool, err error) {
+ for _, f := range files.UnsortedList() {
+ if err := cw.watcher.Add(f); err != nil {
+ watchErr = err
+ return false, nil //nolint:nilerr // We want to keep trying.
+ }
+ // We've added the watch, remove it from the set.
+ files.Delete(f)
+ }
+ return true, nil
+ }); err != nil {
+ return fmt.Errorf("failed to add watches: %w", kerrors.NewAggregate([]error{err, watchErr}))
+ }
+ }
+
+ go cw.Watch()
+
+ log.Info("Starting certificate watcher")
+
+ // Block until the context is done.
+ <-ctx.Done()
+
+ return cw.watcher.Close()
+}
+
+// Watch reads events from the watcher's channel and reacts to changes.
+func (cw *CertWatcher) Watch() {
+ for {
+ select {
+ case event, ok := <-cw.watcher.Events:
+ // Channel is closed.
+ if !ok {
+ return
+ }
+
+ cw.handleEvent(event)
+
+ case err, ok := <-cw.watcher.Errors:
+ // Channel is closed.
+ if !ok {
+ return
+ }
+
+ log.Error(err, "certificate watch error")
+ }
+ }
+}
+
+// ReadCertificate reads the certificate and key files from disk, parses them,
+// and updates the current certificate on the watcher. If a callback is set, it
+// is invoked with the new certificate.
+func (cw *CertWatcher) ReadCertificate() error {
+ metrics.ReadCertificateTotal.Inc()
+ cert, err := tls.LoadX509KeyPair(cw.certPath, cw.keyPath)
+ if err != nil {
+ metrics.ReadCertificateErrors.Inc()
+ return err
+ }
+
+ cw.Lock()
+ cw.currentCert = &cert
+ cw.Unlock()
+
+ log.Info("Updated current TLS certificate")
+
+ // If a callback is registered, invoke it with the new certificate.
+ cw.RLock()
+ defer cw.RUnlock()
+ if cw.callback != nil {
+ go func() {
+ cw.callback(cert)
+ }()
+ }
+ return nil
+}
+
+func (cw *CertWatcher) handleEvent(event fsnotify.Event) {
+ // Only care about events which may modify the contents of the file.
+ if !(isWrite(event) || isRemove(event) || isCreate(event)) {
+ return
+ }
+
+ log.V(1).Info("certificate event", "event", event)
+
+ // If the file was removed, re-add the watch.
+ if isRemove(event) {
+ if err := cw.watcher.Add(event.Name); err != nil {
+ log.Error(err, "error re-watching file")
+ }
+ }
+
+ if err := cw.ReadCertificate(); err != nil {
+ log.Error(err, "error re-reading certificate")
+ }
+}
+
+func isWrite(event fsnotify.Event) bool {
+ return event.Op.Has(fsnotify.Write)
+}
+
+func isCreate(event fsnotify.Event) bool {
+ return event.Op.Has(fsnotify.Create)
+}
+
+func isRemove(event fsnotify.Event) bool {
+ return event.Op.Has(fsnotify.Remove)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher_suite_test.go
new file mode 100644
index 00000000000..a44a968c895
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher_suite_test.go
@@ -0,0 +1,47 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package certwatcher_test
+
+import (
+ "os"
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+var (
+ certPath = "testdata/tls.crt"
+ keyPath = "testdata/tls.key"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "CertWatcher Suite")
+}
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+})
+
+var _ = AfterSuite(func() {
+ for _, file := range []string{certPath, keyPath} {
+ _ = os.Remove(file)
+ }
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher_test.go
new file mode 100644
index 00000000000..7eef9d8b0e8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher_test.go
@@ -0,0 +1,251 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package certwatcher_test
+
+import (
+ "context"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/tls"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "fmt"
+ "math/big"
+ "net"
+ "os"
+ "sync/atomic"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/prometheus/client_golang/prometheus/testutil"
+ "sigs.k8s.io/controller-runtime/pkg/certwatcher"
+ "sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics"
+)
+
+var _ = Describe("CertWatcher", func() {
+ var _ = Describe("certwatcher New", func() {
+ It("should errors without cert/key", func() {
+ _, err := certwatcher.New("", "")
+ Expect(err).ToNot(BeNil())
+ })
+ })
+
+ var _ = Describe("certwatcher Start", func() {
+ var (
+ ctx context.Context
+ ctxCancel context.CancelFunc
+ watcher *certwatcher.CertWatcher
+ )
+
+ BeforeEach(func() {
+ ctx, ctxCancel = context.WithCancel(context.Background())
+
+ err := writeCerts(certPath, keyPath, "127.0.0.1")
+ Expect(err).To(BeNil())
+
+ Eventually(func() error {
+ for _, file := range []string{certPath, keyPath} {
+ _, err := os.ReadFile(file)
+ if err != nil {
+ return err
+ }
+ continue
+ }
+
+ return nil
+ }).Should(Succeed())
+
+ watcher, err = certwatcher.New(certPath, keyPath)
+ Expect(err).To(BeNil())
+ })
+
+ startWatcher := func() (done <-chan struct{}) {
+ doneCh := make(chan struct{})
+ go func() {
+ defer GinkgoRecover()
+ defer close(doneCh)
+ Expect(watcher.Start(ctx)).To(Succeed())
+ }()
+ // wait till we read first cert
+ Eventually(func() error {
+ err := watcher.ReadCertificate()
+ return err
+ }).Should(Succeed())
+ return doneCh
+ }
+
+ It("should read the initial cert/key", func() {
+ doneCh := startWatcher()
+
+ ctxCancel()
+ Eventually(doneCh, "4s").Should(BeClosed())
+ })
+
+ It("should reload currentCert when changed", func() {
+ doneCh := startWatcher()
+ called := atomic.Int64{}
+ watcher.RegisterCallback(func(crt tls.Certificate) {
+ called.Add(1)
+ Expect(crt.Certificate).ToNot(BeEmpty())
+ })
+
+ firstcert, _ := watcher.GetCertificate(nil)
+
+ err := writeCerts(certPath, keyPath, "192.168.0.1")
+ Expect(err).To(BeNil())
+
+ Eventually(func() bool {
+ secondcert, _ := watcher.GetCertificate(nil)
+ first := firstcert.PrivateKey.(*rsa.PrivateKey)
+ return first.Equal(secondcert.PrivateKey)
+ }).ShouldNot(BeTrue())
+
+ ctxCancel()
+ Eventually(doneCh, "4s").Should(BeClosed())
+ Expect(called.Load()).To(BeNumerically(">=", 1))
+ })
+
+ Context("prometheus metric read_certificate_total", func() {
+ var readCertificateTotalBefore float64
+ var readCertificateErrorsBefore float64
+
+ BeforeEach(func() {
+ readCertificateTotalBefore = testutil.ToFloat64(metrics.ReadCertificateTotal)
+ readCertificateErrorsBefore = testutil.ToFloat64(metrics.ReadCertificateErrors)
+ })
+
+ It("should get updated on successful certificate read", func() {
+ doneCh := startWatcher()
+
+ Eventually(func() error {
+ readCertificateTotalAfter := testutil.ToFloat64(metrics.ReadCertificateTotal)
+ if readCertificateTotalAfter != readCertificateTotalBefore+1.0 {
+ return fmt.Errorf("metric read certificate total expected: %v and got: %v", readCertificateTotalBefore+1.0, readCertificateTotalAfter)
+ }
+ return nil
+ }, "4s").Should(Succeed())
+
+ ctxCancel()
+ Eventually(doneCh, "4s").Should(BeClosed())
+ })
+
+ It("should get updated on read certificate errors", func() {
+ doneCh := startWatcher()
+
+ Eventually(func() error {
+ readCertificateTotalAfter := testutil.ToFloat64(metrics.ReadCertificateTotal)
+ if readCertificateTotalAfter != readCertificateTotalBefore+1.0 {
+ return fmt.Errorf("metric read certificate total expected: %v and got: %v", readCertificateTotalBefore+1.0, readCertificateTotalAfter)
+ }
+ readCertificateTotalBefore = readCertificateTotalAfter
+ return nil
+ }, "4s").Should(Succeed())
+
+ Expect(os.Remove(keyPath)).To(BeNil())
+
+ Eventually(func() error {
+ readCertificateTotalAfter := testutil.ToFloat64(metrics.ReadCertificateTotal)
+ if readCertificateTotalAfter != readCertificateTotalBefore+1.0 {
+ return fmt.Errorf("metric read certificate total expected: %v and got: %v", readCertificateTotalBefore+1.0, readCertificateTotalAfter)
+ }
+ return nil
+ }, "4s").Should(Succeed())
+ Eventually(func() error {
+ readCertificateErrorsAfter := testutil.ToFloat64(metrics.ReadCertificateErrors)
+ if readCertificateErrorsAfter != readCertificateErrorsBefore+1.0 {
+ return fmt.Errorf("metric read certificate errors expected: %v and got: %v", readCertificateErrorsBefore+1.0, readCertificateErrorsAfter)
+ }
+ return nil
+ }, "4s").Should(Succeed())
+
+ ctxCancel()
+ Eventually(doneCh, "4s").Should(BeClosed())
+ })
+ })
+ })
+})
+
+func writeCerts(certPath, keyPath, ip string) error {
+ var priv interface{}
+ var err error
+ priv, err = rsa.GenerateKey(rand.Reader, 2048)
+ if err != nil {
+ return err
+ }
+
+ keyUsage := x509.KeyUsageDigitalSignature
+ if _, isRSA := priv.(*rsa.PrivateKey); isRSA {
+ keyUsage |= x509.KeyUsageKeyEncipherment
+ }
+
+ notBefore := time.Now()
+ notAfter := notBefore.Add(1 * time.Hour)
+
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+ if err != nil {
+ return err
+ }
+
+ template := x509.Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{
+ Organization: []string{"Kubernetes"},
+ },
+ NotBefore: notBefore,
+ NotAfter: notAfter,
+
+ KeyUsage: keyUsage,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+ BasicConstraintsValid: true,
+ }
+
+ template.IPAddresses = append(template.IPAddresses, net.ParseIP(ip))
+
+ privkey := priv.(*rsa.PrivateKey)
+
+ derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privkey.PublicKey, priv)
+ if err != nil {
+ return err
+ }
+
+ certOut, err := os.Create(certPath)
+ if err != nil {
+ return err
+ }
+ if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
+ return err
+ }
+ if err := certOut.Close(); err != nil {
+ return err
+ }
+
+ keyOut, err := os.OpenFile(keyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+ if err != nil {
+ return err
+ }
+ privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
+ if err != nil {
+ return err
+ }
+ if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
+ return err
+ }
+ return keyOut.Close()
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/doc.go
new file mode 100644
index 00000000000..40c2fc0bfbf
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/doc.go
@@ -0,0 +1,23 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package certwatcher is a helper for reloading Certificates from disk to be used
+with tls servers. It provides a helper func `GetCertificate` which can be
+called from `tls.Config` and passed into your tls.Listener. For a detailed
+example server view pkg/webhook/server.go.
+*/
+package certwatcher
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/example_test.go
new file mode 100644
index 00000000000..e322aeebfc8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/example_test.go
@@ -0,0 +1,81 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package certwatcher_test
+
+import (
+ "context"
+ "crypto/tls"
+ "net/http"
+ "time"
+
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/certwatcher"
+)
+
+type sampleServer struct {
+}
+
+func Example() {
+ // Setup Context
+ ctx := ctrl.SetupSignalHandler()
+
+ // Initialize a new cert watcher with cert/key pair
+ watcher, err := certwatcher.New("ssl/tls.crt", "ssl/tls.key")
+ if err != nil {
+ panic(err)
+ }
+
+ // Start goroutine with certwatcher running fsnotify against supplied certdir
+ go func() {
+ if err := watcher.Start(ctx); err != nil {
+ panic(err)
+ }
+ }()
+
+ // Setup TLS listener using GetCertficate for fetching the cert when changes
+ listener, err := tls.Listen("tcp", "localhost:9443", &tls.Config{
+ GetCertificate: watcher.GetCertificate,
+ MinVersion: tls.VersionTLS12,
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ // Initialize your tls server
+ srv := &http.Server{
+ Handler: &sampleServer{},
+ ReadHeaderTimeout: 5 * time.Second,
+ }
+
+ // Start goroutine for handling server shutdown.
+ go func() {
+ <-ctx.Done()
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+ if err := srv.Shutdown(ctx); err != nil {
+ panic(err)
+ }
+ }()
+
+ // Serve t
+ if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed {
+ panic(err)
+ }
+}
+
+func (s *sampleServer) ServeHTTP(http.ResponseWriter, *http.Request) {
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics/metrics.go b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics/metrics.go
new file mode 100644
index 00000000000..05869eff030
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics/metrics.go
@@ -0,0 +1,45 @@
+/*
+Copyright 2022 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package metrics
+
+import (
+ "github.com/prometheus/client_golang/prometheus"
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+)
+
+var (
+ // ReadCertificateTotal is a prometheus counter metrics which holds the total
+ // number of certificate reads.
+ ReadCertificateTotal = prometheus.NewCounter(prometheus.CounterOpts{
+ Name: "certwatcher_read_certificate_total",
+ Help: "Total number of certificate reads",
+ })
+
+ // ReadCertificateErrors is a prometheus counter metrics which holds the total
+ // number of errors from certificate read.
+ ReadCertificateErrors = prometheus.NewCounter(prometheus.CounterOpts{
+ Name: "certwatcher_read_certificate_errors_total",
+ Help: "Total number of certificate read errors",
+ })
+)
+
+func init() {
+ metrics.Registry.MustRegister(
+ ReadCertificateTotal,
+ ReadCertificateErrors,
+ )
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/testdata/.gitkeep b/third_party/sigs.k8s.io/controller-runtime/pkg/certwatcher/testdata/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go
new file mode 100644
index 00000000000..6a1bfb546ea
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go
@@ -0,0 +1,246 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package apiutil contains utilities for working with raw Kubernetes
+// API machinery, such as creating RESTMappers and raw REST clients,
+// and extracting the GVK of an object.
+package apiutil
+
+import (
+ "errors"
+ "fmt"
+ "net/http"
+ "reflect"
+ "sync"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ "k8s.io/client-go/discovery"
+ "k8s.io/client-go/dynamic"
+ clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/restmapper"
+)
+
+var (
+ protobufScheme = runtime.NewScheme()
+ protobufSchemeLock sync.RWMutex
+)
+
+func init() {
+ // Currently only enabled for built-in resources which are guaranteed to implement Protocol Buffers.
+ // For custom resources, CRDs can not support Protocol Buffers but Aggregated API can.
+ // See doc: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#advanced-features-and-flexibility
+ if err := clientgoscheme.AddToScheme(protobufScheme); err != nil {
+ panic(err)
+ }
+}
+
+// AddToProtobufScheme add the given SchemeBuilder into protobufScheme, which should
+// be additional types that do support protobuf.
+func AddToProtobufScheme(addToScheme func(*runtime.Scheme) error) error {
+ protobufSchemeLock.Lock()
+ defer protobufSchemeLock.Unlock()
+ return addToScheme(protobufScheme)
+}
+
+// NewDiscoveryRESTMapper constructs a new RESTMapper based on discovery
+// information fetched by a new client with the given config.
+func NewDiscoveryRESTMapper(c *rest.Config, httpClient *http.Client) (meta.RESTMapper, error) {
+ if httpClient == nil {
+ return nil, fmt.Errorf("httpClient must not be nil, consider using rest.HTTPClientFor(c) to create a client")
+ }
+
+ // Get a mapper
+ dc, err := discovery.NewDiscoveryClientForConfigAndClient(c, httpClient)
+ if err != nil {
+ return nil, err
+ }
+ gr, err := restmapper.GetAPIGroupResources(dc)
+ if err != nil {
+ return nil, err
+ }
+ return restmapper.NewDiscoveryRESTMapper(gr), nil
+}
+
+// IsObjectNamespaced returns true if the object is namespace scoped.
+// For unstructured objects the gvk is found from the object itself.
+func IsObjectNamespaced(obj runtime.Object, scheme *runtime.Scheme, restmapper meta.RESTMapper) (bool, error) {
+ gvk, err := GVKForObject(obj, scheme)
+ if err != nil {
+ return false, err
+ }
+
+ return IsGVKNamespaced(gvk, restmapper)
+}
+
+// IsGVKNamespaced returns true if the object having the provided
+// GVK is namespace scoped.
+func IsGVKNamespaced(gvk schema.GroupVersionKind, restmapper meta.RESTMapper) (bool, error) {
+ restmapping, err := restmapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind})
+ if err != nil {
+ return false, fmt.Errorf("failed to get restmapping: %w", err)
+ }
+
+ scope := restmapping.Scope.Name()
+ if scope == "" {
+ return false, errors.New("scope cannot be identified, empty scope returned")
+ }
+
+ if scope != meta.RESTScopeNameRoot {
+ return true, nil
+ }
+ return false, nil
+}
+
+// GVKForObject finds the GroupVersionKind associated with the given object, if there is only a single such GVK.
+func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionKind, error) {
+ // TODO(directxman12): do we want to generalize this to arbitrary container types?
+ // I think we'd need a generalized form of scheme or something. It's a
+ // shame there's not a reliable "GetGVK" interface that works by default
+ // for unpopulated static types and populated "dynamic" types
+ // (unstructured, partial, etc)
+
+ // check for PartialObjectMetadata, which is analogous to unstructured, but isn't handled by ObjectKinds
+ _, isPartial := obj.(*metav1.PartialObjectMetadata)
+ _, isPartialList := obj.(*metav1.PartialObjectMetadataList)
+ if isPartial || isPartialList {
+ // we require that the GVK be populated in order to recognize the object
+ gvk := obj.GetObjectKind().GroupVersionKind()
+ if len(gvk.Kind) == 0 {
+ return schema.GroupVersionKind{}, runtime.NewMissingKindErr("unstructured object has no kind")
+ }
+ if len(gvk.Version) == 0 {
+ return schema.GroupVersionKind{}, runtime.NewMissingVersionErr("unstructured object has no version")
+ }
+ return gvk, nil
+ }
+
+ // Use the given scheme to retrieve all the GVKs for the object.
+ gvks, isUnversioned, err := scheme.ObjectKinds(obj)
+ if err != nil {
+ return schema.GroupVersionKind{}, err
+ }
+ if isUnversioned {
+ return schema.GroupVersionKind{}, fmt.Errorf("cannot create group-version-kind for unversioned type %T", obj)
+ }
+
+ switch {
+ case len(gvks) < 1:
+ // If the object has no GVK, the object might not have been registered with the scheme.
+ // or it's not a valid object.
+ return schema.GroupVersionKind{}, fmt.Errorf("no GroupVersionKind associated with Go type %T, was the type registered with the Scheme?", obj)
+ case len(gvks) > 1:
+ err := fmt.Errorf("multiple GroupVersionKinds associated with Go type %T within the Scheme, this can happen when a type is registered for multiple GVKs at the same time", obj)
+
+ // We've found multiple GVKs for the object.
+ currentGVK := obj.GetObjectKind().GroupVersionKind()
+ if !currentGVK.Empty() {
+ // If the base object has a GVK, check if it's in the list of GVKs before using it.
+ for _, gvk := range gvks {
+ if gvk == currentGVK {
+ return gvk, nil
+ }
+ }
+
+ return schema.GroupVersionKind{}, fmt.Errorf(
+ "%w: the object's supplied GroupVersionKind %q was not found in the Scheme's list; refusing to guess at one: %q", err, currentGVK, gvks)
+ }
+
+ // This should only trigger for things like metav1.XYZ --
+ // normal versioned types should be fine.
+ //
+ // See https://github.com/kubernetes-sigs/controller-runtime/issues/362
+ // for more information.
+ return schema.GroupVersionKind{}, fmt.Errorf(
+ "%w: callers can either fix their type registration to only register it once, or specify the GroupVersionKind to use for object passed in; refusing to guess at one: %q", err, gvks)
+ default:
+ // In any other case, we've found a single GVK for the object.
+ return gvks[0], nil
+ }
+}
+
+// RESTClientForGVK constructs a new rest.Interface capable of accessing the resource associated
+// with the given GroupVersionKind. The REST client will be configured to use the negotiated serializer from
+// baseConfig, if set, otherwise a default serializer will be set.
+func RESTClientForGVK(gvk schema.GroupVersionKind, isUnstructured bool, baseConfig *rest.Config, codecs serializer.CodecFactory, httpClient *http.Client) (rest.Interface, error) {
+ if httpClient == nil {
+ return nil, fmt.Errorf("httpClient must not be nil, consider using rest.HTTPClientFor(c) to create a client")
+ }
+ return rest.RESTClientForConfigAndClient(createRestConfig(gvk, isUnstructured, baseConfig, codecs), httpClient)
+}
+
+// createRestConfig copies the base config and updates needed fields for a new rest config.
+func createRestConfig(gvk schema.GroupVersionKind, isUnstructured bool, baseConfig *rest.Config, codecs serializer.CodecFactory) *rest.Config {
+ gv := gvk.GroupVersion()
+
+ cfg := rest.CopyConfig(baseConfig)
+ cfg.GroupVersion = &gv
+ if gvk.Group == "" {
+ cfg.APIPath = "/api"
+ } else {
+ cfg.APIPath = "/apis"
+ }
+ if cfg.UserAgent == "" {
+ cfg.UserAgent = rest.DefaultKubernetesUserAgent()
+ }
+ // TODO(FillZpp): In the long run, we want to check discovery or something to make sure that this is actually true.
+ if cfg.ContentType == "" && !isUnstructured {
+ protobufSchemeLock.RLock()
+ if protobufScheme.Recognizes(gvk) {
+ cfg.ContentType = runtime.ContentTypeProtobuf
+ }
+ protobufSchemeLock.RUnlock()
+ }
+
+ if isUnstructured {
+ // If the object is unstructured, we use the client-go dynamic serializer.
+ cfg = dynamic.ConfigFor(cfg)
+ } else {
+ cfg.NegotiatedSerializer = serializerWithTargetZeroingDecode{NegotiatedSerializer: serializer.WithoutConversionCodecFactory{CodecFactory: codecs}}
+ }
+
+ return cfg
+}
+
+type serializerWithTargetZeroingDecode struct {
+ runtime.NegotiatedSerializer
+}
+
+func (s serializerWithTargetZeroingDecode) DecoderToVersion(serializer runtime.Decoder, r runtime.GroupVersioner) runtime.Decoder {
+ return targetZeroingDecoder{upstream: s.NegotiatedSerializer.DecoderToVersion(serializer, r)}
+}
+
+type targetZeroingDecoder struct {
+ upstream runtime.Decoder
+}
+
+func (t targetZeroingDecoder) Decode(data []byte, defaults *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
+ zero(into)
+ return t.upstream.Decode(data, defaults, into)
+}
+
+// zero zeros the value of a pointer.
+func zero(x interface{}) {
+ if x == nil {
+ return
+ }
+ res := reflect.ValueOf(x).Elem()
+ res.Set(reflect.Zero(res.Type()))
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apiutil_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apiutil_suite_test.go
new file mode 100644
index 00000000000..7fe960b9179
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apiutil_suite_test.go
@@ -0,0 +1,42 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package apiutil
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/rest"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "API Utilities Test Suite")
+}
+
+var cfg *rest.Config
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+ // for things that technically need a rest.Config for defaulting, but don't actually use them
+ cfg = &rest.Config{}
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/restmapper.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/restmapper.go
new file mode 100644
index 00000000000..f14f8a9f598
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/restmapper.go
@@ -0,0 +1,287 @@
+/*
+Copyright 2023 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package apiutil
+
+import (
+ "fmt"
+ "net/http"
+ "sync"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/discovery"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/restmapper"
+)
+
+// NewDynamicRESTMapper returns a dynamic RESTMapper for cfg. The dynamic
+// RESTMapper dynamically discovers resource types at runtime.
+func NewDynamicRESTMapper(cfg *rest.Config, httpClient *http.Client) (meta.RESTMapper, error) {
+ if httpClient == nil {
+ return nil, fmt.Errorf("httpClient must not be nil, consider using rest.HTTPClientFor(c) to create a client")
+ }
+
+ client, err := discovery.NewDiscoveryClientForConfigAndClient(cfg, httpClient)
+ if err != nil {
+ return nil, err
+ }
+ return &mapper{
+ mapper: restmapper.NewDiscoveryRESTMapper([]*restmapper.APIGroupResources{}),
+ client: client,
+ knownGroups: map[string]*restmapper.APIGroupResources{},
+ apiGroups: map[string]*metav1.APIGroup{},
+ }, nil
+}
+
+// mapper is a RESTMapper that will lazily query the provided
+// client for discovery information to do REST mappings.
+type mapper struct {
+ mapper meta.RESTMapper
+ client *discovery.DiscoveryClient
+ knownGroups map[string]*restmapper.APIGroupResources
+ apiGroups map[string]*metav1.APIGroup
+
+ // mutex to provide thread-safe mapper reloading.
+ mu sync.RWMutex
+}
+
+// KindFor implements Mapper.KindFor.
+func (m *mapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
+ res, err := m.getMapper().KindFor(resource)
+ if meta.IsNoMatchError(err) {
+ if err := m.addKnownGroupAndReload(resource.Group, resource.Version); err != nil {
+ return schema.GroupVersionKind{}, err
+ }
+ res, err = m.getMapper().KindFor(resource)
+ }
+
+ return res, err
+}
+
+// KindsFor implements Mapper.KindsFor.
+func (m *mapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
+ res, err := m.getMapper().KindsFor(resource)
+ if meta.IsNoMatchError(err) {
+ if err := m.addKnownGroupAndReload(resource.Group, resource.Version); err != nil {
+ return nil, err
+ }
+ res, err = m.getMapper().KindsFor(resource)
+ }
+
+ return res, err
+}
+
+// ResourceFor implements Mapper.ResourceFor.
+func (m *mapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) {
+ res, err := m.getMapper().ResourceFor(input)
+ if meta.IsNoMatchError(err) {
+ if err := m.addKnownGroupAndReload(input.Group, input.Version); err != nil {
+ return schema.GroupVersionResource{}, err
+ }
+ res, err = m.getMapper().ResourceFor(input)
+ }
+
+ return res, err
+}
+
+// ResourcesFor implements Mapper.ResourcesFor.
+func (m *mapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
+ res, err := m.getMapper().ResourcesFor(input)
+ if meta.IsNoMatchError(err) {
+ if err := m.addKnownGroupAndReload(input.Group, input.Version); err != nil {
+ return nil, err
+ }
+ res, err = m.getMapper().ResourcesFor(input)
+ }
+
+ return res, err
+}
+
+// RESTMapping implements Mapper.RESTMapping.
+func (m *mapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) {
+ res, err := m.getMapper().RESTMapping(gk, versions...)
+ if meta.IsNoMatchError(err) {
+ if err := m.addKnownGroupAndReload(gk.Group, versions...); err != nil {
+ return nil, err
+ }
+ res, err = m.getMapper().RESTMapping(gk, versions...)
+ }
+
+ return res, err
+}
+
+// RESTMappings implements Mapper.RESTMappings.
+func (m *mapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) {
+ res, err := m.getMapper().RESTMappings(gk, versions...)
+ if meta.IsNoMatchError(err) {
+ if err := m.addKnownGroupAndReload(gk.Group, versions...); err != nil {
+ return nil, err
+ }
+ res, err = m.getMapper().RESTMappings(gk, versions...)
+ }
+
+ return res, err
+}
+
+// ResourceSingularizer implements Mapper.ResourceSingularizer.
+func (m *mapper) ResourceSingularizer(resource string) (string, error) {
+ return m.getMapper().ResourceSingularizer(resource)
+}
+
+func (m *mapper) getMapper() meta.RESTMapper {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ return m.mapper
+}
+
+// addKnownGroupAndReload reloads the mapper with updated information about missing API group.
+// versions can be specified for partial updates, for instance for v1beta1 version only.
+func (m *mapper) addKnownGroupAndReload(groupName string, versions ...string) error {
+ // If no specific versions are set by user, we will scan all available ones for the API group.
+ // This operation requires 2 requests: /api and /apis, but only once. For all subsequent calls
+ // this data will be taken from cache.
+ if len(versions) == 0 {
+ apiGroup, err := m.findAPIGroupByName(groupName)
+ if err != nil {
+ return err
+ }
+ for _, version := range apiGroup.Versions {
+ versions = append(versions, version.Version)
+ }
+ }
+
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ // Create or fetch group resources from cache.
+ groupResources := &restmapper.APIGroupResources{
+ Group: metav1.APIGroup{Name: groupName},
+ VersionedResources: make(map[string][]metav1.APIResource),
+ }
+ if _, ok := m.knownGroups[groupName]; ok {
+ groupResources = m.knownGroups[groupName]
+ }
+
+ // Update information for group resources about versioned resources.
+ // The number of API calls is equal to the number of versions: /apis//.
+ groupVersionResources, err := m.fetchGroupVersionResources(groupName, versions...)
+ if err != nil {
+ return fmt.Errorf("failed to get API group resources: %w", err)
+ }
+ for version, resources := range groupVersionResources {
+ groupResources.VersionedResources[version.Version] = resources.APIResources
+ }
+
+ // Update information for group resources about the API group by adding new versions.
+ // Ignore the versions that are already registered.
+ for _, version := range versions {
+ found := false
+ for _, v := range groupResources.Group.Versions {
+ if v.Version == version {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ groupResources.Group.Versions = append(groupResources.Group.Versions, metav1.GroupVersionForDiscovery{
+ GroupVersion: metav1.GroupVersion{Group: groupName, Version: version}.String(),
+ Version: version,
+ })
+ }
+ }
+
+ // Update data in the cache.
+ m.knownGroups[groupName] = groupResources
+
+ // Finally, update the group with received information and regenerate the mapper.
+ updatedGroupResources := make([]*restmapper.APIGroupResources, 0, len(m.knownGroups))
+ for _, agr := range m.knownGroups {
+ updatedGroupResources = append(updatedGroupResources, agr)
+ }
+
+ m.mapper = restmapper.NewDiscoveryRESTMapper(updatedGroupResources)
+ return nil
+}
+
+// findAPIGroupByNameLocked returns API group by its name.
+func (m *mapper) findAPIGroupByName(groupName string) (*metav1.APIGroup, error) {
+ // Looking in the cache first.
+ {
+ m.mu.RLock()
+ group, ok := m.apiGroups[groupName]
+ m.mu.RUnlock()
+ if ok {
+ return group, nil
+ }
+ }
+
+ // Update the cache if nothing was found.
+ apiGroups, err := m.client.ServerGroups()
+ if err != nil {
+ return nil, fmt.Errorf("failed to get server groups: %w", err)
+ }
+ if len(apiGroups.Groups) == 0 {
+ return nil, fmt.Errorf("received an empty API groups list")
+ }
+
+ m.mu.Lock()
+ for i := range apiGroups.Groups {
+ group := &apiGroups.Groups[i]
+ m.apiGroups[group.Name] = group
+ }
+ m.mu.Unlock()
+
+ // Looking in the cache again.
+ {
+ m.mu.RLock()
+ group, ok := m.apiGroups[groupName]
+ m.mu.RUnlock()
+ if ok {
+ return group, nil
+ }
+ }
+
+ // If there is still nothing, return an error.
+ return nil, fmt.Errorf("failed to find API group %q", groupName)
+}
+
+// fetchGroupVersionResources fetches the resources for the specified group and its versions.
+func (m *mapper) fetchGroupVersionResources(groupName string, versions ...string) (map[schema.GroupVersion]*metav1.APIResourceList, error) {
+ groupVersionResources := make(map[schema.GroupVersion]*metav1.APIResourceList)
+ failedGroups := make(map[schema.GroupVersion]error)
+
+ for _, version := range versions {
+ groupVersion := schema.GroupVersion{Group: groupName, Version: version}
+
+ apiResourceList, err := m.client.ServerResourcesForGroupVersion(groupVersion.String())
+ if err != nil {
+ failedGroups[groupVersion] = err
+ }
+ if apiResourceList != nil {
+ // even in case of error, some fallback might have been returned.
+ groupVersionResources[groupVersion] = apiResourceList
+ }
+ }
+
+ if len(failedGroups) > 0 {
+ return nil, &discovery.ErrGroupDiscoveryFailed{Groups: failedGroups}
+ }
+
+ return groupVersionResources, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/restmapper_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/restmapper_test.go
new file mode 100644
index 00000000000..99ea5a79d8d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/restmapper_test.go
@@ -0,0 +1,483 @@
+/*
+Copyright 2023 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package apiutil_test
+
+import (
+ "context"
+ "net/http"
+ "testing"
+
+ _ "github.com/onsi/ginkgo/v2"
+ gmg "github.com/onsi/gomega"
+
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+)
+
+// countingRoundTripper is used to count HTTP requests.
+type countingRoundTripper struct {
+ roundTripper http.RoundTripper
+ requestCount int
+}
+
+func newCountingRoundTripper(rt http.RoundTripper) *countingRoundTripper {
+ return &countingRoundTripper{roundTripper: rt}
+}
+
+// RoundTrip implements http.RoundTripper.RoundTrip that additionally counts requests.
+func (crt *countingRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
+ crt.requestCount++
+
+ return crt.roundTripper.RoundTrip(r)
+}
+
+// GetRequestCount returns how many requests have been made.
+func (crt *countingRoundTripper) GetRequestCount() int {
+ return crt.requestCount
+}
+
+// Reset sets the counter to 0.
+func (crt *countingRoundTripper) Reset() {
+ crt.requestCount = 0
+}
+
+func setupEnvtest(t *testing.T) (*rest.Config, func(t *testing.T)) {
+ t.Log("Setup envtest")
+
+ g := gmg.NewWithT(t)
+ testEnv := &envtest.Environment{
+ CRDDirectoryPaths: []string{"testdata"},
+ }
+
+ cfg, err := testEnv.Start()
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(cfg).NotTo(gmg.BeNil())
+
+ teardownFunc := func(t *testing.T) {
+ t.Log("Stop envtest")
+ g.Expect(testEnv.Stop()).To(gmg.Succeed())
+ }
+
+ return cfg, teardownFunc
+}
+
+func TestLazyRestMapperProvider(t *testing.T) {
+ restCfg, tearDownFn := setupEnvtest(t)
+ defer tearDownFn(t)
+
+ t.Run("LazyRESTMapper should fetch data based on the request", func(t *testing.T) {
+ g := gmg.NewWithT(t)
+
+ // For each new group it performs just one request to the API server:
+ // GET https://host/apis//
+
+ httpClient, err := rest.HTTPClientFor(restCfg)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ crt := newCountingRoundTripper(httpClient.Transport)
+ httpClient.Transport = crt
+
+ lazyRestMapper, err := apiutil.NewDynamicRESTMapper(restCfg, httpClient)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ // There are no requests before any call
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(0))
+
+ mapping, err := lazyRestMapper.RESTMapping(schema.GroupKind{Group: "apps", Kind: "deployment"}, "v1")
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("deployment"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(1))
+
+ mappings, err := lazyRestMapper.RESTMappings(schema.GroupKind{Group: "", Kind: "pod"}, "v1")
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(len(mappings)).To(gmg.Equal(1))
+ g.Expect(mappings[0].GroupVersionKind.Kind).To(gmg.Equal("pod"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(2))
+
+ kind, err := lazyRestMapper.KindFor(schema.GroupVersionResource{Group: "networking.k8s.io", Version: "v1", Resource: "ingresses"})
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(kind.Kind).To(gmg.Equal("Ingress"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(3))
+
+ kinds, err := lazyRestMapper.KindsFor(schema.GroupVersionResource{Group: "authentication.k8s.io", Version: "v1", Resource: "tokenreviews"})
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(len(kinds)).To(gmg.Equal(1))
+ g.Expect(kinds[0].Kind).To(gmg.Equal("TokenReview"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(4))
+
+ resource, err := lazyRestMapper.ResourceFor(schema.GroupVersionResource{Group: "scheduling.k8s.io", Version: "v1", Resource: "priorityclasses"})
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(resource.Resource).To(gmg.Equal("priorityclasses"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(5))
+
+ resources, err := lazyRestMapper.ResourcesFor(schema.GroupVersionResource{Group: "policy", Version: "v1", Resource: "poddisruptionbudgets"})
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(len(resources)).To(gmg.Equal(1))
+ g.Expect(resources[0].Resource).To(gmg.Equal("poddisruptionbudgets"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(6))
+ })
+
+ t.Run("LazyRESTMapper should cache fetched data and doesn't perform any additional requests", func(t *testing.T) {
+ g := gmg.NewWithT(t)
+
+ httpClient, err := rest.HTTPClientFor(restCfg)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ crt := newCountingRoundTripper(httpClient.Transport)
+ httpClient.Transport = crt
+
+ lazyRestMapper, err := apiutil.NewDynamicRESTMapper(restCfg, httpClient)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(0))
+
+ mapping, err := lazyRestMapper.RESTMapping(schema.GroupKind{Group: "apps", Kind: "deployment"})
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("deployment"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(3))
+
+ // Data taken from cache - there are no more additional requests.
+
+ mapping, err = lazyRestMapper.RESTMapping(schema.GroupKind{Group: "apps", Kind: "deployment"})
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("deployment"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(3))
+
+ kind, err := lazyRestMapper.KindFor((schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployment"}))
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(kind.Kind).To(gmg.Equal("Deployment"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(3))
+
+ resource, err := lazyRestMapper.ResourceFor((schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployment"}))
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(resource.Resource).To(gmg.Equal("deployments"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(3))
+ })
+
+ t.Run("LazyRESTMapper should work correctly with empty versions list", func(t *testing.T) {
+ g := gmg.NewWithT(t)
+
+ httpClient, err := rest.HTTPClientFor(restCfg)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ crt := newCountingRoundTripper(httpClient.Transport)
+ httpClient.Transport = crt
+
+ lazyRestMapper, err := apiutil.NewDynamicRESTMapper(restCfg, httpClient)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(0))
+
+ // crew.example.com has 2 versions: v1 and v2
+
+ // If no versions were provided by user, we fetch all of them.
+ // Here we expect 4 calls.
+ // To initialize:
+ // #1: GET https://host/api
+ // #2: GET https://host/apis
+ // Then, for each version it performs one request to the API server:
+ // #3: GET https://host/apis/crew.example.com/v1
+ // #4: GET https://host/apis/crew.example.com/v2
+ mapping, err := lazyRestMapper.RESTMapping(schema.GroupKind{Group: "crew.example.com", Kind: "driver"})
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("driver"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(4))
+
+ // All subsequent calls won't send requests to the server.
+ mapping, err = lazyRestMapper.RESTMapping(schema.GroupKind{Group: "crew.example.com", Kind: "driver"})
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("driver"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(4))
+ })
+
+ t.Run("LazyRESTMapper should work correctly with multiple API group versions", func(t *testing.T) {
+ g := gmg.NewWithT(t)
+
+ httpClient, err := rest.HTTPClientFor(restCfg)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ crt := newCountingRoundTripper(httpClient.Transport)
+ httpClient.Transport = crt
+
+ lazyRestMapper, err := apiutil.NewDynamicRESTMapper(restCfg, httpClient)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(0))
+
+ // We explicitly ask for 2 versions: v1 and v2.
+ // For each version it performs one request to the API server:
+ // #1: GET https://host/apis/crew.example.com/v1
+ // #2: GET https://host/apis/crew.example.com/v2
+ mapping, err := lazyRestMapper.RESTMapping(schema.GroupKind{Group: "crew.example.com", Kind: "driver"}, "v1", "v2")
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("driver"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(2))
+
+ // All subsequent calls won't send requests to the server as everything is stored in the cache.
+ mapping, err = lazyRestMapper.RESTMapping(schema.GroupKind{Group: "crew.example.com", Kind: "driver"}, "v1")
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("driver"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(2))
+
+ mapping, err = lazyRestMapper.RESTMapping(schema.GroupKind{Group: "crew.example.com", Kind: "driver"})
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("driver"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(2))
+ })
+
+ t.Run("LazyRESTMapper should work correctly with different API group versions", func(t *testing.T) {
+ g := gmg.NewWithT(t)
+
+ httpClient, err := rest.HTTPClientFor(restCfg)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ crt := newCountingRoundTripper(httpClient.Transport)
+ httpClient.Transport = crt
+
+ lazyRestMapper, err := apiutil.NewDynamicRESTMapper(restCfg, httpClient)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(0))
+
+ // Now we want resources for crew.example.com/v1 version only.
+ // Here we expect 1 call:
+ // #1: GET https://host/apis/crew.example.com/v1
+ mapping, err := lazyRestMapper.RESTMapping(schema.GroupKind{Group: "crew.example.com", Kind: "driver"}, "v1")
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("driver"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(1))
+
+ // Get additional resources from v2.
+ // It sends another request:
+ // #2: GET https://host/apis/crew.example.com/v2
+ mapping, err = lazyRestMapper.RESTMapping(schema.GroupKind{Group: "crew.example.com", Kind: "driver"}, "v2")
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("driver"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(2))
+
+ // No subsequent calls require additional API requests.
+ mapping, err = lazyRestMapper.RESTMapping(schema.GroupKind{Group: "crew.example.com", Kind: "driver"}, "v1")
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("driver"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(2))
+
+ mapping, err = lazyRestMapper.RESTMapping(schema.GroupKind{Group: "crew.example.com", Kind: "driver"}, "v1", "v2")
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("driver"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(2))
+ })
+
+ t.Run("LazyRESTMapper should return an error if the group doesn't exist", func(t *testing.T) {
+ g := gmg.NewWithT(t)
+
+ // After initialization for each invalid group the mapper performs just 1 request to the API server.
+
+ httpClient, err := rest.HTTPClientFor(restCfg)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ crt := newCountingRoundTripper(httpClient.Transport)
+ httpClient.Transport = crt
+
+ lazyRestMapper, err := apiutil.NewDynamicRESTMapper(restCfg, httpClient)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ _, err = lazyRestMapper.RESTMapping(schema.GroupKind{Group: "INVALID1"}, "v1")
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(1))
+
+ _, err = lazyRestMapper.RESTMappings(schema.GroupKind{Group: "INVALID2"}, "v1")
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(2))
+
+ _, err = lazyRestMapper.KindFor(schema.GroupVersionResource{Group: "INVALID3", Version: "v1"})
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(3))
+
+ _, err = lazyRestMapper.KindsFor(schema.GroupVersionResource{Group: "INVALID4", Version: "v1"})
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(4))
+
+ _, err = lazyRestMapper.ResourceFor(schema.GroupVersionResource{Group: "INVALID5", Version: "v1"})
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(5))
+
+ _, err = lazyRestMapper.ResourcesFor(schema.GroupVersionResource{Group: "INVALID6", Version: "v1"})
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(6))
+ })
+
+ t.Run("LazyRESTMapper should return an error if a resource doesn't exist", func(t *testing.T) {
+ g := gmg.NewWithT(t)
+
+ // For each invalid resource the mapper performs just 1 request to the API server.
+
+ httpClient, err := rest.HTTPClientFor(restCfg)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ crt := newCountingRoundTripper(httpClient.Transport)
+ httpClient.Transport = crt
+
+ lazyRestMapper, err := apiutil.NewDynamicRESTMapper(restCfg, httpClient)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ _, err = lazyRestMapper.RESTMapping(schema.GroupKind{Group: "apps", Kind: "INVALID"}, "v1")
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(1))
+
+ _, err = lazyRestMapper.RESTMappings(schema.GroupKind{Group: "", Kind: "INVALID"}, "v1")
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(2))
+
+ _, err = lazyRestMapper.KindFor(schema.GroupVersionResource{Group: "networking.k8s.io", Version: "v1", Resource: "INVALID"})
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(3))
+
+ _, err = lazyRestMapper.KindsFor(schema.GroupVersionResource{Group: "authentication.k8s.io", Version: "v1", Resource: "INVALID"})
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(4))
+
+ _, err = lazyRestMapper.ResourceFor(schema.GroupVersionResource{Group: "scheduling.k8s.io", Version: "v1", Resource: "INVALID"})
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(5))
+
+ _, err = lazyRestMapper.ResourcesFor(schema.GroupVersionResource{Group: "policy", Version: "v1", Resource: "INVALID"})
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(6))
+ })
+
+ t.Run("LazyRESTMapper should return an error if the version doesn't exist", func(t *testing.T) {
+ g := gmg.NewWithT(t)
+
+ // After initialization, for each invalid resource mapper performs 1 requests to the API server.
+
+ httpClient, err := rest.HTTPClientFor(restCfg)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ crt := newCountingRoundTripper(httpClient.Transport)
+ httpClient.Transport = crt
+
+ lazyRestMapper, err := apiutil.NewDynamicRESTMapper(restCfg, httpClient)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ _, err = lazyRestMapper.RESTMapping(schema.GroupKind{Group: "apps", Kind: "deployment"}, "INVALID")
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(1))
+
+ _, err = lazyRestMapper.RESTMappings(schema.GroupKind{Group: "", Kind: "pod"}, "INVALID")
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(2))
+
+ _, err = lazyRestMapper.KindFor(schema.GroupVersionResource{Group: "networking.k8s.io", Version: "INVALID", Resource: "ingresses"})
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(3))
+
+ _, err = lazyRestMapper.KindsFor(schema.GroupVersionResource{Group: "authentication.k8s.io", Version: "INVALID", Resource: "tokenreviews"})
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(4))
+
+ _, err = lazyRestMapper.ResourceFor(schema.GroupVersionResource{Group: "scheduling.k8s.io", Version: "INVALID", Resource: "priorityclasses"})
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(5))
+
+ _, err = lazyRestMapper.ResourcesFor(schema.GroupVersionResource{Group: "policy", Version: "INVALID", Resource: "poddisruptionbudgets"})
+ g.Expect(err).To(gmg.HaveOccurred())
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(6))
+ })
+
+ t.Run("LazyRESTMapper can fetch CRDs if they were created at runtime", func(t *testing.T) {
+ g := gmg.NewWithT(t)
+
+ // To fetch all versions mapper does 2 requests:
+ // GET https://host/api
+ // GET https://host/apis
+ // Then, for each version it performs just one request to the API server as usual:
+ // GET https://host/apis//
+
+ httpClient, err := rest.HTTPClientFor(restCfg)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ crt := newCountingRoundTripper(httpClient.Transport)
+ httpClient.Transport = crt
+
+ lazyRestMapper, err := apiutil.NewDynamicRESTMapper(restCfg, httpClient)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ // There are no requests before any call
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(0))
+
+ // Since we don't specify what version we expect, restmapper will fetch them all and search there.
+ // To fetch a list of available versions
+ // #1: GET https://host/api
+ // #2: GET https://host/apis
+ // Then, for each currently registered version:
+ // #3: GET https://host/apis/crew.example.com/v1
+ // #4: GET https://host/apis/crew.example.com/v2
+ mapping, err := lazyRestMapper.RESTMapping(schema.GroupKind{Group: "crew.example.com", Kind: "driver"})
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("driver"))
+ g.Expect(crt.GetRequestCount()).To(gmg.Equal(4))
+
+ s := scheme.Scheme
+ err = apiextensionsv1.AddToScheme(s)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ c, err := client.New(restCfg, client.Options{Scheme: s})
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+
+ // Register another CRD in runtime - "riders.crew.example.com".
+
+ crd := &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(crd.Spec.Names.Kind).To(gmg.Equal("Driver"))
+
+ newCRD := &apiextensionsv1.CustomResourceDefinition{}
+ crd.DeepCopyInto(newCRD)
+ newCRD.Name = "riders.crew.example.com"
+ newCRD.Spec.Names = apiextensionsv1.CustomResourceDefinitionNames{
+ Kind: "Rider",
+ Plural: "riders",
+ }
+ newCRD.ResourceVersion = ""
+
+ // Create the new CRD.
+ g.Expect(c.Create(context.TODO(), newCRD)).To(gmg.Succeed())
+
+ // Wait a bit until the CRD is registered.
+ g.Eventually(func() error {
+ _, err := lazyRestMapper.RESTMapping(schema.GroupKind{Group: "crew.example.com", Kind: "rider"})
+ return err
+ }).Should(gmg.Succeed())
+
+ // Since we don't specify what version we expect, restmapper will fetch them all and search there.
+ // To fetch a list of available versions
+ // #1: GET https://host/api
+ // #2: GET https://host/apis
+ // Then, for each currently registered version:
+ // #3: GET https://host/apis/crew.example.com/v1
+ // #4: GET https://host/apis/crew.example.com/v2
+ mapping, err = lazyRestMapper.RESTMapping(schema.GroupKind{Group: "crew.example.com", Kind: "rider"})
+ g.Expect(err).NotTo(gmg.HaveOccurred())
+ g.Expect(mapping.GroupVersionKind.Kind).To(gmg.Equal("rider"))
+ })
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/testdata/crd.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/testdata/crd.yaml
new file mode 100644
index 00000000000..5bb2d73f698
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/apiutil/testdata/crd.yaml
@@ -0,0 +1,62 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ creationTimestamp: null
+ name: drivers.crew.example.com
+spec:
+ group: crew.example.com
+ names:
+ kind: Driver
+ plural: drivers
+ scope: Namespaced
+ versions:
+ - name: v1
+ served: true
+ storage: true
+ schema:
+ openAPIV3Schema:
+ description: Driver is the Schema for the drivers 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/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/api-conventions.md#types-kinds'
+ type: string
+ spec:
+ type: object
+ status:
+ type: object
+ type: object
+ - name: v2
+ served: true
+ storage: false
+ schema:
+ openAPIV3Schema:
+ description: Driver is the Schema for the drivers 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/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/api-conventions.md#types-kinds'
+ type: string
+ spec:
+ type: object
+ status:
+ type: object
+ type: object
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/client.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/client.go
new file mode 100644
index 00000000000..21067b6f8fc
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/client.go
@@ -0,0 +1,587 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "strings"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/metadata"
+ "k8s.io/client-go/rest"
+
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+// Options are creation options for a Client.
+type Options struct {
+ // HTTPClient is the HTTP client to use for requests.
+ HTTPClient *http.Client
+
+ // Scheme, if provided, will be used to map go structs to GroupVersionKinds
+ Scheme *runtime.Scheme
+
+ // Mapper, if provided, will be used to map GroupVersionKinds to Resources
+ Mapper meta.RESTMapper
+
+ // Cache, if provided, is used to read objects from the cache.
+ Cache *CacheOptions
+
+ // WarningHandler is used to configure the warning handler responsible for
+ // surfacing and handling warnings messages sent by the API server.
+ WarningHandler WarningHandlerOptions
+
+ // DryRun instructs the client to only perform dry run requests.
+ DryRun *bool
+}
+
+// WarningHandlerOptions are options for configuring a
+// warning handler for the client which is responsible
+// for surfacing API Server warnings.
+type WarningHandlerOptions struct {
+ // SuppressWarnings decides if the warnings from the
+ // API server are suppressed or surfaced in the client.
+ SuppressWarnings bool
+ // AllowDuplicateLogs does not deduplicate the to-be
+ // logged surfaced warnings messages. See
+ // log.WarningHandlerOptions for considerations
+ // regarding deduplication
+ AllowDuplicateLogs bool
+}
+
+// CacheOptions are options for creating a cache-backed client.
+type CacheOptions struct {
+ // Reader is a cache-backed reader that will be used to read objects from the cache.
+ // +required
+ Reader Reader
+ // DisableFor is a list of objects that should not be read from the cache.
+ DisableFor []Object
+ // Unstructured is a flag that indicates whether the cache-backed client should
+ // read unstructured objects or lists from the cache.
+ Unstructured bool
+}
+
+// NewClientFunc allows a user to define how to create a client.
+type NewClientFunc func(config *rest.Config, options Options) (Client, error)
+
+// New returns a new Client using the provided config and Options.
+// The returned client reads *and* writes directly from the server
+// (it doesn't use object caches). It understands how to work with
+// normal types (both custom resources and aggregated/built-in resources),
+// as well as unstructured types.
+//
+// In the case of normal types, the scheme will be used to look up the
+// corresponding group, version, and kind for the given type. In the
+// case of unstructured types, the group, version, and kind will be extracted
+// from the corresponding fields on the object.
+func New(config *rest.Config, options Options) (c Client, err error) {
+ c, err = newClient(config, options)
+ if err == nil && options.DryRun != nil && *options.DryRun {
+ c = NewDryRunClient(c)
+ }
+ return c, err
+}
+
+func newClient(config *rest.Config, options Options) (*client, error) {
+ if config == nil {
+ return nil, fmt.Errorf("must provide non-nil rest.Config to client.New")
+ }
+
+ if !options.WarningHandler.SuppressWarnings {
+ // surface warnings
+ logger := log.Log.WithName("KubeAPIWarningLogger")
+ // Set a WarningHandler, the default WarningHandler
+ // is log.KubeAPIWarningLogger with deduplication enabled.
+ // See log.KubeAPIWarningLoggerOptions for considerations
+ // regarding deduplication.
+ config = rest.CopyConfig(config)
+ config.WarningHandler = log.NewKubeAPIWarningLogger(
+ logger,
+ log.KubeAPIWarningLoggerOptions{
+ Deduplicate: !options.WarningHandler.AllowDuplicateLogs,
+ },
+ )
+ }
+
+ // Use the rest HTTP client for the provided config if unset
+ if options.HTTPClient == nil {
+ var err error
+ options.HTTPClient, err = rest.HTTPClientFor(config)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Init a scheme if none provided
+ if options.Scheme == nil {
+ options.Scheme = scheme.Scheme
+ }
+
+ // Init a Mapper if none provided
+ if options.Mapper == nil {
+ var err error
+ options.Mapper, err = apiutil.NewDynamicRESTMapper(config, options.HTTPClient)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ resources := &clientRestResources{
+ httpClient: options.HTTPClient,
+ config: config,
+ scheme: options.Scheme,
+ mapper: options.Mapper,
+ codecs: serializer.NewCodecFactory(options.Scheme),
+
+ structuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
+ unstructuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
+ }
+
+ rawMetaClient, err := metadata.NewForConfigAndClient(config, options.HTTPClient)
+ if err != nil {
+ return nil, fmt.Errorf("unable to construct metadata-only client for use as part of client: %w", err)
+ }
+
+ c := &client{
+ typedClient: typedClient{
+ resources: resources,
+ paramCodec: runtime.NewParameterCodec(options.Scheme),
+ },
+ unstructuredClient: unstructuredClient{
+ resources: resources,
+ paramCodec: noConversionParamCodec{},
+ },
+ metadataClient: metadataClient{
+ client: rawMetaClient,
+ restMapper: options.Mapper,
+ },
+ scheme: options.Scheme,
+ mapper: options.Mapper,
+ }
+ if options.Cache == nil || options.Cache.Reader == nil {
+ return c, nil
+ }
+
+ // We want a cache if we're here.
+ // Set the cache.
+ c.cache = options.Cache.Reader
+
+ // Load uncached GVKs.
+ c.cacheUnstructured = options.Cache.Unstructured
+ c.uncachedGVKs = map[schema.GroupVersionKind]struct{}{}
+ for _, obj := range options.Cache.DisableFor {
+ gvk, err := c.GroupVersionKindFor(obj)
+ if err != nil {
+ return nil, err
+ }
+ c.uncachedGVKs[gvk] = struct{}{}
+ }
+ return c, nil
+}
+
+var _ Client = &client{}
+
+// client is a client.Client that reads and writes directly from/to an API server.
+// It lazily initializes new clients at the time they are used.
+type client struct {
+ typedClient typedClient
+ unstructuredClient unstructuredClient
+ metadataClient metadataClient
+ scheme *runtime.Scheme
+ mapper meta.RESTMapper
+
+ cache Reader
+ uncachedGVKs map[schema.GroupVersionKind]struct{}
+ cacheUnstructured bool
+}
+
+func (c *client) shouldBypassCache(obj runtime.Object) (bool, error) {
+ if c.cache == nil {
+ return true, nil
+ }
+
+ gvk, err := c.GroupVersionKindFor(obj)
+ if err != nil {
+ return false, err
+ }
+ // TODO: this is producing unsafe guesses that don't actually work,
+ // but it matches ~99% of the cases out there.
+ if meta.IsListType(obj) {
+ gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
+ }
+ if _, isUncached := c.uncachedGVKs[gvk]; isUncached {
+ return true, nil
+ }
+ if !c.cacheUnstructured {
+ _, isUnstructured := obj.(runtime.Unstructured)
+ return isUnstructured, nil
+ }
+ return false, nil
+}
+
+// resetGroupVersionKind is a helper function to restore and preserve GroupVersionKind on an object.
+func (c *client) resetGroupVersionKind(obj runtime.Object, gvk schema.GroupVersionKind) {
+ if gvk != schema.EmptyObjectKind.GroupVersionKind() {
+ if v, ok := obj.(schema.ObjectKind); ok {
+ v.SetGroupVersionKind(gvk)
+ }
+ }
+}
+
+// GroupVersionKindFor returns the GroupVersionKind for the given object.
+func (c *client) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
+ return apiutil.GVKForObject(obj, c.scheme)
+}
+
+// IsObjectNamespaced returns true if the GroupVersionKind of the object is namespaced.
+func (c *client) IsObjectNamespaced(obj runtime.Object) (bool, error) {
+ return apiutil.IsObjectNamespaced(obj, c.scheme, c.mapper)
+}
+
+// Scheme returns the scheme this client is using.
+func (c *client) Scheme() *runtime.Scheme {
+ return c.scheme
+}
+
+// RESTMapper returns the scheme this client is using.
+func (c *client) RESTMapper() meta.RESTMapper {
+ return c.mapper
+}
+
+// Create implements client.Client.
+func (c *client) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
+ switch obj.(type) {
+ case runtime.Unstructured:
+ return c.unstructuredClient.Create(ctx, obj, opts...)
+ case *metav1.PartialObjectMetadata:
+ return fmt.Errorf("cannot create using only metadata")
+ default:
+ return c.typedClient.Create(ctx, obj, opts...)
+ }
+}
+
+// Update implements client.Client.
+func (c *client) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
+ switch obj.(type) {
+ case runtime.Unstructured:
+ return c.unstructuredClient.Update(ctx, obj, opts...)
+ case *metav1.PartialObjectMetadata:
+ return fmt.Errorf("cannot update using only metadata -- did you mean to patch?")
+ default:
+ return c.typedClient.Update(ctx, obj, opts...)
+ }
+}
+
+// Delete implements client.Client.
+func (c *client) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
+ switch obj.(type) {
+ case runtime.Unstructured:
+ return c.unstructuredClient.Delete(ctx, obj, opts...)
+ case *metav1.PartialObjectMetadata:
+ return c.metadataClient.Delete(ctx, obj, opts...)
+ default:
+ return c.typedClient.Delete(ctx, obj, opts...)
+ }
+}
+
+// DeleteAllOf implements client.Client.
+func (c *client) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
+ switch obj.(type) {
+ case runtime.Unstructured:
+ return c.unstructuredClient.DeleteAllOf(ctx, obj, opts...)
+ case *metav1.PartialObjectMetadata:
+ return c.metadataClient.DeleteAllOf(ctx, obj, opts...)
+ default:
+ return c.typedClient.DeleteAllOf(ctx, obj, opts...)
+ }
+}
+
+// Patch implements client.Client.
+func (c *client) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
+ switch obj.(type) {
+ case runtime.Unstructured:
+ return c.unstructuredClient.Patch(ctx, obj, patch, opts...)
+ case *metav1.PartialObjectMetadata:
+ return c.metadataClient.Patch(ctx, obj, patch, opts...)
+ default:
+ return c.typedClient.Patch(ctx, obj, patch, opts...)
+ }
+}
+
+// Get implements client.Client.
+func (c *client) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
+ if isUncached, err := c.shouldBypassCache(obj); err != nil {
+ return err
+ } else if !isUncached {
+ return c.cache.Get(ctx, key, obj, opts...)
+ }
+
+ switch obj.(type) {
+ case runtime.Unstructured:
+ return c.unstructuredClient.Get(ctx, key, obj, opts...)
+ case *metav1.PartialObjectMetadata:
+ // Metadata only object should always preserve the GVK coming in from the caller.
+ defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
+ return c.metadataClient.Get(ctx, key, obj, opts...)
+ default:
+ return c.typedClient.Get(ctx, key, obj, opts...)
+ }
+}
+
+// List implements client.Client.
+func (c *client) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
+ if isUncached, err := c.shouldBypassCache(obj); err != nil {
+ return err
+ } else if !isUncached {
+ return c.cache.List(ctx, obj, opts...)
+ }
+
+ switch x := obj.(type) {
+ case runtime.Unstructured:
+ return c.unstructuredClient.List(ctx, obj, opts...)
+ case *metav1.PartialObjectMetadataList:
+ // Metadata only object should always preserve the GVK.
+ gvk := obj.GetObjectKind().GroupVersionKind()
+ defer c.resetGroupVersionKind(obj, gvk)
+
+ // Call the list client.
+ if err := c.metadataClient.List(ctx, obj, opts...); err != nil {
+ return err
+ }
+
+ // Restore the GVK for each item in the list.
+ itemGVK := schema.GroupVersionKind{
+ Group: gvk.Group,
+ Version: gvk.Version,
+ // TODO: this is producing unsafe guesses that don't actually work,
+ // but it matches ~99% of the cases out there.
+ Kind: strings.TrimSuffix(gvk.Kind, "List"),
+ }
+ for i := range x.Items {
+ item := &x.Items[i]
+ item.SetGroupVersionKind(itemGVK)
+ }
+
+ return nil
+ default:
+ return c.typedClient.List(ctx, obj, opts...)
+ }
+}
+
+// Status implements client.StatusClient.
+func (c *client) Status() SubResourceWriter {
+ return c.SubResource("status")
+}
+
+func (c *client) SubResource(subResource string) SubResourceClient {
+ return &subResourceClient{client: c, subResource: subResource}
+}
+
+// subResourceClient is client.SubResourceWriter that writes to subresources.
+type subResourceClient struct {
+ client *client
+ subResource string
+}
+
+// ensure subResourceClient implements client.SubResourceClient.
+var _ SubResourceClient = &subResourceClient{}
+
+// SubResourceGetOptions holds all the possible configuration
+// for a subresource Get request.
+type SubResourceGetOptions struct {
+ Raw *metav1.GetOptions
+}
+
+// ApplyToSubResourceGet updates the configuaration to the given get options.
+func (getOpt *SubResourceGetOptions) ApplyToSubResourceGet(o *SubResourceGetOptions) {
+ if getOpt.Raw != nil {
+ o.Raw = getOpt.Raw
+ }
+}
+
+// ApplyOptions applues the given options.
+func (getOpt *SubResourceGetOptions) ApplyOptions(opts []SubResourceGetOption) *SubResourceGetOptions {
+ for _, o := range opts {
+ o.ApplyToSubResourceGet(getOpt)
+ }
+
+ return getOpt
+}
+
+// AsGetOptions returns the configured options as *metav1.GetOptions.
+func (getOpt *SubResourceGetOptions) AsGetOptions() *metav1.GetOptions {
+ if getOpt.Raw == nil {
+ return &metav1.GetOptions{}
+ }
+ return getOpt.Raw
+}
+
+// SubResourceUpdateOptions holds all the possible configuration
+// for a subresource update request.
+type SubResourceUpdateOptions struct {
+ UpdateOptions
+ SubResourceBody Object
+}
+
+// ApplyToSubResourceUpdate updates the configuration on the given create options
+func (uo *SubResourceUpdateOptions) ApplyToSubResourceUpdate(o *SubResourceUpdateOptions) {
+ uo.UpdateOptions.ApplyToUpdate(&o.UpdateOptions)
+ if uo.SubResourceBody != nil {
+ o.SubResourceBody = uo.SubResourceBody
+ }
+}
+
+// ApplyOptions applies the given options.
+func (uo *SubResourceUpdateOptions) ApplyOptions(opts []SubResourceUpdateOption) *SubResourceUpdateOptions {
+ for _, o := range opts {
+ o.ApplyToSubResourceUpdate(uo)
+ }
+
+ return uo
+}
+
+// SubResourceUpdateAndPatchOption is an option that can be used for either
+// a subresource update or patch request.
+type SubResourceUpdateAndPatchOption interface {
+ SubResourceUpdateOption
+ SubResourcePatchOption
+}
+
+// WithSubResourceBody returns an option that uses the given body
+// for a subresource Update or Patch operation.
+func WithSubResourceBody(body Object) SubResourceUpdateAndPatchOption {
+ return &withSubresourceBody{body: body}
+}
+
+type withSubresourceBody struct {
+ body Object
+}
+
+func (wsr *withSubresourceBody) ApplyToSubResourceUpdate(o *SubResourceUpdateOptions) {
+ o.SubResourceBody = wsr.body
+}
+
+func (wsr *withSubresourceBody) ApplyToSubResourcePatch(o *SubResourcePatchOptions) {
+ o.SubResourceBody = wsr.body
+}
+
+// SubResourceCreateOptions are all the possible configurations for a subresource
+// create request.
+type SubResourceCreateOptions struct {
+ CreateOptions
+}
+
+// ApplyOptions applies the given options.
+func (co *SubResourceCreateOptions) ApplyOptions(opts []SubResourceCreateOption) *SubResourceCreateOptions {
+ for _, o := range opts {
+ o.ApplyToSubResourceCreate(co)
+ }
+
+ return co
+}
+
+// ApplyToSubresourceCreate applies the the configuration on the given create options.
+func (co *SubResourceCreateOptions) ApplyToSubresourceCreate(o *SubResourceCreateOptions) {
+ co.CreateOptions.ApplyToCreate(&co.CreateOptions)
+}
+
+// SubResourcePatchOptions holds all possible configurations for a subresource patch
+// request.
+type SubResourcePatchOptions struct {
+ PatchOptions
+ SubResourceBody Object
+}
+
+// ApplyOptions applies the given options.
+func (po *SubResourcePatchOptions) ApplyOptions(opts []SubResourcePatchOption) *SubResourcePatchOptions {
+ for _, o := range opts {
+ o.ApplyToSubResourcePatch(po)
+ }
+
+ return po
+}
+
+// ApplyToSubResourcePatch applies the configuration on the given patch options.
+func (po *SubResourcePatchOptions) ApplyToSubResourcePatch(o *SubResourcePatchOptions) {
+ po.PatchOptions.ApplyToPatch(&o.PatchOptions)
+ if po.SubResourceBody != nil {
+ o.SubResourceBody = po.SubResourceBody
+ }
+}
+
+func (sc *subResourceClient) Get(ctx context.Context, obj Object, subResource Object, opts ...SubResourceGetOption) error {
+ switch obj.(type) {
+ case runtime.Unstructured:
+ return sc.client.unstructuredClient.GetSubResource(ctx, obj, subResource, sc.subResource, opts...)
+ case *metav1.PartialObjectMetadata:
+ return errors.New("can not get subresource using only metadata")
+ default:
+ return sc.client.typedClient.GetSubResource(ctx, obj, subResource, sc.subResource, opts...)
+ }
+}
+
+// Create implements client.SubResourceClient
+func (sc *subResourceClient) Create(ctx context.Context, obj Object, subResource Object, opts ...SubResourceCreateOption) error {
+ defer sc.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
+ defer sc.client.resetGroupVersionKind(subResource, subResource.GetObjectKind().GroupVersionKind())
+
+ switch obj.(type) {
+ case runtime.Unstructured:
+ return sc.client.unstructuredClient.CreateSubResource(ctx, obj, subResource, sc.subResource, opts...)
+ case *metav1.PartialObjectMetadata:
+ return fmt.Errorf("cannot update status using only metadata -- did you mean to patch?")
+ default:
+ return sc.client.typedClient.CreateSubResource(ctx, obj, subResource, sc.subResource, opts...)
+ }
+}
+
+// Update implements client.SubResourceClient
+func (sc *subResourceClient) Update(ctx context.Context, obj Object, opts ...SubResourceUpdateOption) error {
+ defer sc.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
+ switch obj.(type) {
+ case runtime.Unstructured:
+ return sc.client.unstructuredClient.UpdateSubResource(ctx, obj, sc.subResource, opts...)
+ case *metav1.PartialObjectMetadata:
+ return fmt.Errorf("cannot update status using only metadata -- did you mean to patch?")
+ default:
+ return sc.client.typedClient.UpdateSubResource(ctx, obj, sc.subResource, opts...)
+ }
+}
+
+// Patch implements client.SubResourceWriter.
+func (sc *subResourceClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...SubResourcePatchOption) error {
+ defer sc.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
+ switch obj.(type) {
+ case runtime.Unstructured:
+ return sc.client.unstructuredClient.PatchSubResource(ctx, obj, sc.subResource, patch, opts...)
+ case *metav1.PartialObjectMetadata:
+ return sc.client.metadataClient.PatchSubResource(ctx, obj, sc.subResource, patch, opts...)
+ default:
+ return sc.client.typedClient.PatchSubResource(ctx, obj, sc.subResource, patch, opts...)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/client_rest_resources.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/client_rest_resources.go
new file mode 100644
index 00000000000..2d07879520b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/client_rest_resources.go
@@ -0,0 +1,151 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "net/http"
+ "strings"
+ "sync"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+)
+
+// clientRestResources creates and stores rest clients and metadata for Kubernetes types.
+type clientRestResources struct {
+ // httpClient is the http client to use for requests
+ httpClient *http.Client
+
+ // config is the rest.Config to talk to an apiserver
+ config *rest.Config
+
+ // scheme maps go structs to GroupVersionKinds
+ scheme *runtime.Scheme
+
+ // mapper maps GroupVersionKinds to Resources
+ mapper meta.RESTMapper
+
+ // codecs are used to create a REST client for a gvk
+ codecs serializer.CodecFactory
+
+ // structuredResourceByType stores structured type metadata
+ structuredResourceByType map[schema.GroupVersionKind]*resourceMeta
+ // unstructuredResourceByType stores unstructured type metadata
+ unstructuredResourceByType map[schema.GroupVersionKind]*resourceMeta
+ mu sync.RWMutex
+}
+
+// newResource maps obj to a Kubernetes Resource and constructs a client for that Resource.
+// If the object is a list, the resource represents the item's type instead.
+func (c *clientRestResources) newResource(gvk schema.GroupVersionKind, isList, isUnstructured bool) (*resourceMeta, error) {
+ if strings.HasSuffix(gvk.Kind, "List") && isList {
+ // if this was a list, treat it as a request for the item's resource
+ gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
+ }
+
+ client, err := apiutil.RESTClientForGVK(gvk, isUnstructured, c.config, c.codecs, c.httpClient)
+ if err != nil {
+ return nil, err
+ }
+ mapping, err := c.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
+ if err != nil {
+ return nil, err
+ }
+ return &resourceMeta{Interface: client, mapping: mapping, gvk: gvk}, nil
+}
+
+// getResource returns the resource meta information for the given type of object.
+// If the object is a list, the resource represents the item's type instead.
+func (c *clientRestResources) getResource(obj runtime.Object) (*resourceMeta, error) {
+ gvk, err := apiutil.GVKForObject(obj, c.scheme)
+ if err != nil {
+ return nil, err
+ }
+
+ _, isUnstructured := obj.(runtime.Unstructured)
+
+ // It's better to do creation work twice than to not let multiple
+ // people make requests at once
+ c.mu.RLock()
+ resourceByType := c.structuredResourceByType
+ if isUnstructured {
+ resourceByType = c.unstructuredResourceByType
+ }
+ r, known := resourceByType[gvk]
+ c.mu.RUnlock()
+
+ if known {
+ return r, nil
+ }
+
+ // Initialize a new Client
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ r, err = c.newResource(gvk, meta.IsListType(obj), isUnstructured)
+ if err != nil {
+ return nil, err
+ }
+ resourceByType[gvk] = r
+ return r, err
+}
+
+// getObjMeta returns objMeta containing both type and object metadata and state.
+func (c *clientRestResources) getObjMeta(obj runtime.Object) (*objMeta, error) {
+ r, err := c.getResource(obj)
+ if err != nil {
+ return nil, err
+ }
+ m, err := meta.Accessor(obj)
+ if err != nil {
+ return nil, err
+ }
+ return &objMeta{resourceMeta: r, Object: m}, err
+}
+
+// resourceMeta stores state for a Kubernetes type.
+type resourceMeta struct {
+ // client is the rest client used to talk to the apiserver
+ rest.Interface
+ // gvk is the GroupVersionKind of the resourceMeta
+ gvk schema.GroupVersionKind
+ // mapping is the rest mapping
+ mapping *meta.RESTMapping
+}
+
+// isNamespaced returns true if the type is namespaced.
+func (r *resourceMeta) isNamespaced() bool {
+ return r.mapping.Scope.Name() != meta.RESTScopeNameRoot
+}
+
+// resource returns the resource name of the type.
+func (r *resourceMeta) resource() string {
+ return r.mapping.Resource.Resource
+}
+
+// objMeta stores type and object information about a Kubernetes type.
+type objMeta struct {
+ // resourceMeta contains type information for the object
+ *resourceMeta
+
+ // Object contains meta data for the object instance
+ metav1.Object
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/client_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/client_suite_test.go
new file mode 100644
index 00000000000..f3942502d3f
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/client_suite_test.go
@@ -0,0 +1,60 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/examples/crd/pkg"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestClient(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Client Suite")
+}
+
+var testenv *envtest.Environment
+var cfg *rest.Config
+var clientset *kubernetes.Clientset
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+ testenv = &envtest.Environment{CRDDirectoryPaths: []string{"./testdata"}}
+
+ var err error
+ cfg, err = testenv.Start()
+ Expect(err).NotTo(HaveOccurred())
+
+ clientset, err = kubernetes.NewForConfig(cfg)
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(pkg.AddToScheme(scheme.Scheme)).NotTo(HaveOccurred())
+})
+
+var _ = AfterSuite(func() {
+ Expect(testenv.Stop()).To(Succeed())
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/client_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/client_test.go
new file mode 100644
index 00000000000..bd368e7a3fd
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/client_test.go
@@ -0,0 +1,3952 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client_test
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "reflect"
+ "sync/atomic"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ appsv1 "k8s.io/api/apps/v1"
+ authenticationv1 "k8s.io/api/authentication/v1"
+ autoscalingv1 "k8s.io/api/autoscaling/v1"
+ certificatesv1 "k8s.io/api/certificates/v1"
+ corev1 "k8s.io/api/core/v1"
+ policyv1 "k8s.io/api/policy/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/types"
+ kscheme "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/utils/pointer"
+
+ "sigs.k8s.io/controller-runtime/examples/crd/pkg"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+func deleteDeployment(ctx context.Context, dep *appsv1.Deployment, ns string) {
+ _, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ if err == nil {
+ err = clientset.AppsV1().Deployments(ns).Delete(ctx, dep.Name, metav1.DeleteOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ }
+}
+
+func deleteNamespace(ctx context.Context, ns *corev1.Namespace) {
+ ns, err := clientset.CoreV1().Namespaces().Get(ctx, ns.Name, metav1.GetOptions{})
+ if err != nil {
+ return
+ }
+
+ err = clientset.CoreV1().Namespaces().Delete(ctx, ns.Name, metav1.DeleteOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ // finalize if necessary
+ pos := -1
+ finalizers := ns.Spec.Finalizers
+ for i, fin := range finalizers {
+ if fin == "kubernetes" {
+ pos = i
+ break
+ }
+ }
+ if pos == -1 {
+ // no need to finalize
+ return
+ }
+
+ // re-get in order to finalize
+ ns, err = clientset.CoreV1().Namespaces().Get(ctx, ns.Name, metav1.GetOptions{})
+ if err != nil {
+ return
+ }
+
+ ns.Spec.Finalizers = append(finalizers[:pos], finalizers[pos+1:]...)
+ _, err = clientset.CoreV1().Namespaces().Finalize(ctx, ns, metav1.UpdateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+WAIT_LOOP:
+ for i := 0; i < 10; i++ {
+ ns, err = clientset.CoreV1().Namespaces().Get(ctx, ns.Name, metav1.GetOptions{})
+ if apierrors.IsNotFound(err) {
+ // success!
+ return
+ }
+ select {
+ case <-ctx.Done():
+ break WAIT_LOOP
+ // failed to delete in time, see failure below
+ case <-time.After(100 * time.Millisecond):
+ // do nothing, try again
+ }
+ }
+ Fail(fmt.Sprintf("timed out waiting for namespace %q to be deleted", ns.Name))
+}
+
+type mockPatchOption struct {
+ applied bool
+}
+
+func (o *mockPatchOption) ApplyToPatch(_ *client.PatchOptions) {
+ o.applied = true
+}
+
+// metaOnlyFromObj returns PartialObjectMetadata from a concrete Go struct that
+// returns a concrete *metav1.ObjectMeta from GetObjectMeta (yes, that plays a
+// bit fast and loose, but the only other options are serializing and then
+// deserializing, or manually calling all the accessor funcs, which are both a bit annoying).
+func metaOnlyFromObj(obj interface {
+ runtime.Object
+ metav1.ObjectMetaAccessor
+}, scheme *runtime.Scheme) *metav1.PartialObjectMetadata {
+ metaObj := metav1.PartialObjectMetadata{}
+ obj.GetObjectMeta().(*metav1.ObjectMeta).DeepCopyInto(&metaObj.ObjectMeta)
+ kinds, _, err := scheme.ObjectKinds(obj)
+ if err != nil {
+ panic(err)
+ }
+ metaObj.SetGroupVersionKind(kinds[0])
+ return &metaObj
+}
+
+var _ = Describe("Client", func() {
+
+ var scheme *runtime.Scheme
+ var depGvk schema.GroupVersionKind
+ var dep *appsv1.Deployment
+ var pod *corev1.Pod
+ var node *corev1.Node
+ var serviceAccount *corev1.ServiceAccount
+ var csr *certificatesv1.CertificateSigningRequest
+ var count uint64 = 0
+ var replicaCount int32 = 2
+ var ns = "default"
+ ctx := context.TODO()
+
+ BeforeEach(func() {
+ atomic.AddUint64(&count, 1)
+ dep = &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("deployment-name-%v", count), Namespace: ns, Labels: map[string]string{"app": fmt.Sprintf("bar-%v", count)}},
+ Spec: appsv1.DeploymentSpec{
+ Replicas: &replicaCount,
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depGvk = schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ }
+ // Pod is invalid without a container field in the PodSpec
+ pod = &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("pod-%v", count), Namespace: ns},
+ Spec: corev1.PodSpec{},
+ }
+ node = &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("node-name-%v", count)},
+ Spec: corev1.NodeSpec{},
+ }
+ serviceAccount = &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("sa-%v", count), Namespace: ns}}
+ csr = &certificatesv1.CertificateSigningRequest{
+ ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("csr-%v", count)},
+ Spec: certificatesv1.CertificateSigningRequestSpec{
+ SignerName: "org.io/my-signer",
+ Request: []byte(`-----BEGIN CERTIFICATE REQUEST-----
+MIIChzCCAW8CAQAwQjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0
+eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBANe06dLX/bDNm6mVEnKdJexcJM6WKMFSt5o6BEdD1+Ki
+WyUcvfNgIBbwAZjkF9U1r7+KuDcc6XYFnb6ky1wPo4C+XwcIIx7Nnbf8IdWJukPb
+2BCsqO4NCsG6kKFavmH9J3q//nwKUvlQE+AJ2MPuOAZTwZ4KskghiGuS8hyk6/PZ
+XH9QhV7Jma43bDzQozd2C7OujRBhLsuP94KSu839RRFWd9ms3XHgTxLxb7nxwZDx
+9l7/ZVAObJoQYlHENqs12NCVP4gpJfbcY8/rd+IG4ftcZEmpeO4kKO+d2TpRKQqw
+bjCMoAdD5Y43iLTtyql4qRnbMe3nxYG2+1inEryuV/cCAwEAAaAAMA0GCSqGSIb3
+DQEBCwUAA4IBAQDH5hDByRN7wERQtC/o6uc8Y+yhjq9YcBJjjbnD6Vwru5pOdWtx
+qfKkkXI5KNOdEhWzLnJyOcWHjj8UoHqI3AjxGC7dTM95eGjxQGUpsUOX8JSd4MiZ
+cct4g4BKBj02AGqZLiEgN+PLCYAmEaYU7oZc4OAh6WzMrljNRsj66awMQpw8O1eY
+YuBa8vwz8ko8vn/pn7IrFu8cZ+EA3rluJ+budX/QrEGi1hijg27q7/Qr0wNI9f1v
+086mLKdqaBTkblXWEvF3WP4CcLNyrSNi4eu+G0fcAgGp1F/Nqh0MuWKSOLprv5Om
+U5wwSivyi7vmegHKmblOzNVKA5qPO8zWzqBC
+-----END CERTIFICATE REQUEST-----`),
+ Usages: []certificatesv1.KeyUsage{certificatesv1.UsageClientAuth},
+ },
+ }
+ scheme = kscheme.Scheme
+ })
+
+ var delOptions *metav1.DeleteOptions
+ AfterEach(func() {
+ // Cleanup
+ var zero int64 = 0
+ policy := metav1.DeletePropagationForeground
+ delOptions = &metav1.DeleteOptions{
+ GracePeriodSeconds: &zero,
+ PropagationPolicy: &policy,
+ }
+ deleteDeployment(ctx, dep, ns)
+ _, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
+ if err == nil {
+ err = clientset.CoreV1().Nodes().Delete(ctx, node.Name, *delOptions)
+ Expect(err).NotTo(HaveOccurred())
+ }
+ err = clientset.CoreV1().ServiceAccounts(ns).Delete(ctx, serviceAccount.Name, *delOptions)
+ Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
+
+ err = clientset.CertificatesV1().CertificateSigningRequests().Delete(ctx, csr.Name, *delOptions)
+ Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
+ })
+
+ Describe("New", func() {
+ It("should return a new Client", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+ })
+
+ It("should fail if the config is nil", func() {
+ cl, err := client.New(nil, client.Options{})
+ Expect(err).To(HaveOccurred())
+ Expect(cl).To(BeNil())
+ })
+
+ It("should use the provided Scheme if provided", func() {
+ cl, err := client.New(cfg, client.Options{Scheme: scheme})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+ Expect(cl.Scheme()).ToNot(BeNil())
+ Expect(cl.Scheme()).To(Equal(scheme))
+ })
+
+ It("should default the Scheme if not provided", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+ Expect(cl.Scheme()).ToNot(BeNil())
+ Expect(cl.Scheme()).To(Equal(kscheme.Scheme))
+ })
+
+ It("should use the provided Mapper if provided", func() {
+ mapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{})
+ cl, err := client.New(cfg, client.Options{Mapper: mapper})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+ Expect(cl.RESTMapper()).ToNot(BeNil())
+ Expect(cl.RESTMapper()).To(Equal(mapper))
+ })
+
+ It("should create a Mapper if not provided", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+ Expect(cl.RESTMapper()).ToNot(BeNil())
+ })
+
+ It("should use the provided reader cache if provided, on get and list", func() {
+ cache := &fakeReader{}
+ cl, err := client.New(cfg, client.Options{Cache: &client.CacheOptions{Reader: cache}})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+ Expect(cl.Get(ctx, client.ObjectKey{Name: "test"}, &appsv1.Deployment{})).To(Succeed())
+ Expect(cl.List(ctx, &appsv1.DeploymentList{})).To(Succeed())
+ Expect(cache.Called).To(Equal(2))
+ })
+
+ It("should not use the provided reader cache if provided, on get and list for uncached GVKs", func() {
+ cache := &fakeReader{}
+ cl, err := client.New(cfg, client.Options{Cache: &client.CacheOptions{Reader: cache, DisableFor: []client.Object{&corev1.Namespace{}}}})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+ Expect(cl.Get(ctx, client.ObjectKey{Name: "default"}, &corev1.Namespace{})).To(Succeed())
+ Expect(cl.List(ctx, &corev1.NamespaceList{})).To(Succeed())
+ Expect(cache.Called).To(Equal(0))
+ })
+ })
+
+ Describe("Create", func() {
+ Context("with structured objects", func() {
+ It("should create a new object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("creating the object")
+ err = cl.Create(context.TODO(), dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+
+ By("writing the result back to the go struct")
+ Expect(dep).To(Equal(actual))
+ })
+
+ It("should create a new object non-namespace object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("creating the object")
+ err = cl.Create(context.TODO(), node)
+ Expect(err).NotTo(HaveOccurred())
+
+ actual, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+
+ By("writing the result back to the go struct")
+ Expect(node).To(Equal(actual))
+ })
+
+ It("should fail if the object already exists", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ old := dep.DeepCopy()
+
+ By("creating the object")
+ err = cl.Create(context.TODO(), dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+
+ By("creating the object a second time")
+ err = cl.Create(context.TODO(), old)
+ Expect(err).To(HaveOccurred())
+ Expect(apierrors.IsAlreadyExists(err)).To(BeTrue())
+ })
+
+ It("should fail if the object does not pass server-side validation", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("creating the pod, since required field Containers is empty")
+ err = cl.Create(context.TODO(), pod)
+ Expect(err).To(HaveOccurred())
+ // TODO(seans): Add test to validate the returned error. Problems currently with
+ // different returned error locally versus travis.
+ })
+
+ It("should fail if the object cannot be mapped to a GVK", func() {
+ By("creating client with empty Scheme")
+ emptyScheme := runtime.NewScheme()
+ cl, err := client.New(cfg, client.Options{Scheme: emptyScheme})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("creating the object fails")
+ err = cl.Create(context.TODO(), dep)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("no kind is registered for the type"))
+ })
+
+ PIt("should fail if the GVK cannot be mapped to a Resource", func() {
+ // TODO(seans3): implement these
+ // Example: ListOptions
+ })
+
+ Context("with the DryRun option", func() {
+ It("should not create a new object, global option", func() {
+ cl, err := client.New(cfg, client.Options{DryRun: pointer.Bool(true)})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("creating the object (with DryRun)")
+ err = cl.Create(context.TODO(), dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ Expect(actual).To(Equal(&appsv1.Deployment{}))
+ })
+
+ It("should not create a new object, inline option", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("creating the object (with DryRun)")
+ err = cl.Create(context.TODO(), dep, client.DryRunAll)
+ Expect(err).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ Expect(actual).To(Equal(&appsv1.Deployment{}))
+ })
+ })
+ })
+
+ Context("with unstructured objects", func() {
+ It("should create a new object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("encoding the deployment as unstructured")
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+
+ By("creating the object")
+ err = cl.Create(context.TODO(), u)
+ Expect(err).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ })
+
+ It("should create a new non-namespace object ", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("encoding the deployment as unstructured")
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(node, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Kind: "Node",
+ Version: "v1",
+ })
+
+ By("creating the object")
+ err = cl.Create(context.TODO(), node)
+ Expect(err).NotTo(HaveOccurred())
+
+ actual, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ au := &unstructured.Unstructured{}
+ Expect(scheme.Convert(actual, au, nil)).To(Succeed())
+ Expect(scheme.Convert(node, u, nil)).To(Succeed())
+ By("writing the result back to the go struct")
+
+ Expect(u).To(Equal(au))
+ })
+
+ It("should fail if the object already exists", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ old := dep.DeepCopy()
+
+ By("creating the object")
+ err = cl.Create(context.TODO(), dep)
+ Expect(err).NotTo(HaveOccurred())
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+
+ By("encoding the deployment as unstructured")
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(old, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+
+ By("creating the object a second time")
+ err = cl.Create(context.TODO(), u)
+ Expect(err).To(HaveOccurred())
+ Expect(apierrors.IsAlreadyExists(err)).To(BeTrue())
+ })
+
+ It("should fail if the object does not pass server-side validation", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("creating the pod, since required field Containers is empty")
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(pod, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Version: "v1",
+ Kind: "Pod",
+ })
+ err = cl.Create(context.TODO(), u)
+ Expect(err).To(HaveOccurred())
+ // TODO(seans): Add test to validate the returned error. Problems currently with
+ // different returned error locally versus travis.
+ })
+
+ })
+
+ Context("with metadata objects", func() {
+ It("should fail with an error", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ obj := metaOnlyFromObj(dep, scheme)
+ Expect(cl.Create(context.TODO(), obj)).NotTo(Succeed())
+ })
+ })
+
+ Context("with the DryRun option", func() {
+ It("should not create a new object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("encoding the deployment as unstructured")
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+
+ By("creating the object")
+ err = cl.Create(context.TODO(), u, client.DryRunAll)
+ Expect(err).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ Expect(actual).To(Equal(&appsv1.Deployment{}))
+ })
+ })
+ })
+
+ Describe("Update", func() {
+ Context("with structured objects", func() {
+ It("should update an existing object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the Deployment")
+ dep.Annotations = map[string]string{"foo": "bar"}
+ err = cl.Update(context.TODO(), dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has new annotation")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Annotations["foo"]).To(Equal("bar"))
+ })
+
+ It("should update and preserve type information", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the Deployment")
+ dep.SetGroupVersionKind(depGvk)
+ err = cl.Update(context.TODO(), dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has type information")
+ Expect(dep.GroupVersionKind()).To(Equal(depGvk))
+ })
+
+ It("should update an existing object non-namespace object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the object")
+ node.Annotations = map[string]string{"foo": "bar"}
+ err = cl.Update(context.TODO(), node)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validate updated Node had new annotation")
+ actual, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Annotations["foo"]).To(Equal("bar"))
+ })
+
+ It("should fail if the object does not exist", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("updating non-existent object")
+ err = cl.Update(context.TODO(), dep)
+ Expect(err).To(HaveOccurred())
+ })
+
+ PIt("should fail if the object does not pass server-side validation", func() {
+
+ })
+
+ PIt("should fail if the object doesn't have meta", func() {
+
+ })
+
+ It("should fail if the object cannot be mapped to a GVK", func() {
+ By("creating client with empty Scheme")
+ emptyScheme := runtime.NewScheme()
+ cl, err := client.New(cfg, client.Options{Scheme: emptyScheme})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the Deployment")
+ dep.Annotations = map[string]string{"foo": "bar"}
+ err = cl.Update(context.TODO(), dep)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("no kind is registered for the type"))
+ })
+
+ PIt("should fail if the GVK cannot be mapped to a Resource", func() {
+
+ })
+ })
+ Context("with unstructured objects", func() {
+ It("should update an existing object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the Deployment")
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+ u.SetAnnotations(map[string]string{"foo": "bar"})
+ err = cl.Update(context.TODO(), u)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has new annotation")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Annotations["foo"]).To(Equal("bar"))
+ })
+
+ It("should update and preserve type information", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the Deployment")
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(depGvk)
+ u.SetAnnotations(map[string]string{"foo": "bar"})
+ err = cl.Update(context.TODO(), u)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has type information")
+ Expect(u.GroupVersionKind()).To(Equal(depGvk))
+ })
+
+ It("should update an existing object non-namespace object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the object")
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(node, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Kind: "Node",
+ Version: "v1",
+ })
+ u.SetAnnotations(map[string]string{"foo": "bar"})
+ err = cl.Update(context.TODO(), u)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validate updated Node had new annotation")
+ actual, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Annotations["foo"]).To(Equal("bar"))
+ })
+ It("should fail if the object does not exist", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("updating non-existent object")
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(depGvk)
+ err = cl.Update(context.TODO(), dep)
+ Expect(err).To(HaveOccurred())
+ })
+ })
+ Context("with metadata objects", func() {
+ It("should fail with an error", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ obj := metaOnlyFromObj(dep, scheme)
+
+ Expect(cl.Update(context.TODO(), obj)).NotTo(Succeed())
+ })
+ })
+ })
+
+ Describe("Patch", func() {
+ Context("Metadata Client", func() {
+ It("should merge patch with options", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ metadata := metaOnlyFromObj(dep, scheme)
+ if metadata.Labels == nil {
+ metadata.Labels = make(map[string]string)
+ }
+ metadata.Labels["foo"] = "bar"
+
+ testOption := &mockPatchOption{}
+ Expect(cl.Patch(context.TODO(), metadata, client.Merge, testOption)).To(Succeed())
+
+ By("validating that patched metadata has new labels")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Labels["foo"]).To(Equal("bar"))
+
+ By("validating patch options were applied")
+ Expect(testOption.applied).To(Equal(true))
+ })
+ })
+ })
+
+ Describe("SubResourceClient", func() {
+ Context("with structured objects", func() {
+ It("should be able to read the Scale subresource", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Creating a deployment")
+ dep, err := clientset.AppsV1().Deployments(dep.Namespace).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("reading the scale subresource")
+ scale := &autoscalingv1.Scale{}
+ err = cl.SubResource("scale").Get(ctx, dep, scale)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(scale.Spec.Replicas).To(Equal(*dep.Spec.Replicas))
+ })
+ It("should be able to create ServiceAccount tokens", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Creating the serviceAccount")
+ _, err = clientset.CoreV1().ServiceAccounts(serviceAccount.Namespace).Create(ctx, serviceAccount, metav1.CreateOptions{})
+ Expect((err)).NotTo(HaveOccurred())
+
+ token := &authenticationv1.TokenRequest{}
+ err = cl.SubResource("token").Create(ctx, serviceAccount, token)
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(token.Status.Token).NotTo(Equal(""))
+ })
+
+ It("should be able to create Pod evictions", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ // Make the pod valid
+ pod.Spec.Containers = []corev1.Container{{Name: "foo", Image: "busybox"}}
+
+ By("Creating the pod")
+ pod, err = clientset.CoreV1().Pods(pod.Namespace).Create(ctx, pod, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Creating the eviction")
+ eviction := &policyv1.Eviction{
+ DeleteOptions: &metav1.DeleteOptions{GracePeriodSeconds: ptr(int64(0))},
+ }
+ err = cl.SubResource("eviction").Create(ctx, pod, eviction)
+ Expect((err)).NotTo(HaveOccurred())
+
+ By("Asserting the pod is gone")
+ _, err = clientset.CoreV1().Pods(pod.Namespace).Get(ctx, pod.Name, metav1.GetOptions{})
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+
+ It("should be able to create Pod bindings", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ // Make the pod valid
+ pod.Spec.Containers = []corev1.Container{{Name: "foo", Image: "busybox"}}
+
+ By("Creating the pod")
+ pod, err = clientset.CoreV1().Pods(pod.Namespace).Create(ctx, pod, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Creating the binding")
+ binding := &corev1.Binding{
+ Target: corev1.ObjectReference{Name: node.Name},
+ }
+ err = cl.SubResource("binding").Create(ctx, pod, binding)
+ Expect((err)).NotTo(HaveOccurred())
+
+ By("Asserting the pod is bound")
+ pod, err = clientset.CoreV1().Pods(pod.Namespace).Get(ctx, pod.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(pod.Spec.NodeName).To(Equal(node.Name))
+ })
+
+ It("should be able to approve CSRs", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Creating the CSR")
+ csr, err := clientset.CertificatesV1().CertificateSigningRequests().Create(ctx, csr, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Approving the CSR")
+ csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1.CertificateSigningRequestCondition{
+ Type: certificatesv1.CertificateApproved,
+ Status: corev1.ConditionTrue,
+ })
+ err = cl.SubResource("approval").Update(ctx, csr)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Asserting the CSR is approved")
+ csr, err = clientset.CertificatesV1().CertificateSigningRequests().Get(ctx, csr.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(csr.Status.Conditions[0].Type).To(Equal(certificatesv1.CertificateApproved))
+ Expect(csr.Status.Conditions[0].Status).To(Equal(corev1.ConditionTrue))
+ })
+
+ It("should be able to approve CSRs using Patch", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Creating the CSR")
+ csr, err := clientset.CertificatesV1().CertificateSigningRequests().Create(ctx, csr, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Approving the CSR")
+ patch := client.MergeFrom(csr.DeepCopy())
+ csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1.CertificateSigningRequestCondition{
+ Type: certificatesv1.CertificateApproved,
+ Status: corev1.ConditionTrue,
+ })
+ err = cl.SubResource("approval").Patch(ctx, csr, patch)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Asserting the CSR is approved")
+ csr, err = clientset.CertificatesV1().CertificateSigningRequests().Get(ctx, csr.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(csr.Status.Conditions[0].Type).To(Equal(certificatesv1.CertificateApproved))
+ Expect(csr.Status.Conditions[0].Status).To(Equal(corev1.ConditionTrue))
+ })
+
+ It("should be able to update the scale subresource", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Creating a deployment")
+ dep, err := clientset.AppsV1().Deployments(dep.Namespace).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Updating the scale subresurce")
+ replicaCount := *dep.Spec.Replicas
+ scale := &autoscalingv1.Scale{Spec: autoscalingv1.ScaleSpec{Replicas: replicaCount}}
+ err = cl.SubResource("scale").Update(ctx, dep, client.WithSubResourceBody(scale))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Asserting replicas got updated")
+ dep, err = clientset.AppsV1().Deployments(dep.Namespace).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(*dep.Spec.Replicas).To(Equal(replicaCount))
+ })
+
+ It("should be able to patch the scale subresource", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Creating a deployment")
+ dep, err := clientset.AppsV1().Deployments(dep.Namespace).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Updating the scale subresurce")
+ replicaCount := *dep.Spec.Replicas
+ patch := client.MergeFrom(&autoscalingv1.Scale{})
+ scale := &autoscalingv1.Scale{Spec: autoscalingv1.ScaleSpec{Replicas: replicaCount}}
+ err = cl.SubResource("scale").Patch(ctx, dep, patch, client.WithSubResourceBody(scale))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Asserting replicas got updated")
+ dep, err = clientset.AppsV1().Deployments(dep.Namespace).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(*dep.Spec.Replicas).To(Equal(replicaCount))
+ })
+ })
+
+ Context("with unstructured objects", func() {
+ It("should be able to read the Scale subresource", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Creating a deployment")
+ dep, err := clientset.AppsV1().Deployments(dep.Namespace).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ dep.APIVersion = appsv1.SchemeGroupVersion.String()
+ dep.Kind = reflect.TypeOf(dep).Elem().Name()
+ depUnstructured, err := toUnstructured(dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("reading the scale subresource")
+ scale := &unstructured.Unstructured{}
+ scale.SetAPIVersion("autoscaling/v1")
+ scale.SetKind("Scale")
+ err = cl.SubResource("scale").Get(ctx, depUnstructured, scale)
+ Expect(err).NotTo(HaveOccurred())
+
+ val, found, err := unstructured.NestedInt64(scale.UnstructuredContent(), "spec", "replicas")
+ Expect(err).NotTo(HaveOccurred())
+ Expect(found).To(BeTrue())
+ Expect(int32(val)).To(Equal(*dep.Spec.Replicas))
+ })
+ It("should be able to create ServiceAccount tokens", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Creating the serviceAccount")
+ _, err = clientset.CoreV1().ServiceAccounts(serviceAccount.Namespace).Create(ctx, serviceAccount, metav1.CreateOptions{})
+ Expect((err)).NotTo(HaveOccurred())
+
+ serviceAccount.APIVersion = "v1"
+ serviceAccount.Kind = "ServiceAccount"
+ serviceAccountUnstructured, err := toUnstructured(serviceAccount)
+ Expect(err).NotTo(HaveOccurred())
+
+ token := &unstructured.Unstructured{}
+ token.SetAPIVersion("authentication.k8s.io/v1")
+ token.SetKind("TokenRequest")
+ err = cl.SubResource("token").Create(ctx, serviceAccountUnstructured, token)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(token.GetAPIVersion()).To(Equal("authentication.k8s.io/v1"))
+ Expect(token.GetKind()).To(Equal("TokenRequest"))
+
+ val, found, err := unstructured.NestedString(token.UnstructuredContent(), "status", "token")
+ Expect(err).NotTo(HaveOccurred())
+ Expect(found).To(BeTrue())
+ Expect(val).NotTo(Equal(""))
+ })
+
+ It("should be able to create Pod evictions", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ // Make the pod valid
+ pod.Spec.Containers = []corev1.Container{{Name: "foo", Image: "busybox"}}
+
+ By("Creating the pod")
+ pod, err = clientset.CoreV1().Pods(pod.Namespace).Create(ctx, pod, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ pod.APIVersion = "v1"
+ pod.Kind = "Pod"
+ podUnstructured, err := toUnstructured(pod)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Creating the eviction")
+ eviction := &unstructured.Unstructured{}
+ eviction.SetAPIVersion("policy/v1")
+ eviction.SetKind("Eviction")
+ err = unstructured.SetNestedField(eviction.UnstructuredContent(), int64(0), "deleteOptions", "gracePeriodSeconds")
+ Expect(err).NotTo(HaveOccurred())
+ err = cl.SubResource("eviction").Create(ctx, podUnstructured, eviction)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(eviction.GetAPIVersion()).To(Equal("policy/v1"))
+ Expect(eviction.GetKind()).To(Equal("Eviction"))
+
+ By("Asserting the pod is gone")
+ _, err = clientset.CoreV1().Pods(pod.Namespace).Get(ctx, pod.Name, metav1.GetOptions{})
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+
+ It("should be able to create Pod bindings", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ // Make the pod valid
+ pod.Spec.Containers = []corev1.Container{{Name: "foo", Image: "busybox"}}
+
+ By("Creating the pod")
+ pod, err = clientset.CoreV1().Pods(pod.Namespace).Create(ctx, pod, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ pod.APIVersion = "v1"
+ pod.Kind = "Pod"
+ podUnstructured, err := toUnstructured(pod)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Creating the binding")
+ binding := &unstructured.Unstructured{}
+ binding.SetAPIVersion("v1")
+ binding.SetKind("Binding")
+ err = unstructured.SetNestedField(binding.UnstructuredContent(), node.Name, "target", "name")
+ Expect(err).NotTo(HaveOccurred())
+
+ err = cl.SubResource("binding").Create(ctx, podUnstructured, binding)
+ Expect((err)).NotTo(HaveOccurred())
+ Expect(binding.GetAPIVersion()).To(Equal("v1"))
+ Expect(binding.GetKind()).To(Equal("Binding"))
+
+ By("Asserting the pod is bound")
+ pod, err = clientset.CoreV1().Pods(pod.Namespace).Get(ctx, pod.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(pod.Spec.NodeName).To(Equal(node.Name))
+ })
+
+ It("should be able to approve CSRs", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Creating the CSR")
+ csr, err := clientset.CertificatesV1().CertificateSigningRequests().Create(ctx, csr, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Approving the CSR")
+ csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1.CertificateSigningRequestCondition{
+ Type: certificatesv1.CertificateApproved,
+ Status: corev1.ConditionTrue,
+ })
+ csr.APIVersion = "certificates.k8s.io/v1"
+ csr.Kind = "CertificateSigningRequest"
+ csrUnstructured, err := toUnstructured(csr)
+ Expect(err).NotTo(HaveOccurred())
+
+ err = cl.SubResource("approval").Update(ctx, csrUnstructured)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(csrUnstructured.GetAPIVersion()).To(Equal("certificates.k8s.io/v1"))
+ Expect(csrUnstructured.GetKind()).To(Equal("CertificateSigningRequest"))
+
+ By("Asserting the CSR is approved")
+ csr, err = clientset.CertificatesV1().CertificateSigningRequests().Get(ctx, csr.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(csr.Status.Conditions[0].Type).To(Equal(certificatesv1.CertificateApproved))
+ Expect(csr.Status.Conditions[0].Status).To(Equal(corev1.ConditionTrue))
+ })
+
+ It("should be able to approve CSRs using Patch", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Creating the CSR")
+ csr, err := clientset.CertificatesV1().CertificateSigningRequests().Create(ctx, csr, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Approving the CSR")
+ patch := client.MergeFrom(csr.DeepCopy())
+ csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1.CertificateSigningRequestCondition{
+ Type: certificatesv1.CertificateApproved,
+ Status: corev1.ConditionTrue,
+ })
+ csr.APIVersion = "certificates.k8s.io/v1"
+ csr.Kind = "CertificateSigningRequest"
+ csrUnstructured, err := toUnstructured(csr)
+ Expect(err).NotTo(HaveOccurred())
+
+ err = cl.SubResource("approval").Patch(ctx, csrUnstructured, patch)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(csrUnstructured.GetAPIVersion()).To(Equal("certificates.k8s.io/v1"))
+ Expect(csrUnstructured.GetKind()).To(Equal("CertificateSigningRequest"))
+
+ By("Asserting the CSR is approved")
+ csr, err = clientset.CertificatesV1().CertificateSigningRequests().Get(ctx, csr.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(csr.Status.Conditions[0].Type).To(Equal(certificatesv1.CertificateApproved))
+ Expect(csr.Status.Conditions[0].Status).To(Equal(corev1.ConditionTrue))
+ })
+
+ It("should be able to update the scale subresource", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Creating a deployment")
+ dep, err := clientset.AppsV1().Deployments(dep.Namespace).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ dep.APIVersion = "apps/v1"
+ dep.Kind = "Deployment"
+ depUnstructured, err := toUnstructured(dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Updating the scale subresurce")
+ replicaCount := *dep.Spec.Replicas
+ scale := &unstructured.Unstructured{}
+ scale.SetAPIVersion("autoscaling/v1")
+ scale.SetKind("Scale")
+ Expect(unstructured.SetNestedField(scale.Object, int64(replicaCount), "spec", "replicas")).NotTo(HaveOccurred())
+ err = cl.SubResource("scale").Update(ctx, depUnstructured, client.WithSubResourceBody(scale))
+ Expect(err).NotTo(HaveOccurred())
+ Expect(scale.GetAPIVersion()).To(Equal("autoscaling/v1"))
+ Expect(scale.GetKind()).To(Equal("Scale"))
+
+ By("Asserting replicas got updated")
+ dep, err = clientset.AppsV1().Deployments(dep.Namespace).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(*dep.Spec.Replicas).To(Equal(replicaCount))
+ })
+
+ It("should be able to patch the scale subresource", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Creating a deployment")
+ dep, err := clientset.AppsV1().Deployments(dep.Namespace).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ dep.APIVersion = "apps/v1"
+ dep.Kind = "Deployment"
+ depUnstructured, err := toUnstructured(dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Updating the scale subresurce")
+ replicaCount := *dep.Spec.Replicas
+ scale := &unstructured.Unstructured{}
+ scale.SetAPIVersion("autoscaling/v1")
+ scale.SetKind("Scale")
+ patch := client.MergeFrom(scale.DeepCopy())
+ Expect(unstructured.SetNestedField(scale.Object, int64(replicaCount), "spec", "replicas")).NotTo(HaveOccurred())
+ err = cl.SubResource("scale").Patch(ctx, depUnstructured, patch, client.WithSubResourceBody(scale))
+ Expect(err).NotTo(HaveOccurred())
+ Expect(scale.GetAPIVersion()).To(Equal("autoscaling/v1"))
+ Expect(scale.GetKind()).To(Equal("Scale"))
+
+ By("Asserting replicas got updated")
+ dep, err = clientset.AppsV1().Deployments(dep.Namespace).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(*dep.Spec.Replicas).To(Equal(replicaCount))
+ })
+ })
+
+ })
+
+ Describe("StatusClient", func() {
+ Context("with structured objects", func() {
+ It("should update status of an existing object", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the status of Deployment")
+ dep.Status.Replicas = 1
+ err = cl.Status().Update(context.TODO(), dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has new status")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Status.Replicas).To(BeEquivalentTo(1))
+ })
+
+ It("should update status and preserve type information", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the status of Deployment")
+ dep.SetGroupVersionKind(depGvk)
+ dep.Status.Replicas = 1
+ err = cl.Status().Update(context.TODO(), dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has type information")
+ Expect(dep.GroupVersionKind()).To(Equal(depGvk))
+ })
+
+ It("should patch status and preserve type information", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("patching the status of Deployment")
+ dep.SetGroupVersionKind(depGvk)
+ depPatch := client.MergeFrom(dep.DeepCopy())
+ dep.Status.Replicas = 1
+ err = cl.Status().Patch(context.TODO(), dep, depPatch)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has type information")
+ Expect(dep.GroupVersionKind()).To(Equal(depGvk))
+ })
+
+ It("should not update spec of an existing object", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the spec and status of Deployment")
+ var rc int32 = 1
+ dep.Status.Replicas = 1
+ dep.Spec.Replicas = &rc
+ err = cl.Status().Update(context.TODO(), dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has new status and unchanged spec")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Status.Replicas).To(BeEquivalentTo(1))
+ Expect(*actual.Spec.Replicas).To(BeEquivalentTo(replicaCount))
+ })
+
+ It("should update an existing object non-namespace object", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating status of the object")
+ node.Status.Phase = corev1.NodeRunning
+ err = cl.Status().Update(context.TODO(), node)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validate updated Node had new annotation")
+ actual, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Status.Phase).To(Equal(corev1.NodeRunning))
+ })
+
+ It("should fail if the object does not exist", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("updating status of a non-existent object")
+ err = cl.Status().Update(context.TODO(), dep)
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should fail if the object cannot be mapped to a GVK", func() {
+ By("creating client with empty Scheme")
+ emptyScheme := runtime.NewScheme()
+ cl, err := client.New(cfg, client.Options{Scheme: emptyScheme})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating status of the Deployment")
+ dep.Status.Replicas = 1
+ err = cl.Status().Update(context.TODO(), dep)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("no kind is registered for the type"))
+ })
+
+ PIt("should fail if the GVK cannot be mapped to a Resource", func() {
+
+ })
+
+ PIt("should fail if an API does not implement Status subresource", func() {
+
+ })
+ })
+
+ Context("with unstructured objects", func() {
+ It("should update status of an existing object", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the status of Deployment")
+ u := &unstructured.Unstructured{}
+ dep.Status.Replicas = 1
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+ err = cl.Status().Update(context.TODO(), u)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has new status")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Status.Replicas).To(BeEquivalentTo(1))
+ })
+
+ It("should update status and preserve type information", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the status of Deployment")
+ u := &unstructured.Unstructured{}
+ dep.Status.Replicas = 1
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+ err = cl.Status().Update(context.TODO(), u)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has type information")
+ Expect(u.GroupVersionKind()).To(Equal(depGvk))
+ })
+
+ It("should patch status and preserve type information", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("patching the status of Deployment")
+ u := &unstructured.Unstructured{}
+ depPatch := client.MergeFrom(dep.DeepCopy())
+ dep.Status.Replicas = 1
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+ err = cl.Status().Patch(context.TODO(), u, depPatch)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has type information")
+ Expect(u.GroupVersionKind()).To(Equal(depGvk))
+
+ By("validating patched Deployment has new status")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Status.Replicas).To(BeEquivalentTo(1))
+ })
+
+ It("should not update spec of an existing object", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the spec and status of Deployment")
+ u := &unstructured.Unstructured{}
+ var rc int32 = 1
+ dep.Status.Replicas = 1
+ dep.Spec.Replicas = &rc
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+ err = cl.Status().Update(context.TODO(), u)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has new status and unchanged spec")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Status.Replicas).To(BeEquivalentTo(1))
+ Expect(*actual.Spec.Replicas).To(BeEquivalentTo(replicaCount))
+ })
+
+ It("should update an existing object non-namespace object", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating status of the object")
+ u := &unstructured.Unstructured{}
+ node.Status.Phase = corev1.NodeRunning
+ Expect(scheme.Convert(node, u, nil)).To(Succeed())
+ err = cl.Status().Update(context.TODO(), u)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validate updated Node had new annotation")
+ actual, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Status.Phase).To(Equal(corev1.NodeRunning))
+ })
+
+ It("should fail if the object does not exist", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("updating status of a non-existent object")
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+ err = cl.Status().Update(context.TODO(), u)
+ Expect(err).To(HaveOccurred())
+ })
+
+ PIt("should fail if the GVK cannot be mapped to a Resource", func() {
+
+ })
+
+ PIt("should fail if an API does not implement Status subresource", func() {
+
+ })
+
+ })
+
+ Context("with metadata objects", func() {
+ It("should fail to update with an error", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ obj := metaOnlyFromObj(dep, scheme)
+ Expect(cl.Status().Update(context.TODO(), obj)).NotTo(Succeed())
+ })
+
+ It("should patch status and preserve type information", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("patching the status of Deployment")
+ objPatch := client.MergeFrom(metaOnlyFromObj(dep, scheme))
+ dep.Annotations = map[string]string{"some-new-annotation": "some-new-value"}
+ obj := metaOnlyFromObj(dep, scheme)
+ err = cl.Status().Patch(context.TODO(), obj, objPatch)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating updated Deployment has type information")
+ Expect(obj.GroupVersionKind()).To(Equal(depGvk))
+
+ By("validating patched Deployment has new status")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Annotations).To(HaveKeyWithValue("some-new-annotation", "some-new-value"))
+ })
+ })
+ })
+
+ Describe("Delete", func() {
+ Context("with structured objects", func() {
+ It("should delete an existing object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("deleting the Deployment")
+ depName := dep.Name
+ err = cl.Delete(context.TODO(), dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating the Deployment no longer exists")
+ _, err = clientset.AppsV1().Deployments(ns).Get(ctx, depName, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should delete an existing object non-namespace object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Node")
+ node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("deleting the Node")
+ nodeName := node.Name
+ err = cl.Delete(context.TODO(), node)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating the Node no longer exists")
+ _, err = clientset.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should fail if the object does not exist", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Deleting node before it is ever created")
+ err = cl.Delete(context.TODO(), node)
+ Expect(err).To(HaveOccurred())
+ })
+
+ PIt("should fail if the object doesn't have meta", func() {
+
+ })
+
+ It("should fail if the object cannot be mapped to a GVK", func() {
+ By("creating client with empty Scheme")
+ emptyScheme := runtime.NewScheme()
+ cl, err := client.New(cfg, client.Options{Scheme: emptyScheme})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("deleting the Deployment fails")
+ err = cl.Delete(context.TODO(), dep)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("no kind is registered for the type"))
+ })
+
+ PIt("should fail if the GVK cannot be mapped to a Resource", func() {
+
+ })
+
+ It("should delete a collection of objects", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating two Deployments")
+
+ dep2 := dep.DeepCopy()
+ dep2.Name += "-2"
+
+ dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ dep2, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep2, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ depName := dep.Name
+ dep2Name := dep2.Name
+
+ By("deleting Deployments")
+ err = cl.DeleteAllOf(context.TODO(), dep, client.InNamespace(ns), client.MatchingLabels(dep.ObjectMeta.Labels))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating the Deployment no longer exists")
+ _, err = clientset.AppsV1().Deployments(ns).Get(ctx, depName, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ _, err = clientset.AppsV1().Deployments(ns).Get(ctx, dep2Name, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ })
+ })
+ Context("with unstructured objects", func() {
+ It("should delete an existing object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("deleting the Deployment")
+ depName := dep.Name
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+ err = cl.Delete(context.TODO(), u)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating the Deployment no longer exists")
+ _, err = clientset.AppsV1().Deployments(ns).Get(ctx, depName, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should delete an existing object non-namespace object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Node")
+ node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("deleting the Node")
+ nodeName := node.Name
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(node, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Kind: "Node",
+ Version: "v1",
+ })
+ err = cl.Delete(context.TODO(), u)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating the Node no longer exists")
+ _, err = clientset.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should fail if the object does not exist", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Deleting node before it is ever created")
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(node, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Kind: "Node",
+ Version: "v1",
+ })
+ err = cl.Delete(context.TODO(), node)
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should delete a collection of object", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating two Deployments")
+
+ dep2 := dep.DeepCopy()
+ dep2.Name += "-2"
+
+ dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ dep2, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep2, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ depName := dep.Name
+ dep2Name := dep2.Name
+
+ By("deleting Deployments")
+ u := &unstructured.Unstructured{}
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+ err = cl.DeleteAllOf(context.TODO(), u, client.InNamespace(ns), client.MatchingLabels(dep.ObjectMeta.Labels))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating the Deployment no longer exists")
+ _, err = clientset.AppsV1().Deployments(ns).Get(ctx, depName, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ _, err = clientset.AppsV1().Deployments(ns).Get(ctx, dep2Name, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ })
+ })
+ Context("with metadata objects", func() {
+ It("should delete an existing object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("deleting the Deployment")
+ metaObj := metaOnlyFromObj(dep, scheme)
+ err = cl.Delete(context.TODO(), metaObj)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating the Deployment no longer exists")
+ _, err = clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should delete an existing object non-namespace object from a go struct", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating a Node")
+ node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("deleting the Node")
+ metaObj := metaOnlyFromObj(node, scheme)
+ err = cl.Delete(context.TODO(), metaObj)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating the Node no longer exists")
+ _, err = clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should fail if the object does not exist", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("Deleting node before it is ever created")
+ metaObj := metaOnlyFromObj(node, scheme)
+ err = cl.Delete(context.TODO(), metaObj)
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should delete a collection of object", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("initially creating two Deployments")
+
+ dep2 := dep.DeepCopy()
+ dep2.Name += "-2"
+
+ dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ dep2, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep2, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ depName := dep.Name
+ dep2Name := dep2.Name
+
+ By("deleting Deployments")
+ metaObj := metaOnlyFromObj(dep, scheme)
+ err = cl.DeleteAllOf(context.TODO(), metaObj, client.InNamespace(ns), client.MatchingLabels(dep.ObjectMeta.Labels))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating the Deployment no longer exists")
+ _, err = clientset.AppsV1().Deployments(ns).Get(ctx, depName, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ _, err = clientset.AppsV1().Deployments(ns).Get(ctx, dep2Name, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ })
+ })
+ })
+
+ Describe("Get", func() {
+ Context("with structured objects", func() {
+ It("should fetch an existing object for a go struct", func() {
+ By("first creating the Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("fetching the created Deployment")
+ var actual appsv1.Deployment
+ key := client.ObjectKey{Namespace: ns, Name: dep.Name}
+ err = cl.Get(context.TODO(), key, &actual)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+
+ By("validating the fetched deployment equals the created one")
+ Expect(dep).To(Equal(&actual))
+ })
+
+ It("should fetch an existing non-namespace object for a go struct", func() {
+ By("first creating the object")
+ node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("retrieving node through client")
+ var actual corev1.Node
+ key := client.ObjectKey{Namespace: ns, Name: node.Name}
+ err = cl.Get(context.TODO(), key, &actual)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+
+ Expect(node).To(Equal(&actual))
+ })
+
+ It("should fail if the object does not exist", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("fetching object that has not been created yet")
+ key := client.ObjectKey{Namespace: ns, Name: dep.Name}
+ var actual appsv1.Deployment
+ err = cl.Get(context.TODO(), key, &actual)
+ Expect(err).To(HaveOccurred())
+ })
+
+ PIt("should fail if the object doesn't have meta", func() {
+
+ })
+
+ It("should fail if the object cannot be mapped to a GVK", func() {
+ By("first creating the Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a client with an empty Scheme")
+ emptyScheme := runtime.NewScheme()
+ cl, err := client.New(cfg, client.Options{Scheme: emptyScheme})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("fetching the created Deployment fails")
+ var actual appsv1.Deployment
+ key := client.ObjectKey{Namespace: ns, Name: dep.Name}
+ err = cl.Get(context.TODO(), key, &actual)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("no kind is registered for the type"))
+ })
+
+ PIt("should fail if the GVK cannot be mapped to a Resource", func() {
+
+ })
+
+ // Test this with an integrated type and a CRD to make sure it covers both proto
+ // and json deserialization.
+ for idx, object := range []client.Object{&corev1.ConfigMap{}, &pkg.ChaosPod{}} {
+ idx, object := idx, object
+ It(fmt.Sprintf("should not retain any data in the obj variable that is not on the server for %T", object), func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ object.SetName(fmt.Sprintf("retain-test-%d", idx))
+ object.SetNamespace(ns)
+
+ By("First creating the object")
+ toCreate := object.DeepCopyObject().(client.Object)
+ Expect(cl.Create(ctx, toCreate)).NotTo(HaveOccurred())
+
+ By("Fetching it into a variable that has finalizers set")
+ toGetInto := object.DeepCopyObject().(client.Object)
+ toGetInto.SetFinalizers([]string{"some-finalizer"})
+ Expect(cl.Get(ctx, client.ObjectKeyFromObject(object), toGetInto)).NotTo(HaveOccurred())
+
+ By("Ensuring the created and the received object are equal")
+ Expect(toCreate).Should(Equal(toGetInto))
+ })
+ }
+
+ })
+
+ Context("with unstructured objects", func() {
+ It("should fetch an existing object", func() {
+ By("first creating the Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("encoding the Deployment as unstructured")
+ var u runtime.Unstructured = &unstructured.Unstructured{}
+ Expect(scheme.Convert(dep, u, nil)).To(Succeed())
+
+ By("fetching the created Deployment")
+ var actual unstructured.Unstructured
+ actual.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+ key := client.ObjectKey{Namespace: ns, Name: dep.Name}
+ err = cl.Get(context.TODO(), key, &actual)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+
+ By("validating the fetched Deployment equals the created one")
+ Expect(u).To(Equal(&actual))
+ })
+
+ It("should fetch an existing non-namespace object", func() {
+ By("first creating the Node")
+ node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("encoding the Node as unstructured")
+ var u runtime.Unstructured = &unstructured.Unstructured{}
+ Expect(scheme.Convert(node, u, nil)).To(Succeed())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("fetching the created Node")
+ var actual unstructured.Unstructured
+ actual.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "",
+ Kind: "Node",
+ Version: "v1",
+ })
+ key := client.ObjectKey{Namespace: ns, Name: node.Name}
+ err = cl.Get(context.TODO(), key, &actual)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+
+ By("validating the fetched Node equals the created one")
+ Expect(u).To(Equal(&actual))
+ })
+
+ It("should fail if the object does not exist", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("fetching object that has not been created yet")
+ key := client.ObjectKey{Namespace: ns, Name: dep.Name}
+ u := &unstructured.Unstructured{}
+ err = cl.Get(context.TODO(), key, u)
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should not retain any data in the obj variable that is not on the server", func() {
+ object := &unstructured.Unstructured{}
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ object.SetName("retain-unstructured")
+ object.SetNamespace(ns)
+ object.SetAPIVersion("chaosapps.metamagical.io/v1")
+ object.SetKind("ChaosPod")
+
+ By("First creating the object")
+ toCreate := object.DeepCopyObject().(client.Object)
+ Expect(cl.Create(ctx, toCreate)).NotTo(HaveOccurred())
+
+ By("Fetching it into a variable that has finalizers set")
+ toGetInto := object.DeepCopyObject().(client.Object)
+ toGetInto.SetFinalizers([]string{"some-finalizer"})
+ Expect(cl.Get(ctx, client.ObjectKeyFromObject(object), toGetInto)).NotTo(HaveOccurred())
+
+ By("Ensuring the created and the received object are equal")
+ Expect(toCreate).Should(Equal(toGetInto))
+ })
+ })
+ Context("with metadata objects", func() {
+ It("should fetch an existing object for a go struct", func() {
+ By("first creating the Deployment")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("fetching the created Deployment")
+ var actual metav1.PartialObjectMetadata
+ gvk := schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "Deployment",
+ }
+ actual.SetGroupVersionKind(gvk)
+ key := client.ObjectKey{Namespace: ns, Name: dep.Name}
+ err = cl.Get(context.TODO(), key, &actual)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+
+ By("validating that the GVK has been preserved")
+ Expect(actual.GroupVersionKind()).To(Equal(gvk))
+
+ By("validating the fetched deployment equals the created one")
+ Expect(metaOnlyFromObj(dep, scheme)).To(Equal(&actual))
+ })
+
+ It("should fetch an existing non-namespace object for a go struct", func() {
+ By("first creating the object")
+ node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("retrieving node through client")
+ var actual metav1.PartialObjectMetadata
+ actual.SetGroupVersionKind(schema.GroupVersionKind{
+ Version: "v1",
+ Kind: "Node",
+ })
+ key := client.ObjectKey{Namespace: ns, Name: node.Name}
+ err = cl.Get(context.TODO(), key, &actual)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+
+ Expect(metaOnlyFromObj(node, scheme)).To(Equal(&actual))
+ })
+
+ It("should fail if the object does not exist", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("fetching object that has not been created yet")
+ key := client.ObjectKey{Namespace: ns, Name: dep.Name}
+ var actual metav1.PartialObjectMetadata
+ actual.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "Deployment",
+ })
+ err = cl.Get(context.TODO(), key, &actual)
+ Expect(err).To(HaveOccurred())
+ })
+
+ PIt("should fail if the object doesn't have meta", func() {
+
+ })
+
+ PIt("should fail if the GVK cannot be mapped to a Resource", func() {
+
+ })
+
+ It("should not retain any data in the obj variable that is not on the server", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ By("First creating the object")
+ toCreate := &pkg.ChaosPod{ObjectMeta: metav1.ObjectMeta{Name: "retain-metadata", Namespace: ns}}
+ Expect(cl.Create(ctx, toCreate)).NotTo(HaveOccurred())
+
+ By("Fetching it into a variable that has finalizers set")
+ toGetInto := &metav1.PartialObjectMetadata{
+ TypeMeta: metav1.TypeMeta{APIVersion: "chaosapps.metamagical.io/v1", Kind: "ChaosPod"},
+ ObjectMeta: metav1.ObjectMeta{Namespace: ns, Name: "retain-metadata"},
+ }
+ toGetInto.SetFinalizers([]string{"some-finalizer"})
+ Expect(cl.Get(ctx, client.ObjectKeyFromObject(toGetInto), toGetInto)).NotTo(HaveOccurred())
+
+ By("Ensuring the created and the received objects metadata are equal")
+ Expect(toCreate.ObjectMeta).Should(Equal(toGetInto.ObjectMeta))
+ })
+ })
+ })
+
+ Describe("List", func() {
+ Context("with structured objects", func() {
+ It("should fetch collection of objects", func() {
+ By("creating an initial object")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all objects of that type in the cluster")
+ deps := &appsv1.DeploymentList{}
+ Expect(cl.List(context.Background(), deps)).NotTo(HaveOccurred())
+
+ Expect(deps.Items).NotTo(BeEmpty())
+ hasDep := false
+ for _, item := range deps.Items {
+ if item.Name == dep.Name && item.Namespace == dep.Namespace {
+ hasDep = true
+ break
+ }
+ }
+ Expect(hasDep).To(BeTrue())
+ })
+
+ It("should fetch unstructured collection of objects", func() {
+ By("create an initial object")
+ _, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all objects of that type in the cluster")
+ deps := &unstructured.UnstructuredList{}
+ deps.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "DeploymentList",
+ Version: "v1",
+ })
+ err = cl.List(context.Background(), deps)
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(deps.Items).NotTo(BeEmpty())
+ hasDep := false
+ for _, item := range deps.Items {
+ Expect(item.GroupVersionKind()).To(Equal(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ }))
+ if item.GetName() == dep.Name && item.GetNamespace() == dep.Namespace {
+ hasDep = true
+ break
+ }
+ }
+ Expect(hasDep).To(BeTrue())
+ })
+
+ It("should fetch unstructured collection of objects, even if scheme is empty", func() {
+ By("create an initial object")
+ _, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{Scheme: runtime.NewScheme()})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all objects of that type in the cluster")
+ deps := &unstructured.UnstructuredList{}
+ deps.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "DeploymentList",
+ Version: "v1",
+ })
+ err = cl.List(context.Background(), deps)
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(deps.Items).NotTo(BeEmpty())
+ hasDep := false
+ for _, item := range deps.Items {
+ if item.GetName() == dep.Name && item.GetNamespace() == dep.Namespace {
+ hasDep = true
+ break
+ }
+ }
+ Expect(hasDep).To(BeTrue())
+ })
+
+ It("should return an empty list if there are no matching objects", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments in the cluster")
+ deps := &appsv1.DeploymentList{}
+ Expect(cl.List(context.Background(), deps)).NotTo(HaveOccurred())
+
+ By("validating no Deployments are returned")
+ Expect(deps.Items).To(BeEmpty())
+ })
+
+ // TODO(seans): get label selector test working
+ It("should filter results by label selector", func() {
+ By("creating a Deployment with the app=frontend label")
+ depFrontend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-frontend",
+ Namespace: ns,
+ Labels: map[string]string{"app": "frontend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend, err := clientset.AppsV1().Deployments(ns).Create(ctx, depFrontend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment with the app=backend label")
+ depBackend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-backend",
+ Namespace: ns,
+ Labels: map[string]string{"app": "backend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "backend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depBackend, err = clientset.AppsV1().Deployments(ns).Create(ctx, depBackend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments with label app=backend")
+ deps := &appsv1.DeploymentList{}
+ labels := map[string]string{"app": "backend"}
+ err = cl.List(context.Background(), deps, client.MatchingLabels(labels))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("only the Deployment with the backend label is returned")
+ Expect(deps.Items).NotTo(BeEmpty())
+ Expect(1).To(Equal(len(deps.Items)))
+ actual := deps.Items[0]
+ Expect(actual.Name).To(Equal("deployment-backend"))
+
+ deleteDeployment(ctx, depFrontend, ns)
+ deleteDeployment(ctx, depBackend, ns)
+ })
+
+ It("should filter results by namespace selector", func() {
+ By("creating a Deployment in test-namespace-1")
+ tns1 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-1"}}
+ _, err := clientset.CoreV1().Namespaces().Create(ctx, tns1, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ depFrontend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: "test-namespace-1"},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend, err = clientset.AppsV1().Deployments("test-namespace-1").Create(ctx, depFrontend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment in test-namespace-2")
+ tns2 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-2"}}
+ _, err = clientset.CoreV1().Namespaces().Create(ctx, tns2, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ depBackend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: "test-namespace-2"},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "backend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depBackend, err = clientset.AppsV1().Deployments("test-namespace-2").Create(ctx, depBackend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments in test-namespace-1")
+ deps := &appsv1.DeploymentList{}
+ err = cl.List(context.Background(), deps, client.InNamespace("test-namespace-1"))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("only the Deployment in test-namespace-1 is returned")
+ Expect(deps.Items).NotTo(BeEmpty())
+ Expect(1).To(Equal(len(deps.Items)))
+ actual := deps.Items[0]
+ Expect(actual.Name).To(Equal("deployment-frontend"))
+
+ deleteDeployment(ctx, depFrontend, "test-namespace-1")
+ deleteDeployment(ctx, depBackend, "test-namespace-2")
+ deleteNamespace(ctx, tns1)
+ deleteNamespace(ctx, tns2)
+ })
+
+ It("should filter results by field selector", func() {
+ By("creating a Deployment with name deployment-frontend")
+ depFrontend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: ns},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend, err := clientset.AppsV1().Deployments(ns).Create(ctx, depFrontend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment with name deployment-backend")
+ depBackend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: ns},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "backend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depBackend, err = clientset.AppsV1().Deployments(ns).Create(ctx, depBackend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments with field metadata.name=deployment-backend")
+ deps := &appsv1.DeploymentList{}
+ err = cl.List(context.Background(), deps,
+ client.MatchingFields{"metadata.name": "deployment-backend"})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("only the Deployment with the backend field is returned")
+ Expect(deps.Items).NotTo(BeEmpty())
+ Expect(1).To(Equal(len(deps.Items)))
+ actual := deps.Items[0]
+ Expect(actual.Name).To(Equal("deployment-backend"))
+
+ deleteDeployment(ctx, depFrontend, ns)
+ deleteDeployment(ctx, depBackend, ns)
+ })
+
+ It("should filter results by namespace selector and label selector", func() {
+ By("creating a Deployment in test-namespace-3 with the app=frontend label")
+ tns3 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-3"}}
+ _, err := clientset.CoreV1().Namespaces().Create(ctx, tns3, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ depFrontend3 := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-frontend",
+ Namespace: "test-namespace-3",
+ Labels: map[string]string{"app": "frontend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend3, err = clientset.AppsV1().Deployments("test-namespace-3").Create(ctx, depFrontend3, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment in test-namespace-3 with the app=backend label")
+ depBackend3 := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-backend",
+ Namespace: "test-namespace-3",
+ Labels: map[string]string{"app": "backend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "backend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depBackend3, err = clientset.AppsV1().Deployments("test-namespace-3").Create(ctx, depBackend3, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment in test-namespace-4 with the app=frontend label")
+ tns4 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-4"}}
+ _, err = clientset.CoreV1().Namespaces().Create(ctx, tns4, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ depFrontend4 := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-frontend",
+ Namespace: "test-namespace-4",
+ Labels: map[string]string{"app": "frontend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend4, err = clientset.AppsV1().Deployments("test-namespace-4").Create(ctx, depFrontend4, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments in test-namespace-3 with label app=frontend")
+ deps := &appsv1.DeploymentList{}
+ labels := map[string]string{"app": "frontend"}
+ err = cl.List(context.Background(), deps,
+ client.InNamespace("test-namespace-3"),
+ client.MatchingLabels(labels),
+ )
+ Expect(err).NotTo(HaveOccurred())
+
+ By("only the Deployment in test-namespace-3 with label app=frontend is returned")
+ Expect(deps.Items).NotTo(BeEmpty())
+ Expect(1).To(Equal(len(deps.Items)))
+ actual := deps.Items[0]
+ Expect(actual.Name).To(Equal("deployment-frontend"))
+ Expect(actual.Namespace).To(Equal("test-namespace-3"))
+
+ deleteDeployment(ctx, depFrontend3, "test-namespace-3")
+ deleteDeployment(ctx, depBackend3, "test-namespace-3")
+ deleteDeployment(ctx, depFrontend4, "test-namespace-4")
+ deleteNamespace(ctx, tns3)
+ deleteNamespace(ctx, tns4)
+ })
+
+ It("should filter results using limit and continue options", func() {
+
+ makeDeployment := func(suffix string) *appsv1.Deployment {
+ return &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: fmt.Sprintf("deployment-%s", suffix),
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ }
+
+ By("creating 4 deployments")
+ dep1 := makeDeployment("1")
+ dep1, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep1, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ defer deleteDeployment(ctx, dep1, ns)
+
+ dep2 := makeDeployment("2")
+ dep2, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep2, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ defer deleteDeployment(ctx, dep2, ns)
+
+ dep3 := makeDeployment("3")
+ dep3, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep3, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ defer deleteDeployment(ctx, dep3, ns)
+
+ dep4 := makeDeployment("4")
+ dep4, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep4, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ defer deleteDeployment(ctx, dep4, ns)
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing 1 deployment when limit=1 is used")
+ deps := &appsv1.DeploymentList{}
+ err = cl.List(context.Background(), deps,
+ client.Limit(1),
+ )
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(deps.Items).To(HaveLen(1))
+ Expect(deps.Continue).NotTo(BeEmpty())
+ Expect(deps.Items[0].Name).To(Equal(dep1.Name))
+
+ continueToken := deps.Continue
+
+ By("listing the next deployment when previous continuation token is used and limit=1")
+ deps = &appsv1.DeploymentList{}
+ err = cl.List(context.Background(), deps,
+ client.Limit(1),
+ client.Continue(continueToken),
+ )
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(deps.Items).To(HaveLen(1))
+ Expect(deps.Continue).NotTo(BeEmpty())
+ Expect(deps.Items[0].Name).To(Equal(dep2.Name))
+
+ continueToken = deps.Continue
+
+ By("listing the 2 remaining deployments when previous continuation token is used without a limit")
+ deps = &appsv1.DeploymentList{}
+ err = cl.List(context.Background(), deps,
+ client.Continue(continueToken),
+ )
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(deps.Items).To(HaveLen(2))
+ Expect(deps.Continue).To(BeEmpty())
+ Expect(deps.Items[0].Name).To(Equal(dep3.Name))
+ Expect(deps.Items[1].Name).To(Equal(dep4.Name))
+ })
+
+ PIt("should fail if the object doesn't have meta", func() {
+
+ })
+
+ PIt("should fail if the object cannot be mapped to a GVK", func() {
+
+ })
+
+ PIt("should fail if the GVK cannot be mapped to a Resource", func() {
+
+ })
+ })
+
+ Context("with unstructured objects", func() {
+ It("should fetch collection of objects", func() {
+ By("create an initial object")
+ _, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all objects of that type in the cluster")
+ deps := &unstructured.UnstructuredList{}
+ deps.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "DeploymentList",
+ Version: "v1",
+ })
+ err = cl.List(context.Background(), deps)
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(deps.Items).NotTo(BeEmpty())
+ hasDep := false
+ for _, item := range deps.Items {
+ if item.GetName() == dep.Name && item.GetNamespace() == dep.Namespace {
+ hasDep = true
+ break
+ }
+ }
+ Expect(hasDep).To(BeTrue())
+ })
+
+ It("should return an empty list if there are no matching objects", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments in the cluster")
+ deps := &unstructured.UnstructuredList{}
+ deps.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "DeploymentList",
+ Version: "v1",
+ })
+ Expect(cl.List(context.Background(), deps)).NotTo(HaveOccurred())
+
+ By("validating no Deployments are returned")
+ Expect(deps.Items).To(BeEmpty())
+ })
+
+ It("should filter results by namespace selector", func() {
+ By("creating a Deployment in test-namespace-5")
+ tns1 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-5"}}
+ _, err := clientset.CoreV1().Namespaces().Create(ctx, tns1, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ depFrontend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: "test-namespace-5"},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend, err = clientset.AppsV1().Deployments("test-namespace-5").Create(ctx, depFrontend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment in test-namespace-6")
+ tns2 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-6"}}
+ _, err = clientset.CoreV1().Namespaces().Create(ctx, tns2, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ depBackend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: "test-namespace-6"},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "backend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depBackend, err = clientset.AppsV1().Deployments("test-namespace-6").Create(ctx, depBackend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments in test-namespace-5")
+ deps := &unstructured.UnstructuredList{}
+ deps.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "DeploymentList",
+ Version: "v1",
+ })
+ err = cl.List(context.Background(), deps, client.InNamespace("test-namespace-5"))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("only the Deployment in test-namespace-5 is returned")
+ Expect(deps.Items).NotTo(BeEmpty())
+ Expect(1).To(Equal(len(deps.Items)))
+ actual := deps.Items[0]
+ Expect(actual.GetName()).To(Equal("deployment-frontend"))
+
+ deleteDeployment(ctx, depFrontend, "test-namespace-5")
+ deleteDeployment(ctx, depBackend, "test-namespace-6")
+ deleteNamespace(ctx, tns1)
+ deleteNamespace(ctx, tns2)
+ })
+
+ It("should filter results by field selector", func() {
+ By("creating a Deployment with name deployment-frontend")
+ depFrontend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: ns},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend, err := clientset.AppsV1().Deployments(ns).Create(ctx, depFrontend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment with name deployment-backend")
+ depBackend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: ns},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "backend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depBackend, err = clientset.AppsV1().Deployments(ns).Create(ctx, depBackend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments with field metadata.name=deployment-backend")
+ deps := &unstructured.UnstructuredList{}
+ deps.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "DeploymentList",
+ Version: "v1",
+ })
+ err = cl.List(context.Background(), deps,
+ client.MatchingFields{"metadata.name": "deployment-backend"})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("only the Deployment with the backend field is returned")
+ Expect(deps.Items).NotTo(BeEmpty())
+ Expect(1).To(Equal(len(deps.Items)))
+ actual := deps.Items[0]
+ Expect(actual.GetName()).To(Equal("deployment-backend"))
+
+ deleteDeployment(ctx, depFrontend, ns)
+ deleteDeployment(ctx, depBackend, ns)
+ })
+
+ It("should filter results by namespace selector and label selector", func() {
+ By("creating a Deployment in test-namespace-7 with the app=frontend label")
+ tns3 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-7"}}
+ _, err := clientset.CoreV1().Namespaces().Create(ctx, tns3, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ depFrontend3 := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-frontend",
+ Namespace: "test-namespace-7",
+ Labels: map[string]string{"app": "frontend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend3, err = clientset.AppsV1().Deployments("test-namespace-7").Create(ctx, depFrontend3, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment in test-namespace-7 with the app=backend label")
+ depBackend3 := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-backend",
+ Namespace: "test-namespace-7",
+ Labels: map[string]string{"app": "backend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "backend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depBackend3, err = clientset.AppsV1().Deployments("test-namespace-7").Create(ctx, depBackend3, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment in test-namespace-8 with the app=frontend label")
+ tns4 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-8"}}
+ _, err = clientset.CoreV1().Namespaces().Create(ctx, tns4, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ depFrontend4 := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-frontend",
+ Namespace: "test-namespace-8",
+ Labels: map[string]string{"app": "frontend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend4, err = clientset.AppsV1().Deployments("test-namespace-8").Create(ctx, depFrontend4, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments in test-namespace-8 with label app=frontend")
+ deps := &unstructured.UnstructuredList{}
+ deps.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "DeploymentList",
+ Version: "v1",
+ })
+ labels := map[string]string{"app": "frontend"}
+ err = cl.List(context.Background(), deps,
+ client.InNamespace("test-namespace-7"), client.MatchingLabels(labels))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("only the Deployment in test-namespace-7 with label app=frontend is returned")
+ Expect(deps.Items).NotTo(BeEmpty())
+ Expect(1).To(Equal(len(deps.Items)))
+ actual := deps.Items[0]
+ Expect(actual.GetName()).To(Equal("deployment-frontend"))
+ Expect(actual.GetNamespace()).To(Equal("test-namespace-7"))
+
+ deleteDeployment(ctx, depFrontend3, "test-namespace-7")
+ deleteDeployment(ctx, depBackend3, "test-namespace-7")
+ deleteDeployment(ctx, depFrontend4, "test-namespace-8")
+ deleteNamespace(ctx, tns3)
+ deleteNamespace(ctx, tns4)
+ })
+
+ PIt("should fail if the object doesn't have meta", func() {
+
+ })
+
+ PIt("should filter results by namespace selector", func() {
+
+ })
+ })
+ Context("with metadata objects", func() {
+ It("should fetch collection of objects", func() {
+ By("creating an initial object")
+ dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all objects of that type in the cluster")
+ gvk := schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "DeploymentList",
+ }
+ metaList := &metav1.PartialObjectMetadataList{}
+ metaList.SetGroupVersionKind(gvk)
+ Expect(cl.List(context.Background(), metaList)).NotTo(HaveOccurred())
+
+ By("validating that the list GVK has been preserved")
+ Expect(metaList.GroupVersionKind()).To(Equal(gvk))
+
+ By("validating that the list has the expected deployment")
+ Expect(metaList.Items).NotTo(BeEmpty())
+ hasDep := false
+ for _, item := range metaList.Items {
+ Expect(item.GroupVersionKind()).To(Equal(schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "Deployment",
+ }))
+
+ if item.Name == dep.Name && item.Namespace == dep.Namespace {
+ hasDep = true
+ break
+ }
+ }
+ Expect(hasDep).To(BeTrue())
+ })
+
+ It("should return an empty list if there are no matching objects", func() {
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments in the cluster")
+ metaList := &metav1.PartialObjectMetadataList{}
+ metaList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "DeploymentList",
+ })
+ Expect(cl.List(context.Background(), metaList)).NotTo(HaveOccurred())
+
+ By("validating no Deployments are returned")
+ Expect(metaList.Items).To(BeEmpty())
+ })
+
+ // TODO(seans): get label selector test working
+ It("should filter results by label selector", func() {
+ By("creating a Deployment with the app=frontend label")
+ depFrontend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-frontend",
+ Namespace: ns,
+ Labels: map[string]string{"app": "frontend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend, err := clientset.AppsV1().Deployments(ns).Create(ctx, depFrontend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment with the app=backend label")
+ depBackend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-backend",
+ Namespace: ns,
+ Labels: map[string]string{"app": "backend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "backend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depBackend, err = clientset.AppsV1().Deployments(ns).Create(ctx, depBackend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments with label app=backend")
+ metaList := &metav1.PartialObjectMetadataList{}
+ metaList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "DeploymentList",
+ })
+ labels := map[string]string{"app": "backend"}
+ err = cl.List(context.Background(), metaList, client.MatchingLabels(labels))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("only the Deployment with the backend label is returned")
+ Expect(metaList.Items).NotTo(BeEmpty())
+ Expect(1).To(Equal(len(metaList.Items)))
+ actual := metaList.Items[0]
+ Expect(actual.Name).To(Equal("deployment-backend"))
+
+ deleteDeployment(ctx, depFrontend, ns)
+ deleteDeployment(ctx, depBackend, ns)
+ })
+
+ It("should filter results by namespace selector", func() {
+ By("creating a Deployment in test-namespace-1")
+ tns1 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-1"}}
+ _, err := clientset.CoreV1().Namespaces().Create(ctx, tns1, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ depFrontend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: "test-namespace-1"},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend, err = clientset.AppsV1().Deployments("test-namespace-1").Create(ctx, depFrontend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment in test-namespace-2")
+ tns2 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-2"}}
+ _, err = clientset.CoreV1().Namespaces().Create(ctx, tns2, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ depBackend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: "test-namespace-2"},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "backend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depBackend, err = clientset.AppsV1().Deployments("test-namespace-2").Create(ctx, depBackend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments in test-namespace-1")
+ metaList := &metav1.PartialObjectMetadataList{}
+ metaList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "DeploymentList",
+ })
+ err = cl.List(context.Background(), metaList, client.InNamespace("test-namespace-1"))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("only the Deployment in test-namespace-1 is returned")
+ Expect(metaList.Items).NotTo(BeEmpty())
+ Expect(1).To(Equal(len(metaList.Items)))
+ actual := metaList.Items[0]
+ Expect(actual.Name).To(Equal("deployment-frontend"))
+
+ deleteDeployment(ctx, depFrontend, "test-namespace-1")
+ deleteDeployment(ctx, depBackend, "test-namespace-2")
+ deleteNamespace(ctx, tns1)
+ deleteNamespace(ctx, tns2)
+ })
+
+ It("should filter results by field selector", func() {
+ By("creating a Deployment with name deployment-frontend")
+ depFrontend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: ns},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend, err := clientset.AppsV1().Deployments(ns).Create(ctx, depFrontend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment with name deployment-backend")
+ depBackend := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: ns},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "backend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depBackend, err = clientset.AppsV1().Deployments(ns).Create(ctx, depBackend, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments with field metadata.name=deployment-backend")
+ metaList := &metav1.PartialObjectMetadataList{}
+ metaList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "DeploymentList",
+ })
+ err = cl.List(context.Background(), metaList,
+ client.MatchingFields{"metadata.name": "deployment-backend"})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("only the Deployment with the backend field is returned")
+ Expect(metaList.Items).NotTo(BeEmpty())
+ Expect(1).To(Equal(len(metaList.Items)))
+ actual := metaList.Items[0]
+ Expect(actual.Name).To(Equal("deployment-backend"))
+
+ deleteDeployment(ctx, depFrontend, ns)
+ deleteDeployment(ctx, depBackend, ns)
+ })
+
+ It("should filter results by namespace selector and label selector", func() {
+ By("creating a Deployment in test-namespace-3 with the app=frontend label")
+ tns3 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-3"}}
+ _, err := clientset.CoreV1().Namespaces().Create(ctx, tns3, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ depFrontend3 := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-frontend",
+ Namespace: "test-namespace-3",
+ Labels: map[string]string{"app": "frontend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend3, err = clientset.AppsV1().Deployments("test-namespace-3").Create(ctx, depFrontend3, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment in test-namespace-3 with the app=backend label")
+ depBackend3 := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-backend",
+ Namespace: "test-namespace-3",
+ Labels: map[string]string{"app": "backend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "backend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depBackend3, err = clientset.AppsV1().Deployments("test-namespace-3").Create(ctx, depBackend3, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("creating a Deployment in test-namespace-4 with the app=frontend label")
+ tns4 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-4"}}
+ _, err = clientset.CoreV1().Namespaces().Create(ctx, tns4, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ depFrontend4 := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-frontend",
+ Namespace: "test-namespace-4",
+ Labels: map[string]string{"app": "frontend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ depFrontend4, err = clientset.AppsV1().Deployments("test-namespace-4").Create(ctx, depFrontend4, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing all Deployments in test-namespace-3 with label app=frontend")
+ metaList := &metav1.PartialObjectMetadataList{}
+ metaList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "DeploymentList",
+ })
+ labels := map[string]string{"app": "frontend"}
+ err = cl.List(context.Background(), metaList,
+ client.InNamespace("test-namespace-3"),
+ client.MatchingLabels(labels),
+ )
+ Expect(err).NotTo(HaveOccurred())
+
+ By("only the Deployment in test-namespace-3 with label app=frontend is returned")
+ Expect(metaList.Items).NotTo(BeEmpty())
+ Expect(1).To(Equal(len(metaList.Items)))
+ actual := metaList.Items[0]
+ Expect(actual.Name).To(Equal("deployment-frontend"))
+ Expect(actual.Namespace).To(Equal("test-namespace-3"))
+
+ deleteDeployment(ctx, depFrontend3, "test-namespace-3")
+ deleteDeployment(ctx, depBackend3, "test-namespace-3")
+ deleteDeployment(ctx, depFrontend4, "test-namespace-4")
+ deleteNamespace(ctx, tns3)
+ deleteNamespace(ctx, tns4)
+ })
+
+ It("should filter results using limit and continue options", func() {
+
+ makeDeployment := func(suffix string) *appsv1.Deployment {
+ return &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: fmt.Sprintf("deployment-%s", suffix),
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ }
+
+ By("creating 4 deployments")
+ dep1 := makeDeployment("1")
+ dep1, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep1, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ defer deleteDeployment(ctx, dep1, ns)
+
+ dep2 := makeDeployment("2")
+ dep2, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep2, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ defer deleteDeployment(ctx, dep2, ns)
+
+ dep3 := makeDeployment("3")
+ dep3, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep3, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ defer deleteDeployment(ctx, dep3, ns)
+
+ dep4 := makeDeployment("4")
+ dep4, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep4, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ defer deleteDeployment(ctx, dep4, ns)
+
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("listing 1 deployment when limit=1 is used")
+ metaList := &metav1.PartialObjectMetadataList{}
+ metaList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "DeploymentList",
+ })
+ err = cl.List(context.Background(), metaList,
+ client.Limit(1),
+ )
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(metaList.Items).To(HaveLen(1))
+ Expect(metaList.Continue).NotTo(BeEmpty())
+ Expect(metaList.Items[0].Name).To(Equal(dep1.Name))
+
+ continueToken := metaList.Continue
+
+ By("listing the next deployment when previous continuation token is used and limit=1")
+ metaList = &metav1.PartialObjectMetadataList{}
+ metaList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "DeploymentList",
+ })
+ err = cl.List(context.Background(), metaList,
+ client.Limit(1),
+ client.Continue(continueToken),
+ )
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(metaList.Items).To(HaveLen(1))
+ Expect(metaList.Continue).NotTo(BeEmpty())
+ Expect(metaList.Items[0].Name).To(Equal(dep2.Name))
+
+ continueToken = metaList.Continue
+
+ By("listing the 2 remaining deployments when previous continuation token is used without a limit")
+ metaList = &metav1.PartialObjectMetadataList{}
+ metaList.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "DeploymentList",
+ })
+ err = cl.List(context.Background(), metaList,
+ client.Continue(continueToken),
+ )
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(metaList.Items).To(HaveLen(2))
+ Expect(metaList.Continue).To(BeEmpty())
+ Expect(metaList.Items[0].Name).To(Equal(dep3.Name))
+ Expect(metaList.Items[1].Name).To(Equal(dep4.Name))
+ })
+
+ PIt("should fail if the object doesn't have meta", func() {
+
+ })
+
+ PIt("should fail if the object cannot be mapped to a GVK", func() {
+
+ })
+
+ PIt("should fail if the GVK cannot be mapped to a Resource", func() {
+
+ })
+ })
+ })
+
+ Describe("CreateOptions", func() {
+ It("should allow setting DryRun to 'all'", func() {
+ co := &client.CreateOptions{}
+ client.DryRunAll.ApplyToCreate(co)
+ all := []string{metav1.DryRunAll}
+ Expect(co.AsCreateOptions().DryRun).To(Equal(all))
+ })
+
+ It("should allow setting the field manager", func() {
+ po := &client.CreateOptions{}
+ client.FieldOwner("some-owner").ApplyToCreate(po)
+ Expect(po.AsCreateOptions().FieldManager).To(Equal("some-owner"))
+ })
+
+ It("should produce empty metav1.CreateOptions if nil", func() {
+ var co *client.CreateOptions
+ Expect(co.AsCreateOptions()).To(Equal(&metav1.CreateOptions{}))
+ co = &client.CreateOptions{}
+ Expect(co.AsCreateOptions()).To(Equal(&metav1.CreateOptions{}))
+ })
+ })
+
+ Describe("DeleteOptions", func() {
+ It("should allow setting GracePeriodSeconds", func() {
+ do := &client.DeleteOptions{}
+ client.GracePeriodSeconds(1).ApplyToDelete(do)
+ gp := int64(1)
+ Expect(do.AsDeleteOptions().GracePeriodSeconds).To(Equal(&gp))
+ })
+
+ It("should allow setting Precondition", func() {
+ do := &client.DeleteOptions{}
+ pc := metav1.NewUIDPreconditions("uid")
+ client.Preconditions(*pc).ApplyToDelete(do)
+ Expect(do.AsDeleteOptions().Preconditions).To(Equal(pc))
+ Expect(do.Preconditions).To(Equal(pc))
+ })
+
+ It("should allow setting PropagationPolicy", func() {
+ do := &client.DeleteOptions{}
+ client.PropagationPolicy(metav1.DeletePropagationForeground).ApplyToDelete(do)
+ dp := metav1.DeletePropagationForeground
+ Expect(do.AsDeleteOptions().PropagationPolicy).To(Equal(&dp))
+ })
+
+ It("should allow setting DryRun", func() {
+ do := &client.DeleteOptions{}
+ client.DryRunAll.ApplyToDelete(do)
+ all := []string{metav1.DryRunAll}
+ Expect(do.AsDeleteOptions().DryRun).To(Equal(all))
+ })
+
+ It("should produce empty metav1.DeleteOptions if nil", func() {
+ var do *client.DeleteOptions
+ Expect(do.AsDeleteOptions()).To(Equal(&metav1.DeleteOptions{}))
+ do = &client.DeleteOptions{}
+ Expect(do.AsDeleteOptions()).To(Equal(&metav1.DeleteOptions{}))
+ })
+
+ It("should merge multiple options together", func() {
+ gp := int64(1)
+ pc := metav1.NewUIDPreconditions("uid")
+ dp := metav1.DeletePropagationForeground
+ do := &client.DeleteOptions{}
+ do.ApplyOptions([]client.DeleteOption{
+ client.GracePeriodSeconds(gp),
+ client.Preconditions(*pc),
+ client.PropagationPolicy(dp),
+ })
+ Expect(do.GracePeriodSeconds).To(Equal(&gp))
+ Expect(do.Preconditions).To(Equal(pc))
+ Expect(do.PropagationPolicy).To(Equal(&dp))
+ })
+ })
+
+ Describe("DeleteCollectionOptions", func() {
+ It("should be convertable to list options", func() {
+ gp := int64(1)
+ do := &client.DeleteAllOfOptions{}
+ do.ApplyOptions([]client.DeleteAllOfOption{
+ client.GracePeriodSeconds(gp),
+ client.MatchingLabels{"foo": "bar"},
+ })
+
+ listOpts := do.AsListOptions()
+ Expect(listOpts).NotTo(BeNil())
+ Expect(listOpts.LabelSelector).To(Equal("foo=bar"))
+ })
+
+ It("should be convertable to delete options", func() {
+ gp := int64(1)
+ do := &client.DeleteAllOfOptions{}
+ do.ApplyOptions([]client.DeleteAllOfOption{
+ client.GracePeriodSeconds(gp),
+ client.MatchingLabels{"foo": "bar"},
+ })
+
+ deleteOpts := do.AsDeleteOptions()
+ Expect(deleteOpts).NotTo(BeNil())
+ Expect(deleteOpts.GracePeriodSeconds).To(Equal(&gp))
+ })
+ })
+
+ Describe("GetOptions", func() {
+ It("should be convertable to metav1.GetOptions", func() {
+ o := (&client.GetOptions{}).ApplyOptions([]client.GetOption{
+ &client.GetOptions{Raw: &metav1.GetOptions{ResourceVersion: "RV0"}},
+ })
+ mo := o.AsGetOptions()
+ Expect(mo).NotTo(BeNil())
+ Expect(mo.ResourceVersion).To(Equal("RV0"))
+ })
+
+ It("should produce empty metav1.GetOptions if nil", func() {
+ var o *client.GetOptions
+ Expect(o.AsGetOptions()).To(Equal(&metav1.GetOptions{}))
+ o = &client.GetOptions{}
+ Expect(o.AsGetOptions()).To(Equal(&metav1.GetOptions{}))
+ })
+ })
+
+ Describe("ListOptions", func() {
+ It("should be convertable to metav1.ListOptions", func() {
+ lo := (&client.ListOptions{}).ApplyOptions([]client.ListOption{
+ client.MatchingFields{"field1": "bar"},
+ client.InNamespace("test-namespace"),
+ client.MatchingLabels{"foo": "bar"},
+ client.Limit(1),
+ client.Continue("foo"),
+ })
+ mlo := lo.AsListOptions()
+ Expect(mlo).NotTo(BeNil())
+ Expect(mlo.LabelSelector).To(Equal("foo=bar"))
+ Expect(mlo.FieldSelector).To(Equal("field1=bar"))
+ Expect(mlo.Limit).To(Equal(int64(1)))
+ Expect(mlo.Continue).To(Equal("foo"))
+ })
+
+ It("should be populated by MatchingLabels", func() {
+ lo := &client.ListOptions{}
+ client.MatchingLabels{"foo": "bar"}.ApplyToList(lo)
+ Expect(lo).NotTo(BeNil())
+ Expect(lo.LabelSelector.String()).To(Equal("foo=bar"))
+ })
+
+ It("should be populated by MatchingField", func() {
+ lo := &client.ListOptions{}
+ client.MatchingFields{"field1": "bar"}.ApplyToList(lo)
+ Expect(lo).NotTo(BeNil())
+ Expect(lo.FieldSelector.String()).To(Equal("field1=bar"))
+ })
+
+ It("should be populated by InNamespace", func() {
+ lo := &client.ListOptions{}
+ client.InNamespace("test").ApplyToList(lo)
+ Expect(lo).NotTo(BeNil())
+ Expect(lo.Namespace).To(Equal("test"))
+ })
+
+ It("should produce empty metav1.ListOptions if nil", func() {
+ var do *client.ListOptions
+ Expect(do.AsListOptions()).To(Equal(&metav1.ListOptions{}))
+ do = &client.ListOptions{}
+ Expect(do.AsListOptions()).To(Equal(&metav1.ListOptions{}))
+ })
+
+ It("should be populated by Limit", func() {
+ lo := &client.ListOptions{}
+ client.Limit(1).ApplyToList(lo)
+ Expect(lo).NotTo(BeNil())
+ Expect(lo.Limit).To(Equal(int64(1)))
+ })
+
+ It("should ignore Limit when converted to metav1.ListOptions and watch is true", func() {
+ lo := &client.ListOptions{
+ Raw: &metav1.ListOptions{Watch: true},
+ }
+ lo.ApplyOptions([]client.ListOption{
+ client.Limit(1),
+ })
+ mlo := lo.AsListOptions()
+ Expect(mlo).NotTo(BeNil())
+ Expect(mlo.Limit).To(BeZero())
+ })
+
+ It("should be populated by Continue", func() {
+ lo := &client.ListOptions{}
+ client.Continue("foo").ApplyToList(lo)
+ Expect(lo).NotTo(BeNil())
+ Expect(lo.Continue).To(Equal("foo"))
+ })
+
+ It("should ignore Continue token when converted to metav1.ListOptions and watch is true", func() {
+ lo := &client.ListOptions{
+ Raw: &metav1.ListOptions{Watch: true},
+ }
+ lo.ApplyOptions([]client.ListOption{
+ client.Continue("foo"),
+ })
+ mlo := lo.AsListOptions()
+ Expect(mlo).NotTo(BeNil())
+ Expect(mlo.Continue).To(BeEmpty())
+ })
+
+ It("should ignore both Limit and Continue token when converted to metav1.ListOptions and watch is true", func() {
+ lo := &client.ListOptions{
+ Raw: &metav1.ListOptions{Watch: true},
+ }
+ lo.ApplyOptions([]client.ListOption{
+ client.Limit(1),
+ client.Continue("foo"),
+ })
+ mlo := lo.AsListOptions()
+ Expect(mlo).NotTo(BeNil())
+ Expect(mlo.Limit).To(BeZero())
+ Expect(mlo.Continue).To(BeEmpty())
+ })
+ })
+
+ Describe("UpdateOptions", func() {
+ It("should allow setting DryRun to 'all'", func() {
+ uo := &client.UpdateOptions{}
+ client.DryRunAll.ApplyToUpdate(uo)
+ all := []string{metav1.DryRunAll}
+ Expect(uo.AsUpdateOptions().DryRun).To(Equal(all))
+ })
+
+ It("should allow setting the field manager", func() {
+ po := &client.UpdateOptions{}
+ client.FieldOwner("some-owner").ApplyToUpdate(po)
+ Expect(po.AsUpdateOptions().FieldManager).To(Equal("some-owner"))
+ })
+
+ It("should produce empty metav1.UpdateOptions if nil", func() {
+ var co *client.UpdateOptions
+ Expect(co.AsUpdateOptions()).To(Equal(&metav1.UpdateOptions{}))
+ co = &client.UpdateOptions{}
+ Expect(co.AsUpdateOptions()).To(Equal(&metav1.UpdateOptions{}))
+ })
+ })
+
+ Describe("PatchOptions", func() {
+ It("should allow setting DryRun to 'all'", func() {
+ po := &client.PatchOptions{}
+ client.DryRunAll.ApplyToPatch(po)
+ all := []string{metav1.DryRunAll}
+ Expect(po.AsPatchOptions().DryRun).To(Equal(all))
+ })
+
+ It("should allow setting Force to 'true'", func() {
+ po := &client.PatchOptions{}
+ client.ForceOwnership.ApplyToPatch(po)
+ mpo := po.AsPatchOptions()
+ Expect(mpo.Force).NotTo(BeNil())
+ Expect(*mpo.Force).To(BeTrue())
+ })
+
+ It("should allow setting the field manager", func() {
+ po := &client.PatchOptions{}
+ client.FieldOwner("some-owner").ApplyToPatch(po)
+ Expect(po.AsPatchOptions().FieldManager).To(Equal("some-owner"))
+ })
+
+ It("should produce empty metav1.PatchOptions if nil", func() {
+ var po *client.PatchOptions
+ Expect(po.AsPatchOptions()).To(Equal(&metav1.PatchOptions{}))
+ po = &client.PatchOptions{}
+ Expect(po.AsPatchOptions()).To(Equal(&metav1.PatchOptions{}))
+ })
+ })
+})
+
+var _ = Describe("ClientWithCache", func() {
+ Describe("Get", func() {
+ It("should call cache reader when structured object", func() {
+ cachedReader := &fakeReader{}
+ cl, err := client.New(cfg, client.Options{
+ Cache: &client.CacheOptions{
+ Reader: cachedReader,
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ var actual appsv1.Deployment
+ key := client.ObjectKey{Namespace: "ns", Name: "name"}
+ Expect(cl.Get(context.TODO(), key, &actual)).To(Succeed())
+ Expect(1).To(Equal(cachedReader.Called))
+ })
+
+ When("getting unstructured objects", func() {
+ var dep *appsv1.Deployment
+
+ BeforeEach(func() {
+ dep = &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment1",
+ Labels: map[string]string{"app": "frontend"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"app": "frontend"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "x", Image: "x"}}},
+ },
+ },
+ }
+ var err error
+ dep, err = clientset.AppsV1().Deployments("default").Create(context.Background(), dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ })
+ AfterEach(func() {
+ Expect(clientset.AppsV1().Deployments("default").Delete(
+ context.Background(),
+ dep.Name,
+ metav1.DeleteOptions{},
+ )).To(Succeed())
+ })
+ It("should call client reader when not cached", func() {
+ cachedReader := &fakeReader{}
+ cl, err := client.New(cfg, client.Options{
+ Cache: &client.CacheOptions{
+ Reader: cachedReader,
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ actual := &unstructured.Unstructured{}
+ actual.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+ actual.SetName(dep.Name)
+ key := client.ObjectKey{Namespace: dep.Namespace, Name: dep.Name}
+ Expect(cl.Get(context.TODO(), key, actual)).To(Succeed())
+ Expect(0).To(Equal(cachedReader.Called))
+ })
+ It("should call cache reader when cached", func() {
+ cachedReader := &fakeReader{}
+ cl, err := client.New(cfg, client.Options{
+ Cache: &client.CacheOptions{
+ Reader: cachedReader,
+ Unstructured: true,
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ actual := &unstructured.Unstructured{}
+ actual.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+ actual.SetName(dep.Name)
+ key := client.ObjectKey{Namespace: dep.Namespace, Name: dep.Name}
+ Expect(cl.Get(context.TODO(), key, actual)).To(Succeed())
+ Expect(1).To(Equal(cachedReader.Called))
+ })
+ })
+ })
+ Describe("List", func() {
+ It("should call cache reader when structured object", func() {
+ cachedReader := &fakeReader{}
+ cl, err := client.New(cfg, client.Options{
+ Cache: &client.CacheOptions{
+ Reader: cachedReader,
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ var actual appsv1.DeploymentList
+ Expect(cl.List(context.Background(), &actual)).To(Succeed())
+ Expect(1).To(Equal(cachedReader.Called))
+ })
+
+ When("listing unstructured objects", func() {
+ It("should call client reader when not cached", func() {
+ cachedReader := &fakeReader{}
+ cl, err := client.New(cfg, client.Options{
+ Cache: &client.CacheOptions{
+ Reader: cachedReader,
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ actual := &unstructured.UnstructuredList{}
+ actual.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "DeploymentList",
+ Version: "v1",
+ })
+ Expect(cl.List(context.Background(), actual)).To(Succeed())
+ Expect(0).To(Equal(cachedReader.Called))
+ })
+ It("should call cache reader when cached", func() {
+ cachedReader := &fakeReader{}
+ cl, err := client.New(cfg, client.Options{
+ Cache: &client.CacheOptions{
+ Reader: cachedReader,
+ Unstructured: true,
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ actual := &unstructured.UnstructuredList{}
+ actual.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "DeploymentList",
+ Version: "v1",
+ })
+ Expect(cl.List(context.Background(), actual)).To(Succeed())
+ Expect(1).To(Equal(cachedReader.Called))
+ })
+ })
+ })
+})
+
+var _ = Describe("Patch", func() {
+ Describe("MergeFrom", func() {
+ var cm *corev1.ConfigMap
+
+ BeforeEach(func() {
+ cm = &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: metav1.NamespaceDefault,
+ Name: "cm",
+ ResourceVersion: "10",
+ },
+ }
+ })
+
+ It("creates a merge patch with the modifications applied during the mutation", func() {
+ const (
+ annotationKey = "test"
+ annotationValue = "foo"
+ )
+
+ By("creating a merge patch")
+ patch := client.MergeFrom(cm.DeepCopy())
+
+ By("returning a patch with type MergePatch")
+ Expect(patch.Type()).To(Equal(types.MergePatchType))
+
+ By("retrieving modifying the config map")
+ metav1.SetMetaDataAnnotation(&cm.ObjectMeta, annotationKey, annotationValue)
+
+ By("computing the patch data")
+ data, err := patch.Data(cm)
+
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning a patch with data only containing the annotation change")
+ Expect(data).To(Equal([]byte(fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, annotationKey, annotationValue))))
+ })
+
+ It("creates a merge patch with the modifications applied during the mutation, using optimistic locking", func() {
+ const (
+ annotationKey = "test"
+ annotationValue = "foo"
+ )
+
+ By("creating a merge patch")
+ patch := client.MergeFromWithOptions(cm.DeepCopy(), client.MergeFromWithOptimisticLock{})
+
+ By("returning a patch with type MergePatch")
+ Expect(patch.Type()).To(Equal(types.MergePatchType))
+
+ By("retrieving modifying the config map")
+ metav1.SetMetaDataAnnotation(&cm.ObjectMeta, annotationKey, annotationValue)
+
+ By("computing the patch data")
+ data, err := patch.Data(cm)
+
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning a patch with data containing the annotation change and the resourceVersion change")
+ Expect(data).To(Equal([]byte(fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"},"resourceVersion":"%s"}}`, annotationKey, annotationValue, cm.ResourceVersion))))
+ })
+ })
+
+ Describe("StrategicMergeFrom", func() {
+ var dep *appsv1.Deployment
+
+ BeforeEach(func() {
+ dep = &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: metav1.NamespaceDefault,
+ Name: "dep",
+ ResourceVersion: "10",
+ },
+ Spec: appsv1.DeploymentSpec{
+ Template: corev1.PodTemplateSpec{
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{
+ Name: "main",
+ Image: "foo:v1",
+ }, {
+ Name: "sidecar",
+ Image: "bar:v1",
+ }}},
+ },
+ },
+ }
+ })
+
+ It("creates a strategic merge patch with the modifications applied during the mutation", func() {
+ By("creating a strategic merge patch")
+ patch := client.StrategicMergeFrom(dep.DeepCopy())
+
+ By("returning a patch with type StrategicMergePatchType")
+ Expect(patch.Type()).To(Equal(types.StrategicMergePatchType))
+
+ By("updating the main container's image")
+ for i, c := range dep.Spec.Template.Spec.Containers {
+ if c.Name == "main" {
+ c.Image = "foo:v2"
+ }
+ dep.Spec.Template.Spec.Containers[i] = c
+ }
+
+ By("computing the patch data")
+ data, err := patch.Data(dep)
+
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning a patch with data only containing the image change")
+ Expect(data).To(Equal([]byte(`{"spec":{"template":{"spec":{"$setElementOrder/containers":[{"name":"main"},` +
+ `{"name":"sidecar"}],"containers":[{"image":"foo:v2","name":"main"}]}}}}`)))
+ })
+
+ It("creates a strategic merge patch with the modifications applied during the mutation, using optimistic locking", func() {
+ By("creating a strategic merge patch")
+ patch := client.StrategicMergeFrom(dep.DeepCopy(), client.MergeFromWithOptimisticLock{})
+
+ By("returning a patch with type StrategicMergePatchType")
+ Expect(patch.Type()).To(Equal(types.StrategicMergePatchType))
+
+ By("updating the main container's image")
+ for i, c := range dep.Spec.Template.Spec.Containers {
+ if c.Name == "main" {
+ c.Image = "foo:v2"
+ }
+ dep.Spec.Template.Spec.Containers[i] = c
+ }
+
+ By("computing the patch data")
+ data, err := patch.Data(dep)
+
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning a patch with data containing the image change and the resourceVersion change")
+ Expect(data).To(Equal([]byte(fmt.Sprintf(`{"metadata":{"resourceVersion":"%s"},`+
+ `"spec":{"template":{"spec":{"$setElementOrder/containers":[{"name":"main"},{"name":"sidecar"}],"containers":[{"image":"foo:v2","name":"main"}]}}}}`,
+ dep.ResourceVersion))))
+ })
+ })
+})
+
+var _ = Describe("IgnoreNotFound", func() {
+ It("should return nil on a 'NotFound' error", func() {
+ By("creating a NotFound error")
+ err := apierrors.NewNotFound(schema.GroupResource{}, "")
+
+ By("returning no error")
+ Expect(client.IgnoreNotFound(err)).To(Succeed())
+ })
+
+ It("should return the error on a status other than not found", func() {
+ By("creating a BadRequest error")
+ err := apierrors.NewBadRequest("")
+
+ By("returning an error")
+ Expect(client.IgnoreNotFound(err)).To(HaveOccurred())
+ })
+
+ It("should return the error on a non-status error", func() {
+ By("creating an fmt error")
+ err := fmt.Errorf("arbitrary error")
+
+ By("returning an error")
+ Expect(client.IgnoreNotFound(err)).To(HaveOccurred())
+ })
+})
+
+var _ = Describe("IgnoreAlreadyExists", func() {
+ It("should return nil on a 'AlreadyExists' error", func() {
+ By("creating a AlreadyExists error")
+ err := apierrors.NewAlreadyExists(schema.GroupResource{}, "")
+
+ By("returning no error")
+ Expect(client.IgnoreAlreadyExists(err)).To(Succeed())
+ })
+
+ It("should return the error on a status other than already exists", func() {
+ By("creating a BadRequest error")
+ err := apierrors.NewBadRequest("")
+
+ By("returning an error")
+ Expect(client.IgnoreAlreadyExists(err)).To(HaveOccurred())
+ })
+
+ It("should return the error on a non-status error", func() {
+ By("creating an fmt error")
+ err := fmt.Errorf("arbitrary error")
+
+ By("returning an error")
+ Expect(client.IgnoreAlreadyExists(err)).To(HaveOccurred())
+ })
+})
+
+type fakeReader struct {
+ Called int
+}
+
+func (f *fakeReader) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
+ f.Called++
+ return nil
+}
+
+func (f *fakeReader) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
+ f.Called++
+ return nil
+}
+
+func ptr[T any](to T) *T {
+ return &to
+}
+
+func toUnstructured(o client.Object) (*unstructured.Unstructured, error) {
+ serialized, err := json.Marshal(o)
+ if err != nil {
+ return nil, err
+ }
+ u := &unstructured.Unstructured{}
+ return u, json.Unmarshal(serialized, u)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/codec.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/codec.go
new file mode 100644
index 00000000000..9c2923106c9
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/codec.go
@@ -0,0 +1,40 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "errors"
+ "net/url"
+
+ "k8s.io/apimachinery/pkg/conversion/queryparams"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+var _ runtime.ParameterCodec = noConversionParamCodec{}
+
+// noConversionParamCodec is a no-conversion codec for serializing parameters into URL query strings.
+// it's useful in scenarios with the unstructured client and arbitrary resources.
+type noConversionParamCodec struct{}
+
+func (noConversionParamCodec) EncodeParameters(obj runtime.Object, to schema.GroupVersion) (url.Values, error) {
+ return queryparams.Convert(obj)
+}
+
+func (noConversionParamCodec) DecodeParameters(parameters url.Values, from schema.GroupVersion, into runtime.Object) error {
+ return errors.New("DecodeParameters not implemented on noConversionParamCodec")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/config/config.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
new file mode 100644
index 00000000000..5f0a6d4b1dd
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
@@ -0,0 +1,181 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "os/user"
+ "path/filepath"
+
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/clientcmd"
+ clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+// KubeconfigFlagName is the name of the kubeconfig flag
+const KubeconfigFlagName = "kubeconfig"
+
+var (
+ kubeconfig string
+ log = logf.RuntimeLog.WithName("client").WithName("config")
+)
+
+// init registers the "kubeconfig" flag to the default command line FlagSet.
+// TODO: This should be removed, as it potentially leads to redefined flag errors for users, if they already
+// have registered the "kubeconfig" flag to the command line FlagSet in other parts of their code.
+func init() {
+ RegisterFlags(flag.CommandLine)
+}
+
+// RegisterFlags registers flag variables to the given FlagSet if not already registered.
+// It uses the default command line FlagSet, if none is provided. Currently, it only registers the kubeconfig flag.
+func RegisterFlags(fs *flag.FlagSet) {
+ if fs == nil {
+ fs = flag.CommandLine
+ }
+ if f := fs.Lookup(KubeconfigFlagName); f != nil {
+ kubeconfig = f.Value.String()
+ } else {
+ fs.StringVar(&kubeconfig, KubeconfigFlagName, "", "Paths to a kubeconfig. Only required if out-of-cluster.")
+ }
+}
+
+// GetConfig creates a *rest.Config for talking to a Kubernetes API server.
+// If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running
+// in cluster and use the cluster provided kubeconfig.
+//
+// It also applies saner defaults for QPS and burst based on the Kubernetes
+// controller manager defaults (20 QPS, 30 burst)
+//
+// Config precedence:
+//
+// * --kubeconfig flag pointing at a file
+//
+// * KUBECONFIG environment variable pointing at a file
+//
+// * In-cluster config if running in cluster
+//
+// * $HOME/.kube/config if exists.
+func GetConfig() (*rest.Config, error) {
+ return GetConfigWithContext("")
+}
+
+// GetConfigWithContext creates a *rest.Config for talking to a Kubernetes API server with a specific context.
+// If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running
+// in cluster and use the cluster provided kubeconfig.
+//
+// It also applies saner defaults for QPS and burst based on the Kubernetes
+// controller manager defaults (20 QPS, 30 burst)
+//
+// Config precedence:
+//
+// * --kubeconfig flag pointing at a file
+//
+// * KUBECONFIG environment variable pointing at a file
+//
+// * In-cluster config if running in cluster
+//
+// * $HOME/.kube/config if exists.
+func GetConfigWithContext(context string) (*rest.Config, error) {
+ cfg, err := loadConfig(context)
+ if err != nil {
+ return nil, err
+ }
+ if cfg.QPS == 0.0 {
+ cfg.QPS = 20.0
+ }
+ if cfg.Burst == 0 {
+ cfg.Burst = 30
+ }
+ return cfg, nil
+}
+
+// loadInClusterConfig is a function used to load the in-cluster
+// Kubernetes client config. This variable makes is possible to
+// test the precedence of loading the config.
+var loadInClusterConfig = rest.InClusterConfig
+
+// loadConfig loads a REST Config as per the rules specified in GetConfig.
+func loadConfig(context string) (config *rest.Config, configErr error) {
+ // If a flag is specified with the config location, use that
+ if len(kubeconfig) > 0 {
+ return loadConfigWithContext("", &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfig}, context)
+ }
+
+ // If the recommended kubeconfig env variable is not specified,
+ // try the in-cluster config.
+ kubeconfigPath := os.Getenv(clientcmd.RecommendedConfigPathEnvVar)
+ if len(kubeconfigPath) == 0 {
+ c, err := loadInClusterConfig()
+ if err == nil {
+ return c, nil
+ }
+
+ defer func() {
+ if configErr != nil {
+ log.Error(err, "unable to load in-cluster config")
+ }
+ }()
+ }
+
+ // If the recommended kubeconfig env variable is set, or there
+ // is no in-cluster config, try the default recommended locations.
+ //
+ // NOTE: For default config file locations, upstream only checks
+ // $HOME for the user's home directory, but we can also try
+ // os/user.HomeDir when $HOME is unset.
+ //
+ // TODO(jlanford): could this be done upstream?
+ loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
+ if _, ok := os.LookupEnv("HOME"); !ok {
+ u, err := user.Current()
+ if err != nil {
+ return nil, fmt.Errorf("could not get current user: %w", err)
+ }
+ loadingRules.Precedence = append(loadingRules.Precedence, filepath.Join(u.HomeDir, clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName))
+ }
+
+ return loadConfigWithContext("", loadingRules, context)
+}
+
+func loadConfigWithContext(apiServerURL string, loader clientcmd.ClientConfigLoader, context string) (*rest.Config, error) {
+ return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
+ loader,
+ &clientcmd.ConfigOverrides{
+ ClusterInfo: clientcmdapi.Cluster{
+ Server: apiServerURL,
+ },
+ CurrentContext: context,
+ }).ClientConfig()
+}
+
+// GetConfigOrDie creates a *rest.Config for talking to a Kubernetes apiserver.
+// If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running
+// in cluster and use the cluster provided kubeconfig.
+//
+// Will log an error and exit if there is an error creating the rest.Config.
+func GetConfigOrDie() *rest.Config {
+ config, err := GetConfig()
+ if err != nil {
+ log.Error(err, "unable to get kubeconfig")
+ os.Exit(1)
+ }
+ return config
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/config/config_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/config/config_suite_test.go
new file mode 100644
index 00000000000..626613cef4f
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/config/config_suite_test.go
@@ -0,0 +1,36 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestConfig(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Client Config Test Suite")
+}
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/config/config_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/config/config_test.go
new file mode 100644
index 00000000000..058ff33c1ff
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/config/config_test.go
@@ -0,0 +1,234 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/clientcmd"
+)
+
+type testCase struct {
+ text string
+ context string
+ kubeconfigFlag string
+ kubeconfigEnv []string
+ wantHost string
+}
+
+var _ = Describe("Config", func() {
+
+ var dir string
+
+ origRecommendedHomeFile := clientcmd.RecommendedHomeFile
+
+ BeforeEach(func() {
+ // create temporary directory for test case
+ var err error
+ dir, err = os.MkdirTemp("", "cr-test")
+ Expect(err).NotTo(HaveOccurred())
+
+ // override $HOME/.kube/config
+ clientcmd.RecommendedHomeFile = filepath.Join(dir, ".kubeconfig")
+ })
+
+ AfterEach(func() {
+ os.Unsetenv(clientcmd.RecommendedConfigPathEnvVar)
+ kubeconfig = ""
+ clientcmd.RecommendedHomeFile = origRecommendedHomeFile
+
+ err := os.RemoveAll(dir)
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ Describe("GetConfigWithContext", func() {
+ defineTests := func(testCases []testCase) {
+ for _, testCase := range testCases {
+ tc := testCase
+ It(tc.text, func() {
+ // set global and environment configs
+ setConfigs(tc, dir)
+
+ // run the test
+ cfg, err := GetConfigWithContext(tc.context)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cfg.Host).To(Equal(tc.wantHost))
+ })
+ }
+ }
+
+ Context("when kubeconfig files don't exist", func() {
+ It("should fail", func() {
+ err := os.Unsetenv(clientcmd.RecommendedConfigPathEnvVar)
+ Expect(err).NotTo(HaveOccurred())
+
+ cfg, err := GetConfigWithContext("")
+ Expect(cfg).To(BeNil())
+ Expect(err).To(HaveOccurred())
+ })
+ })
+
+ Context("when in-cluster", func() {
+ kubeconfigFiles := map[string]string{
+ "kubeconfig-multi-context": genKubeconfig("from-multi-env-1", "from-multi-env-2"),
+ ".kubeconfig": genKubeconfig("from-home"),
+ }
+ BeforeEach(func() {
+ err := createFiles(kubeconfigFiles, dir)
+ Expect(err).NotTo(HaveOccurred())
+
+ // override in-cluster config loader
+ loadInClusterConfig = func() (*rest.Config, error) {
+ return &rest.Config{Host: "from-in-cluster"}, nil
+ }
+ })
+ AfterEach(func() { loadInClusterConfig = rest.InClusterConfig })
+
+ testCases := []testCase{
+ {
+ text: "should prefer the envvar over the in-cluster config",
+ kubeconfigEnv: []string{"kubeconfig-multi-context"},
+ wantHost: "from-multi-env-1",
+ },
+ {
+ text: "should prefer in-cluster over the recommended home file",
+ wantHost: "from-in-cluster",
+ },
+ }
+ defineTests(testCases)
+ })
+
+ Context("when outside the cluster", func() {
+ kubeconfigFiles := map[string]string{
+ "kubeconfig-flag": genKubeconfig("from-flag"),
+ "kubeconfig-multi-context": genKubeconfig("from-multi-env-1", "from-multi-env-2"),
+ "kubeconfig-env-1": genKubeconfig("from-env-1"),
+ "kubeconfig-env-2": genKubeconfig("from-env-2"),
+ ".kubeconfig": genKubeconfig("from-home"),
+ }
+ BeforeEach(func() {
+ err := createFiles(kubeconfigFiles, dir)
+ Expect(err).NotTo(HaveOccurred())
+ })
+ testCases := []testCase{
+ {
+ text: "should use the --kubeconfig flag",
+ kubeconfigFlag: "kubeconfig-flag",
+ wantHost: "from-flag",
+ },
+ {
+ text: "should use the envvar",
+ kubeconfigEnv: []string{"kubeconfig-multi-context"},
+ wantHost: "from-multi-env-1",
+ },
+ {
+ text: "should use the recommended home file",
+ wantHost: "from-home",
+ },
+ {
+ text: "should prefer the flag over the envvar",
+ kubeconfigFlag: "kubeconfig-flag",
+ kubeconfigEnv: []string{"kubeconfig-multi-context"},
+ wantHost: "from-flag",
+ },
+ {
+ text: "should prefer the envvar over the recommended home file",
+ kubeconfigEnv: []string{"kubeconfig-multi-context"},
+ wantHost: "from-multi-env-1",
+ },
+ {
+ text: "should allow overriding the context",
+ context: "from-multi-env-2",
+ kubeconfigEnv: []string{"kubeconfig-multi-context"},
+ wantHost: "from-multi-env-2",
+ },
+ {
+ text: "should support a multi-value envvar",
+ context: "from-env-2",
+ kubeconfigEnv: []string{"kubeconfig-env-1", "kubeconfig-env-2"},
+ wantHost: "from-env-2",
+ },
+ }
+ defineTests(testCases)
+ })
+ })
+})
+
+func setConfigs(tc testCase, dir string) {
+ // Set kubeconfig flag value
+ if len(tc.kubeconfigFlag) > 0 {
+ kubeconfig = filepath.Join(dir, tc.kubeconfigFlag)
+ }
+
+ // Set KUBECONFIG env value
+ if len(tc.kubeconfigEnv) > 0 {
+ kubeconfigEnvPaths := []string{}
+ for _, k := range tc.kubeconfigEnv {
+ kubeconfigEnvPaths = append(kubeconfigEnvPaths, filepath.Join(dir, k))
+ }
+ os.Setenv(clientcmd.RecommendedConfigPathEnvVar, strings.Join(kubeconfigEnvPaths, ":"))
+ }
+}
+
+func createFiles(files map[string]string, dir string) error {
+ for path, data := range files {
+ if err := os.WriteFile(filepath.Join(dir, path), []byte(data), 0644); err != nil { //nolint:gosec
+ return err
+ }
+ }
+ return nil
+}
+
+func genKubeconfig(contexts ...string) string {
+ var sb strings.Builder
+ sb.WriteString(`---
+apiVersion: v1
+kind: Config
+clusters:
+`)
+ for _, ctx := range contexts {
+ sb.WriteString(`- cluster:
+ server: ` + ctx + `
+ name: ` + ctx + `
+`)
+ }
+ sb.WriteString("contexts:\n")
+ for _, ctx := range contexts {
+ sb.WriteString(`- context:
+ cluster: ` + ctx + `
+ user: ` + ctx + `
+ name: ` + ctx + `
+`)
+ }
+
+ sb.WriteString("users:\n")
+ for _, ctx := range contexts {
+ sb.WriteString(`- name: ` + ctx + `
+`)
+ }
+ sb.WriteString("preferences: {}\n")
+ if len(contexts) > 0 {
+ sb.WriteString("current-context: " + contexts[0] + "\n")
+ }
+
+ return sb.String()
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go
new file mode 100644
index 00000000000..796c9cf590b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go
@@ -0,0 +1,18 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package config contains libraries for initializing REST configs for talking to the Kubernetes API
+package config
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/doc.go
new file mode 100644
index 00000000000..b2e20249428
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/doc.go
@@ -0,0 +1,49 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package client contains functionality for interacting with Kubernetes API
+// servers.
+//
+// # Clients
+//
+// Clients are split into two interfaces -- Readers and Writers. Readers
+// get and list, while writers create, update, and delete.
+//
+// The New function can be used to create a new client that talks directly
+// to the API server.
+//
+// It is a common pattern in Kubernetes to read from a cache and write to the API
+// server. This pattern is covered by the creating the Client with a Cache.
+//
+// # Options
+//
+// Many client operations in Kubernetes support options. These options are
+// represented as variadic arguments at the end of a given method call.
+// For instance, to use a label selector on list, you can call
+//
+// err := someReader.List(context.Background(), &podList, client.MatchingLabels{"somelabel": "someval"})
+//
+// # Indexing
+//
+// Indexes may be added to caches using a FieldIndexer. This allows you to easily
+// and efficiently look up objects with certain properties. You can then make
+// use of the index by specifying a field selector on calls to List on the Reader
+// corresponding to the given Cache.
+//
+// For instance, a Secret controller might have an index on the
+// `.spec.volumes.secret.secretName` field in Pod objects, so that it could
+// easily look up all pods that reference a given secret.
+package client
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go
new file mode 100644
index 00000000000..bbcdd383215
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go
@@ -0,0 +1,130 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// NewDryRunClient wraps an existing client and enforces DryRun mode
+// on all mutating api calls.
+func NewDryRunClient(c Client) Client {
+ return &dryRunClient{client: c}
+}
+
+var _ Client = &dryRunClient{}
+
+// dryRunClient is a Client that wraps another Client in order to enforce DryRun mode.
+type dryRunClient struct {
+ client Client
+}
+
+// Scheme returns the scheme this client is using.
+func (c *dryRunClient) Scheme() *runtime.Scheme {
+ return c.client.Scheme()
+}
+
+// RESTMapper returns the rest mapper this client is using.
+func (c *dryRunClient) RESTMapper() meta.RESTMapper {
+ return c.client.RESTMapper()
+}
+
+// GroupVersionKindFor returns the GroupVersionKind for the given object.
+func (c *dryRunClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
+ return c.client.GroupVersionKindFor(obj)
+}
+
+// IsObjectNamespaced returns true if the GroupVersionKind of the object is namespaced.
+func (c *dryRunClient) IsObjectNamespaced(obj runtime.Object) (bool, error) {
+ return c.client.IsObjectNamespaced(obj)
+}
+
+// Create implements client.Client.
+func (c *dryRunClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
+ return c.client.Create(ctx, obj, append(opts, DryRunAll)...)
+}
+
+// Update implements client.Client.
+func (c *dryRunClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ return c.client.Update(ctx, obj, append(opts, DryRunAll)...)
+}
+
+// Delete implements client.Client.
+func (c *dryRunClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
+ return c.client.Delete(ctx, obj, append(opts, DryRunAll)...)
+}
+
+// DeleteAllOf implements client.Client.
+func (c *dryRunClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
+ return c.client.DeleteAllOf(ctx, obj, append(opts, DryRunAll)...)
+}
+
+// Patch implements client.Client.
+func (c *dryRunClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ return c.client.Patch(ctx, obj, patch, append(opts, DryRunAll)...)
+}
+
+// Get implements client.Client.
+func (c *dryRunClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
+ return c.client.Get(ctx, key, obj, opts...)
+}
+
+// List implements client.Client.
+func (c *dryRunClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
+ return c.client.List(ctx, obj, opts...)
+}
+
+// Status implements client.StatusClient.
+func (c *dryRunClient) Status() SubResourceWriter {
+ return c.SubResource("status")
+}
+
+// SubResource implements client.SubResourceClient.
+func (c *dryRunClient) SubResource(subResource string) SubResourceClient {
+ return &dryRunSubResourceClient{client: c.client.SubResource(subResource)}
+}
+
+// ensure dryRunSubResourceWriter implements client.SubResourceWriter.
+var _ SubResourceWriter = &dryRunSubResourceClient{}
+
+// dryRunSubResourceClient is client.SubResourceWriter that writes status subresource with dryRun mode
+// enforced.
+type dryRunSubResourceClient struct {
+ client SubResourceClient
+}
+
+func (sw *dryRunSubResourceClient) Get(ctx context.Context, obj, subResource Object, opts ...SubResourceGetOption) error {
+ return sw.client.Get(ctx, obj, subResource, opts...)
+}
+
+func (sw *dryRunSubResourceClient) Create(ctx context.Context, obj, subResource Object, opts ...SubResourceCreateOption) error {
+ return sw.client.Create(ctx, obj, subResource, append(opts, DryRunAll)...)
+}
+
+// Update implements client.SubResourceWriter.
+func (sw *dryRunSubResourceClient) Update(ctx context.Context, obj Object, opts ...SubResourceUpdateOption) error {
+ return sw.client.Update(ctx, obj, append(opts, DryRunAll)...)
+}
+
+// Patch implements client.SubResourceWriter.
+func (sw *dryRunSubResourceClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...SubResourcePatchOption) error {
+ return sw.client.Patch(ctx, obj, patch, append(opts, DryRunAll)...)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/dryrun_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/dryrun_test.go
new file mode 100644
index 00000000000..72907fefabe
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/dryrun_test.go
@@ -0,0 +1,265 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client_test
+
+import (
+ "context"
+ "fmt"
+ "sync/atomic"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ appsv1 "k8s.io/api/apps/v1"
+ 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/types"
+ "k8s.io/utils/pointer"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+var _ = Describe("DryRunClient", func() {
+ var dep *appsv1.Deployment
+ var count uint64 = 0
+ var replicaCount int32 = 2
+ var ns = "default"
+ ctx := context.Background()
+
+ getClient := func() client.Client {
+ cl, err := client.New(cfg, client.Options{DryRun: pointer.Bool(true)})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+ return cl
+ }
+
+ BeforeEach(func() {
+ atomic.AddUint64(&count, 1)
+ dep = &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: fmt.Sprintf("dry-run-deployment-%v", count),
+ Namespace: ns,
+ Labels: map[string]string{"name": fmt.Sprintf("dry-run-deployment-%v", count)},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Replicas: &replicaCount,
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+
+ var err error
+ dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ AfterEach(func() {
+ deleteDeployment(ctx, dep, ns)
+ })
+
+ It("should successfully Get an object", func() {
+ name := types.NamespacedName{Namespace: ns, Name: dep.Name}
+ result := &appsv1.Deployment{}
+
+ Expect(getClient().Get(ctx, name, result)).NotTo(HaveOccurred())
+ Expect(result).To(BeEquivalentTo(dep))
+ })
+
+ It("should successfully List objects", func() {
+ result := &appsv1.DeploymentList{}
+ opts := client.MatchingLabels(dep.Labels)
+
+ Expect(getClient().List(ctx, result, opts)).NotTo(HaveOccurred())
+
+ Expect(len(result.Items)).To(BeEquivalentTo(1))
+ Expect(result.Items[0]).To(BeEquivalentTo(*dep))
+ })
+
+ It("should not create an object", func() {
+ newDep := dep.DeepCopy()
+ newDep.Name = "new-deployment"
+
+ Expect(getClient().Create(ctx, newDep)).ToNot(HaveOccurred())
+
+ _, err := clientset.AppsV1().Deployments(ns).Get(ctx, newDep.Name, metav1.GetOptions{})
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+
+ It("should not create an object with opts", func() {
+ newDep := dep.DeepCopy()
+ newDep.Name = "new-deployment"
+ opts := &client.CreateOptions{DryRun: []string{"Bye", "Pippa"}}
+
+ Expect(getClient().Create(ctx, newDep, opts)).ToNot(HaveOccurred())
+
+ _, err := clientset.AppsV1().Deployments(ns).Get(ctx, newDep.Name, metav1.GetOptions{})
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+
+ It("should refuse a create request for an invalid object", func() {
+ changedDep := dep.DeepCopy()
+ changedDep.Spec.Template.Spec.Containers = nil
+
+ err := getClient().Create(ctx, changedDep)
+ Expect(apierrors.IsInvalid(err)).To(BeTrue())
+ })
+
+ It("should not change objects via update", func() {
+ changedDep := dep.DeepCopy()
+ *changedDep.Spec.Replicas = 2
+
+ Expect(getClient().Update(ctx, changedDep)).ToNot(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual).To(BeEquivalentTo(dep))
+ })
+
+ It("should not change objects via update with opts", func() {
+ changedDep := dep.DeepCopy()
+ *changedDep.Spec.Replicas = 2
+ opts := &client.UpdateOptions{DryRun: []string{"Bye", "Pippa"}}
+
+ Expect(getClient().Update(ctx, changedDep, opts)).ToNot(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual).To(BeEquivalentTo(dep))
+ })
+
+ It("should refuse an update request for an invalid change", func() {
+ changedDep := dep.DeepCopy()
+ changedDep.Spec.Template.Spec.Containers = nil
+
+ err := getClient().Update(ctx, changedDep)
+ Expect(apierrors.IsInvalid(err)).To(BeTrue())
+ })
+
+ It("should not change objects via patch", func() {
+ changedDep := dep.DeepCopy()
+ *changedDep.Spec.Replicas = 2
+
+ Expect(getClient().Patch(ctx, changedDep, client.MergeFrom(dep))).ToNot(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual).To(BeEquivalentTo(dep))
+ })
+
+ It("should not change objects via patch with opts", func() {
+ changedDep := dep.DeepCopy()
+ *changedDep.Spec.Replicas = 2
+ opts := &client.PatchOptions{DryRun: []string{"Bye", "Pippa"}}
+
+ Expect(getClient().Patch(ctx, changedDep, client.MergeFrom(dep), opts)).ToNot(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual).To(BeEquivalentTo(dep))
+ })
+
+ It("should not delete objects", func() {
+ Expect(getClient().Delete(ctx, dep)).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual).To(BeEquivalentTo(dep))
+ })
+
+ It("should not delete objects with opts", func() {
+ opts := &client.DeleteOptions{DryRun: []string{"Bye", "Pippa"}}
+
+ Expect(getClient().Delete(ctx, dep, opts)).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual).To(BeEquivalentTo(dep))
+ })
+
+ It("should not delete objects via deleteAllOf", func() {
+ opts := []client.DeleteAllOfOption{client.InNamespace(ns), client.MatchingLabels(dep.Labels)}
+
+ Expect(getClient().DeleteAllOf(ctx, dep, opts...)).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual).To(BeEquivalentTo(dep))
+ })
+
+ It("should not change objects via update status", func() {
+ changedDep := dep.DeepCopy()
+ changedDep.Status.Replicas = 99
+
+ Expect(getClient().Status().Update(ctx, changedDep)).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual).To(BeEquivalentTo(dep))
+ })
+
+ It("should not change objects via update status with opts", func() {
+ changedDep := dep.DeepCopy()
+ changedDep.Status.Replicas = 99
+ opts := &client.SubResourceUpdateOptions{UpdateOptions: client.UpdateOptions{DryRun: []string{"Bye", "Pippa"}}}
+
+ Expect(getClient().Status().Update(ctx, changedDep, opts)).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual).To(BeEquivalentTo(dep))
+ })
+
+ It("should not change objects via status patch", func() {
+ changedDep := dep.DeepCopy()
+ changedDep.Status.Replicas = 99
+
+ Expect(getClient().Status().Patch(ctx, changedDep, client.MergeFrom(dep))).ToNot(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual).To(BeEquivalentTo(dep))
+ })
+
+ It("should not change objects via status patch with opts", func() {
+ changedDep := dep.DeepCopy()
+ changedDep.Status.Replicas = 99
+
+ opts := &client.SubResourcePatchOptions{PatchOptions: client.PatchOptions{DryRun: []string{"Bye", "Pippa"}}}
+
+ Expect(getClient().Status().Patch(ctx, changedDep, client.MergeFrom(dep), opts)).ToNot(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual).To(BeEquivalentTo(dep))
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/example_test.go
new file mode 100644
index 00000000000..7d4cb8c6163
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/example_test.go
@@ -0,0 +1,268 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client_test
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "time"
+
+ 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/types"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/config"
+)
+
+var (
+ c client.Client
+ someIndexer client.FieldIndexer
+)
+
+func ExampleNew() {
+ cl, err := client.New(config.GetConfigOrDie(), client.Options{})
+ if err != nil {
+ fmt.Println("failed to create client")
+ os.Exit(1)
+ }
+
+ podList := &corev1.PodList{}
+
+ err = cl.List(context.Background(), podList, client.InNamespace("default"))
+ if err != nil {
+ fmt.Printf("failed to list pods in namespace default: %v\n", err)
+ os.Exit(1)
+ }
+}
+
+// This example shows how to use the client with typed and unstructured objects to retrieve an object.
+func ExampleClient_get() {
+ // Using a typed object.
+ pod := &corev1.Pod{}
+ // c is a created client.
+ _ = c.Get(context.Background(), client.ObjectKey{
+ Namespace: "namespace",
+ Name: "name",
+ }, pod)
+
+ // Using a unstructured object.
+ u := &unstructured.Unstructured{}
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+ _ = c.Get(context.Background(), client.ObjectKey{
+ Namespace: "namespace",
+ Name: "name",
+ }, u)
+}
+
+// This example shows how to use the client with typed and unstructured objects to create objects.
+func ExampleClient_create() {
+ // Using a typed object.
+ pod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "namespace",
+ Name: "name",
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Image: "nginx",
+ Name: "nginx",
+ },
+ },
+ },
+ }
+ // c is a created client.
+ _ = c.Create(context.Background(), pod)
+
+ // Using a unstructured object.
+ u := &unstructured.Unstructured{}
+ u.Object = map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "name": "name",
+ "namespace": "namespace",
+ },
+ "spec": map[string]interface{}{
+ "replicas": 2,
+ "selector": map[string]interface{}{
+ "matchLabels": map[string]interface{}{
+ "foo": "bar",
+ },
+ },
+ "template": map[string]interface{}{
+ "labels": map[string]interface{}{
+ "foo": "bar",
+ },
+ "spec": map[string]interface{}{
+ "containers": []map[string]interface{}{
+ {
+ "name": "nginx",
+ "image": "nginx",
+ },
+ },
+ },
+ },
+ },
+ }
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+ _ = c.Create(context.Background(), u)
+}
+
+// This example shows how to use the client with typed and unstructured objects to list objects.
+func ExampleClient_list() {
+ // Using a typed object.
+ pod := &corev1.PodList{}
+ // c is a created client.
+ _ = c.List(context.Background(), pod)
+
+ // Using a unstructured object.
+ u := &unstructured.UnstructuredList{}
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "DeploymentList",
+ Version: "v1",
+ })
+ _ = c.List(context.Background(), u)
+}
+
+// This example shows how to use the client with typed and unstructured objects to update objects.
+func ExampleClient_update() {
+ // Using a typed object.
+ pod := &corev1.Pod{}
+ // c is a created client.
+ _ = c.Get(context.Background(), client.ObjectKey{
+ Namespace: "namespace",
+ Name: "name",
+ }, pod)
+ pod.SetFinalizers(append(pod.GetFinalizers(), "new-finalizer"))
+ _ = c.Update(context.Background(), pod)
+
+ // Using a unstructured object.
+ u := &unstructured.Unstructured{}
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+ _ = c.Get(context.Background(), client.ObjectKey{
+ Namespace: "namespace",
+ Name: "name",
+ }, u)
+ u.SetFinalizers(append(u.GetFinalizers(), "new-finalizer"))
+ _ = c.Update(context.Background(), u)
+}
+
+// This example shows how to use the client with typed and unstructured objects to patch objects.
+func ExampleClient_patch() {
+ patch := []byte(`{"metadata":{"annotations":{"version": "v2"}}}`)
+ _ = c.Patch(context.Background(), &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "namespace",
+ Name: "name",
+ },
+ }, client.RawPatch(types.StrategicMergePatchType, patch))
+}
+
+// This example shows how to use the client with typed and unstructured objects to patch objects' status.
+func ExampleClient_patchStatus() {
+ u := &unstructured.Unstructured{}
+ u.Object = map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "name": "foo",
+ "namespace": "namespace",
+ },
+ }
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "batch",
+ Version: "v1beta1",
+ Kind: "CronJob",
+ })
+ patch := []byte(fmt.Sprintf(`{"status":{"lastScheduleTime":"%s"}}`, time.Now().Format(time.RFC3339)))
+ _ = c.Status().Patch(context.Background(), u, client.RawPatch(types.MergePatchType, patch))
+}
+
+// This example shows how to use the client with typed and unstructured objects to delete objects.
+func ExampleClient_delete() {
+ // Using a typed object.
+ pod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "namespace",
+ Name: "name",
+ },
+ }
+ // c is a created client.
+ _ = c.Delete(context.Background(), pod)
+
+ // Using a unstructured object.
+ u := &unstructured.Unstructured{}
+ u.SetName("name")
+ u.SetNamespace("namespace")
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+ _ = c.Delete(context.Background(), u)
+}
+
+// This example shows how to use the client with typed and unstructured objects to delete collections of objects.
+func ExampleClient_deleteAllOf() {
+ // Using a typed object.
+ // c is a created client.
+ _ = c.DeleteAllOf(context.Background(), &corev1.Pod{}, client.InNamespace("foo"), client.MatchingLabels{"app": "foo"})
+
+ // Using an unstructured Object
+ u := &unstructured.Unstructured{}
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+ _ = c.DeleteAllOf(context.Background(), u, client.InNamespace("foo"), client.MatchingLabels{"app": "foo"})
+}
+
+// This example shows how to set up and consume a field selector over a pod's volumes' secretName field.
+func ExampleFieldIndexer_secretName() {
+ // someIndexer is a FieldIndexer over a Cache
+ _ = someIndexer.IndexField(context.TODO(), &corev1.Pod{}, "spec.volumes.secret.secretName", func(o client.Object) []string {
+ var res []string
+ for _, vol := range o.(*corev1.Pod).Spec.Volumes {
+ if vol.Secret == nil {
+ continue
+ }
+ // just return the raw field value -- the indexer will take care of dealing with namespaces for us
+ res = append(res, vol.Secret.SecretName)
+ }
+ return res
+ })
+
+ // elsewhere (e.g. in your reconciler)
+ mySecretName := "someSecret" // derived from the reconcile.Request, for instance
+ var podsWithSecrets corev1.PodList
+ _ = c.List(context.Background(), &podsWithSecrets, client.MatchingFields{"spec.volumes.secret.secretName": mySecretName})
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go
new file mode 100644
index 00000000000..7167c5505ec
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go
@@ -0,0 +1,1283 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package fake
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "reflect"
+ "runtime/debug"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ // Using v4 to match upstream
+ jsonpatch "github.com/evanphx/json-patch"
+ "sigs.k8s.io/controller-runtime/pkg/client/interceptor"
+
+ corev1 "k8s.io/api/core/v1"
+ policyv1 "k8s.io/api/policy/v1"
+ policyv1beta1 "k8s.io/api/policy/v1beta1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/fields"
+ "k8s.io/apimachinery/pkg/labels"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/types"
+ utilrand "k8s.io/apimachinery/pkg/util/rand"
+ "k8s.io/apimachinery/pkg/util/sets"
+ "k8s.io/apimachinery/pkg/util/strategicpatch"
+ "k8s.io/apimachinery/pkg/util/validation/field"
+ "k8s.io/apimachinery/pkg/watch"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/testing"
+ "sigs.k8s.io/controller-runtime/pkg/internal/field/selector"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/internal/objectutil"
+)
+
+type versionedTracker struct {
+ testing.ObjectTracker
+ scheme *runtime.Scheme
+ withStatusSubresource sets.Set[schema.GroupVersionKind]
+}
+
+type fakeClient struct {
+ tracker versionedTracker
+ scheme *runtime.Scheme
+ restMapper meta.RESTMapper
+ withStatusSubresource sets.Set[schema.GroupVersionKind]
+
+ // indexes maps each GroupVersionKind (GVK) to the indexes registered for that GVK.
+ // The inner map maps from index name to IndexerFunc.
+ indexes map[schema.GroupVersionKind]map[string]client.IndexerFunc
+
+ schemeWriteLock sync.Mutex
+}
+
+var _ client.WithWatch = &fakeClient{}
+
+const (
+ maxNameLength = 63
+ randomLength = 5
+ maxGeneratedNameLength = maxNameLength - randomLength
+)
+
+// NewFakeClient creates a new fake client for testing.
+// You can choose to initialize it with a slice of runtime.Object.
+//
+// Deprecated: Please use NewClientBuilder instead.
+func NewFakeClient(initObjs ...runtime.Object) client.WithWatch {
+ return NewClientBuilder().WithRuntimeObjects(initObjs...).Build()
+}
+
+// NewFakeClientWithScheme creates a new fake client with the given scheme
+// for testing.
+// You can choose to initialize it with a slice of runtime.Object.
+//
+// Deprecated: Please use NewClientBuilder instead.
+func NewFakeClientWithScheme(clientScheme *runtime.Scheme, initObjs ...runtime.Object) client.WithWatch {
+ return NewClientBuilder().WithScheme(clientScheme).WithRuntimeObjects(initObjs...).Build()
+}
+
+// NewClientBuilder returns a new builder to create a fake client.
+func NewClientBuilder() *ClientBuilder {
+ return &ClientBuilder{}
+}
+
+// ClientBuilder builds a fake client.
+type ClientBuilder struct {
+ scheme *runtime.Scheme
+ restMapper meta.RESTMapper
+ initObject []client.Object
+ initLists []client.ObjectList
+ initRuntimeObjects []runtime.Object
+ withStatusSubresource []client.Object
+ objectTracker testing.ObjectTracker
+ interceptorFuncs *interceptor.Funcs
+
+ // indexes maps each GroupVersionKind (GVK) to the indexes registered for that GVK.
+ // The inner map maps from index name to IndexerFunc.
+ indexes map[schema.GroupVersionKind]map[string]client.IndexerFunc
+}
+
+// WithScheme sets this builder's internal scheme.
+// If not set, defaults to client-go's global scheme.Scheme.
+func (f *ClientBuilder) WithScheme(scheme *runtime.Scheme) *ClientBuilder {
+ f.scheme = scheme
+ return f
+}
+
+// WithRESTMapper sets this builder's restMapper.
+// The restMapper is directly set as mapper in the Client. This can be used for example
+// with a meta.DefaultRESTMapper to provide a static rest mapping.
+// If not set, defaults to an empty meta.DefaultRESTMapper.
+func (f *ClientBuilder) WithRESTMapper(restMapper meta.RESTMapper) *ClientBuilder {
+ f.restMapper = restMapper
+ return f
+}
+
+// WithObjects can be optionally used to initialize this fake client with client.Object(s).
+func (f *ClientBuilder) WithObjects(initObjs ...client.Object) *ClientBuilder {
+ f.initObject = append(f.initObject, initObjs...)
+ return f
+}
+
+// WithLists can be optionally used to initialize this fake client with client.ObjectList(s).
+func (f *ClientBuilder) WithLists(initLists ...client.ObjectList) *ClientBuilder {
+ f.initLists = append(f.initLists, initLists...)
+ return f
+}
+
+// WithRuntimeObjects can be optionally used to initialize this fake client with runtime.Object(s).
+func (f *ClientBuilder) WithRuntimeObjects(initRuntimeObjs ...runtime.Object) *ClientBuilder {
+ f.initRuntimeObjects = append(f.initRuntimeObjects, initRuntimeObjs...)
+ return f
+}
+
+// WithObjectTracker can be optionally used to initialize this fake client with testing.ObjectTracker.
+func (f *ClientBuilder) WithObjectTracker(ot testing.ObjectTracker) *ClientBuilder {
+ f.objectTracker = ot
+ return f
+}
+
+// WithIndex can be optionally used to register an index with name `field` and indexer `extractValue`
+// for API objects of the same GroupVersionKind (GVK) as `obj` in the fake client.
+// It can be invoked multiple times, both with objects of the same GVK or different ones.
+// Invoking WithIndex twice with the same `field` and GVK (via `obj`) arguments will panic.
+// WithIndex retrieves the GVK of `obj` using the scheme registered via WithScheme if
+// WithScheme was previously invoked, the default scheme otherwise.
+func (f *ClientBuilder) WithIndex(obj runtime.Object, field string, extractValue client.IndexerFunc) *ClientBuilder {
+ objScheme := f.scheme
+ if objScheme == nil {
+ objScheme = scheme.Scheme
+ }
+
+ gvk, err := apiutil.GVKForObject(obj, objScheme)
+ if err != nil {
+ panic(err)
+ }
+
+ // If this is the first index being registered, we initialize the map storing all the indexes.
+ if f.indexes == nil {
+ f.indexes = make(map[schema.GroupVersionKind]map[string]client.IndexerFunc)
+ }
+
+ // If this is the first index being registered for the GroupVersionKind of `obj`, we initialize
+ // the map storing the indexes for that GroupVersionKind.
+ if f.indexes[gvk] == nil {
+ f.indexes[gvk] = make(map[string]client.IndexerFunc)
+ }
+
+ if _, fieldAlreadyIndexed := f.indexes[gvk][field]; fieldAlreadyIndexed {
+ panic(fmt.Errorf("indexer conflict: field %s for GroupVersionKind %v is already indexed",
+ field, gvk))
+ }
+
+ f.indexes[gvk][field] = extractValue
+
+ return f
+}
+
+// WithStatusSubresource configures the passed object with a status subresource, which means
+// calls to Update and Patch will not alter its status.
+func (f *ClientBuilder) WithStatusSubresource(o ...client.Object) *ClientBuilder {
+ f.withStatusSubresource = append(f.withStatusSubresource, o...)
+ return f
+}
+
+// WithInterceptorFuncs configures the client methods to be intercepted using the provided interceptor.Funcs.
+func (f *ClientBuilder) WithInterceptorFuncs(interceptorFuncs interceptor.Funcs) *ClientBuilder {
+ f.interceptorFuncs = &interceptorFuncs
+ return f
+}
+
+// Build builds and returns a new fake client.
+func (f *ClientBuilder) Build() client.WithWatch {
+ if f.scheme == nil {
+ f.scheme = scheme.Scheme
+ }
+ if f.restMapper == nil {
+ f.restMapper = meta.NewDefaultRESTMapper([]schema.GroupVersion{})
+ }
+
+ var tracker versionedTracker
+
+ withStatusSubResource := sets.New(inTreeResourcesWithStatus()...)
+ for _, o := range f.withStatusSubresource {
+ gvk, err := apiutil.GVKForObject(o, f.scheme)
+ if err != nil {
+ panic(fmt.Errorf("failed to get gvk for object %T: %w", withStatusSubResource, err))
+ }
+ withStatusSubResource.Insert(gvk)
+ }
+
+ if f.objectTracker == nil {
+ tracker = versionedTracker{ObjectTracker: testing.NewObjectTracker(f.scheme, scheme.Codecs.UniversalDecoder()), scheme: f.scheme, withStatusSubresource: withStatusSubResource}
+ } else {
+ tracker = versionedTracker{ObjectTracker: f.objectTracker, scheme: f.scheme, withStatusSubresource: withStatusSubResource}
+ }
+
+ for _, obj := range f.initObject {
+ if err := tracker.Add(obj); err != nil {
+ panic(fmt.Errorf("failed to add object %v to fake client: %w", obj, err))
+ }
+ }
+ for _, obj := range f.initLists {
+ if err := tracker.Add(obj); err != nil {
+ panic(fmt.Errorf("failed to add list %v to fake client: %w", obj, err))
+ }
+ }
+ for _, obj := range f.initRuntimeObjects {
+ if err := tracker.Add(obj); err != nil {
+ panic(fmt.Errorf("failed to add runtime object %v to fake client: %w", obj, err))
+ }
+ }
+
+ var result client.WithWatch = &fakeClient{
+ tracker: tracker,
+ scheme: f.scheme,
+ restMapper: f.restMapper,
+ indexes: f.indexes,
+ withStatusSubresource: withStatusSubResource,
+ }
+
+ if f.interceptorFuncs != nil {
+ result = interceptor.NewClient(result, *f.interceptorFuncs)
+ }
+
+ return result
+}
+
+const trackerAddResourceVersion = "999"
+
+func (t versionedTracker) Add(obj runtime.Object) error {
+ var objects []runtime.Object
+ if meta.IsListType(obj) {
+ var err error
+ objects, err = meta.ExtractList(obj)
+ if err != nil {
+ return err
+ }
+ } else {
+ objects = []runtime.Object{obj}
+ }
+ for _, obj := range objects {
+ accessor, err := meta.Accessor(obj)
+ if err != nil {
+ return fmt.Errorf("failed to get accessor for object: %w", err)
+ }
+ if accessor.GetDeletionTimestamp() != nil && len(accessor.GetFinalizers()) == 0 {
+ return fmt.Errorf("refusing to create obj %s with metadata.deletionTimestamp but no finalizers", accessor.GetName())
+ }
+ if accessor.GetResourceVersion() == "" {
+ // We use a "magic" value of 999 here because this field
+ // is parsed as uint and and 0 is already used in Update.
+ // As we can't go lower, go very high instead so this can
+ // be recognized
+ accessor.SetResourceVersion(trackerAddResourceVersion)
+ }
+
+ obj, err = convertFromUnstructuredIfNecessary(t.scheme, obj)
+ if err != nil {
+ return err
+ }
+ if err := t.ObjectTracker.Add(obj); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (t versionedTracker) Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error {
+ accessor, err := meta.Accessor(obj)
+ if err != nil {
+ return fmt.Errorf("failed to get accessor for object: %w", err)
+ }
+ if accessor.GetName() == "" {
+ return apierrors.NewInvalid(
+ obj.GetObjectKind().GroupVersionKind().GroupKind(),
+ accessor.GetName(),
+ field.ErrorList{field.Required(field.NewPath("metadata.name"), "name is required")})
+ }
+ if accessor.GetResourceVersion() != "" {
+ return apierrors.NewBadRequest("resourceVersion can not be set for Create requests")
+ }
+ accessor.SetResourceVersion("1")
+ obj, err = convertFromUnstructuredIfNecessary(t.scheme, obj)
+ if err != nil {
+ return err
+ }
+ if err := t.ObjectTracker.Create(gvr, obj, ns); err != nil {
+ accessor.SetResourceVersion("")
+ return err
+ }
+
+ return nil
+}
+
+// convertFromUnstructuredIfNecessary will convert runtime.Unstructured for a GVK that is recognized
+// by the schema into the whatever the schema produces with New() for said GVK.
+// This is required because the tracker unconditionally saves on manipulations, but its List() implementation
+// tries to assign whatever it finds into a ListType it gets from schema.New() - Thus we have to ensure
+// we save as the very same type, otherwise subsequent List requests will fail.
+func convertFromUnstructuredIfNecessary(s *runtime.Scheme, o runtime.Object) (runtime.Object, error) {
+ gvk := o.GetObjectKind().GroupVersionKind()
+
+ u, isUnstructured := o.(runtime.Unstructured)
+ if !isUnstructured || !s.Recognizes(gvk) {
+ return o, nil
+ }
+
+ typed, err := s.New(gvk)
+ if err != nil {
+ return nil, fmt.Errorf("scheme recognizes %s but failed to produce an object for it: %w", gvk, err)
+ }
+
+ unstructuredSerialized, err := json.Marshal(u)
+ if err != nil {
+ return nil, fmt.Errorf("failed to serialize %T: %w", unstructuredSerialized, err)
+ }
+ if err := json.Unmarshal(unstructuredSerialized, typed); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal the content of %T into %T: %w", u, typed, err)
+ }
+
+ return typed, nil
+}
+
+func (t versionedTracker) Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error {
+ isStatus := false
+ // We apply patches using a client-go reaction that ends up calling the trackers Update. As we can't change
+ // that reaction, we use the callstack to figure out if this originated from the status client.
+ if bytes.Contains(debug.Stack(), []byte("sigs.k8s.io/controller-runtime/pkg/client/fake.(*fakeSubResourceClient).Patch")) {
+ isStatus = true
+ }
+ return t.update(gvr, obj, ns, isStatus, false)
+}
+
+func (t versionedTracker) update(gvr schema.GroupVersionResource, obj runtime.Object, ns string, isStatus bool, deleting bool) error {
+ accessor, err := meta.Accessor(obj)
+ if err != nil {
+ return fmt.Errorf("failed to get accessor for object: %w", err)
+ }
+
+ if accessor.GetName() == "" {
+ return apierrors.NewInvalid(
+ obj.GetObjectKind().GroupVersionKind().GroupKind(),
+ accessor.GetName(),
+ field.ErrorList{field.Required(field.NewPath("metadata.name"), "name is required")})
+ }
+
+ gvk := obj.GetObjectKind().GroupVersionKind()
+ if gvk.Empty() {
+ gvk, err = apiutil.GVKForObject(obj, t.scheme)
+ if err != nil {
+ return err
+ }
+ }
+
+ oldObject, err := t.ObjectTracker.Get(gvr, ns, accessor.GetName())
+ if err != nil {
+ // If the resource is not found and the resource allows create on update, issue a
+ // create instead.
+ if apierrors.IsNotFound(err) && allowsCreateOnUpdate(gvk) {
+ return t.Create(gvr, obj, ns)
+ }
+ return err
+ }
+
+ if t.withStatusSubresource.Has(gvk) {
+ if isStatus { // copy everything but status and metadata.ResourceVersion from original object
+ if err := copyNonStatusFrom(oldObject, obj); err != nil {
+ return fmt.Errorf("failed to copy non-status field for object with status subresouce: %w", err)
+ }
+ } else { // copy status from original object
+ if err := copyStatusFrom(oldObject, obj); err != nil {
+ return fmt.Errorf("failed to copy the status for object with status subresource: %w", err)
+ }
+ }
+ } else if isStatus {
+ return apierrors.NewNotFound(gvr.GroupResource(), accessor.GetName())
+ }
+
+ oldAccessor, err := meta.Accessor(oldObject)
+ if err != nil {
+ return err
+ }
+
+ // If the new object does not have the resource version set and it allows unconditional update,
+ // default it to the resource version of the existing resource
+ if accessor.GetResourceVersion() == "" && allowsUnconditionalUpdate(gvk) {
+ accessor.SetResourceVersion(oldAccessor.GetResourceVersion())
+ }
+ if accessor.GetResourceVersion() != oldAccessor.GetResourceVersion() {
+ return apierrors.NewConflict(gvr.GroupResource(), accessor.GetName(), errors.New("object was modified"))
+ }
+ if oldAccessor.GetResourceVersion() == "" {
+ oldAccessor.SetResourceVersion("0")
+ }
+ intResourceVersion, err := strconv.ParseUint(oldAccessor.GetResourceVersion(), 10, 64)
+ if err != nil {
+ return fmt.Errorf("can not convert resourceVersion %q to int: %w", oldAccessor.GetResourceVersion(), err)
+ }
+ intResourceVersion++
+ accessor.SetResourceVersion(strconv.FormatUint(intResourceVersion, 10))
+
+ if !deleting && !deletionTimestampEqual(accessor, oldAccessor) {
+ return fmt.Errorf("error: Unable to edit %s: metadata.deletionTimestamp field is immutable", accessor.GetName())
+ }
+
+ if !accessor.GetDeletionTimestamp().IsZero() && len(accessor.GetFinalizers()) == 0 {
+ return t.ObjectTracker.Delete(gvr, accessor.GetNamespace(), accessor.GetName())
+ }
+ obj, err = convertFromUnstructuredIfNecessary(t.scheme, obj)
+ if err != nil {
+ return err
+ }
+ return t.ObjectTracker.Update(gvr, obj, ns)
+}
+
+func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
+ gvr, err := getGVRFromObject(obj, c.scheme)
+ if err != nil {
+ return err
+ }
+ o, err := c.tracker.Get(gvr, key.Namespace, key.Name)
+ if err != nil {
+ return err
+ }
+
+ gvk, err := apiutil.GVKForObject(obj, c.scheme)
+ if err != nil {
+ return err
+ }
+ ta, err := meta.TypeAccessor(o)
+ if err != nil {
+ return err
+ }
+ ta.SetKind(gvk.Kind)
+ ta.SetAPIVersion(gvk.GroupVersion().String())
+
+ j, err := json.Marshal(o)
+ if err != nil {
+ return err
+ }
+ decoder := scheme.Codecs.UniversalDecoder()
+ zero(obj)
+ _, _, err = decoder.Decode(j, nil, obj)
+ return err
+}
+
+func (c *fakeClient) Watch(ctx context.Context, list client.ObjectList, opts ...client.ListOption) (watch.Interface, error) {
+ gvk, err := apiutil.GVKForObject(list, c.scheme)
+ if err != nil {
+ return nil, err
+ }
+
+ gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
+
+ listOpts := client.ListOptions{}
+ listOpts.ApplyOptions(opts)
+
+ gvr, _ := meta.UnsafeGuessKindToResource(gvk)
+ return c.tracker.Watch(gvr, listOpts.Namespace)
+}
+
+func (c *fakeClient) List(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error {
+ gvk, err := apiutil.GVKForObject(obj, c.scheme)
+ if err != nil {
+ return err
+ }
+
+ originalKind := gvk.Kind
+
+ gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
+
+ if _, isUnstructuredList := obj.(runtime.Unstructured); isUnstructuredList && !c.scheme.Recognizes(gvk) {
+ // We need to register the ListKind with UnstructuredList:
+ // https://github.com/kubernetes/kubernetes/blob/7b2776b89fb1be28d4e9203bdeec079be903c103/staging/src/k8s.io/client-go/dynamic/fake/simple.go#L44-L51
+ c.schemeWriteLock.Lock()
+ c.scheme.AddKnownTypeWithName(gvk.GroupVersion().WithKind(gvk.Kind+"List"), &unstructured.UnstructuredList{})
+ c.schemeWriteLock.Unlock()
+ }
+
+ listOpts := client.ListOptions{}
+ listOpts.ApplyOptions(opts)
+
+ gvr, _ := meta.UnsafeGuessKindToResource(gvk)
+ o, err := c.tracker.List(gvr, gvk, listOpts.Namespace)
+ if err != nil {
+ return err
+ }
+
+ ta, err := meta.TypeAccessor(o)
+ if err != nil {
+ return err
+ }
+ ta.SetKind(originalKind)
+ ta.SetAPIVersion(gvk.GroupVersion().String())
+
+ j, err := json.Marshal(o)
+ if err != nil {
+ return err
+ }
+ decoder := scheme.Codecs.UniversalDecoder()
+ zero(obj)
+ _, _, err = decoder.Decode(j, nil, obj)
+ if err != nil {
+ return err
+ }
+
+ if listOpts.LabelSelector == nil && listOpts.FieldSelector == nil {
+ return nil
+ }
+
+ // If we're here, either a label or field selector are specified (or both), so before we return
+ // the list we must filter it. If both selectors are set, they are ANDed.
+ objs, err := meta.ExtractList(obj)
+ if err != nil {
+ return err
+ }
+
+ filteredList, err := c.filterList(objs, gvk, listOpts.LabelSelector, listOpts.FieldSelector)
+ if err != nil {
+ return err
+ }
+
+ return meta.SetList(obj, filteredList)
+}
+
+func (c *fakeClient) filterList(list []runtime.Object, gvk schema.GroupVersionKind, ls labels.Selector, fs fields.Selector) ([]runtime.Object, error) {
+ // Filter the objects with the label selector
+ filteredList := list
+ if ls != nil {
+ objsFilteredByLabel, err := objectutil.FilterWithLabels(list, ls)
+ if err != nil {
+ return nil, err
+ }
+ filteredList = objsFilteredByLabel
+ }
+
+ // Filter the result of the previous pass with the field selector
+ if fs != nil {
+ objsFilteredByField, err := c.filterWithFields(filteredList, gvk, fs)
+ if err != nil {
+ return nil, err
+ }
+ filteredList = objsFilteredByField
+ }
+
+ return filteredList, nil
+}
+
+func (c *fakeClient) filterWithFields(list []runtime.Object, gvk schema.GroupVersionKind, fs fields.Selector) ([]runtime.Object, error) {
+ // We only allow filtering on the basis of a single field to ensure consistency with the
+ // behavior of the cache reader (which we're faking here).
+ fieldKey, fieldVal, requiresExact := selector.RequiresExactMatch(fs)
+ if !requiresExact {
+ return nil, fmt.Errorf("field selector %s is not in one of the two supported forms \"key==val\" or \"key=val\"",
+ fs)
+ }
+
+ // Field selection is mimicked via indexes, so there's no sane answer this function can give
+ // if there are no indexes registered for the GroupVersionKind of the objects in the list.
+ indexes := c.indexes[gvk]
+ if len(indexes) == 0 || indexes[fieldKey] == nil {
+ return nil, fmt.Errorf("List on GroupVersionKind %v specifies selector on field %s, but no "+
+ "index with name %s has been registered for GroupVersionKind %v", gvk, fieldKey, fieldKey, gvk)
+ }
+
+ indexExtractor := indexes[fieldKey]
+ filteredList := make([]runtime.Object, 0, len(list))
+ for _, obj := range list {
+ if c.objMatchesFieldSelector(obj, indexExtractor, fieldVal) {
+ filteredList = append(filteredList, obj)
+ }
+ }
+ return filteredList, nil
+}
+
+func (c *fakeClient) objMatchesFieldSelector(o runtime.Object, extractIndex client.IndexerFunc, val string) bool {
+ obj, isClientObject := o.(client.Object)
+ if !isClientObject {
+ panic(fmt.Errorf("expected object %v to be of type client.Object, but it's not", o))
+ }
+
+ for _, extractedVal := range extractIndex(obj) {
+ if extractedVal == val {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (c *fakeClient) Scheme() *runtime.Scheme {
+ return c.scheme
+}
+
+func (c *fakeClient) RESTMapper() meta.RESTMapper {
+ return c.restMapper
+}
+
+// GroupVersionKindFor returns the GroupVersionKind for the given object.
+func (c *fakeClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
+ return apiutil.GVKForObject(obj, c.scheme)
+}
+
+// IsObjectNamespaced returns true if the GroupVersionKind of the object is namespaced.
+func (c *fakeClient) IsObjectNamespaced(obj runtime.Object) (bool, error) {
+ return apiutil.IsObjectNamespaced(obj, c.scheme, c.restMapper)
+}
+
+func (c *fakeClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
+ createOptions := &client.CreateOptions{}
+ createOptions.ApplyOptions(opts)
+
+ for _, dryRunOpt := range createOptions.DryRun {
+ if dryRunOpt == metav1.DryRunAll {
+ return nil
+ }
+ }
+
+ gvr, err := getGVRFromObject(obj, c.scheme)
+ if err != nil {
+ return err
+ }
+ accessor, err := meta.Accessor(obj)
+ if err != nil {
+ return err
+ }
+
+ if accessor.GetName() == "" && accessor.GetGenerateName() != "" {
+ base := accessor.GetGenerateName()
+ if len(base) > maxGeneratedNameLength {
+ base = base[:maxGeneratedNameLength]
+ }
+ accessor.SetName(fmt.Sprintf("%s%s", base, utilrand.String(randomLength)))
+ }
+ // Ignore attempts to set deletion timestamp
+ if !accessor.GetDeletionTimestamp().IsZero() {
+ accessor.SetDeletionTimestamp(nil)
+ }
+
+ return c.tracker.Create(gvr, obj, accessor.GetNamespace())
+}
+
+func (c *fakeClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
+ gvr, err := getGVRFromObject(obj, c.scheme)
+ if err != nil {
+ return err
+ }
+ accessor, err := meta.Accessor(obj)
+ if err != nil {
+ return err
+ }
+ delOptions := client.DeleteOptions{}
+ delOptions.ApplyOptions(opts)
+
+ for _, dryRunOpt := range delOptions.DryRun {
+ if dryRunOpt == metav1.DryRunAll {
+ return nil
+ }
+ }
+
+ // Check the ResourceVersion if that Precondition was specified.
+ if delOptions.Preconditions != nil && delOptions.Preconditions.ResourceVersion != nil {
+ name := accessor.GetName()
+ dbObj, err := c.tracker.Get(gvr, accessor.GetNamespace(), name)
+ if err != nil {
+ return err
+ }
+ oldAccessor, err := meta.Accessor(dbObj)
+ if err != nil {
+ return err
+ }
+ actualRV := oldAccessor.GetResourceVersion()
+ expectRV := *delOptions.Preconditions.ResourceVersion
+ if actualRV != expectRV {
+ msg := fmt.Sprintf(
+ "the ResourceVersion in the precondition (%s) does not match the ResourceVersion in record (%s). "+
+ "The object might have been modified",
+ expectRV, actualRV)
+ return apierrors.NewConflict(gvr.GroupResource(), name, errors.New(msg))
+ }
+ }
+
+ return c.deleteObject(gvr, accessor)
+}
+
+func (c *fakeClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
+ gvk, err := apiutil.GVKForObject(obj, c.scheme)
+ if err != nil {
+ return err
+ }
+
+ dcOptions := client.DeleteAllOfOptions{}
+ dcOptions.ApplyOptions(opts)
+
+ for _, dryRunOpt := range dcOptions.DryRun {
+ if dryRunOpt == metav1.DryRunAll {
+ return nil
+ }
+ }
+
+ gvr, _ := meta.UnsafeGuessKindToResource(gvk)
+ o, err := c.tracker.List(gvr, gvk, dcOptions.Namespace)
+ if err != nil {
+ return err
+ }
+
+ objs, err := meta.ExtractList(o)
+ if err != nil {
+ return err
+ }
+ filteredObjs, err := objectutil.FilterWithLabels(objs, dcOptions.LabelSelector)
+ if err != nil {
+ return err
+ }
+ for _, o := range filteredObjs {
+ accessor, err := meta.Accessor(o)
+ if err != nil {
+ return err
+ }
+ err = c.deleteObject(gvr, accessor)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (c *fakeClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return c.update(obj, false, opts...)
+}
+
+func (c *fakeClient) update(obj client.Object, isStatus bool, opts ...client.UpdateOption) error {
+ updateOptions := &client.UpdateOptions{}
+ updateOptions.ApplyOptions(opts)
+
+ for _, dryRunOpt := range updateOptions.DryRun {
+ if dryRunOpt == metav1.DryRunAll {
+ return nil
+ }
+ }
+
+ gvr, err := getGVRFromObject(obj, c.scheme)
+ if err != nil {
+ return err
+ }
+ accessor, err := meta.Accessor(obj)
+ if err != nil {
+ return err
+ }
+ return c.tracker.update(gvr, obj, accessor.GetNamespace(), isStatus, false)
+}
+
+func (c *fakeClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+ return c.patch(obj, patch, opts...)
+}
+
+func (c *fakeClient) patch(obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+ patchOptions := &client.PatchOptions{}
+ patchOptions.ApplyOptions(opts)
+
+ for _, dryRunOpt := range patchOptions.DryRun {
+ if dryRunOpt == metav1.DryRunAll {
+ return nil
+ }
+ }
+
+ gvr, err := getGVRFromObject(obj, c.scheme)
+ if err != nil {
+ return err
+ }
+ accessor, err := meta.Accessor(obj)
+ if err != nil {
+ return err
+ }
+ data, err := patch.Data(obj)
+ if err != nil {
+ return err
+ }
+
+ gvk, err := apiutil.GVKForObject(obj, c.scheme)
+ if err != nil {
+ return err
+ }
+
+ oldObj, err := c.tracker.Get(gvr, accessor.GetNamespace(), accessor.GetName())
+ if err != nil {
+ return err
+ }
+ oldAccessor, err := meta.Accessor(oldObj)
+ if err != nil {
+ return err
+ }
+
+ // Apply patch without updating object.
+ // To remain in accordance with the behavior of k8s api behavior,
+ // a patch must not allow for changes to the deletionTimestamp of an object.
+ // The reaction() function applies the patch to the object and calls Update(),
+ // whereas dryPatch() replicates this behavior but skips the call to Update().
+ // This ensures that the patch may be rejected if a deletionTimestamp is modified, prior
+ // to updating the object.
+ action := testing.NewPatchAction(gvr, accessor.GetNamespace(), accessor.GetName(), patch.Type(), data)
+ o, err := dryPatch(action, c.tracker)
+ if err != nil {
+ return err
+ }
+ newObj, err := meta.Accessor(o)
+ if err != nil {
+ return err
+ }
+
+ // Validate that deletionTimestamp has not been changed
+ if !deletionTimestampEqual(newObj, oldAccessor) {
+ return fmt.Errorf("rejected patch, metadata.deletionTimestamp immutable")
+ }
+
+ reaction := testing.ObjectReaction(c.tracker)
+ handled, o, err := reaction(action)
+ if err != nil {
+ return err
+ }
+ if !handled {
+ panic("tracker could not handle patch method")
+ }
+ ta, err := meta.TypeAccessor(o)
+ if err != nil {
+ return err
+ }
+ ta.SetKind(gvk.Kind)
+ ta.SetAPIVersion(gvk.GroupVersion().String())
+
+ j, err := json.Marshal(o)
+ if err != nil {
+ return err
+ }
+ decoder := scheme.Codecs.UniversalDecoder()
+ zero(obj)
+ _, _, err = decoder.Decode(j, nil, obj)
+ return err
+}
+
+// Applying a patch results in a deletionTimestamp that is truncated to the nearest second.
+// Check that the diff between a new and old deletion timestamp is within a reasonable threshold
+// to be considered unchanged.
+func deletionTimestampEqual(newObj metav1.Object, obj metav1.Object) bool {
+ newTime := newObj.GetDeletionTimestamp()
+ oldTime := obj.GetDeletionTimestamp()
+
+ if newTime == nil || oldTime == nil {
+ return newTime == oldTime
+ }
+ return newTime.Time.Sub(oldTime.Time).Abs() < time.Second
+}
+
+// The behavior of applying the patch is pulled out into dryPatch(),
+// which applies the patch and returns an object, but does not Update() the object.
+// This function returns a patched runtime object that may then be validated before a call to Update() is executed.
+// This results in some code duplication, but was found to be a cleaner alternative than unmarshalling and introspecting the patch data
+// and easier than refactoring the k8s client-go method upstream.
+// Duplicate of upstream: https://github.com/kubernetes/client-go/blob/783d0d33626e59d55d52bfd7696b775851f92107/testing/fixture.go#L146-L194
+func dryPatch(action testing.PatchActionImpl, tracker testing.ObjectTracker) (runtime.Object, error) {
+ ns := action.GetNamespace()
+ gvr := action.GetResource()
+
+ obj, err := tracker.Get(gvr, ns, action.GetName())
+ if err != nil {
+ return nil, err
+ }
+
+ old, err := json.Marshal(obj)
+ if err != nil {
+ return nil, err
+ }
+
+ // reset the object in preparation to unmarshal, since unmarshal does not guarantee that fields
+ // in obj that are removed by patch are cleared
+ value := reflect.ValueOf(obj)
+ value.Elem().Set(reflect.New(value.Type().Elem()).Elem())
+
+ switch action.GetPatchType() {
+ case types.JSONPatchType:
+ patch, err := jsonpatch.DecodePatch(action.GetPatch())
+ if err != nil {
+ return nil, err
+ }
+ modified, err := patch.Apply(old)
+ if err != nil {
+ return nil, err
+ }
+
+ if err = json.Unmarshal(modified, obj); err != nil {
+ return nil, err
+ }
+ case types.MergePatchType:
+ modified, err := jsonpatch.MergePatch(old, action.GetPatch())
+ if err != nil {
+ return nil, err
+ }
+
+ if err := json.Unmarshal(modified, obj); err != nil {
+ return nil, err
+ }
+ case types.StrategicMergePatchType, types.ApplyPatchType:
+ mergedByte, err := strategicpatch.StrategicMergePatch(old, action.GetPatch(), obj)
+ if err != nil {
+ return nil, err
+ }
+ if err = json.Unmarshal(mergedByte, obj); err != nil {
+ return nil, err
+ }
+ default:
+ return nil, fmt.Errorf("PatchType is not supported")
+ }
+ return obj, nil
+}
+
+func copyNonStatusFrom(old, new runtime.Object) error {
+ newClientObject, ok := new.(client.Object)
+ if !ok {
+ return fmt.Errorf("%T is not a client.Object", new)
+ }
+ // The only thing other than status we have to retain
+ rv := newClientObject.GetResourceVersion()
+
+ oldMapStringAny, err := toMapStringAny(old)
+ if err != nil {
+ return fmt.Errorf("failed to convert old to *unstructured.Unstructured: %w", err)
+ }
+ newMapStringAny, err := toMapStringAny(new)
+ if err != nil {
+ return fmt.Errorf("failed to convert new to *unststructured.Unstructured: %w", err)
+ }
+
+ // delete everything other than status in case it has fields that were not present in
+ // the old object
+ for k := range newMapStringAny {
+ if k != "status" {
+ delete(newMapStringAny, k)
+ }
+ }
+ // copy everything other than status from the old object
+ for k := range oldMapStringAny {
+ if k != "status" {
+ newMapStringAny[k] = oldMapStringAny[k]
+ }
+ }
+
+ newClientObject.SetResourceVersion(rv)
+
+ if err := fromMapStringAny(newMapStringAny, new); err != nil {
+ return fmt.Errorf("failed to convert back from map[string]any: %w", err)
+ }
+ return nil
+}
+
+// copyStatusFrom copies the status from old into new
+func copyStatusFrom(old, new runtime.Object) error {
+ oldMapStringAny, err := toMapStringAny(old)
+ if err != nil {
+ return fmt.Errorf("failed to convert old to *unstructured.Unstructured: %w", err)
+ }
+ newMapStringAny, err := toMapStringAny(new)
+ if err != nil {
+ return fmt.Errorf("failed to convert new to *unststructured.Unstructured: %w", err)
+ }
+
+ newMapStringAny["status"] = oldMapStringAny["status"]
+
+ if err := fromMapStringAny(newMapStringAny, new); err != nil {
+ return fmt.Errorf("failed to convert back from map[string]any: %w", err)
+ }
+
+ return nil
+}
+
+func toMapStringAny(obj runtime.Object) (map[string]any, error) {
+ if unstructured, isUnstructured := obj.(*unstructured.Unstructured); isUnstructured {
+ return unstructured.Object, nil
+ }
+
+ serialized, err := json.Marshal(obj)
+ if err != nil {
+ return nil, err
+ }
+
+ u := map[string]any{}
+ return u, json.Unmarshal(serialized, &u)
+}
+
+func fromMapStringAny(u map[string]any, target runtime.Object) error {
+ if targetUnstructured, isUnstructured := target.(*unstructured.Unstructured); isUnstructured {
+ targetUnstructured.Object = u
+ return nil
+ }
+
+ serialized, err := json.Marshal(u)
+ if err != nil {
+ return fmt.Errorf("failed to serialize: %w", err)
+ }
+
+ if err := json.Unmarshal(serialized, &target); err != nil {
+ return fmt.Errorf("failed to deserialize: %w", err)
+ }
+
+ return nil
+}
+
+func (c *fakeClient) Status() client.SubResourceWriter {
+ return c.SubResource("status")
+}
+
+func (c *fakeClient) SubResource(subResource string) client.SubResourceClient {
+ return &fakeSubResourceClient{client: c, subResource: subResource}
+}
+
+func (c *fakeClient) deleteObject(gvr schema.GroupVersionResource, accessor metav1.Object) error {
+ old, err := c.tracker.Get(gvr, accessor.GetNamespace(), accessor.GetName())
+ if err == nil {
+ oldAccessor, err := meta.Accessor(old)
+ if err == nil {
+ if len(oldAccessor.GetFinalizers()) > 0 {
+ now := metav1.Now()
+ oldAccessor.SetDeletionTimestamp(&now)
+ // Call update directly with mutability parameter set to true to allow
+ // changes to deletionTimestamp
+ return c.tracker.update(gvr, old, accessor.GetNamespace(), false, true)
+ }
+ }
+ }
+
+ //TODO: implement propagation
+ return c.tracker.Delete(gvr, accessor.GetNamespace(), accessor.GetName())
+}
+
+func getGVRFromObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionResource, error) {
+ gvk, err := apiutil.GVKForObject(obj, scheme)
+ if err != nil {
+ return schema.GroupVersionResource{}, err
+ }
+ gvr, _ := meta.UnsafeGuessKindToResource(gvk)
+ return gvr, nil
+}
+
+type fakeSubResourceClient struct {
+ client *fakeClient
+ subResource string
+}
+
+func (sw *fakeSubResourceClient) Get(ctx context.Context, obj, subResource client.Object, opts ...client.SubResourceGetOption) error {
+ panic("fakeSubResourceClient does not support get")
+}
+
+func (sw *fakeSubResourceClient) Create(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error {
+ switch sw.subResource {
+ case "eviction":
+ _, isEviction := subResource.(*policyv1beta1.Eviction)
+ if !isEviction {
+ _, isEviction = subResource.(*policyv1.Eviction)
+ }
+ if !isEviction {
+ return apierrors.NewBadRequest(fmt.Sprintf("got invalid type %t, expected Eviction", subResource))
+ }
+ if _, isPod := obj.(*corev1.Pod); !isPod {
+ return apierrors.NewNotFound(schema.GroupResource{}, "")
+ }
+
+ return sw.client.Delete(ctx, obj)
+ default:
+ return fmt.Errorf("fakeSubResourceWriter does not support create for %s", sw.subResource)
+ }
+}
+
+func (sw *fakeSubResourceClient) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
+ updateOptions := client.SubResourceUpdateOptions{}
+ updateOptions.ApplyOptions(opts)
+
+ body := obj
+ if updateOptions.SubResourceBody != nil {
+ body = updateOptions.SubResourceBody
+ }
+ return sw.client.update(body, true, &updateOptions.UpdateOptions)
+}
+
+func (sw *fakeSubResourceClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error {
+ patchOptions := client.SubResourcePatchOptions{}
+ patchOptions.ApplyOptions(opts)
+
+ body := obj
+ if patchOptions.SubResourceBody != nil {
+ body = patchOptions.SubResourceBody
+ }
+
+ return sw.client.patch(body, patch, &patchOptions.PatchOptions)
+}
+
+func allowsUnconditionalUpdate(gvk schema.GroupVersionKind) bool {
+ switch gvk.Group {
+ case "apps":
+ switch gvk.Kind {
+ case "ControllerRevision", "DaemonSet", "Deployment", "ReplicaSet", "StatefulSet":
+ return true
+ }
+ case "autoscaling":
+ switch gvk.Kind {
+ case "HorizontalPodAutoscaler":
+ return true
+ }
+ case "batch":
+ switch gvk.Kind {
+ case "CronJob", "Job":
+ return true
+ }
+ case "certificates":
+ switch gvk.Kind {
+ case "Certificates":
+ return true
+ }
+ case "flowcontrol":
+ switch gvk.Kind {
+ case "FlowSchema", "PriorityLevelConfiguration":
+ return true
+ }
+ case "networking":
+ switch gvk.Kind {
+ case "Ingress", "IngressClass", "NetworkPolicy":
+ return true
+ }
+ case "policy":
+ switch gvk.Kind {
+ case "PodSecurityPolicy":
+ return true
+ }
+ case "rbac":
+ switch gvk.Kind {
+ case "ClusterRole", "ClusterRoleBinding", "Role", "RoleBinding":
+ return true
+ }
+ case "scheduling":
+ switch gvk.Kind {
+ case "PriorityClass":
+ return true
+ }
+ case "settings":
+ switch gvk.Kind {
+ case "PodPreset":
+ return true
+ }
+ case "storage":
+ switch gvk.Kind {
+ case "StorageClass":
+ return true
+ }
+ case "":
+ switch gvk.Kind {
+ case "ConfigMap", "Endpoint", "Event", "LimitRange", "Namespace", "Node",
+ "PersistentVolume", "PersistentVolumeClaim", "Pod", "PodTemplate",
+ "ReplicationController", "ResourceQuota", "Secret", "Service",
+ "ServiceAccount", "EndpointSlice":
+ return true
+ }
+ }
+
+ return false
+}
+
+func allowsCreateOnUpdate(gvk schema.GroupVersionKind) bool {
+ switch gvk.Group {
+ case "coordination":
+ switch gvk.Kind {
+ case "Lease":
+ return true
+ }
+ case "node":
+ switch gvk.Kind {
+ case "RuntimeClass":
+ return true
+ }
+ case "rbac":
+ switch gvk.Kind {
+ case "ClusterRole", "ClusterRoleBinding", "Role", "RoleBinding":
+ return true
+ }
+ case "":
+ switch gvk.Kind {
+ case "Endpoint", "Event", "LimitRange", "Service":
+ return true
+ }
+ }
+
+ return false
+}
+
+func inTreeResourcesWithStatus() []schema.GroupVersionKind {
+ return []schema.GroupVersionKind{
+ {Version: "v1", Kind: "Namespace"},
+ {Version: "v1", Kind: "Node"},
+ {Version: "v1", Kind: "PersistentVolumeClaim"},
+ {Version: "v1", Kind: "PersistentVolume"},
+ {Version: "v1", Kind: "Pod"},
+ {Version: "v1", Kind: "ReplicationController"},
+ {Version: "v1", Kind: "Service"},
+
+ {Group: "apps", Version: "v1", Kind: "Deployment"},
+ {Group: "apps", Version: "v1", Kind: "DaemonSet"},
+ {Group: "apps", Version: "v1", Kind: "ReplicaSet"},
+ {Group: "apps", Version: "v1", Kind: "StatefulSet"},
+
+ {Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscaler"},
+
+ {Group: "batch", Version: "v1", Kind: "CronJob"},
+ {Group: "batch", Version: "v1", Kind: "Job"},
+
+ {Group: "certificates.k8s.io", Version: "v1", Kind: "CertificateSigningRequest"},
+
+ {Group: "networking.k8s.io", Version: "v1", Kind: "Ingress"},
+ {Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicy"},
+
+ {Group: "policy", Version: "v1", Kind: "PodDisruptionBudget"},
+
+ {Group: "storage.k8s.io", Version: "v1", Kind: "VolumeAttachment"},
+
+ {Group: "apiextensions.k8s.io", Version: "v1", Kind: "CustomResourceDefinition"},
+
+ {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Kind: "FlowSchema"},
+ {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Kind: "PriorityLevelConfiguration"},
+ }
+}
+
+// zero zeros the value of a pointer.
+func zero(x interface{}) {
+ if x == nil {
+ return
+ }
+ res := reflect.ValueOf(x).Elem()
+ res.Set(reflect.Zero(res.Type()))
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/fake/client_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/fake/client_suite_test.go
new file mode 100644
index 00000000000..66590f0b58b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/fake/client_suite_test.go
@@ -0,0 +1,36 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package fake
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Fake client Suite")
+}
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/fake/client_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/fake/client_test.go
new file mode 100644
index 00000000000..a4e807a5269
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/fake/client_test.go
@@ -0,0 +1,1699 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package fake
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "strconv"
+ "time"
+
+ "sigs.k8s.io/controller-runtime/pkg/client/interceptor"
+
+ "github.com/google/go-cmp/cmp"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/fields"
+ "k8s.io/apimachinery/pkg/labels"
+ "k8s.io/client-go/kubernetes/fake"
+
+ appsv1 "k8s.io/api/apps/v1"
+ coordinationv1 "k8s.io/api/coordination/v1"
+ corev1 "k8s.io/api/core/v1"
+ policyv1 "k8s.io/api/policy/v1"
+ policyv1beta1 "k8s.io/api/policy/v1beta1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/apimachinery/pkg/watch"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+var _ = Describe("Fake client", func() {
+ var dep *appsv1.Deployment
+ var dep2 *appsv1.Deployment
+ var cm *corev1.ConfigMap
+ var cl client.WithWatch
+
+ BeforeEach(func() {
+ replicas := int32(1)
+ dep = &appsv1.Deployment{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "apps/v1",
+ Kind: "Deployment",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-deployment",
+ Namespace: "ns1",
+ ResourceVersion: trackerAddResourceVersion,
+ },
+ Spec: appsv1.DeploymentSpec{
+ Replicas: &replicas,
+ Strategy: appsv1.DeploymentStrategy{
+ Type: appsv1.RecreateDeploymentStrategyType,
+ },
+ },
+ }
+ dep2 = &appsv1.Deployment{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "apps/v1",
+ Kind: "Deployment",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-deployment-2",
+ Namespace: "ns1",
+ Labels: map[string]string{
+ "test-label": "label-value",
+ },
+ ResourceVersion: trackerAddResourceVersion,
+ },
+ Spec: appsv1.DeploymentSpec{
+ Replicas: &replicas,
+ },
+ }
+ cm = &corev1.ConfigMap{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "ConfigMap",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cm",
+ Namespace: "ns2",
+ ResourceVersion: trackerAddResourceVersion,
+ },
+ Data: map[string]string{
+ "test-key": "test-value",
+ },
+ }
+ })
+
+ AssertClientWithoutIndexBehavior := func() {
+ It("should be able to Get", func() {
+ By("Getting a deployment")
+ namespacedName := types.NamespacedName{
+ Name: "test-deployment",
+ Namespace: "ns1",
+ }
+ obj := &appsv1.Deployment{}
+ err := cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ Expect(obj).To(Equal(dep))
+ })
+
+ It("should be able to Get using unstructured", func() {
+ By("Getting a deployment")
+ namespacedName := types.NamespacedName{
+ Name: "test-deployment",
+ Namespace: "ns1",
+ }
+ obj := &unstructured.Unstructured{}
+ obj.SetAPIVersion("apps/v1")
+ obj.SetKind("Deployment")
+ err := cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ })
+
+ It("should be able to List", func() {
+ By("Listing all deployments in a namespace")
+ list := &appsv1.DeploymentList{}
+ err := cl.List(context.Background(), list, client.InNamespace("ns1"))
+ Expect(err).To(BeNil())
+ Expect(list.Items).To(HaveLen(2))
+ Expect(list.Items).To(ConsistOf(*dep, *dep2))
+ })
+
+ It("should be able to List using unstructured list", func() {
+ By("Listing all deployments in a namespace")
+ list := &unstructured.UnstructuredList{}
+ list.SetAPIVersion("apps/v1")
+ list.SetKind("DeploymentList")
+ err := cl.List(context.Background(), list, client.InNamespace("ns1"))
+ Expect(err).To(BeNil())
+ Expect(list.Items).To(HaveLen(2))
+ })
+
+ It("should be able to List using unstructured list when setting a non-list kind", func() {
+ By("Listing all deployments in a namespace")
+ list := &unstructured.UnstructuredList{}
+ list.SetAPIVersion("apps/v1")
+ list.SetKind("Deployment")
+ err := cl.List(context.Background(), list, client.InNamespace("ns1"))
+ Expect(err).To(BeNil())
+ Expect(list.Items).To(HaveLen(2))
+ })
+
+ It("should be able to retrieve registered objects that got manipulated as unstructured", func() {
+ list := func() {
+ By("Listing all endpoints in a namespace")
+ list := &unstructured.UnstructuredList{}
+ list.SetAPIVersion("v1")
+ list.SetKind("EndpointsList")
+ err := cl.List(context.Background(), list, client.InNamespace("ns1"))
+ Expect(err).To(BeNil())
+ Expect(list.Items).To(HaveLen(1))
+ }
+
+ unstructuredEndpoint := func() *unstructured.Unstructured {
+ item := &unstructured.Unstructured{}
+ item.SetAPIVersion("v1")
+ item.SetKind("Endpoints")
+ item.SetName("test-endpoint")
+ item.SetNamespace("ns1")
+ return item
+ }
+
+ By("Adding the object during client initialization")
+ cl = NewFakeClient(unstructuredEndpoint())
+ list()
+ Expect(cl.Delete(context.Background(), unstructuredEndpoint())).To(BeNil())
+
+ By("Creating an object")
+ item := unstructuredEndpoint()
+ err := cl.Create(context.Background(), item)
+ Expect(err).To(BeNil())
+ list()
+
+ By("Updating the object")
+ item.SetAnnotations(map[string]string{"foo": "bar"})
+ err = cl.Update(context.Background(), item)
+ Expect(err).To(BeNil())
+ list()
+
+ By("Patching the object")
+ old := item.DeepCopy()
+ item.SetAnnotations(map[string]string{"bar": "baz"})
+ err = cl.Patch(context.Background(), item, client.MergeFrom(old))
+ Expect(err).To(BeNil())
+ list()
+ })
+
+ It("should be able to Create an unregistered type using unstructured", func() {
+ item := &unstructured.Unstructured{}
+ item.SetAPIVersion("custom/v1")
+ item.SetKind("Image")
+ item.SetName("my-item")
+ err := cl.Create(context.Background(), item)
+ Expect(err).To(BeNil())
+ })
+
+ It("should be able to Get an unregisted type using unstructured", func() {
+ By("Creating an object of an unregistered type")
+ item := &unstructured.Unstructured{}
+ item.SetAPIVersion("custom/v2")
+ item.SetKind("Image")
+ item.SetName("my-item")
+ err := cl.Create(context.Background(), item)
+ Expect(err).To(BeNil())
+
+ By("Getting and the object")
+ item = &unstructured.Unstructured{}
+ item.SetAPIVersion("custom/v2")
+ item.SetKind("Image")
+ item.SetName("my-item")
+ err = cl.Get(context.Background(), client.ObjectKeyFromObject(item), item)
+ Expect(err).To(BeNil())
+ })
+
+ It("should be able to List an unregistered type using unstructured", func() {
+ list := &unstructured.UnstructuredList{}
+ list.SetAPIVersion("custom/v3")
+ list.SetKind("ImageList")
+ err := cl.List(context.Background(), list)
+ Expect(err).To(BeNil())
+ })
+
+ It("should be able to List an unregistered type using unstructured", func() {
+ list := &unstructured.UnstructuredList{}
+ list.SetAPIVersion("custom/v4")
+ list.SetKind("Image")
+ err := cl.List(context.Background(), list)
+ Expect(err).To(BeNil())
+ })
+
+ It("should be able to Update an unregistered type using unstructured", func() {
+ By("Creating an object of an unregistered type")
+ item := &unstructured.Unstructured{}
+ item.SetAPIVersion("custom/v5")
+ item.SetKind("Image")
+ item.SetName("my-item")
+ err := cl.Create(context.Background(), item)
+ Expect(err).To(BeNil())
+
+ By("Updating the object")
+ err = unstructured.SetNestedField(item.Object, int64(2), "spec", "replicas")
+ Expect(err).To(BeNil())
+ err = cl.Update(context.Background(), item)
+ Expect(err).To(BeNil())
+
+ By("Getting the object")
+ item = &unstructured.Unstructured{}
+ item.SetAPIVersion("custom/v5")
+ item.SetKind("Image")
+ item.SetName("my-item")
+ err = cl.Get(context.Background(), client.ObjectKeyFromObject(item), item)
+ Expect(err).To(BeNil())
+
+ By("Inspecting the object")
+ value, found, err := unstructured.NestedInt64(item.Object, "spec", "replicas")
+ Expect(err).To(BeNil())
+ Expect(found).To(BeTrue())
+ Expect(value).To(Equal(int64(2)))
+ })
+
+ It("should be able to Patch an unregistered type using unstructured", func() {
+ By("Creating an object of an unregistered type")
+ item := &unstructured.Unstructured{}
+ item.SetAPIVersion("custom/v6")
+ item.SetKind("Image")
+ item.SetName("my-item")
+ err := cl.Create(context.Background(), item)
+ Expect(err).To(BeNil())
+
+ By("Updating the object")
+ original := item.DeepCopy()
+ err = unstructured.SetNestedField(item.Object, int64(2), "spec", "replicas")
+ Expect(err).To(BeNil())
+ err = cl.Patch(context.Background(), item, client.MergeFrom(original))
+ Expect(err).To(BeNil())
+
+ By("Getting the object")
+ item = &unstructured.Unstructured{}
+ item.SetAPIVersion("custom/v6")
+ item.SetKind("Image")
+ item.SetName("my-item")
+ err = cl.Get(context.Background(), client.ObjectKeyFromObject(item), item)
+ Expect(err).To(BeNil())
+
+ By("Inspecting the object")
+ value, found, err := unstructured.NestedInt64(item.Object, "spec", "replicas")
+ Expect(err).To(BeNil())
+ Expect(found).To(BeTrue())
+ Expect(value).To(Equal(int64(2)))
+ })
+
+ It("should be able to Delete an unregistered type using unstructured", func() {
+ By("Creating an object of an unregistered type")
+ item := &unstructured.Unstructured{}
+ item.SetAPIVersion("custom/v7")
+ item.SetKind("Image")
+ item.SetName("my-item")
+ err := cl.Create(context.Background(), item)
+ Expect(err).To(BeNil())
+
+ By("Deleting the object")
+ err = cl.Delete(context.Background(), item)
+ Expect(err).To(BeNil())
+
+ By("Getting the object")
+ item = &unstructured.Unstructured{}
+ item.SetAPIVersion("custom/v7")
+ item.SetKind("Image")
+ item.SetName("my-item")
+ err = cl.Get(context.Background(), client.ObjectKeyFromObject(item), item)
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+
+ It("should support filtering by labels and their values", func() {
+ By("Listing deployments with a particular label and value")
+ list := &appsv1.DeploymentList{}
+ err := cl.List(context.Background(), list, client.InNamespace("ns1"),
+ client.MatchingLabels(map[string]string{
+ "test-label": "label-value",
+ }))
+ Expect(err).To(BeNil())
+ Expect(list.Items).To(HaveLen(1))
+ Expect(list.Items).To(ConsistOf(*dep2))
+ })
+
+ It("should support filtering by label existence", func() {
+ By("Listing deployments with a particular label")
+ list := &appsv1.DeploymentList{}
+ err := cl.List(context.Background(), list, client.InNamespace("ns1"),
+ client.HasLabels{"test-label"})
+ Expect(err).To(BeNil())
+ Expect(list.Items).To(HaveLen(1))
+ Expect(list.Items).To(ConsistOf(*dep2))
+ })
+
+ It("should be able to Create", func() {
+ By("Creating a new configmap")
+ newcm := &corev1.ConfigMap{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "ConfigMap",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "new-test-cm",
+ Namespace: "ns2",
+ },
+ }
+ err := cl.Create(context.Background(), newcm)
+ Expect(err).To(BeNil())
+
+ By("Getting the new configmap")
+ namespacedName := types.NamespacedName{
+ Name: "new-test-cm",
+ Namespace: "ns2",
+ }
+ obj := &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ Expect(obj).To(Equal(newcm))
+ Expect(obj.ObjectMeta.ResourceVersion).To(Equal("1"))
+ })
+
+ It("should error on create with set resourceVersion", func() {
+ By("Creating a new configmap")
+ newcm := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "new-test-cm",
+ Namespace: "ns2",
+ ResourceVersion: "1",
+ },
+ }
+ err := cl.Create(context.Background(), newcm)
+ Expect(apierrors.IsBadRequest(err)).To(BeTrue())
+ })
+
+ It("should not change the submitted object if Create failed", func() {
+ By("Trying to create an existing configmap")
+ submitted := cm.DeepCopy()
+ submitted.ResourceVersion = ""
+ submittedReference := submitted.DeepCopy()
+ err := cl.Create(context.Background(), submitted)
+ Expect(err).ToNot(BeNil())
+ Expect(apierrors.IsAlreadyExists(err)).To(BeTrue())
+ Expect(submitted).To(Equal(submittedReference))
+ })
+
+ It("should error on Create with empty Name", func() {
+ By("Creating a new configmap")
+ newcm := &corev1.ConfigMap{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "ConfigMap",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "ns2",
+ },
+ }
+ err := cl.Create(context.Background(), newcm)
+ Expect(err.Error()).To(Equal("ConfigMap \"\" is invalid: metadata.name: Required value: name is required"))
+ })
+
+ It("should error on Update with empty Name", func() {
+ By("Creating a new configmap")
+ newcm := &corev1.ConfigMap{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "ConfigMap",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "ns2",
+ },
+ }
+ err := cl.Update(context.Background(), newcm)
+ Expect(err.Error()).To(Equal("ConfigMap \"\" is invalid: metadata.name: Required value: name is required"))
+ })
+
+ It("should be able to Create with GenerateName", func() {
+ By("Creating a new configmap")
+ newcm := &corev1.ConfigMap{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "ConfigMap",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ GenerateName: "new-test-cm",
+ Namespace: "ns2",
+ Labels: map[string]string{
+ "test-label": "label-value",
+ },
+ },
+ }
+ err := cl.Create(context.Background(), newcm)
+ Expect(err).To(BeNil())
+
+ By("Listing configmaps with a particular label")
+ list := &corev1.ConfigMapList{}
+ err = cl.List(context.Background(), list, client.InNamespace("ns2"),
+ client.MatchingLabels(map[string]string{
+ "test-label": "label-value",
+ }))
+ Expect(err).To(BeNil())
+ Expect(list.Items).To(HaveLen(1))
+ Expect(list.Items[0].Name).NotTo(BeEmpty())
+ })
+
+ It("should be able to Update", func() {
+ By("Updating a new configmap")
+ newcm := &corev1.ConfigMap{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "ConfigMap",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cm",
+ Namespace: "ns2",
+ ResourceVersion: "",
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+ err := cl.Update(context.Background(), newcm)
+ Expect(err).To(BeNil())
+
+ By("Getting the new configmap")
+ namespacedName := types.NamespacedName{
+ Name: "test-cm",
+ Namespace: "ns2",
+ }
+ obj := &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ Expect(obj).To(Equal(newcm))
+ Expect(obj.ObjectMeta.ResourceVersion).To(Equal("1000"))
+ })
+
+ It("should allow updates with non-set ResourceVersion for a resource that allows unconditional updates", func() {
+ By("Updating a new configmap")
+ newcm := &corev1.ConfigMap{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "ConfigMap",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cm",
+ Namespace: "ns2",
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+ err := cl.Update(context.Background(), newcm)
+ Expect(err).To(BeNil())
+
+ By("Getting the configmap")
+ namespacedName := types.NamespacedName{
+ Name: "test-cm",
+ Namespace: "ns2",
+ }
+ obj := &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ Expect(obj).To(Equal(newcm))
+ Expect(obj.ObjectMeta.ResourceVersion).To(Equal("1000"))
+ })
+
+ It("should reject updates with non-set ResourceVersion for a resource that doesn't allow unconditional updates", func() {
+ By("Creating a new binding")
+ binding := &corev1.Binding{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Binding",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-binding",
+ Namespace: "ns2",
+ },
+ Target: corev1.ObjectReference{
+ Kind: "ConfigMap",
+ APIVersion: "v1",
+ Namespace: cm.Namespace,
+ Name: cm.Name,
+ },
+ }
+ Expect(cl.Create(context.Background(), binding)).To(Succeed())
+
+ By("Updating the binding with a new resource lacking resource version")
+ newBinding := &corev1.Binding{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Binding",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: binding.Name,
+ Namespace: binding.Namespace,
+ },
+ Target: corev1.ObjectReference{
+ Namespace: binding.Namespace,
+ Name: "blue",
+ },
+ }
+ Expect(cl.Update(context.Background(), newBinding)).NotTo(Succeed())
+ })
+
+ It("should allow create on update for a resource that allows create on update", func() {
+ By("Creating a new lease with update")
+ lease := &coordinationv1.Lease{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "coordination.k8s.io/v1",
+ Kind: "Lease",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-lease",
+ Namespace: "ns2",
+ },
+ Spec: coordinationv1.LeaseSpec{},
+ }
+ Expect(cl.Create(context.Background(), lease)).To(Succeed())
+
+ By("Getting the lease")
+ namespacedName := types.NamespacedName{
+ Name: lease.Name,
+ Namespace: lease.Namespace,
+ }
+ obj := &coordinationv1.Lease{}
+ Expect(cl.Get(context.Background(), namespacedName, obj)).To(Succeed())
+ Expect(obj).To(Equal(lease))
+ Expect(obj.ObjectMeta.ResourceVersion).To(Equal("1"))
+ })
+
+ It("should reject create on update for a resource that does not allow create on update", func() {
+ By("Attemping to create a new configmap with update")
+ newcm := &corev1.ConfigMap{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "ConfigMap",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "different-test-cm",
+ Namespace: "ns2",
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+ Expect(cl.Update(context.Background(), newcm)).NotTo(Succeed())
+ })
+
+ It("should reject updates with non-matching ResourceVersion", func() {
+ By("Updating a new configmap")
+ newcm := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cm",
+ Namespace: "ns2",
+ ResourceVersion: "1",
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+ err := cl.Update(context.Background(), newcm)
+ Expect(apierrors.IsConflict(err)).To(BeTrue())
+
+ By("Getting the configmap")
+ namespacedName := types.NamespacedName{
+ Name: "test-cm",
+ Namespace: "ns2",
+ }
+ obj := &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ Expect(obj).To(Equal(cm))
+ Expect(obj.ObjectMeta.ResourceVersion).To(Equal(trackerAddResourceVersion))
+ })
+
+ It("should reject Delete with a mismatched ResourceVersion", func() {
+ bogusRV := "bogus"
+ By("Deleting with a mismatched ResourceVersion Precondition")
+ err := cl.Delete(context.Background(), dep, client.Preconditions{ResourceVersion: &bogusRV})
+ Expect(apierrors.IsConflict(err)).To(BeTrue())
+
+ list := &appsv1.DeploymentList{}
+ err = cl.List(context.Background(), list, client.InNamespace("ns1"))
+ Expect(err).To(BeNil())
+ Expect(list.Items).To(HaveLen(2))
+ Expect(list.Items).To(ConsistOf(*dep, *dep2))
+ })
+
+ It("should successfully Delete with a matching ResourceVersion", func() {
+ goodRV := trackerAddResourceVersion
+ By("Deleting with a matching ResourceVersion Precondition")
+ err := cl.Delete(context.Background(), dep, client.Preconditions{ResourceVersion: &goodRV})
+ Expect(err).To(BeNil())
+
+ list := &appsv1.DeploymentList{}
+ err = cl.List(context.Background(), list, client.InNamespace("ns1"))
+ Expect(err).To(BeNil())
+ Expect(list.Items).To(HaveLen(1))
+ Expect(list.Items).To(ConsistOf(*dep2))
+ })
+
+ It("should be able to Delete with no ResourceVersion Precondition", func() {
+ By("Deleting a deployment")
+ err := cl.Delete(context.Background(), dep)
+ Expect(err).To(BeNil())
+
+ By("Listing all deployments in the namespace")
+ list := &appsv1.DeploymentList{}
+ err = cl.List(context.Background(), list, client.InNamespace("ns1"))
+ Expect(err).To(BeNil())
+ Expect(list.Items).To(HaveLen(1))
+ Expect(list.Items).To(ConsistOf(*dep2))
+ })
+
+ It("should be able to Delete with no opts even if object's ResourceVersion doesn't match server", func() {
+ By("Deleting a deployment")
+ depCopy := dep.DeepCopy()
+ depCopy.ResourceVersion = "bogus"
+ err := cl.Delete(context.Background(), depCopy)
+ Expect(err).To(BeNil())
+
+ By("Listing all deployments in the namespace")
+ list := &appsv1.DeploymentList{}
+ err = cl.List(context.Background(), list, client.InNamespace("ns1"))
+ Expect(err).To(BeNil())
+ Expect(list.Items).To(HaveLen(1))
+ Expect(list.Items).To(ConsistOf(*dep2))
+ })
+
+ It("should handle finalizers on Update", func() {
+ namespacedName := types.NamespacedName{
+ Name: "test-cm",
+ Namespace: "delete-with-finalizers",
+ }
+ By("Updating a new object")
+ newObj := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespacedName.Name,
+ Namespace: namespacedName.Namespace,
+ Finalizers: []string{"finalizers.sigs.k8s.io/test"},
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+ err := cl.Create(context.Background(), newObj)
+ Expect(err).To(BeNil())
+
+ By("Deleting the object")
+ err = cl.Delete(context.Background(), newObj)
+ Expect(err).To(BeNil())
+
+ By("Getting the object")
+ obj := &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ Expect(obj.DeletionTimestamp).NotTo(BeNil())
+
+ By("Removing the finalizer")
+ obj.Finalizers = []string{}
+ err = cl.Update(context.Background(), obj)
+ Expect(err).To(BeNil())
+
+ By("Getting the object")
+ obj = &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+
+ It("should reject changes to deletionTimestamp on Update", func() {
+ namespacedName := types.NamespacedName{
+ Name: "test-cm",
+ Namespace: "reject-with-deletiontimestamp",
+ }
+ By("Updating a new object")
+ newObj := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespacedName.Name,
+ Namespace: namespacedName.Namespace,
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+ err := cl.Create(context.Background(), newObj)
+ Expect(err).To(BeNil())
+
+ By("Getting the object")
+ obj := &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ Expect(obj.DeletionTimestamp).To(BeNil())
+
+ By("Adding deletionTimestamp")
+ now := metav1.Now()
+ obj.DeletionTimestamp = &now
+ err = cl.Update(context.Background(), obj)
+ Expect(err).NotTo(BeNil())
+
+ By("Deleting the object")
+ err = cl.Delete(context.Background(), newObj)
+ Expect(err).To(BeNil())
+
+ By("Changing the deletionTimestamp to new value")
+ obj = &corev1.ConfigMap{}
+ t := metav1.NewTime(time.Now().Add(time.Second))
+ obj.DeletionTimestamp = &t
+ err = cl.Update(context.Background(), obj)
+ Expect(err).NotTo(BeNil())
+
+ By("Removing deletionTimestamp")
+ obj.DeletionTimestamp = nil
+ err = cl.Update(context.Background(), obj)
+ Expect(err).NotTo(BeNil())
+
+ })
+
+ It("should be able to Delete a Collection", func() {
+ By("Deleting a deploymentList")
+ err := cl.DeleteAllOf(context.Background(), &appsv1.Deployment{}, client.InNamespace("ns1"))
+ Expect(err).To(BeNil())
+
+ By("Listing all deployments in the namespace")
+ list := &appsv1.DeploymentList{}
+ err = cl.List(context.Background(), list, client.InNamespace("ns1"))
+ Expect(err).To(BeNil())
+ Expect(list.Items).To(BeEmpty())
+ })
+
+ It("should handle finalizers deleting a collection", func() {
+ for i := 0; i < 5; i++ {
+ namespacedName := types.NamespacedName{
+ Name: fmt.Sprintf("test-cm-%d", i),
+ Namespace: "delete-collection-with-finalizers",
+ }
+ By("Creating a new object")
+ newObj := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespacedName.Name,
+ Namespace: namespacedName.Namespace,
+ Finalizers: []string{"finalizers.sigs.k8s.io/test"},
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+ err := cl.Create(context.Background(), newObj)
+ Expect(err).To(BeNil())
+ }
+
+ By("Deleting the object")
+ err := cl.DeleteAllOf(context.Background(), &corev1.ConfigMap{}, client.InNamespace("delete-collection-with-finalizers"))
+ Expect(err).To(BeNil())
+
+ configmaps := corev1.ConfigMapList{}
+ err = cl.List(context.Background(), &configmaps, client.InNamespace("delete-collection-with-finalizers"))
+ Expect(err).To(BeNil())
+
+ Expect(len(configmaps.Items)).To(Equal(5))
+ for _, cm := range configmaps.Items {
+ Expect(cm.DeletionTimestamp).NotTo(BeNil())
+ }
+ })
+
+ It("should be able to watch", func() {
+ By("Creating a watch")
+ objWatch, err := cl.Watch(context.Background(), &corev1.ServiceList{})
+ Expect(err).NotTo(HaveOccurred())
+
+ defer objWatch.Stop()
+
+ go func() {
+ defer GinkgoRecover()
+ // It is likely starting a new goroutine is slower than progressing
+ // in the outer routine, sleep to make sure this is always true
+ time.Sleep(100 * time.Millisecond)
+
+ err := cl.Create(context.Background(), &corev1.Service{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "for-watch"}})
+ Expect(err).ToNot(HaveOccurred())
+ }()
+
+ event, ok := <-objWatch.ResultChan()
+ Expect(ok).To(BeTrue())
+ Expect(event.Type).To(Equal(watch.Added))
+
+ service, ok := event.Object.(*corev1.Service)
+ Expect(ok).To(BeTrue())
+ Expect(service.Name).To(Equal("for-watch"))
+ })
+
+ Context("with the DryRun option", func() {
+ It("should not create a new object", func() {
+ By("Creating a new configmap with DryRun")
+ newcm := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "new-test-cm",
+ Namespace: "ns2",
+ },
+ }
+ err := cl.Create(context.Background(), newcm, client.DryRunAll)
+ Expect(err).To(BeNil())
+
+ By("Getting the new configmap")
+ namespacedName := types.NamespacedName{
+ Name: "new-test-cm",
+ Namespace: "ns2",
+ }
+ obj := &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(HaveOccurred())
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ Expect(obj).NotTo(Equal(newcm))
+ })
+
+ It("should not Update the object", func() {
+ By("Updating a new configmap with DryRun")
+ newcm := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cm",
+ Namespace: "ns2",
+ ResourceVersion: "1",
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+ err := cl.Update(context.Background(), newcm, client.DryRunAll)
+ Expect(err).To(BeNil())
+
+ By("Getting the new configmap")
+ namespacedName := types.NamespacedName{
+ Name: "test-cm",
+ Namespace: "ns2",
+ }
+ obj := &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ Expect(obj).To(Equal(cm))
+ Expect(obj.ObjectMeta.ResourceVersion).To(Equal(trackerAddResourceVersion))
+ })
+
+ It("Should not Delete the object", func() {
+ By("Deleting a configmap with DryRun with Delete()")
+ err := cl.Delete(context.Background(), cm, client.DryRunAll)
+ Expect(err).To(BeNil())
+
+ By("Deleting a configmap with DryRun with DeleteAllOf()")
+ err = cl.DeleteAllOf(context.Background(), cm, client.DryRunAll)
+ Expect(err).To(BeNil())
+
+ By("Getting the configmap")
+ namespacedName := types.NamespacedName{
+ Name: "test-cm",
+ Namespace: "ns2",
+ }
+ obj := &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ Expect(obj).To(Equal(cm))
+ Expect(obj.ObjectMeta.ResourceVersion).To(Equal(trackerAddResourceVersion))
+ })
+ })
+
+ It("should be able to Patch", func() {
+ By("Patching a deployment")
+ mergePatch, err := json.Marshal(map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "annotations": map[string]interface{}{
+ "foo": "bar",
+ },
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ err = cl.Patch(context.Background(), dep, client.RawPatch(types.StrategicMergePatchType, mergePatch))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Getting the patched deployment")
+ namespacedName := types.NamespacedName{
+ Name: "test-deployment",
+ Namespace: "ns1",
+ }
+ obj := &appsv1.Deployment{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(obj.Annotations["foo"]).To(Equal("bar"))
+ Expect(obj.ObjectMeta.ResourceVersion).To(Equal("1000"))
+ })
+
+ It("should ignore deletionTimestamp without finalizer on Create", func() {
+ namespacedName := types.NamespacedName{
+ Name: "test-cm",
+ Namespace: "ignore-deletiontimestamp",
+ }
+ By("Creating a new object")
+ now := metav1.Now()
+ newObj := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespacedName.Name,
+ Namespace: namespacedName.Namespace,
+ Finalizers: []string{"finalizers.sigs.k8s.io/test"},
+ DeletionTimestamp: &now,
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+
+ err := cl.Create(context.Background(), newObj)
+ Expect(err).To(BeNil())
+
+ By("Getting the object")
+ obj := &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ Expect(obj.DeletionTimestamp).To(BeNil())
+
+ })
+
+ It("should reject deletionTimestamp without finalizers on Build", func() {
+ namespacedName := types.NamespacedName{
+ Name: "test-cm",
+ Namespace: "reject-deletiontimestamp-no-finalizers",
+ }
+ By("Build with a new object without finalizer")
+ now := metav1.Now()
+ obj := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespacedName.Name,
+ Namespace: namespacedName.Namespace,
+ DeletionTimestamp: &now,
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+
+ Expect(func() { NewClientBuilder().WithObjects(obj).Build() }).To(Panic())
+
+ By("Build with a new object with finalizer")
+ newObj := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespacedName.Name,
+ Namespace: namespacedName.Namespace,
+ Finalizers: []string{"finalizers.sigs.k8s.io/test"},
+ DeletionTimestamp: &now,
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+
+ cl := NewClientBuilder().WithObjects(newObj).Build()
+
+ By("Getting the object")
+ obj = &corev1.ConfigMap{}
+ err := cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+
+ })
+
+ It("should reject changes to deletionTimestamp on Patch", func() {
+ namespacedName := types.NamespacedName{
+ Name: "test-cm",
+ Namespace: "reject-deletiontimestamp",
+ }
+ By("Creating a new object")
+ now := metav1.Now()
+ newObj := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespacedName.Name,
+ Namespace: namespacedName.Namespace,
+ Finalizers: []string{"finalizers.sigs.k8s.io/test"},
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+ err := cl.Create(context.Background(), newObj)
+ Expect(err).To(BeNil())
+
+ By("Add a deletionTimestamp")
+ obj := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespacedName.Name,
+ Namespace: namespacedName.Namespace,
+ Finalizers: []string{},
+ DeletionTimestamp: &now,
+ },
+ }
+ err = cl.Patch(context.Background(), obj, client.MergeFrom(newObj))
+ Expect(err).NotTo(BeNil())
+
+ By("Deleting the object")
+ err = cl.Delete(context.Background(), newObj)
+ Expect(err).To(BeNil())
+
+ By("Getting the object")
+ obj = &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ Expect(obj.DeletionTimestamp).NotTo(BeNil())
+
+ By("Changing the deletionTimestamp to new value")
+ newObj = &corev1.ConfigMap{}
+ t := metav1.NewTime(time.Now().Add(time.Second))
+ newObj.DeletionTimestamp = &t
+ err = cl.Patch(context.Background(), newObj, client.MergeFrom(obj))
+ Expect(err).NotTo(BeNil())
+
+ By("Removing deletionTimestamp")
+ newObj = &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespacedName.Name,
+ Namespace: namespacedName.Namespace,
+ DeletionTimestamp: nil,
+ },
+ }
+ err = cl.Patch(context.Background(), newObj, client.MergeFrom(obj))
+ Expect(err).NotTo(BeNil())
+
+ })
+
+ It("should handle finalizers on Patch", func() {
+ namespacedName := types.NamespacedName{
+ Name: "test-cm",
+ Namespace: "delete-with-finalizers",
+ }
+ By("Creating a new object")
+ newObj := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespacedName.Name,
+ Namespace: namespacedName.Namespace,
+ Finalizers: []string{"finalizers.sigs.k8s.io/test"},
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+ err := cl.Create(context.Background(), newObj)
+ Expect(err).To(BeNil())
+
+ By("Deleting the object")
+ err = cl.Delete(context.Background(), newObj)
+ Expect(err).To(BeNil())
+
+ By("Removing the finalizer")
+ obj := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespacedName.Name,
+ Namespace: namespacedName.Namespace,
+ Finalizers: []string{},
+ },
+ }
+ err = cl.Patch(context.Background(), obj, client.MergeFrom(newObj))
+ Expect(err).To(BeNil())
+
+ By("Getting the object")
+ obj = &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, obj)
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+
+ It("should remove finalizers of the object on Patch", func() {
+ namespacedName := types.NamespacedName{
+ Name: "test-cm",
+ Namespace: "patch-finalizers-in-obj",
+ }
+ By("Creating a new object")
+ obj := &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: namespacedName.Name,
+ Namespace: namespacedName.Namespace,
+ Finalizers: []string{"finalizers.sigs.k8s.io/test"},
+ },
+ Data: map[string]string{
+ "test-key": "new-value",
+ },
+ }
+ err := cl.Create(context.Background(), obj)
+ Expect(err).To(BeNil())
+
+ By("Removing the finalizer")
+ mergePatch, err := json.Marshal(map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "$deleteFromPrimitiveList/finalizers": []string{
+ "finalizers.sigs.k8s.io/test",
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ err = cl.Patch(context.Background(), obj, client.RawPatch(types.StrategicMergePatchType, mergePatch))
+ Expect(err).To(BeNil())
+
+ By("Check the finalizer has been removed in the object")
+ Expect(len(obj.Finalizers)).To(Equal(0))
+
+ By("Check the finalizer has been removed in client")
+ newObj := &corev1.ConfigMap{}
+ err = cl.Get(context.Background(), namespacedName, newObj)
+ Expect(err).To(BeNil())
+ Expect(len(newObj.Finalizers)).To(Equal(0))
+ })
+
+ }
+
+ Context("with default scheme.Scheme", func() {
+ BeforeEach(func() {
+ cl = NewClientBuilder().
+ WithObjects(dep, dep2, cm).
+ Build()
+ })
+ AssertClientWithoutIndexBehavior()
+ })
+
+ Context("with given scheme", func() {
+ BeforeEach(func() {
+ scheme := runtime.NewScheme()
+ Expect(corev1.AddToScheme(scheme)).To(Succeed())
+ Expect(appsv1.AddToScheme(scheme)).To(Succeed())
+ Expect(coordinationv1.AddToScheme(scheme)).To(Succeed())
+ cl = NewClientBuilder().
+ WithScheme(scheme).
+ WithObjects(cm).
+ WithLists(&appsv1.DeploymentList{Items: []appsv1.Deployment{*dep, *dep2}}).
+ Build()
+ })
+ AssertClientWithoutIndexBehavior()
+ })
+
+ Context("with Indexes", func() {
+ depReplicasIndexer := func(obj client.Object) []string {
+ dep, ok := obj.(*appsv1.Deployment)
+ if !ok {
+ panic(fmt.Errorf("indexer function for type %T's spec.replicas field received"+
+ " object of type %T, this should never happen", appsv1.Deployment{}, obj))
+ }
+ indexVal := ""
+ if dep.Spec.Replicas != nil {
+ indexVal = strconv.Itoa(int(*dep.Spec.Replicas))
+ }
+ return []string{indexVal}
+ }
+
+ depStrategyTypeIndexer := func(obj client.Object) []string {
+ dep, ok := obj.(*appsv1.Deployment)
+ if !ok {
+ panic(fmt.Errorf("indexer function for type %T's spec.strategy.type field received"+
+ " object of type %T, this should never happen", appsv1.Deployment{}, obj))
+ }
+ return []string{string(dep.Spec.Strategy.Type)}
+ }
+
+ var cb *ClientBuilder
+ BeforeEach(func() {
+ cb = NewClientBuilder().
+ WithObjects(dep, dep2, cm).
+ WithIndex(&appsv1.Deployment{}, "spec.replicas", depReplicasIndexer)
+ })
+
+ Context("client has just one Index", func() {
+ BeforeEach(func() { cl = cb.Build() })
+
+ Context("behavior that doesn't use an Index", func() {
+ AssertClientWithoutIndexBehavior()
+ })
+
+ Context("filtered List using field selector", func() {
+ It("errors when there's no Index for the GroupVersionResource", func() {
+ listOpts := &client.ListOptions{
+ FieldSelector: fields.OneTermEqualSelector("key", "val"),
+ }
+ err := cl.List(context.Background(), &corev1.ConfigMapList{}, listOpts)
+ Expect(err).NotTo(BeNil())
+ })
+
+ It("errors when there's no Index matching the field name", func() {
+ listOpts := &client.ListOptions{
+ FieldSelector: fields.OneTermEqualSelector("spec.paused", "false"),
+ }
+ err := cl.List(context.Background(), &appsv1.DeploymentList{}, listOpts)
+ Expect(err).NotTo(BeNil())
+ })
+
+ It("errors when field selector uses two requirements", func() {
+ listOpts := &client.ListOptions{
+ FieldSelector: fields.AndSelectors(
+ fields.OneTermEqualSelector("spec.replicas", "1"),
+ fields.OneTermEqualSelector("spec.strategy.type", string(appsv1.RecreateDeploymentStrategyType)),
+ )}
+ err := cl.List(context.Background(), &appsv1.DeploymentList{}, listOpts)
+ Expect(err).NotTo(BeNil())
+ })
+
+ It("returns two deployments that match the only field selector requirement", func() {
+ listOpts := &client.ListOptions{
+ FieldSelector: fields.OneTermEqualSelector("spec.replicas", "1"),
+ }
+ list := &appsv1.DeploymentList{}
+ Expect(cl.List(context.Background(), list, listOpts)).To(Succeed())
+ Expect(list.Items).To(ConsistOf(*dep, *dep2))
+ })
+
+ It("returns no object because no object matches the only field selector requirement", func() {
+ listOpts := &client.ListOptions{
+ FieldSelector: fields.OneTermEqualSelector("spec.replicas", "2"),
+ }
+ list := &appsv1.DeploymentList{}
+ Expect(cl.List(context.Background(), list, listOpts)).To(Succeed())
+ Expect(list.Items).To(BeEmpty())
+ })
+
+ It("returns deployment that matches both the field and label selectors", func() {
+ listOpts := &client.ListOptions{
+ FieldSelector: fields.OneTermEqualSelector("spec.replicas", "1"),
+ LabelSelector: labels.SelectorFromSet(dep2.Labels),
+ }
+ list := &appsv1.DeploymentList{}
+ Expect(cl.List(context.Background(), list, listOpts)).To(Succeed())
+ Expect(list.Items).To(ConsistOf(*dep2))
+ })
+
+ It("returns no object even if field selector matches because label selector doesn't", func() {
+ listOpts := &client.ListOptions{
+ FieldSelector: fields.OneTermEqualSelector("spec.replicas", "1"),
+ LabelSelector: labels.Nothing(),
+ }
+ list := &appsv1.DeploymentList{}
+ Expect(cl.List(context.Background(), list, listOpts)).To(Succeed())
+ Expect(list.Items).To(BeEmpty())
+ })
+
+ It("returns no object even if label selector matches because field selector doesn't", func() {
+ listOpts := &client.ListOptions{
+ FieldSelector: fields.OneTermEqualSelector("spec.replicas", "2"),
+ LabelSelector: labels.Everything(),
+ }
+ list := &appsv1.DeploymentList{}
+ Expect(cl.List(context.Background(), list, listOpts)).To(Succeed())
+ Expect(list.Items).To(BeEmpty())
+ })
+ })
+ })
+
+ Context("client has two Indexes", func() {
+ BeforeEach(func() {
+ cl = cb.WithIndex(&appsv1.Deployment{}, "spec.strategy.type", depStrategyTypeIndexer).Build()
+ })
+
+ Context("behavior that doesn't use an Index", func() {
+ AssertClientWithoutIndexBehavior()
+ })
+
+ Context("filtered List using field selector", func() {
+ It("uses the second index to retrieve the indexed objects when there are matches", func() {
+ listOpts := &client.ListOptions{
+ FieldSelector: fields.OneTermEqualSelector("spec.strategy.type", string(appsv1.RecreateDeploymentStrategyType)),
+ }
+ list := &appsv1.DeploymentList{}
+ Expect(cl.List(context.Background(), list, listOpts)).To(Succeed())
+ Expect(list.Items).To(ConsistOf(*dep))
+ })
+
+ It("uses the second index to retrieve the indexed objects when there are no matches", func() {
+ listOpts := &client.ListOptions{
+ FieldSelector: fields.OneTermEqualSelector("spec.strategy.type", string(appsv1.RollingUpdateDeploymentStrategyType)),
+ }
+ list := &appsv1.DeploymentList{}
+ Expect(cl.List(context.Background(), list, listOpts)).To(Succeed())
+ Expect(list.Items).To(BeEmpty())
+ })
+
+ It("errors when field selector uses two requirements", func() {
+ listOpts := &client.ListOptions{
+ FieldSelector: fields.AndSelectors(
+ fields.OneTermEqualSelector("spec.replicas", "1"),
+ fields.OneTermEqualSelector("spec.strategy.type", string(appsv1.RecreateDeploymentStrategyType)),
+ )}
+ err := cl.List(context.Background(), &appsv1.DeploymentList{}, listOpts)
+ Expect(err).NotTo(BeNil())
+ })
+ })
+ })
+ })
+
+ It("should set the ResourceVersion to 999 when adding an object to the tracker", func() {
+ cl := NewClientBuilder().WithObjects(&corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "cm"}}).Build()
+
+ retrieved := &corev1.Secret{}
+ Expect(cl.Get(context.Background(), types.NamespacedName{Name: "cm"}, retrieved)).To(Succeed())
+
+ reference := &corev1.Secret{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Secret",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "cm",
+ ResourceVersion: "999",
+ },
+ }
+ Expect(retrieved).To(Equal(reference))
+ })
+
+ It("should be able to build with given tracker and get resource", func() {
+ clientSet := fake.NewSimpleClientset(dep)
+ cl := NewClientBuilder().WithRuntimeObjects(dep2).WithObjectTracker(clientSet.Tracker()).Build()
+
+ By("Getting a deployment")
+ namespacedName := types.NamespacedName{
+ Name: "test-deployment",
+ Namespace: "ns1",
+ }
+ obj := &appsv1.Deployment{}
+ err := cl.Get(context.Background(), namespacedName, obj)
+ Expect(err).To(BeNil())
+ Expect(obj).To(Equal(dep))
+
+ By("Getting a deployment from clientSet")
+ csDep2, err := clientSet.AppsV1().Deployments("ns1").Get(context.Background(), "test-deployment-2", metav1.GetOptions{})
+ Expect(err).To(BeNil())
+ Expect(csDep2).To(Equal(dep2))
+
+ By("Getting a new deployment")
+ namespacedName3 := types.NamespacedName{
+ Name: "test-deployment-3",
+ Namespace: "ns1",
+ }
+
+ dep3 := &appsv1.Deployment{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "apps/v1",
+ Kind: "Deployment",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-deployment-3",
+ Namespace: "ns1",
+ Labels: map[string]string{
+ "test-label": "label-value",
+ },
+ ResourceVersion: trackerAddResourceVersion,
+ },
+ }
+
+ _, err = clientSet.AppsV1().Deployments("ns1").Create(context.Background(), dep3, metav1.CreateOptions{})
+ Expect(err).To(BeNil())
+
+ obj = &appsv1.Deployment{}
+ err = cl.Get(context.Background(), namespacedName3, obj)
+ Expect(err).To(BeNil())
+ Expect(obj).To(Equal(dep3))
+ })
+
+ It("should not change the status of typed objects that have a status subresource on update", func() {
+ obj := &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node",
+ },
+ Status: corev1.NodeStatus{
+ NodeInfo: corev1.NodeSystemInfo{MachineID: "machine-id"},
+ },
+ }
+ cl := NewClientBuilder().WithStatusSubresource(obj).WithObjects(obj).Build()
+
+ obj.Status.NodeInfo.MachineID = "updated-machine-id"
+ Expect(cl.Update(context.Background(), obj)).To(BeNil())
+
+ Expect(cl.Get(context.Background(), client.ObjectKeyFromObject(obj), obj)).To(BeNil())
+
+ Expect(obj.Status).To(BeEquivalentTo(corev1.NodeStatus{NodeInfo: corev1.NodeSystemInfo{MachineID: "machine-id"}}))
+ })
+
+ It("should return a conflict error when an incorrect RV is used on status update", func() {
+ obj := &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node",
+ },
+ }
+ cl := NewClientBuilder().WithStatusSubresource(obj).WithObjects(obj).Build()
+
+ obj.Status.Phase = corev1.NodeRunning
+ obj.ResourceVersion = "invalid"
+ err := cl.Update(context.Background(), obj)
+ Expect(apierrors.IsConflict(err)).To(BeTrue())
+ })
+
+ It("should not change non-status field of typed objects that have a status subresource on status update", func() {
+ obj := &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node",
+ },
+ Spec: corev1.NodeSpec{
+ PodCIDR: "old-cidr",
+ },
+ Status: corev1.NodeStatus{
+ NodeInfo: corev1.NodeSystemInfo{
+ MachineID: "machine-id",
+ },
+ },
+ }
+ cl := NewClientBuilder().WithStatusSubresource(obj).WithObjects(obj).Build()
+ objOriginal := obj.DeepCopy()
+
+ obj.Spec.PodCIDR = "cidr-from-status-update"
+ obj.Status.NodeInfo.MachineID = "machine-id-from-status-update"
+ Expect(cl.Status().Update(context.Background(), obj)).NotTo(HaveOccurred())
+
+ actual := &corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: obj.Name}}
+ Expect(cl.Get(context.Background(), client.ObjectKeyFromObject(actual), actual)).NotTo(HaveOccurred())
+
+ objOriginal.APIVersion = actual.APIVersion
+ objOriginal.Kind = actual.Kind
+ objOriginal.ResourceVersion = actual.ResourceVersion
+ objOriginal.Status.NodeInfo.MachineID = "machine-id-from-status-update"
+ Expect(cmp.Diff(objOriginal, actual)).To(BeEmpty())
+ })
+
+ It("should not change the status of typed objects that have a status subresource on patch", func() {
+ obj := &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node",
+ },
+ Status: corev1.NodeStatus{
+ NodeInfo: corev1.NodeSystemInfo{
+ MachineID: "machine-id",
+ },
+ },
+ }
+ Expect(cl.Create(context.Background(), obj)).To(BeNil())
+ original := obj.DeepCopy()
+
+ obj.Status.NodeInfo.MachineID = "machine-id-from-patch"
+ Expect(cl.Patch(context.Background(), obj, client.MergeFrom(original))).To(BeNil())
+
+ Expect(cl.Get(context.Background(), client.ObjectKeyFromObject(obj), obj)).To(BeNil())
+
+ Expect(obj.Status).To(BeEquivalentTo(corev1.NodeStatus{NodeInfo: corev1.NodeSystemInfo{MachineID: "machine-id"}}))
+ })
+
+ It("should not change non-status field of typed objects that have a status subresource on status patch", func() {
+ obj := &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node",
+ },
+ Spec: corev1.NodeSpec{
+ PodCIDR: "old-cidr",
+ },
+ }
+ cl := NewClientBuilder().WithStatusSubresource(obj).WithObjects(obj).Build()
+ objOriginal := obj.DeepCopy()
+
+ obj.Spec.PodCIDR = "cidr-from-status-update"
+ obj.Status.NodeInfo.MachineID = "machine-id"
+ Expect(cl.Status().Patch(context.Background(), obj, client.MergeFrom(objOriginal))).NotTo(HaveOccurred())
+
+ actual := &corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: obj.Name}}
+ Expect(cl.Get(context.Background(), client.ObjectKeyFromObject(actual), actual)).NotTo(HaveOccurred())
+
+ objOriginal.APIVersion = actual.APIVersion
+ objOriginal.Kind = actual.Kind
+ objOriginal.ResourceVersion = actual.ResourceVersion
+ objOriginal.Status.NodeInfo.MachineID = "machine-id"
+ Expect(cmp.Diff(objOriginal, actual)).To(BeEmpty())
+ })
+
+ It("should not change the status of unstructured objects that are configured to have a status subresource on update", func() {
+ obj := &unstructured.Unstructured{}
+ obj.SetAPIVersion("foo/v1")
+ obj.SetKind("Foo")
+ obj.SetName("a-foo")
+
+ err := unstructured.SetNestedField(obj.Object, map[string]any{"state": "old"}, "status")
+ Expect(err).NotTo(HaveOccurred())
+
+ cl := NewClientBuilder().WithStatusSubresource(obj).WithObjects(obj).Build()
+
+ err = unstructured.SetNestedField(obj.Object, map[string]any{"state": "new"}, "status")
+ Expect(err).To(BeNil())
+
+ Expect(cl.Update(context.Background(), obj)).To(BeNil())
+
+ Expect(cl.Get(context.Background(), client.ObjectKeyFromObject(obj), obj)).To(BeNil())
+
+ Expect(obj.Object["status"]).To(BeEquivalentTo(map[string]any{"state": "old"}))
+ })
+
+ It("should not change non-status fields of unstructured objects that are configured to have a status subresource on status update", func() {
+ obj := &unstructured.Unstructured{}
+ obj.SetAPIVersion("foo/v1")
+ obj.SetKind("Foo")
+ obj.SetName("a-foo")
+
+ err := unstructured.SetNestedField(obj.Object, "original", "spec")
+ Expect(err).NotTo(HaveOccurred())
+
+ cl := NewClientBuilder().WithStatusSubresource(obj).WithObjects(obj).Build()
+
+ err = unstructured.SetNestedField(obj.Object, "from-status-update", "spec")
+ Expect(err).NotTo(HaveOccurred())
+ err = unstructured.SetNestedField(obj.Object, map[string]any{"state": "new"}, "status")
+ Expect(err).To(BeNil())
+
+ Expect(cl.Status().Update(context.Background(), obj)).To(BeNil())
+ Expect(cl.Get(context.Background(), client.ObjectKeyFromObject(obj), obj)).To(BeNil())
+
+ Expect(obj.Object["status"]).To(BeEquivalentTo(map[string]any{"state": "new"}))
+ Expect(obj.Object["spec"]).To(BeEquivalentTo("original"))
+ })
+
+ It("should not change the status of unstructured objects that are configured to have a status subresource on patch", func() {
+ obj := &unstructured.Unstructured{}
+ obj.SetAPIVersion("foo/v1")
+ obj.SetKind("Foo")
+ obj.SetName("a-foo")
+ cl := NewClientBuilder().WithStatusSubresource(obj).Build()
+
+ Expect(cl.Create(context.Background(), obj)).To(BeNil())
+ original := obj.DeepCopy()
+
+ err := unstructured.SetNestedField(obj.Object, map[string]interface{}{"count": int64(2)}, "status")
+ Expect(err).To(BeNil())
+ Expect(cl.Patch(context.Background(), obj, client.MergeFrom(original))).To(BeNil())
+
+ Expect(cl.Get(context.Background(), client.ObjectKeyFromObject(obj), obj)).To(BeNil())
+
+ Expect(obj.Object["status"]).To(BeNil())
+
+ })
+
+ It("should not change non-status fields of unstructured objects that are configured to have a status subresource on status patch", func() {
+ obj := &unstructured.Unstructured{}
+ obj.SetAPIVersion("foo/v1")
+ obj.SetKind("Foo")
+ obj.SetName("a-foo")
+
+ err := unstructured.SetNestedField(obj.Object, "original", "spec")
+ Expect(err).NotTo(HaveOccurred())
+
+ cl := NewClientBuilder().WithStatusSubresource(obj).WithObjects(obj).Build()
+ original := obj.DeepCopy()
+
+ err = unstructured.SetNestedField(obj.Object, "from-status-update", "spec")
+ Expect(err).NotTo(HaveOccurred())
+ err = unstructured.SetNestedField(obj.Object, map[string]any{"state": "new"}, "status")
+ Expect(err).To(BeNil())
+
+ Expect(cl.Status().Patch(context.Background(), obj, client.MergeFrom(original))).To(BeNil())
+ Expect(cl.Get(context.Background(), client.ObjectKeyFromObject(obj), obj)).To(BeNil())
+
+ Expect(obj.Object["status"]).To(BeEquivalentTo(map[string]any{"state": "new"}))
+ Expect(obj.Object["spec"]).To(BeEquivalentTo("original"))
+ })
+
+ It("should return not found on status update of resources that don't have a status subresource", func() {
+ obj := &unstructured.Unstructured{}
+ obj.SetAPIVersion("foo/v1")
+ obj.SetKind("Foo")
+ obj.SetName("a-foo")
+
+ cl := NewClientBuilder().WithObjects(obj).Build()
+
+ err := cl.Status().Update(context.Background(), obj)
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+
+ evictionTypes := []client.Object{
+ &policyv1beta1.Eviction{},
+ &policyv1.Eviction{},
+ }
+ for _, tp := range evictionTypes {
+ It("should delete a pod through the eviction subresource", func() {
+ pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}
+
+ cl := NewClientBuilder().WithObjects(pod).Build()
+
+ err := cl.SubResource("eviction").Create(context.Background(), pod, tp)
+ Expect(err).NotTo(HaveOccurred())
+
+ err = cl.Get(context.Background(), client.ObjectKeyFromObject(pod), pod)
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+
+ It("should return not found when attempting to evict a pod that doesn't exist", func() {
+ cl := NewClientBuilder().Build()
+
+ pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}
+ err := cl.SubResource("eviction").Create(context.Background(), pod, tp)
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+
+ It("should return not found when attempting to evict something other than a pod", func() {
+ ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}
+ cl := NewClientBuilder().WithObjects(ns).Build()
+
+ err := cl.SubResource("eviction").Create(context.Background(), ns, tp)
+ Expect(apierrors.IsNotFound(err)).To(BeTrue())
+ })
+
+ It("should return an error when using the wrong subresource", func() {
+ cl := NewClientBuilder().Build()
+
+ err := cl.SubResource("eviction-subresource").Create(context.Background(), &corev1.Namespace{}, tp)
+ Expect(err).NotTo(BeNil())
+ })
+ }
+
+ It("should error when creating an eviction with the wrong type", func() {
+
+ cl := NewClientBuilder().Build()
+ err := cl.SubResource("eviction").Create(context.Background(), &corev1.Pod{}, &corev1.Namespace{})
+ Expect(apierrors.IsBadRequest(err)).To(BeTrue())
+ })
+})
+
+var _ = Describe("Fake client builder", func() {
+ It("panics when an index with the same name and GroupVersionKind is registered twice", func() {
+ // We need any realistic GroupVersionKind, the choice of apps/v1 Deployment is arbitrary.
+ cb := NewClientBuilder().WithIndex(&appsv1.Deployment{},
+ "test-name",
+ func(client.Object) []string { return nil })
+
+ Expect(func() {
+ cb.WithIndex(&appsv1.Deployment{},
+ "test-name",
+ func(client.Object) []string { return []string{"foo"} })
+ }).To(Panic())
+ })
+
+ It("should wrap the fake client with an interceptor when WithInterceptorFuncs is called", func() {
+ var called bool
+ cli := NewClientBuilder().WithInterceptorFuncs(interceptor.Funcs{
+ Get: func(ctx context.Context, client client.WithWatch, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
+ called = true
+ return nil
+ },
+ }).Build()
+ err := cli.Get(context.Background(), client.ObjectKey{}, &corev1.Pod{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(called).To(BeTrue())
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/fake/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/fake/doc.go
new file mode 100644
index 00000000000..d0614666e37
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/fake/doc.go
@@ -0,0 +1,38 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package fake provides a fake client for testing.
+
+A fake client is backed by its simple object store indexed by GroupVersionResource.
+You can create a fake client with optional objects.
+
+ client := NewFakeClientWithScheme(scheme, initObjs...) // initObjs is a slice of runtime.Object
+
+You can invoke the methods defined in the Client interface.
+
+When in doubt, it's almost always better not to use this package and instead use
+envtest.Environment with a real client and API server.
+
+WARNING: ⚠️ Current Limitations / Known Issues with the fake Client ⚠️
+ - This client does not have a way to inject specific errors to test handled vs. unhandled errors.
+ - There is some support for sub resources which can cause issues with tests if you're trying to update
+ e.g. metadata and status in the same reconcile.
+ - No OpenAPI validation is performed when creating or updating objects.
+ - ObjectMeta's `Generation` and `ResourceVersion` don't behave properly, Patch or Update
+ operations that rely on these fields will fail, or give false positives.
+*/
+package fake
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/interceptor/intercept.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/interceptor/intercept.go
new file mode 100644
index 00000000000..3d3f3cb0118
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/interceptor/intercept.go
@@ -0,0 +1,166 @@
+package interceptor
+
+import (
+ "context"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/watch"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// Funcs contains functions that are called instead of the underlying client's methods.
+type Funcs struct {
+ Get func(ctx context.Context, client client.WithWatch, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error
+ List func(ctx context.Context, client client.WithWatch, list client.ObjectList, opts ...client.ListOption) error
+ Create func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.CreateOption) error
+ Delete func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.DeleteOption) error
+ DeleteAllOf func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.DeleteAllOfOption) error
+ Update func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.UpdateOption) error
+ Patch func(ctx context.Context, client client.WithWatch, obj client.Object, patch client.Patch, opts ...client.PatchOption) error
+ Watch func(ctx context.Context, client client.WithWatch, obj client.ObjectList, opts ...client.ListOption) (watch.Interface, error)
+ SubResource func(client client.WithWatch, subResource string) client.SubResourceClient
+ SubResourceGet func(ctx context.Context, client client.Client, subResourceName string, obj client.Object, subResource client.Object, opts ...client.SubResourceGetOption) error
+ SubResourceCreate func(ctx context.Context, client client.Client, subResourceName string, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error
+ SubResourceUpdate func(ctx context.Context, client client.Client, subResourceName string, obj client.Object, opts ...client.SubResourceUpdateOption) error
+ SubResourcePatch func(ctx context.Context, client client.Client, subResourceName string, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error
+}
+
+// NewClient returns a new interceptor client that calls the functions in funcs instead of the underlying client's methods, if they are not nil.
+func NewClient(interceptedClient client.WithWatch, funcs Funcs) client.WithWatch {
+ return interceptor{
+ client: interceptedClient,
+ funcs: funcs,
+ }
+}
+
+type interceptor struct {
+ client client.WithWatch
+ funcs Funcs
+}
+
+var _ client.WithWatch = &interceptor{}
+
+func (c interceptor) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
+ return c.client.GroupVersionKindFor(obj)
+}
+
+func (c interceptor) IsObjectNamespaced(obj runtime.Object) (bool, error) {
+ return c.client.IsObjectNamespaced(obj)
+}
+
+func (c interceptor) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
+ if c.funcs.Get != nil {
+ return c.funcs.Get(ctx, c.client, key, obj, opts...)
+ }
+ return c.client.Get(ctx, key, obj, opts...)
+}
+
+func (c interceptor) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
+ if c.funcs.List != nil {
+ return c.funcs.List(ctx, c.client, list, opts...)
+ }
+ return c.client.List(ctx, list, opts...)
+}
+
+func (c interceptor) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
+ if c.funcs.Create != nil {
+ return c.funcs.Create(ctx, c.client, obj, opts...)
+ }
+ return c.client.Create(ctx, obj, opts...)
+}
+
+func (c interceptor) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
+ if c.funcs.Delete != nil {
+ return c.funcs.Delete(ctx, c.client, obj, opts...)
+ }
+ return c.client.Delete(ctx, obj, opts...)
+}
+
+func (c interceptor) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ if c.funcs.Update != nil {
+ return c.funcs.Update(ctx, c.client, obj, opts...)
+ }
+ return c.client.Update(ctx, obj, opts...)
+}
+
+func (c interceptor) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+ if c.funcs.Patch != nil {
+ return c.funcs.Patch(ctx, c.client, obj, patch, opts...)
+ }
+ return c.client.Patch(ctx, obj, patch, opts...)
+}
+
+func (c interceptor) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
+ if c.funcs.DeleteAllOf != nil {
+ return c.funcs.DeleteAllOf(ctx, c.client, obj, opts...)
+ }
+ return c.client.DeleteAllOf(ctx, obj, opts...)
+}
+
+func (c interceptor) Status() client.SubResourceWriter {
+ return c.SubResource("status")
+}
+
+func (c interceptor) SubResource(subResource string) client.SubResourceClient {
+ if c.funcs.SubResource != nil {
+ return c.funcs.SubResource(c.client, subResource)
+ }
+ return subResourceInterceptor{
+ subResourceName: subResource,
+ client: c.client,
+ funcs: c.funcs,
+ }
+}
+
+func (c interceptor) Scheme() *runtime.Scheme {
+ return c.client.Scheme()
+}
+
+func (c interceptor) RESTMapper() meta.RESTMapper {
+ return c.client.RESTMapper()
+}
+
+func (c interceptor) Watch(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) (watch.Interface, error) {
+ if c.funcs.Watch != nil {
+ return c.funcs.Watch(ctx, c.client, obj, opts...)
+ }
+ return c.client.Watch(ctx, obj, opts...)
+}
+
+type subResourceInterceptor struct {
+ subResourceName string
+ client client.Client
+ funcs Funcs
+}
+
+var _ client.SubResourceClient = &subResourceInterceptor{}
+
+func (s subResourceInterceptor) Get(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceGetOption) error {
+ if s.funcs.SubResourceGet != nil {
+ return s.funcs.SubResourceGet(ctx, s.client, s.subResourceName, obj, subResource, opts...)
+ }
+ return s.client.SubResource(s.subResourceName).Get(ctx, obj, subResource, opts...)
+}
+
+func (s subResourceInterceptor) Create(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error {
+ if s.funcs.SubResourceCreate != nil {
+ return s.funcs.SubResourceCreate(ctx, s.client, s.subResourceName, obj, subResource, opts...)
+ }
+ return s.client.SubResource(s.subResourceName).Create(ctx, obj, subResource, opts...)
+}
+
+func (s subResourceInterceptor) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
+ if s.funcs.SubResourceUpdate != nil {
+ return s.funcs.SubResourceUpdate(ctx, s.client, s.subResourceName, obj, opts...)
+ }
+ return s.client.SubResource(s.subResourceName).Update(ctx, obj, opts...)
+}
+
+func (s subResourceInterceptor) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error {
+ if s.funcs.SubResourcePatch != nil {
+ return s.funcs.SubResourcePatch(ctx, s.client, s.subResourceName, obj, patch, opts...)
+ }
+ return s.client.SubResource(s.subResourceName).Patch(ctx, obj, patch, opts...)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/interceptor/intercept_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/interceptor/intercept_test.go
new file mode 100644
index 00000000000..a0536789b17
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/interceptor/intercept_test.go
@@ -0,0 +1,393 @@
+package interceptor
+
+import (
+ "context"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/apimachinery/pkg/watch"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+var _ = Describe("NewClient", func() {
+ wrappedClient := dummyClient{}
+ ctx := context.Background()
+ It("should call the provided Get function", func() {
+ var called bool
+ client := NewClient(wrappedClient, Funcs{
+ Get: func(ctx context.Context, client client.WithWatch, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
+ called = true
+ return nil
+ },
+ })
+ _ = client.Get(ctx, types.NamespacedName{}, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the underlying client if the provided Get function is nil", func() {
+ var called bool
+ client1 := NewClient(wrappedClient, Funcs{
+ Get: func(ctx context.Context, client client.WithWatch, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
+ called = true
+ return nil
+ },
+ })
+ client2 := NewClient(client1, Funcs{})
+ _ = client2.Get(ctx, types.NamespacedName{}, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the provided List function", func() {
+ var called bool
+ client := NewClient(wrappedClient, Funcs{
+ List: func(ctx context.Context, client client.WithWatch, list client.ObjectList, opts ...client.ListOption) error {
+ called = true
+ return nil
+ },
+ })
+ _ = client.List(ctx, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the underlying client if the provided List function is nil", func() {
+ var called bool
+ client1 := NewClient(wrappedClient, Funcs{
+ List: func(ctx context.Context, client client.WithWatch, list client.ObjectList, opts ...client.ListOption) error {
+ called = true
+ return nil
+ },
+ })
+ client2 := NewClient(client1, Funcs{})
+ _ = client2.List(ctx, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the provided Create function", func() {
+ var called bool
+ client := NewClient(wrappedClient, Funcs{
+ Create: func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.CreateOption) error {
+ called = true
+ return nil
+ },
+ })
+ _ = client.Create(ctx, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the underlying client if the provided Create function is nil", func() {
+ var called bool
+ client1 := NewClient(wrappedClient, Funcs{
+ Create: func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.CreateOption) error {
+ called = true
+ return nil
+ },
+ })
+ client2 := NewClient(client1, Funcs{})
+ _ = client2.Create(ctx, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the provided Delete function", func() {
+ var called bool
+ client := NewClient(wrappedClient, Funcs{
+ Delete: func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.DeleteOption) error {
+ called = true
+ return nil
+ },
+ })
+ _ = client.Delete(ctx, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the underlying client if the provided Delete function is nil", func() {
+ var called bool
+ client1 := NewClient(wrappedClient, Funcs{
+ Delete: func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.DeleteOption) error {
+ called = true
+ return nil
+ },
+ })
+ client2 := NewClient(client1, Funcs{})
+ _ = client2.Delete(ctx, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the provided DeleteAllOf function", func() {
+ var called bool
+ client := NewClient(wrappedClient, Funcs{
+ DeleteAllOf: func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.DeleteAllOfOption) error {
+ called = true
+ return nil
+ },
+ })
+ _ = client.DeleteAllOf(ctx, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the underlying client if the provided DeleteAllOf function is nil", func() {
+ var called bool
+ client1 := NewClient(wrappedClient, Funcs{
+ DeleteAllOf: func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.DeleteAllOfOption) error {
+ called = true
+ return nil
+ },
+ })
+ client2 := NewClient(client1, Funcs{})
+ _ = client2.DeleteAllOf(ctx, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the provided Update function", func() {
+ var called bool
+ client := NewClient(wrappedClient, Funcs{
+ Update: func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.UpdateOption) error {
+ called = true
+ return nil
+ },
+ })
+ _ = client.Update(ctx, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the underlying client if the provided Update function is nil", func() {
+ var called bool
+ client1 := NewClient(wrappedClient, Funcs{
+ Update: func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.UpdateOption) error {
+ called = true
+ return nil
+ },
+ })
+ client2 := NewClient(client1, Funcs{})
+ _ = client2.Update(ctx, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the provided Patch function", func() {
+ var called bool
+ client := NewClient(wrappedClient, Funcs{
+ Patch: func(ctx context.Context, client client.WithWatch, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+ called = true
+ return nil
+ },
+ })
+ _ = client.Patch(ctx, nil, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the underlying client if the provided Patch function is nil", func() {
+ var called bool
+ client1 := NewClient(wrappedClient, Funcs{
+ Patch: func(ctx context.Context, client client.WithWatch, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+ called = true
+ return nil
+ },
+ })
+ client2 := NewClient(client1, Funcs{})
+ _ = client2.Patch(ctx, nil, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the provided Watch function", func() {
+ var called bool
+ client := NewClient(wrappedClient, Funcs{
+ Watch: func(ctx context.Context, client client.WithWatch, obj client.ObjectList, opts ...client.ListOption) (watch.Interface, error) {
+ called = true
+ return nil, nil
+ },
+ })
+ _, _ = client.Watch(ctx, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the underlying client if the provided Watch function is nil", func() {
+ var called bool
+ client1 := NewClient(wrappedClient, Funcs{
+ Watch: func(ctx context.Context, client client.WithWatch, obj client.ObjectList, opts ...client.ListOption) (watch.Interface, error) {
+ called = true
+ return nil, nil
+ },
+ })
+ client2 := NewClient(client1, Funcs{})
+ _, _ = client2.Watch(ctx, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the provided SubResource function", func() {
+ var called bool
+ client := NewClient(wrappedClient, Funcs{
+ SubResource: func(client client.WithWatch, subResource string) client.SubResourceClient {
+ called = true
+ return nil
+ },
+ })
+ _ = client.SubResource("")
+ Expect(called).To(BeTrue())
+ })
+ It("should call the provided SubResource function with 'status' when calling Status()", func() {
+ var called bool
+ client := NewClient(wrappedClient, Funcs{
+ SubResource: func(client client.WithWatch, subResource string) client.SubResourceClient {
+ if subResource == "status" {
+ called = true
+ }
+ return nil
+ },
+ })
+ _ = client.Status()
+ Expect(called).To(BeTrue())
+ })
+})
+
+var _ = Describe("NewSubResourceClient", func() {
+ c := dummyClient{}
+ ctx := context.Background()
+ It("should call the provided Get function", func() {
+ var called bool
+ c := NewClient(c, Funcs{
+ SubResourceGet: func(_ context.Context, client client.Client, subResourceName string, obj, subResource client.Object, opts ...client.SubResourceGetOption) error {
+ called = true
+ Expect(subResourceName).To(BeEquivalentTo("foo"))
+ return nil
+ },
+ })
+ _ = c.SubResource("foo").Get(ctx, nil, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the underlying client if the provided Get function is nil", func() {
+ var called bool
+ client1 := NewClient(c, Funcs{
+ SubResourceGet: func(_ context.Context, client client.Client, subResourceName string, obj, subResource client.Object, opts ...client.SubResourceGetOption) error {
+ called = true
+ Expect(subResourceName).To(BeEquivalentTo("foo"))
+ return nil
+ },
+ })
+ client2 := NewClient(client1, Funcs{})
+ _ = client2.SubResource("foo").Get(ctx, nil, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the provided Update function", func() {
+ var called bool
+ client := NewClient(c, Funcs{
+ SubResourceUpdate: func(_ context.Context, client client.Client, subResourceName string, obj client.Object, opts ...client.SubResourceUpdateOption) error {
+ called = true
+ Expect(subResourceName).To(BeEquivalentTo("foo"))
+ return nil
+ },
+ })
+ _ = client.SubResource("foo").Update(ctx, nil, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the underlying client if the provided Update function is nil", func() {
+ var called bool
+ client1 := NewClient(c, Funcs{
+ SubResourceUpdate: func(_ context.Context, client client.Client, subResourceName string, obj client.Object, opts ...client.SubResourceUpdateOption) error {
+ called = true
+ Expect(subResourceName).To(BeEquivalentTo("foo"))
+ return nil
+ },
+ })
+ client2 := NewClient(client1, Funcs{})
+ _ = client2.SubResource("foo").Update(ctx, nil, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the provided Patch function", func() {
+ var called bool
+ client := NewClient(c, Funcs{
+ SubResourcePatch: func(_ context.Context, client client.Client, subResourceName string, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error {
+ called = true
+ Expect(subResourceName).To(BeEquivalentTo("foo"))
+ return nil
+ },
+ })
+ _ = client.SubResource("foo").Patch(ctx, nil, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the underlying client if the provided Patch function is nil", func() {
+ var called bool
+ client1 := NewClient(c, Funcs{
+ SubResourcePatch: func(ctx context.Context, client client.Client, subResourceName string, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error {
+ called = true
+ Expect(subResourceName).To(BeEquivalentTo("foo"))
+ return nil
+ },
+ })
+ client2 := NewClient(client1, Funcs{})
+ _ = client2.SubResource("foo").Patch(ctx, nil, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the provided Create function", func() {
+ var called bool
+ client := NewClient(c, Funcs{
+ SubResourceCreate: func(_ context.Context, client client.Client, subResourceName string, obj, subResource client.Object, opts ...client.SubResourceCreateOption) error {
+ called = true
+ Expect(subResourceName).To(BeEquivalentTo("foo"))
+ return nil
+ },
+ })
+ _ = client.SubResource("foo").Create(ctx, nil, nil)
+ Expect(called).To(BeTrue())
+ })
+ It("should call the underlying client if the provided Create function is nil", func() {
+ var called bool
+ client1 := NewClient(c, Funcs{
+ SubResourceCreate: func(_ context.Context, client client.Client, subResourceName string, obj, subResource client.Object, opts ...client.SubResourceCreateOption) error {
+ called = true
+ Expect(subResourceName).To(BeEquivalentTo("foo"))
+ return nil
+ },
+ })
+ client2 := NewClient(client1, Funcs{})
+ _ = client2.SubResource("foo").Create(ctx, nil, nil)
+ Expect(called).To(BeTrue())
+ })
+})
+
+type dummyClient struct{}
+
+var _ client.WithWatch = &dummyClient{}
+
+func (d dummyClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
+ return nil
+}
+
+func (d dummyClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
+ return nil
+}
+
+func (d dummyClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
+ return nil
+}
+
+func (d dummyClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
+ return nil
+}
+
+func (d dummyClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return nil
+}
+
+func (d dummyClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+ return nil
+}
+
+func (d dummyClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
+ return nil
+}
+
+func (d dummyClient) Status() client.SubResourceWriter {
+ return d.SubResource("status")
+}
+
+func (d dummyClient) SubResource(subResource string) client.SubResourceClient {
+ return nil
+}
+
+func (d dummyClient) Scheme() *runtime.Scheme {
+ return nil
+}
+
+func (d dummyClient) RESTMapper() meta.RESTMapper {
+ return nil
+}
+
+func (d dummyClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
+ return schema.GroupVersionKind{}, nil
+}
+
+func (d dummyClient) IsObjectNamespaced(obj runtime.Object) (bool, error) {
+ return false, nil
+}
+
+func (d dummyClient) Watch(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) (watch.Interface, error) {
+ return nil, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/interceptor/interceptor_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/interceptor/interceptor_suite_test.go
new file mode 100644
index 00000000000..08d9fe22812
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/interceptor/interceptor_suite_test.go
@@ -0,0 +1,36 @@
+/*
+Copyright 2022 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package interceptor
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestInterceptor(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Fake client Suite")
+}
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
new file mode 100644
index 00000000000..0ddda3163d8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
@@ -0,0 +1,222 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/apimachinery/pkg/watch"
+)
+
+// ObjectKey identifies a Kubernetes Object.
+type ObjectKey = types.NamespacedName
+
+// ObjectKeyFromObject returns the ObjectKey given a runtime.Object.
+func ObjectKeyFromObject(obj Object) ObjectKey {
+ return ObjectKey{Namespace: obj.GetNamespace(), Name: obj.GetName()}
+}
+
+// Patch is a patch that can be applied to a Kubernetes object.
+type Patch interface {
+ // Type is the PatchType of the patch.
+ Type() types.PatchType
+ // Data is the raw data representing the patch.
+ Data(obj Object) ([]byte, error)
+}
+
+// TODO(directxman12): is there a sane way to deal with get/delete options?
+
+// Reader knows how to read and list Kubernetes objects.
+type Reader interface {
+ // Get retrieves an obj for the given object key from the Kubernetes Cluster.
+ // obj must be a struct pointer so that obj can be updated with the response
+ // returned by the Server.
+ Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error
+
+ // List retrieves list of objects for a given namespace and list options. On a
+ // successful call, Items field in the list will be populated with the
+ // result returned from the server.
+ List(ctx context.Context, list ObjectList, opts ...ListOption) error
+}
+
+// Writer knows how to create, delete, and update Kubernetes objects.
+type Writer interface {
+ // Create saves the object obj in the Kubernetes cluster. obj must be a
+ // struct pointer so that obj can be updated with the content returned by the Server.
+ Create(ctx context.Context, obj Object, opts ...CreateOption) error
+
+ // Delete deletes the given obj from Kubernetes cluster.
+ Delete(ctx context.Context, obj Object, opts ...DeleteOption) error
+
+ // Update updates the given obj in the Kubernetes cluster. obj must be a
+ // struct pointer so that obj can be updated with the content returned by the Server.
+ Update(ctx context.Context, obj Object, opts ...UpdateOption) error
+
+ // Patch patches the given obj in the Kubernetes cluster. obj must be a
+ // struct pointer so that obj can be updated with the content returned by the Server.
+ Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error
+
+ // DeleteAllOf deletes all objects of the given type matching the given options.
+ DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error
+}
+
+// StatusClient knows how to create a client which can update status subresource
+// for kubernetes objects.
+type StatusClient interface {
+ Status() SubResourceWriter
+}
+
+// SubResourceClientConstructor knows how to create a client which can update subresource
+// for kubernetes objects.
+type SubResourceClientConstructor interface {
+ // SubResourceClientConstructor returns a subresource client for the named subResource. Known
+ // upstream subResources usages are:
+ // - ServiceAccount token creation:
+ // sa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}}
+ // token := &authenticationv1.TokenRequest{}
+ // c.SubResourceClient("token").Create(ctx, sa, token)
+ //
+ // - Pod eviction creation:
+ // pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}}
+ // c.SubResourceClient("eviction").Create(ctx, pod, &policyv1.Eviction{})
+ //
+ // - Pod binding creation:
+ // pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}}
+ // binding := &corev1.Binding{Target: corev1.ObjectReference{Name: "my-node"}}
+ // c.SubResourceClient("binding").Create(ctx, pod, binding)
+ //
+ // - CertificateSigningRequest approval:
+ // csr := &certificatesv1.CertificateSigningRequest{
+ // ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
+ // Status: certificatesv1.CertificateSigningRequestStatus{
+ // Conditions: []certificatesv1.[]CertificateSigningRequestCondition{{
+ // Type: certificatesv1.CertificateApproved,
+ // Status: corev1.ConditionTrue,
+ // }},
+ // },
+ // }
+ // c.SubResourceClient("approval").Update(ctx, csr)
+ //
+ // - Scale retrieval:
+ // dep := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}}
+ // scale := &autoscalingv1.Scale{}
+ // c.SubResourceClient("scale").Get(ctx, dep, scale)
+ //
+ // - Scale update:
+ // dep := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}}
+ // scale := &autoscalingv1.Scale{Spec: autoscalingv1.ScaleSpec{Replicas: 2}}
+ // c.SubResourceClient("scale").Update(ctx, dep, client.WithSubResourceBody(scale))
+ SubResource(subResource string) SubResourceClient
+}
+
+// StatusWriter is kept for backward compatibility.
+type StatusWriter = SubResourceWriter
+
+// SubResourceReader knows how to read SubResources
+type SubResourceReader interface {
+ Get(ctx context.Context, obj Object, subResource Object, opts ...SubResourceGetOption) error
+}
+
+// SubResourceWriter knows how to update subresource of a Kubernetes object.
+type SubResourceWriter interface {
+ // Create saves the subResource object in the Kubernetes cluster. obj must be a
+ // struct pointer so that obj can be updated with the content returned by the Server.
+ Create(ctx context.Context, obj Object, subResource Object, opts ...SubResourceCreateOption) error
+ // Update updates the fields corresponding to the status subresource for the
+ // given obj. obj must be a struct pointer so that obj can be updated
+ // with the content returned by the Server.
+ Update(ctx context.Context, obj Object, opts ...SubResourceUpdateOption) error
+
+ // Patch patches the given object's subresource. obj must be a struct
+ // pointer so that obj can be updated with the content returned by the
+ // Server.
+ Patch(ctx context.Context, obj Object, patch Patch, opts ...SubResourcePatchOption) error
+}
+
+// SubResourceClient knows how to perform CRU operations on Kubernetes objects.
+type SubResourceClient interface {
+ SubResourceReader
+ SubResourceWriter
+}
+
+// Client knows how to perform CRUD operations on Kubernetes objects.
+type Client interface {
+ Reader
+ Writer
+ StatusClient
+ SubResourceClientConstructor
+
+ // Scheme returns the scheme this client is using.
+ Scheme() *runtime.Scheme
+ // RESTMapper returns the rest this client is using.
+ RESTMapper() meta.RESTMapper
+ // GroupVersionKindFor returns the GroupVersionKind for the given object.
+ GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error)
+ // IsObjectNamespaced returns true if the GroupVersionKind of the object is namespaced.
+ IsObjectNamespaced(obj runtime.Object) (bool, error)
+}
+
+// WithWatch supports Watch on top of the CRUD operations supported by
+// the normal Client. Its intended use-case are CLI apps that need to wait for
+// events.
+type WithWatch interface {
+ Client
+ Watch(ctx context.Context, obj ObjectList, opts ...ListOption) (watch.Interface, error)
+}
+
+// IndexerFunc knows how to take an object and turn it into a series
+// of non-namespaced keys. Namespaced objects are automatically given
+// namespaced and non-spaced variants, so keys do not need to include namespace.
+type IndexerFunc func(Object) []string
+
+// FieldIndexer knows how to index over a particular "field" such that it
+// can later be used by a field selector.
+type FieldIndexer interface {
+ // IndexFields adds an index with the given field name on the given object type
+ // by using the given function to extract the value for that field. If you want
+ // compatibility with the Kubernetes API server, only return one key, and only use
+ // fields that the API server supports. Otherwise, you can return multiple keys,
+ // and "equality" in the field selector means that at least one key matches the value.
+ // The FieldIndexer will automatically take care of indexing over namespace
+ // and supporting efficient all-namespace queries.
+ IndexField(ctx context.Context, obj Object, field string, extractValue IndexerFunc) error
+}
+
+// IgnoreNotFound returns nil on NotFound errors.
+// All other values that are not NotFound errors or nil are returned unmodified.
+func IgnoreNotFound(err error) error {
+ if apierrors.IsNotFound(err) {
+ return nil
+ }
+ return err
+}
+
+// IgnoreAlreadyExists returns nil on AlreadyExists errors.
+// All other values that are not AlreadyExists errors or nil are returned unmodified.
+func IgnoreAlreadyExists(err error) error {
+ if apierrors.IsAlreadyExists(err) {
+ return nil
+ }
+
+ return err
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go
new file mode 100644
index 00000000000..d0c6b8e13ae
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go
@@ -0,0 +1,204 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/metadata"
+)
+
+// TODO(directxman12): we could rewrite this on top of the low-level REST
+// client to avoid the extra shallow copy at the end, but I'm not sure it's
+// worth it -- the metadata client deals with falling back to loading the whole
+// object on older API servers, etc, and we'd have to reproduce that.
+
+// metadataClient is a client that reads & writes metadata-only requests to/from the API server.
+type metadataClient struct {
+ client metadata.Interface
+ restMapper meta.RESTMapper
+}
+
+func (mc *metadataClient) getResourceInterface(gvk schema.GroupVersionKind, ns string) (metadata.ResourceInterface, error) {
+ mapping, err := mc.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
+ if err != nil {
+ return nil, err
+ }
+ if mapping.Scope.Name() == meta.RESTScopeNameRoot {
+ return mc.client.Resource(mapping.Resource), nil
+ }
+ return mc.client.Resource(mapping.Resource).Namespace(ns), nil
+}
+
+// Delete implements client.Client.
+func (mc *metadataClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
+ metadata, ok := obj.(*metav1.PartialObjectMetadata)
+ if !ok {
+ return fmt.Errorf("metadata client did not understand object: %T", obj)
+ }
+
+ resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), metadata.Namespace)
+ if err != nil {
+ return err
+ }
+
+ deleteOpts := DeleteOptions{}
+ deleteOpts.ApplyOptions(opts)
+
+ return resInt.Delete(ctx, metadata.Name, *deleteOpts.AsDeleteOptions())
+}
+
+// DeleteAllOf implements client.Client.
+func (mc *metadataClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
+ metadata, ok := obj.(*metav1.PartialObjectMetadata)
+ if !ok {
+ return fmt.Errorf("metadata client did not understand object: %T", obj)
+ }
+
+ deleteAllOfOpts := DeleteAllOfOptions{}
+ deleteAllOfOpts.ApplyOptions(opts)
+
+ resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), deleteAllOfOpts.ListOptions.Namespace)
+ if err != nil {
+ return err
+ }
+
+ return resInt.DeleteCollection(ctx, *deleteAllOfOpts.AsDeleteOptions(), *deleteAllOfOpts.AsListOptions())
+}
+
+// Patch implements client.Client.
+func (mc *metadataClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ metadata, ok := obj.(*metav1.PartialObjectMetadata)
+ if !ok {
+ return fmt.Errorf("metadata client did not understand object: %T", obj)
+ }
+
+ gvk := metadata.GroupVersionKind()
+ resInt, err := mc.getResourceInterface(gvk, metadata.Namespace)
+ if err != nil {
+ return err
+ }
+
+ data, err := patch.Data(obj)
+ if err != nil {
+ return err
+ }
+
+ patchOpts := &PatchOptions{}
+ patchOpts.ApplyOptions(opts)
+
+ res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions())
+ if err != nil {
+ return err
+ }
+ *metadata = *res
+ metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
+ return nil
+}
+
+// Get implements client.Client.
+func (mc *metadataClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
+ metadata, ok := obj.(*metav1.PartialObjectMetadata)
+ if !ok {
+ return fmt.Errorf("metadata client did not understand object: %T", obj)
+ }
+
+ gvk := metadata.GroupVersionKind()
+
+ getOpts := GetOptions{}
+ getOpts.ApplyOptions(opts)
+
+ resInt, err := mc.getResourceInterface(gvk, key.Namespace)
+ if err != nil {
+ return err
+ }
+
+ res, err := resInt.Get(ctx, key.Name, *getOpts.AsGetOptions())
+ if err != nil {
+ return err
+ }
+ *metadata = *res
+ metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
+ return nil
+}
+
+// List implements client.Client.
+func (mc *metadataClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
+ metadata, ok := obj.(*metav1.PartialObjectMetadataList)
+ if !ok {
+ return fmt.Errorf("metadata client did not understand object: %T", obj)
+ }
+
+ gvk := metadata.GroupVersionKind()
+ gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
+
+ listOpts := ListOptions{}
+ listOpts.ApplyOptions(opts)
+
+ resInt, err := mc.getResourceInterface(gvk, listOpts.Namespace)
+ if err != nil {
+ return err
+ }
+
+ res, err := resInt.List(ctx, *listOpts.AsListOptions())
+ if err != nil {
+ return err
+ }
+ *metadata = *res
+ metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
+ return nil
+}
+
+func (mc *metadataClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...SubResourcePatchOption) error {
+ metadata, ok := obj.(*metav1.PartialObjectMetadata)
+ if !ok {
+ return fmt.Errorf("metadata client did not understand object: %T", obj)
+ }
+
+ gvk := metadata.GroupVersionKind()
+ resInt, err := mc.getResourceInterface(gvk, metadata.Namespace)
+ if err != nil {
+ return err
+ }
+
+ patchOpts := &SubResourcePatchOptions{}
+ patchOpts.ApplyOptions(opts)
+
+ body := obj
+ if patchOpts.SubResourceBody != nil {
+ body = patchOpts.SubResourceBody
+ }
+
+ data, err := patch.Data(body)
+ if err != nil {
+ return err
+ }
+
+ res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions(), subResource)
+ if err != nil {
+ return err
+ }
+
+ *metadata = *res
+ metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
+ return nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go
new file mode 100644
index 00000000000..222dc795793
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go
@@ -0,0 +1,262 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "fmt"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// NewNamespacedClient wraps an existing client enforcing the namespace value.
+// All functions using this client will have the same namespace declared here.
+func NewNamespacedClient(c Client, ns string) Client {
+ return &namespacedClient{
+ client: c,
+ namespace: ns,
+ }
+}
+
+var _ Client = &namespacedClient{}
+
+// namespacedClient is a Client that wraps another Client in order to enforce the specified namespace value.
+type namespacedClient struct {
+ namespace string
+ client Client
+}
+
+// Scheme returns the scheme this client is using.
+func (n *namespacedClient) Scheme() *runtime.Scheme {
+ return n.client.Scheme()
+}
+
+// RESTMapper returns the scheme this client is using.
+func (n *namespacedClient) RESTMapper() meta.RESTMapper {
+ return n.client.RESTMapper()
+}
+
+// GroupVersionKindFor returns the GroupVersionKind for the given object.
+func (n *namespacedClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
+ return n.client.GroupVersionKindFor(obj)
+}
+
+// IsObjectNamespaced returns true if the GroupVersionKind of the object is namespaced.
+func (n *namespacedClient) IsObjectNamespaced(obj runtime.Object) (bool, error) {
+ return n.client.IsObjectNamespaced(obj)
+}
+
+// Create implements client.Client.
+func (n *namespacedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
+ isNamespaceScoped, err := n.IsObjectNamespaced(obj)
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %w", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != n.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(n.namespace)
+ }
+ return n.client.Create(ctx, obj, opts...)
+}
+
+// Update implements client.Client.
+func (n *namespacedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ isNamespaceScoped, err := n.IsObjectNamespaced(obj)
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %w", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != n.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(n.namespace)
+ }
+ return n.client.Update(ctx, obj, opts...)
+}
+
+// Delete implements client.Client.
+func (n *namespacedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
+ isNamespaceScoped, err := n.IsObjectNamespaced(obj)
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %w", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != n.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(n.namespace)
+ }
+ return n.client.Delete(ctx, obj, opts...)
+}
+
+// DeleteAllOf implements client.Client.
+func (n *namespacedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
+ isNamespaceScoped, err := n.IsObjectNamespaced(obj)
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %w", err)
+ }
+
+ if isNamespaceScoped {
+ opts = append(opts, InNamespace(n.namespace))
+ }
+ return n.client.DeleteAllOf(ctx, obj, opts...)
+}
+
+// Patch implements client.Client.
+func (n *namespacedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ isNamespaceScoped, err := n.IsObjectNamespaced(obj)
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %w", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != n.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(n.namespace)
+ }
+ return n.client.Patch(ctx, obj, patch, opts...)
+}
+
+// Get implements client.Client.
+func (n *namespacedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
+ isNamespaceScoped, err := n.IsObjectNamespaced(obj)
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %w", err)
+ }
+ if isNamespaceScoped {
+ if key.Namespace != "" && key.Namespace != n.namespace {
+ return fmt.Errorf("namespace %s provided for the object %s does not match the namespace %s on the client", key.Namespace, obj.GetName(), n.namespace)
+ }
+ key.Namespace = n.namespace
+ }
+ return n.client.Get(ctx, key, obj, opts...)
+}
+
+// List implements client.Client.
+func (n *namespacedClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
+ if n.namespace != "" {
+ opts = append(opts, InNamespace(n.namespace))
+ }
+ return n.client.List(ctx, obj, opts...)
+}
+
+// Status implements client.StatusClient.
+func (n *namespacedClient) Status() SubResourceWriter {
+ return n.SubResource("status")
+}
+
+// SubResource implements client.SubResourceClient.
+func (n *namespacedClient) SubResource(subResource string) SubResourceClient {
+ return &namespacedClientSubResourceClient{client: n.client.SubResource(subResource), namespace: n.namespace, namespacedclient: n}
+}
+
+// ensure namespacedClientSubResourceClient implements client.SubResourceClient.
+var _ SubResourceClient = &namespacedClientSubResourceClient{}
+
+type namespacedClientSubResourceClient struct {
+ client SubResourceClient
+ namespace string
+ namespacedclient Client
+}
+
+func (nsw *namespacedClientSubResourceClient) Get(ctx context.Context, obj, subResource Object, opts ...SubResourceGetOption) error {
+ isNamespaceScoped, err := nsw.namespacedclient.IsObjectNamespaced(obj)
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %w", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != nsw.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(nsw.namespace)
+ }
+
+ return nsw.client.Get(ctx, obj, subResource, opts...)
+}
+
+func (nsw *namespacedClientSubResourceClient) Create(ctx context.Context, obj, subResource Object, opts ...SubResourceCreateOption) error {
+ isNamespaceScoped, err := nsw.namespacedclient.IsObjectNamespaced(obj)
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %w", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != nsw.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(nsw.namespace)
+ }
+
+ return nsw.client.Create(ctx, obj, subResource, opts...)
+}
+
+// Update implements client.SubResourceWriter.
+func (nsw *namespacedClientSubResourceClient) Update(ctx context.Context, obj Object, opts ...SubResourceUpdateOption) error {
+ isNamespaceScoped, err := nsw.namespacedclient.IsObjectNamespaced(obj)
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %w", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != nsw.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(nsw.namespace)
+ }
+ return nsw.client.Update(ctx, obj, opts...)
+}
+
+// Patch implements client.SubResourceWriter.
+func (nsw *namespacedClientSubResourceClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...SubResourcePatchOption) error {
+ isNamespaceScoped, err := nsw.namespacedclient.IsObjectNamespaced(obj)
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %w", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != nsw.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(nsw.namespace)
+ }
+ return nsw.client.Patch(ctx, obj, patch, opts...)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client_test.go
new file mode 100644
index 00000000000..1692b7fcd9b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client_test.go
@@ -0,0 +1,583 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client_test
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "sync/atomic"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ rbacv1 "k8s.io/api/rbac/v1"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/types"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+var _ = Describe("NamespacedClient", func() {
+ var dep *appsv1.Deployment
+ var ns = "default"
+ ctx := context.Background()
+ var count uint64 = 0
+ var replicaCount int32 = 2
+
+ getClient := func() client.Client {
+ var sch = runtime.NewScheme()
+
+ err := rbacv1.AddToScheme(sch)
+ Expect(err).To(BeNil())
+ err = appsv1.AddToScheme(sch)
+ Expect(err).To(BeNil())
+
+ nonNamespacedClient, err := client.New(cfg, client.Options{Scheme: sch})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(nonNamespacedClient).NotTo(BeNil())
+ return client.NewNamespacedClient(nonNamespacedClient, ns)
+ }
+
+ BeforeEach(func() {
+ atomic.AddUint64(&count, 1)
+ dep = &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: fmt.Sprintf("namespaced-deployment-%v", count),
+ Labels: map[string]string{"name": fmt.Sprintf("namespaced-deployment-%v", count)},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Replicas: &replicaCount,
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ })
+
+ Describe("Get", func() {
+
+ BeforeEach(func() {
+ var err error
+ dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ AfterEach(func() {
+ deleteDeployment(ctx, dep, ns)
+ })
+ It("should successfully Get a namespace-scoped object", func() {
+ name := types.NamespacedName{Name: dep.Name}
+ result := &appsv1.Deployment{}
+
+ Expect(getClient().Get(ctx, name, result)).NotTo(HaveOccurred())
+ Expect(result).To(BeEquivalentTo(dep))
+ })
+
+ It("should error when namespace provided in the object is different than the one "+
+ "specified in client", func() {
+ name := types.NamespacedName{Name: dep.Name, Namespace: "non-default"}
+ result := &appsv1.Deployment{}
+
+ Expect(getClient().Get(ctx, name, result)).To(HaveOccurred())
+ })
+ })
+
+ Describe("List", func() {
+ BeforeEach(func() {
+ var err error
+ dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ AfterEach(func() {
+ deleteDeployment(ctx, dep, ns)
+ })
+
+ It("should successfully List objects when namespace is not specified with the object", func() {
+ result := &appsv1.DeploymentList{}
+ opts := client.MatchingLabels(dep.Labels)
+
+ Expect(getClient().List(ctx, result, opts)).NotTo(HaveOccurred())
+ Expect(len(result.Items)).To(BeEquivalentTo(1))
+ Expect(result.Items[0]).To(BeEquivalentTo(*dep))
+ })
+
+ It("should List objects from the namespace specified in the client", func() {
+ result := &appsv1.DeploymentList{}
+ opts := client.InNamespace("non-default")
+
+ Expect(getClient().List(ctx, result, opts)).NotTo(HaveOccurred())
+ Expect(len(result.Items)).To(BeEquivalentTo(1))
+ Expect(result.Items[0]).To(BeEquivalentTo(*dep))
+ })
+ })
+
+ Describe("Create", func() {
+ AfterEach(func() {
+ deleteDeployment(ctx, dep, ns)
+ })
+
+ It("should successfully create object in the right namespace", func() {
+ By("creating the object initially")
+ err := getClient().Create(ctx, dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("checking if the object was created in the right namespace")
+ res, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(res.GetNamespace()).To(BeEquivalentTo(ns))
+ })
+
+ It("should not create object if the namespace of the object is different", func() {
+ By("creating the object initially")
+ dep.SetNamespace("non-default")
+ err := getClient().Create(ctx, dep)
+ Expect(err).To(HaveOccurred())
+ })
+ It("should create a cluster scoped object", func() {
+ cr := &rbacv1.ClusterRole{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: fmt.Sprintf("clusterRole-%v", count),
+ Labels: map[string]string{"name": fmt.Sprintf("clusterRole-%v", count)},
+ },
+ }
+ cr.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "rbac.authorization.k8s.io",
+ Version: "v1",
+ Kind: "ClusterRole",
+ })
+
+ By("creating the object initially")
+ err := getClient().Create(ctx, cr)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("checking if the object was created")
+ res, err := clientset.RbacV1().ClusterRoles().Get(ctx, cr.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(res).NotTo(BeNil())
+
+ // Delete the clusterRole Resource
+ deleteClusterRole(ctx, cr)
+ })
+ })
+
+ Describe("Update", func() {
+ var err error
+ BeforeEach(func() {
+ dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ dep.Annotations = map[string]string{"foo": "bar"}
+ Expect(err).NotTo(HaveOccurred())
+ })
+ AfterEach(func() {
+ deleteDeployment(ctx, dep, ns)
+ })
+
+ It("should successfully update the provided object", func() {
+ By("updating the Deployment")
+ err = getClient().Update(ctx, dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating if the updated Deployment has new annotation")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.GetNamespace()).To(Equal(ns))
+ Expect(actual.Annotations["foo"]).To(Equal("bar"))
+ })
+
+ It("should successfully update the provided object when namespace is not provided", func() {
+ By("updating the Deployment")
+ dep.SetNamespace("")
+ err = getClient().Update(ctx, dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating if the updated Deployment has new annotation")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.GetNamespace()).To(Equal(ns))
+ Expect(actual.Annotations["foo"]).To(Equal("bar"))
+ })
+
+ It("should not update when object namespace is different", func() {
+ By("updating the Deployment")
+ dep.SetNamespace("non-default")
+ err = getClient().Update(ctx, dep)
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should not update any object from other namespace", func() {
+ By("creating a new namespace")
+ tns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "non-default-1"}}
+ _, err := clientset.CoreV1().Namespaces().Create(ctx, tns, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ changedDep := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "changed-dep",
+ Namespace: tns.Name,
+ Labels: map[string]string{"name": "changed-dep"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Replicas: &replicaCount,
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+ changedDep.Annotations = map[string]string{"foo": "bar"}
+
+ By("creating the object initially")
+ _, err = clientset.AppsV1().Deployments(tns.Name).Create(ctx, changedDep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the object")
+ err = getClient().Update(ctx, changedDep)
+ Expect(err).To(HaveOccurred())
+
+ deleteDeployment(ctx, changedDep, tns.Name)
+ deleteNamespace(ctx, tns)
+ })
+
+ It("should update a cluster scoped resource", func() {
+ changedCR := &rbacv1.ClusterRole{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: fmt.Sprintf("clusterRole-%v", count),
+ Labels: map[string]string{"name": fmt.Sprintf("clusterRole-%v", count)},
+ },
+ }
+
+ changedCR.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "rbac.authorization.k8s.io",
+ Version: "v1",
+ Kind: "ClusterRole",
+ })
+
+ By("Setting annotations and creating the resource")
+ changedCR.Annotations = map[string]string{"foo": "bar"}
+ changedCR, err = clientset.RbacV1().ClusterRoles().Create(ctx, changedCR, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("updating the deployment")
+ err = getClient().Update(ctx, changedCR)
+
+ By("validating if the cluster role was update")
+ actual, err := clientset.RbacV1().ClusterRoles().Get(ctx, changedCR.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.Annotations["foo"]).To(Equal("bar"))
+
+ // delete cluster role resource
+ deleteClusterRole(ctx, changedCR)
+ })
+
+ })
+
+ Describe("Patch", func() {
+ var err error
+ BeforeEach(func() {
+ dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ AfterEach(func() {
+ deleteDeployment(ctx, dep, ns)
+ })
+
+ It("should successfully modify the object using Patch", func() {
+ By("Applying Patch")
+ err = getClient().Patch(ctx, dep, client.RawPatch(types.MergePatchType, generatePatch()))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating patched Deployment has new annotations")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual.Annotations["foo"]).To(Equal("bar"))
+ Expect(actual.GetNamespace()).To(Equal(ns))
+ })
+
+ It("should successfully modify the object using Patch when namespace is not provided", func() {
+ By("Applying Patch")
+ dep.SetNamespace("")
+ err = getClient().Patch(ctx, dep, client.RawPatch(types.MergePatchType, generatePatch()))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating patched Deployment has new annotations")
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual.Annotations["foo"]).To(Equal("bar"))
+ Expect(actual.GetNamespace()).To(Equal(ns))
+ })
+
+ It("should not modify the object when namespace of the object is different", func() {
+ dep.SetNamespace("non-default")
+ err = getClient().Patch(ctx, dep, client.RawPatch(types.MergePatchType, generatePatch()))
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should not modify an object from a different namespace", func() {
+ By("creating a new namespace")
+ tns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "non-default-2"}}
+ _, err := clientset.CoreV1().Namespaces().Create(ctx, tns, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ changedDep := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "changed-dep",
+ Namespace: tns.Name,
+ Labels: map[string]string{"name": "changed-dep"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Replicas: &replicaCount,
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+
+ By("creating the object initially")
+ changedDep, err = clientset.AppsV1().Deployments(tns.Name).Create(ctx, changedDep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ err = getClient().Patch(ctx, changedDep, client.RawPatch(types.MergePatchType, generatePatch()))
+ Expect(err).To(HaveOccurred())
+
+ deleteDeployment(ctx, changedDep, tns.Name)
+ deleteNamespace(ctx, tns)
+ })
+
+ It("should successfully modify cluster scoped resource", func() {
+ cr := &rbacv1.ClusterRole{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: fmt.Sprintf("clusterRole-%v", count),
+ Labels: map[string]string{"name": fmt.Sprintf("clusterRole-%v", count)},
+ },
+ }
+
+ cr.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "rbac.authorization.k8s.io",
+ Version: "v1",
+ Kind: "ClusterRole",
+ })
+
+ By("creating the resource")
+ cr, err = clientset.RbacV1().ClusterRoles().Create(ctx, cr, metav1.CreateOptions{})
+ Expect(err).ToNot(HaveOccurred())
+
+ By("Applying Patch")
+ err = getClient().Patch(ctx, cr, client.RawPatch(types.MergePatchType, generatePatch()))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Validating the patch")
+ actual, err := clientset.RbacV1().ClusterRoles().Get(ctx, cr.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual.Annotations["foo"]).To(Equal("bar"))
+
+ // delete the resource
+ deleteClusterRole(ctx, cr)
+ })
+ })
+
+ Describe("Delete and DeleteAllOf", func() {
+ var err error
+ BeforeEach(func() {
+ dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ AfterEach(func() {
+ deleteDeployment(ctx, dep, ns)
+ })
+ It("should successfully delete an object when namespace is not specified", func() {
+ By("deleting the object")
+ dep.SetNamespace("")
+ err = getClient().Delete(ctx, dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating the Deployment no longer exists")
+ _, err = clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should successfully delete all of the deployments in the given namespace", func() {
+ By("Deleting all objects in the namespace")
+ err = getClient().DeleteAllOf(ctx, dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating the Deployment no longer exists")
+ _, err = clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should not delete deployments in other namespaces", func() {
+ tns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "non-default-3"}}
+ _, err = clientset.CoreV1().Namespaces().Create(ctx, tns, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ changedDep := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "changed-dep",
+ Namespace: tns.Name,
+ Labels: map[string]string{"name": "changed-dep"},
+ },
+ Spec: appsv1.DeploymentSpec{
+ Replicas: &replicaCount,
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+
+ By("creating the object initially in other namespace")
+ changedDep, err = clientset.AppsV1().Deployments(tns.Name).Create(ctx, changedDep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ err = getClient().DeleteAllOf(ctx, dep)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("validating the Deployment exists")
+ actual, err := clientset.AppsV1().Deployments(tns.Name).Get(ctx, changedDep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).To(BeEquivalentTo(changedDep))
+
+ deleteDeployment(ctx, changedDep, tns.Name)
+ deleteNamespace(ctx, tns)
+ })
+ })
+
+ Describe("SubResourceWriter", func() {
+ var err error
+ BeforeEach(func() {
+ dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ AfterEach(func() {
+ deleteDeployment(ctx, dep, ns)
+ })
+
+ It("should change objects via update status", func() {
+ changedDep := dep.DeepCopy()
+ changedDep.Status.Replicas = 99
+
+ Expect(getClient().SubResource("status").Update(ctx, changedDep)).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.GetNamespace()).To(BeEquivalentTo(ns))
+ Expect(actual.Status.Replicas).To(BeEquivalentTo(99))
+ })
+
+ It("should not change objects via update status when object namespace is different", func() {
+ changedDep := dep.DeepCopy()
+ changedDep.SetNamespace("test")
+ changedDep.Status.Replicas = 99
+
+ Expect(getClient().SubResource("status").Update(ctx, changedDep)).To(HaveOccurred())
+ })
+
+ It("should change objects via status patch", func() {
+ changedDep := dep.DeepCopy()
+ changedDep.Status.Replicas = 99
+
+ Expect(getClient().SubResource("status").Patch(ctx, changedDep, client.MergeFrom(dep))).NotTo(HaveOccurred())
+
+ actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(actual).NotTo(BeNil())
+ Expect(actual.GetNamespace()).To(BeEquivalentTo(ns))
+ Expect(actual.Status.Replicas).To(BeEquivalentTo(99))
+ })
+
+ It("should not change objects via status patch when object namespace is different", func() {
+ changedDep := dep.DeepCopy()
+ changedDep.Status.Replicas = 99
+ changedDep.SetNamespace("test")
+
+ Expect(getClient().SubResource("status").Patch(ctx, changedDep, client.MergeFrom(dep))).To(HaveOccurred())
+ })
+ })
+
+ Describe("Test on invalid objects", func() {
+ It("should refuse to perform operations on invalid object", func() {
+ err := getClient().Create(ctx, nil)
+ Expect(err).To(HaveOccurred())
+
+ err = getClient().List(ctx, nil)
+ Expect(err).To(HaveOccurred())
+
+ err = getClient().Patch(ctx, nil, client.MergeFrom(dep))
+ Expect(err).To(HaveOccurred())
+
+ err = getClient().Update(ctx, nil)
+ Expect(err).To(HaveOccurred())
+
+ err = getClient().Delete(ctx, nil)
+ Expect(err).To(HaveOccurred())
+
+ err = getClient().Status().Patch(ctx, nil, client.MergeFrom(dep))
+ Expect(err).To(HaveOccurred())
+
+ err = getClient().Status().Update(ctx, nil)
+ Expect(err).To(HaveOccurred())
+
+ })
+
+ })
+})
+
+func generatePatch() []byte {
+ mergePatch, err := json.Marshal(map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "annotations": map[string]interface{}{
+ "foo": "bar",
+ },
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ return mergePatch
+}
+
+func deleteClusterRole(ctx context.Context, cr *rbacv1.ClusterRole) {
+ _, err := clientset.RbacV1().ClusterRoles().Get(ctx, cr.Name, metav1.GetOptions{})
+ if err == nil {
+ err = clientset.RbacV1().ClusterRoles().Delete(ctx, cr.Name, metav1.DeleteOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/object.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/object.go
new file mode 100644
index 00000000000..31e334d6c2d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/object.go
@@ -0,0 +1,77 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// Object is a Kubernetes object, allows functions to work indistinctly with
+// any resource that implements both Object interfaces.
+//
+// Semantically, these are objects which are both serializable (runtime.Object)
+// and identifiable (metav1.Object) -- think any object which you could write
+// as YAML or JSON, and then `kubectl create`.
+//
+// Code-wise, this means that any object which embeds both ObjectMeta (which
+// provides metav1.Object) and TypeMeta (which provides half of runtime.Object)
+// and has a `DeepCopyObject` implementation (the other half of runtime.Object)
+// will implement this by default.
+//
+// For example, nearly all the built-in types are Objects, as well as all
+// KubeBuilder-generated CRDs (unless you do something real funky to them).
+//
+// By and large, most things that implement runtime.Object also implement
+// Object -- it's very rare to have *just* a runtime.Object implementation (the
+// cases tend to be funky built-in types like Webhook payloads that don't have
+// a `metadata` field).
+//
+// Notice that XYZList types are distinct: they implement ObjectList instead.
+type Object interface {
+ metav1.Object
+ runtime.Object
+}
+
+// ObjectList is a Kubernetes object list, allows functions to work
+// indistinctly with any resource that implements both runtime.Object and
+// metav1.ListInterface interfaces.
+//
+// Semantically, this is any object which may be serialized (ObjectMeta), and
+// is a kubernetes list wrapper (has items, pagination fields, etc) -- think
+// the wrapper used in a response from a `kubectl list --output yaml` call.
+//
+// Code-wise, this means that any object which embedds both ListMeta (which
+// provides metav1.ListInterface) and TypeMeta (which provides half of
+// runtime.Object) and has a `DeepCopyObject` implementation (the other half of
+// runtime.Object) will implement this by default.
+//
+// For example, nearly all the built-in XYZList types are ObjectLists, as well
+// as the XYZList types for all KubeBuilder-generated CRDs (unless you do
+// something real funky to them).
+//
+// By and large, most things that are XYZList and implement runtime.Object also
+// implement ObjectList -- it's very rare to have *just* a runtime.Object
+// implementation (the cases tend to be funky built-in types like Webhook
+// payloads that don't have a `metadata` field).
+//
+// This is similar to Object, which is almost always implemented by the items
+// in the list themselves.
+type ObjectList interface {
+ metav1.ListInterface
+ runtime.Object
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/options.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/options.go
new file mode 100644
index 00000000000..50a461f1cc6
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/options.go
@@ -0,0 +1,831 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/fields"
+ "k8s.io/apimachinery/pkg/labels"
+ "k8s.io/apimachinery/pkg/selection"
+)
+
+// {{{ "Functional" Option Interfaces
+
+// CreateOption is some configuration that modifies options for a create request.
+type CreateOption interface {
+ // ApplyToCreate applies this configuration to the given create options.
+ ApplyToCreate(*CreateOptions)
+}
+
+// DeleteOption is some configuration that modifies options for a delete request.
+type DeleteOption interface {
+ // ApplyToDelete applies this configuration to the given delete options.
+ ApplyToDelete(*DeleteOptions)
+}
+
+// GetOption is some configuration that modifies options for a get request.
+type GetOption interface {
+ // ApplyToGet applies this configuration to the given get options.
+ ApplyToGet(*GetOptions)
+}
+
+// ListOption is some configuration that modifies options for a list request.
+type ListOption interface {
+ // ApplyToList applies this configuration to the given list options.
+ ApplyToList(*ListOptions)
+}
+
+// UpdateOption is some configuration that modifies options for a update request.
+type UpdateOption interface {
+ // ApplyToUpdate applies this configuration to the given update options.
+ ApplyToUpdate(*UpdateOptions)
+}
+
+// PatchOption is some configuration that modifies options for a patch request.
+type PatchOption interface {
+ // ApplyToPatch applies this configuration to the given patch options.
+ ApplyToPatch(*PatchOptions)
+}
+
+// DeleteAllOfOption is some configuration that modifies options for a delete request.
+type DeleteAllOfOption interface {
+ // ApplyToDeleteAllOf applies this configuration to the given deletecollection options.
+ ApplyToDeleteAllOf(*DeleteAllOfOptions)
+}
+
+// SubResourceGetOption modifies options for a SubResource Get request.
+type SubResourceGetOption interface {
+ ApplyToSubResourceGet(*SubResourceGetOptions)
+}
+
+// SubResourceUpdateOption is some configuration that modifies options for a update request.
+type SubResourceUpdateOption interface {
+ // ApplyToSubResourceUpdate applies this configuration to the given update options.
+ ApplyToSubResourceUpdate(*SubResourceUpdateOptions)
+}
+
+// SubResourceCreateOption is some configuration that modifies options for a create request.
+type SubResourceCreateOption interface {
+ // ApplyToSubResourceCreate applies this configuration to the given create options.
+ ApplyToSubResourceCreate(*SubResourceCreateOptions)
+}
+
+// SubResourcePatchOption configures a subresource patch request.
+type SubResourcePatchOption interface {
+ // ApplyToSubResourcePatch applies the configuration on the given patch options.
+ ApplyToSubResourcePatch(*SubResourcePatchOptions)
+}
+
+// }}}
+
+// {{{ Multi-Type Options
+
+// DryRunAll sets the "dry run" option to "all", executing all
+// validation, etc without persisting the change to storage.
+var DryRunAll = dryRunAll{}
+
+type dryRunAll struct{}
+
+// ApplyToCreate applies this configuration to the given create options.
+func (dryRunAll) ApplyToCreate(opts *CreateOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+
+// ApplyToUpdate applies this configuration to the given update options.
+func (dryRunAll) ApplyToUpdate(opts *UpdateOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+
+// ApplyToPatch applies this configuration to the given patch options.
+func (dryRunAll) ApplyToPatch(opts *PatchOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+
+// ApplyToPatch applies this configuration to the given delete options.
+func (dryRunAll) ApplyToDelete(opts *DeleteOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+
+func (dryRunAll) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+
+func (dryRunAll) ApplyToSubResourceCreate(opts *SubResourceCreateOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+
+func (dryRunAll) ApplyToSubResourceUpdate(opts *SubResourceUpdateOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+
+func (dryRunAll) ApplyToSubResourcePatch(opts *SubResourcePatchOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+
+// FieldOwner set the field manager name for the given server-side apply patch.
+type FieldOwner string
+
+// ApplyToPatch applies this configuration to the given patch options.
+func (f FieldOwner) ApplyToPatch(opts *PatchOptions) {
+ opts.FieldManager = string(f)
+}
+
+// ApplyToCreate applies this configuration to the given create options.
+func (f FieldOwner) ApplyToCreate(opts *CreateOptions) {
+ opts.FieldManager = string(f)
+}
+
+// ApplyToUpdate applies this configuration to the given update options.
+func (f FieldOwner) ApplyToUpdate(opts *UpdateOptions) {
+ opts.FieldManager = string(f)
+}
+
+// ApplyToSubResourcePatch applies this configuration to the given patch options.
+func (f FieldOwner) ApplyToSubResourcePatch(opts *SubResourcePatchOptions) {
+ opts.FieldManager = string(f)
+}
+
+// ApplyToSubResourceCreate applies this configuration to the given create options.
+func (f FieldOwner) ApplyToSubResourceCreate(opts *SubResourceCreateOptions) {
+ opts.FieldManager = string(f)
+}
+
+// ApplyToSubResourceUpdate applies this configuration to the given update options.
+func (f FieldOwner) ApplyToSubResourceUpdate(opts *SubResourceUpdateOptions) {
+ opts.FieldManager = string(f)
+}
+
+// }}}
+
+// {{{ Create Options
+
+// CreateOptions contains options for create requests. It's generally a subset
+// of metav1.CreateOptions.
+type CreateOptions struct {
+ // When present, indicates that modifications should not be
+ // persisted. An invalid or unrecognized dryRun directive will
+ // result in an error response and no further processing of the
+ // request. Valid values are:
+ // - All: all dry run stages will be processed
+ DryRun []string
+
+ // FieldManager is the name of the user or component submitting
+ // this request. It must be set with server-side apply.
+ FieldManager string
+
+ // Raw represents raw CreateOptions, as passed to the API server.
+ Raw *metav1.CreateOptions
+}
+
+// AsCreateOptions returns these options as a metav1.CreateOptions.
+// This may mutate the Raw field.
+func (o *CreateOptions) AsCreateOptions() *metav1.CreateOptions {
+ if o == nil {
+ return &metav1.CreateOptions{}
+ }
+ if o.Raw == nil {
+ o.Raw = &metav1.CreateOptions{}
+ }
+
+ o.Raw.DryRun = o.DryRun
+ o.Raw.FieldManager = o.FieldManager
+ return o.Raw
+}
+
+// ApplyOptions applies the given create options on these options,
+// and then returns itself (for convenient chaining).
+func (o *CreateOptions) ApplyOptions(opts []CreateOption) *CreateOptions {
+ for _, opt := range opts {
+ opt.ApplyToCreate(o)
+ }
+ return o
+}
+
+// ApplyToCreate implements CreateOption.
+func (o *CreateOptions) ApplyToCreate(co *CreateOptions) {
+ if o.DryRun != nil {
+ co.DryRun = o.DryRun
+ }
+ if o.FieldManager != "" {
+ co.FieldManager = o.FieldManager
+ }
+ if o.Raw != nil {
+ co.Raw = o.Raw
+ }
+}
+
+var _ CreateOption = &CreateOptions{}
+
+// }}}
+
+// {{{ Delete Options
+
+// DeleteOptions contains options for delete requests. It's generally a subset
+// of metav1.DeleteOptions.
+type DeleteOptions struct {
+ // GracePeriodSeconds is the duration in seconds before the object should be
+ // deleted. Value must be non-negative integer. The value zero indicates
+ // delete immediately. If this value is nil, the default grace period for the
+ // specified type will be used.
+ GracePeriodSeconds *int64
+
+ // Preconditions must be fulfilled before a deletion is carried out. If not
+ // possible, a 409 Conflict status will be returned.
+ Preconditions *metav1.Preconditions
+
+ // PropagationPolicy determined whether and how garbage collection will be
+ // performed. Either this field or OrphanDependents may be set, but not both.
+ // The default policy is decided by the existing finalizer set in the
+ // metadata.finalizers and the resource-specific default policy.
+ // Acceptable values are: 'Orphan' - orphan the dependents; 'Background' -
+ // allow the garbage collector to delete the dependents in the background;
+ // 'Foreground' - a cascading policy that deletes all dependents in the
+ // foreground.
+ PropagationPolicy *metav1.DeletionPropagation
+
+ // Raw represents raw DeleteOptions, as passed to the API server.
+ Raw *metav1.DeleteOptions
+
+ // When present, indicates that modifications should not be
+ // persisted. An invalid or unrecognized dryRun directive will
+ // result in an error response and no further processing of the
+ // request. Valid values are:
+ // - All: all dry run stages will be processed
+ DryRun []string
+}
+
+// AsDeleteOptions returns these options as a metav1.DeleteOptions.
+// This may mutate the Raw field.
+func (o *DeleteOptions) AsDeleteOptions() *metav1.DeleteOptions {
+ if o == nil {
+ return &metav1.DeleteOptions{}
+ }
+ if o.Raw == nil {
+ o.Raw = &metav1.DeleteOptions{}
+ }
+
+ o.Raw.GracePeriodSeconds = o.GracePeriodSeconds
+ o.Raw.Preconditions = o.Preconditions
+ o.Raw.PropagationPolicy = o.PropagationPolicy
+ o.Raw.DryRun = o.DryRun
+ return o.Raw
+}
+
+// ApplyOptions applies the given delete options on these options,
+// and then returns itself (for convenient chaining).
+func (o *DeleteOptions) ApplyOptions(opts []DeleteOption) *DeleteOptions {
+ for _, opt := range opts {
+ opt.ApplyToDelete(o)
+ }
+ return o
+}
+
+var _ DeleteOption = &DeleteOptions{}
+
+// ApplyToDelete implements DeleteOption.
+func (o *DeleteOptions) ApplyToDelete(do *DeleteOptions) {
+ if o.GracePeriodSeconds != nil {
+ do.GracePeriodSeconds = o.GracePeriodSeconds
+ }
+ if o.Preconditions != nil {
+ do.Preconditions = o.Preconditions
+ }
+ if o.PropagationPolicy != nil {
+ do.PropagationPolicy = o.PropagationPolicy
+ }
+ if o.Raw != nil {
+ do.Raw = o.Raw
+ }
+ if o.DryRun != nil {
+ do.DryRun = o.DryRun
+ }
+}
+
+// GracePeriodSeconds sets the grace period for the deletion
+// to the given number of seconds.
+type GracePeriodSeconds int64
+
+// ApplyToDelete applies this configuration to the given delete options.
+func (s GracePeriodSeconds) ApplyToDelete(opts *DeleteOptions) {
+ secs := int64(s)
+ opts.GracePeriodSeconds = &secs
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (s GracePeriodSeconds) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ s.ApplyToDelete(&opts.DeleteOptions)
+}
+
+// Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out.
+type Preconditions metav1.Preconditions
+
+// ApplyToDelete applies this configuration to the given delete options.
+func (p Preconditions) ApplyToDelete(opts *DeleteOptions) {
+ preconds := metav1.Preconditions(p)
+ opts.Preconditions = &preconds
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (p Preconditions) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ p.ApplyToDelete(&opts.DeleteOptions)
+}
+
+// PropagationPolicy determined whether and how garbage collection will be
+// performed. Either this field or OrphanDependents may be set, but not both.
+// The default policy is decided by the existing finalizer set in the
+// metadata.finalizers and the resource-specific default policy.
+// Acceptable values are: 'Orphan' - orphan the dependents; 'Background' -
+// allow the garbage collector to delete the dependents in the background;
+// 'Foreground' - a cascading policy that deletes all dependents in the
+// foreground.
+type PropagationPolicy metav1.DeletionPropagation
+
+// ApplyToDelete applies the given delete options on these options.
+// It will propagate to the dependents of the object to let the garbage collector handle it.
+func (p PropagationPolicy) ApplyToDelete(opts *DeleteOptions) {
+ policy := metav1.DeletionPropagation(p)
+ opts.PropagationPolicy = &policy
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (p PropagationPolicy) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ p.ApplyToDelete(&opts.DeleteOptions)
+}
+
+// }}}
+
+// {{{ Get Options
+
+// GetOptions contains options for get operation.
+// Now it only has a Raw field, with support for specific resourceVersion.
+type GetOptions struct {
+ // Raw represents raw GetOptions, as passed to the API server. Note
+ // that these may not be respected by all implementations of interface.
+ Raw *metav1.GetOptions
+}
+
+var _ GetOption = &GetOptions{}
+
+// ApplyToGet implements GetOption for GetOptions.
+func (o *GetOptions) ApplyToGet(lo *GetOptions) {
+ if o.Raw != nil {
+ lo.Raw = o.Raw
+ }
+}
+
+// AsGetOptions returns these options as a flattened metav1.GetOptions.
+// This may mutate the Raw field.
+func (o *GetOptions) AsGetOptions() *metav1.GetOptions {
+ if o == nil || o.Raw == nil {
+ return &metav1.GetOptions{}
+ }
+ return o.Raw
+}
+
+// ApplyOptions applies the given get options on these options,
+// and then returns itself (for convenient chaining).
+func (o *GetOptions) ApplyOptions(opts []GetOption) *GetOptions {
+ for _, opt := range opts {
+ opt.ApplyToGet(o)
+ }
+ return o
+}
+
+// }}}
+
+// {{{ List Options
+
+// ListOptions contains options for limiting or filtering results.
+// It's generally a subset of metav1.ListOptions, with support for
+// pre-parsed selectors (since generally, selectors will be executed
+// against the cache).
+type ListOptions struct {
+ // LabelSelector filters results by label. Use labels.Parse() to
+ // set from raw string form.
+ LabelSelector labels.Selector
+ // FieldSelector filters results by a particular field. In order
+ // to use this with cache-based implementations, restrict usage to
+ // a single field-value pair that's been added to the indexers.
+ FieldSelector fields.Selector
+
+ // Namespace represents the namespace to list for, or empty for
+ // non-namespaced objects, or to list across all namespaces.
+ Namespace string
+
+ // Limit specifies the maximum number of results to return from the server. The server may
+ // not support this field on all resource types, but if it does and more results remain it
+ // will set the continue field on the returned list object. This field is not supported if watch
+ // is true in the Raw ListOptions.
+ Limit int64
+ // Continue is a token returned by the server that lets a client retrieve chunks of results
+ // from the server by specifying limit. The server may reject requests for continuation tokens
+ // it does not recognize and will return a 410 error if the token can no longer be used because
+ // it has expired. This field is not supported if watch is true in the Raw ListOptions.
+ Continue string
+
+ // UnsafeDisableDeepCopy indicates not to deep copy objects during list objects.
+ // Be very careful with this, when enabled you must DeepCopy any object before mutating it,
+ // otherwise you will mutate the object in the cache.
+ // +optional
+ UnsafeDisableDeepCopy *bool
+
+ // Raw represents raw ListOptions, as passed to the API server. Note
+ // that these may not be respected by all implementations of interface,
+ // and the LabelSelector, FieldSelector, Limit and Continue fields are ignored.
+ Raw *metav1.ListOptions
+}
+
+var _ ListOption = &ListOptions{}
+
+// ApplyToList implements ListOption for ListOptions.
+func (o *ListOptions) ApplyToList(lo *ListOptions) {
+ if o.LabelSelector != nil {
+ lo.LabelSelector = o.LabelSelector
+ }
+ if o.FieldSelector != nil {
+ lo.FieldSelector = o.FieldSelector
+ }
+ if o.Namespace != "" {
+ lo.Namespace = o.Namespace
+ }
+ if o.Raw != nil {
+ lo.Raw = o.Raw
+ }
+ if o.Limit > 0 {
+ lo.Limit = o.Limit
+ }
+ if o.Continue != "" {
+ lo.Continue = o.Continue
+ }
+ if o.UnsafeDisableDeepCopy != nil {
+ lo.UnsafeDisableDeepCopy = o.UnsafeDisableDeepCopy
+ }
+}
+
+// AsListOptions returns these options as a flattened metav1.ListOptions.
+// This may mutate the Raw field.
+func (o *ListOptions) AsListOptions() *metav1.ListOptions {
+ if o == nil {
+ return &metav1.ListOptions{}
+ }
+ if o.Raw == nil {
+ o.Raw = &metav1.ListOptions{}
+ }
+ if o.LabelSelector != nil {
+ o.Raw.LabelSelector = o.LabelSelector.String()
+ }
+ if o.FieldSelector != nil {
+ o.Raw.FieldSelector = o.FieldSelector.String()
+ }
+ if !o.Raw.Watch {
+ o.Raw.Limit = o.Limit
+ o.Raw.Continue = o.Continue
+ }
+ return o.Raw
+}
+
+// ApplyOptions applies the given list options on these options,
+// and then returns itself (for convenient chaining).
+func (o *ListOptions) ApplyOptions(opts []ListOption) *ListOptions {
+ for _, opt := range opts {
+ opt.ApplyToList(o)
+ }
+ return o
+}
+
+// MatchingLabels filters the list/delete operation on the given set of labels.
+type MatchingLabels map[string]string
+
+// ApplyToList applies this configuration to the given list options.
+func (m MatchingLabels) ApplyToList(opts *ListOptions) {
+ // TODO(directxman12): can we avoid reserializing this over and over?
+ sel := labels.SelectorFromValidatedSet(map[string]string(m))
+ opts.LabelSelector = sel
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (m MatchingLabels) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ m.ApplyToList(&opts.ListOptions)
+}
+
+// HasLabels filters the list/delete operation checking if the set of labels exists
+// without checking their values.
+type HasLabels []string
+
+// ApplyToList applies this configuration to the given list options.
+func (m HasLabels) ApplyToList(opts *ListOptions) {
+ sel := labels.NewSelector()
+ for _, label := range m {
+ r, err := labels.NewRequirement(label, selection.Exists, nil)
+ if err == nil {
+ sel = sel.Add(*r)
+ }
+ }
+ opts.LabelSelector = sel
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (m HasLabels) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ m.ApplyToList(&opts.ListOptions)
+}
+
+// MatchingLabelsSelector filters the list/delete operation on the given label
+// selector (or index in the case of cached lists). A struct is used because
+// labels.Selector is an interface, which cannot be aliased.
+type MatchingLabelsSelector struct {
+ labels.Selector
+}
+
+// ApplyToList applies this configuration to the given list options.
+func (m MatchingLabelsSelector) ApplyToList(opts *ListOptions) {
+ opts.LabelSelector = m
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (m MatchingLabelsSelector) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ m.ApplyToList(&opts.ListOptions)
+}
+
+// MatchingFields filters the list/delete operation on the given field Set
+// (or index in the case of cached lists).
+type MatchingFields fields.Set
+
+// ApplyToList applies this configuration to the given list options.
+func (m MatchingFields) ApplyToList(opts *ListOptions) {
+ // TODO(directxman12): can we avoid re-serializing this?
+ sel := fields.Set(m).AsSelector()
+ opts.FieldSelector = sel
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (m MatchingFields) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ m.ApplyToList(&opts.ListOptions)
+}
+
+// MatchingFieldsSelector filters the list/delete operation on the given field
+// selector (or index in the case of cached lists). A struct is used because
+// fields.Selector is an interface, which cannot be aliased.
+type MatchingFieldsSelector struct {
+ fields.Selector
+}
+
+// ApplyToList applies this configuration to the given list options.
+func (m MatchingFieldsSelector) ApplyToList(opts *ListOptions) {
+ opts.FieldSelector = m
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (m MatchingFieldsSelector) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ m.ApplyToList(&opts.ListOptions)
+}
+
+// InNamespace restricts the list/delete operation to the given namespace.
+type InNamespace string
+
+// ApplyToList applies this configuration to the given list options.
+func (n InNamespace) ApplyToList(opts *ListOptions) {
+ opts.Namespace = string(n)
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (n InNamespace) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ n.ApplyToList(&opts.ListOptions)
+}
+
+// AsSelector returns a selector that matches objects in the given namespace.
+func (n InNamespace) AsSelector() fields.Selector {
+ return fields.SelectorFromSet(fields.Set{"metadata.namespace": string(n)})
+}
+
+// Limit specifies the maximum number of results to return from the server.
+// Limit does not implement DeleteAllOfOption interface because the server
+// does not support setting it for deletecollection operations.
+type Limit int64
+
+// ApplyToList applies this configuration to the given an list options.
+func (l Limit) ApplyToList(opts *ListOptions) {
+ opts.Limit = int64(l)
+}
+
+// UnsafeDisableDeepCopyOption indicates not to deep copy objects during list objects.
+// Be very careful with this, when enabled you must DeepCopy any object before mutating it,
+// otherwise you will mutate the object in the cache.
+type UnsafeDisableDeepCopyOption bool
+
+// ApplyToList applies this configuration to the given an List options.
+func (d UnsafeDisableDeepCopyOption) ApplyToList(opts *ListOptions) {
+ definitelyTrue := true
+ definitelyFalse := false
+ if d {
+ opts.UnsafeDisableDeepCopy = &definitelyTrue
+ } else {
+ opts.UnsafeDisableDeepCopy = &definitelyFalse
+ }
+}
+
+// UnsafeDisableDeepCopy indicates not to deep copy objects during list objects.
+const UnsafeDisableDeepCopy = UnsafeDisableDeepCopyOption(true)
+
+// Continue sets a continuation token to retrieve chunks of results when using limit.
+// Continue does not implement DeleteAllOfOption interface because the server
+// does not support setting it for deletecollection operations.
+type Continue string
+
+// ApplyToList applies this configuration to the given an List options.
+func (c Continue) ApplyToList(opts *ListOptions) {
+ opts.Continue = string(c)
+}
+
+// }}}
+
+// {{{ Update Options
+
+// UpdateOptions contains options for create requests. It's generally a subset
+// of metav1.UpdateOptions.
+type UpdateOptions struct {
+ // When present, indicates that modifications should not be
+ // persisted. An invalid or unrecognized dryRun directive will
+ // result in an error response and no further processing of the
+ // request. Valid values are:
+ // - All: all dry run stages will be processed
+ DryRun []string
+
+ // FieldManager is the name of the user or component submitting
+ // this request. It must be set with server-side apply.
+ FieldManager string
+
+ // Raw represents raw UpdateOptions, as passed to the API server.
+ Raw *metav1.UpdateOptions
+}
+
+// AsUpdateOptions returns these options as a metav1.UpdateOptions.
+// This may mutate the Raw field.
+func (o *UpdateOptions) AsUpdateOptions() *metav1.UpdateOptions {
+ if o == nil {
+ return &metav1.UpdateOptions{}
+ }
+ if o.Raw == nil {
+ o.Raw = &metav1.UpdateOptions{}
+ }
+
+ o.Raw.DryRun = o.DryRun
+ o.Raw.FieldManager = o.FieldManager
+ return o.Raw
+}
+
+// ApplyOptions applies the given update options on these options,
+// and then returns itself (for convenient chaining).
+func (o *UpdateOptions) ApplyOptions(opts []UpdateOption) *UpdateOptions {
+ for _, opt := range opts {
+ opt.ApplyToUpdate(o)
+ }
+ return o
+}
+
+var _ UpdateOption = &UpdateOptions{}
+
+// ApplyToUpdate implements UpdateOption.
+func (o *UpdateOptions) ApplyToUpdate(uo *UpdateOptions) {
+ if o.DryRun != nil {
+ uo.DryRun = o.DryRun
+ }
+ if o.FieldManager != "" {
+ uo.FieldManager = o.FieldManager
+ }
+ if o.Raw != nil {
+ uo.Raw = o.Raw
+ }
+}
+
+// }}}
+
+// {{{ Patch Options
+
+// PatchOptions contains options for patch requests.
+type PatchOptions struct {
+ // When present, indicates that modifications should not be
+ // persisted. An invalid or unrecognized dryRun directive will
+ // result in an error response and no further processing of the
+ // request. Valid values are:
+ // - All: all dry run stages will be processed
+ DryRun []string
+
+ // Force is going to "force" Apply requests. It means user will
+ // re-acquire conflicting fields owned by other people. Force
+ // flag must be unset for non-apply patch requests.
+ // +optional
+ Force *bool
+
+ // FieldManager is the name of the user or component submitting
+ // this request. It must be set with server-side apply.
+ FieldManager string
+
+ // Raw represents raw PatchOptions, as passed to the API server.
+ Raw *metav1.PatchOptions
+}
+
+// ApplyOptions applies the given patch options on these options,
+// and then returns itself (for convenient chaining).
+func (o *PatchOptions) ApplyOptions(opts []PatchOption) *PatchOptions {
+ for _, opt := range opts {
+ opt.ApplyToPatch(o)
+ }
+ return o
+}
+
+// AsPatchOptions returns these options as a metav1.PatchOptions.
+// This may mutate the Raw field.
+func (o *PatchOptions) AsPatchOptions() *metav1.PatchOptions {
+ if o == nil {
+ return &metav1.PatchOptions{}
+ }
+ if o.Raw == nil {
+ o.Raw = &metav1.PatchOptions{}
+ }
+
+ o.Raw.DryRun = o.DryRun
+ o.Raw.Force = o.Force
+ o.Raw.FieldManager = o.FieldManager
+ return o.Raw
+}
+
+var _ PatchOption = &PatchOptions{}
+
+// ApplyToPatch implements PatchOptions.
+func (o *PatchOptions) ApplyToPatch(po *PatchOptions) {
+ if o.DryRun != nil {
+ po.DryRun = o.DryRun
+ }
+ if o.Force != nil {
+ po.Force = o.Force
+ }
+ if o.FieldManager != "" {
+ po.FieldManager = o.FieldManager
+ }
+ if o.Raw != nil {
+ po.Raw = o.Raw
+ }
+}
+
+// ForceOwnership indicates that in case of conflicts with server-side apply,
+// the client should acquire ownership of the conflicting field. Most
+// controllers should use this.
+var ForceOwnership = forceOwnership{}
+
+type forceOwnership struct{}
+
+func (forceOwnership) ApplyToPatch(opts *PatchOptions) {
+ definitelyTrue := true
+ opts.Force = &definitelyTrue
+}
+
+func (forceOwnership) ApplyToSubResourcePatch(opts *SubResourcePatchOptions) {
+ definitelyTrue := true
+ opts.Force = &definitelyTrue
+}
+
+// }}}
+
+// {{{ DeleteAllOf Options
+
+// these are all just delete options and list options
+
+// DeleteAllOfOptions contains options for deletecollection (deleteallof) requests.
+// It's just list and delete options smooshed together.
+type DeleteAllOfOptions struct {
+ ListOptions
+ DeleteOptions
+}
+
+// ApplyOptions applies the given deleteallof options on these options,
+// and then returns itself (for convenient chaining).
+func (o *DeleteAllOfOptions) ApplyOptions(opts []DeleteAllOfOption) *DeleteAllOfOptions {
+ for _, opt := range opts {
+ opt.ApplyToDeleteAllOf(o)
+ }
+ return o
+}
+
+var _ DeleteAllOfOption = &DeleteAllOfOptions{}
+
+// ApplyToDeleteAllOf implements DeleteAllOfOption.
+func (o *DeleteAllOfOptions) ApplyToDeleteAllOf(do *DeleteAllOfOptions) {
+ o.ApplyToList(&do.ListOptions)
+ o.ApplyToDelete(&do.DeleteOptions)
+}
+
+// }}}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/options_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/options_test.go
new file mode 100644
index 00000000000..efba976c4f8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/options_test.go
@@ -0,0 +1,294 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client_test
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/fields"
+ "k8s.io/apimachinery/pkg/labels"
+ utilpointer "k8s.io/utils/pointer"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+var _ = Describe("ListOptions", func() {
+ It("Should set LabelSelector", func() {
+ labelSelector, err := labels.Parse("a=b")
+ Expect(err).NotTo(HaveOccurred())
+ o := &client.ListOptions{LabelSelector: labelSelector}
+ newListOpts := &client.ListOptions{}
+ o.ApplyToList(newListOpts)
+ Expect(newListOpts).To(Equal(o))
+ })
+ It("Should set FieldSelector", func() {
+ o := &client.ListOptions{FieldSelector: fields.Nothing()}
+ newListOpts := &client.ListOptions{}
+ o.ApplyToList(newListOpts)
+ Expect(newListOpts).To(Equal(o))
+ })
+ It("Should set Namespace", func() {
+ o := &client.ListOptions{Namespace: "my-ns"}
+ newListOpts := &client.ListOptions{}
+ o.ApplyToList(newListOpts)
+ Expect(newListOpts).To(Equal(o))
+ })
+ It("Should set Raw", func() {
+ o := &client.ListOptions{Raw: &metav1.ListOptions{FieldSelector: "Hans"}}
+ newListOpts := &client.ListOptions{}
+ o.ApplyToList(newListOpts)
+ Expect(newListOpts).To(Equal(o))
+ })
+ It("Should set Limit", func() {
+ o := &client.ListOptions{Limit: int64(1)}
+ newListOpts := &client.ListOptions{}
+ o.ApplyToList(newListOpts)
+ Expect(newListOpts).To(Equal(o))
+ })
+ It("Should set Continue", func() {
+ o := &client.ListOptions{Continue: "foo"}
+ newListOpts := &client.ListOptions{}
+ o.ApplyToList(newListOpts)
+ Expect(newListOpts).To(Equal(o))
+ })
+ It("Should not set anything", func() {
+ o := &client.ListOptions{}
+ newListOpts := &client.ListOptions{}
+ o.ApplyToList(newListOpts)
+ Expect(newListOpts).To(Equal(o))
+ })
+})
+
+var _ = Describe("GetOptions", func() {
+ It("Should set Raw", func() {
+ o := &client.GetOptions{Raw: &metav1.GetOptions{ResourceVersion: "RV0"}}
+ newGetOpts := &client.GetOptions{}
+ o.ApplyToGet(newGetOpts)
+ Expect(newGetOpts).To(Equal(o))
+ })
+})
+
+var _ = Describe("CreateOptions", func() {
+ It("Should set DryRun", func() {
+ o := &client.CreateOptions{DryRun: []string{"Hello", "Theodore"}}
+ newCreateOpts := &client.CreateOptions{}
+ o.ApplyToCreate(newCreateOpts)
+ Expect(newCreateOpts).To(Equal(o))
+ })
+ It("Should set FieldManager", func() {
+ o := &client.CreateOptions{FieldManager: "FieldManager"}
+ newCreateOpts := &client.CreateOptions{}
+ o.ApplyToCreate(newCreateOpts)
+ Expect(newCreateOpts).To(Equal(o))
+ })
+ It("Should set Raw", func() {
+ o := &client.CreateOptions{Raw: &metav1.CreateOptions{DryRun: []string{"Bye", "Theodore"}}}
+ newCreateOpts := &client.CreateOptions{}
+ o.ApplyToCreate(newCreateOpts)
+ Expect(newCreateOpts).To(Equal(o))
+ })
+ It("Should not set anything", func() {
+ o := &client.CreateOptions{}
+ newCreateOpts := &client.CreateOptions{}
+ o.ApplyToCreate(newCreateOpts)
+ Expect(newCreateOpts).To(Equal(o))
+ })
+})
+
+var _ = Describe("DeleteOptions", func() {
+ It("Should set GracePeriodSeconds", func() {
+ o := &client.DeleteOptions{GracePeriodSeconds: utilpointer.Int64(42)}
+ newDeleteOpts := &client.DeleteOptions{}
+ o.ApplyToDelete(newDeleteOpts)
+ Expect(newDeleteOpts).To(Equal(o))
+ })
+ It("Should set Preconditions", func() {
+ o := &client.DeleteOptions{Preconditions: &metav1.Preconditions{}}
+ newDeleteOpts := &client.DeleteOptions{}
+ o.ApplyToDelete(newDeleteOpts)
+ Expect(newDeleteOpts).To(Equal(o))
+ })
+ It("Should set PropagationPolicy", func() {
+ policy := metav1.DeletePropagationBackground
+ o := &client.DeleteOptions{PropagationPolicy: &policy}
+ newDeleteOpts := &client.DeleteOptions{}
+ o.ApplyToDelete(newDeleteOpts)
+ Expect(newDeleteOpts).To(Equal(o))
+ })
+ It("Should set Raw", func() {
+ o := &client.DeleteOptions{Raw: &metav1.DeleteOptions{}}
+ newDeleteOpts := &client.DeleteOptions{}
+ o.ApplyToDelete(newDeleteOpts)
+ Expect(newDeleteOpts).To(Equal(o))
+ })
+ It("Should set DryRun", func() {
+ o := &client.DeleteOptions{DryRun: []string{"Hello", "Pippa"}}
+ newDeleteOpts := &client.DeleteOptions{}
+ o.ApplyToDelete(newDeleteOpts)
+ Expect(newDeleteOpts).To(Equal(o))
+ })
+ It("Should not set anything", func() {
+ o := &client.DeleteOptions{}
+ newDeleteOpts := &client.DeleteOptions{}
+ o.ApplyToDelete(newDeleteOpts)
+ Expect(newDeleteOpts).To(Equal(o))
+ })
+})
+
+var _ = Describe("UpdateOptions", func() {
+ It("Should set DryRun", func() {
+ o := &client.UpdateOptions{DryRun: []string{"Bye", "Pippa"}}
+ newUpdateOpts := &client.UpdateOptions{}
+ o.ApplyToUpdate(newUpdateOpts)
+ Expect(newUpdateOpts).To(Equal(o))
+ })
+ It("Should set FieldManager", func() {
+ o := &client.UpdateOptions{FieldManager: "Hello Boris"}
+ newUpdateOpts := &client.UpdateOptions{}
+ o.ApplyToUpdate(newUpdateOpts)
+ Expect(newUpdateOpts).To(Equal(o))
+ })
+ It("Should set Raw", func() {
+ o := &client.UpdateOptions{Raw: &metav1.UpdateOptions{}}
+ newUpdateOpts := &client.UpdateOptions{}
+ o.ApplyToUpdate(newUpdateOpts)
+ Expect(newUpdateOpts).To(Equal(o))
+ })
+ It("Should not set anything", func() {
+ o := &client.UpdateOptions{}
+ newUpdateOpts := &client.UpdateOptions{}
+ o.ApplyToUpdate(newUpdateOpts)
+ Expect(newUpdateOpts).To(Equal(o))
+ })
+})
+
+var _ = Describe("PatchOptions", func() {
+ It("Should set DryRun", func() {
+ o := &client.PatchOptions{DryRun: []string{"Bye", "Boris"}}
+ newPatchOpts := &client.PatchOptions{}
+ o.ApplyToPatch(newPatchOpts)
+ Expect(newPatchOpts).To(Equal(o))
+ })
+ It("Should set Force", func() {
+ o := &client.PatchOptions{Force: utilpointer.Bool(true)}
+ newPatchOpts := &client.PatchOptions{}
+ o.ApplyToPatch(newPatchOpts)
+ Expect(newPatchOpts).To(Equal(o))
+ })
+ It("Should set FieldManager", func() {
+ o := &client.PatchOptions{FieldManager: "Hello Julian"}
+ newPatchOpts := &client.PatchOptions{}
+ o.ApplyToPatch(newPatchOpts)
+ Expect(newPatchOpts).To(Equal(o))
+ })
+ It("Should set Raw", func() {
+ o := &client.PatchOptions{Raw: &metav1.PatchOptions{}}
+ newPatchOpts := &client.PatchOptions{}
+ o.ApplyToPatch(newPatchOpts)
+ Expect(newPatchOpts).To(Equal(o))
+ })
+ It("Should not set anything", func() {
+ o := &client.PatchOptions{}
+ newPatchOpts := &client.PatchOptions{}
+ o.ApplyToPatch(newPatchOpts)
+ Expect(newPatchOpts).To(Equal(o))
+ })
+})
+
+var _ = Describe("DeleteAllOfOptions", func() {
+ It("Should set ListOptions", func() {
+ o := &client.DeleteAllOfOptions{ListOptions: client.ListOptions{Raw: &metav1.ListOptions{}}}
+ newDeleteAllOfOpts := &client.DeleteAllOfOptions{}
+ o.ApplyToDeleteAllOf(newDeleteAllOfOpts)
+ Expect(newDeleteAllOfOpts).To(Equal(o))
+ })
+ It("Should set DeleleteOptions", func() {
+ o := &client.DeleteAllOfOptions{DeleteOptions: client.DeleteOptions{GracePeriodSeconds: utilpointer.Int64(44)}}
+ newDeleteAllOfOpts := &client.DeleteAllOfOptions{}
+ o.ApplyToDeleteAllOf(newDeleteAllOfOpts)
+ Expect(newDeleteAllOfOpts).To(Equal(o))
+ })
+})
+
+var _ = Describe("MatchingLabels", func() {
+ It("Should produce an invalid selector when given invalid input", func() {
+ matchingLabels := client.MatchingLabels(map[string]string{"k": "axahm2EJ8Phiephe2eixohbee9eGeiyees1thuozi1xoh0GiuH3diewi8iem7Nui"})
+ listOpts := &client.ListOptions{}
+ matchingLabels.ApplyToList(listOpts)
+
+ r, _ := listOpts.LabelSelector.Requirements()
+ _, err := labels.NewRequirement(r[0].Key(), r[0].Operator(), r[0].Values().List())
+ Expect(err).ToNot(BeNil())
+ expectedErrMsg := `values[0][k]: Invalid value: "axahm2EJ8Phiephe2eixohbee9eGeiyees1thuozi1xoh0GiuH3diewi8iem7Nui": must be no more than 63 characters`
+ Expect(err.Error()).To(Equal(expectedErrMsg))
+ })
+})
+
+var _ = Describe("FieldOwner", func() {
+ It("Should apply to PatchOptions", func() {
+ o := &client.PatchOptions{FieldManager: "bar"}
+ t := client.FieldOwner("foo")
+ t.ApplyToPatch(o)
+ Expect(o.FieldManager).To(Equal("foo"))
+ })
+ It("Should apply to CreateOptions", func() {
+ o := &client.CreateOptions{FieldManager: "bar"}
+ t := client.FieldOwner("foo")
+ t.ApplyToCreate(o)
+ Expect(o.FieldManager).To(Equal("foo"))
+ })
+ It("Should apply to UpdateOptions", func() {
+ o := &client.UpdateOptions{FieldManager: "bar"}
+ t := client.FieldOwner("foo")
+ t.ApplyToUpdate(o)
+ Expect(o.FieldManager).To(Equal("foo"))
+ })
+ It("Should apply to SubResourcePatchOptions", func() {
+ o := &client.SubResourcePatchOptions{PatchOptions: client.PatchOptions{FieldManager: "bar"}}
+ t := client.FieldOwner("foo")
+ t.ApplyToSubResourcePatch(o)
+ Expect(o.FieldManager).To(Equal("foo"))
+ })
+ It("Should apply to SubResourceCreateOptions", func() {
+ o := &client.SubResourceCreateOptions{CreateOptions: client.CreateOptions{FieldManager: "bar"}}
+ t := client.FieldOwner("foo")
+ t.ApplyToSubResourceCreate(o)
+ Expect(o.FieldManager).To(Equal("foo"))
+ })
+ It("Should apply to SubResourceUpdateOptions", func() {
+ o := &client.SubResourceUpdateOptions{UpdateOptions: client.UpdateOptions{FieldManager: "bar"}}
+ t := client.FieldOwner("foo")
+ t.ApplyToSubResourceUpdate(o)
+ Expect(o.FieldManager).To(Equal("foo"))
+ })
+})
+
+var _ = Describe("ForceOwnership", func() {
+ It("Should apply to PatchOptions", func() {
+ o := &client.PatchOptions{}
+ t := client.ForceOwnership
+ t.ApplyToPatch(o)
+ Expect(*o.Force).To(Equal(true))
+ })
+ It("Should apply to SubResourcePatchOptions", func() {
+ o := &client.SubResourcePatchOptions{PatchOptions: client.PatchOptions{}}
+ t := client.ForceOwnership
+ t.ApplyToSubResourcePatch(o)
+ Expect(*o.Force).To(Equal(true))
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/patch.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/patch.go
new file mode 100644
index 00000000000..11d60838856
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/patch.go
@@ -0,0 +1,213 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "fmt"
+
+ jsonpatch "github.com/evanphx/json-patch/v5"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/apimachinery/pkg/util/json"
+ "k8s.io/apimachinery/pkg/util/strategicpatch"
+)
+
+var (
+ // Apply uses server-side apply to patch the given object.
+ Apply Patch = applyPatch{}
+
+ // Merge uses the raw object as a merge patch, without modifications.
+ // Use MergeFrom if you wish to compute a diff instead.
+ Merge Patch = mergePatch{}
+)
+
+type patch struct {
+ patchType types.PatchType
+ data []byte
+}
+
+// Type implements Patch.
+func (s *patch) Type() types.PatchType {
+ return s.patchType
+}
+
+// Data implements Patch.
+func (s *patch) Data(obj Object) ([]byte, error) {
+ return s.data, nil
+}
+
+// RawPatch constructs a new Patch with the given PatchType and data.
+func RawPatch(patchType types.PatchType, data []byte) Patch {
+ return &patch{patchType, data}
+}
+
+// MergeFromWithOptimisticLock can be used if clients want to make sure a patch
+// is being applied to the latest resource version of an object.
+//
+// The behavior is similar to what an Update would do, without the need to send the
+// whole object. Usually this method is useful if you might have multiple clients
+// acting on the same object and the same API version, but with different versions of the Go structs.
+//
+// For example, an "older" copy of a Widget that has fields A and B, and a "newer" copy with A, B, and C.
+// Sending an update using the older struct definition results in C being dropped, whereas using a patch does not.
+type MergeFromWithOptimisticLock struct{}
+
+// ApplyToMergeFrom applies this configuration to the given patch options.
+func (m MergeFromWithOptimisticLock) ApplyToMergeFrom(in *MergeFromOptions) {
+ in.OptimisticLock = true
+}
+
+// MergeFromOption is some configuration that modifies options for a merge-from patch data.
+type MergeFromOption interface {
+ // ApplyToMergeFrom applies this configuration to the given patch options.
+ ApplyToMergeFrom(*MergeFromOptions)
+}
+
+// MergeFromOptions contains options to generate a merge-from patch data.
+type MergeFromOptions struct {
+ // OptimisticLock, when true, includes `metadata.resourceVersion` into the final
+ // patch data. If the `resourceVersion` field doesn't match what's stored,
+ // the operation results in a conflict and clients will need to try again.
+ OptimisticLock bool
+}
+
+type mergeFromPatch struct {
+ patchType types.PatchType
+ createPatch func(originalJSON, modifiedJSON []byte, dataStruct interface{}) ([]byte, error)
+ from Object
+ opts MergeFromOptions
+}
+
+// Type implements Patch.
+func (s *mergeFromPatch) Type() types.PatchType {
+ return s.patchType
+}
+
+// Data implements Patch.
+func (s *mergeFromPatch) Data(obj Object) ([]byte, error) {
+ original := s.from
+ modified := obj
+
+ if s.opts.OptimisticLock {
+ version := original.GetResourceVersion()
+ if len(version) == 0 {
+ return nil, fmt.Errorf("cannot use OptimisticLock, object %q does not have any resource version we can use", original)
+ }
+
+ original = original.DeepCopyObject().(Object)
+ original.SetResourceVersion("")
+
+ modified = modified.DeepCopyObject().(Object)
+ modified.SetResourceVersion(version)
+ }
+
+ originalJSON, err := json.Marshal(original)
+ if err != nil {
+ return nil, err
+ }
+
+ modifiedJSON, err := json.Marshal(modified)
+ if err != nil {
+ return nil, err
+ }
+
+ data, err := s.createPatch(originalJSON, modifiedJSON, obj)
+ if err != nil {
+ return nil, err
+ }
+
+ return data, nil
+}
+
+func createMergePatch(originalJSON, modifiedJSON []byte, _ interface{}) ([]byte, error) {
+ return jsonpatch.CreateMergePatch(originalJSON, modifiedJSON)
+}
+
+func createStrategicMergePatch(originalJSON, modifiedJSON []byte, dataStruct interface{}) ([]byte, error) {
+ return strategicpatch.CreateTwoWayMergePatch(originalJSON, modifiedJSON, dataStruct)
+}
+
+// MergeFrom creates a Patch that patches using the merge-patch strategy with the given object as base.
+// The difference between MergeFrom and StrategicMergeFrom lays in the handling of modified list fields.
+// When using MergeFrom, existing lists will be completely replaced by new lists.
+// When using StrategicMergeFrom, the list field's `patchStrategy` is respected if specified in the API type,
+// e.g. the existing list is not replaced completely but rather merged with the new one using the list's `patchMergeKey`.
+// See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ for more details on
+// the difference between merge-patch and strategic-merge-patch.
+func MergeFrom(obj Object) Patch {
+ return &mergeFromPatch{patchType: types.MergePatchType, createPatch: createMergePatch, from: obj}
+}
+
+// MergeFromWithOptions creates a Patch that patches using the merge-patch strategy with the given object as base.
+// See MergeFrom for more details.
+func MergeFromWithOptions(obj Object, opts ...MergeFromOption) Patch {
+ options := &MergeFromOptions{}
+ for _, opt := range opts {
+ opt.ApplyToMergeFrom(options)
+ }
+ return &mergeFromPatch{patchType: types.MergePatchType, createPatch: createMergePatch, from: obj, opts: *options}
+}
+
+// StrategicMergeFrom creates a Patch that patches using the strategic-merge-patch strategy with the given object as base.
+// The difference between MergeFrom and StrategicMergeFrom lays in the handling of modified list fields.
+// When using MergeFrom, existing lists will be completely replaced by new lists.
+// When using StrategicMergeFrom, the list field's `patchStrategy` is respected if specified in the API type,
+// e.g. the existing list is not replaced completely but rather merged with the new one using the list's `patchMergeKey`.
+// See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ for more details on
+// the difference between merge-patch and strategic-merge-patch.
+// Please note, that CRDs don't support strategic-merge-patch, see
+// https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#advanced-features-and-flexibility
+func StrategicMergeFrom(obj Object, opts ...MergeFromOption) Patch {
+ options := &MergeFromOptions{}
+ for _, opt := range opts {
+ opt.ApplyToMergeFrom(options)
+ }
+ return &mergeFromPatch{patchType: types.StrategicMergePatchType, createPatch: createStrategicMergePatch, from: obj, opts: *options}
+}
+
+// mergePatch uses a raw merge strategy to patch the object.
+type mergePatch struct{}
+
+// Type implements Patch.
+func (p mergePatch) Type() types.PatchType {
+ return types.MergePatchType
+}
+
+// Data implements Patch.
+func (p mergePatch) Data(obj Object) ([]byte, error) {
+ // NB(directxman12): we might technically want to be using an actual encoder
+ // here (in case some more performant encoder is introduced) but this is
+ // correct and sufficient for our uses (it's what the JSON serializer in
+ // client-go does, more-or-less).
+ return json.Marshal(obj)
+}
+
+// applyPatch uses server-side apply to patch the object.
+type applyPatch struct{}
+
+// Type implements Patch.
+func (p applyPatch) Type() types.PatchType {
+ return types.ApplyPatchType
+}
+
+// Data implements Patch.
+func (p applyPatch) Data(obj Object) ([]byte, error) {
+ // NB(directxman12): we might technically want to be using an actual encoder
+ // here (in case some more performant encoder is introduced) but this is
+ // correct and sufficient for our uses (it's what the JSON serializer in
+ // client-go does, more-or-less).
+ return json.Marshal(obj)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/patch_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/patch_test.go
new file mode 100644
index 00000000000..2910ef56bf2
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/patch_test.go
@@ -0,0 +1,95 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "testing"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/resource"
+)
+
+func BenchmarkMergeFrom(b *testing.B) {
+ cm1 := &corev1.ConfigMap{}
+ cm1.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("ConfigMap"))
+ cm1.ResourceVersion = "anything"
+
+ cm2 := cm1.DeepCopy()
+ cm2.Data = map[string]string{"key": "value"}
+
+ sts1 := &appsv1.StatefulSet{}
+ sts1.SetGroupVersionKind(appsv1.SchemeGroupVersion.WithKind("StatefulSet"))
+ sts1.ResourceVersion = "somesuch"
+
+ sts2 := sts1.DeepCopy()
+ sts2.Spec.Template.Spec.Containers = []corev1.Container{{
+ Resources: corev1.ResourceRequirements{
+ Requests: map[corev1.ResourceName]resource.Quantity{
+ corev1.ResourceCPU: resource.MustParse("1m"),
+ corev1.ResourceMemory: resource.MustParse("1M"),
+ },
+ },
+ ReadinessProbe: &corev1.Probe{
+ ProbeHandler: corev1.ProbeHandler{
+ HTTPGet: &corev1.HTTPGetAction{},
+ },
+ },
+ Lifecycle: &corev1.Lifecycle{
+ PreStop: &corev1.LifecycleHandler{
+ HTTPGet: &corev1.HTTPGetAction{},
+ },
+ },
+ SecurityContext: &corev1.SecurityContext{},
+ }}
+
+ b.Run("NoOptions", func(b *testing.B) {
+ cmPatch := MergeFrom(cm1)
+ if _, err := cmPatch.Data(cm2); err != nil {
+ b.Fatalf("expected no error, got %v", err)
+ }
+
+ stsPatch := MergeFrom(sts1)
+ if _, err := stsPatch.Data(sts2); err != nil {
+ b.Fatalf("expected no error, got %v", err)
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, _ = cmPatch.Data(cm2)
+ _, _ = stsPatch.Data(sts2)
+ }
+ })
+
+ b.Run("WithOptimisticLock", func(b *testing.B) {
+ cmPatch := MergeFromWithOptions(cm1, MergeFromWithOptimisticLock{})
+ if _, err := cmPatch.Data(cm2); err != nil {
+ b.Fatalf("expected no error, got %v", err)
+ }
+
+ stsPatch := MergeFromWithOptions(sts1, MergeFromWithOptimisticLock{})
+ if _, err := stsPatch.Data(sts2); err != nil {
+ b.Fatalf("expected no error, got %v", err)
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, _ = cmPatch.Data(cm2)
+ _, _ = stsPatch.Data(sts2)
+ }
+ })
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/testdata/examplecrd.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/client/testdata/examplecrd.yaml
new file mode 100644
index 00000000000..5409ee97898
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/testdata/examplecrd.yaml
@@ -0,0 +1,17 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: chaospods.chaosapps.metamagical.io
+spec:
+ group: chaosapps.metamagical.io
+ names:
+ kind: ChaosPod
+ plural: chaospods
+ scope: Namespaced
+ versions:
+ - name: "v1"
+ storage: true
+ served: true
+ schema:
+ openAPIV3Schema:
+ type: object
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go
new file mode 100644
index 00000000000..92afd9a9c25
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go
@@ -0,0 +1,279 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+var _ Reader = &typedClient{}
+var _ Writer = &typedClient{}
+
+type typedClient struct {
+ resources *clientRestResources
+ paramCodec runtime.ParameterCodec
+}
+
+// Create implements client.Client.
+func (c *typedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
+ o, err := c.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ createOpts := &CreateOptions{}
+ createOpts.ApplyOptions(opts)
+
+ return o.Post().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Body(obj).
+ VersionedParams(createOpts.AsCreateOptions(), c.paramCodec).
+ Do(ctx).
+ Into(obj)
+}
+
+// Update implements client.Client.
+func (c *typedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ o, err := c.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ updateOpts := &UpdateOptions{}
+ updateOpts.ApplyOptions(opts)
+
+ return o.Put().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ Body(obj).
+ VersionedParams(updateOpts.AsUpdateOptions(), c.paramCodec).
+ Do(ctx).
+ Into(obj)
+}
+
+// Delete implements client.Client.
+func (c *typedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
+ o, err := c.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ deleteOpts := DeleteOptions{}
+ deleteOpts.ApplyOptions(opts)
+
+ return o.Delete().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ Body(deleteOpts.AsDeleteOptions()).
+ Do(ctx).
+ Error()
+}
+
+// DeleteAllOf implements client.Client.
+func (c *typedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
+ o, err := c.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ deleteAllOfOpts := DeleteAllOfOptions{}
+ deleteAllOfOpts.ApplyOptions(opts)
+
+ return o.Delete().
+ NamespaceIfScoped(deleteAllOfOpts.ListOptions.Namespace, o.isNamespaced()).
+ Resource(o.resource()).
+ VersionedParams(deleteAllOfOpts.AsListOptions(), c.paramCodec).
+ Body(deleteAllOfOpts.AsDeleteOptions()).
+ Do(ctx).
+ Error()
+}
+
+// Patch implements client.Client.
+func (c *typedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ o, err := c.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ data, err := patch.Data(obj)
+ if err != nil {
+ return err
+ }
+
+ patchOpts := &PatchOptions{}
+ patchOpts.ApplyOptions(opts)
+
+ return o.Patch(patch.Type()).
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ VersionedParams(patchOpts.AsPatchOptions(), c.paramCodec).
+ Body(data).
+ Do(ctx).
+ Into(obj)
+}
+
+// Get implements client.Client.
+func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
+ r, err := c.resources.getResource(obj)
+ if err != nil {
+ return err
+ }
+ getOpts := GetOptions{}
+ getOpts.ApplyOptions(opts)
+ return r.Get().
+ NamespaceIfScoped(key.Namespace, r.isNamespaced()).
+ Resource(r.resource()).
+ VersionedParams(getOpts.AsGetOptions(), c.paramCodec).
+ Name(key.Name).Do(ctx).Into(obj)
+}
+
+// List implements client.Client.
+func (c *typedClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
+ r, err := c.resources.getResource(obj)
+ if err != nil {
+ return err
+ }
+
+ listOpts := ListOptions{}
+ listOpts.ApplyOptions(opts)
+
+ return r.Get().
+ NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()).
+ Resource(r.resource()).
+ VersionedParams(listOpts.AsListOptions(), c.paramCodec).
+ Do(ctx).
+ Into(obj)
+}
+
+func (c *typedClient) GetSubResource(ctx context.Context, obj, subResourceObj Object, subResource string, opts ...SubResourceGetOption) error {
+ o, err := c.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ if subResourceObj.GetName() == "" {
+ subResourceObj.SetName(obj.GetName())
+ }
+
+ getOpts := &SubResourceGetOptions{}
+ getOpts.ApplyOptions(opts)
+
+ return o.Get().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ SubResource(subResource).
+ VersionedParams(getOpts.AsGetOptions(), c.paramCodec).
+ Do(ctx).
+ Into(subResourceObj)
+}
+
+func (c *typedClient) CreateSubResource(ctx context.Context, obj Object, subResourceObj Object, subResource string, opts ...SubResourceCreateOption) error {
+ o, err := c.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ if subResourceObj.GetName() == "" {
+ subResourceObj.SetName(obj.GetName())
+ }
+
+ createOpts := &SubResourceCreateOptions{}
+ createOpts.ApplyOptions(opts)
+
+ return o.Post().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ SubResource(subResource).
+ Body(subResourceObj).
+ VersionedParams(createOpts.AsCreateOptions(), c.paramCodec).
+ Do(ctx).
+ Into(subResourceObj)
+}
+
+// UpdateSubResource used by SubResourceWriter to write status.
+func (c *typedClient) UpdateSubResource(ctx context.Context, obj Object, subResource string, opts ...SubResourceUpdateOption) error {
+ o, err := c.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+ // TODO(droot): examine the returned error and check if it error needs to be
+ // wrapped to improve the UX ?
+ // It will be nice to receive an error saying the object doesn't implement
+ // status subresource and check CRD definition
+ updateOpts := &SubResourceUpdateOptions{}
+ updateOpts.ApplyOptions(opts)
+
+ body := obj
+ if updateOpts.SubResourceBody != nil {
+ body = updateOpts.SubResourceBody
+ }
+ if body.GetName() == "" {
+ body.SetName(obj.GetName())
+ }
+ if body.GetNamespace() == "" {
+ body.SetNamespace(obj.GetNamespace())
+ }
+
+ return o.Put().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ SubResource(subResource).
+ Body(body).
+ VersionedParams(updateOpts.AsUpdateOptions(), c.paramCodec).
+ Do(ctx).
+ Into(body)
+}
+
+// PatchSubResource used by SubResourceWriter to write subresource.
+func (c *typedClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...SubResourcePatchOption) error {
+ o, err := c.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ patchOpts := &SubResourcePatchOptions{}
+ patchOpts.ApplyOptions(opts)
+
+ body := obj
+ if patchOpts.SubResourceBody != nil {
+ body = patchOpts.SubResourceBody
+ }
+
+ data, err := patch.Data(body)
+ if err != nil {
+ return err
+ }
+
+ return o.Patch(patch.Type()).
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ SubResource(subResource).
+ Body(data).
+ VersionedParams(patchOpts.AsPatchOptions(), c.paramCodec).
+ Do(ctx).
+ Into(body)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go
new file mode 100644
index 00000000000..b8d4146c9f3
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go
@@ -0,0 +1,361 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+var _ Reader = &unstructuredClient{}
+var _ Writer = &unstructuredClient{}
+
+type unstructuredClient struct {
+ resources *clientRestResources
+ paramCodec runtime.ParameterCodec
+}
+
+// Create implements client.Client.
+func (uc *unstructuredClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
+ u, ok := obj.(runtime.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ gvk := u.GetObjectKind().GroupVersionKind()
+
+ o, err := uc.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ createOpts := &CreateOptions{}
+ createOpts.ApplyOptions(opts)
+
+ result := o.Post().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Body(obj).
+ VersionedParams(createOpts.AsCreateOptions(), uc.paramCodec).
+ Do(ctx).
+ Into(obj)
+
+ u.GetObjectKind().SetGroupVersionKind(gvk)
+ return result
+}
+
+// Update implements client.Client.
+func (uc *unstructuredClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ u, ok := obj.(runtime.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ gvk := u.GetObjectKind().GroupVersionKind()
+
+ o, err := uc.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ updateOpts := UpdateOptions{}
+ updateOpts.ApplyOptions(opts)
+
+ result := o.Put().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ Body(obj).
+ VersionedParams(updateOpts.AsUpdateOptions(), uc.paramCodec).
+ Do(ctx).
+ Into(obj)
+
+ u.GetObjectKind().SetGroupVersionKind(gvk)
+ return result
+}
+
+// Delete implements client.Client.
+func (uc *unstructuredClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
+ if _, ok := obj.(runtime.Unstructured); !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ o, err := uc.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ deleteOpts := DeleteOptions{}
+ deleteOpts.ApplyOptions(opts)
+
+ return o.Delete().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ Body(deleteOpts.AsDeleteOptions()).
+ Do(ctx).
+ Error()
+}
+
+// DeleteAllOf implements client.Client.
+func (uc *unstructuredClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
+ if _, ok := obj.(runtime.Unstructured); !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ o, err := uc.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ deleteAllOfOpts := DeleteAllOfOptions{}
+ deleteAllOfOpts.ApplyOptions(opts)
+
+ return o.Delete().
+ NamespaceIfScoped(deleteAllOfOpts.ListOptions.Namespace, o.isNamespaced()).
+ Resource(o.resource()).
+ VersionedParams(deleteAllOfOpts.AsListOptions(), uc.paramCodec).
+ Body(deleteAllOfOpts.AsDeleteOptions()).
+ Do(ctx).
+ Error()
+}
+
+// Patch implements client.Client.
+func (uc *unstructuredClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ if _, ok := obj.(runtime.Unstructured); !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ o, err := uc.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ data, err := patch.Data(obj)
+ if err != nil {
+ return err
+ }
+
+ patchOpts := &PatchOptions{}
+ patchOpts.ApplyOptions(opts)
+
+ return o.Patch(patch.Type()).
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ VersionedParams(patchOpts.AsPatchOptions(), uc.paramCodec).
+ Body(data).
+ Do(ctx).
+ Into(obj)
+}
+
+// Get implements client.Client.
+func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
+ u, ok := obj.(runtime.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ gvk := u.GetObjectKind().GroupVersionKind()
+
+ getOpts := GetOptions{}
+ getOpts.ApplyOptions(opts)
+
+ r, err := uc.resources.getResource(obj)
+ if err != nil {
+ return err
+ }
+
+ result := r.Get().
+ NamespaceIfScoped(key.Namespace, r.isNamespaced()).
+ Resource(r.resource()).
+ VersionedParams(getOpts.AsGetOptions(), uc.paramCodec).
+ Name(key.Name).
+ Do(ctx).
+ Into(obj)
+
+ u.GetObjectKind().SetGroupVersionKind(gvk)
+
+ return result
+}
+
+// List implements client.Client.
+func (uc *unstructuredClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
+ u, ok := obj.(runtime.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ gvk := u.GetObjectKind().GroupVersionKind()
+ gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
+
+ r, err := uc.resources.getResource(obj)
+ if err != nil {
+ return err
+ }
+
+ listOpts := ListOptions{}
+ listOpts.ApplyOptions(opts)
+
+ return r.Get().
+ NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()).
+ Resource(r.resource()).
+ VersionedParams(listOpts.AsListOptions(), uc.paramCodec).
+ Do(ctx).
+ Into(obj)
+}
+
+func (uc *unstructuredClient) GetSubResource(ctx context.Context, obj, subResourceObj Object, subResource string, opts ...SubResourceGetOption) error {
+ if _, ok := obj.(runtime.Unstructured); !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", subResource)
+ }
+
+ if _, ok := subResourceObj.(runtime.Unstructured); !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ if subResourceObj.GetName() == "" {
+ subResourceObj.SetName(obj.GetName())
+ }
+
+ o, err := uc.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ getOpts := &SubResourceGetOptions{}
+ getOpts.ApplyOptions(opts)
+
+ return o.Get().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ SubResource(subResource).
+ VersionedParams(getOpts.AsGetOptions(), uc.paramCodec).
+ Do(ctx).
+ Into(subResourceObj)
+}
+
+func (uc *unstructuredClient) CreateSubResource(ctx context.Context, obj, subResourceObj Object, subResource string, opts ...SubResourceCreateOption) error {
+ if _, ok := obj.(runtime.Unstructured); !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", subResourceObj)
+ }
+
+ if _, ok := subResourceObj.(runtime.Unstructured); !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ if subResourceObj.GetName() == "" {
+ subResourceObj.SetName(obj.GetName())
+ }
+
+ o, err := uc.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ createOpts := &SubResourceCreateOptions{}
+ createOpts.ApplyOptions(opts)
+
+ return o.Post().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ SubResource(subResource).
+ Body(subResourceObj).
+ VersionedParams(createOpts.AsCreateOptions(), uc.paramCodec).
+ Do(ctx).
+ Into(subResourceObj)
+}
+
+func (uc *unstructuredClient) UpdateSubResource(ctx context.Context, obj Object, subResource string, opts ...SubResourceUpdateOption) error {
+ if _, ok := obj.(runtime.Unstructured); !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ o, err := uc.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ updateOpts := SubResourceUpdateOptions{}
+ updateOpts.ApplyOptions(opts)
+
+ body := obj
+ if updateOpts.SubResourceBody != nil {
+ body = updateOpts.SubResourceBody
+ }
+ if body.GetName() == "" {
+ body.SetName(obj.GetName())
+ }
+ if body.GetNamespace() == "" {
+ body.SetNamespace(obj.GetNamespace())
+ }
+
+ return o.Put().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ SubResource(subResource).
+ Body(body).
+ VersionedParams(updateOpts.AsUpdateOptions(), uc.paramCodec).
+ Do(ctx).
+ Into(body)
+}
+
+func (uc *unstructuredClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...SubResourcePatchOption) error {
+ u, ok := obj.(runtime.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ gvk := u.GetObjectKind().GroupVersionKind()
+
+ o, err := uc.resources.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ patchOpts := &SubResourcePatchOptions{}
+ patchOpts.ApplyOptions(opts)
+
+ body := obj
+ if patchOpts.SubResourceBody != nil {
+ body = patchOpts.SubResourceBody
+ }
+
+ data, err := patch.Data(body)
+ if err != nil {
+ return err
+ }
+
+ result := o.Patch(patch.Type()).
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ SubResource(subResource).
+ Body(data).
+ VersionedParams(patchOpts.AsPatchOptions(), uc.paramCodec).
+ Do(ctx).
+ Into(body)
+
+ u.GetObjectKind().SetGroupVersionKind(gvk)
+ return result
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/watch.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/watch.go
new file mode 100644
index 00000000000..181b22a6732
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/watch.go
@@ -0,0 +1,106 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "strings"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/watch"
+ "k8s.io/client-go/rest"
+)
+
+// NewWithWatch returns a new WithWatch.
+func NewWithWatch(config *rest.Config, options Options) (WithWatch, error) {
+ client, err := newClient(config, options)
+ if err != nil {
+ return nil, err
+ }
+ return &watchingClient{client: client}, nil
+}
+
+type watchingClient struct {
+ *client
+}
+
+func (w *watchingClient) Watch(ctx context.Context, list ObjectList, opts ...ListOption) (watch.Interface, error) {
+ switch l := list.(type) {
+ case runtime.Unstructured:
+ return w.unstructuredWatch(ctx, l, opts...)
+ case *metav1.PartialObjectMetadataList:
+ return w.metadataWatch(ctx, l, opts...)
+ default:
+ return w.typedWatch(ctx, l, opts...)
+ }
+}
+
+func (w *watchingClient) listOpts(opts ...ListOption) ListOptions {
+ listOpts := ListOptions{}
+ listOpts.ApplyOptions(opts)
+ if listOpts.Raw == nil {
+ listOpts.Raw = &metav1.ListOptions{}
+ }
+ listOpts.Raw.Watch = true
+
+ return listOpts
+}
+
+func (w *watchingClient) metadataWatch(ctx context.Context, obj *metav1.PartialObjectMetadataList, opts ...ListOption) (watch.Interface, error) {
+ gvk := obj.GroupVersionKind()
+ gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
+
+ listOpts := w.listOpts(opts...)
+
+ resInt, err := w.client.metadataClient.getResourceInterface(gvk, listOpts.Namespace)
+ if err != nil {
+ return nil, err
+ }
+
+ return resInt.Watch(ctx, *listOpts.AsListOptions())
+}
+
+func (w *watchingClient) unstructuredWatch(ctx context.Context, obj runtime.Unstructured, opts ...ListOption) (watch.Interface, error) {
+ r, err := w.client.unstructuredClient.resources.getResource(obj)
+ if err != nil {
+ return nil, err
+ }
+
+ listOpts := w.listOpts(opts...)
+
+ return r.Get().
+ NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()).
+ Resource(r.resource()).
+ VersionedParams(listOpts.AsListOptions(), w.client.unstructuredClient.paramCodec).
+ Watch(ctx)
+}
+
+func (w *watchingClient) typedWatch(ctx context.Context, obj ObjectList, opts ...ListOption) (watch.Interface, error) {
+ r, err := w.client.typedClient.resources.getResource(obj)
+ if err != nil {
+ return nil, err
+ }
+
+ listOpts := w.listOpts(opts...)
+
+ return r.Get().
+ NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()).
+ Resource(r.resource()).
+ VersionedParams(listOpts.AsListOptions(), w.client.typedClient.paramCodec).
+ Watch(ctx)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/client/watch_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/client/watch_test.go
new file mode 100644
index 00000000000..26d90f65501
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/client/watch_test.go
@@ -0,0 +1,133 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client_test
+
+import (
+ "context"
+ "fmt"
+ "sync/atomic"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ appsv1 "k8s.io/api/apps/v1"
+ 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/fields"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/watch"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+var _ = Describe("ClientWithWatch", func() {
+ var dep *appsv1.Deployment
+ var count uint64 = 0
+ var replicaCount int32 = 2
+ var ns = "kube-public"
+ ctx := context.TODO()
+
+ BeforeEach(func() {
+ atomic.AddUint64(&count, 1)
+ dep = &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("watch-deployment-name-%v", count), Namespace: ns, Labels: map[string]string{"app": fmt.Sprintf("bar-%v", count)}},
+ Spec: appsv1.DeploymentSpec{
+ Replicas: &replicaCount,
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
+ },
+ },
+ }
+
+ var err error
+ dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ AfterEach(func() {
+ deleteDeployment(ctx, dep, ns)
+ })
+
+ Describe("NewWithWatch", func() {
+ It("should return a new Client", func() {
+ cl, err := client.NewWithWatch(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+ })
+
+ watchSuite := func(through client.ObjectList, expectedType client.Object, checkGvk bool) {
+ cl, err := client.NewWithWatch(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cl).NotTo(BeNil())
+
+ watchInterface, err := cl.Watch(ctx, through, &client.ListOptions{
+ FieldSelector: fields.OneTermEqualSelector("metadata.name", dep.Name),
+ Namespace: dep.Namespace,
+ })
+ Expect(err).NotTo(HaveOccurred())
+ Expect(watchInterface).NotTo(BeNil())
+
+ defer watchInterface.Stop()
+
+ event, ok := <-watchInterface.ResultChan()
+ Expect(ok).To(BeTrue())
+ Expect(event.Type).To(BeIdenticalTo(watch.Added))
+ Expect(event.Object).To(BeAssignableToTypeOf(expectedType))
+
+ // The metadata client doesn't set GVK so we just use the
+ // name and UID as a proxy to confirm that we got the right
+ // object.
+ metaObject, ok := event.Object.(metav1.Object)
+ Expect(ok).To(BeTrue())
+ Expect(metaObject.GetName()).To(Equal(dep.Name))
+ Expect(metaObject.GetUID()).To(Equal(dep.UID))
+
+ if checkGvk {
+ runtimeObject := event.Object
+ gvk := runtimeObject.GetObjectKind().GroupVersionKind()
+ Expect(gvk).To(Equal(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ }))
+ }
+ }
+
+ It("should receive a create event when watching the typed object", func() {
+ watchSuite(&appsv1.DeploymentList{}, &appsv1.Deployment{}, false)
+ })
+
+ It("should receive a create event when watching the unstructured object", func() {
+ u := &unstructured.UnstructuredList{}
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Group: "apps",
+ Kind: "Deployment",
+ Version: "v1",
+ })
+ watchSuite(u, &unstructured.Unstructured{}, true)
+ })
+
+ It("should receive a create event when watching the metadata object", func() {
+ m := &metav1.PartialObjectMetadataList{TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: "apps/v1"}}
+ watchSuite(m, &metav1.PartialObjectMetadata{}, false)
+ })
+ })
+
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go
new file mode 100644
index 00000000000..7d00c3c4b0e
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go
@@ -0,0 +1,343 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cluster
+
+import (
+ "context"
+ "errors"
+ "net/http"
+ "time"
+
+ "github.com/go-logr/logr"
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/record"
+ "k8s.io/utils/pointer"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
+)
+
+// Cluster provides various methods to interact with a cluster.
+type Cluster interface {
+ // GetHTTPClient returns an HTTP client that can be used to talk to the apiserver
+ GetHTTPClient() *http.Client
+
+ // GetConfig returns an initialized Config
+ GetConfig() *rest.Config
+
+ // GetCache returns a cache.Cache
+ GetCache() cache.Cache
+
+ // GetScheme returns an initialized Scheme
+ GetScheme() *runtime.Scheme
+
+ // GetClient returns a client configured with the Config. This client may
+ // not be a fully "direct" client -- it may read from a cache, for
+ // instance. See Options.NewClient for more information on how the default
+ // implementation works.
+ GetClient() client.Client
+
+ // GetFieldIndexer returns a client.FieldIndexer configured with the client
+ GetFieldIndexer() client.FieldIndexer
+
+ // GetEventRecorderFor returns a new EventRecorder for the provided name
+ GetEventRecorderFor(name string) record.EventRecorder
+
+ // GetRESTMapper returns a RESTMapper
+ GetRESTMapper() meta.RESTMapper
+
+ // GetAPIReader returns a reader that will be configured to use the API server.
+ // This should be used sparingly and only when the client does not fit your
+ // use case.
+ GetAPIReader() client.Reader
+
+ // Start starts the cluster
+ Start(ctx context.Context) error
+}
+
+// Options are the possible options that can be configured for a Cluster.
+type Options struct {
+ // Scheme is the scheme used to resolve runtime.Objects to GroupVersionKinds / Resources
+ // Defaults to the kubernetes/client-go scheme.Scheme, but it's almost always better
+ // idea to pass your own scheme in. See the documentation in pkg/scheme for more information.
+ Scheme *runtime.Scheme
+
+ // MapperProvider provides the rest mapper used to map go types to Kubernetes APIs
+ MapperProvider func(c *rest.Config, httpClient *http.Client) (meta.RESTMapper, error)
+
+ // Logger is the logger that should be used by this Cluster.
+ // If none is set, it defaults to log.Log global logger.
+ Logger logr.Logger
+
+ // SyncPeriod determines the minimum frequency at which watched resources are
+ // reconciled. A lower period will correct entropy more quickly, but reduce
+ // responsiveness to change if there are many watched resources. Change this
+ // value only if you know what you are doing. Defaults to 10 hours if unset.
+ // there will a 10 percent jitter between the SyncPeriod of all controllers
+ // so that all controllers will not send list requests simultaneously.
+ SyncPeriod *time.Duration
+
+ // Namespace if specified restricts the manager's cache to watch objects in
+ // the desired namespace Defaults to all namespaces
+ //
+ // Note: If a namespace is specified, controllers can still Watch for a
+ // cluster-scoped resource (e.g Node). For namespaced resources the cache
+ // will only hold objects from the desired namespace.
+ //
+ // Deprecated: Use Cache.Namespaces instead.
+ Namespace string
+
+ // HTTPClient is the http client that will be used to create the default
+ // Cache and Client. If not set the rest.HTTPClientFor function will be used
+ // to create the http client.
+ HTTPClient *http.Client
+
+ // Cache is the cache.Options that will be used to create the default Cache.
+ // By default, the cache will watch and list requested objects in all namespaces.
+ Cache cache.Options
+
+ // NewCache is the function that will create the cache to be used
+ // by the manager. If not set this will use the default new cache function.
+ //
+ // When using a custom NewCache, the Cache options will be passed to the
+ // NewCache function.
+ //
+ // NOTE: LOW LEVEL PRIMITIVE!
+ // Only use a custom NewCache if you know what you are doing.
+ NewCache cache.NewCacheFunc
+
+ // Client is the client.Options that will be used to create the default Client.
+ // By default, the client will use the cache for reads and direct calls for writes.
+ Client client.Options
+
+ // NewClient is the func that creates the client to be used by the manager.
+ // If not set this will create a Client backed by a Cache for read operations
+ // and a direct Client for write operations.
+ //
+ // When using a custom NewClient, the Client options will be passed to the
+ // NewClient function.
+ //
+ // NOTE: LOW LEVEL PRIMITIVE!
+ // Only use a custom NewClient if you know what you are doing.
+ NewClient client.NewClientFunc
+
+ // ClientDisableCacheFor tells the client that, if any cache is used, to bypass it
+ // for the given objects.
+ //
+ // Deprecated: Use Client.Cache.DisableFor instead.
+ ClientDisableCacheFor []client.Object
+
+ // DryRunClient specifies whether the client should be configured to enforce
+ // dryRun mode.
+ //
+ // Deprecated: Use Client.DryRun instead.
+ DryRunClient bool
+
+ // EventBroadcaster records Events emitted by the manager and sends them to the Kubernetes API
+ // Use this to customize the event correlator and spam filter
+ //
+ // Deprecated: using this may cause goroutine leaks if the lifetime of your manager or controllers
+ // is shorter than the lifetime of your process.
+ EventBroadcaster record.EventBroadcaster
+
+ // makeBroadcaster allows deferring the creation of the broadcaster to
+ // avoid leaking goroutines if we never call Start on this manager. It also
+ // returns whether or not this is a "owned" broadcaster, and as such should be
+ // stopped with the manager.
+ makeBroadcaster intrec.EventBroadcasterProducer
+
+ // Dependency injection for testing
+ newRecorderProvider func(config *rest.Config, httpClient *http.Client, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster intrec.EventBroadcasterProducer) (*intrec.Provider, error)
+}
+
+// Option can be used to manipulate Options.
+type Option func(*Options)
+
+// New constructs a brand new cluster.
+func New(config *rest.Config, opts ...Option) (Cluster, error) {
+ if config == nil {
+ return nil, errors.New("must specify Config")
+ }
+
+ options := Options{}
+ for _, opt := range opts {
+ opt(&options)
+ }
+ options, err := setOptionsDefaults(options, config)
+ if err != nil {
+ options.Logger.Error(err, "Failed to set defaults")
+ return nil, err
+ }
+
+ // Create the mapper provider
+ mapper, err := options.MapperProvider(config, options.HTTPClient)
+ if err != nil {
+ options.Logger.Error(err, "Failed to get API Group-Resources")
+ return nil, err
+ }
+
+ // Create the cache for the cached read client and registering informers
+ cacheOpts := options.Cache
+ {
+ if cacheOpts.Scheme == nil {
+ cacheOpts.Scheme = options.Scheme
+ }
+ if cacheOpts.Mapper == nil {
+ cacheOpts.Mapper = mapper
+ }
+ if cacheOpts.HTTPClient == nil {
+ cacheOpts.HTTPClient = options.HTTPClient
+ }
+ if cacheOpts.SyncPeriod == nil {
+ cacheOpts.SyncPeriod = options.SyncPeriod
+ }
+ if len(cacheOpts.Namespaces) == 0 && options.Namespace != "" {
+ cacheOpts.Namespaces = []string{options.Namespace}
+ }
+ }
+ cache, err := options.NewCache(config, cacheOpts)
+ if err != nil {
+ return nil, err
+ }
+
+ // Create the client, and default its options.
+ clientOpts := options.Client
+ {
+ if clientOpts.Scheme == nil {
+ clientOpts.Scheme = options.Scheme
+ }
+ if clientOpts.Mapper == nil {
+ clientOpts.Mapper = mapper
+ }
+ if clientOpts.HTTPClient == nil {
+ clientOpts.HTTPClient = options.HTTPClient
+ }
+ if clientOpts.Cache == nil {
+ clientOpts.Cache = &client.CacheOptions{
+ Unstructured: false,
+ }
+ }
+ if clientOpts.Cache.Reader == nil {
+ clientOpts.Cache.Reader = cache
+ }
+
+ // For backward compatibility, the ClientDisableCacheFor option should
+ // be appended to the DisableFor option in the client.
+ clientOpts.Cache.DisableFor = append(clientOpts.Cache.DisableFor, options.ClientDisableCacheFor...)
+
+ if clientOpts.DryRun == nil && options.DryRunClient {
+ // For backward compatibility, the DryRunClient (if set) option should override
+ // the DryRun option in the client (if unset).
+ clientOpts.DryRun = pointer.Bool(true)
+ }
+ }
+ clientWriter, err := options.NewClient(config, clientOpts)
+ if err != nil {
+ return nil, err
+ }
+
+ // Create the API Reader, a client with no cache.
+ clientReader, err := client.New(config, client.Options{
+ HTTPClient: options.HTTPClient,
+ Scheme: options.Scheme,
+ Mapper: mapper,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ // Create the recorder provider to inject event recorders for the components.
+ // TODO(directxman12): the log for the event provider should have a context (name, tags, etc) specific
+ // to the particular controller that it's being injected into, rather than a generic one like is here.
+ recorderProvider, err := options.newRecorderProvider(config, options.HTTPClient, options.Scheme, options.Logger.WithName("events"), options.makeBroadcaster)
+ if err != nil {
+ return nil, err
+ }
+
+ return &cluster{
+ config: config,
+ httpClient: options.HTTPClient,
+ scheme: options.Scheme,
+ cache: cache,
+ fieldIndexes: cache,
+ client: clientWriter,
+ apiReader: clientReader,
+ recorderProvider: recorderProvider,
+ mapper: mapper,
+ logger: options.Logger,
+ }, nil
+}
+
+// setOptionsDefaults set default values for Options fields.
+func setOptionsDefaults(options Options, config *rest.Config) (Options, error) {
+ if options.HTTPClient == nil {
+ var err error
+ options.HTTPClient, err = rest.HTTPClientFor(config)
+ if err != nil {
+ return options, err
+ }
+ }
+
+ // Use the Kubernetes client-go scheme if none is specified
+ if options.Scheme == nil {
+ options.Scheme = scheme.Scheme
+ }
+
+ if options.MapperProvider == nil {
+ options.MapperProvider = apiutil.NewDynamicRESTMapper
+ }
+
+ // Allow users to define how to create a new client
+ if options.NewClient == nil {
+ options.NewClient = client.New
+ }
+
+ // Allow newCache to be mocked
+ if options.NewCache == nil {
+ options.NewCache = cache.New
+ }
+
+ // Allow newRecorderProvider to be mocked
+ if options.newRecorderProvider == nil {
+ options.newRecorderProvider = intrec.NewProvider
+ }
+
+ // This is duplicated with pkg/manager, we need it here to provide
+ // the user with an EventBroadcaster and there for the Leader election
+ if options.EventBroadcaster == nil {
+ // defer initialization to avoid leaking by default
+ options.makeBroadcaster = func() (record.EventBroadcaster, bool) {
+ return record.NewBroadcaster(), true
+ }
+ } else {
+ options.makeBroadcaster = func() (record.EventBroadcaster, bool) {
+ return options.EventBroadcaster, false
+ }
+ }
+
+ if options.Logger.GetSink() == nil {
+ options.Logger = logf.RuntimeLog.WithName("cluster")
+ }
+
+ return options, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cluster/cluster_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cluster/cluster_suite_test.go
new file mode 100644
index 00000000000..dc1f9ac7786
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cluster/cluster_suite_test.go
@@ -0,0 +1,68 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cluster
+
+import (
+ "net/http"
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Cluster Suite")
+}
+
+var testenv *envtest.Environment
+var cfg *rest.Config
+var clientset *kubernetes.Clientset
+
+// clientTransport is used to force-close keep-alives in tests that check for leaks.
+var clientTransport *http.Transport
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+ testenv = &envtest.Environment{}
+
+ var err error
+ cfg, err = testenv.Start()
+ Expect(err).NotTo(HaveOccurred())
+
+ cfg.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
+ // NB(directxman12): we can't set Transport *and* use TLS options,
+ // so we grab the transport right after it gets created so that we can
+ // type-assert on it (hopefully)?
+ // hopefully this doesn't break 🤞
+ clientTransport = rt.(*http.Transport)
+ return rt
+ }
+
+ clientset, err = kubernetes.NewForConfig(cfg)
+ Expect(err).NotTo(HaveOccurred())
+})
+
+var _ = AfterSuite(func() {
+ Expect(testenv.Stop()).To(Succeed())
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cluster/cluster_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cluster/cluster_test.go
new file mode 100644
index 00000000000..dc52b2d9b31
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cluster/cluster_test.go
@@ -0,0 +1,170 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cluster
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+
+ "github.com/go-logr/logr"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "go.uber.org/goleak"
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
+)
+
+var _ = Describe("cluster.Cluster", func() {
+ Describe("New", func() {
+ It("should return an error if there is no Config", func() {
+ c, err := New(nil)
+ Expect(c).To(BeNil())
+ Expect(err.Error()).To(ContainSubstring("must specify Config"))
+
+ })
+
+ It("should return an error if it can't create a RestMapper", func() {
+ expected := fmt.Errorf("expected error: RestMapper")
+ c, err := New(cfg, func(o *Options) {
+ o.MapperProvider = func(c *rest.Config, httpClient *http.Client) (meta.RESTMapper, error) { return nil, expected }
+ })
+ Expect(c).To(BeNil())
+ Expect(err).To(Equal(expected))
+
+ })
+
+ It("should return an error it can't create a client.Client", func() {
+ c, err := New(cfg, func(o *Options) {
+ o.NewClient = func(config *rest.Config, options client.Options) (client.Client, error) {
+ return nil, errors.New("expected error")
+ }
+ })
+ Expect(c).To(BeNil())
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("expected error"))
+ })
+
+ It("should return an error it can't create a cache.Cache", func() {
+ c, err := New(cfg, func(o *Options) {
+ o.NewCache = func(config *rest.Config, opts cache.Options) (cache.Cache, error) {
+ return nil, fmt.Errorf("expected error")
+ }
+ })
+ Expect(c).To(BeNil())
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("expected error"))
+ })
+
+ It("should create a client defined in by the new client function", func() {
+ c, err := New(cfg, func(o *Options) {
+ o.NewClient = func(config *rest.Config, options client.Options) (client.Client, error) {
+ return nil, nil
+ }
+ })
+ Expect(c).ToNot(BeNil())
+ Expect(err).ToNot(HaveOccurred())
+ Expect(c.GetClient()).To(BeNil())
+ })
+
+ It("should return an error it can't create a recorder.Provider", func() {
+ c, err := New(cfg, func(o *Options) {
+ o.newRecorderProvider = func(_ *rest.Config, _ *http.Client, _ *runtime.Scheme, _ logr.Logger, _ intrec.EventBroadcasterProducer) (*intrec.Provider, error) {
+ return nil, fmt.Errorf("expected error")
+ }
+ })
+ Expect(c).To(BeNil())
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("expected error"))
+ })
+
+ })
+
+ Describe("Start", func() {
+ It("should stop when context is cancelled", func() {
+ c, err := New(cfg)
+ Expect(err).NotTo(HaveOccurred())
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ Expect(c.Start(ctx)).NotTo(HaveOccurred())
+ })
+ })
+
+ It("should not leak goroutines when stopped", func() {
+ currentGRs := goleak.IgnoreCurrent()
+
+ c, err := New(cfg)
+ Expect(err).NotTo(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ Expect(c.Start(ctx)).NotTo(HaveOccurred())
+
+ // force-close keep-alive connections. These'll time anyway (after
+ // like 30s or so) but force it to speed up the tests.
+ clientTransport.CloseIdleConnections()
+ Eventually(func() error { return goleak.Find(currentGRs) }).Should(Succeed())
+ })
+
+ It("should provide a function to get the Config", func() {
+ c, err := New(cfg)
+ Expect(err).NotTo(HaveOccurred())
+ cluster, ok := c.(*cluster)
+ Expect(ok).To(BeTrue())
+ Expect(c.GetConfig()).To(Equal(cluster.config))
+ })
+
+ It("should provide a function to get the Client", func() {
+ c, err := New(cfg)
+ Expect(err).NotTo(HaveOccurred())
+ cluster, ok := c.(*cluster)
+ Expect(ok).To(BeTrue())
+ Expect(c.GetClient()).To(Equal(cluster.client))
+ })
+
+ It("should provide a function to get the Scheme", func() {
+ c, err := New(cfg)
+ Expect(err).NotTo(HaveOccurred())
+ cluster, ok := c.(*cluster)
+ Expect(ok).To(BeTrue())
+ Expect(c.GetScheme()).To(Equal(cluster.scheme))
+ })
+
+ It("should provide a function to get the FieldIndexer", func() {
+ c, err := New(cfg)
+ Expect(err).NotTo(HaveOccurred())
+ cluster, ok := c.(*cluster)
+ Expect(ok).To(BeTrue())
+ Expect(c.GetFieldIndexer()).To(Equal(cluster.cache))
+ })
+
+ It("should provide a function to get the EventRecorder", func() {
+ c, err := New(cfg)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(c.GetEventRecorderFor("test")).NotTo(BeNil())
+ })
+ It("should provide a function to get the APIReader", func() {
+ c, err := New(cfg)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(c.GetAPIReader()).NotTo(BeNil())
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go b/third_party/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go
new file mode 100644
index 00000000000..2742764231b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go
@@ -0,0 +1,105 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cluster
+
+import (
+ "context"
+ "net/http"
+
+ "github.com/go-logr/logr"
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/record"
+
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
+)
+
+type cluster struct {
+ // config is the rest.config used to talk to the apiserver. Required.
+ config *rest.Config
+
+ httpClient *http.Client
+ scheme *runtime.Scheme
+ cache cache.Cache
+ client client.Client
+
+ // apiReader is the reader that will make requests to the api server and not the cache.
+ apiReader client.Reader
+
+ // fieldIndexes knows how to add field indexes over the Cache used by this controller,
+ // which can later be consumed via field selectors from the injected client.
+ fieldIndexes client.FieldIndexer
+
+ // recorderProvider is used to generate event recorders that will be injected into Controllers
+ // (and EventHandlers, Sources and Predicates).
+ recorderProvider *intrec.Provider
+
+ // mapper is used to map resources to kind, and map kind and version.
+ mapper meta.RESTMapper
+
+ // Logger is the logger that should be used by this manager.
+ // If none is set, it defaults to log.Log global logger.
+ logger logr.Logger
+}
+
+func (c *cluster) GetConfig() *rest.Config {
+ return c.config
+}
+
+func (c *cluster) GetHTTPClient() *http.Client {
+ return c.httpClient
+}
+
+func (c *cluster) GetClient() client.Client {
+ return c.client
+}
+
+func (c *cluster) GetScheme() *runtime.Scheme {
+ return c.scheme
+}
+
+func (c *cluster) GetFieldIndexer() client.FieldIndexer {
+ return c.fieldIndexes
+}
+
+func (c *cluster) GetCache() cache.Cache {
+ return c.cache
+}
+
+func (c *cluster) GetEventRecorderFor(name string) record.EventRecorder {
+ return c.recorderProvider.GetEventRecorderFor(name)
+}
+
+func (c *cluster) GetRESTMapper() meta.RESTMapper {
+ return c.mapper
+}
+
+func (c *cluster) GetAPIReader() client.Reader {
+ return c.apiReader
+}
+
+func (c *cluster) GetLogger() logr.Logger {
+ return c.logger
+}
+
+func (c *cluster) Start(ctx context.Context) error {
+ defer c.recorderProvider.Stop(ctx)
+ return c.cache.Start(ctx)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/config/config.go b/third_party/sigs.k8s.io/controller-runtime/pkg/config/config.go
new file mode 100644
index 00000000000..9c7b875a860
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/config/config.go
@@ -0,0 +1,112 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config
+
+import (
+ "fmt"
+ "os"
+ "sync"
+
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+ "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
+)
+
+// ControllerManagerConfiguration defines the functions necessary to parse a config file
+// and to configure the Options struct for the ctrl.Manager.
+//
+// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+type ControllerManagerConfiguration interface {
+ runtime.Object
+
+ // Complete returns the versioned configuration
+ Complete() (v1alpha1.ControllerManagerConfigurationSpec, error)
+}
+
+// DeferredFileLoader is used to configure the decoder for loading controller
+// runtime component config types.
+//
+// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+type DeferredFileLoader struct {
+ ControllerManagerConfiguration
+ path string
+ scheme *runtime.Scheme
+ once sync.Once
+ err error
+}
+
+// File will set up the deferred file loader for the configuration
+// this will also configure the defaults for the loader if nothing is
+//
+// Defaults:
+// * Path: "./config.yaml"
+// * Kind: GenericControllerManagerConfiguration
+//
+// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+func File() *DeferredFileLoader {
+ scheme := runtime.NewScheme()
+ utilruntime.Must(v1alpha1.AddToScheme(scheme))
+ return &DeferredFileLoader{
+ path: "./config.yaml",
+ ControllerManagerConfiguration: &v1alpha1.ControllerManagerConfiguration{},
+ scheme: scheme,
+ }
+}
+
+// Complete will use sync.Once to set the scheme.
+func (d *DeferredFileLoader) Complete() (v1alpha1.ControllerManagerConfigurationSpec, error) {
+ d.once.Do(d.loadFile)
+ if d.err != nil {
+ return v1alpha1.ControllerManagerConfigurationSpec{}, d.err
+ }
+ return d.ControllerManagerConfiguration.Complete()
+}
+
+// AtPath will set the path to load the file for the decoder.
+func (d *DeferredFileLoader) AtPath(path string) *DeferredFileLoader {
+ d.path = path
+ return d
+}
+
+// OfKind will set the type to be used for decoding the file into.
+func (d *DeferredFileLoader) OfKind(obj ControllerManagerConfiguration) *DeferredFileLoader {
+ d.ControllerManagerConfiguration = obj
+ return d
+}
+
+// loadFile is used from the mutex.Once to load the file.
+func (d *DeferredFileLoader) loadFile() {
+ if d.scheme == nil {
+ d.err = fmt.Errorf("scheme not supplied to controller configuration loader")
+ return
+ }
+
+ content, err := os.ReadFile(d.path)
+ if err != nil {
+ d.err = fmt.Errorf("could not read file at %s", d.path)
+ return
+ }
+
+ codecs := serializer.NewCodecFactory(d.scheme)
+
+ // Regardless of if the bytes are of any external version,
+ // it will be read successfully and converted into the internal version
+ if err = runtime.DecodeInto(codecs.UniversalDecoder(), content, d.ControllerManagerConfiguration); err != nil {
+ d.err = fmt.Errorf("could not decode file into runtime.Object")
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/config/config_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/config/config_suite_test.go
new file mode 100644
index 00000000000..8df933ba9db
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/config/config_suite_test.go
@@ -0,0 +1,26 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestScheme(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Config Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/config/config_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/config/config_test.go
new file mode 100644
index 00000000000..329c0296c5a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/config/config_test.go
@@ -0,0 +1,45 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config_test
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "sigs.k8s.io/controller-runtime/pkg/config"
+ "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
+)
+
+var _ = Describe("config", func() {
+ Describe("File", func() {
+
+ It("should error loading from non existent file", func() {
+ loader := config.File()
+ _, err := loader.Complete()
+ Expect(err).ToNot(BeNil())
+ })
+
+ It("should load a config from file", func() {
+ conf := v1alpha1.ControllerManagerConfiguration{}
+ loader := config.File().AtPath("./testdata/config.yaml").OfKind(&conf)
+ Expect(conf.CacheNamespace).To(Equal(""))
+
+ _, err := loader.Complete()
+ Expect(err).To(BeNil())
+
+ Expect(*conf.LeaderElection.LeaderElect).To(Equal(true))
+ Expect(conf.CacheNamespace).To(Equal("default"))
+ Expect(conf.Metrics.BindAddress).To(Equal(":8081"))
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/config/controller.go b/third_party/sigs.k8s.io/controller-runtime/pkg/config/controller.go
new file mode 100644
index 00000000000..b37dffaeea4
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/config/controller.go
@@ -0,0 +1,49 @@
+/*
+Copyright 2023 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config
+
+import "time"
+
+// Controller contains configuration options for a controller.
+type Controller struct {
+ // GroupKindConcurrency is a map from a Kind to the number of concurrent reconciliation
+ // allowed for that controller.
+ //
+ // When a controller is registered within this manager using the builder utilities,
+ // users have to specify the type the controller reconciles in the For(...) call.
+ // If the object's kind passed matches one of the keys in this map, the concurrency
+ // for that controller is set to the number specified.
+ //
+ // The key is expected to be consistent in form with GroupKind.String(),
+ // e.g. ReplicaSet in apps group (regardless of version) would be `ReplicaSet.apps`.
+ GroupKindConcurrency map[string]int
+
+ // MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
+ MaxConcurrentReconciles int
+
+ // CacheSyncTimeout refers to the time limit set to wait for syncing caches.
+ // Defaults to 2 minutes if not set.
+ CacheSyncTimeout time.Duration
+
+ // RecoverPanic indicates whether the panic caused by reconcile should be recovered.
+ // Defaults to the Controller.RecoverPanic setting from the Manager if unset.
+ RecoverPanic *bool
+
+ // NeedLeaderElection indicates whether the controller needs to use leader election.
+ // Defaults to true, which means the controller will use leader election.
+ NeedLeaderElection *bool
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/config/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/config/doc.go
new file mode 100644
index 00000000000..47a5a2f1d73
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/config/doc.go
@@ -0,0 +1,19 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package config contains functionality for interacting with
+// configuration for controller-runtime components.
+package config
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/config/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/config/example_test.go
new file mode 100644
index 00000000000..3d80d68effb
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/config/example_test.go
@@ -0,0 +1,50 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config_test
+
+import (
+ "fmt"
+ "os"
+
+ "k8s.io/apimachinery/pkg/runtime"
+ "sigs.k8s.io/controller-runtime/pkg/config"
+
+ "sigs.k8s.io/controller-runtime/examples/configfile/custom/v1alpha1"
+)
+
+var scheme = runtime.NewScheme()
+
+func init() {
+ _ = v1alpha1.AddToScheme(scheme)
+}
+
+// This example will load a file using Complete with only
+// defaults set.
+func ExampleFile() {
+ // This will load a config file from ./config.yaml
+ loader := config.File()
+ if _, err := loader.Complete(); err != nil {
+ fmt.Println("failed to load config")
+ os.Exit(1)
+ }
+}
+
+// This example will load the file from a custom path.
+func ExampleFile_atPath() {
+ loader := config.File().AtPath("/var/run/controller-runtime/config.yaml")
+ if _, err := loader.Complete(); err != nil {
+ fmt.Println("failed to load config")
+ os.Exit(1)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/config/testdata/config.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/config/testdata/config.yaml
new file mode 100644
index 00000000000..d88da3a65b4
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/config/testdata/config.yaml
@@ -0,0 +1,7 @@
+apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
+kind: ControllerManagerConfiguration
+cacheNamespace: default
+metrics:
+ bindAddress: :8081
+leaderElection:
+ leaderElect: true
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go
new file mode 100644
index 00000000000..8fdf14d39ad
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go
@@ -0,0 +1,22 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package v1alpha1 provides the ControllerManagerConfiguration used for
+// configuring ctrl.Manager
+// +kubebuilder:object:generate=true
+//
+// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+package v1alpha1
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go b/third_party/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go
new file mode 100644
index 00000000000..ca854bcf300
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go
@@ -0,0 +1,43 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+ // GroupVersion is group version used to register these objects.
+ //
+ // Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+ GroupVersion = schema.GroupVersion{Group: "controller-runtime.sigs.k8s.io", Version: "v1alpha1"}
+
+ // SchemeBuilder is used to add go types to the GroupVersionKind scheme.
+ //
+ // Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+ SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+ // AddToScheme adds the types in this group-version to the given scheme.
+ //
+ // Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+ AddToScheme = SchemeBuilder.AddToScheme
+)
+
+func init() {
+ SchemeBuilder.Register(&ControllerManagerConfiguration{})
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go b/third_party/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go
new file mode 100644
index 00000000000..52c8ab300f2
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go
@@ -0,0 +1,179 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+ "time"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ configv1alpha1 "k8s.io/component-base/config/v1alpha1"
+)
+
+// ControllerManagerConfigurationSpec defines the desired state of GenericControllerManagerConfiguration.
+//
+// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+type ControllerManagerConfigurationSpec struct {
+ // SyncPeriod determines the minimum frequency at which watched resources are
+ // reconciled. A lower period will correct entropy more quickly, but reduce
+ // responsiveness to change if there are many watched resources. Change this
+ // value only if you know what you are doing. Defaults to 10 hours if unset.
+ // there will a 10 percent jitter between the SyncPeriod of all controllers
+ // so that all controllers will not send list requests simultaneously.
+ // +optional
+ SyncPeriod *metav1.Duration `json:"syncPeriod,omitempty"`
+
+ // LeaderElection is the LeaderElection config to be used when configuring
+ // the manager.Manager leader election
+ // +optional
+ LeaderElection *configv1alpha1.LeaderElectionConfiguration `json:"leaderElection,omitempty"`
+
+ // CacheNamespace if specified restricts the manager's cache to watch objects in
+ // the desired namespace Defaults to all namespaces
+ //
+ // Note: If a namespace is specified, controllers can still Watch for a
+ // cluster-scoped resource (e.g Node). For namespaced resources the cache
+ // will only hold objects from the desired namespace.
+ // +optional
+ CacheNamespace string `json:"cacheNamespace,omitempty"`
+
+ // GracefulShutdownTimeout is the duration given to runnable to stop before the manager actually returns on stop.
+ // To disable graceful shutdown, set to time.Duration(0)
+ // To use graceful shutdown without timeout, set to a negative duration, e.G. time.Duration(-1)
+ // The graceful shutdown is skipped for safety reasons in case the leader election lease is lost.
+ GracefulShutdownTimeout *metav1.Duration `json:"gracefulShutDown,omitempty"`
+
+ // Controller contains global configuration options for controllers
+ // registered within this manager.
+ // +optional
+ Controller *ControllerConfigurationSpec `json:"controller,omitempty"`
+
+ // Metrics contains the controller metrics configuration
+ // +optional
+ Metrics ControllerMetrics `json:"metrics,omitempty"`
+
+ // Health contains the controller health configuration
+ // +optional
+ Health ControllerHealth `json:"health,omitempty"`
+
+ // Webhook contains the controllers webhook configuration
+ // +optional
+ Webhook ControllerWebhook `json:"webhook,omitempty"`
+}
+
+// ControllerConfigurationSpec defines the global configuration for
+// controllers registered with the manager.
+//
+// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+//
+// Deprecated: Controller global configuration can now be set at the manager level,
+// using the manager.Options.Controller field.
+type ControllerConfigurationSpec struct {
+ // GroupKindConcurrency is a map from a Kind to the number of concurrent reconciliation
+ // allowed for that controller.
+ //
+ // When a controller is registered within this manager using the builder utilities,
+ // users have to specify the type the controller reconciles in the For(...) call.
+ // If the object's kind passed matches one of the keys in this map, the concurrency
+ // for that controller is set to the number specified.
+ //
+ // The key is expected to be consistent in form with GroupKind.String(),
+ // e.g. ReplicaSet in apps group (regardless of version) would be `ReplicaSet.apps`.
+ //
+ // +optional
+ GroupKindConcurrency map[string]int `json:"groupKindConcurrency,omitempty"`
+
+ // CacheSyncTimeout refers to the time limit set to wait for syncing caches.
+ // Defaults to 2 minutes if not set.
+ // +optional
+ CacheSyncTimeout *time.Duration `json:"cacheSyncTimeout,omitempty"`
+
+ // RecoverPanic indicates if panics should be recovered.
+ // +optional
+ RecoverPanic *bool `json:"recoverPanic,omitempty"`
+}
+
+// ControllerMetrics defines the metrics configs.
+//
+// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+type ControllerMetrics 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"`
+}
+
+// ControllerHealth defines the health configs.
+//
+// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+type ControllerHealth struct {
+ // HealthProbeBindAddress 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
+ HealthProbeBindAddress string `json:"healthProbeBindAddress,omitempty"`
+
+ // ReadinessEndpointName, defaults to "readyz"
+ // +optional
+ ReadinessEndpointName string `json:"readinessEndpointName,omitempty"`
+
+ // LivenessEndpointName, defaults to "healthz"
+ // +optional
+ LivenessEndpointName string `json:"livenessEndpointName,omitempty"`
+}
+
+// ControllerWebhook defines the webhook server for the controller.
+//
+// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+type ControllerWebhook struct {
+ // Port is the port that the webhook server serves at.
+ // It is used to set webhook.Server.Port.
+ // +optional
+ Port *int `json:"port,omitempty"`
+
+ // Host is the hostname that the webhook server binds to.
+ // It is used to set webhook.Server.Host.
+ // +optional
+ Host string `json:"host,omitempty"`
+
+ // CertDir is the directory that contains the server key and certificate.
+ // if not set, webhook server would look up the server key and certificate in
+ // {TempDir}/k8s-webhook-server/serving-certs. The server key and certificate
+ // must be named tls.key and tls.crt, respectively.
+ // +optional
+ CertDir string `json:"certDir,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ControllerManagerConfiguration is the Schema for the GenericControllerManagerConfigurations API.
+//
+// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+type ControllerManagerConfiguration struct {
+ metav1.TypeMeta `json:",inline"`
+
+ // ControllerManagerConfiguration returns the contfigurations for controllers
+ ControllerManagerConfigurationSpec `json:",inline"`
+}
+
+// Complete returns the configuration for controller-runtime.
+//
+// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
+func (c *ControllerManagerConfigurationSpec) Complete() (ControllerManagerConfigurationSpec, error) {
+ return *c, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go b/third_party/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go
new file mode 100644
index 00000000000..cdc7c334bef
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go
@@ -0,0 +1,158 @@
+//go:build !ignore_autogenerated
+// +build !ignore_autogenerated
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ "k8s.io/apimachinery/pkg/apis/meta/v1"
+ runtime "k8s.io/apimachinery/pkg/runtime"
+ configv1alpha1 "k8s.io/component-base/config/v1alpha1"
+ timex "time"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ControllerConfigurationSpec) DeepCopyInto(out *ControllerConfigurationSpec) {
+ *out = *in
+ if in.GroupKindConcurrency != nil {
+ in, out := &in.GroupKindConcurrency, &out.GroupKindConcurrency
+ *out = make(map[string]int, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val
+ }
+ }
+ if in.CacheSyncTimeout != nil {
+ in, out := &in.CacheSyncTimeout, &out.CacheSyncTimeout
+ *out = new(timex.Duration)
+ **out = **in
+ }
+ if in.RecoverPanic != nil {
+ in, out := &in.RecoverPanic, &out.RecoverPanic
+ *out = new(bool)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerConfigurationSpec.
+func (in *ControllerConfigurationSpec) DeepCopy() *ControllerConfigurationSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ControllerConfigurationSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ControllerHealth) DeepCopyInto(out *ControllerHealth) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerHealth.
+func (in *ControllerHealth) DeepCopy() *ControllerHealth {
+ if in == nil {
+ return nil
+ }
+ out := new(ControllerHealth)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ControllerManagerConfiguration) DeepCopyInto(out *ControllerManagerConfiguration) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ControllerManagerConfigurationSpec.DeepCopyInto(&out.ControllerManagerConfigurationSpec)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerManagerConfiguration.
+func (in *ControllerManagerConfiguration) DeepCopy() *ControllerManagerConfiguration {
+ if in == nil {
+ return nil
+ }
+ out := new(ControllerManagerConfiguration)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ControllerManagerConfiguration) 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 *ControllerManagerConfigurationSpec) DeepCopyInto(out *ControllerManagerConfigurationSpec) {
+ *out = *in
+ if in.SyncPeriod != nil {
+ in, out := &in.SyncPeriod, &out.SyncPeriod
+ *out = new(v1.Duration)
+ **out = **in
+ }
+ if in.LeaderElection != nil {
+ in, out := &in.LeaderElection, &out.LeaderElection
+ *out = new(configv1alpha1.LeaderElectionConfiguration)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.GracefulShutdownTimeout != nil {
+ in, out := &in.GracefulShutdownTimeout, &out.GracefulShutdownTimeout
+ *out = new(v1.Duration)
+ **out = **in
+ }
+ if in.Controller != nil {
+ in, out := &in.Controller, &out.Controller
+ *out = new(ControllerConfigurationSpec)
+ (*in).DeepCopyInto(*out)
+ }
+ out.Metrics = in.Metrics
+ out.Health = in.Health
+ in.Webhook.DeepCopyInto(&out.Webhook)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerManagerConfigurationSpec.
+func (in *ControllerManagerConfigurationSpec) DeepCopy() *ControllerManagerConfigurationSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ControllerManagerConfigurationSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ControllerMetrics) DeepCopyInto(out *ControllerMetrics) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerMetrics.
+func (in *ControllerMetrics) DeepCopy() *ControllerMetrics {
+ if in == nil {
+ return nil
+ }
+ out := new(ControllerMetrics)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ControllerWebhook) DeepCopyInto(out *ControllerWebhook) {
+ *out = *in
+ if in.Port != nil {
+ in, out := &in.Port, &out.Port
+ *out = new(int)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerWebhook.
+func (in *ControllerWebhook) DeepCopy() *ControllerWebhook {
+ if in == nil {
+ return nil
+ }
+ out := new(ControllerWebhook)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controller.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controller.go
new file mode 100644
index 00000000000..6732b6f709d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controller.go
@@ -0,0 +1,174 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controller
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/go-logr/logr"
+ "k8s.io/client-go/util/workqueue"
+ "k8s.io/klog/v2"
+
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/internal/controller"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+ "sigs.k8s.io/controller-runtime/pkg/ratelimiter"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+// Options are the arguments for creating a new Controller.
+type Options struct {
+ // MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
+ MaxConcurrentReconciles int
+
+ // CacheSyncTimeout refers to the time limit set to wait for syncing caches.
+ // Defaults to 2 minutes if not set.
+ CacheSyncTimeout time.Duration
+
+ // RecoverPanic indicates whether the panic caused by reconcile should be recovered.
+ // Defaults to the Controller.RecoverPanic setting from the Manager if unset.
+ RecoverPanic *bool
+
+ // NeedLeaderElection indicates whether the controller needs to use leader election.
+ // Defaults to true, which means the controller will use leader election.
+ NeedLeaderElection *bool
+
+ // Reconciler reconciles an object
+ Reconciler reconcile.Reconciler
+
+ // RateLimiter is used to limit how frequently requests may be queued.
+ // Defaults to MaxOfRateLimiter which has both overall and per-item rate limiting.
+ // The overall is a token bucket and the per-item is exponential.
+ RateLimiter ratelimiter.RateLimiter
+
+ // LogConstructor is used to construct a logger used for this controller and passed
+ // to each reconciliation via the context field.
+ LogConstructor func(request *reconcile.Request) logr.Logger
+}
+
+// Controller implements a Kubernetes API. A Controller manages a work queue fed reconcile.Requests
+// from source.Sources. Work is performed through the reconcile.Reconciler for each enqueued item.
+// Work typically is reads and writes Kubernetes objects to make the system state match the state specified
+// in the object Spec.
+type Controller interface {
+ // Reconciler is called to reconcile an object by Namespace/Name
+ reconcile.Reconciler
+
+ // Watch takes events provided by a Source and uses the EventHandler to
+ // enqueue reconcile.Requests in response to the events.
+ //
+ // Watch may be provided one or more Predicates to filter events before
+ // they are given to the EventHandler. Events will be passed to the
+ // EventHandler if all provided Predicates evaluate to true.
+ Watch(src source.Source, eventhandler handler.EventHandler, predicates ...predicate.Predicate) error
+
+ // Start starts the controller. Start blocks until the context is closed or a
+ // controller has an error starting.
+ Start(ctx context.Context) error
+
+ // GetLogger returns this controller logger prefilled with basic information.
+ GetLogger() logr.Logger
+}
+
+// New returns a new Controller registered with the Manager. The Manager will ensure that shared Caches have
+// been synced before the Controller is Started.
+func New(name string, mgr manager.Manager, options Options) (Controller, error) {
+ c, err := NewUnmanaged(name, mgr, options)
+ if err != nil {
+ return nil, err
+ }
+
+ // Add the controller as a Manager components
+ return c, mgr.Add(c)
+}
+
+// NewUnmanaged returns a new controller without adding it to the manager. The
+// caller is responsible for starting the returned controller.
+func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller, error) {
+ if options.Reconciler == nil {
+ return nil, fmt.Errorf("must specify Reconciler")
+ }
+
+ if len(name) == 0 {
+ return nil, fmt.Errorf("must specify Name for Controller")
+ }
+
+ if options.LogConstructor == nil {
+ log := mgr.GetLogger().WithValues(
+ "controller", name,
+ )
+ options.LogConstructor = func(req *reconcile.Request) logr.Logger {
+ log := log
+ if req != nil {
+ log = log.WithValues(
+ "object", klog.KRef(req.Namespace, req.Name),
+ "namespace", req.Namespace, "name", req.Name,
+ )
+ }
+ return log
+ }
+ }
+
+ if options.MaxConcurrentReconciles <= 0 {
+ if mgr.GetControllerOptions().MaxConcurrentReconciles > 0 {
+ options.MaxConcurrentReconciles = mgr.GetControllerOptions().MaxConcurrentReconciles
+ } else {
+ options.MaxConcurrentReconciles = 1
+ }
+ }
+
+ if options.CacheSyncTimeout == 0 {
+ if mgr.GetControllerOptions().CacheSyncTimeout != 0 {
+ options.CacheSyncTimeout = mgr.GetControllerOptions().CacheSyncTimeout
+ } else {
+ options.CacheSyncTimeout = 2 * time.Minute
+ }
+ }
+
+ if options.RateLimiter == nil {
+ options.RateLimiter = workqueue.DefaultControllerRateLimiter()
+ }
+
+ if options.RecoverPanic == nil {
+ options.RecoverPanic = mgr.GetControllerOptions().RecoverPanic
+ }
+
+ if options.NeedLeaderElection == nil {
+ options.NeedLeaderElection = mgr.GetControllerOptions().NeedLeaderElection
+ }
+
+ // Create controller with dependencies set
+ return &controller.Controller{
+ Do: options.Reconciler,
+ MakeQueue: func() workqueue.RateLimitingInterface {
+ return workqueue.NewNamedRateLimitingQueue(options.RateLimiter, name)
+ },
+ MaxConcurrentReconciles: options.MaxConcurrentReconciles,
+ CacheSyncTimeout: options.CacheSyncTimeout,
+ Name: name,
+ LogConstructor: options.LogConstructor,
+ RecoverPanic: options.RecoverPanic,
+ LeaderElected: options.NeedLeaderElection,
+ }, nil
+}
+
+// ReconcileIDFromContext gets the reconcileID from the current context.
+var ReconcileIDFromContext = controller.ReconcileIDFromContext
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controller_integration_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controller_integration_test.go
new file mode 100644
index 00000000000..48facf1e947
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controller_integration_test.go
@@ -0,0 +1,180 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controller_test
+
+import (
+ "context"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/types"
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllertest"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+)
+
+var _ = Describe("controller", func() {
+ var reconciled chan reconcile.Request
+ ctx := context.Background()
+
+ BeforeEach(func() {
+ reconciled = make(chan reconcile.Request)
+ Expect(cfg).NotTo(BeNil())
+ })
+
+ Describe("controller", func() {
+ // TODO(directxman12): write a whole suite of controller-client interaction tests
+
+ It("should reconcile", func() {
+ By("Creating the Manager")
+ cm, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Creating the Controller")
+ instance, err := controller.New("foo-controller", cm, controller.Options{
+ Reconciler: reconcile.Func(
+ func(_ context.Context, request reconcile.Request) (reconcile.Result, error) {
+ reconciled <- request
+ return reconcile.Result{}, nil
+ }),
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Watching Resources")
+ err = instance.Watch(
+ source.Kind(cm.GetCache(), &appsv1.ReplicaSet{}),
+ handler.EnqueueRequestForOwner(cm.GetScheme(), cm.GetRESTMapper(), &appsv1.Deployment{}),
+ )
+ Expect(err).NotTo(HaveOccurred())
+
+ err = instance.Watch(source.Kind(cm.GetCache(), &appsv1.Deployment{}), &handler.EnqueueRequestForObject{})
+ Expect(err).NotTo(HaveOccurred())
+
+ err = cm.GetClient().Get(ctx, types.NamespacedName{Name: "foo"}, &corev1.Namespace{})
+ Expect(err).To(Equal(&cache.ErrCacheNotStarted{}))
+ err = cm.GetClient().List(ctx, &corev1.NamespaceList{})
+ Expect(err).To(Equal(&cache.ErrCacheNotStarted{}))
+
+ By("Starting the Manager")
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(cm.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ deployment := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-name"},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx",
+ SecurityContext: &corev1.SecurityContext{
+ Privileged: truePtr(),
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+ expectedReconcileRequest := reconcile.Request{NamespacedName: types.NamespacedName{
+ Namespace: "default",
+ Name: "deployment-name",
+ }}
+
+ By("Invoking Reconciling for Create")
+ deployment, err = clientset.AppsV1().Deployments("default").Create(ctx, deployment, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(<-reconciled).To(Equal(expectedReconcileRequest))
+
+ By("Invoking Reconciling for Update")
+ newDeployment := deployment.DeepCopy()
+ newDeployment.Labels = map[string]string{"foo": "bar"}
+ _, err = clientset.AppsV1().Deployments("default").Update(ctx, newDeployment, metav1.UpdateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(<-reconciled).To(Equal(expectedReconcileRequest))
+
+ By("Invoking Reconciling for an OwnedObject when it is created")
+ replicaset := &appsv1.ReplicaSet{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "rs-name",
+ OwnerReferences: []metav1.OwnerReference{
+ *metav1.NewControllerRef(deployment, schema.GroupVersionKind{
+ Group: "apps",
+ Version: "v1",
+ Kind: "Deployment",
+ }),
+ },
+ },
+ Spec: appsv1.ReplicaSetSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: deployment.Spec.Template,
+ },
+ }
+ replicaset, err = clientset.AppsV1().ReplicaSets("default").Create(ctx, replicaset, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(<-reconciled).To(Equal(expectedReconcileRequest))
+
+ By("Invoking Reconciling for an OwnedObject when it is updated")
+ newReplicaset := replicaset.DeepCopy()
+ newReplicaset.Labels = map[string]string{"foo": "bar"}
+ _, err = clientset.AppsV1().ReplicaSets("default").Update(ctx, newReplicaset, metav1.UpdateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(<-reconciled).To(Equal(expectedReconcileRequest))
+
+ By("Invoking Reconciling for an OwnedObject when it is deleted")
+ err = clientset.AppsV1().ReplicaSets("default").Delete(ctx, replicaset.Name, metav1.DeleteOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(<-reconciled).To(Equal(expectedReconcileRequest))
+
+ By("Invoking Reconciling for Delete")
+ err = clientset.AppsV1().Deployments("default").
+ Delete(ctx, "deployment-name", metav1.DeleteOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(<-reconciled).To(Equal(expectedReconcileRequest))
+
+ By("Listing a type with a slice of pointers as items field")
+ err = cm.GetClient().
+ List(context.Background(), &controllertest.UnconventionalListTypeList{})
+ Expect(err).NotTo(HaveOccurred())
+ })
+ })
+})
+
+func truePtr() *bool {
+ t := true
+ return &t
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controller_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controller_suite_test.go
new file mode 100644
index 00000000000..af818d12cdd
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controller_suite_test.go
@@ -0,0 +1,90 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controller_test
+
+import (
+ "net/http"
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllertest"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+ crscheme "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Controller Integration Suite")
+}
+
+var testenv *envtest.Environment
+var cfg *rest.Config
+var clientset *kubernetes.Clientset
+
+// clientTransport is used to force-close keep-alives in tests that check for leaks.
+var clientTransport *http.Transport
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+ err := (&crscheme.Builder{
+ GroupVersion: schema.GroupVersion{Group: "chaosapps.metamagical.io", Version: "v1"},
+ }).
+ Register(
+ &controllertest.UnconventionalListType{},
+ &controllertest.UnconventionalListTypeList{},
+ ).AddToScheme(scheme.Scheme)
+ Expect(err).To(BeNil())
+
+ testenv = &envtest.Environment{
+ CRDDirectoryPaths: []string{"testdata/crds"},
+ }
+
+ cfg, err = testenv.Start()
+ Expect(err).NotTo(HaveOccurred())
+
+ cfg.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
+ // NB(directxman12): we can't set Transport *and* use TLS options,
+ // so we grab the transport right after it gets created so that we can
+ // type-assert on it (hopefully)?
+ // hopefully this doesn't break 🤞
+ clientTransport = rt.(*http.Transport)
+ return rt
+ }
+
+ clientset, err = kubernetes.NewForConfig(cfg)
+ Expect(err).NotTo(HaveOccurred())
+
+ // Prevent the metrics listener being created
+ metrics.DefaultBindAddress = "0"
+})
+
+var _ = AfterSuite(func() {
+ Expect(testenv.Stop()).To(Succeed())
+
+ // Put the DefaultBindAddress back
+ metrics.DefaultBindAddress = ":8080"
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controller_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controller_test.go
new file mode 100644
index 00000000000..b75ed1a4e4f
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controller_test.go
@@ -0,0 +1,336 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controller_test
+
+import (
+ "context"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "go.uber.org/goleak"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/utils/pointer"
+
+ "sigs.k8s.io/controller-runtime/pkg/config"
+ "sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ internalcontroller "sigs.k8s.io/controller-runtime/pkg/internal/controller"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+var _ = Describe("controller.Controller", func() {
+ rec := reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
+ return reconcile.Result{}, nil
+ })
+
+ Describe("New", func() {
+ It("should return an error if Name is not Specified", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ c, err := controller.New("", m, controller.Options{Reconciler: rec})
+ Expect(c).To(BeNil())
+ Expect(err.Error()).To(ContainSubstring("must specify Name for Controller"))
+ })
+
+ It("should return an error if Reconciler is not Specified", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("foo", m, controller.Options{})
+ Expect(c).To(BeNil())
+ Expect(err.Error()).To(ContainSubstring("must specify Reconciler"))
+ })
+
+ It("should not return an error if two controllers are registered with different names", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ c1, err := controller.New("c1", m, controller.Options{Reconciler: rec})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(c1).ToNot(BeNil())
+
+ c2, err := controller.New("c2", m, controller.Options{Reconciler: rec})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(c2).ToNot(BeNil())
+ })
+
+ It("should not leak goroutines when stopped", func() {
+ currentGRs := goleak.IgnoreCurrent()
+
+ ctx, cancel := context.WithCancel(context.Background())
+ watchChan := make(chan event.GenericEvent, 1)
+ watch := &source.Channel{Source: watchChan}
+ watchChan <- event.GenericEvent{Object: &corev1.Pod{}}
+
+ reconcileStarted := make(chan struct{})
+ controllerFinished := make(chan struct{})
+ rec := reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
+ defer GinkgoRecover()
+ close(reconcileStarted)
+ // Make sure reconciliation takes a moment and is not quicker than the controllers
+ // shutdown.
+ time.Sleep(50 * time.Millisecond)
+ // Explicitly test this on top of the leakdetection, as the latter uses Eventually
+ // so might succeed even when the controller does not wait for all reconciliations
+ // to finish.
+ Expect(controllerFinished).NotTo(BeClosed())
+ return reconcile.Result{}, nil
+ })
+
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{Reconciler: rec})
+ Expect(c.Watch(watch, &handler.EnqueueRequestForObject{})).To(Succeed())
+ Expect(err).NotTo(HaveOccurred())
+
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).To(Succeed())
+ close(controllerFinished)
+ }()
+
+ <-reconcileStarted
+ cancel()
+ <-controllerFinished
+
+ // force-close keep-alive connections. These'll time anyway (after
+ // like 30s or so) but force it to speed up the tests.
+ clientTransport.CloseIdleConnections()
+ Eventually(func() error { return goleak.Find(currentGRs) }).Should(Succeed())
+ })
+
+ It("should not create goroutines if never started", func() {
+ currentGRs := goleak.IgnoreCurrent()
+
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = controller.New("new-controller", m, controller.Options{Reconciler: rec})
+ Expect(err).NotTo(HaveOccurred())
+
+ // force-close keep-alive connections. These'll time anyway (after
+ // like 30s or so) but force it to speed up the tests.
+ clientTransport.CloseIdleConnections()
+ Eventually(func() error { return goleak.Find(currentGRs) }).Should(Succeed())
+ })
+
+ It("should default RecoverPanic from the manager", func() {
+ m, err := manager.New(cfg, manager.Options{Controller: config.Controller{RecoverPanic: pointer.Bool(true)}})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ Reconciler: reconcile.Func(nil),
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctrl, ok := c.(*internalcontroller.Controller)
+ Expect(ok).To(BeTrue())
+
+ Expect(ctrl.RecoverPanic).NotTo(BeNil())
+ Expect(*ctrl.RecoverPanic).To(BeTrue())
+ })
+
+ It("should not override RecoverPanic on the controller", func() {
+ m, err := manager.New(cfg, manager.Options{Controller: config.Controller{RecoverPanic: pointer.Bool(true)}})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ RecoverPanic: pointer.Bool(false),
+ Reconciler: reconcile.Func(nil),
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctrl, ok := c.(*internalcontroller.Controller)
+ Expect(ok).To(BeTrue())
+
+ Expect(ctrl.RecoverPanic).NotTo(BeNil())
+ Expect(*ctrl.RecoverPanic).To(BeFalse())
+ })
+
+ It("should default NeedLeaderElection from the manager", func() {
+ m, err := manager.New(cfg, manager.Options{Controller: config.Controller{NeedLeaderElection: pointer.Bool(true)}})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ Reconciler: reconcile.Func(nil),
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctrl, ok := c.(*internalcontroller.Controller)
+ Expect(ok).To(BeTrue())
+
+ Expect(ctrl.NeedLeaderElection()).To(BeTrue())
+ })
+
+ It("should not override NeedLeaderElection on the controller", func() {
+ m, err := manager.New(cfg, manager.Options{Controller: config.Controller{NeedLeaderElection: pointer.Bool(true)}})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ NeedLeaderElection: pointer.Bool(false),
+ Reconciler: reconcile.Func(nil),
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctrl, ok := c.(*internalcontroller.Controller)
+ Expect(ok).To(BeTrue())
+
+ Expect(ctrl.NeedLeaderElection()).To(BeFalse())
+ })
+
+ It("Should default MaxConcurrentReconciles from the manager if set", func() {
+ m, err := manager.New(cfg, manager.Options{Controller: config.Controller{MaxConcurrentReconciles: 5}})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ Reconciler: reconcile.Func(nil),
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctrl, ok := c.(*internalcontroller.Controller)
+ Expect(ok).To(BeTrue())
+
+ Expect(ctrl.MaxConcurrentReconciles).To(BeEquivalentTo(5))
+ })
+
+ It("Should default MaxConcurrentReconciles to 1 if unset", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ Reconciler: reconcile.Func(nil),
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctrl, ok := c.(*internalcontroller.Controller)
+ Expect(ok).To(BeTrue())
+
+ Expect(ctrl.MaxConcurrentReconciles).To(BeEquivalentTo(1))
+ })
+
+ It("Should leave MaxConcurrentReconciles if set", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ Reconciler: reconcile.Func(nil),
+ MaxConcurrentReconciles: 5,
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctrl, ok := c.(*internalcontroller.Controller)
+ Expect(ok).To(BeTrue())
+
+ Expect(ctrl.MaxConcurrentReconciles).To(BeEquivalentTo(5))
+ })
+
+ It("Should default CacheSyncTimeout from the manager if set", func() {
+ m, err := manager.New(cfg, manager.Options{Controller: config.Controller{CacheSyncTimeout: 5}})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ Reconciler: reconcile.Func(nil),
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctrl, ok := c.(*internalcontroller.Controller)
+ Expect(ok).To(BeTrue())
+
+ Expect(ctrl.CacheSyncTimeout).To(BeEquivalentTo(5))
+ })
+
+ It("Should default CacheSyncTimeout to 2 minutes if unset", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ Reconciler: reconcile.Func(nil),
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctrl, ok := c.(*internalcontroller.Controller)
+ Expect(ok).To(BeTrue())
+
+ Expect(ctrl.CacheSyncTimeout).To(BeEquivalentTo(2 * time.Minute))
+ })
+
+ It("Should leave CacheSyncTimeout if set", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ Reconciler: reconcile.Func(nil),
+ CacheSyncTimeout: 5,
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctrl, ok := c.(*internalcontroller.Controller)
+ Expect(ok).To(BeTrue())
+
+ Expect(ctrl.CacheSyncTimeout).To(BeEquivalentTo(5))
+ })
+
+ It("should default NeedLeaderElection on the controller to true", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ Reconciler: rec,
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctrl, ok := c.(*internalcontroller.Controller)
+ Expect(ok).To(BeTrue())
+
+ Expect(ctrl.NeedLeaderElection()).To(BeTrue())
+ })
+
+ It("should allow for setting leaderElected to false", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ NeedLeaderElection: pointer.Bool(false),
+ Reconciler: rec,
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctrl, ok := c.(*internalcontroller.Controller)
+ Expect(ok).To(BeTrue())
+
+ Expect(ctrl.NeedLeaderElection()).To(BeFalse())
+ })
+
+ It("should implement manager.LeaderElectionRunnable", func() {
+ m, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err := controller.New("new-controller", m, controller.Options{
+ Reconciler: rec,
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ _, ok := c.(manager.LeaderElectionRunnable)
+ Expect(ok).To(BeTrue())
+ })
+ })
+})
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/doc.go
similarity index 100%
rename from vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/doc.go
rename to third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/doc.go
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/testing.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/testing.go
similarity index 79%
rename from vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/testing.go
rename to third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/testing.go
index b9f97d52893..627915f94bf 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/testing.go
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/testing.go
@@ -17,6 +17,7 @@ limitations under the License.
package controllertest
import (
+ "sync"
"time"
"k8s.io/apimachinery/pkg/runtime"
@@ -35,28 +36,33 @@ func (ErrorType) GetObjectKind() schema.ObjectKind { return nil }
// DeepCopyObject implements runtime.Object.
func (ErrorType) DeepCopyObject() runtime.Object { return nil }
-var _ workqueue.RateLimitingInterface = Queue{}
+var _ workqueue.RateLimitingInterface = &Queue{}
// Queue implements a RateLimiting queue as a non-ratelimited queue for testing.
// This helps testing by having functions that use a RateLimiting queue synchronously add items to the queue.
type Queue struct {
workqueue.Interface
+ AddedRateLimitedLock sync.Mutex
+ AddedRatelimited []any
}
// AddAfter implements RateLimitingInterface.
-func (q Queue) AddAfter(item interface{}, duration time.Duration) {
+func (q *Queue) AddAfter(item interface{}, duration time.Duration) {
q.Add(item)
}
// AddRateLimited implements RateLimitingInterface. TODO(community): Implement this.
-func (q Queue) AddRateLimited(item interface{}) {
+func (q *Queue) AddRateLimited(item interface{}) {
+ q.AddedRateLimitedLock.Lock()
+ q.AddedRatelimited = append(q.AddedRatelimited, item)
+ q.AddedRateLimitedLock.Unlock()
q.Add(item)
}
// Forget implements RateLimitingInterface. TODO(community): Implement this.
-func (q Queue) Forget(item interface{}) {}
+func (q *Queue) Forget(item interface{}) {}
// NumRequeues implements RateLimitingInterface. TODO(community): Implement this.
-func (q Queue) NumRequeues(item interface{}) int {
+func (q *Queue) NumRequeues(item interface{}) int {
return 0
}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/unconventionallisttypecrd.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/unconventionallisttypecrd.go
similarity index 100%
rename from vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/unconventionallisttypecrd.go
rename to third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/unconventionallisttypecrd.go
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/util.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/util.go
new file mode 100644
index 00000000000..60ec61edec7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/util.go
@@ -0,0 +1,171 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controllertest
+
+import (
+ "time"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/client-go/tools/cache"
+)
+
+var _ cache.SharedIndexInformer = &FakeInformer{}
+
+// FakeInformer provides fake Informer functionality for testing.
+type FakeInformer struct {
+ // Synced is returned by the HasSynced functions to implement the Informer interface
+ Synced bool
+
+ // RunCount is incremented each time RunInformersAndControllers is called
+ RunCount int
+
+ handlers []eventHandlerWrapper
+}
+
+type modernResourceEventHandler interface {
+ OnAdd(obj interface{}, isInInitialList bool)
+ OnUpdate(oldObj, newObj interface{})
+ OnDelete(obj interface{})
+}
+
+type legacyResourceEventHandler interface {
+ OnAdd(obj interface{})
+ OnUpdate(oldObj, newObj interface{})
+ OnDelete(obj interface{})
+}
+
+// eventHandlerWrapper wraps a ResourceEventHandler in a manner that is compatible with client-go 1.27+ and older.
+// The interface was changed in these versions.
+type eventHandlerWrapper struct {
+ handler any
+}
+
+func (e eventHandlerWrapper) OnAdd(obj interface{}) {
+ if m, ok := e.handler.(modernResourceEventHandler); ok {
+ m.OnAdd(obj, false)
+ return
+ }
+ e.handler.(legacyResourceEventHandler).OnAdd(obj)
+}
+
+func (e eventHandlerWrapper) OnUpdate(oldObj, newObj interface{}) {
+ if m, ok := e.handler.(modernResourceEventHandler); ok {
+ m.OnUpdate(oldObj, newObj)
+ return
+ }
+ e.handler.(legacyResourceEventHandler).OnUpdate(oldObj, newObj)
+}
+
+func (e eventHandlerWrapper) OnDelete(obj interface{}) {
+ if m, ok := e.handler.(modernResourceEventHandler); ok {
+ m.OnDelete(obj)
+ return
+ }
+ e.handler.(legacyResourceEventHandler).OnDelete(obj)
+}
+
+// AddIndexers does nothing. TODO(community): Implement this.
+func (f *FakeInformer) AddIndexers(indexers cache.Indexers) error {
+ return nil
+}
+
+// GetIndexer does nothing. TODO(community): Implement this.
+func (f *FakeInformer) GetIndexer() cache.Indexer {
+ return nil
+}
+
+// Informer returns the fake Informer.
+func (f *FakeInformer) Informer() cache.SharedIndexInformer {
+ return f
+}
+
+// HasSynced implements the Informer interface. Returns f.Synced.
+func (f *FakeInformer) HasSynced() bool {
+ return f.Synced
+}
+
+// AddEventHandler implements the Informer interface. Adds an EventHandler to the fake Informers. TODO(community): Implement Registration.
+func (f *FakeInformer) AddEventHandler(handler cache.ResourceEventHandler) (cache.ResourceEventHandlerRegistration, error) {
+ f.handlers = append(f.handlers, eventHandlerWrapper{handler})
+ return nil, nil
+}
+
+// Run implements the Informer interface. Increments f.RunCount.
+func (f *FakeInformer) Run(<-chan struct{}) {
+ f.RunCount++
+}
+
+// Add fakes an Add event for obj.
+func (f *FakeInformer) Add(obj metav1.Object) {
+ for _, h := range f.handlers {
+ h.OnAdd(obj)
+ }
+}
+
+// Update fakes an Update event for obj.
+func (f *FakeInformer) Update(oldObj, newObj metav1.Object) {
+ for _, h := range f.handlers {
+ h.OnUpdate(oldObj, newObj)
+ }
+}
+
+// Delete fakes an Delete event for obj.
+func (f *FakeInformer) Delete(obj metav1.Object) {
+ for _, h := range f.handlers {
+ h.OnDelete(obj)
+ }
+}
+
+// AddEventHandlerWithResyncPeriod does nothing. TODO(community): Implement this.
+func (f *FakeInformer) AddEventHandlerWithResyncPeriod(handler cache.ResourceEventHandler, resyncPeriod time.Duration) (cache.ResourceEventHandlerRegistration, error) {
+ return nil, nil
+}
+
+// RemoveEventHandler does nothing. TODO(community): Implement this.
+func (f *FakeInformer) RemoveEventHandler(handle cache.ResourceEventHandlerRegistration) error {
+ return nil
+}
+
+// GetStore does nothing. TODO(community): Implement this.
+func (f *FakeInformer) GetStore() cache.Store {
+ return nil
+}
+
+// GetController does nothing. TODO(community): Implement this.
+func (f *FakeInformer) GetController() cache.Controller {
+ return nil
+}
+
+// LastSyncResourceVersion does nothing. TODO(community): Implement this.
+func (f *FakeInformer) LastSyncResourceVersion() string {
+ return ""
+}
+
+// SetWatchErrorHandler does nothing. TODO(community): Implement this.
+func (f *FakeInformer) SetWatchErrorHandler(cache.WatchErrorHandler) error {
+ return nil
+}
+
+// SetTransform does nothing. TODO(community): Implement this.
+func (f *FakeInformer) SetTransform(t cache.TransformFunc) error {
+ return nil
+}
+
+// IsStopped does nothing. TODO(community): Implement this.
+func (f *FakeInformer) IsStopped() bool {
+ return false
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go
new file mode 100644
index 00000000000..344abcd288c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go
@@ -0,0 +1,394 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controllerutil
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+
+ "k8s.io/apimachinery/pkg/api/equality"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/utils/pointer"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+)
+
+// AlreadyOwnedError is an error returned if the object you are trying to assign
+// a controller reference is already owned by another controller Object is the
+// subject and Owner is the reference for the current owner.
+type AlreadyOwnedError struct {
+ Object metav1.Object
+ Owner metav1.OwnerReference
+}
+
+func (e *AlreadyOwnedError) Error() string {
+ return fmt.Sprintf("Object %s/%s is already owned by another %s controller %s", e.Object.GetNamespace(), e.Object.GetName(), e.Owner.Kind, e.Owner.Name)
+}
+
+func newAlreadyOwnedError(obj metav1.Object, owner metav1.OwnerReference) *AlreadyOwnedError {
+ return &AlreadyOwnedError{
+ Object: obj,
+ Owner: owner,
+ }
+}
+
+// SetControllerReference sets owner as a Controller OwnerReference on controlled.
+// This is used for garbage collection of the controlled object and for
+// reconciling the owner object on changes to controlled (with a Watch + EnqueueRequestForOwner).
+// Since only one OwnerReference can be a controller, it returns an error if
+// there is another OwnerReference with Controller flag set.
+func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Scheme) error {
+ // Validate the owner.
+ ro, ok := owner.(runtime.Object)
+ if !ok {
+ return fmt.Errorf("%T is not a runtime.Object, cannot call SetControllerReference", owner)
+ }
+ if err := validateOwner(owner, controlled); err != nil {
+ return err
+ }
+
+ // Create a new controller ref.
+ gvk, err := apiutil.GVKForObject(ro, scheme)
+ if err != nil {
+ return err
+ }
+ ref := metav1.OwnerReference{
+ APIVersion: gvk.GroupVersion().String(),
+ Kind: gvk.Kind,
+ Name: owner.GetName(),
+ UID: owner.GetUID(),
+ BlockOwnerDeletion: pointer.Bool(true),
+ Controller: pointer.Bool(true),
+ }
+
+ // Return early with an error if the object is already controlled.
+ if existing := metav1.GetControllerOf(controlled); existing != nil && !referSameObject(*existing, ref) {
+ return newAlreadyOwnedError(controlled, *existing)
+ }
+
+ // Update owner references and return.
+ upsertOwnerRef(ref, controlled)
+ return nil
+}
+
+// SetOwnerReference is a helper method to make sure the given object contains an object reference to the object provided.
+// This allows you to declare that owner has a dependency on the object without specifying it as a controller.
+// If a reference to the same object already exists, it'll be overwritten with the newly provided version.
+func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) error {
+ // Validate the owner.
+ ro, ok := owner.(runtime.Object)
+ if !ok {
+ return fmt.Errorf("%T is not a runtime.Object, cannot call SetOwnerReference", owner)
+ }
+ if err := validateOwner(owner, object); err != nil {
+ return err
+ }
+
+ // Create a new owner ref.
+ gvk, err := apiutil.GVKForObject(ro, scheme)
+ if err != nil {
+ return err
+ }
+ ref := metav1.OwnerReference{
+ APIVersion: gvk.GroupVersion().String(),
+ Kind: gvk.Kind,
+ UID: owner.GetUID(),
+ Name: owner.GetName(),
+ }
+
+ // Update owner references and return.
+ upsertOwnerRef(ref, object)
+ return nil
+}
+
+func upsertOwnerRef(ref metav1.OwnerReference, object metav1.Object) {
+ owners := object.GetOwnerReferences()
+ if idx := indexOwnerRef(owners, ref); idx == -1 {
+ owners = append(owners, ref)
+ } else {
+ owners[idx] = ref
+ }
+ object.SetOwnerReferences(owners)
+}
+
+// indexOwnerRef returns the index of the owner reference in the slice if found, or -1.
+func indexOwnerRef(ownerReferences []metav1.OwnerReference, ref metav1.OwnerReference) int {
+ for index, r := range ownerReferences {
+ if referSameObject(r, ref) {
+ return index
+ }
+ }
+ return -1
+}
+
+func validateOwner(owner, object metav1.Object) error {
+ ownerNs := owner.GetNamespace()
+ if ownerNs != "" {
+ objNs := object.GetNamespace()
+ if objNs == "" {
+ return fmt.Errorf("cluster-scoped resource must not have a namespace-scoped owner, owner's namespace %s", ownerNs)
+ }
+ if ownerNs != objNs {
+ return fmt.Errorf("cross-namespace owner references are disallowed, owner's namespace %s, obj's namespace %s", owner.GetNamespace(), object.GetNamespace())
+ }
+ }
+ return nil
+}
+
+// Returns true if a and b point to the same object.
+func referSameObject(a, b metav1.OwnerReference) bool {
+ aGV, err := schema.ParseGroupVersion(a.APIVersion)
+ if err != nil {
+ return false
+ }
+
+ bGV, err := schema.ParseGroupVersion(b.APIVersion)
+ if err != nil {
+ return false
+ }
+
+ return aGV.Group == bGV.Group && a.Kind == b.Kind && a.Name == b.Name
+}
+
+// OperationResult is the action result of a CreateOrUpdate call.
+type OperationResult string
+
+const ( // They should complete the sentence "Deployment default/foo has been ..."
+ // OperationResultNone means that the resource has not been changed.
+ OperationResultNone OperationResult = "unchanged"
+ // OperationResultCreated means that a new resource is created.
+ OperationResultCreated OperationResult = "created"
+ // OperationResultUpdated means that an existing resource is updated.
+ OperationResultUpdated OperationResult = "updated"
+ // OperationResultUpdatedStatus means that an existing resource and its status is updated.
+ OperationResultUpdatedStatus OperationResult = "updatedStatus"
+ // OperationResultUpdatedStatusOnly means that only an existing status is updated.
+ OperationResultUpdatedStatusOnly OperationResult = "updatedStatusOnly"
+)
+
+// CreateOrUpdate creates or updates the given object in the Kubernetes
+// cluster. The object's desired state must be reconciled with the existing
+// state inside the passed in callback MutateFn.
+//
+// The MutateFn is called regardless of creating or updating an object.
+//
+// It returns the executed operation and an error.
+func CreateOrUpdate(ctx context.Context, c client.Client, obj client.Object, f MutateFn) (OperationResult, error) {
+ key := client.ObjectKeyFromObject(obj)
+ if err := c.Get(ctx, key, obj); err != nil {
+ if !apierrors.IsNotFound(err) {
+ return OperationResultNone, err
+ }
+ if err := mutate(f, key, obj); err != nil {
+ return OperationResultNone, err
+ }
+ if err := c.Create(ctx, obj); err != nil {
+ return OperationResultNone, err
+ }
+ return OperationResultCreated, nil
+ }
+
+ existing := obj.DeepCopyObject()
+ if err := mutate(f, key, obj); err != nil {
+ return OperationResultNone, err
+ }
+
+ if equality.Semantic.DeepEqual(existing, obj) {
+ return OperationResultNone, nil
+ }
+
+ if err := c.Update(ctx, obj); err != nil {
+ return OperationResultNone, err
+ }
+ return OperationResultUpdated, nil
+}
+
+// CreateOrPatch creates or patches the given object in the Kubernetes
+// cluster. The object's desired state must be reconciled with the before
+// state inside the passed in callback MutateFn.
+//
+// The MutateFn is called regardless of creating or updating an object.
+//
+// It returns the executed operation and an error.
+func CreateOrPatch(ctx context.Context, c client.Client, obj client.Object, f MutateFn) (OperationResult, error) {
+ key := client.ObjectKeyFromObject(obj)
+ if err := c.Get(ctx, key, obj); err != nil {
+ if !apierrors.IsNotFound(err) {
+ return OperationResultNone, err
+ }
+ if f != nil {
+ if err := mutate(f, key, obj); err != nil {
+ return OperationResultNone, err
+ }
+ }
+ if err := c.Create(ctx, obj); err != nil {
+ return OperationResultNone, err
+ }
+ return OperationResultCreated, nil
+ }
+
+ // Create patches for the object and its possible status.
+ objPatch := client.MergeFrom(obj.DeepCopyObject().(client.Object))
+ statusPatch := client.MergeFrom(obj.DeepCopyObject().(client.Object))
+
+ // Create a copy of the original object as well as converting that copy to
+ // unstructured data.
+ before, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj.DeepCopyObject())
+ if err != nil {
+ return OperationResultNone, err
+ }
+
+ // Attempt to extract the status from the resource for easier comparison later
+ beforeStatus, hasBeforeStatus, err := unstructured.NestedFieldCopy(before, "status")
+ if err != nil {
+ return OperationResultNone, err
+ }
+
+ // If the resource contains a status then remove it from the unstructured
+ // copy to avoid unnecessary patching later.
+ if hasBeforeStatus {
+ unstructured.RemoveNestedField(before, "status")
+ }
+
+ // Mutate the original object.
+ if f != nil {
+ if err := mutate(f, key, obj); err != nil {
+ return OperationResultNone, err
+ }
+ }
+
+ // Convert the resource to unstructured to compare against our before copy.
+ after, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
+ if err != nil {
+ return OperationResultNone, err
+ }
+
+ // Attempt to extract the status from the resource for easier comparison later
+ afterStatus, hasAfterStatus, err := unstructured.NestedFieldCopy(after, "status")
+ if err != nil {
+ return OperationResultNone, err
+ }
+
+ // If the resource contains a status then remove it from the unstructured
+ // copy to avoid unnecessary patching later.
+ if hasAfterStatus {
+ unstructured.RemoveNestedField(after, "status")
+ }
+
+ result := OperationResultNone
+
+ if !reflect.DeepEqual(before, after) {
+ // Only issue a Patch if the before and after resources (minus status) differ
+ if err := c.Patch(ctx, obj, objPatch); err != nil {
+ return result, err
+ }
+ result = OperationResultUpdated
+ }
+
+ if (hasBeforeStatus || hasAfterStatus) && !reflect.DeepEqual(beforeStatus, afterStatus) {
+ // Only issue a Status Patch if the resource has a status and the beforeStatus
+ // and afterStatus copies differ
+ if result == OperationResultUpdated {
+ // If Status was replaced by Patch before, set it to afterStatus
+ objectAfterPatch, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
+ if err != nil {
+ return result, err
+ }
+ if err = unstructured.SetNestedField(objectAfterPatch, afterStatus, "status"); err != nil {
+ return result, err
+ }
+ // If Status was replaced by Patch before, restore patched structure to the obj
+ if err = runtime.DefaultUnstructuredConverter.FromUnstructured(objectAfterPatch, obj); err != nil {
+ return result, err
+ }
+ }
+ if err := c.Status().Patch(ctx, obj, statusPatch); err != nil {
+ return result, err
+ }
+ if result == OperationResultUpdated {
+ result = OperationResultUpdatedStatus
+ } else {
+ result = OperationResultUpdatedStatusOnly
+ }
+ }
+
+ return result, nil
+}
+
+// mutate wraps a MutateFn and applies validation to its result.
+func mutate(f MutateFn, key client.ObjectKey, obj client.Object) error {
+ if err := f(); err != nil {
+ return err
+ }
+ if newKey := client.ObjectKeyFromObject(obj); key != newKey {
+ return fmt.Errorf("MutateFn cannot mutate object name and/or object namespace")
+ }
+ return nil
+}
+
+// MutateFn is a function which mutates the existing object into its desired state.
+type MutateFn func() error
+
+// AddFinalizer accepts an Object and adds the provided finalizer if not present.
+// It returns an indication of whether it updated the object's list of finalizers.
+func AddFinalizer(o client.Object, finalizer string) (finalizersUpdated bool) {
+ f := o.GetFinalizers()
+ for _, e := range f {
+ if e == finalizer {
+ return false
+ }
+ }
+ o.SetFinalizers(append(f, finalizer))
+ return true
+}
+
+// RemoveFinalizer accepts an Object and removes the provided finalizer if present.
+// It returns an indication of whether it updated the object's list of finalizers.
+func RemoveFinalizer(o client.Object, finalizer string) (finalizersUpdated bool) {
+ f := o.GetFinalizers()
+ for i := 0; i < len(f); i++ {
+ if f[i] == finalizer {
+ f = append(f[:i], f[i+1:]...)
+ i--
+ finalizersUpdated = true
+ }
+ }
+ o.SetFinalizers(f)
+ return
+}
+
+// ContainsFinalizer checks an Object that the provided finalizer is present.
+func ContainsFinalizer(o client.Object, finalizer string) bool {
+ f := o.GetFinalizers()
+ for _, e := range f {
+ if e == finalizer {
+ return true
+ }
+ }
+ return false
+}
+
+// Object allows functions to work indistinctly with any resource that
+// implements both Object interfaces.
+//
+// Deprecated: Use client.Object instead.
+type Object = client.Object
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil_suite_test.go
new file mode 100644
index 00000000000..a4ac5cc746a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil_suite_test.go
@@ -0,0 +1,53 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controllerutil_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+)
+
+func TestControllerutil(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Controllerutil Suite")
+}
+
+var testenv *envtest.Environment
+var cfg *rest.Config
+var c client.Client
+
+var _ = BeforeSuite(func() {
+ var err error
+
+ testenv = &envtest.Environment{}
+
+ cfg, err = testenv.Start()
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err = client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+})
+
+var _ = AfterSuite(func() {
+ Expect(testenv.Stop()).To(Succeed())
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil_test.go
new file mode 100644
index 00000000000..d176c4fb6a1
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil_test.go
@@ -0,0 +1,840 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controllerutil_test
+
+import (
+ "context"
+ "fmt"
+ "math/rand"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/utils/pointer"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+)
+
+var _ = Describe("Controllerutil", func() {
+ Describe("SetOwnerReference", func() {
+ It("should set ownerRef on an empty list", func() {
+ rs := &appsv1.ReplicaSet{}
+ dep := &extensionsv1beta1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "foo-uid"},
+ }
+ Expect(controllerutil.SetOwnerReference(dep, rs, scheme.Scheme)).ToNot(HaveOccurred())
+ Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
+ Name: "foo",
+ Kind: "Deployment",
+ APIVersion: "extensions/v1beta1",
+ UID: "foo-uid",
+ }))
+ })
+
+ It("should not duplicate owner references", func() {
+ rs := &appsv1.ReplicaSet{
+ ObjectMeta: metav1.ObjectMeta{
+ OwnerReferences: []metav1.OwnerReference{
+ {
+ Name: "foo",
+ Kind: "Deployment",
+ APIVersion: "extensions/v1beta1",
+ UID: "foo-uid",
+ },
+ },
+ },
+ }
+ dep := &extensionsv1beta1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "foo-uid"},
+ }
+
+ Expect(controllerutil.SetOwnerReference(dep, rs, scheme.Scheme)).ToNot(HaveOccurred())
+ Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
+ Name: "foo",
+ Kind: "Deployment",
+ APIVersion: "extensions/v1beta1",
+ UID: "foo-uid",
+ }))
+ })
+
+ It("should update the reference", func() {
+ rs := &appsv1.ReplicaSet{
+ ObjectMeta: metav1.ObjectMeta{
+ OwnerReferences: []metav1.OwnerReference{
+ {
+ Name: "foo",
+ Kind: "Deployment",
+ APIVersion: "extensions/v1alpha1",
+ UID: "foo-uid-1",
+ },
+ },
+ },
+ }
+ dep := &extensionsv1beta1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "foo-uid-2"},
+ }
+
+ Expect(controllerutil.SetOwnerReference(dep, rs, scheme.Scheme)).ToNot(HaveOccurred())
+ Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
+ Name: "foo",
+ Kind: "Deployment",
+ APIVersion: "extensions/v1beta1",
+ UID: "foo-uid-2",
+ }))
+ })
+ })
+
+ Describe("SetControllerReference", func() {
+ It("should set the OwnerReference if it can find the group version kind", func() {
+ rs := &appsv1.ReplicaSet{}
+ dep := &extensionsv1beta1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "foo-uid"},
+ }
+
+ Expect(controllerutil.SetControllerReference(dep, rs, scheme.Scheme)).NotTo(HaveOccurred())
+ t := true
+ Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
+ Name: "foo",
+ Kind: "Deployment",
+ APIVersion: "extensions/v1beta1",
+ UID: "foo-uid",
+ Controller: &t,
+ BlockOwnerDeletion: &t,
+ }))
+ })
+
+ It("should return an error if it can't find the group version kind of the owner", func() {
+ rs := &appsv1.ReplicaSet{}
+ dep := &extensionsv1beta1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "foo"},
+ }
+ Expect(controllerutil.SetControllerReference(dep, rs, runtime.NewScheme())).To(HaveOccurred())
+ })
+
+ It("should return an error if the owner isn't a runtime.Object", func() {
+ rs := &appsv1.ReplicaSet{}
+ Expect(controllerutil.SetControllerReference(&errMetaObj{}, rs, scheme.Scheme)).To(HaveOccurred())
+ })
+
+ It("should return an error if object is already owned by another controller", func() {
+ t := true
+ rsOwners := []metav1.OwnerReference{
+ {
+ Name: "bar",
+ Kind: "Deployment",
+ APIVersion: "extensions/v1beta1",
+ UID: "bar-uid",
+ Controller: &t,
+ BlockOwnerDeletion: &t,
+ },
+ }
+ rs := &appsv1.ReplicaSet{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default", OwnerReferences: rsOwners}}
+ dep := &extensionsv1beta1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default", UID: "foo-uid"}}
+
+ err := controllerutil.SetControllerReference(dep, rs, scheme.Scheme)
+
+ Expect(err).To(HaveOccurred())
+ Expect(err).To(BeAssignableToTypeOf(&controllerutil.AlreadyOwnedError{}))
+ })
+
+ It("should not duplicate existing owner reference", func() {
+ f := false
+ t := true
+ rsOwners := []metav1.OwnerReference{
+ {
+ Name: "foo",
+ Kind: "Deployment",
+ APIVersion: "extensions/v1beta1",
+ UID: "foo-uid",
+ Controller: &f,
+ BlockOwnerDeletion: &t,
+ },
+ }
+ rs := &appsv1.ReplicaSet{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default", OwnerReferences: rsOwners}}
+ dep := &extensionsv1beta1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default", UID: "foo-uid"}}
+
+ Expect(controllerutil.SetControllerReference(dep, rs, scheme.Scheme)).NotTo(HaveOccurred())
+ Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
+ Name: "foo",
+ Kind: "Deployment",
+ APIVersion: "extensions/v1beta1",
+ UID: "foo-uid",
+ Controller: &t,
+ BlockOwnerDeletion: &t,
+ }))
+ })
+
+ It("should replace the owner reference if it's already present", func() {
+ t := true
+ rsOwners := []metav1.OwnerReference{
+ {
+ Name: "foo",
+ Kind: "Deployment",
+ APIVersion: "extensions/v1alpha1",
+ UID: "foo-uid",
+ Controller: &t,
+ BlockOwnerDeletion: &t,
+ },
+ }
+ rs := &appsv1.ReplicaSet{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default", OwnerReferences: rsOwners}}
+ dep := &extensionsv1beta1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default", UID: "foo-uid"}}
+
+ Expect(controllerutil.SetControllerReference(dep, rs, scheme.Scheme)).NotTo(HaveOccurred())
+ Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
+ Name: "foo",
+ Kind: "Deployment",
+ APIVersion: "extensions/v1beta1",
+ UID: "foo-uid",
+ Controller: &t,
+ BlockOwnerDeletion: &t,
+ }))
+ })
+
+ It("should return an error if it's setting a cross-namespace owner reference", func() {
+ rs := &appsv1.ReplicaSet{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "namespace1"}}
+ dep := &extensionsv1beta1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "namespace2", UID: "foo-uid"}}
+
+ err := controllerutil.SetControllerReference(dep, rs, scheme.Scheme)
+
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should return an error if it's owner is namespaced resource but dependant is cluster-scoped resource", func() {
+ pv := &corev1.PersistentVolume{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}
+ pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default", UID: "foo-uid"}}
+
+ err := controllerutil.SetControllerReference(pod, pv, scheme.Scheme)
+
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should not return any error if the existing owner has a different version", func() {
+ f := false
+ t := true
+ rsOwners := []metav1.OwnerReference{
+ {
+ Name: "foo",
+ Kind: "Deployment",
+ APIVersion: "extensions/v1alpha1",
+ UID: "foo-uid",
+ Controller: &f,
+ BlockOwnerDeletion: &t,
+ },
+ }
+ rs := &appsv1.ReplicaSet{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default", OwnerReferences: rsOwners}}
+ dep := &extensionsv1beta1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default", UID: "foo-uid"}}
+
+ Expect(controllerutil.SetControllerReference(dep, rs, scheme.Scheme)).NotTo(HaveOccurred())
+ Expect(rs.OwnerReferences).To(ConsistOf(metav1.OwnerReference{
+ Name: "foo",
+ Kind: "Deployment",
+ // APIVersion is the new owner's one
+ APIVersion: "extensions/v1beta1",
+ UID: "foo-uid",
+ Controller: &t,
+ BlockOwnerDeletion: &t,
+ }))
+ })
+ })
+
+ Describe("CreateOrUpdate", func() {
+ var deploy *appsv1.Deployment
+ var deplSpec appsv1.DeploymentSpec
+ var deplKey types.NamespacedName
+ var specr controllerutil.MutateFn
+
+ BeforeEach(func() {
+ deploy = &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: fmt.Sprintf("deploy-%d", rand.Int31()), //nolint:gosec
+ Namespace: "default",
+ },
+ }
+
+ deplSpec = appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{
+ Labels: map[string]string{
+ "foo": "bar",
+ },
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "busybox",
+ Image: "busybox",
+ },
+ },
+ },
+ },
+ }
+
+ deplKey = types.NamespacedName{
+ Name: deploy.Name,
+ Namespace: deploy.Namespace,
+ }
+
+ specr = deploymentSpecr(deploy, deplSpec)
+ })
+
+ It("creates a new object if one doesn't exists", func() {
+ op, err := controllerutil.CreateOrUpdate(context.TODO(), c, deploy, specr)
+
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning OperationResultCreated")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+
+ By("actually having the deployment created")
+ fetched := &appsv1.Deployment{}
+ Expect(c.Get(context.TODO(), deplKey, fetched)).To(Succeed())
+
+ By("being mutated by MutateFn")
+ Expect(fetched.Spec.Template.Spec.Containers).To(HaveLen(1))
+ Expect(fetched.Spec.Template.Spec.Containers[0].Name).To(Equal(deplSpec.Template.Spec.Containers[0].Name))
+ Expect(fetched.Spec.Template.Spec.Containers[0].Image).To(Equal(deplSpec.Template.Spec.Containers[0].Image))
+ })
+
+ It("updates existing object", func() {
+ var scale int32 = 2
+ op, err := controllerutil.CreateOrUpdate(context.TODO(), c, deploy, specr)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+
+ op, err = controllerutil.CreateOrUpdate(context.TODO(), c, deploy, deploymentScaler(deploy, scale))
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning OperationResultUpdated")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultUpdated))
+
+ By("actually having the deployment scaled")
+ fetched := &appsv1.Deployment{}
+ Expect(c.Get(context.TODO(), deplKey, fetched)).To(Succeed())
+ Expect(*fetched.Spec.Replicas).To(Equal(scale))
+ })
+
+ It("updates only changed objects", func() {
+ op, err := controllerutil.CreateOrUpdate(context.TODO(), c, deploy, specr)
+
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+ Expect(err).NotTo(HaveOccurred())
+
+ op, err = controllerutil.CreateOrUpdate(context.TODO(), c, deploy, deploymentIdentity)
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning OperationResultNone")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultNone))
+ })
+
+ It("errors when MutateFn changes object name on creation", func() {
+ op, err := controllerutil.CreateOrUpdate(context.TODO(), c, deploy, func() error {
+ Expect(specr()).To(Succeed())
+ return deploymentRenamer(deploy)()
+ })
+
+ By("returning error")
+ Expect(err).To(HaveOccurred())
+
+ By("returning OperationResultNone")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultNone))
+ })
+
+ It("errors when MutateFn renames an object", func() {
+ op, err := controllerutil.CreateOrUpdate(context.TODO(), c, deploy, specr)
+
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+ Expect(err).NotTo(HaveOccurred())
+
+ op, err = controllerutil.CreateOrUpdate(context.TODO(), c, deploy, deploymentRenamer(deploy))
+
+ By("returning error")
+ Expect(err).To(HaveOccurred())
+
+ By("returning OperationResultNone")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultNone))
+ })
+
+ It("errors when object namespace changes", func() {
+ op, err := controllerutil.CreateOrUpdate(context.TODO(), c, deploy, specr)
+
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+ Expect(err).NotTo(HaveOccurred())
+
+ op, err = controllerutil.CreateOrUpdate(context.TODO(), c, deploy, deploymentNamespaceChanger(deploy))
+
+ By("returning error")
+ Expect(err).To(HaveOccurred())
+
+ By("returning OperationResultNone")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultNone))
+ })
+
+ It("aborts immediately if there was an error initially retrieving the object", func() {
+ op, err := controllerutil.CreateOrUpdate(context.TODO(), errorReader{c}, deploy, func() error {
+ Fail("Mutation method should not run")
+ return nil
+ })
+
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultNone))
+ Expect(err).To(HaveOccurred())
+ })
+ })
+
+ Describe("CreateOrPatch", func() {
+ var deploy *appsv1.Deployment
+ var deplSpec appsv1.DeploymentSpec
+ var deplKey types.NamespacedName
+ var specr controllerutil.MutateFn
+
+ BeforeEach(func() {
+ deploy = &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: fmt.Sprintf("deploy-%d", rand.Int31()), //nolint:gosec
+ Namespace: "default",
+ },
+ }
+
+ deplSpec = appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{
+ Labels: map[string]string{
+ "foo": "bar",
+ },
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "busybox",
+ Image: "busybox",
+ },
+ },
+ },
+ },
+ }
+
+ deplKey = types.NamespacedName{
+ Name: deploy.Name,
+ Namespace: deploy.Namespace,
+ }
+
+ specr = deploymentSpecr(deploy, deplSpec)
+ })
+
+ assertLocalDeployWasUpdated := func(fetched *appsv1.Deployment) {
+ By("local deploy object was updated during patch & has same spec, status, resource version as fetched")
+ if fetched == nil {
+ fetched = &appsv1.Deployment{}
+ ExpectWithOffset(1, c.Get(context.TODO(), deplKey, fetched)).To(Succeed())
+ }
+ ExpectWithOffset(1, fetched.ResourceVersion).To(Equal(deploy.ResourceVersion))
+ ExpectWithOffset(1, fetched.Spec).To(BeEquivalentTo(deploy.Spec))
+ ExpectWithOffset(1, fetched.Status).To(BeEquivalentTo(deploy.Status))
+ }
+
+ assertLocalDeployStatusWasUpdated := func(fetched *appsv1.Deployment) {
+ By("local deploy object was updated during patch & has same spec, status, resource version as fetched")
+ if fetched == nil {
+ fetched = &appsv1.Deployment{}
+ ExpectWithOffset(1, c.Get(context.TODO(), deplKey, fetched)).To(Succeed())
+ }
+ ExpectWithOffset(1, fetched.ResourceVersion).To(Equal(deploy.ResourceVersion))
+ ExpectWithOffset(1, *fetched.Spec.Replicas).To(BeEquivalentTo(int32(5)))
+ ExpectWithOffset(1, fetched.Status).To(BeEquivalentTo(deploy.Status))
+ ExpectWithOffset(1, len(fetched.Status.Conditions)).To(BeEquivalentTo(1))
+ }
+
+ It("creates a new object if one doesn't exists", func() {
+ op, err := controllerutil.CreateOrPatch(context.TODO(), c, deploy, specr)
+
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning OperationResultCreated")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+
+ By("actually having the deployment created")
+ fetched := &appsv1.Deployment{}
+ Expect(c.Get(context.TODO(), deplKey, fetched)).To(Succeed())
+
+ By("being mutated by MutateFn")
+ Expect(fetched.Spec.Template.Spec.Containers).To(HaveLen(1))
+ Expect(fetched.Spec.Template.Spec.Containers[0].Name).To(Equal(deplSpec.Template.Spec.Containers[0].Name))
+ Expect(fetched.Spec.Template.Spec.Containers[0].Image).To(Equal(deplSpec.Template.Spec.Containers[0].Image))
+ })
+
+ It("patches existing object", func() {
+ var scale int32 = 2
+ op, err := controllerutil.CreateOrPatch(context.TODO(), c, deploy, specr)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+
+ op, err = controllerutil.CreateOrPatch(context.TODO(), c, deploy, deploymentScaler(deploy, scale))
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning OperationResultUpdated")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultUpdated))
+
+ By("actually having the deployment scaled")
+ fetched := &appsv1.Deployment{}
+ Expect(c.Get(context.TODO(), deplKey, fetched)).To(Succeed())
+ Expect(*fetched.Spec.Replicas).To(Equal(scale))
+ assertLocalDeployWasUpdated(fetched)
+ })
+
+ It("patches only changed objects", func() {
+ op, err := controllerutil.CreateOrPatch(context.TODO(), c, deploy, specr)
+
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+ Expect(err).NotTo(HaveOccurred())
+
+ op, err = controllerutil.CreateOrPatch(context.TODO(), c, deploy, deploymentIdentity)
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning OperationResultNone")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultNone))
+
+ assertLocalDeployWasUpdated(nil)
+ })
+
+ It("patches only changed status", func() {
+ op, err := controllerutil.CreateOrPatch(context.TODO(), c, deploy, specr)
+
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+ Expect(err).NotTo(HaveOccurred())
+
+ deployStatus := appsv1.DeploymentStatus{
+ ReadyReplicas: 1,
+ Replicas: 3,
+ }
+ op, err = controllerutil.CreateOrPatch(context.TODO(), c, deploy, deploymentStatusr(deploy, deployStatus))
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning OperationResultUpdatedStatusOnly")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultUpdatedStatusOnly))
+
+ assertLocalDeployWasUpdated(nil)
+ })
+
+ It("patches resource and status", func() {
+ op, err := controllerutil.CreateOrPatch(context.TODO(), c, deploy, specr)
+
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+ Expect(err).NotTo(HaveOccurred())
+
+ replicas := int32(3)
+ deployStatus := appsv1.DeploymentStatus{
+ ReadyReplicas: 1,
+ Replicas: replicas,
+ }
+ op, err = controllerutil.CreateOrPatch(context.TODO(), c, deploy, func() error {
+ Expect(deploymentScaler(deploy, replicas)()).To(Succeed())
+ return deploymentStatusr(deploy, deployStatus)()
+ })
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning OperationResultUpdatedStatus")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultUpdatedStatus))
+
+ assertLocalDeployWasUpdated(nil)
+ })
+
+ It("patches resource and not empty status", func() {
+ op, err := controllerutil.CreateOrPatch(context.TODO(), c, deploy, specr)
+
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+ Expect(err).NotTo(HaveOccurred())
+
+ replicas := int32(3)
+ deployStatus := appsv1.DeploymentStatus{
+ ReadyReplicas: 1,
+ Replicas: replicas,
+ }
+ op, err = controllerutil.CreateOrPatch(context.TODO(), c, deploy, func() error {
+ Expect(deploymentScaler(deploy, replicas)()).To(Succeed())
+ return deploymentStatusr(deploy, deployStatus)()
+ })
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning OperationResultUpdatedStatus")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultUpdatedStatus))
+
+ assertLocalDeployWasUpdated(nil)
+
+ op, err = controllerutil.CreateOrPatch(context.TODO(), c, deploy, func() error {
+ deploy.Spec.Replicas = pointer.Int32(5)
+ deploy.Status.Conditions = []appsv1.DeploymentCondition{{
+ Type: appsv1.DeploymentProgressing,
+ Status: corev1.ConditionTrue,
+ }}
+ return nil
+ })
+ By("returning no error")
+ Expect(err).NotTo(HaveOccurred())
+
+ By("returning OperationResultUpdatedStatus")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultUpdatedStatus))
+
+ assertLocalDeployStatusWasUpdated(nil)
+ })
+
+ It("errors when MutateFn changes object name on creation", func() {
+ op, err := controllerutil.CreateOrPatch(context.TODO(), c, deploy, func() error {
+ Expect(specr()).To(Succeed())
+ return deploymentRenamer(deploy)()
+ })
+
+ By("returning error")
+ Expect(err).To(HaveOccurred())
+
+ By("returning OperationResultNone")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultNone))
+ })
+
+ It("errors when MutateFn renames an object", func() {
+ op, err := controllerutil.CreateOrPatch(context.TODO(), c, deploy, specr)
+
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+ Expect(err).NotTo(HaveOccurred())
+
+ op, err = controllerutil.CreateOrPatch(context.TODO(), c, deploy, deploymentRenamer(deploy))
+
+ By("returning error")
+ Expect(err).To(HaveOccurred())
+
+ By("returning OperationResultNone")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultNone))
+ })
+
+ It("errors when object namespace changes", func() {
+ op, err := controllerutil.CreateOrPatch(context.TODO(), c, deploy, specr)
+
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultCreated))
+ Expect(err).NotTo(HaveOccurred())
+
+ op, err = controllerutil.CreateOrPatch(context.TODO(), c, deploy, deploymentNamespaceChanger(deploy))
+
+ By("returning error")
+ Expect(err).To(HaveOccurred())
+
+ By("returning OperationResultNone")
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultNone))
+ })
+
+ It("aborts immediately if there was an error initially retrieving the object", func() {
+ op, err := controllerutil.CreateOrPatch(context.TODO(), errorReader{c}, deploy, func() error {
+ Fail("Mutation method should not run")
+ return nil
+ })
+
+ Expect(op).To(BeEquivalentTo(controllerutil.OperationResultNone))
+ Expect(err).To(HaveOccurred())
+ })
+ })
+
+ Describe("Finalizers", func() {
+ var deploy *appsv1.Deployment
+
+ Describe("AddFinalizer", func() {
+ deploy = &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Finalizers: []string{},
+ },
+ }
+
+ It("should add the finalizer when not present", func() {
+ controllerutil.AddFinalizer(deploy, testFinalizer)
+ Expect(deploy.ObjectMeta.GetFinalizers()).To(Equal([]string{testFinalizer}))
+ })
+
+ It("should not add the finalizer when already present", func() {
+ controllerutil.AddFinalizer(deploy, testFinalizer)
+ Expect(deploy.ObjectMeta.GetFinalizers()).To(Equal([]string{testFinalizer}))
+ })
+ })
+
+ Describe("RemoveFinalizer", func() {
+ It("should remove finalizer if present", func() {
+ controllerutil.RemoveFinalizer(deploy, testFinalizer)
+ Expect(deploy.ObjectMeta.GetFinalizers()).To(Equal([]string{}))
+ })
+
+ It("should remove all equal finalizers if present", func() {
+ deploy.SetFinalizers(append(deploy.Finalizers, testFinalizer, testFinalizer))
+ controllerutil.RemoveFinalizer(deploy, testFinalizer)
+ Expect(deploy.ObjectMeta.GetFinalizers()).To(Equal([]string{}))
+ })
+ })
+
+ Describe("AddFinalizer, which returns an indication of whether it modified the object's list of finalizers,", func() {
+ deploy = &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Finalizers: []string{},
+ },
+ }
+
+ When("the object's list of finalizers has no instances of the input finalizer", func() {
+ It("should return true", func() {
+ Expect(controllerutil.AddFinalizer(deploy, testFinalizer)).To(BeTrue())
+ })
+ It("should add the input finalizer to the object's list of finalizers", func() {
+ Expect(deploy.ObjectMeta.GetFinalizers()).To(Equal([]string{testFinalizer}))
+ })
+ })
+
+ When("the object's list of finalizers has an instance of the input finalizer", func() {
+ It("should return false", func() {
+ Expect(controllerutil.AddFinalizer(deploy, testFinalizer)).To(BeFalse())
+ })
+ It("should not modify the object's list of finalizers", func() {
+ Expect(deploy.ObjectMeta.GetFinalizers()).To(Equal([]string{testFinalizer}))
+ })
+ })
+ })
+
+ Describe("RemoveFinalizer, which returns an indication of whether it modified the object's list of finalizers,", func() {
+ When("the object's list of finalizers has no instances of the input finalizer", func() {
+ It("should return false", func() {
+ Expect(controllerutil.RemoveFinalizer(deploy, testFinalizer1)).To(BeFalse())
+ })
+ It("should not modify the object's list of finalizers", func() {
+ Expect(deploy.ObjectMeta.GetFinalizers()).To(Equal([]string{testFinalizer}))
+ })
+ })
+
+ When("the object's list of finalizers has one instance of the input finalizer", func() {
+ It("should return true", func() {
+ Expect(controllerutil.RemoveFinalizer(deploy, testFinalizer)).To(BeTrue())
+ })
+ It("should remove the instance of the input finalizer from the object's list of finalizers", func() {
+ Expect(deploy.ObjectMeta.GetFinalizers()).To(Equal([]string{}))
+ })
+ })
+
+ When("the object's list of finalizers has multiple instances of the input finalizer", func() {
+ It("should return true", func() {
+ deploy.SetFinalizers(append(deploy.Finalizers, testFinalizer, testFinalizer))
+ Expect(controllerutil.RemoveFinalizer(deploy, testFinalizer)).To(BeTrue())
+ })
+ It("should remove each instance of the input finalizer from the object's list of finalizers", func() {
+ Expect(deploy.ObjectMeta.GetFinalizers()).To(Equal([]string{}))
+ })
+ })
+ })
+
+ Describe("ContainsFinalizer", func() {
+ It("should check that finalizer is present", func() {
+ controllerutil.AddFinalizer(deploy, testFinalizer)
+ Expect(controllerutil.ContainsFinalizer(deploy, testFinalizer)).To(Equal(true))
+ })
+
+ It("should check that finalizer is not present after RemoveFinalizer call", func() {
+ controllerutil.RemoveFinalizer(deploy, testFinalizer)
+ Expect(controllerutil.ContainsFinalizer(deploy, testFinalizer)).To(Equal(false))
+ })
+ })
+ })
+})
+
+const (
+ testFinalizer = "foo.bar.baz"
+ testFinalizer1 = testFinalizer + "1"
+)
+
+var (
+ _ runtime.Object = &errRuntimeObj{}
+ _ metav1.Object = &errMetaObj{}
+)
+
+type errRuntimeObj struct {
+ runtime.TypeMeta
+}
+
+func (o *errRuntimeObj) DeepCopyObject() runtime.Object {
+ return &errRuntimeObj{}
+}
+
+type errMetaObj struct {
+ metav1.ObjectMeta
+}
+
+func deploymentSpecr(deploy *appsv1.Deployment, spec appsv1.DeploymentSpec) controllerutil.MutateFn {
+ return func() error {
+ deploy.Spec = spec
+ return nil
+ }
+}
+
+func deploymentStatusr(deploy *appsv1.Deployment, status appsv1.DeploymentStatus) controllerutil.MutateFn {
+ return func() error {
+ deploy.Status = status
+ return nil
+ }
+}
+
+var deploymentIdentity controllerutil.MutateFn = func() error {
+ return nil
+}
+
+func deploymentRenamer(deploy *appsv1.Deployment) controllerutil.MutateFn {
+ return func() error {
+ deploy.Name = fmt.Sprintf("%s-1", deploy.Name)
+ return nil
+ }
+}
+
+func deploymentNamespaceChanger(deploy *appsv1.Deployment) controllerutil.MutateFn {
+ return func() error {
+ deploy.Namespace = fmt.Sprintf("%s-1", deploy.Namespace)
+ return nil
+ }
+}
+
+func deploymentScaler(deploy *appsv1.Deployment, replicas int32) controllerutil.MutateFn {
+ fn := func() error {
+ deploy.Spec.Replicas = &replicas
+ return nil
+ }
+ return fn
+}
+
+type errorReader struct {
+ client.Client
+}
+
+func (e errorReader) Get(ctx context.Context, key client.ObjectKey, into client.Object, opts ...client.GetOption) error {
+ return fmt.Errorf("unexpected error")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go
new file mode 100644
index 00000000000..ab386b29cdb
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package controllerutil contains utility functions for working with and implementing Controllers.
+*/
+package controllerutil
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/example_test.go
new file mode 100644
index 00000000000..b2d6f71a5c6
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/example_test.go
@@ -0,0 +1,75 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controllerutil_test
+
+import (
+ "context"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+var (
+ log = logf.Log.WithName("controllerutil-examples")
+)
+
+// This example creates or updates an existing deployment.
+func ExampleCreateOrUpdate() {
+ // c is client.Client
+
+ // Create or Update the deployment default/foo
+ deploy := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}}
+
+ op, err := controllerutil.CreateOrUpdate(context.TODO(), c, deploy, func() error {
+ // Deployment selector is immutable so we set this value only if
+ // a new object is going to be created
+ if deploy.ObjectMeta.CreationTimestamp.IsZero() {
+ deploy.Spec.Selector = &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ }
+ }
+
+ // update the Deployment pod template
+ deploy.Spec.Template = corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{
+ Labels: map[string]string{
+ "foo": "bar",
+ },
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "busybox",
+ Image: "busybox",
+ },
+ },
+ },
+ }
+
+ return nil
+ })
+
+ if err != nil {
+ log.Error(err, "Deployment reconcile failed")
+ } else {
+ log.Info("Deployment successfully reconciled", "operation", op)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/doc.go
new file mode 100644
index 00000000000..228335e9293
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/doc.go
@@ -0,0 +1,25 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package controller provides types and functions for building Controllers. Controllers implement Kubernetes APIs.
+
+# Creation
+
+To create a new Controller, first create a manager.Manager and pass it to the controller.New function.
+The Controller MUST be started by calling Manager.Start.
+*/
+package controller
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/example_test.go
new file mode 100644
index 00000000000..d4fa1aef0be
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/example_test.go
@@ -0,0 +1,165 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controller_test
+
+import (
+ "context"
+ "os"
+
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/manager/signals"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+var (
+ mgr manager.Manager
+ // NB: don't call SetLogger in init(), or else you'll mess up logging in the main suite.
+ log = logf.Log.WithName("controller-examples")
+)
+
+// This example creates a new Controller named "pod-controller" with a no-op reconcile function. The
+// manager.Manager will be used to Start the Controller, and will provide it a shared Cache and Client.
+func ExampleNew() {
+ _, err := controller.New("pod-controller", mgr, controller.Options{
+ Reconciler: reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
+ // Your business logic to implement the API by creating, updating, deleting objects goes here.
+ return reconcile.Result{}, nil
+ }),
+ })
+ if err != nil {
+ log.Error(err, "unable to create pod-controller")
+ os.Exit(1)
+ }
+}
+
+// This example starts a new Controller named "pod-controller" to Watch Pods and call a no-op Reconciler.
+func ExampleController() {
+ // mgr is a manager.Manager
+
+ // Create a new Controller that will call the provided Reconciler function in response
+ // to events.
+ c, err := controller.New("pod-controller", mgr, controller.Options{
+ Reconciler: reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
+ // Your business logic to implement the API by creating, updating, deleting objects goes here.
+ return reconcile.Result{}, nil
+ }),
+ })
+ if err != nil {
+ log.Error(err, "unable to create pod-controller")
+ os.Exit(1)
+ }
+
+ // Watch for Pod create / update / delete events and call Reconcile
+ err = c.Watch(source.Kind(mgr.GetCache(), &corev1.Pod{}), &handler.EnqueueRequestForObject{})
+ if err != nil {
+ log.Error(err, "unable to watch pods")
+ os.Exit(1)
+ }
+
+ // Start the Controller through the manager.
+ if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+ log.Error(err, "unable to continue running manager")
+ os.Exit(1)
+ }
+}
+
+// This example starts a new Controller named "pod-controller" to Watch Pods with the unstructured object and call a no-op Reconciler.
+func ExampleController_unstructured() {
+ // mgr is a manager.Manager
+
+ // Create a new Controller that will call the provided Reconciler function in response
+ // to events.
+ c, err := controller.New("pod-controller", mgr, controller.Options{
+ Reconciler: reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
+ // Your business logic to implement the API by creating, updating, deleting objects goes here.
+ return reconcile.Result{}, nil
+ }),
+ })
+ if err != nil {
+ log.Error(err, "unable to create pod-controller")
+ os.Exit(1)
+ }
+
+ u := &unstructured.Unstructured{}
+ u.SetGroupVersionKind(schema.GroupVersionKind{
+ Kind: "Pod",
+ Group: "",
+ Version: "v1",
+ })
+ // Watch for Pod create / update / delete events and call Reconcile
+ err = c.Watch(source.Kind(mgr.GetCache(), u), &handler.EnqueueRequestForObject{})
+ if err != nil {
+ log.Error(err, "unable to watch pods")
+ os.Exit(1)
+ }
+
+ // Start the Controller through the manager.
+ if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+ log.Error(err, "unable to continue running manager")
+ os.Exit(1)
+ }
+}
+
+// This example creates a new controller named "pod-controller" to watch Pods
+// and call a no-op reconciler. The controller is not added to the provided
+// manager, and must thus be started and stopped by the caller.
+func ExampleNewUnmanaged() {
+ // mgr is a manager.Manager
+
+ // Configure creates a new controller but does not add it to the supplied
+ // manager.
+ c, err := controller.NewUnmanaged("pod-controller", mgr, controller.Options{
+ Reconciler: reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
+ return reconcile.Result{}, nil
+ }),
+ })
+ if err != nil {
+ log.Error(err, "unable to create pod-controller")
+ os.Exit(1)
+ }
+
+ if err := c.Watch(source.Kind(mgr.GetCache(), &corev1.Pod{}), &handler.EnqueueRequestForObject{}); err != nil {
+ log.Error(err, "unable to watch pods")
+ os.Exit(1)
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+
+ // Start our controller in a goroutine so that we do not block.
+ go func() {
+ // Block until our controller manager is elected leader. We presume our
+ // entire process will terminate if we lose leadership, so we don't need
+ // to handle that.
+ <-mgr.Elected()
+
+ // Start our controller. This will block until the context is
+ // closed, or the controller returns an error.
+ if err := c.Start(ctx); err != nil {
+ log.Error(err, "cannot run experiment controller")
+ }
+ }()
+
+ // Stop our controller.
+ cancel()
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/controller/testdata/crds/unconventionallisttype.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/testdata/crds/unconventionallisttype.yaml
new file mode 100644
index 00000000000..3069c473e54
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/controller/testdata/crds/unconventionallisttype.yaml
@@ -0,0 +1,17 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: unconventionallisttypes.chaosapps.metamagical.io
+spec:
+ group: chaosapps.metamagical.io
+ names:
+ kind: UnconventionalListType
+ plural: unconventionallisttypes
+ scope: Namespaced
+ versions:
+ - name: "v1"
+ storage: true
+ served: true
+ schema:
+ openAPIV3Schema:
+ type: object
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/conversion/conversion.go b/third_party/sigs.k8s.io/controller-runtime/pkg/conversion/conversion.go
new file mode 100644
index 00000000000..da32ab48e4b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/conversion/conversion.go
@@ -0,0 +1,40 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package conversion provides interface definitions that an API Type needs to
+implement for it to be supported by the generic conversion webhook handler
+defined under pkg/webhook/conversion.
+*/
+package conversion
+
+import "k8s.io/apimachinery/pkg/runtime"
+
+// Convertible defines capability of a type to convertible i.e. it can be converted to/from a hub type.
+type Convertible interface {
+ runtime.Object
+ ConvertTo(dst Hub) error
+ ConvertFrom(src Hub) error
+}
+
+// Hub marks that a given type is the hub type for conversion. This means that
+// all conversions will first convert to the hub type, then convert from the hub
+// type to the destination type. All types besides the hub type should implement
+// Convertible.
+type Hub interface {
+ runtime.Object
+ Hub()
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/doc.go
new file mode 100644
index 00000000000..89b380c1084
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/doc.go
@@ -0,0 +1,207 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package pkg provides libraries for building Controllers. Controllers implement Kubernetes APIs
+and are foundational to building Operators, Workload APIs, Configuration APIs, Autoscalers, and more.
+
+# Client
+
+Client provides a Read + Write client for reading and writing Kubernetes objects.
+
+# Cache
+
+Cache provides a Read client for reading objects from a local cache.
+A cache may register handlers to respond to events that update the cache.
+
+# Manager
+
+Manager is required for creating a Controller and provides the Controller shared dependencies such as
+clients, caches, schemes, etc. Controllers should be Started through the Manager by calling Manager.Start.
+
+# Controller
+
+Controller implements a Kubernetes API by responding to events (object Create, Update, Delete) and ensuring that
+the state specified in the Spec of the object matches the state of the system. This is called a reconcile.
+If they do not match, the Controller will create / update / delete objects as needed to make them match.
+
+Controllers are implemented as worker queues that process reconcile.Requests (requests to reconcile the
+state for a specific object).
+
+Unlike http handlers, Controllers DO NOT handle events directly, but enqueue Requests to eventually reconcile
+the object. This means the handling of multiple events may be batched together and the full state of the
+system must be read for each reconcile.
+
+* Controllers require a Reconciler to be provided to perform the work pulled from the work queue.
+
+* Controllers require Watches to be configured to enqueue reconcile.Requests in response to events.
+
+# Webhook
+
+Admission Webhooks are a mechanism for extending kubernetes APIs. Webhooks can be configured with target
+event type (object Create, Update, Delete), the API server will send AdmissionRequests to them
+when certain events happen. The webhooks may mutate and (or) validate the object embedded in
+the AdmissionReview requests and send back the response to the API server.
+
+There are 2 types of admission webhook: mutating and validating admission webhook.
+Mutating webhook is used to mutate a core API object or a CRD instance before the API server admits it.
+Validating webhook is used to validate if an object meets certain requirements.
+
+* Admission Webhooks require Handler(s) to be provided to process the received AdmissionReview requests.
+
+# Reconciler
+
+Reconciler is a function provided to a Controller that may be called at anytime with the Name and Namespace of an object.
+When called, the Reconciler will ensure that the state of the system matches what is specified in the object at the
+time the Reconciler is called.
+
+Example: Reconciler invoked for a ReplicaSet object. The ReplicaSet specifies 5 replicas but only
+3 Pods exist in the system. The Reconciler creates 2 more Pods and sets their OwnerReference to point at the
+ReplicaSet with controller=true.
+
+* Reconciler contains all of the business logic of a Controller.
+
+* Reconciler typically works on a single object type. - e.g. it will only reconcile ReplicaSets. For separate
+types use separate Controllers. If you wish to trigger reconciles from other objects, you can provide
+a mapping (e.g. owner references) that maps the object that triggers the reconcile to the object being reconciled.
+
+* Reconciler is provided the Name / Namespace of the object to reconcile.
+
+* Reconciler does not care about the event contents or event type responsible for triggering the reconcile.
+- e.g. it doesn't matter whether a ReplicaSet was created or updated, Reconciler will always compare the number of
+Pods in the system against what is specified in the object at the time it is called.
+
+# Source
+
+resource.Source is an argument to Controller.Watch that provides a stream of events.
+Events typically come from watching Kubernetes APIs (e.g. Pod Create, Update, Delete).
+
+Example: source.Kind uses the Kubernetes API Watch endpoint for a GroupVersionKind to provide
+Create, Update, Delete events.
+
+* Source provides a stream of events (e.g. object Create, Update, Delete) for Kubernetes objects typically
+through the Watch API.
+
+* Users SHOULD only use the provided Source implementations instead of implementing their own for nearly all cases.
+
+# EventHandler
+
+handler.EventHandler is an argument to Controller.Watch that enqueues reconcile.Requests in response to events.
+
+Example: a Pod Create event from a Source is provided to the eventhandler.EnqueueHandler, which enqueues a
+reconcile.Request containing the name / Namespace of the Pod.
+
+* EventHandlers handle events by enqueueing reconcile.Requests for one or more objects.
+
+* EventHandlers MAY map an event for an object to a reconcile.Request for an object of the same type.
+
+* EventHandlers MAY map an event for an object to a reconcile.Request for an object of a different type - e.g.
+map a Pod event to a reconcile.Request for the owning ReplicaSet.
+
+* EventHandlers MAY map an event for an object to multiple reconcile.Requests for objects of the same or a different
+type - e.g. map a Node event to objects that respond to cluster resize events.
+
+* Users SHOULD only use the provided EventHandler implementations instead of implementing their own for almost
+all cases.
+
+# Predicate
+
+predicate.Predicate is an optional argument to Controller.Watch that filters events. This allows common filters to be
+reused and composed.
+
+* Predicate takes an event and returns a bool (true to enqueue)
+
+* Predicates are optional arguments
+
+* Users SHOULD use the provided Predicate implementations, but MAY implement additional
+Predicates e.g. generation changed, label selectors changed etc.
+
+# PodController Diagram
+
+Source provides event:
+
+* &source.KindSource{&v1.Pod{}} -> (Pod foo/bar Create Event)
+
+EventHandler enqueues Request:
+
+* &handler.EnqueueRequestForObject{} -> (reconcile.Request{types.NamespaceName{Name: "foo", Namespace: "bar"}})
+
+Reconciler is called with the Request:
+
+* Reconciler(reconcile.Request{types.NamespaceName{Name: "foo", Namespace: "bar"}})
+
+# Usage
+
+The following example shows creating a new Controller program which Reconciles ReplicaSet objects in response
+to Pod or ReplicaSet events. The Reconciler function simply adds a label to the ReplicaSet.
+
+See the examples/builtins/main.go for a usage example.
+
+Controller Example:
+
+1. Watch ReplicaSet and Pods Sources
+
+1.1 ReplicaSet -> handler.EnqueueRequestForObject - enqueue a Request with the ReplicaSet Namespace and Name.
+
+1.2 Pod (created by ReplicaSet) -> handler.EnqueueRequestForOwnerHandler - enqueue a Request with the
+Owning ReplicaSet Namespace and Name.
+
+2. Reconcile ReplicaSet in response to an event
+
+2.1 ReplicaSet object created -> Read ReplicaSet, try to read Pods -> if is missing create Pods.
+
+2.2 Reconciler triggered by creation of Pods -> Read ReplicaSet and Pods, do nothing.
+
+2.3 Reconciler triggered by deletion of Pods from some other actor -> Read ReplicaSet and Pods, create replacement Pods.
+
+# Watching and EventHandling
+
+Controllers may Watch multiple Kinds of objects (e.g. Pods, ReplicaSets and Deployments), but they reconcile
+only a single Type. When one Type of object must be updated in response to changes in another Type of object,
+an EnqueueRequestsFromMapFunc may be used to map events from one type to another. e.g. Respond to a cluster resize
+event (add / delete Node) by re-reconciling all instances of some API.
+
+A Deployment Controller might use an EnqueueRequestForObject and EnqueueRequestForOwner to:
+
+* Watch for Deployment Events - enqueue the Namespace and Name of the Deployment.
+
+* Watch for ReplicaSet Events - enqueue the Namespace and Name of the Deployment that created the ReplicaSet
+(e.g the Owner)
+
+Note: reconcile.Requests are deduplicated when they are enqueued. Many Pod Events for the same ReplicaSet
+may trigger only 1 reconcile invocation as each Event results in the Handler trying to enqueue
+the same reconcile.Request for the ReplicaSet.
+
+# Controller Writing Tips
+
+Reconciler Runtime Complexity:
+
+* It is better to write Controllers to perform an O(1) reconcile N times (e.g. on N different objects) instead of
+performing an O(N) reconcile 1 time (e.g. on a single object which manages N other objects).
+
+* Example: If you need to update all Services in response to a Node being added - reconcile Services but Watch
+Nodes (transformed to Service object name / Namespaces) instead of Reconciling Nodes and updating Services
+
+Event Multiplexing:
+
+* reconcile.Requests for the same Name / Namespace are batched and deduplicated when they are enqueued. This allows
+Controllers to gracefully handle a high volume of events for a single object. Multiplexing multiple event Sources to
+a single object Type will batch requests across events for different object types.
+
+* Example: Pod events for a ReplicaSet are transformed to a ReplicaSet Name / Namespace, so the ReplicaSet
+will be Reconciled only 1 time for multiple events from multiple Pods.
+*/
+package pkg
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/cache.go b/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/cache.go
deleted file mode 100644
index 57427a1ebfd..00000000000
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/cache.go
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
-package dynamiccache
-
-import (
- "fmt"
- "time"
-
- "github.com/open-policy-agent/gatekeeper/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/client-go/kubernetes/scheme"
- "k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/cache"
- "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
- logf "sigs.k8s.io/controller-runtime/pkg/log"
-)
-
-var log = logf.Log.WithName("object-cache")
-
-var defaultResyncTime = 10 * time.Hour
-
-// New initializes and returns a new Cache.
-func New(config *rest.Config, opts cache.Options) (cache.Cache, error) {
- opts, err := defaultOpts(config, opts)
- if err != nil {
- return nil, err
- }
- selectorsByGVK, err := convertToSelectorsByGVK(opts.SelectorsByObject, opts.Scheme)
- if err != nil {
- return nil, err
- }
- im := internal.NewInformersMap(config, opts.Scheme, opts.Mapper, *opts.Resync, opts.Namespace, selectorsByGVK)
- return &dynamicInformerCache{InformersMap: im}, nil
-}
-
-// BuilderWithOptions returns a Cache constructor that will build the a cache
-// honoring the options argument, this is useful to specify options like
-// SelectorsByObject
-// WARNING: if SelectorsByObject is specified. filtered out resources are not
-// returned.
-func BuilderWithOptions(options cache.Options) cache.NewCacheFunc {
- return func(config *rest.Config, opts cache.Options) (cache.Cache, error) {
- if opts.Scheme == nil {
- opts.Scheme = options.Scheme
- }
- if opts.Mapper == nil {
- opts.Mapper = options.Mapper
- }
- if opts.Resync == nil {
- opts.Resync = options.Resync
- }
- if opts.Namespace == "" {
- opts.Namespace = options.Namespace
- }
- opts.SelectorsByObject = options.SelectorsByObject
- return New(config, opts)
- }
-}
-
-func defaultOpts(config *rest.Config, opts cache.Options) (cache.Options, error) {
- // Use the default Kubernetes Scheme if unset
- if opts.Scheme == nil {
- opts.Scheme = scheme.Scheme
- }
-
- // Construct a new Mapper if unset
- if opts.Mapper == nil {
- var err error
- opts.Mapper, err = apiutil.NewDynamicRESTMapper(config)
- if err != nil {
- log.WithName("setup").Error(err, "Failed to get API Group-Resources")
- return opts, fmt.Errorf("could not create RESTMapper from config")
- }
- }
-
- // Default the resync period to 10 hours if unset
- if opts.Resync == nil {
- opts.Resync = &defaultResyncTime
- }
- return opts, nil
-}
-
-func convertToSelectorsByGVK(selectorsByObject cache.SelectorsByObject, scheme *runtime.Scheme) (internal.SelectorsByGVK, error) {
- selectorsByGVK := internal.SelectorsByGVK{}
- for object, selector := range selectorsByObject {
- gvk, err := apiutil.GVKForObject(object, scheme)
- if err != nil {
- return nil, err
- }
- selectorsByGVK[gvk] = internal.Selector{
- Label: selector.Label,
- Field: selector.Field,
- }
- }
- return selectorsByGVK, nil
-}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/cache_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/cache_test.go
deleted file mode 100644
index 607ab88e8f3..00000000000
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/cache_test.go
+++ /dev/null
@@ -1,1317 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
-package dynamiccache_test
-
-import (
- "context"
- "fmt"
-
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/ginkgo/extensions/table"
- . "github.com/onsi/gomega"
-
- 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/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/fields"
- "k8s.io/apimachinery/pkg/labels"
- "k8s.io/apimachinery/pkg/runtime/schema"
- kscheme "k8s.io/client-go/kubernetes/scheme"
- "k8s.io/client-go/rest"
- kcache "k8s.io/client-go/tools/cache"
-
- "sigs.k8s.io/controller-runtime/pkg/cache"
- "sigs.k8s.io/controller-runtime/pkg/client"
-
- "github.com/open-policy-agent/gatekeeper/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache"
-)
-
-const testNodeOne = "test-node-1"
-const testNamespaceOne = "test-namespace-1"
-const testNamespaceTwo = "test-namespace-2"
-const testNamespaceThree = "test-namespace-3"
-
-// TODO(community): Pull these helper functions into testenv.
-// Restart policy is included to allow indexing on that field.
-func createPodWithLabels(name, namespace string, restartPolicy corev1.RestartPolicy, labels map[string]string) client.Object {
- three := int64(3)
- if labels == nil {
- labels = map[string]string{}
- }
- labels["test-label"] = name
- pod := &corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- Namespace: namespace,
- Labels: labels,
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}},
- RestartPolicy: restartPolicy,
- ActiveDeadlineSeconds: &three,
- },
- }
- cl, err := client.New(cfg, client.Options{})
- Expect(err).NotTo(HaveOccurred())
- err = cl.Create(context.Background(), pod)
- Expect(err).NotTo(HaveOccurred())
- return pod
-}
-
-func createPod(name, namespace string, restartPolicy corev1.RestartPolicy) client.Object {
- return createPodWithLabels(name, namespace, restartPolicy, nil)
-}
-
-func deletePod(pod client.Object) {
- cl, err := client.New(cfg, client.Options{})
- Expect(err).NotTo(HaveOccurred())
- err = cl.Delete(context.Background(), pod)
- Expect(err).NotTo(HaveOccurred())
-}
-
-var _ = Describe("Informer Cache", func() {
- CacheTest(dynamiccache.New)
-})
-var _ = Describe("Multi-Namespace Informer Cache", func() {
- CacheTest(dynamiccache.MultiNamespacedCacheBuilder([]string{testNamespaceOne, testNamespaceTwo, "default"}))
-})
-
-func CacheTest(createCacheFunc func(config *rest.Config, opts cache.Options) (cache.Cache, error)) {
- Describe("Cache test", func() {
- var (
- informerCache cache.Cache
- informerCacheCtx context.Context
- informerCacheCancel context.CancelFunc
- knownPod1 client.Object
- knownPod2 client.Object
- knownPod3 client.Object
- knownPod4 client.Object
- knownPod5 client.Object
- knownPod6 client.Object
- )
-
- BeforeEach(func() {
- informerCacheCtx, informerCacheCancel = context.WithCancel(context.Background())
- Expect(cfg).NotTo(BeNil())
-
- By("creating three pods")
- cl, err := client.New(cfg, client.Options{})
- Expect(err).NotTo(HaveOccurred())
- err = ensureNode(testNodeOne, cl)
- Expect(err).NotTo(HaveOccurred())
- err = ensureNamespace(testNamespaceOne, cl)
- Expect(err).NotTo(HaveOccurred())
- err = ensureNamespace(testNamespaceTwo, cl)
- Expect(err).NotTo(HaveOccurred())
- err = ensureNamespace(testNamespaceThree, cl)
- Expect(err).NotTo(HaveOccurred())
- // Includes restart policy since these objects are indexed on this field.
- knownPod1 = createPod("test-pod-1", testNamespaceOne, corev1.RestartPolicyNever)
- knownPod2 = createPod("test-pod-2", testNamespaceTwo, corev1.RestartPolicyAlways)
- knownPod3 = createPodWithLabels("test-pod-3", testNamespaceTwo, corev1.RestartPolicyOnFailure, map[string]string{"common-label": "common"})
- knownPod4 = createPodWithLabels("test-pod-4", testNamespaceThree, corev1.RestartPolicyNever, map[string]string{"common-label": "common"})
- knownPod5 = createPod("test-pod-5", testNamespaceOne, corev1.RestartPolicyNever)
- knownPod6 = createPod("test-pod-6", testNamespaceTwo, corev1.RestartPolicyAlways)
-
- podGVK := schema.GroupVersionKind{
- Kind: "Pod",
- Version: "v1",
- }
-
- knownPod1.GetObjectKind().SetGroupVersionKind(podGVK)
- knownPod2.GetObjectKind().SetGroupVersionKind(podGVK)
- knownPod3.GetObjectKind().SetGroupVersionKind(podGVK)
- knownPod4.GetObjectKind().SetGroupVersionKind(podGVK)
- knownPod5.GetObjectKind().SetGroupVersionKind(podGVK)
- knownPod6.GetObjectKind().SetGroupVersionKind(podGVK)
-
- By("creating the informer cache")
- informerCache, err = createCacheFunc(cfg, cache.Options{})
- Expect(err).NotTo(HaveOccurred())
- By("running the cache and waiting for it to sync")
- // pass as an arg so that we don't race between close and re-assign
- go func(ctx context.Context) {
- defer GinkgoRecover()
- Expect(informerCache.Start(ctx)).To(Succeed())
- }(informerCacheCtx)
- Expect(informerCache.WaitForCacheSync(informerCacheCtx)).To(BeTrue())
- })
-
- AfterEach(func() {
- By("cleaning up created pods")
- deletePod(knownPod1)
- deletePod(knownPod2)
- deletePod(knownPod3)
- deletePod(knownPod4)
- deletePod(knownPod5)
- deletePod(knownPod6)
-
- informerCacheCancel()
- })
-
- Describe("as a Reader", func() {
- Context("with structured objects", func() {
- It("should be able to list objects that haven't been watched previously", func() {
- By("listing all services in the cluster")
- listObj := &corev1.ServiceList{}
- Expect(informerCache.List(context.Background(), listObj)).To(Succeed())
-
- By("verifying that the returned list contains the Kubernetes service")
- // NB: kubernetes default service is automatically created in testenv.
- Expect(listObj.Items).NotTo(BeEmpty())
- hasKubeService := false
- for i := range listObj.Items {
- svc := &listObj.Items[i]
- if isKubeService(svc) {
- hasKubeService = true
- break
- }
- }
- Expect(hasKubeService).To(BeTrue())
- })
-
- It("should be able to get objects that haven't been watched previously", func() {
- By("getting the Kubernetes service")
- svc := &corev1.Service{}
- svcKey := client.ObjectKey{Namespace: "default", Name: "kubernetes"}
- Expect(informerCache.Get(context.Background(), svcKey, svc)).To(Succeed())
-
- By("verifying that the returned service looks reasonable")
- Expect(svc.Name).To(Equal("kubernetes"))
- Expect(svc.Namespace).To(Equal("default"))
- })
-
- It("should support filtering by labels in a single namespace", func() {
- By("listing pods with a particular label")
- // NB: each pod has a "test-label":
- out := corev1.PodList{}
- Expect(informerCache.List(context.Background(), &out,
- client.InNamespace(testNamespaceTwo),
- client.MatchingLabels(map[string]string{"test-label": "test-pod-2"}))).To(Succeed())
-
- By("verifying the returned pods have the correct label")
- Expect(out.Items).NotTo(BeEmpty())
- Expect(out.Items).Should(HaveLen(1))
- actual := out.Items[0]
- Expect(actual.Labels["test-label"]).To(Equal("test-pod-2"))
- })
-
- It("should support filtering by labels from multiple namespaces", func() {
- By("creating another pod with the same label but different namespace")
- anotherPod := createPod("test-pod-2", testNamespaceOne, corev1.RestartPolicyAlways)
- defer deletePod(anotherPod)
-
- By("listing pods with a particular label")
- // NB: each pod has a "test-label":
- out := corev1.PodList{}
- labels := map[string]string{"test-label": "test-pod-2"}
- Expect(informerCache.List(context.Background(), &out, client.MatchingLabels(labels))).To(Succeed())
-
- By("verifying multiple pods with the same label in different namespaces are returned")
- Expect(out.Items).NotTo(BeEmpty())
- Expect(out.Items).Should(HaveLen(2))
- for _, actual := range out.Items {
- Expect(actual.Labels["test-label"]).To(Equal("test-pod-2"))
- }
- })
-
- It("should be able to list objects with GVK populated", func() {
- By("listing pods")
- out := &corev1.PodList{}
- Expect(informerCache.List(context.Background(), out)).To(Succeed())
-
- By("verifying that the returned pods have GVK populated")
- Expect(out.Items).NotTo(BeEmpty())
- Expect(out.Items).Should(SatisfyAny(HaveLen(5), HaveLen(6)))
- for _, p := range out.Items {
- Expect(p.GroupVersionKind()).To(Equal(corev1.SchemeGroupVersion.WithKind("Pod")))
- }
- })
-
- It("should be able to list objects by namespace", func() {
- By("listing pods in test-namespace-1")
- listObj := &corev1.PodList{}
- Expect(informerCache.List(context.Background(), listObj,
- client.InNamespace(testNamespaceOne))).To(Succeed())
-
- By("verifying that the returned pods are in test-namespace-1")
- Expect(listObj.Items).NotTo(BeEmpty())
- Expect(listObj.Items).Should(HaveLen(2))
- for _, item := range listObj.Items {
- Expect(item.Namespace).To(Equal(testNamespaceOne))
- }
- })
-
- It("should deep copy the object unless told otherwise", func() {
- By("retrieving a specific pod from the cache")
- out := &corev1.Pod{}
- podKey := client.ObjectKey{Name: "test-pod-2", Namespace: testNamespaceTwo}
- Expect(informerCache.Get(context.Background(), podKey, out)).To(Succeed())
-
- By("verifying the retrieved pod is equal to a known pod")
- Expect(out).To(Equal(knownPod2))
-
- By("altering a field in the retrieved pod")
- *out.Spec.ActiveDeadlineSeconds = 4
-
- By("verifying the pods are no longer equal")
- Expect(out).NotTo(Equal(knownPod2))
- })
-
- It("should return an error if the object is not found", func() {
- By("getting a service that does not exists")
- svc := &corev1.Service{}
- svcKey := client.ObjectKey{Namespace: testNamespaceOne, Name: "unknown"}
-
- By("verifying that an error is returned")
- err := informerCache.Get(context.Background(), svcKey, svc)
- Expect(err).To(HaveOccurred())
- Expect(apierrors.IsNotFound(err)).To(BeTrue())
- })
-
- It("should return an error if getting object in unwatched namespace", func() {
- By("getting a service that does not exists")
- svc := &corev1.Service{}
- svcKey := client.ObjectKey{Namespace: "unknown", Name: "unknown"}
-
- By("verifying that an error is returned")
- err := informerCache.Get(context.Background(), svcKey, svc)
- Expect(err).To(HaveOccurred())
- })
-
- It("should return an error when context is cancelled", func() {
- By("cancelling the context")
- informerCacheCancel()
-
- By("listing pods in test-namespace-1 with a cancelled context")
- listObj := &corev1.PodList{}
- err := informerCache.List(informerCacheCtx, listObj, client.InNamespace(testNamespaceOne))
-
- By("verifying that an error is returned")
- Expect(err).To(HaveOccurred())
- Expect(apierrors.IsTimeout(err)).To(BeTrue())
- })
-
- It("should set the Limit option and limit number of objects to Limit when List is called", func() {
- opts := &client.ListOptions{Limit: int64(3)}
- By("verifying that only Limit (3) number of objects are retrieved from the cache")
- listObj := &corev1.PodList{}
- Expect(informerCache.List(context.Background(), listObj, opts)).To(Succeed())
- Expect(listObj.Items).Should(HaveLen(3))
- })
- })
-
- Context("with unstructured objects", func() {
- It("should be able to list objects that haven't been watched previously", func() {
- By("listing all services in the cluster")
- listObj := &unstructured.UnstructuredList{}
- listObj.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "ServiceList",
- })
- err := informerCache.List(context.Background(), listObj)
- Expect(err).To(Succeed())
-
- By("verifying that the returned list contains the Kubernetes service")
- // NB: kubernetes default service is automatically created in testenv.
- Expect(listObj.Items).NotTo(BeEmpty())
- hasKubeService := false
- for i := range listObj.Items {
- svc := &listObj.Items[i]
- if isKubeService(svc) {
- hasKubeService = true
- break
- }
- }
- Expect(hasKubeService).To(BeTrue())
- })
- It("should be able to get objects that haven't been watched previously", func() {
- By("getting the Kubernetes service")
- svc := &unstructured.Unstructured{}
- svc.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Service",
- })
- svcKey := client.ObjectKey{Namespace: "default", Name: "kubernetes"}
- Expect(informerCache.Get(context.Background(), svcKey, svc)).To(Succeed())
-
- By("verifying that the returned service looks reasonable")
- Expect(svc.GetName()).To(Equal("kubernetes"))
- Expect(svc.GetNamespace()).To(Equal("default"))
- })
-
- It("should support filtering by labels in a single namespace", func() {
- By("listing pods with a particular label")
- // NB: each pod has a "test-label":
- out := unstructured.UnstructuredList{}
- out.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "PodList",
- })
- err := informerCache.List(context.Background(), &out,
- client.InNamespace(testNamespaceTwo),
- client.MatchingLabels(map[string]string{"test-label": "test-pod-2"}))
- Expect(err).To(Succeed())
-
- By("verifying the returned pods have the correct label")
- Expect(out.Items).NotTo(BeEmpty())
- Expect(out.Items).Should(HaveLen(1))
- actual := out.Items[0]
- Expect(actual.GetLabels()["test-label"]).To(Equal("test-pod-2"))
- })
-
- It("should support filtering by labels from multiple namespaces", func() {
- By("creating another pod with the same label but different namespace")
- anotherPod := createPod("test-pod-2", testNamespaceOne, corev1.RestartPolicyAlways)
- defer deletePod(anotherPod)
-
- By("listing pods with a particular label")
- // NB: each pod has a "test-label":
- out := unstructured.UnstructuredList{}
- out.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "PodList",
- })
- labels := map[string]string{"test-label": "test-pod-2"}
- err := informerCache.List(context.Background(), &out, client.MatchingLabels(labels))
- Expect(err).To(Succeed())
-
- By("verifying multiple pods with the same label in different namespaces are returned")
- Expect(out.Items).NotTo(BeEmpty())
- Expect(out.Items).Should(HaveLen(2))
- for _, actual := range out.Items {
- Expect(actual.GetLabels()["test-label"]).To(Equal("test-pod-2"))
- }
- })
-
- It("should be able to list objects by namespace", func() {
- By("listing pods in test-namespace-1")
- listObj := &unstructured.UnstructuredList{}
- listObj.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "PodList",
- })
- err := informerCache.List(context.Background(), listObj, client.InNamespace(testNamespaceOne))
- Expect(err).To(Succeed())
-
- By("verifying that the returned pods are in test-namespace-1")
- Expect(listObj.Items).NotTo(BeEmpty())
- Expect(listObj.Items).Should(HaveLen(2))
- for _, item := range listObj.Items {
- Expect(item.GetNamespace()).To(Equal(testNamespaceOne))
- }
- })
-
- It("should be able to restrict cache to a namespace", func() {
- By("creating a namespaced cache")
- namespacedCache, err := dynamiccache.New(cfg, cache.Options{Namespace: testNamespaceOne})
- Expect(err).NotTo(HaveOccurred())
-
- By("running the cache and waiting for it to sync")
- go func() {
- defer GinkgoRecover()
- Expect(namespacedCache.Start(informerCacheCtx)).To(Succeed())
- }()
- Expect(namespacedCache.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
-
- By("listing pods in all namespaces")
- out := &unstructured.UnstructuredList{}
- out.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "PodList",
- })
- Expect(namespacedCache.List(context.Background(), out)).To(Succeed())
-
- By("verifying the returned pod is from the watched namespace")
- Expect(out.Items).NotTo(BeEmpty())
- Expect(out.Items).Should(HaveLen(2))
- for _, item := range out.Items {
- Expect(item.GetNamespace()).To(Equal(testNamespaceOne))
- }
- By("listing all nodes - should still be able to list a cluster-scoped resource")
- nodeList := &unstructured.UnstructuredList{}
- nodeList.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "NodeList",
- })
- Expect(namespacedCache.List(context.Background(), nodeList)).To(Succeed())
-
- By("verifying the node list is not empty")
- Expect(nodeList.Items).NotTo(BeEmpty())
-
- By("getting a node - should still be able to get a cluster-scoped resource")
- node := &unstructured.Unstructured{}
- node.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Node",
- })
-
- By("verifying that getting the node works with an empty namespace")
- key1 := client.ObjectKey{Namespace: "", Name: testNodeOne}
- Expect(namespacedCache.Get(context.Background(), key1, node)).To(Succeed())
-
- By("verifying that the namespace is ignored when getting a cluster-scoped resource")
- key2 := client.ObjectKey{Namespace: "random", Name: testNodeOne}
- Expect(namespacedCache.Get(context.Background(), key2, node)).To(Succeed())
- })
-
- It("should deep copy the object unless told otherwise", func() {
- By("retrieving a specific pod from the cache")
- out := &unstructured.Unstructured{}
- out.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- })
- uKnownPod2 := &unstructured.Unstructured{}
- Expect(kscheme.Scheme.Convert(knownPod2, uKnownPod2, nil)).To(Succeed())
-
- podKey := client.ObjectKey{Name: "test-pod-2", Namespace: testNamespaceTwo}
- Expect(informerCache.Get(context.Background(), podKey, out)).To(Succeed())
-
- By("verifying the retrieved pod is equal to a known pod")
- Expect(out).To(Equal(uKnownPod2))
-
- By("altering a field in the retrieved pod")
- m, _ := out.Object["spec"].(map[string]interface{})
- m["activeDeadlineSeconds"] = 4
-
- By("verifying the pods are no longer equal")
- Expect(out).NotTo(Equal(knownPod2))
- })
-
- It("should return an error if the object is not found", func() {
- By("getting a service that does not exists")
- svc := &unstructured.Unstructured{}
- svc.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Service",
- })
- svcKey := client.ObjectKey{Namespace: testNamespaceOne, Name: "unknown"}
-
- By("verifying that an error is returned")
- err := informerCache.Get(context.Background(), svcKey, svc)
- Expect(err).To(HaveOccurred())
- Expect(apierrors.IsNotFound(err)).To(BeTrue())
- })
- It("should return an error if getting object in unwatched namespace", func() {
- By("getting a service that does not exists")
- svc := &corev1.Service{}
- svcKey := client.ObjectKey{Namespace: "unknown", Name: "unknown"}
-
- By("verifying that an error is returned")
- err := informerCache.Get(context.Background(), svcKey, svc)
- Expect(err).To(HaveOccurred())
- })
- It("test multinamespaced cache for cluster scoped resources", func() {
- By("creating a multinamespaced cache to watch specific namespaces")
- multi := cache.MultiNamespacedCacheBuilder([]string{"default", testNamespaceOne})
- m, err := multi(cfg, cache.Options{})
- Expect(err).NotTo(HaveOccurred())
-
- By("running the cache and waiting it for sync")
- go func() {
- defer GinkgoRecover()
- Expect(m.Start(informerCacheCtx)).To(Succeed())
- }()
- Expect(m.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
-
- By("should be able to fetch cluster scoped resource")
- node := &corev1.Node{}
-
- By("verifying that getting the node works with an empty namespace")
- key1 := client.ObjectKey{Namespace: "", Name: testNodeOne}
- Expect(m.Get(context.Background(), key1, node)).To(Succeed())
-
- By("verifying if the cluster scoped resources are not duplicated")
- nodeList := &unstructured.UnstructuredList{}
- nodeList.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "NodeList",
- })
- Expect(m.List(context.Background(), nodeList)).To(Succeed())
-
- By("verifying the node list is not empty")
- Expect(nodeList.Items).NotTo(BeEmpty())
- Expect(len(nodeList.Items)).To(BeEquivalentTo(1))
- })
- })
- Context("with metadata-only objects", func() {
- It("should be able to list objects that haven't been watched previously", func() {
- By("listing all services in the cluster")
- listObj := &metav1.PartialObjectMetadataList{}
- listObj.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "ServiceList",
- })
- err := informerCache.List(context.Background(), listObj)
- Expect(err).To(Succeed())
-
- By("verifying that the returned list contains the Kubernetes service")
- // NB: kubernetes default service is automatically created in testenv.
- Expect(listObj.Items).NotTo(BeEmpty())
- hasKubeService := false
- for i := range listObj.Items {
- svc := &listObj.Items[i]
- if isKubeService(svc) {
- hasKubeService = true
- break
- }
- }
- Expect(hasKubeService).To(BeTrue())
- })
- It("should be able to get objects that haven't been watched previously", func() {
- By("getting the Kubernetes service")
- svc := &metav1.PartialObjectMetadata{}
- svc.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Service",
- })
- svcKey := client.ObjectKey{Namespace: "default", Name: "kubernetes"}
- Expect(informerCache.Get(context.Background(), svcKey, svc)).To(Succeed())
-
- By("verifying that the returned service looks reasonable")
- Expect(svc.GetName()).To(Equal("kubernetes"))
- Expect(svc.GetNamespace()).To(Equal("default"))
- })
-
- It("should support filtering by labels in a single namespace", func() {
- By("listing pods with a particular label")
- // NB: each pod has a "test-label":
- out := metav1.PartialObjectMetadataList{}
- out.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "PodList",
- })
- err := informerCache.List(context.Background(), &out,
- client.InNamespace(testNamespaceTwo),
- client.MatchingLabels(map[string]string{"test-label": "test-pod-2"}))
- Expect(err).To(Succeed())
-
- By("verifying the returned pods have the correct label")
- Expect(out.Items).NotTo(BeEmpty())
- Expect(out.Items).Should(HaveLen(1))
- actual := out.Items[0]
- Expect(actual.GetLabels()["test-label"]).To(Equal("test-pod-2"))
- })
-
- It("should support filtering by labels from multiple namespaces", func() {
- By("creating another pod with the same label but different namespace")
- anotherPod := createPod("test-pod-2", testNamespaceOne, corev1.RestartPolicyAlways)
- defer deletePod(anotherPod)
-
- By("listing pods with a particular label")
- // NB: each pod has a "test-label":
- out := metav1.PartialObjectMetadataList{}
- out.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "PodList",
- })
- labels := map[string]string{"test-label": "test-pod-2"}
- err := informerCache.List(context.Background(), &out, client.MatchingLabels(labels))
- Expect(err).To(Succeed())
-
- By("verifying multiple pods with the same label in different namespaces are returned")
- Expect(out.Items).NotTo(BeEmpty())
- Expect(out.Items).Should(HaveLen(2))
- for _, actual := range out.Items {
- Expect(actual.GetLabels()["test-label"]).To(Equal("test-pod-2"))
- }
- })
-
- It("should be able to list objects by namespace", func() {
- By("listing pods in test-namespace-1")
- listObj := &metav1.PartialObjectMetadataList{}
- listObj.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "PodList",
- })
- err := informerCache.List(context.Background(), listObj, client.InNamespace(testNamespaceOne))
- Expect(err).To(Succeed())
-
- By("verifying that the returned pods are in test-namespace-1")
- Expect(listObj.Items).NotTo(BeEmpty())
- Expect(listObj.Items).Should(HaveLen(2))
- for _, item := range listObj.Items {
- Expect(item.Namespace).To(Equal(testNamespaceOne))
- }
- })
-
- It("should be able to restrict cache to a namespace", func() {
- By("creating a namespaced cache")
- namespacedCache, err := dynamiccache.New(cfg, cache.Options{Namespace: testNamespaceOne})
- Expect(err).NotTo(HaveOccurred())
-
- By("running the cache and waiting for it to sync")
- go func() {
- defer GinkgoRecover()
- Expect(namespacedCache.Start(informerCacheCtx)).To(Succeed())
- }()
- Expect(namespacedCache.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
-
- By("listing pods in all namespaces")
- out := &metav1.PartialObjectMetadataList{}
- out.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "PodList",
- })
- Expect(namespacedCache.List(context.Background(), out)).To(Succeed())
-
- By("verifying the returned pod is from the watched namespace")
- Expect(out.Items).NotTo(BeEmpty())
- Expect(out.Items).Should(HaveLen(2))
- for _, item := range out.Items {
- Expect(item.Namespace).To(Equal(testNamespaceOne))
- }
- By("listing all nodes - should still be able to list a cluster-scoped resource")
- nodeList := &metav1.PartialObjectMetadataList{}
- nodeList.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "NodeList",
- })
- Expect(namespacedCache.List(context.Background(), nodeList)).To(Succeed())
-
- By("verifying the node list is not empty")
- Expect(nodeList.Items).NotTo(BeEmpty())
-
- By("getting a node - should still be able to get a cluster-scoped resource")
- node := &metav1.PartialObjectMetadata{}
- node.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Node",
- })
-
- By("verifying that getting the node works with an empty namespace")
- key1 := client.ObjectKey{Namespace: "", Name: testNodeOne}
- Expect(namespacedCache.Get(context.Background(), key1, node)).To(Succeed())
-
- By("verifying that the namespace is ignored when getting a cluster-scoped resource")
- key2 := client.ObjectKey{Namespace: "random", Name: testNodeOne}
- Expect(namespacedCache.Get(context.Background(), key2, node)).To(Succeed())
- })
-
- It("should deep copy the object unless told otherwise", func() {
- By("retrieving a specific pod from the cache")
- out := &metav1.PartialObjectMetadata{}
- out.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- })
- uKnownPod2 := &metav1.PartialObjectMetadata{}
- knownPod2.(*corev1.Pod).ObjectMeta.DeepCopyInto(&uKnownPod2.ObjectMeta)
- uKnownPod2.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- })
-
- podKey := client.ObjectKey{Name: "test-pod-2", Namespace: testNamespaceTwo}
- Expect(informerCache.Get(context.Background(), podKey, out)).To(Succeed())
-
- By("verifying the retrieved pod is equal to a known pod")
- Expect(out).To(Equal(uKnownPod2))
-
- By("altering a field in the retrieved pod")
- out.Labels["foo"] = "bar"
-
- By("verifying the pods are no longer equal")
- Expect(out).NotTo(Equal(knownPod2))
- })
-
- It("should return an error if the object is not found", func() {
- By("getting a service that does not exists")
- svc := &metav1.PartialObjectMetadata{}
- svc.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Service",
- })
- svcKey := client.ObjectKey{Namespace: testNamespaceOne, Name: "unknown"}
-
- By("verifying that an error is returned")
- err := informerCache.Get(context.Background(), svcKey, svc)
- Expect(err).To(HaveOccurred())
- Expect(apierrors.IsNotFound(err)).To(BeTrue())
- })
- It("should return an error if getting object in unwatched namespace", func() {
- By("getting a service that does not exists")
- svc := &corev1.Service{}
- svcKey := client.ObjectKey{Namespace: "unknown", Name: "unknown"}
-
- By("verifying that an error is returned")
- err := informerCache.Get(context.Background(), svcKey, svc)
- Expect(err).To(HaveOccurred())
- })
- })
- type selectorsTestCase struct {
- fieldSelectors map[string]string
- labelSelectors map[string]string
- expectedPods []string
- }
- DescribeTable(" and cache with selectors", func(tc selectorsTestCase) {
- By("creating the cache")
- builder := cache.BuilderWithOptions(
- cache.Options{
- SelectorsByObject: cache.SelectorsByObject{
- &corev1.Pod{}: {
- Label: labels.Set(tc.labelSelectors).AsSelector(),
- Field: fields.Set(tc.fieldSelectors).AsSelector(),
- },
- },
- },
- )
- informer, err := builder(cfg, cache.Options{})
- Expect(err).NotTo(HaveOccurred())
-
- By("running the cache and waiting for it to sync")
- go func() {
- defer GinkgoRecover()
- Expect(informer.Start(informerCacheCtx)).To(Succeed())
- }()
- Expect(informer.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
-
- By("Checking with structured")
- obtainedStructuredPodList := corev1.PodList{}
- Expect(informer.List(context.Background(), &obtainedStructuredPodList)).To(Succeed())
- Expect(obtainedStructuredPodList.Items).Should(WithTransform(func(pods []corev1.Pod) []string {
- obtainedPodNames := []string{}
- for _, pod := range pods {
- obtainedPodNames = append(obtainedPodNames, pod.Name)
- }
- return obtainedPodNames
- }, ConsistOf(tc.expectedPods)))
-
- By("Checking with unstructured")
- obtainedUnstructuredPodList := unstructured.UnstructuredList{}
- obtainedUnstructuredPodList.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "PodList",
- })
- err = informer.List(context.Background(), &obtainedUnstructuredPodList)
- Expect(err).To(Succeed())
- Expect(obtainedUnstructuredPodList.Items).Should(WithTransform(func(pods []unstructured.Unstructured) []string {
- obtainedPodNames := []string{}
- for _, pod := range pods {
- obtainedPodNames = append(obtainedPodNames, pod.GetName())
- }
- return obtainedPodNames
- }, ConsistOf(tc.expectedPods)))
-
- By("Checking with metadata")
- obtainedMetadataPodList := metav1.PartialObjectMetadataList{}
- obtainedMetadataPodList.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "PodList",
- })
- err = informer.List(context.Background(), &obtainedMetadataPodList)
- Expect(err).To(Succeed())
- Expect(obtainedMetadataPodList.Items).Should(WithTransform(func(pods []metav1.PartialObjectMetadata) []string {
- obtainedPodNames := []string{}
- for _, pod := range pods {
- obtainedPodNames = append(obtainedPodNames, pod.Name)
- }
- return obtainedPodNames
- }, ConsistOf(tc.expectedPods)))
- },
- Entry("when selectors are empty it has to inform about all the pods", selectorsTestCase{
- fieldSelectors: map[string]string{},
- labelSelectors: map[string]string{},
- expectedPods: []string{"test-pod-1", "test-pod-2", "test-pod-3", "test-pod-4", "test-pod-5", "test-pod-6"},
- }),
- Entry("when field matches one pod it has to inform about it", selectorsTestCase{
- fieldSelectors: map[string]string{"metadata.name": "test-pod-2"},
- expectedPods: []string{"test-pod-2"},
- }),
- Entry("when field matches multiple pods it has to inform about all of them", selectorsTestCase{
- fieldSelectors: map[string]string{"metadata.namespace": testNamespaceTwo},
- expectedPods: []string{"test-pod-2", "test-pod-3", "test-pod-6"},
- }),
- Entry("when label matches one pod it has to inform about it", selectorsTestCase{
- labelSelectors: map[string]string{"test-label": "test-pod-4"},
- expectedPods: []string{"test-pod-4"},
- }),
- Entry("when label matches multiple pods it has to inform about all of them", selectorsTestCase{
- labelSelectors: map[string]string{"common-label": "common"},
- expectedPods: []string{"test-pod-3", "test-pod-4"},
- }),
- Entry("when label and field matches one pod it has to inform about about it", selectorsTestCase{
- labelSelectors: map[string]string{"common-label": "common"},
- fieldSelectors: map[string]string{"metadata.namespace": testNamespaceTwo},
- expectedPods: []string{"test-pod-3"},
- }),
- Entry("when label does not match it does not has to inform", selectorsTestCase{
- labelSelectors: map[string]string{"new-label": "new"},
- expectedPods: []string{},
- }),
- Entry("when field does not match it does not has to inform", selectorsTestCase{
- fieldSelectors: map[string]string{"metadata.namespace": "new"},
- expectedPods: []string{},
- }),
- )
- })
- Describe("as an Informer", func() {
- Context("with structured objects", func() {
- It("should be able to get informer for the object", func() {
- By("getting a shared index informer for a pod")
- pod := &corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "informer-obj",
- Namespace: "default",
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Name: "nginx",
- Image: "nginx",
- },
- },
- },
- }
- sii, err := informerCache.GetInformer(context.TODO(), pod)
- Expect(err).NotTo(HaveOccurred())
- Expect(sii).NotTo(BeNil())
- Expect(sii.HasSynced()).To(BeTrue())
-
- By("adding an event handler listening for object creation which sends the object to a channel")
- out := make(chan interface{})
- addFunc := func(obj interface{}) {
- out <- obj
- }
- sii.AddEventHandler(kcache.ResourceEventHandlerFuncs{AddFunc: addFunc})
-
- By("adding an object")
- cl, err := client.New(cfg, client.Options{})
- Expect(err).NotTo(HaveOccurred())
- Expect(cl.Create(context.Background(), pod)).To(Succeed())
- defer deletePod(pod)
-
- By("verifying the object is received on the channel")
- Eventually(out).Should(Receive(Equal(pod)))
- })
- It("should be able to get an informer by group/version/kind", func() {
- By("getting an shared index informer for gvk = core/v1/pod")
- gvk := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}
- sii, err := informerCache.GetInformerForKind(context.TODO(), gvk)
- Expect(err).NotTo(HaveOccurred())
- Expect(sii).NotTo(BeNil())
- Expect(sii.HasSynced()).To(BeTrue())
-
- By("adding an event handler listening for object creation which sends the object to a channel")
- out := make(chan interface{})
- addFunc := func(obj interface{}) {
- out <- obj
- }
- sii.AddEventHandler(kcache.ResourceEventHandlerFuncs{AddFunc: addFunc})
-
- By("adding an object")
- cl, err := client.New(cfg, client.Options{})
- Expect(err).NotTo(HaveOccurred())
- pod := &corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "informer-gvk",
- Namespace: "default",
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Name: "nginx",
- Image: "nginx",
- },
- },
- },
- }
- Expect(cl.Create(context.Background(), pod)).To(Succeed())
- defer deletePod(pod)
-
- By("verifying the object is received on the channel")
- Eventually(out).Should(Receive(Equal(pod)))
- })
- It("should be able to index an object field then retrieve objects by that field", func() {
- By("creating the cache")
- informer, err := dynamiccache.New(cfg, cache.Options{})
- Expect(err).NotTo(HaveOccurred())
-
- By("indexing the restartPolicy field of the Pod object before starting")
- pod := &corev1.Pod{}
- indexFunc := func(obj client.Object) []string {
- return []string{string(obj.(*corev1.Pod).Spec.RestartPolicy)}
- }
- Expect(informer.IndexField(context.TODO(), pod, "spec.restartPolicy", indexFunc)).To(Succeed())
-
- By("running the cache and waiting for it to sync")
- go func() {
- defer GinkgoRecover()
- Expect(informer.Start(informerCacheCtx)).To(Succeed())
- }()
- Expect(informer.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
-
- By("listing Pods with restartPolicyOnFailure")
- listObj := &corev1.PodList{}
- Expect(informer.List(context.Background(), listObj,
- client.MatchingFields{"spec.restartPolicy": "OnFailure"})).To(Succeed())
- By("verifying that the returned pods have correct restart policy")
- Expect(listObj.Items).NotTo(BeEmpty())
- Expect(listObj.Items).Should(HaveLen(1))
- actual := listObj.Items[0]
- Expect(actual.Name).To(Equal("test-pod-3"))
- })
-
- It("should allow for get informer to be cancelled", func() {
- By("creating a context and cancelling it")
- informerCacheCancel()
-
- By("getting a shared index informer for a pod with a cancelled context")
- pod := &corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "informer-obj",
- Namespace: "default",
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Name: "nginx",
- Image: "nginx",
- },
- },
- },
- }
- sii, err := informerCache.GetInformer(informerCacheCtx, pod)
- Expect(err).To(HaveOccurred())
- Expect(sii).To(BeNil())
- Expect(apierrors.IsTimeout(err)).To(BeTrue())
- })
-
- It("should allow getting an informer by group/version/kind to be cancelled", func() {
- By("creating a context and cancelling it")
- informerCacheCancel()
-
- By("getting an shared index informer for gvk = core/v1/pod with a cancelled context")
- gvk := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}
- sii, err := informerCache.GetInformerForKind(informerCacheCtx, gvk)
- Expect(err).To(HaveOccurred())
- Expect(sii).To(BeNil())
- Expect(apierrors.IsTimeout(err)).To(BeTrue())
- })
- })
- Context("with unstructured objects", func() {
- It("should be able to get informer for the object", func() {
- By("getting a shared index informer for a pod")
-
- pod := &unstructured.Unstructured{
- Object: map[string]interface{}{
- "spec": map[string]interface{}{
- "containers": []map[string]interface{}{
- {
- "name": "nginx",
- "image": "nginx",
- },
- },
- },
- },
- }
- pod.SetName("informer-obj2")
- pod.SetNamespace("default")
- pod.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- })
- sii, err := informerCache.GetInformer(context.TODO(), pod)
- Expect(err).NotTo(HaveOccurred())
- Expect(sii).NotTo(BeNil())
- Expect(sii.HasSynced()).To(BeTrue())
-
- By("adding an event handler listening for object creation which sends the object to a channel")
- out := make(chan interface{})
- addFunc := func(obj interface{}) {
- out <- obj
- }
- sii.AddEventHandler(kcache.ResourceEventHandlerFuncs{AddFunc: addFunc})
-
- By("adding an object")
- cl, err := client.New(cfg, client.Options{})
- Expect(err).NotTo(HaveOccurred())
- Expect(cl.Create(context.Background(), pod)).To(Succeed())
- defer deletePod(pod)
-
- By("verifying the object is received on the channel")
- Eventually(out).Should(Receive(Equal(pod)))
- }, 3)
-
- It("should be able to index an object field then retrieve objects by that field", func() {
- By("creating the cache")
- informer, err := dynamiccache.New(cfg, cache.Options{})
- Expect(err).NotTo(HaveOccurred())
-
- By("indexing the restartPolicy field of the Pod object before starting")
- pod := &unstructured.Unstructured{}
- pod.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- })
- indexFunc := func(obj client.Object) []string {
- s, ok := obj.(*unstructured.Unstructured).Object["spec"]
- if !ok {
- return []string{}
- }
- m, ok := s.(map[string]interface{})
- if !ok {
- return []string{}
- }
- return []string{fmt.Sprintf("%v", m["restartPolicy"])}
- }
- Expect(informer.IndexField(context.TODO(), pod, "spec.restartPolicy", indexFunc)).To(Succeed())
-
- By("running the cache and waiting for it to sync")
- go func() {
- defer GinkgoRecover()
- Expect(informer.Start(informerCacheCtx)).To(Succeed())
- }()
- Expect(informer.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
-
- By("listing Pods with restartPolicyOnFailure")
- listObj := &unstructured.UnstructuredList{}
- listObj.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "PodList",
- })
- err = informer.List(context.Background(), listObj,
- client.MatchingFields{"spec.restartPolicy": "OnFailure"})
- Expect(err).To(Succeed())
-
- By("verifying that the returned pods have correct restart policy")
- Expect(listObj.Items).NotTo(BeEmpty())
- Expect(listObj.Items).Should(HaveLen(1))
- actual := listObj.Items[0]
- Expect(actual.GetName()).To(Equal("test-pod-3"))
- }, 3)
-
- It("should allow for get informer to be cancelled", func() {
- By("cancelling the context")
- informerCacheCancel()
-
- By("getting a shared index informer for a pod with a cancelled context")
- pod := &unstructured.Unstructured{}
- pod.SetName("informer-obj2")
- pod.SetNamespace("default")
- pod.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- })
- sii, err := informerCache.GetInformer(informerCacheCtx, pod)
- Expect(err).To(HaveOccurred())
- Expect(sii).To(BeNil())
- Expect(apierrors.IsTimeout(err)).To(BeTrue())
- })
- })
- Context("with metadata-only objects", func() {
- It("should be able to get informer for the object", func() {
- By("getting a shared index informer for a pod")
-
- pod := &corev1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "informer-obj",
- Namespace: "default",
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Name: "nginx",
- Image: "nginx",
- },
- },
- },
- }
-
- podMeta := &metav1.PartialObjectMetadata{}
- pod.ObjectMeta.DeepCopyInto(&podMeta.ObjectMeta)
- podMeta.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- })
-
- sii, err := informerCache.GetInformer(context.TODO(), podMeta)
- Expect(err).NotTo(HaveOccurred())
- Expect(sii).NotTo(BeNil())
- Expect(sii.HasSynced()).To(BeTrue())
-
- By("adding an event handler listening for object creation which sends the object to a channel")
- out := make(chan interface{})
- addFunc := func(obj interface{}) {
- out <- obj
- }
- sii.AddEventHandler(kcache.ResourceEventHandlerFuncs{AddFunc: addFunc})
-
- By("adding an object")
- cl, err := client.New(cfg, client.Options{})
- Expect(err).NotTo(HaveOccurred())
- Expect(cl.Create(context.Background(), pod)).To(Succeed())
- defer deletePod(pod)
- // re-copy the result in so that we can match on it properly
- pod.ObjectMeta.DeepCopyInto(&podMeta.ObjectMeta)
-
- By("verifying the object's metadata is received on the channel")
- Eventually(out).Should(Receive(Equal(podMeta)))
- }, 3)
-
- It("should be able to index an object field then retrieve objects by that field", func() {
- By("creating the cache")
- informer, err := dynamiccache.New(cfg, cache.Options{})
- Expect(err).NotTo(HaveOccurred())
-
- By("indexing the restartPolicy field of the Pod object before starting")
- pod := &metav1.PartialObjectMetadata{}
- pod.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- })
- indexFunc := func(obj client.Object) []string {
- metadata := obj.(*metav1.PartialObjectMetadata)
- return []string{metadata.Labels["test-label"]}
- }
- Expect(informer.IndexField(context.TODO(), pod, "metadata.labels.test-label", indexFunc)).To(Succeed())
-
- By("running the cache and waiting for it to sync")
- go func() {
- defer GinkgoRecover()
- Expect(informer.Start(informerCacheCtx)).To(Succeed())
- }()
- Expect(informer.WaitForCacheSync(informerCacheCtx)).NotTo(BeFalse())
-
- By("listing Pods with restartPolicyOnFailure")
- listObj := &metav1.PartialObjectMetadataList{}
- gvk := schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "PodList",
- }
- listObj.SetGroupVersionKind(gvk)
- err = informer.List(context.Background(), listObj,
- client.MatchingFields{"metadata.labels.test-label": "test-pod-3"})
- Expect(err).To(Succeed())
-
- By("verifying that the GVK has been preserved for the list object")
- Expect(listObj.GroupVersionKind()).To(Equal(gvk))
-
- By("verifying that the returned pods have correct restart policy")
- Expect(listObj.Items).NotTo(BeEmpty())
- Expect(listObj.Items).Should(HaveLen(1))
- actual := listObj.Items[0]
- Expect(actual.GetName()).To(Equal("test-pod-3"))
-
- By("verifying that the GVK has been preserved for the item in the list")
- Expect(actual.GroupVersionKind()).To(Equal(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- }))
- }, 3)
-
- It("should allow for get informer to be cancelled", func() {
- By("creating a context and cancelling it")
- ctx, cancel := context.WithCancel(context.Background())
- cancel()
-
- By("getting a shared index informer for a pod with a cancelled context")
- pod := &metav1.PartialObjectMetadata{}
- pod.SetName("informer-obj2")
- pod.SetNamespace("default")
- pod.SetGroupVersionKind(schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Pod",
- })
- sii, err := informerCache.GetInformer(ctx, pod)
- Expect(err).To(HaveOccurred())
- Expect(sii).To(BeNil())
- Expect(apierrors.IsTimeout(err)).To(BeTrue())
- })
- })
- })
- })
-}
-
-// ensureNamespace installs namespace of a given name if not exists.
-func ensureNamespace(namespace string, client client.Client) error {
- ns := corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{
- Name: namespace,
- },
- TypeMeta: metav1.TypeMeta{
- Kind: "Namespace",
- APIVersion: "v1",
- },
- }
- err := client.Create(context.TODO(), &ns)
- if apierrors.IsAlreadyExists(err) {
- return nil
- }
- return err
-}
-
-func ensureNode(name string, client client.Client) error {
- node := corev1.Node{
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- },
- TypeMeta: metav1.TypeMeta{
- Kind: "Node",
- APIVersion: "v1",
- },
- }
- err := client.Create(context.TODO(), &node)
- if apierrors.IsAlreadyExists(err) {
- return nil
- }
- return err
-}
-
-//nolint:interfacer
-func isKubeService(svc metav1.Object) bool {
- // grumble grumble linters grumble grumble
- return svc.GetNamespace() == "default" && svc.GetName() == "kubernetes"
-}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/doc.go
deleted file mode 100644
index 89413c04cd8..00000000000
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/doc.go
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
-Copyright 2019 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
-// Package cache provides object caches that act as caching client.Reader
-// instances and help drive Kubernetes-object-based event handlers.
-// The code is forked from controller-runtime's cache package and has been
-// modified to support dynamic addition and removal of informers.
-package dynamiccache
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/informer_cache.go b/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/informer_cache.go
deleted file mode 100644
index 2360cfbdbcd..00000000000
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/informer_cache.go
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
-package dynamiccache
-
-import (
- "context"
- "fmt"
- "reflect"
- "strings"
-
- "github.com/open-policy-agent/gatekeeper/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal"
- apierrors "k8s.io/apimachinery/pkg/api/errors"
- apimeta "k8s.io/apimachinery/pkg/api/meta"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/runtime/schema"
- toolscache "k8s.io/client-go/tools/cache"
- "sigs.k8s.io/controller-runtime/pkg/cache"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
-)
-
-var (
- _ cache.Informers = &dynamicInformerCache{}
- _ client.Reader = &dynamicInformerCache{}
- _ cache.Cache = &dynamicInformerCache{}
-)
-
-// ErrCacheNotStarted is returned when trying to read from the cache that wasn't started.
-type ErrCacheNotStarted struct{}
-
-func (*ErrCacheNotStarted) Error() string {
- return "the cache is not started, can not read objects"
-}
-
-// dynamicInformerCache is a Kubernetes Object cache populated from InformersMap. dynamicInformerCache wraps an InformersMap.
-type dynamicInformerCache struct {
- *internal.InformersMap
-}
-
-// Get implements Reader.
-func (ip *dynamicInformerCache) Get(ctx context.Context, key client.ObjectKey, out client.Object) error {
- gvk, err := apiutil.GVKForObject(out, ip.Scheme)
- if err != nil {
- return err
- }
-
- started, cache, err := ip.InformersMap.Get(ctx, gvk, out)
- if err != nil {
- return err
- }
-
- if !started {
- return &ErrCacheNotStarted{}
- }
- return cache.Reader.Get(ctx, key, out)
-}
-
-// List implements Reader.
-func (ip *dynamicInformerCache) List(ctx context.Context, out client.ObjectList, opts ...client.ListOption) error {
- gvk, cacheTypeObj, err := ip.objectTypeForListObject(out)
- if err != nil {
- return err
- }
-
- started, cache, err := ip.InformersMap.Get(ctx, *gvk, cacheTypeObj)
- if err != nil {
- return err
- }
-
- if !started {
- return &ErrCacheNotStarted{}
- }
-
- return cache.Reader.List(ctx, out, opts...)
-}
-
-// objectTypeForListObject tries to find the runtime.Object and associated GVK
-// for a single object corresponding to the passed-in list type. We need them
-// because they are used as cache map key.
-func (ip *dynamicInformerCache) objectTypeForListObject(list client.ObjectList) (*schema.GroupVersionKind, runtime.Object, error) {
- gvk, err := apiutil.GVKForObject(list, ip.Scheme)
- if err != nil {
- return nil, nil, err
- }
-
- if !strings.HasSuffix(gvk.Kind, "List") {
- return nil, nil, fmt.Errorf("non-list type %T (kind %q) passed as output", list, gvk)
- }
- // we need the non-list GVK, so chop off the "List" from the end of the kind
- gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
- _, isUnstructured := list.(*unstructured.UnstructuredList)
- var cacheTypeObj runtime.Object
- if isUnstructured {
- u := &unstructured.Unstructured{}
- u.SetGroupVersionKind(gvk)
- cacheTypeObj = u
- } else {
- itemsPtr, err := apimeta.GetItemsPtr(list)
- if err != nil {
- return nil, nil, err
- }
- // http://knowyourmeme.com/memes/this-is-fine
- elemType := reflect.Indirect(reflect.ValueOf(itemsPtr)).Type().Elem()
- if elemType.Kind() != reflect.Ptr {
- elemType = reflect.PtrTo(elemType)
- }
-
- cacheTypeValue := reflect.Zero(elemType)
- var ok bool
- cacheTypeObj, ok = cacheTypeValue.Interface().(runtime.Object)
- if !ok {
- return nil, nil, fmt.Errorf("cannot get cache for %T, its element %T is not a runtime.Object", list, cacheTypeValue.Interface())
- }
- }
-
- return &gvk, cacheTypeObj, nil
-}
-
-// GetInformerForKind returns the informer for the GroupVersionKind.
-func (ip *dynamicInformerCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (cache.Informer, error) {
- // Map the gvk to an object
- obj, err := ip.Scheme.New(gvk)
- if err != nil {
- return nil, err
- }
-
- _, i, err := ip.InformersMap.Get(ctx, gvk, obj)
- if err != nil {
- return nil, err
- }
- return i.Informer, err
-}
-
-// GetInformer returns the informer for the obj.
-func (ip *dynamicInformerCache) GetInformer(ctx context.Context, obj client.Object) (cache.Informer, error) {
- gvk, err := apiutil.GVKForObject(obj, ip.Scheme)
- if err != nil {
- return nil, err
- }
-
- _, i, err := ip.InformersMap.Get(ctx, gvk, obj)
- if err != nil {
- return nil, err
- }
- return i.Informer, err
-}
-
-// GetInformerNonBlocking returns the informer for the obj without waiting for its cache to sync.
-func (ip *dynamicInformerCache) GetInformerNonBlocking(obj client.Object) (cache.Informer, error) {
- gvk, err := apiutil.GVKForObject(obj, ip.Scheme)
- if err != nil {
- return nil, err
- }
-
- // Use a canceled context to signal non-blocking
- ctx, cancel := context.WithCancel(context.Background())
- cancel()
-
- _, i, err := ip.InformersMap.Get(ctx, gvk, obj)
- if err != nil && !apierrors.IsTimeout(err) {
- return nil, err
- }
- return i.Informer, nil
-}
-
-// NeedLeaderElection implements the LeaderElectionRunnable interface
-// to indicate that this can be started without requiring the leader lock.
-func (ip *dynamicInformerCache) NeedLeaderElection() bool {
- return false
-}
-
-// IndexField adds an indexer to the underlying cache, using extraction function to get
-// value(s) from the given field. This index can then be used by passing a field selector
-// to List. For one-to-one compatibility with "normal" field selectors, only return one value.
-// The values may be anything. They will automatically be prefixed with the namespace of the
-// given object, if present. The objects passed are guaranteed to be objects of the correct type.
-func (ip *dynamicInformerCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error {
- informer, err := ip.GetInformer(ctx, obj)
- if err != nil {
- return err
- }
- return indexByField(informer, field, extractValue)
-}
-
-func indexByField(indexer cache.Informer, field string, extractor client.IndexerFunc) error {
- indexFunc := func(objRaw interface{}) ([]string, error) {
- // TODO(directxman12): check if this is the correct type?
- obj, isObj := objRaw.(client.Object)
- if !isObj {
- return nil, fmt.Errorf("object of type %T is not an Object", objRaw)
- }
- meta, err := apimeta.Accessor(obj)
- if err != nil {
- return nil, err
- }
- ns := meta.GetNamespace()
-
- rawVals := extractor(obj)
- var vals []string
- if ns == "" {
- // if we're not doubling the keys for the namespaced case, just re-use what was returned to us
- vals = rawVals
- } else {
- // if we need to add non-namespaced versions too, double the length
- vals = make([]string, len(rawVals)*2)
- }
- for i, rawVal := range rawVals {
- // save a namespaced variant, so that we can ask
- // "what are all the object matching a given index *in a given namespace*"
- vals[i] = internal.KeyToNamespacedKey(ns, rawVal)
- if ns != "" {
- // if we have a namespace, also inject a special index key for listing
- // regardless of the object namespace
- vals[i+len(rawVals)] = internal.KeyToNamespacedKey("", rawVal)
- }
- }
-
- return vals, nil
- }
-
- return indexer.AddIndexers(toolscache.Indexers{internal.FieldIndexName(field): indexFunc})
-}
-
-// Remove removes an informer specified by the obj argument from the cache and stops it if it existed.
-func (ip *dynamicInformerCache) Remove(obj client.Object) error {
- gvk, err := apiutil.GVKForObject(obj, ip.Scheme)
- if err != nil {
- return err
- }
-
- ip.InformersMap.Remove(gvk, obj)
- return nil
-}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/informer_cache_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/informer_cache_test.go
deleted file mode 100644
index d9d2de872e8..00000000000
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/informer_cache_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-Copyright 2021 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
-package dynamiccache_test
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "k8s.io/client-go/rest"
-
- "github.com/open-policy-agent/gatekeeper/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache"
- "sigs.k8s.io/controller-runtime/pkg/cache"
- "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
- "sigs.k8s.io/controller-runtime/pkg/manager"
-)
-
-var _ = Describe("dynamicInformerCache", func() {
- It("should not require LeaderElection", func() {
- cfg := &rest.Config{}
-
- mapper, err := apiutil.NewDynamicRESTMapper(cfg, apiutil.WithLazyDiscovery)
- Expect(err).ToNot(HaveOccurred())
-
- c, err := dynamiccache.New(cfg, cache.Options{Mapper: mapper})
- Expect(err).ToNot(HaveOccurred())
-
- leaderElectionRunnable, ok := c.(manager.LeaderElectionRunnable)
- Expect(ok).To(BeTrue())
- Expect(leaderElectionRunnable.NeedLeaderElection()).To(BeFalse())
- })
-})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/deleg_map.go b/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/deleg_map.go
deleted file mode 100644
index 1f1a01f0596..00000000000
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/deleg_map.go
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
-package internal
-
-import (
- "context"
- "time"
-
- "k8s.io/apimachinery/pkg/api/meta"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/client-go/rest"
- "k8s.io/client-go/tools/cache"
-)
-
-// InformersMap create and caches Informers for (runtime.Object, schema.GroupVersionKind) pairs.
-// It uses a standard parameter codec constructed based on the given generated Scheme.
-type InformersMap struct {
- // we abstract over the details of structured/unstructured/metadata with the specificInformerMaps
- // TODO(directxman12): genericize this over different projections now that we have 3 different maps
-
- structured *specificInformersMap
- unstructured *specificInformersMap
- metadata *specificInformersMap
-
- // Scheme maps runtime.Objects to GroupVersionKinds
- Scheme *runtime.Scheme
-}
-
-// NewInformersMap creates a new InformersMap that can create informers for
-// both structured and unstructured objects.
-func NewInformersMap(config *rest.Config,
- scheme *runtime.Scheme,
- mapper meta.RESTMapper,
- resync time.Duration,
- namespace string,
- selectors SelectorsByGVK,
-) *InformersMap {
- return &InformersMap{
- structured: newStructuredInformersMap(config, scheme, mapper, resync, namespace, selectors),
- unstructured: newUnstructuredInformersMap(config, scheme, mapper, resync, namespace, selectors),
- metadata: newMetadataInformersMap(config, scheme, mapper, resync, namespace, selectors),
-
- Scheme: scheme,
- }
-}
-
-// Start calls Run on each of the informers and sets started to true. Blocks on the context.
-func (m *InformersMap) Start(ctx context.Context) error {
- go m.structured.Start(ctx)
- go m.unstructured.Start(ctx)
- go m.metadata.Start(ctx)
- <-ctx.Done()
- return nil
-}
-
-// WaitForCacheSync waits until all the caches have been started and synced.
-func (m *InformersMap) WaitForCacheSync(ctx context.Context) bool {
- syncedFuncs := append([]cache.InformerSynced(nil), m.structured.HasSyncedFuncs()...)
- syncedFuncs = append(syncedFuncs, m.unstructured.HasSyncedFuncs()...)
- syncedFuncs = append(syncedFuncs, m.metadata.HasSyncedFuncs()...)
-
- if !m.structured.waitForStarted(ctx) {
- return false
- }
- if !m.unstructured.waitForStarted(ctx) {
- return false
- }
- if !m.metadata.waitForStarted(ctx) {
- return false
- }
- return cache.WaitForCacheSync(ctx.Done(), syncedFuncs...)
-}
-
-// Get will create a new Informer and add it to the map of InformersMap if none exists. Returns
-// the Informer from the map.
-func (m *InformersMap) Get(ctx context.Context, gvk schema.GroupVersionKind, obj runtime.Object) (bool, *MapEntry, error) {
- switch obj.(type) {
- case *unstructured.Unstructured:
- return m.unstructured.Get(ctx, gvk, obj)
- case *unstructured.UnstructuredList:
- return m.unstructured.Get(ctx, gvk, obj)
- case *metav1.PartialObjectMetadata:
- return m.metadata.Get(ctx, gvk, obj)
- case *metav1.PartialObjectMetadataList:
- return m.metadata.Get(ctx, gvk, obj)
- default:
- return m.structured.Get(ctx, gvk, obj)
- }
-}
-
-// Remove will remove an new Informer from the InformersMap and stop it if it exists.
-func (m *InformersMap) Remove(gvk schema.GroupVersionKind, obj runtime.Object) {
- switch obj.(type) {
- case *unstructured.Unstructured:
- m.unstructured.Remove(gvk)
- case *unstructured.UnstructuredList:
- m.unstructured.Remove(gvk)
- case *metav1.PartialObjectMetadata:
- m.metadata.Remove(gvk)
- case *metav1.PartialObjectMetadataList:
- m.metadata.Remove(gvk)
- default:
- m.structured.Remove(gvk)
- }
-}
-
-// newStructuredInformersMap creates a new InformersMap for structured objects.
-func newStructuredInformersMap(config *rest.Config, scheme *runtime.Scheme, mapper meta.RESTMapper, resync time.Duration,
- namespace string, selectors SelectorsByGVK) *specificInformersMap {
- return newSpecificInformersMap(config, scheme, mapper, resync, namespace, selectors, createStructuredListWatch)
-}
-
-// newUnstructuredInformersMap creates a new InformersMap for unstructured objects.
-func newUnstructuredInformersMap(config *rest.Config, scheme *runtime.Scheme, mapper meta.RESTMapper, resync time.Duration,
- namespace string, selectors SelectorsByGVK) *specificInformersMap {
- return newSpecificInformersMap(config, scheme, mapper, resync, namespace, selectors, createUnstructuredListWatch)
-}
-
-// newMetadataInformersMap creates a new InformersMap for metadata-only objects.
-func newMetadataInformersMap(config *rest.Config, scheme *runtime.Scheme, mapper meta.RESTMapper, resync time.Duration,
- namespace string, selectors SelectorsByGVK) *specificInformersMap {
- return newSpecificInformersMap(config, scheme, mapper, resync, namespace, selectors, createMetadataListWatch)
-}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/informers_map.go b/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/informers_map.go
deleted file mode 100644
index 3a3fd53e5b8..00000000000
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/informers_map.go
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
-package internal
-
-import (
- "context"
- "fmt"
- "math/rand"
- "sync"
- "time"
-
- apierrors "k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/api/meta"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/apimachinery/pkg/runtime/serializer"
- "k8s.io/apimachinery/pkg/watch"
- "k8s.io/client-go/dynamic"
- "k8s.io/client-go/metadata"
- "k8s.io/client-go/rest"
- "k8s.io/client-go/tools/cache"
- "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
-)
-
-func init() {
- rand.Seed(time.Now().UnixNano())
-}
-
-// clientListWatcherFunc knows how to create a ListWatcher.
-type createListWatcherFunc func(gvk schema.GroupVersionKind, ip *specificInformersMap) (*cache.ListWatch, error)
-
-// newSpecificInformersMap returns a new specificInformersMap (like
-// the generical InformersMap, except that it doesn't implement WaitForCacheSync).
-func newSpecificInformersMap(config *rest.Config,
- scheme *runtime.Scheme,
- mapper meta.RESTMapper,
- resync time.Duration,
- namespace string,
- selectors SelectorsByGVK,
- createListWatcher createListWatcherFunc) *specificInformersMap {
- ip := &specificInformersMap{
- config: config,
- Scheme: scheme,
- mapper: mapper,
- informersByGVK: make(map[schema.GroupVersionKind]*MapEntry),
- codecs: serializer.NewCodecFactory(scheme),
- paramCodec: runtime.NewParameterCodec(scheme),
- resync: resync,
- startWait: make(chan struct{}),
- createListWatcher: createListWatcher,
- namespace: namespace,
- selectors: selectors,
- }
- return ip
-}
-
-// MapEntry contains the cached data for an Informer.
-type MapEntry struct {
- // Informer is the cached informer
- Informer cache.SharedIndexInformer
-
- // CacheReader wraps Informer and implements the CacheReader interface for a single type
- Reader CacheReader
-
- // Stop can be used to stop this individual informer without stopping the entire specificInformersMap.
- stop chan struct{}
-}
-
-// specificInformersMap create and caches Informers for (runtime.Object, schema.GroupVersionKind) pairs.
-// It uses a standard parameter codec constructed based on the given generated Scheme.
-type specificInformersMap struct {
- // Scheme maps runtime.Objects to GroupVersionKinds
- Scheme *runtime.Scheme
-
- // config is used to talk to the apiserver
- config *rest.Config
-
- // mapper maps GroupVersionKinds to Resources
- mapper meta.RESTMapper
-
- // informersByGVK is the cache of informers keyed by groupVersionKind
- informersByGVK map[schema.GroupVersionKind]*MapEntry
-
- // codecs is used to create a new REST client
- codecs serializer.CodecFactory
-
- // paramCodec is used by list and watch
- paramCodec runtime.ParameterCodec
-
- // stop is the stop channel to stop informers
- stop <-chan struct{}
-
- // resync is the base frequency the informers are resynced
- // a 10 percent jitter will be added to the resync period between informers
- // so that all informers will not send list requests simultaneously.
- resync time.Duration
-
- // mu guards access to the map
- mu sync.RWMutex
-
- // start is true if the informers have been started
- started bool
-
- // startWait is a channel that is closed after the
- // informer has been started.
- startWait chan struct{}
-
- // createClient knows how to create a client and a list object,
- // and allows for abstracting over the particulars of structured vs
- // unstructured objects.
- createListWatcher createListWatcherFunc
-
- // namespace is the namespace that all ListWatches are restricted to
- // default or empty string means all namespaces
- namespace string
-
- // selectors are the label or field selectors that will be added to the
- // ListWatch ListOptions.
- selectors SelectorsByGVK
-}
-
-// Start starts the informer managed by a MapEntry.
-// Blocks until the informer stops. The informer can be stopped
-// either individually (via the entry's stop channel) or globally
-// via the provided stop argument.
-func (e *MapEntry) Start(stop <-chan struct{}) {
- // Stop on either the whole map stopping or just this informer being removed.
- internalStop, cancel := eitherChan(stop, e.stop)
- defer cancel()
- e.Informer.Run(internalStop)
-}
-
-// Start calls Run on each of the informers and sets started to true. Blocks on the context.
-// It doesn't return start because it can't return an error, and it's not a runnable directly.
-func (ip *specificInformersMap) Start(ctx context.Context) {
- func() {
- ip.mu.Lock()
- defer ip.mu.Unlock()
-
- // Set the stop channel so it can be passed to informers that are added later
- ip.stop = ctx.Done()
-
- // Start each informer
- for _, entry := range ip.informersByGVK {
- go entry.Start(ctx.Done())
- }
-
- // Set started to true so we immediately start any informers added later.
- ip.started = true
- close(ip.startWait)
- }()
- <-ctx.Done()
-}
-
-func (ip *specificInformersMap) waitForStarted(ctx context.Context) bool {
- select {
- case <-ip.startWait:
- return true
- case <-ctx.Done():
- return false
- }
-}
-
-// HasSyncedFuncs returns all the HasSynced functions for the informers in this map.
-func (ip *specificInformersMap) HasSyncedFuncs() []cache.InformerSynced {
- ip.mu.RLock()
- defer ip.mu.RUnlock()
- syncedFuncs := make([]cache.InformerSynced, 0, len(ip.informersByGVK))
- for _, informer := range ip.informersByGVK {
- syncedFuncs = append(syncedFuncs, informer.Informer.HasSynced)
- }
- return syncedFuncs
-}
-
-// Get will create a new Informer and add it to the map of specificInformersMap if none exists. Returns
-// the Informer from the map.
-func (ip *specificInformersMap) Get(ctx context.Context, gvk schema.GroupVersionKind, obj runtime.Object) (bool, *MapEntry, error) {
- // Return the informer if it is found
- i, started, ok := func() (*MapEntry, bool, bool) {
- ip.mu.RLock()
- defer ip.mu.RUnlock()
- i, ok := ip.informersByGVK[gvk]
- return i, ip.started, ok
- }()
-
- if !ok {
- var err error
- if i, started, err = ip.addInformerToMap(gvk, obj); err != nil {
- return started, nil, err
- }
- }
-
- if started && !i.Informer.HasSynced() {
- // Wait for it to sync before returning the Informer so that folks don't read from a stale cache.
- // Cancel for context, informer stopping, or entire map stopping.
- syncStop, cancel := mergeChan(ctx.Done(), i.stop, ip.stop)
- defer cancel()
- if !cache.WaitForCacheSync(syncStop, i.Informer.HasSynced) {
- // Return entry even on timeout - caller may have intended a non-blocking fetch.
- return started, i, apierrors.NewTimeoutError(fmt.Sprintf("failed waiting for %T Informer to sync", obj), 0)
- }
- }
-
- return started, i, nil
-}
-
-func (ip *specificInformersMap) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.Object) (*MapEntry, bool, error) {
- ip.mu.Lock()
- defer ip.mu.Unlock()
-
- // Check the cache to see if we already have an Informer. If we do, return the Informer.
- // This is for the case where 2 routines tried to get the informer when it wasn't in the map
- // so neither returned early, but the first one created it.
- if i, ok := ip.informersByGVK[gvk]; ok {
- return i, ip.started, nil
- }
-
- // Create a NewSharedIndexInformer and add it to the map.
- var lw *cache.ListWatch
- lw, err := ip.createListWatcher(gvk, ip)
- if err != nil {
- return nil, false, err
- }
- ni := cache.NewSharedIndexInformer(lw, obj, resyncPeriod(ip.resync)(), cache.Indexers{
- cache.NamespaceIndex: cache.MetaNamespaceIndexFunc,
- })
- rm, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
- if err != nil {
- return nil, false, err
- }
-
- switch obj.(type) {
- case *metav1.PartialObjectMetadata, *metav1.PartialObjectMetadataList:
- ni = metadataSharedIndexInformerPreserveGVK(gvk, ni)
- default:
- }
-
- i := &MapEntry{
- Informer: ni,
- Reader: CacheReader{indexer: ni.GetIndexer(), groupVersionKind: gvk, scopeName: rm.Scope.Name()},
- stop: make(chan struct{}),
- }
- ip.informersByGVK[gvk] = i
-
- // Start the Informer if need by
- // TODO(seans): write thorough tests and document what happens here - can you add indexers?
- // can you add eventhandlers?
- if ip.started {
- go i.Start(ip.stop)
- }
- return i, ip.started, nil
-}
-
-// Remove removes an informer entry and stops it if it was running.
-func (ip *specificInformersMap) Remove(gvk schema.GroupVersionKind) {
- ip.mu.Lock()
- defer ip.mu.Unlock()
-
- entry, ok := ip.informersByGVK[gvk]
- if !ok {
- return
- }
- close(entry.stop)
- delete(ip.informersByGVK, gvk)
-}
-
-// newListWatch returns a new ListWatch object that can be used to create a SharedIndexInformer.
-func createStructuredListWatch(gvk schema.GroupVersionKind, ip *specificInformersMap) (*cache.ListWatch, error) {
- // Kubernetes APIs work against Resources, not GroupVersionKinds. Map the
- // groupVersionKind to the Resource API we will use.
- mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
- if err != nil {
- return nil, err
- }
-
- client, err := apiutil.RESTClientForGVK(gvk, false, ip.config, ip.codecs)
- if err != nil {
- return nil, err
- }
- listGVK := gvk.GroupVersion().WithKind(gvk.Kind + "List")
- listObj, err := ip.Scheme.New(listGVK)
- if err != nil {
- return nil, err
- }
-
- // TODO: the functions that make use of this ListWatch should be adapted to
- // pass in their own contexts instead of relying on this fixed one here.
- ctx := context.TODO()
- // Create a new ListWatch for the obj
- return &cache.ListWatch{
- ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
- ip.selectors[gvk].ApplyToList(&opts)
- res := listObj.DeepCopyObject()
- isNamespaceScoped := ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot
- err := client.Get().NamespaceIfScoped(ip.namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Do(ctx).Into(res)
- return res, err
- },
- // Setup the watch function
- WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
- ip.selectors[gvk].ApplyToList(&opts)
- // Watch needs to be set to true separately
- opts.Watch = true
- isNamespaceScoped := ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot
- return client.Get().NamespaceIfScoped(ip.namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Watch(ctx)
- },
- }, nil
-}
-
-func createUnstructuredListWatch(gvk schema.GroupVersionKind, ip *specificInformersMap) (*cache.ListWatch, error) {
- // Kubernetes APIs work against Resources, not GroupVersionKinds. Map the
- // groupVersionKind to the Resource API we will use.
- mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
- if err != nil {
- return nil, err
- }
-
- // If the rest configuration has a negotiated serializer passed in,
- // we should remove it and use the one that the dynamic client sets for us.
- cfg := rest.CopyConfig(ip.config)
- cfg.NegotiatedSerializer = nil
- dynamicClient, err := dynamic.NewForConfig(cfg)
- if err != nil {
- return nil, err
- }
-
- // TODO: the functions that make use of this ListWatch should be adapted to
- // pass in their own contexts instead of relying on this fixed one here.
- ctx := context.TODO()
- // Create a new ListWatch for the obj
- return &cache.ListWatch{
- ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
- ip.selectors[gvk].ApplyToList(&opts)
- if ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
- return dynamicClient.Resource(mapping.Resource).Namespace(ip.namespace).List(ctx, opts)
- }
- return dynamicClient.Resource(mapping.Resource).List(ctx, opts)
- },
- // Setup the watch function
- WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
- ip.selectors[gvk].ApplyToList(&opts)
- // Watch needs to be set to true separately
- opts.Watch = true
- if ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
- return dynamicClient.Resource(mapping.Resource).Namespace(ip.namespace).Watch(ctx, opts)
- }
- return dynamicClient.Resource(mapping.Resource).Watch(ctx, opts)
- },
- }, nil
-}
-
-func createMetadataListWatch(gvk schema.GroupVersionKind, ip *specificInformersMap) (*cache.ListWatch, error) {
- // Kubernetes APIs work against Resources, not GroupVersionKinds. Map the
- // groupVersionKind to the Resource API we will use.
- mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
- if err != nil {
- return nil, err
- }
-
- // Always clear the negotiated serializer and use the one
- // set from the metadata client.
- cfg := rest.CopyConfig(ip.config)
- cfg.NegotiatedSerializer = nil
-
- // grab the metadata client
- client, err := metadata.NewForConfig(cfg)
- if err != nil {
- return nil, err
- }
-
- // TODO: the functions that make use of this ListWatch should be adapted to
- // pass in their own contexts instead of relying on this fixed one here.
- ctx := context.TODO()
-
- // create the relevant listwatch
- return &cache.ListWatch{
- ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
- ip.selectors[gvk].ApplyToList(&opts)
- if ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
- return client.Resource(mapping.Resource).Namespace(ip.namespace).List(ctx, opts)
- }
- return client.Resource(mapping.Resource).List(ctx, opts)
- },
- // Setup the watch function
- WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
- ip.selectors[gvk].ApplyToList(&opts)
- // Watch needs to be set to true separately
- opts.Watch = true
- if ip.namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
- return client.Resource(mapping.Resource).Namespace(ip.namespace).Watch(ctx, opts)
- }
- return client.Resource(mapping.Resource).Watch(ctx, opts)
- },
- }, nil
-}
-
-// resyncPeriod returns a function which generates a duration each time it is
-// invoked; this is so that multiple controllers don't get into lock-step and all
-// hammer the apiserver with list requests simultaneously.
-func resyncPeriod(resync time.Duration) func() time.Duration {
- return func() time.Duration {
- /* #nosec */
- // using math/rand insted of crypto/rand will cause G404 issue while using gosec
- // the factor will fall into [0.9, 1.1)
- factor := rand.Float64()/5.0 + 0.9 //nolint:gosec
- return time.Duration(float64(resync.Nanoseconds()) * factor)
- }
-}
-
-// eitherChan returns a channel that is closed when either of the input channels are signaled.
-// The caller must call the returned CancelFunc to ensure no resources are leaked.
-func eitherChan(a, b <-chan struct{}) (<-chan struct{}, context.CancelFunc) {
- var once sync.Once
- out := make(chan struct{})
- cancel := make(chan struct{})
- cancelFunc := func() {
- once.Do(func() {
- close(cancel)
- })
- }
- go func() {
- defer close(out)
- select {
- case <-a:
- case <-b:
- case <-cancel:
- }
- }()
-
- return out, cancelFunc
-}
-
-// mergeChan returns a channel that is closed when any of the input channels are signaled.
-// The caller must call the returned CancelFunc to ensure no resources are leaked.
-func mergeChan(a, b, c <-chan struct{}) (<-chan struct{}, context.CancelFunc) {
- var once sync.Once
- out := make(chan struct{})
- cancel := make(chan struct{})
- cancelFunc := func() {
- once.Do(func() {
- close(cancel)
- })
- }
- go func() {
- defer close(out)
- select {
- case <-a:
- case <-b:
- case <-c:
- case <-cancel:
- }
- }()
-
- return out, cancelFunc
-}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/metadata_infomer_wrapper.go b/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/metadata_infomer_wrapper.go
deleted file mode 100644
index f7fdb963a1c..00000000000
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/internal/metadata_infomer_wrapper.go
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-Copyright 2021 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
-package internal
-
-import (
- "time"
-
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/client-go/tools/cache"
-)
-
-func metadataSharedIndexInformerPreserveGVK(gvk schema.GroupVersionKind, si cache.SharedIndexInformer) cache.SharedIndexInformer {
- return &sharedInformerWrapper{
- gvk: gvk,
- SharedIndexInformer: si,
- }
-}
-
-type sharedInformerWrapper struct {
- gvk schema.GroupVersionKind
- cache.SharedIndexInformer
-}
-
-func (s *sharedInformerWrapper) AddEventHandler(handler cache.ResourceEventHandler) {
- s.SharedIndexInformer.AddEventHandler(&handlerPreserveGVK{s.gvk, handler})
-}
-
-func (s *sharedInformerWrapper) AddEventHandlerWithResyncPeriod(handler cache.ResourceEventHandler, resyncPeriod time.Duration) {
- s.SharedIndexInformer.AddEventHandlerWithResyncPeriod(&handlerPreserveGVK{s.gvk, handler}, resyncPeriod)
-}
-
-type handlerPreserveGVK struct {
- gvk schema.GroupVersionKind
- cache.ResourceEventHandler
-}
-
-func (h *handlerPreserveGVK) resetGroupVersionKind(obj interface{}) {
- if v, ok := obj.(schema.ObjectKind); ok {
- v.SetGroupVersionKind(h.gvk)
- }
-}
-
-func (h *handlerPreserveGVK) OnAdd(obj interface{}) {
- h.resetGroupVersionKind(obj)
- h.ResourceEventHandler.OnAdd(obj)
-}
-
-func (h *handlerPreserveGVK) OnUpdate(oldObj, newObj interface{}) {
- h.resetGroupVersionKind(oldObj)
- h.resetGroupVersionKind(newObj)
- h.ResourceEventHandler.OnUpdate(oldObj, newObj)
-}
-
-func (h *handlerPreserveGVK) OnDelete(obj interface{}) {
- h.resetGroupVersionKind(obj)
- h.ResourceEventHandler.OnDelete(obj)
-}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/multi_namespace_cache.go b/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/multi_namespace_cache.go
deleted file mode 100644
index 3e2f43ad2b8..00000000000
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/dynamiccache/multi_namespace_cache.go
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
-Copyright 2019 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Modified from the original source (available at
-// https://github.com/kubernetes-sigs/controller-runtime/tree/v0.9.2/pkg/cache)
-
-package dynamiccache
-
-import (
- "context"
- "fmt"
- "time"
-
- "github.com/open-policy-agent/gatekeeper/third_party/sigs.k8s.io/controller-runtime/pkg/internal/objectutil"
- corev1 "k8s.io/api/core/v1"
- apimeta "k8s.io/apimachinery/pkg/api/meta"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/client-go/rest"
- toolscache "k8s.io/client-go/tools/cache"
- "sigs.k8s.io/controller-runtime/pkg/cache"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-// NewCacheFunc - Function for creating a new cache from the options and a rest config.
-type NewCacheFunc func(config *rest.Config, opts cache.Options) (cache.Cache, error)
-
-// a new global namespaced cache to handle cluster scoped resources.
-const globalCache = "_cluster-scope"
-
-// MultiNamespacedCacheBuilder - Builder function to create a new multi-namespaced cache.
-// This will scope the cache to a list of namespaces. Listing for all namespaces
-// will list for all the namespaces that this knows about. By default this will create
-// a global cache for cluster scoped resource. Note that this is not intended
-// to be used for excluding namespaces, this is better done via a Predicate. Also note that
-// you may face performance issues when using this with a high number of namespaces.
-func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
- return func(config *rest.Config, opts cache.Options) (cache.Cache, error) {
- opts, err := defaultOpts(config, opts)
- if err != nil {
- return nil, err
- }
-
- caches := map[string]cache.Cache{}
-
- // create a cache for cluster scoped resources
- gCache, err := New(config, opts)
- if err != nil {
- return nil, fmt.Errorf("error creating global cache %v", err)
- }
-
- for _, ns := range namespaces {
- opts.Namespace = ns
- c, err := New(config, opts)
- if err != nil {
- return nil, err
- }
- caches[ns] = c
- }
- return &multiNamespaceCache{namespaceToCache: caches, Scheme: opts.Scheme, RESTMapper: opts.Mapper, clusterCache: gCache}, nil
- }
-}
-
-// multiNamespaceCache knows how to handle multiple namespaced caches
-// Use this feature when scoping permissions for your
-// operator to a list of namespaces instead of watching every namespace
-// in the cluster.
-type multiNamespaceCache struct {
- namespaceToCache map[string]cache.Cache
- Scheme *runtime.Scheme
- RESTMapper apimeta.RESTMapper
- clusterCache cache.Cache
-}
-
-var _ cache.Cache = &multiNamespaceCache{}
-
-// Methods for multiNamespaceCache to conform to the Informers interface.
-func (c *multiNamespaceCache) GetInformer(ctx context.Context, obj client.Object) (cache.Informer, error) {
- informers := map[string]cache.Informer{}
-
- // If the object is clusterscoped, get the informer from clusterCache,
- // if not use the namespaced caches.
- isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper)
- if err != nil {
- return nil, err
- }
- if !isNamespaced {
- clusterCacheInf, err := c.clusterCache.GetInformer(ctx, obj)
- if err != nil {
- return nil, err
- }
- informers[globalCache] = clusterCacheInf
-
- return &multiNamespaceInformer{namespaceToInformer: informers}, nil
- }
-
- for ns, cache := range c.namespaceToCache {
- informer, err := cache.GetInformer(ctx, obj)
- if err != nil {
- return nil, err
- }
- informers[ns] = informer
- }
-
- return &multiNamespaceInformer{namespaceToInformer: informers}, nil
-}
-
-func (c *multiNamespaceCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (cache.Informer, error) {
- informers := map[string]cache.Informer{}
-
- // If the object is clusterscoped, get the informer from clusterCache,
- // if not use the namespaced caches.
- isNamespaced, err := objectutil.IsAPINamespacedWithGVK(gvk, c.Scheme, c.RESTMapper)
- if err != nil {
- return nil, err
- }
- if !isNamespaced {
- clusterCacheInf, err := c.clusterCache.GetInformerForKind(ctx, gvk)
- if err != nil {
- return nil, err
- }
- informers[globalCache] = clusterCacheInf
-
- return &multiNamespaceInformer{namespaceToInformer: informers}, nil
- }
-
- for ns, cache := range c.namespaceToCache {
- informer, err := cache.GetInformerForKind(ctx, gvk)
- if err != nil {
- return nil, err
- }
- informers[ns] = informer
- }
-
- return &multiNamespaceInformer{namespaceToInformer: informers}, nil
-}
-
-func (c *multiNamespaceCache) Start(ctx context.Context) error {
- // start global cache
- go func() {
- err := c.clusterCache.Start(ctx)
- if err != nil {
- log.Error(err, "cluster scoped cache failed to start")
- }
- }()
-
- // start namespaced caches
- for ns, entry := range c.namespaceToCache {
- go func(ns string, cache cache.Cache) {
- err := cache.Start(ctx)
- if err != nil {
- log.Error(err, "multinamespace cache failed to start namespaced informer", "namespace", ns)
- }
- }(ns, entry)
- }
-
- <-ctx.Done()
- return nil
-}
-
-func (c *multiNamespaceCache) WaitForCacheSync(ctx context.Context) bool {
- synced := true
- for _, cache := range c.namespaceToCache {
- if s := cache.WaitForCacheSync(ctx); !s {
- synced = s
- }
- }
-
- // check if cluster scoped cache has synced
- if !c.clusterCache.WaitForCacheSync(ctx) {
- synced = false
- }
- return synced
-}
-
-func (c *multiNamespaceCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error {
- isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper)
- if err != nil {
- return nil //nolint:nilerr
- }
-
- if !isNamespaced {
- return c.clusterCache.IndexField(ctx, obj, field, extractValue)
- }
-
- for _, cache := range c.namespaceToCache {
- if err := cache.IndexField(ctx, obj, field, extractValue); err != nil {
- return err
- }
- }
- return nil
-}
-
-func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
- isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper)
- if err != nil {
- return err
- }
-
- if !isNamespaced {
- // Look into the global cache to fetch the object
- return c.clusterCache.Get(ctx, key, obj)
- }
-
- cache, ok := c.namespaceToCache[key.Namespace]
- if !ok {
- return fmt.Errorf("unable to get: %v because of unknown namespace for the cache", key)
- }
- return cache.Get(ctx, key, obj)
-}
-
-// List multi namespace cache will get all the objects in the namespaces that the cache is watching if asked for all namespaces.
-func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
- listOpts := client.ListOptions{}
- listOpts.ApplyOptions(opts)
-
- isNamespaced, err := objectutil.IsAPINamespaced(list, c.Scheme, c.RESTMapper)
- if err != nil {
- return err
- }
-
- if !isNamespaced {
- // Look at the global cache to get the objects with the specified GVK
- return c.clusterCache.List(ctx, list, opts...)
- }
-
- if listOpts.Namespace != corev1.NamespaceAll {
- cache, ok := c.namespaceToCache[listOpts.Namespace]
- if !ok {
- return fmt.Errorf("unable to get: %v because of unknown namespace for the cache", listOpts.Namespace)
- }
- return cache.List(ctx, list, opts...)
- }
-
- listAccessor, err := apimeta.ListAccessor(list)
- if err != nil {
- return err
- }
-
- allItems, err := apimeta.ExtractList(list)
- if err != nil {
- return err
- }
-
- limitSet := listOpts.Limit > 0
-
- var resourceVersion string
- for _, cache := range c.namespaceToCache {
- listObj := list.DeepCopyObject().(client.ObjectList)
- err = cache.List(ctx, listObj, &listOpts)
- if err != nil {
- return err
- }
- items, err := apimeta.ExtractList(listObj)
- if err != nil {
- return err
- }
- accessor, err := apimeta.ListAccessor(listObj)
- if err != nil {
- return fmt.Errorf("object: %T must be a list type", list)
- }
- allItems = append(allItems, items...)
- // The last list call should have the most correct resource version.
- resourceVersion = accessor.GetResourceVersion()
- if limitSet {
- // decrement Limit by the number of items
- // fetched from the current namespace.
- listOpts.Limit -= int64(len(items))
- // if a Limit was set and the number of
- // items read has reached this set limit,
- // then stop reading.
- if listOpts.Limit == 0 {
- break
- }
- }
- }
- listAccessor.SetResourceVersion(resourceVersion)
-
- return apimeta.SetList(list, allItems)
-}
-
-// multiNamespaceInformer knows how to handle interacting with the underlying informer across multiple namespaces.
-type multiNamespaceInformer struct {
- namespaceToInformer map[string]cache.Informer
-}
-
-var _ cache.Informer = &multiNamespaceInformer{}
-
-// AddEventHandler adds the handler to each namespaced informer.
-func (i *multiNamespaceInformer) AddEventHandler(handler toolscache.ResourceEventHandler) {
- for _, informer := range i.namespaceToInformer {
- informer.AddEventHandler(handler)
- }
-}
-
-// AddEventHandlerWithResyncPeriod adds the handler with a resync period to each namespaced informer.
-func (i *multiNamespaceInformer) AddEventHandlerWithResyncPeriod(handler toolscache.ResourceEventHandler, resyncPeriod time.Duration) {
- for _, informer := range i.namespaceToInformer {
- informer.AddEventHandlerWithResyncPeriod(handler, resyncPeriod)
- }
-}
-
-// AddIndexers adds the indexer for each namespaced informer.
-func (i *multiNamespaceInformer) AddIndexers(indexers toolscache.Indexers) error {
- for _, informer := range i.namespaceToInformer {
- err := informer.AddIndexers(indexers)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-// HasSynced checks if each namespaced informer has synced.
-func (i *multiNamespaceInformer) HasSynced() bool {
- for _, informer := range i.namespaceToInformer {
- if ok := informer.HasSynced(); !ok {
- return ok
- }
- }
- return true
-}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/crd.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/crd.go
new file mode 100644
index 00000000000..f9c58ea26a3
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/crd.go
@@ -0,0 +1,458 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package envtest
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "time"
+
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/util/sets"
+ "k8s.io/apimachinery/pkg/util/wait"
+ k8syaml "k8s.io/apimachinery/pkg/util/yaml"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/util/retry"
+ "k8s.io/utils/pointer"
+ "sigs.k8s.io/yaml"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/conversion"
+)
+
+// CRDInstallOptions are the options for installing CRDs.
+type CRDInstallOptions struct {
+ // Scheme is used to determine if conversion webhooks should be enabled
+ // for a particular CRD / object.
+ //
+ // Conversion webhooks are going to be enabled if an object in the scheme
+ // implements Hub and Spoke conversions.
+ //
+ // If nil, scheme.Scheme is used.
+ Scheme *runtime.Scheme
+
+ // Paths is a list of paths to the directories or files containing CRDs
+ Paths []string
+
+ // CRDs is a list of CRDs to install
+ CRDs []*apiextensionsv1.CustomResourceDefinition
+
+ // ErrorIfPathMissing will cause an error if a Path does not exist
+ ErrorIfPathMissing bool
+
+ // MaxTime is the max time to wait
+ MaxTime time.Duration
+
+ // PollInterval is the interval to check
+ PollInterval time.Duration
+
+ // CleanUpAfterUse will cause the CRDs listed for installation to be
+ // uninstalled when terminating the test environment.
+ // Defaults to false.
+ CleanUpAfterUse bool
+
+ // WebhookOptions contains the conversion webhook information to install
+ // on the CRDs. This field is usually inherited by the EnvTest options.
+ //
+ // If you're passing this field manually, you need to make sure that
+ // the CA information and host port is filled in properly.
+ WebhookOptions WebhookInstallOptions
+}
+
+const (
+ defaultPollInterval = 100 * time.Millisecond
+ defaultMaxWait = 10 * time.Second
+)
+
+// InstallCRDs installs a collection of CRDs into a cluster by reading the crd yaml files from a directory.
+func InstallCRDs(config *rest.Config, options CRDInstallOptions) ([]*apiextensionsv1.CustomResourceDefinition, error) {
+ defaultCRDOptions(&options)
+
+ // Read the CRD yamls into options.CRDs
+ if err := readCRDFiles(&options); err != nil {
+ return nil, fmt.Errorf("unable to read CRD files: %w", err)
+ }
+
+ if err := modifyConversionWebhooks(options.CRDs, options.Scheme, options.WebhookOptions); err != nil {
+ return nil, err
+ }
+
+ // Create the CRDs in the apiserver
+ if err := CreateCRDs(config, options.CRDs); err != nil {
+ return options.CRDs, fmt.Errorf("unable to create CRD instances: %w", err)
+ }
+
+ // Wait for the CRDs to appear as Resources in the apiserver
+ if err := WaitForCRDs(config, options.CRDs, options); err != nil {
+ return options.CRDs, fmt.Errorf("something went wrong waiting for CRDs to appear as API resources: %w", err)
+ }
+
+ return options.CRDs, nil
+}
+
+// readCRDFiles reads the directories of CRDs in options.Paths and adds the CRD structs to options.CRDs.
+func readCRDFiles(options *CRDInstallOptions) error {
+ if len(options.Paths) > 0 {
+ crdList, err := renderCRDs(options)
+ if err != nil {
+ return err
+ }
+
+ options.CRDs = append(options.CRDs, crdList...)
+ }
+ return nil
+}
+
+// defaultCRDOptions sets the default values for CRDs.
+func defaultCRDOptions(o *CRDInstallOptions) {
+ if o.Scheme == nil {
+ o.Scheme = scheme.Scheme
+ }
+ if o.MaxTime == 0 {
+ o.MaxTime = defaultMaxWait
+ }
+ if o.PollInterval == 0 {
+ o.PollInterval = defaultPollInterval
+ }
+}
+
+// WaitForCRDs waits for the CRDs to appear in discovery.
+func WaitForCRDs(config *rest.Config, crds []*apiextensionsv1.CustomResourceDefinition, options CRDInstallOptions) error {
+ // Add each CRD to a map of GroupVersion to Resource
+ waitingFor := map[schema.GroupVersion]*sets.Set[string]{}
+ for _, crd := range crds {
+ gvs := []schema.GroupVersion{}
+ for _, version := range crd.Spec.Versions {
+ if version.Served {
+ gvs = append(gvs, schema.GroupVersion{Group: crd.Spec.Group, Version: version.Name})
+ }
+ }
+
+ for _, gv := range gvs {
+ log.V(1).Info("adding API in waitlist", "GV", gv)
+ if _, found := waitingFor[gv]; !found {
+ // Initialize the set
+ waitingFor[gv] = &sets.Set[string]{}
+ }
+ // Add the Resource
+ waitingFor[gv].Insert(crd.Spec.Names.Plural)
+ }
+ }
+
+ // Poll until all resources are found in discovery
+ p := &poller{config: config, waitingFor: waitingFor}
+ return wait.PollUntilContextTimeout(context.TODO(), options.PollInterval, options.MaxTime, true, p.poll)
+}
+
+// poller checks if all the resources have been found in discovery, and returns false if not.
+type poller struct {
+ // config is used to get discovery
+ config *rest.Config
+
+ // waitingFor is the map of resources keyed by group version that have not yet been found in discovery
+ waitingFor map[schema.GroupVersion]*sets.Set[string]
+}
+
+// poll checks if all the resources have been found in discovery, and returns false if not.
+func (p *poller) poll(ctx context.Context) (done bool, err error) {
+ // Create a new clientset to avoid any client caching of discovery
+ cs, err := clientset.NewForConfig(p.config)
+ if err != nil {
+ return false, err
+ }
+
+ allFound := true
+ for gv, resources := range p.waitingFor {
+ // All resources found, do nothing
+ if resources.Len() == 0 {
+ delete(p.waitingFor, gv)
+ continue
+ }
+
+ // Get the Resources for this GroupVersion
+ // TODO: Maybe the controller-runtime client should be able to do this...
+ resourceList, err := cs.Discovery().ServerResourcesForGroupVersion(gv.Group + "/" + gv.Version)
+ if err != nil {
+ return false, nil //nolint:nilerr
+ }
+
+ // Remove each found resource from the resources set that we are waiting for
+ for _, resource := range resourceList.APIResources {
+ resources.Delete(resource.Name)
+ }
+
+ // Still waiting on some resources in this group version
+ if resources.Len() != 0 {
+ allFound = false
+ }
+ }
+ return allFound, nil
+}
+
+// UninstallCRDs uninstalls a collection of CRDs by reading the crd yaml files from a directory.
+func UninstallCRDs(config *rest.Config, options CRDInstallOptions) error {
+ // Read the CRD yamls into options.CRDs
+ if err := readCRDFiles(&options); err != nil {
+ return err
+ }
+
+ // Delete the CRDs from the apiserver
+ cs, err := client.New(config, client.Options{})
+ if err != nil {
+ return err
+ }
+
+ // Uninstall each CRD
+ for _, crd := range options.CRDs {
+ crd := crd
+ log.V(1).Info("uninstalling CRD", "crd", crd.GetName())
+ if err := cs.Delete(context.TODO(), crd); err != nil {
+ // If CRD is not found, we can consider success
+ if !apierrors.IsNotFound(err) {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
+
+// CreateCRDs creates the CRDs.
+func CreateCRDs(config *rest.Config, crds []*apiextensionsv1.CustomResourceDefinition) error {
+ cs, err := client.New(config, client.Options{})
+ if err != nil {
+ return fmt.Errorf("unable to create client: %w", err)
+ }
+
+ // Create each CRD
+ for _, crd := range crds {
+ crd := crd
+ log.V(1).Info("installing CRD", "crd", crd.GetName())
+ existingCrd := crd.DeepCopy()
+ err := cs.Get(context.TODO(), client.ObjectKey{Name: crd.GetName()}, existingCrd)
+ switch {
+ case apierrors.IsNotFound(err):
+ if err := cs.Create(context.TODO(), crd); err != nil {
+ return fmt.Errorf("unable to create CRD %q: %w", crd.GetName(), err)
+ }
+ case err != nil:
+ return fmt.Errorf("unable to get CRD %q to check if it exists: %w", crd.GetName(), err)
+ default:
+ log.V(1).Info("CRD already exists, updating", "crd", crd.GetName())
+ if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
+ if err := cs.Get(context.TODO(), client.ObjectKey{Name: crd.GetName()}, existingCrd); err != nil {
+ return err
+ }
+ crd.SetResourceVersion(existingCrd.GetResourceVersion())
+ return cs.Update(context.TODO(), crd)
+ }); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// renderCRDs iterate through options.Paths and extract all CRD files.
+func renderCRDs(options *CRDInstallOptions) ([]*apiextensionsv1.CustomResourceDefinition, error) {
+ type GVKN struct {
+ GVK schema.GroupVersionKind
+ Name string
+ }
+
+ crds := map[GVKN]*apiextensionsv1.CustomResourceDefinition{}
+
+ for _, path := range options.Paths {
+ var (
+ err error
+ info os.FileInfo
+ files []string
+ filePath = path
+ )
+
+ // Return the error if ErrorIfPathMissing exists
+ if info, err = os.Stat(path); os.IsNotExist(err) {
+ if options.ErrorIfPathMissing {
+ return nil, err
+ }
+ continue
+ }
+
+ if !info.IsDir() {
+ filePath, files = filepath.Dir(path), []string{info.Name()}
+ } else {
+ entries, err := os.ReadDir(path)
+ if err != nil {
+ return nil, err
+ }
+ for _, e := range entries {
+ files = append(files, e.Name())
+ }
+ }
+
+ log.V(1).Info("reading CRDs from path", "path", path)
+ crdList, err := readCRDs(filePath, files)
+ if err != nil {
+ return nil, err
+ }
+
+ for i, crd := range crdList {
+ gvkn := GVKN{GVK: crd.GroupVersionKind(), Name: crd.GetName()}
+ if _, found := crds[gvkn]; found {
+ // Currently, we only print a log when there are duplicates. We may want to error out if that makes more sense.
+ log.Info("there are more than one CRD definitions with the same ", "GVKN", gvkn)
+ }
+ // We always use the CRD definition that we found last.
+ crds[gvkn] = crdList[i]
+ }
+ }
+
+ // Converting map to a list to return
+ res := []*apiextensionsv1.CustomResourceDefinition{}
+ for _, obj := range crds {
+ res = append(res, obj)
+ }
+ return res, nil
+}
+
+// modifyConversionWebhooks takes all the registered CustomResourceDefinitions and applies modifications
+// to conditionally enable webhooks if the type is registered within the scheme.
+func modifyConversionWebhooks(crds []*apiextensionsv1.CustomResourceDefinition, scheme *runtime.Scheme, webhookOptions WebhookInstallOptions) error {
+ if len(webhookOptions.LocalServingCAData) == 0 {
+ return nil
+ }
+
+ // Determine all registered convertible types.
+ convertibles := map[schema.GroupKind]struct{}{}
+ for gvk := range scheme.AllKnownTypes() {
+ obj, err := scheme.New(gvk)
+ if err != nil {
+ return err
+ }
+ if ok, err := conversion.IsConvertible(scheme, obj); ok && err == nil {
+ convertibles[gvk.GroupKind()] = struct{}{}
+ }
+ }
+
+ // generate host port.
+ hostPort, err := webhookOptions.generateHostPort()
+ if err != nil {
+ return err
+ }
+ url := pointer.String(fmt.Sprintf("https://%s/convert", hostPort))
+
+ for i := range crds {
+ // Continue if we're preserving unknown fields.
+ if crds[i].Spec.PreserveUnknownFields {
+ continue
+ }
+ // Continue if the GroupKind isn't registered as being convertible.
+ if _, ok := convertibles[schema.GroupKind{
+ Group: crds[i].Spec.Group,
+ Kind: crds[i].Spec.Names.Kind,
+ }]; !ok {
+ continue
+ }
+ if crds[i].Spec.Conversion == nil {
+ crds[i].Spec.Conversion = &apiextensionsv1.CustomResourceConversion{
+ Webhook: &apiextensionsv1.WebhookConversion{},
+ }
+ }
+ crds[i].Spec.Conversion.Strategy = apiextensionsv1.WebhookConverter
+ crds[i].Spec.Conversion.Webhook.ConversionReviewVersions = []string{"v1", "v1beta1"}
+ crds[i].Spec.Conversion.Webhook.ClientConfig = &apiextensionsv1.WebhookClientConfig{
+ Service: nil,
+ URL: url,
+ CABundle: webhookOptions.LocalServingCAData,
+ }
+ }
+
+ return nil
+}
+
+// readCRDs reads the CRDs from files and Unmarshals them into structs.
+func readCRDs(basePath string, files []string) ([]*apiextensionsv1.CustomResourceDefinition, error) {
+ var crds []*apiextensionsv1.CustomResourceDefinition
+
+ // White list the file extensions that may contain CRDs
+ crdExts := sets.NewString(".json", ".yaml", ".yml")
+
+ for _, file := range files {
+ // Only parse allowlisted file types
+ if !crdExts.Has(filepath.Ext(file)) {
+ continue
+ }
+
+ // Unmarshal CRDs from file into structs
+ docs, err := readDocuments(filepath.Join(basePath, file))
+ if err != nil {
+ return nil, err
+ }
+
+ for _, doc := range docs {
+ crd := &apiextensionsv1.CustomResourceDefinition{}
+ if err = yaml.Unmarshal(doc, crd); err != nil {
+ return nil, err
+ }
+
+ if crd.Kind != "CustomResourceDefinition" || crd.Spec.Names.Kind == "" || crd.Spec.Group == "" {
+ continue
+ }
+ crds = append(crds, crd)
+ }
+
+ log.V(1).Info("read CRDs from file", "file", file)
+ }
+ return crds, nil
+}
+
+// readDocuments reads documents from file.
+func readDocuments(fp string) ([][]byte, error) {
+ b, err := os.ReadFile(fp)
+ if err != nil {
+ return nil, err
+ }
+
+ docs := [][]byte{}
+ reader := k8syaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(b)))
+ for {
+ // Read document
+ doc, err := reader.Read()
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return nil, err
+ }
+
+ docs = append(docs, doc)
+ }
+
+ return docs, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/crd_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/crd_test.go
new file mode 100644
index 00000000000..92dc48e9630
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/crd_test.go
@@ -0,0 +1,51 @@
+/*
+Copyright 2022 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package envtest
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/apimachinery/pkg/util/sets"
+)
+
+var _ = Describe("Test", func() {
+ Describe("readCRDFiles", func() {
+ It("should not mix up files from different directories", func() {
+ opt := CRDInstallOptions{
+ Paths: []string{
+ "testdata/crds",
+ "testdata/crdv1_original",
+ },
+ }
+ err := readCRDFiles(&opt)
+ Expect(err).NotTo(HaveOccurred())
+
+ expectedCRDs := sets.NewString(
+ "frigates.ship.example.com",
+ "configs.foo.example.com",
+ "drivers.crew.example.com",
+ )
+
+ foundCRDs := sets.NewString()
+ for _, crd := range opt.CRDs {
+ foundCRDs.Insert(crd.Name)
+ }
+
+ Expect(expectedCRDs).To(Equal(foundCRDs))
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/doc.go
new file mode 100644
index 00000000000..412e794cc8c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/doc.go
@@ -0,0 +1,26 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package envtest provides libraries for integration testing by starting a local control plane
+//
+// Control plane binaries (etcd and kube-apiserver) are loaded by default from
+// /usr/local/kubebuilder/bin. This can be overridden by setting the
+// KUBEBUILDER_ASSETS environment variable, or by directly creating a
+// ControlPlane for the Environment to use.
+//
+// Environment can also be configured to work with an existing cluster, and
+// simply load CRDs and provide client configuration.
+package envtest
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/envtest_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/envtest_suite_test.go
new file mode 100644
index 00000000000..f7788bf0902
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/envtest_suite_test.go
@@ -0,0 +1,134 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package envtest
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ admissionv1 "k8s.io/api/admissionregistration/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Envtest Suite")
+}
+
+var env *Environment
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+ env = &Environment{}
+ // we're initializing webhook here and not in webhook.go to also test the envtest install code via WebhookOptions
+ initializeWebhookInEnvironment()
+ _, err := env.Start()
+ Expect(err).NotTo(HaveOccurred())
+})
+
+func initializeWebhookInEnvironment() {
+ namespacedScopeV1 := admissionv1.NamespacedScope
+ failedTypeV1 := admissionv1.Fail
+ equivalentTypeV1 := admissionv1.Equivalent
+ noSideEffectsV1 := admissionv1.SideEffectClassNone
+ webhookPathV1 := "/failing"
+
+ env.WebhookInstallOptions = WebhookInstallOptions{
+ ValidatingWebhooks: []*admissionv1.ValidatingWebhookConfiguration{
+ {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-validation-webhook-config",
+ },
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ValidatingWebhookConfiguration",
+ APIVersion: "admissionregistration.k8s.io/v1",
+ },
+ Webhooks: []admissionv1.ValidatingWebhook{
+ {
+ Name: "deployment-validation.kubebuilder.io",
+ Rules: []admissionv1.RuleWithOperations{
+ {
+ Operations: []admissionv1.OperationType{"CREATE", "UPDATE"},
+ Rule: admissionv1.Rule{
+ APIGroups: []string{"apps"},
+ APIVersions: []string{"v1"},
+ Resources: []string{"deployments"},
+ Scope: &namespacedScopeV1,
+ },
+ },
+ },
+ FailurePolicy: &failedTypeV1,
+ MatchPolicy: &equivalentTypeV1,
+ SideEffects: &noSideEffectsV1,
+ ClientConfig: admissionv1.WebhookClientConfig{
+ Service: &admissionv1.ServiceReference{
+ Name: "deployment-validation-service",
+ Namespace: "default",
+ Path: &webhookPathV1,
+ },
+ },
+ AdmissionReviewVersions: []string{"v1"},
+ },
+ },
+ },
+ {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-validation-webhook-config",
+ },
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ValidatingWebhookConfiguration",
+ APIVersion: "admissionregistration.k8s.io/v1",
+ },
+ Webhooks: []admissionv1.ValidatingWebhook{
+ {
+ Name: "deployment-validation.kubebuilder.io",
+ Rules: []admissionv1.RuleWithOperations{
+ {
+ Operations: []admissionv1.OperationType{"CREATE", "UPDATE"},
+ Rule: admissionv1.Rule{
+ APIGroups: []string{"apps"},
+ APIVersions: []string{"v1"},
+ Resources: []string{"deployments"},
+ Scope: &namespacedScopeV1,
+ },
+ },
+ },
+ FailurePolicy: &failedTypeV1,
+ MatchPolicy: &equivalentTypeV1,
+ SideEffects: &noSideEffectsV1,
+ ClientConfig: admissionv1.WebhookClientConfig{
+ Service: &admissionv1.ServiceReference{
+ Name: "deployment-validation-service",
+ Namespace: "default",
+ Path: &webhookPathV1,
+ },
+ },
+ AdmissionReviewVersions: []string{"v1"},
+ },
+ },
+ },
+ },
+ }
+}
+
+var _ = AfterSuite(func() {
+ Expect(env.Stop()).NotTo(HaveOccurred())
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/envtest_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/envtest_test.go
new file mode 100644
index 00000000000..21464e10bef
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/envtest_test.go
@@ -0,0 +1,961 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package envtest
+
+import (
+ "context"
+ "path/filepath"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/kubernetes/scheme"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+var _ = Describe("Test", func() {
+ var crds []*apiextensionsv1.CustomResourceDefinition
+ var err error
+ var s *runtime.Scheme
+ var c client.Client
+
+ var validDirectory = filepath.Join(".", "testdata")
+ var invalidDirectory = "fake"
+
+ var teardownTimeoutSeconds float64 = 10
+
+ // Initialize the client
+ BeforeEach(func() {
+ crds = []*apiextensionsv1.CustomResourceDefinition{}
+ s = scheme.Scheme
+ err = apiextensionsv1.AddToScheme(s)
+ Expect(err).NotTo(HaveOccurred())
+
+ c, err = client.New(env.Config, client.Options{Scheme: s})
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ // Cleanup CRDs
+ AfterEach(func() {
+ for _, crd := range crds {
+ crd := crd
+ // Delete only if CRD exists.
+ crdObjectKey := client.ObjectKey{
+ Name: crd.GetName(),
+ }
+ var placeholder apiextensionsv1.CustomResourceDefinition
+ if err = c.Get(context.TODO(), crdObjectKey, &placeholder); err != nil &&
+ apierrors.IsNotFound(err) {
+ // CRD doesn't need to be deleted.
+ continue
+ }
+ Expect(err).NotTo(HaveOccurred())
+ Expect(c.Delete(context.TODO(), crd)).To(Succeed())
+ Eventually(func() bool {
+ err := c.Get(context.TODO(), crdObjectKey, &placeholder)
+ return apierrors.IsNotFound(err)
+ }, 5*time.Second).Should(BeTrue())
+ }
+ }, teardownTimeoutSeconds)
+
+ Describe("InstallCRDs", func() {
+ It("should install the unserved CRDs into the cluster", func() {
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{filepath.Join(".", "testdata", "crds", "examplecrd_unserved.yaml")},
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ // Expect to find the CRDs
+
+ crd := &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "frigates.ship.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Frigate"))
+
+ err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "ship.example.com",
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "frigates",
+ },
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: false,
+ },
+ {
+ Name: "v1beta1",
+ Storage: false,
+ Served: false,
+ },
+ }},
+ },
+ },
+ CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
+ )
+ Expect(err).NotTo(HaveOccurred())
+ })
+ It("should install the CRDs into the cluster using directory", func() {
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{validDirectory},
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ // Expect to find the CRDs
+
+ crd := &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "foos.bar.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Foo"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "bazs.qux.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Baz"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "captains.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Captain"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "firstmates.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("FirstMate"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Driver"))
+
+ err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "bar.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
+ Type: "object",
+ },
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "foos",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "qux.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "bazs",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "captains",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "firstmates",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "drivers",
+ },
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: true,
+ },
+ {
+ Name: "v2",
+ Storage: false,
+ Served: true,
+ },
+ }},
+ },
+ },
+ CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
+ )
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ It("should install the CRDs into the cluster using file", func() {
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{filepath.Join(".", "testdata", "crds", "examplecrd3.yaml")},
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ crd := &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "configs.foo.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Config"))
+
+ err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "foo.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "configs",
+ }},
+ },
+ },
+ CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
+ )
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ It("should be able to install CRDs using multiple files", func() {
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{
+ filepath.Join(".", "testdata", "examplecrd.yaml"),
+ filepath.Join(".", "testdata", "examplecrd_v1.yaml"),
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crds).To(HaveLen(2))
+ })
+
+ It("should filter out already existent CRD", func() {
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{
+ filepath.Join(".", "testdata"),
+ filepath.Join(".", "testdata", "examplecrd1.yaml"),
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ crd := &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "foos.bar.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Foo"))
+
+ err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "bar.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
+ Type: "object",
+ },
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "foos",
+ }},
+ },
+ },
+ CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
+ )
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ It("should not return an not error if the directory doesn't exist", func() {
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{Paths: []string{invalidDirectory}})
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ It("should return an error if the directory doesn't exist", func() {
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{invalidDirectory}, ErrorIfPathMissing: true,
+ })
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should return an error if the file doesn't exist", func() {
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{Paths: []string{
+ filepath.Join(".", "testdata", "fake.yaml")}, ErrorIfPathMissing: true,
+ })
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should return an error if the resource group version isn't found", func() {
+ // Wait for a CRD where the Group and Version don't exist
+ err := WaitForCRDs(env.Config,
+ []*apiextensionsv1.CustomResourceDefinition{
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "notfound",
+ }},
+ },
+ },
+ CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
+ )
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should return an error if the resource isn't found in the group version", func() {
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{"."},
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ // Wait for a CRD that doesn't exist, but the Group and Version do
+ err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "qux.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "bazs",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "bar.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "fake",
+ }},
+ }},
+ CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
+ )
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("should reinstall the CRDs if already present in the cluster", func() {
+
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{filepath.Join(".", "testdata")},
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ // Expect to find the CRDs
+
+ crd := &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "foos.bar.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Foo"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "bazs.qux.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Baz"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "captains.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Captain"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "firstmates.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("FirstMate"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Driver"))
+
+ err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "bar.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
+ Type: "object",
+ },
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "foos",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "qux.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "bazs",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "captains",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "firstmates",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "drivers",
+ },
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: true,
+ },
+ {
+ Name: "v2",
+ Storage: false,
+ Served: true,
+ },
+ }},
+ },
+ },
+ CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
+ )
+ Expect(err).NotTo(HaveOccurred())
+
+ // Try to re-install the CRDs
+
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{filepath.Join(".", "testdata")},
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ // Expect to find the CRDs
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "foos.bar.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Foo"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "bazs.qux.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Baz"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "captains.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Captain"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "firstmates.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("FirstMate"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Driver"))
+
+ err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "bar.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
+ Type: "object",
+ },
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "foos",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "qux.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "bazs",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "captains",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "firstmates",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "drivers",
+ },
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: true,
+ },
+ {
+ Name: "v2",
+ Storage: false,
+ Served: true,
+ },
+ }},
+ },
+ },
+ CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
+ )
+ Expect(err).NotTo(HaveOccurred())
+ })
+ })
+
+ It("should update CRDs if already present in the cluster", func() {
+
+ // Install only the CRDv1 multi-version example
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{filepath.Join(".", "testdata")},
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ // Expect to find the CRDs
+
+ crd := &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Driver"))
+ Expect(len(crd.Spec.Versions)).To(BeEquivalentTo(2))
+
+ // Store resource version for comparison later on
+ firstRV := crd.ResourceVersion
+
+ err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "drivers",
+ },
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: true,
+ },
+ {
+ Name: "v2",
+ Storage: false,
+ Served: true,
+ },
+ }},
+ },
+ },
+ CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
+ )
+ Expect(err).NotTo(HaveOccurred())
+
+ // Add one more version and update
+ _, err = InstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{filepath.Join(".", "testdata", "crdv1_updated")},
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ // Expect to find updated CRD
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Driver"))
+ Expect(len(crd.Spec.Versions)).To(BeEquivalentTo(3))
+ Expect(crd.ResourceVersion).NotTo(BeEquivalentTo(firstRV))
+
+ err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "drivers",
+ },
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: true,
+ },
+ {
+ Name: "v2",
+ Storage: false,
+ Served: true,
+ },
+ {
+ Name: "v3",
+ Storage: false,
+ Served: true,
+ },
+ }},
+ },
+ },
+ CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
+ )
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ Describe("UninstallCRDs", func() {
+ It("should uninstall the CRDs from the cluster", func() {
+
+ crds, err = InstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{validDirectory},
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ // Expect to find the CRDs
+
+ crd := &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "foos.bar.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Foo"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "bazs.qux.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Baz"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "captains.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Captain"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "firstmates.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("FirstMate"))
+
+ crd = &apiextensionsv1.CustomResourceDefinition{}
+ err = c.Get(context.TODO(), types.NamespacedName{Name: "drivers.crew.example.com"}, crd)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(crd.Spec.Names.Kind).To(Equal("Driver"))
+
+ err = WaitForCRDs(env.Config, []*apiextensionsv1.CustomResourceDefinition{
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "bar.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
+ Type: "object",
+ },
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "foos",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "qux.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "bazs",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "captains",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1beta1",
+ Storage: true,
+ Served: true,
+ Schema: &apiextensionsv1.CustomResourceValidation{
+ OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{},
+ },
+ },
+ },
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "firstmates",
+ }},
+ },
+ {
+ Spec: apiextensionsv1.CustomResourceDefinitionSpec{
+ Group: "crew.example.com",
+ Names: apiextensionsv1.CustomResourceDefinitionNames{
+ Plural: "drivers",
+ },
+ Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
+ {
+ Name: "v1",
+ Storage: true,
+ Served: true,
+ },
+ {
+ Name: "v2",
+ Storage: false,
+ Served: true,
+ },
+ }},
+ },
+ },
+ CRDInstallOptions{MaxTime: 50 * time.Millisecond, PollInterval: 15 * time.Millisecond},
+ )
+ Expect(err).NotTo(HaveOccurred())
+
+ err = UninstallCRDs(env.Config, CRDInstallOptions{
+ Paths: []string{validDirectory},
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ // Expect to NOT find the CRDs
+
+ crds := []string{
+ "foos.bar.example.com",
+ "bazs.qux.example.com",
+ "captains.crew.example.com",
+ "firstmates.crew.example.com",
+ "drivers.crew.example.com",
+ }
+ placeholder := &apiextensionsv1.CustomResourceDefinition{}
+ Eventually(func() bool {
+ for _, crd := range crds {
+ err = c.Get(context.TODO(), types.NamespacedName{Name: crd}, placeholder)
+ notFound := err != nil && apierrors.IsNotFound(err)
+ if !notFound {
+ return false
+ }
+ }
+ return true
+ }, 20).Should(BeTrue())
+ })
+ })
+
+ Describe("Start", func() {
+ It("should raise an error on invalid dir when flag is enabled", func() {
+ env := &Environment{ErrorIfCRDPathMissing: true, CRDDirectoryPaths: []string{invalidDirectory}}
+ _, err := env.Start()
+ Expect(err).To(HaveOccurred())
+ Expect(env.Stop()).To(Succeed())
+ })
+
+ It("should not raise an error on invalid dir when flag is disabled", func() {
+ env := &Environment{ErrorIfCRDPathMissing: false, CRDDirectoryPaths: []string{invalidDirectory}}
+ _, err := env.Start()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(env.Stop()).To(Succeed())
+ })
+ })
+
+ Describe("Stop", func() {
+ It("should cleanup webhook /tmp folder with no error when using existing cluster", func() {
+ env := &Environment{}
+ _, err := env.Start()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(env.Stop()).To(Succeed())
+
+ // check if the /tmp/envtest-serving-certs-* dir doesnt exists any more
+ Expect(env.WebhookInstallOptions.LocalServingCertDir).ShouldNot(BeADirectory())
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/helper.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/helper.go
new file mode 100644
index 00000000000..d3b52017d23
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/helper.go
@@ -0,0 +1,69 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package envtest
+
+import (
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ "k8s.io/client-go/kubernetes/scheme"
+)
+
+var (
+ crdScheme = scheme.Scheme
+)
+
+// init is required to correctly initialize the crdScheme package variable.
+func init() {
+ _ = apiextensionsv1.AddToScheme(crdScheme)
+}
+
+// mergePaths merges two string slices containing paths.
+// This function makes no guarantees about order of the merged slice.
+func mergePaths(s1, s2 []string) []string {
+ m := make(map[string]struct{})
+ for _, s := range s1 {
+ m[s] = struct{}{}
+ }
+ for _, s := range s2 {
+ m[s] = struct{}{}
+ }
+ merged := make([]string, len(m))
+ i := 0
+ for key := range m {
+ merged[i] = key
+ i++
+ }
+ return merged
+}
+
+// mergeCRDs merges two CRD slices using their names.
+// This function makes no guarantees about order of the merged slice.
+func mergeCRDs(s1, s2 []*apiextensionsv1.CustomResourceDefinition) []*apiextensionsv1.CustomResourceDefinition {
+ m := make(map[string]*apiextensionsv1.CustomResourceDefinition)
+ for _, obj := range s1 {
+ m[obj.GetName()] = obj
+ }
+ for _, obj := range s2 {
+ m[obj.GetName()] = obj
+ }
+ merged := make([]*apiextensionsv1.CustomResourceDefinition, len(m))
+ i := 0
+ for _, obj := range m {
+ merged[i] = obj.DeepCopy()
+ i++
+ }
+ return merged
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/OWNERS b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/OWNERS
new file mode 100644
index 00000000000..ba347dae2b5
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/OWNERS
@@ -0,0 +1,14 @@
+approvers:
+ - controller-runtime-admins
+ - controller-runtime-maintainers
+ - controller-runtime-approvers
+ - schrej
+ - JoelSpeed
+ - sbueringer
+reviewers:
+ - controller-runtime-admins
+ - controller-runtime-reviewers
+ - controller-runtime-approvers
+ - schrej
+ - JoelSpeed
+ - sbueringer
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/default.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/default.go
new file mode 100644
index 00000000000..48fb927a200
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/default.go
@@ -0,0 +1,104 @@
+package komega
+
+import (
+ "context"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// defaultK is the Komega used by the package global functions.
+var defaultK = &komega{ctx: context.Background()}
+
+// SetClient sets the client used by the package global functions.
+func SetClient(c client.Client) {
+ defaultK.client = c
+}
+
+// SetContext sets the context used by the package global functions.
+func SetContext(c context.Context) {
+ defaultK.ctx = c
+}
+
+func checkDefaultClient() {
+ if defaultK.client == nil {
+ panic("Default Komega's client is not set. Use SetClient to set it.")
+ }
+}
+
+// Get returns a function that fetches a resource and returns the occurring error.
+// It can be used with gomega.Eventually() like this
+//
+// deployment := appsv1.Deployment{ ... }
+// gomega.Eventually(komega.Get(&deployment)).To(gomega.Succeed())
+//
+// By calling the returned function directly it can also be used with gomega.Expect(komega.Get(...)()).To(...)
+func Get(obj client.Object) func() error {
+ checkDefaultClient()
+ return defaultK.Get(obj)
+}
+
+// List returns a function that lists resources and returns the occurring error.
+// It can be used with gomega.Eventually() like this
+//
+// deployments := v1.DeploymentList{ ... }
+// gomega.Eventually(k.List(&deployments)).To(gomega.Succeed())
+//
+// By calling the returned function directly it can also be used as gomega.Expect(k.List(...)()).To(...)
+func List(list client.ObjectList, opts ...client.ListOption) func() error {
+ checkDefaultClient()
+ return defaultK.List(list, opts...)
+}
+
+// Update returns a function that fetches a resource, applies the provided update function and then updates the resource.
+// It can be used with gomega.Eventually() like this:
+//
+// deployment := appsv1.Deployment{ ... }
+// gomega.Eventually(k.Update(&deployment, func (o client.Object) {
+// deployment.Spec.Replicas = 3
+// return &deployment
+// })).To(gomega.Succeed())
+//
+// By calling the returned function directly it can also be used as gomega.Expect(k.Update(...)()).To(...)
+func Update(obj client.Object, f func(), opts ...client.UpdateOption) func() error {
+ checkDefaultClient()
+ return defaultK.Update(obj, f, opts...)
+}
+
+// UpdateStatus returns a function that fetches a resource, applies the provided update function and then updates the resource's status.
+// It can be used with gomega.Eventually() like this:
+//
+// deployment := appsv1.Deployment{ ... }
+// gomega.Eventually(k.UpdateStatus(&deployment, func (o client.Object) {
+// deployment.Status.AvailableReplicas = 1
+// return &deployment
+// })).To(gomega.Succeed())
+//
+// By calling the returned function directly it can also be used as gomega.Expect(k.UpdateStatus(...)()).To(...)
+func UpdateStatus(obj client.Object, f func(), opts ...client.SubResourceUpdateOption) func() error {
+ checkDefaultClient()
+ return defaultK.UpdateStatus(obj, f, opts...)
+}
+
+// Object returns a function that fetches a resource and returns the object.
+// It can be used with gomega.Eventually() like this:
+//
+// deployment := appsv1.Deployment{ ... }
+// gomega.Eventually(k.Object(&deployment)).To(HaveField("Spec.Replicas", gomega.Equal(pointer.Int32(3))))
+//
+// By calling the returned function directly it can also be used as gomega.Expect(k.Object(...)()).To(...)
+func Object(obj client.Object) func() (client.Object, error) {
+ checkDefaultClient()
+ return defaultK.Object(obj)
+}
+
+// ObjectList returns a function that fetches a resource and returns the object.
+// It can be used with gomega.Eventually() like this:
+//
+// deployments := appsv1.DeploymentList{ ... }
+// gomega.Eventually(k.ObjectList(&deployments)).To(HaveField("Items", HaveLen(1)))
+//
+// By calling the returned function directly it can also be used as gomega.Expect(k.ObjectList(...)()).To(...)
+func ObjectList(list client.ObjectList, opts ...client.ListOption) func() (client.ObjectList, error) {
+ checkDefaultClient()
+ return defaultK.ObjectList(list, opts...)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/default_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/default_test.go
new file mode 100644
index 00000000000..238a4abd9e7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/default_test.go
@@ -0,0 +1,116 @@
+package komega
+
+import (
+ "testing"
+
+ . "github.com/onsi/gomega"
+ appsv1 "k8s.io/api/apps/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/utils/pointer"
+)
+
+func TestDefaultGet(t *testing.T) {
+ g := NewWithT(t)
+
+ fc := createFakeClient()
+ SetClient(fc)
+
+ fetched := appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: "test",
+ },
+ }
+ g.Eventually(Get(&fetched)).Should(Succeed())
+
+ g.Expect(*fetched.Spec.Replicas).To(BeEquivalentTo(5))
+}
+
+func TestDefaultList(t *testing.T) {
+ g := NewWithT(t)
+
+ fc := createFakeClient()
+ SetClient(fc)
+
+ list := appsv1.DeploymentList{}
+ g.Eventually(List(&list)).Should(Succeed())
+
+ g.Expect(list.Items).To(HaveLen(1))
+ depl := exampleDeployment()
+ g.Expect(list.Items[0]).To(And(
+ HaveField("ObjectMeta.Name", Equal(depl.ObjectMeta.Name)),
+ HaveField("ObjectMeta.Namespace", Equal(depl.ObjectMeta.Namespace)),
+ ))
+}
+
+func TestDefaultUpdate(t *testing.T) {
+ g := NewWithT(t)
+
+ fc := createFakeClient()
+ SetClient(fc)
+
+ updateDeployment := appsv1.Deployment{
+ ObjectMeta: exampleDeployment().ObjectMeta,
+ }
+ g.Eventually(Update(&updateDeployment, func() {
+ updateDeployment.Annotations = map[string]string{"updated": "true"}
+ })).Should(Succeed())
+
+ fetched := appsv1.Deployment{
+ ObjectMeta: exampleDeployment().ObjectMeta,
+ }
+ g.Expect(Object(&fetched)()).To(HaveField("ObjectMeta.Annotations", HaveKeyWithValue("updated", "true")))
+}
+
+func TestDefaultUpdateStatus(t *testing.T) {
+ g := NewWithT(t)
+
+ fc := createFakeClient()
+ SetClient(fc)
+
+ updateDeployment := appsv1.Deployment{
+ ObjectMeta: exampleDeployment().ObjectMeta,
+ }
+ g.Eventually(UpdateStatus(&updateDeployment, func() {
+ updateDeployment.Status.AvailableReplicas = 1
+ })).Should(Succeed())
+
+ fetched := appsv1.Deployment{
+ ObjectMeta: exampleDeployment().ObjectMeta,
+ }
+ g.Expect(Object(&fetched)()).To(HaveField("Status.AvailableReplicas", BeEquivalentTo(1)))
+}
+
+func TestDefaultObject(t *testing.T) {
+ g := NewWithT(t)
+
+ fc := createFakeClient()
+ SetClient(fc)
+
+ fetched := appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: "test",
+ },
+ }
+ g.Eventually(Object(&fetched)).Should(And(
+ Not(BeNil()),
+ HaveField("Spec.Replicas", Equal(pointer.Int32(5))),
+ ))
+}
+
+func TestDefaultObjectList(t *testing.T) {
+ g := NewWithT(t)
+
+ fc := createFakeClient()
+ SetClient(fc)
+
+ list := appsv1.DeploymentList{}
+ g.Eventually(ObjectList(&list)).Should(And(
+ Not(BeNil()),
+ HaveField("Items", And(
+ HaveLen(1),
+ ContainElement(HaveField("Spec.Replicas", Equal(pointer.Int32(5)))),
+ )),
+ ))
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/equalobject.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/equalobject.go
new file mode 100644
index 00000000000..a931c2718a9
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/equalobject.go
@@ -0,0 +1,297 @@
+/*
+Copyright 2022 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package komega
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+
+ "github.com/google/go-cmp/cmp"
+ "github.com/onsi/gomega/format"
+ "github.com/onsi/gomega/types"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// These package variables hold pre-created commonly used options that can be used to reduce the manual work involved in
+// identifying the paths that need to be compared for testing equality between objects.
+var (
+ // IgnoreAutogeneratedMetadata contains the paths for all the metadata fields that are commonly set by the
+ // client and APIServer. This is used as a MatchOption for situations when only user-provided metadata is relevant.
+ IgnoreAutogeneratedMetadata = IgnorePaths{
+ "metadata.uid",
+ "metadata.generation",
+ "metadata.creationTimestamp",
+ "metadata.resourceVersion",
+ "metadata.managedFields",
+ "metadata.deletionGracePeriodSeconds",
+ "metadata.deletionTimestamp",
+ "metadata.selfLink",
+ "metadata.generateName",
+ }
+)
+
+type diffPath struct {
+ types []string
+ json []string
+}
+
+// equalObjectMatcher is a Gomega matcher used to establish equality between two Kubernetes runtime.Objects.
+type equalObjectMatcher struct {
+ // original holds the object that will be used to Match.
+ original runtime.Object
+
+ // diffPaths contains the paths that differ between two objects.
+ diffPaths []diffPath
+
+ // options holds the options that identify what should and should not be matched.
+ options *EqualObjectOptions
+}
+
+// EqualObject returns a Matcher for the passed Kubernetes runtime.Object with the passed Options. This function can be
+// used as a Gomega Matcher in Gomega Assertions.
+func EqualObject(original runtime.Object, opts ...EqualObjectOption) types.GomegaMatcher {
+ matchOptions := &EqualObjectOptions{}
+ matchOptions = matchOptions.ApplyOptions(opts)
+
+ return &equalObjectMatcher{
+ options: matchOptions,
+ original: original,
+ }
+}
+
+// Match compares the current object to the passed object and returns true if the objects are the same according to
+// the Matcher and MatchOptions.
+func (m *equalObjectMatcher) Match(actual interface{}) (success bool, err error) {
+ // Nil checks required first here for:
+ // 1) Nil equality which returns true
+ // 2) One object nil which returns an error
+ actualIsNil := reflect.ValueOf(actual).IsNil()
+ originalIsNil := reflect.ValueOf(m.original).IsNil()
+
+ if actualIsNil && originalIsNil {
+ return true, nil
+ }
+ if actualIsNil || originalIsNil {
+ return false, fmt.Errorf("can not compare an object with a nil. original %v , actual %v", m.original, actual)
+ }
+
+ m.diffPaths = m.calculateDiff(actual)
+ return len(m.diffPaths) == 0, nil
+}
+
+// FailureMessage returns a message comparing the full objects after an unexpected failure to match has occurred.
+func (m *equalObjectMatcher) FailureMessage(actual interface{}) (message string) {
+ return fmt.Sprintf("the following fields were expected to match but did not:\n%v\n%s", m.diffPaths,
+ format.Message(actual, "expected to match", m.original))
+}
+
+// NegatedFailureMessage returns a string stating that all fields matched, even though that was not expected.
+func (m *equalObjectMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return "it was expected that some fields do not match, but all of them did"
+}
+
+func (d diffPath) String() string {
+ return fmt.Sprintf("(%s/%s)", strings.Join(d.types, "."), strings.Join(d.json, "."))
+}
+
+// diffReporter is a custom recorder for cmp.Diff which records all paths that are
+// different between two objects.
+type diffReporter struct {
+ stack []cmp.PathStep
+
+ diffPaths []diffPath
+}
+
+func (r *diffReporter) PushStep(s cmp.PathStep) {
+ r.stack = append(r.stack, s)
+}
+
+func (r *diffReporter) Report(res cmp.Result) {
+ if !res.Equal() {
+ r.diffPaths = append(r.diffPaths, r.currentPath())
+ }
+}
+
+// currentPath converts the current stack into string representations that match
+// the IgnorePaths and MatchPaths syntax.
+func (r *diffReporter) currentPath() diffPath {
+ p := diffPath{types: []string{""}, json: []string{""}}
+ for si, s := range r.stack[1:] {
+ switch s := s.(type) {
+ case cmp.StructField:
+ p.types = append(p.types, s.String()[1:])
+ // fetch the type information from the parent struct.
+ // Note: si has an offset of 1 compared to r.stack as we loop over r.stack[1:], so we don't need -1
+ field := r.stack[si].Type().Field(s.Index())
+ p.json = append(p.json, strings.Split(field.Tag.Get("json"), ",")[0])
+ case cmp.SliceIndex:
+ key := fmt.Sprintf("[%d]", s.Key())
+ p.types[len(p.types)-1] += key
+ p.json[len(p.json)-1] += key
+ case cmp.MapIndex:
+ key := fmt.Sprintf("%v", s.Key())
+ if strings.ContainsAny(key, ".[]/\\") {
+ key = fmt.Sprintf("[%s]", key)
+ p.types[len(p.types)-1] += key
+ p.json[len(p.json)-1] += key
+ } else {
+ p.types = append(p.types, key)
+ p.json = append(p.json, key)
+ }
+ }
+ }
+ // Empty strings were added as the first element. If they're still empty, remove them again.
+ if len(p.json) > 0 && len(p.json[0]) == 0 {
+ p.json = p.json[1:]
+ p.types = p.types[1:]
+ }
+ return p
+}
+
+func (r *diffReporter) PopStep() {
+ r.stack = r.stack[:len(r.stack)-1]
+}
+
+// calculateDiff calculates the difference between two objects and returns the
+// paths of the fields that do not match.
+func (m *equalObjectMatcher) calculateDiff(actual interface{}) []diffPath {
+ var original interface{} = m.original
+ // Remove the wrapping Object from unstructured.Unstructured to make comparison behave similar to
+ // regular objects.
+ if u, isUnstructured := actual.(runtime.Unstructured); isUnstructured {
+ actual = u.UnstructuredContent()
+ }
+ if u, ok := m.original.(runtime.Unstructured); ok {
+ original = u.UnstructuredContent()
+ }
+ r := diffReporter{}
+ cmp.Diff(original, actual, cmp.Reporter(&r))
+ return filterDiffPaths(*m.options, r.diffPaths)
+}
+
+// filterDiffPaths filters the diff paths using the paths in EqualObjectOptions.
+func filterDiffPaths(opts EqualObjectOptions, paths []diffPath) []diffPath {
+ result := []diffPath{}
+
+ for _, p := range paths {
+ if len(opts.matchPaths) > 0 && !hasAnyPathPrefix(p, opts.matchPaths) {
+ continue
+ }
+ if hasAnyPathPrefix(p, opts.ignorePaths) {
+ continue
+ }
+
+ result = append(result, p)
+ }
+
+ return result
+}
+
+// hasPathPrefix compares the segments of a path.
+func hasPathPrefix(path []string, prefix []string) bool {
+ for i, p := range prefix {
+ if i >= len(path) {
+ return false
+ }
+ // return false if a segment doesn't match
+ if path[i] != p && (i < len(prefix)-1 || !segmentHasPrefix(path[i], p)) {
+ return false
+ }
+ }
+ return true
+}
+
+func segmentHasPrefix(s, prefix string) bool {
+ return len(s) >= len(prefix) && s[0:len(prefix)] == prefix &&
+ // if it is a prefix match, make sure the next character is a [ for array/map access
+ (len(s) == len(prefix) || s[len(prefix)] == '[')
+}
+
+// hasAnyPathPrefix returns true if path matches any of the path prefixes.
+// It respects the name boundaries within paths, so 'ObjectMeta.Name' does not
+// match 'ObjectMeta.Namespace' for example.
+func hasAnyPathPrefix(path diffPath, prefixes [][]string) bool {
+ for _, prefix := range prefixes {
+ if hasPathPrefix(path.types, prefix) || hasPathPrefix(path.json, prefix) {
+ return true
+ }
+ }
+ return false
+}
+
+// EqualObjectOption describes an Option that can be applied to a Matcher.
+type EqualObjectOption interface {
+ // ApplyToEqualObjectMatcher applies this configuration to the given MatchOption.
+ ApplyToEqualObjectMatcher(options *EqualObjectOptions)
+}
+
+// EqualObjectOptions holds the available types of EqualObjectOptions that can be applied to a Matcher.
+type EqualObjectOptions struct {
+ ignorePaths [][]string
+ matchPaths [][]string
+}
+
+// ApplyOptions adds the passed MatchOptions to the MatchOptions struct.
+func (o *EqualObjectOptions) ApplyOptions(opts []EqualObjectOption) *EqualObjectOptions {
+ for _, opt := range opts {
+ opt.ApplyToEqualObjectMatcher(o)
+ }
+ return o
+}
+
+// IgnorePaths instructs the Matcher to ignore given paths when computing a diff.
+// Paths are written in a syntax similar to Go with a few special cases. Both types and
+// json/yaml field names are supported.
+//
+// Regular Paths:
+// * "ObjectMeta.Name"
+// * "metadata.name"
+// Arrays:
+// * "metadata.ownerReferences[0].name"
+// Maps, if they do not contain any of .[]/\:
+// * "metadata.labels.something"
+// Maps, if they contain any of .[]/\:
+// * "metadata.labels[kubernetes.io/something]"
+type IgnorePaths []string
+
+// ApplyToEqualObjectMatcher applies this configuration to the given MatchOptions.
+func (i IgnorePaths) ApplyToEqualObjectMatcher(opts *EqualObjectOptions) {
+ for _, p := range i {
+ opts.ignorePaths = append(opts.ignorePaths, strings.Split(p, "."))
+ }
+}
+
+// MatchPaths instructs the Matcher to restrict its diff to the given paths. If empty the Matcher will look at all paths.
+// Paths are written in a syntax similar to Go with a few special cases. Both types and
+// json/yaml field names are supported.
+//
+// Regular Paths:
+// * "ObjectMeta.Name"
+// * "metadata.name"
+// Arrays:
+// * "metadata.ownerReferences[0].name"
+// Maps, if they do not contain any of .[]/\:
+// * "metadata.labels.something"
+// Maps, if they contain any of .[]/\:
+// * "metadata.labels[kubernetes.io/something]"
+type MatchPaths []string
+
+// ApplyToEqualObjectMatcher applies this configuration to the given MatchOptions.
+func (i MatchPaths) ApplyToEqualObjectMatcher(opts *EqualObjectOptions) {
+ for _, p := range i {
+ opts.matchPaths = append(opts.ignorePaths, strings.Split(p, "."))
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/equalobject_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/equalobject_test.go
new file mode 100644
index 00000000000..9fe10d1779d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/equalobject_test.go
@@ -0,0 +1,662 @@
+package komega
+
+import (
+ "testing"
+
+ . "github.com/onsi/gomega"
+ appsv1 "k8s.io/api/apps/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+func TestEqualObjectMatcher(t *testing.T) {
+ cases := []struct {
+ name string
+ original client.Object
+ modified client.Object
+ options []EqualObjectOption
+ want bool
+ }{
+ {
+ name: "succeed with equal objects",
+ original: &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test",
+ },
+ },
+ modified: &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test",
+ },
+ },
+ want: true,
+ },
+ {
+ name: "fail with non equal objects",
+ original: &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test",
+ },
+ },
+ modified: &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "somethingelse",
+ },
+ },
+ want: false,
+ },
+ {
+ name: "succeeds if ignored fields do not match",
+ original: &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test",
+ Labels: map[string]string{"somelabel": "somevalue"},
+ OwnerReferences: []metav1.OwnerReference{{
+ Name: "controller",
+ }},
+ },
+ },
+ modified: &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "somethingelse",
+ Labels: map[string]string{"somelabel": "anothervalue"},
+ OwnerReferences: []metav1.OwnerReference{{
+ Name: "another",
+ }},
+ },
+ },
+ want: true,
+ options: []EqualObjectOption{
+ IgnorePaths{
+ "ObjectMeta.Name",
+ "ObjectMeta.CreationTimestamp",
+ "ObjectMeta.Labels.somelabel",
+ "ObjectMeta.OwnerReferences[0].Name",
+ "Spec.Template.ObjectMeta",
+ },
+ },
+ },
+ {
+ name: "succeeds if ignored fields in json notation do not match",
+ original: &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test",
+ Labels: map[string]string{"somelabel": "somevalue"},
+ OwnerReferences: []metav1.OwnerReference{{
+ Name: "controller",
+ }},
+ },
+ },
+ modified: &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "somethingelse",
+ Labels: map[string]string{"somelabel": "anothervalue"},
+ OwnerReferences: []metav1.OwnerReference{{
+ Name: "another",
+ }},
+ },
+ },
+ want: true,
+ options: []EqualObjectOption{
+ IgnorePaths{
+ "metadata.name",
+ "metadata.creationTimestamp",
+ "metadata.labels.somelabel",
+ "metadata.ownerReferences[0].name",
+ "spec.template.metadata",
+ },
+ },
+ },
+ {
+ name: "succeeds if all allowed fields match, and some others do not",
+ original: &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test",
+ Namespace: "default",
+ },
+ },
+ modified: &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test",
+ Namespace: "special",
+ },
+ },
+ want: true,
+ options: []EqualObjectOption{
+ MatchPaths{
+ "ObjectMeta.Name",
+ },
+ },
+ },
+ {
+ name: "works with unstructured.Unstructured",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "name": "something",
+ "namespace": "test",
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "name": "somethingelse",
+ "namespace": "test",
+ },
+ },
+ },
+ want: true,
+ options: []EqualObjectOption{
+ IgnorePaths{
+ "metadata.name",
+ },
+ },
+ },
+
+ // Test when objects are equal.
+ {
+ name: "Equal field (spec) both in original and in modified",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "foo": "bar",
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "foo": "bar",
+ },
+ },
+ },
+ want: true,
+ },
+
+ {
+ name: "Equal nested field both in original and in modified",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "template": map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ },
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "template": map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ },
+ },
+ },
+ },
+ want: true,
+ },
+
+ // Test when there is a difference between the objects.
+ {
+ name: "Unequal field both in original and in modified",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "foo": "bar-changed",
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "foo": "bar",
+ },
+ },
+ },
+ want: false,
+ },
+ {
+ name: "Unequal nested field both in original and modified",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "template": map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A-Changed",
+ },
+ },
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "template": map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ },
+ },
+ },
+ },
+ want: false,
+ },
+
+ {
+ name: "Value of type map with different values",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "map": map[string]string{
+ "A": "A-changed",
+ "B": "B",
+ // C missing
+ },
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "map": map[string]string{
+ "A": "A",
+ // B missing
+ "C": "C",
+ },
+ },
+ },
+ },
+ want: false,
+ },
+
+ {
+ name: "Value of type Array or Slice with same length but different values",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "slice": []string{
+ "D",
+ "C",
+ "B",
+ },
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "slice": []string{
+ "A",
+ "B",
+ "C",
+ },
+ },
+ },
+ },
+ want: false,
+ },
+
+ // This tests specific behaviour in how Kubernetes marshals the zero value of metav1.Time{}.
+ {
+ name: "Creation timestamp set to empty value on both original and modified",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ "metadata": map[string]interface{}{
+ "selfLink": "foo",
+ "creationTimestamp": metav1.Time{},
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ "metadata": map[string]interface{}{
+ "selfLink": "foo",
+ "creationTimestamp": metav1.Time{},
+ },
+ },
+ },
+ want: true,
+ },
+
+ // Cases to test diff when fields exist only in modified object.
+ {
+ name: "Field only in modified",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{},
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "foo": "bar",
+ },
+ },
+ },
+ want: false,
+ },
+ {
+ name: "Nested field only in modified",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{},
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "template": map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ },
+ },
+ },
+ },
+ want: false,
+ },
+ {
+ name: "Creation timestamp exists on modified but not on original",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ "metadata": map[string]interface{}{
+ "selfLink": "foo",
+ "creationTimestamp": "2021-11-03T11:05:17Z",
+ },
+ },
+ },
+ want: false,
+ },
+
+ // Test when fields exists only in the original object.
+ {
+ name: "Field only in original",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "foo": "bar",
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{},
+ },
+ want: false,
+ },
+ {
+ name: "Nested field only in original",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "template": map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ },
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{},
+ },
+ want: false,
+ },
+ {
+ name: "Creation timestamp exists on original but not on modified",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ "metadata": map[string]interface{}{
+ "selfLink": "foo",
+ "creationTimestamp": "2021-11-03T11:05:17Z",
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ },
+ },
+
+ want: false,
+ },
+
+ // Test metadata fields computed by the system or in status are compared.
+ {
+ name: "Unequal Metadata fields computed by the system or in status",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{},
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "selfLink": "foo",
+ "uid": "foo",
+ "resourceVersion": "foo",
+ "generation": "foo",
+ "managedFields": "foo",
+ },
+ "status": map[string]interface{}{
+ "foo": "bar",
+ },
+ },
+ },
+ want: false,
+ },
+ {
+ name: "Unequal labels and annotations",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{},
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "labels": map[string]interface{}{
+ "foo": "bar",
+ },
+ "annotations": map[string]interface{}{
+ "foo": "bar",
+ },
+ },
+ },
+ },
+ want: false,
+ },
+
+ // Ignore fields MatchOption
+ {
+ name: "Unequal metadata fields ignored by IgnorePaths MatchOption",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "name": "test",
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "name": "test",
+ "selfLink": "foo",
+ "uid": "foo",
+ "resourceVersion": "foo",
+ "generation": "foo",
+ "managedFields": "foo",
+ },
+ },
+ },
+ options: []EqualObjectOption{IgnoreAutogeneratedMetadata},
+ want: true,
+ },
+ {
+ name: "Unequal labels and annotations ignored by IgnorePaths MatchOption",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "name": "test",
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "name": "test",
+ "labels": map[string]interface{}{
+ "foo": "bar",
+ },
+ "annotations": map[string]interface{}{
+ "foo": "bar",
+ },
+ },
+ },
+ },
+ options: []EqualObjectOption{IgnorePaths{"metadata.labels", "metadata.annotations"}},
+ want: true,
+ },
+ {
+ name: "Ignore fields are not compared",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{},
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "controlPlaneEndpoint": map[string]interface{}{
+ "host": "",
+ "port": 0,
+ },
+ },
+ },
+ },
+ options: []EqualObjectOption{IgnorePaths{"spec.controlPlaneEndpoint"}},
+ want: true,
+ },
+ {
+ name: "Not-ignored fields are still compared",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "annotations": map[string]interface{}{},
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "annotations": map[string]interface{}{
+ "ignored": "somevalue",
+ "superflous": "shouldcausefailure",
+ },
+ },
+ },
+ },
+ options: []EqualObjectOption{IgnorePaths{"metadata.annotations.ignored"}},
+ want: false,
+ },
+
+ // MatchPaths MatchOption
+ {
+ name: "Unequal metadata fields not compared by setting MatchPaths MatchOption",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ },
+ "metadata": map[string]interface{}{
+ "selfLink": "foo",
+ "uid": "foo",
+ },
+ },
+ },
+ options: []EqualObjectOption{MatchPaths{"spec"}},
+ want: true,
+ },
+
+ // More tests
+ {
+ name: "No changes",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ "B": "B",
+ "C": "C", // C only in original
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ "B": "B",
+ },
+ },
+ },
+ want: false,
+ },
+ {
+ name: "Many changes",
+ original: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ // B missing
+ "C": "C", // C only in original
+ },
+ },
+ },
+ modified: &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "spec": map[string]interface{}{
+ "A": "A",
+ "B": "B",
+ },
+ },
+ },
+ want: false,
+ },
+ }
+
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ g := NewWithT(t)
+ m := EqualObject(c.original, c.options...)
+ success, _ := m.Match(c.modified)
+ if !success {
+ t.Log(m.FailureMessage(c.modified))
+ }
+ g.Expect(success).To(Equal(c.want))
+ })
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/interfaces.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/interfaces.go
new file mode 100644
index 00000000000..6f7e5db35b2
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/interfaces.go
@@ -0,0 +1,78 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package komega
+
+import (
+ "context"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// Komega is a collection of utilites for writing tests involving a mocked
+// Kubernetes API.
+type Komega interface {
+ // Get returns a function that fetches a resource and returns the occurring error.
+ // It can be used with gomega.Eventually() like this
+ // deployment := appsv1.Deployment{ ... }
+ // gomega.Eventually(k.Get(&deployment)).To(gomega.Succeed())
+ // By calling the returned function directly it can also be used with gomega.Expect(k.Get(...)()).To(...)
+ Get(client.Object) func() error
+
+ // List returns a function that lists resources and returns the occurring error.
+ // It can be used with gomega.Eventually() like this
+ // deployments := v1.DeploymentList{ ... }
+ // gomega.Eventually(k.List(&deployments)).To(gomega.Succeed())
+ // By calling the returned function directly it can also be used as gomega.Expect(k.List(...)()).To(...)
+ List(client.ObjectList, ...client.ListOption) func() error
+
+ // Update returns a function that fetches a resource, applies the provided update function and then updates the resource.
+ // It can be used with gomega.Eventually() like this:
+ // deployment := appsv1.Deployment{ ... }
+ // gomega.Eventually(k.Update(&deployment, func (o client.Object) {
+ // deployment.Spec.Replicas = 3
+ // return &deployment
+ // })).To(gomega.Succeed())
+ // By calling the returned function directly it can also be used as gomega.Expect(k.Update(...)()).To(...)
+ Update(client.Object, func(), ...client.UpdateOption) func() error
+
+ // UpdateStatus returns a function that fetches a resource, applies the provided update function and then updates the resource's status.
+ // It can be used with gomega.Eventually() like this:
+ // deployment := appsv1.Deployment{ ... }
+ // gomega.Eventually(k.Update(&deployment, func (o client.Object) {
+ // deployment.Status.AvailableReplicas = 1
+ // return &deployment
+ // })).To(gomega.Succeed())
+ // By calling the returned function directly it can also be used as gomega.Expect(k.UpdateStatus(...)()).To(...)
+ UpdateStatus(client.Object, func(), ...client.SubResourceUpdateOption) func() error
+
+ // Object returns a function that fetches a resource and returns the object.
+ // It can be used with gomega.Eventually() like this:
+ // deployment := appsv1.Deployment{ ... }
+ // gomega.Eventually(k.Object(&deployment)).To(HaveField("Spec.Replicas", gomega.Equal(pointer.Int32(3))))
+ // By calling the returned function directly it can also be used as gomega.Expect(k.Object(...)()).To(...)
+ Object(client.Object) func() (client.Object, error)
+
+ // ObjectList returns a function that fetches a resource and returns the object.
+ // It can be used with gomega.Eventually() like this:
+ // deployments := appsv1.DeploymentList{ ... }
+ // gomega.Eventually(k.ObjectList(&deployments)).To(HaveField("Items", HaveLen(1)))
+ // By calling the returned function directly it can also be used as gomega.Expect(k.ObjectList(...)()).To(...)
+ ObjectList(client.ObjectList, ...client.ListOption) func() (client.ObjectList, error)
+
+ // WithContext returns a copy that uses the given context.
+ WithContext(context.Context) Komega
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/komega.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/komega.go
new file mode 100644
index 00000000000..e19d9b5f0ba
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/komega.go
@@ -0,0 +1,117 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package komega
+
+import (
+ "context"
+
+ "k8s.io/apimachinery/pkg/types"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// komega is a collection of utilites for writing tests involving a mocked
+// Kubernetes API.
+type komega struct {
+ ctx context.Context
+ client client.Client
+}
+
+var _ Komega = &komega{}
+
+// New creates a new Komega instance with the given client.
+func New(c client.Client) Komega {
+ return &komega{
+ client: c,
+ ctx: context.Background(),
+ }
+}
+
+// WithContext returns a copy that uses the given context.
+func (k komega) WithContext(ctx context.Context) Komega {
+ k.ctx = ctx
+ return &k
+}
+
+// Get returns a function that fetches a resource and returns the occurring error.
+func (k *komega) Get(obj client.Object) func() error {
+ key := types.NamespacedName{
+ Name: obj.GetName(),
+ Namespace: obj.GetNamespace(),
+ }
+ return func() error {
+ return k.client.Get(k.ctx, key, obj)
+ }
+}
+
+// List returns a function that lists resources and returns the occurring error.
+func (k *komega) List(obj client.ObjectList, opts ...client.ListOption) func() error {
+ return func() error {
+ return k.client.List(k.ctx, obj, opts...)
+ }
+}
+
+// Update returns a function that fetches a resource, applies the provided update function and then updates the resource.
+func (k *komega) Update(obj client.Object, updateFunc func(), opts ...client.UpdateOption) func() error {
+ key := types.NamespacedName{
+ Name: obj.GetName(),
+ Namespace: obj.GetNamespace(),
+ }
+ return func() error {
+ err := k.client.Get(k.ctx, key, obj)
+ if err != nil {
+ return err
+ }
+ updateFunc()
+ return k.client.Update(k.ctx, obj, opts...)
+ }
+}
+
+// UpdateStatus returns a function that fetches a resource, applies the provided update function and then updates the resource's status.
+func (k *komega) UpdateStatus(obj client.Object, updateFunc func(), opts ...client.SubResourceUpdateOption) func() error {
+ key := types.NamespacedName{
+ Name: obj.GetName(),
+ Namespace: obj.GetNamespace(),
+ }
+ return func() error {
+ err := k.client.Get(k.ctx, key, obj)
+ if err != nil {
+ return err
+ }
+ updateFunc()
+ return k.client.Status().Update(k.ctx, obj, opts...)
+ }
+}
+
+// Object returns a function that fetches a resource and returns the object.
+func (k *komega) Object(obj client.Object) func() (client.Object, error) {
+ key := types.NamespacedName{
+ Name: obj.GetName(),
+ Namespace: obj.GetNamespace(),
+ }
+ return func() (client.Object, error) {
+ err := k.client.Get(k.ctx, key, obj)
+ return obj, err
+ }
+}
+
+// ObjectList returns a function that fetches a resource and returns the object.
+func (k *komega) ObjectList(obj client.ObjectList, opts ...client.ListOption) func() (client.ObjectList, error) {
+ return func() (client.ObjectList, error) {
+ err := k.client.List(k.ctx, obj, opts...)
+ return obj, err
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/komega_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/komega_test.go
new file mode 100644
index 00000000000..275610c8bb0
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/komega/komega_test.go
@@ -0,0 +1,138 @@
+package komega
+
+import (
+ "testing"
+
+ _ "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ appsv1 "k8s.io/api/apps/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/utils/pointer"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
+)
+
+func exampleDeployment() *appsv1.Deployment {
+ return &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: "test",
+ },
+ Spec: appsv1.DeploymentSpec{
+ Replicas: pointer.Int32(5),
+ },
+ }
+}
+
+func createFakeClient() client.Client {
+ return fakeclient.NewClientBuilder().
+ WithObjects(exampleDeployment()).
+ Build()
+}
+
+func TestGet(t *testing.T) {
+ g := NewWithT(t)
+
+ fc := createFakeClient()
+ k := New(fc)
+
+ fetched := appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: "test",
+ },
+ }
+ g.Eventually(k.Get(&fetched)).Should(Succeed())
+
+ g.Expect(*fetched.Spec.Replicas).To(BeEquivalentTo(5))
+}
+
+func TestList(t *testing.T) {
+ g := NewWithT(t)
+
+ fc := createFakeClient()
+ k := New(fc)
+
+ list := appsv1.DeploymentList{}
+ g.Eventually(k.List(&list)).Should(Succeed())
+
+ g.Expect(list.Items).To(HaveLen(1))
+ depl := exampleDeployment()
+ g.Expect(list.Items[0]).To(And(
+ HaveField("ObjectMeta.Name", Equal(depl.ObjectMeta.Name)),
+ HaveField("ObjectMeta.Namespace", Equal(depl.ObjectMeta.Namespace)),
+ ))
+}
+
+func TestUpdate(t *testing.T) {
+ g := NewWithT(t)
+
+ fc := createFakeClient()
+ k := New(fc)
+
+ updateDeployment := appsv1.Deployment{
+ ObjectMeta: exampleDeployment().ObjectMeta,
+ }
+ g.Eventually(k.Update(&updateDeployment, func() {
+ updateDeployment.Annotations = map[string]string{"updated": "true"}
+ })).Should(Succeed())
+
+ fetched := appsv1.Deployment{
+ ObjectMeta: exampleDeployment().ObjectMeta,
+ }
+ g.Expect(k.Object(&fetched)()).To(HaveField("ObjectMeta.Annotations", HaveKeyWithValue("updated", "true")))
+}
+
+func TestUpdateStatus(t *testing.T) {
+ g := NewWithT(t)
+
+ fc := createFakeClient()
+ k := New(fc)
+
+ updateDeployment := appsv1.Deployment{
+ ObjectMeta: exampleDeployment().ObjectMeta,
+ }
+ g.Eventually(k.UpdateStatus(&updateDeployment, func() {
+ updateDeployment.Status.AvailableReplicas = 1
+ })).Should(Succeed())
+
+ fetched := appsv1.Deployment{
+ ObjectMeta: exampleDeployment().ObjectMeta,
+ }
+ g.Expect(k.Object(&fetched)()).To(HaveField("Status.AvailableReplicas", BeEquivalentTo(1)))
+}
+
+func TestObject(t *testing.T) {
+ g := NewWithT(t)
+
+ fc := createFakeClient()
+ k := New(fc)
+
+ fetched := appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: "test",
+ },
+ }
+ g.Eventually(k.Object(&fetched)).Should(And(
+ Not(BeNil()),
+ HaveField("Spec.Replicas", Equal(pointer.Int32(5))),
+ ))
+}
+
+func TestObjectList(t *testing.T) {
+ g := NewWithT(t)
+
+ fc := createFakeClient()
+ k := New(fc)
+
+ list := appsv1.DeploymentList{}
+ g.Eventually(k.ObjectList(&list)).Should(And(
+ Not(BeNil()),
+ HaveField("Items", And(
+ HaveLen(1),
+ ContainElement(HaveField("Spec.Replicas", Equal(pointer.Int32(5)))),
+ )),
+ ))
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/server.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/server.go
new file mode 100644
index 00000000000..4ee440df9c0
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/server.go
@@ -0,0 +1,376 @@
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package envtest
+
+import (
+ "fmt"
+ "os"
+ "strings"
+ "time"
+
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+
+ "sigs.k8s.io/controller-runtime/pkg/client/config"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/process"
+)
+
+var log = logf.RuntimeLog.WithName("test-env")
+
+/*
+It's possible to override some defaults, by setting the following environment variables:
+* USE_EXISTING_CLUSTER (boolean): if set to true, envtest will use an existing cluster
+* TEST_ASSET_KUBE_APISERVER (string): path to the api-server binary to use
+* TEST_ASSET_ETCD (string): path to the etcd binary to use
+* TEST_ASSET_KUBECTL (string): path to the kubectl binary to use
+* KUBEBUILDER_ASSETS (string): directory containing the binaries to use (api-server, etcd and kubectl). Defaults to /usr/local/kubebuilder/bin.
+* KUBEBUILDER_CONTROLPLANE_START_TIMEOUT (string supported by time.ParseDuration): timeout for test control plane to start. Defaults to 20s.
+* KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT (string supported by time.ParseDuration): timeout for test control plane to start. Defaults to 20s.
+* KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT (boolean): if set to true, the control plane's stdout and stderr are attached to os.Stdout and os.Stderr
+*/
+const (
+ envUseExistingCluster = "USE_EXISTING_CLUSTER"
+ envStartTimeout = "KUBEBUILDER_CONTROLPLANE_START_TIMEOUT"
+ envStopTimeout = "KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT"
+ envAttachOutput = "KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT"
+ StartTimeout = 60
+ StopTimeout = 60
+
+ defaultKubebuilderControlPlaneStartTimeout = 20 * time.Second
+ defaultKubebuilderControlPlaneStopTimeout = 20 * time.Second
+)
+
+// internal types we expose as part of our public API.
+type (
+ // ControlPlane is the re-exported ControlPlane type from the internal testing package.
+ ControlPlane = controlplane.ControlPlane
+
+ // APIServer is the re-exported APIServer from the internal testing package.
+ APIServer = controlplane.APIServer
+
+ // Etcd is the re-exported Etcd from the internal testing package.
+ Etcd = controlplane.Etcd
+
+ // User represents a Kubernetes user to provision for auth purposes.
+ User = controlplane.User
+
+ // AuthenticatedUser represets a Kubernetes user that's been provisioned.
+ AuthenticatedUser = controlplane.AuthenticatedUser
+
+ // ListenAddr indicates the address and port that the API server should listen on.
+ ListenAddr = process.ListenAddr
+
+ // SecureServing contains details describing how the API server should serve
+ // its secure endpoint.
+ SecureServing = controlplane.SecureServing
+
+ // Authn is an authentication method that can be used with the control plane to
+ // provision users.
+ Authn = controlplane.Authn
+
+ // Arguments allows configuring a process's flags.
+ Arguments = process.Arguments
+
+ // Arg is a single flag with one or more values.
+ Arg = process.Arg
+)
+
+var (
+ // EmptyArguments constructs a new set of flags with nothing set.
+ //
+ // This is mostly useful for testing helper methods -- you'll want to call
+ // Configure on the APIServer (or etcd) to configure their arguments.
+ EmptyArguments = process.EmptyArguments
+)
+
+// Environment creates a Kubernetes test environment that will start / stop the Kubernetes control plane and
+// install extension APIs.
+type Environment struct {
+ // ControlPlane is the ControlPlane including the apiserver and etcd
+ ControlPlane controlplane.ControlPlane
+
+ // Scheme is used to determine if conversion webhooks should be enabled
+ // for a particular CRD / object.
+ //
+ // Conversion webhooks are going to be enabled if an object in the scheme
+ // implements Hub and Spoke conversions.
+ //
+ // If nil, scheme.Scheme is used.
+ Scheme *runtime.Scheme
+
+ // Config can be used to talk to the apiserver. It's automatically
+ // populated if not set using the standard controller-runtime config
+ // loading.
+ Config *rest.Config
+
+ // CRDInstallOptions are the options for installing CRDs.
+ CRDInstallOptions CRDInstallOptions
+
+ // WebhookInstallOptions are the options for installing webhooks.
+ WebhookInstallOptions WebhookInstallOptions
+
+ // ErrorIfCRDPathMissing provides an interface for the underlying
+ // CRDInstallOptions.ErrorIfPathMissing. It prevents silent failures
+ // for missing CRD paths.
+ ErrorIfCRDPathMissing bool
+
+ // CRDs is a list of CRDs to install.
+ // If both this field and CRDs field in CRDInstallOptions are specified, the
+ // values are merged.
+ CRDs []*apiextensionsv1.CustomResourceDefinition
+
+ // CRDDirectoryPaths is a list of paths containing CRD yaml or json configs.
+ // If both this field and Paths field in CRDInstallOptions are specified, the
+ // values are merged.
+ CRDDirectoryPaths []string
+
+ // BinaryAssetsDirectory is the path where the binaries required for the envtest are
+ // located in the local environment. This field can be overridden by setting KUBEBUILDER_ASSETS.
+ BinaryAssetsDirectory string
+
+ // UseExistingCluster indicates that this environments should use an
+ // existing kubeconfig, instead of trying to stand up a new control plane.
+ // This is useful in cases that need aggregated API servers and the like.
+ UseExistingCluster *bool
+
+ // ControlPlaneStartTimeout is the maximum duration each controlplane component
+ // may take to start. It defaults to the KUBEBUILDER_CONTROLPLANE_START_TIMEOUT
+ // environment variable or 20 seconds if unspecified
+ ControlPlaneStartTimeout time.Duration
+
+ // ControlPlaneStopTimeout is the maximum duration each controlplane component
+ // may take to stop. It defaults to the KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT
+ // environment variable or 20 seconds if unspecified
+ ControlPlaneStopTimeout time.Duration
+
+ // KubeAPIServerFlags is the set of flags passed while starting the api server.
+ //
+ // Deprecated: use ControlPlane.GetAPIServer().Configure() instead.
+ KubeAPIServerFlags []string
+
+ // AttachControlPlaneOutput indicates if control plane output will be attached to os.Stdout and os.Stderr.
+ // Enable this to get more visibility of the testing control plane.
+ // It respect KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT environment variable.
+ AttachControlPlaneOutput bool
+}
+
+// Stop stops a running server.
+// Previously installed CRDs, as listed in CRDInstallOptions.CRDs, will be uninstalled
+// if CRDInstallOptions.CleanUpAfterUse are set to true.
+func (te *Environment) Stop() error {
+ if te.CRDInstallOptions.CleanUpAfterUse {
+ if err := UninstallCRDs(te.Config, te.CRDInstallOptions); err != nil {
+ return err
+ }
+ }
+
+ if err := te.WebhookInstallOptions.Cleanup(); err != nil {
+ return err
+ }
+
+ if te.useExistingCluster() {
+ return nil
+ }
+
+ return te.ControlPlane.Stop()
+}
+
+// Start starts a local Kubernetes server and updates te.ApiserverPort with the port it is listening on.
+func (te *Environment) Start() (*rest.Config, error) {
+ if te.useExistingCluster() {
+ log.V(1).Info("using existing cluster")
+ if te.Config == nil {
+ // we want to allow people to pass in their own config, so
+ // only load a config if it hasn't already been set.
+ log.V(1).Info("automatically acquiring client configuration")
+
+ var err error
+ te.Config, err = config.GetConfig()
+ if err != nil {
+ return nil, fmt.Errorf("unable to get configuration for existing cluster: %w", err)
+ }
+ }
+ } else {
+ apiServer := te.ControlPlane.GetAPIServer()
+ if len(apiServer.Args) == 0 { //nolint:staticcheck
+ // pass these through separately from above in case something like
+ // AddUser defaults APIServer.
+ //
+ // TODO(directxman12): if/when we feel like making a bigger
+ // breaking change here, just make APIServer and Etcd non-pointers
+ // in ControlPlane.
+
+ // NB(directxman12): we still pass these in so that things work if the
+ // user manually specifies them, but in most cases we expect them to
+ // be nil so that we use the new .Configure() logic.
+ apiServer.Args = te.KubeAPIServerFlags //nolint:staticcheck
+ }
+ if te.ControlPlane.Etcd == nil {
+ te.ControlPlane.Etcd = &controlplane.Etcd{}
+ }
+
+ if os.Getenv(envAttachOutput) == "true" {
+ te.AttachControlPlaneOutput = true
+ }
+ if te.AttachControlPlaneOutput {
+ if apiServer.Out == nil {
+ apiServer.Out = os.Stdout
+ }
+ if apiServer.Err == nil {
+ apiServer.Err = os.Stderr
+ }
+ if te.ControlPlane.Etcd.Out == nil {
+ te.ControlPlane.Etcd.Out = os.Stdout
+ }
+ if te.ControlPlane.Etcd.Err == nil {
+ te.ControlPlane.Etcd.Err = os.Stderr
+ }
+ }
+
+ apiServer.Path = process.BinPathFinder("kube-apiserver", te.BinaryAssetsDirectory)
+ te.ControlPlane.Etcd.Path = process.BinPathFinder("etcd", te.BinaryAssetsDirectory)
+ te.ControlPlane.KubectlPath = process.BinPathFinder("kubectl", te.BinaryAssetsDirectory)
+
+ if err := te.defaultTimeouts(); err != nil {
+ return nil, fmt.Errorf("failed to default controlplane timeouts: %w", err)
+ }
+ te.ControlPlane.Etcd.StartTimeout = te.ControlPlaneStartTimeout
+ te.ControlPlane.Etcd.StopTimeout = te.ControlPlaneStopTimeout
+ apiServer.StartTimeout = te.ControlPlaneStartTimeout
+ apiServer.StopTimeout = te.ControlPlaneStopTimeout
+
+ log.V(1).Info("starting control plane")
+ if err := te.startControlPlane(); err != nil {
+ return nil, fmt.Errorf("unable to start control plane itself: %w", err)
+ }
+
+ // Create the *rest.Config for creating new clients
+ baseConfig := &rest.Config{
+ // gotta go fast during tests -- we don't really care about overwhelming our test API server
+ QPS: 1000.0,
+ Burst: 2000.0,
+ }
+
+ adminInfo := User{Name: "admin", Groups: []string{"system:masters"}}
+ adminUser, err := te.ControlPlane.AddUser(adminInfo, baseConfig)
+ if err != nil {
+ return te.Config, fmt.Errorf("unable to provision admin user: %w", err)
+ }
+ te.Config = adminUser.Config()
+ }
+
+ // Set the default scheme if nil.
+ if te.Scheme == nil {
+ te.Scheme = scheme.Scheme
+ }
+
+ // Call PrepWithoutInstalling to setup certificates first
+ // and have them available to patch CRD conversion webhook as well.
+ if err := te.WebhookInstallOptions.PrepWithoutInstalling(); err != nil {
+ return nil, err
+ }
+
+ log.V(1).Info("installing CRDs")
+ te.CRDInstallOptions.CRDs = mergeCRDs(te.CRDInstallOptions.CRDs, te.CRDs)
+ te.CRDInstallOptions.Paths = mergePaths(te.CRDInstallOptions.Paths, te.CRDDirectoryPaths)
+ te.CRDInstallOptions.ErrorIfPathMissing = te.ErrorIfCRDPathMissing
+ te.CRDInstallOptions.WebhookOptions = te.WebhookInstallOptions
+ crds, err := InstallCRDs(te.Config, te.CRDInstallOptions)
+ if err != nil {
+ return te.Config, fmt.Errorf("unable to install CRDs onto control plane: %w", err)
+ }
+ te.CRDs = crds
+
+ log.V(1).Info("installing webhooks")
+ if err := te.WebhookInstallOptions.Install(te.Config); err != nil {
+ return nil, fmt.Errorf("unable to install webhooks onto control plane: %w", err)
+ }
+ return te.Config, nil
+}
+
+// AddUser provisions a new user for connecting to this Environment. The user will
+// have the specified name & belong to the specified groups.
+//
+// If you specify a "base" config, the returned REST Config will contain those
+// settings as well as any required by the authentication method. You can use
+// this to easily specify options like QPS.
+//
+// This is effectively a convinience alias for ControlPlane.AddUser -- see that
+// for more low-level details.
+func (te *Environment) AddUser(user User, baseConfig *rest.Config) (*AuthenticatedUser, error) {
+ return te.ControlPlane.AddUser(user, baseConfig)
+}
+
+func (te *Environment) startControlPlane() error {
+ numTries, maxRetries := 0, 5
+ var err error
+ for ; numTries < maxRetries; numTries++ {
+ // Start the control plane - retry if it fails
+ err = te.ControlPlane.Start()
+ if err == nil {
+ break
+ }
+ log.Error(err, "unable to start the controlplane", "tries", numTries)
+ }
+ if numTries == maxRetries {
+ return fmt.Errorf("failed to start the controlplane. retried %d times: %w", numTries, err)
+ }
+ return nil
+}
+
+func (te *Environment) defaultTimeouts() error {
+ var err error
+ if te.ControlPlaneStartTimeout == 0 {
+ if envVal := os.Getenv(envStartTimeout); envVal != "" {
+ te.ControlPlaneStartTimeout, err = time.ParseDuration(envVal)
+ if err != nil {
+ return err
+ }
+ } else {
+ te.ControlPlaneStartTimeout = defaultKubebuilderControlPlaneStartTimeout
+ }
+ }
+
+ if te.ControlPlaneStopTimeout == 0 {
+ if envVal := os.Getenv(envStopTimeout); envVal != "" {
+ te.ControlPlaneStopTimeout, err = time.ParseDuration(envVal)
+ if err != nil {
+ return err
+ }
+ } else {
+ te.ControlPlaneStopTimeout = defaultKubebuilderControlPlaneStopTimeout
+ }
+ }
+ return nil
+}
+
+func (te *Environment) useExistingCluster() bool {
+ if te.UseExistingCluster == nil {
+ return strings.ToLower(os.Getenv(envUseExistingCluster)) == "true"
+ }
+ return *te.UseExistingCluster
+}
+
+// DefaultKubeAPIServerFlags exposes the default args for the APIServer so that
+// you can use those to append your own additional arguments.
+//
+// Deprecated: use APIServer.Configure() instead.
+var DefaultKubeAPIServerFlags = controlplane.APIServerDefaultArgs //nolint:staticcheck
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/crds/examplecrd3.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/crds/examplecrd3.yaml
new file mode 100644
index 00000000000..479a6e56458
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/crds/examplecrd3.yaml
@@ -0,0 +1,17 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: configs.foo.example.com
+spec:
+ group: foo.example.com
+ names:
+ kind: Config
+ plural: configs
+ scope: Namespaced
+ versions:
+ - name: "v1beta1"
+ storage: true
+ served: true
+ schema:
+ openAPIV3Schema:
+ type: object
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/crds/examplecrd_unserved.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/crds/examplecrd_unserved.yaml
new file mode 100644
index 00000000000..09fac4f0804
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/crds/examplecrd_unserved.yaml
@@ -0,0 +1,88 @@
+
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.3.0
+ creationTimestamp: null
+ name: frigates.ship.example.com
+spec:
+ group: ship.example.com
+ names:
+ kind: Frigate
+ listKind: FrigateList
+ plural: frigates
+ singular: frigate
+ scope: Namespaced
+ subresources:
+ status: {}
+ versions:
+ - name: v1
+ served: false
+ storage: true
+ schema:
+ openAPIV3Schema:
+ description: Frigate is the Schema for the frigates 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: FrigateSpec defines the desired state of Frigate
+ properties:
+ foo:
+ description: Foo is an example field of Frigate. Edit Frigate_types.go
+ to remove/update
+ type: string
+ type: object
+ status:
+ description: FrigateStatus defines the observed state of Frigate
+ type: object
+ type: object
+ - name: v1beta1
+ served: false
+ storage: false
+ schema:
+ openAPIV3Schema:
+ description: Frigate is the Schema for the frigates 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: FrigateSpec defines the desired state of Frigate
+ properties:
+ foo:
+ description: Foo is an example field of Frigate. Edit Frigate_types.go
+ to remove/update
+ type: string
+ type: object
+ status:
+ description: FrigateStatus defines the observed state of Frigate
+ type: object
+ type: object
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/crdv1_original/example_multiversion_crd1.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/crdv1_original/example_multiversion_crd1.yaml
new file mode 100644
index 00000000000..5dead8186a0
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/crdv1_original/example_multiversion_crd1.yaml
@@ -0,0 +1,61 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: drivers.crew.example.com
+spec:
+ group: crew.example.com
+ names:
+ kind: Driver
+ plural: drivers
+ scope: ""
+ versions:
+ - name: v1
+ served: true
+ storage: true
+ schema:
+ openAPIV3Schema:
+ description: Driver is the Schema for the drivers 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/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/api-conventions.md#types-kinds'
+ type: string
+ spec:
+ type: object
+ status:
+ type: object
+ type: object
+ - name: v2
+ served: true
+ storage: false
+ schema:
+ openAPIV3Schema:
+ description: Driver is the Schema for the drivers 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/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/api-conventions.md#types-kinds'
+ type: string
+ spec:
+ type: object
+ status:
+ type: object
+ type: object
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/crdv1_updated/example_multiversion_crd1_one_more_version.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/crdv1_updated/example_multiversion_crd1_one_more_version.yaml
new file mode 100644
index 00000000000..9eb0ec91a26
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/crdv1_updated/example_multiversion_crd1_one_more_version.yaml
@@ -0,0 +1,83 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: drivers.crew.example.com
+spec:
+ group: crew.example.com
+ names:
+ kind: Driver
+ plural: drivers
+ scope: Namespaced
+ versions:
+ - name: v1
+ served: true
+ storage: true
+ schema:
+ openAPIV3Schema:
+ description: Driver is the Schema for the drivers 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/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/api-conventions.md#types-kinds'
+ type: string
+ spec:
+ type: object
+ status:
+ type: object
+ type: object
+ - name: v2
+ served: true
+ storage: false
+ schema:
+ openAPIV3Schema:
+ description: Driver is the Schema for the drivers 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/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/api-conventions.md#types-kinds'
+ type: string
+ spec:
+ type: object
+ status:
+ type: object
+ type: object
+ - name: v3
+ served: true
+ storage: false
+ schema:
+ openAPIV3Schema:
+ description: Driver is the Schema for the drivers 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/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/api-conventions.md#types-kinds'
+ type: string
+ spec:
+ type: object
+ status:
+ type: object
+ type: object
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/example_multiversion_crd1.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/example_multiversion_crd1.yaml
new file mode 100644
index 00000000000..5bb2d73f698
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/example_multiversion_crd1.yaml
@@ -0,0 +1,62 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ creationTimestamp: null
+ name: drivers.crew.example.com
+spec:
+ group: crew.example.com
+ names:
+ kind: Driver
+ plural: drivers
+ scope: Namespaced
+ versions:
+ - name: v1
+ served: true
+ storage: true
+ schema:
+ openAPIV3Schema:
+ description: Driver is the Schema for the drivers 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/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/api-conventions.md#types-kinds'
+ type: string
+ spec:
+ type: object
+ status:
+ type: object
+ type: object
+ - name: v2
+ served: true
+ storage: false
+ schema:
+ openAPIV3Schema:
+ description: Driver is the Schema for the drivers 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/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/api-conventions.md#types-kinds'
+ type: string
+ spec:
+ type: object
+ status:
+ type: object
+ type: object
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/examplecrd.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/examplecrd.yaml
new file mode 100644
index 00000000000..f1638f83102
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/examplecrd.yaml
@@ -0,0 +1,17 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: bazs.qux.example.com
+spec:
+ group: qux.example.com
+ names:
+ kind: Baz
+ plural: bazs
+ scope: Namespaced
+ versions:
+ - name: "v1beta1"
+ storage: true
+ served: true
+ schema:
+ openAPIV3Schema:
+ type: object
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/examplecrd_v1.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/examplecrd_v1.yaml
new file mode 100644
index 00000000000..e2bddbc528b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/examplecrd_v1.yaml
@@ -0,0 +1,17 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: foos.bar.example.com
+spec:
+ group: bar.example.com
+ names:
+ kind: Foo
+ plural: foos
+ scope: Namespaced
+ versions:
+ - name: "v1"
+ storage: true
+ served: true
+ schema:
+ openAPIV3Schema:
+ type: object
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/multiplecrds.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/multiplecrds.yaml
new file mode 100644
index 00000000000..a855140ead3
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/multiplecrds.yaml
@@ -0,0 +1,37 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: captains.crew.example.com
+spec:
+ group: crew.example.com
+ names:
+ kind: Captain
+ plural: captains
+ scope: Namespaced
+ versions:
+ - name: "v1beta1"
+ storage: true
+ served: true
+ schema:
+ openAPIV3Schema:
+ type: object
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: firstmates.crew.example.com
+spec:
+ group: crew.example.com
+ names:
+ kind: FirstMate
+ plural: firstmates
+ scope: Namespaced
+ versions:
+ - name: "v1beta1"
+ storage: true
+ served: true
+ schema:
+ openAPIV3Schema:
+ type: object
+---
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/notcrd.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/notcrd.yaml
new file mode 100644
index 00000000000..a0f1f582c87
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/notcrd.yaml
@@ -0,0 +1,18 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: nginx-deployment
+ labels:
+ app: nginx
+spec:
+ selector:
+ matchLabels:
+ app: nginx
+ template:
+ metadata:
+ labels:
+ app: nginx
+ spec:
+ containers:
+ - name: nginx
+ image: nginx:1.7.9
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/webhooks/manifests.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/webhooks/manifests.yaml
new file mode 100644
index 00000000000..72437905cdc
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/testdata/webhooks/manifests.yaml
@@ -0,0 +1,101 @@
+---
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+ creationTimestamp: null
+ name: mutating-webhook-configuration
+webhooks:
+- clientConfig:
+ caBundle: Cg==
+ service:
+ name: webhook-service
+ namespace: system
+ path: /mutate-v1
+ failurePolicy: Fail
+ name: mpods.kb.io
+ rules:
+ - apiGroups:
+ - ""
+ apiVersions:
+ - v1
+ operations:
+ - CREATE
+ - UPDATE
+ resources:
+ - pods
+---
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+ creationTimestamp: null
+ name: mutating-webhook-configuration2
+webhooks:
+- clientConfig:
+ caBundle: Cg==
+ service:
+ name: webhook-service
+ namespace: system
+ path: /mutate-v1
+ failurePolicy: Fail
+ name: mpods2.kb.io
+ rules:
+ - apiGroups:
+ - ""
+ apiVersions:
+ - v1
+ operations:
+ - CREATE
+ - UPDATE
+ resources:
+ - pods
+---
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+ creationTimestamp: null
+ name: validating-webhook-configuration
+webhooks:
+- clientConfig:
+ caBundle: Cg==
+ service:
+ name: webhook-service
+ namespace: system
+ path: /validate-v1
+ failurePolicy: Fail
+ name: vpods.kb.io
+ rules:
+ - apiGroups:
+ - ""
+ apiVersions:
+ - v1
+ operations:
+ - CREATE
+ - UPDATE
+ resources:
+ - pods
+---
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+ creationTimestamp: null
+ name: validating-webhook-configuration2
+webhooks:
+- clientConfig:
+ caBundle: Cg==
+ service:
+ name: webhook-service
+ namespace: system
+ path: /validate-v1
+ failurePolicy: Fail
+ name: vpods2.kb.io
+ rules:
+ - apiGroups:
+ - ""
+ apiVersions:
+ - v1
+ operations:
+ - CREATE
+ - UPDATE
+ resources:
+ - pods
+
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/webhook.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/webhook.go
new file mode 100644
index 00000000000..f7e43a14802
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/webhook.go
@@ -0,0 +1,445 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package envtest
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "os"
+ "path/filepath"
+ "time"
+
+ admissionv1 "k8s.io/api/admissionregistration/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/util/sets"
+ "k8s.io/apimachinery/pkg/util/wait"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/yaml"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/addr"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/certs"
+)
+
+// WebhookInstallOptions are the options for installing mutating or validating webhooks.
+type WebhookInstallOptions struct {
+ // Paths is a list of paths to the directories or files containing the mutating or validating webhooks yaml or json configs.
+ Paths []string
+
+ // MutatingWebhooks is a list of MutatingWebhookConfigurations to install
+ MutatingWebhooks []*admissionv1.MutatingWebhookConfiguration
+
+ // ValidatingWebhooks is a list of ValidatingWebhookConfigurations to install
+ ValidatingWebhooks []*admissionv1.ValidatingWebhookConfiguration
+
+ // IgnoreErrorIfPathMissing will ignore an error if a DirectoryPath does not exist when set to true
+ IgnoreErrorIfPathMissing bool
+
+ // LocalServingHost is the host for serving webhooks on.
+ // it will be automatically populated
+ LocalServingHost string
+
+ // LocalServingPort is the allocated port for serving webhooks on.
+ // it will be automatically populated by a random available local port
+ LocalServingPort int
+
+ // LocalServingCertDir is the allocated directory for serving certificates.
+ // it will be automatically populated by the local temp dir
+ LocalServingCertDir string
+
+ // CAData is the CA that can be used to trust the serving certificates in LocalServingCertDir.
+ LocalServingCAData []byte
+
+ // LocalServingHostExternalName is the hostname to use to reach the webhook server.
+ LocalServingHostExternalName string
+
+ // MaxTime is the max time to wait
+ MaxTime time.Duration
+
+ // PollInterval is the interval to check
+ PollInterval time.Duration
+}
+
+// ModifyWebhookDefinitions modifies webhook definitions by:
+// - applying CABundle based on the provided tinyca
+// - if webhook client config uses service spec, it's removed and replaced with direct url.
+func (o *WebhookInstallOptions) ModifyWebhookDefinitions() error {
+ caData := o.LocalServingCAData
+
+ // generate host port.
+ hostPort, err := o.generateHostPort()
+ if err != nil {
+ return err
+ }
+
+ for i := range o.MutatingWebhooks {
+ for j := range o.MutatingWebhooks[i].Webhooks {
+ updateClientConfig(&o.MutatingWebhooks[i].Webhooks[j].ClientConfig, hostPort, caData)
+ }
+ }
+
+ for i := range o.ValidatingWebhooks {
+ for j := range o.ValidatingWebhooks[i].Webhooks {
+ updateClientConfig(&o.ValidatingWebhooks[i].Webhooks[j].ClientConfig, hostPort, caData)
+ }
+ }
+ return nil
+}
+
+func updateClientConfig(cc *admissionv1.WebhookClientConfig, hostPort string, caData []byte) {
+ cc.CABundle = caData
+ if cc.Service != nil && cc.Service.Path != nil {
+ url := fmt.Sprintf("https://%s/%s", hostPort, *cc.Service.Path)
+ cc.URL = &url
+ cc.Service = nil
+ }
+}
+
+func (o *WebhookInstallOptions) generateHostPort() (string, error) {
+ if o.LocalServingPort == 0 {
+ port, host, err := addr.Suggest(o.LocalServingHost)
+ if err != nil {
+ return "", fmt.Errorf("unable to grab random port for serving webhooks on: %w", err)
+ }
+ o.LocalServingPort = port
+ o.LocalServingHost = host
+ }
+ host := o.LocalServingHostExternalName
+ if host == "" {
+ host = o.LocalServingHost
+ }
+ return net.JoinHostPort(host, fmt.Sprintf("%d", o.LocalServingPort)), nil
+}
+
+// PrepWithoutInstalling does the setup parts of Install (populating host-port,
+// setting up CAs, etc), without actually truing to do anything with webhook
+// definitions. This is largely useful for internal testing of
+// controller-runtime, where we need a random host-port & caData for webhook
+// tests, but may be useful in similar scenarios.
+func (o *WebhookInstallOptions) PrepWithoutInstalling() error {
+ if err := o.setupCA(); err != nil {
+ return err
+ }
+
+ if err := parseWebhook(o); err != nil {
+ return err
+ }
+
+ return o.ModifyWebhookDefinitions()
+}
+
+// Install installs specified webhooks to the API server.
+func (o *WebhookInstallOptions) Install(config *rest.Config) error {
+ defaultWebhookOptions(o)
+
+ if len(o.LocalServingCAData) == 0 {
+ if err := o.PrepWithoutInstalling(); err != nil {
+ return err
+ }
+ }
+
+ if err := createWebhooks(config, o.MutatingWebhooks, o.ValidatingWebhooks); err != nil {
+ return err
+ }
+
+ return WaitForWebhooks(config, o.MutatingWebhooks, o.ValidatingWebhooks, *o)
+}
+
+// Cleanup cleans up cert directories.
+func (o *WebhookInstallOptions) Cleanup() error {
+ if o.LocalServingCertDir != "" {
+ return os.RemoveAll(o.LocalServingCertDir)
+ }
+ return nil
+}
+
+// defaultWebhookOptions sets the default values for Webhooks.
+func defaultWebhookOptions(o *WebhookInstallOptions) {
+ if o.MaxTime == 0 {
+ o.MaxTime = defaultMaxWait
+ }
+ if o.PollInterval == 0 {
+ o.PollInterval = defaultPollInterval
+ }
+}
+
+// WaitForWebhooks waits for the Webhooks to be available through API server.
+func WaitForWebhooks(config *rest.Config,
+ mutatingWebhooks []*admissionv1.MutatingWebhookConfiguration,
+ validatingWebhooks []*admissionv1.ValidatingWebhookConfiguration,
+ options WebhookInstallOptions) error {
+ waitingFor := map[schema.GroupVersionKind]*sets.Set[string]{}
+
+ for _, hook := range mutatingWebhooks {
+ h := hook
+ gvk, err := apiutil.GVKForObject(h, scheme.Scheme)
+ if err != nil {
+ return fmt.Errorf("unable to get gvk for MutatingWebhookConfiguration %s: %w", hook.GetName(), err)
+ }
+
+ if _, ok := waitingFor[gvk]; !ok {
+ waitingFor[gvk] = &sets.Set[string]{}
+ }
+ waitingFor[gvk].Insert(h.GetName())
+ }
+
+ for _, hook := range validatingWebhooks {
+ h := hook
+ gvk, err := apiutil.GVKForObject(h, scheme.Scheme)
+ if err != nil {
+ return fmt.Errorf("unable to get gvk for ValidatingWebhookConfiguration %s: %w", hook.GetName(), err)
+ }
+
+ if _, ok := waitingFor[gvk]; !ok {
+ waitingFor[gvk] = &sets.Set[string]{}
+ }
+ waitingFor[gvk].Insert(hook.GetName())
+ }
+
+ // Poll until all resources are found in discovery
+ p := &webhookPoller{config: config, waitingFor: waitingFor}
+ return wait.PollUntilContextTimeout(context.TODO(), options.PollInterval, options.MaxTime, true, p.poll)
+}
+
+// poller checks if all the resources have been found in discovery, and returns false if not.
+type webhookPoller struct {
+ // config is used to get discovery
+ config *rest.Config
+
+ // waitingFor is the map of resources keyed by group version that have not yet been found in discovery
+ waitingFor map[schema.GroupVersionKind]*sets.Set[string]
+}
+
+// poll checks if all the resources have been found in discovery, and returns false if not.
+func (p *webhookPoller) poll(ctx context.Context) (done bool, err error) {
+ // Create a new clientset to avoid any client caching of discovery
+ c, err := client.New(p.config, client.Options{})
+ if err != nil {
+ return false, err
+ }
+
+ allFound := true
+ for gvk, names := range p.waitingFor {
+ if names.Len() == 0 {
+ delete(p.waitingFor, gvk)
+ continue
+ }
+ for _, name := range names.UnsortedList() {
+ var obj = &unstructured.Unstructured{}
+ obj.SetGroupVersionKind(gvk)
+ err := c.Get(context.Background(), client.ObjectKey{
+ Namespace: "",
+ Name: name,
+ }, obj)
+
+ if err == nil {
+ names.Delete(name)
+ }
+
+ if apierrors.IsNotFound(err) {
+ allFound = false
+ }
+ if err != nil {
+ return false, err
+ }
+ }
+ }
+ return allFound, nil
+}
+
+// setupCA creates CA for testing and writes them to disk.
+func (o *WebhookInstallOptions) setupCA() error {
+ hookCA, err := certs.NewTinyCA()
+ if err != nil {
+ return fmt.Errorf("unable to set up webhook CA: %w", err)
+ }
+
+ names := []string{"localhost", o.LocalServingHost, o.LocalServingHostExternalName}
+ hookCert, err := hookCA.NewServingCert(names...)
+ if err != nil {
+ return fmt.Errorf("unable to set up webhook serving certs: %w", err)
+ }
+
+ localServingCertsDir, err := os.MkdirTemp("", "envtest-serving-certs-")
+ o.LocalServingCertDir = localServingCertsDir
+ if err != nil {
+ return fmt.Errorf("unable to create directory for webhook serving certs: %w", err)
+ }
+
+ certData, keyData, err := hookCert.AsBytes()
+ if err != nil {
+ return fmt.Errorf("unable to marshal webhook serving certs: %w", err)
+ }
+
+ if err := os.WriteFile(filepath.Join(localServingCertsDir, "tls.crt"), certData, 0640); err != nil { //nolint:gosec
+ return fmt.Errorf("unable to write webhook serving cert to disk: %w", err)
+ }
+ if err := os.WriteFile(filepath.Join(localServingCertsDir, "tls.key"), keyData, 0640); err != nil { //nolint:gosec
+ return fmt.Errorf("unable to write webhook serving key to disk: %w", err)
+ }
+
+ o.LocalServingCAData = certData
+ return err
+}
+
+func createWebhooks(config *rest.Config, mutHooks []*admissionv1.MutatingWebhookConfiguration, valHooks []*admissionv1.ValidatingWebhookConfiguration) error {
+ cs, err := client.New(config, client.Options{})
+ if err != nil {
+ return err
+ }
+
+ // Create each webhook
+ for _, hook := range mutHooks {
+ hook := hook
+ log.V(1).Info("installing mutating webhook", "webhook", hook.GetName())
+ if err := ensureCreated(cs, hook); err != nil {
+ return err
+ }
+ }
+ for _, hook := range valHooks {
+ hook := hook
+ log.V(1).Info("installing validating webhook", "webhook", hook.GetName())
+ if err := ensureCreated(cs, hook); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ensureCreated creates or update object if already exists in the cluster.
+func ensureCreated(cs client.Client, obj client.Object) error {
+ existing := obj.DeepCopyObject().(client.Object)
+ err := cs.Get(context.Background(), client.ObjectKey{Name: obj.GetName()}, existing)
+ switch {
+ case apierrors.IsNotFound(err):
+ if err := cs.Create(context.Background(), obj); err != nil {
+ return err
+ }
+ case err != nil:
+ return err
+ default:
+ log.V(1).Info("Webhook configuration already exists, updating", "webhook", obj.GetName())
+ obj.SetResourceVersion(existing.GetResourceVersion())
+ if err := cs.Update(context.Background(), obj); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// parseWebhook reads the directories or files of Webhooks in options.Paths and adds the Webhook structs to options.
+func parseWebhook(options *WebhookInstallOptions) error {
+ if len(options.Paths) > 0 {
+ for _, path := range options.Paths {
+ _, err := os.Stat(path)
+ if options.IgnoreErrorIfPathMissing && os.IsNotExist(err) {
+ continue // skip this path
+ }
+ if !options.IgnoreErrorIfPathMissing && os.IsNotExist(err) {
+ return err // treat missing path as error
+ }
+ mutHooks, valHooks, err := readWebhooks(path)
+ if err != nil {
+ return err
+ }
+ options.MutatingWebhooks = append(options.MutatingWebhooks, mutHooks...)
+ options.ValidatingWebhooks = append(options.ValidatingWebhooks, valHooks...)
+ }
+ }
+ return nil
+}
+
+// readWebhooks reads the Webhooks from files and Unmarshals them into structs
+// returns slice of mutating and validating webhook configurations.
+func readWebhooks(path string) ([]*admissionv1.MutatingWebhookConfiguration, []*admissionv1.ValidatingWebhookConfiguration, error) {
+ // Get the webhook files
+ var files []string
+ var err error
+ log.V(1).Info("reading Webhooks from path", "path", path)
+ info, err := os.Stat(path)
+ if err != nil {
+ return nil, nil, err
+ }
+ if !info.IsDir() {
+ path, files = filepath.Dir(path), []string{info.Name()}
+ } else {
+ entries, err := os.ReadDir(path)
+ if err != nil {
+ return nil, nil, err
+ }
+ for _, e := range entries {
+ files = append(files, e.Name())
+ }
+ }
+
+ // file extensions that may contain Webhooks
+ resourceExtensions := sets.NewString(".json", ".yaml", ".yml")
+
+ var mutHooks []*admissionv1.MutatingWebhookConfiguration
+ var valHooks []*admissionv1.ValidatingWebhookConfiguration
+ for _, file := range files {
+ // Only parse allowlisted file types
+ if !resourceExtensions.Has(filepath.Ext(file)) {
+ continue
+ }
+
+ // Unmarshal Webhooks from file into structs
+ docs, err := readDocuments(filepath.Join(path, file))
+ if err != nil {
+ return nil, nil, err
+ }
+
+ for _, doc := range docs {
+ var generic metav1.PartialObjectMetadata
+ if err = yaml.Unmarshal(doc, &generic); err != nil {
+ return nil, nil, err
+ }
+
+ const (
+ admissionregv1 = "admissionregistration.k8s.io/v1"
+ )
+ switch {
+ case generic.Kind == "MutatingWebhookConfiguration":
+ if generic.APIVersion != admissionregv1 {
+ return nil, nil, fmt.Errorf("only v1 is supported right now for MutatingWebhookConfiguration (name: %s)", generic.Name)
+ }
+ hook := &admissionv1.MutatingWebhookConfiguration{}
+ if err := yaml.Unmarshal(doc, hook); err != nil {
+ return nil, nil, err
+ }
+ mutHooks = append(mutHooks, hook)
+ case generic.Kind == "ValidatingWebhookConfiguration":
+ if generic.APIVersion != admissionregv1 {
+ return nil, nil, fmt.Errorf("only v1 is supported right now for ValidatingWebhookConfiguration (name: %s)", generic.Name)
+ }
+ hook := &admissionv1.ValidatingWebhookConfiguration{}
+ if err := yaml.Unmarshal(doc, hook); err != nil {
+ return nil, nil, err
+ }
+ valHooks = append(valHooks, hook)
+ default:
+ continue
+ }
+ }
+
+ log.V(1).Info("read webhooks from file", "file", file)
+ }
+ return mutHooks, valHooks, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/webhook_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/webhook_test.go
new file mode 100644
index 00000000000..2cbc9ab9c8e
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/envtest/webhook_test.go
@@ -0,0 +1,124 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package envtest
+
+import (
+ "context"
+ "crypto/tls"
+ "path/filepath"
+ "strings"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+var _ = Describe("Test", func() {
+
+ Describe("Webhook", func() {
+ It("should reject create request for webhook that rejects all requests", func() {
+ m, err := manager.New(env.Config, manager.Options{
+ Port: env.WebhookInstallOptions.LocalServingPort,
+ Host: env.WebhookInstallOptions.LocalServingHost,
+ CertDir: env.WebhookInstallOptions.LocalServingCertDir,
+ TLSOpts: []func(*tls.Config){
+ func(config *tls.Config) {},
+ },
+ }) // we need manager here just to leverage manager.SetFields
+ Expect(err).NotTo(HaveOccurred())
+ server := m.GetWebhookServer()
+ server.Register("/failing", &webhook.Admission{Handler: &rejectingValidator{}})
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ _ = server.Start(ctx)
+ }()
+
+ c, err := client.New(env.Config, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ obj := &appsv1.Deployment{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "apps/v1",
+ Kind: "Deployment",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-deployment",
+ Namespace: "default",
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx",
+ },
+ },
+ },
+ },
+ },
+ }
+
+ Eventually(func() bool {
+ err = c.Create(context.TODO(), obj)
+ return err != nil && strings.HasSuffix(err.Error(), "Always denied") && apierrors.ReasonForError(err) == metav1.StatusReasonForbidden
+ }, 1*time.Second).Should(BeTrue())
+
+ cancel()
+ })
+
+ It("should load webhooks from directory", func() {
+ installOptions := WebhookInstallOptions{
+ Paths: []string{filepath.Join("testdata", "webhooks")},
+ }
+ err := parseWebhook(&installOptions)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(len(installOptions.MutatingWebhooks)).To(Equal(2))
+ Expect(len(installOptions.ValidatingWebhooks)).To(Equal(2))
+ })
+
+ It("should load webhooks from files", func() {
+ installOptions := WebhookInstallOptions{
+ Paths: []string{filepath.Join("testdata", "webhooks", "manifests.yaml")},
+ }
+ err := parseWebhook(&installOptions)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(len(installOptions.MutatingWebhooks)).To(Equal(2))
+ Expect(len(installOptions.ValidatingWebhooks)).To(Equal(2))
+ })
+ })
+})
+
+type rejectingValidator struct {
+}
+
+func (v *rejectingValidator) Handle(_ context.Context, _ admission.Request) admission.Response {
+ return admission.Denied("Always denied")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/event/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/event/doc.go
new file mode 100644
index 00000000000..adba3bbc16e
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/event/doc.go
@@ -0,0 +1,28 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package event contains the definitions for the Event types produced by source.Sources and transformed into
+reconcile.Requests by handler.EventHandler.
+
+You should rarely need to work with these directly -- instead, use Controller.Watch with
+source.Sources and handler.EventHandlers.
+
+Events generally contain both a full runtime.Object that caused the event, as well
+as a direct handle to that object's metadata. This saves a lot of typecasting in
+code that works with Events.
+*/
+package event
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/event/event.go b/third_party/sigs.k8s.io/controller-runtime/pkg/event/event.go
new file mode 100644
index 00000000000..271b3c00fb3
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/event/event.go
@@ -0,0 +1,55 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package event
+
+import "sigs.k8s.io/controller-runtime/pkg/client"
+
+// CreateEvent is an event where a Kubernetes object was created. CreateEvent should be generated
+// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler.
+type CreateEvent struct {
+ // Object is the object from the event
+ Object client.Object
+}
+
+// UpdateEvent is an event where a Kubernetes object was updated. UpdateEvent should be generated
+// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler.
+type UpdateEvent struct {
+ // ObjectOld is the object from the event
+ ObjectOld client.Object
+
+ // ObjectNew is the object from the event
+ ObjectNew client.Object
+}
+
+// DeleteEvent is an event where a Kubernetes object was deleted. DeleteEvent should be generated
+// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler.
+type DeleteEvent struct {
+ // Object is the object from the event
+ Object client.Object
+
+ // DeleteStateUnknown is true if the Delete event was missed but we identified the object
+ // as having been deleted.
+ DeleteStateUnknown bool
+}
+
+// GenericEvent is an event where the operation type is unknown (e.g. polling or event originating outside the cluster).
+// GenericEvent should be generated by a source.Source and transformed into a reconcile.Request by an
+// handler.EventHandler.
+type GenericEvent struct {
+ // Object is the object from the event
+ Object client.Object
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/finalizer/finalizer.go b/third_party/sigs.k8s.io/controller-runtime/pkg/finalizer/finalizer.go
new file mode 100644
index 00000000000..10c5645dbe3
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/finalizer/finalizer.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package finalizer
+
+import (
+ "context"
+ "fmt"
+
+ kerrors "k8s.io/apimachinery/pkg/util/errors"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+)
+
+type finalizers map[string]Finalizer
+
+// Result struct holds information about what parts of an object were updated by finalizer(s).
+type Result struct {
+ // Updated will be true if at least one of the object's non-status field
+ // was updated by some registered finalizer.
+ Updated bool
+ // StatusUpdated will be true if at least one of the object's status' fields
+ // was updated by some registered finalizer.
+ StatusUpdated bool
+}
+
+// NewFinalizers returns the Finalizers interface.
+func NewFinalizers() Finalizers {
+ return finalizers{}
+}
+
+func (f finalizers) Register(key string, finalizer Finalizer) error {
+ if _, ok := f[key]; ok {
+ return fmt.Errorf("finalizer for key %q already registered", key)
+ }
+ f[key] = finalizer
+ return nil
+}
+
+func (f finalizers) Finalize(ctx context.Context, obj client.Object) (Result, error) {
+ var (
+ res Result
+ errList []error
+ )
+ res.Updated = false
+ for key, finalizer := range f {
+ if dt := obj.GetDeletionTimestamp(); dt.IsZero() && !controllerutil.ContainsFinalizer(obj, key) {
+ controllerutil.AddFinalizer(obj, key)
+ res.Updated = true
+ } else if !dt.IsZero() && controllerutil.ContainsFinalizer(obj, key) {
+ finalizerRes, err := finalizer.Finalize(ctx, obj)
+ if err != nil {
+ // Even when the finalizer fails, it may need to signal to update the primary
+ // object (e.g. it may set a condition and need a status update).
+ res.Updated = res.Updated || finalizerRes.Updated
+ res.StatusUpdated = res.StatusUpdated || finalizerRes.StatusUpdated
+ errList = append(errList, fmt.Errorf("finalizer %q failed: %w", key, err))
+ } else {
+ // If the finalizer succeeds, we remove the finalizer from the primary
+ // object's metadata, so we know it will need an update.
+ res.Updated = true
+ controllerutil.RemoveFinalizer(obj, key)
+ // The finalizer may have updated the status too.
+ res.StatusUpdated = res.StatusUpdated || finalizerRes.StatusUpdated
+ }
+ }
+ }
+ return res, kerrors.NewAggregate(errList)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/finalizer/finalizer_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/finalizer/finalizer_test.go
new file mode 100644
index 00000000000..eb85bd020a2
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/finalizer/finalizer_test.go
@@ -0,0 +1,215 @@
+package finalizer
+
+import (
+ "context"
+ "fmt"
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+type mockFinalizer struct {
+ result Result
+ err error
+}
+
+func (f mockFinalizer) Finalize(context.Context, client.Object) (Result, error) {
+ return f.result, f.err
+}
+
+func TestFinalizer(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Finalizer Suite")
+}
+
+var _ = Describe("TestFinalizer", func() {
+ var err error
+ var pod *corev1.Pod
+ var finalizers Finalizers
+ var f mockFinalizer
+ BeforeEach(func() {
+ pod = &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{},
+ }
+ finalizers = NewFinalizers()
+ f = mockFinalizer{}
+ })
+ Describe("Register", func() {
+ It("successfully registers a finalizer", func() {
+ err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f)
+ Expect(err).To(BeNil())
+ })
+
+ It("should fail when trying to register a finalizer that was already registered", func() {
+ err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f)
+ Expect(err).To(BeNil())
+
+ // calling Register again with the same key should return an error
+ err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f)
+ Expect(err).NotTo(BeNil())
+ Expect(err.Error()).To(ContainSubstring("already registered"))
+
+ })
+ })
+
+ Describe("Finalize", func() {
+ It("successfully finalizes and returns true for Updated when deletion timestamp is nil and finalizer does not exist", func() {
+ err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f)
+ Expect(err).To(BeNil())
+
+ pod.DeletionTimestamp = nil
+ pod.Finalizers = []string{}
+
+ result, err := finalizers.Finalize(context.TODO(), pod)
+ Expect(err).To(BeNil())
+ Expect(result.Updated).To(BeTrue())
+ // when deletion timestamp is nil and finalizer is not present, the registered finalizer would be added to the obj
+ Expect(len(pod.Finalizers)).To(Equal(1))
+ Expect(pod.Finalizers[0]).To(Equal("finalizers.sigs.k8s.io/testfinalizer"))
+
+ })
+
+ It("successfully finalizes and returns true for Updated when deletion timestamp is not nil and the finalizer exists", func() {
+ now := metav1.Now()
+ pod.DeletionTimestamp = &now
+
+ err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f)
+ Expect(err).To(BeNil())
+
+ pod.Finalizers = []string{"finalizers.sigs.k8s.io/testfinalizer"}
+
+ result, err := finalizers.Finalize(context.TODO(), pod)
+ Expect(err).To(BeNil())
+ Expect(result.Updated).To(BeTrue())
+ // finalizer will be removed from the obj upon successful finalization
+ Expect(len(pod.Finalizers)).To(Equal(0))
+ })
+
+ It("should return no error and return false for Updated when deletion timestamp is nil and finalizer doesn't exist", func() {
+ pod.DeletionTimestamp = nil
+ pod.Finalizers = []string{}
+
+ result, err := finalizers.Finalize(context.TODO(), pod)
+ Expect(err).To(BeNil())
+ Expect(result.Updated).To(BeFalse())
+ Expect(len(pod.Finalizers)).To(Equal(0))
+
+ })
+
+ It("should return no error and return false for Updated when deletion timestamp is not nil and the finalizer doesn't exist", func() {
+ now := metav1.Now()
+ pod.DeletionTimestamp = &now
+ pod.Finalizers = []string{}
+
+ result, err := finalizers.Finalize(context.TODO(), pod)
+ Expect(err).To(BeNil())
+ Expect(result.Updated).To(BeFalse())
+ Expect(len(pod.Finalizers)).To(Equal(0))
+
+ })
+
+ It("successfully finalizes multiple finalizers and returns true for Updated when deletion timestamp is not nil and the finalizer exists", func() {
+ now := metav1.Now()
+ pod.DeletionTimestamp = &now
+
+ err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f)
+ Expect(err).To(BeNil())
+
+ err = finalizers.Register("finalizers.sigs.k8s.io/newtestfinalizer", f)
+ Expect(err).To(BeNil())
+
+ pod.Finalizers = []string{"finalizers.sigs.k8s.io/testfinalizer", "finalizers.sigs.k8s.io/newtestfinalizer"}
+
+ result, err := finalizers.Finalize(context.TODO(), pod)
+ Expect(err).To(BeNil())
+ Expect(result.Updated).To(BeTrue())
+ Expect(result.StatusUpdated).To(BeFalse())
+ Expect(len(pod.Finalizers)).To(Equal(0))
+ })
+
+ It("should return result as false and a non-nil error", func() {
+ now := metav1.Now()
+ pod.DeletionTimestamp = &now
+ pod.Finalizers = []string{"finalizers.sigs.k8s.io/testfinalizer"}
+
+ f.result.Updated = false
+ f.result.StatusUpdated = false
+ f.err = fmt.Errorf("finalizer failed for %q", pod.Finalizers[0])
+
+ err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer", f)
+ Expect(err).To(BeNil())
+
+ result, err := finalizers.Finalize(context.TODO(), pod)
+ Expect(err).ToNot(BeNil())
+ Expect(err.Error()).To(ContainSubstring("finalizer failed"))
+ Expect(result.Updated).To(BeFalse())
+ Expect(result.StatusUpdated).To(BeFalse())
+ Expect(len(pod.Finalizers)).To(Equal(1))
+ Expect(pod.Finalizers[0]).To(Equal("finalizers.sigs.k8s.io/testfinalizer"))
+ })
+
+ It("should return expected result values and error values when registering multiple finalizers", func() {
+ now := metav1.Now()
+ pod.DeletionTimestamp = &now
+ pod.Finalizers = []string{
+ "finalizers.sigs.k8s.io/testfinalizer1",
+ "finalizers.sigs.k8s.io/testfinalizer2",
+ "finalizers.sigs.k8s.io/testfinalizer3",
+ }
+
+ // registering multiple finalizers with different return values
+ // test for Updated as true, and nil error
+ f.result.Updated = true
+ f.result.StatusUpdated = false
+ f.err = nil
+ err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer1", f)
+ Expect(err).To(BeNil())
+
+ result, err := finalizers.Finalize(context.TODO(), pod)
+ Expect(err).To(BeNil())
+ Expect(result.Updated).To(BeTrue())
+ Expect(result.StatusUpdated).To(BeFalse())
+ // `finalizers.sigs.k8s.io/testfinalizer1` will be removed from the list
+ // of finalizers, so length will be 2.
+ Expect(len(pod.Finalizers)).To(Equal(2))
+ Expect(pod.Finalizers[0]).To(Equal("finalizers.sigs.k8s.io/testfinalizer2"))
+ Expect(pod.Finalizers[1]).To(Equal("finalizers.sigs.k8s.io/testfinalizer3"))
+
+ // test for Updated and StatusUpdated as false, and non-nil error
+ f.result.Updated = false
+ f.result.StatusUpdated = false
+ f.err = fmt.Errorf("finalizer failed")
+ err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer2", f)
+ Expect(err).To(BeNil())
+
+ result, err = finalizers.Finalize(context.TODO(), pod)
+ Expect(err).ToNot(BeNil())
+ Expect(err.Error()).To(ContainSubstring("finalizer failed"))
+ Expect(result.Updated).To(BeFalse())
+ Expect(result.StatusUpdated).To(BeFalse())
+ Expect(len(pod.Finalizers)).To(Equal(2))
+ Expect(pod.Finalizers[0]).To(Equal("finalizers.sigs.k8s.io/testfinalizer2"))
+ Expect(pod.Finalizers[1]).To(Equal("finalizers.sigs.k8s.io/testfinalizer3"))
+
+ // test for result as true, and non-nil error
+ f.result.Updated = true
+ f.result.StatusUpdated = true
+ f.err = fmt.Errorf("finalizer failed")
+ err = finalizers.Register("finalizers.sigs.k8s.io/testfinalizer3", f)
+ Expect(err).To(BeNil())
+
+ result, err = finalizers.Finalize(context.TODO(), pod)
+ Expect(err).ToNot(BeNil())
+ Expect(err.Error()).To(ContainSubstring("finalizer failed"))
+ Expect(result.Updated).To(BeTrue())
+ Expect(result.StatusUpdated).To(BeTrue())
+ Expect(len(pod.Finalizers)).To(Equal(2))
+ Expect(pod.Finalizers[0]).To(Equal("finalizers.sigs.k8s.io/testfinalizer2"))
+ Expect(pod.Finalizers[1]).To(Equal("finalizers.sigs.k8s.io/testfinalizer3"))
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/finalizer/types.go b/third_party/sigs.k8s.io/controller-runtime/pkg/finalizer/types.go
new file mode 100644
index 00000000000..e3a002a9358
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/finalizer/types.go
@@ -0,0 +1,42 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package finalizer
+
+import (
+ "context"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// Registerer holds Register that will check if a key is already registered
+// and error out and it does; and if not registered, it will add the finalizer
+// to the finalizers map as the value for the provided key.
+type Registerer interface {
+ Register(key string, f Finalizer) error
+}
+
+// Finalizer holds Finalize that will add/remove a finalizer based on the
+// deletion timestamp being set and return an indication of whether the
+// obj needs an update or not.
+type Finalizer interface {
+ Finalize(context.Context, client.Object) (Result, error)
+}
+
+// Finalizers implements Registerer and Finalizer to finalize all registered
+// finalizers if the provided object has a deletion timestamp or set all
+// registered finalizers if it does not.
+type Finalizers interface {
+ Registerer
+ Finalizer
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/handler/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/doc.go
new file mode 100644
index 00000000000..e5fd177aff8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/doc.go
@@ -0,0 +1,38 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package handler defines EventHandlers that enqueue reconcile.Requests in response to Create, Update, Deletion Events
+observed from Watching Kubernetes APIs. Users should provide a source.Source and handler.EventHandler to
+Controller.Watch in order to generate and enqueue reconcile.Request work items.
+
+Generally, following premade event handlers should be sufficient for most use cases:
+
+EventHandlers:
+
+EnqueueRequestForObject - Enqueues a reconcile.Request containing the Name and Namespace of the object in the Event. This will
+cause the object that was the source of the Event (e.g. the created / deleted / updated object) to be
+reconciled.
+
+EnqueueRequestForOwner - Enqueues a reconcile.Request containing the Name and Namespace of the Owner of the object in the Event.
+This will cause owner of the object that was the source of the Event (e.g. the owner object that created the object)
+to be reconciled.
+
+EnqueueRequestsFromMapFunc - Enqueues reconcile.Requests resulting from a user provided transformation function run against the
+object in the Event. This will cause an arbitrary collection of objects (defined from a transformation of the
+source object) to be reconciled.
+*/
+package handler
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go
new file mode 100644
index 00000000000..c72b2e1ebb1
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go
@@ -0,0 +1,92 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package handler
+
+import (
+ "context"
+
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+var enqueueLog = logf.RuntimeLog.WithName("eventhandler").WithName("EnqueueRequestForObject")
+
+type empty struct{}
+
+var _ EventHandler = &EnqueueRequestForObject{}
+
+// EnqueueRequestForObject enqueues a Request containing the Name and Namespace of the object that is the source of the Event.
+// (e.g. the created / deleted / updated objects Name and Namespace). handler.EnqueueRequestForObject is used by almost all
+// Controllers that have associated Resources (e.g. CRDs) to reconcile the associated Resource.
+type EnqueueRequestForObject struct{}
+
+// Create implements EventHandler.
+func (e *EnqueueRequestForObject) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
+ if evt.Object == nil {
+ enqueueLog.Error(nil, "CreateEvent received with no metadata", "event", evt)
+ return
+ }
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: evt.Object.GetName(),
+ Namespace: evt.Object.GetNamespace(),
+ }})
+}
+
+// Update implements EventHandler.
+func (e *EnqueueRequestForObject) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
+ switch {
+ case evt.ObjectNew != nil:
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: evt.ObjectNew.GetName(),
+ Namespace: evt.ObjectNew.GetNamespace(),
+ }})
+ case evt.ObjectOld != nil:
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: evt.ObjectOld.GetName(),
+ Namespace: evt.ObjectOld.GetNamespace(),
+ }})
+ default:
+ enqueueLog.Error(nil, "UpdateEvent received with no metadata", "event", evt)
+ }
+}
+
+// Delete implements EventHandler.
+func (e *EnqueueRequestForObject) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
+ if evt.Object == nil {
+ enqueueLog.Error(nil, "DeleteEvent received with no metadata", "event", evt)
+ return
+ }
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: evt.Object.GetName(),
+ Namespace: evt.Object.GetNamespace(),
+ }})
+}
+
+// Generic implements EventHandler.
+func (e *EnqueueRequestForObject) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
+ if evt.Object == nil {
+ enqueueLog.Error(nil, "GenericEvent received with no metadata", "event", evt)
+ return
+ }
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: evt.Object.GetName(),
+ Namespace: evt.Object.GetNamespace(),
+ }})
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go
new file mode 100644
index 00000000000..b55fdde6ba5
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go
@@ -0,0 +1,88 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package handler
+
+import (
+ "context"
+
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+// MapFunc is the signature required for enqueueing requests from a generic function.
+// This type is usually used with EnqueueRequestsFromMapFunc when registering an event handler.
+type MapFunc func(context.Context, client.Object) []reconcile.Request
+
+// EnqueueRequestsFromMapFunc enqueues Requests by running a transformation function that outputs a collection
+// of reconcile.Requests on each Event. The reconcile.Requests may be for an arbitrary set of objects
+// defined by some user specified transformation of the source Event. (e.g. trigger Reconciler for a set of objects
+// in response to a cluster resize event caused by adding or deleting a Node)
+//
+// EnqueueRequestsFromMapFunc is frequently used to fan-out updates from one object to one or more other
+// objects of a differing type.
+//
+// For UpdateEvents which contain both a new and old object, the transformation function is run on both
+// objects and both sets of Requests are enqueue.
+func EnqueueRequestsFromMapFunc(fn MapFunc) EventHandler {
+ return &enqueueRequestsFromMapFunc{
+ toRequests: fn,
+ }
+}
+
+var _ EventHandler = &enqueueRequestsFromMapFunc{}
+
+type enqueueRequestsFromMapFunc struct {
+ // Mapper transforms the argument into a slice of keys to be reconciled
+ toRequests MapFunc
+}
+
+// Create implements EventHandler.
+func (e *enqueueRequestsFromMapFunc) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.mapAndEnqueue(ctx, q, evt.Object, reqs)
+}
+
+// Update implements EventHandler.
+func (e *enqueueRequestsFromMapFunc) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.mapAndEnqueue(ctx, q, evt.ObjectOld, reqs)
+ e.mapAndEnqueue(ctx, q, evt.ObjectNew, reqs)
+}
+
+// Delete implements EventHandler.
+func (e *enqueueRequestsFromMapFunc) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.mapAndEnqueue(ctx, q, evt.Object, reqs)
+}
+
+// Generic implements EventHandler.
+func (e *enqueueRequestsFromMapFunc) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.mapAndEnqueue(ctx, q, evt.Object, reqs)
+}
+
+func (e *enqueueRequestsFromMapFunc) mapAndEnqueue(ctx context.Context, q workqueue.RateLimitingInterface, object client.Object, reqs map[reconcile.Request]empty) {
+ for _, req := range e.toRequests(ctx, object) {
+ _, ok := reqs[req]
+ if !ok {
+ q.Add(req)
+ reqs[req] = empty{}
+ }
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go
new file mode 100644
index 00000000000..02e7d756f80
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go
@@ -0,0 +1,199 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package handler
+
+import (
+ "context"
+ "fmt"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+var _ EventHandler = &enqueueRequestForOwner{}
+
+var log = logf.RuntimeLog.WithName("eventhandler").WithName("enqueueRequestForOwner")
+
+// OwnerOption modifies an EnqueueRequestForOwner EventHandler.
+type OwnerOption func(e *enqueueRequestForOwner)
+
+// EnqueueRequestForOwner enqueues Requests for the Owners of an object. E.g. the object that created
+// the object that was the source of the Event.
+//
+// If a ReplicaSet creates Pods, users may reconcile the ReplicaSet in response to Pod Events using:
+//
+// - a source.Kind Source with Type of Pod.
+//
+// - a handler.enqueueRequestForOwner EventHandler with an OwnerType of ReplicaSet and OnlyControllerOwner set to true.
+func EnqueueRequestForOwner(scheme *runtime.Scheme, mapper meta.RESTMapper, ownerType client.Object, opts ...OwnerOption) EventHandler {
+ e := &enqueueRequestForOwner{
+ ownerType: ownerType,
+ mapper: mapper,
+ }
+ if err := e.parseOwnerTypeGroupKind(scheme); err != nil {
+ panic(err)
+ }
+ for _, opt := range opts {
+ opt(e)
+ }
+ return e
+}
+
+// OnlyControllerOwner if provided will only look at the first OwnerReference with Controller: true.
+func OnlyControllerOwner() OwnerOption {
+ return func(e *enqueueRequestForOwner) {
+ e.isController = true
+ }
+}
+
+type enqueueRequestForOwner struct {
+ // ownerType is the type of the Owner object to look for in OwnerReferences. Only Group and Kind are compared.
+ ownerType runtime.Object
+
+ // isController if set will only look at the first OwnerReference with Controller: true.
+ isController bool
+
+ // groupKind is the cached Group and Kind from OwnerType
+ groupKind schema.GroupKind
+
+ // mapper maps GroupVersionKinds to Resources
+ mapper meta.RESTMapper
+}
+
+// Create implements EventHandler.
+func (e *enqueueRequestForOwner) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.getOwnerReconcileRequest(evt.Object, reqs)
+ for req := range reqs {
+ q.Add(req)
+ }
+}
+
+// Update implements EventHandler.
+func (e *enqueueRequestForOwner) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.getOwnerReconcileRequest(evt.ObjectOld, reqs)
+ e.getOwnerReconcileRequest(evt.ObjectNew, reqs)
+ for req := range reqs {
+ q.Add(req)
+ }
+}
+
+// Delete implements EventHandler.
+func (e *enqueueRequestForOwner) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.getOwnerReconcileRequest(evt.Object, reqs)
+ for req := range reqs {
+ q.Add(req)
+ }
+}
+
+// Generic implements EventHandler.
+func (e *enqueueRequestForOwner) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.getOwnerReconcileRequest(evt.Object, reqs)
+ for req := range reqs {
+ q.Add(req)
+ }
+}
+
+// parseOwnerTypeGroupKind parses the OwnerType into a Group and Kind and caches the result. Returns false
+// if the OwnerType could not be parsed using the scheme.
+func (e *enqueueRequestForOwner) parseOwnerTypeGroupKind(scheme *runtime.Scheme) error {
+ // Get the kinds of the type
+ kinds, _, err := scheme.ObjectKinds(e.ownerType)
+ if err != nil {
+ log.Error(err, "Could not get ObjectKinds for OwnerType", "owner type", fmt.Sprintf("%T", e.ownerType))
+ return err
+ }
+ // Expect only 1 kind. If there is more than one kind this is probably an edge case such as ListOptions.
+ if len(kinds) != 1 {
+ err := fmt.Errorf("expected exactly 1 kind for OwnerType %T, but found %s kinds", e.ownerType, kinds)
+ log.Error(nil, "expected exactly 1 kind for OwnerType", "owner type", fmt.Sprintf("%T", e.ownerType), "kinds", kinds)
+ return err
+ }
+ // Cache the Group and Kind for the OwnerType
+ e.groupKind = schema.GroupKind{Group: kinds[0].Group, Kind: kinds[0].Kind}
+ return nil
+}
+
+// getOwnerReconcileRequest looks at object and builds a map of reconcile.Request to reconcile
+// owners of object that match e.OwnerType.
+func (e *enqueueRequestForOwner) getOwnerReconcileRequest(object metav1.Object, result map[reconcile.Request]empty) {
+ // Iterate through the OwnerReferences looking for a match on Group and Kind against what was requested
+ // by the user
+ for _, ref := range e.getOwnersReferences(object) {
+ // Parse the Group out of the OwnerReference to compare it to what was parsed out of the requested OwnerType
+ refGV, err := schema.ParseGroupVersion(ref.APIVersion)
+ if err != nil {
+ log.Error(err, "Could not parse OwnerReference APIVersion",
+ "api version", ref.APIVersion)
+ return
+ }
+
+ // Compare the OwnerReference Group and Kind against the OwnerType Group and Kind specified by the user.
+ // If the two match, create a Request for the objected referred to by
+ // the OwnerReference. Use the Name from the OwnerReference and the Namespace from the
+ // object in the event.
+ if ref.Kind == e.groupKind.Kind && refGV.Group == e.groupKind.Group {
+ // Match found - add a Request for the object referred to in the OwnerReference
+ request := reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: ref.Name,
+ }}
+
+ // if owner is not namespaced then we should not set the namespace
+ mapping, err := e.mapper.RESTMapping(e.groupKind, refGV.Version)
+ if err != nil {
+ log.Error(err, "Could not retrieve rest mapping", "kind", e.groupKind)
+ return
+ }
+ if mapping.Scope.Name() != meta.RESTScopeNameRoot {
+ request.Namespace = object.GetNamespace()
+ }
+
+ result[request] = empty{}
+ }
+ }
+}
+
+// getOwnersReferences returns the OwnerReferences for an object as specified by the enqueueRequestForOwner
+// - if IsController is true: only take the Controller OwnerReference (if found)
+// - if IsController is false: take all OwnerReferences.
+func (e *enqueueRequestForOwner) getOwnersReferences(object metav1.Object) []metav1.OwnerReference {
+ if object == nil {
+ return nil
+ }
+
+ // If not filtered as Controller only, then use all the OwnerReferences
+ if !e.isController {
+ return object.GetOwnerReferences()
+ }
+ // If filtered to a Controller, only take the Controller OwnerReference
+ if ownerRef := metav1.GetControllerOf(object); ownerRef != nil {
+ return []metav1.OwnerReference{*ownerRef}
+ }
+ // No Controller OwnerReference found
+ return nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go
new file mode 100644
index 00000000000..2f380f4fc4d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go
@@ -0,0 +1,106 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package handler
+
+import (
+ "context"
+
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+)
+
+// EventHandler enqueues reconcile.Requests in response to events (e.g. Pod Create). EventHandlers map an Event
+// for one object to trigger Reconciles for either the same object or different objects - e.g. if there is an
+// Event for object with type Foo (using source.KindSource) then reconcile one or more object(s) with type Bar.
+//
+// Identical reconcile.Requests will be batched together through the queuing mechanism before reconcile is called.
+//
+// * Use EnqueueRequestForObject to reconcile the object the event is for
+// - do this for events for the type the Controller Reconciles. (e.g. Deployment for a Deployment Controller)
+//
+// * Use EnqueueRequestForOwner to reconcile the owner of the object the event is for
+// - do this for events for the types the Controller creates. (e.g. ReplicaSets created by a Deployment Controller)
+//
+// * Use EnqueueRequestsFromMapFunc to transform an event for an object to a reconcile of an object
+// of a different type - do this for events for types the Controller may be interested in, but doesn't create.
+// (e.g. If Foo responds to cluster size events, map Node events to Foo objects.)
+//
+// Unless you are implementing your own EventHandler, you can ignore the functions on the EventHandler interface.
+// Most users shouldn't need to implement their own EventHandler.
+type EventHandler interface {
+ // Create is called in response to an create event - e.g. Pod Creation.
+ Create(context.Context, event.CreateEvent, workqueue.RateLimitingInterface)
+
+ // Update is called in response to an update event - e.g. Pod Updated.
+ Update(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface)
+
+ // Delete is called in response to a delete event - e.g. Pod Deleted.
+ Delete(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface)
+
+ // Generic is called in response to an event of an unknown type or a synthetic event triggered as a cron or
+ // external trigger request - e.g. reconcile Autoscaling, or a Webhook.
+ Generic(context.Context, event.GenericEvent, workqueue.RateLimitingInterface)
+}
+
+var _ EventHandler = Funcs{}
+
+// Funcs implements EventHandler.
+type Funcs struct {
+ // Create is called in response to an add event. Defaults to no-op.
+ // RateLimitingInterface is used to enqueue reconcile.Requests.
+ CreateFunc func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface)
+
+ // Update is called in response to an update event. Defaults to no-op.
+ // RateLimitingInterface is used to enqueue reconcile.Requests.
+ UpdateFunc func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface)
+
+ // Delete is called in response to a delete event. Defaults to no-op.
+ // RateLimitingInterface is used to enqueue reconcile.Requests.
+ DeleteFunc func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface)
+
+ // GenericFunc is called in response to a generic event. Defaults to no-op.
+ // RateLimitingInterface is used to enqueue reconcile.Requests.
+ GenericFunc func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface)
+}
+
+// Create implements EventHandler.
+func (h Funcs) Create(ctx context.Context, e event.CreateEvent, q workqueue.RateLimitingInterface) {
+ if h.CreateFunc != nil {
+ h.CreateFunc(ctx, e, q)
+ }
+}
+
+// Delete implements EventHandler.
+func (h Funcs) Delete(ctx context.Context, e event.DeleteEvent, q workqueue.RateLimitingInterface) {
+ if h.DeleteFunc != nil {
+ h.DeleteFunc(ctx, e, q)
+ }
+}
+
+// Update implements EventHandler.
+func (h Funcs) Update(ctx context.Context, e event.UpdateEvent, q workqueue.RateLimitingInterface) {
+ if h.UpdateFunc != nil {
+ h.UpdateFunc(ctx, e, q)
+ }
+}
+
+// Generic implements EventHandler.
+func (h Funcs) Generic(ctx context.Context, e event.GenericEvent, q workqueue.RateLimitingInterface) {
+ if h.GenericFunc != nil {
+ h.GenericFunc(ctx, e, q)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler_suite_test.go
new file mode 100644
index 00000000000..3f6b17f3377
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler_suite_test.go
@@ -0,0 +1,49 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package handler_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestEventhandler(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Eventhandler Suite")
+}
+
+var testenv *envtest.Environment
+var cfg *rest.Config
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+ testenv = &envtest.Environment{}
+ var err error
+ cfg, err = testenv.Start()
+ Expect(err).NotTo(HaveOccurred())
+})
+
+var _ = AfterSuite(func() {
+ Expect(testenv.Stop()).To(Succeed())
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler_test.go
new file mode 100644
index 00000000000..6ae87b0988a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler_test.go
@@ -0,0 +1,794 @@
+/*
+ Copyright 2018 The Kubernetes Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package handler_test
+
+import (
+ "context"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ appsv1 "k8s.io/api/apps/v1"
+ autoscalingv1 "k8s.io/api/autoscaling/v1"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/util/workqueue"
+ "k8s.io/utils/pointer"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllertest"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+var _ = Describe("Eventhandler", func() {
+ var ctx = context.Background()
+ var q workqueue.RateLimitingInterface
+ var instance handler.EnqueueRequestForObject
+ var pod *corev1.Pod
+ var mapper meta.RESTMapper
+ BeforeEach(func() {
+ q = &controllertest.Queue{Interface: workqueue.New()}
+ pod = &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{Namespace: "biz", Name: "baz"},
+ }
+ Expect(cfg).NotTo(BeNil())
+
+ httpClient, err := rest.HTTPClientFor(cfg)
+ Expect(err).ShouldNot(HaveOccurred())
+ mapper, err = apiutil.NewDiscoveryRESTMapper(cfg, httpClient)
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ Describe("EnqueueRequestForObject", func() {
+ It("should enqueue a Request with the Name / Namespace of the object in the CreateEvent.", func() {
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+
+ i, _ := q.Get()
+ Expect(i).NotTo(BeNil())
+ req, ok := i.(reconcile.Request)
+ Expect(ok).To(BeTrue())
+ Expect(req.NamespacedName).To(Equal(types.NamespacedName{Namespace: "biz", Name: "baz"}))
+ })
+
+ It("should enqueue a Request with the Name / Namespace of the object in the DeleteEvent.", func() {
+ evt := event.DeleteEvent{
+ Object: pod,
+ }
+ instance.Delete(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+
+ i, _ := q.Get()
+ Expect(i).NotTo(BeNil())
+ req, ok := i.(reconcile.Request)
+ Expect(ok).To(BeTrue())
+ Expect(req.NamespacedName).To(Equal(types.NamespacedName{Namespace: "biz", Name: "baz"}))
+ })
+
+ It("should enqueue a Request with the Name / Namespace of one object in the UpdateEvent.",
+ func() {
+ newPod := pod.DeepCopy()
+ newPod.Name = "baz2"
+ newPod.Namespace = "biz2"
+
+ evt := event.UpdateEvent{
+ ObjectOld: pod,
+ ObjectNew: newPod,
+ }
+ instance.Update(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+
+ i, _ := q.Get()
+ Expect(i).NotTo(BeNil())
+ req, ok := i.(reconcile.Request)
+ Expect(ok).To(BeTrue())
+ Expect(req.NamespacedName).To(Equal(types.NamespacedName{Namespace: "biz2", Name: "baz2"}))
+ })
+
+ It("should enqueue a Request with the Name / Namespace of the object in the GenericEvent.", func() {
+ evt := event.GenericEvent{
+ Object: pod,
+ }
+ instance.Generic(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+ i, _ := q.Get()
+ Expect(i).NotTo(BeNil())
+ req, ok := i.(reconcile.Request)
+ Expect(ok).To(BeTrue())
+ Expect(req.NamespacedName).To(Equal(types.NamespacedName{Namespace: "biz", Name: "baz"}))
+ })
+
+ Context("for a runtime.Object without Object", func() {
+ It("should do nothing if the Object is missing for a CreateEvent.", func() {
+ evt := event.CreateEvent{
+ Object: nil,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(0))
+ })
+
+ It("should do nothing if the Object is missing for a UpdateEvent.", func() {
+ newPod := pod.DeepCopy()
+ newPod.Name = "baz2"
+ newPod.Namespace = "biz2"
+
+ evt := event.UpdateEvent{
+ ObjectNew: newPod,
+ ObjectOld: nil,
+ }
+ instance.Update(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+ i, _ := q.Get()
+ Expect(i).NotTo(BeNil())
+ req, ok := i.(reconcile.Request)
+ Expect(ok).To(BeTrue())
+ Expect(req.NamespacedName).To(Equal(types.NamespacedName{Namespace: "biz2", Name: "baz2"}))
+
+ evt.ObjectNew = nil
+ evt.ObjectOld = pod
+ instance.Update(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+ i, _ = q.Get()
+ Expect(i).NotTo(BeNil())
+ req, ok = i.(reconcile.Request)
+ Expect(ok).To(BeTrue())
+ Expect(req.NamespacedName).To(Equal(types.NamespacedName{Namespace: "biz", Name: "baz"}))
+ })
+
+ It("should do nothing if the Object is missing for a DeleteEvent.", func() {
+ evt := event.DeleteEvent{
+ Object: nil,
+ }
+ instance.Delete(ctx, evt, q)
+ Expect(q.Len()).To(Equal(0))
+ })
+
+ It("should do nothing if the Object is missing for a GenericEvent.", func() {
+ evt := event.GenericEvent{
+ Object: nil,
+ }
+ instance.Generic(ctx, evt, q)
+ Expect(q.Len()).To(Equal(0))
+ })
+ })
+ })
+
+ Describe("EnqueueRequestsFromMapFunc", func() {
+ It("should enqueue a Request with the function applied to the CreateEvent.", func() {
+ req := []reconcile.Request{}
+ instance := handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a client.Object) []reconcile.Request {
+ defer GinkgoRecover()
+ Expect(a).To(Equal(pod))
+ req = []reconcile.Request{
+ {
+ NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"},
+ },
+ {
+ NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz"},
+ },
+ }
+ return req
+ })
+
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(2))
+
+ i1, _ := q.Get()
+ i2, _ := q.Get()
+ Expect([]interface{}{i1, i2}).To(ConsistOf(
+ reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"}},
+ reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz"}},
+ ))
+ })
+
+ It("should enqueue a Request with the function applied to the DeleteEvent.", func() {
+ req := []reconcile.Request{}
+ instance := handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a client.Object) []reconcile.Request {
+ defer GinkgoRecover()
+ Expect(a).To(Equal(pod))
+ req = []reconcile.Request{
+ {
+ NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"},
+ },
+ {
+ NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz"},
+ },
+ }
+ return req
+ })
+
+ evt := event.DeleteEvent{
+ Object: pod,
+ }
+ instance.Delete(ctx, evt, q)
+ Expect(q.Len()).To(Equal(2))
+
+ i1, _ := q.Get()
+ i2, _ := q.Get()
+ Expect([]interface{}{i1, i2}).To(ConsistOf(
+ reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"}},
+ reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz"}},
+ ))
+ })
+
+ It("should enqueue a Request with the function applied to both objects in the UpdateEvent.",
+ func() {
+ newPod := pod.DeepCopy()
+
+ req := []reconcile.Request{}
+
+ instance := handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a client.Object) []reconcile.Request {
+ defer GinkgoRecover()
+ req = []reconcile.Request{
+ {
+ NamespacedName: types.NamespacedName{Namespace: "foo", Name: a.GetName() + "-bar"},
+ },
+ {
+ NamespacedName: types.NamespacedName{Namespace: "biz", Name: a.GetName() + "-baz"},
+ },
+ }
+ return req
+ })
+
+ evt := event.UpdateEvent{
+ ObjectOld: pod,
+ ObjectNew: newPod,
+ }
+ instance.Update(ctx, evt, q)
+ Expect(q.Len()).To(Equal(2))
+
+ i, _ := q.Get()
+ Expect(i).To(Equal(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "foo", Name: "baz-bar"}}))
+
+ i, _ = q.Get()
+ Expect(i).To(Equal(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz-baz"}}))
+ })
+
+ It("should enqueue a Request with the function applied to the GenericEvent.", func() {
+ req := []reconcile.Request{}
+ instance := handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a client.Object) []reconcile.Request {
+ defer GinkgoRecover()
+ Expect(a).To(Equal(pod))
+ req = []reconcile.Request{
+ {
+ NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"},
+ },
+ {
+ NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz"},
+ },
+ }
+ return req
+ })
+
+ evt := event.GenericEvent{
+ Object: pod,
+ }
+ instance.Generic(ctx, evt, q)
+ Expect(q.Len()).To(Equal(2))
+
+ i1, _ := q.Get()
+ i2, _ := q.Get()
+ Expect([]interface{}{i1, i2}).To(ConsistOf(
+ reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"}},
+ reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz"}},
+ ))
+ })
+ })
+
+ Describe("EnqueueRequestForOwner", func() {
+ It("should enqueue a Request with the Owner of the object in the CreateEvent.", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
+
+ pod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ }
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+
+ i, _ := q.Get()
+ Expect(i).To(Equal(reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo-parent"}}))
+ })
+
+ It("should enqueue a Request with the Owner of the object in the DeleteEvent.", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
+
+ pod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ }
+ evt := event.DeleteEvent{
+ Object: pod,
+ }
+ instance.Delete(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+
+ i, _ := q.Get()
+ Expect(i).To(Equal(reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo-parent"}}))
+ })
+
+ It("should enqueue a Request with the Owners of both objects in the UpdateEvent.", func() {
+ newPod := pod.DeepCopy()
+ newPod.Name = pod.Name + "2"
+ newPod.Namespace = pod.Namespace + "2"
+
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
+
+ pod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo1-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ }
+ newPod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo2-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ }
+ evt := event.UpdateEvent{
+ ObjectOld: pod,
+ ObjectNew: newPod,
+ }
+ instance.Update(ctx, evt, q)
+ Expect(q.Len()).To(Equal(2))
+
+ i1, _ := q.Get()
+ i2, _ := q.Get()
+ Expect([]interface{}{i1, i2}).To(ConsistOf(
+ reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo1-parent"}},
+ reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: newPod.GetNamespace(), Name: "foo2-parent"}},
+ ))
+ })
+
+ It("should enqueue a Request with the one duplicate Owner of both objects in the UpdateEvent.", func() {
+ newPod := pod.DeepCopy()
+ newPod.Name = pod.Name + "2"
+
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
+
+ pod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ }
+ newPod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ }
+ evt := event.UpdateEvent{
+ ObjectOld: pod,
+ ObjectNew: newPod,
+ }
+ instance.Update(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+
+ i, _ := q.Get()
+ Expect(i).To(Equal(reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo-parent"}}))
+ })
+
+ It("should enqueue a Request with the Owner of the object in the GenericEvent.", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
+ pod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ }
+ evt := event.GenericEvent{
+ Object: pod,
+ }
+ instance.Generic(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+
+ i, _ := q.Get()
+ Expect(i).To(Equal(reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo-parent"}}))
+ })
+
+ It("should not enqueue a Request if there are no owners matching Group and Kind.", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{}, handler.OnlyControllerOwner())
+ pod.OwnerReferences = []metav1.OwnerReference{
+ { // Wrong group
+ Name: "foo1-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "extensions/v1",
+ },
+ { // Wrong kind
+ Name: "foo2-parent",
+ Kind: "Deployment",
+ APIVersion: "apps/v1",
+ },
+ }
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(0))
+ })
+
+ It("should enqueue a Request if there are owners matching Group "+
+ "and Kind with a different version.", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &autoscalingv1.HorizontalPodAutoscaler{})
+ pod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo-parent",
+ Kind: "HorizontalPodAutoscaler",
+ APIVersion: "autoscaling/v2beta1",
+ },
+ }
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+
+ i, _ := q.Get()
+ Expect(i).To(Equal(reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo-parent"}}))
+ })
+
+ It("should enqueue a Request for a owner that is cluster scoped", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &corev1.Node{})
+ pod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "node-1",
+ Kind: "Node",
+ APIVersion: "v1",
+ },
+ }
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+
+ i, _ := q.Get()
+ Expect(i).To(Equal(reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: "", Name: "node-1"}}))
+
+ })
+
+ It("should not enqueue a Request if there are no owners.", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(0))
+ })
+
+ Context("with the Controller field set to true", func() {
+ It("should enqueue reconcile.Requests for only the first the Controller if there are "+
+ "multiple Controller owners.", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{}, handler.OnlyControllerOwner())
+ pod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo1-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ {
+ Name: "foo2-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ Controller: pointer.Bool(true),
+ },
+ {
+ Name: "foo3-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ {
+ Name: "foo4-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ Controller: pointer.Bool(true),
+ },
+ {
+ Name: "foo5-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ }
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(1))
+ i, _ := q.Get()
+ Expect(i).To(Equal(reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo2-parent"}}))
+ })
+
+ It("should not enqueue reconcile.Requests if there are no Controller owners.", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{}, handler.OnlyControllerOwner())
+ pod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo1-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ {
+ Name: "foo2-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ {
+ Name: "foo3-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ }
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(0))
+ })
+
+ It("should not enqueue reconcile.Requests if there are no owners.", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{}, handler.OnlyControllerOwner())
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(0))
+ })
+ })
+
+ Context("with the Controller field set to false", func() {
+ It("should enqueue a reconcile.Requests for all owners.", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
+ pod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo1-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ {
+ Name: "foo2-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ {
+ Name: "foo3-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ }
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(3))
+
+ i1, _ := q.Get()
+ i2, _ := q.Get()
+ i3, _ := q.Get()
+ Expect([]interface{}{i1, i2, i3}).To(ConsistOf(
+ reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo1-parent"}},
+ reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo2-parent"}},
+ reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo3-parent"}},
+ ))
+ })
+ })
+
+ Context("with a nil object", func() {
+ It("should do nothing.", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
+ pod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo1-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1",
+ },
+ }
+ evt := event.CreateEvent{
+ Object: nil,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(0))
+ })
+ })
+
+ Context("with a nil OwnerType", func() {
+ It("should panic", func() {
+ Expect(func() {
+ handler.EnqueueRequestForOwner(nil, nil, nil)
+ }).To(Panic())
+ })
+ })
+
+ Context("with an invalid APIVersion in the OwnerReference", func() {
+ It("should do nothing.", func() {
+ instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
+ pod.OwnerReferences = []metav1.OwnerReference{
+ {
+ Name: "foo1-parent",
+ Kind: "ReplicaSet",
+ APIVersion: "apps/v1/fail",
+ },
+ }
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ Expect(q.Len()).To(Equal(0))
+ })
+ })
+ })
+
+ Describe("Funcs", func() {
+ failingFuncs := handler.Funcs{
+ CreateFunc: func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Did not expect CreateEvent to be called.")
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Did not expect DeleteEvent to be called.")
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Did not expect UpdateEvent to be called.")
+ },
+ GenericFunc: func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Did not expect GenericEvent to be called.")
+ },
+ }
+
+ It("should call CreateFunc for a CreateEvent if provided.", func() {
+ instance := failingFuncs
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.CreateFunc = func(ctx context.Context, evt2 event.CreateEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(q2).To(Equal(q))
+ Expect(evt2).To(Equal(evt))
+ }
+ instance.Create(ctx, evt, q)
+ })
+
+ It("should NOT call CreateFunc for a CreateEvent if NOT provided.", func() {
+ instance := failingFuncs
+ instance.CreateFunc = nil
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ instance.Create(ctx, evt, q)
+ })
+
+ It("should call UpdateFunc for an UpdateEvent if provided.", func() {
+ newPod := pod.DeepCopy()
+ newPod.Name = pod.Name + "2"
+ newPod.Namespace = pod.Namespace + "2"
+ evt := event.UpdateEvent{
+ ObjectOld: pod,
+ ObjectNew: newPod,
+ }
+
+ instance := failingFuncs
+ instance.UpdateFunc = func(ctx context.Context, evt2 event.UpdateEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(q2).To(Equal(q))
+ Expect(evt2).To(Equal(evt))
+ }
+
+ instance.Update(ctx, evt, q)
+ })
+
+ It("should NOT call UpdateFunc for an UpdateEvent if NOT provided.", func() {
+ newPod := pod.DeepCopy()
+ newPod.Name = pod.Name + "2"
+ newPod.Namespace = pod.Namespace + "2"
+ evt := event.UpdateEvent{
+ ObjectOld: pod,
+ ObjectNew: newPod,
+ }
+ instance.Update(ctx, evt, q)
+ })
+
+ It("should call DeleteFunc for a DeleteEvent if provided.", func() {
+ instance := failingFuncs
+ evt := event.DeleteEvent{
+ Object: pod,
+ }
+ instance.DeleteFunc = func(ctx context.Context, evt2 event.DeleteEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(q2).To(Equal(q))
+ Expect(evt2).To(Equal(evt))
+ }
+ instance.Delete(ctx, evt, q)
+ })
+
+ It("should NOT call DeleteFunc for a DeleteEvent if NOT provided.", func() {
+ instance := failingFuncs
+ instance.DeleteFunc = nil
+ evt := event.DeleteEvent{
+ Object: pod,
+ }
+ instance.Delete(ctx, evt, q)
+ })
+
+ It("should call GenericFunc for a GenericEvent if provided.", func() {
+ instance := failingFuncs
+ evt := event.GenericEvent{
+ Object: pod,
+ }
+ instance.GenericFunc = func(ctx context.Context, evt2 event.GenericEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(q2).To(Equal(q))
+ Expect(evt2).To(Equal(evt))
+ }
+ instance.Generic(ctx, evt, q)
+ })
+
+ It("should NOT call GenericFunc for a GenericEvent if NOT provided.", func() {
+ instance := failingFuncs
+ instance.GenericFunc = nil
+ evt := event.GenericEvent{
+ Object: pod,
+ }
+ instance.Generic(ctx, evt, q)
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/handler/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/example_test.go
new file mode 100644
index 00000000000..ad07e4e31df
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/handler/example_test.go
@@ -0,0 +1,123 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package handler_test
+
+import (
+ "context"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+var mgr manager.Manager
+var c controller.Controller
+
+// This example watches Pods and enqueues Requests with the Name and Namespace of the Pod from
+// the Event (i.e. change caused by a Create, Update, Delete).
+func ExampleEnqueueRequestForObject() {
+ // controller is a controller.controller
+ err := c.Watch(
+ source.Kind(mgr.GetCache(), &corev1.Pod{}),
+ &handler.EnqueueRequestForObject{},
+ )
+ if err != nil {
+ // handle it
+ }
+}
+
+// This example watches ReplicaSets and enqueues a Request containing the Name and Namespace of the
+// owning (direct) Deployment responsible for the creation of the ReplicaSet.
+func ExampleEnqueueRequestForOwner() {
+ // controller is a controller.controller
+ err := c.Watch(
+ source.Kind(mgr.GetCache(), &appsv1.ReplicaSet{}),
+ handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &appsv1.Deployment{}, handler.OnlyControllerOwner()),
+ )
+ if err != nil {
+ // handle it
+ }
+}
+
+// This example watches Deployments and enqueues a Request contain the Name and Namespace of different
+// objects (of Type: MyKind) using a mapping function defined by the user.
+func ExampleEnqueueRequestsFromMapFunc() {
+ // controller is a controller.controller
+ err := c.Watch(
+ source.Kind(mgr.GetCache(), &appsv1.Deployment{}),
+ handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a client.Object) []reconcile.Request {
+ return []reconcile.Request{
+ {NamespacedName: types.NamespacedName{
+ Name: a.GetName() + "-1",
+ Namespace: a.GetNamespace(),
+ }},
+ {NamespacedName: types.NamespacedName{
+ Name: a.GetName() + "-2",
+ Namespace: a.GetNamespace(),
+ }},
+ }
+ }),
+ )
+ if err != nil {
+ // handle it
+ }
+}
+
+// This example implements handler.EnqueueRequestForObject.
+func ExampleFuncs() {
+ // controller is a controller.controller
+ err := c.Watch(
+ source.Kind(mgr.GetCache(), &corev1.Pod{}),
+ handler.Funcs{
+ CreateFunc: func(ctx context.Context, e event.CreateEvent, q workqueue.RateLimitingInterface) {
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: e.Object.GetName(),
+ Namespace: e.Object.GetNamespace(),
+ }})
+ },
+ UpdateFunc: func(ctx context.Context, e event.UpdateEvent, q workqueue.RateLimitingInterface) {
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: e.ObjectNew.GetName(),
+ Namespace: e.ObjectNew.GetNamespace(),
+ }})
+ },
+ DeleteFunc: func(ctx context.Context, e event.DeleteEvent, q workqueue.RateLimitingInterface) {
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: e.Object.GetName(),
+ Namespace: e.Object.GetNamespace(),
+ }})
+ },
+ GenericFunc: func(ctx context.Context, e event.GenericEvent, q workqueue.RateLimitingInterface) {
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: e.Object.GetName(),
+ Namespace: e.Object.GetNamespace(),
+ }})
+ },
+ },
+ )
+ if err != nil {
+ // handle it
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/healthz/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/healthz/doc.go
new file mode 100644
index 00000000000..9827eeafed3
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/healthz/doc.go
@@ -0,0 +1,32 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package healthz contains helpers from supporting liveness and readiness endpoints.
+// (often referred to as healthz and readyz, respectively).
+//
+// This package draws heavily from the apiserver's healthz package
+// ( https://github.com/kubernetes/apiserver/tree/master/pkg/server/healthz )
+// but has some changes to bring it in line with controller-runtime's style.
+//
+// The main entrypoint is the Handler -- this serves both aggregated health status
+// and individual health check endpoints.
+package healthz
+
+import (
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("healthz")
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/healthz/healthz.go b/third_party/sigs.k8s.io/controller-runtime/pkg/healthz/healthz.go
new file mode 100644
index 00000000000..cfb5dc8d02b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/healthz/healthz.go
@@ -0,0 +1,206 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package healthz
+
+import (
+ "fmt"
+ "net/http"
+ "path"
+ "sort"
+ "strings"
+
+ "k8s.io/apimachinery/pkg/util/sets"
+)
+
+// Handler is an http.Handler that aggregates the results of the given
+// checkers to the root path, and supports calling individual checkers on
+// subpaths of the name of the checker.
+//
+// Adding checks on the fly is *not* threadsafe -- use a wrapper.
+type Handler struct {
+ Checks map[string]Checker
+}
+
+// checkStatus holds the output of a particular check.
+type checkStatus struct {
+ name string
+ healthy bool
+ excluded bool
+}
+
+func (h *Handler) serveAggregated(resp http.ResponseWriter, req *http.Request) {
+ failed := false
+ excluded := getExcludedChecks(req)
+
+ parts := make([]checkStatus, 0, len(h.Checks))
+
+ // calculate the results...
+ for checkName, check := range h.Checks {
+ // no-op the check if we've specified we want to exclude the check
+ if excluded.Has(checkName) {
+ excluded.Delete(checkName)
+ parts = append(parts, checkStatus{name: checkName, healthy: true, excluded: true})
+ continue
+ }
+ if err := check(req); err != nil {
+ log.V(1).Info("healthz check failed", "checker", checkName, "error", err)
+ parts = append(parts, checkStatus{name: checkName, healthy: false})
+ failed = true
+ } else {
+ parts = append(parts, checkStatus{name: checkName, healthy: true})
+ }
+ }
+
+ // ...default a check if none is present...
+ if len(h.Checks) == 0 {
+ parts = append(parts, checkStatus{name: "ping", healthy: true})
+ }
+
+ for _, c := range excluded.UnsortedList() {
+ log.V(1).Info("cannot exclude health check, no matches for it", "checker", c)
+ }
+
+ // ...sort to be consistent...
+ sort.Slice(parts, func(i, j int) bool { return parts[i].name < parts[j].name })
+
+ // ...and write out the result
+ // TODO(directxman12): this should also accept a request for JSON content (via a accept header)
+ _, forceVerbose := req.URL.Query()["verbose"]
+ writeStatusesAsText(resp, parts, excluded, failed, forceVerbose)
+}
+
+// writeStatusAsText writes out the given check statuses in some semi-arbitrary
+// bespoke text format that we copied from Kubernetes. unknownExcludes lists
+// any checks that the user requested to have excluded, but weren't actually
+// known checks. writeStatusAsText is always verbose on failure, and can be
+// forced to be verbose on success using the given argument.
+func writeStatusesAsText(resp http.ResponseWriter, parts []checkStatus, unknownExcludes sets.Set[string], failed, forceVerbose bool) {
+ resp.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ resp.Header().Set("X-Content-Type-Options", "nosniff")
+
+ // always write status code first
+ if failed {
+ resp.WriteHeader(http.StatusInternalServerError)
+ } else {
+ resp.WriteHeader(http.StatusOK)
+ }
+
+ // shortcut for easy non-verbose success
+ if !failed && !forceVerbose {
+ fmt.Fprint(resp, "ok")
+ return
+ }
+
+ // we're always verbose on failure, so from this point on we're guaranteed to be verbose
+
+ for _, checkOut := range parts {
+ switch {
+ case checkOut.excluded:
+ fmt.Fprintf(resp, "[+]%s excluded: ok\n", checkOut.name)
+ case checkOut.healthy:
+ fmt.Fprintf(resp, "[+]%s ok\n", checkOut.name)
+ default:
+ // don't include the error since this endpoint is public. If someone wants more detail
+ // they should have explicit permission to the detailed checks.
+ fmt.Fprintf(resp, "[-]%s failed: reason withheld\n", checkOut.name)
+ }
+ }
+
+ if unknownExcludes.Len() > 0 {
+ fmt.Fprintf(resp, "warn: some health checks cannot be excluded: no matches for %s\n", formatQuoted(unknownExcludes.UnsortedList()...))
+ }
+
+ if failed {
+ log.Info("healthz check failed", "statuses", parts)
+ fmt.Fprintf(resp, "healthz check failed\n")
+ } else {
+ fmt.Fprint(resp, "healthz check passed\n")
+ }
+}
+
+func (h *Handler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
+ // clean up the request (duplicating the internal logic of http.ServeMux a bit)
+ // clean up the path a bit
+ reqPath := req.URL.Path
+ if reqPath == "" || reqPath[0] != '/' {
+ reqPath = "/" + reqPath
+ }
+ // path.Clean removes the trailing slash except for root for us
+ // (which is fine, since we're only serving one layer of sub-paths)
+ reqPath = path.Clean(reqPath)
+
+ // either serve the root endpoint...
+ if reqPath == "/" {
+ h.serveAggregated(resp, req)
+ return
+ }
+
+ // ...the default check (if nothing else is present)...
+ if len(h.Checks) == 0 && reqPath[1:] == "ping" {
+ CheckHandler{Checker: Ping}.ServeHTTP(resp, req)
+ return
+ }
+
+ // ...or an individual checker
+ checkName := reqPath[1:] // ignore the leading slash
+ checker, known := h.Checks[checkName]
+ if !known {
+ http.NotFoundHandler().ServeHTTP(resp, req)
+ return
+ }
+
+ CheckHandler{Checker: checker}.ServeHTTP(resp, req)
+}
+
+// CheckHandler is an http.Handler that serves a health check endpoint at the root path,
+// based on its checker.
+type CheckHandler struct {
+ Checker
+}
+
+func (h CheckHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
+ if err := h.Checker(req); err != nil {
+ http.Error(resp, fmt.Sprintf("internal server error: %v", err), http.StatusInternalServerError)
+ } else {
+ fmt.Fprint(resp, "ok")
+ }
+}
+
+// Checker knows how to perform a health check.
+type Checker func(req *http.Request) error
+
+// Ping returns true automatically when checked.
+var Ping Checker = func(_ *http.Request) error { return nil }
+
+// getExcludedChecks extracts the health check names to be excluded from the query param.
+func getExcludedChecks(r *http.Request) sets.Set[string] {
+ checks, found := r.URL.Query()["exclude"]
+ if found {
+ return sets.New[string](checks...)
+ }
+ return sets.New[string]()
+}
+
+// formatQuoted returns a formatted string of the health check names,
+// preserving the order passed in.
+func formatQuoted(names ...string) string {
+ quoted := make([]string, 0, len(names))
+ for _, name := range names {
+ quoted = append(quoted, fmt.Sprintf("%q", name))
+ }
+ return strings.Join(quoted, ",")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/healthz/healthz_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/healthz/healthz_suite_test.go
new file mode 100644
index 00000000000..8e16a58aa0b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/healthz/healthz_suite_test.go
@@ -0,0 +1,35 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package healthz_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestHealthz(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Healthz Suite")
+}
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/healthz/healthz_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/healthz/healthz_test.go
new file mode 100644
index 00000000000..639a7575f30
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/healthz/healthz_test.go
@@ -0,0 +1,203 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package healthz_test
+
+import (
+ "errors"
+ "net/http"
+ "net/http/httptest"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "sigs.k8s.io/controller-runtime/pkg/healthz"
+)
+
+const (
+ contentType = "text/plain; charset=utf-8"
+)
+
+func requestTo(handler http.Handler, dest string) *httptest.ResponseRecorder {
+ req, err := http.NewRequest("GET", dest, nil)
+ Expect(err).NotTo(HaveOccurred())
+ resp := httptest.NewRecorder()
+ handler.ServeHTTP(resp, req)
+
+ return resp
+}
+
+var _ = Describe("Healthz Handler", func() {
+ Describe("the aggregated endpoint", func() {
+ It("should return healthy if all checks succeed", func() {
+ handler := &healthz.Handler{Checks: map[string]healthz.Checker{
+ "ok1": healthz.Ping,
+ "ok2": healthz.Ping,
+ }}
+
+ resp := requestTo(handler, "/")
+ Expect(resp.Code).To(Equal(http.StatusOK))
+ })
+
+ It("should return unhealthy if at least one check fails", func() {
+ handler := &healthz.Handler{Checks: map[string]healthz.Checker{
+ "ok1": healthz.Ping,
+ "bad1": func(req *http.Request) error {
+ return errors.New("blech")
+ },
+ }}
+
+ resp := requestTo(handler, "/")
+ Expect(resp.Code).To(Equal(http.StatusInternalServerError))
+ })
+
+ It("should ingore excluded checks when determining health", func() {
+ handler := &healthz.Handler{Checks: map[string]healthz.Checker{
+ "ok1": healthz.Ping,
+ "bad1": func(req *http.Request) error {
+ return errors.New("blech")
+ },
+ }}
+
+ resp := requestTo(handler, "/?exclude=bad1")
+ Expect(resp.Code).To(Equal(http.StatusOK))
+ })
+
+ It("should be fine if asked to exclude a check that doesn't exist", func() {
+ handler := &healthz.Handler{Checks: map[string]healthz.Checker{
+ "ok1": healthz.Ping,
+ "ok2": healthz.Ping,
+ }}
+
+ resp := requestTo(handler, "/?exclude=nonexistant")
+ Expect(resp.Code).To(Equal(http.StatusOK))
+ })
+
+ Context("when verbose output is requested with ?verbose=true", func() {
+ It("should return verbose output for ok cases", func() {
+ handler := &healthz.Handler{Checks: map[string]healthz.Checker{
+ "ok1": healthz.Ping,
+ "ok2": healthz.Ping,
+ }}
+
+ resp := requestTo(handler, "/?verbose=true")
+ Expect(resp.Code).To(Equal(http.StatusOK))
+ Expect(resp.Header().Get("Content-Type")).To(Equal(contentType))
+ Expect(resp.Body.String()).To(Equal("[+]ok1 ok\n[+]ok2 ok\nhealthz check passed\n"))
+ })
+
+ It("should return verbose output for failures", func() {
+ handler := &healthz.Handler{Checks: map[string]healthz.Checker{
+ "ok1": healthz.Ping,
+ "bad1": func(req *http.Request) error {
+ return errors.New("blech")
+ },
+ }}
+
+ resp := requestTo(handler, "/?verbose=true")
+ Expect(resp.Code).To(Equal(http.StatusInternalServerError))
+ Expect(resp.Header().Get("Content-Type")).To(Equal(contentType))
+ Expect(resp.Body.String()).To(Equal("[-]bad1 failed: reason withheld\n[+]ok1 ok\nhealthz check failed\n"))
+ })
+ })
+
+ It("should return non-verbose output when healthy and not specified as verbose", func() {
+ handler := &healthz.Handler{Checks: map[string]healthz.Checker{
+ "ok1": healthz.Ping,
+ "ok2": healthz.Ping,
+ }}
+
+ resp := requestTo(handler, "/")
+ Expect(resp.Header().Get("Content-Type")).To(Equal(contentType))
+ Expect(resp.Body.String()).To(Equal("ok"))
+
+ })
+
+ It("should always be verbose if a check fails", func() {
+ handler := &healthz.Handler{Checks: map[string]healthz.Checker{
+ "ok1": healthz.Ping,
+ "bad1": func(req *http.Request) error {
+ return errors.New("blech")
+ },
+ }}
+
+ resp := requestTo(handler, "/")
+ Expect(resp.Header().Get("Content-Type")).To(Equal(contentType))
+ Expect(resp.Body.String()).To(Equal("[-]bad1 failed: reason withheld\n[+]ok1 ok\nhealthz check failed\n"))
+ })
+
+ It("should always return a ping endpoint if no other ones are present", func() {
+ resp := requestTo(&healthz.Handler{}, "/?verbose=true")
+ Expect(resp.Code).To(Equal(http.StatusOK))
+ Expect(resp.Header().Get("Content-Type")).To(Equal(contentType))
+ Expect(resp.Body.String()).To(Equal("[+]ping ok\nhealthz check passed\n"))
+ })
+ })
+
+ Describe("the per-check endpoints", func() {
+ It("should return ok if the requested check is healthy", func() {
+ handler := &healthz.Handler{Checks: map[string]healthz.Checker{
+ "okcheck": healthz.Ping,
+ }}
+
+ resp := requestTo(handler, "/okcheck")
+ Expect(resp.Code).To(Equal(http.StatusOK))
+ Expect(resp.Header().Get("Content-Type")).To(Equal(contentType))
+ Expect(resp.Body.String()).To(Equal("ok"))
+ })
+
+ It("should return an error if the requested check is unhealthy", func() {
+ handler := &healthz.Handler{Checks: map[string]healthz.Checker{
+ "failcheck": func(req *http.Request) error {
+ return errors.New("blech")
+ },
+ }}
+
+ resp := requestTo(handler, "/failcheck")
+ Expect(resp.Code).To(Equal(http.StatusInternalServerError))
+ Expect(resp.Header().Get("Content-Type")).To(Equal(contentType))
+ Expect(resp.Body.String()).To(Equal("internal server error: blech\n"))
+ })
+
+ It("shouldn't take other checks into account", func() {
+ handler := &healthz.Handler{Checks: map[string]healthz.Checker{
+ "failcheck": func(req *http.Request) error {
+ return errors.New("blech")
+ },
+ "okcheck": healthz.Ping,
+ }}
+
+ By("checking the bad endpoint and expecting it to fail")
+ resp := requestTo(handler, "/failcheck")
+ Expect(resp.Code).To(Equal(http.StatusInternalServerError))
+
+ By("checking the good endpoint and expecting it to succeed")
+ resp = requestTo(handler, "/okcheck")
+ Expect(resp.Code).To(Equal(http.StatusOK))
+ })
+
+ It("should return non-found for paths that don't match a checker", func() {
+ handler := &healthz.Handler{}
+
+ resp := requestTo(handler, "/doesnotexist")
+ Expect(resp.Code).To(Equal(http.StatusNotFound))
+ })
+
+ It("should always return a ping endpoint if no other ones are present", func() {
+ resp := requestTo(&healthz.Handler{}, "/ping")
+ Expect(resp.Code).To(Equal(http.StatusOK))
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go
new file mode 100644
index 00000000000..83aba28cb7b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go
@@ -0,0 +1,370 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controller
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/go-logr/logr"
+ "k8s.io/apimachinery/pkg/types"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+ "k8s.io/apimachinery/pkg/util/uuid"
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+// Controller implements controller.Controller.
+type Controller struct {
+ // Name is used to uniquely identify a Controller in tracing, logging and monitoring. Name is required.
+ Name string
+
+ // MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
+ MaxConcurrentReconciles int
+
+ // Reconciler is a function that can be called at any time with the Name / Namespace of an object and
+ // ensures that the state of the system matches the state specified in the object.
+ // Defaults to the DefaultReconcileFunc.
+ Do reconcile.Reconciler
+
+ // MakeQueue constructs the queue for this controller once the controller is ready to start.
+ // This exists because the standard Kubernetes workqueues start themselves immediately, which
+ // leads to goroutine leaks if something calls controller.New repeatedly.
+ MakeQueue func() workqueue.RateLimitingInterface
+
+ // Queue is an listeningQueue that listens for events from Informers and adds object keys to
+ // the Queue for processing
+ Queue workqueue.RateLimitingInterface
+
+ // mu is used to synchronize Controller setup
+ mu sync.Mutex
+
+ // Started is true if the Controller has been Started
+ Started bool
+
+ // ctx is the context that was passed to Start() and used when starting watches.
+ //
+ // According to the docs, contexts should not be stored in a struct: https://golang.org/pkg/context,
+ // while we usually always strive to follow best practices, we consider this a legacy case and it should
+ // undergo a major refactoring and redesign to allow for context to not be stored in a struct.
+ ctx context.Context
+
+ // CacheSyncTimeout refers to the time limit set on waiting for cache to sync
+ // Defaults to 2 minutes if not set.
+ CacheSyncTimeout time.Duration
+
+ // startWatches maintains a list of sources, handlers, and predicates to start when the controller is started.
+ startWatches []watchDescription
+
+ // LogConstructor is used to construct a logger to then log messages to users during reconciliation,
+ // or for example when a watch is started.
+ // Note: LogConstructor has to be able to handle nil requests as we are also using it
+ // outside the context of a reconciliation.
+ LogConstructor func(request *reconcile.Request) logr.Logger
+
+ // RecoverPanic indicates whether the panic caused by reconcile should be recovered.
+ RecoverPanic *bool
+
+ // LeaderElected indicates whether the controller is leader elected or always running.
+ LeaderElected *bool
+}
+
+// watchDescription contains all the information necessary to start a watch.
+type watchDescription struct {
+ src source.Source
+ handler handler.EventHandler
+ predicates []predicate.Predicate
+}
+
+// Reconcile implements reconcile.Reconciler.
+func (c *Controller) Reconcile(ctx context.Context, req reconcile.Request) (_ reconcile.Result, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if c.RecoverPanic != nil && *c.RecoverPanic {
+ for _, fn := range utilruntime.PanicHandlers {
+ fn(r)
+ }
+ err = fmt.Errorf("panic: %v [recovered]", r)
+ return
+ }
+
+ log := logf.FromContext(ctx)
+ log.Info(fmt.Sprintf("Observed a panic in reconciler: %v", r))
+ panic(r)
+ }
+ }()
+ return c.Do.Reconcile(ctx, req)
+}
+
+// Watch implements controller.Controller.
+func (c *Controller) Watch(src source.Source, evthdler handler.EventHandler, prct ...predicate.Predicate) error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ // Controller hasn't started yet, store the watches locally and return.
+ //
+ // These watches are going to be held on the controller struct until the manager or user calls Start(...).
+ if !c.Started {
+ c.startWatches = append(c.startWatches, watchDescription{src: src, handler: evthdler, predicates: prct})
+ return nil
+ }
+
+ c.LogConstructor(nil).Info("Starting EventSource", "source", src)
+ return src.Start(c.ctx, evthdler, c.Queue, prct...)
+}
+
+// NeedLeaderElection implements the manager.LeaderElectionRunnable interface.
+func (c *Controller) NeedLeaderElection() bool {
+ if c.LeaderElected == nil {
+ return true
+ }
+ return *c.LeaderElected
+}
+
+// Start implements controller.Controller.
+func (c *Controller) Start(ctx context.Context) error {
+ // use an IIFE to get proper lock handling
+ // but lock outside to get proper handling of the queue shutdown
+ c.mu.Lock()
+ if c.Started {
+ return errors.New("controller was started more than once. This is likely to be caused by being added to a manager multiple times")
+ }
+
+ c.initMetrics()
+
+ // Set the internal context.
+ c.ctx = ctx
+
+ c.Queue = c.MakeQueue()
+ go func() {
+ <-ctx.Done()
+ c.Queue.ShutDown()
+ }()
+
+ wg := &sync.WaitGroup{}
+ err := func() error {
+ defer c.mu.Unlock()
+
+ // TODO(pwittrock): Reconsider HandleCrash
+ defer utilruntime.HandleCrash()
+
+ // NB(directxman12): launch the sources *before* trying to wait for the
+ // caches to sync so that they have a chance to register their intendeded
+ // caches.
+ for _, watch := range c.startWatches {
+ c.LogConstructor(nil).Info("Starting EventSource", "source", fmt.Sprintf("%s", watch.src))
+
+ if err := watch.src.Start(ctx, watch.handler, c.Queue, watch.predicates...); err != nil {
+ return err
+ }
+ }
+
+ // Start the SharedIndexInformer factories to begin populating the SharedIndexInformer caches
+ c.LogConstructor(nil).Info("Starting Controller")
+
+ for _, watch := range c.startWatches {
+ syncingSource, ok := watch.src.(source.SyncingSource)
+ if !ok {
+ continue
+ }
+
+ if err := func() error {
+ // use a context with timeout for launching sources and syncing caches.
+ sourceStartCtx, cancel := context.WithTimeout(ctx, c.CacheSyncTimeout)
+ defer cancel()
+
+ // WaitForSync waits for a definitive timeout, and returns if there
+ // is an error or a timeout
+ if err := syncingSource.WaitForSync(sourceStartCtx); err != nil {
+ err := fmt.Errorf("failed to wait for %s caches to sync: %w", c.Name, err)
+ c.LogConstructor(nil).Error(err, "Could not wait for Cache to sync")
+ return err
+ }
+
+ return nil
+ }(); err != nil {
+ return err
+ }
+ }
+
+ // All the watches have been started, we can reset the local slice.
+ //
+ // We should never hold watches more than necessary, each watch source can hold a backing cache,
+ // which won't be garbage collected if we hold a reference to it.
+ c.startWatches = nil
+
+ // Launch workers to process resources
+ c.LogConstructor(nil).Info("Starting workers", "worker count", c.MaxConcurrentReconciles)
+ wg.Add(c.MaxConcurrentReconciles)
+ for i := 0; i < c.MaxConcurrentReconciles; i++ {
+ go func() {
+ defer wg.Done()
+ // Run a worker thread that just dequeues items, processes them, and marks them done.
+ // It enforces that the reconcileHandler is never invoked concurrently with the same object.
+ for c.processNextWorkItem(ctx) {
+ }
+ }()
+ }
+
+ c.Started = true
+ return nil
+ }()
+ if err != nil {
+ return err
+ }
+
+ <-ctx.Done()
+ c.LogConstructor(nil).Info("Shutdown signal received, waiting for all workers to finish")
+ wg.Wait()
+ c.LogConstructor(nil).Info("All workers finished")
+ return nil
+}
+
+// processNextWorkItem will read a single work item off the workqueue and
+// attempt to process it, by calling the reconcileHandler.
+func (c *Controller) processNextWorkItem(ctx context.Context) bool {
+ obj, shutdown := c.Queue.Get()
+ if shutdown {
+ // Stop working
+ return false
+ }
+
+ // We call Done here so the workqueue knows we have finished
+ // processing this item. We also must remember to call Forget if we
+ // do not want this work item being re-queued. For example, we do
+ // not call Forget if a transient error occurs, instead the item is
+ // put back on the workqueue and attempted again after a back-off
+ // period.
+ defer c.Queue.Done(obj)
+
+ ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Add(1)
+ defer ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Add(-1)
+
+ c.reconcileHandler(ctx, obj)
+ return true
+}
+
+const (
+ labelError = "error"
+ labelRequeueAfter = "requeue_after"
+ labelRequeue = "requeue"
+ labelSuccess = "success"
+)
+
+func (c *Controller) initMetrics() {
+ ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Set(0)
+ ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Add(0)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelError).Add(0)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeueAfter).Add(0)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeue).Add(0)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelSuccess).Add(0)
+ ctrlmetrics.WorkerCount.WithLabelValues(c.Name).Set(float64(c.MaxConcurrentReconciles))
+}
+
+func (c *Controller) reconcileHandler(ctx context.Context, obj interface{}) {
+ // Update metrics after processing each item
+ reconcileStartTS := time.Now()
+ defer func() {
+ c.updateMetrics(time.Since(reconcileStartTS))
+ }()
+
+ // Make sure that the object is a valid request.
+ req, ok := obj.(reconcile.Request)
+ if !ok {
+ // As the item in the workqueue is actually invalid, we call
+ // Forget here else we'd go into a loop of attempting to
+ // process a work item that is invalid.
+ c.Queue.Forget(obj)
+ c.LogConstructor(nil).Error(nil, "Queue item was not a Request", "type", fmt.Sprintf("%T", obj), "value", obj)
+ // Return true, don't take a break
+ return
+ }
+
+ log := c.LogConstructor(&req)
+ reconcileID := uuid.NewUUID()
+
+ log = log.WithValues("reconcileID", reconcileID)
+ ctx = logf.IntoContext(ctx, log)
+ ctx = addReconcileID(ctx, reconcileID)
+
+ // RunInformersAndControllers the syncHandler, passing it the Namespace/Name string of the
+ // resource to be synced.
+ result, err := c.Reconcile(ctx, req)
+ switch {
+ case err != nil:
+ if errors.Is(err, reconcile.TerminalError(nil)) {
+ ctrlmetrics.TerminalReconcileErrors.WithLabelValues(c.Name).Inc()
+ } else {
+ c.Queue.AddRateLimited(req)
+ }
+ ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Inc()
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelError).Inc()
+ log.Error(err, "Reconciler error")
+ case result.RequeueAfter > 0:
+ // The result.RequeueAfter request will be lost, if it is returned
+ // along with a non-nil error. But this is intended as
+ // We need to drive to stable reconcile loops before queuing due
+ // to result.RequestAfter
+ c.Queue.Forget(obj)
+ c.Queue.AddAfter(req, result.RequeueAfter)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeueAfter).Inc()
+ case result.Requeue:
+ c.Queue.AddRateLimited(req)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeue).Inc()
+ default:
+ // Finally, if no error occurs we Forget this item so it does not
+ // get queued again until another change happens.
+ c.Queue.Forget(obj)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelSuccess).Inc()
+ }
+}
+
+// GetLogger returns this controller's logger.
+func (c *Controller) GetLogger() logr.Logger {
+ return c.LogConstructor(nil)
+}
+
+// updateMetrics updates prometheus metrics within the controller.
+func (c *Controller) updateMetrics(reconcileTime time.Duration) {
+ ctrlmetrics.ReconcileTime.WithLabelValues(c.Name).Observe(reconcileTime.Seconds())
+}
+
+// ReconcileIDFromContext gets the reconcileID from the current context.
+func ReconcileIDFromContext(ctx context.Context) types.UID {
+ r, ok := ctx.Value(reconcileIDKey{}).(types.UID)
+ if !ok {
+ return ""
+ }
+
+ return r
+}
+
+// reconcileIDKey is a context.Context Value key. Its associated value should
+// be a types.UID.
+type reconcileIDKey struct{}
+
+func addReconcileID(ctx context.Context, reconcileID types.UID) context.Context {
+ return context.WithValue(ctx, reconcileIDKey{}, reconcileID)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller_suite_test.go
new file mode 100644
index 00000000000..3143d3dd74b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller_suite_test.go
@@ -0,0 +1,55 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controller
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Controller internal Suite")
+}
+
+var testenv *envtest.Environment
+var cfg *rest.Config
+var clientset *kubernetes.Clientset
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+ testenv = &envtest.Environment{}
+
+ var err error
+ cfg, err = testenv.Start()
+ Expect(err).NotTo(HaveOccurred())
+
+ clientset, err = kubernetes.NewForConfig(cfg)
+ Expect(err).NotTo(HaveOccurred())
+})
+
+var _ = AfterSuite(func() {
+ Expect(testenv.Stop()).To(Succeed())
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller_test.go
new file mode 100644
index 00000000000..d669b1acf0c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller_test.go
@@ -0,0 +1,879 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controller
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/go-logr/logr"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/prometheus/client_golang/prometheus"
+ dto "github.com/prometheus/client_model/go"
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/util/workqueue"
+ "k8s.io/utils/pointer"
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/cache/informertest"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllertest"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics"
+ "sigs.k8s.io/controller-runtime/pkg/internal/log"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+var _ = Describe("controller", func() {
+ var fakeReconcile *fakeReconciler
+ var ctrl *Controller
+ var queue *controllertest.Queue
+ var reconciled chan reconcile.Request
+ var request = reconcile.Request{
+ NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"},
+ }
+
+ BeforeEach(func() {
+ reconciled = make(chan reconcile.Request)
+ fakeReconcile = &fakeReconciler{
+ Requests: reconciled,
+ results: make(chan fakeReconcileResultPair, 10 /* chosen by the completely scientific approach of guessing */),
+ }
+ queue = &controllertest.Queue{
+ Interface: workqueue.New(),
+ }
+ ctrl = &Controller{
+ MaxConcurrentReconciles: 1,
+ Do: fakeReconcile,
+ MakeQueue: func() workqueue.RateLimitingInterface { return queue },
+ LogConstructor: func(_ *reconcile.Request) logr.Logger {
+ return log.RuntimeLog.WithName("controller").WithName("test")
+ },
+ }
+ })
+
+ Describe("Reconciler", func() {
+ It("should call the Reconciler function", func() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ ctrl.Do = reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
+ return reconcile.Result{Requeue: true}, nil
+ })
+ result, err := ctrl.Reconcile(ctx,
+ reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"}})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(result).To(Equal(reconcile.Result{Requeue: true}))
+ })
+
+ It("should not recover panic if RecoverPanic is false by default", func() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ defer func() {
+ Expect(recover()).ShouldNot(BeNil())
+ }()
+ ctrl.Do = reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
+ var res *reconcile.Result
+ return *res, nil
+ })
+ _, _ = ctrl.Reconcile(ctx,
+ reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"}})
+ })
+
+ It("should recover panic if RecoverPanic is true", func() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ defer func() {
+ Expect(recover()).To(BeNil())
+ }()
+ ctrl.RecoverPanic = pointer.Bool(true)
+ ctrl.Do = reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
+ var res *reconcile.Result
+ return *res, nil
+ })
+ _, err := ctrl.Reconcile(ctx,
+ reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"}})
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("[recovered]"))
+ })
+ })
+
+ Describe("Start", func() {
+ It("should return an error if there is an error waiting for the informers", func() {
+ f := false
+ ctrl.startWatches = []watchDescription{{
+ src: source.Kind(&informertest.FakeInformers{Synced: &f}, &corev1.Pod{}),
+ }}
+ ctrl.Name = "foo"
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ err := ctrl.Start(ctx)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("failed to wait for foo caches to sync"))
+ })
+
+ It("should error when cache sync timeout occurs", func() {
+ ctrl.CacheSyncTimeout = 10 * time.Nanosecond
+
+ c, err := cache.New(cfg, cache.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ c = &cacheWithIndefinitelyBlockingGetInformer{c}
+
+ ctrl.startWatches = []watchDescription{{
+ src: source.Kind(c, &appsv1.Deployment{}),
+ }}
+ ctrl.Name = "testcontroller"
+
+ err = ctrl.Start(context.TODO())
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("failed to wait for testcontroller caches to sync: timed out waiting for cache to be synced"))
+ })
+
+ It("should not error when context cancelled", func() {
+ ctrl.CacheSyncTimeout = 1 * time.Second
+
+ sourceSynced := make(chan struct{})
+ c, err := cache.New(cfg, cache.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ c = &cacheWithIndefinitelyBlockingGetInformer{c}
+ ctrl.startWatches = []watchDescription{{
+ src: &singnallingSourceWrapper{
+ SyncingSource: source.Kind(c, &appsv1.Deployment{}),
+ cacheSyncDone: sourceSynced,
+ },
+ }}
+ ctrl.Name = "testcontroller"
+
+ ctx, cancel := context.WithCancel(context.TODO())
+ go func() {
+ defer GinkgoRecover()
+ err = ctrl.Start(ctx)
+ Expect(err).To(Succeed())
+ }()
+
+ cancel()
+ <-sourceSynced
+ })
+
+ It("should not error when cache sync timeout is of sufficiently high", func() {
+ ctrl.CacheSyncTimeout = 1 * time.Second
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ sourceSynced := make(chan struct{})
+ c, err := cache.New(cfg, cache.Options{})
+ Expect(err).NotTo(HaveOccurred())
+ ctrl.startWatches = []watchDescription{{
+ src: &singnallingSourceWrapper{
+ SyncingSource: source.Kind(c, &appsv1.Deployment{}),
+ cacheSyncDone: sourceSynced,
+ },
+ }}
+
+ go func() {
+ defer GinkgoRecover()
+ Expect(c.Start(ctx)).To(Succeed())
+ }()
+
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).To(Succeed())
+ }()
+
+ <-sourceSynced
+ })
+
+ It("should process events from source.Channel", func() {
+ // channel to be closed when event is processed
+ processed := make(chan struct{})
+ // source channel
+ ch := make(chan event.GenericEvent, 1)
+
+ ctx, cancel := context.WithCancel(context.TODO())
+ defer cancel()
+
+ // event to be sent to the channel
+ p := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
+ }
+ evt := event.GenericEvent{
+ Object: p,
+ }
+
+ ins := &source.Channel{Source: ch}
+ ins.DestBufferSize = 1
+
+ // send the event to the channel
+ ch <- evt
+
+ ctrl.startWatches = []watchDescription{{
+ src: ins,
+ handler: handler.Funcs{
+ GenericFunc: func(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ close(processed)
+ },
+ },
+ }}
+
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).To(Succeed())
+ }()
+ <-processed
+ })
+
+ It("should error when channel source is not specified", func() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ ins := &source.Channel{}
+ ctrl.startWatches = []watchDescription{{
+ src: ins,
+ }}
+
+ e := ctrl.Start(ctx)
+ Expect(e).NotTo(BeNil())
+ Expect(e.Error()).To(ContainSubstring("must specify Channel.Source"))
+ })
+
+ It("should call Start on sources with the appropriate EventHandler, Queue, and Predicates", func() {
+ pr1 := &predicate.Funcs{}
+ pr2 := &predicate.Funcs{}
+ evthdl := &handler.EnqueueRequestForObject{}
+ started := false
+ src := source.Func(func(ctx context.Context, e handler.EventHandler, q workqueue.RateLimitingInterface, p ...predicate.Predicate) error {
+ defer GinkgoRecover()
+ Expect(e).To(Equal(evthdl))
+ Expect(q).To(Equal(ctrl.Queue))
+ Expect(p).To(ConsistOf(pr1, pr2))
+
+ started = true
+ return nil
+ })
+ Expect(ctrl.Watch(src, evthdl, pr1, pr2)).NotTo(HaveOccurred())
+
+ // Use a cancelled context so Start doesn't block
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ Expect(ctrl.Start(ctx)).To(Succeed())
+ Expect(started).To(BeTrue())
+ })
+
+ It("should return an error if there is an error starting sources", func() {
+ err := fmt.Errorf("Expected Error: could not start source")
+ src := source.Func(func(context.Context, handler.EventHandler,
+ workqueue.RateLimitingInterface,
+ ...predicate.Predicate) error {
+ defer GinkgoRecover()
+ return err
+ })
+ Expect(ctrl.Watch(src, &handler.EnqueueRequestForObject{})).To(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ Expect(ctrl.Start(ctx)).To(Equal(err))
+ })
+
+ It("should return an error if it gets started more than once", func() {
+ // Use a cancelled context so Start doesn't block
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ Expect(ctrl.Start(ctx)).To(BeNil())
+ err := ctrl.Start(ctx)
+ Expect(err).NotTo(BeNil())
+ Expect(err.Error()).To(Equal("controller was started more than once. This is likely to be caused by being added to a manager multiple times"))
+ })
+
+ })
+
+ Describe("Processing queue items from a Controller", func() {
+ It("should call Reconciler if an item is enqueued", func() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ queue.Add(request)
+
+ By("Invoking Reconciler")
+ fakeReconcile.AddResult(reconcile.Result{}, nil)
+ Expect(<-reconciled).To(Equal(request))
+
+ By("Removing the item from the queue")
+ Eventually(queue.Len).Should(Equal(0))
+ Eventually(func() int { return queue.NumRequeues(request) }).Should(Equal(0))
+ })
+
+ It("should continue to process additional queue items after the first", func() {
+ ctrl.Do = reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
+ defer GinkgoRecover()
+ Fail("Reconciler should not have been called")
+ return reconcile.Result{}, nil
+ })
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ By("adding two bad items to the queue")
+ queue.Add("foo/bar1")
+ queue.Add("foo/bar2")
+
+ By("expecting both of them to be skipped")
+ Eventually(queue.Len).Should(Equal(0))
+ Eventually(func() int { return queue.NumRequeues(request) }).Should(Equal(0))
+ })
+
+ PIt("should forget an item if it is not a Request and continue processing items", func() {
+ // TODO(community): write this test
+ })
+
+ It("should requeue a Request if there is an error and continue processing items", func() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ queue.Add(request)
+
+ By("Invoking Reconciler which will give an error")
+ fakeReconcile.AddResult(reconcile.Result{}, fmt.Errorf("expected error: reconcile"))
+ Expect(<-reconciled).To(Equal(request))
+ queue.AddedRateLimitedLock.Lock()
+ Expect(queue.AddedRatelimited).To(Equal([]any{request}))
+ queue.AddedRateLimitedLock.Unlock()
+
+ By("Invoking Reconciler a second time without error")
+ fakeReconcile.AddResult(reconcile.Result{}, nil)
+ Expect(<-reconciled).To(Equal(request))
+
+ By("Removing the item from the queue")
+ Eventually(queue.Len).Should(Equal(0))
+ Eventually(func() int { return queue.NumRequeues(request) }, 1.0).Should(Equal(0))
+ })
+
+ It("should not requeue a Request if there is a terminal error", func() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ queue.Add(request)
+
+ By("Invoking Reconciler which will give an error")
+ fakeReconcile.AddResult(reconcile.Result{}, reconcile.TerminalError(fmt.Errorf("expected error: reconcile")))
+ Expect(<-reconciled).To(Equal(request))
+
+ queue.AddedRateLimitedLock.Lock()
+ Expect(queue.AddedRatelimited).To(BeEmpty())
+ queue.AddedRateLimitedLock.Unlock()
+
+ Expect(queue.Len()).Should(Equal(0))
+ })
+
+ // TODO(directxman12): we should ensure that backoff occurrs with error requeue
+
+ It("should not reset backoff until there's a non-error result", func() {
+ dq := &DelegatingQueue{RateLimitingInterface: ctrl.MakeQueue()}
+ ctrl.MakeQueue = func() workqueue.RateLimitingInterface { return dq }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ dq.Add(request)
+ Expect(dq.getCounts()).To(Equal(countInfo{Trying: 1}))
+
+ By("Invoking Reconciler which returns an error")
+ fakeReconcile.AddResult(reconcile.Result{}, fmt.Errorf("something's wrong"))
+ Expect(<-reconciled).To(Equal(request))
+ Eventually(dq.getCounts).Should(Equal(countInfo{Trying: 1, AddRateLimited: 1}))
+
+ By("Invoking Reconciler a second time with an error")
+ fakeReconcile.AddResult(reconcile.Result{}, fmt.Errorf("another thing's wrong"))
+ Expect(<-reconciled).To(Equal(request))
+
+ Eventually(dq.getCounts).Should(Equal(countInfo{Trying: 1, AddRateLimited: 2}))
+
+ By("Invoking Reconciler a third time, where it finally does not return an error")
+ fakeReconcile.AddResult(reconcile.Result{}, nil)
+ Expect(<-reconciled).To(Equal(request))
+
+ Eventually(dq.getCounts).Should(Equal(countInfo{Trying: 0, AddRateLimited: 2}))
+
+ By("Removing the item from the queue")
+ Eventually(dq.Len).Should(Equal(0))
+ Eventually(func() int { return dq.NumRequeues(request) }).Should(Equal(0))
+ })
+
+ It("should requeue a Request with rate limiting if the Result sets Requeue:true and continue processing items", func() {
+ dq := &DelegatingQueue{RateLimitingInterface: ctrl.MakeQueue()}
+ ctrl.MakeQueue = func() workqueue.RateLimitingInterface { return dq }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ dq.Add(request)
+ Expect(dq.getCounts()).To(Equal(countInfo{Trying: 1}))
+
+ By("Invoking Reconciler which will ask for requeue")
+ fakeReconcile.AddResult(reconcile.Result{Requeue: true}, nil)
+ Expect(<-reconciled).To(Equal(request))
+ Eventually(dq.getCounts).Should(Equal(countInfo{Trying: 1, AddRateLimited: 1}))
+
+ By("Invoking Reconciler a second time without asking for requeue")
+ fakeReconcile.AddResult(reconcile.Result{Requeue: false}, nil)
+ Expect(<-reconciled).To(Equal(request))
+
+ Eventually(dq.getCounts).Should(Equal(countInfo{Trying: 0, AddRateLimited: 1}))
+
+ By("Removing the item from the queue")
+ Eventually(dq.Len).Should(Equal(0))
+ Eventually(func() int { return dq.NumRequeues(request) }).Should(Equal(0))
+ })
+
+ It("should requeue a Request after a duration (but not rate-limitted) if the Result sets RequeueAfter (regardless of Requeue)", func() {
+ dq := &DelegatingQueue{RateLimitingInterface: ctrl.MakeQueue()}
+ ctrl.MakeQueue = func() workqueue.RateLimitingInterface { return dq }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ dq.Add(request)
+ Expect(dq.getCounts()).To(Equal(countInfo{Trying: 1}))
+
+ By("Invoking Reconciler which will ask for requeue & requeueafter")
+ fakeReconcile.AddResult(reconcile.Result{RequeueAfter: time.Millisecond * 100, Requeue: true}, nil)
+ Expect(<-reconciled).To(Equal(request))
+ Eventually(dq.getCounts).Should(Equal(countInfo{Trying: 0, AddAfter: 1}))
+
+ By("Invoking Reconciler a second time asking for a requeueafter only")
+ fakeReconcile.AddResult(reconcile.Result{RequeueAfter: time.Millisecond * 100}, nil)
+ Expect(<-reconciled).To(Equal(request))
+
+ Eventually(dq.getCounts).Should(Equal(countInfo{Trying: -1 /* we don't increment the count in addafter */, AddAfter: 2}))
+
+ By("Removing the item from the queue")
+ Eventually(dq.Len).Should(Equal(0))
+ Eventually(func() int { return dq.NumRequeues(request) }).Should(Equal(0))
+ })
+
+ It("should perform error behavior if error is not nil, regardless of RequeueAfter", func() {
+ dq := &DelegatingQueue{RateLimitingInterface: ctrl.MakeQueue()}
+ ctrl.MakeQueue = func() workqueue.RateLimitingInterface { return dq }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ dq.Add(request)
+ Expect(dq.getCounts()).To(Equal(countInfo{Trying: 1}))
+
+ By("Invoking Reconciler which will ask for requeueafter with an error")
+ fakeReconcile.AddResult(reconcile.Result{RequeueAfter: time.Millisecond * 100}, fmt.Errorf("expected error: reconcile"))
+ Expect(<-reconciled).To(Equal(request))
+ Eventually(dq.getCounts).Should(Equal(countInfo{Trying: 1, AddRateLimited: 1}))
+
+ By("Invoking Reconciler a second time asking for requeueafter without errors")
+ fakeReconcile.AddResult(reconcile.Result{RequeueAfter: time.Millisecond * 100}, nil)
+ Expect(<-reconciled).To(Equal(request))
+ Eventually(dq.getCounts).Should(Equal(countInfo{AddAfter: 1, AddRateLimited: 1}))
+
+ By("Removing the item from the queue")
+ Eventually(dq.Len).Should(Equal(0))
+ Eventually(func() int { return dq.NumRequeues(request) }).Should(Equal(0))
+ })
+
+ PIt("should return if the queue is shutdown", func() {
+ // TODO(community): write this test
+ })
+
+ PIt("should wait for informers to be synced before processing items", func() {
+ // TODO(community): write this test
+ })
+
+ PIt("should create a new go routine for MaxConcurrentReconciles", func() {
+ // TODO(community): write this test
+ })
+
+ Context("prometheus metric reconcile_total", func() {
+ var reconcileTotal dto.Metric
+
+ BeforeEach(func() {
+ ctrlmetrics.ReconcileTotal.Reset()
+ reconcileTotal.Reset()
+ })
+
+ It("should get updated on successful reconciliation", func() {
+ Expect(func() error {
+ Expect(ctrlmetrics.ReconcileTotal.WithLabelValues(ctrl.Name, "success").Write(&reconcileTotal)).To(Succeed())
+ if reconcileTotal.GetCounter().GetValue() != 0.0 {
+ return fmt.Errorf("metric reconcile total not reset")
+ }
+ return nil
+ }()).Should(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ By("Invoking Reconciler which will succeed")
+ queue.Add(request)
+
+ fakeReconcile.AddResult(reconcile.Result{}, nil)
+ Expect(<-reconciled).To(Equal(request))
+ Eventually(func() error {
+ Expect(ctrlmetrics.ReconcileTotal.WithLabelValues(ctrl.Name, "success").Write(&reconcileTotal)).To(Succeed())
+ if actual := reconcileTotal.GetCounter().GetValue(); actual != 1.0 {
+ return fmt.Errorf("metric reconcile total expected: %v and got: %v", 1.0, actual)
+ }
+ return nil
+ }, 2.0).Should(Succeed())
+ })
+
+ It("should get updated on reconcile errors", func() {
+ Expect(func() error {
+ Expect(ctrlmetrics.ReconcileTotal.WithLabelValues(ctrl.Name, "error").Write(&reconcileTotal)).To(Succeed())
+ if reconcileTotal.GetCounter().GetValue() != 0.0 {
+ return fmt.Errorf("metric reconcile total not reset")
+ }
+ return nil
+ }()).Should(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ By("Invoking Reconciler which will give an error")
+ queue.Add(request)
+
+ fakeReconcile.AddResult(reconcile.Result{}, fmt.Errorf("expected error: reconcile"))
+ Expect(<-reconciled).To(Equal(request))
+ Eventually(func() error {
+ Expect(ctrlmetrics.ReconcileTotal.WithLabelValues(ctrl.Name, "error").Write(&reconcileTotal)).To(Succeed())
+ if actual := reconcileTotal.GetCounter().GetValue(); actual != 1.0 {
+ return fmt.Errorf("metric reconcile total expected: %v and got: %v", 1.0, actual)
+ }
+ return nil
+ }, 2.0).Should(Succeed())
+ })
+
+ It("should get updated when reconcile returns with retry enabled", func() {
+ Expect(func() error {
+ Expect(ctrlmetrics.ReconcileTotal.WithLabelValues(ctrl.Name, "retry").Write(&reconcileTotal)).To(Succeed())
+ if reconcileTotal.GetCounter().GetValue() != 0.0 {
+ return fmt.Errorf("metric reconcile total not reset")
+ }
+ return nil
+ }()).Should(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ By("Invoking Reconciler which will return result with Requeue enabled")
+ queue.Add(request)
+
+ fakeReconcile.AddResult(reconcile.Result{Requeue: true}, nil)
+ Expect(<-reconciled).To(Equal(request))
+ Eventually(func() error {
+ Expect(ctrlmetrics.ReconcileTotal.WithLabelValues(ctrl.Name, "requeue").Write(&reconcileTotal)).To(Succeed())
+ if actual := reconcileTotal.GetCounter().GetValue(); actual != 1.0 {
+ return fmt.Errorf("metric reconcile total expected: %v and got: %v", 1.0, actual)
+ }
+ return nil
+ }, 2.0).Should(Succeed())
+ })
+
+ It("should get updated when reconcile returns with retryAfter enabled", func() {
+ Expect(func() error {
+ Expect(ctrlmetrics.ReconcileTotal.WithLabelValues(ctrl.Name, "retry_after").Write(&reconcileTotal)).To(Succeed())
+ if reconcileTotal.GetCounter().GetValue() != 0.0 {
+ return fmt.Errorf("metric reconcile total not reset")
+ }
+ return nil
+ }()).Should(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ By("Invoking Reconciler which will return result with requeueAfter enabled")
+ queue.Add(request)
+
+ fakeReconcile.AddResult(reconcile.Result{RequeueAfter: 5 * time.Hour}, nil)
+ Expect(<-reconciled).To(Equal(request))
+ Eventually(func() error {
+ Expect(ctrlmetrics.ReconcileTotal.WithLabelValues(ctrl.Name, "requeue_after").Write(&reconcileTotal)).To(Succeed())
+ if actual := reconcileTotal.GetCounter().GetValue(); actual != 1.0 {
+ return fmt.Errorf("metric reconcile total expected: %v and got: %v", 1.0, actual)
+ }
+ return nil
+ }, 2.0).Should(Succeed())
+ })
+ })
+
+ Context("should update prometheus metrics", func() {
+ It("should requeue a Request if there is an error and continue processing items", func() {
+ var reconcileErrs dto.Metric
+ ctrlmetrics.ReconcileErrors.Reset()
+ Expect(func() error {
+ Expect(ctrlmetrics.ReconcileErrors.WithLabelValues(ctrl.Name).Write(&reconcileErrs)).To(Succeed())
+ if reconcileErrs.GetCounter().GetValue() != 0.0 {
+ return fmt.Errorf("metric reconcile errors not reset")
+ }
+ return nil
+ }()).Should(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ queue.Add(request)
+
+ By("Invoking Reconciler which will give an error")
+ fakeReconcile.AddResult(reconcile.Result{}, fmt.Errorf("expected error: reconcile"))
+ Expect(<-reconciled).To(Equal(request))
+ Eventually(func() error {
+ Expect(ctrlmetrics.ReconcileErrors.WithLabelValues(ctrl.Name).Write(&reconcileErrs)).To(Succeed())
+ if reconcileErrs.GetCounter().GetValue() != 1.0 {
+ return fmt.Errorf("metrics not updated")
+ }
+ return nil
+ }, 2.0).Should(Succeed())
+
+ By("Invoking Reconciler a second time without error")
+ fakeReconcile.AddResult(reconcile.Result{}, nil)
+ Expect(<-reconciled).To(Equal(request))
+
+ By("Removing the item from the queue")
+ Eventually(queue.Len).Should(Equal(0))
+ Eventually(func() int { return queue.NumRequeues(request) }).Should(Equal(0))
+ })
+
+ It("should add a reconcile time to the reconcile time histogram", func() {
+ var reconcileTime dto.Metric
+ ctrlmetrics.ReconcileTime.Reset()
+
+ Expect(func() error {
+ histObserver := ctrlmetrics.ReconcileTime.WithLabelValues(ctrl.Name)
+ hist := histObserver.(prometheus.Histogram)
+ Expect(hist.Write(&reconcileTime)).To(Succeed())
+ if reconcileTime.GetHistogram().GetSampleCount() != uint64(0) {
+ return fmt.Errorf("metrics not reset")
+ }
+ return nil
+ }()).Should(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ queue.Add(request)
+
+ By("Invoking Reconciler")
+ fakeReconcile.AddResult(reconcile.Result{}, nil)
+ Expect(<-reconciled).To(Equal(request))
+
+ By("Removing the item from the queue")
+ Eventually(queue.Len).Should(Equal(0))
+ Eventually(func() int { return queue.NumRequeues(request) }).Should(Equal(0))
+
+ Eventually(func() error {
+ histObserver := ctrlmetrics.ReconcileTime.WithLabelValues(ctrl.Name)
+ hist := histObserver.(prometheus.Histogram)
+ Expect(hist.Write(&reconcileTime)).To(Succeed())
+ if reconcileTime.GetHistogram().GetSampleCount() == uint64(0) {
+ return fmt.Errorf("metrics not updated")
+ }
+ return nil
+ }, 2.0).Should(Succeed())
+ })
+ })
+ })
+})
+
+var _ = Describe("ReconcileIDFromContext function", func() {
+ It("should return an empty string if there is nothing in the context", func() {
+ ctx := context.Background()
+ reconcileID := ReconcileIDFromContext(ctx)
+
+ Expect(reconcileID).To(Equal(types.UID("")))
+ })
+
+ It("should return the correct reconcileID from context", func() {
+ const expectedReconcileID = types.UID("uuid")
+ ctx := addReconcileID(context.Background(), expectedReconcileID)
+ reconcileID := ReconcileIDFromContext(ctx)
+
+ Expect(reconcileID).To(Equal(expectedReconcileID))
+ })
+})
+
+type DelegatingQueue struct {
+ workqueue.RateLimitingInterface
+ mu sync.Mutex
+
+ countAddRateLimited int
+ countAdd int
+ countAddAfter int
+}
+
+func (q *DelegatingQueue) AddRateLimited(item interface{}) {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+
+ q.countAddRateLimited++
+ q.RateLimitingInterface.AddRateLimited(item)
+}
+
+func (q *DelegatingQueue) AddAfter(item interface{}, d time.Duration) {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+
+ q.countAddAfter++
+ q.RateLimitingInterface.AddAfter(item, d)
+}
+
+func (q *DelegatingQueue) Add(item interface{}) {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+ q.countAdd++
+
+ q.RateLimitingInterface.Add(item)
+}
+
+func (q *DelegatingQueue) Forget(item interface{}) {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+ q.countAdd--
+
+ q.RateLimitingInterface.Forget(item)
+}
+
+type countInfo struct {
+ Trying, AddAfter, AddRateLimited int
+}
+
+func (q *DelegatingQueue) getCounts() countInfo {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+
+ return countInfo{
+ Trying: q.countAdd,
+ AddAfter: q.countAddAfter,
+ AddRateLimited: q.countAddRateLimited,
+ }
+}
+
+type fakeReconcileResultPair struct {
+ Result reconcile.Result
+ Err error
+}
+
+type fakeReconciler struct {
+ Requests chan reconcile.Request
+ results chan fakeReconcileResultPair
+}
+
+func (f *fakeReconciler) AddResult(res reconcile.Result, err error) {
+ f.results <- fakeReconcileResultPair{Result: res, Err: err}
+}
+
+func (f *fakeReconciler) Reconcile(_ context.Context, r reconcile.Request) (reconcile.Result, error) {
+ res := <-f.results
+ if f.Requests != nil {
+ f.Requests <- r
+ }
+ return res.Result, res.Err
+}
+
+type singnallingSourceWrapper struct {
+ cacheSyncDone chan struct{}
+ source.SyncingSource
+}
+
+func (s *singnallingSourceWrapper) WaitForSync(ctx context.Context) error {
+ defer func() {
+ close(s.cacheSyncDone)
+ }()
+ return s.SyncingSource.WaitForSync(ctx)
+}
+
+var _ cache.Cache = &cacheWithIndefinitelyBlockingGetInformer{}
+
+// cacheWithIndefinitelyBlockingGetInformer has a GetInformer implementation that blocks indefinitely or until its
+// context is cancelled.
+// We need it as a workaround for testenvs lack of support for a secure apiserver, because the insecure port always
+// implies the allow all authorizer, so we can not simulate rbac issues with it. They are the usual cause of the real
+// caches GetInformer blocking showing this behavior.
+// TODO: Remove this once envtest supports a secure apiserver.
+type cacheWithIndefinitelyBlockingGetInformer struct {
+ cache.Cache
+}
+
+func (c *cacheWithIndefinitelyBlockingGetInformer) GetInformer(ctx context.Context, obj client.Object) (cache.Informer, error) {
+ <-ctx.Done()
+ return nil, errors.New("GetInformer timed out")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go
new file mode 100644
index 00000000000..b74ce062be7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go
@@ -0,0 +1,86 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package metrics
+
+import (
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/collectors"
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+)
+
+var (
+ // ReconcileTotal is a prometheus counter metrics which holds the total
+ // number of reconciliations per controller. It has two labels. controller label refers
+ // to the controller name and result label refers to the reconcile result i.e
+ // success, error, requeue, requeue_after.
+ ReconcileTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Name: "controller_runtime_reconcile_total",
+ Help: "Total number of reconciliations per controller",
+ }, []string{"controller", "result"})
+
+ // ReconcileErrors is a prometheus counter metrics which holds the total
+ // number of errors from the Reconciler.
+ ReconcileErrors = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Name: "controller_runtime_reconcile_errors_total",
+ Help: "Total number of reconciliation errors per controller",
+ }, []string{"controller"})
+
+ // TerminalReconcileErrors is a prometheus counter metrics which holds the total
+ // number of terminal errors from the Reconciler.
+ TerminalReconcileErrors = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Name: "controller_runtime_terminal_reconcile_errors_total",
+ Help: "Total number of terminal reconciliation errors per controller",
+ }, []string{"controller"})
+
+ // ReconcileTime is a prometheus metric which keeps track of the duration
+ // of reconciliations.
+ ReconcileTime = prometheus.NewHistogramVec(prometheus.HistogramOpts{
+ Name: "controller_runtime_reconcile_time_seconds",
+ Help: "Length of time per reconciliation per controller",
+ Buckets: []float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
+ 1.25, 1.5, 1.75, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40, 50, 60},
+ }, []string{"controller"})
+
+ // WorkerCount is a prometheus metric which holds the number of
+ // concurrent reconciles per controller.
+ WorkerCount = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "controller_runtime_max_concurrent_reconciles",
+ Help: "Maximum number of concurrent reconciles per controller",
+ }, []string{"controller"})
+
+ // ActiveWorkers is a prometheus metric which holds the number
+ // of active workers per controller.
+ ActiveWorkers = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "controller_runtime_active_workers",
+ Help: "Number of currently used workers per controller",
+ }, []string{"controller"})
+)
+
+func init() {
+ metrics.Registry.MustRegister(
+ ReconcileTotal,
+ ReconcileErrors,
+ TerminalReconcileErrors,
+ ReconcileTime,
+ WorkerCount,
+ ActiveWorkers,
+ // expose process metrics like CPU, Memory, file descriptor usage etc.
+ collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
+ // expose Go runtime metrics like GC stats, memory stats etc.
+ collectors.NewGoCollector(),
+ )
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/field/selector/utils.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/field/selector/utils.go
new file mode 100644
index 00000000000..4f6d0843184
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/field/selector/utils.go
@@ -0,0 +1,35 @@
+/*
+Copyright 2022 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package selector
+
+import (
+ "k8s.io/apimachinery/pkg/fields"
+ "k8s.io/apimachinery/pkg/selection"
+)
+
+// RequiresExactMatch checks if the given field selector is of the form `k=v` or `k==v`.
+func RequiresExactMatch(sel fields.Selector) (field, val string, required bool) {
+ reqs := sel.Requirements()
+ if len(reqs) != 1 {
+ return "", "", false
+ }
+ req := reqs[0]
+ if req.Operator != selection.Equals && req.Operator != selection.DoubleEquals {
+ return "", "", false
+ }
+ return req.Field, req.Value, true
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/field/selector/utils_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/field/selector/utils_suite_test.go
new file mode 100644
index 00000000000..dd42f1d1ac1
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/field/selector/utils_suite_test.go
@@ -0,0 +1,29 @@
+/*
+Copyright 2022 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package selector_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Fields Selector Utils Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/field/selector/utils_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/field/selector/utils_test.go
new file mode 100644
index 00000000000..fba214ff16c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/field/selector/utils_test.go
@@ -0,0 +1,88 @@
+/*
+Copyright 2022 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package selector_test
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/apimachinery/pkg/fields"
+
+ . "sigs.k8s.io/controller-runtime/pkg/internal/field/selector"
+)
+
+var _ = Describe("RequiresExactMatch function", func() {
+
+ It("Returns false when the selector matches everything", func() {
+ _, _, requiresExactMatch := RequiresExactMatch(fields.Everything())
+ Expect(requiresExactMatch).To(BeFalse())
+ })
+
+ It("Returns false when the selector matches nothing", func() {
+ _, _, requiresExactMatch := RequiresExactMatch(fields.Nothing())
+ Expect(requiresExactMatch).To(BeFalse())
+ })
+
+ It("Returns false when the selector has the form key!=val", func() {
+ _, _, requiresExactMatch := RequiresExactMatch(fields.ParseSelectorOrDie("key!=val"))
+ Expect(requiresExactMatch).To(BeFalse())
+ })
+
+ It("Returns false when the selector has the form key1==val1,key2==val2", func() {
+ _, _, requiresExactMatch := RequiresExactMatch(fields.ParseSelectorOrDie("key1==val1,key2==val2"))
+ Expect(requiresExactMatch).To(BeFalse())
+ })
+
+ It("Returns true when the selector has the form key==val", func() {
+ _, _, requiresExactMatch := RequiresExactMatch(fields.ParseSelectorOrDie("key==val"))
+ Expect(requiresExactMatch).To(BeTrue())
+ })
+
+ It("Returns true when the selector has the form key=val", func() {
+ _, _, requiresExactMatch := RequiresExactMatch(fields.ParseSelectorOrDie("key=val"))
+ Expect(requiresExactMatch).To(BeTrue())
+ })
+
+ It("Returns empty key and value when the selector matches everything", func() {
+ key, val, _ := RequiresExactMatch(fields.Everything())
+ Expect(key).To(Equal(""))
+ Expect(val).To(Equal(""))
+ })
+
+ It("Returns empty key and value when the selector matches nothing", func() {
+ key, val, _ := RequiresExactMatch(fields.Nothing())
+ Expect(key).To(Equal(""))
+ Expect(val).To(Equal(""))
+ })
+
+ It("Returns empty key and value when the selector has the form key!=val", func() {
+ key, val, _ := RequiresExactMatch(fields.ParseSelectorOrDie("key!=val"))
+ Expect(key).To(Equal(""))
+ Expect(val).To(Equal(""))
+ })
+
+ It("Returns key and value when the selector has the form key==val", func() {
+ key, val, _ := RequiresExactMatch(fields.ParseSelectorOrDie("key==val"))
+ Expect(key).To(Equal("key"))
+ Expect(val).To(Equal("val"))
+ })
+
+ It("Returns key and value when the selector has the form key=val", func() {
+ key, val, _ := RequiresExactMatch(fields.ParseSelectorOrDie("key=val"))
+ Expect(key).To(Equal("key"))
+ Expect(val).To(Equal("val"))
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/flock/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/flock/doc.go
new file mode 100644
index 00000000000..11e39823ede
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/flock/doc.go
@@ -0,0 +1,21 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package flock is copied from k8s.io/kubernetes/pkg/util/flock to avoid
+// importing k8s.io/kubernetes as a dependency.
+//
+// Provides file locking functionalities on unix systems.
+package flock
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/flock/errors.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/flock/errors.go
new file mode 100644
index 00000000000..ee7a4343722
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/flock/errors.go
@@ -0,0 +1,24 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package flock
+
+import "errors"
+
+var (
+ // ErrAlreadyLocked is returned when the file is already locked.
+ ErrAlreadyLocked = errors.New("the file is already locked")
+)
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/flock/flock_other.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/flock/flock_other.go
new file mode 100644
index 00000000000..069a5b3a2cb
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/flock/flock_other.go
@@ -0,0 +1,24 @@
+// +build !linux,!darwin,!freebsd,!openbsd,!netbsd,!dragonfly
+
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package flock
+
+// Acquire is not implemented on non-unix systems.
+func Acquire(path string) error {
+ return nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/flock/flock_unix.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/flock/flock_unix.go
new file mode 100644
index 00000000000..71ec576df23
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/flock/flock_unix.go
@@ -0,0 +1,48 @@
+//go:build linux || darwin || freebsd || openbsd || netbsd || dragonfly
+// +build linux darwin freebsd openbsd netbsd dragonfly
+
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package flock
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+// Acquire acquires a lock on a file for the duration of the process. This method
+// is reentrant.
+func Acquire(path string) error {
+ fd, err := unix.Open(path, unix.O_CREAT|unix.O_RDWR|unix.O_CLOEXEC, 0600)
+ if err != nil {
+ if errors.Is(err, os.ErrExist) {
+ return fmt.Errorf("cannot lock file %q: %w", path, ErrAlreadyLocked)
+ }
+ return err
+ }
+
+ // We don't need to close the fd since we should hold
+ // it until the process exits.
+ err = unix.Flock(fd, unix.LOCK_NB|unix.LOCK_EX)
+ if errors.Is(err, unix.EWOULDBLOCK) { // This condition requires LOCK_NB.
+ return fmt.Errorf("cannot lock file %q: %w", path, ErrAlreadyLocked)
+ }
+ return err
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/httpserver/server.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/httpserver/server.go
new file mode 100644
index 00000000000..b5f91f18e07
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/httpserver/server.go
@@ -0,0 +1,16 @@
+package httpserver
+
+import (
+ "net/http"
+ "time"
+)
+
+// New returns a new server with sane defaults.
+func New(handler http.Handler) *http.Server {
+ return &http.Server{
+ Handler: handler,
+ MaxHeaderBytes: 1 << 20,
+ IdleTimeout: 90 * time.Second, // matches http.DefaultTransport keep-alive timeout
+ ReadHeaderTimeout: 32 * time.Second,
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/log/log.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/log/log.go
new file mode 100644
index 00000000000..d91a0ca50cf
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/log/log.go
@@ -0,0 +1,32 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package log
+
+import (
+ "github.com/go-logr/logr"
+
+ "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+var (
+ // RuntimeLog is a base parent logger for use inside controller-runtime.
+ RuntimeLog logr.Logger
+)
+
+func init() {
+ RuntimeLog = log.Log.WithName("controller-runtime")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go
index 7057f3dbe43..0189c043233 100644
--- a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go
@@ -17,14 +17,9 @@ limitations under the License.
package objectutil
import (
- "errors"
- "fmt"
-
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
)
// FilterWithLabels returns a copy of the items in objs matching labelSel.
@@ -45,34 +40,3 @@ func FilterWithLabels(objs []runtime.Object, labelSel labels.Selector) ([]runtim
}
return outItems, nil
}
-
-// IsAPINamespaced returns true if the object is namespace scoped.
-// For unstructured objects the gvk is found from the object itself.
-func IsAPINamespaced(obj runtime.Object, scheme *runtime.Scheme, restmapper apimeta.RESTMapper) (bool, error) {
- gvk, err := apiutil.GVKForObject(obj, scheme)
- if err != nil {
- return false, err
- }
-
- return IsAPINamespacedWithGVK(gvk, scheme, restmapper)
-}
-
-// IsAPINamespacedWithGVK returns true if the object having the provided
-// GVK is namespace scoped.
-func IsAPINamespacedWithGVK(gk schema.GroupVersionKind, scheme *runtime.Scheme, restmapper apimeta.RESTMapper) (bool, error) {
- restmapping, err := restmapper.RESTMapping(schema.GroupKind{Group: gk.Group, Kind: gk.Kind})
- if err != nil {
- return false, fmt.Errorf("failed to get restmapping: %w", err)
- }
-
- scope := restmapping.Scope.Name()
-
- if scope == "" {
- return false, errors.New("scope cannot be identified, empty scope returned")
- }
-
- if scope != apimeta.RESTScopeNameRoot {
- return true, nil
- }
- return false, nil
-}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go
new file mode 100644
index 00000000000..21f0146ba3b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go
@@ -0,0 +1,181 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package recorder
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "sync"
+
+ "github.com/go-logr/logr"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/record"
+)
+
+// EventBroadcasterProducer makes an event broadcaster, returning
+// whether or not the broadcaster should be stopped with the Provider,
+// or not (e.g. if it's shared, it shouldn't be stopped with the Provider).
+type EventBroadcasterProducer func() (caster record.EventBroadcaster, stopWithProvider bool)
+
+// Provider is a recorder.Provider that records events to the k8s API server
+// and to a logr Logger.
+type Provider struct {
+ lock sync.RWMutex
+ stopped bool
+
+ // scheme to specify when creating a recorder
+ scheme *runtime.Scheme
+ // logger is the logger to use when logging diagnostic event info
+ logger logr.Logger
+ evtClient corev1client.EventInterface
+ makeBroadcaster EventBroadcasterProducer
+
+ broadcasterOnce sync.Once
+ broadcaster record.EventBroadcaster
+ stopBroadcaster bool
+}
+
+// NB(directxman12): this manually implements Stop instead of Being a runnable because we need to
+// stop it *after* everything else shuts down, otherwise we'll cause panics as the leader election
+// code finishes up and tries to continue emitting events.
+
+// Stop attempts to stop this provider, stopping the underlying broadcaster
+// if the broadcaster asked to be stopped. It kinda tries to honor the given
+// context, but the underlying broadcaster has an indefinite wait that doesn't
+// return until all queued events are flushed, so this may end up just returning
+// before the underlying wait has finished instead of cancelling the wait.
+// This is Very Frustrating™.
+func (p *Provider) Stop(shutdownCtx context.Context) {
+ doneCh := make(chan struct{})
+
+ go func() {
+ // technically, this could start the broadcaster, but practically, it's
+ // almost certainly already been started (e.g. by leader election). We
+ // need to invoke this to ensure that we don't inadvertently race with
+ // an invocation of getBroadcaster.
+ broadcaster := p.getBroadcaster()
+ if p.stopBroadcaster {
+ p.lock.Lock()
+ broadcaster.Shutdown()
+ p.stopped = true
+ p.lock.Unlock()
+ }
+ close(doneCh)
+ }()
+
+ select {
+ case <-shutdownCtx.Done():
+ case <-doneCh:
+ }
+}
+
+// getBroadcaster ensures that a broadcaster is started for this
+// provider, and returns it. It's threadsafe.
+func (p *Provider) getBroadcaster() record.EventBroadcaster {
+ // NB(directxman12): this can technically still leak if something calls
+ // "getBroadcaster" (i.e. Emits an Event) but never calls Start, but if we
+ // create the broadcaster in start, we could race with other things that
+ // are started at the same time & want to emit events. The alternative is
+ // silently swallowing events and more locking, but that seems suboptimal.
+
+ p.broadcasterOnce.Do(func() {
+ broadcaster, stop := p.makeBroadcaster()
+ broadcaster.StartRecordingToSink(&corev1client.EventSinkImpl{Interface: p.evtClient})
+ broadcaster.StartEventWatcher(
+ func(e *corev1.Event) {
+ p.logger.V(1).Info(e.Message, "type", e.Type, "object", e.InvolvedObject, "reason", e.Reason)
+ })
+ p.broadcaster = broadcaster
+ p.stopBroadcaster = stop
+ })
+
+ return p.broadcaster
+}
+
+// NewProvider create a new Provider instance.
+func NewProvider(config *rest.Config, httpClient *http.Client, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster EventBroadcasterProducer) (*Provider, error) {
+ if httpClient == nil {
+ panic("httpClient must not be nil")
+ }
+
+ corev1Client, err := corev1client.NewForConfigAndClient(config, httpClient)
+ if err != nil {
+ return nil, fmt.Errorf("failed to init client: %w", err)
+ }
+
+ p := &Provider{scheme: scheme, logger: logger, makeBroadcaster: makeBroadcaster, evtClient: corev1Client.Events("")}
+ return p, nil
+}
+
+// GetEventRecorderFor returns an event recorder that broadcasts to this provider's
+// broadcaster. All events will be associated with a component of the given name.
+func (p *Provider) GetEventRecorderFor(name string) record.EventRecorder {
+ return &lazyRecorder{
+ prov: p,
+ name: name,
+ }
+}
+
+// lazyRecorder is a recorder that doesn't actually instantiate any underlying
+// recorder until the first event is emitted.
+type lazyRecorder struct {
+ prov *Provider
+ name string
+
+ recOnce sync.Once
+ rec record.EventRecorder
+}
+
+// ensureRecording ensures that a concrete recorder is populated for this recorder.
+func (l *lazyRecorder) ensureRecording() {
+ l.recOnce.Do(func() {
+ broadcaster := l.prov.getBroadcaster()
+ l.rec = broadcaster.NewRecorder(l.prov.scheme, corev1.EventSource{Component: l.name})
+ })
+}
+
+func (l *lazyRecorder) Event(object runtime.Object, eventtype, reason, message string) {
+ l.ensureRecording()
+
+ l.prov.lock.RLock()
+ if !l.prov.stopped {
+ l.rec.Event(object, eventtype, reason, message)
+ }
+ l.prov.lock.RUnlock()
+}
+func (l *lazyRecorder) Eventf(object runtime.Object, eventtype, reason, messageFmt string, args ...interface{}) {
+ l.ensureRecording()
+
+ l.prov.lock.RLock()
+ if !l.prov.stopped {
+ l.rec.Eventf(object, eventtype, reason, messageFmt, args...)
+ }
+ l.prov.lock.RUnlock()
+}
+func (l *lazyRecorder) AnnotatedEventf(object runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) {
+ l.ensureRecording()
+
+ l.prov.lock.RLock()
+ if !l.prov.stopped {
+ l.rec.AnnotatedEventf(object, annotations, eventtype, reason, messageFmt, args...)
+ }
+ l.prov.lock.RUnlock()
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder_integration_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder_integration_test.go
new file mode 100644
index 00000000000..130a306053b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder_integration_test.go
@@ -0,0 +1,113 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package recorder_test
+
+import (
+ "context"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/watch"
+ "k8s.io/client-go/kubernetes/scheme"
+ ref "k8s.io/client-go/tools/reference"
+ "sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("recorder", func() {
+ Describe("recorder", func() {
+ It("should publish events", func() {
+ By("Creating the Manager")
+ cm, err := manager.New(cfg, manager.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Creating the Controller")
+ recorder := cm.GetEventRecorderFor("test-recorder")
+ instance, err := controller.New("foo-controller", cm, controller.Options{
+ Reconciler: reconcile.Func(
+ func(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
+ dp, err := clientset.AppsV1().Deployments(request.Namespace).Get(ctx, request.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ recorder.Event(dp, corev1.EventTypeNormal, "test-reason", "test-msg")
+ return reconcile.Result{}, nil
+ }),
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Watching Resources")
+ err = instance.Watch(source.Kind(cm.GetCache(), &appsv1.Deployment{}), &handler.EnqueueRequestForObject{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Starting the Manager")
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(cm.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ deployment := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-name"},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx",
+ },
+ },
+ },
+ },
+ },
+ }
+
+ By("Invoking Reconciling")
+ deployment, err = clientset.AppsV1().Deployments("default").Create(ctx, deployment, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Validate event is published as expected")
+ evtWatcher, err := clientset.CoreV1().Events("default").Watch(ctx, metav1.ListOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ resultEvent := <-evtWatcher.ResultChan()
+
+ Expect(resultEvent.Type).To(Equal(watch.Added))
+ evt, isEvent := resultEvent.Object.(*corev1.Event)
+ Expect(isEvent).To(BeTrue())
+
+ dpRef, err := ref.GetReference(scheme.Scheme, deployment)
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(evt.InvolvedObject).To(Equal(*dpRef))
+ Expect(evt.Type).To(Equal(corev1.EventTypeNormal))
+ Expect(evt.Reason).To(Equal("test-reason"))
+ Expect(evt.Message).To(Equal("test-msg"))
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder_suite_test.go
new file mode 100644
index 00000000000..e5b5836d58c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder_suite_test.go
@@ -0,0 +1,60 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package recorder_test
+
+import (
+ "net/http"
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestRecorder(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Recorder Integration Suite")
+}
+
+var testenv *envtest.Environment
+var cfg *rest.Config
+var httpClient *http.Client
+var clientset *kubernetes.Clientset
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+ testenv = &envtest.Environment{}
+
+ var err error
+ cfg, err = testenv.Start()
+ Expect(err).NotTo(HaveOccurred())
+
+ httpClient, err = rest.HTTPClientFor(cfg)
+ Expect(err).ToNot(HaveOccurred())
+
+ clientset, err = kubernetes.NewForConfig(cfg)
+ Expect(err).NotTo(HaveOccurred())
+})
+
+var _ = AfterSuite(func() {
+ Expect(testenv.Stop()).To(Succeed())
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder_test.go
new file mode 100644
index 00000000000..804bdb3d211
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder_test.go
@@ -0,0 +1,55 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package recorder_test
+
+import (
+ "github.com/go-logr/logr"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/tools/record"
+ "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
+)
+
+var _ = Describe("recorder.Provider", func() {
+ makeBroadcaster := func() (record.EventBroadcaster, bool) { return record.NewBroadcaster(), true }
+ Describe("NewProvider", func() {
+ It("should return a provider instance and a nil error.", func() {
+ provider, err := recorder.NewProvider(cfg, httpClient, scheme.Scheme, logr.Discard(), makeBroadcaster)
+ Expect(provider).NotTo(BeNil())
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ It("should return an error if failed to init client.", func() {
+ // Invalid the config
+ cfg1 := *cfg
+ cfg1.Host = "invalid host"
+ _, err := recorder.NewProvider(&cfg1, httpClient, scheme.Scheme, logr.Discard(), makeBroadcaster)
+ Expect(err).NotTo(BeNil())
+ Expect(err.Error()).To(ContainSubstring("failed to init client"))
+ })
+ })
+ Describe("GetEventRecorder", func() {
+ It("should return a recorder instance.", func() {
+ provider, err := recorder.NewProvider(cfg, httpClient, scheme.Scheme, logr.Discard(), makeBroadcaster)
+ Expect(err).NotTo(HaveOccurred())
+
+ recorder := provider.GetEventRecorderFor("test")
+ Expect(recorder).NotTo(BeNil())
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/source/event_handler.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/source/event_handler.go
new file mode 100644
index 00000000000..ae8404a1fa4
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/source/event_handler.go
@@ -0,0 +1,170 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package internal
+
+import (
+ "context"
+ "fmt"
+
+ "k8s.io/client-go/tools/cache"
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+)
+
+var log = logf.RuntimeLog.WithName("source").WithName("EventHandler")
+
+// NewEventHandler creates a new EventHandler.
+func NewEventHandler(ctx context.Context, queue workqueue.RateLimitingInterface, handler handler.EventHandler, predicates []predicate.Predicate) *EventHandler {
+ return &EventHandler{
+ ctx: ctx,
+ handler: handler,
+ queue: queue,
+ predicates: predicates,
+ }
+}
+
+// EventHandler adapts a handler.EventHandler interface to a cache.ResourceEventHandler interface.
+type EventHandler struct {
+ // ctx stores the context that created the event handler
+ // that is used to propagate cancellation signals to each handler function.
+ ctx context.Context
+
+ handler handler.EventHandler
+ queue workqueue.RateLimitingInterface
+ predicates []predicate.Predicate
+}
+
+// HandlerFuncs converts EventHandler to a ResourceEventHandlerFuncs
+// TODO: switch to ResourceEventHandlerDetailedFuncs with client-go 1.27
+func (e *EventHandler) HandlerFuncs() cache.ResourceEventHandlerFuncs {
+ return cache.ResourceEventHandlerFuncs{
+ AddFunc: e.OnAdd,
+ UpdateFunc: e.OnUpdate,
+ DeleteFunc: e.OnDelete,
+ }
+}
+
+// OnAdd creates CreateEvent and calls Create on EventHandler.
+func (e *EventHandler) OnAdd(obj interface{}) {
+ c := event.CreateEvent{}
+
+ // Pull Object out of the object
+ if o, ok := obj.(client.Object); ok {
+ c.Object = o
+ } else {
+ log.Error(nil, "OnAdd missing Object",
+ "object", obj, "type", fmt.Sprintf("%T", obj))
+ return
+ }
+
+ for _, p := range e.predicates {
+ if !p.Create(c) {
+ return
+ }
+ }
+
+ // Invoke create handler
+ ctx, cancel := context.WithCancel(e.ctx)
+ defer cancel()
+ e.handler.Create(ctx, c, e.queue)
+}
+
+// OnUpdate creates UpdateEvent and calls Update on EventHandler.
+func (e *EventHandler) OnUpdate(oldObj, newObj interface{}) {
+ u := event.UpdateEvent{}
+
+ if o, ok := oldObj.(client.Object); ok {
+ u.ObjectOld = o
+ } else {
+ log.Error(nil, "OnUpdate missing ObjectOld",
+ "object", oldObj, "type", fmt.Sprintf("%T", oldObj))
+ return
+ }
+
+ // Pull Object out of the object
+ if o, ok := newObj.(client.Object); ok {
+ u.ObjectNew = o
+ } else {
+ log.Error(nil, "OnUpdate missing ObjectNew",
+ "object", newObj, "type", fmt.Sprintf("%T", newObj))
+ return
+ }
+
+ for _, p := range e.predicates {
+ if !p.Update(u) {
+ return
+ }
+ }
+
+ // Invoke update handler
+ ctx, cancel := context.WithCancel(e.ctx)
+ defer cancel()
+ e.handler.Update(ctx, u, e.queue)
+}
+
+// OnDelete creates DeleteEvent and calls Delete on EventHandler.
+func (e *EventHandler) OnDelete(obj interface{}) {
+ d := event.DeleteEvent{}
+
+ // Deal with tombstone events by pulling the object out. Tombstone events wrap the object in a
+ // DeleteFinalStateUnknown struct, so the object needs to be pulled out.
+ // Copied from sample-controller
+ // This should never happen if we aren't missing events, which we have concluded that we are not
+ // and made decisions off of this belief. Maybe this shouldn't be here?
+ var ok bool
+ if _, ok = obj.(client.Object); !ok {
+ // If the object doesn't have Metadata, assume it is a tombstone object of type DeletedFinalStateUnknown
+ tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
+ if !ok {
+ log.Error(nil, "Error decoding objects. Expected cache.DeletedFinalStateUnknown",
+ "type", fmt.Sprintf("%T", obj),
+ "object", obj)
+ return
+ }
+
+ // Set DeleteStateUnknown to true
+ d.DeleteStateUnknown = true
+
+ // Set obj to the tombstone obj
+ obj = tombstone.Obj
+ }
+
+ // Pull Object out of the object
+ if o, ok := obj.(client.Object); ok {
+ d.Object = o
+ } else {
+ log.Error(nil, "OnDelete missing Object",
+ "object", obj, "type", fmt.Sprintf("%T", obj))
+ return
+ }
+
+ for _, p := range e.predicates {
+ if !p.Delete(d) {
+ return
+ }
+ }
+
+ // Invoke delete handler
+ ctx, cancel := context.WithCancel(e.ctx)
+ defer cancel()
+ e.handler.Delete(ctx, d, e.queue)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/source/internal_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/source/internal_suite_test.go
new file mode 100644
index 00000000000..eeee8b22cdc
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/source/internal_suite_test.go
@@ -0,0 +1,35 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package internal_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestInternal(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Source Internal Suite")
+}
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/source/internal_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/source/internal_test.go
new file mode 100644
index 00000000000..0574f7180ed
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/source/internal_test.go
@@ -0,0 +1,297 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package internal_test
+
+import (
+ "context"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/tools/cache"
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ internal "sigs.k8s.io/controller-runtime/pkg/internal/source"
+
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllertest"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+)
+
+var _ = Describe("Internal", func() {
+ var ctx = context.Background()
+ var instance *internal.EventHandler
+ var funcs, setfuncs *handler.Funcs
+ var set bool
+ BeforeEach(func() {
+ funcs = &handler.Funcs{
+ CreateFunc: func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Did not expect CreateEvent to be called.")
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Did not expect DeleteEvent to be called.")
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Did not expect UpdateEvent to be called.")
+ },
+ GenericFunc: func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Did not expect GenericEvent to be called.")
+ },
+ }
+
+ setfuncs = &handler.Funcs{
+ CreateFunc: func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface) {
+ set = true
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ set = true
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ set = true
+ },
+ GenericFunc: func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface) {
+ set = true
+ },
+ }
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, funcs, nil)
+ })
+
+ Describe("EventHandler", func() {
+ var pod, newPod *corev1.Pod
+
+ BeforeEach(func() {
+ pod = &corev1.Pod{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{{Name: "test", Image: "test"}},
+ },
+ }
+ newPod = pod.DeepCopy()
+ newPod.Labels = map[string]string{"foo": "bar"}
+ })
+
+ It("should create a CreateEvent", func() {
+ funcs.CreateFunc = func(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(evt.Object).To(Equal(pod))
+ }
+ instance.OnAdd(pod)
+ })
+
+ It("should used Predicates to filter CreateEvents", func() {
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{CreateFunc: func(event.CreateEvent) bool { return false }},
+ })
+ set = false
+ instance.OnAdd(pod)
+ Expect(set).To(BeFalse())
+
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{CreateFunc: func(event.CreateEvent) bool { return true }},
+ })
+ instance.OnAdd(pod)
+ Expect(set).To(BeTrue())
+
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{CreateFunc: func(event.CreateEvent) bool { return true }},
+ predicate.Funcs{CreateFunc: func(event.CreateEvent) bool { return false }},
+ })
+ instance.OnAdd(pod)
+ Expect(set).To(BeFalse())
+
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{CreateFunc: func(event.CreateEvent) bool { return false }},
+ predicate.Funcs{CreateFunc: func(event.CreateEvent) bool { return true }},
+ })
+ instance.OnAdd(pod)
+ Expect(set).To(BeFalse())
+
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{CreateFunc: func(event.CreateEvent) bool { return true }},
+ predicate.Funcs{CreateFunc: func(event.CreateEvent) bool { return true }},
+ })
+ instance.OnAdd(pod)
+ Expect(set).To(BeTrue())
+ })
+
+ It("should not call Create EventHandler if the object is not a runtime.Object", func() {
+ instance.OnAdd(&metav1.ObjectMeta{})
+ })
+
+ It("should not call Create EventHandler if the object does not have metadata", func() {
+ instance.OnAdd(FooRuntimeObject{})
+ })
+
+ It("should create an UpdateEvent", func() {
+ funcs.UpdateFunc = func(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(evt.ObjectOld).To(Equal(pod))
+ Expect(evt.ObjectNew).To(Equal(newPod))
+ }
+ instance.OnUpdate(pod, newPod)
+ })
+
+ It("should used Predicates to filter UpdateEvents", func() {
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{UpdateFunc: func(updateEvent event.UpdateEvent) bool { return false }},
+ })
+ instance.OnUpdate(pod, newPod)
+ Expect(set).To(BeFalse())
+
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{UpdateFunc: func(event.UpdateEvent) bool { return true }},
+ })
+ instance.OnUpdate(pod, newPod)
+ Expect(set).To(BeTrue())
+
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{UpdateFunc: func(event.UpdateEvent) bool { return true }},
+ predicate.Funcs{UpdateFunc: func(event.UpdateEvent) bool { return false }},
+ })
+ instance.OnUpdate(pod, newPod)
+ Expect(set).To(BeFalse())
+
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{UpdateFunc: func(event.UpdateEvent) bool { return false }},
+ predicate.Funcs{UpdateFunc: func(event.UpdateEvent) bool { return true }},
+ })
+ instance.OnUpdate(pod, newPod)
+ Expect(set).To(BeFalse())
+
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{CreateFunc: func(event.CreateEvent) bool { return true }},
+ predicate.Funcs{CreateFunc: func(event.CreateEvent) bool { return true }},
+ })
+ instance.OnUpdate(pod, newPod)
+ Expect(set).To(BeTrue())
+ })
+
+ It("should not call Update EventHandler if the object is not a runtime.Object", func() {
+ instance.OnUpdate(&metav1.ObjectMeta{}, &corev1.Pod{})
+ instance.OnUpdate(&corev1.Pod{}, &metav1.ObjectMeta{})
+ })
+
+ It("should not call Update EventHandler if the object does not have metadata", func() {
+ instance.OnUpdate(FooRuntimeObject{}, &corev1.Pod{})
+ instance.OnUpdate(&corev1.Pod{}, FooRuntimeObject{})
+ })
+
+ It("should create a DeleteEvent", func() {
+ funcs.DeleteFunc = func(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(evt.Object).To(Equal(pod))
+ }
+ instance.OnDelete(pod)
+ })
+
+ It("should used Predicates to filter DeleteEvents", func() {
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{DeleteFunc: func(event.DeleteEvent) bool { return false }},
+ })
+ instance.OnDelete(pod)
+ Expect(set).To(BeFalse())
+
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{DeleteFunc: func(event.DeleteEvent) bool { return true }},
+ })
+ instance.OnDelete(pod)
+ Expect(set).To(BeTrue())
+
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{DeleteFunc: func(event.DeleteEvent) bool { return true }},
+ predicate.Funcs{DeleteFunc: func(event.DeleteEvent) bool { return false }},
+ })
+ instance.OnDelete(pod)
+ Expect(set).To(BeFalse())
+
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{DeleteFunc: func(event.DeleteEvent) bool { return false }},
+ predicate.Funcs{DeleteFunc: func(event.DeleteEvent) bool { return true }},
+ })
+ instance.OnDelete(pod)
+ Expect(set).To(BeFalse())
+
+ set = false
+ instance = internal.NewEventHandler(ctx, &controllertest.Queue{}, setfuncs, []predicate.Predicate{
+ predicate.Funcs{DeleteFunc: func(event.DeleteEvent) bool { return true }},
+ predicate.Funcs{DeleteFunc: func(event.DeleteEvent) bool { return true }},
+ })
+ instance.OnDelete(pod)
+ Expect(set).To(BeTrue())
+ })
+
+ It("should not call Delete EventHandler if the object is not a runtime.Object", func() {
+ instance.OnDelete(&metav1.ObjectMeta{})
+ })
+
+ It("should not call Delete EventHandler if the object does not have metadata", func() {
+ instance.OnDelete(FooRuntimeObject{})
+ })
+
+ It("should create a DeleteEvent from a tombstone", func() {
+
+ tombstone := cache.DeletedFinalStateUnknown{
+ Obj: pod,
+ }
+ funcs.DeleteFunc = func(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(evt.Object).To(Equal(pod))
+ Expect(evt.DeleteStateUnknown).Should(BeTrue())
+ }
+
+ instance.OnDelete(tombstone)
+ })
+
+ It("should ignore tombstone objects without meta", func() {
+ tombstone := cache.DeletedFinalStateUnknown{Obj: Foo{}}
+ instance.OnDelete(tombstone)
+ })
+ It("should ignore objects without meta", func() {
+ instance.OnAdd(Foo{})
+ instance.OnUpdate(Foo{}, Foo{})
+ instance.OnDelete(Foo{})
+ })
+ })
+})
+
+type Foo struct{}
+
+var _ runtime.Object = FooRuntimeObject{}
+
+type FooRuntimeObject struct{}
+
+func (FooRuntimeObject) GetObjectKind() schema.ObjectKind { return nil }
+func (FooRuntimeObject) DeepCopyObject() runtime.Object { return nil }
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/source/kind.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/source/kind.go
new file mode 100644
index 00000000000..b3a82271256
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/source/kind.go
@@ -0,0 +1,117 @@
+package internal
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "time"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/util/wait"
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+)
+
+// Kind is used to provide a source of events originating inside the cluster from Watches (e.g. Pod Create).
+type Kind struct {
+ // Type is the type of object to watch. e.g. &v1.Pod{}
+ Type client.Object
+
+ // Cache used to watch APIs
+ Cache cache.Cache
+
+ // started may contain an error if one was encountered during startup. If its closed and does not
+ // contain an error, startup and syncing finished.
+ started chan error
+ startCancel func()
+}
+
+// Start is internal and should be called only by the Controller to register an EventHandler with the Informer
+// to enqueue reconcile.Requests.
+func (ks *Kind) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface,
+ prct ...predicate.Predicate) error {
+ if ks.Type == nil {
+ return fmt.Errorf("must create Kind with a non-nil object")
+ }
+ if ks.Cache == nil {
+ return fmt.Errorf("must create Kind with a non-nil cache")
+ }
+
+ // cache.GetInformer will block until its context is cancelled if the cache was already started and it can not
+ // sync that informer (most commonly due to RBAC issues).
+ ctx, ks.startCancel = context.WithCancel(ctx)
+ ks.started = make(chan error)
+ go func() {
+ var (
+ i cache.Informer
+ lastErr error
+ )
+
+ // Tries to get an informer until it returns true,
+ // an error or the specified context is cancelled or expired.
+ if err := wait.PollUntilContextCancel(ctx, 10*time.Second, true, func(ctx context.Context) (bool, error) {
+ // Lookup the Informer from the Cache and add an EventHandler which populates the Queue
+ i, lastErr = ks.Cache.GetInformer(ctx, ks.Type)
+ if lastErr != nil {
+ kindMatchErr := &meta.NoKindMatchError{}
+ switch {
+ case errors.As(lastErr, &kindMatchErr):
+ log.Error(lastErr, "if kind is a CRD, it should be installed before calling Start",
+ "kind", kindMatchErr.GroupKind)
+ case runtime.IsNotRegisteredError(lastErr):
+ log.Error(lastErr, "kind must be registered to the Scheme")
+ default:
+ log.Error(lastErr, "failed to get informer from cache")
+ }
+ return false, nil // Retry.
+ }
+ return true, nil
+ }); err != nil {
+ if lastErr != nil {
+ ks.started <- fmt.Errorf("failed to get informer from cache: %w", lastErr)
+ return
+ }
+ ks.started <- err
+ return
+ }
+
+ _, err := i.AddEventHandler(NewEventHandler(ctx, queue, handler, prct).HandlerFuncs())
+ if err != nil {
+ ks.started <- err
+ return
+ }
+ if !ks.Cache.WaitForCacheSync(ctx) {
+ // Would be great to return something more informative here
+ ks.started <- errors.New("cache did not sync")
+ }
+ close(ks.started)
+ }()
+
+ return nil
+}
+
+func (ks *Kind) String() string {
+ if ks.Type != nil {
+ return fmt.Sprintf("kind source: %T", ks.Type)
+ }
+ return "kind source: unknown type"
+}
+
+// WaitForSync implements SyncingSource to allow controllers to wait with starting
+// workers until the cache is synced.
+func (ks *Kind) WaitForSync(ctx context.Context) error {
+ select {
+ case err := <-ks.started:
+ return err
+ case <-ctx.Done():
+ ks.startCancel()
+ if errors.Is(ctx.Err(), context.Canceled) {
+ return nil
+ }
+ return fmt.Errorf("timed out waiting for cache to be synced for Kind %T", ks.Type)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/syncs/syncs.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/syncs/syncs.go
new file mode 100644
index 00000000000..84beb1b2654
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/syncs/syncs.go
@@ -0,0 +1,37 @@
+package syncs
+
+import (
+ "context"
+ "reflect"
+ "sync"
+)
+
+// MergeChans returns a channel that is closed when any of the input channels are signaled.
+// The caller must call the returned CancelFunc to ensure no resources are leaked.
+func MergeChans[T any](chans ...<-chan T) (<-chan T, context.CancelFunc) {
+ var once sync.Once
+ out := make(chan T)
+ cancel := make(chan T)
+ cancelFunc := func() {
+ once.Do(func() {
+ close(cancel)
+ })
+ }
+ cases := make([]reflect.SelectCase, len(chans)+1)
+ for i := range chans {
+ cases[i] = reflect.SelectCase{
+ Dir: reflect.SelectRecv,
+ Chan: reflect.ValueOf(chans[i]),
+ }
+ }
+ cases[len(cases)-1] = reflect.SelectCase{
+ Dir: reflect.SelectRecv,
+ Chan: reflect.ValueOf(cancel),
+ }
+ go func() {
+ defer close(out)
+ _, _, _ = reflect.Select(cases)
+ }()
+
+ return out, cancelFunc
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/OWNERS b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/OWNERS
new file mode 100644
index 00000000000..25fda2ebacd
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/OWNERS
@@ -0,0 +1,4 @@
+# See the OWNERS docs: https://git.k8s.io/community/contributors/devel/owners.md
+
+approvers:
+ - testing-integration-approvers
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/addr/addr_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/addr/addr_suite_test.go
new file mode 100644
index 00000000000..3869bb02072
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/addr/addr_suite_test.go
@@ -0,0 +1,30 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package addr_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestAddr(t *testing.T) {
+ t.Parallel()
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Addr Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/addr/manager.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/addr/manager.go
new file mode 100644
index 00000000000..ffa33a88616
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/addr/manager.go
@@ -0,0 +1,142 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package addr
+
+import (
+ "errors"
+ "fmt"
+ "io/fs"
+ "net"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "sigs.k8s.io/controller-runtime/pkg/internal/flock"
+)
+
+// TODO(directxman12): interface / release functionality for external port managers
+
+const (
+ portReserveTime = 2 * time.Minute
+ portConflictRetry = 100
+ portFilePrefix = "port-"
+)
+
+var (
+ cacheDir string
+)
+
+func init() {
+ baseDir, err := os.UserCacheDir()
+ if err == nil {
+ cacheDir = filepath.Join(baseDir, "kubebuilder-envtest")
+ err = os.MkdirAll(cacheDir, 0o750)
+ }
+ if err != nil {
+ // Either we didn't get a cache directory, or we can't use it
+ baseDir = os.TempDir()
+ cacheDir = filepath.Join(baseDir, "kubebuilder-envtest")
+ err = os.MkdirAll(cacheDir, 0o750)
+ }
+ if err != nil {
+ panic(err)
+ }
+}
+
+type portCache struct{}
+
+func (c *portCache) add(port int) (bool, error) {
+ // Remove outdated ports.
+ if err := fs.WalkDir(os.DirFS(cacheDir), ".", func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ return err
+ }
+ if d.IsDir() || !d.Type().IsRegular() || !strings.HasPrefix(path, portFilePrefix) {
+ return nil
+ }
+ info, err := d.Info()
+ if err != nil {
+ // No-op if file no longer exists; may have been deleted by another
+ // process/thread trying to allocate ports.
+ if errors.Is(err, fs.ErrNotExist) {
+ return nil
+ }
+ return err
+ }
+ if time.Since(info.ModTime()) > portReserveTime {
+ if err := os.Remove(filepath.Join(cacheDir, path)); err != nil {
+ // No-op if file no longer exists; may have been deleted by another
+ // process/thread trying to allocate ports.
+ if os.IsNotExist(err) {
+ return nil
+ }
+ return err
+ }
+ }
+ return nil
+ }); err != nil {
+ return false, err
+ }
+ // Try allocating new port, by acquiring a file.
+ path := fmt.Sprintf("%s/%s%d", cacheDir, portFilePrefix, port)
+ if err := flock.Acquire(path); errors.Is(err, flock.ErrAlreadyLocked) {
+ return false, nil
+ } else if err != nil {
+ return false, err
+ }
+ return true, nil
+}
+
+var cache = &portCache{}
+
+func suggest(listenHost string) (*net.TCPListener, int, string, error) {
+ if listenHost == "" {
+ listenHost = "localhost"
+ }
+ addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(listenHost, "0"))
+ if err != nil {
+ return nil, -1, "", err
+ }
+ l, err := net.ListenTCP("tcp", addr)
+ if err != nil {
+ return nil, -1, "", err
+ }
+ return l, l.Addr().(*net.TCPAddr).Port,
+ addr.IP.String(),
+ nil
+}
+
+// Suggest suggests an address a process can listen on. It returns
+// a tuple consisting of a free port and the hostname resolved to its IP.
+// It makes sure that new port allocated does not conflict with old ports
+// allocated within 1 minute.
+func Suggest(listenHost string) (int, string, error) {
+ for i := 0; i < portConflictRetry; i++ {
+ listener, port, resolvedHost, err := suggest(listenHost)
+ if err != nil {
+ return -1, "", err
+ }
+ defer listener.Close()
+ if ok, err := cache.add(port); ok {
+ return port, resolvedHost, nil
+ } else if err != nil {
+ return -1, "", err
+ }
+ }
+ return -1, "", fmt.Errorf("no free ports found after %d retries", portConflictRetry)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/addr/manager_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/addr/manager_test.go
new file mode 100644
index 00000000000..065e847dc54
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/addr/manager_test.go
@@ -0,0 +1,77 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package addr_test
+
+import (
+ "net"
+ "strconv"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/addr"
+)
+
+var _ = Describe("SuggestAddress", func() {
+ It("returns a free port and an address to bind to", func() {
+ port, host, err := addr.Suggest("")
+
+ Expect(err).NotTo(HaveOccurred())
+ Expect(host).To(Or(Equal("127.0.0.1"), Equal("::1")))
+ Expect(port).NotTo(Equal(0))
+
+ addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
+ Expect(err).NotTo(HaveOccurred())
+ l, err := net.ListenTCP("tcp", addr)
+ defer func() {
+ Expect(l.Close()).To(Succeed())
+ }()
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ It("supports an explicit listenHost", func() {
+ port, host, err := addr.Suggest("localhost")
+
+ Expect(err).NotTo(HaveOccurred())
+ Expect(host).To(Or(Equal("127.0.0.1"), Equal("::1")))
+ Expect(port).NotTo(Equal(0))
+
+ addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
+ Expect(err).NotTo(HaveOccurred())
+ l, err := net.ListenTCP("tcp", addr)
+ defer func() {
+ Expect(l.Close()).To(Succeed())
+ }()
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ It("supports a 0.0.0.0 listenHost", func() {
+ port, host, err := addr.Suggest("0.0.0.0")
+
+ Expect(err).NotTo(HaveOccurred())
+ Expect(host).To(Equal("0.0.0.0"))
+ Expect(port).NotTo(Equal(0))
+
+ addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
+ Expect(err).NotTo(HaveOccurred())
+ l, err := net.ListenTCP("tcp", addr)
+ defer func() {
+ Expect(l.Close()).To(Succeed())
+ }()
+ Expect(err).NotTo(HaveOccurred())
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/certs/certs_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/certs/certs_suite_test.go
new file mode 100644
index 00000000000..3b3008c294b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/certs/certs_suite_test.go
@@ -0,0 +1,30 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package certs_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestInternal(t *testing.T) {
+ t.Parallel()
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "TinyCA (Internal Certs) Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/certs/tinyca.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/certs/tinyca.go
new file mode 100644
index 00000000000..b4188237e69
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/certs/tinyca.go
@@ -0,0 +1,224 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package certs
+
+// NB(directxman12): nothing has verified that this has good settings. In fact,
+// the setting generated here are probably terrible, but they're fine for integration
+// tests. These ABSOLUTELY SHOULD NOT ever be exposed in the public API. They're
+// ONLY for use with envtest's ability to configure webhook testing.
+// If I didn't otherwise not want to add a dependency on cfssl, I'd just use that.
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ crand "crypto/rand"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "fmt"
+ "math/big"
+ "net"
+ "time"
+
+ certutil "k8s.io/client-go/util/cert"
+)
+
+var (
+ ellipticCurve = elliptic.P256()
+ bigOne = big.NewInt(1)
+)
+
+// CertPair is a private key and certificate for use for client auth, as a CA, or serving.
+type CertPair struct {
+ Key crypto.Signer
+ Cert *x509.Certificate
+}
+
+// CertBytes returns the PEM-encoded version of the certificate for this pair.
+func (k CertPair) CertBytes() []byte {
+ return pem.EncodeToMemory(&pem.Block{
+ Type: "CERTIFICATE",
+ Bytes: k.Cert.Raw,
+ })
+}
+
+// AsBytes encodes keypair in the appropriate formats for on-disk storage (PEM and
+// PKCS8, respectively).
+func (k CertPair) AsBytes() (cert []byte, key []byte, err error) {
+ cert = k.CertBytes()
+
+ rawKeyData, err := x509.MarshalPKCS8PrivateKey(k.Key)
+ if err != nil {
+ return nil, nil, fmt.Errorf("unable to encode private key: %w", err)
+ }
+
+ key = pem.EncodeToMemory(&pem.Block{
+ Type: "PRIVATE KEY",
+ Bytes: rawKeyData,
+ })
+
+ return cert, key, nil
+}
+
+// TinyCA supports signing serving certs and client-certs,
+// and can be used as an auth mechanism with envtest.
+type TinyCA struct {
+ CA CertPair
+ orgName string
+
+ nextSerial *big.Int
+}
+
+// newPrivateKey generates a new private key of a relatively sane size (see
+// rsaKeySize).
+func newPrivateKey() (crypto.Signer, error) {
+ return ecdsa.GenerateKey(ellipticCurve, crand.Reader)
+}
+
+// NewTinyCA creates a new a tiny CA utility for provisioning serving certs and client certs FOR TESTING ONLY.
+// Don't use this for anything else!
+func NewTinyCA() (*TinyCA, error) {
+ caPrivateKey, err := newPrivateKey()
+ if err != nil {
+ return nil, fmt.Errorf("unable to generate private key for CA: %w", err)
+ }
+ caCfg := certutil.Config{CommonName: "envtest-environment", Organization: []string{"envtest"}}
+ caCert, err := certutil.NewSelfSignedCACert(caCfg, caPrivateKey)
+ if err != nil {
+ return nil, fmt.Errorf("unable to generate certificate for CA: %w", err)
+ }
+
+ return &TinyCA{
+ CA: CertPair{Key: caPrivateKey, Cert: caCert},
+ orgName: "envtest",
+ nextSerial: big.NewInt(1),
+ }, nil
+}
+
+func (c *TinyCA) makeCert(cfg certutil.Config) (CertPair, error) {
+ now := time.Now()
+
+ key, err := newPrivateKey()
+ if err != nil {
+ return CertPair{}, fmt.Errorf("unable to create private key: %w", err)
+ }
+
+ serial := new(big.Int).Set(c.nextSerial)
+ c.nextSerial.Add(c.nextSerial, bigOne)
+
+ template := x509.Certificate{
+ Subject: pkix.Name{CommonName: cfg.CommonName, Organization: cfg.Organization},
+ DNSNames: cfg.AltNames.DNSNames,
+ IPAddresses: cfg.AltNames.IPs,
+ SerialNumber: serial,
+
+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ ExtKeyUsage: cfg.Usages,
+
+ // technically not necessary for testing, but let's set anyway just in case.
+ NotBefore: now.UTC(),
+ // 1 week -- the default for cfssl, and just long enough for a
+ // long-term test, but not too long that anyone would try to use this
+ // seriously.
+ NotAfter: now.Add(168 * time.Hour).UTC(),
+ }
+
+ certRaw, err := x509.CreateCertificate(crand.Reader, &template, c.CA.Cert, key.Public(), c.CA.Key)
+ if err != nil {
+ return CertPair{}, fmt.Errorf("unable to create certificate: %w", err)
+ }
+
+ cert, err := x509.ParseCertificate(certRaw)
+ if err != nil {
+ return CertPair{}, fmt.Errorf("generated invalid certificate, could not parse: %w", err)
+ }
+
+ return CertPair{
+ Key: key,
+ Cert: cert,
+ }, nil
+}
+
+// NewServingCert returns a new CertPair for a serving HTTPS on localhost (or other specified names).
+func (c *TinyCA) NewServingCert(names ...string) (CertPair, error) {
+ if len(names) == 0 {
+ names = []string{"localhost"}
+ }
+ dnsNames, ips, err := resolveNames(names)
+ if err != nil {
+ return CertPair{}, err
+ }
+
+ return c.makeCert(certutil.Config{
+ CommonName: "localhost",
+ Organization: []string{c.orgName},
+ AltNames: certutil.AltNames{
+ DNSNames: dnsNames,
+ IPs: ips,
+ },
+ Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+ })
+}
+
+// ClientInfo describes some Kubernetes user for the purposes of creating
+// client certificates.
+type ClientInfo struct {
+ // Name is the user name (embedded as the cert's CommonName)
+ Name string
+ // Groups are the groups to which this user belongs (embedded as the cert's
+ // Organization)
+ Groups []string
+}
+
+// NewClientCert produces a new CertPair suitable for use with Kubernetes
+// client cert auth with an API server validating based on this CA.
+func (c *TinyCA) NewClientCert(user ClientInfo) (CertPair, error) {
+ return c.makeCert(certutil.Config{
+ CommonName: user.Name,
+ Organization: user.Groups,
+ Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+ })
+}
+
+func resolveNames(names []string) ([]string, []net.IP, error) {
+ dnsNames := []string{}
+ ips := []net.IP{}
+ for _, name := range names {
+ if name == "" {
+ continue
+ }
+ ip := net.ParseIP(name)
+ if ip == nil {
+ dnsNames = append(dnsNames, name)
+ // Also resolve to IPs.
+ nameIPs, err := net.LookupHost(name)
+ if err != nil {
+ return nil, nil, err
+ }
+ for _, nameIP := range nameIPs {
+ ip = net.ParseIP(nameIP)
+ if ip != nil {
+ ips = append(ips, ip)
+ }
+ }
+ } else {
+ ips = append(ips, ip)
+ }
+ }
+ return dnsNames, ips, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/certs/tinyca_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/certs/tinyca_test.go
new file mode 100644
index 00000000000..6e0540ba9f0
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/certs/tinyca_test.go
@@ -0,0 +1,254 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package certs_test
+
+import (
+ "crypto/x509"
+ "encoding/pem"
+ "math/big"
+ "net"
+ "sort"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/gstruct"
+
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/certs"
+)
+
+var _ = Describe("TinyCA", func() {
+ var ca *certs.TinyCA
+
+ BeforeEach(func() {
+ var err error
+ ca, err = certs.NewTinyCA()
+ Expect(err).NotTo(HaveOccurred(), "should be able to initialize the CA")
+ })
+
+ Describe("the CA certs themselves", func() {
+ It("should be retrievable as a cert pair", func() {
+ Expect(ca.CA.Key).NotTo(BeNil(), "should have a key")
+ Expect(ca.CA.Cert).NotTo(BeNil(), "should have a cert")
+ })
+
+ It("should be usable for signing & verifying", func() {
+ Expect(ca.CA.Cert.KeyUsage&x509.KeyUsageCertSign).NotTo(Equal(0), "should be usable for cert signing")
+ Expect(ca.CA.Cert.KeyUsage&x509.KeyUsageDigitalSignature).NotTo(Equal(0), "should be usable for signature verifying")
+ })
+ })
+
+ It("should produce unique serials among all generated certificates of all types", func() {
+ By("generating a few cert pairs for both serving and client auth")
+ firstCerts, err := ca.NewServingCert()
+ Expect(err).NotTo(HaveOccurred())
+ secondCerts, err := ca.NewClientCert(certs.ClientInfo{Name: "user"})
+ Expect(err).NotTo(HaveOccurred())
+ thirdCerts, err := ca.NewServingCert()
+ Expect(err).NotTo(HaveOccurred())
+
+ By("checking that they have different serials")
+ serials := []*big.Int{
+ firstCerts.Cert.SerialNumber,
+ secondCerts.Cert.SerialNumber,
+ thirdCerts.Cert.SerialNumber,
+ }
+ // quick uniqueness check of numbers: sort, then you only have to compare sequential entries
+ sort.Slice(serials, func(i, j int) bool {
+ return serials[i].Cmp(serials[j]) == -1
+ })
+ Expect(serials[1].Cmp(serials[0])).NotTo(Equal(0), "serials shouldn't be equal")
+ Expect(serials[2].Cmp(serials[1])).NotTo(Equal(0), "serials shouldn't be equal")
+ })
+
+ Describe("Generated serving certs", func() {
+ It("should be valid for short enough to avoid production usage, but long enough for long-running tests", func() {
+ cert, err := ca.NewServingCert()
+ Expect(err).NotTo(HaveOccurred(), "should be able to generate the serving certs")
+
+ duration := time.Until(cert.Cert.NotAfter)
+ Expect(duration).To(BeNumerically("<=", 168*time.Hour), "not-after should be short-ish (<= 1 week)")
+ Expect(duration).To(BeNumerically(">=", 2*time.Hour), "not-after should be enough for long tests (couple of hours)")
+ })
+
+ Context("when encoding names", func() {
+ var cert certs.CertPair
+ BeforeEach(func() {
+ By("generating a serving cert with IPv4 & IPv6 addresses, and DNS names")
+ var err error
+ // IPs are in the "example & docs" blocks for IPv4 (TEST-NET-1) & IPv6
+ cert, err = ca.NewServingCert("192.0.2.1", "localhost", "2001:db8::")
+ Expect(err).NotTo(HaveOccurred(), "should be able to create the serving certs")
+ })
+
+ It("should encode all non-IP names as DNS SANs", func() {
+ Expect(cert.Cert.DNSNames).To(ConsistOf("localhost"))
+ })
+
+ It("should encode all IP names as IP SANs", func() {
+ // NB(directxman12): this is non-exhaustive because we also
+ // convert DNS SANs to IPs too (see test below)
+ Expect(cert.Cert.IPAddresses).To(ContainElements(
+ // normalize the elements with To16 so we can compare them to the output of
+ // of ParseIP safely (the alternative is a custom matcher that calls Equal,
+ // but this is easier)
+ WithTransform(net.IP.To16, Equal(net.ParseIP("192.0.2.1"))),
+ WithTransform(net.IP.To16, Equal(net.ParseIP("2001:db8::"))),
+ ))
+ })
+
+ It("should add the corresponding IP address(es) (as IP SANs) for DNS names", func() {
+ // NB(directxman12): we currently fail if the lookup fails.
+ // I'm not certain this is the best idea (both the bailing on
+ // error and the actual idea), so if this causes issues, you
+ // might want to reconsider.
+
+ localhostAddrs, err := net.LookupHost("localhost")
+ Expect(err).NotTo(HaveOccurred(), "should be able to find IPs for localhost")
+ localhostIPs := make([]interface{}, len(localhostAddrs))
+ for i, addr := range localhostAddrs {
+ // normalize the elements with To16 so we can compare them to the output of
+ // of ParseIP safely (the alternative is a custom matcher that calls Equal,
+ // but this is easier)
+ localhostIPs[i] = WithTransform(net.IP.To16, Equal(net.ParseIP(addr)))
+ }
+ Expect(cert.Cert.IPAddresses).To(ContainElements(localhostIPs...))
+ })
+ })
+
+ It("should assume a name of localhost (DNS SAN) if no names are given", func() {
+ cert, err := ca.NewServingCert()
+ Expect(err).NotTo(HaveOccurred(), "should be able to generate a serving cert with the default name")
+ Expect(cert.Cert.DNSNames).To(ConsistOf("localhost"), "the default DNS name should be localhost")
+
+ })
+
+ It("should be usable for server auth, verifying, and enciphering", func() {
+ cert, err := ca.NewServingCert()
+ Expect(err).NotTo(HaveOccurred(), "should be able to generate a serving cert")
+
+ Expect(cert.Cert.KeyUsage&x509.KeyUsageKeyEncipherment).NotTo(Equal(0), "should be usable for key enciphering")
+ Expect(cert.Cert.KeyUsage&x509.KeyUsageDigitalSignature).NotTo(Equal(0), "should be usable for signature verifying")
+ Expect(cert.Cert.ExtKeyUsage).To(ContainElement(x509.ExtKeyUsageServerAuth), "should be usable for server auth")
+
+ })
+
+ It("should be signed by the CA", func() {
+ cert, err := ca.NewServingCert()
+ Expect(err).NotTo(HaveOccurred(), "should be able to generate a serving cert")
+ Expect(cert.Cert.CheckSignatureFrom(ca.CA.Cert)).To(Succeed())
+ })
+ })
+
+ Describe("Generated client certs", func() {
+ var cert certs.CertPair
+ BeforeEach(func() {
+ var err error
+ cert, err = ca.NewClientCert(certs.ClientInfo{
+ Name: "user",
+ Groups: []string{"group1", "group2"},
+ })
+ Expect(err).NotTo(HaveOccurred(), "should be able to create a client cert")
+ })
+
+ It("should be valid for short enough to avoid production usage, but long enough for long-running tests", func() {
+ duration := time.Until(cert.Cert.NotAfter)
+ Expect(duration).To(BeNumerically("<=", 168*time.Hour), "not-after should be short-ish (<= 1 week)")
+ Expect(duration).To(BeNumerically(">=", 2*time.Hour), "not-after should be enough for long tests (couple of hours)")
+ })
+
+ It("should be usable for client auth, verifying, and enciphering", func() {
+ Expect(cert.Cert.KeyUsage&x509.KeyUsageKeyEncipherment).NotTo(Equal(0), "should be usable for key enciphering")
+ Expect(cert.Cert.KeyUsage&x509.KeyUsageDigitalSignature).NotTo(Equal(0), "should be usable for signature verifying")
+ Expect(cert.Cert.ExtKeyUsage).To(ContainElement(x509.ExtKeyUsageClientAuth), "should be usable for client auth")
+ })
+
+ It("should encode the user name as the common name", func() {
+ Expect(cert.Cert.Subject.CommonName).To(Equal("user"))
+ })
+
+ It("should encode the groups as the organization values", func() {
+ Expect(cert.Cert.Subject.Organization).To(ConsistOf("group1", "group2"))
+ })
+
+ It("should be signed by the CA", func() {
+ Expect(cert.Cert.CheckSignatureFrom(ca.CA.Cert)).To(Succeed())
+ })
+ })
+})
+
+var _ = Describe("Certificate Pairs", func() {
+ var pair certs.CertPair
+ BeforeEach(func() {
+ ca, err := certs.NewTinyCA()
+ Expect(err).NotTo(HaveOccurred(), "should be able to generate a cert pair")
+
+ pair = ca.CA
+ })
+
+ Context("when serializing just the public key", func() {
+ It("should serialize into a CERTIFICATE PEM block", func() {
+ bytes := pair.CertBytes()
+ Expect(bytes).NotTo(BeEmpty(), "should produce some cert bytes")
+
+ block, rest := pem.Decode(bytes)
+ Expect(rest).To(BeEmpty(), "shouldn't have any data besides the PEM block")
+
+ Expect(block).To(PointTo(MatchAllFields(Fields{
+ "Type": Equal("CERTIFICATE"),
+ "Headers": BeEmpty(),
+ "Bytes": Equal(pair.Cert.Raw),
+ })))
+ })
+ })
+
+ Context("when serializing both parts", func() {
+ var certBytes, keyBytes []byte
+ BeforeEach(func() {
+ var err error
+ certBytes, keyBytes, err = pair.AsBytes()
+ Expect(err).NotTo(HaveOccurred(), "should be able to serialize the pair")
+ })
+
+ It("should serialize the private key in PKCS8 form in a PRIVATE KEY PEM block", func() {
+ Expect(keyBytes).NotTo(BeEmpty(), "should produce some key bytes")
+
+ By("decoding & checking the PEM block")
+ block, rest := pem.Decode(keyBytes)
+ Expect(rest).To(BeEmpty(), "shouldn't have any data besides the PEM block")
+
+ Expect(block.Type).To(Equal("PRIVATE KEY"))
+
+ By("decoding & checking the PKCS8 data")
+ Expect(x509.ParsePKCS8PrivateKey(block.Bytes)).NotTo(BeNil(), "should be able to parse back the private key")
+ })
+
+ It("should serialize the public key into a CERTIFICATE PEM block", func() {
+ Expect(certBytes).NotTo(BeEmpty(), "should produce some cert bytes")
+
+ block, rest := pem.Decode(certBytes)
+ Expect(rest).To(BeEmpty(), "shouldn't have any data besides the PEM block")
+
+ Expect(block).To(PointTo(MatchAllFields(Fields{
+ "Type": Equal("CERTIFICATE"),
+ "Headers": BeEmpty(),
+ "Bytes": Equal(pair.Cert.Raw),
+ })))
+ })
+
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/apiserver.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/apiserver.go
new file mode 100644
index 00000000000..c9a1a232ea9
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/apiserver.go
@@ -0,0 +1,468 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controlplane
+
+import (
+ "fmt"
+ "io"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strconv"
+ "time"
+
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/addr"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/certs"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/process"
+)
+
+const (
+ // saKeyFile is the name of the service account signing private key file.
+ saKeyFile = "sa-signer.key"
+ // saKeyFile is the name of the service account signing public key (cert) file.
+ saCertFile = "sa-signer.crt"
+)
+
+// SecureServing provides/configures how the API server serves on the secure port.
+type SecureServing struct {
+ // ListenAddr contains the host & port to serve on.
+ //
+ // Configurable. If unset, it will be defaulted.
+ process.ListenAddr
+ // CA contains the CA that signed the API server's serving certificates.
+ //
+ // Read-only.
+ CA []byte
+ // Authn can be used to provision users, and override what type of
+ // authentication is used to provision users.
+ //
+ // Configurable. If unset, it will be defaulted.
+ Authn
+}
+
+// APIServer knows how to run a kubernetes apiserver.
+type APIServer struct {
+ // URL is the address the ApiServer should listen on for client
+ // connections.
+ //
+ // If set, this will configure the *insecure* serving details.
+ // If unset, it will contain the insecure port if insecure serving is enabled,
+ // and otherwise will contain the secure port.
+ //
+ // If this is not specified, we default to a random free port on localhost.
+ //
+ // Deprecated: use InsecureServing (for the insecure URL) or SecureServing, ideally.
+ URL *url.URL
+
+ // SecurePort is the additional secure port that the APIServer should listen on.
+ //
+ // If set, this will override SecureServing.Port.
+ //
+ // Deprecated: use SecureServing.
+ SecurePort int
+
+ // SecureServing indicates how the API server will serve on the secure port.
+ //
+ // Some parts are configurable. Will be defaulted if unset.
+ SecureServing
+
+ // InsecureServing indicates how the API server will serve on the insecure port.
+ //
+ // If unset, the insecure port will be disabled. Set to an empty struct to get
+ // default values.
+ //
+ // Deprecated: does not work with Kubernetes versions 1.20 and above. Use secure
+ // serving instead.
+ InsecureServing *process.ListenAddr
+
+ // Path is the path to the apiserver binary.
+ //
+ // If this is left as the empty string, we will attempt to locate a binary,
+ // by checking for the TEST_ASSET_KUBE_APISERVER environment variable, and
+ // the default test assets directory. See the "Binaries" section above (in
+ // doc.go) for details.
+ Path string
+
+ // Args is a list of arguments which will passed to the APIServer binary.
+ // Before they are passed on, they will be evaluated as go-template strings.
+ // This means you can use fields which are defined and exported on this
+ // APIServer struct (e.g. "--cert-dir={{ .Dir }}").
+ // Those templates will be evaluated after the defaulting of the APIServer's
+ // fields has already happened and just before the binary actually gets
+ // started. Thus you have access to calculated fields like `URL` and others.
+ //
+ // If not specified, the minimal set of arguments to run the APIServer will
+ // be used.
+ //
+ // They will be loaded into the same argument set as Configure. Each flag
+ // will be Append-ed to the configured arguments just before launch.
+ //
+ // Deprecated: use Configure instead.
+ Args []string
+
+ // CertDir is a path to a directory containing whatever certificates the
+ // APIServer will need.
+ //
+ // If left unspecified, then the Start() method will create a fresh temporary
+ // directory, and the Stop() method will clean it up.
+ CertDir string
+
+ // EtcdURL is the URL of the Etcd the APIServer should use.
+ //
+ // If this is not specified, the Start() method will return an error.
+ EtcdURL *url.URL
+
+ // StartTimeout, StopTimeout specify the time the APIServer is allowed to
+ // take when starting and stoppping before an error is emitted.
+ //
+ // If not specified, these default to 20 seconds.
+ StartTimeout time.Duration
+ StopTimeout time.Duration
+
+ // Out, Err specify where APIServer should write its StdOut, StdErr to.
+ //
+ // If not specified, the output will be discarded.
+ Out io.Writer
+ Err io.Writer
+
+ processState *process.State
+
+ // args contains the structured arguments to use for running the API server
+ // Lazily initialized by .Configure(), Defaulted eventually with .defaultArgs()
+ args *process.Arguments
+}
+
+// Configure returns Arguments that may be used to customize the
+// flags used to launch the API server. A set of defaults will
+// be applied underneath.
+func (s *APIServer) Configure() *process.Arguments {
+ if s.args == nil {
+ s.args = process.EmptyArguments()
+ }
+ return s.args
+}
+
+// Start starts the apiserver, waits for it to come up, and returns an error,
+// if occurred.
+func (s *APIServer) Start() error {
+ if err := s.prepare(); err != nil {
+ return err
+ }
+ return s.processState.Start(s.Out, s.Err)
+}
+
+func (s *APIServer) prepare() error {
+ if err := s.setProcessState(); err != nil {
+ return err
+ }
+ return s.Authn.Start()
+}
+
+// configurePorts configures the serving ports for this API server.
+//
+// Most of this method currently deals with making the deprecated fields
+// take precedence over the new fields.
+func (s *APIServer) configurePorts() error {
+ // prefer the old fields to the new fields if a user set one,
+ // otherwise, default the new fields and populate the old ones.
+
+ // Insecure: URL, InsecureServing
+ if s.URL != nil {
+ s.InsecureServing = &process.ListenAddr{
+ Address: s.URL.Hostname(),
+ Port: s.URL.Port(),
+ }
+ } else if insec := s.InsecureServing; insec != nil {
+ if insec.Port == "" || insec.Address == "" {
+ port, host, err := addr.Suggest("")
+ if err != nil {
+ return fmt.Errorf("unable to provision unused insecure port: %w", err)
+ }
+ s.InsecureServing.Port = strconv.Itoa(port)
+ s.InsecureServing.Address = host
+ }
+ s.URL = s.InsecureServing.URL("http", "")
+ }
+
+ // Secure: SecurePort, SecureServing
+ if s.SecurePort != 0 {
+ s.SecureServing.Port = strconv.Itoa(s.SecurePort)
+ // if we don't have an address, try the insecure address, and otherwise
+ // default to loopback.
+ if s.SecureServing.Address == "" {
+ if s.InsecureServing != nil {
+ s.SecureServing.Address = s.InsecureServing.Address
+ } else {
+ s.SecureServing.Address = "127.0.0.1"
+ }
+ }
+ } else if s.SecureServing.Port == "" || s.SecureServing.Address == "" {
+ port, host, err := addr.Suggest("")
+ if err != nil {
+ return fmt.Errorf("unable to provision unused secure port: %w", err)
+ }
+ s.SecureServing.Port = strconv.Itoa(port)
+ s.SecureServing.Address = host
+ s.SecurePort = port
+ }
+
+ return nil
+}
+
+func (s *APIServer) setProcessState() error {
+ if s.EtcdURL == nil {
+ return fmt.Errorf("expected EtcdURL to be configured")
+ }
+
+ var err error
+
+ // unconditionally re-set this so we can successfully restart
+ // TODO(directxman12): we supported this in the past, but do we actually
+ // want to support re-using an API server object to restart? The loss
+ // of provisioned users is surprising to say the least.
+ s.processState = &process.State{
+ Dir: s.CertDir,
+ Path: s.Path,
+ StartTimeout: s.StartTimeout,
+ StopTimeout: s.StopTimeout,
+ }
+ if err := s.processState.Init("kube-apiserver"); err != nil {
+ return err
+ }
+
+ if err := s.configurePorts(); err != nil {
+ return err
+ }
+
+ // the secure port will always be on, so use that
+ s.processState.HealthCheck.URL = *s.SecureServing.URL("https", "/healthz")
+
+ s.CertDir = s.processState.Dir
+ s.Path = s.processState.Path
+ s.StartTimeout = s.processState.StartTimeout
+ s.StopTimeout = s.processState.StopTimeout
+
+ if err := s.populateAPIServerCerts(); err != nil {
+ return err
+ }
+
+ if s.SecureServing.Authn == nil {
+ authn, err := NewCertAuthn()
+ if err != nil {
+ return err
+ }
+ s.SecureServing.Authn = authn
+ }
+
+ if err := s.Authn.Configure(s.CertDir, s.Configure()); err != nil {
+ return err
+ }
+
+ // NB(directxman12): insecure port is a mess:
+ // - 1.19 and below have the `--insecure-port` flag, and require it to be set to zero to
+ // disable it, otherwise the default will be used and we'll conflict.
+ // - 1.20 requires the flag to be unset or set to zero, and yells at you if you configure it
+ // - 1.24 won't have the flag at all...
+ //
+ // In an effort to automatically do the right thing during this mess, we do feature discovery
+ // on the flags, and hope that we've "parsed" them properly.
+ //
+ // TODO(directxman12): once we support 1.20 as the min version (might be when 1.24 comes out,
+ // might be around 1.25 or 1.26), remove this logic and the corresponding line in API server's
+ // default args.
+ if err := s.discoverFlags(); err != nil {
+ return err
+ }
+
+ s.processState.Args, s.Args, err = process.TemplateAndArguments(s.Args, s.Configure(), process.TemplateDefaults{ //nolint:staticcheck
+ Data: s,
+ Defaults: s.defaultArgs(),
+ MinimalDefaults: map[string][]string{
+ // as per kubernetes-sigs/controller-runtime#641, we need this (we
+ // probably need other stuff too, but this is the only thing that was
+ // previously considered a "minimal default")
+ "service-cluster-ip-range": {"10.0.0.0/24"},
+
+ // we need *some* authorization mode for health checks on the secure port,
+ // so default to RBAC unless the user set something else (in which case
+ // this'll be ignored due to SliceToArguments using AppendNoDefaults).
+ "authorization-mode": {"RBAC"},
+ },
+ })
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// discoverFlags checks for certain flags that *must* be set in certain
+// versions, and *must not* be set in others.
+func (s *APIServer) discoverFlags() error {
+ // Present: <1.24, Absent: >= 1.24
+ present, err := s.processState.CheckFlag("insecure-port")
+ if err != nil {
+ return err
+ }
+
+ if !present {
+ s.Configure().Disable("insecure-port")
+ }
+
+ return nil
+}
+
+func (s *APIServer) defaultArgs() map[string][]string {
+ args := map[string][]string{
+ "service-cluster-ip-range": {"10.0.0.0/24"},
+ "allow-privileged": {"true"},
+ // we're keeping this disabled because if enabled, default SA is
+ // missing which would force all tests to create one in normal
+ // apiserver operation this SA is created by controller, but that is
+ // not run in integration environment
+ "disable-admission-plugins": {"ServiceAccount"},
+ "cert-dir": {s.CertDir},
+ "authorization-mode": {"RBAC"},
+ "secure-port": {s.SecureServing.Port},
+ // NB(directxman12): previously we didn't set the bind address for the secure
+ // port. It *shouldn't* make a difference unless people are doing something really
+ // funky, but if you start to get bug reports look here ;-)
+ "bind-address": {s.SecureServing.Address},
+
+ // required on 1.20+, fine to leave on for <1.20
+ "service-account-issuer": {s.SecureServing.URL("https", "/").String()},
+ "service-account-key-file": {filepath.Join(s.CertDir, saCertFile)},
+ "service-account-signing-key-file": {filepath.Join(s.CertDir, saKeyFile)},
+ }
+ if s.EtcdURL != nil {
+ args["etcd-servers"] = []string{s.EtcdURL.String()}
+ }
+ if s.URL != nil {
+ args["insecure-port"] = []string{s.URL.Port()}
+ args["insecure-bind-address"] = []string{s.URL.Hostname()}
+ } else {
+ // TODO(directxman12): remove this once 1.21 is the lowest version we support
+ // (this might be a while, but this line'll break as of 1.24, so see the comment
+ // in Start
+ args["insecure-port"] = []string{"0"}
+ }
+ return args
+}
+
+func (s *APIServer) populateAPIServerCerts() error {
+ _, statErr := os.Stat(filepath.Join(s.CertDir, "apiserver.crt"))
+ if !os.IsNotExist(statErr) {
+ return statErr
+ }
+
+ ca, err := certs.NewTinyCA()
+ if err != nil {
+ return err
+ }
+
+ servingCerts, err := ca.NewServingCert()
+ if err != nil {
+ return err
+ }
+
+ certData, keyData, err := servingCerts.AsBytes()
+ if err != nil {
+ return err
+ }
+
+ if err := os.WriteFile(filepath.Join(s.CertDir, "apiserver.crt"), certData, 0640); err != nil { //nolint:gosec
+ return err
+ }
+ if err := os.WriteFile(filepath.Join(s.CertDir, "apiserver.key"), keyData, 0640); err != nil { //nolint:gosec
+ return err
+ }
+
+ s.SecureServing.CA = ca.CA.CertBytes()
+
+ // service account signing files too
+ saCA, err := certs.NewTinyCA()
+ if err != nil {
+ return err
+ }
+
+ saCert, saKey, err := saCA.CA.AsBytes()
+ if err != nil {
+ return err
+ }
+
+ if err := os.WriteFile(filepath.Join(s.CertDir, saCertFile), saCert, 0640); err != nil { //nolint:gosec
+ return err
+ }
+ return os.WriteFile(filepath.Join(s.CertDir, saKeyFile), saKey, 0640) //nolint:gosec
+}
+
+// Stop stops this process gracefully, waits for its termination, and cleans up
+// the CertDir if necessary.
+func (s *APIServer) Stop() error {
+ if s.processState != nil {
+ if s.processState.DirNeedsCleaning {
+ s.CertDir = "" // reset the directory if it was randomly allocated, so that we can safely restart
+ }
+ if err := s.processState.Stop(); err != nil {
+ return err
+ }
+ }
+ return s.Authn.Stop()
+}
+
+// APIServerDefaultArgs exposes the default args for the APIServer so that you
+// can use those to append your own additional arguments.
+//
+// Note that these arguments don't handle newer API servers well to due the more
+// complex feature detection neeeded. It's recommended that you switch to .Configure
+// as you upgrade API server versions.
+//
+// Deprecated: use APIServer.Configure().
+var APIServerDefaultArgs = []string{
+ "--advertise-address=127.0.0.1",
+ "--etcd-servers={{ if .EtcdURL }}{{ .EtcdURL.String }}{{ end }}",
+ "--cert-dir={{ .CertDir }}",
+ "--insecure-port={{ if .URL }}{{ .URL.Port }}{{else}}0{{ end }}",
+ "{{ if .URL }}--insecure-bind-address={{ .URL.Hostname }}{{ end }}",
+ "--secure-port={{ if .SecurePort }}{{ .SecurePort }}{{ end }}",
+ // we're keeping this disabled because if enabled, default SA is missing which would force all tests to create one
+ // in normal apiserver operation this SA is created by controller, but that is not run in integration environment
+ "--disable-admission-plugins=ServiceAccount",
+ "--service-cluster-ip-range=10.0.0.0/24",
+ "--allow-privileged=true",
+ // NB(directxman12): we also enable RBAC if nothing else was enabled
+}
+
+// PrepareAPIServer is an internal-only (NEVER SHOULD BE EXPOSED)
+// function that sets up the API server just before starting it,
+// without actually starting it. This saves time on tests.
+//
+// NB(directxman12): do not expose this outside of internal -- it's unsafe to
+// use, because things like port allocation could race even more than they
+// currently do if you later call start!
+func PrepareAPIServer(s *APIServer) error {
+ return s.prepare()
+}
+
+// APIServerArguments is an internal-only (NEVER SHOULD BE EXPOSED)
+// function that sets up the API server just before starting it,
+// without actually starting it. It's public to make testing easier.
+//
+// NB(directxman12): do not expose this outside of internal.
+func APIServerArguments(s *APIServer) []string {
+ return s.processState.Args
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/apiserver_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/apiserver_test.go
new file mode 100644
index 00000000000..6ce1577d457
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/apiserver_test.go
@@ -0,0 +1,295 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controlplane_test
+
+import (
+ "errors"
+ "net/url"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/rest"
+
+ . "sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/process"
+)
+
+var _ = Describe("APIServer", func() {
+ var server *APIServer
+ BeforeEach(func() {
+ server = &APIServer{
+ EtcdURL: &url.URL{},
+ }
+ })
+ JustBeforeEach(func() {
+ Expect(PrepareAPIServer(server)).To(Succeed())
+ })
+ Describe("setting up serving hosts & ports", func() {
+ Context("when URL is set", func() {
+ BeforeEach(func() {
+ server.URL = &url.URL{Scheme: "http", Host: "localhost:8675", Path: "/some-path"}
+ })
+
+ Context("when insecure serving is also set", func() {
+ BeforeEach(func() {
+ server.InsecureServing = &process.ListenAddr{
+ Address: "localhost",
+ Port: "1234",
+ }
+ })
+
+ It("should override the existing insecure serving", func() {
+ Expect(server.InsecureServing).To(Equal(&process.ListenAddr{
+ Address: "localhost",
+ Port: "8675",
+ }))
+ })
+ })
+
+ It("should set insecure serving off of that", func() {
+ Expect(server.InsecureServing).To(Equal(&process.ListenAddr{
+ Address: "localhost",
+ Port: "8675",
+ }))
+ })
+
+ It("should keep URL as-is", func() {
+ Expect(server.URL.String()).To(Equal("http://localhost:8675/some-path"))
+ })
+ })
+
+ Context("when URL is not set but InsecureServing is set", func() {
+ BeforeEach(func() {
+ server.InsecureServing = &process.ListenAddr{}
+ })
+
+ Context("when host and port are set", func() {
+ BeforeEach(func() {
+ server.InsecureServing.Address = "localhost"
+ server.InsecureServing.Port = "8675"
+ })
+ It("should set URL from InsecureServing", func() {
+ Expect(server.URL.String()).To(Equal("http://localhost:8675"))
+ })
+
+ It("should leave InsecureServing as-is if address and port are filled out", func() {
+ Expect(server.InsecureServing).To(Equal(&process.ListenAddr{
+ Address: "localhost",
+ Port: "8675",
+ }))
+ })
+ })
+
+ Context("when address and port are not filled out", func() {
+ BeforeEach(func() {
+ server.InsecureServing = &process.ListenAddr{}
+ })
+ It("should default an insecure port", func() {
+ Expect(server.InsecureServing.Port).NotTo(BeEmpty())
+ })
+ It("should set URL from InsecureServing", func() {
+ Expect(server.URL.String()).To(Equal("http://" + server.InsecureServing.Address + ":" + server.InsecureServing.Port))
+ })
+ })
+ })
+
+ Context("when neither URL or InsecureServing are set", func() {
+ It("should not default either of them", func() {
+ Expect(server.URL).To(BeNil(), "no URL should be set")
+ Expect(server.InsecureServing).To(BeNil(), "no insecure serving details should be set")
+ })
+ })
+
+ Context("when SecureServing host & port are set", func() {
+ BeforeEach(func() {
+ server.Address = "localhost"
+ server.Port = "8675"
+ })
+
+ It("should leave SecureServing as-is", func() {
+ Expect(server.SecureServing.Address).To(Equal("localhost"))
+ Expect(server.SecureServing.Port).To(Equal("8675"))
+ })
+ })
+
+ Context("when SecureServing is not set", func() {
+ It("should be defaulted with a random port", func() {
+ Expect(server.Port).NotTo(Equal(0))
+ })
+ })
+ })
+
+ It("should default authn if not set", func() {
+ Expect(server.Authn).NotTo(BeNil())
+ })
+
+ Describe("argument defaulting", func() {
+ // NB(directxman12): most of the templating vs configure logic is tested
+ // in arguments/arguments_test.go, so just test secure vs insecure port logic here
+
+ Context("when insecure serving is set, on a binary that supports it", func() {
+ BeforeEach(func() {
+ server.InsecureServing = &process.ListenAddr{
+ Address: "localhost",
+ Port: "8675",
+ }
+ server.Path = "./testdata/fake-1.19-apiserver.sh"
+ })
+ It("should set the insecure-port and insecure-bind-address fields from insecureserving", func() {
+ Expect(APIServerArguments(server)).To(ContainElements(
+ "--insecure-port=8675",
+ "--insecure-bind-address=localhost",
+ ))
+ })
+ })
+
+ Context("when insecureserving is disabled, on binaries with no insecure-port flag", func() {
+ BeforeEach(func() {
+ server.Path = "./testdata/fake-1.20-apiserver.sh"
+ })
+ It("should not try to explicitly disable the insecure port", func() {
+ Expect(APIServerArguments(server)).NotTo(ContainElement(HavePrefix("--insecure-port")))
+ })
+ })
+
+ Context("when insecureserving is disabled, on binaries with an insecure-port flag", func() {
+ BeforeEach(func() {
+ server.Path = "./testdata/fake-1.19-apiserver.sh"
+ })
+ It("should explicitly disable the insecure port", func() {
+ Expect(APIServerArguments(server)).To(ContainElement("--insecure-port=0"))
+ })
+ })
+
+ Context("when given legacy-style template arguments", func() {
+ BeforeEach(func() {
+ server.Args = []string{"--foo=bar", "--baz={{ .Port }}"}
+ })
+ It("should use the passed in args with the minimal required defaults", func() {
+ Expect(APIServerArguments(server)).To(ConsistOf(
+ "--foo=bar",
+ MatchRegexp(`--baz=\d+`),
+ "--service-cluster-ip-range=10.0.0.0/24",
+ MatchRegexp("--client-ca-file=.+"),
+ "--authorization-mode=RBAC",
+ ))
+ })
+ })
+ })
+
+ Describe("setting up auth", func() {
+ var auth *fakeAuthn
+ BeforeEach(func() {
+ auth = &fakeAuthn{
+ setFlag: true,
+ }
+ server.Authn = auth
+ })
+ It("should configure with the cert dir", func() {
+ Expect(auth.workDir).To(Equal(server.CertDir))
+ })
+ It("should pass its args to be configured", func() {
+ Expect(server.Configure().Get("configure-called").Get(nil)).To(ConsistOf("true"))
+ })
+
+ Context("when configuring auth errors out", func() {
+ It("should fail to configure", func() {
+ server := &APIServer{
+ EtcdURL: &url.URL{},
+ SecureServing: SecureServing{
+ Authn: auth,
+ },
+ }
+ auth.configureErr = errors.New("Oh no")
+ Expect(PrepareAPIServer(server)).NotTo(Succeed())
+ })
+ })
+ })
+
+ Describe("managing", func() {
+ // some of these tests are combined for speed reasons -- starting the apiserver
+ // takes a while, relatively speaking
+
+ var (
+ auth *fakeAuthn
+ etcd *Etcd
+ )
+ BeforeEach(func() {
+ etcd = &Etcd{}
+ Expect(etcd.Start()).To(Succeed())
+ server.EtcdURL = etcd.URL
+
+ auth = &fakeAuthn{}
+ server.Authn = auth
+ })
+ AfterEach(func() {
+ Expect(etcd.Stop()).To(Succeed())
+ })
+
+ Context("after starting", func() {
+ BeforeEach(func() {
+ Expect(server.Start()).To(Succeed())
+ })
+
+ It("should stop successfully, and stop auth", func() {
+ Expect(server.Stop()).To(Succeed())
+ Expect(auth.stopCalled).To(BeTrue())
+ })
+ })
+
+ It("should fail to start when auth fails to start", func() {
+ auth.startErr = errors.New("Oh no")
+ Expect(server.Start()).NotTo(Succeed())
+ })
+
+ It("should start successfully & start auth", func() {
+ Expect(server.Start()).To(Succeed())
+ defer func() { Expect(server.Stop()).To(Succeed()) }()
+ Expect(auth.startCalled).To(BeTrue())
+ })
+ })
+})
+
+type fakeAuthn struct {
+ workDir string
+
+ startCalled bool
+ stopCalled bool
+ setFlag bool
+
+ configureErr error
+ startErr error
+}
+
+func (f *fakeAuthn) Configure(workDir string, args *process.Arguments) error {
+ f.workDir = workDir
+ if f.setFlag {
+ args.Set("configure-called", "true")
+ }
+ return f.configureErr
+}
+func (f *fakeAuthn) Start() error {
+ f.startCalled = true
+ return f.startErr
+}
+func (f *fakeAuthn) AddUser(user User, baseCfg *rest.Config) (*rest.Config, error) {
+ return nil, nil
+}
+func (f *fakeAuthn) Stop() error {
+ f.stopCalled = true
+ return nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/auth.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/auth.go
new file mode 100644
index 00000000000..16c86a712c1
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/auth.go
@@ -0,0 +1,142 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controlplane
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/certs"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/process"
+)
+
+// User represents a Kubernetes user.
+type User struct {
+ // Name is the user's Name.
+ Name string
+ // Groups are the groups to which the user belongs.
+ Groups []string
+}
+
+// Authn knows how to configure an API server for a particular type of authentication,
+// and provision users under that authentication scheme.
+//
+// The methods must be called in the following order (as presented below in the interface
+// for a mnemonic):
+//
+// 1. Configure
+// 2. Start
+// 3. AddUsers (0+ calls)
+// 4. Stop.
+type Authn interface {
+ // Configure provides the working directory to this authenticator,
+ // and configures the given API server arguments to make use of this authenticator.
+ //
+ // Should be called first.
+ Configure(workDir string, args *process.Arguments) error
+ // Start runs this authenticator. Will be called just before API server start.
+ //
+ // Must be called after Configure.
+ Start() error
+ // AddUser provisions a user, returning a copy of the given base rest.Config
+ // configured to authenticate as that users.
+ //
+ // May only be called while the authenticator is "running".
+ AddUser(user User, baseCfg *rest.Config) (*rest.Config, error)
+ // Stop shuts down this authenticator.
+ Stop() error
+}
+
+// CertAuthn is an authenticator (Authn) that makes use of client certificate authn.
+type CertAuthn struct {
+ // ca is the CA used to sign the client certs
+ ca *certs.TinyCA
+ // certDir is the directory used to write the CA crt file
+ // so that the API server can read it.
+ certDir string
+}
+
+// NewCertAuthn creates a new client-cert-based Authn with a new CA.
+func NewCertAuthn() (*CertAuthn, error) {
+ ca, err := certs.NewTinyCA()
+ if err != nil {
+ return nil, fmt.Errorf("unable to provision client certificate auth CA: %w", err)
+ }
+ return &CertAuthn{
+ ca: ca,
+ }, nil
+}
+
+// AddUser provisions a new user that's authenticated via certificates, with
+// the given uesrname and groups embedded in the certificate as expected by the
+// API server.
+func (c *CertAuthn) AddUser(user User, baseCfg *rest.Config) (*rest.Config, error) {
+ certs, err := c.ca.NewClientCert(certs.ClientInfo{
+ Name: user.Name,
+ Groups: user.Groups,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("unable to create client certificates for %s: %w", user.Name, err)
+ }
+
+ crt, key, err := certs.AsBytes()
+ if err != nil {
+ return nil, fmt.Errorf("unable to serialize client certificates for %s: %w", user.Name, err)
+ }
+
+ cfg := rest.CopyConfig(baseCfg)
+ cfg.CertData = crt
+ cfg.KeyData = key
+
+ return cfg, nil
+}
+
+// caCrtPath returns the path to the on-disk client-cert CA crt file.
+func (c *CertAuthn) caCrtPath() string {
+ return filepath.Join(c.certDir, "client-cert-auth-ca.crt")
+}
+
+// Configure provides the working directory to this authenticator,
+// and configures the given API server arguments to make use of this authenticator.
+func (c *CertAuthn) Configure(workDir string, args *process.Arguments) error {
+ c.certDir = workDir
+ args.Set("client-ca-file", c.caCrtPath())
+ return nil
+}
+
+// Start runs this authenticator. Will be called just before API server start.
+//
+// Must be called after Configure.
+func (c *CertAuthn) Start() error {
+ if len(c.certDir) == 0 {
+ return fmt.Errorf("start called before configure")
+ }
+ caCrt := c.ca.CA.CertBytes()
+ if err := os.WriteFile(c.caCrtPath(), caCrt, 0640); err != nil { //nolint:gosec
+ return fmt.Errorf("unable to save the client certificate CA to %s: %w", c.caCrtPath(), err)
+ }
+
+ return nil
+}
+
+// Stop shuts down this authenticator.
+func (c *CertAuthn) Stop() error {
+ // no-op -- our workdir is cleaned up for us automatically
+ return nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/auth_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/auth_test.go
new file mode 100644
index 00000000000..9891c6f2e26
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/auth_test.go
@@ -0,0 +1,175 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controlplane_test
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "os"
+ "path/filepath"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/rest"
+ kcert "k8s.io/client-go/util/cert"
+
+ cp "sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/process"
+)
+
+var _ = Describe("Cert Authentication", func() {
+ var authn *cp.CertAuthn
+ BeforeEach(func() {
+ var err error
+ authn, err = cp.NewCertAuthn()
+ Expect(err).NotTo(HaveOccurred(), "should be able to create the cert authn")
+ })
+ Context("when starting", func() {
+ It("should write the verifying CA to the configured directory", func() {
+ By("setting up a temp dir")
+ dir, err := os.MkdirTemp("", "envtest_controlplane_*")
+ Expect(err).NotTo(HaveOccurred(), "should be able to provision a temp dir")
+ if dir != "" {
+ defer os.RemoveAll(dir)
+ }
+
+ By("configuring to use that dir")
+ Expect(authn.Configure(dir, process.EmptyArguments())).To(Succeed())
+
+ By("starting and checking the dir")
+ Expect(authn.Start()).To(Succeed())
+ defer func() { Expect(authn.Stop()).To(Succeed()) }() // not strictly necessary, but future-proof
+
+ _, err = os.Stat(filepath.Join(dir, "client-cert-auth-ca.crt"))
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ It("should error out if we haven't been configured yet", func() {
+ // NB(directxman12): no configure here intentionally
+ Expect(authn.Start()).NotTo(Succeed())
+ })
+ })
+ Context("when configuring", func() {
+ It("should have set up the API server to use the written file for client cert auth", func() {
+ args := process.EmptyArguments()
+ Expect(authn.Configure("/tmp/____doesnotexist", args)).To(Succeed())
+ Expect(args.Get("client-ca-file").Get(nil)).To(ConsistOf("/tmp/____doesnotexist/client-cert-auth-ca.crt"))
+ })
+ })
+
+ Describe("creating users", func() {
+ user := cp.User{Name: "someuser", Groups: []string{"group1", "group2"}}
+
+ Context("before starting", func() {
+ It("should yield a REST config that contains certs valid for the to-be-written CA", func() {
+ cfg, err := authn.AddUser(user, &rest.Config{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cfg).NotTo(BeNil())
+
+ Expect(cfg.CertData).NotTo(BeEmpty())
+ Expect(cfg.KeyData).NotTo(BeEmpty())
+
+ // double-check the cert (assume the key is fine if it's present
+ // and the cert is also present, cause it's more annoying to verify
+ // and we have separate tinyca & integration tests.
+ By("parsing the config's cert & key data")
+ certs, err := tls.X509KeyPair(cfg.CertData, cfg.KeyData)
+ Expect(err).NotTo(HaveOccurred(), "config cert/key data should be valid key pair")
+ cert, err := x509.ParseCertificate(certs.Certificate[0]) // re-parse cause .Leaf isn't saved
+ Expect(err).NotTo(HaveOccurred())
+
+ By("starting and loading the CA cert")
+ dir, err := os.MkdirTemp("", "envtest_controlplane_*")
+ Expect(err).NotTo(HaveOccurred(), "should be able to provision a temp dir")
+ if dir != "" {
+ defer os.RemoveAll(dir)
+ }
+ Expect(authn.Configure(dir, process.EmptyArguments())).To(Succeed())
+ Expect(authn.Start()).To(Succeed())
+ caCerts, err := kcert.CertsFromFile(filepath.Join(dir, "client-cert-auth-ca.crt"))
+ Expect(err).NotTo(HaveOccurred(), "should be able to read the CA cert file))))")
+ Expect(cert.CheckSignatureFrom(caCerts[0])).To(Succeed(), "the config's cert should be signed by the written CA")
+ })
+
+ It("should copy the configuration from the base CA without modifying it", func() {
+ By("creating a user and checking the output config")
+ base := &rest.Config{Burst: 30}
+ cfg, err := authn.AddUser(user, base)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cfg).NotTo(BeNil())
+ Expect(cfg.Burst).To(Equal(30))
+
+ By("mutating the base and verifying the cfg doesn't change")
+ base.Burst = 8675
+ Expect(cfg.Burst).To(Equal(30))
+ })
+ })
+
+ Context("after starting", func() {
+ var dir string
+ BeforeEach(func() {
+ By("setting up a temp dir & starting with it")
+ var err error
+ dir, err = os.MkdirTemp("", "envtest_controlplane_*")
+ Expect(err).NotTo(HaveOccurred(), "should be able to provision a temp dir")
+ Expect(authn.Configure(dir, process.EmptyArguments())).To(Succeed())
+ Expect(authn.Start()).To(Succeed())
+ })
+ AfterEach(func() {
+ if dir != "" {
+ defer os.RemoveAll(dir)
+ }
+ })
+
+ It("should yield a REST config that contains certs valid for the written CA", func() {
+ cfg, err := authn.AddUser(user, &rest.Config{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cfg).NotTo(BeNil())
+
+ Expect(cfg.CertData).NotTo(BeEmpty())
+ Expect(cfg.KeyData).NotTo(BeEmpty())
+
+ // double-check the cert (assume the key is fine if it's present
+ // and the cert is also present, cause it's more annoying to verify
+ // and we have separate tinyca & integration tests.
+ By("parsing the config's cert & key data")
+ certs, err := tls.X509KeyPair(cfg.CertData, cfg.KeyData)
+ Expect(err).NotTo(HaveOccurred(), "config cert/key data should be valid key pair")
+ cert, err := x509.ParseCertificate(certs.Certificate[0]) // re-parse cause .Leaf isn't saved
+ Expect(err).NotTo(HaveOccurred())
+
+ By("loading the CA cert")
+ caCerts, err := kcert.CertsFromFile(filepath.Join(dir, "client-cert-auth-ca.crt"))
+ Expect(err).NotTo(HaveOccurred(), "should be able to read the CA cert file))))")
+ Expect(cert.CheckSignatureFrom(caCerts[0])).To(Succeed(), "the config's cert should be signed by the written CA")
+ })
+
+ It("should copy the configuration from the base CA without modifying it", func() {
+ By("creating a user and checking the output config")
+ base := &rest.Config{Burst: 30}
+ cfg, err := authn.AddUser(user, base)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cfg).NotTo(BeNil())
+ Expect(cfg.Burst).To(Equal(30))
+
+ By("mutating the base and verifying the cfg doesn't change")
+ base.Burst = 8675
+ Expect(cfg.Burst).To(Equal(30))
+ })
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/controlplane_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/controlplane_suite_test.go
new file mode 100644
index 00000000000..9ac69047f03
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/controlplane_suite_test.go
@@ -0,0 +1,30 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controlplane_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestIntegration(t *testing.T) {
+ t.Parallel()
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Control Plane Standup Unit Tests")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/etcd.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/etcd.go
new file mode 100644
index 00000000000..c30d2132952
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/etcd.go
@@ -0,0 +1,202 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controlplane
+
+import (
+ "io"
+ "net"
+ "net/url"
+ "strconv"
+ "time"
+
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/addr"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/process"
+)
+
+// Etcd knows how to run an etcd server.
+type Etcd struct {
+ // URL is the address the Etcd should listen on for client connections.
+ //
+ // If this is not specified, we default to a random free port on localhost.
+ URL *url.URL
+
+ // Path is the path to the etcd binary.
+ //
+ // If this is left as the empty string, we will attempt to locate a binary,
+ // by checking for the TEST_ASSET_ETCD environment variable, and the default
+ // test assets directory. See the "Binaries" section above (in doc.go) for
+ // details.
+ Path string
+
+ // Args is a list of arguments which will passed to the Etcd binary. Before
+ // they are passed on, the`y will be evaluated as go-template strings. This
+ // means you can use fields which are defined and exported on this Etcd
+ // struct (e.g. "--data-dir={{ .Dir }}").
+ // Those templates will be evaluated after the defaulting of the Etcd's
+ // fields has already happened and just before the binary actually gets
+ // started. Thus you have access to calculated fields like `URL` and others.
+ //
+ // If not specified, the minimal set of arguments to run the Etcd will be
+ // used.
+ //
+ // They will be loaded into the same argument set as Configure. Each flag
+ // will be Append-ed to the configured arguments just before launch.
+ //
+ // Deprecated: use Configure instead.
+ Args []string
+
+ // DataDir is a path to a directory in which etcd can store its state.
+ //
+ // If left unspecified, then the Start() method will create a fresh temporary
+ // directory, and the Stop() method will clean it up.
+ DataDir string
+
+ // StartTimeout, StopTimeout specify the time the Etcd is allowed to
+ // take when starting and stopping before an error is emitted.
+ //
+ // If not specified, these default to 20 seconds.
+ StartTimeout time.Duration
+ StopTimeout time.Duration
+
+ // Out, Err specify where Etcd should write its StdOut, StdErr to.
+ //
+ // If not specified, the output will be discarded.
+ Out io.Writer
+ Err io.Writer
+
+ // processState contains the actual details about this running process
+ processState *process.State
+
+ // args contains the structured arguments to use for running etcd.
+ // Lazily initialized by .Configure(), Defaulted eventually with .defaultArgs()
+ args *process.Arguments
+
+ // listenPeerURL is the address the Etcd should listen on for peer connections.
+ // It's automatically generated and a random port is picked during execution.
+ listenPeerURL *url.URL
+}
+
+// Start starts the etcd, waits for it to come up, and returns an error, if one
+// occurred.
+func (e *Etcd) Start() error {
+ if err := e.setProcessState(); err != nil {
+ return err
+ }
+ return e.processState.Start(e.Out, e.Err)
+}
+
+func (e *Etcd) setProcessState() error {
+ e.processState = &process.State{
+ Dir: e.DataDir,
+ Path: e.Path,
+ StartTimeout: e.StartTimeout,
+ StopTimeout: e.StopTimeout,
+ }
+
+ // unconditionally re-set this so we can successfully restart
+ // TODO(directxman12): we supported this in the past, but do we actually
+ // want to support re-using an API server object to restart? The loss
+ // of provisioned users is surprising to say the least.
+ if err := e.processState.Init("etcd"); err != nil {
+ return err
+ }
+
+ // Set the listen url.
+ if e.URL == nil {
+ port, host, err := addr.Suggest("")
+ if err != nil {
+ return err
+ }
+ e.URL = &url.URL{
+ Scheme: "http",
+ Host: net.JoinHostPort(host, strconv.Itoa(port)),
+ }
+ }
+
+ // Set the listen peer URL.
+ {
+ port, host, err := addr.Suggest("")
+ if err != nil {
+ return err
+ }
+ e.listenPeerURL = &url.URL{
+ Scheme: "http",
+ Host: net.JoinHostPort(host, strconv.Itoa(port)),
+ }
+ }
+
+ // can use /health as of etcd 3.3.0
+ e.processState.HealthCheck.URL = *e.URL
+ e.processState.HealthCheck.Path = "/health"
+
+ e.DataDir = e.processState.Dir
+ e.Path = e.processState.Path
+ e.StartTimeout = e.processState.StartTimeout
+ e.StopTimeout = e.processState.StopTimeout
+
+ var err error
+ e.processState.Args, e.Args, err = process.TemplateAndArguments(e.Args, e.Configure(), process.TemplateDefaults{ //nolint:staticcheck
+ Data: e,
+ Defaults: e.defaultArgs(),
+ })
+ return err
+}
+
+// Stop stops this process gracefully, waits for its termination, and cleans up
+// the DataDir if necessary.
+func (e *Etcd) Stop() error {
+ if e.processState.DirNeedsCleaning {
+ e.DataDir = "" // reset the directory if it was randomly allocated, so that we can safely restart
+ }
+ return e.processState.Stop()
+}
+
+func (e *Etcd) defaultArgs() map[string][]string {
+ args := map[string][]string{
+ "listen-peer-urls": {e.listenPeerURL.String()},
+ "data-dir": {e.DataDir},
+ }
+ if e.URL != nil {
+ args["advertise-client-urls"] = []string{e.URL.String()}
+ args["listen-client-urls"] = []string{e.URL.String()}
+ }
+
+ // Add unsafe no fsync, available from etcd 3.5
+ if ok, _ := e.processState.CheckFlag("unsafe-no-fsync"); ok {
+ args["unsafe-no-fsync"] = []string{"true"}
+ }
+ return args
+}
+
+// Configure returns Arguments that may be used to customize the
+// flags used to launch etcd. A set of defaults will
+// be applied underneath.
+func (e *Etcd) Configure() *process.Arguments {
+ if e.args == nil {
+ e.args = process.EmptyArguments()
+ }
+ return e.args
+}
+
+// EtcdDefaultArgs exposes the default args for Etcd so that you
+// can use those to append your own additional arguments.
+var EtcdDefaultArgs = []string{
+ "--listen-peer-urls=http://localhost:0",
+ "--advertise-client-urls={{ if .URL }}{{ .URL.String }}{{ end }}",
+ "--listen-client-urls={{ if .URL }}{{ .URL.String }}{{ end }}",
+ "--data-dir={{ .DataDir }}",
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/etcd_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/etcd_test.go
new file mode 100644
index 00000000000..7c7c7561ffd
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/etcd_test.go
@@ -0,0 +1,36 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controlplane_test
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ . "sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane"
+)
+
+var _ = Describe("etcd", func() {
+ // basic coherence test
+ It("should start and stop successfully", func() {
+ etcd := &Etcd{}
+ Expect(etcd.Start()).To(Succeed())
+ defer func() {
+ Expect(etcd.Stop()).To(Succeed())
+ }()
+ Expect(etcd.URL).NotTo(BeNil())
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/kubectl.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/kubectl.go
new file mode 100644
index 00000000000..a27b7a0ff88
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/kubectl.go
@@ -0,0 +1,119 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controlplane
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "net/url"
+ "os/exec"
+
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/clientcmd"
+ kcapi "k8s.io/client-go/tools/clientcmd/api"
+
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/process"
+)
+
+const (
+ envtestName = "envtest"
+)
+
+// KubeConfigFromREST reverse-engineers a kubeconfig file from a rest.Config.
+// The options are tailored towards the rest.Configs we generate, so they're
+// not broadly applicable.
+//
+// This is not intended to be exposed beyond internal for the above reasons.
+func KubeConfigFromREST(cfg *rest.Config) ([]byte, error) {
+ kubeConfig := kcapi.NewConfig()
+ protocol := "https"
+ if !rest.IsConfigTransportTLS(*cfg) {
+ protocol = "http"
+ }
+
+ // cfg.Host is a URL, so we need to parse it so we can properly append the API path
+ baseURL, err := url.Parse(cfg.Host)
+ if err != nil {
+ return nil, fmt.Errorf("unable to interpret config's host value as a URL: %w", err)
+ }
+
+ kubeConfig.Clusters[envtestName] = &kcapi.Cluster{
+ // TODO(directxman12): if client-go ever decides to expose defaultServerUrlFor(config),
+ // we can just use that. Note that this is not the same as the public DefaultServerURL,
+ // which requires us to pass a bunch of stuff in manually.
+ Server: (&url.URL{Scheme: protocol, Host: baseURL.Host, Path: cfg.APIPath}).String(),
+ CertificateAuthorityData: cfg.CAData,
+ }
+ kubeConfig.AuthInfos[envtestName] = &kcapi.AuthInfo{
+ // try to cover all auth strategies that aren't plugins
+ ClientCertificateData: cfg.CertData,
+ ClientKeyData: cfg.KeyData,
+ Token: cfg.BearerToken,
+ Username: cfg.Username,
+ Password: cfg.Password,
+ }
+ kcCtx := kcapi.NewContext()
+ kcCtx.Cluster = envtestName
+ kcCtx.AuthInfo = envtestName
+ kubeConfig.Contexts[envtestName] = kcCtx
+ kubeConfig.CurrentContext = envtestName
+
+ contents, err := clientcmd.Write(*kubeConfig)
+ if err != nil {
+ return nil, fmt.Errorf("unable to serialize kubeconfig file: %w", err)
+ }
+ return contents, nil
+}
+
+// KubeCtl is a wrapper around the kubectl binary.
+type KubeCtl struct {
+ // Path where the kubectl binary can be found.
+ //
+ // If this is left empty, we will attempt to locate a binary, by checking for
+ // the TEST_ASSET_KUBECTL environment variable, and the default test assets
+ // directory. See the "Binaries" section above (in doc.go) for details.
+ Path string
+
+ // Opts can be used to configure additional flags which will be used each
+ // time the wrapped binary is called.
+ //
+ // For example, you might want to use this to set the URL of the APIServer to
+ // connect to.
+ Opts []string
+}
+
+// Run executes the wrapped binary with some preconfigured options and the
+// arguments given to this method. It returns Readers for the stdout and
+// stderr.
+func (k *KubeCtl) Run(args ...string) (stdout, stderr io.Reader, err error) {
+ if k.Path == "" {
+ k.Path = process.BinPathFinder("kubectl", "")
+ }
+
+ stdoutBuffer := &bytes.Buffer{}
+ stderrBuffer := &bytes.Buffer{}
+ allArgs := append(k.Opts, args...)
+
+ cmd := exec.Command(k.Path, allArgs...)
+ cmd.Stdout = stdoutBuffer
+ cmd.Stderr = stderrBuffer
+
+ err = cmd.Run()
+
+ return stdoutBuffer, stderrBuffer, err
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/kubectl_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/kubectl_test.go
new file mode 100644
index 00000000000..5484bc31a1a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/kubectl_test.go
@@ -0,0 +1,138 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controlplane_test
+
+import (
+ "io"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/gstruct"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/clientcmd"
+ ccapi "k8s.io/client-go/tools/clientcmd/api"
+
+ . "sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane"
+)
+
+var _ = Describe("Kubectl", func() {
+ It("runs kubectl", func() {
+ k := &KubeCtl{Path: "bash"}
+ args := []string{"-c", "echo 'something'"}
+ stdout, stderr, err := k.Run(args...)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(stdout).To(ContainSubstring("something"))
+ bytes, err := io.ReadAll(stderr)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(bytes).To(BeEmpty())
+ })
+
+ Context("when the command returns a non-zero exit code", func() {
+ It("returns an error", func() {
+ k := &KubeCtl{Path: "bash"}
+ args := []string{
+ "-c", "echo 'this is StdErr' >&2; echo 'but this is StdOut' >&1; exit 66",
+ }
+
+ stdout, stderr, err := k.Run(args...)
+
+ Expect(err).To(MatchError(ContainSubstring("exit status 66")))
+
+ Expect(stdout).To(ContainSubstring("but this is StdOut"))
+ Expect(stderr).To(ContainSubstring("this is StdErr"))
+ })
+ })
+})
+
+var _ = Describe("KubeConfigFromREST", func() {
+ var (
+ restCfg *rest.Config
+ rawCfg []byte
+ cfg *ccapi.Config
+ )
+
+ BeforeEach(func() {
+ restCfg = &rest.Config{
+ Host: "https://some-host:8675",
+ APIPath: "/some-prefix",
+ TLSClientConfig: rest.TLSClientConfig{
+ CertData: []byte("cert"),
+ KeyData: []byte("key"),
+ CAData: []byte("ca-cert"),
+ },
+ BearerToken: "some-tok",
+ Username: "some-user",
+ Password: "some-password",
+ }
+ })
+
+ JustBeforeEach(func() {
+ var err error
+ rawCfg, err = KubeConfigFromREST(restCfg)
+ Expect(err).NotTo(HaveOccurred(), "should be able to convert & serialize the kubeconfig")
+
+ cfg, err = clientcmd.Load(rawCfg)
+ Expect(err).NotTo(HaveOccurred(), "should be able to deserialize the generated kubeconfig")
+ })
+
+ It("should set up a context, and set it as the current one", func() {
+ By("checking that the current context exists")
+ Expect(cfg.CurrentContext).NotTo(BeEmpty(), "should have a current context")
+ Expect(cfg.Contexts).To(HaveKeyWithValue(cfg.CurrentContext, Not(BeNil())), "the current context should exist as a context")
+
+ By("checking that it points to valid info")
+ currCtx := cfg.Contexts[cfg.CurrentContext]
+ Expect(currCtx).To(PointTo(MatchFields(IgnoreExtras, Fields{
+ "Cluster": Not(BeEmpty()),
+ "AuthInfo": Not(BeEmpty()),
+ })))
+
+ Expect(cfg.Clusters).To(HaveKeyWithValue(currCtx.Cluster, Not(BeNil())), "should point to a cluster")
+ Expect(cfg.AuthInfos).To(HaveKeyWithValue(currCtx.AuthInfo, Not(BeNil())), "should point to a user")
+ })
+
+ Context("when no TLS is enabled", func() {
+ BeforeEach(func() {
+ restCfg.Host = "http://some-host:8675"
+ restCfg.TLSClientConfig = rest.TLSClientConfig{}
+ })
+
+ It("should use http in the server url", func() {
+ cluster := cfg.Clusters[cfg.Contexts[cfg.CurrentContext].Cluster]
+ Expect(cluster.Server).To(HavePrefix("http://"))
+ })
+ })
+
+ It("configure the current context to point to the given REST config's server, with CA data", func() {
+ cluster := cfg.Clusters[cfg.Contexts[cfg.CurrentContext].Cluster]
+ Expect(cluster).To(PointTo(MatchFields(IgnoreExtras, Fields{
+ "Server": Equal("https://some-host:8675/some-prefix"),
+ "CertificateAuthorityData": Equal([]byte("ca-cert")),
+ })))
+ })
+
+ It("should copy all non-plugin auth info over", func() {
+ user := cfg.AuthInfos[cfg.Contexts[cfg.CurrentContext].AuthInfo]
+ Expect(user).To(PointTo(MatchFields(IgnoreExtras, Fields{
+ "ClientCertificateData": Equal([]byte("cert")),
+ "ClientKeyData": Equal([]byte("key")),
+ "Token": Equal("some-tok"),
+ "Username": Equal("some-user"),
+ "Password": Equal("some-password"),
+ })))
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/plane.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/plane.go
new file mode 100644
index 00000000000..456183a7a32
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/plane.go
@@ -0,0 +1,259 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controlplane
+
+import (
+ "fmt"
+ "net/url"
+ "os"
+
+ kerrors "k8s.io/apimachinery/pkg/util/errors"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/certs"
+)
+
+// NewTinyCA creates a new a tiny CA utility for provisioning serving certs and client certs FOR TESTING ONLY.
+// Don't use this for anything else!
+var NewTinyCA = certs.NewTinyCA
+
+// ControlPlane is a struct that knows how to start your test control plane.
+//
+// Right now, that means Etcd and your APIServer. This is likely to increase in
+// future.
+type ControlPlane struct {
+ APIServer *APIServer
+ Etcd *Etcd
+
+ // Kubectl will override the default asset search path for kubectl
+ KubectlPath string
+
+ // for the deprecated methods (Kubectl, etc)
+ defaultUserCfg *rest.Config
+ defaultUserKubectl *KubeCtl
+}
+
+// Start will start your control plane processes. To stop them, call Stop().
+func (f *ControlPlane) Start() (retErr error) {
+ if f.Etcd == nil {
+ f.Etcd = &Etcd{}
+ }
+ if err := f.Etcd.Start(); err != nil {
+ return err
+ }
+ defer func() {
+ if retErr != nil {
+ _ = f.Etcd.Stop()
+ }
+ }()
+
+ if f.APIServer == nil {
+ f.APIServer = &APIServer{}
+ }
+ f.APIServer.EtcdURL = f.Etcd.URL
+ if err := f.APIServer.Start(); err != nil {
+ return err
+ }
+ defer func() {
+ if retErr != nil {
+ _ = f.APIServer.Stop()
+ }
+ }()
+
+ // provision the default user -- can be removed when the related
+ // methods are removed. The default user has admin permissions to
+ // mimic legacy no-authz setups.
+ user, err := f.AddUser(User{Name: "default", Groups: []string{"system:masters"}}, &rest.Config{})
+ if err != nil {
+ return fmt.Errorf("unable to provision the default (legacy) user: %w", err)
+ }
+ kubectl, err := user.Kubectl()
+ if err != nil {
+ return fmt.Errorf("unable to provision the default (legacy) kubeconfig: %w", err)
+ }
+ f.defaultUserCfg = user.Config()
+ f.defaultUserKubectl = kubectl
+ return nil
+}
+
+// Stop will stop your control plane processes, and clean up their data.
+func (f *ControlPlane) Stop() error {
+ var errList []error
+
+ if f.APIServer != nil {
+ if err := f.APIServer.Stop(); err != nil {
+ errList = append(errList, err)
+ }
+ }
+
+ if f.Etcd != nil {
+ if err := f.Etcd.Stop(); err != nil {
+ errList = append(errList, err)
+ }
+ }
+
+ return kerrors.NewAggregate(errList)
+}
+
+// APIURL returns the URL you should connect to to talk to your API server.
+//
+// If insecure serving is configured, this will contain the insecure port.
+// Otherwise, it will contain the secure port.
+//
+// Deprecated: use AddUser instead, or APIServer.{Ins|S}ecureServing.URL if
+// you really want just the URL.
+func (f *ControlPlane) APIURL() *url.URL {
+ return f.APIServer.URL
+}
+
+// KubeCtl returns a pre-configured KubeCtl, ready to connect to this
+// ControlPlane.
+//
+// Deprecated: use AddUser & AuthenticatedUser.Kubectl instead.
+func (f *ControlPlane) KubeCtl() *KubeCtl {
+ return f.defaultUserKubectl
+}
+
+// RESTClientConfig returns a pre-configured restconfig, ready to connect to
+// this ControlPlane.
+//
+// Deprecated: use AddUser & AuthenticatedUser.Config instead.
+func (f *ControlPlane) RESTClientConfig() (*rest.Config, error) {
+ return f.defaultUserCfg, nil
+}
+
+// AuthenticatedUser contains access information for an provisioned user,
+// including REST config, kubeconfig contents, and access to a KubeCtl instance.
+//
+// It's not "safe" to use the methods on this till after the API server has been
+// started (due to certificate initialization and such). The various methods will
+// panic if this is done.
+type AuthenticatedUser struct {
+ // cfg is the rest.Config for connecting to the API server. It's lazily initialized.
+ cfg *rest.Config
+ // cfgIsComplete indicates the cfg has had late-initialized fields (e.g.
+ // API server CA data) initialized.
+ cfgIsComplete bool
+
+ // apiServer is a handle to the APIServer that's used when finalizing cfg
+ // and producing the kubectl instance.
+ plane *ControlPlane
+
+ // kubectl is our existing, provisioned kubectl. We don't provision one
+ // till someone actually asks for it.
+ kubectl *KubeCtl
+}
+
+// Config returns the REST config that can be used to connect to the API server
+// as this user.
+//
+// Will panic if used before the API server is started.
+func (u *AuthenticatedUser) Config() *rest.Config {
+ // NB(directxman12): we choose to panic here for ergonomics sake, and because there's
+ // not really much you can do to "handle" this error. This machinery is intended to be
+ // used in tests anyway, so panicing is not a particularly big deal.
+ if u.cfgIsComplete {
+ return u.cfg
+ }
+ if len(u.plane.APIServer.SecureServing.CA) == 0 {
+ panic("the API server has not yet been started, please do that before accessing connection details")
+ }
+
+ u.cfg.CAData = u.plane.APIServer.SecureServing.CA
+ u.cfg.Host = u.plane.APIServer.SecureServing.URL("https", "/").String()
+ u.cfgIsComplete = true
+ return u.cfg
+}
+
+// KubeConfig returns a KubeConfig that's roughly equivalent to this user's REST config.
+//
+// Will panic if used before the API server is started.
+func (u AuthenticatedUser) KubeConfig() ([]byte, error) {
+ // NB(directxman12): we don't return the actual API object to avoid yet another
+ // piece of kubernetes API in our public API, and also because generally the thing
+ // you want to do with this is just write it out to a file for external debugging
+ // purposes, etc.
+ return KubeConfigFromREST(u.Config())
+}
+
+// Kubectl returns a KubeCtl instance for talking to the API server as this user. It uses
+// a kubeconfig equivalent to that returned by .KubeConfig.
+//
+// Will panic if used before the API server is started.
+func (u *AuthenticatedUser) Kubectl() (*KubeCtl, error) {
+ if u.kubectl != nil {
+ return u.kubectl, nil
+ }
+ if len(u.plane.APIServer.CertDir) == 0 {
+ panic("the API server has not yet been started, please do that before accessing connection details")
+ }
+
+ // cleaning this up is handled when our tmpDir is deleted
+ out, err := os.CreateTemp(u.plane.APIServer.CertDir, "*.kubecfg")
+ if err != nil {
+ return nil, fmt.Errorf("unable to create file for kubeconfig: %w", err)
+ }
+ defer out.Close()
+ contents, err := KubeConfigFromREST(u.Config())
+ if err != nil {
+ return nil, err
+ }
+ if _, err := out.Write(contents); err != nil {
+ return nil, fmt.Errorf("unable to write kubeconfig to disk at %s: %w", out.Name(), err)
+ }
+ k := &KubeCtl{
+ Path: u.plane.KubectlPath,
+ }
+ k.Opts = append(k.Opts, fmt.Sprintf("--kubeconfig=%s", out.Name()))
+ u.kubectl = k
+ return k, nil
+}
+
+// AddUser provisions a new user in the cluster. It uses the APIServer's authentication
+// strategy -- see APIServer.SecureServing.Authn.
+//
+// Unlike AddUser, it's safe to pass a nil rest.Config here if you have no
+// particular opinions about the config.
+//
+// The default authentication strategy is not guaranteed to any specific strategy, but it is
+// guaranteed to be callable both before and after Start has been called (but, as noted in the
+// AuthenticatedUser docs, the given user objects are only valid after Start has been called).
+func (f *ControlPlane) AddUser(user User, baseConfig *rest.Config) (*AuthenticatedUser, error) {
+ if f.GetAPIServer().SecureServing.Authn == nil {
+ return nil, fmt.Errorf("no API server authentication is configured yet. The API server defaults one when Start is called, did you mean to use that?")
+ }
+
+ if baseConfig == nil {
+ baseConfig = &rest.Config{}
+ }
+ cfg, err := f.GetAPIServer().SecureServing.AddUser(user, baseConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ return &AuthenticatedUser{
+ cfg: cfg,
+ plane: f,
+ }, nil
+}
+
+// GetAPIServer returns this ControlPlane's APIServer, initializing it if necessary.
+func (f *ControlPlane) GetAPIServer() *APIServer {
+ if f.APIServer == nil {
+ f.APIServer = &APIServer{}
+ }
+ return f.APIServer
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/plane_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/plane_test.go
new file mode 100644
index 00000000000..cd0359dbca8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/plane_test.go
@@ -0,0 +1,109 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controlplane_test
+
+import (
+ "context"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ kauthn "k8s.io/api/authorization/v1"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ . "sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane"
+)
+
+var _ = Describe("Control Plane", func() {
+ It("should start and stop successfully with a default etcd & apiserver", func() {
+ plane := &ControlPlane{}
+ Expect(plane.Start()).To(Succeed())
+ Expect(plane.Stop()).To(Succeed())
+ })
+ It("should use the given etcd & apiserver when starting, if present", func() {
+ apiServer := &APIServer{}
+ etcd := &Etcd{}
+ plane := &ControlPlane{
+ APIServer: apiServer,
+ Etcd: etcd,
+ }
+ Expect(plane.Start()).To(Succeed())
+ defer func() { Expect(plane.Stop()).To(Succeed()) }()
+
+ Expect(plane.APIServer).To(BeIdenticalTo(apiServer))
+ Expect(plane.Etcd).To(BeIdenticalTo(etcd))
+ })
+
+ It("should be able to restart", func() {
+ // NB(directxman12): currently restarting invalidates all current users
+ // when using CertAuthn. We need to support restarting as per our previous
+ // contract, but it's not clear how much else we actually need to handle, or
+ // whether or not this is a safe operation.
+ plane := &ControlPlane{}
+ Expect(plane.Start()).To(Succeed())
+ Expect(plane.Stop()).To(Succeed())
+ Expect(plane.Start()).To(Succeed())
+ Expect(plane.Stop()).To(Succeed())
+ })
+
+ Context("after having started", func() {
+ var plane *ControlPlane
+ BeforeEach(func() {
+ plane = &ControlPlane{}
+ Expect(plane.Start()).To(Succeed())
+ })
+ AfterEach(func() {
+ Expect(plane.Stop()).To(Succeed())
+ })
+
+ It("should provision a working legacy user and legacy kubectl", func() {
+ By("grabbing the legacy kubectl")
+ Expect(plane.KubeCtl()).NotTo(BeNil())
+
+ By("grabbing the legacy REST config and testing it")
+ cfg, err := plane.RESTClientConfig()
+ Expect(err).NotTo(HaveOccurred(), "should be able to grab the legacy REST config")
+ cl, err := client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred(), "should be able to create a client")
+
+ sar := &kauthn.SelfSubjectAccessReview{
+ Spec: kauthn.SelfSubjectAccessReviewSpec{
+ ResourceAttributes: &kauthn.ResourceAttributes{
+ Verb: "*",
+ Group: "*",
+ Version: "*",
+ Resource: "*",
+ },
+ },
+ }
+ Expect(cl.Create(context.Background(), sar)).To(Succeed(), "should be able to make a Self-SAR")
+ Expect(sar.Status.Allowed).To(BeTrue(), "admin user should be able to do everything")
+ })
+
+ // TODO(directxman12): more explicit tests for AddUser -- it's tested indirectly via the
+ // legacy user flow, but we should be explicit
+
+ Describe("adding users", func() {
+ PIt("should be able to provision new users that have a corresponding REST config and & kubectl", func() {
+
+ })
+
+ PIt("should produce a default base REST config if none is given to add", func() {
+
+ })
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/testdata/fake-1.19-apiserver.sh b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/testdata/fake-1.19-apiserver.sh
new file mode 100755
index 00000000000..8b71661185d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/testdata/fake-1.19-apiserver.sh
@@ -0,0 +1,312 @@
+#!/usr/bin/env sh
+
+cat </=true|false for a specific API group and version (e.g. apps/v1=true)
+ api/all=true|false controls all API versions
+ api/ga=true|false controls all API versions of the form v[0-9]+
+ api/beta=true|false controls all API versions of the form v[0-9]+beta[0-9]+
+ api/alpha=true|false controls all API versions of the form v[0-9]+alpha[0-9]+
+ api/legacy is deprecated, and will be removed in a future version
+
+Egress selector flags:
+
+ --egress-selector-config-file string File with apiserver egress selector configuration.
+
+Admission flags:
+
+ --admission-control strings Admission is divided into two phases. In the first phase, only mutating admission plugins run. In the second phase, only validating admission plugins run. The names in the below list may represent a validating plugin, a mutating plugin, or both. The order of plugins in which they are passed to this flag does not matter. Comma-delimited list of: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyEscalatingExec, DenyExecOnPrivileged, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodPreset, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. (DEPRECATED: Use --enable-admission-plugins or --disable-admission-plugins instead. Will be removed in a future version.)
+ --admission-control-config-file string File with admission control configuration.
+ --disable-admission-plugins strings admission plugins that should be disabled although they are in the default enabled plugins list (NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota). Comma-delimited list of admission plugins: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyEscalatingExec, DenyExecOnPrivileged, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodPreset, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. The order of plugins in this flag does not matter.
+ --enable-admission-plugins strings admission plugins that should be enabled in addition to default enabled ones (NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota). Comma-delimited list of admission plugins: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyEscalatingExec, DenyExecOnPrivileged, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodPreset, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. The order of plugins in this flag does not matter.
+
+Metrics flags:
+
+ --show-hidden-metrics-for-version string The previous version for which you want to show hidden metrics. Only the previous minor version is meaningful, other values will not be allowed. The format is ., e.g.: '1.16'. The purpose of this format is make sure you have the opportunity to notice if the next release hides additional metrics, rather than being surprised when they are permanently removed in the release after that.
+
+Logs flags:
+
+ --logging-format string Sets the log format. Permitted formats: "json", "text".
+ Non-default formats don't honor these flags: --add_dir_header, --alsologtostderr, --log_backtrace_at, --log_dir, --log_file, --log_file_max_size, --logtostderr, --skip_headers, --skip_log_headers, --stderrthreshold, --vmodule, --log-flush-frequency.
+ Non-default choices are currently alpha and subject to change without warning. (default "text")
+
+Misc flags:
+
+ --allow-privileged If true, allow privileged containers. [default=false]
+ --apiserver-count int The number of apiservers running in the cluster, must be a positive number. (In use when --endpoint-reconciler-type=master-count is enabled.) (default 1)
+ --enable-aggregator-routing Turns on aggregator routing requests to endpoints IP rather than cluster IP.
+ --endpoint-reconciler-type string Use an endpoint reconciler (master-count, lease, none) (default "lease")
+ --event-ttl duration Amount of time to retain events. (default 1h0m0s)
+ --kubelet-certificate-authority string Path to a cert file for the certificate authority.
+ --kubelet-client-certificate string Path to a client cert file for TLS.
+ --kubelet-client-key string Path to a client key file for TLS.
+ --kubelet-preferred-address-types strings List of the preferred NodeAddressTypes to use for kubelet connections. (default [Hostname,InternalDNS,InternalIP,ExternalDNS,ExternalIP])
+ --kubelet-timeout duration Timeout for kubelet operations. (default 5s)
+ --kubernetes-service-node-port int If non-zero, the Kubernetes master service (which apiserver creates/maintains) will be of type NodePort, using this as the value of the port. If zero, the Kubernetes master service will be of type ClusterIP.
+ --max-connection-bytes-per-sec int If non-zero, throttle each user connection to this number of bytes/sec. Currently only applies to long-running requests.
+ --proxy-client-cert-file string Client certificate used to prove the identity of the aggregator or kube-apiserver when it must call out during a request. This includes proxying requests to a user api-server and calling out to webhook admission plugins. It is expected that this cert includes a signature from the CA in the --requestheader-client-ca-file flag. That CA is published in the 'extension-apiserver-authentication' configmap in the kube-system namespace. Components receiving calls from kube-aggregator should use that CA to perform their half of the mutual TLS verification.
+ --proxy-client-key-file string Private key for the client certificate used to prove the identity of the aggregator or kube-apiserver when it must call out during a request. This includes proxying requests to a user api-server and calling out to webhook admission plugins.
+ --service-account-signing-key-file string Path to the file that contains the current private key of the service account token issuer. The issuer will sign issued ID tokens with this private key. (Requires the 'TokenRequest' feature gate.)
+ --service-cluster-ip-range string A CIDR notation IP range from which to assign service cluster IPs. This must not overlap with any IP ranges assigned to nodes or pods.
+ --service-node-port-range portRange A port range to reserve for services with NodePort visibility. Example: '30000-32767'. Inclusive at both ends of the range. (default 30000-32767)
+
+Global flags:
+
+ --add-dir-header If true, adds the file directory to the header of the log messages
+ --alsologtostderr log to standard error as well as files
+ -h, --help help for kube-apiserver
+ --log-backtrace-at traceLocation when logging hits line file:N, emit a stack trace (default :0)
+ --log-dir string If non-empty, write log files in this directory
+ --log-file string If non-empty, use this log file
+ --log-file-max-size uint Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
+ --log-flush-frequency duration Maximum number of seconds between log flushes (default 5s)
+ --logtostderr log to standard error instead of files (default true)
+ --skip-headers If true, avoid header prefixes in the log messages
+ --skip-log-headers If true, avoid headers when opening log files
+ --stderrthreshold severity logs at or above this threshold go to stderr (default 2)
+ -v, --v Level number for the log level verbosity
+ --version version[=true] Print version information and quit
+ --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
+
+EOF
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/testdata/fake-1.20-apiserver.sh b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/testdata/fake-1.20-apiserver.sh
new file mode 100755
index 00000000000..112346cce6b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/testdata/fake-1.20-apiserver.sh
@@ -0,0 +1,318 @@
+#!/usr/bin/env sh
+
+cat </=true|false for a specific API group and version (e.g. apps/v1=true)
+ api/all=true|false controls all API versions
+ api/ga=true|false controls all API versions of the form v[0-9]+
+ api/beta=true|false controls all API versions of the form v[0-9]+beta[0-9]+
+ api/alpha=true|false controls all API versions of the form v[0-9]+alpha[0-9]+
+ api/legacy is deprecated, and will be removed in a future version
+
+Egress selector flags:
+
+ --egress-selector-config-file string File with apiserver egress selector configuration.
+
+Admission flags:
+
+ --admission-control strings Admission is divided into two phases. In the first phase, only mutating admission plugins run. In the second phase, only validating admission plugins run. The names in the below list may represent a validating plugin, a mutating plugin, or both. The order of plugins in which they are passed to this flag does not matter. Comma-delimited list of: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyEscalatingExec, DenyExecOnPrivileged, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. (DEPRECATED: Use --enable-admission-plugins or --disable-admission-plugins instead. Will be removed in a future version.)
+ --admission-control-config-file string File with admission control configuration.
+ --disable-admission-plugins strings admission plugins that should be disabled although they are in the default enabled plugins list (NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota). Comma-delimited list of admission plugins: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyEscalatingExec, DenyExecOnPrivileged, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. The order of plugins in this flag does not matter.
+ --enable-admission-plugins strings admission plugins that should be enabled in addition to default enabled ones (NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota). Comma-delimited list of admission plugins: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyEscalatingExec, DenyExecOnPrivileged, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. The order of plugins in this flag does not matter.
+
+Metrics flags:
+
+ --show-hidden-metrics-for-version string The previous version for which you want to show hidden metrics. Only the previous minor version is meaningful, other values will not be allowed. The format is ., e.g.: '1.16'. The purpose of this format is make sure you have the opportunity to notice if the next release hides additional metrics, rather than being surprised when they are permanently removed in the release after that.
+
+Logs flags:
+
+ --experimental-logging-sanitization [Experimental] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
+ Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.
+ --logging-format string Sets the log format. Permitted formats: "json", "text".
+ Non-default formats don't honor these flags: --add_dir_header, --alsologtostderr, --log_backtrace_at, --log_dir, --log_file, --log_file_max_size, --logtostderr, --one_output, --skip_headers, --skip_log_headers, --stderrthreshold, --vmodule, --log-flush-frequency.
+ Non-default choices are currently alpha and subject to change without warning. (default "text")
+
+Misc flags:
+
+ --allow-privileged If true, allow privileged containers. [default=false]
+ --apiserver-count int The number of apiservers running in the cluster, must be a positive number. (In use when --endpoint-reconciler-type=master-count is enabled.) (default 1)
+ --enable-aggregator-routing Turns on aggregator routing requests to endpoints IP rather than cluster IP.
+ --endpoint-reconciler-type string Use an endpoint reconciler (master-count, lease, none) (default "lease")
+ --event-ttl duration Amount of time to retain events. (default 1h0m0s)
+ --identity-lease-duration-seconds int The duration of kube-apiserver lease in seconds, must be a positive number. (In use when the APIServerIdentity feature gate is enabled.) (default 3600)
+ --identity-lease-renew-interval-seconds int The interval of kube-apiserver renewing its lease in seconds, must be a positive number. (In use when the APIServerIdentity feature gate is enabled.) (default 10)
+ --kubelet-certificate-authority string Path to a cert file for the certificate authority.
+ --kubelet-client-certificate string Path to a client cert file for TLS.
+ --kubelet-client-key string Path to a client key file for TLS.
+ --kubelet-preferred-address-types strings List of the preferred NodeAddressTypes to use for kubelet connections. (default [Hostname,InternalDNS,InternalIP,ExternalDNS,ExternalIP])
+ --kubelet-timeout duration Timeout for kubelet operations. (default 5s)
+ --kubernetes-service-node-port int If non-zero, the Kubernetes master service (which apiserver creates/maintains) will be of type NodePort, using this as the value of the port. If zero, the Kubernetes master service will be of type ClusterIP.
+ --max-connection-bytes-per-sec int If non-zero, throttle each user connection to this number of bytes/sec. Currently only applies to long-running requests.
+ --proxy-client-cert-file string Client certificate used to prove the identity of the aggregator or kube-apiserver when it must call out during a request. This includes proxying requests to a user api-server and calling out to webhook admission plugins. It is expected that this cert includes a signature from the CA in the --requestheader-client-ca-file flag. That CA is published in the 'extension-apiserver-authentication' configmap in the kube-system namespace. Components receiving calls from kube-aggregator should use that CA to perform their half of the mutual TLS verification.
+ --proxy-client-key-file string Private key for the client certificate used to prove the identity of the aggregator or kube-apiserver when it must call out during a request. This includes proxying requests to a user api-server and calling out to webhook admission plugins.
+ --service-account-signing-key-file string Path to the file that contains the current private key of the service account token issuer. The issuer will sign issued ID tokens with this private key.
+ --service-cluster-ip-range string A CIDR notation IP range from which to assign service cluster IPs. This must not overlap with any IP ranges assigned to nodes or pods.
+ --service-node-port-range portRange A port range to reserve for services with NodePort visibility. Example: '30000-32767'. Inclusive at both ends of the range. (default 30000-32767)
+
+Global flags:
+
+ --add-dir-header If true, adds the file directory to the header of the log messages
+ --alsologtostderr log to standard error as well as files
+ -h, --help help for kube-apiserver
+ --log-backtrace-at traceLocation when logging hits line file:N, emit a stack trace (default :0)
+ --log-dir string If non-empty, write log files in this directory
+ --log-file string If non-empty, use this log file
+ --log-file-max-size uint Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
+ --log-flush-frequency duration Maximum number of seconds between log flushes (default 5s)
+ --logtostderr log to standard error instead of files (default true)
+ --one-output If true, only write logs to their native severity level (vs also writing to each lower severity level
+ --skip-headers If true, avoid header prefixes in the log messages
+ --skip-log-headers If true, avoid headers when opening log files
+ --stderrthreshold severity logs at or above this threshold go to stderr (default 2)
+ -v, --v Level number for the log level verbosity
+ --version version[=true] Print version information and quit
+ --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
+EOF
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/arguments.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/arguments.go
new file mode 100644
index 00000000000..391eec1facf
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/arguments.go
@@ -0,0 +1,340 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package process
+
+import (
+ "bytes"
+ "html/template"
+ "sort"
+ "strings"
+)
+
+// RenderTemplates returns an []string to render the templates
+//
+// Deprecated: will be removed in favor of Arguments.
+func RenderTemplates(argTemplates []string, data interface{}) (args []string, err error) {
+ var t *template.Template
+
+ for _, arg := range argTemplates {
+ t, err = template.New(arg).Parse(arg)
+ if err != nil {
+ args = nil
+ return
+ }
+
+ buf := &bytes.Buffer{}
+ err = t.Execute(buf, data)
+ if err != nil {
+ args = nil
+ return
+ }
+ args = append(args, buf.String())
+ }
+
+ return
+}
+
+// SliceToArguments converts a slice of arguments to structured arguments,
+// appending each argument that starts with `--` and contains an `=` to the
+// argument set (ignoring defaults), returning the rest.
+//
+// Deprecated: will be removed when RenderTemplates is removed.
+func SliceToArguments(sliceArgs []string, args *Arguments) []string {
+ var rest []string
+ for i, arg := range sliceArgs {
+ if arg == "--" {
+ rest = append(rest, sliceArgs[i:]...)
+ return rest
+ }
+ // skip non-flag arguments, skip arguments w/o equals because we
+ // can't tell if the next argument should take a value
+ if !strings.HasPrefix(arg, "--") || !strings.Contains(arg, "=") {
+ rest = append(rest, arg)
+ continue
+ }
+
+ parts := strings.SplitN(arg[2:], "=", 2)
+ name := parts[0]
+ val := parts[1]
+
+ args.AppendNoDefaults(name, val)
+ }
+
+ return rest
+}
+
+// TemplateDefaults specifies defaults to be used for joining structured arguments with templates.
+//
+// Deprecated: will be removed when RenderTemplates is removed.
+type TemplateDefaults struct {
+ // Data will be used to render the template.
+ Data interface{}
+ // Defaults will be used to default structured arguments if no template is passed.
+ Defaults map[string][]string
+ // MinimalDefaults will be used to default structured arguments if a template is passed.
+ // Use this for flags which *must* be present.
+ MinimalDefaults map[string][]string // for api server service-cluster-ip-range
+}
+
+// TemplateAndArguments joins structured arguments and non-structured arguments, preserving existing
+// behavior. Namely:
+//
+// 1. if templ has len > 0, it will be rendered against data
+// 2. the rendered template values that look like `--foo=bar` will be split
+// and appended to args, the rest will be kept around
+// 3. the given args will be rendered as string form. If a template is given,
+// no defaults will be used, otherwise defaults will be used
+// 4. a result of [args..., rest...] will be returned
+//
+// It returns the resulting rendered arguments, plus the arguments that were
+// not transferred to `args` during rendering.
+//
+// Deprecated: will be removed when RenderTemplates is removed.
+func TemplateAndArguments(templ []string, args *Arguments, data TemplateDefaults) (allArgs []string, nonFlagishArgs []string, err error) {
+ if len(templ) == 0 { // 3 & 4 (no template case)
+ return args.AsStrings(data.Defaults), nil, nil
+ }
+
+ // 1: render the template
+ rendered, err := RenderTemplates(templ, data.Data)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // 2: filter out structured args and add them to args
+ rest := SliceToArguments(rendered, args)
+
+ // 3 (template case): render structured args, no defaults (matching the
+ // legacy case where if Args was specified, no defaults were used)
+ res := args.AsStrings(data.MinimalDefaults)
+
+ // 4: return the rendered structured args + all non-structured args
+ return append(res, rest...), rest, nil
+}
+
+// EmptyArguments constructs an empty set of flags with no defaults.
+func EmptyArguments() *Arguments {
+ return &Arguments{
+ values: make(map[string]Arg),
+ }
+}
+
+// Arguments are structured, overridable arguments.
+// Each Arguments object contains some set of default arguments, which may
+// be appended to, or overridden.
+//
+// When ready, you can serialize them to pass to exec.Command and friends using
+// AsStrings.
+//
+// All flag-setting methods return the *same* instance of Arguments so that you
+// can chain calls.
+type Arguments struct {
+ // values contains the user-set values for the arguments.
+ // `values[key] = dontPass` means "don't pass this flag"
+ // `values[key] = passAsName` means "pass this flag without args like --key`
+ // `values[key] = []string{a, b, c}` means "--key=a --key=b --key=c`
+ // any values not explicitly set here will be copied from defaults on final rendering.
+ values map[string]Arg
+}
+
+// Arg is an argument that has one or more values,
+// and optionally falls back to default values.
+type Arg interface {
+ // Append adds new values to this argument, returning
+ // a new instance contain the new value. The intermediate
+ // argument should generally be assumed to be consumed.
+ Append(vals ...string) Arg
+ // Get returns the full set of values, optionally including
+ // the passed in defaults. If it returns nil, this will be
+ // skipped. If it returns a non-nil empty slice, it'll be
+ // assumed that the argument should be passed as name-only.
+ Get(defaults []string) []string
+}
+
+type userArg []string
+
+func (a userArg) Append(vals ...string) Arg {
+ return userArg(append(a, vals...)) //nolint:unconvert
+}
+func (a userArg) Get(_ []string) []string {
+ return []string(a)
+}
+
+type defaultedArg []string
+
+func (a defaultedArg) Append(vals ...string) Arg {
+ return defaultedArg(append(a, vals...)) //nolint:unconvert
+}
+func (a defaultedArg) Get(defaults []string) []string {
+ res := append([]string(nil), defaults...)
+ return append(res, a...)
+}
+
+type dontPassArg struct{}
+
+func (a dontPassArg) Append(vals ...string) Arg {
+ return userArg(vals)
+}
+func (dontPassArg) Get(_ []string) []string {
+ return nil
+}
+
+type passAsNameArg struct{}
+
+func (a passAsNameArg) Append(_ ...string) Arg {
+ return passAsNameArg{}
+}
+func (passAsNameArg) Get(_ []string) []string {
+ return []string{}
+}
+
+var (
+ // DontPass indicates that the given argument will not actually be
+ // rendered.
+ DontPass Arg = dontPassArg{}
+ // PassAsName indicates that the given flag will be passed as `--key`
+ // without any value.
+ PassAsName Arg = passAsNameArg{}
+)
+
+// AsStrings serializes this set of arguments to a slice of strings appropriate
+// for passing to exec.Command and friends, making use of the given defaults
+// as indicated for each particular argument.
+//
+// - Any flag in defaults that's not in Arguments will be present in the output
+// - Any flag that's present in Arguments will be passed the corresponding
+// defaults to do with as it will (ignore, append-to, suppress, etc).
+func (a *Arguments) AsStrings(defaults map[string][]string) []string {
+ // sort for deterministic ordering
+ keysInOrder := make([]string, 0, len(defaults)+len(a.values))
+ for key := range defaults {
+ if _, userSet := a.values[key]; userSet {
+ continue
+ }
+ keysInOrder = append(keysInOrder, key)
+ }
+ for key := range a.values {
+ keysInOrder = append(keysInOrder, key)
+ }
+ sort.Strings(keysInOrder)
+
+ var res []string
+ for _, key := range keysInOrder {
+ vals := a.Get(key).Get(defaults[key])
+ switch {
+ case vals == nil: // don't pass
+ continue
+ case len(vals) == 0: // pass as name
+ res = append(res, "--"+key)
+ default:
+ for _, val := range vals {
+ res = append(res, "--"+key+"="+val)
+ }
+ }
+ }
+
+ return res
+}
+
+// Get returns the value of the given flag. If nil,
+// it will not be passed in AsString, otherwise:
+//
+// len == 0 --> `--key`, len > 0 --> `--key=val1 --key=val2 ...`.
+func (a *Arguments) Get(key string) Arg {
+ if vals, ok := a.values[key]; ok {
+ return vals
+ }
+ return defaultedArg(nil)
+}
+
+// Enable configures the given key to be passed as a "name-only" flag,
+// like, `--key`.
+func (a *Arguments) Enable(key string) *Arguments {
+ a.values[key] = PassAsName
+ return a
+}
+
+// Disable prevents this flag from be passed.
+func (a *Arguments) Disable(key string) *Arguments {
+ a.values[key] = DontPass
+ return a
+}
+
+// Append adds additional values to this flag. If this flag has
+// yet to be set, initial values will include defaults. If you want
+// to intentionally ignore defaults/start from scratch, call AppendNoDefaults.
+//
+// Multiple values will look like `--key=value1 --key=value2 ...`.
+func (a *Arguments) Append(key string, values ...string) *Arguments {
+ vals, present := a.values[key]
+ if !present {
+ vals = defaultedArg{}
+ }
+ a.values[key] = vals.Append(values...)
+ return a
+}
+
+// AppendNoDefaults adds additional values to this flag. However,
+// unlike Append, it will *not* copy values from defaults.
+func (a *Arguments) AppendNoDefaults(key string, values ...string) *Arguments {
+ vals, present := a.values[key]
+ if !present {
+ vals = userArg{}
+ }
+ a.values[key] = vals.Append(values...)
+ return a
+}
+
+// Set resets the given flag to the specified values, ignoring any existing
+// values or defaults.
+func (a *Arguments) Set(key string, values ...string) *Arguments {
+ a.values[key] = userArg(values)
+ return a
+}
+
+// SetRaw sets the given flag to the given Arg value directly. Use this if
+// you need to do some complicated deferred logic or something.
+//
+// Otherwise behaves like Set.
+func (a *Arguments) SetRaw(key string, val Arg) *Arguments {
+ a.values[key] = val
+ return a
+}
+
+// FuncArg is a basic implementation of Arg that can be used for custom argument logic,
+// like pulling values out of APIServer, or dynamically calculating values just before
+// launch.
+//
+// The given function will be mapped directly to Arg#Get, and will generally be
+// used in conjunction with SetRaw. For example, to set `--some-flag` to the
+// API server's CertDir, you could do:
+//
+// server.Configure().SetRaw("--some-flag", FuncArg(func(defaults []string) []string {
+// return []string{server.CertDir}
+// }))
+//
+// FuncArg ignores Appends; if you need to support appending values too, consider implementing
+// Arg directly.
+type FuncArg func([]string) []string
+
+// Append is a no-op for FuncArg, and just returns itself.
+func (a FuncArg) Append(vals ...string) Arg { return a }
+
+// Get delegates functionality to the FuncArg function itself.
+func (a FuncArg) Get(defaults []string) []string {
+ return a(defaults)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/arguments_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/arguments_test.go
new file mode 100644
index 00000000000..b513cbdf86a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/arguments_test.go
@@ -0,0 +1,346 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package process_test
+
+import (
+ "net/url"
+ "strings"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ . "sigs.k8s.io/controller-runtime/pkg/internal/testing/process"
+)
+
+var _ = Describe("Arguments Templates", func() {
+ It("templates URLs", func() {
+ templates := []string{
+ "plain URL: {{ .SomeURL }}",
+ "method on URL: {{ .SomeURL.Hostname }}",
+ "empty URL: {{ .EmptyURL }}",
+ "handled empty URL: {{- if .EmptyURL }}{{ .EmptyURL }}{{ end }}",
+ }
+ data := struct {
+ SomeURL *url.URL
+ EmptyURL *url.URL
+ }{
+ &url.URL{Scheme: "https", Host: "the.host.name:3456"},
+ nil,
+ }
+
+ out, err := RenderTemplates(templates, data)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(out).To(BeEquivalentTo([]string{
+ "plain URL: https://the.host.name:3456",
+ "method on URL: the.host.name",
+ "empty URL: <nil>",
+ "handled empty URL:",
+ }))
+ })
+
+ It("templates strings", func() {
+ templates := []string{
+ "a string: {{ .SomeString }}",
+ "empty string: {{- .EmptyString }}",
+ }
+ data := struct {
+ SomeString string
+ EmptyString string
+ }{
+ "this is some random string",
+ "",
+ }
+
+ out, err := RenderTemplates(templates, data)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(out).To(BeEquivalentTo([]string{
+ "a string: this is some random string",
+ "empty string:",
+ }))
+ })
+
+ It("has no access to unexported fields", func() {
+ templates := []string{
+ "this is just a string",
+ "this blows up {{ .test }}",
+ }
+ data := struct{ test string }{"ooops private"}
+
+ out, err := RenderTemplates(templates, data)
+ Expect(out).To(BeEmpty())
+ Expect(err).To(MatchError(
+ ContainSubstring("is an unexported field of struct"),
+ ))
+ })
+
+ It("errors when field cannot be found", func() {
+ templates := []string{"this does {{ .NotExist }}"}
+ data := struct{ Unused string }{"unused"}
+
+ out, err := RenderTemplates(templates, data)
+ Expect(out).To(BeEmpty())
+ Expect(err).To(MatchError(
+ ContainSubstring("can't evaluate field"),
+ ))
+ })
+
+ Context("when joining with structured Arguments", func() {
+ var (
+ args *Arguments
+ templ = []string{
+ "--cheese=parmesean",
+ "-om",
+ "nom nom nom",
+ "--sharpness={{ .sharpness }}",
+ }
+ data = TemplateDefaults{
+ Data: map[string]string{"sharpness": "extra"},
+ Defaults: map[string][]string{
+ "cracker": {"ritz"},
+ "pickle": {"kosher-dill"},
+ },
+ MinimalDefaults: map[string][]string{
+ "pickle": {"kosher-dill"},
+ },
+ }
+ )
+ BeforeEach(func() {
+ args = EmptyArguments()
+ })
+
+ Context("when a template is given", func() {
+ It("should use minimal defaults", func() {
+ all, _, err := TemplateAndArguments(templ, args, data)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(all).To(SatisfyAll(
+ Not(ContainElement("--cracker=ritz")),
+ ContainElement("--pickle=kosher-dill"),
+ ))
+ })
+
+ It("should render the template against the data", func() {
+ all, _, err := TemplateAndArguments(templ, args, data)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(all).To(ContainElements(
+ "--sharpness=extra",
+ ))
+ })
+
+ It("should append the rendered template to structured arguments", func() {
+ args.Append("cheese", "cheddar")
+
+ all, _, err := TemplateAndArguments(templ, args, data)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(all).To(Equal([]string{
+ "--cheese=cheddar",
+ "--cheese=parmesean",
+ "--pickle=kosher-dill",
+ "--sharpness=extra",
+ "-om",
+ "nom nom nom",
+ }))
+ })
+
+ It("should indicate which arguments were not able to be converted to structured flags", func() {
+ _, rest, err := TemplateAndArguments(templ, args, data)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(rest).To(Equal([]string{"-om", "nom nom nom"}))
+
+ })
+ })
+
+ Context("when no template is given", func() {
+ It("should render the structured arguments with the given defaults", func() {
+ args.
+ Append("cheese", "cheddar", "parmesean").
+ Append("cracker", "triscuit")
+
+ Expect(TemplateAndArguments(nil, args, data)).To(Equal([]string{
+ "--cheese=cheddar",
+ "--cheese=parmesean",
+ "--cracker=ritz",
+ "--cracker=triscuit",
+ "--pickle=kosher-dill",
+ }))
+ })
+ })
+ })
+
+ Context("when converting to structured Arguments", func() {
+ var args *Arguments
+ BeforeEach(func() {
+ args = EmptyArguments()
+ })
+
+ It("should skip arguments that don't start with `--`", func() {
+ rest := SliceToArguments([]string{"-first", "second", "--foo=bar"}, args)
+ Expect(rest).To(Equal([]string{"-first", "second"}))
+ Expect(args.AsStrings(nil)).To(Equal([]string{"--foo=bar"}))
+ })
+
+ It("should skip arguments that don't contain an `=` because they're ambiguous", func() {
+ rest := SliceToArguments([]string{"--first", "--second", "--foo=bar"}, args)
+ Expect(rest).To(Equal([]string{"--first", "--second"}))
+ Expect(args.AsStrings(nil)).To(Equal([]string{"--foo=bar"}))
+ })
+
+ It("should stop at the flag terminator (`--`)", func() {
+ rest := SliceToArguments([]string{"--first", "--second", "--", "--foo=bar"}, args)
+ Expect(rest).To(Equal([]string{"--first", "--second", "--", "--foo=bar"}))
+ Expect(args.AsStrings(nil)).To(BeEmpty())
+ })
+
+ It("should split --foo=bar into Append(foo, bar)", func() {
+ rest := SliceToArguments([]string{"--foo=bar1", "--foo=bar2"}, args)
+ Expect(rest).To(BeEmpty())
+ Expect(args.Get("foo").Get(nil)).To(Equal([]string{"bar1", "bar2"}))
+ })
+
+ It("should split --foo=bar=baz into Append(foo, bar=baz)", func() {
+ rest := SliceToArguments([]string{"--vmodule=file.go=3", "--vmodule=other.go=4"}, args)
+ Expect(rest).To(BeEmpty())
+ Expect(args.Get("vmodule").Get(nil)).To(Equal([]string{"file.go=3", "other.go=4"}))
+ })
+
+ It("should append to existing arguments", func() {
+ args.Append("foo", "barA")
+ rest := SliceToArguments([]string{"--foo=bar1", "--foo=bar2"}, args)
+ Expect(rest).To(BeEmpty())
+ Expect(args.Get("foo").Get([]string{"barI"})).To(Equal([]string{"barI", "barA", "bar1", "bar2"}))
+ })
+ })
+})
+
+var _ = Describe("Arguments", func() {
+ Context("when appending", func() {
+ It("should copy from defaults when appending for the first time", func() {
+ args := EmptyArguments().
+ Append("some-key", "val3")
+ Expect(args.Get("some-key").Get([]string{"val1", "val2"})).To(Equal([]string{"val1", "val2", "val3"}))
+ })
+
+ It("should not copy from defaults if the flag has been disabled previously", func() {
+ args := EmptyArguments().
+ Disable("some-key").
+ Append("some-key", "val3")
+ Expect(args.Get("some-key").Get([]string{"val1", "val2"})).To(Equal([]string{"val3"}))
+ })
+
+ It("should only copy defaults the first time", func() {
+ args := EmptyArguments().
+ Append("some-key", "val3", "val4").
+ Append("some-key", "val5")
+ Expect(args.Get("some-key").Get([]string{"val1", "val2"})).To(Equal([]string{"val1", "val2", "val3", "val4", "val5"}))
+ })
+
+ It("should not copy from defaults if the flag has been previously overridden", func() {
+ args := EmptyArguments().
+ Set("some-key", "vala").
+ Append("some-key", "valb", "valc")
+ Expect(args.Get("some-key").Get([]string{"val1", "val2"})).To(Equal([]string{"vala", "valb", "valc"}))
+ })
+
+ Context("when explicitly overriding defaults", func() {
+ It("should not copy from defaults, but should append to previous calls", func() {
+ args := EmptyArguments().
+ AppendNoDefaults("some-key", "vala").
+ AppendNoDefaults("some-key", "valb", "valc")
+ Expect(args.Get("some-key").Get([]string{"val1", "val2"})).To(Equal([]string{"vala", "valb", "valc"}))
+ })
+
+ It("should not copy from defaults, but should respect previous appends' copies", func() {
+ args := EmptyArguments().
+ Append("some-key", "vala").
+ AppendNoDefaults("some-key", "valb", "valc")
+ Expect(args.Get("some-key").Get([]string{"val1", "val2"})).To(Equal([]string{"val1", "val2", "vala", "valb", "valc"}))
+ })
+
+ It("should not copy from defaults if the flag has been previously appended to ignoring defaults", func() {
+ args := EmptyArguments().
+ AppendNoDefaults("some-key", "vala").
+ Append("some-key", "valb", "valc")
+ Expect(args.Get("some-key").Get([]string{"val1", "val2"})).To(Equal([]string{"vala", "valb", "valc"}))
+ })
+ })
+ })
+
+ It("should ignore defaults when overriding", func() {
+ args := EmptyArguments().
+ Set("some-key", "vala")
+ Expect(args.Get("some-key").Get([]string{"val1", "val2"})).To(Equal([]string{"vala"}))
+ })
+
+ It("should allow directly setting the argument value for custom argument types", func() {
+ args := EmptyArguments().
+ SetRaw("custom-key", commaArg{"val3"}).
+ Append("custom-key", "val4")
+ Expect(args.Get("custom-key").Get([]string{"val1", "val2"})).To(Equal([]string{"val1,val2,val3,val4"}))
+ })
+
+ Context("when rendering flags", func() {
+ It("should not render defaults for disabled flags", func() {
+ defs := map[string][]string{
+ "some-key": {"val1", "val2"},
+ "other-key": {"val"},
+ }
+ args := EmptyArguments().
+ Disable("some-key")
+ Expect(args.AsStrings(defs)).To(ConsistOf("--other-key=val"))
+ })
+
+ It("should render name-only flags as --key", func() {
+ args := EmptyArguments().
+ Enable("some-key")
+ Expect(args.AsStrings(nil)).To(ConsistOf("--some-key"))
+ })
+
+ It("should render multiple values as --key=val1, --key=val2", func() {
+ args := EmptyArguments().
+ Append("some-key", "val1", "val2").
+ Append("other-key", "vala", "valb")
+ Expect(args.AsStrings(nil)).To(ConsistOf("--other-key=valb", "--other-key=vala", "--some-key=val1", "--some-key=val2"))
+ })
+
+ It("should read from defaults if the user hasn't set a value for a flag", func() {
+ defs := map[string][]string{
+ "some-key": {"val1", "val2"},
+ }
+ args := EmptyArguments().
+ Append("other-key", "vala", "valb")
+ Expect(args.AsStrings(defs)).To(ConsistOf("--other-key=valb", "--other-key=vala", "--some-key=val1", "--some-key=val2"))
+ })
+
+ It("should not render defaults if the user has set a value for a flag", func() {
+ defs := map[string][]string{
+ "some-key": {"val1", "val2"},
+ }
+ args := EmptyArguments().
+ Set("some-key", "vala")
+ Expect(args.AsStrings(defs)).To(ConsistOf("--some-key=vala"))
+ })
+ })
+})
+
+type commaArg []string
+
+func (a commaArg) Get(defs []string) []string {
+ // not quite, but close enough
+ return []string{strings.Join(defs, ",") + "," + strings.Join(a, ",")}
+}
+func (a commaArg) Append(vals ...string) Arg {
+ return commaArg(append(a, vals...)) //nolint:unconvert
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/bin_path_finder.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/bin_path_finder.go
new file mode 100644
index 00000000000..e1428aa6e5a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/bin_path_finder.go
@@ -0,0 +1,70 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package process
+
+import (
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+)
+
+const (
+ // EnvAssetsPath is the environment variable that stores the global test
+ // binary location override.
+ EnvAssetsPath = "KUBEBUILDER_ASSETS"
+ // EnvAssetOverridePrefix is the environment variable prefix for per-binary
+ // location overrides.
+ EnvAssetOverridePrefix = "TEST_ASSET_"
+ // AssetsDefaultPath is the default location to look for test binaries in,
+ // if no override was provided.
+ AssetsDefaultPath = "/usr/local/kubebuilder/bin"
+)
+
+// BinPathFinder finds the path to the given named binary, using the following locations
+// in order of precedence (highest first). Notice that the various env vars only need
+// to be set -- the asset is not checked for existence on the filesystem.
+//
+// 1. TEST_ASSET_{tr/a-z-/A-Z_/} (if set; asset overrides -- EnvAssetOverridePrefix)
+// 1. KUBEBUILDER_ASSETS (if set; global asset path -- EnvAssetsPath)
+// 3. assetDirectory (if set; per-config asset directory)
+// 4. /usr/local/kubebuilder/bin (AssetsDefaultPath).
+func BinPathFinder(symbolicName, assetDirectory string) (binPath string) {
+ punctuationPattern := regexp.MustCompile("[^A-Z0-9]+")
+ sanitizedName := punctuationPattern.ReplaceAllString(strings.ToUpper(symbolicName), "_")
+ leadingNumberPattern := regexp.MustCompile("^[0-9]+")
+ sanitizedName = leadingNumberPattern.ReplaceAllString(sanitizedName, "")
+ envVar := EnvAssetOverridePrefix + sanitizedName
+
+ // TEST_ASSET_XYZ
+ if val, ok := os.LookupEnv(envVar); ok {
+ return val
+ }
+
+ // KUBEBUILDER_ASSETS
+ if val, ok := os.LookupEnv(EnvAssetsPath); ok {
+ return filepath.Join(val, symbolicName)
+ }
+
+ // assetDirectory
+ if assetDirectory != "" {
+ return filepath.Join(assetDirectory, symbolicName)
+ }
+
+ // default path
+ return filepath.Join(AssetsDefaultPath, symbolicName)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/bin_path_finder_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/bin_path_finder_test.go
new file mode 100644
index 00000000000..1b159418402
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/bin_path_finder_test.go
@@ -0,0 +1,76 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package process
+
+import (
+ "os"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("BinPathFinder", func() {
+ var prevAssetPath string
+ BeforeEach(func() {
+ prevAssetPath = os.Getenv(EnvAssetsPath)
+ Expect(os.Unsetenv(EnvAssetsPath)).To(Succeed())
+ Expect(os.Unsetenv(EnvAssetOverridePrefix + "_SOME_FAKE"))
+ Expect(os.Unsetenv(EnvAssetOverridePrefix + "OTHERFAKE"))
+ })
+ AfterEach(func() {
+ if prevAssetPath != "" {
+ Expect(os.Setenv(EnvAssetsPath, prevAssetPath))
+ }
+ })
+ Context("when individual overrides are present", func() {
+ BeforeEach(func() {
+ Expect(os.Setenv(EnvAssetOverridePrefix+"OTHERFAKE", "/other/path")).To(Succeed())
+ Expect(os.Setenv(EnvAssetOverridePrefix+"_SOME_FAKE", "/some/path")).To(Succeed())
+ // set the global path to make sure we don't prefer it
+ Expect(os.Setenv(EnvAssetsPath, "/global/path")).To(Succeed())
+ })
+
+ It("should prefer individual overrides, using them unmodified", func() {
+ Expect(BinPathFinder("otherfake", "/hardcoded/path")).To(Equal("/other/path"))
+ })
+
+ It("should convert lowercase to uppercase, remove leading numbers, and replace punctuation with underscores when resolving the env var name", func() {
+ Expect(BinPathFinder("123.some-fake", "/hardcoded/path")).To(Equal("/some/path"))
+ })
+ })
+
+ Context("when individual overrides are missing but the global override is present", func() {
+ BeforeEach(func() {
+ Expect(os.Setenv(EnvAssetsPath, "/global/path")).To(Succeed())
+ })
+ It("should prefer the global override, appending the name to that path", func() {
+ Expect(BinPathFinder("some-fake", "/hardcoded/path")).To(Equal("/global/path/some-fake"))
+ })
+ })
+
+ Context("when an asset directory is given and no overrides are present", func() {
+ It("should use the asset directory, appending the name to that path", func() {
+ Expect(BinPathFinder("some-fake", "/hardcoded/path")).To(Equal("/hardcoded/path/some-fake"))
+ })
+ })
+
+ Context("when no path configuration is given", func() {
+ It("should just use the default path", func() {
+ Expect(BinPathFinder("some-fake", "")).To(Equal("/usr/local/kubebuilder/bin/some-fake"))
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process.go
new file mode 100644
index 00000000000..af83c70a2fa
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process.go
@@ -0,0 +1,272 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package process
+
+import (
+ "crypto/tls"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "os/exec"
+ "path"
+ "regexp"
+ "sync"
+ "syscall"
+ "time"
+)
+
+// ListenAddr represents some listening address and port.
+type ListenAddr struct {
+ Address string
+ Port string
+}
+
+// URL returns a URL for this address with the given scheme and subpath.
+func (l *ListenAddr) URL(scheme string, path string) *url.URL {
+ return &url.URL{
+ Scheme: scheme,
+ Host: l.HostPort(),
+ Path: path,
+ }
+}
+
+// HostPort returns the joined host-port pair for this address.
+func (l *ListenAddr) HostPort() string {
+ return net.JoinHostPort(l.Address, l.Port)
+}
+
+// HealthCheck describes the information needed to health-check a process via
+// some health-check URL.
+type HealthCheck struct {
+ url.URL
+
+ // HealthCheckPollInterval is the interval which will be used for polling the
+ // endpoint described by Host, Port, and Path.
+ //
+ // If left empty it will default to 100 Milliseconds.
+ PollInterval time.Duration
+}
+
+// State define the state of the process.
+type State struct {
+ Cmd *exec.Cmd
+
+ // HealthCheck describes how to check if this process is up. If we get an http.StatusOK,
+ // we assume the process is ready to operate.
+ //
+ // For example, the /healthz endpoint of the k8s API server, or the /health endpoint of etcd.
+ HealthCheck HealthCheck
+
+ Args []string
+
+ StopTimeout time.Duration
+ StartTimeout time.Duration
+
+ Dir string
+ DirNeedsCleaning bool
+ Path string
+
+ // ready holds whether the process is currently in ready state (hit the ready condition) or not.
+ // It will be set to true on a successful `Start()` and set to false on a successful `Stop()`
+ ready bool
+
+ // waitDone is closed when our call to wait finishes up, and indicates that
+ // our process has terminated.
+ waitDone chan struct{}
+ errMu sync.Mutex
+ exitErr error
+ exited bool
+}
+
+// Init sets up this process, configuring binary paths if missing, initializing
+// temporary directories, etc.
+//
+// This defaults all defaultable fields.
+func (ps *State) Init(name string) error {
+ if ps.Path == "" {
+ if name == "" {
+ return fmt.Errorf("must have at least one of name or path")
+ }
+ ps.Path = BinPathFinder(name, "")
+ }
+
+ if ps.Dir == "" {
+ newDir, err := os.MkdirTemp("", "k8s_test_framework_")
+ if err != nil {
+ return err
+ }
+ ps.Dir = newDir
+ ps.DirNeedsCleaning = true
+ }
+
+ if ps.StartTimeout == 0 {
+ ps.StartTimeout = 20 * time.Second
+ }
+
+ if ps.StopTimeout == 0 {
+ ps.StopTimeout = 20 * time.Second
+ }
+ return nil
+}
+
+type stopChannel chan struct{}
+
+// CheckFlag checks the help output of this command for the presence of the given flag, specified
+// without the leading `--` (e.g. `CheckFlag("insecure-port")` checks for `--insecure-port`),
+// returning true if the flag is present.
+func (ps *State) CheckFlag(flag string) (bool, error) {
+ cmd := exec.Command(ps.Path, "--help")
+ outContents, err := cmd.CombinedOutput()
+ if err != nil {
+ return false, fmt.Errorf("unable to run command %q to check for flag %q: %w", ps.Path, flag, err)
+ }
+ pat := `(?m)^\s*--` + flag + `\b` // (m --> multi-line --> ^ matches start of line)
+ matched, err := regexp.Match(pat, outContents)
+ if err != nil {
+ return false, fmt.Errorf("unable to check command %q for flag %q in help output: %w", ps.Path, flag, err)
+ }
+ return matched, nil
+}
+
+// Start starts the apiserver, waits for it to come up, and returns an error,
+// if occurred.
+func (ps *State) Start(stdout, stderr io.Writer) (err error) {
+ if ps.ready {
+ return nil
+ }
+
+ ps.Cmd = exec.Command(ps.Path, ps.Args...)
+ ps.Cmd.Stdout = stdout
+ ps.Cmd.Stderr = stderr
+
+ ready := make(chan bool)
+ timedOut := time.After(ps.StartTimeout)
+ pollerStopCh := make(stopChannel)
+ go pollURLUntilOK(ps.HealthCheck.URL, ps.HealthCheck.PollInterval, ready, pollerStopCh)
+
+ ps.waitDone = make(chan struct{})
+
+ if err := ps.Cmd.Start(); err != nil {
+ ps.errMu.Lock()
+ defer ps.errMu.Unlock()
+ ps.exited = true
+ return err
+ }
+ go func() {
+ defer close(ps.waitDone)
+ err := ps.Cmd.Wait()
+
+ ps.errMu.Lock()
+ defer ps.errMu.Unlock()
+ ps.exitErr = err
+ ps.exited = true
+ }()
+
+ select {
+ case <-ready:
+ ps.ready = true
+ return nil
+ case <-ps.waitDone:
+ close(pollerStopCh)
+ return fmt.Errorf("timeout waiting for process %s to start successfully "+
+ "(it may have failed to start, or stopped unexpectedly before becoming ready)",
+ path.Base(ps.Path))
+ case <-timedOut:
+ close(pollerStopCh)
+ if ps.Cmd != nil {
+ // intentionally ignore this -- we might've crashed, failed to start, etc
+ ps.Cmd.Process.Signal(syscall.SIGTERM) //nolint:errcheck
+ }
+ return fmt.Errorf("timeout waiting for process %s to start", path.Base(ps.Path))
+ }
+}
+
+// Exited returns true if the process exited, and may also
+// return an error (as per Cmd.Wait) if the process did not
+// exit with error code 0.
+func (ps *State) Exited() (bool, error) {
+ ps.errMu.Lock()
+ defer ps.errMu.Unlock()
+ return ps.exited, ps.exitErr
+}
+
+func pollURLUntilOK(url url.URL, interval time.Duration, ready chan bool, stopCh stopChannel) {
+ client := &http.Client{
+ Transport: &http.Transport{
+ TLSClientConfig: &tls.Config{
+ // there's probably certs *somewhere*,
+ // but it's fine to just skip validating
+ // them for health checks during testing
+ InsecureSkipVerify: true, //nolint:gosec
+ },
+ },
+ }
+ if interval <= 0 {
+ interval = 100 * time.Millisecond
+ }
+ for {
+ res, err := client.Get(url.String())
+ if err == nil {
+ res.Body.Close()
+ if res.StatusCode == http.StatusOK {
+ ready <- true
+ return
+ }
+ }
+
+ select {
+ case <-stopCh:
+ return
+ default:
+ time.Sleep(interval)
+ }
+ }
+}
+
+// Stop stops this process gracefully, waits for its termination, and cleans up
+// the CertDir if necessary.
+func (ps *State) Stop() error {
+ // Always clear the directory if we need to.
+ defer func() {
+ if ps.DirNeedsCleaning {
+ _ = os.RemoveAll(ps.Dir)
+ }
+ }()
+ if ps.Cmd == nil {
+ return nil
+ }
+ if done, _ := ps.Exited(); done {
+ return nil
+ }
+ if err := ps.Cmd.Process.Signal(syscall.SIGTERM); err != nil {
+ return fmt.Errorf("unable to signal for process %s to stop: %w", ps.Path, err)
+ }
+
+ timedOut := time.After(ps.StopTimeout)
+
+ select {
+ case <-ps.waitDone:
+ break
+ case <-timedOut:
+ return fmt.Errorf("timeout waiting for process %s to stop", path.Base(ps.Path))
+ }
+ ps.ready = false
+ return nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process_suite_test.go
new file mode 100644
index 00000000000..5a64e9d2f09
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process_suite_test.go
@@ -0,0 +1,30 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package process_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestInternal(t *testing.T) {
+ t.Parallel()
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Envtest Process Launcher Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process_test.go
new file mode 100644
index 00000000000..5b0708227a0
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process_test.go
@@ -0,0 +1,372 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package process_test
+
+import (
+ "bytes"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "strconv"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/onsi/gomega/ghttp"
+ "sigs.k8s.io/controller-runtime/pkg/internal/testing/addr"
+ . "sigs.k8s.io/controller-runtime/pkg/internal/testing/process"
+)
+
+const (
+ healthURLPath = "/healthz"
+)
+
+var _ = Describe("Start method", func() {
+ var (
+ processState *State
+ server *ghttp.Server
+ )
+ BeforeEach(func() {
+ server = ghttp.NewServer()
+
+ processState = &State{
+ Path: "bash",
+ Args: simpleBashScript,
+ HealthCheck: HealthCheck{
+ URL: getServerURL(server),
+ },
+ }
+ processState.Path = "bash"
+ processState.Args = simpleBashScript
+
+ })
+ AfterEach(func() {
+ server.Close()
+ })
+
+ Context("when process takes too long to start", func() {
+ BeforeEach(func() {
+ server.RouteToHandler("GET", healthURLPath, func(resp http.ResponseWriter, _ *http.Request) {
+ time.Sleep(250 * time.Millisecond)
+ resp.WriteHeader(http.StatusOK)
+ })
+ })
+ It("returns a timeout error", func() {
+ processState.StartTimeout = 200 * time.Millisecond
+
+ err := processState.Start(nil, nil)
+ Expect(err).To(MatchError(ContainSubstring("timeout")))
+
+ Eventually(func() bool { done, _ := processState.Exited(); return done }).Should(BeTrue())
+ })
+ })
+
+ Context("when the healthcheck returns ok", func() {
+ BeforeEach(func() {
+
+ server.RouteToHandler("GET", healthURLPath, ghttp.RespondWith(http.StatusOK, ""))
+ })
+
+ It("can start a process", func() {
+ processState.StartTimeout = 10 * time.Second
+
+ err := processState.Start(nil, nil)
+ Expect(err).NotTo(HaveOccurred())
+
+ Consistently(processState.Exited).Should(BeFalse())
+ })
+
+ It("hits the endpoint, and successfully starts", func() {
+ processState.StartTimeout = 100 * time.Millisecond
+
+ err := processState.Start(nil, nil)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(server.ReceivedRequests()).To(HaveLen(1))
+ Consistently(processState.Exited).Should(BeFalse())
+ })
+
+ Context("when the command cannot be started", func() {
+ var err error
+
+ BeforeEach(func() {
+ processState = &State{}
+ processState.Path = "/nonexistent"
+
+ err = processState.Start(nil, nil)
+ })
+
+ It("propagates the error", func() {
+ Expect(os.IsNotExist(err)).To(BeTrue())
+ })
+
+ Context("but Stop() is called on it", func() {
+ It("does not panic", func() {
+ stoppingFailedProcess := func() {
+ Expect(processState.Stop()).To(Succeed())
+ }
+
+ Expect(stoppingFailedProcess).NotTo(Panic())
+ })
+ })
+ })
+
+ Context("when IO is configured", func() {
+ It("can inspect stdout & stderr", func() {
+ stdout := &bytes.Buffer{}
+ stderr := &bytes.Buffer{}
+
+ processState.Args = []string{
+ "-c",
+ `
+ echo 'this is stderr' >&2
+ echo 'that is stdout'
+ echo 'i started' >&2
+ `,
+ }
+ processState.StartTimeout = 5 * time.Second
+
+ Expect(processState.Start(stdout, stderr)).To(Succeed())
+ Eventually(processState.Exited).Should(BeTrue())
+
+ Expect(stdout.String()).To(Equal("that is stdout\n"))
+ Expect(stderr.String()).To(Equal("this is stderr\ni started\n"))
+ })
+ })
+ })
+
+ Context("when the healthcheck always returns failure", func() {
+ BeforeEach(func() {
+ server.RouteToHandler("GET", healthURLPath, ghttp.RespondWith(http.StatusInternalServerError, ""))
+ })
+ It("returns a timeout error and stops health API checker", func() {
+ processState.HealthCheck.URL = getServerURL(server)
+ processState.HealthCheck.Path = healthURLPath
+ processState.StartTimeout = 500 * time.Millisecond
+
+ err := processState.Start(nil, nil)
+ Expect(err).To(MatchError(ContainSubstring("timeout")))
+
+ nrReceivedRequests := len(server.ReceivedRequests())
+ Expect(nrReceivedRequests).To(Equal(5))
+ time.Sleep(200 * time.Millisecond)
+ Expect(nrReceivedRequests).To(Equal(5))
+ })
+ })
+
+ Context("when the healthcheck isn't even listening", func() {
+ BeforeEach(func() {
+ server.Close()
+ })
+
+ It("returns a timeout error", func() {
+ processState.HealthCheck.Path = healthURLPath
+ processState.StartTimeout = 500 * time.Millisecond
+
+ port, host, err := addr.Suggest("")
+ Expect(err).NotTo(HaveOccurred())
+
+ processState.HealthCheck.URL = url.URL{
+ Scheme: "http",
+ Host: net.JoinHostPort(host, strconv.Itoa(port)),
+ }
+
+ err = processState.Start(nil, nil)
+ Expect(err).To(MatchError(ContainSubstring("timeout")))
+ })
+ })
+
+ Context("when the healthcheck fails initially but succeeds eventually", func() {
+ BeforeEach(func() {
+ server.AppendHandlers(
+ ghttp.RespondWith(http.StatusInternalServerError, ""),
+ ghttp.RespondWith(http.StatusInternalServerError, ""),
+ ghttp.RespondWith(http.StatusInternalServerError, ""),
+ ghttp.RespondWith(http.StatusOK, ""),
+ )
+ })
+
+ It("hits the endpoint repeatedly, and successfully starts", func() {
+ processState.HealthCheck.URL = getServerURL(server)
+ processState.HealthCheck.Path = healthURLPath
+ processState.StartTimeout = 20 * time.Second
+
+ err := processState.Start(nil, nil)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(server.ReceivedRequests()).To(HaveLen(4))
+ Consistently(processState.Exited).Should(BeFalse())
+ })
+
+ Context("when the polling interval is not configured", func() {
+ It("uses the default interval for polling", func() {
+ processState.HealthCheck.URL = getServerURL(server)
+ processState.HealthCheck.Path = "/helathz"
+ processState.StartTimeout = 300 * time.Millisecond
+
+ Expect(processState.Start(nil, nil)).To(MatchError(ContainSubstring("timeout")))
+ Expect(server.ReceivedRequests()).To(HaveLen(3))
+ })
+ })
+
+ Context("when the polling interval is configured", func() {
+ BeforeEach(func() {
+ processState.HealthCheck.URL = getServerURL(server)
+ processState.HealthCheck.Path = healthURLPath
+ processState.HealthCheck.PollInterval = time.Millisecond * 150
+ })
+
+ It("hits the endpoint in the configured interval", func() {
+ processState.StartTimeout = 3 * processState.HealthCheck.PollInterval
+
+ Expect(processState.Start(nil, nil)).To(MatchError(ContainSubstring("timeout")))
+ Expect(server.ReceivedRequests()).To(HaveLen(3))
+ })
+ })
+ })
+})
+
+var _ = Describe("Stop method", func() {
+ var (
+ server *ghttp.Server
+ processState *State
+ )
+ BeforeEach(func() {
+ server = ghttp.NewServer()
+ server.RouteToHandler("GET", healthURLPath, ghttp.RespondWith(http.StatusOK, ""))
+ processState = &State{
+ Path: "bash",
+ Args: simpleBashScript,
+ HealthCheck: HealthCheck{
+ URL: getServerURL(server),
+ },
+ }
+ processState.StartTimeout = 10 * time.Second
+ })
+
+ AfterEach(func() {
+ server.Close()
+ })
+ Context("when Stop() is called", func() {
+ BeforeEach(func() {
+ Expect(processState.Start(nil, nil)).To(Succeed())
+ processState.StopTimeout = 10 * time.Second
+ })
+
+ It("stops the process", func() {
+ Expect(processState.Stop()).To(Succeed())
+ })
+
+ Context("multiple times", func() {
+ It("does not error or panic on consecutive calls", func() {
+ stoppingTheProcess := func() {
+ Expect(processState.Stop()).To(Succeed())
+ }
+ Expect(stoppingTheProcess).NotTo(Panic())
+ Expect(stoppingTheProcess).NotTo(Panic())
+ Expect(stoppingTheProcess).NotTo(Panic())
+ })
+ })
+ })
+
+ Context("when the command cannot be stopped", func() {
+ It("returns a timeout error", func() {
+ Expect(processState.Start(nil, nil)).To(Succeed())
+ processState.StopTimeout = 1 * time.Nanosecond // much shorter than the sleep in the script
+
+ Expect(processState.Stop()).To(MatchError(ContainSubstring("timeout")))
+ })
+ })
+
+ Context("when the directory needs to be cleaned up", func() {
+ It("removes the directory", func() {
+ var err error
+
+ Expect(processState.Start(nil, nil)).To(Succeed())
+ processState.Dir, err = os.MkdirTemp("", "k8s_test_framework_")
+ Expect(err).NotTo(HaveOccurred())
+ processState.DirNeedsCleaning = true
+ processState.StopTimeout = 400 * time.Millisecond
+
+ Expect(processState.Stop()).To(Succeed())
+ Expect(processState.Dir).NotTo(BeAnExistingFile())
+ })
+ })
+})
+
+var _ = Describe("Init", func() {
+ Context("when all inputs are provided", func() {
+ It("passes them through", func() {
+ ps := &State{
+ Dir: "/some/dir",
+ Path: "/some/path/to/some/bin",
+ StartTimeout: 20 * time.Hour,
+ StopTimeout: 65537 * time.Millisecond,
+ }
+
+ Expect(ps.Init("some name")).To(Succeed())
+
+ Expect(ps.Dir).To(Equal("/some/dir"))
+ Expect(ps.DirNeedsCleaning).To(BeFalse())
+ Expect(ps.Path).To(Equal("/some/path/to/some/bin"))
+ Expect(ps.StartTimeout).To(Equal(20 * time.Hour))
+ Expect(ps.StopTimeout).To(Equal(65537 * time.Millisecond))
+ })
+ })
+
+ Context("when inputs are empty", func() {
+ It("ps them", func() {
+ ps := &State{}
+ Expect(ps.Init("some name")).To(Succeed())
+
+ Expect(ps.Dir).To(BeADirectory())
+ Expect(os.RemoveAll(ps.Dir)).To(Succeed())
+ Expect(ps.DirNeedsCleaning).To(BeTrue())
+
+ Expect(ps.Path).NotTo(BeEmpty())
+
+ Expect(ps.StartTimeout).NotTo(BeZero())
+ Expect(ps.StopTimeout).NotTo(BeZero())
+ })
+ })
+
+ Context("when neither name nor path are provided", func() {
+ It("returns an error", func() {
+ ps := &State{}
+ Expect(ps.Init("")).To(MatchError("must have at least one of name or path"))
+ })
+ })
+})
+
+var simpleBashScript = []string{
+ "-c",
+ `
+ i=0
+ while true
+ do
+ echo "loop $i" >&2
+ let 'i += 1'
+ sleep 0.2
+ done
+ `,
+}
+
+func getServerURL(server *ghttp.Server) url.URL {
+ url, err := url.Parse(server.URL())
+ Expect(err).NotTo(HaveOccurred())
+ url.Path = healthURLPath
+ return *url
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/leaderelection/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/leaderelection/doc.go
new file mode 100644
index 00000000000..37a9aefab58
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/leaderelection/doc.go
@@ -0,0 +1,24 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package leaderelection contains a constructor for a leader election resource lock.
+This is used to ensure that multiple copies of a controller manager can be run with
+only one active set of controllers, for active-passive HA.
+
+It uses built-in Kubernetes leader election APIs.
+*/
+package leaderelection
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/leaderelection/fake/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/leaderelection/fake/doc.go
new file mode 100644
index 00000000000..3fff7c7189a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/leaderelection/fake/doc.go
@@ -0,0 +1,21 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package fake mocks a resource lock for testing purposes.
+Always returns leadership.
+*/
+package fake
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/leaderelection/fake/leader_election.go b/third_party/sigs.k8s.io/controller-runtime/pkg/leaderelection/fake/leader_election.go
new file mode 100644
index 00000000000..5a82cf43b87
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/leaderelection/fake/leader_election.go
@@ -0,0 +1,96 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package fake
+
+import (
+ "context"
+ "encoding/json"
+ "os"
+ "time"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/util/uuid"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/leaderelection/resourcelock"
+ "sigs.k8s.io/controller-runtime/pkg/leaderelection"
+ "sigs.k8s.io/controller-runtime/pkg/recorder"
+)
+
+// NewResourceLock creates a new ResourceLock for use in testing
+// leader election.
+func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, options leaderelection.Options) (resourcelock.Interface, error) {
+ // Leader id, needs to be unique
+ id, err := os.Hostname()
+ if err != nil {
+ return nil, err
+ }
+ id = id + "_" + string(uuid.NewUUID())
+
+ return &ResourceLock{
+ id: id,
+ record: resourcelock.LeaderElectionRecord{
+ HolderIdentity: id,
+ LeaseDurationSeconds: 15,
+ AcquireTime: metav1.NewTime(time.Now()),
+ RenewTime: metav1.NewTime(time.Now().Add(15 * time.Second)),
+ LeaderTransitions: 1,
+ },
+ }, nil
+}
+
+// ResourceLock implements the ResourceLockInterface.
+// By default returns that the current identity holds the lock.
+type ResourceLock struct {
+ id string
+ record resourcelock.LeaderElectionRecord
+}
+
+// Get implements the ResourceLockInterface.
+func (f *ResourceLock) Get(ctx context.Context) (*resourcelock.LeaderElectionRecord, []byte, error) {
+ recordBytes, err := json.Marshal(f.record)
+ if err != nil {
+ return nil, nil, err
+ }
+ return &f.record, recordBytes, nil
+}
+
+// Create implements the ResourceLockInterface.
+func (f *ResourceLock) Create(ctx context.Context, ler resourcelock.LeaderElectionRecord) error {
+ f.record = ler
+ return nil
+}
+
+// Update implements the ResourceLockInterface.
+func (f *ResourceLock) Update(ctx context.Context, ler resourcelock.LeaderElectionRecord) error {
+ f.record = ler
+ return nil
+}
+
+// RecordEvent implements the ResourceLockInterface.
+func (f *ResourceLock) RecordEvent(s string) {
+
+}
+
+// Identity implements the ResourceLockInterface.
+func (f *ResourceLock) Identity() string {
+ return f.id
+}
+
+// Describe implements the ResourceLockInterface.
+func (f *ResourceLock) Describe() string {
+ return f.id
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/leaderelection/leader_election.go b/third_party/sigs.k8s.io/controller-runtime/pkg/leaderelection/leader_election.go
new file mode 100644
index 00000000000..ee4fcf4cbe0
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/leaderelection/leader_election.go
@@ -0,0 +1,127 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package leaderelection
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ "k8s.io/apimachinery/pkg/util/uuid"
+ coordinationv1client "k8s.io/client-go/kubernetes/typed/coordination/v1"
+ corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/leaderelection/resourcelock"
+
+ "sigs.k8s.io/controller-runtime/pkg/recorder"
+)
+
+const inClusterNamespacePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
+
+// Options provides the required configuration to create a new resource lock.
+type Options struct {
+ // LeaderElection determines whether or not to use leader election when
+ // starting the manager.
+ LeaderElection bool
+
+ // LeaderElectionResourceLock determines which resource lock to use for leader election,
+ // defaults to "leases".
+ LeaderElectionResourceLock string
+
+ // LeaderElectionNamespace determines the namespace in which the leader
+ // election resource will be created.
+ LeaderElectionNamespace string
+
+ // LeaderElectionID determines the name of the resource that leader election
+ // will use for holding the leader lock.
+ LeaderElectionID string
+}
+
+// NewResourceLock creates a new resource lock for use in a leader election loop.
+func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, options Options) (resourcelock.Interface, error) {
+ if !options.LeaderElection {
+ return nil, nil
+ }
+
+ // Default resource lock to "leases". The previous default (from v0.7.0 to v0.11.x) was configmapsleases, which was
+ // used to migrate from configmaps to leases. Since the default was "configmapsleases" for over a year, spanning
+ // five minor releases, any actively maintained operators are very likely to have a released version that uses
+ // "configmapsleases". Therefore defaulting to "leases" should be safe.
+ if options.LeaderElectionResourceLock == "" {
+ options.LeaderElectionResourceLock = resourcelock.LeasesResourceLock
+ }
+
+ // LeaderElectionID must be provided to prevent clashes
+ if options.LeaderElectionID == "" {
+ return nil, errors.New("LeaderElectionID must be configured")
+ }
+
+ // Default the namespace (if running in cluster)
+ if options.LeaderElectionNamespace == "" {
+ var err error
+ options.LeaderElectionNamespace, err = getInClusterNamespace()
+ if err != nil {
+ return nil, fmt.Errorf("unable to find leader election namespace: %w", err)
+ }
+ }
+
+ // Leader id, needs to be unique
+ id, err := os.Hostname()
+ if err != nil {
+ return nil, err
+ }
+ id = id + "_" + string(uuid.NewUUID())
+
+ // Construct clients for leader election
+ rest.AddUserAgent(config, "leader-election")
+ corev1Client, err := corev1client.NewForConfig(config)
+ if err != nil {
+ return nil, err
+ }
+
+ coordinationClient, err := coordinationv1client.NewForConfig(config)
+ if err != nil {
+ return nil, err
+ }
+
+ return resourcelock.New(options.LeaderElectionResourceLock,
+ options.LeaderElectionNamespace,
+ options.LeaderElectionID,
+ corev1Client,
+ coordinationClient,
+ resourcelock.ResourceLockConfig{
+ Identity: id,
+ EventRecorder: recorderProvider.GetEventRecorderFor(id),
+ })
+}
+
+func getInClusterNamespace() (string, error) {
+ // Check whether the namespace file exists.
+ // If not, we are not running in cluster so can't guess the namespace.
+ if _, err := os.Stat(inClusterNamespacePath); os.IsNotExist(err) {
+ return "", fmt.Errorf("not running in-cluster, please specify LeaderElectionNamespace")
+ } else if err != nil {
+ return "", fmt.Errorf("error checking namespace file: %w", err)
+ }
+
+ // Load the namespace file and return its content
+ namespace, err := os.ReadFile(inClusterNamespacePath)
+ if err != nil {
+ return "", fmt.Errorf("error reading namespace file: %w", err)
+ }
+ return string(namespace), nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/log/deleg.go b/third_party/sigs.k8s.io/controller-runtime/pkg/log/deleg.go
new file mode 100644
index 00000000000..c27b4305f8b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/log/deleg.go
@@ -0,0 +1,205 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package log
+
+import (
+ "sync"
+
+ "github.com/go-logr/logr"
+)
+
+// loggerPromise knows how to populate a concrete logr.Logger
+// with options, given an actual base logger later on down the line.
+type loggerPromise struct {
+ logger *delegatingLogSink
+ childPromises []*loggerPromise
+ promisesLock sync.Mutex
+
+ name *string
+ tags []interface{}
+}
+
+func (p *loggerPromise) WithName(l *delegatingLogSink, name string) *loggerPromise {
+ res := &loggerPromise{
+ logger: l,
+ name: &name,
+ promisesLock: sync.Mutex{},
+ }
+
+ p.promisesLock.Lock()
+ defer p.promisesLock.Unlock()
+ p.childPromises = append(p.childPromises, res)
+ return res
+}
+
+// WithValues provides a new Logger with the tags appended.
+func (p *loggerPromise) WithValues(l *delegatingLogSink, tags ...interface{}) *loggerPromise {
+ res := &loggerPromise{
+ logger: l,
+ tags: tags,
+ promisesLock: sync.Mutex{},
+ }
+
+ p.promisesLock.Lock()
+ defer p.promisesLock.Unlock()
+ p.childPromises = append(p.childPromises, res)
+ return res
+}
+
+// Fulfill instantiates the Logger with the provided logger.
+func (p *loggerPromise) Fulfill(parentLogSink logr.LogSink) {
+ sink := parentLogSink
+ if p.name != nil {
+ sink = sink.WithName(*p.name)
+ }
+
+ if p.tags != nil {
+ sink = sink.WithValues(p.tags...)
+ }
+
+ p.logger.lock.Lock()
+ p.logger.logger = sink
+ if withCallDepth, ok := sink.(logr.CallDepthLogSink); ok {
+ p.logger.logger = withCallDepth.WithCallDepth(1)
+ }
+ p.logger.promise = nil
+ p.logger.lock.Unlock()
+
+ for _, childPromise := range p.childPromises {
+ childPromise.Fulfill(sink)
+ }
+}
+
+// delegatingLogSink is a logsink that delegates to another logr.LogSink.
+// If the underlying promise is not nil, it registers calls to sub-loggers with
+// the logging factory to be populated later, and returns a new delegating
+// logger. It expects to have *some* logr.Logger set at all times (generally
+// a no-op logger before the promises are fulfilled).
+type delegatingLogSink struct {
+ lock sync.RWMutex
+ logger logr.LogSink
+ promise *loggerPromise
+ info logr.RuntimeInfo
+}
+
+// Init implements logr.LogSink.
+func (l *delegatingLogSink) Init(info logr.RuntimeInfo) {
+ eventuallyFulfillRoot()
+ l.lock.Lock()
+ defer l.lock.Unlock()
+ l.info = info
+}
+
+// Enabled tests whether this Logger is enabled. For example, commandline
+// flags might be used to set the logging verbosity and disable some info
+// logs.
+func (l *delegatingLogSink) Enabled(level int) bool {
+ eventuallyFulfillRoot()
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+ return l.logger.Enabled(level)
+}
+
+// Info logs a non-error message with the given key/value pairs as context.
+//
+// The msg argument should be used to add some constant description to
+// the log line. The key/value pairs can then be used to add additional
+// variable information. The key/value pairs should alternate string
+// keys and arbitrary values.
+func (l *delegatingLogSink) Info(level int, msg string, keysAndValues ...interface{}) {
+ eventuallyFulfillRoot()
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+ l.logger.Info(level, msg, keysAndValues...)
+}
+
+// Error logs an error, with the given message and key/value pairs as context.
+// It functions similarly to calling Info with the "error" named value, but may
+// have unique behavior, and should be preferred for logging errors (see the
+// package documentations for more information).
+//
+// The msg field should be used to add context to any underlying error,
+// while the err field should be used to attach the actual error that
+// triggered this log line, if present.
+func (l *delegatingLogSink) Error(err error, msg string, keysAndValues ...interface{}) {
+ eventuallyFulfillRoot()
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+ l.logger.Error(err, msg, keysAndValues...)
+}
+
+// WithName provides a new Logger with the name appended.
+func (l *delegatingLogSink) WithName(name string) logr.LogSink {
+ eventuallyFulfillRoot()
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+
+ if l.promise == nil {
+ sink := l.logger.WithName(name)
+ if withCallDepth, ok := sink.(logr.CallDepthLogSink); ok {
+ sink = withCallDepth.WithCallDepth(-1)
+ }
+ return sink
+ }
+
+ res := &delegatingLogSink{logger: l.logger}
+ promise := l.promise.WithName(res, name)
+ res.promise = promise
+
+ return res
+}
+
+// WithValues provides a new Logger with the tags appended.
+func (l *delegatingLogSink) WithValues(tags ...interface{}) logr.LogSink {
+ eventuallyFulfillRoot()
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+
+ if l.promise == nil {
+ sink := l.logger.WithValues(tags...)
+ if withCallDepth, ok := sink.(logr.CallDepthLogSink); ok {
+ sink = withCallDepth.WithCallDepth(-1)
+ }
+ return sink
+ }
+
+ res := &delegatingLogSink{logger: l.logger}
+ promise := l.promise.WithValues(res, tags...)
+ res.promise = promise
+
+ return res
+}
+
+// Fulfill switches the logger over to use the actual logger
+// provided, instead of the temporary initial one, if this method
+// has not been previously called.
+func (l *delegatingLogSink) Fulfill(actual logr.LogSink) {
+ if l.promise != nil {
+ l.promise.Fulfill(actual)
+ }
+}
+
+// newDelegatingLogSink constructs a new DelegatingLogSink which uses
+// the given logger before its promise is fulfilled.
+func newDelegatingLogSink(initial logr.LogSink) *delegatingLogSink {
+ l := &delegatingLogSink{
+ logger: initial,
+ promise: &loggerPromise{promisesLock: sync.Mutex{}},
+ }
+ l.promise.logger = l
+ return l
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/log/log.go b/third_party/sigs.k8s.io/controller-runtime/pkg/log/log.go
new file mode 100644
index 00000000000..a79151c69ed
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/log/log.go
@@ -0,0 +1,96 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package log contains utilities for fetching a new logger
+// when one is not already available.
+//
+// # The Log Handle
+//
+// This package contains a root logr.Logger Log. It may be used to
+// get a handle to whatever the root logging implementation is. By
+// default, no implementation exists, and the handle returns "promises"
+// to loggers. When the implementation is set using SetLogger, these
+// "promises" will be converted over to real loggers.
+//
+// # Logr
+//
+// All logging in controller-runtime is structured, using a set of interfaces
+// defined by a package called logr
+// (https://pkg.go.dev/github.com/go-logr/logr). The sub-package zap provides
+// helpers for setting up logr backed by Zap (go.uber.org/zap).
+package log
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "runtime/debug"
+ "sync/atomic"
+ "time"
+
+ "github.com/go-logr/logr"
+)
+
+// SetLogger sets a concrete logging implementation for all deferred Loggers.
+func SetLogger(l logr.Logger) {
+ logFullfilled.Store(true)
+ rootLog.Fulfill(l.GetSink())
+}
+
+func eventuallyFulfillRoot() {
+ if logFullfilled.Load() {
+ return
+ }
+ if time.Since(rootLogCreated).Seconds() >= 30 {
+ if logFullfilled.CompareAndSwap(false, true) {
+ fmt.Fprintf(os.Stderr, "[controller-runtime] log.SetLogger(...) was never called, logs will not be displayed:\n%s", debug.Stack())
+ SetLogger(logr.New(NullLogSink{}))
+ }
+ }
+}
+
+var (
+ logFullfilled atomic.Bool
+)
+
+// Log is the base logger used by kubebuilder. It delegates
+// to another logr.Logger. You *must* call SetLogger to
+// get any actual logging. If SetLogger is not called within
+// the first 30 seconds of a binaries lifetime, it will get
+// set to a NullLogSink.
+var (
+ rootLog, rootLogCreated = func() (*delegatingLogSink, time.Time) {
+ return newDelegatingLogSink(NullLogSink{}), time.Now()
+ }()
+ Log = logr.New(rootLog)
+)
+
+// FromContext returns a logger with predefined values from a context.Context.
+func FromContext(ctx context.Context, keysAndValues ...interface{}) logr.Logger {
+ log := Log
+ if ctx != nil {
+ if logger, err := logr.FromContext(ctx); err == nil {
+ log = logger
+ }
+ }
+ return log.WithValues(keysAndValues...)
+}
+
+// IntoContext takes a context and sets the logger as one of its values.
+// Use FromContext function to retrieve the logger.
+func IntoContext(ctx context.Context, log logr.Logger) context.Context {
+ return logr.NewContext(ctx, log)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/log/log_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/log/log_suite_test.go
new file mode 100644
index 00000000000..f0e349aa867
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/log/log_suite_test.go
@@ -0,0 +1,29 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package log
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Log Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/log/log_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/log/log_test.go
new file mode 100644
index 00000000000..c0ca462369f
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/log/log_test.go
@@ -0,0 +1,330 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package log
+
+import (
+ "context"
+ "errors"
+
+ "github.com/go-logr/logr"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+var _ logr.LogSink = &delegatingLogSink{}
+
+// logInfo is the information for a particular fakeLogger message.
+type logInfo struct {
+ name []string
+ tags []interface{}
+ msg string
+}
+
+// fakeLoggerRoot is the root object to which all fakeLoggers record their messages.
+type fakeLoggerRoot struct {
+ messages []logInfo
+}
+
+// fakeLogger is a fake implementation of logr.Logger that records
+// messages, tags, and names,
+// just records the name.
+type fakeLogger struct {
+ name []string
+ tags []interface{}
+
+ root *fakeLoggerRoot
+}
+
+func (f *fakeLogger) Init(info logr.RuntimeInfo) {
+}
+
+func (f *fakeLogger) WithName(name string) logr.LogSink {
+ names := append([]string(nil), f.name...)
+ names = append(names, name)
+ return &fakeLogger{
+ name: names,
+ tags: f.tags,
+ root: f.root,
+ }
+}
+
+func (f *fakeLogger) WithValues(vals ...interface{}) logr.LogSink {
+ tags := append([]interface{}(nil), f.tags...)
+ tags = append(tags, vals...)
+ return &fakeLogger{
+ name: f.name,
+ tags: tags,
+ root: f.root,
+ }
+}
+
+func (f *fakeLogger) Error(err error, msg string, vals ...interface{}) {
+ tags := append([]interface{}(nil), f.tags...)
+ tags = append(tags, "error", err)
+ tags = append(tags, vals...)
+ f.root.messages = append(f.root.messages, logInfo{
+ name: append([]string(nil), f.name...),
+ tags: tags,
+ msg: msg,
+ })
+}
+
+func (f *fakeLogger) Info(level int, msg string, vals ...interface{}) {
+ tags := append([]interface{}(nil), f.tags...)
+ tags = append(tags, vals...)
+ f.root.messages = append(f.root.messages, logInfo{
+ name: append([]string(nil), f.name...),
+ tags: tags,
+ msg: msg,
+ })
+}
+
+func (f *fakeLogger) Enabled(level int) bool { return true }
+
+var _ = Describe("logging", func() {
+
+ Describe("top-level logger", func() {
+ It("hold newly created loggers until a logger is set", func() {
+ By("grabbing a new sub-logger and logging to it")
+ l1 := Log.WithName("runtimeLog").WithValues("newtag", "newvalue1")
+ l1.Info("before msg")
+
+ By("actually setting the logger")
+ logger := &fakeLogger{root: &fakeLoggerRoot{}}
+ SetLogger(logr.New(logger))
+
+ By("grabbing another sub-logger and logging to both loggers")
+ l2 := Log.WithName("runtimeLog").WithValues("newtag", "newvalue2")
+ l1.Info("after msg 1")
+ l2.Info("after msg 2")
+
+ By("ensuring that messages after the logger was set were logged")
+ Expect(logger.root.messages).To(ConsistOf(
+ logInfo{name: []string{"runtimeLog"}, tags: []interface{}{"newtag", "newvalue1"}, msg: "after msg 1"},
+ logInfo{name: []string{"runtimeLog"}, tags: []interface{}{"newtag", "newvalue2"}, msg: "after msg 2"},
+ ))
+ })
+ })
+
+ Describe("lazy logger initialization", func() {
+ var (
+ root *fakeLoggerRoot
+ baseLog logr.LogSink
+ delegLog *delegatingLogSink
+ )
+
+ BeforeEach(func() {
+ root = &fakeLoggerRoot{}
+ baseLog = &fakeLogger{root: root}
+ delegLog = newDelegatingLogSink(NullLogSink{})
+ })
+
+ It("should delegate with name", func() {
+ By("asking for a logger with a name before fulfill, and logging")
+ befFulfill1 := logr.New(delegLog).WithName("before-fulfill")
+ befFulfill2 := befFulfill1.WithName("two")
+ befFulfill1.Info("before fulfill")
+
+ By("logging on the base logger before fulfill")
+ logr.New(delegLog).Info("before fulfill base")
+
+ By("ensuring that no messages were actually recorded")
+ Expect(root.messages).To(BeEmpty())
+
+ By("fulfilling the promise")
+ delegLog.Fulfill(baseLog)
+
+ By("logging with the existing loggers after fulfilling")
+ befFulfill1.Info("after 1")
+ befFulfill2.Info("after 2")
+
+ By("grabbing a new sub-logger of a previously constructed logger and logging to it")
+ befFulfill1.WithName("after-from-before").Info("after 3")
+
+ By("logging with new loggers")
+ logr.New(delegLog).WithName("after-fulfill").Info("after 4")
+
+ By("ensuring that the messages are appropriately named")
+ Expect(root.messages).To(ConsistOf(
+ logInfo{name: []string{"before-fulfill"}, msg: "after 1"},
+ logInfo{name: []string{"before-fulfill", "two"}, msg: "after 2"},
+ logInfo{name: []string{"before-fulfill", "after-from-before"}, msg: "after 3"},
+ logInfo{name: []string{"after-fulfill"}, msg: "after 4"},
+ ))
+ })
+
+ // This test in itself will always succeed, a failure will be indicated by the
+ // race detector going off
+ It("should be threadsafe", func() {
+ fulfillDone := make(chan struct{})
+ withNameDone := make(chan struct{})
+ withValuesDone := make(chan struct{})
+ grandChildDone := make(chan struct{})
+ logEnabledDone := make(chan struct{})
+ logInfoDone := make(chan struct{})
+ logErrorDone := make(chan struct{})
+ logVDone := make(chan struct{})
+
+ // Constructing the child in the goroutine does not reliably
+ // trigger the race detector
+ child := logr.New(delegLog).WithName("child")
+ go func() {
+ defer GinkgoRecover()
+ delegLog.Fulfill(NullLogSink{})
+ close(fulfillDone)
+ }()
+ go func() {
+ defer GinkgoRecover()
+ delegLog.WithName("with-name")
+ close(withNameDone)
+ }()
+ go func() {
+ defer GinkgoRecover()
+ delegLog.WithValues("with-value")
+ close(withValuesDone)
+ }()
+ go func() {
+ defer GinkgoRecover()
+ child.WithValues("grandchild")
+ close(grandChildDone)
+ }()
+ go func() {
+ defer GinkgoRecover()
+ logr.New(delegLog).Enabled()
+ close(logEnabledDone)
+ }()
+ go func() {
+ defer GinkgoRecover()
+ logr.New(delegLog).Info("hello world")
+ close(logInfoDone)
+ }()
+ go func() {
+ defer GinkgoRecover()
+ delegLog.Error(errors.New("err"), "hello world")
+ close(logErrorDone)
+ }()
+ go func() {
+ defer GinkgoRecover()
+ logr.New(delegLog).V(1)
+ close(logVDone)
+ }()
+
+ <-fulfillDone
+ <-withNameDone
+ <-withValuesDone
+ <-grandChildDone
+ <-logEnabledDone
+ <-logInfoDone
+ <-logErrorDone
+ <-logVDone
+ })
+
+ It("should delegate with tags", func() {
+ By("asking for a logger with a name before fulfill, and logging")
+ befFulfill1 := logr.New(delegLog).WithValues("tag1", "val1")
+ befFulfill2 := befFulfill1.WithValues("tag2", "val2")
+ befFulfill1.Info("before fulfill")
+
+ By("logging on the base logger before fulfill")
+ logr.New(delegLog).Info("before fulfill base")
+
+ By("ensuring that no messages were actually recorded")
+ Expect(root.messages).To(BeEmpty())
+
+ By("fulfilling the promise")
+ delegLog.Fulfill(baseLog)
+
+ By("logging with the existing loggers after fulfilling")
+ befFulfill1.Info("after 1")
+ befFulfill2.Info("after 2")
+
+ By("grabbing a new sub-logger of a previously constructed logger and logging to it")
+ befFulfill1.WithValues("tag3", "val3").Info("after 3")
+
+ By("logging with new loggers")
+ logr.New(delegLog).WithValues("tag3", "val3").Info("after 4")
+
+ By("ensuring that the messages are appropriately named")
+ Expect(root.messages).To(ConsistOf(
+ logInfo{tags: []interface{}{"tag1", "val1"}, msg: "after 1"},
+ logInfo{tags: []interface{}{"tag1", "val1", "tag2", "val2"}, msg: "after 2"},
+ logInfo{tags: []interface{}{"tag1", "val1", "tag3", "val3"}, msg: "after 3"},
+ logInfo{tags: []interface{}{"tag3", "val3"}, msg: "after 4"},
+ ))
+ })
+
+ It("shouldn't fulfill twice", func() {
+ By("fulfilling once")
+ delegLog.Fulfill(baseLog)
+
+ By("logging a bit")
+ logr.New(delegLog).Info("msg 1")
+
+ By("fulfilling with a new logger")
+ delegLog.Fulfill(&fakeLogger{})
+
+ By("logging some more")
+ logr.New(delegLog).Info("msg 2")
+
+ By("checking that all log messages are present")
+ Expect(root.messages).To(ConsistOf(
+ logInfo{msg: "msg 1"},
+ logInfo{msg: "msg 2"},
+ ))
+ })
+ })
+
+ Describe("logger from context", func() {
+ It("should return default logger when context is empty", func() {
+ gotLog := FromContext(context.Background())
+ Expect(gotLog).To(Not(BeNil()))
+ })
+
+ It("should return existing logger", func() {
+ root := &fakeLoggerRoot{}
+ baseLog := &fakeLogger{root: root}
+
+ wantLog := logr.New(baseLog).WithName("my-logger")
+ ctx := IntoContext(context.Background(), wantLog)
+
+ gotLog := FromContext(ctx)
+ Expect(gotLog).To(Not(BeNil()))
+
+ gotLog.Info("test message")
+ Expect(root.messages).To(ConsistOf(
+ logInfo{name: []string{"my-logger"}, msg: "test message"},
+ ))
+ })
+
+ It("should have added key-values", func() {
+ root := &fakeLoggerRoot{}
+ baseLog := &fakeLogger{root: root}
+
+ wantLog := logr.New(baseLog).WithName("my-logger")
+ ctx := IntoContext(context.Background(), wantLog)
+
+ gotLog := FromContext(ctx, "tag1", "value1")
+ Expect(gotLog).To(Not(BeNil()))
+
+ gotLog.Info("test message")
+ Expect(root.messages).To(ConsistOf(
+ logInfo{name: []string{"my-logger"}, tags: []interface{}{"tag1", "value1"}, msg: "test message"},
+ ))
+ })
+ })
+
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/log/null.go b/third_party/sigs.k8s.io/controller-runtime/pkg/log/null.go
new file mode 100644
index 00000000000..f3e81074fee
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/log/null.go
@@ -0,0 +1,59 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package log
+
+import (
+ "github.com/go-logr/logr"
+)
+
+// NB: this is the same as the null logger logr/testing,
+// but avoids accidentally adding the testing flags to
+// all binaries.
+
+// NullLogSink is a logr.Logger that does nothing.
+type NullLogSink struct{}
+
+var _ logr.LogSink = NullLogSink{}
+
+// Init implements logr.LogSink.
+func (log NullLogSink) Init(logr.RuntimeInfo) {
+}
+
+// Info implements logr.InfoLogger.
+func (NullLogSink) Info(_ int, _ string, _ ...interface{}) {
+ // Do nothing.
+}
+
+// Enabled implements logr.InfoLogger.
+func (NullLogSink) Enabled(level int) bool {
+ return false
+}
+
+// Error implements logr.Logger.
+func (NullLogSink) Error(_ error, _ string, _ ...interface{}) {
+ // Do nothing.
+}
+
+// WithName implements logr.Logger.
+func (log NullLogSink) WithName(_ string) logr.LogSink {
+ return log
+}
+
+// WithValues implements logr.Logger.
+func (log NullLogSink) WithValues(_ ...interface{}) logr.LogSink {
+ return log
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/log/warning_handler.go b/third_party/sigs.k8s.io/controller-runtime/pkg/log/warning_handler.go
new file mode 100644
index 00000000000..e9522632d3d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/log/warning_handler.go
@@ -0,0 +1,76 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package log
+
+import (
+ "sync"
+
+ "github.com/go-logr/logr"
+)
+
+// KubeAPIWarningLoggerOptions controls the behavior
+// of a rest.WarningHandler constructed using NewKubeAPIWarningLogger().
+type KubeAPIWarningLoggerOptions struct {
+ // Deduplicate indicates a given warning message should only be written once.
+ // Setting this to true in a long-running process handling many warnings can
+ // result in increased memory use.
+ Deduplicate bool
+}
+
+// KubeAPIWarningLogger is a wrapper around
+// a provided logr.Logger that implements the
+// rest.WarningHandler interface.
+type KubeAPIWarningLogger struct {
+ // logger is used to log responses with the warning header
+ logger logr.Logger
+ // opts contain options controlling warning output
+ opts KubeAPIWarningLoggerOptions
+ // writtenLock gurads written
+ writtenLock sync.Mutex
+ // used to keep track of already logged messages
+ // and help in de-duplication.
+ written map[string]struct{}
+}
+
+// HandleWarningHeader handles logging for responses from API server that are
+// warnings with code being 299 and uses a logr.Logger for its logging purposes.
+func (l *KubeAPIWarningLogger) HandleWarningHeader(code int, agent string, message string) {
+ if code != 299 || len(message) == 0 {
+ return
+ }
+
+ if l.opts.Deduplicate {
+ l.writtenLock.Lock()
+ defer l.writtenLock.Unlock()
+
+ if _, alreadyLogged := l.written[message]; alreadyLogged {
+ return
+ }
+ l.written[message] = struct{}{}
+ }
+ l.logger.Info(message)
+}
+
+// NewKubeAPIWarningLogger returns an implementation of rest.WarningHandler that logs warnings
+// with code = 299 to the provided logr.Logger.
+func NewKubeAPIWarningLogger(l logr.Logger, opts KubeAPIWarningLoggerOptions) *KubeAPIWarningLogger {
+ h := &KubeAPIWarningLogger{logger: l, opts: opts}
+ if opts.Deduplicate {
+ h.written = map[string]struct{}{}
+ }
+ return h
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/flags.go b/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/flags.go
new file mode 100644
index 00000000000..fb492b14da8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/flags.go
@@ -0,0 +1,168 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package zap contains helpers for setting up a new logr.Logger instance
+// using the Zap logging framework.
+package zap
+
+import (
+ "flag"
+ "fmt"
+ "strconv"
+ "strings"
+
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+)
+
+var levelStrings = map[string]zapcore.Level{
+ "debug": zap.DebugLevel,
+ "info": zap.InfoLevel,
+ "error": zap.ErrorLevel,
+}
+
+var stackLevelStrings = map[string]zapcore.Level{
+ "info": zap.InfoLevel,
+ "error": zap.ErrorLevel,
+ "panic": zap.PanicLevel,
+}
+
+type encoderFlag struct {
+ setFunc func(NewEncoderFunc)
+ value string
+}
+
+var _ flag.Value = &encoderFlag{}
+
+func (ev *encoderFlag) String() string {
+ return ev.value
+}
+
+func (ev *encoderFlag) Type() string {
+ return "encoder"
+}
+
+func (ev *encoderFlag) Set(flagValue string) error {
+ val := strings.ToLower(flagValue)
+ switch val {
+ case "json":
+ ev.setFunc(newJSONEncoder)
+ case "console":
+ ev.setFunc(newConsoleEncoder)
+ default:
+ return fmt.Errorf("invalid encoder value \"%s\"", flagValue)
+ }
+ ev.value = flagValue
+ return nil
+}
+
+type levelFlag struct {
+ setFunc func(zapcore.LevelEnabler)
+ value string
+}
+
+var _ flag.Value = &levelFlag{}
+
+func (ev *levelFlag) Set(flagValue string) error {
+ level, validLevel := levelStrings[strings.ToLower(flagValue)]
+ if !validLevel {
+ logLevel, err := strconv.Atoi(flagValue)
+ if err != nil {
+ return fmt.Errorf("invalid log level \"%s\"", flagValue)
+ }
+ if logLevel > 0 {
+ intLevel := -1 * logLevel
+ ev.setFunc(zap.NewAtomicLevelAt(zapcore.Level(int8(intLevel))))
+ } else {
+ return fmt.Errorf("invalid log level \"%s\"", flagValue)
+ }
+ } else {
+ ev.setFunc(zap.NewAtomicLevelAt(level))
+ }
+ ev.value = flagValue
+ return nil
+}
+
+func (ev *levelFlag) String() string {
+ return ev.value
+}
+
+func (ev *levelFlag) Type() string {
+ return "level"
+}
+
+type stackTraceFlag struct {
+ setFunc func(zapcore.LevelEnabler)
+ value string
+}
+
+var _ flag.Value = &stackTraceFlag{}
+
+func (ev *stackTraceFlag) Set(flagValue string) error {
+ level, validLevel := stackLevelStrings[strings.ToLower(flagValue)]
+ if !validLevel {
+ return fmt.Errorf("invalid stacktrace level \"%s\"", flagValue)
+ }
+ ev.setFunc(zap.NewAtomicLevelAt(level))
+ ev.value = flagValue
+ return nil
+}
+
+func (ev *stackTraceFlag) String() string {
+ return ev.value
+}
+
+func (ev *stackTraceFlag) Type() string {
+ return "level"
+}
+
+type timeEncodingFlag struct {
+ setFunc func(zapcore.TimeEncoder)
+ value string
+}
+
+var _ flag.Value = &timeEncodingFlag{}
+
+func (ev *timeEncodingFlag) String() string {
+ return ev.value
+}
+
+func (ev *timeEncodingFlag) Type() string {
+ return "time-encoding"
+}
+
+func (ev *timeEncodingFlag) Set(flagValue string) error {
+ val := strings.ToLower(flagValue)
+ switch val {
+ case "rfc3339nano":
+ ev.setFunc(zapcore.RFC3339NanoTimeEncoder)
+ case "rfc3339":
+ ev.setFunc(zapcore.RFC3339TimeEncoder)
+ case "iso8601":
+ ev.setFunc(zapcore.ISO8601TimeEncoder)
+ case "millis":
+ ev.setFunc(zapcore.EpochMillisTimeEncoder)
+ case "nanos":
+ ev.setFunc(zapcore.EpochNanosTimeEncoder)
+ case "epoch":
+ ev.setFunc(zapcore.EpochTimeEncoder)
+ default:
+ return fmt.Errorf("invalid time-encoding value \"%s\"", flagValue)
+ }
+
+ ev.value = flagValue
+ return nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/kube_helpers.go b/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/kube_helpers.go
new file mode 100644
index 00000000000..3b4ebfdaa0b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/kube_helpers.go
@@ -0,0 +1,111 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package zap
+
+import (
+ "fmt"
+ "reflect"
+
+ "go.uber.org/zap/buffer"
+ "go.uber.org/zap/zapcore"
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// KubeAwareEncoder is a Kubernetes-aware Zap Encoder.
+// Instead of trying to force Kubernetes objects to implement
+// ObjectMarshaller, we just implement a wrapper around a normal
+// ObjectMarshaller that checks for Kubernetes objects.
+type KubeAwareEncoder struct {
+ // Encoder is the zapcore.Encoder that this encoder delegates to
+ zapcore.Encoder
+
+ // Verbose controls whether or not the full object is printed.
+ // If false, only name, namespace, api version, and kind are printed.
+ // Otherwise, the full object is logged.
+ Verbose bool
+}
+
+// kubeObjectWrapper is a zapcore.ObjectMarshaler for Kubernetes objects.
+type kubeObjectWrapper struct {
+ obj runtime.Object
+}
+
+// MarshalLogObject implements zapcore.ObjectMarshaler.
+func (w kubeObjectWrapper) MarshalLogObject(enc zapcore.ObjectEncoder) error {
+ // TODO(directxman12): log kind and apiversion if not set explicitly (common case)
+ // -- needs an a scheme to convert to the GVK.
+
+ if reflect.ValueOf(w.obj).IsNil() {
+ return fmt.Errorf("got nil for runtime.Object")
+ }
+
+ if gvk := w.obj.GetObjectKind().GroupVersionKind(); gvk.Version != "" {
+ enc.AddString("apiVersion", gvk.GroupVersion().String())
+ enc.AddString("kind", gvk.Kind)
+ }
+
+ objMeta, err := meta.Accessor(w.obj)
+ if err != nil {
+ return fmt.Errorf("got runtime.Object without object metadata: %v", w.obj)
+ }
+
+ if ns := objMeta.GetNamespace(); ns != "" {
+ enc.AddString("namespace", ns)
+ }
+ enc.AddString("name", objMeta.GetName())
+
+ return nil
+}
+
+// NB(directxman12): can't just override AddReflected, since the encoder calls AddReflected on itself directly
+
+// Clone implements zapcore.Encoder.
+func (k *KubeAwareEncoder) Clone() zapcore.Encoder {
+ return &KubeAwareEncoder{
+ Encoder: k.Encoder.Clone(),
+ }
+}
+
+// EncodeEntry implements zapcore.Encoder.
+func (k *KubeAwareEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
+ if k.Verbose {
+ // Kubernetes objects implement fmt.Stringer, so if we
+ // want verbose output, just delegate to that.
+ return k.Encoder.EncodeEntry(entry, fields)
+ }
+
+ for i, field := range fields {
+ // intercept stringer fields that happen to be Kubernetes runtime.Object or
+ // types.NamespacedName values (Kubernetes runtime.Objects commonly
+ // implement String, apparently).
+ // *unstructured.Unstructured does NOT implement fmt.Striger interface.
+ // We have handle it specially.
+ if field.Type == zapcore.StringerType || field.Type == zapcore.ReflectType {
+ switch val := field.Interface.(type) {
+ case runtime.Object:
+ fields[i] = zapcore.Field{
+ Type: zapcore.ObjectMarshalerType,
+ Key: field.Key,
+ Interface: kubeObjectWrapper{obj: val},
+ }
+ }
+ }
+ }
+
+ return k.Encoder.EncodeEntry(entry, fields)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/zap.go b/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/zap.go
new file mode 100644
index 00000000000..ee89a7c6a49
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/zap.go
@@ -0,0 +1,311 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package zap contains helpers for setting up a new logr.Logger instance
+// using the Zap logging framework.
+package zap
+
+import (
+ "flag"
+ "io"
+ "os"
+ "time"
+
+ "github.com/go-logr/logr"
+ "github.com/go-logr/zapr"
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+)
+
+// EncoderConfigOption is a function that can modify a `zapcore.EncoderConfig`.
+type EncoderConfigOption func(*zapcore.EncoderConfig)
+
+// NewEncoderFunc is a function that creates an Encoder using the provided EncoderConfigOptions.
+type NewEncoderFunc func(...EncoderConfigOption) zapcore.Encoder
+
+// New returns a brand new Logger configured with Opts. It
+// uses KubeAwareEncoder which adds Type information and
+// Namespace/Name to the log.
+func New(opts ...Opts) logr.Logger {
+ return zapr.NewLogger(NewRaw(opts...))
+}
+
+// Opts allows to manipulate Options.
+type Opts func(*Options)
+
+// UseDevMode sets the logger to use (or not use) development mode (more
+// human-readable output, extra stack traces and logging information, etc).
+// See Options.Development.
+func UseDevMode(enabled bool) Opts {
+ return func(o *Options) {
+ o.Development = enabled
+ }
+}
+
+// WriteTo configures the logger to write to the given io.Writer, instead of standard error.
+// See Options.DestWriter.
+func WriteTo(out io.Writer) Opts {
+ return func(o *Options) {
+ o.DestWriter = out
+ }
+}
+
+// Encoder configures how the logger will encode the output e.g JSON or console.
+// See Options.Encoder.
+func Encoder(encoder zapcore.Encoder) func(o *Options) {
+ return func(o *Options) {
+ o.Encoder = encoder
+ }
+}
+
+// JSONEncoder configures the logger to use a JSON Encoder.
+func JSONEncoder(opts ...EncoderConfigOption) func(o *Options) {
+ return func(o *Options) {
+ o.Encoder = newJSONEncoder(opts...)
+ }
+}
+
+func newJSONEncoder(opts ...EncoderConfigOption) zapcore.Encoder {
+ encoderConfig := zap.NewProductionEncoderConfig()
+ for _, opt := range opts {
+ opt(&encoderConfig)
+ }
+ return zapcore.NewJSONEncoder(encoderConfig)
+}
+
+// ConsoleEncoder configures the logger to use a Console encoder.
+func ConsoleEncoder(opts ...EncoderConfigOption) func(o *Options) {
+ return func(o *Options) {
+ o.Encoder = newConsoleEncoder(opts...)
+ }
+}
+
+func newConsoleEncoder(opts ...EncoderConfigOption) zapcore.Encoder {
+ encoderConfig := zap.NewDevelopmentEncoderConfig()
+ for _, opt := range opts {
+ opt(&encoderConfig)
+ }
+ return zapcore.NewConsoleEncoder(encoderConfig)
+}
+
+// Level sets Options.Level, which configures the minimum enabled logging level e.g Debug, Info.
+// A zap log level should be multiplied by -1 to get the logr verbosity.
+// For example, to get logr verbosity of 3, pass zapcore.Level(-3) to this Opts.
+// See https://pkg.go.dev/github.com/go-logr/zapr for how zap level relates to logr verbosity.
+func Level(level zapcore.LevelEnabler) func(o *Options) {
+ return func(o *Options) {
+ o.Level = level
+ }
+}
+
+// StacktraceLevel sets Options.StacktraceLevel, which configures the logger to record a stack trace
+// for all messages at or above a given level.
+// See the Level Opts for the relationship of zap log level to logr verbosity.
+func StacktraceLevel(stacktraceLevel zapcore.LevelEnabler) func(o *Options) {
+ return func(o *Options) {
+ o.StacktraceLevel = stacktraceLevel
+ }
+}
+
+// RawZapOpts allows appending arbitrary zap.Options to configure the underlying zap logger.
+// See Options.ZapOpts.
+func RawZapOpts(zapOpts ...zap.Option) func(o *Options) {
+ return func(o *Options) {
+ o.ZapOpts = append(o.ZapOpts, zapOpts...)
+ }
+}
+
+// Options contains all possible settings.
+type Options struct {
+ // Development configures the logger to use a Zap development config
+ // (stacktraces on warnings, no sampling), otherwise a Zap production
+ // config will be used (stacktraces on errors, sampling).
+ Development bool
+ // Encoder configures how Zap will encode the output. Defaults to
+ // console when Development is true and JSON otherwise
+ Encoder zapcore.Encoder
+ // EncoderConfigOptions can modify the EncoderConfig needed to initialize an Encoder.
+ // See https://pkg.go.dev/go.uber.org/zap/zapcore#EncoderConfig for the list of options
+ // that can be configured.
+ // Note that the EncoderConfigOptions are not applied when the Encoder option is already set.
+ EncoderConfigOptions []EncoderConfigOption
+ // NewEncoder configures Encoder using the provided EncoderConfigOptions.
+ // Note that the NewEncoder function is not used when the Encoder option is already set.
+ NewEncoder NewEncoderFunc
+ // DestWriter controls the destination of the log output. Defaults to
+ // os.Stderr.
+ DestWriter io.Writer
+ // DestWritter controls the destination of the log output. Defaults to
+ // os.Stderr.
+ //
+ // Deprecated: Use DestWriter instead
+ DestWritter io.Writer
+ // Level configures the verbosity of the logging.
+ // Defaults to Debug when Development is true and Info otherwise.
+ // A zap log level should be multiplied by -1 to get the logr verbosity.
+ // For example, to get logr verbosity of 3, set this field to zapcore.Level(-3).
+ // See https://pkg.go.dev/github.com/go-logr/zapr for how zap level relates to logr verbosity.
+ Level zapcore.LevelEnabler
+ // StacktraceLevel is the level at and above which stacktraces will
+ // be recorded for all messages. Defaults to Warn when Development
+ // is true and Error otherwise.
+ // See Level for the relationship of zap log level to logr verbosity.
+ StacktraceLevel zapcore.LevelEnabler
+ // ZapOpts allows passing arbitrary zap.Options to configure on the
+ // underlying Zap logger.
+ ZapOpts []zap.Option
+ // TimeEncoder specifies the encoder for the timestamps in log messages.
+ // Defaults to RFC3339TimeEncoder.
+ TimeEncoder zapcore.TimeEncoder
+}
+
+// addDefaults adds defaults to the Options.
+func (o *Options) addDefaults() {
+ if o.DestWriter == nil && o.DestWritter == nil {
+ o.DestWriter = os.Stderr
+ } else if o.DestWriter == nil && o.DestWritter != nil {
+ // while misspelled DestWritter is deprecated but still not removed
+ o.DestWriter = o.DestWritter
+ }
+
+ if o.Development {
+ if o.NewEncoder == nil {
+ o.NewEncoder = newConsoleEncoder
+ }
+ if o.Level == nil {
+ lvl := zap.NewAtomicLevelAt(zap.DebugLevel)
+ o.Level = &lvl
+ }
+ if o.StacktraceLevel == nil {
+ lvl := zap.NewAtomicLevelAt(zap.WarnLevel)
+ o.StacktraceLevel = &lvl
+ }
+ o.ZapOpts = append(o.ZapOpts, zap.Development())
+ } else {
+ if o.NewEncoder == nil {
+ o.NewEncoder = newJSONEncoder
+ }
+ if o.Level == nil {
+ lvl := zap.NewAtomicLevelAt(zap.InfoLevel)
+ o.Level = &lvl
+ }
+ if o.StacktraceLevel == nil {
+ lvl := zap.NewAtomicLevelAt(zap.ErrorLevel)
+ o.StacktraceLevel = &lvl
+ }
+ // Disable sampling for increased Debug levels. Otherwise, this will
+ // cause index out of bounds errors in the sampling code.
+ if !o.Level.Enabled(zapcore.Level(-2)) {
+ o.ZapOpts = append(o.ZapOpts,
+ zap.WrapCore(func(core zapcore.Core) zapcore.Core {
+ return zapcore.NewSamplerWithOptions(core, time.Second, 100, 100)
+ }))
+ }
+ }
+
+ if o.TimeEncoder == nil {
+ o.TimeEncoder = zapcore.RFC3339TimeEncoder
+ }
+ f := func(ecfg *zapcore.EncoderConfig) {
+ ecfg.EncodeTime = o.TimeEncoder
+ }
+ // prepend instead of append it in case someone adds a time encoder option in it
+ o.EncoderConfigOptions = append([]EncoderConfigOption{f}, o.EncoderConfigOptions...)
+
+ if o.Encoder == nil {
+ o.Encoder = o.NewEncoder(o.EncoderConfigOptions...)
+ }
+ o.ZapOpts = append(o.ZapOpts, zap.AddStacktrace(o.StacktraceLevel))
+}
+
+// NewRaw returns a new zap.Logger configured with the passed Opts
+// or their defaults. It uses KubeAwareEncoder which adds Type
+// information and Namespace/Name to the log.
+func NewRaw(opts ...Opts) *zap.Logger {
+ o := &Options{}
+ for _, opt := range opts {
+ opt(o)
+ }
+ o.addDefaults()
+
+ // this basically mimics NewConfig, but with a custom sink
+ sink := zapcore.AddSync(o.DestWriter)
+
+ o.ZapOpts = append(o.ZapOpts, zap.ErrorOutput(sink))
+ log := zap.New(zapcore.NewCore(&KubeAwareEncoder{Encoder: o.Encoder, Verbose: o.Development}, sink, o.Level))
+ log = log.WithOptions(o.ZapOpts...)
+ return log
+}
+
+// BindFlags will parse the given flagset for zap option flags and set the log options accordingly:
+// - zap-devel:
+// Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn)
+// Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error)
+// - zap-encoder: Zap log encoding (one of 'json' or 'console')
+// - zap-log-level: Zap Level to configure the verbosity of logging. Can be one of 'debug', 'info', 'error',
+// or any integer value > 0 which corresponds to custom debug levels of increasing verbosity").
+// - zap-stacktrace-level: Zap Level at and above which stacktraces are captured (one of 'info', 'error' or 'panic')
+// - zap-time-encoding: Zap time encoding (one of 'epoch', 'millis', 'nano', 'iso8601', 'rfc3339' or 'rfc3339nano'),
+// Defaults to 'epoch'.
+func (o *Options) BindFlags(fs *flag.FlagSet) {
+ // Set Development mode value
+ fs.BoolVar(&o.Development, "zap-devel", o.Development,
+ "Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). "+
+ "Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error)")
+
+ // Set Encoder value
+ var encVal encoderFlag
+ encVal.setFunc = func(fromFlag NewEncoderFunc) {
+ o.NewEncoder = fromFlag
+ }
+ fs.Var(&encVal, "zap-encoder", "Zap log encoding (one of 'json' or 'console')")
+
+ // Set the Log Level
+ var levelVal levelFlag
+ levelVal.setFunc = func(fromFlag zapcore.LevelEnabler) {
+ o.Level = fromFlag
+ }
+ fs.Var(&levelVal, "zap-log-level",
+ "Zap Level to configure the verbosity of logging. Can be one of 'debug', 'info', 'error', "+
+ "or any integer value > 0 which corresponds to custom debug levels of increasing verbosity")
+
+ // Set the StrackTrace Level
+ var stackVal stackTraceFlag
+ stackVal.setFunc = func(fromFlag zapcore.LevelEnabler) {
+ o.StacktraceLevel = fromFlag
+ }
+ fs.Var(&stackVal, "zap-stacktrace-level",
+ "Zap Level at and above which stacktraces are captured (one of 'info', 'error', 'panic').")
+
+ // Set the time encoding
+ var timeEncoderVal timeEncodingFlag
+ timeEncoderVal.setFunc = func(fromFlag zapcore.TimeEncoder) {
+ o.TimeEncoder = fromFlag
+ }
+ fs.Var(&timeEncoderVal, "zap-time-encoding", "Zap time encoding (one of 'epoch', 'millis', 'nano', 'iso8601', 'rfc3339' or 'rfc3339nano'). Defaults to 'epoch'.")
+}
+
+// UseFlagOptions configures the logger to use the Options set by parsing zap option flags from the CLI.
+//
+// opts := zap.Options{}
+// opts.BindFlags(flag.CommandLine)
+// flag.Parse()
+// log := zap.New(zap.UseFlagOptions(&opts))
+func UseFlagOptions(in *Options) Opts {
+ return func(o *Options) {
+ *o = *in
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/zap_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/zap_suite_test.go
new file mode 100644
index 00000000000..d7a7f228664
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/zap_suite_test.go
@@ -0,0 +1,29 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package zap
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Zap Log Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/zap_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/zap_test.go
new file mode 100644
index 00000000000..f7fad41f061
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/log/zap/zap_test.go
@@ -0,0 +1,591 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package zap
+
+import (
+ "bytes"
+ "encoding/json"
+ "flag"
+ "os"
+ "reflect"
+
+ "github.com/go-logr/logr"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "go.uber.org/zap/zapcore"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/types"
+)
+
+// testStringer is a fmt.Stringer.
+type testStringer struct{}
+
+func (testStringer) String() string {
+ return "value"
+}
+
+// fakeSyncWriter is a fake zap.SyncerWriter that lets us test if sync was called.
+type fakeSyncWriter bool
+
+func (w *fakeSyncWriter) Write(p []byte) (int, error) {
+ return len(p), nil
+}
+
+func (w *fakeSyncWriter) Sync() error {
+ *w = true
+ return nil
+}
+
+// logInfo is the information for a particular fakeLogger message.
+type logInfo struct {
+ name []string
+ tags []interface{}
+ msg string
+}
+
+// fakeLoggerRoot is the root object to which all fakeLoggers record their messages.
+type fakeLoggerRoot struct {
+ messages []logInfo
+}
+
+var _ logr.LogSink = &fakeLogger{}
+
+// fakeLogger is a fake implementation of logr.Logger that records
+// messages, tags, and names,
+// just records the name.
+type fakeLogger struct {
+ name []string
+ tags []interface{}
+
+ root *fakeLoggerRoot
+}
+
+func (f *fakeLogger) Init(info logr.RuntimeInfo) {
+}
+
+func (f *fakeLogger) WithName(name string) logr.LogSink {
+ names := append([]string(nil), f.name...)
+ names = append(names, name)
+ return &fakeLogger{
+ name: names,
+ tags: f.tags,
+ root: f.root,
+ }
+}
+
+func (f *fakeLogger) WithValues(vals ...interface{}) logr.LogSink {
+ tags := append([]interface{}(nil), f.tags...)
+ tags = append(tags, vals...)
+ return &fakeLogger{
+ name: f.name,
+ tags: tags,
+ root: f.root,
+ }
+}
+
+func (f *fakeLogger) Error(err error, msg string, vals ...interface{}) {
+ tags := append([]interface{}(nil), f.tags...)
+ tags = append(tags, "error", err)
+ tags = append(tags, vals...)
+ f.root.messages = append(f.root.messages, logInfo{
+ name: append([]string(nil), f.name...),
+ tags: tags,
+ msg: msg,
+ })
+}
+
+func (f *fakeLogger) Info(level int, msg string, vals ...interface{}) {
+ tags := append([]interface{}(nil), f.tags...)
+ tags = append(tags, vals...)
+ f.root.messages = append(f.root.messages, logInfo{
+ name: append([]string(nil), f.name...),
+ tags: tags,
+ msg: msg,
+ })
+}
+
+func (f *fakeLogger) Enabled(level int) bool { return true }
+func (f *fakeLogger) V(lvl int) logr.LogSink { return f }
+
+var _ = Describe("Zap options setup", func() {
+ var opts *Options
+
+ BeforeEach(func() {
+ opts = &Options{}
+ })
+
+ It("should enable development mode", func() {
+ UseDevMode(true)(opts)
+ Expect(opts.Development).To(BeTrue())
+ })
+
+ It("should disable development mode", func() {
+ UseDevMode(false)(opts)
+ Expect(opts.Development).To(BeFalse())
+ })
+
+ It("should set a custom writer", func() {
+ var w fakeSyncWriter
+ WriteTo(&w)(opts)
+ Expect(opts.DestWriter).To(Equal(&w))
+ })
+})
+
+var _ = Describe("Zap logger setup", func() {
+ Context("when logging kubernetes objects", func() {
+ var logOut *bytes.Buffer
+ var logger logr.Logger
+
+ defineTests := func() {
+ It("should log a standard namespaced Kubernetes object name and namespace", func() {
+ pod := &corev1.Pod{}
+ pod.Name = "some-pod"
+ pod.Namespace = "some-ns"
+ logger.Info("here's a kubernetes object", "thing", pod)
+
+ outRaw := logOut.Bytes()
+ res := map[string]interface{}{}
+ Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
+
+ Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
+ "name": pod.Name,
+ "namespace": pod.Namespace,
+ }))
+ })
+
+ It("should work fine with normal stringers", func() {
+ logger.Info("here's a non-kubernetes stringer", "thing", testStringer{})
+ outRaw := logOut.Bytes()
+ res := map[string]interface{}{}
+ Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
+
+ Expect(res).To(HaveKeyWithValue("thing", "value"))
+ })
+
+ It("should log a standard non-namespaced Kubernetes object name", func() {
+ node := &corev1.Node{}
+ node.Name = "some-node"
+ logger.Info("here's a kubernetes object", "thing", node)
+
+ outRaw := logOut.Bytes()
+ res := map[string]interface{}{}
+ Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
+
+ Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
+ "name": node.Name,
+ }))
+ })
+
+ It("should log a standard Kubernetes object's kind, if set", func() {
+ node := &corev1.Node{}
+ node.Name = "some-node"
+ node.APIVersion = "v1"
+ node.Kind = "Node"
+ logger.Info("here's a kubernetes object", "thing", node)
+
+ outRaw := logOut.Bytes()
+ res := map[string]interface{}{}
+ Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
+
+ Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
+ "name": node.Name,
+ "apiVersion": "v1",
+ "kind": "Node",
+ }))
+ })
+
+ It("should log a standard non-namespaced NamespacedName name", func() {
+ name := types.NamespacedName{Name: "some-node"}
+ logger.Info("here's a kubernetes object", "thing", name)
+
+ outRaw := logOut.Bytes()
+ res := map[string]interface{}{}
+ Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
+
+ Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
+ "name": name.Name,
+ }))
+ })
+
+ It("should log an unstructured Kubernetes object", func() {
+ pod := &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "metadata": map[string]interface{}{
+ "name": "some-pod",
+ "namespace": "some-ns",
+ },
+ },
+ }
+ logger.Info("here's a kubernetes object", "thing", pod)
+
+ outRaw := logOut.Bytes()
+ res := map[string]interface{}{}
+ Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
+
+ Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
+ "name": "some-pod",
+ "namespace": "some-ns",
+ }))
+ })
+
+ It("should log a standard namespaced NamespacedName name and namespace", func() {
+ name := types.NamespacedName{Name: "some-pod", Namespace: "some-ns"}
+ logger.Info("here's a kubernetes object", "thing", name)
+
+ outRaw := logOut.Bytes()
+ res := map[string]interface{}{}
+ Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
+
+ Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
+ "name": name.Name,
+ "namespace": name.Namespace,
+ }))
+ })
+
+ It("should not panic with nil obj", func() {
+ var pod *corev1.Pod
+ logger.Info("here's a kubernetes object", "thing", pod)
+
+ outRaw := logOut.Bytes()
+ Expect(string(outRaw)).Should(ContainSubstring("got nil for runtime.Object"))
+ })
+ }
+
+ Context("with logger created using New", func() {
+ BeforeEach(func() {
+ logOut = new(bytes.Buffer)
+ By("setting up the logger")
+ // use production settings (false) to get just json output
+ logger = New(WriteTo(logOut), UseDevMode(false))
+ })
+ defineTests()
+ })
+ })
+})
+
+var _ = Describe("Zap log level flag options setup", func() {
+ var (
+ fromFlags Options
+ fs flag.FlagSet
+ logInfoLevel0 = "info text"
+ logDebugLevel1 = "debug 1 text"
+ logDebugLevel2 = "debug 2 text"
+ logDebugLevel3 = "debug 3 text"
+ )
+
+ BeforeEach(func() {
+ fromFlags = Options{}
+ fs = *flag.NewFlagSet(os.Args[0], flag.ExitOnError)
+ })
+
+ Context("with zap-log-level options provided", func() {
+ It("Should output logs for info and debug zap-log-level.", func() {
+ args := []string{"--zap-log-level=debug"}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).ToNot(HaveOccurred())
+ logOut := new(bytes.Buffer)
+
+ logger := New(UseFlagOptions(&fromFlags), WriteTo(logOut))
+ logger.V(0).Info(logInfoLevel0)
+ logger.V(1).Info(logDebugLevel1)
+
+ outRaw := logOut.Bytes()
+
+ Expect(string(outRaw)).Should(ContainSubstring(logInfoLevel0))
+ Expect(string(outRaw)).Should(ContainSubstring(logDebugLevel1))
+ })
+
+ It("Should output only error logs, otherwise empty logs", func() {
+ args := []string{"--zap-log-level=error"}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).ToNot(HaveOccurred())
+
+ logOut := new(bytes.Buffer)
+
+ logger := New(UseFlagOptions(&fromFlags), WriteTo(logOut))
+ logger.V(0).Info(logInfoLevel0)
+ logger.V(1).Info(logDebugLevel1)
+
+ outRaw := logOut.Bytes()
+
+ Expect(outRaw).To(BeEmpty())
+ })
+ })
+
+ Context("with zap-log-level with increased verbosity.", func() {
+ It("Should output debug and info log, with default production mode.", func() {
+ args := []string{"--zap-log-level=1"}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).ToNot(HaveOccurred())
+ logOut := new(bytes.Buffer)
+
+ logger := New(UseFlagOptions(&fromFlags), WriteTo(logOut))
+ logger.V(0).Info(logInfoLevel0)
+ logger.V(1).Info(logDebugLevel1)
+
+ outRaw := logOut.Bytes()
+
+ Expect(string(outRaw)).Should(ContainSubstring(logInfoLevel0))
+ Expect(string(outRaw)).Should(ContainSubstring(logDebugLevel1))
+ })
+
+ It("Should output info and debug logs, with development mode.", func() {
+ args := []string{"--zap-log-level=1", "--zap-devel=true"}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).ToNot(HaveOccurred())
+ logOut := new(bytes.Buffer)
+
+ logger := New(UseFlagOptions(&fromFlags), WriteTo(logOut))
+ logger.V(0).Info(logInfoLevel0)
+ logger.V(1).Info(logDebugLevel1)
+
+ outRaw := logOut.Bytes()
+
+ Expect(string(outRaw)).Should(ContainSubstring(logInfoLevel0))
+ Expect(string(outRaw)).Should(ContainSubstring(logDebugLevel1))
+ })
+
+ It("Should output info, and debug logs with increased verbosity, and with development mode set to true.", func() {
+ args := []string{"--zap-log-level=3", "--zap-devel=false"}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).ToNot(HaveOccurred())
+ logOut := new(bytes.Buffer)
+
+ logger := New(UseFlagOptions(&fromFlags), WriteTo(logOut))
+ logger.V(0).Info(logInfoLevel0)
+ logger.V(1).Info(logDebugLevel1)
+ logger.V(2).Info(logDebugLevel2)
+ logger.V(3).Info(logDebugLevel3)
+
+ outRaw := logOut.Bytes()
+
+ Expect(string(outRaw)).Should(ContainSubstring(logInfoLevel0))
+ Expect(string(outRaw)).Should(ContainSubstring(logDebugLevel1))
+ Expect(string(outRaw)).Should(ContainSubstring(logDebugLevel2))
+ Expect(string(outRaw)).Should(ContainSubstring(logDebugLevel3))
+ })
+ It("Should output info, and debug logs with increased verbosity, and with production mode set to true.", func() {
+ args := []string{"--zap-log-level=3", "--zap-devel=true"}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).ToNot(HaveOccurred())
+ logOut := new(bytes.Buffer)
+
+ logger := New(UseFlagOptions(&fromFlags), WriteTo(logOut))
+ logger.V(0).Info(logInfoLevel0)
+ logger.V(1).Info(logDebugLevel1)
+ logger.V(2).Info(logDebugLevel2)
+ logger.V(3).Info(logDebugLevel3)
+
+ outRaw := logOut.Bytes()
+
+ Expect(string(outRaw)).Should(ContainSubstring(logInfoLevel0))
+ Expect(string(outRaw)).Should(ContainSubstring(logDebugLevel1))
+ Expect(string(outRaw)).Should(ContainSubstring(logDebugLevel2))
+ Expect(string(outRaw)).Should(ContainSubstring(logDebugLevel3))
+ })
+ })
+
+ Context("with zap-stacktrace-level options provided", func() {
+ It("Should output stacktrace at info level, with development mode set to true.", func() {
+ args := []string{"--zap-stacktrace-level=info", "--zap-devel=true"}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).ToNot(HaveOccurred())
+ out := Options{}
+ UseFlagOptions(&fromFlags)(&out)
+
+ Expect(out.StacktraceLevel.Enabled(zapcore.InfoLevel)).To(BeTrue())
+ })
+
+ It("Should output stacktrace at error level, with development mode set to true.", func() {
+ args := []string{"--zap-stacktrace-level=error", "--zap-devel=true"}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).ToNot(HaveOccurred())
+ out := Options{}
+ UseFlagOptions(&fromFlags)(&out)
+
+ Expect(out.StacktraceLevel.Enabled(zapcore.ErrorLevel)).To(BeTrue())
+ })
+
+ It("Should output stacktrace at panic level, with development mode set to true.", func() {
+ args := []string{"--zap-stacktrace-level=panic", "--zap-devel=true"}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).ToNot(HaveOccurred())
+ out := Options{}
+ UseFlagOptions(&fromFlags)(&out)
+
+ Expect(out.StacktraceLevel.Enabled(zapcore.PanicLevel)).To(BeTrue())
+ Expect(out.StacktraceLevel.Enabled(zapcore.ErrorLevel)).To(BeFalse())
+ Expect(out.StacktraceLevel.Enabled(zapcore.InfoLevel)).To(BeFalse())
+ })
+ })
+
+ Context("with only -zap-devel flag provided", func() {
+ It("Should set dev=true.", func() {
+ args := []string{"--zap-devel=true"}
+ fromFlags.BindFlags(&fs)
+ if err := fs.Parse(args); err != nil {
+ Expect(err).ToNot(HaveOccurred())
+ }
+ out := Options{}
+ UseFlagOptions(&fromFlags)(&out)
+
+ Expect(out.Development).To(BeTrue())
+ Expect(out.Encoder).To(BeNil())
+ Expect(out.Level).To(BeNil())
+ Expect(out.StacktraceLevel).To(BeNil())
+ Expect(out.EncoderConfigOptions).To(BeNil())
+ })
+ It("Should set dev=false", func() {
+ args := []string{"--zap-devel=false"}
+ fromFlags.BindFlags(&fs)
+ if err := fs.Parse(args); err != nil {
+ Expect(err).ToNot(HaveOccurred())
+ }
+ out := Options{}
+ UseFlagOptions(&fromFlags)(&out)
+
+ Expect(out.Development).To(BeFalse())
+ Expect(out.Encoder).To(BeNil())
+ Expect(out.Level).To(BeNil())
+ Expect(out.StacktraceLevel).To(BeNil())
+ Expect(out.EncoderConfigOptions).To(BeNil())
+ })
+ })
+
+ Context("with zap-time-encoding flag provided", func() {
+ It("Should set time encoder in options", func() {
+ args := []string{"--zap-time-encoding=rfc3339"}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).ToNot(HaveOccurred())
+
+ opt := Options{}
+ UseFlagOptions(&fromFlags)(&opt)
+ opt.addDefaults()
+
+ optVal := reflect.ValueOf(opt.TimeEncoder)
+ expVal := reflect.ValueOf(zapcore.RFC3339TimeEncoder)
+
+ Expect(optVal.Pointer()).To(Equal(expVal.Pointer()))
+ })
+
+ It("Should default to 'rfc3339' time encoding", func() {
+ args := []string{""}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).ToNot(HaveOccurred())
+
+ opt := Options{}
+ UseFlagOptions(&fromFlags)(&opt)
+ opt.addDefaults()
+
+ optVal := reflect.ValueOf(opt.TimeEncoder)
+ expVal := reflect.ValueOf(zapcore.RFC3339TimeEncoder)
+
+ Expect(optVal.Pointer()).To(Equal(expVal.Pointer()))
+ })
+
+ It("Should return an error message, with unknown time-encoding", func() {
+ fs = *flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
+ args := []string{"--zap-time-encoding=foobar"}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).To(HaveOccurred())
+ })
+
+ It("Should propagate time encoder to logger", func() {
+ // zaps ISO8601TimeEncoder uses 2006-01-02T15:04:05.000Z0700 as pattern for iso8601 encoding
+ iso8601Pattern := `^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}([-+][0-9]{4}|Z)`
+
+ args := []string{"--zap-time-encoding=iso8601"}
+ fromFlags.BindFlags(&fs)
+ err := fs.Parse(args)
+ Expect(err).ToNot(HaveOccurred())
+ logOut := new(bytes.Buffer)
+
+ logger := New(UseFlagOptions(&fromFlags), WriteTo(logOut))
+ logger.Info("This is a test message")
+
+ outRaw := logOut.Bytes()
+
+ res := map[string]interface{}{}
+ Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
+ Expect(res["ts"]).Should(MatchRegexp(iso8601Pattern))
+ })
+ })
+
+ Context("with encoder options provided programmatically", func() {
+ It("Should set JSON Encoder, with given Millis TimeEncoder option, and MessageKey", func() {
+ logOut := new(bytes.Buffer)
+ f := func(ec *zapcore.EncoderConfig) {
+ ec.MessageKey = "MillisTimeFormat"
+ }
+ opts := func(o *Options) {
+ o.EncoderConfigOptions = append(o.EncoderConfigOptions, f)
+ }
+ log := New(UseDevMode(false), WriteTo(logOut), opts)
+ log.Info("This is a test message")
+ outRaw := logOut.Bytes()
+ // Assert for JSON Encoder
+ res := map[string]interface{}{}
+ Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
+ // Assert for MessageKey
+ Expect(string(outRaw)).Should(ContainSubstring("MillisTimeFormat"))
+ })
+
+ Context("using Level()", func() {
+ var logOut *bytes.Buffer
+
+ BeforeEach(func() {
+ logOut = new(bytes.Buffer)
+ })
+
+ It("logs with negative logr level", func() {
+ By("setting up the logger")
+ logger := New(WriteTo(logOut), Level(zapcore.Level(-3)))
+ logger.V(3).Info("test 3") // Should be logged
+ Expect(logOut.String()).To(ContainSubstring(`"msg":"test 3"`))
+ logOut.Truncate(0)
+ logger.V(1).Info("test 1") // Should be logged
+ Expect(logOut.String()).To(ContainSubstring(`"msg":"test 1"`))
+ logOut.Truncate(0)
+ logger.V(4).Info("test 4") // Should not be logged
+ Expect(logOut.String()).To(BeEmpty())
+ logger.V(-3).Info("test -3")
+ Expect(logOut.String()).To(ContainSubstring("test -3"))
+ })
+ It("does not log with positive logr level", func() {
+ By("setting up the logger")
+ logger := New(WriteTo(logOut), Level(zapcore.Level(1)))
+ logger.V(1).Info("test 1")
+ Expect(logOut.String()).To(BeEmpty())
+ logger.V(3).Info("test 3")
+ Expect(logOut.String()).To(BeEmpty())
+ })
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/doc.go
new file mode 100644
index 00000000000..f2976c7f754
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/doc.go
@@ -0,0 +1,21 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package manager is required to create Controllers and provides shared dependencies such as clients, caches, schemes,
+etc. Controllers must be started by calling Manager.Start.
+*/
+package manager
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/example_test.go
new file mode 100644
index 00000000000..06712d71715
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/example_test.go
@@ -0,0 +1,133 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package manager_test
+
+import (
+ "context"
+ "os"
+
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client/config"
+ conf "sigs.k8s.io/controller-runtime/pkg/config"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/manager/signals"
+)
+
+var (
+ mgr manager.Manager
+ // NB: don't call SetLogger in init(), or else you'll mess up logging in the main suite.
+ log = logf.Log.WithName("manager-examples")
+)
+
+// This example creates a new Manager that can be used with controller.New to create Controllers.
+func ExampleNew() {
+ cfg, err := config.GetConfig()
+ if err != nil {
+ log.Error(err, "unable to get kubeconfig")
+ os.Exit(1)
+ }
+
+ mgr, err := manager.New(cfg, manager.Options{})
+ if err != nil {
+ log.Error(err, "unable to set up manager")
+ os.Exit(1)
+ }
+ log.Info("created manager", "manager", mgr)
+}
+
+// This example creates a new Manager that has a cache scoped to a list of namespaces.
+func ExampleNew_limitToNamespaces() {
+ cfg, err := config.GetConfig()
+ if err != nil {
+ log.Error(err, "unable to get kubeconfig")
+ os.Exit(1)
+ }
+
+ mgr, err := manager.New(cfg, manager.Options{
+ NewCache: func(config *rest.Config, opts cache.Options) (cache.Cache, error) {
+ opts.Namespaces = []string{"namespace1", "namespace2"}
+ return cache.New(config, opts)
+ }},
+ )
+ if err != nil {
+ log.Error(err, "unable to set up manager")
+ os.Exit(1)
+ }
+ log.Info("created manager", "manager", mgr)
+}
+
+// This example adds a Runnable for the Manager to Start.
+func ExampleManager_add() {
+ err := mgr.Add(manager.RunnableFunc(func(context.Context) error {
+ // Do something
+ return nil
+ }))
+ if err != nil {
+ log.Error(err, "unable add a runnable to the manager")
+ os.Exit(1)
+ }
+}
+
+// This example starts a Manager that has had Runnables added.
+func ExampleManager_start() {
+ if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+ log.Error(err, "unable start the manager")
+ os.Exit(1)
+ }
+}
+
+// This example will populate Options from a custom config file
+// using defaults.
+func ExampleOptions_andFrom() {
+ opts := manager.Options{}
+ if _, err := opts.AndFrom(conf.File()); err != nil {
+ log.Error(err, "unable to load config")
+ os.Exit(1)
+ }
+
+ cfg, err := config.GetConfig()
+ if err != nil {
+ log.Error(err, "unable to get kubeconfig")
+ os.Exit(1)
+ }
+
+ mgr, err := manager.New(cfg, opts)
+ if err != nil {
+ log.Error(err, "unable to set up manager")
+ os.Exit(1)
+ }
+ log.Info("created manager", "manager", mgr)
+}
+
+// This example will populate Options from a custom config file
+// using defaults and will panic if there are errors.
+func ExampleOptions_andFromOrDie() {
+ cfg, err := config.GetConfig()
+ if err != nil {
+ log.Error(err, "unable to get kubeconfig")
+ os.Exit(1)
+ }
+
+ mgr, err := manager.New(cfg, manager.Options{}.AndFromOrDie(conf.File()))
+ if err != nil {
+ log.Error(err, "unable to set up manager")
+ os.Exit(1)
+ }
+ log.Info("created manager", "manager", mgr)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/internal.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/internal.go
new file mode 100644
index 00000000000..f298229e570
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/internal.go
@@ -0,0 +1,667 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package manager
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net"
+ "net/http"
+ "net/http/pprof"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/go-logr/logr"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ kerrors "k8s.io/apimachinery/pkg/util/errors"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/leaderelection"
+ "k8s.io/client-go/tools/leaderelection/resourcelock"
+ "k8s.io/client-go/tools/record"
+
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/cluster"
+ "sigs.k8s.io/controller-runtime/pkg/config"
+ "sigs.k8s.io/controller-runtime/pkg/healthz"
+ "sigs.k8s.io/controller-runtime/pkg/internal/httpserver"
+ intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+const (
+ // Values taken from: https://github.com/kubernetes/component-base/blob/master/config/v1alpha1/defaults.go
+ defaultLeaseDuration = 15 * time.Second
+ defaultRenewDeadline = 10 * time.Second
+ defaultRetryPeriod = 2 * time.Second
+ defaultGracefulShutdownPeriod = 30 * time.Second
+
+ defaultReadinessEndpoint = "/readyz"
+ defaultLivenessEndpoint = "/healthz"
+ defaultMetricsEndpoint = "/metrics"
+)
+
+var _ Runnable = &controllerManager{}
+
+type controllerManager struct {
+ sync.Mutex
+ started bool
+
+ stopProcedureEngaged *int64
+ errChan chan error
+ runnables *runnables
+
+ // cluster holds a variety of methods to interact with a cluster. Required.
+ cluster cluster.Cluster
+
+ // recorderProvider is used to generate event recorders that will be injected into Controllers
+ // (and EventHandlers, Sources and Predicates).
+ recorderProvider *intrec.Provider
+
+ // resourceLock forms the basis for leader election
+ resourceLock resourcelock.Interface
+
+ // leaderElectionReleaseOnCancel defines if the manager should step back from the leader lease
+ // on shutdown
+ leaderElectionReleaseOnCancel bool
+
+ // metricsListener is used to serve prometheus metrics
+ metricsListener net.Listener
+
+ // metricsExtraHandlers contains extra handlers to register on http server that serves metrics.
+ metricsExtraHandlers map[string]http.Handler
+
+ // healthProbeListener is used to serve liveness probe
+ healthProbeListener net.Listener
+
+ // Readiness probe endpoint name
+ readinessEndpointName string
+
+ // Liveness probe endpoint name
+ livenessEndpointName string
+
+ // Readyz probe handler
+ readyzHandler *healthz.Handler
+
+ // Healthz probe handler
+ healthzHandler *healthz.Handler
+
+ // pprofListener is used to serve pprof
+ pprofListener net.Listener
+
+ // controllerConfig are the global controller options.
+ controllerConfig config.Controller
+
+ // Logger is the logger that should be used by this manager.
+ // If none is set, it defaults to log.Log global logger.
+ logger logr.Logger
+
+ // leaderElectionStopped is an internal channel used to signal the stopping procedure that the
+ // LeaderElection.Run(...) function has returned and the shutdown can proceed.
+ leaderElectionStopped chan struct{}
+
+ // leaderElectionCancel is used to cancel the leader election. It is distinct from internalStopper,
+ // because for safety reasons we need to os.Exit() when we lose the leader election, meaning that
+ // it must be deferred until after gracefulShutdown is done.
+ leaderElectionCancel context.CancelFunc
+
+ // elected is closed when this manager becomes the leader of a group of
+ // managers, either because it won a leader election or because no leader
+ // election was configured.
+ elected chan struct{}
+
+ webhookServer webhook.Server
+ // webhookServerOnce will be called in GetWebhookServer() to optionally initialize
+ // webhookServer if unset, and Add() it to controllerManager.
+ webhookServerOnce sync.Once
+
+ // leaderElectionID is the name of the resource that leader election
+ // will use for holding the leader lock.
+ leaderElectionID string
+ // leaseDuration is the duration that non-leader candidates will
+ // wait to force acquire leadership.
+ leaseDuration time.Duration
+ // renewDeadline is the duration that the acting controlplane will retry
+ // refreshing leadership before giving up.
+ renewDeadline time.Duration
+ // retryPeriod is the duration the LeaderElector clients should wait
+ // between tries of actions.
+ retryPeriod time.Duration
+
+ // gracefulShutdownTimeout is the duration given to runnable to stop
+ // before the manager actually returns on stop.
+ gracefulShutdownTimeout time.Duration
+
+ // onStoppedLeading is callled when the leader election lease is lost.
+ // It can be overridden for tests.
+ onStoppedLeading func()
+
+ // shutdownCtx is the context that can be used during shutdown. It will be cancelled
+ // after the gracefulShutdownTimeout ended. It must not be accessed before internalStop
+ // is closed because it will be nil.
+ shutdownCtx context.Context
+
+ internalCtx context.Context
+ internalCancel context.CancelFunc
+
+ // internalProceduresStop channel is used internally to the manager when coordinating
+ // the proper shutdown of servers. This channel is also used for dependency injection.
+ internalProceduresStop chan struct{}
+}
+
+type hasCache interface {
+ Runnable
+ GetCache() cache.Cache
+}
+
+// Add sets dependencies on i, and adds it to the list of Runnables to start.
+func (cm *controllerManager) Add(r Runnable) error {
+ cm.Lock()
+ defer cm.Unlock()
+ return cm.add(r)
+}
+
+func (cm *controllerManager) add(r Runnable) error {
+ return cm.runnables.Add(r)
+}
+
+// AddMetricsExtraHandler adds extra handler served on path to the http server that serves metrics.
+func (cm *controllerManager) AddMetricsExtraHandler(path string, handler http.Handler) error {
+ cm.Lock()
+ defer cm.Unlock()
+
+ if cm.started {
+ return fmt.Errorf("unable to add new metrics handler because metrics endpoint has already been created")
+ }
+
+ if path == defaultMetricsEndpoint {
+ return fmt.Errorf("overriding builtin %s endpoint is not allowed", defaultMetricsEndpoint)
+ }
+
+ if _, found := cm.metricsExtraHandlers[path]; found {
+ return fmt.Errorf("can't register extra handler by duplicate path %q on metrics http server", path)
+ }
+
+ cm.metricsExtraHandlers[path] = handler
+ cm.logger.V(2).Info("Registering metrics http server extra handler", "path", path)
+ return nil
+}
+
+// AddHealthzCheck allows you to add Healthz checker.
+func (cm *controllerManager) AddHealthzCheck(name string, check healthz.Checker) error {
+ cm.Lock()
+ defer cm.Unlock()
+
+ if cm.started {
+ return fmt.Errorf("unable to add new checker because healthz endpoint has already been created")
+ }
+
+ if cm.healthzHandler == nil {
+ cm.healthzHandler = &healthz.Handler{Checks: map[string]healthz.Checker{}}
+ }
+
+ cm.healthzHandler.Checks[name] = check
+ return nil
+}
+
+// AddReadyzCheck allows you to add Readyz checker.
+func (cm *controllerManager) AddReadyzCheck(name string, check healthz.Checker) error {
+ cm.Lock()
+ defer cm.Unlock()
+
+ if cm.started {
+ return fmt.Errorf("unable to add new checker because healthz endpoint has already been created")
+ }
+
+ if cm.readyzHandler == nil {
+ cm.readyzHandler = &healthz.Handler{Checks: map[string]healthz.Checker{}}
+ }
+
+ cm.readyzHandler.Checks[name] = check
+ return nil
+}
+
+func (cm *controllerManager) GetHTTPClient() *http.Client {
+ return cm.cluster.GetHTTPClient()
+}
+
+func (cm *controllerManager) GetConfig() *rest.Config {
+ return cm.cluster.GetConfig()
+}
+
+func (cm *controllerManager) GetClient() client.Client {
+ return cm.cluster.GetClient()
+}
+
+func (cm *controllerManager) GetScheme() *runtime.Scheme {
+ return cm.cluster.GetScheme()
+}
+
+func (cm *controllerManager) GetFieldIndexer() client.FieldIndexer {
+ return cm.cluster.GetFieldIndexer()
+}
+
+func (cm *controllerManager) GetCache() cache.Cache {
+ return cm.cluster.GetCache()
+}
+
+func (cm *controllerManager) GetEventRecorderFor(name string) record.EventRecorder {
+ return cm.cluster.GetEventRecorderFor(name)
+}
+
+func (cm *controllerManager) GetRESTMapper() meta.RESTMapper {
+ return cm.cluster.GetRESTMapper()
+}
+
+func (cm *controllerManager) GetAPIReader() client.Reader {
+ return cm.cluster.GetAPIReader()
+}
+
+func (cm *controllerManager) GetWebhookServer() webhook.Server {
+ cm.webhookServerOnce.Do(func() {
+ if cm.webhookServer == nil {
+ panic("webhook should not be nil")
+ }
+ if err := cm.Add(cm.webhookServer); err != nil {
+ panic(fmt.Sprintf("unable to add webhook server to the controller manager: %s", err))
+ }
+ })
+ return cm.webhookServer
+}
+
+func (cm *controllerManager) GetLogger() logr.Logger {
+ return cm.logger
+}
+
+func (cm *controllerManager) GetControllerOptions() config.Controller {
+ return cm.controllerConfig
+}
+
+func (cm *controllerManager) addMetricsServer() error {
+ mux := http.NewServeMux()
+ srv := httpserver.New(mux)
+
+ handler := promhttp.HandlerFor(metrics.Registry, promhttp.HandlerOpts{
+ ErrorHandling: promhttp.HTTPErrorOnError,
+ })
+ // TODO(JoelSpeed): Use existing Kubernetes machinery for serving metrics
+ mux.Handle(defaultMetricsEndpoint, handler)
+ for path, extraHandler := range cm.metricsExtraHandlers {
+ mux.Handle(path, extraHandler)
+ }
+
+ return cm.add(&server{
+ Kind: "metrics",
+ Log: cm.logger.WithValues("path", defaultMetricsEndpoint),
+ Server: srv,
+ Listener: cm.metricsListener,
+ })
+}
+
+func (cm *controllerManager) serveHealthProbes() {
+ mux := http.NewServeMux()
+ server := httpserver.New(mux)
+
+ if cm.readyzHandler != nil {
+ mux.Handle(cm.readinessEndpointName, http.StripPrefix(cm.readinessEndpointName, cm.readyzHandler))
+ // Append '/' suffix to handle subpaths
+ mux.Handle(cm.readinessEndpointName+"/", http.StripPrefix(cm.readinessEndpointName, cm.readyzHandler))
+ }
+ if cm.healthzHandler != nil {
+ mux.Handle(cm.livenessEndpointName, http.StripPrefix(cm.livenessEndpointName, cm.healthzHandler))
+ // Append '/' suffix to handle subpaths
+ mux.Handle(cm.livenessEndpointName+"/", http.StripPrefix(cm.livenessEndpointName, cm.healthzHandler))
+ }
+
+ go cm.httpServe("health probe", cm.logger, server, cm.healthProbeListener)
+}
+
+func (cm *controllerManager) addPprofServer() error {
+ mux := http.NewServeMux()
+ srv := httpserver.New(mux)
+
+ mux.HandleFunc("/debug/pprof/", pprof.Index)
+ mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
+ mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
+ mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
+ mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
+
+ return cm.add(&server{
+ Kind: "pprof",
+ Log: cm.logger,
+ Server: srv,
+ Listener: cm.pprofListener,
+ })
+}
+
+func (cm *controllerManager) httpServe(kind string, log logr.Logger, server *http.Server, ln net.Listener) {
+ log = log.WithValues("kind", kind, "addr", ln.Addr())
+
+ go func() {
+ log.Info("Starting server")
+ if err := server.Serve(ln); err != nil {
+ if errors.Is(err, http.ErrServerClosed) {
+ return
+ }
+ if atomic.LoadInt64(cm.stopProcedureEngaged) > 0 {
+ // There might be cases where connections are still open and we try to shutdown
+ // but not having enough time to close the connection causes an error in Serve
+ //
+ // In that case we want to avoid returning an error to the main error channel.
+ log.Error(err, "error on Serve after stop has been engaged")
+ return
+ }
+ cm.errChan <- err
+ }
+ }()
+
+ // Shutdown the server when stop is closed.
+ <-cm.internalProceduresStop
+ if err := server.Shutdown(cm.shutdownCtx); err != nil {
+ if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
+ // Avoid logging context related errors.
+ return
+ }
+ if atomic.LoadInt64(cm.stopProcedureEngaged) > 0 {
+ cm.logger.Error(err, "error on Shutdown after stop has been engaged")
+ return
+ }
+ cm.errChan <- err
+ }
+}
+
+// Start starts the manager and waits indefinitely.
+// There is only two ways to have start return:
+// An error has occurred during in one of the internal operations,
+// such as leader election, cache start, webhooks, and so on.
+// Or, the context is cancelled.
+func (cm *controllerManager) Start(ctx context.Context) (err error) {
+ cm.Lock()
+ if cm.started {
+ cm.Unlock()
+ return errors.New("manager already started")
+ }
+ cm.started = true
+
+ var ready bool
+ defer func() {
+ // Only unlock the manager if we haven't reached
+ // the internal readiness condition.
+ if !ready {
+ cm.Unlock()
+ }
+ }()
+
+ // Initialize the internal context.
+ cm.internalCtx, cm.internalCancel = context.WithCancel(ctx)
+
+ // This chan indicates that stop is complete, in other words all runnables have returned or timeout on stop request
+ stopComplete := make(chan struct{})
+ defer close(stopComplete)
+ // This must be deferred after closing stopComplete, otherwise we deadlock.
+ defer func() {
+ // https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/gettyimages-459889618-1533579787.jpg
+ stopErr := cm.engageStopProcedure(stopComplete)
+ if stopErr != nil {
+ if err != nil {
+ // Utilerrors.Aggregate allows to use errors.Is for all contained errors
+ // whereas fmt.Errorf allows wrapping at most one error which means the
+ // other one can not be found anymore.
+ err = kerrors.NewAggregate([]error{err, stopErr})
+ } else {
+ err = stopErr
+ }
+ }
+ }()
+
+ // Add the cluster runnable.
+ if err := cm.add(cm.cluster); err != nil {
+ return fmt.Errorf("failed to add cluster to runnables: %w", err)
+ }
+
+ // Metrics should be served whether the controller is leader or not.
+ // (If we don't serve metrics for non-leaders, prometheus will still scrape
+ // the pod but will get a connection refused).
+ if cm.metricsListener != nil {
+ if err := cm.addMetricsServer(); err != nil {
+ return fmt.Errorf("failed to add metrics server: %w", err)
+ }
+ }
+
+ // Serve health probes.
+ if cm.healthProbeListener != nil {
+ cm.serveHealthProbes()
+ }
+
+ // Add pprof server
+ if cm.pprofListener != nil {
+ if err := cm.addPprofServer(); err != nil {
+ return fmt.Errorf("failed to add pprof server: %w", err)
+ }
+ }
+
+ // First start any webhook servers, which includes conversion, validation, and defaulting
+ // webhooks that are registered.
+ //
+ // WARNING: Webhooks MUST start before any cache is populated, otherwise there is a race condition
+ // between conversion webhooks and the cache sync (usually initial list) which causes the webhooks
+ // to never start because no cache can be populated.
+ if err := cm.runnables.Webhooks.Start(cm.internalCtx); err != nil {
+ if err != nil {
+ return fmt.Errorf("failed to start webhooks: %w", err)
+ }
+ }
+
+ // Start and wait for caches.
+ if err := cm.runnables.Caches.Start(cm.internalCtx); err != nil {
+ if err != nil {
+ return fmt.Errorf("failed to start caches: %w", err)
+ }
+ }
+
+ // Start the non-leaderelection Runnables after the cache has synced.
+ if err := cm.runnables.Others.Start(cm.internalCtx); err != nil {
+ if err != nil {
+ return fmt.Errorf("failed to start other runnables: %w", err)
+ }
+ }
+
+ // Start the leader election and all required runnables.
+ {
+ ctx, cancel := context.WithCancel(context.Background())
+ cm.leaderElectionCancel = cancel
+ go func() {
+ if cm.resourceLock != nil {
+ if err := cm.startLeaderElection(ctx); err != nil {
+ cm.errChan <- err
+ }
+ } else {
+ // Treat not having leader election enabled the same as being elected.
+ if err := cm.startLeaderElectionRunnables(); err != nil {
+ cm.errChan <- err
+ }
+ close(cm.elected)
+ }
+ }()
+ }
+
+ ready = true
+ cm.Unlock()
+ select {
+ case <-ctx.Done():
+ // We are done
+ return nil
+ case err := <-cm.errChan:
+ // Error starting or running a runnable
+ return err
+ }
+}
+
+// engageStopProcedure signals all runnables to stop, reads potential errors
+// from the errChan and waits for them to end. It must not be called more than once.
+func (cm *controllerManager) engageStopProcedure(stopComplete <-chan struct{}) error {
+ if !atomic.CompareAndSwapInt64(cm.stopProcedureEngaged, 0, 1) {
+ return errors.New("stop procedure already engaged")
+ }
+
+ // Populate the shutdown context, this operation MUST be done before
+ // closing the internalProceduresStop channel.
+ //
+ // The shutdown context immediately expires if the gracefulShutdownTimeout is not set.
+ var shutdownCancel context.CancelFunc
+ if cm.gracefulShutdownTimeout < 0 {
+ // We want to wait forever for the runnables to stop.
+ cm.shutdownCtx, shutdownCancel = context.WithCancel(context.Background())
+ } else {
+ cm.shutdownCtx, shutdownCancel = context.WithTimeout(context.Background(), cm.gracefulShutdownTimeout)
+ }
+ defer shutdownCancel()
+
+ // Start draining the errors before acquiring the lock to make sure we don't deadlock
+ // if something that has the lock is blocked on trying to write into the unbuffered
+ // channel after something else already wrote into it.
+ var closeOnce sync.Once
+ go func() {
+ for {
+ // Closing in the for loop is required to avoid race conditions between
+ // the closure of all internal procedures and making sure to have a reader off the error channel.
+ closeOnce.Do(func() {
+ // Cancel the internal stop channel and wait for the procedures to stop and complete.
+ close(cm.internalProceduresStop)
+ cm.internalCancel()
+ })
+ select {
+ case err, ok := <-cm.errChan:
+ if ok {
+ cm.logger.Error(err, "error received after stop sequence was engaged")
+ }
+ case <-stopComplete:
+ return
+ }
+ }
+ }()
+
+ // We want to close this after the other runnables stop, because we don't
+ // want things like leader election to try and emit events on a closed
+ // channel
+ defer cm.recorderProvider.Stop(cm.shutdownCtx)
+ defer func() {
+ // Cancel leader election only after we waited. It will os.Exit() the app for safety.
+ if cm.resourceLock != nil {
+ // After asking the context to be cancelled, make sure
+ // we wait for the leader stopped channel to be closed, otherwise
+ // we might encounter race conditions between this code
+ // and the event recorder, which is used within leader election code.
+ cm.leaderElectionCancel()
+ <-cm.leaderElectionStopped
+ }
+ }()
+
+ go func() {
+ // First stop the non-leader election runnables.
+ cm.logger.Info("Stopping and waiting for non leader election runnables")
+ cm.runnables.Others.StopAndWait(cm.shutdownCtx)
+
+ // Stop all the leader election runnables, which includes reconcilers.
+ cm.logger.Info("Stopping and waiting for leader election runnables")
+ cm.runnables.LeaderElection.StopAndWait(cm.shutdownCtx)
+
+ // Stop the caches before the leader election runnables, this is an important
+ // step to make sure that we don't race with the reconcilers by receiving more events
+ // from the API servers and enqueueing them.
+ cm.logger.Info("Stopping and waiting for caches")
+ cm.runnables.Caches.StopAndWait(cm.shutdownCtx)
+
+ // Webhooks should come last, as they might be still serving some requests.
+ cm.logger.Info("Stopping and waiting for webhooks")
+ cm.runnables.Webhooks.StopAndWait(cm.shutdownCtx)
+
+ // Proceed to close the manager and overall shutdown context.
+ cm.logger.Info("Wait completed, proceeding to shutdown the manager")
+ shutdownCancel()
+ }()
+
+ <-cm.shutdownCtx.Done()
+ if err := cm.shutdownCtx.Err(); err != nil && !errors.Is(err, context.Canceled) {
+ if errors.Is(err, context.DeadlineExceeded) {
+ if cm.gracefulShutdownTimeout > 0 {
+ return fmt.Errorf("failed waiting for all runnables to end within grace period of %s: %w", cm.gracefulShutdownTimeout, err)
+ }
+ return nil
+ }
+ // For any other error, return the error.
+ return err
+ }
+
+ return nil
+}
+
+func (cm *controllerManager) startLeaderElectionRunnables() error {
+ return cm.runnables.LeaderElection.Start(cm.internalCtx)
+}
+
+func (cm *controllerManager) startLeaderElection(ctx context.Context) (err error) {
+ l, err := leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{
+ Lock: cm.resourceLock,
+ LeaseDuration: cm.leaseDuration,
+ RenewDeadline: cm.renewDeadline,
+ RetryPeriod: cm.retryPeriod,
+ Callbacks: leaderelection.LeaderCallbacks{
+ OnStartedLeading: func(_ context.Context) {
+ if err := cm.startLeaderElectionRunnables(); err != nil {
+ cm.errChan <- err
+ return
+ }
+ close(cm.elected)
+ },
+ OnStoppedLeading: func() {
+ if cm.onStoppedLeading != nil {
+ cm.onStoppedLeading()
+ }
+ // Make sure graceful shutdown is skipped if we lost the leader lock without
+ // intending to.
+ cm.gracefulShutdownTimeout = time.Duration(0)
+ // Most implementations of leader election log.Fatal() here.
+ // Since Start is wrapped in log.Fatal when called, we can just return
+ // an error here which will cause the program to exit.
+ cm.errChan <- errors.New("leader election lost")
+ },
+ },
+ ReleaseOnCancel: cm.leaderElectionReleaseOnCancel,
+ Name: cm.leaderElectionID,
+ })
+ if err != nil {
+ return err
+ }
+
+ // Start the leader elector process
+ go func() {
+ l.Run(ctx)
+ <-ctx.Done()
+ close(cm.leaderElectionStopped)
+ }()
+ return nil
+}
+
+func (cm *controllerManager) Elected() <-chan struct{} {
+ return cm.elected
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/manager.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/manager.go
new file mode 100644
index 00000000000..7e65ef0c3ac
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/manager.go
@@ -0,0 +1,746 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package manager
+
+import (
+ "context"
+ "crypto/tls"
+ "fmt"
+ "net"
+ "net/http"
+ "reflect"
+ "time"
+
+ "github.com/go-logr/logr"
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/leaderelection/resourcelock"
+ "k8s.io/client-go/tools/record"
+ "k8s.io/utils/pointer"
+
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/cluster"
+ "sigs.k8s.io/controller-runtime/pkg/config"
+ "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
+ "sigs.k8s.io/controller-runtime/pkg/healthz"
+ intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
+ "sigs.k8s.io/controller-runtime/pkg/leaderelection"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+ "sigs.k8s.io/controller-runtime/pkg/recorder"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+// Manager initializes shared dependencies such as Caches and Clients, and provides them to Runnables.
+// A Manager is required to create Controllers.
+type Manager interface {
+ // Cluster holds a variety of methods to interact with a cluster.
+ cluster.Cluster
+
+ // Add will set requested dependencies on the component, and cause the component to be
+ // started when Start is called.
+ // Depending on if a Runnable implements LeaderElectionRunnable interface, a Runnable can be run in either
+ // non-leaderelection mode (always running) or leader election mode (managed by leader election if enabled).
+ Add(Runnable) error
+
+ // Elected is closed when this manager is elected leader of a group of
+ // managers, either because it won a leader election or because no leader
+ // election was configured.
+ Elected() <-chan struct{}
+
+ // AddMetricsExtraHandler adds an extra handler served on path to the http server that serves metrics.
+ // Might be useful to register some diagnostic endpoints e.g. pprof. Note that these endpoints meant to be
+ // sensitive and shouldn't be exposed publicly.
+ // If the simple path -> handler mapping offered here is not enough, a new http server/listener should be added as
+ // Runnable to the manager via Add method.
+ AddMetricsExtraHandler(path string, handler http.Handler) error
+
+ // AddHealthzCheck allows you to add Healthz checker
+ AddHealthzCheck(name string, check healthz.Checker) error
+
+ // AddReadyzCheck allows you to add Readyz checker
+ AddReadyzCheck(name string, check healthz.Checker) error
+
+ // Start starts all registered Controllers and blocks until the context is cancelled.
+ // Returns an error if there is an error starting any controller.
+ //
+ // If LeaderElection is used, the binary must be exited immediately after this returns,
+ // otherwise components that need leader election might continue to run after the leader
+ // lock was lost.
+ Start(ctx context.Context) error
+
+ // GetWebhookServer returns a webhook.Server
+ GetWebhookServer() webhook.Server
+
+ // GetLogger returns this manager's logger.
+ GetLogger() logr.Logger
+
+ // GetControllerOptions returns controller global configuration options.
+ GetControllerOptions() config.Controller
+}
+
+// Options are the arguments for creating a new Manager.
+type Options struct {
+ // Scheme is the scheme used to resolve runtime.Objects to GroupVersionKinds / Resources.
+ // Defaults to the kubernetes/client-go scheme.Scheme, but it's almost always better
+ // to pass your own scheme in. See the documentation in pkg/scheme for more information.
+ //
+ // If set, the Scheme will be used to create the default Client and Cache.
+ Scheme *runtime.Scheme
+
+ // MapperProvider provides the rest mapper used to map go types to Kubernetes APIs.
+ //
+ // If set, the RESTMapper returned by this function is used to create the RESTMapper
+ // used by the Client and Cache.
+ MapperProvider func(c *rest.Config, httpClient *http.Client) (meta.RESTMapper, error)
+
+ // Cache is the cache.Options that will be used to create the default Cache.
+ // By default, the cache will watch and list requested objects in all namespaces.
+ Cache cache.Options
+
+ // NewCache is the function that will create the cache to be used
+ // by the manager. If not set this will use the default new cache function.
+ //
+ // When using a custom NewCache, the Cache options will be passed to the
+ // NewCache function.
+ //
+ // NOTE: LOW LEVEL PRIMITIVE!
+ // Only use a custom NewCache if you know what you are doing.
+ NewCache cache.NewCacheFunc
+
+ // Client is the client.Options that will be used to create the default Client.
+ // By default, the client will use the cache for reads and direct calls for writes.
+ Client client.Options
+
+ // NewClient is the func that creates the client to be used by the manager.
+ // If not set this will create a Client backed by a Cache for read operations
+ // and a direct Client for write operations.
+ //
+ // When using a custom NewClient, the Client options will be passed to the
+ // NewClient function.
+ //
+ // NOTE: LOW LEVEL PRIMITIVE!
+ // Only use a custom NewClient if you know what you are doing.
+ NewClient client.NewClientFunc
+
+ // SyncPeriod determines the minimum frequency at which watched resources are
+ // reconciled. A lower period will correct entropy more quickly, but reduce
+ // responsiveness to change if there are many watched resources. Change this
+ // value only if you know what you are doing. Defaults to 10 hours if unset.
+ // there will a 10 percent jitter between the SyncPeriod of all controllers
+ // so that all controllers will not send list requests simultaneously.
+ //
+ // This applies to all controllers.
+ //
+ // A period sync happens for two reasons:
+ // 1. To insure against a bug in the controller that causes an object to not
+ // be requeued, when it otherwise should be requeued.
+ // 2. To insure against an unknown bug in controller-runtime, or its dependencies,
+ // that causes an object to not be requeued, when it otherwise should be
+ // requeued, or to be removed from the queue, when it otherwise should not
+ // be removed.
+ //
+ // If you want
+ // 1. to insure against missed watch events, or
+ // 2. to poll services that cannot be watched,
+ // then we recommend that, instead of changing the default period, the
+ // controller requeue, with a constant duration `t`, whenever the controller
+ // is "done" with an object, and would otherwise not requeue it, i.e., we
+ // recommend the `Reconcile` function return `reconcile.Result{RequeueAfter: t}`,
+ // instead of `reconcile.Result{}`.
+ //
+ // Deprecated: Use Cache.SyncPeriod instead.
+ SyncPeriod *time.Duration
+
+ // Logger is the logger that should be used by this manager.
+ // If none is set, it defaults to log.Log global logger.
+ Logger logr.Logger
+
+ // LeaderElection determines whether or not to use leader election when
+ // starting the manager.
+ LeaderElection bool
+
+ // LeaderElectionResourceLock determines which resource lock to use for leader election,
+ // defaults to "leases". Change this value only if you know what you are doing.
+ //
+ // If you are using `configmaps`/`endpoints` resource lock and want to migrate to "leases",
+ // you might do so by migrating to the respective multilock first ("configmapsleases" or "endpointsleases"),
+ // which will acquire a leader lock on both resources.
+ // After all your users have migrated to the multilock, you can go ahead and migrate to "leases".
+ // Please also keep in mind, that users might skip versions of your controller.
+ //
+ // Note: before controller-runtime version v0.7, it was set to "configmaps".
+ // And from v0.7 to v0.11, the default was "configmapsleases", which was
+ // used to migrate from configmaps to leases.
+ // Since the default was "configmapsleases" for over a year, spanning five minor releases,
+ // any actively maintained operators are very likely to have a released version that uses
+ // "configmapsleases". Therefore defaulting to "leases" should be safe since v0.12.
+ //
+ // So, what do you have to do when you are updating your controller-runtime dependency
+ // from a lower version to v0.12 or newer?
+ // - If your operator matches at least one of these conditions:
+ // - the LeaderElectionResourceLock in your operator has already been explicitly set to "leases"
+ // - the old controller-runtime version is between v0.7.0 and v0.11.x and the
+ // LeaderElectionResourceLock wasn't set or was set to "leases"/"configmapsleases"/"endpointsleases"
+ // feel free to update controller-runtime to v0.12 or newer.
+ // - Otherwise, you may have to take these steps:
+ // 1. update controller-runtime to v0.12 or newer in your go.mod
+ // 2. set LeaderElectionResourceLock to "configmapsleases" (or "endpointsleases")
+ // 3. package your operator and upgrade it in all your clusters
+ // 4. only if you have finished 3, you can remove the LeaderElectionResourceLock to use the default "leases"
+ // Otherwise, your operator might end up with multiple running instances that
+ // each acquired leadership through different resource locks during upgrades and thus
+ // act on the same resources concurrently.
+ LeaderElectionResourceLock string
+
+ // LeaderElectionNamespace determines the namespace in which the leader
+ // election resource will be created.
+ LeaderElectionNamespace string
+
+ // LeaderElectionID determines the name of the resource that leader election
+ // will use for holding the leader lock.
+ LeaderElectionID string
+
+ // LeaderElectionConfig can be specified to override the default configuration
+ // that is used to build the leader election client.
+ LeaderElectionConfig *rest.Config
+
+ // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
+ // 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 doesn't have to wait
+ // LeaseDuration time first.
+ LeaderElectionReleaseOnCancel bool
+
+ // LeaderElectionResourceLockInterface allows to provide a custom resourcelock.Interface that was created outside
+ // of the controller-runtime. If this value is set the options LeaderElectionID, LeaderElectionNamespace,
+ // LeaderElectionResourceLock, LeaseDuration, RenewDeadline and RetryPeriod will be ignored. This can be useful if you
+ // want to use a locking mechanism that is currently not supported, like a MultiLock across two Kubernetes clusters.
+ LeaderElectionResourceLockInterface resourcelock.Interface
+
+ // LeaseDuration is the duration that non-leader candidates will
+ // wait to force acquire leadership. This is measured against time of
+ // last observed ack. Default is 15 seconds.
+ LeaseDuration *time.Duration
+ // RenewDeadline is the duration that the acting controlplane will retry
+ // refreshing leadership before giving up. Default is 10 seconds.
+ RenewDeadline *time.Duration
+ // RetryPeriod is the duration the LeaderElector clients should wait
+ // between tries of actions. Default is 2 seconds.
+ RetryPeriod *time.Duration
+
+ // Namespace, if specified, restricts the manager's cache to watch objects in
+ // the desired namespace. Defaults to all namespaces.
+ //
+ // Note: If a namespace is specified, controllers can still Watch for a
+ // cluster-scoped resource (e.g Node). For namespaced resources, the cache
+ // will only hold objects from the desired namespace.
+ //
+ // Deprecated: Use Cache.Namespaces instead.
+ Namespace string
+
+ // MetricsBindAddress 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.
+ MetricsBindAddress string
+
+ // HealthProbeBindAddress 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.
+ HealthProbeBindAddress string
+
+ // Readiness probe endpoint name, defaults to "readyz"
+ ReadinessEndpointName string
+
+ // Liveness probe endpoint name, defaults to "healthz"
+ LivenessEndpointName string
+
+ // PprofBindAddress is the TCP address that the controller should bind to
+ // for serving pprof.
+ // It can be set to "" or "0" to disable the pprof serving.
+ // Since pprof may contain sensitive information, make sure to protect it
+ // before exposing it to public.
+ PprofBindAddress string
+
+ // Port is the port that the webhook server serves at.
+ // It is used to set webhook.Server.Port if WebhookServer is not set.
+ //
+ // Deprecated: Use WebhookServer instead. A WebhookServer can be created via webhook.NewServer.
+ Port int
+ // Host is the hostname that the webhook server binds to.
+ // It is used to set webhook.Server.Host if WebhookServer is not set.
+ //
+ // Deprecated: Use WebhookServer instead. A WebhookServer can be created via webhook.NewServer.
+ Host string
+
+ // CertDir is the directory that contains the server key and certificate.
+ // If not set, webhook server would look up the server key and certificate in
+ // {TempDir}/k8s-webhook-server/serving-certs. The server key and certificate
+ // must be named tls.key and tls.crt, respectively.
+ // It is used to set webhook.Server.CertDir if WebhookServer is not set.
+ //
+ // Deprecated: Use WebhookServer instead. A WebhookServer can be created via webhook.NewServer.
+ CertDir string
+
+ // TLSOpts is used to allow configuring the TLS config used for the webhook server.
+ //
+ // Deprecated: Use WebhookServer instead. A WebhookServer can be created via webhook.NewServer.
+ TLSOpts []func(*tls.Config)
+
+ // WebhookServer is an externally configured webhook.Server. By default,
+ // a Manager will create a default server using Port, Host, and CertDir;
+ // if this is set, the Manager will use this server instead.
+ WebhookServer webhook.Server
+
+ // BaseContext is the function that provides Context values to Runnables
+ // managed by the Manager. If a BaseContext function isn't provided, Runnables
+ // will receive a new Background Context instead.
+ BaseContext BaseContextFunc
+
+ // ClientDisableCacheFor tells the client that, if any cache is used, to bypass it
+ // for the given objects.
+ //
+ // Deprecated: Use Client.Cache.DisableCacheFor instead.
+ ClientDisableCacheFor []client.Object
+
+ // DryRunClient specifies whether the client should be configured to enforce
+ // dryRun mode.
+ //
+ // Deprecated: Use Client.DryRun instead.
+ DryRunClient bool
+
+ // EventBroadcaster records Events emitted by the manager and sends them to the Kubernetes API
+ // Use this to customize the event correlator and spam filter
+ //
+ // Deprecated: using this may cause goroutine leaks if the lifetime of your manager or controllers
+ // is shorter than the lifetime of your process.
+ EventBroadcaster record.EventBroadcaster
+
+ // GracefulShutdownTimeout is the duration given to runnable to stop before the manager actually returns on stop.
+ // To disable graceful shutdown, set to time.Duration(0)
+ // To use graceful shutdown without timeout, set to a negative duration, e.G. time.Duration(-1)
+ // The graceful shutdown is skipped for safety reasons in case the leader election lease is lost.
+ GracefulShutdownTimeout *time.Duration
+
+ // Controller contains global configuration options for controllers
+ // registered within this manager.
+ // +optional
+ Controller config.Controller
+
+ // makeBroadcaster allows deferring the creation of the broadcaster to
+ // avoid leaking goroutines if we never call Start on this manager. It also
+ // returns whether or not this is a "owned" broadcaster, and as such should be
+ // stopped with the manager.
+ makeBroadcaster intrec.EventBroadcasterProducer
+
+ // Dependency injection for testing
+ newRecorderProvider func(config *rest.Config, httpClient *http.Client, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster intrec.EventBroadcasterProducer) (*intrec.Provider, error)
+ newResourceLock func(config *rest.Config, recorderProvider recorder.Provider, options leaderelection.Options) (resourcelock.Interface, error)
+ newMetricsListener func(addr string) (net.Listener, error)
+ newHealthProbeListener func(addr string) (net.Listener, error)
+ newPprofListener func(addr string) (net.Listener, error)
+}
+
+// BaseContextFunc is a function used to provide a base Context to Runnables
+// managed by a Manager.
+type BaseContextFunc func() context.Context
+
+// Runnable allows a component to be started.
+// It's very important that Start blocks until
+// it's done running.
+type Runnable interface {
+ // Start starts running the component. The component will stop running
+ // when the context is closed. Start blocks until the context is closed or
+ // an error occurs.
+ Start(context.Context) error
+}
+
+// RunnableFunc implements Runnable using a function.
+// It's very important that the given function block
+// until it's done running.
+type RunnableFunc func(context.Context) error
+
+// Start implements Runnable.
+func (r RunnableFunc) Start(ctx context.Context) error {
+ return r(ctx)
+}
+
+// LeaderElectionRunnable knows if a Runnable needs to be run in the leader election mode.
+type LeaderElectionRunnable interface {
+ // NeedLeaderElection returns true if the Runnable needs to be run in the leader election mode.
+ // e.g. controllers need to be run in leader election mode, while webhook server doesn't.
+ NeedLeaderElection() bool
+}
+
+// New returns a new Manager for creating Controllers.
+func New(config *rest.Config, options Options) (Manager, error) {
+ // Set default values for options fields
+ options = setOptionsDefaults(options)
+
+ cluster, err := cluster.New(config, func(clusterOptions *cluster.Options) {
+ clusterOptions.Scheme = options.Scheme
+ clusterOptions.MapperProvider = options.MapperProvider
+ clusterOptions.Logger = options.Logger
+ clusterOptions.SyncPeriod = options.SyncPeriod
+ clusterOptions.NewCache = options.NewCache
+ clusterOptions.NewClient = options.NewClient
+ clusterOptions.Cache = options.Cache
+ clusterOptions.Client = options.Client
+ clusterOptions.Namespace = options.Namespace //nolint:staticcheck
+ clusterOptions.ClientDisableCacheFor = options.ClientDisableCacheFor //nolint:staticcheck
+ clusterOptions.DryRunClient = options.DryRunClient //nolint:staticcheck
+ clusterOptions.EventBroadcaster = options.EventBroadcaster //nolint:staticcheck
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ // Create the recorder provider to inject event recorders for the components.
+ // TODO(directxman12): the log for the event provider should have a context (name, tags, etc) specific
+ // to the particular controller that it's being injected into, rather than a generic one like is here.
+ recorderProvider, err := options.newRecorderProvider(config, cluster.GetHTTPClient(), cluster.GetScheme(), options.Logger.WithName("events"), options.makeBroadcaster)
+ if err != nil {
+ return nil, err
+ }
+
+ // Create the resource lock to enable leader election)
+ var leaderConfig *rest.Config
+ var leaderRecorderProvider *intrec.Provider
+
+ if options.LeaderElectionConfig == nil {
+ leaderConfig = rest.CopyConfig(config)
+ leaderRecorderProvider = recorderProvider
+ } else {
+ leaderConfig = rest.CopyConfig(options.LeaderElectionConfig)
+ leaderRecorderProvider, err = options.newRecorderProvider(leaderConfig, cluster.GetHTTPClient(), cluster.GetScheme(), options.Logger.WithName("events"), options.makeBroadcaster)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ var resourceLock resourcelock.Interface
+ if options.LeaderElectionResourceLockInterface != nil && options.LeaderElection {
+ resourceLock = options.LeaderElectionResourceLockInterface
+ } else {
+ resourceLock, err = options.newResourceLock(leaderConfig, leaderRecorderProvider, leaderelection.Options{
+ LeaderElection: options.LeaderElection,
+ LeaderElectionResourceLock: options.LeaderElectionResourceLock,
+ LeaderElectionID: options.LeaderElectionID,
+ LeaderElectionNamespace: options.LeaderElectionNamespace,
+ })
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Create the metrics listener. This will throw an error if the metrics bind
+ // address is invalid or already in use.
+ metricsListener, err := options.newMetricsListener(options.MetricsBindAddress)
+ if err != nil {
+ return nil, err
+ }
+
+ // By default we have no extra endpoints to expose on metrics http server.
+ metricsExtraHandlers := make(map[string]http.Handler)
+
+ // Create health probes listener. This will throw an error if the bind
+ // address is invalid or already in use.
+ healthProbeListener, err := options.newHealthProbeListener(options.HealthProbeBindAddress)
+ if err != nil {
+ return nil, err
+ }
+
+ // Create pprof listener. This will throw an error if the bind
+ // address is invalid or already in use.
+ pprofListener, err := options.newPprofListener(options.PprofBindAddress)
+ if err != nil {
+ return nil, fmt.Errorf("failed to new pprof listener: %w", err)
+ }
+
+ errChan := make(chan error)
+ runnables := newRunnables(options.BaseContext, errChan)
+
+ return &controllerManager{
+ stopProcedureEngaged: pointer.Int64(0),
+ cluster: cluster,
+ runnables: runnables,
+ errChan: errChan,
+ recorderProvider: recorderProvider,
+ resourceLock: resourceLock,
+ metricsListener: metricsListener,
+ metricsExtraHandlers: metricsExtraHandlers,
+ controllerConfig: options.Controller,
+ logger: options.Logger,
+ elected: make(chan struct{}),
+ webhookServer: options.WebhookServer,
+ leaderElectionID: options.LeaderElectionID,
+ leaseDuration: *options.LeaseDuration,
+ renewDeadline: *options.RenewDeadline,
+ retryPeriod: *options.RetryPeriod,
+ healthProbeListener: healthProbeListener,
+ readinessEndpointName: options.ReadinessEndpointName,
+ livenessEndpointName: options.LivenessEndpointName,
+ pprofListener: pprofListener,
+ gracefulShutdownTimeout: *options.GracefulShutdownTimeout,
+ internalProceduresStop: make(chan struct{}),
+ leaderElectionStopped: make(chan struct{}),
+ leaderElectionReleaseOnCancel: options.LeaderElectionReleaseOnCancel,
+ }, nil
+}
+
+// AndFrom will use a supplied type and convert to Options
+// any options already set on Options will be ignored, this is used to allow
+// cli flags to override anything specified in the config file.
+//
+// Deprecated: This function has been deprecated and will be removed in a future release,
+// The Component Configuration package has been unmaintained for over a year and is no longer
+// actively developed. Users should migrate to their own configuration format
+// and configure Manager.Options directly.
+// See https://github.com/kubernetes-sigs/controller-runtime/issues/895
+// for more information, feedback, and comments.
+func (o Options) AndFrom(loader config.ControllerManagerConfiguration) (Options, error) {
+ newObj, err := loader.Complete()
+ if err != nil {
+ return o, err
+ }
+
+ o = o.setLeaderElectionConfig(newObj)
+
+ if o.SyncPeriod == nil && newObj.SyncPeriod != nil {
+ o.SyncPeriod = &newObj.SyncPeriod.Duration
+ }
+
+ if o.Namespace == "" && newObj.CacheNamespace != "" {
+ o.Namespace = newObj.CacheNamespace
+ }
+
+ if o.MetricsBindAddress == "" && newObj.Metrics.BindAddress != "" {
+ o.MetricsBindAddress = newObj.Metrics.BindAddress
+ }
+
+ if o.HealthProbeBindAddress == "" && newObj.Health.HealthProbeBindAddress != "" {
+ o.HealthProbeBindAddress = newObj.Health.HealthProbeBindAddress
+ }
+
+ if o.ReadinessEndpointName == "" && newObj.Health.ReadinessEndpointName != "" {
+ o.ReadinessEndpointName = newObj.Health.ReadinessEndpointName
+ }
+
+ if o.LivenessEndpointName == "" && newObj.Health.LivenessEndpointName != "" {
+ o.LivenessEndpointName = newObj.Health.LivenessEndpointName
+ }
+
+ if o.Port == 0 && newObj.Webhook.Port != nil {
+ o.Port = *newObj.Webhook.Port
+ }
+ if o.Host == "" && newObj.Webhook.Host != "" {
+ o.Host = newObj.Webhook.Host
+ }
+ if o.CertDir == "" && newObj.Webhook.CertDir != "" {
+ o.CertDir = newObj.Webhook.CertDir
+ }
+ if o.WebhookServer == nil {
+ o.WebhookServer = webhook.NewServer(webhook.Options{
+ Port: o.Port,
+ Host: o.Host,
+ CertDir: o.CertDir,
+ })
+ }
+
+ if newObj.Controller != nil {
+ if o.Controller.CacheSyncTimeout == 0 && newObj.Controller.CacheSyncTimeout != nil {
+ o.Controller.CacheSyncTimeout = *newObj.Controller.CacheSyncTimeout
+ }
+
+ if len(o.Controller.GroupKindConcurrency) == 0 && len(newObj.Controller.GroupKindConcurrency) > 0 {
+ o.Controller.GroupKindConcurrency = newObj.Controller.GroupKindConcurrency
+ }
+ }
+
+ return o, nil
+}
+
+// AndFromOrDie will use options.AndFrom() and will panic if there are errors.
+//
+// Deprecated: This function has been deprecated and will be removed in a future release,
+// The Component Configuration package has been unmaintained for over a year and is no longer
+// actively developed. Users should migrate to their own configuration format
+// and configure Manager.Options directly.
+// See https://github.com/kubernetes-sigs/controller-runtime/issues/895
+// for more information, feedback, and comments.
+func (o Options) AndFromOrDie(loader config.ControllerManagerConfiguration) Options {
+ o, err := o.AndFrom(loader)
+ if err != nil {
+ panic(fmt.Sprintf("could not parse config file: %v", err))
+ }
+ return o
+}
+
+func (o Options) setLeaderElectionConfig(obj v1alpha1.ControllerManagerConfigurationSpec) Options {
+ if obj.LeaderElection == nil {
+ // The source does not have any configuration; noop
+ return o
+ }
+
+ if !o.LeaderElection && obj.LeaderElection.LeaderElect != nil {
+ o.LeaderElection = *obj.LeaderElection.LeaderElect
+ }
+
+ if o.LeaderElectionResourceLock == "" && obj.LeaderElection.ResourceLock != "" {
+ o.LeaderElectionResourceLock = obj.LeaderElection.ResourceLock
+ }
+
+ if o.LeaderElectionNamespace == "" && obj.LeaderElection.ResourceNamespace != "" {
+ o.LeaderElectionNamespace = obj.LeaderElection.ResourceNamespace
+ }
+
+ if o.LeaderElectionID == "" && obj.LeaderElection.ResourceName != "" {
+ o.LeaderElectionID = obj.LeaderElection.ResourceName
+ }
+
+ if o.LeaseDuration == nil && !reflect.DeepEqual(obj.LeaderElection.LeaseDuration, metav1.Duration{}) {
+ o.LeaseDuration = &obj.LeaderElection.LeaseDuration.Duration
+ }
+
+ if o.RenewDeadline == nil && !reflect.DeepEqual(obj.LeaderElection.RenewDeadline, metav1.Duration{}) {
+ o.RenewDeadline = &obj.LeaderElection.RenewDeadline.Duration
+ }
+
+ if o.RetryPeriod == nil && !reflect.DeepEqual(obj.LeaderElection.RetryPeriod, metav1.Duration{}) {
+ o.RetryPeriod = &obj.LeaderElection.RetryPeriod.Duration
+ }
+
+ return o
+}
+
+// defaultHealthProbeListener creates the default health probes listener bound to the given address.
+func defaultHealthProbeListener(addr string) (net.Listener, error) {
+ if addr == "" || addr == "0" {
+ return nil, nil
+ }
+
+ ln, err := net.Listen("tcp", addr)
+ if err != nil {
+ return nil, fmt.Errorf("error listening on %s: %w", addr, err)
+ }
+ return ln, nil
+}
+
+// defaultPprofListener creates the default pprof listener bound to the given address.
+func defaultPprofListener(addr string) (net.Listener, error) {
+ if addr == "" || addr == "0" {
+ return nil, nil
+ }
+
+ ln, err := net.Listen("tcp", addr)
+ if err != nil {
+ return nil, fmt.Errorf("error listening on %s: %w", addr, err)
+ }
+ return ln, nil
+}
+
+// defaultBaseContext is used as the BaseContext value in Options if one
+// has not already been set.
+func defaultBaseContext() context.Context {
+ return context.Background()
+}
+
+// setOptionsDefaults set default values for Options fields.
+func setOptionsDefaults(options Options) Options {
+ // Allow newResourceLock to be mocked
+ if options.newResourceLock == nil {
+ options.newResourceLock = leaderelection.NewResourceLock
+ }
+
+ // Allow newRecorderProvider to be mocked
+ if options.newRecorderProvider == nil {
+ options.newRecorderProvider = intrec.NewProvider
+ }
+
+ // This is duplicated with pkg/cluster, we need it here
+ // for the leader election and there to provide the user with
+ // an EventBroadcaster
+ if options.EventBroadcaster == nil {
+ // defer initialization to avoid leaking by default
+ options.makeBroadcaster = func() (record.EventBroadcaster, bool) {
+ return record.NewBroadcaster(), true
+ }
+ } else {
+ options.makeBroadcaster = func() (record.EventBroadcaster, bool) {
+ return options.EventBroadcaster, false
+ }
+ }
+
+ if options.newMetricsListener == nil {
+ options.newMetricsListener = metrics.NewListener
+ }
+ leaseDuration, renewDeadline, retryPeriod := defaultLeaseDuration, defaultRenewDeadline, defaultRetryPeriod
+ if options.LeaseDuration == nil {
+ options.LeaseDuration = &leaseDuration
+ }
+
+ if options.RenewDeadline == nil {
+ options.RenewDeadline = &renewDeadline
+ }
+
+ if options.RetryPeriod == nil {
+ options.RetryPeriod = &retryPeriod
+ }
+
+ if options.ReadinessEndpointName == "" {
+ options.ReadinessEndpointName = defaultReadinessEndpoint
+ }
+
+ if options.LivenessEndpointName == "" {
+ options.LivenessEndpointName = defaultLivenessEndpoint
+ }
+
+ if options.newHealthProbeListener == nil {
+ options.newHealthProbeListener = defaultHealthProbeListener
+ }
+
+ if options.newPprofListener == nil {
+ options.newPprofListener = defaultPprofListener
+ }
+
+ if options.GracefulShutdownTimeout == nil {
+ gracefulShutdownTimeout := defaultGracefulShutdownPeriod
+ options.GracefulShutdownTimeout = &gracefulShutdownTimeout
+ }
+
+ if options.Logger.GetSink() == nil {
+ options.Logger = log.Log
+ }
+
+ if options.BaseContext == nil {
+ options.BaseContext = defaultBaseContext
+ }
+
+ if options.WebhookServer == nil {
+ options.WebhookServer = webhook.NewServer(webhook.Options{
+ Host: options.Host,
+ Port: options.Port,
+ CertDir: options.CertDir,
+ TLSOpts: options.TLSOpts,
+ })
+ }
+
+ return options
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/manager_options_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/manager_options_test.go
new file mode 100644
index 00000000000..3718bedcbe9
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/manager_options_test.go
@@ -0,0 +1,54 @@
+package manager
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ "sigs.k8s.io/controller-runtime/pkg/config"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ configv1alpha1 "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
+)
+
+var _ = Describe("manager.Options", func() {
+ Describe("AndFrom", func() {
+ Describe("reading custom type using OfKind", func() {
+ var (
+ o Options
+ c customConfig
+ err error
+ )
+
+ JustBeforeEach(func() {
+ s := runtime.NewScheme()
+ o = Options{Scheme: s}
+ c = customConfig{}
+
+ _, err = o.AndFrom(config.File().AtPath("./testdata/custom-config.yaml").OfKind(&c))
+ })
+
+ It("should not panic or fail", func() {
+ Expect(err).To(Succeed())
+ })
+ It("should set custom properties", func() {
+ Expect(c.CustomValue).To(Equal("foo"))
+ })
+ })
+ })
+})
+
+type customConfig struct {
+ metav1.TypeMeta `json:",inline"`
+ configv1alpha1.ControllerManagerConfigurationSpec `json:",inline"`
+ CustomValue string `json:"customValue"`
+}
+
+func (in *customConfig) DeepCopyObject() runtime.Object {
+ out := &customConfig{}
+ *out = *in
+
+ in.ControllerManagerConfigurationSpec.DeepCopyInto(&out.ControllerManagerConfigurationSpec)
+
+ return out
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/manager_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/manager_suite_test.go
new file mode 100644
index 00000000000..ab514ef1e95
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/manager_suite_test.go
@@ -0,0 +1,80 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package manager
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Manager Suite")
+}
+
+var testenv *envtest.Environment
+var cfg *rest.Config
+var clientset *kubernetes.Clientset
+
+// clientTransport is used to force-close keep-alives in tests that check for leaks.
+var clientTransport *http.Transport
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+ testenv = &envtest.Environment{}
+
+ var err error
+ cfg, err = testenv.Start()
+ Expect(err).NotTo(HaveOccurred())
+
+ cfg.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
+ // NB(directxman12): we can't set Transport *and* use TLS options,
+ // so we grab the transport right after it gets created so that we can
+ // type-assert on it (hopefully)?
+ // hopefully this doesn't break 🤞
+ transport, isTransport := rt.(*http.Transport)
+ if !isTransport {
+ panic(fmt.Sprintf("wasn't able to grab underlying transport from REST client's RoundTripper, can't figure out how to close keep-alives: expected an *http.Transport, got %#v", rt))
+ }
+ clientTransport = transport
+ return rt
+ }
+
+ clientset, err = kubernetes.NewForConfig(cfg)
+ Expect(err).NotTo(HaveOccurred())
+
+ // Prevent the metrics listener being created
+ metrics.DefaultBindAddress = "0"
+})
+
+var _ = AfterSuite(func() {
+ Expect(testenv.Stop()).To(Succeed())
+
+ // Put the DefaultBindAddress back
+ metrics.DefaultBindAddress = ":8080"
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/manager_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/manager_test.go
new file mode 100644
index 00000000000..1a7c257c259
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/manager_test.go
@@ -0,0 +1,1864 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package manager
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "path"
+ "reflect"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/go-logr/logr"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/prometheus/client_golang/prometheus"
+ "go.uber.org/goleak"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/leaderelection/resourcelock"
+
+ configv1alpha1 "k8s.io/component-base/config/v1alpha1"
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/cache/informertest"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/cluster"
+ "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
+ intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
+ "sigs.k8s.io/controller-runtime/pkg/leaderelection"
+ fakeleaderelection "sigs.k8s.io/controller-runtime/pkg/leaderelection/fake"
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+ "sigs.k8s.io/controller-runtime/pkg/recorder"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+var _ = Describe("manger.Manager", func() {
+ Describe("New", func() {
+ It("should return an error if there is no Config", func() {
+ m, err := New(nil, Options{})
+ Expect(m).To(BeNil())
+ Expect(err.Error()).To(ContainSubstring("must specify Config"))
+
+ })
+
+ It("should return an error if it can't create a RestMapper", func() {
+ expected := fmt.Errorf("expected error: RestMapper")
+ m, err := New(cfg, Options{
+ MapperProvider: func(c *rest.Config, httpClient *http.Client) (meta.RESTMapper, error) { return nil, expected },
+ })
+ Expect(m).To(BeNil())
+ Expect(err).To(Equal(expected))
+
+ })
+
+ It("should return an error it can't create a client.Client", func() {
+ m, err := New(cfg, Options{
+ NewClient: func(config *rest.Config, options client.Options) (client.Client, error) {
+ return nil, errors.New("expected error")
+ },
+ })
+ Expect(m).To(BeNil())
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("expected error"))
+ })
+
+ It("should return an error it can't create a cache.Cache", func() {
+ m, err := New(cfg, Options{
+ NewCache: func(config *rest.Config, opts cache.Options) (cache.Cache, error) {
+ return nil, fmt.Errorf("expected error")
+ },
+ })
+ Expect(m).To(BeNil())
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("expected error"))
+ })
+
+ It("should create a client defined in by the new client function", func() {
+ m, err := New(cfg, Options{
+ NewClient: func(config *rest.Config, options client.Options) (client.Client, error) {
+ return nil, nil
+ },
+ })
+ Expect(m).ToNot(BeNil())
+ Expect(err).ToNot(HaveOccurred())
+ Expect(m.GetClient()).To(BeNil())
+ })
+
+ It("should return an error it can't create a recorder.Provider", func() {
+ m, err := New(cfg, Options{
+ newRecorderProvider: func(_ *rest.Config, _ *http.Client, _ *runtime.Scheme, _ logr.Logger, _ intrec.EventBroadcasterProducer) (*intrec.Provider, error) {
+ return nil, fmt.Errorf("expected error")
+ },
+ })
+ Expect(m).To(BeNil())
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("expected error"))
+ })
+
+ It("should be able to load Options from cfg.ControllerManagerConfiguration type", func() {
+ duration := metav1.Duration{Duration: 48 * time.Hour}
+ port := int(6090)
+ leaderElect := false
+
+ ccfg := &v1alpha1.ControllerManagerConfiguration{
+ ControllerManagerConfigurationSpec: v1alpha1.ControllerManagerConfigurationSpec{
+ SyncPeriod: &duration,
+ LeaderElection: &configv1alpha1.LeaderElectionConfiguration{
+ LeaderElect: &leaderElect,
+ ResourceLock: "leases",
+ ResourceNamespace: "default",
+ ResourceName: "ctrl-lease",
+ LeaseDuration: duration,
+ RenewDeadline: duration,
+ RetryPeriod: duration,
+ },
+ CacheNamespace: "default",
+ Metrics: v1alpha1.ControllerMetrics{
+ BindAddress: ":6000",
+ },
+ Health: v1alpha1.ControllerHealth{
+ HealthProbeBindAddress: "6060",
+ ReadinessEndpointName: "/readyz",
+ LivenessEndpointName: "/livez",
+ },
+ Webhook: v1alpha1.ControllerWebhook{
+ Port: &port,
+ Host: "localhost",
+ CertDir: "/certs",
+ },
+ },
+ }
+
+ m, err := Options{}.AndFrom(&fakeDeferredLoader{ccfg})
+ Expect(err).To(BeNil())
+
+ Expect(*m.SyncPeriod).To(Equal(duration.Duration))
+ Expect(m.LeaderElection).To(Equal(leaderElect))
+ Expect(m.LeaderElectionResourceLock).To(Equal("leases"))
+ Expect(m.LeaderElectionNamespace).To(Equal("default"))
+ Expect(m.LeaderElectionID).To(Equal("ctrl-lease"))
+ Expect(m.LeaseDuration.String()).To(Equal(duration.Duration.String()))
+ Expect(m.RenewDeadline.String()).To(Equal(duration.Duration.String()))
+ Expect(m.RetryPeriod.String()).To(Equal(duration.Duration.String()))
+ Expect(m.Namespace).To(Equal("default"))
+ Expect(m.MetricsBindAddress).To(Equal(":6000"))
+ Expect(m.HealthProbeBindAddress).To(Equal("6060"))
+ Expect(m.ReadinessEndpointName).To(Equal("/readyz"))
+ Expect(m.LivenessEndpointName).To(Equal("/livez"))
+ Expect(m.Port).To(Equal(port))
+ Expect(m.Host).To(Equal("localhost"))
+ Expect(m.CertDir).To(Equal("/certs"))
+ })
+
+ It("should be able to keep Options when cfg.ControllerManagerConfiguration set", func() {
+ optDuration := time.Duration(2)
+ duration := metav1.Duration{Duration: 48 * time.Hour}
+ port := int(6090)
+ leaderElect := false
+
+ ccfg := &v1alpha1.ControllerManagerConfiguration{
+ ControllerManagerConfigurationSpec: v1alpha1.ControllerManagerConfigurationSpec{
+ SyncPeriod: &duration,
+ LeaderElection: &configv1alpha1.LeaderElectionConfiguration{
+ LeaderElect: &leaderElect,
+ ResourceLock: "leases",
+ ResourceNamespace: "default",
+ ResourceName: "ctrl-lease",
+ LeaseDuration: duration,
+ RenewDeadline: duration,
+ RetryPeriod: duration,
+ },
+ CacheNamespace: "default",
+ Metrics: v1alpha1.ControllerMetrics{
+ BindAddress: ":6000",
+ },
+ Health: v1alpha1.ControllerHealth{
+ HealthProbeBindAddress: "6060",
+ ReadinessEndpointName: "/readyz",
+ LivenessEndpointName: "/livez",
+ },
+ Webhook: v1alpha1.ControllerWebhook{
+ Port: &port,
+ Host: "localhost",
+ CertDir: "/certs",
+ },
+ },
+ }
+
+ optionsTlSOptsFuncs := []func(*tls.Config){
+ func(config *tls.Config) {},
+ }
+ m, err := Options{
+ SyncPeriod: &optDuration,
+ LeaderElection: true,
+ LeaderElectionResourceLock: "configmaps",
+ LeaderElectionNamespace: "ctrl",
+ LeaderElectionID: "ctrl-configmap",
+ LeaseDuration: &optDuration,
+ RenewDeadline: &optDuration,
+ RetryPeriod: &optDuration,
+ Namespace: "ctrl",
+ MetricsBindAddress: ":7000",
+ HealthProbeBindAddress: "5000",
+ ReadinessEndpointName: "/readiness",
+ LivenessEndpointName: "/liveness",
+ WebhookServer: webhook.NewServer(webhook.Options{
+ Port: 8080,
+ Host: "example.com",
+ CertDir: "/pki",
+ TLSOpts: optionsTlSOptsFuncs,
+ }),
+ }.AndFrom(&fakeDeferredLoader{ccfg})
+ Expect(err).To(BeNil())
+
+ Expect(m.SyncPeriod.String()).To(Equal(optDuration.String()))
+ Expect(m.LeaderElection).To(Equal(true))
+ Expect(m.LeaderElectionResourceLock).To(Equal("configmaps"))
+ Expect(m.LeaderElectionNamespace).To(Equal("ctrl"))
+ Expect(m.LeaderElectionID).To(Equal("ctrl-configmap"))
+ Expect(m.LeaseDuration.String()).To(Equal(optDuration.String()))
+ Expect(m.RenewDeadline.String()).To(Equal(optDuration.String()))
+ Expect(m.RetryPeriod.String()).To(Equal(optDuration.String()))
+ Expect(m.Namespace).To(Equal("ctrl"))
+ Expect(m.MetricsBindAddress).To(Equal(":7000"))
+ Expect(m.HealthProbeBindAddress).To(Equal("5000"))
+ Expect(m.ReadinessEndpointName).To(Equal("/readiness"))
+ Expect(m.LivenessEndpointName).To(Equal("/liveness"))
+ Expect(m.WebhookServer.(*webhook.DefaultServer).Options.Port).To(Equal(8080))
+ Expect(m.WebhookServer.(*webhook.DefaultServer).Options.Host).To(Equal("example.com"))
+ Expect(m.WebhookServer.(*webhook.DefaultServer).Options.CertDir).To(Equal("/pki"))
+ Expect(m.WebhookServer.(*webhook.DefaultServer).Options.TLSOpts).To(Equal(optionsTlSOptsFuncs))
+ })
+
+ It("should lazily initialize a webhook server if needed", func() {
+ By("creating a manager with options")
+ m, err := New(cfg, Options{WebhookServer: webhook.NewServer(webhook.Options{Port: 9440, Host: "foo.com"})})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(m).NotTo(BeNil())
+
+ By("checking options are passed to the webhook server")
+ svr := m.GetWebhookServer()
+ Expect(svr).NotTo(BeNil())
+ Expect(svr.(*webhook.DefaultServer).Options.Port).To(Equal(9440))
+ Expect(svr.(*webhook.DefaultServer).Options.Host).To(Equal("foo.com"))
+ })
+
+ It("should lazily initialize a webhook server if needed (deprecated)", func() {
+ By("creating a manager with options")
+ m, err := New(cfg, Options{Port: 9440, Host: "foo.com"})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(m).NotTo(BeNil())
+
+ By("checking options are passed to the webhook server")
+ svr := m.GetWebhookServer()
+ Expect(svr).NotTo(BeNil())
+ Expect(svr.(*webhook.DefaultServer).Options.Port).To(Equal(9440))
+ Expect(svr.(*webhook.DefaultServer).Options.Host).To(Equal("foo.com"))
+ })
+
+ It("should not initialize a webhook server if Options.WebhookServer is set", func() {
+ By("creating a manager with options")
+ srv := webhook.NewServer(webhook.Options{Port: 9440})
+ m, err := New(cfg, Options{Port: 9441, WebhookServer: srv})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(m).NotTo(BeNil())
+
+ By("checking the server contains the Port set on the webhook server and not passed to Options")
+ svr := m.GetWebhookServer()
+ Expect(svr).NotTo(BeNil())
+ Expect(svr).To(Equal(srv))
+ Expect(svr.(*webhook.DefaultServer).Options.Port).To(Equal(9440))
+ })
+
+ It("should allow passing a custom webhook.Server implementation", func() {
+ type customWebhook struct {
+ webhook.Server
+ }
+ m, err := New(cfg, Options{WebhookServer: customWebhook{}})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(m).NotTo(BeNil())
+
+ svr := m.GetWebhookServer()
+ Expect(svr).NotTo(BeNil())
+
+ _, isCustomWebhook := svr.(customWebhook)
+ Expect(isCustomWebhook).To(BeTrue())
+ })
+
+ Context("with leader election enabled", func() {
+ It("should only cancel the leader election after all runnables are done", func() {
+ m, err := New(cfg, Options{
+ LeaderElection: true,
+ LeaderElectionNamespace: "default",
+ LeaderElectionID: "test-leader-election-id-2",
+ HealthProbeBindAddress: "0",
+ MetricsBindAddress: "0",
+ PprofBindAddress: "0",
+ })
+ Expect(err).To(BeNil())
+
+ runnableDone := make(chan struct{})
+ slowRunnable := RunnableFunc(func(ctx context.Context) error {
+ <-ctx.Done()
+ time.Sleep(100 * time.Millisecond)
+ close(runnableDone)
+ return nil
+ })
+ Expect(m.Add(slowRunnable)).To(BeNil())
+
+ cm := m.(*controllerManager)
+ cm.gracefulShutdownTimeout = time.Second
+ leaderElectionDone := make(chan struct{})
+ cm.onStoppedLeading = func() {
+ close(leaderElectionDone)
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ mgrDone := make(chan struct{})
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).To(BeNil())
+ close(mgrDone)
+ }()
+ <-cm.Elected()
+ cancel()
+ select {
+ case <-leaderElectionDone:
+ Expect(errors.New("leader election was cancelled before runnables were done")).ToNot(HaveOccurred())
+ case <-runnableDone:
+ // Success
+ }
+ // Don't leak routines
+ <-mgrDone
+
+ })
+ It("should disable gracefulShutdown when stopping to lead", func() {
+ m, err := New(cfg, Options{
+ LeaderElection: true,
+ LeaderElectionNamespace: "default",
+ LeaderElectionID: "test-leader-election-id-3",
+ HealthProbeBindAddress: "0",
+ MetricsBindAddress: "0",
+ PprofBindAddress: "0",
+ })
+ Expect(err).To(BeNil())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ mgrDone := make(chan struct{})
+ go func() {
+ defer GinkgoRecover()
+ err := m.Start(ctx)
+ Expect(err).ToNot(BeNil())
+ Expect(err.Error()).To(ContainSubstring("leader election lost"))
+ close(mgrDone)
+ }()
+ cm := m.(*controllerManager)
+ <-cm.elected
+
+ cm.leaderElectionCancel()
+ <-mgrDone
+
+ Expect(cm.gracefulShutdownTimeout.Nanoseconds()).To(Equal(int64(0)))
+ })
+ It("should default ID to controller-runtime if ID is not set", func() {
+ var rl resourcelock.Interface
+ m1, err := New(cfg, Options{
+ LeaderElection: true,
+ LeaderElectionNamespace: "default",
+ LeaderElectionID: "test-leader-election-id",
+ newResourceLock: func(config *rest.Config, recorderProvider recorder.Provider, options leaderelection.Options) (resourcelock.Interface, error) {
+ var err error
+ rl, err = leaderelection.NewResourceLock(config, recorderProvider, options)
+ return rl, err
+ },
+ HealthProbeBindAddress: "0",
+ MetricsBindAddress: "0",
+ PprofBindAddress: "0",
+ })
+ Expect(err).ToNot(HaveOccurred())
+ Expect(m1).ToNot(BeNil())
+ Expect(rl.Describe()).To(Equal("default/test-leader-election-id"))
+
+ m1cm, ok := m1.(*controllerManager)
+ Expect(ok).To(BeTrue())
+ m1cm.onStoppedLeading = func() {}
+
+ m2, err := New(cfg, Options{
+ LeaderElection: true,
+ LeaderElectionNamespace: "default",
+ LeaderElectionID: "test-leader-election-id",
+ newResourceLock: func(config *rest.Config, recorderProvider recorder.Provider, options leaderelection.Options) (resourcelock.Interface, error) {
+ var err error
+ rl, err = leaderelection.NewResourceLock(config, recorderProvider, options)
+ return rl, err
+ },
+ HealthProbeBindAddress: "0",
+ MetricsBindAddress: "0",
+ PprofBindAddress: "0",
+ })
+ Expect(err).ToNot(HaveOccurred())
+ Expect(m2).ToNot(BeNil())
+ Expect(rl.Describe()).To(Equal("default/test-leader-election-id"))
+
+ m2cm, ok := m2.(*controllerManager)
+ Expect(ok).To(BeTrue())
+ m2cm.onStoppedLeading = func() {}
+
+ c1 := make(chan struct{})
+ Expect(m1.Add(RunnableFunc(func(ctx context.Context) error {
+ defer GinkgoRecover()
+ close(c1)
+ return nil
+ }))).To(Succeed())
+
+ ctx1, cancel1 := context.WithCancel(context.Background())
+ defer cancel1()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m1.Elected()).ShouldNot(BeClosed())
+ Expect(m1.Start(ctx1)).NotTo(HaveOccurred())
+ }()
+ <-m1.Elected()
+ <-c1
+
+ c2 := make(chan struct{})
+ Expect(m2.Add(RunnableFunc(func(context.Context) error {
+ defer GinkgoRecover()
+ close(c2)
+ return nil
+ }))).To(Succeed())
+
+ ctx2, cancel := context.WithCancel(context.Background())
+ m2done := make(chan struct{})
+ go func() {
+ defer GinkgoRecover()
+ Expect(m2.Start(ctx2)).NotTo(HaveOccurred())
+ close(m2done)
+ }()
+ Consistently(m2.Elected()).ShouldNot(Receive())
+
+ Consistently(c2).ShouldNot(Receive())
+ cancel()
+ <-m2done
+ })
+
+ It("should return an error if it can't create a ResourceLock", func() {
+ m, err := New(cfg, Options{
+ newResourceLock: func(_ *rest.Config, _ recorder.Provider, _ leaderelection.Options) (resourcelock.Interface, error) {
+ return nil, fmt.Errorf("expected error")
+ },
+ })
+ Expect(m).To(BeNil())
+ Expect(err).To(MatchError(ContainSubstring("expected error")))
+ })
+
+ It("should return an error if namespace not set and not running in cluster", func() {
+ m, err := New(cfg, Options{LeaderElection: true, LeaderElectionID: "controller-runtime"})
+ Expect(m).To(BeNil())
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("unable to find leader election namespace: not running in-cluster, please specify LeaderElectionNamespace"))
+ })
+
+ // We must keep this default until we are sure all controller-runtime users have upgraded from the original default
+ // ConfigMap lock to a controller-runtime version that has this new default. Many users of controller-runtime skip
+ // versions, so we should be extremely conservative here.
+ It("should default to LeasesResourceLock", func() {
+ m, err := New(cfg, Options{LeaderElection: true, LeaderElectionID: "controller-runtime", LeaderElectionNamespace: "my-ns"})
+ Expect(m).ToNot(BeNil())
+ Expect(err).ToNot(HaveOccurred())
+ cm, ok := m.(*controllerManager)
+ Expect(ok).To(BeTrue())
+ _, isLeaseLock := cm.resourceLock.(*resourcelock.LeaseLock)
+ Expect(isLeaseLock).To(BeTrue())
+
+ })
+ It("should use the specified ResourceLock", func() {
+ m, err := New(cfg, Options{
+ LeaderElection: true,
+ LeaderElectionResourceLock: resourcelock.ConfigMapsLeasesResourceLock,
+ LeaderElectionID: "controller-runtime",
+ LeaderElectionNamespace: "my-ns",
+ })
+ Expect(m).ToNot(BeNil())
+ Expect(err).ToNot(HaveOccurred())
+ cm, ok := m.(*controllerManager)
+ Expect(ok).To(BeTrue())
+ multilock, isMultiLock := cm.resourceLock.(*resourcelock.MultiLock)
+ Expect(isMultiLock).To(BeTrue())
+ primaryLockType := reflect.TypeOf(multilock.Primary)
+ Expect(primaryLockType.Kind()).To(Equal(reflect.Ptr))
+ Expect(primaryLockType.Elem().PkgPath()).To(Equal("k8s.io/client-go/tools/leaderelection/resourcelock"))
+ Expect(primaryLockType.Elem().Name()).To(Equal("configMapLock"))
+ _, secondaryIsLeaseLock := multilock.Secondary.(*resourcelock.LeaseLock)
+ Expect(secondaryIsLeaseLock).To(BeTrue())
+ })
+ It("should release lease if ElectionReleaseOnCancel is true", func() {
+ var rl resourcelock.Interface
+ m, err := New(cfg, Options{
+ LeaderElection: true,
+ LeaderElectionResourceLock: resourcelock.LeasesResourceLock,
+ LeaderElectionID: "controller-runtime",
+ LeaderElectionNamespace: "my-ns",
+ LeaderElectionReleaseOnCancel: true,
+ newResourceLock: func(config *rest.Config, recorderProvider recorder.Provider, options leaderelection.Options) (resourcelock.Interface, error) {
+ var err error
+ rl, err = fakeleaderelection.NewResourceLock(config, recorderProvider, options)
+ return rl, err
+ },
+ })
+ Expect(err).To(BeNil())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ doneCh := make(chan struct{})
+ go func() {
+ defer GinkgoRecover()
+ defer close(doneCh)
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ <-m.(*controllerManager).elected
+ cancel()
+ <-doneCh
+
+ ctx, cancel = context.WithCancel(context.Background())
+ defer cancel()
+ record, _, err := rl.Get(ctx)
+ Expect(err).To(BeNil())
+ Expect(record.HolderIdentity).To(BeEmpty())
+ })
+ When("using a custom LeaderElectionResourceLockInterface", func() {
+ It("should use the custom LeaderElectionResourceLockInterface", func() {
+ rl, err := fakeleaderelection.NewResourceLock(nil, nil, leaderelection.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ m, err := New(cfg, Options{
+ LeaderElection: true,
+ LeaderElectionResourceLockInterface: rl,
+ newResourceLock: func(config *rest.Config, recorderProvider recorder.Provider, options leaderelection.Options) (resourcelock.Interface, error) {
+ return nil, fmt.Errorf("this should not be called")
+ },
+ })
+ Expect(m).ToNot(BeNil())
+ Expect(err).ToNot(HaveOccurred())
+ cm, ok := m.(*controllerManager)
+ Expect(ok).To(BeTrue())
+ Expect(cm.resourceLock).To(Equal(rl))
+ })
+ })
+ })
+
+ It("should create a listener for the metrics if a valid address is provided", func() {
+ var listener net.Listener
+ m, err := New(cfg, Options{
+ MetricsBindAddress: ":0",
+ newMetricsListener: func(addr string) (net.Listener, error) {
+ var err error
+ listener, err = metrics.NewListener(addr)
+ return listener, err
+ },
+ })
+ Expect(m).ToNot(BeNil())
+ Expect(err).ToNot(HaveOccurred())
+ Expect(listener).ToNot(BeNil())
+ Expect(listener.Close()).ToNot(HaveOccurred())
+ })
+
+ It("should return an error if the metrics bind address is already in use", func() {
+ ln, err := metrics.NewListener(":0")
+ Expect(err).ShouldNot(HaveOccurred())
+
+ var listener net.Listener
+ m, err := New(cfg, Options{
+ MetricsBindAddress: ln.Addr().String(),
+ newMetricsListener: func(addr string) (net.Listener, error) {
+ var err error
+ listener, err = metrics.NewListener(addr)
+ return listener, err
+ },
+ })
+ Expect(m).To(BeNil())
+ Expect(err).To(HaveOccurred())
+ Expect(listener).To(BeNil())
+
+ Expect(ln.Close()).ToNot(HaveOccurred())
+ })
+
+ It("should create a listener for the health probes if a valid address is provided", func() {
+ var listener net.Listener
+ m, err := New(cfg, Options{
+ HealthProbeBindAddress: ":0",
+ newHealthProbeListener: func(addr string) (net.Listener, error) {
+ var err error
+ listener, err = defaultHealthProbeListener(addr)
+ return listener, err
+ },
+ })
+ Expect(m).ToNot(BeNil())
+ Expect(err).ToNot(HaveOccurred())
+ Expect(listener).ToNot(BeNil())
+ Expect(listener.Close()).ToNot(HaveOccurred())
+ })
+
+ It("should return an error if the health probes bind address is already in use", func() {
+ ln, err := defaultHealthProbeListener(":0")
+ Expect(err).ShouldNot(HaveOccurred())
+
+ var listener net.Listener
+ m, err := New(cfg, Options{
+ HealthProbeBindAddress: ln.Addr().String(),
+ newHealthProbeListener: func(addr string) (net.Listener, error) {
+ var err error
+ listener, err = defaultHealthProbeListener(addr)
+ return listener, err
+ },
+ })
+ Expect(m).To(BeNil())
+ Expect(err).To(HaveOccurred())
+ Expect(listener).To(BeNil())
+
+ Expect(ln.Close()).ToNot(HaveOccurred())
+ })
+ })
+
+ Describe("Start", func() {
+ var startSuite = func(options Options, callbacks ...func(Manager)) {
+ It("should Start each Component", func() {
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+ var wgRunnableStarted sync.WaitGroup
+ wgRunnableStarted.Add(2)
+ Expect(m.Add(RunnableFunc(func(context.Context) error {
+ defer GinkgoRecover()
+ wgRunnableStarted.Done()
+ return nil
+ }))).To(Succeed())
+
+ Expect(m.Add(RunnableFunc(func(context.Context) error {
+ defer GinkgoRecover()
+ wgRunnableStarted.Done()
+ return nil
+ }))).To(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Elected()).ShouldNot(BeClosed())
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ <-m.Elected()
+ wgRunnableStarted.Wait()
+ })
+
+ It("should not manipulate the provided config", func() {
+ // strip WrapTransport, cause func values are PartialEq, not Eq --
+ // specifically, for reflect.DeepEqual, for all functions F,
+ // F != nil implies F != F, which means no full equivalence relation.
+ cfg := rest.CopyConfig(cfg)
+ cfg.WrapTransport = nil
+ originalCfg := rest.CopyConfig(cfg)
+ // The options object is shared by multiple tests, copy it
+ // into our scope so we manipulate it for this testcase only
+ options := options
+ options.newResourceLock = nil
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+ Expect(m.GetConfig()).To(Equal(originalCfg))
+ })
+
+ It("should stop when context is cancelled", func() {
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ })
+
+ It("should return an error if it can't start the cache", func() {
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+ mgr, ok := m.(*controllerManager)
+ Expect(ok).To(BeTrue())
+ Expect(mgr.Add(
+ &cacheProvider{cache: &informertest.FakeInformers{Error: fmt.Errorf("expected error")}},
+ )).To(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ Expect(m.Start(ctx)).To(MatchError(ContainSubstring("expected error")))
+ })
+
+ It("should start the cache before starting anything else", func() {
+ fakeCache := &startSignalingInformer{Cache: &informertest.FakeInformers{}}
+ options.NewCache = func(_ *rest.Config, _ cache.Options) (cache.Cache, error) {
+ return fakeCache, nil
+ }
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+
+ runnableWasStarted := make(chan struct{})
+ runnable := RunnableFunc(func(ctx context.Context) error {
+ defer GinkgoRecover()
+ if !fakeCache.wasSynced {
+ return errors.New("runnable got started before cache was synced")
+ }
+ close(runnableWasStarted)
+ return nil
+ })
+ Expect(m.Add(runnable)).To(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).ToNot(HaveOccurred())
+ }()
+
+ <-runnableWasStarted
+ })
+
+ It("should start additional clusters before anything else", func() {
+ fakeCache := &startSignalingInformer{Cache: &informertest.FakeInformers{}}
+ options.NewCache = func(_ *rest.Config, _ cache.Options) (cache.Cache, error) {
+ return fakeCache, nil
+ }
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+
+ additionalClusterCache := &startSignalingInformer{Cache: &informertest.FakeInformers{}}
+ additionalCluster, err := cluster.New(cfg, func(o *cluster.Options) {
+ o.NewCache = func(_ *rest.Config, _ cache.Options) (cache.Cache, error) {
+ return additionalClusterCache, nil
+ }
+ })
+ Expect(err).NotTo(HaveOccurred())
+ Expect(m.Add(additionalCluster)).NotTo(HaveOccurred())
+
+ runnableWasStarted := make(chan struct{})
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ defer GinkgoRecover()
+ if !fakeCache.wasSynced {
+ return errors.New("WaitForCacheSyncCalled wasn't called before Runnable got started")
+ }
+ if !additionalClusterCache.wasSynced {
+ return errors.New("the additional clusters WaitForCacheSync wasn't called before Runnable got started")
+ }
+ close(runnableWasStarted)
+ return nil
+ }))).To(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).ToNot(HaveOccurred())
+ }()
+
+ <-runnableWasStarted
+ })
+
+ It("should return an error if any Components fail to Start", func() {
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ defer GinkgoRecover()
+ <-ctx.Done()
+ return nil
+ }))).To(Succeed())
+
+ Expect(m.Add(RunnableFunc(func(context.Context) error {
+ defer GinkgoRecover()
+ return fmt.Errorf("expected error")
+ }))).To(Succeed())
+
+ Expect(m.Add(RunnableFunc(func(context.Context) error {
+ defer GinkgoRecover()
+ return nil
+ }))).To(Succeed())
+
+ defer GinkgoRecover()
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ err = m.Start(ctx)
+ Expect(err).ToNot(BeNil())
+ Expect(err.Error()).To(Equal("expected error"))
+ })
+
+ It("should start caches added after Manager has started", func() {
+ fakeCache := &startSignalingInformer{Cache: &informertest.FakeInformers{}}
+ options.NewCache = func(_ *rest.Config, _ cache.Options) (cache.Cache, error) {
+ return fakeCache, nil
+ }
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+
+ runnableWasStarted := make(chan struct{})
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ defer GinkgoRecover()
+ if !fakeCache.wasSynced {
+ return errors.New("WaitForCacheSyncCalled wasn't called before Runnable got started")
+ }
+ close(runnableWasStarted)
+ return nil
+ }))).To(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).ToNot(HaveOccurred())
+ }()
+
+ <-runnableWasStarted
+
+ additionalClusterCache := &startSignalingInformer{Cache: &informertest.FakeInformers{}}
+ fakeCluster := &startClusterAfterManager{informer: additionalClusterCache}
+
+ Expect(err).NotTo(HaveOccurred())
+ Expect(m.Add(fakeCluster)).NotTo(HaveOccurred())
+
+ Eventually(func() bool {
+ fakeCluster.informer.mu.Lock()
+ defer fakeCluster.informer.mu.Unlock()
+ return fakeCluster.informer.wasStarted && fakeCluster.informer.wasSynced
+ }).Should(BeTrue())
+ })
+
+ It("should wait for runnables to stop", func() {
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+
+ var lock sync.Mutex
+ var runnableDoneCount int64
+ runnableDoneFunc := func() {
+ lock.Lock()
+ defer lock.Unlock()
+ atomic.AddInt64(&runnableDoneCount, 1)
+ }
+ var wgRunnableRunning sync.WaitGroup
+ wgRunnableRunning.Add(2)
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ wgRunnableRunning.Done()
+ defer GinkgoRecover()
+ defer runnableDoneFunc()
+ <-ctx.Done()
+ return nil
+ }))).To(Succeed())
+
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ wgRunnableRunning.Done()
+ defer GinkgoRecover()
+ defer runnableDoneFunc()
+ <-ctx.Done()
+ time.Sleep(300 * time.Millisecond) // slow closure simulation
+ return nil
+ }))).To(Succeed())
+
+ defer GinkgoRecover()
+ ctx, cancel := context.WithCancel(context.Background())
+
+ var wgManagerRunning sync.WaitGroup
+ wgManagerRunning.Add(1)
+ go func() {
+ defer GinkgoRecover()
+ defer wgManagerRunning.Done()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ Eventually(func() int64 {
+ return atomic.LoadInt64(&runnableDoneCount)
+ }).Should(BeEquivalentTo(2))
+ }()
+ wgRunnableRunning.Wait()
+ cancel()
+
+ wgManagerRunning.Wait()
+ })
+
+ It("should return an error if any Components fail to Start and wait for runnables to stop", func() {
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+ defer GinkgoRecover()
+ var lock sync.Mutex
+ runnableDoneCount := 0
+ runnableDoneFunc := func() {
+ lock.Lock()
+ defer lock.Unlock()
+ runnableDoneCount++
+ }
+
+ Expect(m.Add(RunnableFunc(func(context.Context) error {
+ defer GinkgoRecover()
+ defer runnableDoneFunc()
+ return fmt.Errorf("expected error")
+ }))).To(Succeed())
+
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ defer GinkgoRecover()
+ defer runnableDoneFunc()
+ <-ctx.Done()
+ return nil
+ }))).To(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ Expect(m.Start(ctx)).To(HaveOccurred())
+ Expect(runnableDoneCount).To(Equal(2))
+ })
+
+ It("should refuse to add runnable if stop procedure is already engaged", func() {
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+ defer GinkgoRecover()
+
+ var wgRunnableRunning sync.WaitGroup
+ wgRunnableRunning.Add(1)
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ wgRunnableRunning.Done()
+ defer GinkgoRecover()
+ <-ctx.Done()
+ return nil
+ }))).To(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ wgRunnableRunning.Wait()
+ cancel()
+ time.Sleep(100 * time.Millisecond) // give some time for the stop chan closure to be caught by the manager
+ Expect(m.Add(RunnableFunc(func(context.Context) error {
+ defer GinkgoRecover()
+ return nil
+ }))).NotTo(Succeed())
+ })
+
+ It("should return both runnables and stop errors when both error", func() {
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+ m.(*controllerManager).gracefulShutdownTimeout = 1 * time.Nanosecond
+ Expect(m.Add(RunnableFunc(func(context.Context) error {
+ return runnableError{}
+ })))
+ testDone := make(chan struct{})
+ defer close(testDone)
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ <-ctx.Done()
+ timer := time.NewTimer(30 * time.Second)
+ defer timer.Stop()
+ select {
+ case <-testDone:
+ return nil
+ case <-timer.C:
+ return nil
+ }
+ })))
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ err = m.Start(ctx)
+ Expect(err).ToNot(BeNil())
+ eMsg := "[not feeling like that, failed waiting for all runnables to end within grace period of 1ns: context deadline exceeded]"
+ Expect(err.Error()).To(Equal(eMsg))
+ Expect(errors.Is(err, context.DeadlineExceeded)).To(BeTrue())
+ Expect(errors.Is(err, runnableError{})).To(BeTrue())
+ })
+
+ It("should return only stop errors if runnables dont error", func() {
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+ m.(*controllerManager).gracefulShutdownTimeout = 1 * time.Nanosecond
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ <-ctx.Done()
+ return nil
+ })))
+ testDone := make(chan struct{})
+ defer close(testDone)
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ <-ctx.Done()
+ timer := time.NewTimer(30 * time.Second)
+ defer timer.Stop()
+ select {
+ case <-testDone:
+ return nil
+ case <-timer.C:
+ return nil
+ }
+ }))).NotTo(HaveOccurred())
+ ctx, cancel := context.WithCancel(context.Background())
+ managerStopDone := make(chan struct{})
+ go func() { err = m.Start(ctx); close(managerStopDone) }()
+ // Use the 'elected' channel to find out if startup was done, otherwise we stop
+ // before we started the Runnable and see flakes, mostly in low-CPU envs like CI
+ <-m.(*controllerManager).elected
+ cancel()
+ <-managerStopDone
+ Expect(err).ToNot(BeNil())
+ Expect(err.Error()).To(Equal("failed waiting for all runnables to end within grace period of 1ns: context deadline exceeded"))
+ Expect(errors.Is(err, context.DeadlineExceeded)).To(BeTrue())
+ Expect(errors.Is(err, runnableError{})).ToNot(BeTrue())
+ })
+
+ It("should return only runnables error if stop doesn't error", func() {
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+ Expect(m.Add(RunnableFunc(func(context.Context) error {
+ return runnableError{}
+ })))
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ err = m.Start(ctx)
+ Expect(err).ToNot(BeNil())
+ Expect(err.Error()).To(Equal("not feeling like that"))
+ Expect(errors.Is(err, context.DeadlineExceeded)).ToNot(BeTrue())
+ Expect(errors.Is(err, runnableError{})).To(BeTrue())
+ })
+
+ It("should not wait for runnables if gracefulShutdownTimeout is 0", func() {
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+ m.(*controllerManager).gracefulShutdownTimeout = time.Duration(0)
+
+ runnableStopped := make(chan struct{})
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ <-ctx.Done()
+ time.Sleep(100 * time.Millisecond)
+ close(runnableStopped)
+ return nil
+ }))).ToNot(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ managerStopDone := make(chan struct{})
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ close(managerStopDone)
+ }()
+ <-m.Elected()
+ cancel()
+
+ <-managerStopDone
+ <-runnableStopped
+ })
+
+ It("should wait forever for runnables if gracefulShutdownTimeout is <0 (-1)", func() {
+ m, err := New(cfg, options)
+ Expect(err).NotTo(HaveOccurred())
+ for _, cb := range callbacks {
+ cb(m)
+ }
+ m.(*controllerManager).gracefulShutdownTimeout = time.Duration(-1)
+
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ <-ctx.Done()
+ time.Sleep(100 * time.Millisecond)
+ return nil
+ }))).ToNot(HaveOccurred())
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ <-ctx.Done()
+ time.Sleep(200 * time.Millisecond)
+ return nil
+ }))).ToNot(HaveOccurred())
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ <-ctx.Done()
+ time.Sleep(500 * time.Millisecond)
+ return nil
+ }))).ToNot(HaveOccurred())
+ Expect(m.Add(RunnableFunc(func(ctx context.Context) error {
+ <-ctx.Done()
+ time.Sleep(1500 * time.Millisecond)
+ return nil
+ }))).ToNot(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ managerStopDone := make(chan struct{})
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ close(managerStopDone)
+ }()
+ <-m.Elected()
+ cancel()
+
+ beforeDone := time.Now()
+ <-managerStopDone
+ Expect(time.Since(beforeDone)).To(BeNumerically(">=", 1500*time.Millisecond))
+ })
+
+ }
+
+ Context("with defaults", func() {
+ startSuite(Options{})
+ })
+
+ Context("with leaderelection enabled", func() {
+ startSuite(
+ Options{
+ LeaderElection: true,
+ LeaderElectionID: "controller-runtime",
+ LeaderElectionNamespace: "default",
+ newResourceLock: fakeleaderelection.NewResourceLock,
+ },
+ func(m Manager) {
+ cm, ok := m.(*controllerManager)
+ Expect(ok).To(BeTrue())
+ cm.onStoppedLeading = func() {}
+ },
+ )
+ })
+
+ Context("should start serving metrics", func() {
+ var listener net.Listener
+ var opts Options
+
+ BeforeEach(func() {
+ listener = nil
+ opts = Options{
+ newMetricsListener: func(addr string) (net.Listener, error) {
+ var err error
+ listener, err = metrics.NewListener(addr)
+ return listener, err
+ },
+ }
+ })
+
+ AfterEach(func() {
+ if listener != nil {
+ listener.Close()
+ }
+ })
+
+ It("should stop serving metrics when stop is called", func() {
+ opts.MetricsBindAddress = ":0"
+ m, err := New(cfg, opts)
+ Expect(err).NotTo(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ // Check the metrics started
+ endpoint := fmt.Sprintf("http://%s", listener.Addr().String())
+ _, err = http.Get(endpoint)
+ Expect(err).NotTo(HaveOccurred())
+
+ // Shutdown the server
+ cancel()
+
+ // Expect the metrics server to shutdown
+ Eventually(func() error {
+ _, err = http.Get(endpoint)
+ return err
+ }).ShouldNot(Succeed())
+ })
+
+ It("should serve metrics endpoint", func() {
+ opts.MetricsBindAddress = ":0"
+ m, err := New(cfg, opts)
+ Expect(err).NotTo(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ <-m.Elected()
+
+ metricsEndpoint := fmt.Sprintf("http://%s/metrics", listener.Addr().String())
+ resp, err := http.Get(metricsEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(resp.StatusCode).To(Equal(200))
+ })
+
+ It("should not serve anything other than metrics endpoint by default", func() {
+ opts.MetricsBindAddress = ":0"
+ m, err := New(cfg, opts)
+ Expect(err).NotTo(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ <-m.Elected()
+
+ endpoint := fmt.Sprintf("http://%s/should-not-exist", listener.Addr().String())
+ resp, err := http.Get(endpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(404))
+ })
+
+ It("should serve metrics in its registry", func() {
+ one := prometheus.NewCounter(prometheus.CounterOpts{
+ Name: "test_one",
+ Help: "test metric for testing",
+ })
+ one.Inc()
+ err := metrics.Registry.Register(one)
+ Expect(err).NotTo(HaveOccurred())
+
+ opts.MetricsBindAddress = ":0"
+ m, err := New(cfg, opts)
+ Expect(err).NotTo(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ <-m.Elected()
+
+ metricsEndpoint := fmt.Sprintf("http://%s/metrics", listener.Addr().String())
+ resp, err := http.Get(metricsEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(200))
+
+ data, err := io.ReadAll(resp.Body)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(string(data)).To(ContainSubstring("%s\n%s\n%s\n",
+ `# HELP test_one test metric for testing`,
+ `# TYPE test_one counter`,
+ `test_one 1`,
+ ))
+
+ // Unregister will return false if the metric was never registered
+ ok := metrics.Registry.Unregister(one)
+ Expect(ok).To(BeTrue())
+ })
+
+ It("should serve extra endpoints", func() {
+ opts.MetricsBindAddress = ":0"
+ m, err := New(cfg, opts)
+ Expect(err).NotTo(HaveOccurred())
+
+ err = m.AddMetricsExtraHandler("/debug", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ _, _ = w.Write([]byte("Some debug info"))
+ }))
+ Expect(err).NotTo(HaveOccurred())
+
+ // Should error when we add another extra endpoint on the already registered path.
+ err = m.AddMetricsExtraHandler("/debug", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ _, _ = w.Write([]byte("Another debug info"))
+ }))
+ Expect(err).To(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ <-m.Elected()
+
+ endpoint := fmt.Sprintf("http://%s/debug", listener.Addr().String())
+ resp, err := http.Get(endpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ body, err := io.ReadAll(resp.Body)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(string(body)).To(Equal("Some debug info"))
+ })
+ })
+ })
+
+ Context("should start serving health probes", func() {
+ var listener net.Listener
+ var opts Options
+
+ BeforeEach(func() {
+ listener = nil
+ opts = Options{
+ newHealthProbeListener: func(addr string) (net.Listener, error) {
+ var err error
+ listener, err = defaultHealthProbeListener(addr)
+ return listener, err
+ },
+ }
+ })
+
+ AfterEach(func() {
+ if listener != nil {
+ listener.Close()
+ }
+ })
+
+ It("should stop serving health probes when stop is called", func() {
+ opts.HealthProbeBindAddress = ":0"
+ m, err := New(cfg, opts)
+ Expect(err).NotTo(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ <-m.Elected()
+
+ // Check the health probes started
+ endpoint := fmt.Sprintf("http://%s", listener.Addr().String())
+ _, err = http.Get(endpoint)
+ Expect(err).NotTo(HaveOccurred())
+
+ // Shutdown the server
+ cancel()
+
+ // Expect the health probes server to shutdown
+ Eventually(func() error {
+ _, err = http.Get(endpoint)
+ return err
+ }, 10*time.Second).ShouldNot(Succeed())
+ })
+
+ It("should serve readiness endpoint", func() {
+ opts.HealthProbeBindAddress = ":0"
+ m, err := New(cfg, opts)
+ Expect(err).NotTo(HaveOccurred())
+
+ res := fmt.Errorf("not ready yet")
+ namedCheck := "check"
+ err = m.AddReadyzCheck(namedCheck, func(_ *http.Request) error { return res })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ <-m.Elected()
+
+ readinessEndpoint := fmt.Sprint("http://", listener.Addr().String(), defaultReadinessEndpoint)
+
+ // Controller is not ready
+ resp, err := http.Get(readinessEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusInternalServerError))
+
+ // Controller is ready
+ res = nil
+ resp, err = http.Get(readinessEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ // Check readiness path without trailing slash without redirect
+ readinessEndpoint = fmt.Sprint("http://", listener.Addr().String(), defaultReadinessEndpoint)
+ res = nil
+ httpClient := http.Client{
+ CheckRedirect: func(req *http.Request, via []*http.Request) error {
+ return http.ErrUseLastResponse // Do not follow redirect
+ },
+ }
+ resp, err = httpClient.Get(readinessEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ // Check readiness path for individual check
+ readinessEndpoint = fmt.Sprint("http://", listener.Addr().String(), path.Join(defaultReadinessEndpoint, namedCheck))
+ res = nil
+ resp, err = http.Get(readinessEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ })
+
+ It("should serve liveness endpoint", func() {
+ opts.HealthProbeBindAddress = ":0"
+ m, err := New(cfg, opts)
+ Expect(err).NotTo(HaveOccurred())
+
+ res := fmt.Errorf("not alive")
+ namedCheck := "check"
+ err = m.AddHealthzCheck(namedCheck, func(_ *http.Request) error { return res })
+ Expect(err).NotTo(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ <-m.Elected()
+
+ livenessEndpoint := fmt.Sprint("http://", listener.Addr().String(), defaultLivenessEndpoint)
+
+ // Controller is not ready
+ resp, err := http.Get(livenessEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusInternalServerError))
+
+ // Controller is ready
+ res = nil
+ resp, err = http.Get(livenessEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ // Check liveness path without trailing slash without redirect
+ livenessEndpoint = fmt.Sprint("http://", listener.Addr().String(), defaultLivenessEndpoint)
+ res = nil
+ httpClient := http.Client{
+ CheckRedirect: func(req *http.Request, via []*http.Request) error {
+ return http.ErrUseLastResponse // Do not follow redirect
+ },
+ }
+ resp, err = httpClient.Get(livenessEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ // Check readiness path for individual check
+ livenessEndpoint = fmt.Sprint("http://", listener.Addr().String(), path.Join(defaultLivenessEndpoint, namedCheck))
+ res = nil
+ resp, err = http.Get(livenessEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ })
+ })
+
+ Context("should start serving pprof", func() {
+ var listener net.Listener
+ var opts Options
+
+ BeforeEach(func() {
+ listener = nil
+ opts = Options{
+ newPprofListener: func(addr string) (net.Listener, error) {
+ var err error
+ listener, err = defaultPprofListener(addr)
+ return listener, err
+ },
+ }
+ })
+
+ AfterEach(func() {
+ if listener != nil {
+ listener.Close()
+ }
+ })
+
+ It("should stop serving pprof when stop is called", func() {
+ opts.PprofBindAddress = ":0"
+ m, err := New(cfg, opts)
+ Expect(err).NotTo(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ <-m.Elected()
+
+ // Check the pprof started
+ endpoint := fmt.Sprintf("http://%s", listener.Addr().String())
+ _, err = http.Get(endpoint)
+ Expect(err).NotTo(HaveOccurred())
+
+ // Shutdown the server
+ cancel()
+
+ // Expect the pprof server to shutdown
+ Eventually(func() error {
+ _, err = http.Get(endpoint)
+ return err
+ }, 10*time.Second).ShouldNot(Succeed())
+ })
+
+ It("should serve pprof endpoints", func() {
+ opts.PprofBindAddress = ":0"
+ m, err := New(cfg, opts)
+ Expect(err).NotTo(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ <-m.Elected()
+
+ pprofIndexEndpoint := fmt.Sprintf("http://%s/debug/pprof/", listener.Addr().String())
+ resp, err := http.Get(pprofIndexEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ pprofCmdlineEndpoint := fmt.Sprintf("http://%s/debug/pprof/cmdline", listener.Addr().String())
+ resp, err = http.Get(pprofCmdlineEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ pprofProfileEndpoint := fmt.Sprintf("http://%s/debug/pprof/profile", listener.Addr().String())
+ resp, err = http.Get(pprofProfileEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ pprofSymbolEndpoint := fmt.Sprintf("http://%s/debug/pprof/symbol", listener.Addr().String())
+ resp, err = http.Get(pprofSymbolEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ pprofTraceEndpoint := fmt.Sprintf("http://%s/debug/pprof/trace", listener.Addr().String())
+ resp, err = http.Get(pprofTraceEndpoint)
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ })
+ })
+
+ Describe("Add", func() {
+ It("should immediately start the Component if the Manager has already Started another Component",
+ func() {
+ m, err := New(cfg, Options{})
+ Expect(err).NotTo(HaveOccurred())
+ mgr, ok := m.(*controllerManager)
+ Expect(ok).To(BeTrue())
+
+ // Add one component before starting
+ c1 := make(chan struct{})
+ Expect(m.Add(RunnableFunc(func(context.Context) error {
+ defer GinkgoRecover()
+ close(c1)
+ return nil
+ }))).To(Succeed())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ <-m.Elected()
+
+ // Wait for the Manager to start
+ Eventually(func() bool {
+ return mgr.runnables.Caches.Started()
+ }).Should(BeTrue())
+
+ // Add another component after starting
+ c2 := make(chan struct{})
+ Expect(m.Add(RunnableFunc(func(context.Context) error {
+ defer GinkgoRecover()
+ close(c2)
+ return nil
+ }))).To(Succeed())
+ <-c1
+ <-c2
+ })
+
+ It("should immediately start the Component if the Manager has already Started", func() {
+ m, err := New(cfg, Options{})
+ Expect(err).NotTo(HaveOccurred())
+ mgr, ok := m.(*controllerManager)
+ Expect(ok).To(BeTrue())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+
+ // Wait for the Manager to start
+ Eventually(func() bool {
+ return mgr.runnables.Caches.Started()
+ }).Should(BeTrue())
+
+ c1 := make(chan struct{})
+ Expect(m.Add(RunnableFunc(func(context.Context) error {
+ defer GinkgoRecover()
+ close(c1)
+ return nil
+ }))).To(Succeed())
+ <-c1
+ })
+
+ It("should fail if attempted to start a second time", func() {
+ m, err := New(cfg, Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go func() {
+ defer GinkgoRecover()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+ }()
+ // Wait for the Manager to start
+ Eventually(func() bool {
+ mgr, ok := m.(*controllerManager)
+ Expect(ok).To(BeTrue())
+ return mgr.runnables.Caches.Started()
+ }).Should(BeTrue())
+
+ err = m.Start(ctx)
+ Expect(err).ToNot(BeNil())
+ Expect(err.Error()).To(Equal("manager already started"))
+
+ })
+ })
+
+ It("should not leak goroutines when stopped", func() {
+ currentGRs := goleak.IgnoreCurrent()
+
+ m, err := New(cfg, Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ Expect(m.Start(ctx)).NotTo(HaveOccurred())
+
+ // force-close keep-alive connections. These'll time anyway (after
+ // like 30s or so) but force it to speed up the tests.
+ clientTransport.CloseIdleConnections()
+ Eventually(func() error { return goleak.Find(currentGRs) }).Should(Succeed())
+ })
+
+ It("should not leak goroutines if the default event broadcaster is used & events are emitted", func() {
+ currentGRs := goleak.IgnoreCurrent()
+
+ m, err := New(cfg, Options{ /* implicit: default setting for EventBroadcaster */ })
+ Expect(err).NotTo(HaveOccurred())
+
+ By("adding a runnable that emits an event")
+ ns := corev1.Namespace{}
+ ns.Name = "default"
+
+ recorder := m.GetEventRecorderFor("rock-and-roll")
+ Expect(m.Add(RunnableFunc(func(_ context.Context) error {
+ recorder.Event(&ns, "Warning", "BallroomBlitz", "yeah, yeah, yeah-yeah-yeah")
+ return nil
+ }))).To(Succeed())
+
+ By("starting the manager & waiting till we've sent our event")
+ ctx, cancel := context.WithCancel(context.Background())
+ doneCh := make(chan struct{})
+ go func() {
+ defer GinkgoRecover()
+ defer close(doneCh)
+ Expect(m.Start(ctx)).To(Succeed())
+ }()
+ <-m.Elected()
+
+ Eventually(func() *corev1.Event {
+ evts, err := clientset.CoreV1().Events("").Search(m.GetScheme(), &ns)
+ Expect(err).NotTo(HaveOccurred())
+
+ for i, evt := range evts.Items {
+ if evt.Reason == "BallroomBlitz" {
+ return &evts.Items[i]
+ }
+ }
+ return nil
+ }).ShouldNot(BeNil())
+
+ By("making sure there's no extra go routines still running after we stop")
+ cancel()
+ <-doneCh
+
+ // force-close keep-alive connections. These'll time anyway (after
+ // like 30s or so) but force it to speed up the tests.
+ clientTransport.CloseIdleConnections()
+ Eventually(func() error { return goleak.Find(currentGRs) }).Should(Succeed())
+ })
+
+ It("should provide a function to get the Config", func() {
+ m, err := New(cfg, Options{})
+ Expect(err).NotTo(HaveOccurred())
+ mgr, ok := m.(*controllerManager)
+ Expect(ok).To(BeTrue())
+ Expect(m.GetConfig()).To(Equal(mgr.cluster.GetConfig()))
+ })
+
+ It("should provide a function to get the Client", func() {
+ m, err := New(cfg, Options{})
+ Expect(err).NotTo(HaveOccurred())
+ mgr, ok := m.(*controllerManager)
+ Expect(ok).To(BeTrue())
+ Expect(m.GetClient()).To(Equal(mgr.cluster.GetClient()))
+ })
+
+ It("should provide a function to get the Scheme", func() {
+ m, err := New(cfg, Options{})
+ Expect(err).NotTo(HaveOccurred())
+ mgr, ok := m.(*controllerManager)
+ Expect(ok).To(BeTrue())
+ Expect(m.GetScheme()).To(Equal(mgr.cluster.GetScheme()))
+ })
+
+ It("should provide a function to get the FieldIndexer", func() {
+ m, err := New(cfg, Options{})
+ Expect(err).NotTo(HaveOccurred())
+ mgr, ok := m.(*controllerManager)
+ Expect(ok).To(BeTrue())
+ Expect(m.GetFieldIndexer()).To(Equal(mgr.cluster.GetFieldIndexer()))
+ })
+
+ It("should provide a function to get the EventRecorder", func() {
+ m, err := New(cfg, Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(m.GetEventRecorderFor("test")).NotTo(BeNil())
+ })
+ It("should provide a function to get the APIReader", func() {
+ m, err := New(cfg, Options{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(m.GetAPIReader()).NotTo(BeNil())
+ })
+})
+
+type runnableError struct {
+}
+
+func (runnableError) Error() string {
+ return "not feeling like that"
+}
+
+var _ Runnable = &cacheProvider{}
+
+type cacheProvider struct {
+ cache cache.Cache
+}
+
+func (c *cacheProvider) GetCache() cache.Cache {
+ return c.cache
+}
+
+func (c *cacheProvider) Start(ctx context.Context) error {
+ return c.cache.Start(ctx)
+}
+
+type startSignalingInformer struct {
+ mu sync.Mutex
+
+ // The manager calls Start and WaitForCacheSync in
+ // parallel, so we have to protect wasStarted with a Mutex
+ // and block in WaitForCacheSync until it is true.
+ wasStarted bool
+ // was synced will be true once Start was called and
+ // WaitForCacheSync returned, just like a real cache.
+ wasSynced bool
+ cache.Cache
+}
+
+func (c *startSignalingInformer) Start(ctx context.Context) error {
+ c.mu.Lock()
+ c.wasStarted = true
+ c.mu.Unlock()
+ return c.Cache.Start(ctx)
+}
+
+func (c *startSignalingInformer) WaitForCacheSync(ctx context.Context) bool {
+ defer func() {
+ c.mu.Lock()
+ c.wasSynced = true
+ c.mu.Unlock()
+ }()
+ return c.Cache.WaitForCacheSync(ctx)
+}
+
+type startClusterAfterManager struct {
+ informer *startSignalingInformer
+}
+
+func (c *startClusterAfterManager) Start(ctx context.Context) error {
+ return c.informer.Start(ctx)
+}
+
+func (c *startClusterAfterManager) GetCache() cache.Cache {
+ return c.informer
+}
+
+type fakeDeferredLoader struct {
+ *v1alpha1.ControllerManagerConfiguration
+}
+
+func (f *fakeDeferredLoader) Complete() (v1alpha1.ControllerManagerConfigurationSpec, error) {
+ return f.ControllerManagerConfiguration.ControllerManagerConfigurationSpec, nil
+}
+
+func (f *fakeDeferredLoader) InjectScheme(scheme *runtime.Scheme) error {
+ return nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group.go
new file mode 100644
index 00000000000..549741e6e53
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group.go
@@ -0,0 +1,297 @@
+package manager
+
+import (
+ "context"
+ "errors"
+ "sync"
+
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+var (
+ errRunnableGroupStopped = errors.New("can't accept new runnable as stop procedure is already engaged")
+)
+
+// readyRunnable encapsulates a runnable with
+// a ready check.
+type readyRunnable struct {
+ Runnable
+ Check runnableCheck
+ signalReady bool
+}
+
+// runnableCheck can be passed to Add() to let the runnable group determine that a
+// runnable is ready. A runnable check should block until a runnable is ready,
+// if the returned result is false, the runnable is considered not ready and failed.
+type runnableCheck func(ctx context.Context) bool
+
+// runnables handles all the runnables for a manager by grouping them accordingly to their
+// type (webhooks, caches etc.).
+type runnables struct {
+ Webhooks *runnableGroup
+ Caches *runnableGroup
+ LeaderElection *runnableGroup
+ Others *runnableGroup
+}
+
+// newRunnables creates a new runnables object.
+func newRunnables(baseContext BaseContextFunc, errChan chan error) *runnables {
+ return &runnables{
+ Webhooks: newRunnableGroup(baseContext, errChan),
+ Caches: newRunnableGroup(baseContext, errChan),
+ LeaderElection: newRunnableGroup(baseContext, errChan),
+ Others: newRunnableGroup(baseContext, errChan),
+ }
+}
+
+// Add adds a runnable to closest group of runnable that they belong to.
+//
+// Add should be able to be called before and after Start, but not after StopAndWait.
+// Add should return an error when called during StopAndWait.
+// The runnables added before Start are started when Start is called.
+// The runnables added after Start are started directly.
+func (r *runnables) Add(fn Runnable) error {
+ switch runnable := fn.(type) {
+ case hasCache:
+ return r.Caches.Add(fn, func(ctx context.Context) bool {
+ return runnable.GetCache().WaitForCacheSync(ctx)
+ })
+ case webhook.Server:
+ return r.Webhooks.Add(fn, nil)
+ case LeaderElectionRunnable:
+ if !runnable.NeedLeaderElection() {
+ return r.Others.Add(fn, nil)
+ }
+ return r.LeaderElection.Add(fn, nil)
+ default:
+ return r.LeaderElection.Add(fn, nil)
+ }
+}
+
+// runnableGroup manages a group of runnables that are
+// meant to be running together until StopAndWait is called.
+//
+// Runnables can be added to a group after the group has started
+// but not after it's stopped or while shutting down.
+type runnableGroup struct {
+ ctx context.Context
+ cancel context.CancelFunc
+
+ start sync.Mutex
+ startOnce sync.Once
+ started bool
+ startQueue []*readyRunnable
+ startReadyCh chan *readyRunnable
+
+ stop sync.RWMutex
+ stopOnce sync.Once
+ stopped bool
+
+ // errChan is the error channel passed by the caller
+ // when the group is created.
+ // All errors are forwarded to this channel once they occur.
+ errChan chan error
+
+ // ch is the internal channel where the runnables are read off from.
+ ch chan *readyRunnable
+
+ // wg is an internal sync.WaitGroup that allows us to properly stop
+ // and wait for all the runnables to finish before returning.
+ wg *sync.WaitGroup
+}
+
+func newRunnableGroup(baseContext BaseContextFunc, errChan chan error) *runnableGroup {
+ r := &runnableGroup{
+ startReadyCh: make(chan *readyRunnable),
+ errChan: errChan,
+ ch: make(chan *readyRunnable),
+ wg: new(sync.WaitGroup),
+ }
+
+ r.ctx, r.cancel = context.WithCancel(baseContext())
+ return r
+}
+
+// Started returns true if the group has started.
+func (r *runnableGroup) Started() bool {
+ r.start.Lock()
+ defer r.start.Unlock()
+ return r.started
+}
+
+// Start starts the group and waits for all
+// initially registered runnables to start.
+// It can only be called once, subsequent calls have no effect.
+func (r *runnableGroup) Start(ctx context.Context) error {
+ var retErr error
+
+ r.startOnce.Do(func() {
+ defer close(r.startReadyCh)
+
+ // Start the internal reconciler.
+ go r.reconcile()
+
+ // Start the group and queue up all
+ // the runnables that were added prior.
+ r.start.Lock()
+ r.started = true
+ for _, rn := range r.startQueue {
+ rn.signalReady = true
+ r.ch <- rn
+ }
+ r.start.Unlock()
+
+ // If we don't have any queue, return.
+ if len(r.startQueue) == 0 {
+ return
+ }
+
+ // Wait for all runnables to signal.
+ for {
+ select {
+ case <-ctx.Done():
+ if err := ctx.Err(); !errors.Is(err, context.Canceled) {
+ retErr = err
+ }
+ case rn := <-r.startReadyCh:
+ for i, existing := range r.startQueue {
+ if existing == rn {
+ // Remove the item from the start queue.
+ r.startQueue = append(r.startQueue[:i], r.startQueue[i+1:]...)
+ break
+ }
+ }
+ // We're done waiting if the queue is empty, return.
+ if len(r.startQueue) == 0 {
+ return
+ }
+ }
+ }
+ })
+
+ return retErr
+}
+
+// reconcile is our main entrypoint for every runnable added
+// to this group. Its primary job is to read off the internal channel
+// and schedule runnables while tracking their state.
+func (r *runnableGroup) reconcile() {
+ for runnable := range r.ch {
+ // Handle stop.
+ // If the shutdown has been called we want to avoid
+ // adding new goroutines to the WaitGroup because Wait()
+ // panics if Add() is called after it.
+ {
+ r.stop.RLock()
+ if r.stopped {
+ // Drop any runnables if we're stopped.
+ r.errChan <- errRunnableGroupStopped
+ r.stop.RUnlock()
+ continue
+ }
+
+ // Why is this here?
+ // When StopAndWait is called, if a runnable is in the process
+ // of being added, we could end up in a situation where
+ // the WaitGroup is incremented while StopAndWait has called Wait(),
+ // which would result in a panic.
+ r.wg.Add(1)
+ r.stop.RUnlock()
+ }
+
+ // Start the runnable.
+ go func(rn *readyRunnable) {
+ go func() {
+ if rn.Check(r.ctx) {
+ if rn.signalReady {
+ r.startReadyCh <- rn
+ }
+ }
+ }()
+
+ // If we return, the runnable ended cleanly
+ // or returned an error to the channel.
+ //
+ // We should always decrement the WaitGroup here.
+ defer r.wg.Done()
+
+ // Start the runnable.
+ if err := rn.Start(r.ctx); err != nil {
+ r.errChan <- err
+ }
+ }(runnable)
+ }
+}
+
+// Add should be able to be called before and after Start, but not after StopAndWait.
+// Add should return an error when called during StopAndWait.
+func (r *runnableGroup) Add(rn Runnable, ready runnableCheck) error {
+ r.stop.RLock()
+ if r.stopped {
+ r.stop.RUnlock()
+ return errRunnableGroupStopped
+ }
+ r.stop.RUnlock()
+
+ if ready == nil {
+ ready = func(_ context.Context) bool { return true }
+ }
+
+ readyRunnable := &readyRunnable{
+ Runnable: rn,
+ Check: ready,
+ }
+
+ // Handle start.
+ // If the overall runnable group isn't started yet
+ // we want to buffer the runnables and let Start()
+ // queue them up again later.
+ {
+ r.start.Lock()
+
+ // Check if we're already started.
+ if !r.started {
+ // Store the runnable in the internal if not.
+ r.startQueue = append(r.startQueue, readyRunnable)
+ r.start.Unlock()
+ return nil
+ }
+ r.start.Unlock()
+ }
+
+ // Enqueue the runnable.
+ r.ch <- readyRunnable
+ return nil
+}
+
+// StopAndWait waits for all the runnables to finish before returning.
+func (r *runnableGroup) StopAndWait(ctx context.Context) {
+ r.stopOnce.Do(func() {
+ // Close the reconciler channel once we're done.
+ defer close(r.ch)
+
+ _ = r.Start(ctx)
+ r.stop.Lock()
+ // Store the stopped variable so we don't accept any new
+ // runnables for the time being.
+ r.stopped = true
+ r.stop.Unlock()
+
+ // Cancel the internal channel.
+ r.cancel()
+
+ done := make(chan struct{})
+ go func() {
+ defer close(done)
+ // Wait for all the runnables to finish.
+ r.wg.Wait()
+ }()
+
+ select {
+ case <-done:
+ // We're done, exit.
+ case <-ctx.Done():
+ // Calling context has expired, exit.
+ }
+ })
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group_test.go
new file mode 100644
index 00000000000..456b8d7ac06
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group_test.go
@@ -0,0 +1,182 @@
+package manager
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "sync/atomic"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/utils/pointer"
+ "sigs.k8s.io/controller-runtime/pkg/cache/informertest"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+var _ = Describe("runnables", func() {
+ errCh := make(chan error)
+
+ It("should be able to create a new runnables object", func() {
+ Expect(newRunnables(defaultBaseContext, errCh)).ToNot(BeNil())
+ })
+
+ It("should add caches to the appropriate group", func() {
+ cache := &cacheProvider{cache: &informertest.FakeInformers{Error: fmt.Errorf("expected error")}}
+ r := newRunnables(defaultBaseContext, errCh)
+ Expect(r.Add(cache)).To(Succeed())
+ Expect(r.Caches.startQueue).To(HaveLen(1))
+ })
+
+ It("should add webhooks to the appropriate group", func() {
+ webhook := webhook.NewServer(webhook.Options{})
+ r := newRunnables(defaultBaseContext, errCh)
+ Expect(r.Add(webhook)).To(Succeed())
+ Expect(r.Webhooks.startQueue).To(HaveLen(1))
+ })
+
+ It("should add any runnable to the leader election group", func() {
+ err := errors.New("runnable func")
+ runnable := RunnableFunc(func(c context.Context) error {
+ return err
+ })
+
+ r := newRunnables(defaultBaseContext, errCh)
+ Expect(r.Add(runnable)).To(Succeed())
+ Expect(r.LeaderElection.startQueue).To(HaveLen(1))
+ })
+})
+
+var _ = Describe("runnableGroup", func() {
+ errCh := make(chan error)
+
+ It("should be able to add new runnables before it starts", func() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ rg := newRunnableGroup(defaultBaseContext, errCh)
+ Expect(rg.Add(RunnableFunc(func(c context.Context) error {
+ <-ctx.Done()
+ return nil
+ }), nil)).To(Succeed())
+
+ Expect(rg.Started()).To(BeFalse())
+ })
+
+ It("should be able to add new runnables before and after start", func() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ rg := newRunnableGroup(defaultBaseContext, errCh)
+ Expect(rg.Add(RunnableFunc(func(c context.Context) error {
+ <-ctx.Done()
+ return nil
+ }), nil)).To(Succeed())
+ Expect(rg.Start(ctx)).To(Succeed())
+ Expect(rg.Started()).To(BeTrue())
+ Expect(rg.Add(RunnableFunc(func(c context.Context) error {
+ <-ctx.Done()
+ return nil
+ }), nil)).To(Succeed())
+ })
+
+ It("should be able to add new runnables before and after start concurrently", func() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ rg := newRunnableGroup(defaultBaseContext, errCh)
+
+ go func() {
+ defer GinkgoRecover()
+ <-time.After(50 * time.Millisecond)
+ Expect(rg.Start(ctx)).To(Succeed())
+ }()
+
+ for i := 0; i < 20; i++ {
+ go func(i int) {
+ defer GinkgoRecover()
+
+ <-time.After(time.Duration(i) * 10 * time.Millisecond)
+ Expect(rg.Add(RunnableFunc(func(c context.Context) error {
+ <-ctx.Done()
+ return nil
+ }), nil)).To(Succeed())
+ }(i)
+ }
+ })
+
+ It("should be able to close the group and wait for all runnables to finish", func() {
+ ctx, cancel := context.WithCancel(context.Background())
+
+ exited := pointer.Int64(0)
+ rg := newRunnableGroup(defaultBaseContext, errCh)
+ for i := 0; i < 10; i++ {
+ Expect(rg.Add(RunnableFunc(func(c context.Context) error {
+ defer atomic.AddInt64(exited, 1)
+ <-ctx.Done()
+ <-time.After(time.Duration(i) * 10 * time.Millisecond)
+ return nil
+ }), nil)).To(Succeed())
+ }
+ Expect(rg.Start(ctx)).To(Succeed())
+
+ // Cancel the context, asking the runnables to exit.
+ cancel()
+ rg.StopAndWait(context.Background())
+
+ Expect(rg.Add(RunnableFunc(func(c context.Context) error {
+ return nil
+ }), nil)).ToNot(Succeed())
+
+ Expect(atomic.LoadInt64(exited)).To(BeNumerically("==", 10))
+ })
+
+ It("should be able to wait for all runnables to be ready at different intervals", func() {
+ ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
+ defer cancel()
+ rg := newRunnableGroup(defaultBaseContext, errCh)
+
+ go func() {
+ defer GinkgoRecover()
+ <-time.After(50 * time.Millisecond)
+ Expect(rg.Start(ctx)).To(Succeed())
+ }()
+
+ for i := 0; i < 20; i++ {
+ go func(i int) {
+ defer GinkgoRecover()
+
+ Expect(rg.Add(RunnableFunc(func(c context.Context) error {
+ <-ctx.Done()
+ return nil
+ }), func(_ context.Context) bool {
+ <-time.After(time.Duration(i) * 10 * time.Millisecond)
+ return true
+ })).To(Succeed())
+ }(i)
+ }
+ })
+
+ It("should not turn ready if some readiness check fail", func() {
+ ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
+ defer cancel()
+ rg := newRunnableGroup(defaultBaseContext, errCh)
+
+ go func() {
+ defer GinkgoRecover()
+ <-time.After(50 * time.Millisecond)
+ Expect(rg.Start(ctx)).To(Succeed())
+ }()
+
+ for i := 0; i < 20; i++ {
+ go func(i int) {
+ defer GinkgoRecover()
+
+ Expect(rg.Add(RunnableFunc(func(c context.Context) error {
+ <-ctx.Done()
+ return nil
+ }), func(_ context.Context) bool {
+ <-time.After(time.Duration(i) * 10 * time.Millisecond)
+ return i%2 == 0 // Return false readiness all uneven indexes.
+ })).To(Succeed())
+ }(i)
+ }
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/server.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/server.go
new file mode 100644
index 00000000000..b6509f48f24
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/server.go
@@ -0,0 +1,61 @@
+/*
+Copyright 2022 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package manager
+
+import (
+ "context"
+ "errors"
+ "net"
+ "net/http"
+
+ "github.com/go-logr/logr"
+)
+
+// server is a general purpose HTTP server Runnable for a manager
+// to serve some internal handlers such as health probes, metrics and profiling.
+type server struct {
+ Kind string
+ Log logr.Logger
+ Server *http.Server
+ Listener net.Listener
+}
+
+func (s *server) Start(ctx context.Context) error {
+ log := s.Log.WithValues("kind", s.Kind, "addr", s.Listener.Addr())
+
+ serverShutdown := make(chan struct{})
+ go func() {
+ <-ctx.Done()
+ log.Info("shutting down server")
+ if err := s.Server.Shutdown(context.Background()); err != nil {
+ log.Error(err, "error shutting down server")
+ }
+ close(serverShutdown)
+ }()
+
+ log.Info("starting server")
+ if err := s.Server.Serve(s.Listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
+ return err
+ }
+
+ <-serverShutdown
+ return nil
+}
+
+func (s *server) NeedLeaderElection() bool {
+ return false
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/doc.go
new file mode 100644
index 00000000000..737cc7eff28
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package signals contains libraries for handling signals to gracefully
+// shutdown the manager in combination with Kubernetes pod graceful termination
+// policy.
+package signals
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal.go
new file mode 100644
index 00000000000..a79cfb42dfb
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal.go
@@ -0,0 +1,45 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package signals
+
+import (
+ "context"
+ "os"
+ "os/signal"
+)
+
+var onlyOneSignalHandler = make(chan struct{})
+
+// SetupSignalHandler registers for SIGTERM and SIGINT. A context is returned
+// which is canceled on one of these signals. If a second signal is caught, the program
+// is terminated with exit code 1.
+func SetupSignalHandler() context.Context {
+ close(onlyOneSignalHandler) // panics when called twice
+
+ ctx, cancel := context.WithCancel(context.Background())
+
+ c := make(chan os.Signal, 2)
+ signal.Notify(c, shutdownSignals...)
+ go func() {
+ <-c
+ cancel()
+ <-c
+ os.Exit(1) // second signal. Exit directly.
+ }()
+
+ return ctx
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_posix.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_posix.go
new file mode 100644
index 00000000000..a0f00a73213
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_posix.go
@@ -0,0 +1,27 @@
+//go:build !windows
+// +build !windows
+
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package signals
+
+import (
+ "os"
+ "syscall"
+)
+
+var shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_test.go
new file mode 100644
index 00000000000..134937e012f
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_test.go
@@ -0,0 +1,83 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package signals
+
+import (
+ "fmt"
+ "os"
+ "os/signal"
+ "sync"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("runtime signal", func() {
+
+ Context("SignalHandler Test", func() {
+
+ It("test signal handler", func() {
+ ctx := SetupSignalHandler()
+ task := &Task{
+ ticker: time.NewTicker(time.Second * 2),
+ }
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, os.Interrupt)
+ task.wg.Add(1)
+ go func(c chan os.Signal) {
+ defer task.wg.Done()
+ task.Run(c)
+ }(c)
+
+ select {
+ case sig := <-c:
+ fmt.Printf("Got %s signal. Aborting...\n", sig)
+ case _, ok := <-ctx.Done():
+ Expect(ok).To(BeFalse())
+ }
+ })
+
+ })
+
+})
+
+type Task struct {
+ wg sync.WaitGroup
+ ticker *time.Ticker
+}
+
+func (t *Task) Run(c chan os.Signal) {
+ for {
+ go sendSignal(c)
+ handle()
+ }
+}
+
+func handle() {
+ for i := 0; i < 5; i++ {
+ fmt.Print("#")
+ time.Sleep(time.Millisecond * 100)
+ }
+ fmt.Println()
+}
+
+func sendSignal(stopChan chan os.Signal) {
+ fmt.Printf("...")
+ time.Sleep(1 * time.Second)
+ stopChan <- os.Interrupt
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_windows.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_windows.go
new file mode 100644
index 00000000000..4907d573fe0
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_windows.go
@@ -0,0 +1,23 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package signals
+
+import (
+ "os"
+)
+
+var shutdownSignals = []os.Signal{os.Interrupt}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signals_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signals_suite_test.go
new file mode 100644
index 00000000000..bae6d72ed5d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/signals/signals_suite_test.go
@@ -0,0 +1,34 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package signals
+
+import (
+ "os/signal"
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Runtime Signal Suite")
+}
+
+var _ = BeforeSuite(func() {
+ signal.Reset()
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/manager/testdata/custom-config.yaml b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/testdata/custom-config.yaml
new file mode 100644
index 00000000000..a15c9f8e5c7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/manager/testdata/custom-config.yaml
@@ -0,0 +1,3 @@
+apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
+kind: CustomControllerManagerConfiguration
+customValue: foo
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go b/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go
new file mode 100644
index 00000000000..ff28998c44c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go
@@ -0,0 +1,71 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package metrics
+
+import (
+ "context"
+
+ "github.com/prometheus/client_golang/prometheus"
+ clientmetrics "k8s.io/client-go/tools/metrics"
+)
+
+// this file contains setup logic to initialize the myriad of places
+// that client-go registers metrics. We copy the names and formats
+// from Kubernetes so that we match the core controllers.
+
+var (
+ // client metrics.
+
+ requestResult = prometheus.NewCounterVec(
+ prometheus.CounterOpts{
+ Name: "rest_client_requests_total",
+ Help: "Number of HTTP requests, partitioned by status code, method, and host.",
+ },
+ []string{"code", "method", "host"},
+ )
+)
+
+func init() {
+ registerClientMetrics()
+}
+
+// registerClientMetrics sets up the client latency metrics from client-go.
+func registerClientMetrics() {
+ // register the metrics with our registry
+ Registry.MustRegister(requestResult)
+
+ // register the metrics with client-go
+ clientmetrics.Register(clientmetrics.RegisterOpts{
+ RequestResult: &resultAdapter{metric: requestResult},
+ })
+}
+
+// this section contains adapters, implementations, and other sundry organic, artisanally
+// hand-crafted syntax trees required to convince client-go that it actually wants to let
+// someone use its metrics.
+
+// Client metrics adapters (method #1 for client-go metrics),
+// copied (more-or-less directly) from k8s.io/kubernetes setup code
+// (which isn't anywhere in an easily-importable place).
+
+type resultAdapter struct {
+ metric *prometheus.CounterVec
+}
+
+func (r *resultAdapter) Increment(_ context.Context, code, method, host string) {
+ r.metric.WithLabelValues(code, method, host).Inc()
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/doc.go
new file mode 100644
index 00000000000..6ed9df95140
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package metrics contains controller related metrics utilities
+*/
+package metrics
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/leaderelection.go b/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/leaderelection.go
new file mode 100644
index 00000000000..a19c099602e
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/leaderelection.go
@@ -0,0 +1,40 @@
+package metrics
+
+import (
+ "github.com/prometheus/client_golang/prometheus"
+ "k8s.io/client-go/tools/leaderelection"
+)
+
+// This file is copied and adapted from k8s.io/component-base/metrics/prometheus/clientgo/leaderelection
+// which registers metrics to the k8s legacy Registry. We require very
+// similar functionality, but must register metrics to a different Registry.
+
+var (
+ leaderGauge = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "leader_election_master_status",
+ Help: "Gauge of if the reporting system is master of the relevant lease, 0 indicates backup, 1 indicates master. 'name' is the string used to identify the lease. Please make sure to group by name.",
+ }, []string{"name"})
+)
+
+func init() {
+ Registry.MustRegister(leaderGauge)
+ leaderelection.SetProvider(leaderelectionMetricsProvider{})
+}
+
+type leaderelectionMetricsProvider struct{}
+
+func (leaderelectionMetricsProvider) NewLeaderMetric() leaderelection.SwitchMetric {
+ return &switchAdapter{gauge: leaderGauge}
+}
+
+type switchAdapter struct {
+ gauge *prometheus.GaugeVec
+}
+
+func (s *switchAdapter) On(name string) {
+ s.gauge.WithLabelValues(name).Set(1.0)
+}
+
+func (s *switchAdapter) Off(name string) {
+ s.gauge.WithLabelValues(name).Set(0.0)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/listener.go b/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/listener.go
new file mode 100644
index 00000000000..123d8c15f92
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/listener.go
@@ -0,0 +1,52 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package metrics
+
+import (
+ "fmt"
+ "net"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("metrics")
+
+// DefaultBindAddress sets the default bind address for the metrics listener
+// The metrics is on by default.
+var DefaultBindAddress = ":8080"
+
+// NewListener creates a new TCP listener bound to the given address.
+func NewListener(addr string) (net.Listener, error) {
+ if addr == "" {
+ // If the metrics bind address is empty, default to ":8080"
+ addr = DefaultBindAddress
+ }
+
+ // Add a case to disable metrics altogether
+ if addr == "0" {
+ return nil, nil
+ }
+
+ log.Info("Metrics server is starting to listen", "addr", addr)
+ ln, err := net.Listen("tcp", addr)
+ if err != nil {
+ er := fmt.Errorf("error listening on %s: %w", addr, err)
+ log.Error(er, "metrics server failed to listen. You may want to disable the metrics server or use another port if it is due to conflicts")
+ return nil, er
+ }
+ return ln, nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/registry.go b/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/registry.go
new file mode 100644
index 00000000000..ce17124d535
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/registry.go
@@ -0,0 +1,30 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package metrics
+
+import "github.com/prometheus/client_golang/prometheus"
+
+// RegistererGatherer combines both parts of the API of a Prometheus
+// registry, both the Registerer and the Gatherer interfaces.
+type RegistererGatherer interface {
+ prometheus.Registerer
+ prometheus.Gatherer
+}
+
+// Registry is a prometheus registry for storing metrics within the
+// controller-runtime.
+var Registry RegistererGatherer = prometheus.NewRegistry()
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go b/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go
new file mode 100644
index 00000000000..277b8788100
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go
@@ -0,0 +1,130 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package metrics
+
+import (
+ "github.com/prometheus/client_golang/prometheus"
+ "k8s.io/client-go/util/workqueue"
+)
+
+// This file is copied and adapted from k8s.io/component-base/metrics/prometheus/workqueue
+// which registers metrics to the k8s legacy Registry. We require very
+// similar functionality, but must register metrics to a different Registry.
+
+// Metrics subsystem and all keys used by the workqueue.
+const (
+ WorkQueueSubsystem = "workqueue"
+ DepthKey = "depth"
+ AddsKey = "adds_total"
+ QueueLatencyKey = "queue_duration_seconds"
+ WorkDurationKey = "work_duration_seconds"
+ UnfinishedWorkKey = "unfinished_work_seconds"
+ LongestRunningProcessorKey = "longest_running_processor_seconds"
+ RetriesKey = "retries_total"
+)
+
+var (
+ depth = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: DepthKey,
+ Help: "Current depth of workqueue",
+ }, []string{"name"})
+
+ adds = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: AddsKey,
+ Help: "Total number of adds handled by workqueue",
+ }, []string{"name"})
+
+ latency = prometheus.NewHistogramVec(prometheus.HistogramOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: QueueLatencyKey,
+ Help: "How long in seconds an item stays in workqueue before being requested",
+ Buckets: prometheus.ExponentialBuckets(10e-9, 10, 10),
+ }, []string{"name"})
+
+ workDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: WorkDurationKey,
+ Help: "How long in seconds processing an item from workqueue takes.",
+ Buckets: prometheus.ExponentialBuckets(10e-9, 10, 10),
+ }, []string{"name"})
+
+ unfinished = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: UnfinishedWorkKey,
+ Help: "How many seconds of work has been done that " +
+ "is in progress and hasn't been observed by work_duration. Large " +
+ "values indicate stuck threads. One can deduce the number of stuck " +
+ "threads by observing the rate at which this increases.",
+ }, []string{"name"})
+
+ longestRunningProcessor = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: LongestRunningProcessorKey,
+ Help: "How many seconds has the longest running " +
+ "processor for workqueue been running.",
+ }, []string{"name"})
+
+ retries = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: RetriesKey,
+ Help: "Total number of retries handled by workqueue",
+ }, []string{"name"})
+)
+
+func init() {
+ Registry.MustRegister(depth)
+ Registry.MustRegister(adds)
+ Registry.MustRegister(latency)
+ Registry.MustRegister(workDuration)
+ Registry.MustRegister(unfinished)
+ Registry.MustRegister(longestRunningProcessor)
+ Registry.MustRegister(retries)
+
+ workqueue.SetProvider(workqueueMetricsProvider{})
+}
+
+type workqueueMetricsProvider struct{}
+
+func (workqueueMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric {
+ return depth.WithLabelValues(name)
+}
+
+func (workqueueMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric {
+ return adds.WithLabelValues(name)
+}
+
+func (workqueueMetricsProvider) NewLatencyMetric(name string) workqueue.HistogramMetric {
+ return latency.WithLabelValues(name)
+}
+
+func (workqueueMetricsProvider) NewWorkDurationMetric(name string) workqueue.HistogramMetric {
+ return workDuration.WithLabelValues(name)
+}
+
+func (workqueueMetricsProvider) NewUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric {
+ return unfinished.WithLabelValues(name)
+}
+
+func (workqueueMetricsProvider) NewLongestRunningProcessorSecondsMetric(name string) workqueue.SettableGaugeMetric {
+ return longestRunningProcessor.WithLabelValues(name)
+}
+
+func (workqueueMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric {
+ return retries.WithLabelValues(name)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/doc.go
new file mode 100644
index 00000000000..e498107ef7f
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package predicate defines Predicates used by Controllers to filter Events before they are provided to EventHandlers.
+*/
+package predicate
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/example_test.go
new file mode 100644
index 00000000000..57a1ce77796
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/example_test.go
@@ -0,0 +1,33 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package predicate_test
+
+import (
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+)
+
+var p predicate.Predicate
+
+// This example creates a new Predicate to drop Update Events where the Generation has not changed.
+func ExampleFuncs() {
+ p = predicate.Funcs{
+ UpdateFunc: func(e event.UpdateEvent) bool {
+ return e.ObjectOld.GetGeneration() != e.ObjectNew.GetGeneration()
+ },
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go b/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
new file mode 100644
index 00000000000..314635875e5
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
@@ -0,0 +1,360 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package predicate
+
+import (
+ "reflect"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/labels"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("predicate").WithName("eventFilters")
+
+// Predicate filters events before enqueuing the keys.
+type Predicate interface {
+ // Create returns true if the Create event should be processed
+ Create(event.CreateEvent) bool
+
+ // Delete returns true if the Delete event should be processed
+ Delete(event.DeleteEvent) bool
+
+ // Update returns true if the Update event should be processed
+ Update(event.UpdateEvent) bool
+
+ // Generic returns true if the Generic event should be processed
+ Generic(event.GenericEvent) bool
+}
+
+var _ Predicate = Funcs{}
+var _ Predicate = ResourceVersionChangedPredicate{}
+var _ Predicate = GenerationChangedPredicate{}
+var _ Predicate = AnnotationChangedPredicate{}
+var _ Predicate = or{}
+var _ Predicate = and{}
+var _ Predicate = not{}
+
+// Funcs is a function that implements Predicate.
+type Funcs struct {
+ // Create returns true if the Create event should be processed
+ CreateFunc func(event.CreateEvent) bool
+
+ // Delete returns true if the Delete event should be processed
+ DeleteFunc func(event.DeleteEvent) bool
+
+ // Update returns true if the Update event should be processed
+ UpdateFunc func(event.UpdateEvent) bool
+
+ // Generic returns true if the Generic event should be processed
+ GenericFunc func(event.GenericEvent) bool
+}
+
+// Create implements Predicate.
+func (p Funcs) Create(e event.CreateEvent) bool {
+ if p.CreateFunc != nil {
+ return p.CreateFunc(e)
+ }
+ return true
+}
+
+// Delete implements Predicate.
+func (p Funcs) Delete(e event.DeleteEvent) bool {
+ if p.DeleteFunc != nil {
+ return p.DeleteFunc(e)
+ }
+ return true
+}
+
+// Update implements Predicate.
+func (p Funcs) Update(e event.UpdateEvent) bool {
+ if p.UpdateFunc != nil {
+ return p.UpdateFunc(e)
+ }
+ return true
+}
+
+// Generic implements Predicate.
+func (p Funcs) Generic(e event.GenericEvent) bool {
+ if p.GenericFunc != nil {
+ return p.GenericFunc(e)
+ }
+ return true
+}
+
+// NewPredicateFuncs returns a predicate funcs that applies the given filter function
+// on CREATE, UPDATE, DELETE and GENERIC events. For UPDATE events, the filter is applied
+// to the new object.
+func NewPredicateFuncs(filter func(object client.Object) bool) Funcs {
+ return Funcs{
+ CreateFunc: func(e event.CreateEvent) bool {
+ return filter(e.Object)
+ },
+ UpdateFunc: func(e event.UpdateEvent) bool {
+ return filter(e.ObjectNew)
+ },
+ DeleteFunc: func(e event.DeleteEvent) bool {
+ return filter(e.Object)
+ },
+ GenericFunc: func(e event.GenericEvent) bool {
+ return filter(e.Object)
+ },
+ }
+}
+
+// ResourceVersionChangedPredicate implements a default update predicate function on resource version change.
+type ResourceVersionChangedPredicate struct {
+ Funcs
+}
+
+// Update implements default UpdateEvent filter for validating resource version change.
+func (ResourceVersionChangedPredicate) Update(e event.UpdateEvent) bool {
+ if e.ObjectOld == nil {
+ log.Error(nil, "Update event has no old object to update", "event", e)
+ return false
+ }
+ if e.ObjectNew == nil {
+ log.Error(nil, "Update event has no new object to update", "event", e)
+ return false
+ }
+
+ return e.ObjectNew.GetResourceVersion() != e.ObjectOld.GetResourceVersion()
+}
+
+// GenerationChangedPredicate implements a default update predicate function on Generation change.
+//
+// This predicate will skip update events that have no change in the object's metadata.generation field.
+// The metadata.generation field of an object is incremented by the API server when writes are made to the spec field of an object.
+// This allows a controller to ignore update events where the spec is unchanged, and only the metadata and/or status fields are changed.
+//
+// For CustomResource objects the Generation is only incremented when the status subresource is enabled.
+//
+// Caveats:
+//
+// * The assumption that the Generation is incremented only on writing to the spec does not hold for all APIs.
+// E.g For Deployment objects the Generation is also incremented on writes to the metadata.annotations field.
+// For object types other than CustomResources be sure to verify which fields will trigger a Generation increment when they are written to.
+//
+// * With this predicate, any update events with writes only to the status field will not be reconciled.
+// So in the event that the status block is overwritten or wiped by someone else the controller will not self-correct to restore the correct status.
+type GenerationChangedPredicate struct {
+ Funcs
+}
+
+// Update implements default UpdateEvent filter for validating generation change.
+func (GenerationChangedPredicate) Update(e event.UpdateEvent) bool {
+ if e.ObjectOld == nil {
+ log.Error(nil, "Update event has no old object to update", "event", e)
+ return false
+ }
+ if e.ObjectNew == nil {
+ log.Error(nil, "Update event has no new object for update", "event", e)
+ return false
+ }
+
+ return e.ObjectNew.GetGeneration() != e.ObjectOld.GetGeneration()
+}
+
+// AnnotationChangedPredicate implements a default update predicate function on annotation change.
+//
+// This predicate will skip update events that have no change in the object's annotation.
+// It is intended to be used in conjunction with the GenerationChangedPredicate, as in the following example:
+//
+// Controller.Watch(
+// &source.Kind{Type: v1.MyCustomKind},
+// &handler.EnqueueRequestForObject{},
+// predicate.Or(predicate.GenerationChangedPredicate{}, predicate.AnnotationChangedPredicate{}))
+//
+// This is mostly useful for controllers that needs to trigger both when the resource's generation is incremented
+// (i.e., when the resource' .spec changes), or an annotation changes (e.g., for a staging/alpha API).
+type AnnotationChangedPredicate struct {
+ Funcs
+}
+
+// Update implements default UpdateEvent filter for validating annotation change.
+func (AnnotationChangedPredicate) Update(e event.UpdateEvent) bool {
+ if e.ObjectOld == nil {
+ log.Error(nil, "Update event has no old object to update", "event", e)
+ return false
+ }
+ if e.ObjectNew == nil {
+ log.Error(nil, "Update event has no new object for update", "event", e)
+ return false
+ }
+
+ return !reflect.DeepEqual(e.ObjectNew.GetAnnotations(), e.ObjectOld.GetAnnotations())
+}
+
+// LabelChangedPredicate implements a default update predicate function on label change.
+//
+// This predicate will skip update events that have no change in the object's label.
+// It is intended to be used in conjunction with the GenerationChangedPredicate, as in the following example:
+//
+// Controller.Watch(
+//
+// &source.Kind{Type: v1.MyCustomKind},
+// &handler.EnqueueRequestForObject{},
+// predicate.Or(predicate.GenerationChangedPredicate{}, predicate.LabelChangedPredicate{}))
+//
+// This will be helpful when object's labels is carrying some extra specification information beyond object's spec,
+// and the controller will be triggered if any valid spec change (not only in spec, but also in labels) happens.
+type LabelChangedPredicate struct {
+ Funcs
+}
+
+// Update implements default UpdateEvent filter for checking label change.
+func (LabelChangedPredicate) Update(e event.UpdateEvent) bool {
+ if e.ObjectOld == nil {
+ log.Error(nil, "Update event has no old object to update", "event", e)
+ return false
+ }
+ if e.ObjectNew == nil {
+ log.Error(nil, "Update event has no new object for update", "event", e)
+ return false
+ }
+
+ return !reflect.DeepEqual(e.ObjectNew.GetLabels(), e.ObjectOld.GetLabels())
+}
+
+// And returns a composite predicate that implements a logical AND of the predicates passed to it.
+func And(predicates ...Predicate) Predicate {
+ return and{predicates}
+}
+
+type and struct {
+ predicates []Predicate
+}
+
+func (a and) Create(e event.CreateEvent) bool {
+ for _, p := range a.predicates {
+ if !p.Create(e) {
+ return false
+ }
+ }
+ return true
+}
+
+func (a and) Update(e event.UpdateEvent) bool {
+ for _, p := range a.predicates {
+ if !p.Update(e) {
+ return false
+ }
+ }
+ return true
+}
+
+func (a and) Delete(e event.DeleteEvent) bool {
+ for _, p := range a.predicates {
+ if !p.Delete(e) {
+ return false
+ }
+ }
+ return true
+}
+
+func (a and) Generic(e event.GenericEvent) bool {
+ for _, p := range a.predicates {
+ if !p.Generic(e) {
+ return false
+ }
+ }
+ return true
+}
+
+// Or returns a composite predicate that implements a logical OR of the predicates passed to it.
+func Or(predicates ...Predicate) Predicate {
+ return or{predicates}
+}
+
+type or struct {
+ predicates []Predicate
+}
+
+func (o or) Create(e event.CreateEvent) bool {
+ for _, p := range o.predicates {
+ if p.Create(e) {
+ return true
+ }
+ }
+ return false
+}
+
+func (o or) Update(e event.UpdateEvent) bool {
+ for _, p := range o.predicates {
+ if p.Update(e) {
+ return true
+ }
+ }
+ return false
+}
+
+func (o or) Delete(e event.DeleteEvent) bool {
+ for _, p := range o.predicates {
+ if p.Delete(e) {
+ return true
+ }
+ }
+ return false
+}
+
+func (o or) Generic(e event.GenericEvent) bool {
+ for _, p := range o.predicates {
+ if p.Generic(e) {
+ return true
+ }
+ }
+ return false
+}
+
+// Not returns a predicate that implements a logical NOT of the predicate passed to it.
+func Not(predicate Predicate) Predicate {
+ return not{predicate}
+}
+
+type not struct {
+ predicate Predicate
+}
+
+func (n not) Create(e event.CreateEvent) bool {
+ return !n.predicate.Create(e)
+}
+
+func (n not) Update(e event.UpdateEvent) bool {
+ return !n.predicate.Update(e)
+}
+
+func (n not) Delete(e event.DeleteEvent) bool {
+ return !n.predicate.Delete(e)
+}
+
+func (n not) Generic(e event.GenericEvent) bool {
+ return !n.predicate.Generic(e)
+}
+
+// LabelSelectorPredicate constructs a Predicate from a LabelSelector.
+// Only objects matching the LabelSelector will be admitted.
+func LabelSelectorPredicate(s metav1.LabelSelector) (Predicate, error) {
+ selector, err := metav1.LabelSelectorAsSelector(&s)
+ if err != nil {
+ return Funcs{}, err
+ }
+ return NewPredicateFuncs(func(o client.Object) bool {
+ return selector.Matches(labels.Set(o.GetLabels()))
+ }), nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/predicate_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/predicate_suite_test.go
new file mode 100644
index 00000000000..170594ca528
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/predicate_suite_test.go
@@ -0,0 +1,35 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package predicate_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestPredicate(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Predicate Suite")
+}
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/predicate_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/predicate_test.go
new file mode 100644
index 00000000000..f322b7810b9
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/predicate/predicate_test.go
@@ -0,0 +1,959 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package predicate_test
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+)
+
+var _ = Describe("Predicate", func() {
+ var pod *corev1.Pod
+ BeforeEach(func() {
+ pod = &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{Namespace: "biz", Name: "baz"},
+ }
+ })
+
+ Describe("Funcs", func() {
+ failingFuncs := predicate.Funcs{
+ CreateFunc: func(event.CreateEvent) bool {
+ defer GinkgoRecover()
+ Fail("Did not expect CreateFunc to be called.")
+ return false
+ },
+ DeleteFunc: func(event.DeleteEvent) bool {
+ defer GinkgoRecover()
+ Fail("Did not expect DeleteFunc to be called.")
+ return false
+ },
+ UpdateFunc: func(event.UpdateEvent) bool {
+ defer GinkgoRecover()
+ Fail("Did not expect UpdateFunc to be called.")
+ return false
+ },
+ GenericFunc: func(event.GenericEvent) bool {
+ defer GinkgoRecover()
+ Fail("Did not expect GenericFunc to be called.")
+ return false
+ },
+ }
+
+ It("should call Create", func() {
+ instance := failingFuncs
+ instance.CreateFunc = func(evt event.CreateEvent) bool {
+ defer GinkgoRecover()
+ Expect(evt.Object).To(Equal(pod))
+ return false
+ }
+ evt := event.CreateEvent{
+ Object: pod,
+ }
+ Expect(instance.Create(evt)).To(BeFalse())
+
+ instance.CreateFunc = func(evt event.CreateEvent) bool {
+ defer GinkgoRecover()
+ Expect(evt.Object).To(Equal(pod))
+ return true
+ }
+ Expect(instance.Create(evt)).To(BeTrue())
+
+ instance.CreateFunc = nil
+ Expect(instance.Create(evt)).To(BeTrue())
+ })
+
+ It("should call Update", func() {
+ newPod := pod.DeepCopy()
+ newPod.Name = "baz2"
+ newPod.Namespace = "biz2"
+
+ instance := failingFuncs
+ instance.UpdateFunc = func(evt event.UpdateEvent) bool {
+ defer GinkgoRecover()
+ Expect(evt.ObjectOld).To(Equal(pod))
+ Expect(evt.ObjectNew).To(Equal(newPod))
+ return false
+ }
+ evt := event.UpdateEvent{
+ ObjectOld: pod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Update(evt)).To(BeFalse())
+
+ instance.UpdateFunc = func(evt event.UpdateEvent) bool {
+ defer GinkgoRecover()
+ Expect(evt.ObjectOld).To(Equal(pod))
+ Expect(evt.ObjectNew).To(Equal(newPod))
+ return true
+ }
+ Expect(instance.Update(evt)).To(BeTrue())
+
+ instance.UpdateFunc = nil
+ Expect(instance.Update(evt)).To(BeTrue())
+ })
+
+ It("should call Delete", func() {
+ instance := failingFuncs
+ instance.DeleteFunc = func(evt event.DeleteEvent) bool {
+ defer GinkgoRecover()
+ Expect(evt.Object).To(Equal(pod))
+ return false
+ }
+ evt := event.DeleteEvent{
+ Object: pod,
+ }
+ Expect(instance.Delete(evt)).To(BeFalse())
+
+ instance.DeleteFunc = func(evt event.DeleteEvent) bool {
+ defer GinkgoRecover()
+ Expect(evt.Object).To(Equal(pod))
+ return true
+ }
+ Expect(instance.Delete(evt)).To(BeTrue())
+
+ instance.DeleteFunc = nil
+ Expect(instance.Delete(evt)).To(BeTrue())
+ })
+
+ It("should call Generic", func() {
+ instance := failingFuncs
+ instance.GenericFunc = func(evt event.GenericEvent) bool {
+ defer GinkgoRecover()
+ Expect(evt.Object).To(Equal(pod))
+ return false
+ }
+ evt := event.GenericEvent{
+ Object: pod,
+ }
+ Expect(instance.Generic(evt)).To(BeFalse())
+
+ instance.GenericFunc = func(evt event.GenericEvent) bool {
+ defer GinkgoRecover()
+ Expect(evt.Object).To(Equal(pod))
+ return true
+ }
+ Expect(instance.Generic(evt)).To(BeTrue())
+
+ instance.GenericFunc = nil
+ Expect(instance.Generic(evt)).To(BeTrue())
+ })
+ })
+
+ Describe("When checking a ResourceVersionChangedPredicate", func() {
+ instance := predicate.ResourceVersionChangedPredicate{}
+
+ Context("Where the old object doesn't have a ResourceVersion or metadata", func() {
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ ResourceVersion: "1",
+ }}
+
+ failEvnt := event.UpdateEvent{
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).Should(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).Should(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).Should(BeTrue())
+ Expect(instance.Update(failEvnt)).Should(BeFalse())
+ })
+ })
+
+ Context("Where the new object doesn't have a ResourceVersion or metadata", func() {
+ It("should return false", func() {
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ ResourceVersion: "1",
+ }}
+
+ failEvnt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).Should(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).Should(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).Should(BeTrue())
+ Expect(instance.Update(failEvnt)).Should(BeFalse())
+ Expect(instance.Update(failEvnt)).Should(BeFalse())
+ })
+ })
+
+ Context("Where the ResourceVersion hasn't changed", func() {
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ ResourceVersion: "v1",
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ ResourceVersion: "v1",
+ }}
+
+ failEvnt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).Should(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).Should(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).Should(BeTrue())
+ Expect(instance.Update(failEvnt)).Should(BeFalse())
+ Expect(instance.Update(failEvnt)).Should(BeFalse())
+ })
+ })
+
+ Context("Where the ResourceVersion has changed", func() {
+ It("should return true", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ ResourceVersion: "v1",
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ ResourceVersion: "v2",
+ }}
+ passEvt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).Should(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).Should(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).Should(BeTrue())
+ Expect(instance.Update(passEvt)).Should(BeTrue())
+ })
+ })
+
+ Context("Where the objects or metadata are missing", func() {
+
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ ResourceVersion: "v1",
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ ResourceVersion: "v1",
+ }}
+
+ failEvt1 := event.UpdateEvent{ObjectOld: oldPod}
+ failEvt2 := event.UpdateEvent{ObjectNew: newPod}
+ failEvt3 := event.UpdateEvent{ObjectOld: oldPod, ObjectNew: newPod}
+ Expect(instance.Create(event.CreateEvent{})).Should(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).Should(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).Should(BeTrue())
+ Expect(instance.Update(failEvt1)).Should(BeFalse())
+ Expect(instance.Update(failEvt2)).Should(BeFalse())
+ Expect(instance.Update(failEvt3)).Should(BeFalse())
+ })
+ })
+
+ })
+
+ Describe("When checking a GenerationChangedPredicate", func() {
+ instance := predicate.GenerationChangedPredicate{}
+ Context("Where the old object doesn't have a Generation or metadata", func() {
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Generation: 1,
+ }}
+
+ failEvnt := event.UpdateEvent{
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(failEvnt)).To(BeFalse())
+ })
+ })
+
+ Context("Where the new object doesn't have a Generation or metadata", func() {
+ It("should return false", func() {
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Generation: 1,
+ }}
+
+ failEvnt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(failEvnt)).To(BeFalse())
+ })
+ })
+
+ Context("Where the Generation hasn't changed", func() {
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Generation: 1,
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Generation: 1,
+ }}
+
+ failEvnt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(failEvnt)).To(BeFalse())
+ })
+ })
+
+ Context("Where the Generation has changed", func() {
+ It("should return true", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Generation: 1,
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Generation: 2,
+ }}
+ passEvt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(passEvt)).To(BeTrue())
+ })
+ })
+
+ Context("Where the objects or metadata are missing", func() {
+
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Generation: 1,
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Generation: 1,
+ }}
+
+ failEvt1 := event.UpdateEvent{ObjectOld: oldPod}
+ failEvt2 := event.UpdateEvent{ObjectNew: newPod}
+ failEvt3 := event.UpdateEvent{ObjectOld: oldPod, ObjectNew: newPod}
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(failEvt1)).To(BeFalse())
+ Expect(instance.Update(failEvt2)).To(BeFalse())
+ Expect(instance.Update(failEvt3)).To(BeFalse())
+ })
+ })
+
+ })
+
+ // AnnotationChangedPredicate has almost identical test cases as LabelChangedPredicates,
+ // so the duplication linter should be muted on both two test suites.
+ Describe("When checking an AnnotationChangedPredicate", func() {
+ instance := predicate.AnnotationChangedPredicate{}
+ Context("Where the old object is missing", func() {
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Annotations: map[string]string{
+ "booz": "wooz",
+ },
+ }}
+
+ failEvnt := event.UpdateEvent{
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(failEvnt)).To(BeFalse())
+ })
+ })
+
+ Context("Where the new object is missing", func() {
+ It("should return false", func() {
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Annotations: map[string]string{
+ "booz": "wooz",
+ },
+ }}
+
+ failEvnt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(failEvnt)).To(BeFalse())
+ })
+ })
+
+ Context("Where the annotations are empty", func() {
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ }}
+
+ failEvnt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(failEvnt)).To(BeFalse())
+ })
+ })
+
+ Context("Where the annotations haven't changed", func() {
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Annotations: map[string]string{
+ "booz": "wooz",
+ },
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Annotations: map[string]string{
+ "booz": "wooz",
+ },
+ }}
+
+ failEvnt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(failEvnt)).To(BeFalse())
+ })
+ })
+
+ Context("Where an annotation value has changed", func() {
+ It("should return true", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Annotations: map[string]string{
+ "booz": "wooz",
+ },
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Annotations: map[string]string{
+ "booz": "weez",
+ },
+ }}
+
+ passEvt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(passEvt)).To(BeTrue())
+ })
+ })
+
+ Context("Where an annotation has been added", func() {
+ It("should return true", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Annotations: map[string]string{
+ "booz": "wooz",
+ },
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Annotations: map[string]string{
+ "booz": "wooz",
+ "zooz": "qooz",
+ },
+ }}
+
+ passEvt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(passEvt)).To(BeTrue())
+ })
+ })
+
+ Context("Where an annotation has been removed", func() {
+ It("should return true", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Annotations: map[string]string{
+ "booz": "wooz",
+ "zooz": "qooz",
+ },
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Annotations: map[string]string{
+ "booz": "wooz",
+ },
+ }}
+
+ passEvt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(passEvt)).To(BeTrue())
+ })
+ })
+ })
+
+ // LabelChangedPredicates has almost identical test cases as AnnotationChangedPredicates,
+ // so the duplication linter should be muted on both two test suites.
+ Describe("When checking a LabelChangedPredicate", func() {
+ instance := predicate.LabelChangedPredicate{}
+ Context("Where the old object is missing", func() {
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Labels: map[string]string{
+ "foo": "bar",
+ },
+ }}
+
+ evt := event.UpdateEvent{
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(evt)).To(BeFalse())
+ })
+ })
+
+ Context("Where the new object is missing", func() {
+ It("should return false", func() {
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Labels: map[string]string{
+ "foo": "bar",
+ },
+ }}
+
+ evt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(evt)).To(BeFalse())
+ })
+ })
+
+ Context("Where the labels are empty", func() {
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ }}
+
+ evt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(evt)).To(BeFalse())
+ })
+ })
+
+ Context("Where the labels haven't changed", func() {
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Labels: map[string]string{
+ "foo": "bar",
+ },
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Labels: map[string]string{
+ "foo": "bar",
+ },
+ }}
+
+ evt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(evt)).To(BeFalse())
+ })
+ })
+
+ Context("Where a label value has changed", func() {
+ It("should return true", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Labels: map[string]string{
+ "foo": "bar",
+ },
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Labels: map[string]string{
+ "foo": "bee",
+ },
+ }}
+
+ evt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(evt)).To(BeTrue())
+ })
+ })
+
+ Context("Where a label has been added", func() {
+ It("should return true", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Labels: map[string]string{
+ "foo": "bar",
+ },
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Labels: map[string]string{
+ "foo": "bar",
+ "faa": "bor",
+ },
+ }}
+
+ evt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(evt)).To(BeTrue())
+ })
+ })
+
+ Context("Where a label has been removed", func() {
+ It("should return true", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Labels: map[string]string{
+ "foo": "bar",
+ "faa": "bor",
+ },
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ Labels: map[string]string{
+ "foo": "bar",
+ },
+ }}
+
+ evt := event.UpdateEvent{
+ ObjectOld: oldPod,
+ ObjectNew: newPod,
+ }
+ Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
+ Expect(instance.Update(evt)).To(BeTrue())
+ })
+ })
+ })
+
+ Context("With a boolean predicate", func() {
+ funcs := func(pass bool) predicate.Funcs {
+ return predicate.Funcs{
+ CreateFunc: func(event.CreateEvent) bool {
+ return pass
+ },
+ DeleteFunc: func(event.DeleteEvent) bool {
+ return pass
+ },
+ UpdateFunc: func(event.UpdateEvent) bool {
+ return pass
+ },
+ GenericFunc: func(event.GenericEvent) bool {
+ return pass
+ },
+ }
+ }
+ passFuncs := funcs(true)
+ failFuncs := funcs(false)
+
+ Describe("When checking an And predicate", func() {
+ It("should return false when one of its predicates returns false", func() {
+ a := predicate.And(passFuncs, failFuncs)
+ Expect(a.Create(event.CreateEvent{})).To(BeFalse())
+ Expect(a.Update(event.UpdateEvent{})).To(BeFalse())
+ Expect(a.Delete(event.DeleteEvent{})).To(BeFalse())
+ Expect(a.Generic(event.GenericEvent{})).To(BeFalse())
+ })
+ It("should return true when all of its predicates return true", func() {
+ a := predicate.And(passFuncs, passFuncs)
+ Expect(a.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(a.Update(event.UpdateEvent{})).To(BeTrue())
+ Expect(a.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(a.Generic(event.GenericEvent{})).To(BeTrue())
+ })
+ })
+ Describe("When checking an Or predicate", func() {
+ It("should return true when one of its predicates returns true", func() {
+ o := predicate.Or(passFuncs, failFuncs)
+ Expect(o.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(o.Update(event.UpdateEvent{})).To(BeTrue())
+ Expect(o.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(o.Generic(event.GenericEvent{})).To(BeTrue())
+ })
+ It("should return false when all of its predicates return false", func() {
+ o := predicate.Or(failFuncs, failFuncs)
+ Expect(o.Create(event.CreateEvent{})).To(BeFalse())
+ Expect(o.Update(event.UpdateEvent{})).To(BeFalse())
+ Expect(o.Delete(event.DeleteEvent{})).To(BeFalse())
+ Expect(o.Generic(event.GenericEvent{})).To(BeFalse())
+ })
+ })
+ Describe("When checking a Not predicate", func() {
+ It("should return false when its predicate returns true", func() {
+ n := predicate.Not(passFuncs)
+ Expect(n.Create(event.CreateEvent{})).To(BeFalse())
+ Expect(n.Update(event.UpdateEvent{})).To(BeFalse())
+ Expect(n.Delete(event.DeleteEvent{})).To(BeFalse())
+ Expect(n.Generic(event.GenericEvent{})).To(BeFalse())
+ })
+ It("should return true when its predicate returns false", func() {
+ n := predicate.Not(failFuncs)
+ Expect(n.Create(event.CreateEvent{})).To(BeTrue())
+ Expect(n.Update(event.UpdateEvent{})).To(BeTrue())
+ Expect(n.Delete(event.DeleteEvent{})).To(BeTrue())
+ Expect(n.Generic(event.GenericEvent{})).To(BeTrue())
+ })
+ })
+ })
+
+ Describe("NewPredicateFuncs with a namespace filter function", func() {
+ byNamespaceFilter := func(namespace string) func(object client.Object) bool {
+ return func(object client.Object) bool {
+ return object.GetNamespace() == namespace
+ }
+ }
+ byNamespaceFuncs := predicate.NewPredicateFuncs(byNamespaceFilter("biz"))
+ Context("Where the namespace is matching", func() {
+ It("should return true", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ }}
+ passEvt1 := event.UpdateEvent{ObjectOld: oldPod, ObjectNew: newPod}
+ Expect(byNamespaceFuncs.Create(event.CreateEvent{Object: newPod})).To(BeTrue())
+ Expect(byNamespaceFuncs.Delete(event.DeleteEvent{Object: oldPod})).To(BeTrue())
+ Expect(byNamespaceFuncs.Generic(event.GenericEvent{Object: newPod})).To(BeTrue())
+ Expect(byNamespaceFuncs.Update(passEvt1)).To(BeTrue())
+ })
+ })
+
+ Context("Where the namespace is not matching", func() {
+ It("should return false", func() {
+ newPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "bizz",
+ }}
+
+ oldPod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "baz",
+ Namespace: "biz",
+ }}
+ failEvt1 := event.UpdateEvent{ObjectOld: oldPod, ObjectNew: newPod}
+ Expect(byNamespaceFuncs.Create(event.CreateEvent{Object: newPod})).To(BeFalse())
+ Expect(byNamespaceFuncs.Delete(event.DeleteEvent{Object: newPod})).To(BeFalse())
+ Expect(byNamespaceFuncs.Generic(event.GenericEvent{Object: newPod})).To(BeFalse())
+ Expect(byNamespaceFuncs.Update(failEvt1)).To(BeFalse())
+ })
+ })
+ })
+
+ Describe("When checking a LabelSelectorPredicate", func() {
+ instance, err := predicate.LabelSelectorPredicate(metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}})
+ if err != nil {
+ Fail("Improper Label Selector passed during predicate instantiation.")
+ }
+
+ Context("When the Selector does not match the event labels", func() {
+ It("should return false", func() {
+ failMatch := &corev1.Pod{}
+ Expect(instance.Create(event.CreateEvent{Object: failMatch})).To(BeFalse())
+ Expect(instance.Delete(event.DeleteEvent{Object: failMatch})).To(BeFalse())
+ Expect(instance.Generic(event.GenericEvent{Object: failMatch})).To(BeFalse())
+ Expect(instance.Update(event.UpdateEvent{ObjectNew: failMatch})).To(BeFalse())
+ })
+ })
+
+ Context("When the Selector matches the event labels", func() {
+ It("should return true", func() {
+ successMatch := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Labels: map[string]string{"foo": "bar"},
+ },
+ }
+ Expect(instance.Create(event.CreateEvent{Object: successMatch})).To(BeTrue())
+ Expect(instance.Delete(event.DeleteEvent{Object: successMatch})).To(BeTrue())
+ Expect(instance.Generic(event.GenericEvent{Object: successMatch})).To(BeTrue())
+ Expect(instance.Update(event.UpdateEvent{ObjectNew: successMatch})).To(BeTrue())
+ })
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/ratelimiter/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/ratelimiter/doc.go
new file mode 100644
index 00000000000..a01d603fe5b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/ratelimiter/doc.go
@@ -0,0 +1,22 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package ratelimiter defines rate limiters used by Controllers to limit how frequently requests may be queued.
+
+Typical rate limiters that can be used are implemented in client-go's workqueue package.
+*/
+package ratelimiter
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go b/third_party/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go
new file mode 100644
index 00000000000..565a3a227f1
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go
@@ -0,0 +1,30 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package ratelimiter
+
+import "time"
+
+// RateLimiter is an identical interface of client-go workqueue RateLimiter.
+type RateLimiter interface {
+ // When gets an item and gets to decide how long that item should wait
+ When(item interface{}) time.Duration
+ // Forget indicates that an item is finished being retried. Doesn't matter whether its for perm failing
+ // or for success, we'll stop tracking it
+ Forget(item interface{})
+ // NumRequeues returns back how many failures the item has had
+ NumRequeues(item interface{}) int
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/doc.go
new file mode 100644
index 00000000000..d221dd7b3f4
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/doc.go
@@ -0,0 +1,21 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package reconcile defines the Reconciler interface to implement Kubernetes APIs. Reconciler is provided
+to Controllers at creation time as the API implementation.
+*/
+package reconcile
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/example_test.go
new file mode 100644
index 00000000000..2b799df90d7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/example_test.go
@@ -0,0 +1,42 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package reconcile_test
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "k8s.io/apimachinery/pkg/types"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+// This example implements a simple no-op reconcile function that prints the object to be Reconciled.
+func ExampleFunc() {
+ r := reconcile.Func(func(_ context.Context, o reconcile.Request) (reconcile.Result, error) {
+ // Create your business logic to create, update, delete objects here.
+ fmt.Printf("Name: %s, Namespace: %s", o.Name, o.Namespace)
+ return reconcile.Result{}, nil
+ })
+
+ res, err := r.Reconcile(context.Background(), reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "default", Name: "test"}})
+ if err != nil || res.Requeue || res.RequeueAfter != time.Duration(0) {
+ fmt.Printf("got requeue request: %v, %v\n", err, res)
+ }
+
+ // Output: Name: test, Namespace: default
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go b/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go
new file mode 100644
index 00000000000..d51cfc34ab9
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go
@@ -0,0 +1,126 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package reconcile
+
+import (
+ "context"
+ "errors"
+ "time"
+
+ "k8s.io/apimachinery/pkg/types"
+)
+
+// Result contains the result of a Reconciler invocation.
+type Result struct {
+ // Requeue tells the Controller to requeue the reconcile key. Defaults to false.
+ Requeue bool
+
+ // RequeueAfter if greater than 0, tells the Controller to requeue the reconcile key after the Duration.
+ // Implies that Requeue is true, there is no need to set Requeue to true at the same time as RequeueAfter.
+ RequeueAfter time.Duration
+}
+
+// IsZero returns true if this result is empty.
+func (r *Result) IsZero() bool {
+ if r == nil {
+ return true
+ }
+ return *r == Result{}
+}
+
+// Request contains the information necessary to reconcile a Kubernetes object. This includes the
+// information to uniquely identify the object - its Name and Namespace. It does NOT contain information about
+// any specific Event or the object contents itself.
+type Request struct {
+ // NamespacedName is the name and namespace of the object to reconcile.
+ types.NamespacedName
+}
+
+/*
+Reconciler implements a Kubernetes API for a specific Resource by Creating, Updating or Deleting Kubernetes
+objects, or by making changes to systems external to the cluster (e.g. cloudproviders, github, etc).
+
+reconcile implementations compare the state specified in an object by a user against the actual cluster state,
+and then perform operations to make the actual cluster state reflect the state specified by the user.
+
+Typically, reconcile is triggered by a Controller in response to cluster Events (e.g. Creating, Updating,
+Deleting Kubernetes objects) or external Events (GitHub Webhooks, polling external sources, etc).
+
+Example reconcile Logic:
+
+* Read an object and all the Pods it owns.
+* Observe that the object spec specifies 5 replicas but actual cluster contains only 1 Pod replica.
+* Create 4 Pods and set their OwnerReferences to the object.
+
+reconcile may be implemented as either a type:
+
+ type reconciler struct {}
+
+ func (reconciler) Reconcile(ctx context.Context, o reconcile.Request) (reconcile.Result, error) {
+ // Implement business logic of reading and writing objects here
+ return reconcile.Result{}, nil
+ }
+
+Or as a function:
+
+ reconcile.Func(func(ctx context.Context, o reconcile.Request) (reconcile.Result, error) {
+ // Implement business logic of reading and writing objects here
+ return reconcile.Result{}, nil
+ })
+
+Reconciliation is level-based, meaning action isn't driven off changes in individual Events, but instead is
+driven by actual cluster state read from the apiserver or a local cache.
+For example if responding to a Pod Delete Event, the Request won't contain that a Pod was deleted,
+instead the reconcile function observes this when reading the cluster state and seeing the Pod as missing.
+*/
+type Reconciler interface {
+ // Reconcile performs a full reconciliation for the object referred to by the Request.
+ // The Controller will requeue the Request to be processed again if an error is non-nil or
+ // Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
+ Reconcile(context.Context, Request) (Result, error)
+}
+
+// Func is a function that implements the reconcile interface.
+type Func func(context.Context, Request) (Result, error)
+
+var _ Reconciler = Func(nil)
+
+// Reconcile implements Reconciler.
+func (r Func) Reconcile(ctx context.Context, o Request) (Result, error) { return r(ctx, o) }
+
+// TerminalError is an error that will not be retried but still be logged
+// and recorded in metrics.
+func TerminalError(wrapped error) error {
+ return &terminalError{err: wrapped}
+}
+
+type terminalError struct {
+ err error
+}
+
+func (te *terminalError) Unwrap() error {
+ return te.err
+}
+
+func (te *terminalError) Error() string {
+ return "terminal error: " + te.err.Error()
+}
+
+func (te *terminalError) Is(target error) bool {
+ tp := &terminalError{}
+ return errors.As(target, &tp)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile_suite_test.go
new file mode 100644
index 00000000000..9bab444ebd9
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile_suite_test.go
@@ -0,0 +1,35 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package reconcile_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestReconcile(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Reconcile Suite")
+}
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile_test.go
new file mode 100644
index 00000000000..b5660f1b4fe
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile_test.go
@@ -0,0 +1,100 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package reconcile_test
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/types"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+var _ = Describe("reconcile", func() {
+ Describe("Result", func() {
+ It("IsZero should return true if empty", func() {
+ var res *reconcile.Result
+ Expect(res.IsZero()).To(BeTrue())
+ res2 := &reconcile.Result{}
+ Expect(res2.IsZero()).To(BeTrue())
+ res3 := reconcile.Result{}
+ Expect(res3.IsZero()).To(BeTrue())
+ })
+
+ It("IsZero should return false if Requeue is set to true", func() {
+ res := reconcile.Result{Requeue: true}
+ Expect(res.IsZero()).To(BeFalse())
+ })
+
+ It("IsZero should return false if RequeueAfter is set to true", func() {
+ res := reconcile.Result{RequeueAfter: 1 * time.Second}
+ Expect(res.IsZero()).To(BeFalse())
+ })
+ })
+
+ Describe("Func", func() {
+ It("should call the function with the request and return a nil error.", func() {
+ request := reconcile.Request{
+ NamespacedName: types.NamespacedName{Name: "foo", Namespace: "bar"},
+ }
+ result := reconcile.Result{
+ Requeue: true,
+ }
+
+ instance := reconcile.Func(func(_ context.Context, r reconcile.Request) (reconcile.Result, error) {
+ defer GinkgoRecover()
+ Expect(r).To(Equal(request))
+
+ return result, nil
+ })
+ actualResult, actualErr := instance.Reconcile(context.Background(), request)
+ Expect(actualResult).To(Equal(result))
+ Expect(actualErr).NotTo(HaveOccurred())
+ })
+
+ It("should call the function with the request and return an error.", func() {
+ request := reconcile.Request{
+ NamespacedName: types.NamespacedName{Name: "foo", Namespace: "bar"},
+ }
+ result := reconcile.Result{
+ Requeue: false,
+ }
+ err := fmt.Errorf("hello world")
+
+ instance := reconcile.Func(func(_ context.Context, r reconcile.Request) (reconcile.Result, error) {
+ defer GinkgoRecover()
+ Expect(r).To(Equal(request))
+
+ return result, err
+ })
+ actualResult, actualErr := instance.Reconcile(context.Background(), request)
+ Expect(actualResult).To(Equal(result))
+ Expect(actualErr).To(Equal(err))
+ })
+
+ It("should allow unwrapping inner error from terminal error", func() {
+ inner := apierrors.NewGone("")
+ terminalError := reconcile.TerminalError(inner)
+
+ Expect(apierrors.IsGone(terminalError)).To(BeTrue())
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/recorder/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/recorder/example_test.go
new file mode 100644
index 00000000000..969420d8170
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/recorder/example_test.go
@@ -0,0 +1,48 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package recorder_test
+
+import (
+ corev1 "k8s.io/api/core/v1"
+
+ _ "github.com/onsi/ginkgo/v2"
+ "sigs.k8s.io/controller-runtime/pkg/recorder"
+)
+
+var (
+ recorderProvider recorder.Provider
+ somePod *corev1.Pod // the object you're reconciling, for example
+)
+
+func Example_event() {
+ // recorderProvider is a recorder.Provider
+ recorder := recorderProvider.GetEventRecorderFor("my-controller")
+
+ // emit an event with a fixed message
+ recorder.Event(somePod, corev1.EventTypeWarning,
+ "WrongTrousers", "It's the wrong trousers, Gromit!")
+}
+
+func Example_eventf() {
+ // recorderProvider is a recorder.Provider
+ recorder := recorderProvider.GetEventRecorderFor("my-controller")
+
+ // emit an event with a variable message
+ mildCheese := "Wensleydale"
+ recorder.Eventf(somePod, corev1.EventTypeNormal,
+ "DislikesCheese", "Not even %s?", mildCheese)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/recorder/recorder.go b/third_party/sigs.k8s.io/controller-runtime/pkg/recorder/recorder.go
new file mode 100644
index 00000000000..f093f0a7266
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/recorder/recorder.go
@@ -0,0 +1,31 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package recorder defines interfaces for working with Kubernetes event recorders.
+//
+// You can use these to emit Kubernetes events associated with a particular Kubernetes
+// object.
+package recorder
+
+import (
+ "k8s.io/client-go/tools/record"
+)
+
+// Provider knows how to generate new event recorders with given name.
+type Provider interface {
+ // NewRecorder returns an EventRecorder with given name.
+ GetEventRecorderFor(name string) record.EventRecorder
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go b/third_party/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go
new file mode 100644
index 00000000000..55ebe217735
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go
@@ -0,0 +1,93 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package scheme contains utilities for gradually building Schemes,
+// which contain information associating Go types with Kubernetes
+// groups, versions, and kinds.
+//
+// Each API group should define a utility function
+// called AddToScheme for adding its types to a Scheme:
+//
+// // in package myapigroupv1...
+// var (
+// SchemeGroupVersion = schema.GroupVersion{Group: "my.api.group", Version: "v1"}
+// SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
+// AddToScheme = SchemeBuilder.AddToScheme
+// )
+//
+// func init() {
+// SchemeBuilder.Register(&MyType{}, &MyTypeList)
+// }
+// var (
+// scheme *runtime.Scheme = runtime.NewScheme()
+// )
+//
+// This also true of the built-in Kubernetes types. Then, in the entrypoint for
+// your manager, assemble the scheme containing exactly the types you need,
+// panicing if scheme registration failed. For instance, if our controller needs
+// types from the core/v1 API group (e.g. Pod), plus types from my.api.group/v1:
+//
+// func init() {
+// utilruntime.Must(myapigroupv1.AddToScheme(scheme))
+// utilruntime.Must(kubernetesscheme.AddToScheme(scheme))
+// }
+//
+// func main() {
+// mgr := controllers.NewManager(context.Background(), controllers.GetConfigOrDie(), manager.Options{
+// Scheme: scheme,
+// })
+// // ...
+// }
+package scheme
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// Builder builds a new Scheme for mapping go types to Kubernetes GroupVersionKinds.
+type Builder struct {
+ GroupVersion schema.GroupVersion
+ runtime.SchemeBuilder
+}
+
+// Register adds one or more objects to the SchemeBuilder so they can be added to a Scheme. Register mutates bld.
+func (bld *Builder) Register(object ...runtime.Object) *Builder {
+ bld.SchemeBuilder.Register(func(scheme *runtime.Scheme) error {
+ scheme.AddKnownTypes(bld.GroupVersion, object...)
+ metav1.AddToGroupVersion(scheme, bld.GroupVersion)
+ return nil
+ })
+ return bld
+}
+
+// RegisterAll registers all types from the Builder argument. RegisterAll mutates bld.
+func (bld *Builder) RegisterAll(b *Builder) *Builder {
+ bld.SchemeBuilder = append(bld.SchemeBuilder, b.SchemeBuilder...)
+ return bld
+}
+
+// AddToScheme adds all registered types to s.
+func (bld *Builder) AddToScheme(s *runtime.Scheme) error {
+ return bld.SchemeBuilder.AddToScheme(s)
+}
+
+// Build returns a new Scheme containing the registered types.
+func (bld *Builder) Build() (*runtime.Scheme, error) {
+ s := runtime.NewScheme()
+ return s, bld.AddToScheme(s)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/scheme/scheme_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/scheme/scheme_suite_test.go
new file mode 100644
index 00000000000..36ddd9decc8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/scheme/scheme_suite_test.go
@@ -0,0 +1,29 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package scheme_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestScheme(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Scheme Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/scheme/scheme_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/scheme/scheme_test.go
new file mode 100644
index 00000000000..37c6766e6f2
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/scheme/scheme_test.go
@@ -0,0 +1,119 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package scheme_test
+
+import (
+ "reflect"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/gstruct"
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var _ = Describe("Scheme", func() {
+ Describe("Builder", func() {
+ It("should provide a Scheme with the types registered", func() {
+ gv := schema.GroupVersion{Group: "core", Version: "v1"}
+
+ s, err := (&scheme.Builder{GroupVersion: gv}).
+ Register(&corev1.Pod{}, &corev1.PodList{}).
+ Build()
+ Expect(err).NotTo(HaveOccurred())
+
+ internalGv := schema.GroupVersion{Group: "core", Version: "__internal"}
+ emptyGv := schema.GroupVersion{Group: "", Version: "v1"}
+ Expect(s.AllKnownTypes()).To(MatchAllKeys(Keys{
+ gv.WithKind("Pod"): Equal(reflect.TypeOf(corev1.Pod{})),
+ gv.WithKind("PodList"): Equal(reflect.TypeOf(corev1.PodList{})),
+
+ // Base types
+ gv.WithKind("CreateOptions"): Ignore(),
+ gv.WithKind("UpdateOptions"): Ignore(),
+ gv.WithKind("PatchOptions"): Ignore(),
+ gv.WithKind("DeleteOptions"): Ignore(),
+ gv.WithKind("GetOptions"): Ignore(),
+ gv.WithKind("ListOptions"): Ignore(),
+ gv.WithKind("WatchEvent"): Ignore(),
+
+ internalGv.WithKind("WatchEvent"): Ignore(),
+
+ emptyGv.WithKind("APIGroup"): Ignore(),
+ emptyGv.WithKind("APIGroupList"): Ignore(),
+ emptyGv.WithKind("APIResourceList"): Ignore(),
+ emptyGv.WithKind("APIVersions"): Ignore(),
+ emptyGv.WithKind("Status"): Ignore(),
+ }))
+ })
+
+ It("should be able to add types from other Builders", func() {
+ gv1 := schema.GroupVersion{Group: "core", Version: "v1"}
+ b1 := (&scheme.Builder{GroupVersion: gv1}).Register(&corev1.Pod{}, &corev1.PodList{})
+
+ gv2 := schema.GroupVersion{Group: "apps", Version: "v1"}
+ s, err := (&scheme.Builder{GroupVersion: gv2}).
+ Register(&appsv1.Deployment{}).
+ Register(&appsv1.DeploymentList{}).
+ RegisterAll(b1).
+ Build()
+
+ Expect(err).NotTo(HaveOccurred())
+ internalGv1 := schema.GroupVersion{Group: "core", Version: "__internal"}
+ internalGv2 := schema.GroupVersion{Group: "apps", Version: "__internal"}
+ emptyGv := schema.GroupVersion{Group: "", Version: "v1"}
+ Expect(s.AllKnownTypes()).To(MatchAllKeys(Keys{
+ // Types from b1
+ gv1.WithKind("Pod"): Equal(reflect.TypeOf(corev1.Pod{})),
+ gv1.WithKind("PodList"): Equal(reflect.TypeOf(corev1.PodList{})),
+
+ // Types from b2
+ gv2.WithKind("Deployment"): Equal(reflect.TypeOf(appsv1.Deployment{})),
+ gv2.WithKind("DeploymentList"): Equal(reflect.TypeOf(appsv1.DeploymentList{})),
+
+ // Base types
+ gv1.WithKind("CreateOptions"): Ignore(),
+ gv1.WithKind("UpdateOptions"): Ignore(),
+ gv1.WithKind("PatchOptions"): Ignore(),
+ gv1.WithKind("DeleteOptions"): Ignore(),
+ gv1.WithKind("GetOptions"): Ignore(),
+ gv1.WithKind("ListOptions"): Ignore(),
+ gv1.WithKind("WatchEvent"): Ignore(),
+
+ internalGv1.WithKind("WatchEvent"): Ignore(),
+
+ gv2.WithKind("CreateOptions"): Ignore(),
+ gv2.WithKind("UpdateOptions"): Ignore(),
+ gv2.WithKind("PatchOptions"): Ignore(),
+ gv2.WithKind("DeleteOptions"): Ignore(),
+ gv2.WithKind("GetOptions"): Ignore(),
+ gv2.WithKind("ListOptions"): Ignore(),
+ gv2.WithKind("WatchEvent"): Ignore(),
+
+ internalGv2.WithKind("WatchEvent"): Ignore(),
+
+ emptyGv.WithKind("APIGroup"): Ignore(),
+ emptyGv.WithKind("APIGroupList"): Ignore(),
+ emptyGv.WithKind("APIResourceList"): Ignore(),
+ emptyGv.WithKind("APIVersions"): Ignore(),
+ emptyGv.WithKind("Status"): Ignore(),
+ }))
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/source/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/source/doc.go
new file mode 100644
index 00000000000..31935c83c18
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/source/doc.go
@@ -0,0 +1,22 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package source provides event streams to hook up to Controllers with Controller.Watch. Events are
+used with handler.EventHandlers to enqueue reconcile.Requests and trigger Reconciles for Kubernetes
+objects.
+*/
+package source
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/source/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/source/example_test.go
new file mode 100644
index 00000000000..77857729dec
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/source/example_test.go
@@ -0,0 +1,52 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package source_test
+
+import (
+ corev1 "k8s.io/api/core/v1"
+ "sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+var mgr manager.Manager
+var ctrl controller.Controller
+
+// This example Watches for Pod Events (e.g. Create / Update / Delete) and enqueues a reconcile.Request
+// with the Name and Namespace of the Pod.
+func ExampleKind() {
+ err := ctrl.Watch(source.Kind(mgr.GetCache(), &corev1.Pod{}), &handler.EnqueueRequestForObject{})
+ if err != nil {
+ // handle it
+ }
+}
+
+// This example reads GenericEvents from a channel and enqueues a reconcile.Request containing the Name and Namespace
+// provided by the event.
+func ExampleChannel() {
+ events := make(chan event.GenericEvent)
+
+ err := ctrl.Watch(
+ &source.Channel{Source: events},
+ &handler.EnqueueRequestForObject{},
+ )
+ if err != nil {
+ // handle it
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/source/source.go b/third_party/sigs.k8s.io/controller-runtime/pkg/source/source.go
new file mode 100644
index 00000000000..099c8d68fa4
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/source/source.go
@@ -0,0 +1,225 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package source
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ internal "sigs.k8s.io/controller-runtime/pkg/internal/source"
+
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+)
+
+const (
+ // defaultBufferSize is the default number of event notifications that can be buffered.
+ defaultBufferSize = 1024
+)
+
+// Source is a source of events (eh.g. Create, Update, Delete operations on Kubernetes Objects, Webhook callbacks, etc)
+// which should be processed by event.EventHandlers to enqueue reconcile.Requests.
+//
+// * Use Kind for events originating in the cluster (e.g. Pod Create, Pod Update, Deployment Update).
+//
+// * Use Channel for events originating outside the cluster (eh.g. GitHub Webhook callback, Polling external urls).
+//
+// Users may build their own Source implementations.
+type Source interface {
+ // Start is internal and should be called only by the Controller to register an EventHandler with the Informer
+ // to enqueue reconcile.Requests.
+ Start(context.Context, handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error
+}
+
+// SyncingSource is a source that needs syncing prior to being usable. The controller
+// will call its WaitForSync prior to starting workers.
+type SyncingSource interface {
+ Source
+ WaitForSync(ctx context.Context) error
+}
+
+// Kind creates a KindSource with the given cache provider.
+func Kind(cache cache.Cache, object client.Object) SyncingSource {
+ return &internal.Kind{Type: object, Cache: cache}
+}
+
+var _ Source = &Channel{}
+
+// Channel is used to provide a source of events originating outside the cluster
+// (e.g. GitHub Webhook callback). Channel requires the user to wire the external
+// source (eh.g. http handler) to write GenericEvents to the underlying channel.
+type Channel struct {
+ // once ensures the event distribution goroutine will be performed only once
+ once sync.Once
+
+ // Source is the source channel to fetch GenericEvents
+ Source <-chan event.GenericEvent
+
+ // dest is the destination channels of the added event handlers
+ dest []chan event.GenericEvent
+
+ // DestBufferSize is the specified buffer size of dest channels.
+ // Default to 1024 if not specified.
+ DestBufferSize int
+
+ // destLock is to ensure the destination channels are safely added/removed
+ destLock sync.Mutex
+}
+
+func (cs *Channel) String() string {
+ return fmt.Sprintf("channel source: %p", cs)
+}
+
+// Start implements Source and should only be called by the Controller.
+func (cs *Channel) Start(
+ ctx context.Context,
+ handler handler.EventHandler,
+ queue workqueue.RateLimitingInterface,
+ prct ...predicate.Predicate) error {
+ // Source should have been specified by the user.
+ if cs.Source == nil {
+ return fmt.Errorf("must specify Channel.Source")
+ }
+
+ // use default value if DestBufferSize not specified
+ if cs.DestBufferSize == 0 {
+ cs.DestBufferSize = defaultBufferSize
+ }
+
+ dst := make(chan event.GenericEvent, cs.DestBufferSize)
+
+ cs.destLock.Lock()
+ cs.dest = append(cs.dest, dst)
+ cs.destLock.Unlock()
+
+ cs.once.Do(func() {
+ // Distribute GenericEvents to all EventHandler / Queue pairs Watching this source
+ go cs.syncLoop(ctx)
+ })
+
+ go func() {
+ for evt := range dst {
+ shouldHandle := true
+ for _, p := range prct {
+ if !p.Generic(evt) {
+ shouldHandle = false
+ break
+ }
+ }
+
+ if shouldHandle {
+ func() {
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ handler.Generic(ctx, evt, queue)
+ }()
+ }
+ }
+ }()
+
+ return nil
+}
+
+func (cs *Channel) doStop() {
+ cs.destLock.Lock()
+ defer cs.destLock.Unlock()
+
+ for _, dst := range cs.dest {
+ close(dst)
+ }
+}
+
+func (cs *Channel) distribute(evt event.GenericEvent) {
+ cs.destLock.Lock()
+ defer cs.destLock.Unlock()
+
+ for _, dst := range cs.dest {
+ // We cannot make it under goroutine here, or we'll meet the
+ // race condition of writing message to closed channels.
+ // To avoid blocking, the dest channels are expected to be of
+ // proper buffer size. If we still see it blocked, then
+ // the controller is thought to be in an abnormal state.
+ dst <- evt
+ }
+}
+
+func (cs *Channel) syncLoop(ctx context.Context) {
+ for {
+ select {
+ case <-ctx.Done():
+ // Close destination channels
+ cs.doStop()
+ return
+ case evt, stillOpen := <-cs.Source:
+ if !stillOpen {
+ // if the source channel is closed, we're never gonna get
+ // anything more on it, so stop & bail
+ cs.doStop()
+ return
+ }
+ cs.distribute(evt)
+ }
+ }
+}
+
+// Informer is used to provide a source of events originating inside the cluster from Watches (e.g. Pod Create).
+type Informer struct {
+ // Informer is the controller-runtime Informer
+ Informer cache.Informer
+}
+
+var _ Source = &Informer{}
+
+// Start is internal and should be called only by the Controller to register an EventHandler with the Informer
+// to enqueue reconcile.Requests.
+func (is *Informer) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface,
+ prct ...predicate.Predicate) error {
+ // Informer should have been specified by the user.
+ if is.Informer == nil {
+ return fmt.Errorf("must specify Informer.Informer")
+ }
+
+ _, err := is.Informer.AddEventHandler(internal.NewEventHandler(ctx, queue, handler, prct).HandlerFuncs())
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (is *Informer) String() string {
+ return fmt.Sprintf("informer source: %p", is.Informer)
+}
+
+var _ Source = Func(nil)
+
+// Func is a function that implements Source.
+type Func func(context.Context, handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error
+
+// Start implements Source.
+func (f Func) Start(ctx context.Context, evt handler.EventHandler, queue workqueue.RateLimitingInterface,
+ pr ...predicate.Predicate) error {
+ return f(ctx, evt, queue, pr...)
+}
+
+func (f Func) String() string {
+ return fmt.Sprintf("func source: %p", f)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/source/source_integration_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/source/source_integration_test.go
new file mode 100644
index 00000000000..594d3c9a9cd
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/source/source_integration_test.go
@@ -0,0 +1,347 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package source_test
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ kubeinformers "k8s.io/client-go/informers"
+ toolscache "k8s.io/client-go/tools/cache"
+ "k8s.io/client-go/util/workqueue"
+)
+
+var _ = Describe("Source", func() {
+ var instance1, instance2 source.Source
+ var obj client.Object
+ var q workqueue.RateLimitingInterface
+ var c1, c2 chan interface{}
+ var ns string
+ count := 0
+
+ BeforeEach(func() {
+ // Create the namespace for the test
+ ns = fmt.Sprintf("controller-source-kindsource-%v", count)
+ count++
+ _, err := clientset.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{Name: ns},
+ }, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ q = workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ c1 = make(chan interface{})
+ c2 = make(chan interface{})
+ })
+
+ JustBeforeEach(func() {
+ instance1 = source.Kind(icache, obj)
+ instance2 = source.Kind(icache, obj)
+ })
+
+ AfterEach(func() {
+ err := clientset.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ close(c1)
+ close(c2)
+ })
+
+ Describe("Kind", func() {
+ Context("for a Deployment resource", func() {
+ obj = &appsv1.Deployment{}
+
+ It("should provide Deployment Events", func() {
+ var created, updated, deleted *appsv1.Deployment
+ var err error
+
+ // Get the client and Deployment used to create events
+ client := clientset.AppsV1().Deployments(ns)
+ deployment := &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{Name: "deployment-name"},
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx",
+ },
+ },
+ },
+ },
+ },
+ }
+
+ // Create an event handler to verify the events
+ newHandler := func(c chan interface{}) handler.Funcs {
+ return handler.Funcs{
+ CreateFunc: func(ctx context.Context, evt event.CreateEvent, rli workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(rli).To(Equal(q))
+ c <- evt
+ },
+ UpdateFunc: func(ctx context.Context, evt event.UpdateEvent, rli workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(rli).To(Equal(q))
+ c <- evt
+ },
+ DeleteFunc: func(ctx context.Context, evt event.DeleteEvent, rli workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(rli).To(Equal(q))
+ c <- evt
+ },
+ }
+ }
+ handler1 := newHandler(c1)
+ handler2 := newHandler(c2)
+
+ // Create 2 instances
+ Expect(instance1.Start(ctx, handler1, q)).To(Succeed())
+ Expect(instance2.Start(ctx, handler2, q)).To(Succeed())
+
+ By("Creating a Deployment and expecting the CreateEvent.")
+ created, err = client.Create(ctx, deployment, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(created).NotTo(BeNil())
+
+ // Check first CreateEvent
+ evt := <-c1
+ createEvt, ok := evt.(event.CreateEvent)
+ Expect(ok).To(BeTrue(), fmt.Sprintf("expect %T to be %T", evt, event.CreateEvent{}))
+ Expect(createEvt.Object).To(Equal(created))
+
+ // Check second CreateEvent
+ evt = <-c2
+ createEvt, ok = evt.(event.CreateEvent)
+ Expect(ok).To(BeTrue(), fmt.Sprintf("expect %T to be %T", evt, event.CreateEvent{}))
+ Expect(createEvt.Object).To(Equal(created))
+
+ By("Updating a Deployment and expecting the UpdateEvent.")
+ updated = created.DeepCopy()
+ updated.Labels = map[string]string{"biz": "buz"}
+ updated, err = client.Update(ctx, updated, metav1.UpdateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ // Check first UpdateEvent
+ evt = <-c1
+ updateEvt, ok := evt.(event.UpdateEvent)
+ Expect(ok).To(BeTrue(), fmt.Sprintf("expect %T to be %T", evt, event.UpdateEvent{}))
+
+ Expect(updateEvt.ObjectNew).To(Equal(updated))
+
+ Expect(updateEvt.ObjectOld).To(Equal(created))
+
+ // Check second UpdateEvent
+ evt = <-c2
+ updateEvt, ok = evt.(event.UpdateEvent)
+ Expect(ok).To(BeTrue(), fmt.Sprintf("expect %T to be %T", evt, event.UpdateEvent{}))
+
+ Expect(updateEvt.ObjectNew).To(Equal(updated))
+
+ Expect(updateEvt.ObjectOld).To(Equal(created))
+
+ By("Deleting a Deployment and expecting the Delete.")
+ deleted = updated.DeepCopy()
+ err = client.Delete(ctx, created.Name, metav1.DeleteOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ deleted.SetResourceVersion("")
+ evt = <-c1
+ deleteEvt, ok := evt.(event.DeleteEvent)
+ Expect(ok).To(BeTrue(), fmt.Sprintf("expect %T to be %T", evt, event.DeleteEvent{}))
+ deleteEvt.Object.SetResourceVersion("")
+ Expect(deleteEvt.Object).To(Equal(deleted))
+
+ evt = <-c2
+ deleteEvt, ok = evt.(event.DeleteEvent)
+ Expect(ok).To(BeTrue(), fmt.Sprintf("expect %T to be %T", evt, event.DeleteEvent{}))
+ deleteEvt.Object.SetResourceVersion("")
+ Expect(deleteEvt.Object).To(Equal(deleted))
+ })
+ })
+
+ // TODO(pwittrock): Write this test
+ PContext("for a Foo CRD resource", func() {
+ It("should provide Foo Events", func() {
+
+ })
+ })
+ })
+
+ Describe("Informer", func() {
+ var c chan struct{}
+ var rs *appsv1.ReplicaSet
+ var depInformer toolscache.SharedIndexInformer
+ var informerFactory kubeinformers.SharedInformerFactory
+ var stopTest chan struct{}
+
+ BeforeEach(func() {
+ stopTest = make(chan struct{})
+ informerFactory = kubeinformers.NewSharedInformerFactory(clientset, time.Second*30)
+ depInformer = informerFactory.Apps().V1().ReplicaSets().Informer()
+ informerFactory.Start(stopTest)
+ Eventually(depInformer.HasSynced).Should(BeTrue())
+
+ c = make(chan struct{})
+ rs = &appsv1.ReplicaSet{
+ ObjectMeta: metav1.ObjectMeta{Name: "informer-rs-name"},
+ Spec: appsv1.ReplicaSetSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx",
+ },
+ },
+ },
+ },
+ },
+ }
+ })
+
+ AfterEach(func() {
+ close(stopTest)
+ })
+
+ Context("for a ReplicaSet resource", func() {
+ It("should provide a ReplicaSet CreateEvent", func() {
+ c := make(chan struct{})
+
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ instance := &source.Informer{Informer: depInformer}
+ err := instance.Start(ctx, handler.Funcs{
+ CreateFunc: func(ctx context.Context, evt event.CreateEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ var err error
+ rs, err := clientset.AppsV1().ReplicaSets("default").Get(ctx, rs.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(q2).To(BeIdenticalTo(q))
+ Expect(evt.Object).To(Equal(rs))
+ close(c)
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected UpdateEvent")
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected DeleteEvent")
+ },
+ GenericFunc: func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected GenericEvent")
+ },
+ }, q)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = clientset.AppsV1().ReplicaSets("default").Create(ctx, rs, metav1.CreateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ <-c
+ })
+
+ It("should provide a ReplicaSet UpdateEvent", func() {
+ var err error
+ rs, err = clientset.AppsV1().ReplicaSets("default").Get(ctx, rs.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ rs2 := rs.DeepCopy()
+ rs2.SetLabels(map[string]string{"biz": "baz"})
+
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ instance := &source.Informer{Informer: depInformer}
+ err = instance.Start(ctx, handler.Funcs{
+ CreateFunc: func(ctx context.Context, evt event.CreateEvent, q2 workqueue.RateLimitingInterface) {
+ },
+ UpdateFunc: func(ctx context.Context, evt event.UpdateEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ var err error
+ rs2, err := clientset.AppsV1().ReplicaSets("default").Get(ctx, rs.Name, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(q2).To(Equal(q))
+ Expect(evt.ObjectOld).To(Equal(rs))
+
+ Expect(evt.ObjectNew).To(Equal(rs2))
+
+ close(c)
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected DeleteEvent")
+ },
+ GenericFunc: func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected GenericEvent")
+ },
+ }, q)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = clientset.AppsV1().ReplicaSets("default").Update(ctx, rs2, metav1.UpdateOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ <-c
+ })
+
+ It("should provide a ReplicaSet DeletedEvent", func() {
+ c := make(chan struct{})
+
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ instance := &source.Informer{Informer: depInformer}
+ err := instance.Start(ctx, handler.Funcs{
+ CreateFunc: func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface) {
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ },
+ DeleteFunc: func(ctx context.Context, evt event.DeleteEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(q2).To(Equal(q))
+ Expect(evt.Object.GetName()).To(Equal(rs.Name))
+ close(c)
+ },
+ GenericFunc: func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected GenericEvent")
+ },
+ }, q)
+ Expect(err).NotTo(HaveOccurred())
+
+ err = clientset.AppsV1().ReplicaSets("default").Delete(ctx, rs.Name, metav1.DeleteOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ <-c
+ })
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/source/source_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/source/source_suite_test.go
new file mode 100644
index 00000000000..131099f0b9d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/source/source_suite_test.go
@@ -0,0 +1,70 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package source_test
+
+import (
+ "context"
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Source Suite")
+}
+
+var testenv *envtest.Environment
+var config *rest.Config
+var clientset *kubernetes.Clientset
+var icache cache.Cache
+var ctx context.Context
+var cancel context.CancelFunc
+
+var _ = BeforeSuite(func() {
+ ctx, cancel = context.WithCancel(context.Background())
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+ testenv = &envtest.Environment{}
+
+ var err error
+ config, err = testenv.Start()
+ Expect(err).NotTo(HaveOccurred())
+
+ clientset, err = kubernetes.NewForConfig(config)
+ Expect(err).NotTo(HaveOccurred())
+
+ icache, err = cache.New(config, cache.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ go func() {
+ defer GinkgoRecover()
+ Expect(icache.Start(ctx)).NotTo(HaveOccurred())
+ }()
+})
+
+var _ = AfterSuite(func() {
+ cancel()
+ Expect(testenv.Stop()).To(Succeed())
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/source/source_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/source/source_test.go
new file mode 100644
index 00000000000..1e0e3afed36
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/source/source_test.go
@@ -0,0 +1,532 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package source_test
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "sigs.k8s.io/controller-runtime/pkg/cache/informertest"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/client-go/util/workqueue"
+)
+
+var _ = Describe("Source", func() {
+ Describe("Kind", func() {
+ var c chan struct{}
+ var p *corev1.Pod
+ var ic *informertest.FakeInformers
+
+ BeforeEach(func() {
+ ic = &informertest.FakeInformers{}
+ c = make(chan struct{})
+ p = &corev1.Pod{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {Name: "test", Image: "test"},
+ },
+ },
+ }
+ })
+
+ Context("for a Pod resource", func() {
+ It("should provide a Pod CreateEvent", func() {
+ c := make(chan struct{})
+ p := &corev1.Pod{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {Name: "test", Image: "test"},
+ },
+ },
+ }
+
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ instance := source.Kind(ic, &corev1.Pod{})
+ err := instance.Start(ctx, handler.Funcs{
+ CreateFunc: func(ctx context.Context, evt event.CreateEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(q2).To(Equal(q))
+ Expect(evt.Object).To(Equal(p))
+ close(c)
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected UpdateEvent")
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected DeleteEvent")
+ },
+ GenericFunc: func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected GenericEvent")
+ },
+ }, q)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(instance.WaitForSync(context.Background())).NotTo(HaveOccurred())
+
+ i, err := ic.FakeInformerFor(&corev1.Pod{})
+ Expect(err).NotTo(HaveOccurred())
+
+ i.Add(p)
+ <-c
+ })
+
+ It("should provide a Pod UpdateEvent", func() {
+ p2 := p.DeepCopy()
+ p2.SetLabels(map[string]string{"biz": "baz"})
+
+ ic := &informertest.FakeInformers{}
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ instance := source.Kind(ic, &corev1.Pod{})
+ err := instance.Start(ctx, handler.Funcs{
+ CreateFunc: func(ctx context.Context, evt event.CreateEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected CreateEvent")
+ },
+ UpdateFunc: func(ctx context.Context, evt event.UpdateEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(q2).To(BeIdenticalTo(q))
+ Expect(evt.ObjectOld).To(Equal(p))
+
+ Expect(evt.ObjectNew).To(Equal(p2))
+
+ close(c)
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected DeleteEvent")
+ },
+ GenericFunc: func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected GenericEvent")
+ },
+ }, q)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(instance.WaitForSync(context.Background())).NotTo(HaveOccurred())
+
+ i, err := ic.FakeInformerFor(&corev1.Pod{})
+ Expect(err).NotTo(HaveOccurred())
+
+ i.Update(p, p2)
+ <-c
+ })
+
+ It("should provide a Pod DeletedEvent", func() {
+ c := make(chan struct{})
+ p := &corev1.Pod{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {Name: "test", Image: "test"},
+ },
+ },
+ }
+
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ instance := source.Kind(ic, &corev1.Pod{})
+ err := instance.Start(ctx, handler.Funcs{
+ CreateFunc: func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected DeleteEvent")
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected UpdateEvent")
+ },
+ DeleteFunc: func(ctx context.Context, evt event.DeleteEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(q2).To(BeIdenticalTo(q))
+ Expect(evt.Object).To(Equal(p))
+ close(c)
+ },
+ GenericFunc: func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected GenericEvent")
+ },
+ }, q)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(instance.WaitForSync(context.Background())).NotTo(HaveOccurred())
+
+ i, err := ic.FakeInformerFor(&corev1.Pod{})
+ Expect(err).NotTo(HaveOccurred())
+
+ i.Delete(p)
+ <-c
+ })
+ })
+
+ It("should return an error from Start cache was not provided", func() {
+ instance := source.Kind(nil, &corev1.Pod{})
+ err := instance.Start(ctx, nil, nil)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("must create Kind with a non-nil cache"))
+ })
+
+ It("should return an error from Start if a type was not provided", func() {
+ instance := source.Kind(ic, nil)
+ err := instance.Start(ctx, nil, nil)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("must create Kind with a non-nil object"))
+ })
+
+ It("should return an error if syncing fails", func() {
+ f := false
+ instance := source.Kind(&informertest.FakeInformers{Synced: &f}, &corev1.Pod{})
+ Expect(instance.Start(context.Background(), nil, nil)).NotTo(HaveOccurred())
+ err := instance.WaitForSync(context.Background())
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(Equal("cache did not sync"))
+
+ })
+
+ Context("for a Kind not in the cache", func() {
+ It("should return an error when WaitForSync is called", func() {
+ ic.Error = fmt.Errorf("test error")
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+
+ ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
+ defer cancel()
+
+ instance := source.Kind(ic, &corev1.Pod{})
+ err := instance.Start(ctx, handler.Funcs{}, q)
+ Expect(err).NotTo(HaveOccurred())
+ Eventually(instance.WaitForSync(context.Background())).Should(HaveOccurred())
+ })
+ })
+
+ It("should return an error if syncing fails", func() {
+ f := false
+ instance := source.Kind(&informertest.FakeInformers{Synced: &f}, &corev1.Pod{})
+ Expect(instance.Start(context.Background(), nil, nil)).NotTo(HaveOccurred())
+ err := instance.WaitForSync(context.Background())
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(Equal("cache did not sync"))
+
+ })
+ })
+
+ Describe("Func", func() {
+ It("should be called from Start", func() {
+ run := false
+ instance := source.Func(func(
+ context.Context,
+ handler.EventHandler,
+ workqueue.RateLimitingInterface, ...predicate.Predicate) error {
+ run = true
+ return nil
+ })
+ Expect(instance.Start(ctx, nil, nil)).NotTo(HaveOccurred())
+ Expect(run).To(BeTrue())
+
+ expected := fmt.Errorf("expected error: Func")
+ instance = source.Func(func(
+ context.Context,
+ handler.EventHandler,
+ workqueue.RateLimitingInterface, ...predicate.Predicate) error {
+ return expected
+ })
+ Expect(instance.Start(ctx, nil, nil)).To(Equal(expected))
+ })
+ })
+
+ Describe("Channel", func() {
+ var ctx context.Context
+ var cancel context.CancelFunc
+ var ch chan event.GenericEvent
+
+ BeforeEach(func() {
+ ctx, cancel = context.WithCancel(context.Background())
+ ch = make(chan event.GenericEvent)
+ })
+
+ AfterEach(func() {
+ cancel()
+ close(ch)
+ })
+
+ Context("for a source", func() {
+ It("should provide a GenericEvent", func() {
+ ch := make(chan event.GenericEvent)
+ c := make(chan struct{})
+ p := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
+ }
+ evt := event.GenericEvent{
+ Object: p,
+ }
+ // Event that should be filtered out by predicates
+ invalidEvt := event.GenericEvent{}
+
+ // Predicate to filter out empty event
+ prct := predicate.Funcs{
+ GenericFunc: func(e event.GenericEvent) bool {
+ return e.Object != nil
+ },
+ }
+
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ instance := &source.Channel{Source: ch}
+ err := instance.Start(ctx, handler.Funcs{
+ CreateFunc: func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected CreateEvent")
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected UpdateEvent")
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected DeleteEvent")
+ },
+ GenericFunc: func(ctx context.Context, evt event.GenericEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ // The empty event should have been filtered out by the predicates,
+ // and will not be passed to the handler.
+ Expect(q2).To(BeIdenticalTo(q))
+ Expect(evt.Object).To(Equal(p))
+ close(c)
+ },
+ }, q, prct)
+ Expect(err).NotTo(HaveOccurred())
+
+ ch <- invalidEvt
+ ch <- evt
+ <-c
+ })
+ It("should get pending events processed once channel unblocked", func() {
+ ch := make(chan event.GenericEvent)
+ unblock := make(chan struct{})
+ processed := make(chan struct{})
+ evt := event.GenericEvent{}
+ eventCount := 0
+
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ // Add a handler to get distribution blocked
+ instance := &source.Channel{Source: ch}
+ instance.DestBufferSize = 1
+ err := instance.Start(ctx, handler.Funcs{
+ CreateFunc: func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected CreateEvent")
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected UpdateEvent")
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected DeleteEvent")
+ },
+ GenericFunc: func(ctx context.Context, evt event.GenericEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ // Block for the first time
+ if eventCount == 0 {
+ <-unblock
+ }
+ eventCount++
+
+ if eventCount == 3 {
+ close(processed)
+ }
+ },
+ }, q)
+ Expect(err).NotTo(HaveOccurred())
+
+ // Write 3 events into the source channel.
+ // The 1st should be passed into the generic func of the handler;
+ // The 2nd should be fetched out of the source channel, and waiting to write into dest channel;
+ // The 3rd should be pending in the source channel.
+ ch <- evt
+ ch <- evt
+ ch <- evt
+
+ // Validate none of the events have been processed.
+ Expect(eventCount).To(Equal(0))
+
+ close(unblock)
+
+ <-processed
+
+ // Validate all of the events have been processed.
+ Expect(eventCount).To(Equal(3))
+ })
+ It("should be able to cope with events in the channel before the source is started", func() {
+ ch := make(chan event.GenericEvent, 1)
+ processed := make(chan struct{})
+ evt := event.GenericEvent{}
+ ch <- evt
+
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ // Add a handler to get distribution blocked
+ instance := &source.Channel{Source: ch}
+ instance.DestBufferSize = 1
+
+ err := instance.Start(ctx, handler.Funcs{
+ CreateFunc: func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected CreateEvent")
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected UpdateEvent")
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected DeleteEvent")
+ },
+ GenericFunc: func(ctx context.Context, evt event.GenericEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+
+ close(processed)
+ },
+ }, q)
+ Expect(err).NotTo(HaveOccurred())
+
+ <-processed
+ })
+ It("should stop when the source channel is closed", func() {
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ // if we didn't stop, we'd start spamming the queue with empty
+ // messages as we "received" a zero-valued GenericEvent from
+ // the source channel
+
+ By("creating a channel with one element, then closing it")
+ ch := make(chan event.GenericEvent, 1)
+ evt := event.GenericEvent{}
+ ch <- evt
+ close(ch)
+
+ By("feeding that channel to a channel source")
+ src := &source.Channel{Source: ch}
+
+ processed := make(chan struct{})
+ defer close(processed)
+
+ err := src.Start(ctx, handler.Funcs{
+ CreateFunc: func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected CreateEvent")
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected UpdateEvent")
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected DeleteEvent")
+ },
+ GenericFunc: func(ctx context.Context, evt event.GenericEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+
+ processed <- struct{}{}
+ },
+ }, q)
+ Expect(err).NotTo(HaveOccurred())
+
+ By("expecting to only get one event")
+ Eventually(processed).Should(Receive())
+ Consistently(processed).ShouldNot(Receive())
+ })
+ It("should get error if no source specified", func() {
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ instance := &source.Channel{ /*no source specified*/ }
+ err := instance.Start(ctx, handler.Funcs{}, q)
+ Expect(err).To(Equal(fmt.Errorf("must specify Channel.Source")))
+ })
+ })
+ Context("for multi sources (handlers)", func() {
+ It("should provide GenericEvents for all handlers", func() {
+ ch := make(chan event.GenericEvent)
+ p := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
+ }
+ evt := event.GenericEvent{
+ Object: p,
+ }
+
+ var resEvent1, resEvent2 event.GenericEvent
+ c1 := make(chan struct{})
+ c2 := make(chan struct{})
+
+ q := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "test")
+ instance := &source.Channel{Source: ch}
+ err := instance.Start(ctx, handler.Funcs{
+ CreateFunc: func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected CreateEvent")
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected UpdateEvent")
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected DeleteEvent")
+ },
+ GenericFunc: func(ctx context.Context, evt event.GenericEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(q2).To(BeIdenticalTo(q))
+ Expect(evt.Object).To(Equal(p))
+ resEvent1 = evt
+ close(c1)
+ },
+ }, q)
+ Expect(err).NotTo(HaveOccurred())
+
+ err = instance.Start(ctx, handler.Funcs{
+ CreateFunc: func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected CreateEvent")
+ },
+ UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected UpdateEvent")
+ },
+ DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Fail("Unexpected DeleteEvent")
+ },
+ GenericFunc: func(ctx context.Context, evt event.GenericEvent, q2 workqueue.RateLimitingInterface) {
+ defer GinkgoRecover()
+ Expect(q2).To(BeIdenticalTo(q))
+ Expect(evt.Object).To(Equal(p))
+ resEvent2 = evt
+ close(c2)
+ },
+ }, q)
+ Expect(err).NotTo(HaveOccurred())
+
+ ch <- evt
+ <-c1
+ <-c2
+
+ // Validate the two handlers received same event
+ Expect(resEvent1).To(Equal(resEvent2))
+ })
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/admission_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/admission_suite_test.go
new file mode 100644
index 00000000000..f4e561b1b8c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/admission_suite_test.go
@@ -0,0 +1,36 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestAdmissionWebhook(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Admission Webhook Suite")
+}
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
new file mode 100644
index 00000000000..f14f130f7bd
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
@@ -0,0 +1,78 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "fmt"
+
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ "k8s.io/apimachinery/pkg/util/json"
+)
+
+// Decoder knows how to decode the contents of an admission
+// request into a concrete object.
+type Decoder struct {
+ codecs serializer.CodecFactory
+}
+
+// NewDecoder creates a Decoder given the runtime.Scheme.
+func NewDecoder(scheme *runtime.Scheme) *Decoder {
+ if scheme == nil {
+ panic("scheme should never be nil")
+ }
+ return &Decoder{codecs: serializer.NewCodecFactory(scheme)}
+}
+
+// Decode decodes the inlined object in the AdmissionRequest into the passed-in runtime.Object.
+// If you want decode the OldObject in the AdmissionRequest, use DecodeRaw.
+// It errors out if req.Object.Raw is empty i.e. containing 0 raw bytes.
+func (d *Decoder) Decode(req Request, into runtime.Object) error {
+ // we error out if rawObj is an empty object.
+ if len(req.Object.Raw) == 0 {
+ return fmt.Errorf("there is no content to decode")
+ }
+ return d.DecodeRaw(req.Object, into)
+}
+
+// DecodeRaw decodes a RawExtension object into the passed-in runtime.Object.
+// It errors out if rawObj is empty i.e. containing 0 raw bytes.
+func (d *Decoder) DecodeRaw(rawObj runtime.RawExtension, into runtime.Object) error {
+ // NB(directxman12): there's a bug/weird interaction between decoders and
+ // the API server where the API server doesn't send a GVK on the embedded
+ // objects, which means the unstructured decoder refuses to decode. It
+ // also means we can't pass the unstructured directly in, since it'll try
+ // and call unstructured's special Unmarshal implementation, which calls
+ // back into that same decoder :-/
+ // See kubernetes/kubernetes#74373.
+
+ // we error out if rawObj is an empty object.
+ if len(rawObj.Raw) == 0 {
+ return fmt.Errorf("there is no content to decode")
+ }
+ if unstructuredInto, isUnstructured := into.(runtime.Unstructured); isUnstructured {
+ // unmarshal into unstructured's underlying object to avoid calling the decoder
+ var object map[string]interface{}
+ if err := json.Unmarshal(rawObj.Raw, &object); err != nil {
+ return err
+ }
+ unstructuredInto.SetUnstructuredContent(object)
+ }
+
+ deserializer := d.codecs.UniversalDeserializer()
+ return runtime.DecodeInto(deserializer, rawObj.Raw, into)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode_test.go
new file mode 100644
index 00000000000..66586da7900
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode_test.go
@@ -0,0 +1,155 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ admissionv1 "k8s.io/api/admission/v1"
+ 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"
+ "k8s.io/client-go/kubernetes/scheme"
+)
+
+var _ = Describe("Admission Webhook Decoder", func() {
+ var decoder *Decoder
+ BeforeEach(func() {
+ By("creating a new decoder for a scheme")
+ decoder = NewDecoder(scheme.Scheme)
+ Expect(decoder).NotTo(BeNil())
+ })
+
+ req := Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Object: runtime.RawExtension{
+ Raw: []byte(`{
+ "apiVersion": "v1",
+ "kind": "Pod",
+ "metadata": {
+ "name": "foo",
+ "namespace": "default"
+ },
+ "spec": {
+ "containers": [
+ {
+ "image": "bar:v2",
+ "name": "bar"
+ }
+ ]
+ }
+}`),
+ },
+ OldObject: runtime.RawExtension{
+ Raw: []byte(`{
+ "apiVersion": "v1",
+ "kind": "Pod",
+ "metadata": {
+ "name": "foo",
+ "namespace": "default"
+ },
+ "spec": {
+ "containers": [
+ {
+ "image": "bar:v1",
+ "name": "bar"
+ }
+ ]
+ }
+}`),
+ },
+ },
+ }
+
+ It("should decode a valid admission request", func() {
+ By("extracting the object from the request")
+ var actualObj corev1.Pod
+ Expect(decoder.Decode(req, &actualObj)).To(Succeed())
+
+ By("verifying that all data is present in the object")
+ Expect(actualObj).To(Equal(corev1.Pod{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Pod",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "foo",
+ Namespace: "default",
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {Image: "bar:v2", Name: "bar"},
+ },
+ },
+ }))
+ })
+
+ It("should decode a valid RawExtension object", func() {
+ By("decoding the RawExtension object")
+ var actualObj corev1.Pod
+ Expect(decoder.DecodeRaw(req.OldObject, &actualObj)).To(Succeed())
+
+ By("verifying that all data is present in the object")
+ Expect(actualObj).To(Equal(corev1.Pod{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Pod",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "foo",
+ Namespace: "default",
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {Image: "bar:v1", Name: "bar"},
+ },
+ },
+ }))
+ })
+
+ It("should fail to decode if the object in the request doesn't match the passed-in type", func() {
+ By("trying to extract a pod from the quest into a node")
+ Expect(decoder.Decode(req, &corev1.Node{})).NotTo(Succeed())
+
+ By("trying to extract a pod in RawExtension format into a node")
+ Expect(decoder.DecodeRaw(req.OldObject, &corev1.Node{})).NotTo(Succeed())
+ })
+
+ It("should be able to decode into an unstructured object", func() {
+ By("decoding the request into an unstructured object")
+ var target unstructured.Unstructured
+ Expect(decoder.Decode(req, &target)).To(Succeed())
+
+ By("sanity-checking the metadata on the output object")
+ Expect(target.Object["metadata"]).To(Equal(map[string]interface{}{
+ "name": "foo",
+ "namespace": "default",
+ }))
+
+ By("decoding the RawExtension object into an unstructured object")
+ var target2 unstructured.Unstructured
+ Expect(decoder.DecodeRaw(req.Object, &target2)).To(Succeed())
+
+ By("sanity-checking the metadata on the output object")
+ Expect(target2.Object["metadata"]).To(Equal(map[string]interface{}{
+ "name": "foo",
+ "namespace": "default",
+ }))
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
new file mode 100644
index 00000000000..a3b72071687
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
@@ -0,0 +1,82 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "context"
+ "encoding/json"
+ "net/http"
+
+ admissionv1 "k8s.io/api/admission/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// Defaulter defines functions for setting defaults on resources.
+type Defaulter interface {
+ runtime.Object
+ Default()
+}
+
+// DefaultingWebhookFor creates a new Webhook for Defaulting the provided type.
+func DefaultingWebhookFor(scheme *runtime.Scheme, defaulter Defaulter) *Webhook {
+ return &Webhook{
+ Handler: &mutatingHandler{defaulter: defaulter, decoder: NewDecoder(scheme)},
+ }
+}
+
+type mutatingHandler struct {
+ defaulter Defaulter
+ decoder *Decoder
+}
+
+// Handle handles admission requests.
+func (h *mutatingHandler) Handle(ctx context.Context, req Request) Response {
+ if h.decoder == nil {
+ panic("decoder should never be nil")
+ }
+ if h.defaulter == nil {
+ panic("defaulter should never be nil")
+ }
+
+ // always skip when a DELETE operation received in mutation handler
+ // describe in https://github.com/kubernetes-sigs/controller-runtime/issues/1762
+ if req.Operation == admissionv1.Delete {
+ return Response{AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ },
+ }}
+ }
+
+ // Get the object in the request
+ obj := h.defaulter.DeepCopyObject().(Defaulter)
+ if err := h.decoder.Decode(req, obj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ // Default the object
+ obj.Default()
+ marshalled, err := json.Marshal(obj)
+ if err != nil {
+ return Errored(http.StatusInternalServerError, err)
+ }
+
+ // Create the patch
+ return PatchResponseFromRaw(req.Object.Raw, marshalled)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
new file mode 100644
index 00000000000..5f697e7dce7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
@@ -0,0 +1,94 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "net/http"
+
+ admissionv1 "k8s.io/api/admission/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// CustomDefaulter defines functions for setting defaults on resources.
+type CustomDefaulter interface {
+ Default(ctx context.Context, obj runtime.Object) error
+}
+
+// WithCustomDefaulter creates a new Webhook for a CustomDefaulter interface.
+func WithCustomDefaulter(scheme *runtime.Scheme, obj runtime.Object, defaulter CustomDefaulter) *Webhook {
+ return &Webhook{
+ Handler: &defaulterForType{object: obj, defaulter: defaulter, decoder: NewDecoder(scheme)},
+ }
+}
+
+type defaulterForType struct {
+ defaulter CustomDefaulter
+ object runtime.Object
+ decoder *Decoder
+}
+
+// Handle handles admission requests.
+func (h *defaulterForType) Handle(ctx context.Context, req Request) Response {
+ if h.decoder == nil {
+ panic("decoder should never be nil")
+ }
+ if h.defaulter == nil {
+ panic("defaulter should never be nil")
+ }
+ if h.object == nil {
+ panic("object should never be nil")
+ }
+
+ // Always skip when a DELETE operation received in custom mutation handler.
+ if req.Operation == admissionv1.Delete {
+ return Response{AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ },
+ }}
+ }
+
+ ctx = NewContextWithRequest(ctx, req)
+
+ // Get the object in the request
+ obj := h.object.DeepCopyObject()
+ if err := h.decoder.Decode(req, obj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ // Default the object
+ if err := h.defaulter.Default(ctx, obj); err != nil {
+ var apiStatus apierrors.APIStatus
+ if errors.As(err, &apiStatus) {
+ return validationResponseFromStatus(false, apiStatus.Status())
+ }
+ return Denied(err.Error())
+ }
+
+ // Create the patch
+ marshalled, err := json.Marshal(obj)
+ if err != nil {
+ return Errored(http.StatusInternalServerError, err)
+ }
+ return PatchResponseFromRaw(req.Object.Raw, marshalled)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_test.go
new file mode 100644
index 00000000000..cf7571663c0
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_test.go
@@ -0,0 +1,68 @@
+package admission
+
+import (
+ "context"
+ "net/http"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ admissionv1 "k8s.io/api/admission/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+var _ = Describe("Defaulter Handler", func() {
+
+ It("should return ok if received delete verb in defaulter handler", func() {
+ obj := &TestDefaulter{}
+ handler := DefaultingWebhookFor(admissionScheme, obj)
+
+ resp := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Delete,
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ },
+ },
+ })
+ Expect(resp.Allowed).Should(BeTrue())
+ Expect(resp.Result.Code).Should(Equal(int32(http.StatusOK)))
+ })
+
+})
+
+// TestDefaulter.
+var _ runtime.Object = &TestDefaulter{}
+
+type TestDefaulter struct {
+ Replica int `json:"replica,omitempty"`
+}
+
+var testDefaulterGVK = schema.GroupVersionKind{Group: "foo.test.org", Version: "v1", Kind: "TestDefaulter"}
+
+func (d *TestDefaulter) GetObjectKind() schema.ObjectKind { return d }
+func (d *TestDefaulter) DeepCopyObject() runtime.Object {
+ return &TestDefaulter{
+ Replica: d.Replica,
+ }
+}
+
+func (d *TestDefaulter) GroupVersionKind() schema.GroupVersionKind {
+ return testDefaulterGVK
+}
+
+func (d *TestDefaulter) SetGroupVersionKind(gvk schema.GroupVersionKind) {}
+
+var _ runtime.Object = &TestDefaulterList{}
+
+type TestDefaulterList struct{}
+
+func (*TestDefaulterList) GetObjectKind() schema.ObjectKind { return nil }
+func (*TestDefaulterList) DeepCopyObject() runtime.Object { return nil }
+
+func (d *TestDefaulter) Default() {
+ if d.Replica < 2 {
+ d.Replica = 2
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go
new file mode 100644
index 00000000000..8dc0cbec6f7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go
@@ -0,0 +1,22 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package admission provides implementation for admission webhook and methods to implement admission webhook handlers.
+
+See examples/mutatingwebhook.go and examples/validatingwebhook.go for examples of admission webhooks.
+*/
+package admission
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go
new file mode 100644
index 00000000000..84ab5e75a4e
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go
@@ -0,0 +1,153 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+
+ v1 "k8s.io/api/admission/v1"
+ "k8s.io/api/admission/v1beta1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+)
+
+var admissionScheme = runtime.NewScheme()
+var admissionCodecs = serializer.NewCodecFactory(admissionScheme)
+
+func init() {
+ utilruntime.Must(v1.AddToScheme(admissionScheme))
+ utilruntime.Must(v1beta1.AddToScheme(admissionScheme))
+}
+
+var _ http.Handler = &Webhook{}
+
+func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ var body []byte
+ var err error
+ ctx := r.Context()
+ if wh.WithContextFunc != nil {
+ ctx = wh.WithContextFunc(ctx, r)
+ }
+
+ var reviewResponse Response
+ if r.Body == nil {
+ err = errors.New("request body is empty")
+ wh.getLogger(nil).Error(err, "bad request")
+ reviewResponse = Errored(http.StatusBadRequest, err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+
+ defer r.Body.Close()
+ if body, err = io.ReadAll(r.Body); err != nil {
+ wh.getLogger(nil).Error(err, "unable to read the body from the incoming request")
+ reviewResponse = Errored(http.StatusBadRequest, err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+
+ // verify the content type is accurate
+ if contentType := r.Header.Get("Content-Type"); contentType != "application/json" {
+ err = fmt.Errorf("contentType=%s, expected application/json", contentType)
+ wh.getLogger(nil).Error(err, "unable to process a request with unknown content type")
+ reviewResponse = Errored(http.StatusBadRequest, err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+
+ // Both v1 and v1beta1 AdmissionReview types are exactly the same, so the v1beta1 type can
+ // be decoded into the v1 type. However the runtime codec's decoder guesses which type to
+ // decode into by type name if an Object's TypeMeta isn't set. By setting TypeMeta of an
+ // unregistered type to the v1 GVK, the decoder will coerce a v1beta1 AdmissionReview to v1.
+ // The actual AdmissionReview GVK will be used to write a typed response in case the
+ // webhook config permits multiple versions, otherwise this response will fail.
+ req := Request{}
+ ar := unversionedAdmissionReview{}
+ // avoid an extra copy
+ ar.Request = &req.AdmissionRequest
+ ar.SetGroupVersionKind(v1.SchemeGroupVersion.WithKind("AdmissionReview"))
+ _, actualAdmRevGVK, err := admissionCodecs.UniversalDeserializer().Decode(body, nil, &ar)
+ if err != nil {
+ wh.getLogger(nil).Error(err, "unable to decode the request")
+ reviewResponse = Errored(http.StatusBadRequest, err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+ wh.getLogger(&req).V(4).Info("received request")
+
+ reviewResponse = wh.Handle(ctx, req)
+ wh.writeResponseTyped(w, reviewResponse, actualAdmRevGVK)
+}
+
+// writeResponse writes response to w generically, i.e. without encoding GVK information.
+func (wh *Webhook) writeResponse(w io.Writer, response Response) {
+ wh.writeAdmissionResponse(w, v1.AdmissionReview{Response: &response.AdmissionResponse})
+}
+
+// writeResponseTyped writes response to w with GVK set to admRevGVK, which is necessary
+// if multiple AdmissionReview versions are permitted by the webhook.
+func (wh *Webhook) writeResponseTyped(w io.Writer, response Response, admRevGVK *schema.GroupVersionKind) {
+ ar := v1.AdmissionReview{
+ Response: &response.AdmissionResponse,
+ }
+ // Default to a v1 AdmissionReview, otherwise the API server may not recognize the request
+ // if multiple AdmissionReview versions are permitted by the webhook config.
+ // TODO(estroz): this should be configurable since older API servers won't know about v1.
+ if admRevGVK == nil || *admRevGVK == (schema.GroupVersionKind{}) {
+ ar.SetGroupVersionKind(v1.SchemeGroupVersion.WithKind("AdmissionReview"))
+ } else {
+ ar.SetGroupVersionKind(*admRevGVK)
+ }
+ wh.writeAdmissionResponse(w, ar)
+}
+
+// writeAdmissionResponse writes ar to w.
+func (wh *Webhook) writeAdmissionResponse(w io.Writer, ar v1.AdmissionReview) {
+ if err := json.NewEncoder(w).Encode(ar); err != nil {
+ wh.getLogger(nil).Error(err, "unable to encode and write the response")
+ // Since the `ar v1.AdmissionReview` is a clear and legal object,
+ // it should not have problem to be marshalled into bytes.
+ // The error here is probably caused by the abnormal HTTP connection,
+ // e.g., broken pipe, so we can only write the error response once,
+ // to avoid endless circular calling.
+ serverError := Errored(http.StatusInternalServerError, err)
+ if err = json.NewEncoder(w).Encode(v1.AdmissionReview{Response: &serverError.AdmissionResponse}); err != nil {
+ wh.getLogger(nil).Error(err, "still unable to encode and write the InternalServerError response")
+ }
+ } else {
+ res := ar.Response
+ if log := wh.getLogger(nil); log.V(4).Enabled() {
+ if res.Result != nil {
+ log = log.WithValues("code", res.Result.Code, "reason", res.Result.Reason, "message", res.Result.Message)
+ }
+ log.V(4).Info("wrote response", "requestID", res.UID, "allowed", res.Allowed)
+ }
+ }
+}
+
+// unversionedAdmissionReview is used to decode both v1 and v1beta1 AdmissionReview types.
+type unversionedAdmissionReview struct {
+ v1.AdmissionReview
+}
+
+var _ runtime.Object = &unversionedAdmissionReview{}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http_test.go
new file mode 100644
index 00000000000..be10aea4593
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http_test.go
@@ -0,0 +1,231 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ admissionv1 "k8s.io/api/admission/v1"
+)
+
+var _ = Describe("Admission Webhooks", func() {
+
+ const (
+ gvkJSONv1 = `"kind":"AdmissionReview","apiVersion":"admission.k8s.io/v1"`
+ gvkJSONv1beta1 = `"kind":"AdmissionReview","apiVersion":"admission.k8s.io/v1beta1"`
+ )
+
+ Describe("HTTP Handler", func() {
+ var respRecorder *httptest.ResponseRecorder
+ webhook := &Webhook{
+ Handler: nil,
+ }
+ BeforeEach(func() {
+ respRecorder = &httptest.ResponseRecorder{
+ Body: bytes.NewBuffer(nil),
+ }
+ })
+
+ It("should return bad-request when given an empty body", func() {
+ req := &http.Request{Body: nil}
+
+ expected := `{"response":{"uid":"","allowed":false,"status":{"metadata":{},"message":"request body is empty","code":400}}}
+`
+ webhook.ServeHTTP(respRecorder, req)
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should return bad-request when given the wrong content-type", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/foo"}},
+ Body: nopCloser{Reader: bytes.NewBuffer(nil)},
+ }
+
+ expected :=
+ `{"response":{"uid":"","allowed":false,"status":{"metadata":{},"message":"contentType=application/foo, expected application/json","code":400}}}
+`
+ webhook.ServeHTTP(respRecorder, req)
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should return bad-request when given an undecodable body", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Body: nopCloser{Reader: bytes.NewBufferString("{")},
+ }
+
+ expected :=
+ `{"response":{"uid":"","allowed":false,"status":{"metadata":{},"message":"couldn't get version/kind; json parse error: unexpected end of JSON input","code":400}}}
+`
+ webhook.ServeHTTP(respRecorder, req)
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should return the response given by the handler with version defaulted to v1", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Body: nopCloser{Reader: bytes.NewBufferString(`{"request":{}}`)},
+ }
+ webhook := &Webhook{
+ Handler: &fakeHandler{},
+ }
+
+ expected := fmt.Sprintf(`{%s,"response":{"uid":"","allowed":true,"status":{"metadata":{},"code":200}}}
+`, gvkJSONv1)
+ webhook.ServeHTTP(respRecorder, req)
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should return the v1 response given by the handler", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Body: nopCloser{Reader: bytes.NewBufferString(fmt.Sprintf(`{%s,"request":{}}`, gvkJSONv1))},
+ }
+ webhook := &Webhook{
+ Handler: &fakeHandler{},
+ }
+
+ expected := fmt.Sprintf(`{%s,"response":{"uid":"","allowed":true,"status":{"metadata":{},"code":200}}}
+`, gvkJSONv1)
+ webhook.ServeHTTP(respRecorder, req)
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should return the v1beta1 response given by the handler", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Body: nopCloser{Reader: bytes.NewBufferString(fmt.Sprintf(`{%s,"request":{}}`, gvkJSONv1beta1))},
+ }
+ webhook := &Webhook{
+ Handler: &fakeHandler{},
+ }
+
+ expected := fmt.Sprintf(`{%s,"response":{"uid":"","allowed":true,"status":{"metadata":{},"code":200}}}
+`, gvkJSONv1beta1)
+ webhook.ServeHTTP(respRecorder, req)
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should present the Context from the HTTP request, if any", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Body: nopCloser{Reader: bytes.NewBufferString(`{"request":{}}`)},
+ }
+ type ctxkey int
+ const key ctxkey = 1
+ const value = "from-ctx"
+ webhook := &Webhook{
+ Handler: &fakeHandler{
+ fn: func(ctx context.Context, req Request) Response {
+ <-ctx.Done()
+ return Allowed(ctx.Value(key).(string))
+ },
+ },
+ }
+
+ expected := fmt.Sprintf(`{%s,"response":{"uid":"","allowed":true,"status":{"metadata":{},"message":%q,"code":200}}}
+`, gvkJSONv1, value)
+
+ ctx, cancel := context.WithCancel(context.WithValue(context.Background(), key, value))
+ cancel()
+ webhook.ServeHTTP(respRecorder, req.WithContext(ctx))
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should mutate the Context from the HTTP request, if func supplied", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Body: nopCloser{Reader: bytes.NewBufferString(`{"request":{}}`)},
+ }
+ type ctxkey int
+ const key ctxkey = 1
+ webhook := &Webhook{
+ Handler: &fakeHandler{
+ fn: func(ctx context.Context, req Request) Response {
+ return Allowed(ctx.Value(key).(string))
+ },
+ },
+ WithContextFunc: func(ctx context.Context, r *http.Request) context.Context {
+ return context.WithValue(ctx, key, r.Header["Content-Type"][0])
+ },
+ }
+
+ expected := fmt.Sprintf(`{%s,"response":{"uid":"","allowed":true,"status":{"metadata":{},"message":%q,"code":200}}}
+`, gvkJSONv1, "application/json")
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ webhook.ServeHTTP(respRecorder, req.WithContext(ctx))
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should never run into circular calling if the writer has broken", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Body: nopCloser{Reader: bytes.NewBufferString(fmt.Sprintf(`{%s,"request":{}}`, gvkJSONv1))},
+ }
+ webhook := &Webhook{
+ Handler: &fakeHandler{},
+ }
+
+ bw := &brokenWriter{ResponseWriter: respRecorder}
+ Eventually(func() int {
+ // This should not be blocked by the circular calling of writeResponse and writeAdmissionResponse
+ webhook.ServeHTTP(bw, req)
+ return respRecorder.Body.Len()
+ }, time.Second*3).Should(Equal(0))
+ })
+ })
+})
+
+type nopCloser struct {
+ io.Reader
+}
+
+func (nopCloser) Close() error { return nil }
+
+type fakeHandler struct {
+ invoked bool
+ fn func(context.Context, Request) Response
+}
+
+func (h *fakeHandler) Handle(ctx context.Context, req Request) Response {
+ h.invoked = true
+ if h.fn != nil {
+ return h.fn(ctx, req)
+ }
+ return Response{AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ }}
+}
+
+type brokenWriter struct {
+ http.ResponseWriter
+}
+
+func (bw *brokenWriter) Write(buf []byte) (int, error) {
+ return 0, fmt.Errorf("mock: write: broken pipe")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go
new file mode 100644
index 00000000000..2f7820d04b4
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go
@@ -0,0 +1,95 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ jsonpatch "gomodules.xyz/jsonpatch/v2"
+ admissionv1 "k8s.io/api/admission/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+type multiMutating []Handler
+
+func (hs multiMutating) Handle(ctx context.Context, req Request) Response {
+ patches := []jsonpatch.JsonPatchOperation{}
+ for _, handler := range hs {
+ resp := handler.Handle(ctx, req)
+ if !resp.Allowed {
+ return resp
+ }
+ if resp.PatchType != nil && *resp.PatchType != admissionv1.PatchTypeJSONPatch {
+ return Errored(http.StatusInternalServerError,
+ fmt.Errorf("unexpected patch type returned by the handler: %v, only allow: %v",
+ resp.PatchType, admissionv1.PatchTypeJSONPatch))
+ }
+ patches = append(patches, resp.Patches...)
+ }
+ var err error
+ marshaledPatch, err := json.Marshal(patches)
+ if err != nil {
+ return Errored(http.StatusBadRequest, fmt.Errorf("error when marshaling the patch: %w", err))
+ }
+ return Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ },
+ Patch: marshaledPatch,
+ PatchType: func() *admissionv1.PatchType { pt := admissionv1.PatchTypeJSONPatch; return &pt }(),
+ },
+ }
+}
+
+// MultiMutatingHandler combines multiple mutating webhook handlers into a single
+// mutating webhook handler. Handlers are called in sequential order, and the first
+// `allowed: false` response may short-circuit the rest. Users must take care to
+// ensure patches are disjoint.
+func MultiMutatingHandler(handlers ...Handler) Handler {
+ return multiMutating(handlers)
+}
+
+type multiValidating []Handler
+
+func (hs multiValidating) Handle(ctx context.Context, req Request) Response {
+ for _, handler := range hs {
+ resp := handler.Handle(ctx, req)
+ if !resp.Allowed {
+ return resp
+ }
+ }
+ return Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ },
+ },
+ }
+}
+
+// MultiValidatingHandler combines multiple validating webhook handlers into a single
+// validating webhook handler. Handlers are called in sequential order, and the first
+// `allowed: false` response may short-circuit the rest.
+func MultiValidatingHandler(handlers ...Handler) Handler {
+ return multiValidating(handlers)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi_test.go
new file mode 100644
index 00000000000..da85a52e42a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi_test.go
@@ -0,0 +1,132 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "context"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ jsonpatch "gomodules.xyz/jsonpatch/v2"
+ admissionv1 "k8s.io/api/admission/v1"
+)
+
+var _ = Describe("Multi-Handler Admission Webhooks", func() {
+ alwaysAllow := &fakeHandler{
+ fn: func(ctx context.Context, req Request) Response {
+ return Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ },
+ }
+ },
+ }
+ alwaysDeny := &fakeHandler{
+ fn: func(ctx context.Context, req Request) Response {
+ return Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: false,
+ },
+ }
+ },
+ }
+
+ Context("with validating handlers", func() {
+ It("should deny the request if any handler denies the request", func() {
+ By("setting up a handler with accept and deny")
+ handler := MultiValidatingHandler(alwaysAllow, alwaysDeny)
+
+ By("checking that the handler denies the request")
+ resp := handler.Handle(context.Background(), Request{})
+ Expect(resp.Allowed).To(BeFalse())
+ })
+
+ It("should allow the request if all handlers allow the request", func() {
+ By("setting up a handler with only accept")
+ handler := MultiValidatingHandler(alwaysAllow, alwaysAllow)
+
+ By("checking that the handler allows the request")
+ resp := handler.Handle(context.Background(), Request{})
+ Expect(resp.Allowed).To(BeTrue())
+ })
+ })
+
+ Context("with mutating handlers", func() {
+ patcher1 := &fakeHandler{
+ fn: func(ctx context.Context, req Request) Response {
+ return Response{
+ Patches: []jsonpatch.JsonPatchOperation{
+ {
+ Operation: "add",
+ Path: "/metadata/annotation/new-key",
+ Value: "new-value",
+ },
+ {
+ Operation: "replace",
+ Path: "/spec/replicas",
+ Value: "2",
+ },
+ },
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ PatchType: func() *admissionv1.PatchType { pt := admissionv1.PatchTypeJSONPatch; return &pt }(),
+ },
+ }
+ },
+ }
+ patcher2 := &fakeHandler{
+ fn: func(ctx context.Context, req Request) Response {
+ return Response{
+ Patches: []jsonpatch.JsonPatchOperation{
+ {
+ Operation: "add",
+ Path: "/metadata/annotation/hello",
+ Value: "world",
+ },
+ },
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ PatchType: func() *admissionv1.PatchType { pt := admissionv1.PatchTypeJSONPatch; return &pt }(),
+ },
+ }
+ },
+ }
+
+ It("should not return any patches if the request is denied", func() {
+ By("setting up a webhook with some patches and a deny")
+ handler := MultiMutatingHandler(patcher1, patcher2, alwaysDeny)
+
+ By("checking that the handler denies the request and produces no patches")
+ resp := handler.Handle(context.Background(), Request{})
+ Expect(resp.Allowed).To(BeFalse())
+ Expect(resp.Patches).To(BeEmpty())
+ })
+
+ It("should produce all patches if the requests are all allowed", func() {
+ By("setting up a webhook with some patches")
+ handler := MultiMutatingHandler(patcher1, patcher2, alwaysAllow)
+
+ By("checking that the handler accepts the request and returns all patches")
+ resp := handler.Handle(context.Background(), Request{})
+ Expect(resp.Allowed).To(BeTrue())
+ Expect(resp.Patch).To(Equal([]byte(
+ `[{"op":"add","path":"/metadata/annotation/new-key","value":"new-value"},` +
+ `{"op":"replace","path":"/spec/replicas","value":"2"},{"op":"add","path":"/metadata/annotation/hello","value":"world"}]`)))
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go
new file mode 100644
index 00000000000..ec1c88c989b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go
@@ -0,0 +1,124 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "net/http"
+
+ jsonpatch "gomodules.xyz/jsonpatch/v2"
+ admissionv1 "k8s.io/api/admission/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// Allowed constructs a response indicating that the given operation
+// is allowed (without any patches).
+func Allowed(message string) Response {
+ return ValidationResponse(true, message)
+}
+
+// Denied constructs a response indicating that the given operation
+// is not allowed.
+func Denied(message string) Response {
+ return ValidationResponse(false, message)
+}
+
+// Patched constructs a response indicating that the given operation is
+// allowed, and that the target object should be modified by the given
+// JSONPatch operations.
+func Patched(message string, patches ...jsonpatch.JsonPatchOperation) Response {
+ resp := Allowed(message)
+ resp.Patches = patches
+
+ return resp
+}
+
+// Errored creates a new Response for error-handling a request.
+func Errored(code int32, err error) Response {
+ return Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: false,
+ Result: &metav1.Status{
+ Code: code,
+ Message: err.Error(),
+ },
+ },
+ }
+}
+
+// ValidationResponse returns a response for admitting a request.
+func ValidationResponse(allowed bool, message string) Response {
+ code := http.StatusForbidden
+ reason := metav1.StatusReasonForbidden
+ if allowed {
+ code = http.StatusOK
+ reason = ""
+ }
+ resp := Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: allowed,
+ Result: &metav1.Status{
+ Code: int32(code),
+ Reason: reason,
+ },
+ },
+ }
+ if len(message) > 0 {
+ resp.Result.Message = message
+ }
+ return resp
+}
+
+// PatchResponseFromRaw takes 2 byte arrays and returns a new response with json patch.
+// The original object should be passed in as raw bytes to avoid the roundtripping problem
+// described in https://github.com/kubernetes-sigs/kubebuilder/issues/510.
+func PatchResponseFromRaw(original, current []byte) Response {
+ patches, err := jsonpatch.CreatePatch(original, current)
+ if err != nil {
+ return Errored(http.StatusInternalServerError, err)
+ }
+ return Response{
+ Patches: patches,
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ PatchType: func() *admissionv1.PatchType {
+ if len(patches) == 0 {
+ return nil
+ }
+ pt := admissionv1.PatchTypeJSONPatch
+ return &pt
+ }(),
+ },
+ }
+}
+
+// validationResponseFromStatus returns a response for admitting a request with provided Status object.
+func validationResponseFromStatus(allowed bool, status metav1.Status) Response {
+ resp := Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: allowed,
+ Result: &status,
+ },
+ }
+ return resp
+}
+
+// WithWarnings adds the given warnings to the Response.
+// If any warnings were already given, they will not be overwritten.
+func (r Response) WithWarnings(warnings ...string) Response {
+ r.AdmissionResponse.Warnings = append(r.AdmissionResponse.Warnings, warnings...)
+ return r
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response_test.go
new file mode 100644
index 00000000000..03107c92f51
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response_test.go
@@ -0,0 +1,249 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "errors"
+ "net/http"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ jsonpatch "gomodules.xyz/jsonpatch/v2"
+ admissionv1 "k8s.io/api/admission/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+var _ = Describe("Admission Webhook Response Helpers", func() {
+ Describe("Allowed", func() {
+ It("should return an 'allowed' response", func() {
+ Expect(Allowed("")).To(Equal(
+ Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ },
+ },
+ },
+ ))
+ })
+
+ It("should populate a status with a reason when a reason is given", func() {
+ Expect(Allowed("acceptable")).To(Equal(
+ Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ Message: "acceptable",
+ },
+ },
+ },
+ ))
+ })
+ })
+
+ Describe("Denied", func() {
+ It("should return a 'not allowed' response", func() {
+ Expect(Denied("")).To(Equal(
+ Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: false,
+ Result: &metav1.Status{
+ Code: http.StatusForbidden,
+ Reason: metav1.StatusReasonForbidden,
+ },
+ },
+ },
+ ))
+ })
+
+ It("should populate a status with a reason when a reason is given", func() {
+ Expect(Denied("UNACCEPTABLE!")).To(Equal(
+ Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: false,
+ Result: &metav1.Status{
+ Code: http.StatusForbidden,
+ Reason: metav1.StatusReasonForbidden,
+ Message: "UNACCEPTABLE!",
+ },
+ },
+ },
+ ))
+ })
+ })
+
+ Describe("Patched", func() {
+ ops := []jsonpatch.JsonPatchOperation{
+ {
+ Operation: "replace",
+ Path: "/spec/selector/matchLabels",
+ Value: map[string]string{"foo": "bar"},
+ },
+ {
+ Operation: "delete",
+ Path: "/spec/replicas",
+ },
+ }
+ It("should return an 'allowed' response with the given patches", func() {
+ Expect(Patched("", ops...)).To(Equal(
+ Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ },
+ },
+ Patches: ops,
+ },
+ ))
+ })
+ It("should populate a status with a reason when a reason is given", func() {
+ Expect(Patched("some changes", ops...)).To(Equal(
+ Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ Message: "some changes",
+ },
+ },
+ Patches: ops,
+ },
+ ))
+ })
+ })
+
+ Describe("Errored", func() {
+ It("should return a denied response with an error", func() {
+ err := errors.New("this is an error")
+ expected := Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: false,
+ Result: &metav1.Status{
+ Code: http.StatusBadRequest,
+ Message: err.Error(),
+ },
+ },
+ }
+ resp := Errored(http.StatusBadRequest, err)
+ Expect(resp).To(Equal(expected))
+ })
+ })
+
+ Describe("ValidationResponse", func() {
+ It("should populate a status with a message when a message is given", func() {
+ By("checking that a message is populated for 'allowed' responses")
+ Expect(ValidationResponse(true, "acceptable")).To(Equal(
+ Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ Message: "acceptable",
+ },
+ },
+ },
+ ))
+
+ By("checking that a message is populated for 'denied' responses")
+ Expect(ValidationResponse(false, "UNACCEPTABLE!")).To(Equal(
+ Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: false,
+ Result: &metav1.Status{
+ Code: http.StatusForbidden,
+ Reason: metav1.StatusReasonForbidden,
+ Message: "UNACCEPTABLE!",
+ },
+ },
+ },
+ ))
+ })
+
+ It("should return an admission decision", func() {
+ By("checking that it returns an 'allowed' response when allowed is true")
+ Expect(ValidationResponse(true, "")).To(Equal(
+ Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ },
+ },
+ },
+ ))
+
+ By("checking that it returns an 'denied' response when allowed is false")
+ Expect(ValidationResponse(false, "")).To(Equal(
+ Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: false,
+ Result: &metav1.Status{
+ Code: http.StatusForbidden,
+ Reason: metav1.StatusReasonForbidden,
+ },
+ },
+ },
+ ))
+ })
+ })
+
+ Describe("PatchResponseFromRaw", func() {
+ It("should return an 'allowed' response with a patch of the diff between two sets of serialized JSON", func() {
+ expected := Response{
+ Patches: []jsonpatch.JsonPatchOperation{
+ {Operation: "replace", Path: "/a", Value: "bar"},
+ },
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ PatchType: func() *admissionv1.PatchType { pt := admissionv1.PatchTypeJSONPatch; return &pt }(),
+ },
+ }
+ resp := PatchResponseFromRaw([]byte(`{"a": "foo"}`), []byte(`{"a": "bar"}`))
+ Expect(resp).To(Equal(expected))
+ })
+ })
+
+ Describe("WithWarnings", func() {
+ It("should add the warnings to the existing response without removing any existing warnings", func() {
+ initialResponse := Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ },
+ Warnings: []string{"existing-warning"},
+ },
+ }
+ warnings := []string{"additional-warning-1", "additional-warning-2"}
+ expectedResponse := Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ },
+ Warnings: []string{"existing-warning", "additional-warning-1", "additional-warning-2"},
+ },
+ }
+
+ Expect(initialResponse.WithWarnings(warnings...)).To(Equal(expectedResponse))
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
new file mode 100644
index 00000000000..00bda8a4ce5
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
@@ -0,0 +1,125 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+
+ v1 "k8s.io/api/admission/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// Warnings represents warning messages.
+type Warnings []string
+
+// Validator defines functions for validating an operation.
+// The custom resource kind which implements this interface can validate itself.
+// To validate the custom resource with another specific struct, use CustomValidator instead.
+type Validator interface {
+ runtime.Object
+
+ // ValidateCreate validates the object on creation.
+ // The optional warnings will be added to the response as warning messages.
+ // Return an error if the object is invalid.
+ ValidateCreate() (warnings Warnings, err error)
+
+ // ValidateUpdate validates the object on update. The oldObj is the object before the update.
+ // The optional warnings will be added to the response as warning messages.
+ // Return an error if the object is invalid.
+ ValidateUpdate(old runtime.Object) (warnings Warnings, err error)
+
+ // ValidateDelete validates the object on deletion.
+ // The optional warnings will be added to the response as warning messages.
+ // Return an error if the object is invalid.
+ ValidateDelete() (warnings Warnings, err error)
+}
+
+// ValidatingWebhookFor creates a new Webhook for validating the provided type.
+func ValidatingWebhookFor(scheme *runtime.Scheme, validator Validator) *Webhook {
+ return &Webhook{
+ Handler: &validatingHandler{validator: validator, decoder: NewDecoder(scheme)},
+ }
+}
+
+type validatingHandler struct {
+ validator Validator
+ decoder *Decoder
+}
+
+// Handle handles admission requests.
+func (h *validatingHandler) Handle(ctx context.Context, req Request) Response {
+ if h.decoder == nil {
+ panic("decoder should never be nil")
+ }
+ if h.validator == nil {
+ panic("validator should never be nil")
+ }
+ // Get the object in the request
+ obj := h.validator.DeepCopyObject().(Validator)
+
+ var err error
+ var warnings []string
+
+ switch req.Operation {
+ case v1.Connect:
+ // No validation for connect requests.
+ // TODO(vincepri): Should we validate CONNECT requests? In what cases?
+ case v1.Create:
+ if err = h.decoder.Decode(req, obj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ warnings, err = obj.ValidateCreate()
+ case v1.Update:
+ oldObj := obj.DeepCopyObject()
+
+ err = h.decoder.DecodeRaw(req.Object, obj)
+ if err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+ err = h.decoder.DecodeRaw(req.OldObject, oldObj)
+ if err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ warnings, err = obj.ValidateUpdate(oldObj)
+ case v1.Delete:
+ // In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346
+ // OldObject contains the object being deleted
+ err = h.decoder.DecodeRaw(req.OldObject, obj)
+ if err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ warnings, err = obj.ValidateDelete()
+ default:
+ return Errored(http.StatusBadRequest, fmt.Errorf("unknown operation %q", req.Operation))
+ }
+
+ if err != nil {
+ var apiStatus apierrors.APIStatus
+ if errors.As(err, &apiStatus) {
+ return validationResponseFromStatus(false, apiStatus.Status()).WithWarnings(warnings...)
+ }
+ return Denied(err.Error()).WithWarnings(warnings...)
+ }
+ return Allowed("").WithWarnings(warnings...)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
new file mode 100644
index 00000000000..e99fbd8a857
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
@@ -0,0 +1,126 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+
+ v1 "k8s.io/api/admission/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// CustomValidator defines functions for validating an operation.
+// The object to be validated is passed into methods as a parameter.
+type CustomValidator interface {
+
+ // ValidateCreate validates the object on creation.
+ // The optional warnings will be added to the response as warning messages.
+ // Return an error if the object is invalid.
+ ValidateCreate(ctx context.Context, obj runtime.Object) (warnings Warnings, err error)
+
+ // ValidateUpdate validates the object on update.
+ // The optional warnings will be added to the response as warning messages.
+ // Return an error if the object is invalid.
+ ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (warnings Warnings, err error)
+
+ // ValidateDelete validates the object on deletion.
+ // The optional warnings will be added to the response as warning messages.
+ // Return an error if the object is invalid.
+ ValidateDelete(ctx context.Context, obj runtime.Object) (warnings Warnings, err error)
+}
+
+// WithCustomValidator creates a new Webhook for validating the provided type.
+func WithCustomValidator(scheme *runtime.Scheme, obj runtime.Object, validator CustomValidator) *Webhook {
+ return &Webhook{
+ Handler: &validatorForType{object: obj, validator: validator, decoder: NewDecoder(scheme)},
+ }
+}
+
+type validatorForType struct {
+ validator CustomValidator
+ object runtime.Object
+ decoder *Decoder
+}
+
+// Handle handles admission requests.
+func (h *validatorForType) Handle(ctx context.Context, req Request) Response {
+ if h.decoder == nil {
+ panic("decoder should never be nil")
+ }
+ if h.validator == nil {
+ panic("validator should never be nil")
+ }
+ if h.object == nil {
+ panic("object should never be nil")
+ }
+
+ ctx = NewContextWithRequest(ctx, req)
+
+ // Get the object in the request
+ obj := h.object.DeepCopyObject()
+
+ var err error
+ var warnings []string
+
+ switch req.Operation {
+ case v1.Connect:
+ // No validation for connect requests.
+ // TODO(vincepri): Should we validate CONNECT requests? In what cases?
+ case v1.Create:
+ if err := h.decoder.Decode(req, obj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ warnings, err = h.validator.ValidateCreate(ctx, obj)
+ case v1.Update:
+ oldObj := obj.DeepCopyObject()
+ if err := h.decoder.DecodeRaw(req.Object, obj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+ if err := h.decoder.DecodeRaw(req.OldObject, oldObj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ warnings, err = h.validator.ValidateUpdate(ctx, oldObj, obj)
+ case v1.Delete:
+ // In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346
+ // OldObject contains the object being deleted
+ if err := h.decoder.DecodeRaw(req.OldObject, obj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ warnings, err = h.validator.ValidateDelete(ctx, obj)
+ default:
+ return Errored(http.StatusBadRequest, fmt.Errorf("unknown operation %q", req.Operation))
+ }
+
+ // Check the error message first.
+ if err != nil {
+ var apiStatus apierrors.APIStatus
+ if errors.As(err, &apiStatus) {
+ return validationResponseFromStatus(false, apiStatus.Status()).WithWarnings(warnings...)
+ }
+ return Denied(err.Error()).WithWarnings(warnings...)
+ }
+
+ // Return allowed if everything succeeded.
+ return Allowed("").WithWarnings(warnings...)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_test.go
new file mode 100644
index 00000000000..404fad90163
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_test.go
@@ -0,0 +1,494 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "context"
+ "errors"
+ "net/http"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ admissionv1 "k8s.io/api/admission/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/client-go/kubernetes/scheme"
+)
+
+var fakeValidatorVK = schema.GroupVersionKind{Group: "foo.test.org", Version: "v1", Kind: "fakeValidator"}
+
+var _ = Describe("validatingHandler", func() {
+
+ decoder := NewDecoder(scheme.Scheme)
+
+ Context("when dealing with successful results without warning", func() {
+ f := &fakeValidator{ErrorToReturn: nil, GVKToReturn: fakeValidatorVK, WarningsToReturn: nil}
+ handler := validatingHandler{validator: f, decoder: decoder}
+
+ It("should return 200 in response when create succeeds", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Create,
+ Object: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+
+ Expect(response.Allowed).Should(BeTrue())
+ Expect(response.Result.Code).Should(Equal(int32(http.StatusOK)))
+ })
+
+ It("should return 200 in response when update succeeds", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Update,
+ Object: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+ Expect(response.Allowed).Should(BeTrue())
+ Expect(response.Result.Code).Should(Equal(int32(http.StatusOK)))
+ })
+
+ It("should return 200 in response when delete succeeds", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Delete,
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+ Expect(response.Allowed).Should(BeTrue())
+ Expect(response.Result.Code).Should(Equal(int32(http.StatusOK)))
+ })
+ })
+
+ const warningMessage = "warning message"
+ const anotherWarningMessage = "another warning message"
+ Context("when dealing with successful results with warning", func() {
+ f := &fakeValidator{ErrorToReturn: nil, GVKToReturn: fakeValidatorVK, WarningsToReturn: []string{
+ warningMessage,
+ anotherWarningMessage,
+ }}
+ handler := validatingHandler{validator: f, decoder: decoder}
+
+ It("should return 200 in response when create succeeds, with warning messages", func() {
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Create,
+ Object: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+
+ Expect(response.Allowed).Should(BeTrue())
+ Expect(response.Result.Code).Should(Equal(int32(http.StatusOK)))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElement(warningMessage))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElement(anotherWarningMessage))
+ })
+
+ It("should return 200 in response when update succeeds, with warning messages", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Update,
+ Object: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+ Expect(response.Allowed).Should(BeTrue())
+ Expect(response.Result.Code).Should(Equal(int32(http.StatusOK)))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElement(warningMessage))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElement(anotherWarningMessage))
+ })
+
+ It("should return 200 in response when delete succeeds, with warning messages", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Delete,
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+ Expect(response.Allowed).Should(BeTrue())
+ Expect(response.Result.Code).Should(Equal(int32(http.StatusOK)))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElement(warningMessage))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElement(anotherWarningMessage))
+ })
+ })
+
+ Context("when dealing with Status errors, with warning messages", func() {
+ // Status error would overwrite the warning messages, so no warning messages should be observed.
+ expectedError := &apierrors.StatusError{
+ ErrStatus: metav1.Status{
+ Message: "some message",
+ Code: http.StatusUnprocessableEntity,
+ },
+ }
+ f := &fakeValidator{ErrorToReturn: expectedError, GVKToReturn: fakeValidatorVK, WarningsToReturn: []string{warningMessage, anotherWarningMessage}}
+ handler := validatingHandler{validator: f, decoder: decoder}
+
+ It("should propagate the Status from ValidateCreate's return value to the HTTP response", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Create,
+ Object: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+
+ Expect(response.Allowed).Should(BeFalse())
+ Expect(response.Result.Code).Should(Equal(expectedError.Status().Code))
+ Expect(*response.Result).Should(Equal(expectedError.Status()))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElements(warningMessage))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElements(anotherWarningMessage))
+
+ })
+
+ It("should propagate the Status from ValidateUpdate's return value to the HTTP response", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Update,
+ Object: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+
+ Expect(response.Allowed).Should(BeFalse())
+ Expect(response.Result.Code).Should(Equal(expectedError.Status().Code))
+ Expect(*response.Result).Should(Equal(expectedError.Status()))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElements(warningMessage))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElements(anotherWarningMessage))
+
+ })
+
+ It("should propagate the Status from ValidateDelete's return value to the HTTP response", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Delete,
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+
+ Expect(response.Allowed).Should(BeFalse())
+ Expect(response.Result.Code).Should(Equal(expectedError.Status().Code))
+ Expect(*response.Result).Should(Equal(expectedError.Status()))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElements(warningMessage))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElements(anotherWarningMessage))
+
+ })
+
+ })
+
+ Context("when dealing with Status errors, without warning messages", func() {
+
+ expectedError := &apierrors.StatusError{
+ ErrStatus: metav1.Status{
+ Message: "some message",
+ Code: http.StatusUnprocessableEntity,
+ },
+ }
+ f := &fakeValidator{ErrorToReturn: expectedError, GVKToReturn: fakeValidatorVK, WarningsToReturn: nil}
+ handler := validatingHandler{validator: f, decoder: decoder}
+
+ It("should propagate the Status from ValidateCreate's return value to the HTTP response", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Create,
+ Object: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+
+ Expect(response.Allowed).Should(BeFalse())
+ Expect(response.Result.Code).Should(Equal(expectedError.Status().Code))
+ Expect(*response.Result).Should(Equal(expectedError.Status()))
+
+ })
+
+ It("should propagate the Status from ValidateUpdate's return value to the HTTP response", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Update,
+ Object: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+
+ Expect(response.Allowed).Should(BeFalse())
+ Expect(response.Result.Code).Should(Equal(expectedError.Status().Code))
+ Expect(*response.Result).Should(Equal(expectedError.Status()))
+
+ })
+
+ It("should propagate the Status from ValidateDelete's return value to the HTTP response", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Delete,
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+
+ Expect(response.Allowed).Should(BeFalse())
+ Expect(response.Result.Code).Should(Equal(expectedError.Status().Code))
+ Expect(*response.Result).Should(Equal(expectedError.Status()))
+
+ })
+
+ })
+
+ Context("when dealing with non-status errors, without warning messages", func() {
+
+ expectedError := errors.New("some error")
+ f := &fakeValidator{ErrorToReturn: expectedError, GVKToReturn: fakeValidatorVK}
+ handler := validatingHandler{validator: f, decoder: decoder}
+
+ It("should return 403 response when ValidateCreate with error message embedded", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Create,
+ Object: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+ Expect(response.Allowed).Should(BeFalse())
+ Expect(response.Result.Code).Should(Equal(int32(http.StatusForbidden)))
+ Expect(response.Result.Reason).Should(Equal(metav1.StatusReasonForbidden))
+ Expect(response.Result.Message).Should(Equal(expectedError.Error()))
+
+ })
+
+ It("should return 403 response when ValidateUpdate returns non-APIStatus error", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Update,
+ Object: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+ Expect(response.Allowed).Should(BeFalse())
+ Expect(response.Result.Code).Should(Equal(int32(http.StatusForbidden)))
+ Expect(response.Result.Reason).Should(Equal(metav1.StatusReasonForbidden))
+ Expect(response.Result.Message).Should(Equal(expectedError.Error()))
+
+ })
+
+ It("should return 403 response when ValidateDelete returns non-APIStatus error", func() {
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Delete,
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+ Expect(response.Allowed).Should(BeFalse())
+ Expect(response.Result.Code).Should(Equal(int32(http.StatusForbidden)))
+ Expect(response.Result.Reason).Should(Equal(metav1.StatusReasonForbidden))
+ Expect(response.Result.Message).Should(Equal(expectedError.Error()))
+ })
+ })
+
+ Context("when dealing with non-status errors, with warning messages", func() {
+
+ expectedError := errors.New("some error")
+ f := &fakeValidator{ErrorToReturn: expectedError, GVKToReturn: fakeValidatorVK, WarningsToReturn: []string{warningMessage, anotherWarningMessage}}
+ handler := validatingHandler{validator: f, decoder: decoder}
+
+ It("should return 403 response when ValidateCreate with error message embedded", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Create,
+ Object: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+ Expect(response.Allowed).Should(BeFalse())
+ Expect(response.Result.Code).Should(Equal(int32(http.StatusForbidden)))
+ Expect(response.Result.Reason).Should(Equal(metav1.StatusReasonForbidden))
+ Expect(response.Result.Message).Should(Equal(expectedError.Error()))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElement(warningMessage))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElement(anotherWarningMessage))
+ })
+
+ It("should return 403 response when ValidateUpdate returns non-APIStatus error", func() {
+
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Update,
+ Object: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+ Expect(response.Allowed).Should(BeFalse())
+ Expect(response.Result.Code).Should(Equal(int32(http.StatusForbidden)))
+ Expect(response.Result.Reason).Should(Equal(metav1.StatusReasonForbidden))
+ Expect(response.Result.Message).Should(Equal(expectedError.Error()))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElement(warningMessage))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElement(anotherWarningMessage))
+
+ })
+
+ It("should return 403 response when ValidateDelete returns non-APIStatus error", func() {
+ response := handler.Handle(context.TODO(), Request{
+ AdmissionRequest: admissionv1.AdmissionRequest{
+ Operation: admissionv1.Delete,
+ OldObject: runtime.RawExtension{
+ Raw: []byte("{}"),
+ Object: handler.validator,
+ },
+ },
+ })
+ Expect(response.Allowed).Should(BeFalse())
+ Expect(response.Result.Code).Should(Equal(int32(http.StatusForbidden)))
+ Expect(response.Result.Reason).Should(Equal(metav1.StatusReasonForbidden))
+ Expect(response.Result.Message).Should(Equal(expectedError.Error()))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElement(warningMessage))
+ Expect(response.AdmissionResponse.Warnings).Should(ContainElement(anotherWarningMessage))
+
+ })
+ })
+
+ PIt("should return 400 in response when create fails on decode", func() {})
+
+ PIt("should return 400 in response when update fails on decoding new object", func() {})
+
+ PIt("should return 400 in response when update fails on decoding old object", func() {})
+
+ PIt("should return 400 in response when delete fails on decode", func() {})
+
+})
+
+// fakeValidator provides fake validating webhook functionality for testing
+// It implements the admission.Validator interface and
+// rejects all requests with the same configured error
+// or passes if ErrorToReturn is nil.
+// And it would always return configured warning messages WarningsToReturn.
+type fakeValidator struct {
+ // ErrorToReturn is the error for which the fakeValidator rejects all requests
+ ErrorToReturn error `json:"errorToReturn,omitempty"`
+ // GVKToReturn is the GroupVersionKind that the webhook operates on
+ GVKToReturn schema.GroupVersionKind
+ // WarningsToReturn is the warnings for fakeValidator returns to all requests
+ WarningsToReturn []string
+}
+
+func (v *fakeValidator) ValidateCreate() (warnings Warnings, err error) {
+ return v.WarningsToReturn, v.ErrorToReturn
+}
+
+func (v *fakeValidator) ValidateUpdate(old runtime.Object) (warnings Warnings, err error) {
+ return v.WarningsToReturn, v.ErrorToReturn
+}
+
+func (v *fakeValidator) ValidateDelete() (warnings Warnings, err error) {
+ return v.WarningsToReturn, v.ErrorToReturn
+}
+
+func (v *fakeValidator) SetGroupVersionKind(gvk schema.GroupVersionKind) {
+ v.GVKToReturn = gvk
+}
+
+func (v *fakeValidator) GroupVersionKind() schema.GroupVersionKind {
+ return v.GVKToReturn
+}
+
+func (v *fakeValidator) GetObjectKind() schema.ObjectKind {
+ return v
+}
+
+func (v *fakeValidator) DeepCopyObject() runtime.Object {
+ return &fakeValidator{
+ ErrorToReturn: v.ErrorToReturn,
+ GVKToReturn: v.GVKToReturn,
+ WarningsToReturn: v.WarningsToReturn,
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
new file mode 100644
index 00000000000..f1767f31b2e
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
@@ -0,0 +1,251 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "sync"
+
+ "github.com/go-logr/logr"
+ "gomodules.xyz/jsonpatch/v2"
+ admissionv1 "k8s.io/api/admission/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/util/json"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+ "k8s.io/klog/v2"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
+)
+
+var (
+ errUnableToEncodeResponse = errors.New("unable to encode response")
+)
+
+// Request defines the input for an admission handler.
+// It contains information to identify the object in
+// question (group, version, kind, resource, subresource,
+// name, namespace), as well as the operation in question
+// (e.g. Get, Create, etc), and the object itself.
+type Request struct {
+ admissionv1.AdmissionRequest
+}
+
+// Response is the output of an admission handler.
+// It contains a response indicating if a given
+// operation is allowed, as well as a set of patches
+// to mutate the object in the case of a mutating admission handler.
+type Response struct {
+ // Patches are the JSON patches for mutating webhooks.
+ // Using this instead of setting Response.Patch to minimize
+ // overhead of serialization and deserialization.
+ // Patches set here will override any patches in the response,
+ // so leave this empty if you want to set the patch response directly.
+ Patches []jsonpatch.JsonPatchOperation
+ // AdmissionResponse is the raw admission response.
+ // The Patch field in it will be overwritten by the listed patches.
+ admissionv1.AdmissionResponse
+}
+
+// Complete populates any fields that are yet to be set in
+// the underlying AdmissionResponse, It mutates the response.
+func (r *Response) Complete(req Request) error {
+ r.UID = req.UID
+
+ // ensure that we have a valid status code
+ if r.Result == nil {
+ r.Result = &metav1.Status{}
+ }
+ if r.Result.Code == 0 {
+ r.Result.Code = http.StatusOK
+ }
+ // TODO(directxman12): do we need to populate this further, and/or
+ // is code actually necessary (the same webhook doesn't use it)
+
+ if len(r.Patches) == 0 {
+ return nil
+ }
+
+ var err error
+ r.Patch, err = json.Marshal(r.Patches)
+ if err != nil {
+ return err
+ }
+ patchType := admissionv1.PatchTypeJSONPatch
+ r.PatchType = &patchType
+
+ return nil
+}
+
+// Handler can handle an AdmissionRequest.
+type Handler interface {
+ // Handle yields a response to an AdmissionRequest.
+ //
+ // The supplied context is extracted from the received http.Request, allowing wrapping
+ // http.Handlers to inject values into and control cancelation of downstream request processing.
+ Handle(context.Context, Request) Response
+}
+
+// HandlerFunc implements Handler interface using a single function.
+type HandlerFunc func(context.Context, Request) Response
+
+var _ Handler = HandlerFunc(nil)
+
+// Handle process the AdmissionRequest by invoking the underlying function.
+func (f HandlerFunc) Handle(ctx context.Context, req Request) Response {
+ return f(ctx, req)
+}
+
+// Webhook represents each individual webhook.
+//
+// It must be registered with a webhook.Server or
+// populated by StandaloneWebhook to be ran on an arbitrary HTTP server.
+type Webhook struct {
+ // Handler actually processes an admission request returning whether it was allowed or denied,
+ // and potentially patches to apply to the handler.
+ Handler Handler
+
+ // RecoverPanic indicates whether the panic caused by webhook should be recovered.
+ RecoverPanic bool
+
+ // WithContextFunc will allow you to take the http.Request.Context() and
+ // add any additional information such as passing the request path or
+ // headers thus allowing you to read them from within the handler
+ WithContextFunc func(context.Context, *http.Request) context.Context
+
+ // LogConstructor is used to construct a logger for logging messages during webhook calls
+ // based on the given base logger (which might carry more values like the webhook's path).
+ // Note: LogConstructor has to be able to handle nil requests as we are also using it
+ // outside the context of requests.
+ LogConstructor func(base logr.Logger, req *Request) logr.Logger
+
+ setupLogOnce sync.Once
+ log logr.Logger
+}
+
+// WithRecoverPanic takes a bool flag which indicates whether the panic caused by webhook should be recovered.
+func (wh *Webhook) WithRecoverPanic(recoverPanic bool) *Webhook {
+ wh.RecoverPanic = recoverPanic
+ return wh
+}
+
+// Handle processes AdmissionRequest.
+// If the webhook is mutating type, it delegates the AdmissionRequest to each handler and merge the patches.
+// If the webhook is validating type, it delegates the AdmissionRequest to each handler and
+// deny the request if anyone denies.
+func (wh *Webhook) Handle(ctx context.Context, req Request) (response Response) {
+ if wh.RecoverPanic {
+ defer func() {
+ if r := recover(); r != nil {
+ for _, fn := range utilruntime.PanicHandlers {
+ fn(r)
+ }
+ response = Errored(http.StatusInternalServerError, fmt.Errorf("panic: %v [recovered]", r))
+ return
+ }
+ }()
+ }
+
+ reqLog := wh.getLogger(&req)
+ ctx = logf.IntoContext(ctx, reqLog)
+
+ resp := wh.Handler.Handle(ctx, req)
+ if err := resp.Complete(req); err != nil {
+ reqLog.Error(err, "unable to encode response")
+ return Errored(http.StatusInternalServerError, errUnableToEncodeResponse)
+ }
+
+ return resp
+}
+
+// getLogger constructs a logger from the injected log and LogConstructor.
+func (wh *Webhook) getLogger(req *Request) logr.Logger {
+ wh.setupLogOnce.Do(func() {
+ if wh.log.GetSink() == nil {
+ wh.log = logf.Log.WithName("admission")
+ }
+ })
+
+ logConstructor := wh.LogConstructor
+ if logConstructor == nil {
+ logConstructor = DefaultLogConstructor
+ }
+ return logConstructor(wh.log, req)
+}
+
+// DefaultLogConstructor adds some commonly interesting fields to the given logger.
+func DefaultLogConstructor(base logr.Logger, req *Request) logr.Logger {
+ if req != nil {
+ return base.WithValues("object", klog.KRef(req.Namespace, req.Name),
+ "namespace", req.Namespace, "name", req.Name,
+ "resource", req.Resource, "user", req.UserInfo.Username,
+ "requestID", req.UID,
+ )
+ }
+ return base
+}
+
+// StandaloneOptions let you configure a StandaloneWebhook.
+type StandaloneOptions struct {
+ // Logger to be used by the webhook.
+ // If none is set, it defaults to log.Log global logger.
+ Logger logr.Logger
+ // MetricsPath is used for labelling prometheus metrics
+ // by the path is served on.
+ // If none is set, prometheus metrics will not be generated.
+ MetricsPath string
+}
+
+// StandaloneWebhook prepares a webhook for use without a webhook.Server,
+// passing in the information normally populated by webhook.Server
+// and instrumenting the webhook with metrics.
+//
+// Use this to attach your webhook to an arbitrary HTTP server or mux.
+//
+// Note that you are responsible for terminating TLS if you use StandaloneWebhook
+// in your own server/mux. In order to be accessed by a kubernetes cluster,
+// all webhook servers require TLS.
+func StandaloneWebhook(hook *Webhook, opts StandaloneOptions) (http.Handler, error) {
+ if opts.Logger.GetSink() != nil {
+ hook.log = opts.Logger
+ }
+ if opts.MetricsPath == "" {
+ return hook, nil
+ }
+ return metrics.InstrumentedHook(opts.MetricsPath, hook), nil
+}
+
+// requestContextKey is how we find the admission.Request in a context.Context.
+type requestContextKey struct{}
+
+// RequestFromContext returns an admission.Request from ctx.
+func RequestFromContext(ctx context.Context) (Request, error) {
+ if v, ok := ctx.Value(requestContextKey{}).(Request); ok {
+ return v, nil
+ }
+
+ return Request{}, errors.New("admission.Request not found in context")
+}
+
+// NewContextWithRequest returns a new Context, derived from ctx, which carries the
+// provided admission.Request.
+func NewContextWithRequest(ctx context.Context, req Request) context.Context {
+ return context.WithValue(ctx, requestContextKey{}, req)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook_test.go
new file mode 100644
index 00000000000..c7fc3b09ace
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook_test.go
@@ -0,0 +1,268 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package admission
+
+import (
+ "context"
+ "io"
+ "net/http"
+
+ "github.com/go-logr/logr"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/onsi/gomega/gbytes"
+ "gomodules.xyz/jsonpatch/v2"
+ admissionv1 "k8s.io/api/admission/v1"
+ authenticationv1 "k8s.io/api/authentication/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ machinerytypes "k8s.io/apimachinery/pkg/types"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+var _ = Describe("Admission Webhooks", func() {
+ var (
+ logBuffer *gbytes.Buffer
+ testLogger logr.Logger
+ )
+
+ BeforeEach(func() {
+ logBuffer = gbytes.NewBuffer()
+ testLogger = zap.New(zap.JSONEncoder(), zap.WriteTo(io.MultiWriter(logBuffer, GinkgoWriter)))
+ })
+
+ allowHandler := func() *Webhook {
+ handler := &fakeHandler{
+ fn: func(ctx context.Context, req Request) Response {
+ return Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ },
+ }
+ },
+ }
+ webhook := &Webhook{
+ Handler: handler,
+ }
+
+ return webhook
+ }
+
+ It("should invoke the handler to get a response", func() {
+ By("setting up a webhook with an allow handler")
+ webhook := allowHandler()
+
+ By("invoking the webhook")
+ resp := webhook.Handle(context.Background(), Request{})
+
+ By("checking that it allowed the request")
+ Expect(resp.Allowed).To(BeTrue())
+ })
+
+ It("should ensure that the response's UID is set to the request's UID", func() {
+ By("setting up a webhook")
+ webhook := allowHandler()
+
+ By("invoking the webhook")
+ resp := webhook.Handle(context.Background(), Request{AdmissionRequest: admissionv1.AdmissionRequest{UID: "foobar"}})
+
+ By("checking that the response share's the request's UID")
+ Expect(resp.UID).To(Equal(machinerytypes.UID("foobar")))
+ })
+
+ It("should populate the status on a response if one is not provided", func() {
+ By("setting up a webhook")
+ webhook := allowHandler()
+
+ By("invoking the webhook")
+ resp := webhook.Handle(context.Background(), Request{})
+
+ By("checking that the response share's the request's UID")
+ Expect(resp.Result).To(Equal(&metav1.Status{Code: http.StatusOK}))
+ })
+
+ It("shouldn't overwrite the status on a response", func() {
+ By("setting up a webhook that sets a status")
+ webhook := &Webhook{
+ Handler: HandlerFunc(func(ctx context.Context, req Request) Response {
+ return Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{Message: "Ground Control to Major Tom"},
+ },
+ }
+ }),
+ }
+
+ By("invoking the webhook")
+ resp := webhook.Handle(context.Background(), Request{})
+
+ By("checking that the message is intact")
+ Expect(resp.Result).NotTo(BeNil())
+ Expect(resp.Result.Message).To(Equal("Ground Control to Major Tom"))
+ })
+
+ It("should serialize patch operations into a single jsonpatch blob", func() {
+ By("setting up a webhook with a patching handler")
+ webhook := &Webhook{
+ Handler: HandlerFunc(func(ctx context.Context, req Request) Response {
+ return Patched("", jsonpatch.Operation{Operation: "add", Path: "/a", Value: 2}, jsonpatch.Operation{Operation: "replace", Path: "/b", Value: 4})
+ }),
+ }
+
+ By("invoking the webhook")
+ resp := webhook.Handle(context.Background(), Request{})
+
+ By("checking that a JSON patch is populated on the response")
+ patchType := admissionv1.PatchTypeJSONPatch
+ Expect(resp.PatchType).To(Equal(&patchType))
+ Expect(resp.Patch).To(Equal([]byte(`[{"op":"add","path":"/a","value":2},{"op":"replace","path":"/b","value":4}]`)))
+ })
+
+ It("should pass a request logger via the context", func() {
+ By("setting up a webhook that uses the request logger")
+ webhook := &Webhook{
+ Handler: HandlerFunc(func(ctx context.Context, req Request) Response {
+ logf.FromContext(ctx).Info("Received request")
+
+ return Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ },
+ }
+ }),
+ log: testLogger,
+ }
+
+ By("invoking the webhook")
+ resp := webhook.Handle(context.Background(), Request{AdmissionRequest: admissionv1.AdmissionRequest{
+ UID: "test123",
+ Name: "foo",
+ Namespace: "bar",
+ Resource: metav1.GroupVersionResource{
+ Group: "apps",
+ Version: "v1",
+ Resource: "deployments",
+ },
+ UserInfo: authenticationv1.UserInfo{
+ Username: "tim",
+ },
+ }})
+ Expect(resp.Allowed).To(BeTrue())
+
+ By("checking that the log message contains the request fields")
+ Eventually(logBuffer).Should(gbytes.Say(`"msg":"Received request","object":{"name":"foo","namespace":"bar"},"namespace":"bar","name":"foo","resource":{"group":"apps","version":"v1","resource":"deployments"},"user":"tim","requestID":"test123"}`))
+ })
+
+ It("should pass a request logger created by LogConstructor via the context", func() {
+ By("setting up a webhook that uses the request logger")
+ webhook := &Webhook{
+ Handler: HandlerFunc(func(ctx context.Context, req Request) Response {
+ logf.FromContext(ctx).Info("Received request")
+
+ return Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ },
+ }
+ }),
+ LogConstructor: func(base logr.Logger, req *Request) logr.Logger {
+ return base.WithValues("operation", req.Operation, "requestID", req.UID)
+ },
+ log: testLogger,
+ }
+
+ By("invoking the webhook")
+ resp := webhook.Handle(context.Background(), Request{AdmissionRequest: admissionv1.AdmissionRequest{
+ UID: "test123",
+ Operation: admissionv1.Create,
+ }})
+ Expect(resp.Allowed).To(BeTrue())
+
+ By("checking that the log message contains the request fields")
+ Eventually(logBuffer).Should(gbytes.Say(`"msg":"Received request","operation":"CREATE","requestID":"test123"}`))
+ })
+
+ Describe("panic recovery", func() {
+ It("should recover panic if RecoverPanic is true", func() {
+ panicHandler := func() *Webhook {
+ handler := &fakeHandler{
+ fn: func(ctx context.Context, req Request) Response {
+ panic("fake panic test")
+ },
+ }
+ webhook := &Webhook{
+ Handler: handler,
+ RecoverPanic: true,
+ }
+
+ return webhook
+ }
+
+ By("setting up a webhook with a panicking handler")
+ webhook := panicHandler()
+
+ By("invoking the webhook")
+ resp := webhook.Handle(context.Background(), Request{})
+
+ By("checking that it errored the request")
+ Expect(resp.Allowed).To(BeFalse())
+ Expect(resp.Result.Code).To(Equal(int32(http.StatusInternalServerError)))
+ Expect(resp.Result.Message).To(Equal("panic: fake panic test [recovered]"))
+ })
+
+ It("should not recover panic if RecoverPanic is false by default", func() {
+ panicHandler := func() *Webhook {
+ handler := &fakeHandler{
+ fn: func(ctx context.Context, req Request) Response {
+ panic("fake panic test")
+ },
+ }
+ webhook := &Webhook{
+ Handler: handler,
+ }
+
+ return webhook
+ }
+
+ By("setting up a webhook with a panicking handler")
+ defer func() {
+ Expect(recover()).ShouldNot(BeNil())
+ }()
+ webhook := panicHandler()
+
+ By("invoking the webhook")
+ webhook.Handle(context.Background(), Request{})
+ })
+ })
+})
+
+var _ = Describe("Should be able to write/read admission.Request to/from context", func() {
+ ctx := context.Background()
+ testRequest := Request{
+ admissionv1.AdmissionRequest{
+ UID: "test-uid",
+ },
+ }
+
+ ctx = NewContextWithRequest(ctx, testRequest)
+
+ gotRequest, err := RequestFromContext(ctx)
+ Expect(err).To(Not(HaveOccurred()))
+ Expect(gotRequest).To(Equal(testRequest))
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go
new file mode 100644
index 00000000000..293137db498
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package webhook
+
+import (
+ "gomodules.xyz/jsonpatch/v2"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+// define some aliases for common bits of the webhook functionality
+
+// Defaulter defines functions for setting defaults on resources.
+type Defaulter = admission.Defaulter
+
+// Validator defines functions for validating an operation.
+type Validator = admission.Validator
+
+// CustomDefaulter defines functions for setting defaults on resources.
+type CustomDefaulter = admission.CustomDefaulter
+
+// CustomValidator defines functions for validating an operation.
+type CustomValidator = admission.CustomValidator
+
+// AdmissionRequest defines the input for an admission handler.
+// It contains information to identify the object in
+// question (group, version, kind, resource, subresource,
+// name, namespace), as well as the operation in question
+// (e.g. Get, Create, etc), and the object itself.
+type AdmissionRequest = admission.Request
+
+// AdmissionResponse is the output of an admission handler.
+// It contains a response indicating if a given
+// operation is allowed, as well as a set of patches
+// to mutate the object in the case of a mutating admission handler.
+type AdmissionResponse = admission.Response
+
+// Admission is webhook suitable for registration with the server
+// an admission webhook that validates API operations and potentially
+// mutates their contents.
+type Admission = admission.Webhook
+
+// AdmissionHandler knows how to process admission requests, validating them,
+// and potentially mutating the objects they contain.
+type AdmissionHandler = admission.Handler
+
+// AdmissionDecoder knows how to decode objects from admission requests.
+type AdmissionDecoder = admission.Decoder
+
+// JSONPatchOp represents a single JSONPatch patch operation.
+type JSONPatchOp = jsonpatch.Operation
+
+var (
+ // Allowed indicates that the admission request should be allowed for the given reason.
+ Allowed = admission.Allowed
+
+ // Denied indicates that the admission request should be denied for the given reason.
+ Denied = admission.Denied
+
+ // Patched indicates that the admission request should be allowed for the given reason,
+ // and that the contained object should be mutated using the given patches.
+ Patched = admission.Patched
+
+ // Errored indicates that an error occurred in the admission request.
+ Errored = admission.Errored
+)
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/authentication_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/authentication_suite_test.go
new file mode 100644
index 00000000000..29f7b3e17e8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/authentication_suite_test.go
@@ -0,0 +1,36 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package authentication
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestAuthenticationWebhook(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Authentication Webhook Suite")
+}
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/doc.go
new file mode 100644
index 00000000000..d2b85f378c5
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/doc.go
@@ -0,0 +1,23 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package authentication provides implementation for authentication webhook and
+methods to implement authentication webhook handlers.
+
+See examples/tokenreview/ for an example of authentication webhooks.
+*/
+package authentication
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/http.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/http.go
new file mode 100644
index 00000000000..51bc93ee195
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/http.go
@@ -0,0 +1,146 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package authentication
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+
+ authenticationv1 "k8s.io/api/authentication/v1"
+ authenticationv1beta1 "k8s.io/api/authentication/v1beta1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+)
+
+var authenticationScheme = runtime.NewScheme()
+var authenticationCodecs = serializer.NewCodecFactory(authenticationScheme)
+
+func init() {
+ utilruntime.Must(authenticationv1.AddToScheme(authenticationScheme))
+ utilruntime.Must(authenticationv1beta1.AddToScheme(authenticationScheme))
+}
+
+var _ http.Handler = &Webhook{}
+
+func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ var body []byte
+ var err error
+ ctx := r.Context()
+ if wh.WithContextFunc != nil {
+ ctx = wh.WithContextFunc(ctx, r)
+ }
+
+ var reviewResponse Response
+ if r.Body == nil {
+ err = errors.New("request body is empty")
+ wh.getLogger(nil).Error(err, "bad request")
+ reviewResponse = Errored(err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+
+ defer r.Body.Close()
+ if body, err = io.ReadAll(r.Body); err != nil {
+ wh.getLogger(nil).Error(err, "unable to read the body from the incoming request")
+ reviewResponse = Errored(err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+
+ // verify the content type is accurate
+ if contentType := r.Header.Get("Content-Type"); contentType != "application/json" {
+ err = fmt.Errorf("contentType=%s, expected application/json", contentType)
+ wh.getLogger(nil).Error(err, "unable to process a request with unknown content type")
+ reviewResponse = Errored(err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+
+ // Both v1 and v1beta1 TokenReview types are exactly the same, so the v1beta1 type can
+ // be decoded into the v1 type. The v1beta1 api is deprecated as of 1.19 and will be
+ // removed in authenticationv1.22. However the runtime codec's decoder guesses which type to
+ // decode into by type name if an Object's TypeMeta isn't set. By setting TypeMeta of an
+ // unregistered type to the v1 GVK, the decoder will coerce a v1beta1 TokenReview to authenticationv1.
+ // The actual TokenReview GVK will be used to write a typed response in case the
+ // webhook config permits multiple versions, otherwise this response will fail.
+ req := Request{}
+ ar := unversionedTokenReview{}
+ // avoid an extra copy
+ ar.TokenReview = &req.TokenReview
+ ar.SetGroupVersionKind(authenticationv1.SchemeGroupVersion.WithKind("TokenReview"))
+ _, actualTokRevGVK, err := authenticationCodecs.UniversalDeserializer().Decode(body, nil, &ar)
+ if err != nil {
+ wh.getLogger(nil).Error(err, "unable to decode the request")
+ reviewResponse = Errored(err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+ wh.getLogger(&req).V(4).Info("received request")
+
+ if req.Spec.Token == "" {
+ err = errors.New("token is empty")
+ wh.getLogger(&req).Error(err, "bad request")
+ reviewResponse = Errored(err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+
+ reviewResponse = wh.Handle(ctx, req)
+ wh.writeResponseTyped(w, reviewResponse, actualTokRevGVK)
+}
+
+// writeResponse writes response to w generically, i.e. without encoding GVK information.
+func (wh *Webhook) writeResponse(w io.Writer, response Response) {
+ wh.writeTokenResponse(w, response.TokenReview)
+}
+
+// writeResponseTyped writes response to w with GVK set to tokRevGVK, which is necessary
+// if multiple TokenReview versions are permitted by the webhook.
+func (wh *Webhook) writeResponseTyped(w io.Writer, response Response, tokRevGVK *schema.GroupVersionKind) {
+ ar := response.TokenReview
+
+ // Default to a v1 TokenReview, otherwise the API server may not recognize the request
+ // if multiple TokenReview versions are permitted by the webhook config.
+ if tokRevGVK == nil || *tokRevGVK == (schema.GroupVersionKind{}) {
+ ar.SetGroupVersionKind(authenticationv1.SchemeGroupVersion.WithKind("TokenReview"))
+ } else {
+ ar.SetGroupVersionKind(*tokRevGVK)
+ }
+ wh.writeTokenResponse(w, ar)
+}
+
+// writeTokenResponse writes ar to w.
+func (wh *Webhook) writeTokenResponse(w io.Writer, ar authenticationv1.TokenReview) {
+ if err := json.NewEncoder(w).Encode(ar); err != nil {
+ wh.getLogger(nil).Error(err, "unable to encode the response")
+ wh.writeResponse(w, Errored(err))
+ }
+ res := ar
+ wh.getLogger(nil).V(4).Info("wrote response", "requestID", res.UID, "authenticated", res.Status.Authenticated)
+}
+
+// unversionedTokenReview is used to decode both v1 and v1beta1 TokenReview types.
+type unversionedTokenReview struct {
+ *authenticationv1.TokenReview
+}
+
+var _ runtime.Object = &unversionedTokenReview{}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/http_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/http_test.go
new file mode 100644
index 00000000000..86bd5d01532
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/http_test.go
@@ -0,0 +1,208 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package authentication
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "io"
+ "net/http"
+ "net/http/httptest"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ authenticationv1 "k8s.io/api/authentication/v1"
+)
+
+var _ = Describe("Authentication Webhooks", func() {
+
+ const (
+ gvkJSONv1 = `"kind":"TokenReview","apiVersion":"authentication.k8s.io/v1"`
+ )
+
+ Describe("HTTP Handler", func() {
+ var respRecorder *httptest.ResponseRecorder
+ webhook := &Webhook{
+ Handler: nil,
+ }
+ BeforeEach(func() {
+ respRecorder = &httptest.ResponseRecorder{
+ Body: bytes.NewBuffer(nil),
+ }
+ })
+
+ It("should return bad-request when given an empty body", func() {
+ req := &http.Request{Body: nil}
+
+ expected := `{"metadata":{"creationTimestamp":null},"spec":{},"status":{"user":{},"error":"request body is empty"}}
+`
+ webhook.ServeHTTP(respRecorder, req)
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should return bad-request when given the wrong content-type", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/foo"}},
+ Method: http.MethodPost,
+ Body: nopCloser{Reader: bytes.NewBuffer(nil)},
+ }
+
+ expected := `{"metadata":{"creationTimestamp":null},"spec":{},"status":{"user":{},"error":"contentType=application/foo, expected application/json"}}
+`
+ webhook.ServeHTTP(respRecorder, req)
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should return bad-request when given an undecodable body", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Method: http.MethodPost,
+ Body: nopCloser{Reader: bytes.NewBufferString("{")},
+ }
+
+ expected := `{"metadata":{"creationTimestamp":null},"spec":{},"status":{"user":{},"error":"couldn't get version/kind; json parse error: unexpected end of JSON input"}}
+`
+ webhook.ServeHTTP(respRecorder, req)
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should return bad-request when given an undecodable body", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Method: http.MethodPost,
+ Body: nopCloser{Reader: bytes.NewBufferString(`{"spec":{"token":""}}`)},
+ }
+
+ expected := `{"metadata":{"creationTimestamp":null},"spec":{},"status":{"user":{},"error":"token is empty"}}
+`
+ webhook.ServeHTTP(respRecorder, req)
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should return the response given by the handler with version defaulted to v1", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Method: http.MethodPost,
+ Body: nopCloser{Reader: bytes.NewBufferString(`{"spec":{"token":"foobar"}}`)},
+ }
+ webhook := &Webhook{
+ Handler: &fakeHandler{},
+ }
+
+ expected := fmt.Sprintf(`{%s,"metadata":{"creationTimestamp":null},"spec":{},"status":{"authenticated":true,"user":{}}}
+`, gvkJSONv1)
+
+ webhook.ServeHTTP(respRecorder, req)
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should return the v1 response given by the handler", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Method: http.MethodPost,
+ Body: nopCloser{Reader: bytes.NewBufferString(fmt.Sprintf(`{%s,"spec":{"token":"foobar"}}`, gvkJSONv1))},
+ }
+ webhook := &Webhook{
+ Handler: &fakeHandler{},
+ }
+
+ expected := fmt.Sprintf(`{%s,"metadata":{"creationTimestamp":null},"spec":{},"status":{"authenticated":true,"user":{}}}
+`, gvkJSONv1)
+ webhook.ServeHTTP(respRecorder, req)
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should present the Context from the HTTP request, if any", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Method: http.MethodPost,
+ Body: nopCloser{Reader: bytes.NewBufferString(`{"spec":{"token":"foobar"}}`)},
+ }
+ type ctxkey int
+ const key ctxkey = 1
+ const value = "from-ctx"
+ webhook := &Webhook{
+ Handler: &fakeHandler{
+ fn: func(ctx context.Context, req Request) Response {
+ <-ctx.Done()
+ return Authenticated(ctx.Value(key).(string), authenticationv1.UserInfo{})
+ },
+ },
+ }
+
+ expected := fmt.Sprintf(`{%s,"metadata":{"creationTimestamp":null},"spec":{},"status":{"authenticated":true,"user":{},"error":%q}}
+`, gvkJSONv1, value)
+
+ ctx, cancel := context.WithCancel(context.WithValue(context.Background(), key, value))
+ cancel()
+ webhook.ServeHTTP(respRecorder, req.WithContext(ctx))
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+
+ It("should mutate the Context from the HTTP request, if func supplied", func() {
+ req := &http.Request{
+ Header: http.Header{"Content-Type": []string{"application/json"}},
+ Method: http.MethodPost,
+ Body: nopCloser{Reader: bytes.NewBufferString(`{"spec":{"token":"foobar"}}`)},
+ }
+ type ctxkey int
+ const key ctxkey = 1
+ webhook := &Webhook{
+ Handler: &fakeHandler{
+ fn: func(ctx context.Context, req Request) Response {
+ return Authenticated(ctx.Value(key).(string), authenticationv1.UserInfo{})
+ },
+ },
+ WithContextFunc: func(ctx context.Context, r *http.Request) context.Context {
+ return context.WithValue(ctx, key, r.Header["Content-Type"][0])
+ },
+ }
+
+ expected := fmt.Sprintf(`{%s,"metadata":{"creationTimestamp":null},"spec":{},"status":{"authenticated":true,"user":{},"error":%q}}
+`, gvkJSONv1, "application/json")
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ webhook.ServeHTTP(respRecorder, req.WithContext(ctx))
+ Expect(respRecorder.Body.String()).To(Equal(expected))
+ })
+ })
+})
+
+type nopCloser struct {
+ io.Reader
+}
+
+func (nopCloser) Close() error { return nil }
+
+type fakeHandler struct {
+ invoked bool
+ fn func(context.Context, Request) Response
+}
+
+func (h *fakeHandler) Handle(ctx context.Context, req Request) Response {
+ h.invoked = true
+ if h.fn != nil {
+ return h.fn(ctx, req)
+ }
+ return Response{TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: true,
+ },
+ }}
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/response.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/response.go
new file mode 100644
index 00000000000..3e1d362049c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/response.go
@@ -0,0 +1,63 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package authentication
+
+import (
+ authenticationv1 "k8s.io/api/authentication/v1"
+)
+
+// Authenticated constructs a response indicating that the given token
+// is valid.
+func Authenticated(reason string, user authenticationv1.UserInfo) Response {
+ return ReviewResponse(true, user, reason)
+}
+
+// Unauthenticated constructs a response indicating that the given token
+// is not valid.
+func Unauthenticated(reason string, user authenticationv1.UserInfo) Response {
+ return ReviewResponse(false, authenticationv1.UserInfo{}, reason)
+}
+
+// Errored creates a new Response for error-handling a request.
+func Errored(err error) Response {
+ return Response{
+ TokenReview: authenticationv1.TokenReview{
+ Spec: authenticationv1.TokenReviewSpec{},
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: false,
+ Error: err.Error(),
+ },
+ },
+ }
+}
+
+// ReviewResponse returns a response for admitting a request.
+func ReviewResponse(authenticated bool, user authenticationv1.UserInfo, err string, audiences ...string) Response {
+ resp := Response{
+ TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: authenticated,
+ User: user,
+ Audiences: audiences,
+ },
+ },
+ }
+ if len(err) > 0 {
+ resp.TokenReview.Status.Error = err
+ }
+ return resp
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/response_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/response_test.go
new file mode 100644
index 00000000000..6eeef87c115
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/response_test.go
@@ -0,0 +1,160 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package authentication
+
+import (
+ "errors"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ authenticationv1 "k8s.io/api/authentication/v1"
+)
+
+var _ = Describe("Authentication Webhook Response Helpers", func() {
+ Describe("Authenticated", func() {
+ It("should return an 'allowed' response", func() {
+ Expect(Authenticated("", authenticationv1.UserInfo{})).To(Equal(
+ Response{
+ TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: true,
+ User: authenticationv1.UserInfo{},
+ },
+ },
+ },
+ ))
+ })
+
+ It("should populate a status with a reason when a reason is given", func() {
+ Expect(Authenticated("acceptable", authenticationv1.UserInfo{})).To(Equal(
+ Response{
+ TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: true,
+ User: authenticationv1.UserInfo{},
+ Error: "acceptable",
+ },
+ },
+ },
+ ))
+ })
+ })
+
+ Describe("Unauthenticated", func() {
+ It("should return a 'not allowed' response", func() {
+ Expect(Unauthenticated("", authenticationv1.UserInfo{})).To(Equal(
+ Response{
+ TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: false,
+ User: authenticationv1.UserInfo{},
+ Error: "",
+ },
+ },
+ },
+ ))
+ })
+
+ It("should populate a status with a reason when a reason is given", func() {
+ Expect(Unauthenticated("UNACCEPTABLE!", authenticationv1.UserInfo{})).To(Equal(
+ Response{
+ TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: false,
+ User: authenticationv1.UserInfo{},
+ Error: "UNACCEPTABLE!",
+ },
+ },
+ },
+ ))
+ })
+ })
+
+ Describe("Errored", func() {
+ It("should return a unauthenticated response with an error", func() {
+ err := errors.New("this is an error")
+ expected := Response{
+ TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: false,
+ User: authenticationv1.UserInfo{},
+ Error: err.Error(),
+ },
+ },
+ }
+ resp := Errored(err)
+ Expect(resp).To(Equal(expected))
+ })
+ })
+
+ Describe("ReviewResponse", func() {
+ It("should populate a status with a Error when a reason is given", func() {
+ By("checking that a message is populated for 'allowed' responses")
+ Expect(ReviewResponse(true, authenticationv1.UserInfo{}, "acceptable")).To(Equal(
+ Response{
+ TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: true,
+ User: authenticationv1.UserInfo{},
+ Error: "acceptable",
+ },
+ },
+ },
+ ))
+
+ By("checking that a message is populated for 'Unauthenticated' responses")
+ Expect(ReviewResponse(false, authenticationv1.UserInfo{}, "UNACCEPTABLE!")).To(Equal(
+ Response{
+ TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: false,
+ User: authenticationv1.UserInfo{},
+ Error: "UNACCEPTABLE!",
+ },
+ },
+ },
+ ))
+ })
+
+ It("should return an authentication decision", func() {
+ By("checking that it returns an 'allowed' response when allowed is true")
+ Expect(ReviewResponse(true, authenticationv1.UserInfo{}, "")).To(Equal(
+ Response{
+ TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: true,
+ User: authenticationv1.UserInfo{},
+ },
+ },
+ },
+ ))
+
+ By("checking that it returns an 'Unauthenticated' response when allowed is false")
+ Expect(ReviewResponse(false, authenticationv1.UserInfo{}, "")).To(Equal(
+ Response{
+ TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: false,
+ User: authenticationv1.UserInfo{},
+ },
+ },
+ },
+ ))
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/webhook.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/webhook.go
new file mode 100644
index 00000000000..5a0cd4cd25c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/webhook.go
@@ -0,0 +1,126 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package authentication
+
+import (
+ "context"
+ "errors"
+ "net/http"
+ "sync"
+
+ "github.com/go-logr/logr"
+ authenticationv1 "k8s.io/api/authentication/v1"
+ "k8s.io/klog/v2"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+var (
+ errUnableToEncodeResponse = errors.New("unable to encode response")
+)
+
+// Request defines the input for an authentication handler.
+// It contains information to identify the object in
+// question (group, version, kind, resource, subresource,
+// name, namespace), as well as the operation in question
+// (e.g. Get, Create, etc), and the object itself.
+type Request struct {
+ authenticationv1.TokenReview
+}
+
+// Response is the output of an authentication handler.
+// It contains a response indicating if a given
+// operation is allowed.
+type Response struct {
+ authenticationv1.TokenReview
+}
+
+// Complete populates any fields that are yet to be set in
+// the underlying TokenResponse, It mutates the response.
+func (r *Response) Complete(req Request) error {
+ r.UID = req.UID
+
+ return nil
+}
+
+// Handler can handle an TokenReview.
+type Handler interface {
+ // Handle yields a response to an TokenReview.
+ //
+ // The supplied context is extracted from the received http.Request, allowing wrapping
+ // http.Handlers to inject values into and control cancelation of downstream request processing.
+ Handle(context.Context, Request) Response
+}
+
+// HandlerFunc implements Handler interface using a single function.
+type HandlerFunc func(context.Context, Request) Response
+
+var _ Handler = HandlerFunc(nil)
+
+// Handle process the TokenReview by invoking the underlying function.
+func (f HandlerFunc) Handle(ctx context.Context, req Request) Response {
+ return f(ctx, req)
+}
+
+// Webhook represents each individual webhook.
+type Webhook struct {
+ // Handler actually processes an authentication request returning whether it was authenticated or unauthenticated,
+ // and potentially patches to apply to the handler.
+ Handler Handler
+
+ // WithContextFunc will allow you to take the http.Request.Context() and
+ // add any additional information such as passing the request path or
+ // headers thus allowing you to read them from within the handler
+ WithContextFunc func(context.Context, *http.Request) context.Context
+
+ setupLogOnce sync.Once
+ log logr.Logger
+}
+
+// Handle processes TokenReview.
+func (wh *Webhook) Handle(ctx context.Context, req Request) Response {
+ resp := wh.Handler.Handle(ctx, req)
+ if err := resp.Complete(req); err != nil {
+ wh.getLogger(&req).Error(err, "unable to encode response")
+ return Errored(errUnableToEncodeResponse)
+ }
+
+ return resp
+}
+
+// getLogger constructs a logger from the injected log and LogConstructor.
+func (wh *Webhook) getLogger(req *Request) logr.Logger {
+ wh.setupLogOnce.Do(func() {
+ if wh.log.GetSink() == nil {
+ wh.log = logf.Log.WithName("authentication")
+ }
+ })
+
+ return logConstructor(wh.log, req)
+}
+
+// logConstructor adds some commonly interesting fields to the given logger.
+func logConstructor(base logr.Logger, req *Request) logr.Logger {
+ if req != nil {
+ return base.WithValues("object", klog.KRef(req.Namespace, req.Name),
+ "namespace", req.Namespace, "name", req.Name,
+ "user", req.Status.User.Username,
+ "requestID", req.UID,
+ )
+ }
+ return base
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/webhook_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/webhook_test.go
new file mode 100644
index 00000000000..3df446d898f
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/authentication/webhook_test.go
@@ -0,0 +1,106 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package authentication
+
+import (
+ "context"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ authenticationv1 "k8s.io/api/authentication/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ machinerytypes "k8s.io/apimachinery/pkg/types"
+)
+
+var _ = Describe("Authentication Webhooks", func() {
+ allowHandler := func() *Webhook {
+ handler := &fakeHandler{
+ fn: func(ctx context.Context, req Request) Response {
+ return Response{
+ TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: true,
+ },
+ },
+ }
+ },
+ }
+ webhook := &Webhook{
+ Handler: handler,
+ }
+
+ return webhook
+ }
+
+ It("should invoke the handler to get a response", func() {
+ By("setting up a webhook with an allow handler")
+ webhook := allowHandler()
+
+ By("invoking the webhook")
+ resp := webhook.Handle(context.Background(), Request{})
+
+ By("checking that it allowed the request")
+ Expect(resp.Status.Authenticated).To(BeTrue())
+ })
+
+ It("should ensure that the response's UID is set to the request's UID", func() {
+ By("setting up a webhook")
+ webhook := allowHandler()
+
+ By("invoking the webhook")
+ resp := webhook.Handle(context.Background(), Request{TokenReview: authenticationv1.TokenReview{ObjectMeta: metav1.ObjectMeta{UID: "foobar"}}})
+
+ By("checking that the response share's the request's UID")
+ Expect(resp.UID).To(Equal(machinerytypes.UID("foobar")))
+ })
+
+ It("should populate the status on a response if one is not provided", func() {
+ By("setting up a webhook")
+ webhook := allowHandler()
+
+ By("invoking the webhook")
+ resp := webhook.Handle(context.Background(), Request{})
+
+ By("checking that the response share's the request's UID")
+ Expect(resp.Status).To(Equal(authenticationv1.TokenReviewStatus{Authenticated: true}))
+ })
+
+ It("shouldn't overwrite the status on a response", func() {
+ By("setting up a webhook that sets a status")
+ webhook := &Webhook{
+ Handler: HandlerFunc(func(ctx context.Context, req Request) Response {
+ return Response{
+ TokenReview: authenticationv1.TokenReview{
+ Status: authenticationv1.TokenReviewStatus{
+ Authenticated: true,
+ Error: "Ground Control to Major Tom",
+ },
+ },
+ }
+ }),
+ }
+
+ By("invoking the webhook")
+ resp := webhook.Handle(context.Background(), Request{})
+
+ By("checking that the message is intact")
+ Expect(resp.Status).NotTo(BeNil())
+ Expect(resp.Status.Authenticated).To(BeTrue())
+ Expect(resp.Status.Error).To(Equal("Ground Control to Major Tom"))
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go
new file mode 100644
index 00000000000..249a364b381
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go
@@ -0,0 +1,343 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package conversion provides implementation for CRD conversion webhook that implements handler for version conversion requests for types that are convertible.
+
+See pkg/conversion for interface definitions required to ensure an API Type is convertible.
+*/
+package conversion
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ apix "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/conversion"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+var (
+ log = logf.Log.WithName("conversion-webhook")
+)
+
+func NewWebhookHandler(scheme *runtime.Scheme) http.Handler {
+ return &webhook{scheme: scheme, decoder: NewDecoder(scheme)}
+}
+
+// webhook implements a CRD conversion webhook HTTP handler.
+type webhook struct {
+ scheme *runtime.Scheme
+ decoder *Decoder
+}
+
+// ensure Webhook implements http.Handler
+var _ http.Handler = &webhook{}
+
+func (wh *webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ convertReview := &apix.ConversionReview{}
+ err := json.NewDecoder(r.Body).Decode(convertReview)
+ if err != nil {
+ log.Error(err, "failed to read conversion request")
+ w.WriteHeader(http.StatusBadRequest)
+ return
+ }
+
+ if convertReview.Request == nil {
+ log.Error(nil, "conversion request is nil")
+ w.WriteHeader(http.StatusBadRequest)
+ return
+ }
+
+ // TODO(droot): may be move the conversion logic to a separate module to
+ // decouple it from the http layer ?
+ resp, err := wh.handleConvertRequest(convertReview.Request)
+ if err != nil {
+ log.Error(err, "failed to convert", "request", convertReview.Request.UID)
+ convertReview.Response = errored(err)
+ } else {
+ convertReview.Response = resp
+ }
+ convertReview.Response.UID = convertReview.Request.UID
+ convertReview.Request = nil
+
+ err = json.NewEncoder(w).Encode(convertReview)
+ if err != nil {
+ log.Error(err, "failed to write response")
+ return
+ }
+}
+
+// handles a version conversion request.
+func (wh *webhook) handleConvertRequest(req *apix.ConversionRequest) (*apix.ConversionResponse, error) {
+ if req == nil {
+ return nil, fmt.Errorf("conversion request is nil")
+ }
+ var objects []runtime.RawExtension
+
+ for _, obj := range req.Objects {
+ src, gvk, err := wh.decoder.Decode(obj.Raw)
+ if err != nil {
+ return nil, err
+ }
+ dst, err := wh.allocateDstObject(req.DesiredAPIVersion, gvk.Kind)
+ if err != nil {
+ return nil, err
+ }
+ err = wh.convertObject(src, dst)
+ if err != nil {
+ return nil, err
+ }
+ objects = append(objects, runtime.RawExtension{Object: dst})
+ }
+ return &apix.ConversionResponse{
+ UID: req.UID,
+ ConvertedObjects: objects,
+ Result: metav1.Status{
+ Status: metav1.StatusSuccess,
+ },
+ }, nil
+}
+
+// convertObject will convert given a src object to dst object.
+// Note(droot): couldn't find a way to reduce the cyclomatic complexity under 10
+// without compromising readability, so disabling gocyclo linter
+func (wh *webhook) convertObject(src, dst runtime.Object) error {
+ srcGVK := src.GetObjectKind().GroupVersionKind()
+ dstGVK := dst.GetObjectKind().GroupVersionKind()
+
+ if srcGVK.GroupKind() != dstGVK.GroupKind() {
+ return fmt.Errorf("src %T and dst %T does not belong to same API Group", src, dst)
+ }
+
+ if srcGVK == dstGVK {
+ return fmt.Errorf("conversion is not allowed between same type %T", src)
+ }
+
+ srcIsHub, dstIsHub := isHub(src), isHub(dst)
+ srcIsConvertible, dstIsConvertible := isConvertible(src), isConvertible(dst)
+
+ switch {
+ case srcIsHub && dstIsConvertible:
+ return dst.(conversion.Convertible).ConvertFrom(src.(conversion.Hub))
+ case dstIsHub && srcIsConvertible:
+ return src.(conversion.Convertible).ConvertTo(dst.(conversion.Hub))
+ case srcIsConvertible && dstIsConvertible:
+ return wh.convertViaHub(src.(conversion.Convertible), dst.(conversion.Convertible))
+ default:
+ return fmt.Errorf("%T is not convertible to %T", src, dst)
+ }
+}
+
+func (wh *webhook) convertViaHub(src, dst conversion.Convertible) error {
+ hub, err := wh.getHub(src)
+ if err != nil {
+ return err
+ }
+
+ if hub == nil {
+ return fmt.Errorf("%s does not have any Hub defined", src)
+ }
+
+ err = src.ConvertTo(hub)
+ if err != nil {
+ return fmt.Errorf("%T failed to convert to hub version %T : %w", src, hub, err)
+ }
+
+ err = dst.ConvertFrom(hub)
+ if err != nil {
+ return fmt.Errorf("%T failed to convert from hub version %T : %w", dst, hub, err)
+ }
+
+ return nil
+}
+
+// getHub returns an instance of the Hub for passed-in object's group/kind.
+func (wh *webhook) getHub(obj runtime.Object) (conversion.Hub, error) {
+ gvks, err := objectGVKs(wh.scheme, obj)
+ if err != nil {
+ return nil, err
+ }
+ if len(gvks) == 0 {
+ return nil, fmt.Errorf("error retrieving gvks for object : %v", obj)
+ }
+
+ var hub conversion.Hub
+ var hubFoundAlready bool
+ for _, gvk := range gvks {
+ instance, err := wh.scheme.New(gvk)
+ if err != nil {
+ return nil, fmt.Errorf("failed to allocate an instance for gvk %v: %w", gvk, err)
+ }
+ if val, isHub := instance.(conversion.Hub); isHub {
+ if hubFoundAlready {
+ return nil, fmt.Errorf("multiple hub version defined for %T", obj)
+ }
+ hubFoundAlready = true
+ hub = val
+ }
+ }
+ return hub, nil
+}
+
+// allocateDstObject returns an instance for a given GVK.
+func (wh *webhook) allocateDstObject(apiVersion, kind string) (runtime.Object, error) {
+ gvk := schema.FromAPIVersionAndKind(apiVersion, kind)
+
+ obj, err := wh.scheme.New(gvk)
+ if err != nil {
+ return obj, err
+ }
+
+ t, err := meta.TypeAccessor(obj)
+ if err != nil {
+ return obj, err
+ }
+
+ t.SetAPIVersion(apiVersion)
+ t.SetKind(kind)
+
+ return obj, nil
+}
+
+// IsConvertible determines if given type is convertible or not. For a type
+// to be convertible, the group-kind needs to have a Hub type defined and all
+// non-hub types must be able to convert to/from Hub.
+func IsConvertible(scheme *runtime.Scheme, obj runtime.Object) (bool, error) {
+ var hubs, spokes, nonSpokes []runtime.Object
+
+ gvks, err := objectGVKs(scheme, obj)
+ if err != nil {
+ return false, err
+ }
+ if len(gvks) == 0 {
+ return false, fmt.Errorf("error retrieving gvks for object : %v", obj)
+ }
+
+ for _, gvk := range gvks {
+ instance, err := scheme.New(gvk)
+ if err != nil {
+ return false, fmt.Errorf("failed to allocate an instance for gvk %v: %w", gvk, err)
+ }
+
+ if isHub(instance) {
+ hubs = append(hubs, instance)
+ continue
+ }
+
+ if !isConvertible(instance) {
+ nonSpokes = append(nonSpokes, instance)
+ continue
+ }
+
+ spokes = append(spokes, instance)
+ }
+
+ if len(gvks) == 1 {
+ return false, nil // single version
+ }
+
+ if len(hubs) == 0 && len(spokes) == 0 {
+ // multiple version detected with no conversion implementation. This is
+ // true for multi-version built-in types.
+ return false, nil
+ }
+
+ if len(hubs) == 1 && len(nonSpokes) == 0 { // convertible
+ return true, nil
+ }
+
+ return false, PartialImplementationError{
+ hubs: hubs,
+ nonSpokes: nonSpokes,
+ spokes: spokes,
+ }
+}
+
+// objectGVKs returns all (Group,Version,Kind) for the Group/Kind of given object.
+func objectGVKs(scheme *runtime.Scheme, obj runtime.Object) ([]schema.GroupVersionKind, error) {
+ // NB: we should not use `obj.GetObjectKind().GroupVersionKind()` to get the
+ // GVK here, since it is parsed from apiVersion and kind fields and it may
+ // return empty GVK if obj is an uninitialized object.
+ objGVKs, _, err := scheme.ObjectKinds(obj)
+ if err != nil {
+ return nil, err
+ }
+ if len(objGVKs) != 1 {
+ return nil, fmt.Errorf("expect to get only one GVK for %v", obj)
+ }
+ objGVK := objGVKs[0]
+ knownTypes := scheme.AllKnownTypes()
+
+ var gvks []schema.GroupVersionKind
+ for gvk := range knownTypes {
+ if objGVK.GroupKind() == gvk.GroupKind() {
+ gvks = append(gvks, gvk)
+ }
+ }
+ return gvks, nil
+}
+
+// PartialImplementationError represents an error due to partial conversion
+// implementation such as hub without spokes, multiple hubs or spokes without hub.
+type PartialImplementationError struct {
+ gvk schema.GroupVersionKind
+ hubs []runtime.Object
+ nonSpokes []runtime.Object
+ spokes []runtime.Object
+}
+
+func (e PartialImplementationError) Error() string {
+ if len(e.hubs) == 0 {
+ return fmt.Sprintf("no hub defined for gvk %s", e.gvk)
+ }
+ if len(e.hubs) > 1 {
+ return fmt.Sprintf("multiple(%d) hubs defined for group-kind '%s' ",
+ len(e.hubs), e.gvk.GroupKind())
+ }
+ if len(e.nonSpokes) > 0 {
+ return fmt.Sprintf("%d inconvertible types detected for group-kind '%s'",
+ len(e.nonSpokes), e.gvk.GroupKind())
+ }
+ return ""
+}
+
+// isHub determines if passed-in object is a Hub or not.
+func isHub(obj runtime.Object) bool {
+ _, yes := obj.(conversion.Hub)
+ return yes
+}
+
+// isConvertible determines if passed-in object is a convertible.
+func isConvertible(obj runtime.Object) bool {
+ _, yes := obj.(conversion.Convertible)
+ return yes
+}
+
+// helper to construct error response.
+func errored(err error) *apix.ConversionResponse {
+ return &apix.ConversionResponse{
+ Result: metav1.Status{
+ Status: metav1.StatusFailure,
+ Message: err.Error(),
+ },
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion_suite_test.go
new file mode 100644
index 00000000000..7ca3c48ba26
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion_suite_test.go
@@ -0,0 +1,35 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package conversion
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestConversionWebhook(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "CRD conversion Suite")
+}
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion_test.go
new file mode 100644
index 00000000000..be984e232bc
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion_test.go
@@ -0,0 +1,360 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package conversion_test
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "net/http"
+ "net/http/httptest"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ appsv1beta1 "k8s.io/api/apps/v1beta1"
+ apix "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime"
+ kscheme "k8s.io/client-go/kubernetes/scheme"
+
+ "sigs.k8s.io/controller-runtime/pkg/webhook/conversion"
+ jobsv1 "sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v1"
+ jobsv2 "sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2"
+ jobsv3 "sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v3"
+)
+
+var _ = Describe("Conversion Webhook", func() {
+
+ var respRecorder *httptest.ResponseRecorder
+ var decoder *conversion.Decoder
+ var scheme *runtime.Scheme
+ var wh http.Handler
+
+ BeforeEach(func() {
+ respRecorder = &httptest.ResponseRecorder{
+ Body: bytes.NewBuffer(nil),
+ }
+
+ scheme = runtime.NewScheme()
+ Expect(kscheme.AddToScheme(scheme)).To(Succeed())
+ Expect(jobsv1.AddToScheme(scheme)).To(Succeed())
+ Expect(jobsv2.AddToScheme(scheme)).To(Succeed())
+ Expect(jobsv3.AddToScheme(scheme)).To(Succeed())
+
+ decoder = conversion.NewDecoder(scheme)
+ wh = conversion.NewWebhookHandler(scheme)
+ })
+
+ doRequest := func(convReq *apix.ConversionReview) *apix.ConversionReview {
+ var payload bytes.Buffer
+
+ Expect(json.NewEncoder(&payload).Encode(convReq)).Should(Succeed())
+
+ convReview := &apix.ConversionReview{}
+ req := &http.Request{
+ Body: io.NopCloser(bytes.NewReader(payload.Bytes())),
+ }
+ wh.ServeHTTP(respRecorder, req)
+ Expect(json.NewDecoder(respRecorder.Result().Body).Decode(convReview)).To(Succeed())
+ return convReview
+ }
+
+ makeV1Obj := func() *jobsv1.ExternalJob {
+ return &jobsv1.ExternalJob{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ExternalJob",
+ APIVersion: "jobs.testprojects.kb.io/v1",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: "obj-1",
+ },
+ Spec: jobsv1.ExternalJobSpec{
+ RunAt: "every 2 seconds",
+ },
+ }
+ }
+
+ makeV2Obj := func() *jobsv2.ExternalJob {
+ return &jobsv2.ExternalJob{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ExternalJob",
+ APIVersion: "jobs.testprojects.kb.io/v2",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: "obj-1",
+ },
+ Spec: jobsv2.ExternalJobSpec{
+ ScheduleAt: "every 2 seconds",
+ },
+ }
+ }
+
+ It("should convert spoke to hub successfully", func() {
+
+ v1Obj := makeV1Obj()
+
+ expected := &jobsv2.ExternalJob{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ExternalJob",
+ APIVersion: "jobs.testprojects.kb.io/v2",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: "obj-1",
+ },
+ Spec: jobsv2.ExternalJobSpec{
+ ScheduleAt: "every 2 seconds",
+ },
+ }
+
+ convReq := &apix.ConversionReview{
+ TypeMeta: metav1.TypeMeta{},
+ Request: &apix.ConversionRequest{
+ DesiredAPIVersion: "jobs.testprojects.kb.io/v2",
+ Objects: []runtime.RawExtension{
+ {
+ Object: v1Obj,
+ },
+ },
+ },
+ }
+
+ convReview := doRequest(convReq)
+
+ Expect(convReview.Response.ConvertedObjects).To(HaveLen(1))
+ Expect(convReview.Response.Result.Status).To(Equal(metav1.StatusSuccess))
+ got, _, err := decoder.Decode(convReview.Response.ConvertedObjects[0].Raw)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(got).To(Equal(expected))
+ })
+
+ It("should convert hub to spoke successfully", func() {
+
+ v2Obj := makeV2Obj()
+
+ expected := &jobsv1.ExternalJob{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ExternalJob",
+ APIVersion: "jobs.testprojects.kb.io/v1",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: "obj-1",
+ },
+ Spec: jobsv1.ExternalJobSpec{
+ RunAt: "every 2 seconds",
+ },
+ }
+
+ convReq := &apix.ConversionReview{
+ TypeMeta: metav1.TypeMeta{},
+ Request: &apix.ConversionRequest{
+ DesiredAPIVersion: "jobs.testprojects.kb.io/v1",
+ Objects: []runtime.RawExtension{
+ {
+ Object: v2Obj,
+ },
+ },
+ },
+ }
+
+ convReview := doRequest(convReq)
+
+ Expect(convReview.Response.ConvertedObjects).To(HaveLen(1))
+ Expect(convReview.Response.Result.Status).To(Equal(metav1.StatusSuccess))
+ got, _, err := decoder.Decode(convReview.Response.ConvertedObjects[0].Raw)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(got).To(Equal(expected))
+ })
+
+ It("should convert spoke to spoke successfully", func() {
+
+ v1Obj := makeV1Obj()
+
+ expected := &jobsv3.ExternalJob{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ExternalJob",
+ APIVersion: "jobs.testprojects.kb.io/v3",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: "obj-1",
+ },
+ Spec: jobsv3.ExternalJobSpec{
+ DeferredAt: "every 2 seconds",
+ },
+ }
+
+ convReq := &apix.ConversionReview{
+ TypeMeta: metav1.TypeMeta{},
+ Request: &apix.ConversionRequest{
+ DesiredAPIVersion: "jobs.testprojects.kb.io/v3",
+ Objects: []runtime.RawExtension{
+ {
+ Object: v1Obj,
+ },
+ },
+ },
+ }
+
+ convReview := doRequest(convReq)
+
+ Expect(convReview.Response.ConvertedObjects).To(HaveLen(1))
+ Expect(convReview.Response.Result.Status).To(Equal(metav1.StatusSuccess))
+ got, _, err := decoder.Decode(convReview.Response.ConvertedObjects[0].Raw)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(got).To(Equal(expected))
+ })
+
+ It("should return error when dest/src objects belong to different API groups", func() {
+ v1Obj := makeV1Obj()
+
+ convReq := &apix.ConversionReview{
+ TypeMeta: metav1.TypeMeta{},
+ Request: &apix.ConversionRequest{
+ // request conversion for different group
+ DesiredAPIVersion: "jobss.example.org/v2",
+ Objects: []runtime.RawExtension{
+ {
+ Object: v1Obj,
+ },
+ },
+ },
+ }
+
+ convReview := doRequest(convReq)
+ Expect(convReview.Response.Result.Status).To(Equal("Failure"))
+ Expect(convReview.Response.ConvertedObjects).To(BeEmpty())
+ })
+
+ It("should return error when dest/src objects are of same type", func() {
+
+ v1Obj := makeV1Obj()
+
+ convReq := &apix.ConversionReview{
+ TypeMeta: metav1.TypeMeta{},
+ Request: &apix.ConversionRequest{
+ DesiredAPIVersion: "jobs.testprojects.kb.io/v1",
+ Objects: []runtime.RawExtension{
+ {
+ Object: v1Obj,
+ },
+ },
+ },
+ }
+
+ convReview := doRequest(convReq)
+ Expect(convReview.Response.Result.Status).To(Equal("Failure"))
+ Expect(convReview.Response.ConvertedObjects).To(BeEmpty())
+ })
+
+ It("should return error when the API group does not have a hub defined", func() {
+
+ v1Obj := &appsv1beta1.Deployment{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "Deployment",
+ APIVersion: "apps/v1beta1",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "default",
+ Name: "obj-1",
+ },
+ }
+
+ convReq := &apix.ConversionReview{
+ TypeMeta: metav1.TypeMeta{},
+ Request: &apix.ConversionRequest{
+ DesiredAPIVersion: "apps/v1",
+ Objects: []runtime.RawExtension{
+ {
+ Object: v1Obj,
+ },
+ },
+ },
+ }
+
+ convReview := doRequest(convReq)
+ Expect(convReview.Response.Result.Status).To(Equal("Failure"))
+ Expect(convReview.Response.ConvertedObjects).To(BeEmpty())
+ })
+
+})
+
+var _ = Describe("IsConvertible", func() {
+
+ var scheme *runtime.Scheme
+
+ BeforeEach(func() {
+ scheme = runtime.NewScheme()
+
+ Expect(kscheme.AddToScheme(scheme)).To(Succeed())
+ Expect(jobsv1.AddToScheme(scheme)).To(Succeed())
+ Expect(jobsv2.AddToScheme(scheme)).To(Succeed())
+ Expect(jobsv3.AddToScheme(scheme)).To(Succeed())
+ })
+
+ It("should not error for uninitialized types", func() {
+ obj := &jobsv2.ExternalJob{}
+
+ ok, err := conversion.IsConvertible(scheme, obj)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(ok).To(BeTrue())
+ })
+
+ It("should not error for unstructured types", func() {
+ obj := &unstructured.Unstructured{
+ Object: map[string]interface{}{
+ "kind": "ExternalJob",
+ "apiVersion": "jobs.testprojects.kb.io/v2",
+ },
+ }
+
+ ok, err := conversion.IsConvertible(scheme, obj)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(ok).To(BeTrue())
+ })
+
+ It("should return true for convertible types", func() {
+ obj := &jobsv2.ExternalJob{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ExternalJob",
+ APIVersion: "jobs.testprojects.kb.io/v2",
+ },
+ }
+
+ ok, err := conversion.IsConvertible(scheme, obj)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(ok).To(BeTrue())
+ })
+
+ It("should return false for a non convertible type", func() {
+ obj := &appsv1beta1.Deployment{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "Deployment",
+ APIVersion: "apps/v1beta1",
+ },
+ }
+
+ ok, err := conversion.IsConvertible(scheme, obj)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(ok).ToNot(BeTrue())
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/decoder.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/decoder.go
new file mode 100644
index 00000000000..b6bb8bd9384
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/decoder.go
@@ -0,0 +1,50 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package conversion
+
+import (
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+)
+
+// Decoder knows how to decode the contents of a CRD version conversion
+// request into a concrete object.
+// TODO(droot): consider reusing decoder from admission pkg for this.
+type Decoder struct {
+ codecs serializer.CodecFactory
+}
+
+// NewDecoder creates a Decoder given the runtime.Scheme
+func NewDecoder(scheme *runtime.Scheme) *Decoder {
+ if scheme == nil {
+ panic("scheme should never be nil")
+ }
+ return &Decoder{codecs: serializer.NewCodecFactory(scheme)}
+}
+
+// Decode decodes the inlined object.
+func (d *Decoder) Decode(content []byte) (runtime.Object, *schema.GroupVersionKind, error) {
+ deserializer := d.codecs.UniversalDeserializer()
+ return deserializer.Decode(content, nil, nil)
+}
+
+// DecodeInto decodes the inlined object in the into the passed-in runtime.Object.
+func (d *Decoder) DecodeInto(content []byte, into runtime.Object) error {
+ deserializer := d.codecs.UniversalDeserializer()
+ return runtime.DecodeInto(deserializer, content, into)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/.gitignore b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/.gitignore
new file mode 100644
index 00000000000..d97ffc5159b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/.gitignore
@@ -0,0 +1,24 @@
+
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+bin
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Kubernetes Generated files - skip generated files, except for vendored files
+
+!vendor/**/zz_generated.*
+
+# editor and IDE paraphernalia
+.idea
+*.swp
+*.swo
+*~
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/Makefile b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/Makefile
new file mode 100644
index 00000000000..2d9d3dda15a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/Makefile
@@ -0,0 +1,64 @@
+
+# Image URL to use all building/pushing image targets
+IMG ?= controller:latest
+# Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
+CRD_OPTIONS ?= "crd:trivialVersions=true"
+
+all: manager
+
+# Run tests
+test: generate fmt vet manifests
+ go test ./api/... ./controllers/... -coverprofile cover.out
+
+# Build manager binary
+manager: generate fmt vet
+ go build -o bin/manager main.go
+
+# Run against the configured Kubernetes cluster in ~/.kube/config
+run: generate fmt vet
+ go run ./main.go
+
+# Install CRDs into a cluster
+install: manifests
+ kubectl apply -f config/crd/bases
+
+# Deploy controller in the configured Kubernetes cluster in ~/.kube/config
+deploy: manifests
+ kubectl apply -f config/crd/bases
+ kustomize build config/default | kubectl apply -f -
+
+# Generate manifests e.g. CRD, RBAC etc.
+manifests: controller-gen
+ $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
+
+# Run go fmt against code
+fmt:
+ go fmt ./...
+
+# Run go vet against code
+vet:
+ go vet ./...
+
+# Generate code
+generate: controller-gen
+ $(CONTROLLER_GEN) object:headerFile=./hack/boilerplate.go.txt paths=./api/...
+
+# Build the docker image
+docker-build: test
+ docker build . -t ${IMG}
+ @echo "updating kustomize image patch file for manager resource"
+ sed -i'' -e 's@image: .*@image: '"${IMG}"'@' ./config/default/manager_image_patch.yaml
+
+# Push the docker image
+docker-push:
+ docker push ${IMG}
+
+# find or download controller-gen
+# download controller-gen if necessary
+controller-gen:
+ifeq (, $(shell which controller-gen))
+ go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.0-beta.2
+CONTROLLER_GEN=$(shell go env GOPATH)/bin/controller-gen
+else
+CONTROLLER_GEN=$(shell which controller-gen)
+endif
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/PROJECT b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/PROJECT
new file mode 100644
index 00000000000..6b168dcbc11
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/PROJECT
@@ -0,0 +1,13 @@
+version: "2"
+domain: testprojects.kb.io
+repo: sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata
+resources:
+- group: jobs
+ version: v1
+ kind: ExternalJob
+- group: jobs
+ version: v2
+ kind: ExternalJob
+- group: jobs
+ version: v3
+ kind: ExternalJob
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v1/externaljob_types.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v1/externaljob_types.go
new file mode 100644
index 00000000000..bf99e2a2040
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v1/externaljob_types.go
@@ -0,0 +1,92 @@
+/*
+
+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 v1
+
+import (
+ "fmt"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "sigs.k8s.io/controller-runtime/pkg/conversion"
+
+ v2 "sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2"
+)
+
+// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
+// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
+
+// ExternalJobSpec defines the desired state of ExternalJob
+type ExternalJobSpec struct {
+ // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+ RunAt string `json:"runAt"`
+}
+
+// ExternalJobStatus defines the observed state of ExternalJob
+type ExternalJobStatus struct {
+ // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+}
+
+// +kubebuilder:object:root=true
+
+// ExternalJob is the Schema for the externaljobs API
+type ExternalJob struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec ExternalJobSpec `json:"spec,omitempty"`
+ Status ExternalJobStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ExternalJobList contains a list of ExternalJob
+type ExternalJobList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []ExternalJob `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&ExternalJob{}, &ExternalJobList{})
+}
+
+// ConvertTo implements conversion logic to convert to Hub type (v2.ExternalJob
+// in this case)
+func (ej *ExternalJob) ConvertTo(dst conversion.Hub) error {
+ switch t := dst.(type) {
+ case *v2.ExternalJob:
+ jobv2 := dst.(*v2.ExternalJob)
+ jobv2.ObjectMeta = ej.ObjectMeta
+ jobv2.Spec.ScheduleAt = ej.Spec.RunAt
+ return nil
+ default:
+ return fmt.Errorf("unsupported type %v", t)
+ }
+}
+
+// ConvertFrom implements conversion logic to convert from Hub type (v2.ExternalJob
+// in this case)
+func (ej *ExternalJob) ConvertFrom(src conversion.Hub) error {
+ switch t := src.(type) {
+ case *v2.ExternalJob:
+ jobv2 := src.(*v2.ExternalJob)
+ ej.ObjectMeta = jobv2.ObjectMeta
+ ej.Spec.RunAt = jobv2.Spec.ScheduleAt
+ return nil
+ default:
+ return fmt.Errorf("unsupported type %v", t)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v1/groupversion_info.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v1/groupversion_info.go
new file mode 100644
index 00000000000..5bbef617869
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v1/groupversion_info.go
@@ -0,0 +1,35 @@
+/*
+
+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 v1 contains API Schema definitions for the jobs v1 API group
+// +kubebuilder:object:generate=true
+// +groupName=jobs.testprojects.kb.io
+package v1
+
+import (
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+ // GroupVersion is group version used to register these objects
+ GroupVersion = schema.GroupVersion{Group: "jobs.testprojects.kb.io", Version: "v1"}
+
+ // SchemeBuilder is used to add go types to the GroupVersionKind scheme
+ SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+ // AddToScheme adds the types in this group-version to the given scheme.
+ AddToScheme = SchemeBuilder.AddToScheme
+)
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v1/zz_generated.deepcopy.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v1/zz_generated.deepcopy.go
new file mode 100644
index 00000000000..7208ba8c697
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v1/zz_generated.deepcopy.go
@@ -0,0 +1,113 @@
+// +build !ignore_autogenerated
+
+/*
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// autogenerated by controller-gen object, do not modify manually
+
+package v1
+
+import (
+ runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExternalJob) DeepCopyInto(out *ExternalJob) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ out.Spec = in.Spec
+ out.Status = in.Status
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalJob.
+func (in *ExternalJob) DeepCopy() *ExternalJob {
+ if in == nil {
+ return nil
+ }
+ out := new(ExternalJob)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ExternalJob) 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 *ExternalJobList) DeepCopyInto(out *ExternalJobList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ out.ListMeta = in.ListMeta
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]ExternalJob, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalJobList.
+func (in *ExternalJobList) DeepCopy() *ExternalJobList {
+ if in == nil {
+ return nil
+ }
+ out := new(ExternalJobList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ExternalJobList) 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 *ExternalJobSpec) DeepCopyInto(out *ExternalJobSpec) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalJobSpec.
+func (in *ExternalJobSpec) DeepCopy() *ExternalJobSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ExternalJobSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExternalJobStatus) DeepCopyInto(out *ExternalJobStatus) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalJobStatus.
+func (in *ExternalJobStatus) DeepCopy() *ExternalJobStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ExternalJobStatus)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2/externaljob_types.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2/externaljob_types.go
new file mode 100644
index 00000000000..de5a03a212a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2/externaljob_types.go
@@ -0,0 +1,68 @@
+/*
+
+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 v2
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
+// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
+
+// ExternalJobSpec defines the desired state of ExternalJob
+type ExternalJobSpec struct {
+ // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+ ScheduleAt string `json:"scheduleAt"`
+}
+
+// ExternalJobStatus defines the observed state of ExternalJob
+type ExternalJobStatus struct {
+ // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+}
+
+// +kubebuilder:object:root=true
+
+// ExternalJob is the Schema for the externaljobs API
+type ExternalJob struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec ExternalJobSpec `json:"spec,omitempty"`
+ Status ExternalJobStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ExternalJobList contains a list of ExternalJob
+type ExternalJobList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []ExternalJob `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&ExternalJob{}, &ExternalJobList{})
+}
+
+// Hub is just a marker method to indicate that v2.ExternalJob is the Hub type
+// in this case.
+// v2.ExternalJob is the storage version so mark this as Hub.
+// Storage version doesn't need to implement any conversion methods because
+// default conversionHandler implements conversion logic for storage version.
+// TODO(droot): Add comment annotation here to mark it as storage version
+func (ej *ExternalJob) Hub() {}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2/groupversion_info.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2/groupversion_info.go
new file mode 100644
index 00000000000..5019111a00c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2/groupversion_info.go
@@ -0,0 +1,35 @@
+/*
+
+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 v2 contains API Schema definitions for the jobs v2 API group
+// +kubebuilder:object:generate=true
+// +groupName=jobs.testprojects.kb.io
+package v2
+
+import (
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+ // GroupVersion is group version used to register these objects
+ GroupVersion = schema.GroupVersion{Group: "jobs.testprojects.kb.io", Version: "v2"}
+
+ // SchemeBuilder is used to add go types to the GroupVersionKind scheme
+ SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+ // AddToScheme adds the types in this group-version to the given scheme.
+ AddToScheme = SchemeBuilder.AddToScheme
+)
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2/zz_generated.deepcopy.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2/zz_generated.deepcopy.go
new file mode 100644
index 00000000000..53c9f758b1d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2/zz_generated.deepcopy.go
@@ -0,0 +1,113 @@
+// +build !ignore_autogenerated
+
+/*
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// autogenerated by controller-gen object, do not modify manually
+
+package v2
+
+import (
+ runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExternalJob) DeepCopyInto(out *ExternalJob) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ out.Spec = in.Spec
+ out.Status = in.Status
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalJob.
+func (in *ExternalJob) DeepCopy() *ExternalJob {
+ if in == nil {
+ return nil
+ }
+ out := new(ExternalJob)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ExternalJob) 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 *ExternalJobList) DeepCopyInto(out *ExternalJobList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ out.ListMeta = in.ListMeta
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]ExternalJob, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalJobList.
+func (in *ExternalJobList) DeepCopy() *ExternalJobList {
+ if in == nil {
+ return nil
+ }
+ out := new(ExternalJobList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ExternalJobList) 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 *ExternalJobSpec) DeepCopyInto(out *ExternalJobSpec) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalJobSpec.
+func (in *ExternalJobSpec) DeepCopy() *ExternalJobSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ExternalJobSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExternalJobStatus) DeepCopyInto(out *ExternalJobStatus) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalJobStatus.
+func (in *ExternalJobStatus) DeepCopy() *ExternalJobStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ExternalJobStatus)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v3/externaljob_types.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v3/externaljob_types.go
new file mode 100644
index 00000000000..15c438f68a1
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v3/externaljob_types.go
@@ -0,0 +1,92 @@
+/*
+
+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 v3
+
+import (
+ "fmt"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "sigs.k8s.io/controller-runtime/pkg/conversion"
+
+ v2 "sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2"
+)
+
+// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
+// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
+
+// ExternalJobSpec defines the desired state of ExternalJob
+type ExternalJobSpec struct {
+ // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+ DeferredAt string `json:"deferredAt"`
+}
+
+// ExternalJobStatus defines the observed state of ExternalJob
+type ExternalJobStatus struct {
+ // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+}
+
+// +kubebuilder:object:root=true
+
+// ExternalJob is the Schema for the externaljobs API
+type ExternalJob struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec ExternalJobSpec `json:"spec,omitempty"`
+ Status ExternalJobStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ExternalJobList contains a list of ExternalJob
+type ExternalJobList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []ExternalJob `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&ExternalJob{}, &ExternalJobList{})
+}
+
+// ConvertTo implements conversion logic to convert to Hub type (v2.ExternalJob
+// in this case)
+func (ej *ExternalJob) ConvertTo(dst conversion.Hub) error {
+ switch t := dst.(type) {
+ case *v2.ExternalJob:
+ jobv2 := dst.(*v2.ExternalJob)
+ jobv2.ObjectMeta = ej.ObjectMeta
+ jobv2.Spec.ScheduleAt = ej.Spec.DeferredAt
+ return nil
+ default:
+ return fmt.Errorf("unsupported type %v", t)
+ }
+}
+
+// ConvertFrom implements conversion logic to convert from Hub type (v2.ExternalJob
+// in this case)
+func (ej *ExternalJob) ConvertFrom(src conversion.Hub) error {
+ switch t := src.(type) {
+ case *v2.ExternalJob:
+ jobv2 := src.(*v2.ExternalJob)
+ ej.ObjectMeta = jobv2.ObjectMeta
+ ej.Spec.DeferredAt = jobv2.Spec.ScheduleAt
+ return nil
+ default:
+ return fmt.Errorf("unsupported type %v", t)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v3/groupversion_info.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v3/groupversion_info.go
new file mode 100644
index 00000000000..1ae8269614a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v3/groupversion_info.go
@@ -0,0 +1,35 @@
+/*
+
+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 v3 contains API Schema definitions for the jobs v3 API group
+// +kubebuilder:object:generate=true
+// +groupName=jobs.testprojects.kb.io
+package v3
+
+import (
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+ // GroupVersion is group version used to register these objects
+ GroupVersion = schema.GroupVersion{Group: "jobs.testprojects.kb.io", Version: "v3"}
+
+ // SchemeBuilder is used to add go types to the GroupVersionKind scheme
+ SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+ // AddToScheme adds the types in this group-version to the given scheme.
+ AddToScheme = SchemeBuilder.AddToScheme
+)
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v3/zz_generated.deepcopy.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v3/zz_generated.deepcopy.go
new file mode 100644
index 00000000000..a90942b427c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v3/zz_generated.deepcopy.go
@@ -0,0 +1,113 @@
+// +build !ignore_autogenerated
+
+/*
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// autogenerated by controller-gen object, do not modify manually
+
+package v3
+
+import (
+ runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExternalJob) DeepCopyInto(out *ExternalJob) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ out.Spec = in.Spec
+ out.Status = in.Status
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalJob.
+func (in *ExternalJob) DeepCopy() *ExternalJob {
+ if in == nil {
+ return nil
+ }
+ out := new(ExternalJob)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ExternalJob) 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 *ExternalJobList) DeepCopyInto(out *ExternalJobList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ out.ListMeta = in.ListMeta
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]ExternalJob, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalJobList.
+func (in *ExternalJobList) DeepCopy() *ExternalJobList {
+ if in == nil {
+ return nil
+ }
+ out := new(ExternalJobList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ExternalJobList) 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 *ExternalJobSpec) DeepCopyInto(out *ExternalJobSpec) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalJobSpec.
+func (in *ExternalJobSpec) DeepCopy() *ExternalJobSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ExternalJobSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExternalJobStatus) DeepCopyInto(out *ExternalJobStatus) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalJobStatus.
+func (in *ExternalJobStatus) DeepCopy() *ExternalJobStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ExternalJobStatus)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/hack/boilerplate.go.txt b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/hack/boilerplate.go.txt
new file mode 100644
index 00000000000..b92001fb4ed
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/hack/boilerplate.go.txt
@@ -0,0 +1,14 @@
+/*
+
+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.
+*/
\ No newline at end of file
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/main.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/main.go
new file mode 100644
index 00000000000..a3922da009a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/main.go
@@ -0,0 +1,74 @@
+/*
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "context"
+ "flag"
+ "os"
+
+ "k8s.io/apimachinery/pkg/runtime"
+ _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
+
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+ jobsv1 "sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v1"
+ jobsv2 "sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v2"
+ jobsv3 "sigs.k8s.io/controller-runtime/pkg/webhook/conversion/testdata/api/v3"
+ // +kubebuilder:scaffold:imports
+)
+
+var (
+ scheme = runtime.NewScheme()
+ setupLog = ctrl.Log.WithName("setup")
+)
+
+func init() {
+
+ jobsv1.AddToScheme(scheme)
+ jobsv2.AddToScheme(scheme)
+ jobsv3.AddToScheme(scheme)
+ // +kubebuilder:scaffold:scheme
+}
+
+func main() {
+ var metricsAddr string
+ var enableLeaderElection bool
+ flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
+ flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
+ "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
+ flag.Parse()
+
+ ctrl.SetLogger(zap.Logger(true))
+
+ mgr, err := ctrl.NewManager(context.Background(), ctrl.GetConfigOrDie(), ctrl.Options{
+ Scheme: scheme,
+ MetricsBindAddress: metricsAddr,
+ LeaderElection: enableLeaderElection,
+ })
+ if err != nil {
+ setupLog.Error(err, "unable to start manager")
+ os.Exit(1)
+ }
+
+ // +kubebuilder:scaffold:builder
+
+ setupLog.Info("starting manager")
+ if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
+ setupLog.Error(err, "problem running manager")
+ os.Exit(1)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/doc.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/doc.go
new file mode 100644
index 00000000000..2c93f0d995b
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/doc.go
@@ -0,0 +1,28 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package webhook provides methods to build and bootstrap a webhook server.
+
+Currently, it only supports admission webhooks. It will support CRD conversion webhooks in the near future.
+*/
+package webhook
+
+import (
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("webhook")
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/example_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/example_test.go
new file mode 100644
index 00000000000..f68008755d3
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/example_test.go
@@ -0,0 +1,151 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package webhook_test
+
+import (
+ "context"
+ "net/http"
+
+ ctrl "sigs.k8s.io/controller-runtime"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+ "sigs.k8s.io/controller-runtime/pkg/manager/signals"
+ . "sigs.k8s.io/controller-runtime/pkg/webhook"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+var (
+ // Build webhooks used for the various server
+ // configuration options
+ //
+ // These handlers could be also be implementations
+ // of the AdmissionHandler interface for more complex
+ // implementations.
+ mutatingHook = &Admission{
+ Handler: admission.HandlerFunc(func(ctx context.Context, req AdmissionRequest) AdmissionResponse {
+ return Patched("some changes",
+ JSONPatchOp{Operation: "add", Path: "/metadata/annotations/access", Value: "granted"},
+ JSONPatchOp{Operation: "add", Path: "/metadata/annotations/reason", Value: "not so secret"},
+ )
+ }),
+ }
+
+ validatingHook = &Admission{
+ Handler: admission.HandlerFunc(func(ctx context.Context, req AdmissionRequest) AdmissionResponse {
+ return Denied("none shall pass!")
+ }),
+ }
+)
+
+// This example registers a webhooks to a webhook server
+// that gets ran by a controller manager.
+func Example() {
+ // Create a manager
+ // Note: GetConfigOrDie will os.Exit(1) w/o any message if no kube-config can be found
+ mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{})
+ if err != nil {
+ panic(err)
+ }
+
+ // Create a webhook server.
+ hookServer := NewServer(Options{
+ Port: 8443,
+ })
+ if err := mgr.Add(hookServer); err != nil {
+ panic(err)
+ }
+
+ // Register the webhooks in the server.
+ hookServer.Register("/mutating", mutatingHook)
+ hookServer.Register("/validating", validatingHook)
+
+ // Start the server by starting a previously-set-up manager
+ err = mgr.Start(ctrl.SetupSignalHandler())
+ if err != nil {
+ // handle error
+ panic(err)
+ }
+}
+
+// This example creates a webhook server that can be
+// ran without a controller manager.
+//
+// Note that this assumes and requires a valid TLS
+// cert and key at the default locations
+// tls.crt and tls.key.
+func ExampleServer_Start() {
+ // Create a webhook server
+ hookServer := NewServer(Options{
+ Port: 8443,
+ })
+
+ // Register the webhooks in the server.
+ hookServer.Register("/mutating", mutatingHook)
+ hookServer.Register("/validating", validatingHook)
+
+ // Start the server without a manger
+ err := hookServer.Start(signals.SetupSignalHandler())
+ if err != nil {
+ // handle error
+ panic(err)
+ }
+}
+
+// This example creates a standalone webhook handler
+// and runs it on a vanilla go HTTP server to demonstrate
+// how you could run a webhook on an existing server
+// without a controller manager.
+func ExampleStandaloneWebhook() {
+ // Assume you have an existing HTTP server at your disposal
+ // configured as desired (e.g. with TLS).
+ // For this example just create a basic http.ServeMux
+ mux := http.NewServeMux()
+ port := ":8000"
+
+ // Create the standalone HTTP handlers from our webhooks
+ mutatingHookHandler, err := admission.StandaloneWebhook(mutatingHook, admission.StandaloneOptions{
+ // Logger let's you optionally pass
+ // a custom logger (defaults to log.Log global Logger)
+ Logger: logf.RuntimeLog.WithName("mutating-webhook"),
+ // MetricsPath let's you optionally
+ // provide the path it will be served on
+ // to be used for labelling prometheus metrics
+ // If none is set, prometheus metrics will not be generated.
+ MetricsPath: "/mutating",
+ })
+ if err != nil {
+ // handle error
+ panic(err)
+ }
+
+ validatingHookHandler, err := admission.StandaloneWebhook(validatingHook, admission.StandaloneOptions{
+ Logger: logf.RuntimeLog.WithName("validating-webhook"),
+ MetricsPath: "/validating",
+ })
+ if err != nil {
+ // handle error
+ panic(err)
+ }
+
+ // Register the webhook handlers to your server
+ mux.Handle("/mutating", mutatingHookHandler)
+ mux.Handle("/validating", validatingHookHandler)
+
+ // Run your handler
+ if err := http.ListenAndServe(port, mux); err != nil { //nolint:gosec // it's fine to not set timeouts here
+ panic(err)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go
new file mode 100644
index 00000000000..557004908b8
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go
@@ -0,0 +1,85 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package metrics
+
+import (
+ "net/http"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+)
+
+var (
+ // RequestLatency is a prometheus metric which is a histogram of the latency
+ // of processing admission requests.
+ RequestLatency = prometheus.NewHistogramVec(
+ prometheus.HistogramOpts{
+ Name: "controller_runtime_webhook_latency_seconds",
+ Help: "Histogram of the latency of processing admission requests",
+ },
+ []string{"webhook"},
+ )
+
+ // RequestTotal is a prometheus metric which is a counter of the total processed admission requests.
+ RequestTotal = func() *prometheus.CounterVec {
+ return prometheus.NewCounterVec(
+ prometheus.CounterOpts{
+ Name: "controller_runtime_webhook_requests_total",
+ Help: "Total number of admission requests by HTTP status code.",
+ },
+ []string{"webhook", "code"},
+ )
+ }()
+
+ // RequestInFlight is a prometheus metric which is a gauge of the in-flight admission requests.
+ RequestInFlight = func() *prometheus.GaugeVec {
+ return prometheus.NewGaugeVec(
+ prometheus.GaugeOpts{
+ Name: "controller_runtime_webhook_requests_in_flight",
+ Help: "Current number of admission requests being served.",
+ },
+ []string{"webhook"},
+ )
+ }()
+)
+
+func init() {
+ metrics.Registry.MustRegister(RequestLatency, RequestTotal, RequestInFlight)
+}
+
+// InstrumentedHook adds some instrumentation on top of the given webhook.
+func InstrumentedHook(path string, hookRaw http.Handler) http.Handler {
+ lbl := prometheus.Labels{"webhook": path}
+
+ lat := RequestLatency.MustCurryWith(lbl)
+ cnt := RequestTotal.MustCurryWith(lbl)
+ gge := RequestInFlight.With(lbl)
+
+ // Initialize the most likely HTTP status codes.
+ cnt.WithLabelValues("200")
+ cnt.WithLabelValues("500")
+
+ return promhttp.InstrumentHandlerDuration(
+ lat,
+ promhttp.InstrumentHandlerCounter(
+ cnt,
+ promhttp.InstrumentHandlerInFlight(gge, hookRaw),
+ ),
+ )
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/server.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
new file mode 100644
index 00000000000..23d5bf43507
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
@@ -0,0 +1,333 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package webhook
+
+import (
+ "context"
+ "crypto/tls"
+ "crypto/x509"
+ "fmt"
+ "net"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strconv"
+ "sync"
+ "time"
+
+ "sigs.k8s.io/controller-runtime/pkg/certwatcher"
+ "sigs.k8s.io/controller-runtime/pkg/healthz"
+ "sigs.k8s.io/controller-runtime/pkg/internal/httpserver"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
+)
+
+// DefaultPort is the default port that the webhook server serves.
+var DefaultPort = 9443
+
+// Server is an admission webhook server that can serve traffic and
+// generates related k8s resources for deploying.
+//
+// TLS is required for a webhook to be accessed by kubernetes, so
+// you must provide a CertName and KeyName or have valid cert/key
+// at the default locations (tls.crt and tls.key). If you do not
+// want to configure TLS (i.e for testing purposes) run an
+// admission.StandaloneWebhook in your own server.
+type Server interface {
+ // NeedLeaderElection implements the LeaderElectionRunnable interface, which indicates
+ // the webhook server doesn't need leader election.
+ NeedLeaderElection() bool
+
+ // Register marks the given webhook as being served at the given path.
+ // It panics if two hooks are registered on the same path.
+ Register(path string, hook http.Handler)
+
+ // Start runs the server.
+ // It will install the webhook related resources depend on the server configuration.
+ Start(ctx context.Context) error
+
+ // StartedChecker returns an healthz.Checker which is healthy after the
+ // server has been started.
+ StartedChecker() healthz.Checker
+
+ // WebhookMux returns the servers WebhookMux
+ WebhookMux() *http.ServeMux
+}
+
+// Options are all the available options for a webhook.Server
+type Options struct {
+ // Host is the address that the server will listen on.
+ // Defaults to "" - all addresses.
+ Host string
+
+ // Port is the port number that the server will serve.
+ // It will be defaulted to 9443 if unspecified.
+ Port int
+
+ // CertDir is the directory that contains the server key and certificate. The
+ // server key and certificate.
+ CertDir string
+
+ // CertName is the server certificate name. Defaults to tls.crt.
+ //
+ // Note: This option should only be set when TLSOpts does not override GetCertificate.
+ CertName string
+
+ // KeyName is the server key name. Defaults to tls.key.
+ //
+ // Note: This option should only be set when TLSOpts does not override GetCertificate.
+ KeyName string
+
+ // ClientCAName is the CA certificate name which server used to verify remote(client)'s certificate.
+ // Defaults to "", which means server does not verify client's certificate.
+ ClientCAName string
+
+ // TLSVersion is the minimum version of TLS supported. Accepts
+ // "", "1.0", "1.1", "1.2" and "1.3" only ("" is equivalent to "1.0" for backwards compatibility)
+ // Deprecated: Use TLSOpts instead.
+ TLSMinVersion string
+
+ // TLSOpts is used to allow configuring the TLS config used for the server
+ TLSOpts []func(*tls.Config)
+
+ // WebhookMux is the multiplexer that handles different webhooks.
+ WebhookMux *http.ServeMux
+}
+
+// NewServer constructs a new Server from the provided options.
+func NewServer(o Options) Server {
+ return &DefaultServer{
+ Options: o,
+ }
+}
+
+// DefaultServer is the default implementation used for Server.
+type DefaultServer struct {
+ Options Options
+
+ // webhooks keep track of all registered webhooks
+ webhooks map[string]http.Handler
+
+ // defaultingOnce ensures that the default fields are only ever set once.
+ defaultingOnce sync.Once
+
+ // started is set to true immediately before the server is started
+ // and thus can be used to check if the server has been started
+ started bool
+
+ // mu protects access to the webhook map & setFields for Start, Register, etc
+ mu sync.Mutex
+
+ webhookMux *http.ServeMux
+}
+
+// setDefaults does defaulting for the Server.
+func (o *Options) setDefaults() {
+ if o.WebhookMux == nil {
+ o.WebhookMux = http.NewServeMux()
+ }
+
+ if o.Port <= 0 {
+ o.Port = DefaultPort
+ }
+
+ if len(o.CertDir) == 0 {
+ o.CertDir = filepath.Join(os.TempDir(), "k8s-webhook-server", "serving-certs")
+ }
+
+ if len(o.CertName) == 0 {
+ o.CertName = "tls.crt"
+ }
+
+ if len(o.KeyName) == 0 {
+ o.KeyName = "tls.key"
+ }
+}
+
+func (s *DefaultServer) setDefaults() {
+ s.webhooks = map[string]http.Handler{}
+ s.Options.setDefaults()
+
+ s.webhookMux = s.Options.WebhookMux
+}
+
+// NeedLeaderElection implements the LeaderElectionRunnable interface, which indicates
+// the webhook server doesn't need leader election.
+func (*DefaultServer) NeedLeaderElection() bool {
+ return false
+}
+
+// Register marks the given webhook as being served at the given path.
+// It panics if two hooks are registered on the same path.
+func (s *DefaultServer) Register(path string, hook http.Handler) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ s.defaultingOnce.Do(s.setDefaults)
+ if _, found := s.webhooks[path]; found {
+ panic(fmt.Errorf("can't register duplicate path: %v", path))
+ }
+ s.webhooks[path] = hook
+ s.webhookMux.Handle(path, metrics.InstrumentedHook(path, hook))
+
+ regLog := log.WithValues("path", path)
+ regLog.Info("Registering webhook")
+}
+
+// tlsVersion converts from human-readable TLS version (for example "1.1")
+// to the values accepted by tls.Config (for example 0x301).
+func tlsVersion(version string) (uint16, error) {
+ switch version {
+ // default is previous behaviour
+ case "":
+ return tls.VersionTLS10, nil
+ case "1.0":
+ return tls.VersionTLS10, nil
+ case "1.1":
+ return tls.VersionTLS11, nil
+ case "1.2":
+ return tls.VersionTLS12, nil
+ case "1.3":
+ return tls.VersionTLS13, nil
+ default:
+ return 0, fmt.Errorf("invalid TLSMinVersion %v: expects 1.0, 1.1, 1.2, 1.3 or empty", version)
+ }
+}
+
+// Start runs the server.
+// It will install the webhook related resources depend on the server configuration.
+func (s *DefaultServer) Start(ctx context.Context) error {
+ s.defaultingOnce.Do(s.setDefaults)
+
+ baseHookLog := log.WithName("webhooks")
+ baseHookLog.Info("Starting webhook server")
+
+ tlsMinVersion, err := tlsVersion(s.Options.TLSMinVersion)
+ if err != nil {
+ return err
+ }
+
+ cfg := &tls.Config{ //nolint:gosec
+ NextProtos: []string{"h2"},
+ MinVersion: tlsMinVersion,
+ }
+ // fallback TLS config ready, will now mutate if passer wants full control over it
+ for _, op := range s.Options.TLSOpts {
+ op(cfg)
+ }
+
+ if cfg.GetCertificate == nil {
+ certPath := filepath.Join(s.Options.CertDir, s.Options.CertName)
+ keyPath := filepath.Join(s.Options.CertDir, s.Options.KeyName)
+
+ // Create the certificate watcher and
+ // set the config's GetCertificate on the TLSConfig
+ certWatcher, err := certwatcher.New(certPath, keyPath)
+ if err != nil {
+ return err
+ }
+ cfg.GetCertificate = certWatcher.GetCertificate
+
+ go func() {
+ if err := certWatcher.Start(ctx); err != nil {
+ log.Error(err, "certificate watcher error")
+ }
+ }()
+ }
+
+ // Load CA to verify client certificate, if configured.
+ if s.Options.ClientCAName != "" {
+ certPool := x509.NewCertPool()
+ clientCABytes, err := os.ReadFile(filepath.Join(s.Options.CertDir, s.Options.ClientCAName))
+ if err != nil {
+ return fmt.Errorf("failed to read client CA cert: %w", err)
+ }
+
+ ok := certPool.AppendCertsFromPEM(clientCABytes)
+ if !ok {
+ return fmt.Errorf("failed to append client CA cert to CA pool")
+ }
+
+ cfg.ClientCAs = certPool
+ cfg.ClientAuth = tls.RequireAndVerifyClientCert
+ }
+
+ listener, err := tls.Listen("tcp", net.JoinHostPort(s.Options.Host, strconv.Itoa(s.Options.Port)), cfg)
+ if err != nil {
+ return err
+ }
+
+ log.Info("Serving webhook server", "host", s.Options.Host, "port", s.Options.Port)
+
+ srv := httpserver.New(s.webhookMux)
+
+ idleConnsClosed := make(chan struct{})
+ go func() {
+ <-ctx.Done()
+ log.Info("Shutting down webhook server with timeout of 1 minute")
+
+ ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
+ defer cancel()
+ if err := srv.Shutdown(ctx); err != nil {
+ // Error from closing listeners, or context timeout
+ log.Error(err, "error shutting down the HTTP server")
+ }
+ close(idleConnsClosed)
+ }()
+
+ s.mu.Lock()
+ s.started = true
+ s.mu.Unlock()
+ if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed {
+ return err
+ }
+
+ <-idleConnsClosed
+ return nil
+}
+
+// StartedChecker returns an healthz.Checker which is healthy after the
+// server has been started.
+func (s *DefaultServer) StartedChecker() healthz.Checker {
+ config := &tls.Config{
+ InsecureSkipVerify: true, //nolint:gosec // config is used to connect to our own webhook port.
+ }
+ return func(req *http.Request) error {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ if !s.started {
+ return fmt.Errorf("webhook server has not been started yet")
+ }
+
+ d := &net.Dialer{Timeout: 10 * time.Second}
+ conn, err := tls.DialWithDialer(d, "tcp", net.JoinHostPort(s.Options.Host, strconv.Itoa(s.Options.Port)), config)
+ if err != nil {
+ return fmt.Errorf("webhook server is not reachable: %w", err)
+ }
+
+ if err := conn.Close(); err != nil {
+ return fmt.Errorf("webhook server is not reachable: closing connection: %w", err)
+ }
+
+ return nil
+ }
+}
+
+// WebhookMux returns the servers WebhookMux
+func (s *DefaultServer) WebhookMux() *http.ServeMux {
+ return s.webhookMux
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/server_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/server_test.go
new file mode 100644
index 00000000000..9702b0fd6e9
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/server_test.go
@@ -0,0 +1,260 @@
+/*
+Copyright 2019 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package webhook_test
+
+import (
+ "context"
+ "crypto/tls"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "path"
+ "reflect"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+var _ = Describe("Webhook Server", func() {
+ var (
+ ctx context.Context
+ ctxCancel context.CancelFunc
+ testHostPort string
+ client *http.Client
+ server webhook.Server
+ servingOpts envtest.WebhookInstallOptions
+ )
+
+ BeforeEach(func() {
+ ctx, ctxCancel = context.WithCancel(context.Background())
+ // closed in individual tests differently
+
+ servingOpts = envtest.WebhookInstallOptions{}
+ Expect(servingOpts.PrepWithoutInstalling()).To(Succeed())
+
+ testHostPort = net.JoinHostPort(servingOpts.LocalServingHost, fmt.Sprintf("%d", servingOpts.LocalServingPort))
+
+ // bypass needing to set up the x509 cert pool, etc ourselves
+ clientTransport, err := rest.TransportFor(&rest.Config{
+ TLSClientConfig: rest.TLSClientConfig{CAData: servingOpts.LocalServingCAData},
+ })
+ Expect(err).NotTo(HaveOccurred())
+ client = &http.Client{
+ Transport: clientTransport,
+ }
+
+ server = webhook.NewServer(webhook.Options{
+ Host: servingOpts.LocalServingHost,
+ Port: servingOpts.LocalServingPort,
+ CertDir: servingOpts.LocalServingCertDir,
+ })
+ })
+ AfterEach(func() {
+ Expect(servingOpts.Cleanup()).To(Succeed())
+ })
+
+ genericStartServer := func(f func(ctx context.Context)) (done <-chan struct{}) {
+ doneCh := make(chan struct{})
+ go func() {
+ defer GinkgoRecover()
+ defer close(doneCh)
+ f(ctx)
+ }()
+ // wait till we can ping the server to start the test
+ Eventually(func() error {
+ _, err := client.Get(fmt.Sprintf("https://%s/unservedpath", testHostPort))
+ return err
+ }).Should(Succeed())
+
+ return doneCh
+ }
+
+ startServer := func() (done <-chan struct{}) {
+ return genericStartServer(func(ctx context.Context) {
+ Expect(server.Start(ctx)).To(Succeed())
+ })
+ }
+
+ // TODO(directxman12): figure out a good way to test all the serving setup
+ // with httptest.Server to get all the niceness from that.
+
+ Context("when serving", func() {
+ PIt("should verify the client CA name when asked to", func() {
+
+ })
+ PIt("should support HTTP/2", func() {
+
+ })
+
+ // TODO(directxman12): figure out a good way to test the port default, etc
+ })
+
+ It("should panic if a duplicate path is registered", func() {
+ server.Register("/somepath", &testHandler{})
+ doneCh := startServer()
+
+ Expect(func() { server.Register("/somepath", &testHandler{}) }).To(Panic())
+
+ ctxCancel()
+ Eventually(doneCh, "4s").Should(BeClosed())
+ })
+
+ Context("when registering new webhooks before starting", func() {
+ It("should serve a webhook on the requested path", func() {
+ server.Register("/somepath", &testHandler{})
+
+ Expect(server.StartedChecker()(nil)).ToNot(Succeed())
+
+ doneCh := startServer()
+
+ Eventually(func() ([]byte, error) {
+ resp, err := client.Get(fmt.Sprintf("https://%s/somepath", testHostPort))
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ return io.ReadAll(resp.Body)
+ }).Should(Equal([]byte("gadzooks!")))
+
+ Expect(server.StartedChecker()(nil)).To(Succeed())
+
+ ctxCancel()
+ Eventually(doneCh, "4s").Should(BeClosed())
+ })
+ })
+
+ Context("when registering webhooks after starting", func() {
+ var (
+ doneCh <-chan struct{}
+ )
+ BeforeEach(func() {
+ doneCh = startServer()
+ })
+ AfterEach(func() {
+ // wait for cleanup to happen
+ ctxCancel()
+ Eventually(doneCh, "4s").Should(BeClosed())
+ })
+
+ It("should serve a webhook on the requested path", func() {
+ server.Register("/somepath", &testHandler{})
+ resp, err := client.Get(fmt.Sprintf("https://%s/somepath", testHostPort))
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+
+ Expect(io.ReadAll(resp.Body)).To(Equal([]byte("gadzooks!")))
+ })
+ })
+
+ It("should respect passed in TLS configurations", func() {
+ var finalCfg *tls.Config
+ tlsCfgFunc := func(cfg *tls.Config) {
+ cfg.CipherSuites = []uint16{
+ tls.TLS_AES_128_GCM_SHA256,
+ tls.TLS_AES_256_GCM_SHA384,
+ }
+ // save cfg after changes to test against
+ finalCfg = cfg
+ }
+ server = webhook.NewServer(webhook.Options{
+ Host: servingOpts.LocalServingHost,
+ Port: servingOpts.LocalServingPort,
+ CertDir: servingOpts.LocalServingCertDir,
+ TLSMinVersion: "1.2",
+ TLSOpts: []func(*tls.Config){
+ tlsCfgFunc,
+ },
+ })
+ server.Register("/somepath", &testHandler{})
+ doneCh := genericStartServer(func(ctx context.Context) {
+ Expect(server.Start(ctx)).To(Succeed())
+ })
+
+ Eventually(func() ([]byte, error) {
+ resp, err := client.Get(fmt.Sprintf("https://%s/somepath", testHostPort))
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ return io.ReadAll(resp.Body)
+ }).Should(Equal([]byte("gadzooks!")))
+ Expect(finalCfg.MinVersion).To(Equal(uint16(tls.VersionTLS12)))
+ Expect(finalCfg.CipherSuites).To(ContainElements(
+ tls.TLS_AES_128_GCM_SHA256,
+ tls.TLS_AES_256_GCM_SHA384,
+ ))
+
+ ctxCancel()
+ Eventually(doneCh, "4s").Should(BeClosed())
+ })
+
+ It("should prefer GetCertificate through TLSOpts", func() {
+ var finalCfg *tls.Config
+ finalCert, err := tls.LoadX509KeyPair(
+ path.Join(servingOpts.LocalServingCertDir, "tls.crt"),
+ path.Join(servingOpts.LocalServingCertDir, "tls.key"),
+ )
+ Expect(err).NotTo(HaveOccurred())
+ finalGetCertificate := func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) { //nolint:unparam
+ return &finalCert, nil
+ }
+ server = &webhook.DefaultServer{Options: webhook.Options{
+ Host: servingOpts.LocalServingHost,
+ Port: servingOpts.LocalServingPort,
+ CertDir: servingOpts.LocalServingCertDir,
+ TLSMinVersion: "1.2",
+ TLSOpts: []func(*tls.Config){
+ func(cfg *tls.Config) {
+ cfg.GetCertificate = finalGetCertificate
+ // save cfg after changes to test against
+ finalCfg = cfg
+ },
+ },
+ }}
+ server.Register("/somepath", &testHandler{})
+ doneCh := genericStartServer(func(ctx context.Context) {
+ Expect(server.Start(ctx)).To(Succeed())
+ })
+
+ Eventually(func() ([]byte, error) {
+ resp, err := client.Get(fmt.Sprintf("https://%s/somepath", testHostPort))
+ Expect(err).NotTo(HaveOccurred())
+ defer resp.Body.Close()
+ return io.ReadAll(resp.Body)
+ }).Should(Equal([]byte("gadzooks!")))
+ Expect(finalCfg.MinVersion).To(Equal(uint16(tls.VersionTLS12)))
+ // We can't compare the functions directly, but we can compare their pointers
+ if reflect.ValueOf(finalCfg.GetCertificate).Pointer() != reflect.ValueOf(finalGetCertificate).Pointer() {
+ Fail("GetCertificate was not set properly, or overwritten")
+ }
+ cert, err := finalCfg.GetCertificate(nil)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cert).To(BeEquivalentTo(&finalCert))
+
+ ctxCancel()
+ Eventually(doneCh, "4s").Should(BeClosed())
+ })
+})
+
+type testHandler struct {
+}
+
+func (t *testHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
+ if _, err := resp.Write([]byte("gadzooks!")); err != nil {
+ panic("unable to write http response!")
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/webhook_integration_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/webhook_integration_test.go
new file mode 100644
index 00000000000..716692124be
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/webhook_integration_test.go
@@ -0,0 +1,159 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package webhook_test
+
+import (
+ "context"
+ "crypto/tls"
+ "strings"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+var _ = Describe("Webhook", func() {
+ var c client.Client
+ var obj *appsv1.Deployment
+ BeforeEach(func() {
+ Expect(cfg).NotTo(BeNil())
+ var err error
+ c, err = client.New(cfg, client.Options{})
+ Expect(err).NotTo(HaveOccurred())
+
+ obj = &appsv1.Deployment{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "apps/v1",
+ Kind: "Deployment",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-deployment",
+ Namespace: "default",
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"foo": "bar"},
+ },
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "nginx",
+ Image: "nginx",
+ },
+ },
+ },
+ },
+ },
+ }
+ })
+ Context("when running a webhook server with a manager", func() {
+ It("should reject create request for webhook that rejects all requests", func() {
+ m, err := manager.New(cfg, manager.Options{
+ Port: testenv.WebhookInstallOptions.LocalServingPort,
+ Host: testenv.WebhookInstallOptions.LocalServingHost,
+ CertDir: testenv.WebhookInstallOptions.LocalServingCertDir,
+ TLSOpts: []func(*tls.Config){func(config *tls.Config) {}},
+ }) // we need manager here just to leverage manager.SetFields
+ Expect(err).NotTo(HaveOccurred())
+ server := m.GetWebhookServer()
+ server.Register("/failing", &webhook.Admission{Handler: &rejectingValidator{d: admission.NewDecoder(testenv.Scheme)}})
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ err := server.Start(ctx)
+ Expect(err).NotTo(HaveOccurred())
+ }()
+
+ Eventually(func() bool {
+ err := c.Create(context.TODO(), obj)
+ return err != nil && strings.HasSuffix(err.Error(), "Always denied") && apierrors.ReasonForError(err) == metav1.StatusReasonForbidden
+ }, 1*time.Second).Should(BeTrue())
+
+ cancel()
+ })
+ It("should reject create request for multi-webhook that rejects all requests", func() {
+ m, err := manager.New(cfg, manager.Options{
+ MetricsBindAddress: "0",
+ Port: testenv.WebhookInstallOptions.LocalServingPort,
+ Host: testenv.WebhookInstallOptions.LocalServingHost,
+ CertDir: testenv.WebhookInstallOptions.LocalServingCertDir,
+ TLSOpts: []func(*tls.Config){func(config *tls.Config) {}},
+ }) // we need manager here just to leverage manager.SetFields
+ Expect(err).NotTo(HaveOccurred())
+ server := m.GetWebhookServer()
+ server.Register("/failing", &webhook.Admission{Handler: admission.MultiValidatingHandler(&rejectingValidator{d: admission.NewDecoder(testenv.Scheme)})})
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ err = server.Start(ctx)
+ Expect(err).NotTo(HaveOccurred())
+ }()
+
+ Eventually(func() bool {
+ err = c.Create(context.TODO(), obj)
+ return err != nil && strings.HasSuffix(err.Error(), "Always denied") && apierrors.ReasonForError(err) == metav1.StatusReasonForbidden
+ }, 1*time.Second).Should(BeTrue())
+
+ cancel()
+ })
+ })
+ Context("when running a webhook server without a manager", func() {
+ It("should reject create request for webhook that rejects all requests", func() {
+ server := webhook.NewServer(webhook.Options{
+ Port: testenv.WebhookInstallOptions.LocalServingPort,
+ Host: testenv.WebhookInstallOptions.LocalServingHost,
+ CertDir: testenv.WebhookInstallOptions.LocalServingCertDir,
+ })
+ server.Register("/failing", &webhook.Admission{Handler: &rejectingValidator{d: admission.NewDecoder(testenv.Scheme)}})
+
+ ctx, cancel := context.WithCancel(context.Background())
+ go func() {
+ err := server.Start(ctx)
+ Expect(err).NotTo(HaveOccurred())
+ }()
+
+ Eventually(func() bool {
+ err := c.Create(context.TODO(), obj)
+ return err != nil && strings.HasSuffix(err.Error(), "Always denied") && apierrors.ReasonForError(err) == metav1.StatusReasonForbidden
+ }, 1*time.Second).Should(BeTrue())
+
+ cancel()
+ })
+ })
+})
+
+type rejectingValidator struct {
+ d *admission.Decoder
+}
+
+func (v *rejectingValidator) Handle(ctx context.Context, req admission.Request) admission.Response {
+ var obj appsv1.Deployment
+ if err := v.d.Decode(req, &obj); err != nil {
+ return admission.Denied(err.Error())
+ }
+ return admission.Denied("Always denied")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/webhook_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/webhook_suite_test.go
new file mode 100644
index 00000000000..ee9c1f4057f
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/pkg/webhook/webhook_suite_test.go
@@ -0,0 +1,105 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package webhook_test
+
+import (
+ "fmt"
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ admissionv1 "k8s.io/api/admissionregistration/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/client-go/rest"
+
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+)
+
+func TestSource(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Webhook Integration Suite")
+}
+
+var testenv *envtest.Environment
+var cfg *rest.Config
+
+var _ = BeforeSuite(func() {
+ logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+
+ testenv = &envtest.Environment{}
+ // we're initializing webhook here and not in webhook.go to also test the envtest install code via WebhookOptions
+ initializeWebhookInEnvironment()
+ var err error
+ cfg, err = testenv.Start()
+ Expect(err).NotTo(HaveOccurred())
+})
+
+var _ = AfterSuite(func() {
+ fmt.Println("stopping?")
+ Expect(testenv.Stop()).To(Succeed())
+})
+
+func initializeWebhookInEnvironment() {
+ namespacedScopeV1 := admissionv1.NamespacedScope
+ failedTypeV1 := admissionv1.Fail
+ equivalentTypeV1 := admissionv1.Equivalent
+ noSideEffectsV1 := admissionv1.SideEffectClassNone
+ webhookPathV1 := "/failing"
+
+ testenv.WebhookInstallOptions = envtest.WebhookInstallOptions{
+ ValidatingWebhooks: []*admissionv1.ValidatingWebhookConfiguration{
+ {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "deployment-validation-webhook-config",
+ },
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ValidatingWebhookConfiguration",
+ APIVersion: "admissionregistration.k8s.io/v1",
+ },
+ Webhooks: []admissionv1.ValidatingWebhook{
+ {
+ Name: "deployment-validation.kubebuilder.io",
+ Rules: []admissionv1.RuleWithOperations{
+ {
+ Operations: []admissionv1.OperationType{"CREATE", "UPDATE"},
+ Rule: admissionv1.Rule{
+ APIGroups: []string{"apps"},
+ APIVersions: []string{"v1"},
+ Resources: []string{"deployments"},
+ Scope: &namespacedScopeV1,
+ },
+ },
+ },
+ FailurePolicy: &failedTypeV1,
+ MatchPolicy: &equivalentTypeV1,
+ SideEffects: &noSideEffectsV1,
+ ClientConfig: admissionv1.WebhookClientConfig{
+ Service: &admissionv1.ServiceReference{
+ Name: "deployment-validation-service",
+ Namespace: "default",
+ Path: &webhookPathV1,
+ },
+ },
+ AdmissionReviewVersions: []string{"v1"},
+ },
+ },
+ },
+ },
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/README.md b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/README.md
new file mode 100644
index 00000000000..40379c9b8cc
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/README.md
@@ -0,0 +1,125 @@
+# Envtest Binaries Manager
+
+This is a small tool that manages binaries for envtest. It can be used to
+download new binaries, list currently installed and available ones, and
+clean up versions.
+
+To use it, just go-install it on 1.16+ (it's a separate, self-contained
+module):
+
+```shell
+go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
+```
+
+For full documentation, run it with the `--help` flag, but here are some
+examples:
+
+```shell
+# download the latest envtest, and print out info about it
+setup-envtest use
+
+# download the latest 1.19 envtest, and print out the path
+setup-envtest use -p path 1.19.x!
+
+# switch to the most recent 1.21 envtest on disk
+source <(setup-envtest use -i -p env 1.21.x)
+
+# list all available local versions for darwin/amd64
+setup-envtest list -i --os darwin --arch amd64
+
+# remove all versions older than 1.16 from disk
+setup-envtest cleanup <1.16
+
+# use the value from $KUBEBUILDER_ASSETS if set, otherwise follow the normal
+# logic for 'use'
+setup-envtest --use-env
+
+# use the value from $KUBEBUILDER_ASSETS if set, otherwise use the latest
+# installed version
+setup-envtest use -i --use-env
+
+# sideload a pre-downloaded tarball as Kubernetes 1.16.2 into our store
+setup-envtest sideload 1.16.2 < downloaded-envtest.tar.gz
+```
+
+## Where does it put all those binaries?
+
+By default, binaries are stored in a subdirectory of an OS-specific data
+directory, as per the OS's conventions.
+
+On Linux, this is `$XDG_DATA_HOME`; on Windows, `%LocalAppData`; and on
+OSX, `~/Library/Application Support`.
+
+There's an overall folder that holds all files, and inside that is
+a folder for each version/platform pair. The exact directory structure is
+not guarnateed, except that the leaf directory will contain the names
+expected by envtest. You should always use `setup-envtest fetch` or
+`setup-envtest switch` (generally with the `-p path` or `-p env` flags) to
+get the directory that you should use.
+
+## Why do I have to do that `source <(blah blah blah)` thing
+
+This is a normal binary, not a shell script, so we can't set the parent
+process's environment variables. If you use this by hand a lot and want
+to save the typing, you could put something like the following in your
+`~/.zshrc` (or similar for bash/fish/whatever, modified to those):
+
+```shell
+setup-envtest() {
+ if (($@[(Ie)use])); then
+ source <($GOPATH/bin/setup-envtest "$@" -p env)
+ else
+ $GOPATH/bin/setup-envtest "$@"
+ fi
+}
+```
+
+## What if I don't want to talk to the internet?
+
+There are a few options.
+
+First, you'll probably want to set the `-i/--installed` flag. If you want
+to avoid forgetting to set this flag, set the `ENVTEST_INSTALLED_ONLY`
+env variable, which will switch that flag on by default.
+
+Then, you have a few options for managing your binaries:
+
+- If you don't *really* want to manage with this tool, or you want to
+ respect the $KUBEBUILDER_ASSETS variable if it's set to something
+ outside the store, use the `use --use-env -i` command.
+
+ `--use-env` makes the command unconditionally use the value of
+ KUBEBUILDER_ASSETS as long as it contains the required binaries, and
+ `-i` indicates that we only ever want to work with installed binaries
+ (no reaching out the remote GCS storage).
+
+ As noted about, you can use `ENVTEST_INSTALLED_ONLY=true` to switch `-i`
+ on by default, and you can use `ENVTEST_USE_ENV=true` to switch
+ `--use-env` on by default.
+
+- If you want to use this tool, but download your gziped tarballs
+ separately, you can use the `sideload` command. You'll need to use the
+ `-k/--version` flag to indicate which version you're sideloading.
+
+ After that, it'll be as if you'd installed the binaries with `use`.
+
+- If you want to talk to some internal source, you can use the
+ `--remote-bucket` and `--remote-server` options. The former sets which
+ GCS bucket to download from, and the latter sets the host to talk to as
+ if it were a GCS endpoint. Theoretically, you could use the latter
+ version to run an internal "mirror" -- the tool expects
+
+ - `HOST/storage/v1/b/BUCKET/o` to return JSON like
+
+ ```json
+ {"items": [
+ {"name": "kubebuilder-tools-X.Y.Z-os-arch.tar.gz", "md5Hash": ""},
+ {"name": "kubebuilder-tools-X.Y.Z-os-arch.tar.gz", "md5Hash": ""},
+ ]}
+ ```
+
+ - `HOST/storage/v1/b/BUCKET/o/TARBALL_NAME` to return JSON like
+ `{"name": "kubebuilder-tools-X.Y.Z-os-arch.tar.gz", "md5Hash": ""}`
+
+ - `HOST/storage/v1/b/BUCKET/o/TARBALL_NAME?alt=media` to return the
+ actual file contents
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/env.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/env.go
new file mode 100644
index 00000000000..e12a107352e
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/env.go
@@ -0,0 +1,478 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2021 The Kubernetes Authors
+
+package env
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "io/fs"
+ "path/filepath"
+ "sort"
+ "strings"
+ "text/tabwriter"
+
+ "github.com/go-logr/logr"
+ "github.com/spf13/afero" // too bad fs.FS isn't writable :-/
+
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/remote"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/store"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/versions"
+)
+
+// Env represents an environment for downloading and otherwise manipulating
+// envtest binaries.
+//
+// In general, the methods will use the Exit{,Cause} functions from this package
+// to indicate errors. Catch them with a `defer HandleExitWithCode()`.
+type Env struct {
+ // the following *must* be set on input
+
+ // Platform is our current platform
+ Platform versions.PlatformItem
+
+ // VerifiySum indicates whether or not we should run checksums.
+ VerifySum bool
+ // NoDownload forces us to not contact GCS, looking only
+ // at local files instead.
+ NoDownload bool
+ // ForceDownload forces us to ignore local files and always
+ // contact GCS & re-download.
+ ForceDownload bool
+
+ // Client is our remote client for contacting GCS.
+ Client *remote.Client
+
+ // Log allows us to log.
+ Log logr.Logger
+
+ // the following *may* be set on input, or may be discovered
+
+ // Version is the version(s) that we want to download
+ // (may be automatically retrieved later on).
+ Version versions.Spec
+
+ // Store is used to load/store entries to/from disk.
+ Store *store.Store
+
+ // FS is the file system to read from/write to for provisioning temp files
+ // for storing the archives temporarily.
+ FS afero.Afero
+
+ // Out is the place to write output text to
+ Out io.Writer
+
+ // manualPath is the manually discovered path from PathMatches, if
+ // a non-store path was used. It'll be printed by PrintInfo if present.
+ manualPath string
+}
+
+// CheckCoherence checks that this environment has filled-out, coherent settings
+// (e.g. NoDownload & ForceDownload aren't both set).
+func (e *Env) CheckCoherence() {
+ if e.NoDownload && e.ForceDownload {
+ Exit(2, "cannot both skip downloading *and* force re-downloading")
+ }
+
+ if e.Platform.OS == "" || e.Platform.Arch == "" {
+ Exit(2, "must specify non-empty OS and arch (did you specify bad --os or --arch values?)")
+ }
+}
+
+func (e *Env) filter() store.Filter {
+ return store.Filter{Version: e.Version, Platform: e.Platform.Platform}
+}
+
+func (e *Env) item() store.Item {
+ concreteVer := e.Version.AsConcrete()
+ if concreteVer == nil || e.Platform.IsWildcard() {
+ panic("no platform/version set") // unexpected, print stack trace
+ }
+ return store.Item{Version: *concreteVer, Platform: e.Platform.Platform}
+}
+
+// ListVersions prints out all available versions matching this Env's
+// platform & version selector (respecting NoDownload to figure
+// out whether or not to match remote versions).
+func (e *Env) ListVersions(ctx context.Context) {
+ out := tabwriter.NewWriter(e.Out, 4, 4, 2, ' ', 0)
+ defer out.Flush()
+ localVersions, err := e.Store.List(ctx, e.filter())
+ if err != nil {
+ ExitCause(2, err, "unable to list installed versions")
+ }
+ for _, item := range localVersions {
+ // already filtered by onDiskVersions
+ fmt.Fprintf(out, "(installed)\tv%s\t%s\n", item.Version, item.Platform)
+ }
+
+ if e.NoDownload {
+ return
+ }
+
+ remoteVersions, err := e.Client.ListVersions(ctx)
+ if err != nil {
+ ExitCause(2, err, "unable list to available versions")
+ }
+
+ for _, set := range remoteVersions {
+ if !e.Version.Matches(set.Version) {
+ continue
+ }
+ sort.Slice(set.Platforms, func(i, j int) bool {
+ return orderPlatforms(set.Platforms[i].Platform, set.Platforms[j].Platform)
+ })
+ for _, plat := range set.Platforms {
+ if e.Platform.Matches(plat.Platform) {
+ fmt.Fprintf(out, "(available)\tv%s\t%s\n", set.Version, plat)
+ }
+ }
+ }
+}
+
+// LatestVersion returns the latest version matching our version selector and
+// platform from the remote server, with the correspoding checksum for later
+// use as well.
+func (e *Env) LatestVersion(ctx context.Context) (versions.Concrete, versions.PlatformItem) {
+ vers, err := e.Client.ListVersions(ctx)
+ if err != nil {
+ ExitCause(2, err, "unable to list versions to find latest one")
+ }
+ for _, set := range vers {
+ if !e.Version.Matches(set.Version) {
+ e.Log.V(1).Info("skipping non-matching version", "version", set.Version)
+ continue
+ }
+ // double-check that our platform is supported
+ for _, plat := range set.Platforms {
+ // NB(directxman12): we're already iterating in order, so no
+ // need to check if the wildcard is latest vs any
+ if e.Platform.Matches(plat.Platform) && e.Version.Matches(set.Version) {
+ return set.Version, plat
+ }
+ }
+ e.Log.Info("latest version not supported for your platform, checking older ones", "version", set.Version, "platform", e.Platform)
+ }
+
+ Exit(2, "unable to find a version that was supported for platform %s", e.Platform)
+ return versions.Concrete{}, versions.PlatformItem{} // unreachable, but Go's type system can't express the "never" type
+}
+
+// ExistsAndValid checks if our current (concrete) version & platform
+// exist on disk (unless ForceDownload is set, in which cause it always
+// returns false).
+//
+// Must be called after EnsureVersionIsSet so that we have a concrete
+// Version selected. Must have a concrete platform, or ForceDownload
+// must be set.
+func (e *Env) ExistsAndValid() bool {
+ if e.ForceDownload {
+ // we always want to download, so don't check here
+ return false
+ }
+
+ if e.Platform.IsWildcard() {
+ Exit(2, "you must have a concrete platform with this command -- you cannot use wildcard platforms with fetch or switch")
+ }
+
+ exists, err := e.Store.Has(e.item())
+ if err != nil {
+ ExitCause(2, err, "unable to check if existing version exists")
+ }
+
+ if exists {
+ e.Log.Info("applicable version found on disk", "version", e.Version)
+ }
+ return exists
+}
+
+// EnsureVersionIsSet ensures that we have a non-wildcard version
+// configured.
+//
+// If necessary, it will enumerate on-disk and remote versions to accomplish
+// this, finding a version that matches our version selector and platform.
+// It will always yield a concrete version, it *may* yield a concrete platorm
+// as well.
+func (e *Env) EnsureVersionIsSet(ctx context.Context) {
+ if e.Version.AsConcrete() != nil {
+ return
+ }
+ var localVer *versions.Concrete
+ var localPlat versions.Platform
+
+ items, err := e.Store.List(ctx, e.filter())
+ if err != nil {
+ ExitCause(2, err, "unable to determine installed versions")
+ }
+
+ for _, item := range items {
+ if !e.Version.Matches(item.Version) || !e.Platform.Matches(item.Platform) {
+ e.Log.V(1).Info("skipping version, doesn't match", "version", item.Version, "platform", item.Platform)
+ continue
+ }
+ // NB(directxman12): we're already iterating in order, so no
+ // need to check if the wildcard is latest vs any
+ ver := item.Version // copy to avoid referencing iteration variable
+ localVer = &ver
+ localPlat = item.Platform
+ break
+ }
+
+ if e.NoDownload || !e.Version.CheckLatest {
+ // no version specified, but we either
+ //
+ // a) shouldn't contact remote
+ // b) don't care to find the absolute latest
+ //
+ // so just find the latest local version
+ if localVer != nil {
+ e.Version.MakeConcrete(*localVer)
+ e.Platform.Platform = localPlat
+ return
+ }
+ if e.NoDownload {
+ Exit(2, "no applicable on-disk versions for %s found, you'll have to download one, or run list -i to see what you do have", e.Platform)
+ }
+ // if we didn't ask for the latest version, but don't have anything
+ // available, try the internet ;-)
+ }
+
+ // no version specified and we need the latest in some capacity, so find latest from remote
+ // so find the latest local first, then compare it to the latest remote, and use whichever
+ // of the two is more recent.
+ e.Log.Info("no version specified, finding latest")
+ serverVer, platform := e.LatestVersion(ctx)
+
+ // if we're not forcing a download, and we have a newer local version, just use that
+ if !e.ForceDownload && localVer != nil && localVer.NewerThan(serverVer) {
+ e.Platform.Platform = localPlat // update our data with md5
+ e.Version.MakeConcrete(*localVer)
+ return
+ }
+
+ // otherwise, use the new version from the server
+ e.Platform = platform // update our data with md5
+ e.Version.MakeConcrete(serverVer)
+}
+
+// Fetch ensures that the requested platform and version are on disk.
+// You must call EnsureVersionIsSet before calling this method.
+//
+// If ForceDownload is set, we always download, otherwise we only download
+// if we're missing the version on disk.
+func (e *Env) Fetch(ctx context.Context) {
+ log := e.Log.WithName("fetch")
+
+ // if we didn't just fetch it, grab the sum to verify
+ if e.VerifySum && e.Platform.MD5 == "" {
+ if err := e.Client.FetchSum(ctx, *e.Version.AsConcrete(), &e.Platform); err != nil {
+ ExitCause(2, err, "unable to fetch checksum for requested version")
+ }
+ }
+ if !e.VerifySum {
+ e.Platform.MD5 = "" // skip verification
+ }
+
+ var packedPath string
+
+ // cleanup on error (needs to be here so it will happen after the other defers)
+ defer e.cleanupOnError(func() {
+ if packedPath != "" {
+ e.Log.V(1).Info("cleaning up downloaded archive", "path", packedPath)
+ if err := e.FS.Remove(packedPath); err != nil && !errors.Is(err, fs.ErrNotExist) {
+ e.Log.Error(err, "unable to clean up archive path", "path", packedPath)
+ }
+ }
+ })
+
+ archiveOut, err := e.FS.TempFile("", "*-"+e.Platform.ArchiveName(*e.Version.AsConcrete()))
+ if err != nil {
+ ExitCause(2, err, "unable to open file to write downloaded archive to")
+ }
+ defer archiveOut.Close()
+ packedPath = archiveOut.Name()
+ log.V(1).Info("writing downloaded archive", "path", packedPath)
+
+ if err := e.Client.GetVersion(ctx, *e.Version.AsConcrete(), e.Platform, archiveOut); err != nil {
+ ExitCause(2, err, "unable to download requested version")
+ }
+ log.V(1).Info("downloaded archive", "path", packedPath)
+
+ if err := archiveOut.Sync(); err != nil { // sync before reading back
+ ExitCause(2, err, "unable to flush downloaded archive file")
+ }
+ if _, err := archiveOut.Seek(0, 0); err != nil {
+ ExitCause(2, err, "unable to jump back to beginning of archive file to unzip")
+ }
+
+ if err := e.Store.Add(ctx, e.item(), archiveOut); err != nil {
+ ExitCause(2, err, "unable to store version to disk")
+ }
+
+ log.V(1).Info("removing archive from disk", "path", packedPath)
+ if err := e.FS.Remove(packedPath); err != nil {
+ // don't bail, this isn't fatal
+ log.Error(err, "unable to remove downloaded archive", "path", packedPath)
+ }
+}
+
+// cleanup on error cleans up if we hit an exitCode error.
+//
+// Use it in a defer.
+func (e *Env) cleanupOnError(extraCleanup func()) {
+ cause := recover()
+ if cause == nil {
+ return
+ }
+ // don't panic in a panic handler
+ var exit *exitCode
+ if asExit(cause, &exit) && exit.code != 0 {
+ e.Log.Info("cleaning up due to error")
+ // we already log in the function, and don't want to panic, so
+ // ignore the error
+ extraCleanup()
+ }
+ panic(cause) // re-start the panic now that we're done
+}
+
+// Remove removes the data for our version selector & platform from disk.
+func (e *Env) Remove(ctx context.Context) {
+ items, err := e.Store.Remove(ctx, e.filter())
+ for _, item := range items {
+ fmt.Fprintf(e.Out, "removed %s\n", item)
+ }
+ if err != nil {
+ ExitCause(2, err, "unable to remove all requested version(s)")
+ }
+}
+
+// PrintInfo prints out information about a single, current version
+// and platform, according to the given formatting info.
+func (e *Env) PrintInfo(printFmt PrintFormat) {
+ // use the manual path if it's set, otherwise use the standard path
+ path := e.manualPath
+ if e.manualPath == "" {
+ item := e.item()
+ var err error
+ path, err = e.Store.Path(item)
+ if err != nil {
+ ExitCause(2, err, "unable to get path for version %s", item)
+ }
+ }
+ switch printFmt {
+ case PrintOverview:
+ fmt.Fprintf(e.Out, "Version: %s\n", e.Version)
+ fmt.Fprintf(e.Out, "OS/Arch: %s\n", e.Platform)
+ if e.Platform.MD5 != "" {
+ fmt.Fprintf(e.Out, "md5: %s\n", e.Platform.MD5)
+ }
+ fmt.Fprintf(e.Out, "Path: %s\n", path)
+ case PrintPath:
+ fmt.Fprint(e.Out, path) // NB(directxman12): no newline -- want the bare path here
+ case PrintEnv:
+ // quote in case there are spaces, etc in the path
+ // the weird string below works like this:
+ // - you can't escape quotes in shell
+ // - shell strings that are next to each other are concatenated (so "a""b""c" == "abc")
+ // - you can intermix quote styles using the above
+ // - so `'"'"'` --> CLOSE_QUOTE + "'" + OPEN_QUOTE
+ shellQuoted := strings.ReplaceAll(path, "'", `'"'"'`)
+ fmt.Fprintf(e.Out, "export KUBEBUILDER_ASSETS='%s'\n", shellQuoted)
+ default:
+ panic(fmt.Sprintf("unexpected print format %v", printFmt))
+ }
+}
+
+// EnsureBaseDirs ensures that the base packed and unpacked directories
+// exist.
+//
+// This should be the first thing called after CheckCoherence.
+func (e *Env) EnsureBaseDirs(ctx context.Context) {
+ if err := e.Store.Initialize(ctx); err != nil {
+ ExitCause(2, err, "unable to make sure store is initialized")
+ }
+}
+
+// Sideload takes an input stream, and loads it as if it had been a downloaded .tar.gz file
+// for the current *concrete* version and platform.
+func (e *Env) Sideload(ctx context.Context, input io.Reader) {
+ log := e.Log.WithName("sideload")
+ if e.Version.AsConcrete() == nil || e.Platform.IsWildcard() {
+ Exit(2, "must specify a concrete version and platform to sideload. Make sure you've passed a version, like 'sideload 1.21.0'")
+ }
+ log.V(1).Info("sideloading from input stream to version", "version", e.Version, "platform", e.Platform)
+ if err := e.Store.Add(ctx, e.item(), input); err != nil {
+ ExitCause(2, err, "unable to sideload item to disk")
+ }
+}
+
+var (
+ // expectedExectuables are the executables that are checked in PathMatches
+ // for non-store paths.
+ expectedExecutables = []string{
+ "kube-apiserver",
+ "etcd",
+ "kubectl",
+ }
+)
+
+// PathMatches checks if the path (e.g. from the environment variable)
+// matches this version & platform selector, and if so, returns true.
+func (e *Env) PathMatches(value string) bool {
+ e.Log.V(1).Info("checking if (env var) path represents our desired version", "path", value)
+ if value == "" {
+ // if we're unset,
+ return false
+ }
+
+ if e.versionFromPathName(value) {
+ e.Log.V(1).Info("path appears to be in our store, using that info", "path", value)
+ return true
+ }
+
+ e.Log.V(1).Info("path is not in our store, checking for binaries", "path", value)
+ for _, expected := range expectedExecutables {
+ _, err := e.FS.Stat(filepath.Join(value, expected))
+ if err != nil {
+ if errors.Is(err, fs.ErrNotExist) {
+ // one of our required binaries is missing, return false
+ e.Log.V(1).Info("missing required binary in (env var) path", "binary", expected, "path", value)
+ return false
+ }
+ ExitCause(2, err, "unable to check for existence of binary %s from existing (env var) path %s", value, expected)
+ }
+ }
+
+ // success, all binaries present
+ e.Log.V(1).Info("all required binaries present in (env var) path, using that", "path", value)
+
+ // don't bother checking the version, the user explicitly asked us to use this
+ // we don't know the version, so set it to wildcard
+ e.Version = versions.AnyVersion
+ e.Platform.OS = "*"
+ e.Platform.Arch = "*"
+ e.manualPath = value
+ return true
+}
+
+// versionFromPathName checks if the given path's last component looks like one
+// of our versions, and, if so, what version it represents. If succesfull,
+// it'll set version and platform, and return true. Otherwise it returns
+// false.
+func (e *Env) versionFromPathName(value string) bool {
+ baseName := filepath.Base(value)
+ ver, pl := versions.ExtractWithPlatform(versions.VersionPlatformRE, baseName)
+ if ver == nil {
+ // not a version that we can tell
+ return false
+ }
+
+ // yay we got a version!
+ e.Version.MakeConcrete(*ver)
+ e.Platform.Platform = pl
+ e.manualPath = value // might be outside our store, set this just in case
+
+ return true
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/env_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/env_suite_test.go
new file mode 100644
index 00000000000..3400dd91aaa
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/env_suite_test.go
@@ -0,0 +1,47 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package env_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ "github.com/go-logr/logr"
+ "github.com/go-logr/zapr"
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+)
+
+var testLog logr.Logger
+
+func zapLogger() logr.Logger {
+ testOut := zapcore.AddSync(GinkgoWriter)
+ enc := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
+ // bleh setting up logging to the ginkgo writer is annoying
+ zapLog := zap.New(zapcore.NewCore(enc, testOut, zap.DebugLevel),
+ zap.ErrorOutput(testOut), zap.Development(), zap.AddStacktrace(zap.WarnLevel))
+ return zapr.NewLogger(zapLog)
+}
+
+func TestEnv(t *testing.T) {
+ testLog = zapLogger()
+
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Env Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/env_test.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/env_test.go
new file mode 100644
index 00000000000..fd6e7633bda
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/env_test.go
@@ -0,0 +1,108 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package env_test
+
+import (
+ "bytes"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/spf13/afero"
+
+ . "sigs.k8s.io/controller-runtime/tools/setup-envtest/env"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/store"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/versions"
+)
+
+var _ = Describe("Env", func() {
+ // Most of the rest of this is tested e2e via the workflows test,
+ // but there's a few things that are easier to test here. Eventually
+ // we should maybe move some of the tests here.
+ var (
+ env *Env
+ outBuffer *bytes.Buffer
+ )
+ BeforeEach(func() {
+ outBuffer = new(bytes.Buffer)
+ env = &Env{
+ Out: outBuffer,
+ Log: testLog,
+
+ Store: &store.Store{
+ // use spaces and quotes to test our quote escaping below
+ Root: afero.NewBasePathFs(afero.NewMemMapFs(), "/kb's test store"),
+ },
+
+ // shouldn't use these, but just in case
+ NoDownload: true,
+ FS: afero.Afero{Fs: afero.NewMemMapFs()},
+ }
+
+ env.Version.MakeConcrete(versions.Concrete{
+ Major: 1, Minor: 21, Patch: 3,
+ })
+ env.Platform.Platform = versions.Platform{
+ OS: "linux", Arch: "amd64",
+ }
+ })
+
+ Describe("printing", func() {
+ It("should use a manual path if one is present", func() {
+ By("using a manual path")
+ Expect(env.PathMatches("/otherstore/1.21.4-linux-amd64")).To(BeTrue())
+
+ By("checking that that path is printed properly")
+ env.PrintInfo(PrintPath)
+ Expect(outBuffer.String()).To(Equal("/otherstore/1.21.4-linux-amd64"))
+ })
+
+ Context("as human-readable info", func() {
+ BeforeEach(func() {
+ env.PrintInfo(PrintOverview)
+ })
+
+ It("should contain the version", func() {
+ Expect(outBuffer.String()).To(ContainSubstring("/kb's test store/k8s/1.21.3-linux-amd64"))
+ })
+ It("should contain the path", func() {
+ Expect(outBuffer.String()).To(ContainSubstring("1.21.3"))
+ })
+ It("should contain the platform", func() {
+ Expect(outBuffer.String()).To(ContainSubstring("linux/amd64"))
+ })
+
+ })
+ Context("as just a path", func() {
+ It("should print out just the path", func() {
+ env.PrintInfo(PrintPath)
+ Expect(outBuffer.String()).To(Equal(`/kb's test store/k8s/1.21.3-linux-amd64`))
+ })
+ })
+
+ Context("as env vars", func() {
+ BeforeEach(func() {
+ env.PrintInfo(PrintEnv)
+ })
+ It("should set KUBEBUILDER_ASSETS", func() {
+ Expect(outBuffer.String()).To(HavePrefix("export KUBEBUILDER_ASSETS="))
+ })
+ It("should quote the return path, escaping quotes to deal with spaces, etc", func() {
+ Expect(outBuffer.String()).To(HaveSuffix(`='/kb'"'"'s test store/k8s/1.21.3-linux-amd64'` + "\n"))
+ })
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/exit.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/exit.go
new file mode 100644
index 00000000000..ae393b593b1
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/exit.go
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2021 The Kubernetes Authors
+
+package env
+
+import (
+ "errors"
+ "fmt"
+ "os"
+)
+
+// Exit exits with the given code and error message.
+//
+// Defer HandleExitWithCode in main to catch this and get the right behavior.
+func Exit(code int, msg string, args ...interface{}) {
+ panic(&exitCode{
+ code: code,
+ err: fmt.Errorf(msg, args...),
+ })
+}
+
+// ExitCause exits with the given code and error message, automatically
+// wrapping the underlying error passed as well.
+//
+// Defer HandleExitWithCode in main to catch this and get the right behavior.
+func ExitCause(code int, err error, msg string, args ...interface{}) {
+ args = append(args, err)
+ panic(&exitCode{
+ code: code,
+ err: fmt.Errorf(msg+": %w", args...),
+ })
+}
+
+// exitCode is an error that indicates, on a panic, to exit with the given code
+// and message.
+type exitCode struct {
+ code int
+ err error
+}
+
+func (c *exitCode) Error() string {
+ return fmt.Sprintf("%v (exit code %d)", c.err, c.code)
+}
+func (c *exitCode) Unwrap() error {
+ return c.err
+}
+
+// asExit checks if the given (panic) value is an exitCode error,
+// and if so stores it in the given pointer. It's roughly analogous
+// to errors.As, except it works on recover() values.
+func asExit(val interface{}, exit **exitCode) bool {
+ if val == nil {
+ return false
+ }
+ err, isErr := val.(error)
+ if !isErr {
+ return false
+ }
+ if !errors.As(err, exit) {
+ return false
+ }
+ return true
+}
+
+// HandleExitWithCode handles panics of type exitCode,
+// printing the status message and existing with the given
+// exit code, or re-raising if not an exitCode error.
+//
+// This should be the first defer in your main function.
+func HandleExitWithCode() {
+ if cause := recover(); CheckRecover(cause, func(code int, err error) {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(code)
+ }) {
+ panic(cause)
+ }
+}
+
+// CheckRecover checks the value of cause, calling the given callback
+// if it's an exitCode error. It returns true if we should re-panic
+// the cause.
+//
+// It's mainly useful for testing, normally you'd use HandleExitWithCode.
+func CheckRecover(cause interface{}, cb func(int, error)) bool {
+ if cause == nil {
+ return false
+ }
+ var exitErr *exitCode
+ if !asExit(cause, &exitErr) {
+ // re-raise if it's not an exit error
+ return true
+ }
+
+ cb(exitErr.code, exitErr.err)
+ return false
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/helpers.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/helpers.go
new file mode 100644
index 00000000000..2c98c88d959
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/env/helpers.go
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2021 The Kubernetes Authors
+
+package env
+
+import (
+ "fmt"
+
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/versions"
+)
+
+// orderPlatforms orders platforms by OS then arch.
+func orderPlatforms(first, second versions.Platform) bool {
+ // sort by OS, then arch
+ if first.OS != second.OS {
+ return first.OS < second.OS
+ }
+ return first.Arch < second.Arch
+}
+
+// PrintFormat indicates how to print out fetch and switch results.
+// It's a valid pflag.Value so it can be used as a flag directly.
+type PrintFormat int
+
+const (
+ // PrintOverview prints human-readable data,
+ // including path, version, arch, and checksum (when available).
+ PrintOverview PrintFormat = iota
+ // PrintPath prints *only* the path, with no decoration.
+ PrintPath
+ // PrintEnv prints the path with the corresponding env variable, so that
+ // you can source the output like
+ // `source $(fetch-envtest switch -p env 1.20.x)`.
+ PrintEnv
+)
+
+func (f PrintFormat) String() string {
+ switch f {
+ case PrintOverview:
+ return "overview"
+ case PrintPath:
+ return "path"
+ case PrintEnv:
+ return "env"
+ default:
+ panic(fmt.Sprintf("unexpected print format %d", int(f)))
+ }
+}
+
+// Set sets the value of this as a flag.
+func (f *PrintFormat) Set(val string) error {
+ switch val {
+ case "overview":
+ *f = PrintOverview
+ case "path":
+ *f = PrintPath
+ case "env":
+ *f = PrintEnv
+ default:
+ return fmt.Errorf("unknown print format %q, use one of overview|path|env", val)
+ }
+ return nil
+}
+
+// Type is the type of this value as a flag.
+func (PrintFormat) Type() string {
+ return "{overview|path|env}"
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/go.mod b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/go.mod
new file mode 100644
index 00000000000..542759927b7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/go.mod
@@ -0,0 +1,24 @@
+module sigs.k8s.io/controller-runtime/tools/setup-envtest
+
+go 1.20
+
+require (
+ github.com/go-logr/logr v1.2.0
+ github.com/go-logr/zapr v1.2.0
+ github.com/onsi/ginkgo/v2 v2.1.4
+ github.com/onsi/gomega v1.19.0
+ github.com/spf13/afero v1.6.0
+ github.com/spf13/pflag v1.0.5
+ go.uber.org/zap v1.19.1
+)
+
+require (
+ github.com/golang/protobuf v1.5.2 // indirect
+ go.uber.org/atomic v1.7.0 // indirect
+ go.uber.org/multierr v1.6.0 // indirect
+ golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
+ golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
+ golang.org/x/text v0.3.7 // indirect
+ google.golang.org/protobuf v1.26.0 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
+)
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/go.sum b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/go.sum
new file mode 100644
index 00000000000..cb4c52f3e6e
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/go.sum
@@ -0,0 +1,98 @@
+github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+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/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE=
+github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk=
+github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY=
+github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
+github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
+github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
+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/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
+github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
+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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+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.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+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.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4=
+go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
+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/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
+go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
+go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
+golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/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.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/main.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/main.go
new file mode 100644
index 00000000000..8dca7741572
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/main.go
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2021 The Kubernetes Authors
+
+package main
+
+import (
+ goflag "flag"
+ "fmt"
+ "os"
+ "runtime"
+
+ "github.com/go-logr/logr"
+ "github.com/go-logr/zapr"
+ "github.com/spf13/afero"
+ flag "github.com/spf13/pflag"
+ "go.uber.org/zap"
+
+ envp "sigs.k8s.io/controller-runtime/tools/setup-envtest/env"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/remote"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/store"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/versions"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows"
+)
+
+const (
+ // envNoDownload is an env variable that can be set to always force
+ // the --installed-only, -i flag to be set.
+ envNoDownload = "ENVTEST_INSTALLED_ONLY"
+ // envUseEnv is an env variable that can be set to control the --use-env
+ // flag globally.
+ envUseEnv = "ENVTEST_USE_ENV"
+)
+
+var (
+ force = flag.Bool("force", false, "force re-downloading dependencies, even if they're already present and correct")
+ installedOnly = flag.BoolP("installed-only", "i", os.Getenv(envNoDownload) != "",
+ "only look at installed versions -- do not query the remote API server, "+
+ "and error out if it would be necessary to")
+ verify = flag.Bool("verify", true, "verify dependencies while downloading")
+ useEnv = flag.Bool("use-env", os.Getenv(envUseEnv) != "", "whether to return the value of KUBEBUILDER_ASSETS if it's already set")
+
+ targetOS = flag.String("os", runtime.GOOS, "os to download for (e.g. linux, darwin, for listing operations, use '*' to list all platforms)")
+ targetArch = flag.String("arch", runtime.GOARCH, "architecture to download for (e.g. amd64, for listing operations, use '*' to list all platforms)")
+
+ // printFormat is the flag value for -p, --print.
+ printFormat = envp.PrintOverview
+ // zapLvl is the flag value for logging verbosity.
+ zapLvl = zap.WarnLevel
+
+ binDir = flag.String("bin-dir", "",
+ "directory to store binary assets (default: $OS_SPECIFIC_DATA_DIR/envtest-binaries)")
+ remoteBucket = flag.String("remote-bucket", "kubebuilder-tools", "remote GCS bucket to download from")
+ remoteServer = flag.String("remote-server", "storage.googleapis.com",
+ "remote server to query from. You can override this if you want to run "+
+ "an internal storage server instead, or for testing.")
+)
+
+// TODO(directxman12): handle interrupts?
+
+// setupLogging configures a Zap logger.
+func setupLogging() logr.Logger {
+ logCfg := zap.NewDevelopmentConfig()
+ logCfg.Level = zap.NewAtomicLevelAt(zapLvl)
+ zapLog, err := logCfg.Build()
+ if err != nil {
+ envp.ExitCause(1, err, "who logs the logger errors?")
+ }
+ return zapr.NewLogger(zapLog)
+}
+
+// setupEnv initializes the environment from flags.
+func setupEnv(globalLog logr.Logger, version string) *envp.Env {
+ log := globalLog.WithName("setup")
+ if *binDir == "" {
+ dataDir, err := store.DefaultStoreDir()
+ if err != nil {
+ envp.ExitCause(1, err, "unable to deterimine default binaries directory (use --bin-dir to manually override)")
+ }
+
+ *binDir = dataDir
+ }
+ log.V(1).Info("using binaries directory", "dir", *binDir)
+
+ env := &envp.Env{
+ Log: globalLog,
+ Client: &remote.Client{
+ Log: globalLog.WithName("storage-client"),
+ Bucket: *remoteBucket,
+ Server: *remoteServer,
+ },
+ VerifySum: *verify,
+ ForceDownload: *force,
+ NoDownload: *installedOnly,
+ Platform: versions.PlatformItem{
+ Platform: versions.Platform{
+ OS: *targetOS,
+ Arch: *targetArch,
+ },
+ },
+ FS: afero.Afero{Fs: afero.NewOsFs()},
+ Store: store.NewAt(*binDir),
+ Out: os.Stdout,
+ }
+
+ switch version {
+ case "", "latest":
+ env.Version = versions.LatestVersion
+ case "latest-on-disk":
+ // we sort by version, latest first, so this'll give us the latest on
+ // disk (as per the contract from env.List & store.List)
+ env.Version = versions.AnyVersion
+ env.NoDownload = true
+ default:
+ var err error
+ env.Version, err = versions.FromExpr(version)
+ if err != nil {
+ envp.ExitCause(1, err, "version be a valid version, or simply 'latest' or 'latest-on-disk'")
+ }
+ }
+
+ env.CheckCoherence()
+
+ return env
+}
+
+func main() {
+ // exit with appropriate error codes -- this should be the first defer so
+ // that it's the last one executed.
+ defer envp.HandleExitWithCode()
+
+ // set up flags
+ flag.Usage = func() {
+ name := os.Args[0]
+ fmt.Fprintf(os.Stderr, "Usage: %s [FLAGS] use|list|cleanup|sideload [VERSION]\n", name)
+ flag.PrintDefaults()
+ fmt.Fprintf(os.Stderr,
+ `
+Note: this command is currently alpha, and the usage/behavior may change from release to release.
+
+Examples:
+
+ # download the latest envtest, and print out info about it
+ %[1]s use
+
+ # download the latest 1.19 envtest, and print out the path
+ %[1]s use -p path 1.19.x!
+
+ # switch to the most recent 1.21 envtest on disk
+ source <(%[1]s use -i -p env 1.21.x)
+
+ # list all available local versions for darwin/amd64
+ %[1]s list -i --os darwin --arch amd64
+
+ # remove all versions older than 1.16 from disk
+ %[1]s cleanup <1.16
+
+ # use the value from $KUBEBUILDER_ASSETS if set, otherwise follow the normal
+ # logic for 'use'
+ %[1]s --use-env
+
+ # use the value from $KUBEBUILDER_ASSETS if set, otherwise use the latest
+ # installed version
+ %[1]s use -i --use-env
+
+ # sideload a pre-downloaded tarball as Kubernetes 1.16.2 into our store
+ %[1]s sideload 1.16.2 < downloaded-envtest.tar.gz
+
+Commands:
+
+ use:
+ get information for the requested version, downloading it if necessary and allowed.
+ Needs a concrete platform (no wildcards), but wilcard versions are supported.
+
+ list:
+ list installed *and* available versions matching the given version & platform.
+ May have wildcard versions *and* platforms.
+ If the -i flag is passed, only installed versions are listed.
+
+ cleanup:
+ remove all versions matching the given version & platform selector.
+ May have wildcard versions *and* platforms.
+
+ sideload:
+ reads a .tar.gz file from stdin and expand it into the store.
+ must have a concrete version and platform.
+
+Versions:
+
+ Versions take the form of a small subset of semver selectors.
+
+ Basic semver whole versions are accepted: X.Y.Z.
+ Z may also be '*' or 'x' to match a wildcard.
+ You may also just write X.Y, which means X.Y.*.
+
+ A version may be prefixed with '~' to match the most recent Z release
+ in the given Y release ( [X.Y.Z, X.Y+1.0) ).
+
+ Finally, you may suffix the version with '!' to force checking the
+ remote API server for the latest version.
+
+ For example:
+
+ 1.16.x / 1.16.* / 1.16 # any 1.16 version
+ ~1.19.3 # any 1.19 version that's at least 1.19.3
+ <1.17 # any release 1.17.x or below
+ 1.22.x! # the latest one 1.22 release available remotely
+
+Output:
+
+ The fetch & switch commands respect the --print, -p flag.
+
+ overview: human readable information
+ path: print out the path, by itself
+ env: print out the path in a form that can be sourced to use that version with envtest
+
+ Other command have human-readable output formats only.
+
+Environment Variables:
+
+ KUBEBUILDER_ASSETS:
+ --use-env will check this, and '-p/--print env' will return this.
+ If --use-env is true and this is set, we won't check our store
+ for versions -- we'll just immediately return whatever's in
+ this env var.
+
+ %[2]s:
+ will switch the default of -i/--installed to true if set to any value
+
+ %[3]s:
+ will switch the default of --use-env to true if set to any value
+
+`, name, envNoDownload, envUseEnv)
+ }
+ flag.CommandLine.AddGoFlag(&goflag.Flag{Name: "v", Usage: "logging level", Value: &zapLvl})
+ flag.VarP(&printFormat, "print", "p", "what info to print after fetch-style commands (overview, path, env)")
+ needHelp := flag.Bool("help", false, "print out this help text") // register help so that we don't get an error at the end
+ flag.Parse()
+
+ if *needHelp {
+ flag.Usage()
+ envp.Exit(2, "")
+ }
+
+ // check our argument count
+ if numArgs := flag.NArg(); numArgs < 1 || numArgs > 2 {
+ flag.Usage()
+ envp.Exit(2, "please specify a command to use, and optionally a version selector")
+ }
+
+ // set up logging
+ globalLog := setupLogging()
+
+ // set up the environment
+ var version string
+ if flag.NArg() > 1 {
+ version = flag.Arg(1)
+ }
+ env := setupEnv(globalLog, version)
+
+ // perform our main set of actions
+ switch action := flag.Arg(0); action {
+ case "use":
+ workflows.Use{
+ UseEnv: *useEnv,
+ PrintFormat: printFormat,
+ AssetsPath: os.Getenv("KUBEBUILDER_ASSETS"),
+ }.Do(env)
+ case "list":
+ workflows.List{}.Do(env)
+ case "cleanup":
+ workflows.Cleanup{}.Do(env)
+ case "sideload":
+ workflows.Sideload{
+ Input: os.Stdin,
+ PrintFormat: printFormat,
+ }.Do(env)
+ default:
+ flag.Usage()
+ envp.Exit(2, "unknown action %q", action)
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/remote/client.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/remote/client.go
new file mode 100644
index 00000000000..be82532583a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/remote/client.go
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2021 The Kubernetes Authors
+
+package remote
+
+import (
+ "context"
+ "crypto/md5" //nolint:gosec
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "sort"
+
+ "github.com/go-logr/logr"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/versions"
+)
+
+// objectList is the parts we need of the GCS "list-objects-in-bucket" endpoint.
+type objectList struct {
+ Items []bucketObject `json:"items"`
+ NextPageToken string `json:"nextPageToken"`
+}
+
+// bucketObject is the parts we need of the GCS object metadata.
+type bucketObject struct {
+ Name string `json:"name"`
+ Hash string `json:"md5Hash"`
+}
+
+// Client is a basic client for fetching versions of the envtest binary archives
+// from GCS.
+type Client struct {
+ // Bucket is the bucket to fetch from.
+ Bucket string
+
+ // Server is the GCS-like storage server
+ Server string
+
+ // Log allows us to log.
+ Log logr.Logger
+
+ // Insecure uses http for testing
+ Insecure bool
+}
+
+func (c *Client) scheme() string {
+ if c.Insecure {
+ return "http"
+ }
+ return "https"
+}
+
+// ListVersions lists all available tools versions in the given bucket, along
+// with supported os/arch combos and the corresponding hash.
+//
+// The results are sorted with newer versions first.
+func (c *Client) ListVersions(ctx context.Context) ([]versions.Set, error) {
+ loc := &url.URL{
+ Scheme: c.scheme(),
+ Host: c.Server,
+ Path: path.Join("/storage/v1/b/", c.Bucket, "o"),
+ }
+ query := make(url.Values)
+
+ knownVersions := map[versions.Concrete][]versions.PlatformItem{}
+ for cont := true; cont; {
+ c.Log.V(1).Info("listing bucket to get versions", "bucket", c.Bucket)
+
+ loc.RawQuery = query.Encode()
+ req, err := http.NewRequestWithContext(ctx, "GET", loc.String(), nil)
+ if err != nil {
+ return nil, fmt.Errorf("unable to construct request to list bucket items: %w", err)
+ }
+
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("unable to perform request to list bucket items: %w", err)
+ }
+
+ err = func() error {
+ defer resp.Body.Close()
+ if resp.StatusCode != 200 {
+ return fmt.Errorf("unable list bucket items -- got status %q from GCS", resp.Status)
+ }
+
+ var list objectList
+ if err := json.NewDecoder(resp.Body).Decode(&list); err != nil {
+ return fmt.Errorf("unable unmarshal bucket items list: %w", err)
+ }
+
+ // continue listing if needed
+ cont = list.NextPageToken != ""
+ query.Set("pageToken", list.NextPageToken)
+
+ for _, item := range list.Items {
+ ver, details := versions.ExtractWithPlatform(versions.ArchiveRE, item.Name)
+ if ver == nil {
+ c.Log.V(1).Info("skipping bucket object -- does not appear to be a versioned tools object", "name", item.Name)
+ continue
+ }
+ c.Log.V(1).Info("found version", "version", ver, "platform", details)
+ knownVersions[*ver] = append(knownVersions[*ver], versions.PlatformItem{
+ Platform: details,
+ MD5: item.Hash,
+ })
+ }
+
+ return nil
+ }()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ res := make([]versions.Set, 0, len(knownVersions))
+ for ver, details := range knownVersions {
+ res = append(res, versions.Set{Version: ver, Platforms: details})
+ }
+ // sort in inverse order so that the newest one is first
+ sort.Slice(res, func(i, j int) bool {
+ first, second := res[i].Version, res[j].Version
+ return first.NewerThan(second)
+ })
+
+ return res, nil
+}
+
+// GetVersion downloads the given concrete version for the given concrete platform, writing it to the out.
+func (c *Client) GetVersion(ctx context.Context, version versions.Concrete, platform versions.PlatformItem, out io.Writer) error {
+ itemName := platform.ArchiveName(version)
+ loc := &url.URL{
+ Scheme: c.scheme(),
+ Host: c.Server,
+ Path: path.Join("/storage/v1/b/", c.Bucket, "o", itemName),
+ RawQuery: "alt=media",
+ }
+
+ req, err := http.NewRequestWithContext(ctx, "GET", loc.String(), nil)
+ if err != nil {
+ return fmt.Errorf("unable to construct request to fetch %s: %w", itemName, err)
+ }
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return fmt.Errorf("unable to fetch %s (%s): %w", itemName, req.URL, err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != 200 {
+ return fmt.Errorf("unable fetch %s (%s) -- got status %q from GCS", itemName, req.URL, resp.Status)
+ }
+
+ if platform.MD5 != "" {
+ // stream in chunks to do the checksum, don't load the whole thing into
+ // memory to avoid causing issues with big files.
+ buf := make([]byte, 32*1024) // 32KiB, same as io.Copy
+ checksum := md5.New() //nolint:gosec
+ for cont := true; cont; {
+ amt, err := resp.Body.Read(buf)
+ if err != nil && !errors.Is(err, io.EOF) {
+ return fmt.Errorf("unable read next chunk of %s: %w", itemName, err)
+ }
+ if amt > 0 {
+ // checksum never returns errors according to docs
+ checksum.Write(buf[:amt])
+ if _, err := out.Write(buf[:amt]); err != nil {
+ return fmt.Errorf("unable write next chunk of %s: %w", itemName, err)
+ }
+ }
+ cont = amt > 0 && !errors.Is(err, io.EOF)
+ }
+
+ sum := base64.StdEncoding.EncodeToString(checksum.Sum(nil))
+
+ if sum != platform.MD5 {
+ return fmt.Errorf("checksum mismatch for %s: %s (computed) != %s (reported from GCS)", itemName, sum, platform.MD5)
+ }
+ } else if _, err := io.Copy(out, resp.Body); err != nil {
+ return fmt.Errorf("unable to download %s: %w", itemName, err)
+ }
+ return nil
+}
+
+// FetchSum fetches the checksum for the given concrete version & platform into
+// the given platform item.
+func (c *Client) FetchSum(ctx context.Context, ver versions.Concrete, pl *versions.PlatformItem) error {
+ itemName := pl.ArchiveName(ver)
+ loc := &url.URL{
+ Scheme: c.scheme(),
+ Host: c.Server,
+ Path: path.Join("/storage/v1/b/", c.Bucket, "o", itemName),
+ }
+
+ req, err := http.NewRequestWithContext(ctx, "GET", loc.String(), nil)
+ if err != nil {
+ return fmt.Errorf("unable to construct request to fetch metadata for %s: %w", itemName, err)
+ }
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return fmt.Errorf("unable to fetch metadata for %s: %w", itemName, err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != 200 {
+ return fmt.Errorf("unable fetch metadata for %s -- got status %q from GCS", itemName, resp.Status)
+ }
+
+ var item bucketObject
+ if err := json.NewDecoder(resp.Body).Decode(&item); err != nil {
+ return fmt.Errorf("unable to unmarshal metadata for %s: %w", itemName, err)
+ }
+
+ pl.MD5 = item.Hash
+ return nil
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/store/helpers.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/store/helpers.go
new file mode 100644
index 00000000000..30902187e92
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/store/helpers.go
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2021 The Kubernetes Authors
+
+package store
+
+import (
+ "errors"
+ "os"
+ "path/filepath"
+ "runtime"
+)
+
+// DefaultStoreDir returns the default location for the store.
+// It's dependent on operating system:
+//
+// - Windows: %LocalAppData%\kubebuilder-envtest
+// - OSX: ~/Library/Application Support/io.kubebuilder.envtest
+// - Others: ${XDG_DATA_HOME:-~/.local/share}/kubebuilder-envtest
+//
+// Otherwise, it errors out. Note that these paths must not be relied upon
+// manually.
+func DefaultStoreDir() (string, error) {
+ var baseDir string
+
+ // find the base data directory
+ switch runtime.GOOS {
+ case "windows":
+ baseDir = os.Getenv("LocalAppData")
+ if baseDir == "" {
+ return "", errors.New("%LocalAppData% is not defined")
+ }
+ case "darwin", "ios":
+ homeDir := os.Getenv("HOME")
+ if homeDir == "" {
+ return "", errors.New("$HOME is not defined")
+ }
+ baseDir = filepath.Join(homeDir, "Library/Application Support")
+ default:
+ baseDir = os.Getenv("XDG_DATA_HOME")
+ if baseDir == "" {
+ homeDir := os.Getenv("HOME")
+ if homeDir == "" {
+ return "", errors.New("neither $XDG_DATA_HOME nor $HOME are defined")
+ }
+ baseDir = filepath.Join(homeDir, ".local/share")
+ }
+ }
+
+ // append our program-specific dir to it (OSX has a slightly different
+ // convention so try to follow that).
+ switch runtime.GOOS {
+ case "darwin", "ios":
+ return filepath.Join(baseDir, "io.kubebuilder.envtest"), nil
+ default:
+ return filepath.Join(baseDir, "kubebuilder-envtest"), nil
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/store/store.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/store/store.go
new file mode 100644
index 00000000000..e6f258e4ac7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/store/store.go
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2021 The Kubernetes Authors
+
+package store
+
+import (
+ "archive/tar"
+ "compress/gzip"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "sort"
+
+ "github.com/go-logr/logr"
+ "github.com/spf13/afero"
+
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/versions"
+)
+
+// TODO(directxman12): error messages don't show full path, which is gonna make
+// things hard to debug
+
+// Item is a version-platform pair.
+type Item struct {
+ Version versions.Concrete
+ Platform versions.Platform
+}
+
+// dirName returns the directory name in the store for this item.
+func (i Item) dirName() string {
+ return i.Platform.BaseName(i.Version)
+}
+func (i Item) String() string {
+ return fmt.Sprintf("%s (%s)", i.Version, i.Platform)
+}
+
+// Filter is a version spec & platform selector (i.e. platform
+// potentially with wilcards) to filter store items.
+type Filter struct {
+ Version versions.Spec
+ Platform versions.Platform
+}
+
+// Matches checks if this filter matches the given item.
+func (f Filter) Matches(item Item) bool {
+ return f.Version.Matches(item.Version) && f.Platform.Matches(item.Platform)
+}
+
+// Store knows how to list, load, store, and delete envtest tools.
+type Store struct {
+ // Root is the root FS that the store stores in. You'll probably
+ // want to use a BasePathFS to scope it down to a particular directory.
+ //
+ // Note that if for some reason there are nested BasePathFSes, and they're
+ // interrupted by a non-BasePathFS, Path won't work properly.
+ Root afero.Fs
+}
+
+// NewAt creates a new store on disk at the given path.
+func NewAt(path string) *Store {
+ return &Store{
+ Root: afero.NewBasePathFs(afero.NewOsFs(), path),
+ }
+}
+
+// Initialize ensures that the store is all set up on disk, etc.
+func (s *Store) Initialize(ctx context.Context) error {
+ log, err := logr.FromContext(ctx)
+ if err != nil {
+ return err
+ }
+
+ log.V(1).Info("ensuring base binaries dir exists")
+ if err := s.unpackedBase().MkdirAll("", 0755); err != nil {
+ return fmt.Errorf("unable to make sure base binaries dir exists: %w", err)
+ }
+ return nil
+}
+
+// Has checks if an item exists in the store.
+func (s *Store) Has(item Item) (bool, error) {
+ path := s.unpackedPath(item.dirName())
+ _, err := path.Stat("")
+ if err != nil && !errors.Is(err, afero.ErrFileNotFound) {
+ return false, fmt.Errorf("unable to check if version-platform dir exists: %w", err)
+ }
+ return err == nil, nil
+}
+
+// List lists all items matching the given filter.
+//
+// Results are stored by version (newest first), and OS/arch (consistently,
+// but no guaranteed ordering).
+func (s *Store) List(ctx context.Context, matching Filter) ([]Item, error) {
+ var res []Item
+ if err := s.eachItem(ctx, matching, func(_ string, item Item) {
+ res = append(res, item)
+ }); err != nil {
+ return nil, fmt.Errorf("unable to list version-platform pairs in store: %w", err)
+ }
+
+ sort.Slice(res, func(i, j int) bool {
+ if !res[i].Version.Matches(res[j].Version) {
+ return res[i].Version.NewerThan(res[j].Version)
+ }
+ return orderPlatforms(res[i].Platform, res[j].Platform)
+ })
+
+ return res, nil
+}
+
+// Add adds this item to the store, with the given contents (a .tar.gz file).
+func (s *Store) Add(ctx context.Context, item Item, contents io.Reader) (resErr error) {
+ log, err := logr.FromContext(ctx)
+ if err != nil {
+ return err
+ }
+
+ itemName := item.dirName()
+ log = log.WithValues("version-platform", itemName)
+ itemPath := s.unpackedPath(itemName)
+
+ // make sure to clean up if we hit an error
+ defer func() {
+ if resErr != nil {
+ // intentially ignore this because we can't really do anything
+ err := s.removeItem(itemPath)
+ if err != nil {
+ log.Error(err, "unable to clean up partially added version-platform pair after error")
+ }
+ }
+ }()
+
+ log.V(1).Info("ensuring version-platform binaries dir exists and is empty & writable")
+ _, err = itemPath.Stat("")
+ if err != nil && !errors.Is(err, afero.ErrFileNotFound) {
+ return fmt.Errorf("unable to ensure version-platform binaries dir %s exists", itemName)
+ }
+ if err == nil { // exists
+ log.V(1).Info("cleaning up old version-platform binaries dir")
+ if err := s.removeItem(itemPath); err != nil {
+ return fmt.Errorf("unable to clean up existing version-platform binaries dir %s", itemName)
+ }
+ }
+ if err := itemPath.MkdirAll("", 0755); err != nil {
+ return fmt.Errorf("unable to make sure entry dir %s exists", itemName)
+ }
+
+ log.V(1).Info("extracting archive")
+ gzStream, err := gzip.NewReader(contents)
+ if err != nil {
+ return fmt.Errorf("unable to start un-gz-ing entry archive")
+ }
+ tarReader := tar.NewReader(gzStream)
+
+ var header *tar.Header
+ for header, err = tarReader.Next(); err == nil; header, err = tarReader.Next() {
+ if header.Typeflag != tar.TypeReg { // TODO(directxman12): support symlinks, etc?
+ log.V(1).Info("skipping non-regular-file entry in archive", "entry", header.Name)
+ continue
+ }
+ // just dump all files to the main path, ignoring the prefixed directory
+ // paths -- they're redundant. We also ignore bits for the most part (except for X),
+ // preferfing our own scheme.
+ targetPath := filepath.Base(header.Name)
+ log.V(1).Info("writing archive file to disk", "archive file", header.Name, "on-disk file", targetPath)
+ perms := 0555 & header.Mode // make sure we're at most r+x
+ binOut, err := itemPath.OpenFile(targetPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.FileMode(perms))
+ if err != nil {
+ return fmt.Errorf("unable to create file %s from archive to disk for version-platform pair %s", targetPath, itemName)
+ }
+ if err := func() error { // IIFE to get the defer properly in a loop
+ defer binOut.Close()
+ if _, err := io.Copy(binOut, tarReader); err != nil { //nolint:gosec
+ return fmt.Errorf("unable to write file %s from archive to disk for version-platform pair %s", targetPath, itemName)
+ }
+ return nil
+ }(); err != nil {
+ return err
+ }
+ }
+ if err != nil && !errors.Is(err, io.EOF) {
+ return fmt.Errorf("unable to finish un-tar-ing the downloaded archive: %w", err)
+ }
+ log.V(1).Info("unpacked archive")
+
+ log.V(1).Info("switching version-platform directory to read-only")
+ if err := itemPath.Chmod("", 0555); err != nil {
+ // don't bail, this isn't fatal
+ log.Error(err, "unable to make version-platform directory read-only")
+ }
+ return nil
+}
+
+// Remove removes all items matching the given filter.
+//
+// It returns a list of the successfully removed items (even in the case
+// of an error).
+func (s *Store) Remove(ctx context.Context, matching Filter) ([]Item, error) {
+ log, err := logr.FromContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ var removed []Item
+ var savedErr error
+ if err := s.eachItem(ctx, matching, func(name string, item Item) {
+ log.V(1).Info("Removing version-platform pair at path", "version-platform", item, "path", name)
+
+ if err := s.removeItem(s.unpackedPath(name)); err != nil {
+ log.Error(err, "unable to make existing version-platform dir writable to clean it up", "path", name)
+ savedErr = fmt.Errorf("unable to remove version-platform pair %s (dir %s): %w", item, name, err)
+ return // don't mark this as removed in the report
+ }
+ removed = append(removed, item)
+ }); err != nil {
+ return removed, fmt.Errorf("unable to list version-platform pairs to figure out what to delete: %w", err)
+ }
+ if savedErr != nil {
+ return removed, savedErr
+ }
+ return removed, nil
+}
+
+// Path returns an actual path that case be used to access this item.
+func (s *Store) Path(item Item) (string, error) {
+ path := s.unpackedPath(item.dirName())
+ // NB(directxman12): we need root's realpath because RealPath only
+ // looks at its own path, and so thus doesn't prepend the underlying
+ // root's base path.
+ //
+ // Technically, if we're fed something that's double wrapped as root,
+ // this'll be wrong, but this is basically as much as we can do
+ return afero.FullBaseFsPath(path.(*afero.BasePathFs), ""), nil
+}
+
+// unpackedBase returns the directory in which item dirs lives.
+func (s *Store) unpackedBase() afero.Fs {
+ return afero.NewBasePathFs(s.Root, "k8s")
+}
+
+// unpackedPath returns the item dir with this name.
+func (s *Store) unpackedPath(name string) afero.Fs {
+ return afero.NewBasePathFs(s.unpackedBase(), name)
+}
+
+// eachItem iterates through the on-disk versions that match our version & platform selector,
+// calling the callback for each.
+func (s *Store) eachItem(ctx context.Context, filter Filter, cb func(name string, item Item)) error {
+ log, err := logr.FromContext(ctx)
+ if err != nil {
+ return err
+ }
+
+ entries, err := afero.ReadDir(s.unpackedBase(), "")
+ if err != nil {
+ return fmt.Errorf("unable to list folders in store's unpacked directory: %w", err)
+ }
+
+ for _, entry := range entries {
+ if !entry.IsDir() {
+ log.V(1).Info("skipping dir entry, not a folder", "entry", entry.Name())
+ continue
+ }
+ ver, pl := versions.ExtractWithPlatform(versions.VersionPlatformRE, entry.Name())
+ if ver == nil {
+ log.V(1).Info("skipping dir entry, not a version", "entry", entry.Name())
+ continue
+ }
+ item := Item{Version: *ver, Platform: pl}
+
+ if !filter.Matches(item) {
+ log.V(1).Info("skipping on disk version, does not match version and platform selectors", "platform", pl, "version", ver, "entry", entry.Name())
+ continue
+ }
+
+ cb(entry.Name(), item)
+ }
+
+ return nil
+}
+
+// removeItem removes the given item directory from disk.
+func (s *Store) removeItem(itemDir afero.Fs) error {
+ if err := itemDir.Chmod("", 0755); err != nil {
+ // no point in trying to remove if we can't fix the permissions, bail here
+ return fmt.Errorf("unable to make version-platform dir writable: %w", err)
+ }
+ if err := itemDir.RemoveAll(""); err != nil && !errors.Is(err, afero.ErrFileNotFound) {
+ return fmt.Errorf("unable to remove version-platform dir: %w", err)
+ }
+ return nil
+}
+
+// orderPlatforms orders platforms by OS then arch.
+func orderPlatforms(first, second versions.Platform) bool {
+ // sort by OS, then arch
+ if first.OS != second.OS {
+ return first.OS < second.OS
+ }
+ return first.Arch < second.Arch
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/store/store_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/store/store_suite_test.go
new file mode 100644
index 00000000000..c2795a32276
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/store/store_suite_test.go
@@ -0,0 +1,51 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package store_test
+
+import (
+ "context"
+ "testing"
+
+ "github.com/go-logr/logr"
+ "github.com/go-logr/zapr"
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+var testLog logr.Logger
+
+func zapLogger() logr.Logger {
+ testOut := zapcore.AddSync(GinkgoWriter)
+ enc := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
+ // bleh setting up logging to the ginkgo writer is annoying
+ zapLog := zap.New(zapcore.NewCore(enc, testOut, zap.DebugLevel),
+ zap.ErrorOutput(testOut), zap.Development(), zap.AddStacktrace(zap.WarnLevel))
+ return zapr.NewLogger(zapLog)
+}
+
+func logCtx() context.Context {
+ return logr.NewContext(context.Background(), testLog)
+}
+
+func TestStore(t *testing.T) {
+ testLog = zapLogger()
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Store Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/store/store_test.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/store/store_test.go
new file mode 100644
index 00000000000..d5607aede6d
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/store/store_test.go
@@ -0,0 +1,250 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package store_test
+
+import (
+ "archive/tar"
+ "bytes"
+ "compress/gzip"
+ "crypto/rand"
+ "io"
+ "io/fs"
+ "path/filepath"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/spf13/afero"
+
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/store"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/versions"
+)
+
+const (
+ fakeStorePath = "/path/to/the/store"
+)
+
+var _ = Describe("Store", func() {
+ var st *store.Store
+ BeforeEach(func() {
+ fs := afero.NewMemMapFs()
+ fakeStoreFiles(fs, fakeStorePath)
+ st = &store.Store{
+ Root: afero.NewBasePathFs(fs, fakeStorePath),
+ }
+ })
+ Describe("initialization", func() {
+ It("should ensure the repo root exists", func() {
+ // remove the old dir
+ Expect(st.Root.RemoveAll("")).To(Succeed(), "should be able to remove the store before trying to initialize")
+
+ Expect(st.Initialize(logCtx())).To(Succeed(), "initialization should succeed")
+ Expect(st.Root.Stat("k8s")).NotTo(BeNil(), "store's binary dir should exist")
+ })
+
+ It("should be fine if the repo root already exists", func() {
+ Expect(st.Initialize(logCtx())).To(Succeed())
+ })
+ })
+ Describe("listing items", func() {
+ It("should filter results by the given filter, sorted in version order (newest first)", func() {
+ sel, err := versions.FromExpr("<=1.16")
+ Expect(err).NotTo(HaveOccurred(), "should be able to construct <=1.16 selector")
+ Expect(st.List(logCtx(), store.Filter{
+ Version: sel,
+ Platform: versions.Platform{OS: "*", Arch: "amd64"},
+ })).To(Equal([]store.Item{
+ {Version: ver(1, 16, 2), Platform: versions.Platform{OS: "ifonlysingularitywasstillathing", Arch: "amd64"}},
+ {Version: ver(1, 16, 1), Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ {Version: ver(1, 16, 0), Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ {Version: ver(1, 14, 26), Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ }))
+ })
+ It("should skip non-folders in the store", func() {
+ Expect(afero.WriteFile(st.Root, "k8s/2.3.6-linux-amd128", []byte{0x01}, fs.ModePerm)).To(Succeed(), "should be able to create a non-store file in the store directory")
+ Expect(st.List(logCtx(), store.Filter{
+ Version: versions.AnyVersion, Platform: versions.Platform{OS: "linux", Arch: "amd128"},
+ })).To(BeEmpty())
+ })
+
+ It("should skip non-matching names in the store", func() {
+ Expect(st.Root.Mkdir("k8s/somedir-2.3.6-linux-amd128", fs.ModePerm)).To(Succeed(), "should be able to create a non-store file in the store directory")
+ Expect(st.List(logCtx(), store.Filter{
+ Version: versions.AnyVersion, Platform: versions.Platform{OS: "linux", Arch: "amd128"},
+ })).To(BeEmpty())
+ })
+ })
+
+ Describe("removing items", func() {
+ var res []store.Item
+ BeforeEach(func() {
+ sel, err := versions.FromExpr("<=1.16")
+ Expect(err).NotTo(HaveOccurred(), "should be able to construct <=1.16 selector")
+ res, err = st.Remove(logCtx(), store.Filter{
+ Version: sel,
+ Platform: versions.Platform{OS: "*", Arch: "amd64"},
+ })
+ Expect(err).NotTo(HaveOccurred(), "should be able to remove <=1.16 & */amd64")
+ })
+ It("should return all items removed", func() {
+ Expect(res).To(ConsistOf(
+ store.Item{Version: ver(1, 16, 2), Platform: versions.Platform{OS: "ifonlysingularitywasstillathing", Arch: "amd64"}},
+ store.Item{Version: ver(1, 16, 1), Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ store.Item{Version: ver(1, 16, 0), Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ store.Item{Version: ver(1, 14, 26), Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ ))
+ })
+ It("should remove all items matching the given filter from disk", func() {
+ Expect(afero.ReadDir(st.Root, "k8s")).NotTo(ContainElements(
+ WithTransform(fs.FileInfo.Name, Equal("1.16.2-ifonlysingularitywasstillathing-amd64")),
+ WithTransform(fs.FileInfo.Name, Equal("1.16.1-linux-amd64")),
+ WithTransform(fs.FileInfo.Name, Equal("1.16.0-linux-amd64")),
+ WithTransform(fs.FileInfo.Name, Equal("1.14.26-linux-amd64")),
+ ))
+ })
+
+ It("should leave items that don't match in place", func() {
+ Expect(afero.ReadDir(st.Root, "k8s")).To(ContainElements(
+ WithTransform(fs.FileInfo.Name, Equal("1.17.9-linux-amd64")),
+ WithTransform(fs.FileInfo.Name, Equal("1.16.2-linux-yourimagination")),
+ WithTransform(fs.FileInfo.Name, Equal("1.14.26-hyperwarp-pixiedust")),
+ ))
+ })
+ })
+
+ Describe("adding items", func() {
+ It("should support .tar.gz input", func() {
+ Expect(st.Add(logCtx(), newItem, makeFakeArchive(newName))).To(Succeed())
+ Expect(st.Has(newItem)).To(BeTrue(), "should have the item after adding it")
+ })
+
+ It("should extract binaries from the given archive to a directly to the item's directory, regardless of path", func() {
+ Expect(st.Add(logCtx(), newItem, makeFakeArchive(newName))).To(Succeed())
+
+ dirName := newItem.Platform.BaseName(newItem.Version)
+ Expect(afero.ReadFile(st.Root, filepath.Join("k8s", dirName, "some-file"))).To(HavePrefix(newName + "some-file"))
+ Expect(afero.ReadFile(st.Root, filepath.Join("k8s", dirName, "other-file"))).To(HavePrefix(newName + "other-file"))
+ })
+
+ It("should clean up any existing item directory before creating the new one", func() {
+ item := localVersions[0]
+ Expect(st.Add(logCtx(), item, makeFakeArchive(newName))).To(Succeed())
+ Expect(st.Root.Stat(filepath.Join("k8s", item.Platform.BaseName(item.Version)))).NotTo(BeNil(), "new files should exist")
+ })
+ It("should clean up if it errors before finishing", func() {
+ item := localVersions[0]
+ Expect(st.Add(logCtx(), item, new(bytes.Buffer))).NotTo(Succeed(), "should fail to extract")
+ _, err := st.Root.Stat(filepath.Join("k8s", item.Platform.BaseName(item.Version)))
+ Expect(err).To(HaveOccurred(), "the binaries dir for the item should be gone")
+
+ })
+ })
+
+ Describe("checking if items are present", func() {
+ It("should report that present directories are present", func() {
+ Expect(st.Has(localVersions[0])).To(BeTrue())
+ })
+
+ It("should report that absent directories are absent", func() {
+ Expect(st.Has(newItem)).To(BeFalse())
+ })
+ })
+
+ Describe("getting the path", func() {
+ It("should return the absolute on-disk path of the given item", func() {
+ item := localVersions[0]
+ Expect(st.Path(item)).To(Equal(filepath.Join(fakeStorePath, "k8s", item.Platform.BaseName(item.Version))))
+ })
+ })
+})
+
+var (
+ // keep this sorted.
+ localVersions = []store.Item{
+ {Version: ver(1, 17, 9), Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ {Version: ver(1, 16, 2), Platform: versions.Platform{OS: "linux", Arch: "yourimagination"}},
+ {Version: ver(1, 16, 2), Platform: versions.Platform{OS: "ifonlysingularitywasstillathing", Arch: "amd64"}},
+ {Version: ver(1, 16, 1), Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ {Version: ver(1, 16, 0), Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ {Version: ver(1, 14, 26), Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ {Version: ver(1, 14, 26), Platform: versions.Platform{OS: "hyperwarp", Arch: "pixiedust"}},
+ }
+
+ newItem = store.Item{
+ Version: ver(1, 16, 3),
+ Platform: versions.Platform{OS: "linux", Arch: "amd64"},
+ }
+
+ newName = "kubebuilder-tools-1.16.3-linux-amd64.tar.gz"
+)
+
+func ver(major, minor, patch int) versions.Concrete {
+ return versions.Concrete{
+ Major: major,
+ Minor: minor,
+ Patch: patch,
+ }
+}
+
+func makeFakeArchive(magic string) io.Reader {
+ out := new(bytes.Buffer)
+ gzipWriter := gzip.NewWriter(out)
+ tarWriter := tar.NewWriter(gzipWriter)
+ Expect(tarWriter.WriteHeader(&tar.Header{
+ Typeflag: tar.TypeDir,
+ Name: "kubebuilder/bin/", // so we can ensure we skip non-files
+ Mode: 0777,
+ })).To(Succeed())
+ for _, fileName := range []string{"some-file", "other-file"} {
+ // create fake file contents: magic+fileName+randomBytes()
+ var chunk [1024 * 48]byte // 1.5 times our chunk read size in GetVersion
+ copy(chunk[:], magic)
+ copy(chunk[len(magic):], fileName)
+ start := len(magic) + len(fileName)
+ if _, err := rand.Read(chunk[start:]); err != nil {
+ panic(err)
+ }
+
+ // write to kubebuilder/bin/fileName
+ err := tarWriter.WriteHeader(&tar.Header{
+ Name: "kubebuilder/bin/" + fileName,
+ Size: int64(len(chunk[:])),
+ Mode: 0777, // so we can check that we fix this later
+ })
+ if err != nil {
+ panic(err)
+ }
+ _, err = tarWriter.Write(chunk[:])
+ if err != nil {
+ panic(err)
+ }
+ }
+ tarWriter.Close()
+ gzipWriter.Close()
+
+ return out
+}
+
+func fakeStoreFiles(fs afero.Fs, dir string) {
+ By("making the unpacked directory")
+ unpackedBase := filepath.Join(dir, "k8s")
+ Expect(fs.Mkdir(unpackedBase, 0755)).To(Succeed())
+
+ By("making some fake (empty) versions")
+ for _, item := range localVersions {
+ Expect(fs.Mkdir(filepath.Join(unpackedBase, item.Platform.BaseName(item.Version)), 0755)).To(Succeed())
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/misc_test.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/misc_test.go
new file mode 100644
index 00000000000..8a97de04104
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/misc_test.go
@@ -0,0 +1,143 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package versions_test
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ . "sigs.k8s.io/controller-runtime/tools/setup-envtest/versions"
+)
+
+var _ = Describe("Concrete", func() {
+ It("should match the only same version", func() {
+ ver16 := Concrete{Major: 1, Minor: 16}
+ ver17 := Concrete{Major: 1, Minor: 17}
+ Expect(ver16.Matches(ver16)).To(BeTrue(), "should match the same version")
+ Expect(ver16.Matches(ver17)).To(BeFalse(), "should not match a different version")
+ })
+ It("should serialize as X.Y.Z", func() {
+ Expect(Concrete{Major: 1, Minor: 16, Patch: 3}.String()).To(Equal("1.16.3"))
+ })
+ Describe("when ordering relative to other versions", func() {
+ ver1163 := Concrete{Major: 1, Minor: 16, Patch: 3}
+ Specify("newer patch should be newer", func() {
+ Expect(ver1163.NewerThan(Concrete{Major: 1, Minor: 16})).To(BeTrue())
+ })
+ Specify("newer minor should be newer", func() {
+ Expect(ver1163.NewerThan(Concrete{Major: 1, Minor: 15, Patch: 3})).To(BeTrue())
+ })
+ Specify("newer major should be newer", func() {
+ Expect(ver1163.NewerThan(Concrete{Major: 0, Minor: 16, Patch: 3})).To(BeTrue())
+ })
+ })
+})
+
+var _ = Describe("Platform", func() {
+ Specify("a concrete platform should match exactly itself", func() {
+ plat1 := Platform{OS: "linux", Arch: "amd64"}
+ plat2 := Platform{OS: "linux", Arch: "s390x"}
+ plat3 := Platform{OS: "windows", Arch: "amd64"}
+ Expect(plat1.Matches(plat1)).To(BeTrue(), "should match itself")
+ Expect(plat1.Matches(plat2)).To(BeFalse(), "should reject a different arch")
+ Expect(plat1.Matches(plat3)).To(BeFalse(), "should reject a different os")
+ })
+ Specify("a wildcard arch should match any arch", func() {
+ sel := Platform{OS: "linux", Arch: "*"}
+ plat1 := Platform{OS: "linux", Arch: "amd64"}
+ plat2 := Platform{OS: "linux", Arch: "s390x"}
+ plat3 := Platform{OS: "windows", Arch: "amd64"}
+ Expect(sel.Matches(sel)).To(BeTrue(), "should match itself")
+ Expect(sel.Matches(plat1)).To(BeTrue(), "should match some arch with the same OS")
+ Expect(sel.Matches(plat2)).To(BeTrue(), "should match another arch with the same OS")
+ Expect(plat1.Matches(plat3)).To(BeFalse(), "should reject a different os")
+ })
+ Specify("a wildcard os should match any os", func() {
+ sel := Platform{OS: "*", Arch: "amd64"}
+ plat1 := Platform{OS: "linux", Arch: "amd64"}
+ plat2 := Platform{OS: "windows", Arch: "amd64"}
+ plat3 := Platform{OS: "linux", Arch: "s390x"}
+ Expect(sel.Matches(sel)).To(BeTrue(), "should match itself")
+ Expect(sel.Matches(plat1)).To(BeTrue(), "should match some os with the same arch")
+ Expect(sel.Matches(plat2)).To(BeTrue(), "should match another os with the same arch")
+ Expect(plat1.Matches(plat3)).To(BeFalse(), "should reject a different arch")
+ })
+ It("should report a wildcard OS as a wildcard platform", func() {
+ Expect(Platform{OS: "*", Arch: "amd64"}.IsWildcard()).To(BeTrue())
+ })
+ It("should report a wildcard arch as a wildcard platform", func() {
+ Expect(Platform{OS: "linux", Arch: "*"}.IsWildcard()).To(BeTrue())
+ })
+ It("should serialize as os/arch", func() {
+ Expect(Platform{OS: "linux", Arch: "amd64"}.String()).To(Equal("linux/amd64"))
+ })
+
+ Specify("knows how to produce a base store name", func() {
+ plat := Platform{OS: "linux", Arch: "amd64"}
+ ver := Concrete{Major: 1, Minor: 16, Patch: 3}
+ Expect(plat.BaseName(ver)).To(Equal("1.16.3-linux-amd64"))
+ })
+
+ Specify("knows how to produce an archive name", func() {
+ plat := Platform{OS: "linux", Arch: "amd64"}
+ ver := Concrete{Major: 1, Minor: 16, Patch: 3}
+ Expect(plat.ArchiveName(ver)).To(Equal("kubebuilder-tools-1.16.3-linux-amd64.tar.gz"))
+ })
+
+ Describe("parsing", func() {
+ Context("for version-platform names", func() {
+ It("should accept strings of the form x.y.z-os-arch", func() {
+ ver, plat := ExtractWithPlatform(VersionPlatformRE, "1.16.3-linux-amd64")
+ Expect(ver).To(Equal(&Concrete{Major: 1, Minor: 16, Patch: 3}))
+ Expect(plat).To(Equal(Platform{OS: "linux", Arch: "amd64"}))
+ })
+ It("should reject nonsense strings", func() {
+ ver, _ := ExtractWithPlatform(VersionPlatformRE, "1.16-linux-amd64")
+ Expect(ver).To(BeNil())
+ })
+ })
+ Context("for archive names", func() {
+ It("should accept strings of the form kubebuilder-tools-x.y.z-os-arch.tar.gz", func() {
+ ver, plat := ExtractWithPlatform(ArchiveRE, "kubebuilder-tools-1.16.3-linux-amd64.tar.gz")
+ Expect(ver).To(Equal(&Concrete{Major: 1, Minor: 16, Patch: 3}))
+ Expect(plat).To(Equal(Platform{OS: "linux", Arch: "amd64"}))
+ })
+ It("should reject nonsense strings", func() {
+ ver, _ := ExtractWithPlatform(ArchiveRE, "kubebuilder-tools-1.16.3-linux-amd64.tar.sum")
+ Expect(ver).To(BeNil())
+ })
+ })
+ })
+})
+
+var _ = Describe("Spec helpers", func() {
+ Specify("can fill a spec with a concrete version", func() {
+ spec := Spec{Selector: AnySelector{}} // don't just use AnyVersion so we don't modify it
+ spec.MakeConcrete(Concrete{Major: 1, Minor: 16})
+ Expect(spec.AsConcrete()).To(Equal(&Concrete{Major: 1, Minor: 16}))
+ })
+ It("should serialize as the underlying selector with ! for check latest", func() {
+ spec, err := FromExpr("1.16.*!")
+ Expect(err).NotTo(HaveOccurred())
+ Expect(spec.String()).To(Equal("1.16.*!"))
+ })
+ It("should serialize as the underlying selector by itself if not check latest", func() {
+ spec, err := FromExpr("1.16.*")
+ Expect(err).NotTo(HaveOccurred())
+ Expect(spec.String()).To(Equal("1.16.*"))
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/parse.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/parse.go
new file mode 100644
index 00000000000..c053bf87574
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/parse.go
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2021 The Kubernetes Authors
+
+package versions
+
+import (
+ "fmt"
+ "regexp"
+ "strconv"
+)
+
+var (
+ // baseVersionRE is a semver-ish version -- either X.Y.Z, X.Y, or X.Y.{*|x}.
+ baseVersionRE = `(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:\.(?P0|[1-9]\d*|x|\*))?`
+ // versionExprRe matches valid version input for FromExpr.
+ versionExprRE = regexp.MustCompile(`^(?P<|~|<=)?` + baseVersionRE + `(?P!)?$`)
+
+ // ConcreteVersionRE matches a concrete version anywhere in the string.
+ ConcreteVersionRE = regexp.MustCompile(`(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)`)
+ // OnlyConcreteVersionRE matches a string that's just a concrete version.
+ OnlyConcreteVersionRE = regexp.MustCompile(`^` + ConcreteVersionRE.String() + `$`)
+)
+
+// FromExpr extracts a version from a string in the form of a semver version,
+// where X, Y, and Z may also be wildcards ('*', 'x'),
+// and pre-release names & numbers may also be wildcards. The prerelease section is slightly
+// restricted to match what k8s does.
+// The whole string is a version selector as follows:
+// - X.Y.Z matches version X.Y.Z where x, y, and z are
+// are ints >= 0, and Z may be '*' or 'x'
+// - X.Y is equivalent to X.Y.*
+// - ~X.Y.Z means >= X.Y.Z && < X.Y+1.0
+// - = comparisons, if we use
+ // wildcards with a selector we can just set them to zero.
+ if verInfo.Patch == AnyPoint {
+ verInfo.Patch = PointVersion(0)
+ }
+ baseVer := *verInfo.AsConcrete()
+ spec.Selector = TildeSelector{Concrete: baseVer}
+ default:
+ panic("unreachable: mismatch between FromExpr and its RE in selector")
+ }
+
+ return spec, nil
+}
+
+// PointVersionFromValidString extracts a point version
+// from the corresponding string representation, which may
+// be a number >= 0, or x|* (AnyPoint).
+//
+// Anything else will cause a panic (use this on strings
+// extracted from regexes).
+func PointVersionFromValidString(str string) PointVersion {
+ switch str {
+ case "*", "x":
+ return AnyPoint
+ default:
+ ver, err := strconv.Atoi(str)
+ if err != nil {
+ panic(err)
+ }
+ return PointVersion(ver)
+ }
+}
+
+// PatchSelectorFromMatch constructs a simple selector according to the
+// ParseExpr rules out of pre-validated sections.
+//
+// re must include name captures for major, minor, patch, prenum, and prelabel
+//
+// Any bad input may cause a panic. Use with when you got the parts from an RE match.
+func PatchSelectorFromMatch(match []string, re *regexp.Regexp) PatchSelector {
+ // already parsed via RE, should be fine to ignore errors unless it's a
+ // *huge* number
+ major, err := strconv.Atoi(match[re.SubexpIndex("major")])
+ if err != nil {
+ panic("invalid input passed as patch selector (invalid state)")
+ }
+ minor, err := strconv.Atoi(match[re.SubexpIndex("minor")])
+ if err != nil {
+ panic("invalid input passed as patch selector (invalid state)")
+ }
+
+ // patch is optional, means wilcard if left off
+ patch := AnyPoint
+ if patchRaw := match[re.SubexpIndex("patch")]; patchRaw != "" {
+ patch = PointVersionFromValidString(patchRaw)
+ }
+ return PatchSelector{
+ Major: major,
+ Minor: minor,
+ Patch: patch,
+ }
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/parse_test.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/parse_test.go
new file mode 100644
index 00000000000..062fdcc6c8c
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/parse_test.go
@@ -0,0 +1,95 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package versions_test
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ . "sigs.k8s.io/controller-runtime/tools/setup-envtest/versions"
+)
+
+func patchSel(x, y int, z PointVersion) PatchSelector {
+ return PatchSelector{Major: x, Minor: y, Patch: z}
+}
+
+func patchSpec(x, y int, z PointVersion) Spec {
+ return Spec{Selector: patchSel(x, y, z)}
+}
+
+func tildeSel(x, y, z int) TildeSelector {
+ return TildeSelector{
+ Concrete: Concrete{
+ Major: x, Minor: y, Patch: z,
+ },
+ }
+}
+
+func tildeSpec(x, y, z int) Spec {
+ return Spec{Selector: tildeSel(x, y, z)}
+}
+func ltSpec(x, y int, z PointVersion) Spec {
+ // this just keeps the table a bit shorter
+ return Spec{Selector: LessThanSelector{
+ PatchSelector: patchSel(x, y, z),
+ }}
+}
+func lteSpec(x, y int, z PointVersion) Spec {
+ // this just keeps the table a bit shorter
+ return Spec{Selector: LessThanSelector{
+ PatchSelector: patchSel(x, y, z),
+ OrEquals: true,
+ }}
+}
+
+var _ = Describe("Parse", func() {
+ DescribeTable("it should support",
+ func(spec string, expected Spec) {
+ Expect(FromExpr(spec)).To(Equal(expected))
+ },
+ Entry("X.Y versions", "1.16", patchSpec(1, 16, AnyPoint)),
+ Entry("X.Y.Z versions", "1.16.3", patchSpec(1, 16, PointVersion(3))),
+ Entry("X.Y.x wildcard", "1.16.x", patchSpec(1, 16, AnyPoint)),
+ Entry("X.Y.* wildcard", "1.16.*", patchSpec(1, 16, AnyPoint)),
+
+ Entry("~X.Y selector", "~1.16", tildeSpec(1, 16, 0)),
+ Entry("~X.Y.Z selector", "~1.16.3", tildeSpec(1, 16, 3)),
+ Entry("~X.Y.x selector", "~1.16.x", tildeSpec(1, 16, 0)),
+ Entry("~X.Y.* selector", "~1.16.*", tildeSpec(1, 16, 0)),
+
+ Entry("\w+)-(?P\w+)`
+ // VersionPlatformRE matches concrete version-platform strings.
+ VersionPlatformRE = regexp.MustCompile(`^` + versionPlatformREBase + `$`)
+ // ArchiveRE matches concrete version-platform.tar.gz strings.
+ ArchiveRE = regexp.MustCompile(`^kubebuilder-tools-` + versionPlatformREBase + `\.tar\.gz$`)
+)
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/selectors_test.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/selectors_test.go
new file mode 100644
index 00000000000..8357d41c803
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/selectors_test.go
@@ -0,0 +1,216 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package versions_test
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ . "sigs.k8s.io/controller-runtime/tools/setup-envtest/versions"
+)
+
+var _ = Describe("Selectors", func() {
+ Describe("patch", func() {
+ var sel Selector
+ Context("with any patch", func() {
+ BeforeEach(func() {
+ var err error
+ sel, err = FromExpr("1.16.*")
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ It("should match any patch version with the same major & minor", func() {
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 16, Patch: 3})).To(BeTrue(), "should match 1.16.3")
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 16, Patch: 0})).To(BeTrue(), "should match 1.16.0")
+ })
+
+ It("should reject a different major", func() {
+ Expect(sel.Matches(Concrete{Major: 2, Minor: 16, Patch: 3})).To(BeFalse(), "should reject 2.16.3")
+
+ })
+
+ It("should reject a different minor", func() {
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 17, Patch: 3})).To(BeFalse(), "should reject 1.17.3")
+ })
+
+ It("should serialize as X.Y.*", func() {
+ Expect(sel.String()).To(Equal("1.16.*"))
+ })
+
+ It("should not be concrete", func() {
+ Expect(sel.AsConcrete()).To(BeNil())
+ })
+ })
+
+ Context("with a specific patch", func() {
+ BeforeEach(func() {
+ var err error
+ sel, err = FromExpr("1.16.3")
+ Expect(err).NotTo(HaveOccurred())
+ })
+ It("should match exactly the major/minor/patch", func() {
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 16, Patch: 3})).To(BeTrue(), "should match 1.16.3")
+ })
+
+ It("should reject a different major", func() {
+ Expect(sel.Matches(Concrete{Major: 2, Minor: 16, Patch: 3})).To(BeFalse(), "should reject 2.16.3")
+
+ })
+
+ It("should reject a different minor", func() {
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 17, Patch: 3})).To(BeFalse(), "should reject 1.17.3")
+
+ })
+
+ It("should reject a different patch", func() {
+
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 16, Patch: 4})).To(BeFalse(), "should reject 1.16.4")
+ })
+ It("should serialize as X.Y.Z", func() {
+ Expect(sel.String()).To(Equal("1.16.3"))
+ })
+ It("may be concrete", func() {
+ Expect(sel.AsConcrete()).To(Equal(&Concrete{Major: 1, Minor: 16, Patch: 3}))
+ })
+ })
+
+ })
+
+ Describe("tilde", func() {
+ var sel Selector
+ BeforeEach(func() {
+ var err error
+ sel, err = FromExpr("~1.16.3")
+ Expect(err).NotTo(HaveOccurred())
+ })
+ It("should match exactly the major/minor/patch", func() {
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 16, Patch: 3})).To(BeTrue(), "should match 1.16.3")
+ })
+
+ It("should match a patch greater than the given one, with the same major/minor", func() {
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 16, Patch: 4})).To(BeTrue(), "should match 1.16.4")
+ })
+
+ It("should reject a patch less than the given one, with the same major/minor", func() {
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 16, Patch: 2})).To(BeFalse(), "should reject 1.16.2")
+
+ })
+
+ It("should reject a different major", func() {
+ Expect(sel.Matches(Concrete{Major: 2, Minor: 16, Patch: 3})).To(BeFalse(), "should reject 2.16.3")
+
+ })
+
+ It("should reject a different minor", func() {
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 17, Patch: 3})).To(BeFalse(), "should reject 1.17.3")
+
+ })
+
+ It("should treat ~X.Y.* as ~X.Y.Z", func() {
+ sel, err := FromExpr("~1.16.*")
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 16, Patch: 0})).To(BeTrue(), "should match 1.16.0")
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 16, Patch: 3})).To(BeTrue(), "should match 1.16.3")
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 17, Patch: 0})).To(BeFalse(), "should reject 1.17.0")
+ })
+ It("should serialize as ~X.Y.Z", func() {
+ Expect(sel.String()).To(Equal("~1.16.3"))
+ })
+ It("should never be concrete", func() {
+ Expect(sel.AsConcrete()).To(BeNil())
+ })
+ })
+
+ Describe("less-than", func() {
+ var sel Selector
+ BeforeEach(func() {
+ var err error
+ sel, err = FromExpr("<1.16.3")
+ Expect(err).NotTo(HaveOccurred())
+ })
+ It("should reject the exact major/minor/patch", func() {
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 16, Patch: 3})).To(BeFalse(), "should reject 1.16.3")
+
+ })
+ It("should reject greater patches", func() {
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 16, Patch: 4})).To(BeFalse(), "should reject 1.16.4")
+
+ })
+ It("should reject greater majors", func() {
+ Expect(sel.Matches(Concrete{Major: 2, Minor: 16, Patch: 3})).To(BeFalse(), "should reject 2.16.3")
+
+ })
+ It("should reject greater minors", func() {
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 17, Patch: 3})).To(BeFalse(), "should reject 1.17.3")
+
+ })
+
+ It("should accept lesser patches", func() {
+
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 16, Patch: 2})).To(BeTrue(), "should accept 1.16.2")
+ })
+ It("should accept lesser majors", func() {
+ Expect(sel.Matches(Concrete{Major: 0, Minor: 16, Patch: 3})).To(BeTrue(), "should accept 0.16.3")
+
+ })
+ It("should accept lesser minors", func() {
+ Expect(sel.Matches(Concrete{Major: 1, Minor: 15, Patch: 3})).To(BeTrue(), "should accept 1.15.3")
+
+ })
+ It("should serialize as other.Major
+ }
+ if c.Minor != other.Minor {
+ return c.Minor > other.Minor
+ }
+ return c.Patch > other.Patch
+}
+
+// Matches checks if this version is equal to the other one.
+func (c Concrete) Matches(other Concrete) bool {
+ return c == other
+}
+
+func (c Concrete) String() string {
+ return fmt.Sprintf("%d.%d.%d", c.Major, c.Minor, c.Patch)
+}
+
+// PatchSelector selects a set of versions where the patch is a wildcard.
+type PatchSelector struct {
+ Major, Minor int
+ Patch PointVersion
+}
+
+func (s PatchSelector) String() string {
+ return fmt.Sprintf("%d.%d.%s", s.Major, s.Minor, s.Patch)
+}
+
+// Matches checks if the given version matches this selector.
+func (s PatchSelector) Matches(ver Concrete) bool {
+ return s.Major == ver.Major && s.Minor == ver.Minor && s.Patch.Matches(ver.Patch)
+}
+
+// AsConcrete returns nil if there are wildcards in this selector,
+// and the concrete version that this selects otherwise.
+func (s PatchSelector) AsConcrete() *Concrete {
+ if s.Patch == AnyPoint {
+ return nil
+ }
+
+ return &Concrete{
+ Major: s.Major,
+ Minor: s.Minor,
+ Patch: int(s.Patch), // safe to cast, we've just checked wilcards above
+ }
+}
+
+// TildeSelector selects [X.Y.Z, X.Y+1.0).
+type TildeSelector struct {
+ Concrete
+}
+
+// Matches checks if the given version matches this selector.
+func (s TildeSelector) Matches(ver Concrete) bool {
+ if s.Concrete.Matches(ver) {
+ // easy, "exact" match
+ return true
+ }
+ return ver.Major == s.Major && ver.Minor == s.Minor && ver.Patch >= s.Patch
+}
+func (s TildeSelector) String() string {
+ return "~" + s.Concrete.String()
+}
+
+// AsConcrete returns nil (this is never a concrete version).
+func (s TildeSelector) AsConcrete() *Concrete {
+ return nil
+}
+
+// LessThanSelector selects versions older than the given one
+// (mainly useful for cleaning up).
+type LessThanSelector struct {
+ PatchSelector
+ OrEquals bool
+}
+
+// Matches checks if the given version matches this selector.
+func (s LessThanSelector) Matches(ver Concrete) bool {
+ if s.Major != ver.Major {
+ return s.Major > ver.Major
+ }
+ if s.Minor != ver.Minor {
+ return s.Minor > ver.Minor
+ }
+ if !s.Patch.Matches(ver.Patch) {
+ // matches rules out a wildcard, so it's fine to compare as normal numbers
+ return int(s.Patch) > ver.Patch
+ }
+ return s.OrEquals
+}
+func (s LessThanSelector) String() string {
+ if s.OrEquals {
+ return "<=" + s.PatchSelector.String()
+ }
+ return "<" + s.PatchSelector.String()
+}
+
+// AsConcrete returns nil (this is never a concrete version).
+func (s LessThanSelector) AsConcrete() *Concrete {
+ return nil
+}
+
+// AnySelector matches any version at all.
+type AnySelector struct{}
+
+// Matches checks if the given version matches this selector.
+func (AnySelector) Matches(_ Concrete) bool { return true }
+
+// AsConcrete returns nil (this is never a concrete version).
+func (AnySelector) AsConcrete() *Concrete { return nil }
+func (AnySelector) String() string { return "*" }
+
+// Selector selects some concrete version or range of versions.
+type Selector interface {
+ // AsConcrete tries to return this selector as a concrete version.
+ // If the selector would only match a single version, it'll return
+ // that, otherwise it'll return nil.
+ AsConcrete() *Concrete
+ // Matches checks if this selector matches the given concrete version.
+ Matches(ver Concrete) bool
+ String() string
+}
+
+// Spec matches some version or range of versions, and tells us how to deal with local and
+// remote when selecting a version.
+type Spec struct {
+ Selector
+
+ // CheckLatest tells us to check the remote server for the latest
+ // version that matches our selector, instead of just relying on
+ // matching local versions.
+ CheckLatest bool
+}
+
+// MakeConcrete replaces the contents of this spec with one that
+// matches the given concrete version (without checking latest
+// from the server).
+func (s *Spec) MakeConcrete(ver Concrete) {
+ s.Selector = ver
+ s.CheckLatest = false
+}
+
+// AsConcrete returns the underlying selector as a concrete version, if
+// possible.
+func (s Spec) AsConcrete() *Concrete {
+ return s.Selector.AsConcrete()
+}
+
+// Matches checks if the underlying selector matches the given version.
+func (s Spec) Matches(ver Concrete) bool {
+ return s.Selector.Matches(ver)
+}
+
+func (s Spec) String() string {
+ res := s.Selector.String()
+ if s.CheckLatest {
+ res += "!"
+ }
+ return res
+}
+
+// PointVersion represents a wildcard (patch) version
+// or concrete number.
+type PointVersion int
+
+const (
+ // AnyPoint matches any point version.
+ AnyPoint PointVersion = -1
+)
+
+// Matches checks if a point version is compatible
+// with a concrete point version.
+// Two point versions are compatible if they are
+// a) both concrete
+// b) one is a wildcard.
+func (p PointVersion) Matches(other int) bool {
+ switch p {
+ case AnyPoint:
+ return true
+ default:
+ return int(p) == other
+ }
+}
+func (p PointVersion) String() string {
+ switch p {
+ case AnyPoint:
+ return "*"
+ default:
+ return strconv.Itoa(int(p))
+ }
+}
+
+var (
+ // LatestVersion matches the most recent version on the remote server.
+ LatestVersion = Spec{
+ Selector: AnySelector{},
+ CheckLatest: true,
+ }
+ // AnyVersion matches any local or remote version.
+ AnyVersion = Spec{
+ Selector: AnySelector{},
+ }
+)
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/versions_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/versions_suite_test.go
new file mode 100644
index 00000000000..db1fe76403a
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/versions/versions_suite_test.go
@@ -0,0 +1,29 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package versions_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestVersions(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Versions Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows/workflows.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows/workflows.go
new file mode 100644
index 00000000000..fdabd995ae7
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows/workflows.go
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2021 The Kubernetes Authors
+
+package workflows
+
+import (
+ "context"
+ "io"
+
+ "github.com/go-logr/logr"
+
+ envp "sigs.k8s.io/controller-runtime/tools/setup-envtest/env"
+)
+
+// Use is a workflow that prints out information about stored
+// version-platform pairs, downloading them if necessary & requested.
+type Use struct {
+ UseEnv bool
+ AssetsPath string
+ PrintFormat envp.PrintFormat
+}
+
+// Do executes this workflow.
+func (f Use) Do(env *envp.Env) {
+ ctx := logr.NewContext(context.TODO(), env.Log.WithName("use"))
+ env.EnsureBaseDirs(ctx)
+ if f.UseEnv {
+ // the env var unconditionally
+ if env.PathMatches(f.AssetsPath) {
+ env.PrintInfo(f.PrintFormat)
+ return
+ }
+ }
+ env.EnsureVersionIsSet(ctx)
+ if env.ExistsAndValid() {
+ env.PrintInfo(f.PrintFormat)
+ return
+ }
+ if env.NoDownload {
+ envp.Exit(2, "no such version (%s) exists on disk for this architecture (%s) -- try running `list -i` to see what's on disk", env.Version, env.Platform)
+ }
+ env.Fetch(ctx)
+ env.PrintInfo(f.PrintFormat)
+}
+
+// List is a workflow that lists version-platform pairs in the store
+// and on the remote server that match the given filter.
+type List struct{}
+
+// Do executes this workflow.
+func (List) Do(env *envp.Env) {
+ ctx := logr.NewContext(context.TODO(), env.Log.WithName("list"))
+ env.EnsureBaseDirs(ctx)
+ env.ListVersions(ctx)
+}
+
+// Cleanup is a workflow that removes version-platform pairs from the store
+// that match the given filter.
+type Cleanup struct{}
+
+// Do executes this workflow.
+func (Cleanup) Do(env *envp.Env) {
+ ctx := logr.NewContext(context.TODO(), env.Log.WithName("cleanup"))
+
+ env.NoDownload = true
+ env.ForceDownload = false
+
+ env.EnsureBaseDirs(ctx)
+ env.Remove(ctx)
+}
+
+// Sideload is a workflow that adds or replaces a version-platform pair in the
+// store, using the given archive as the files.
+type Sideload struct {
+ Input io.Reader
+ PrintFormat envp.PrintFormat
+}
+
+// Do executes this workflow.
+func (f Sideload) Do(env *envp.Env) {
+ ctx := logr.NewContext(context.TODO(), env.Log.WithName("sideload"))
+
+ env.EnsureBaseDirs(ctx)
+ env.NoDownload = true
+ env.Sideload(ctx, f.Input)
+ env.PrintInfo(f.PrintFormat)
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows/workflows_suite_test.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows/workflows_suite_test.go
new file mode 100644
index 00000000000..1b487622bde
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows/workflows_suite_test.go
@@ -0,0 +1,46 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package workflows_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ "github.com/go-logr/logr"
+ "github.com/go-logr/zapr"
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+)
+
+var testLog logr.Logger
+
+func zapLogger() logr.Logger {
+ testOut := zapcore.AddSync(GinkgoWriter)
+ enc := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
+ // bleh setting up logging to the ginkgo writer is annoying
+ zapLog := zap.New(zapcore.NewCore(enc, testOut, zap.DebugLevel),
+ zap.ErrorOutput(testOut), zap.Development(), zap.AddStacktrace(zap.WarnLevel))
+ return zapr.NewLogger(zapLog)
+}
+
+func TestWorkflows(t *testing.T) {
+ testLog = zapLogger()
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Workflows Suite")
+}
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows/workflows_test.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows/workflows_test.go
new file mode 100644
index 00000000000..a0bd7321f79
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows/workflows_test.go
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2021 The Kubernetes Authors
+
+package workflows_test
+
+import (
+ "bytes"
+ "io/fs"
+ "path/filepath"
+ "strings"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/onsi/gomega/ghttp"
+ "github.com/spf13/afero"
+
+ envp "sigs.k8s.io/controller-runtime/tools/setup-envtest/env"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/remote"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/store"
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/versions"
+ wf "sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows"
+)
+
+func ver(major, minor, patch int) versions.Concrete {
+ return versions.Concrete{
+ Major: major,
+ Minor: minor,
+ Patch: patch,
+ }
+}
+
+func shouldHaveError() {
+ var err error
+ var code int
+ if cause := recover(); envp.CheckRecover(cause, func(caughtCode int, caughtErr error) {
+ err = caughtErr
+ code = caughtCode
+ }) {
+ panic(cause)
+ }
+ Expect(err).To(HaveOccurred(), "should write an error")
+ Expect(code).NotTo(BeZero(), "should exit with a non-zero code")
+}
+
+const (
+ testStorePath = ".teststore"
+)
+
+var _ = Describe("Workflows", func() {
+ var (
+ env *envp.Env
+ out *bytes.Buffer
+ server *ghttp.Server
+ remoteItems []item
+ )
+ BeforeEach(func() {
+ out = new(bytes.Buffer)
+ baseFs := afero.Afero{Fs: afero.NewMemMapFs()}
+ env = &envp.Env{
+ Log: testLog,
+ VerifySum: true, // on by default
+ FS: baseFs,
+ Store: &store.Store{Root: afero.NewBasePathFs(baseFs, testStorePath)},
+ Out: out,
+ Platform: versions.PlatformItem{ // default
+ Platform: versions.Platform{
+ OS: "linux",
+ Arch: "amd64",
+ },
+ },
+ Client: &remote.Client{
+ Log: testLog.WithName("remote-client"),
+ Bucket: "kubebuilder-tools-test", // test custom bucket functionality too
+ Server: "localhost:-1",
+ Insecure: true, // no https in httptest :-(
+ },
+ }
+ server = ghttp.NewServer()
+ env.Client.Server = server.Addr()
+
+ fakeStore(env.FS, testStorePath)
+ remoteItems = remoteVersions
+ })
+ JustBeforeEach(func() {
+ handleRemoteVersions(server, remoteItems)
+ })
+ AfterEach(func() {
+ server.Close()
+ server = nil
+ })
+
+ Describe("use", func() {
+ var flow wf.Use
+ BeforeEach(func() {
+ // some defaults for most tests
+ env.Version = versions.Spec{
+ Selector: ver(1, 16, 0),
+ }
+ flow = wf.Use{
+ PrintFormat: envp.PrintPath,
+ }
+ })
+
+ It("should initialize the store if it doesn't exist", func() {
+ Expect(env.FS.RemoveAll(testStorePath)).To(Succeed())
+ // need to set this to a valid remote version cause our store is now empty
+ env.Version = versions.Spec{Selector: ver(1, 16, 4)}
+ flow.Do(env)
+ Expect(env.FS.Stat(testStorePath)).NotTo(BeNil())
+ })
+
+ Context("when use env is set", func() {
+ BeforeEach(func() {
+ flow.UseEnv = true
+ })
+ It("should fall back to normal behavior when the env is not set", func() {
+ flow.Do(env)
+ Expect(out.String()).To(HaveSuffix("/1.16.0-linux-amd64"), "should fall back to a local version")
+ })
+ It("should fall back to normal behavior if binaries are missing", func() {
+ flow.AssetsPath = ".teststore/missing-binaries"
+ flow.Do(env)
+ Expect(out.String()).To(HaveSuffix("/1.16.0-linux-amd64"), "should fall back to a local version")
+ })
+ It("should use the value of the env if it contains the right binaries", func() {
+ flow.AssetsPath = ".teststore/good-version"
+ flow.Do(env)
+ Expect(out.String()).To(Equal(flow.AssetsPath))
+ })
+ It("should not try and check the version of the binaries", func() {
+ flow.AssetsPath = ".teststore/wrong-version"
+ flow.Do(env)
+ Expect(out.String()).To(Equal(flow.AssetsPath))
+ })
+ It("should not need to contact the network", func() {
+ server.Close()
+ flow.AssetsPath = ".teststore/good-version"
+ flow.Do(env)
+ // expect to not get a panic -- if we do, it'll cause the test to fail
+ })
+ })
+
+ Context("when downloads are disabled", func() {
+ BeforeEach(func() {
+ env.NoDownload = true
+ server.Close()
+ })
+
+ // It("should not contact the network") is a gimme here, because we
+ // call server.Close() above.
+
+ It("should error if no matches are found locally", func() {
+ defer shouldHaveError()
+ env.Version.Selector = versions.Concrete{Major: 9001}
+ flow.Do(env)
+ })
+ It("should settle for the latest local match if latest is requested", func() {
+ env.Version = versions.Spec{
+ CheckLatest: true,
+ Selector: versions.PatchSelector{
+ Major: 1,
+ Minor: 16,
+ Patch: versions.AnyPoint,
+ },
+ }
+
+ flow.Do(env)
+
+ // latest on "server" is 1.16.4, shouldn't use that
+ Expect(out.String()).To(HaveSuffix("/1.16.1-linux-amd64"), "should use the latest local version")
+ })
+ })
+
+ Context("if latest is requested", func() {
+ It("should contact the network to see if there's anything newer", func() {
+ env.Version = versions.Spec{
+ CheckLatest: true,
+ Selector: versions.PatchSelector{
+ Major: 1, Minor: 16, Patch: versions.AnyPoint,
+ },
+ }
+ flow.Do(env)
+ Expect(out.String()).To(HaveSuffix("/1.16.4-linux-amd64"), "should use the latest remote version")
+ })
+ It("should still use the latest local if the network doesn't have anything newer", func() {
+ env.Version = versions.Spec{
+ CheckLatest: true,
+ Selector: versions.PatchSelector{
+ Major: 1, Minor: 14, Patch: versions.AnyPoint,
+ },
+ }
+
+ flow.Do(env)
+
+ // latest on the server is 1.14.1, latest local is 1.14.26
+ Expect(out.String()).To(HaveSuffix("/1.14.26-linux-amd64"), "should use the latest local version")
+ })
+ })
+
+ It("should check local for a match first", func() {
+ server.Close() // confirm no network
+ env.Version = versions.Spec{
+ Selector: versions.TildeSelector{Concrete: ver(1, 16, 0)},
+ }
+ flow.Do(env)
+ // latest on the server is 1.16.4, latest local is 1.16.1
+ Expect(out.String()).To(HaveSuffix("/1.16.1-linux-amd64"), "should use the latest local version")
+ })
+
+ It("should fall back to the network if no local matches are found", func() {
+ env.Version = versions.Spec{
+ Selector: versions.TildeSelector{Concrete: ver(1, 19, 0)},
+ }
+ flow.Do(env)
+ Expect(out.String()).To(HaveSuffix("/1.19.2-linux-amd64"), "should have a remote version")
+ })
+
+ It("should error out if no matches can be found anywhere", func() {
+ defer shouldHaveError()
+ env.Version = versions.Spec{
+ Selector: versions.TildeSelector{Concrete: ver(0, 0, 1)},
+ }
+ flow.Do(env)
+ })
+
+ It("should skip local versions matches with non-matching platforms", func() {
+ env.NoDownload = true // so we get an error
+ defer shouldHaveError()
+ env.Version = versions.Spec{
+ // has non-matching local versions
+ Selector: ver(1, 13, 0),
+ }
+
+ flow.Do(env)
+ })
+
+ It("should skip remote version matches with non-matching platforms", func() {
+ defer shouldHaveError()
+ env.Version = versions.Spec{
+ // has a non-matching remote version
+ Selector: versions.TildeSelector{Concrete: ver(1, 11, 1)},
+ }
+ flow.Do(env)
+ })
+
+ Describe("verifying the checksum", func() {
+ BeforeEach(func() {
+ remoteItems = append(remoteItems, item{
+ meta: bucketObject{
+ Name: "kubebuilder-tools-86.75.309-linux-amd64.tar.gz",
+ Hash: "nottherightone!",
+ },
+ contents: remoteItems[0].contents, // need a valid tar.gz file to not error from that
+ })
+ env.Version = versions.Spec{
+ Selector: ver(86, 75, 309),
+ }
+ })
+ Specify("when enabled, should fail if the downloaded md5 checksum doesn't match", func() {
+ defer shouldHaveError()
+ flow.Do(env)
+ })
+ Specify("when disabled, shouldn't check the checksum at all", func() {
+ env.VerifySum = false
+ flow.Do(env)
+ })
+ })
+ })
+
+ Describe("list", func() {
+ // split by fields so we're not matching on whitespace
+ listFields := func() [][]string {
+ resLines := strings.Split(strings.TrimSpace(out.String()), "\n")
+ resFields := make([][]string, len(resLines))
+ for i, line := range resLines {
+ resFields[i] = strings.Fields(line)
+ }
+ return resFields
+ }
+
+ Context("when downloads are disabled", func() {
+ BeforeEach(func() {
+ server.Close() // ensure no network
+ env.NoDownload = true
+ })
+ It("should include local contents sorted by version", func() {
+ env.Version = versions.AnyVersion
+ env.Platform.Platform = versions.Platform{OS: "*", Arch: "*"}
+ wf.List{}.Do(env)
+
+ Expect(listFields()).To(Equal([][]string{
+ {"(installed)", "v1.17.9", "linux/amd64"},
+ {"(installed)", "v1.16.2", "ifonlysingularitywasstillathing/amd64"},
+ {"(installed)", "v1.16.2", "linux/yourimagination"},
+ {"(installed)", "v1.16.1", "linux/amd64"},
+ {"(installed)", "v1.16.0", "linux/amd64"},
+ {"(installed)", "v1.14.26", "hyperwarp/pixiedust"},
+ {"(installed)", "v1.14.26", "linux/amd64"},
+ }))
+ })
+ It("should skip non-matching local contents", func() {
+ env.Version.Selector = versions.PatchSelector{
+ Major: 1, Minor: 16, Patch: versions.AnyPoint,
+ }
+ env.Platform.Arch = "*"
+ wf.List{}.Do(env)
+
+ Expect(listFields()).To(Equal([][]string{
+ {"(installed)", "v1.16.2", "linux/yourimagination"},
+ {"(installed)", "v1.16.1", "linux/amd64"},
+ {"(installed)", "v1.16.0", "linux/amd64"},
+ }))
+
+ })
+ })
+ Context("when downloads are enabled", func() {
+ Context("when sorting", func() {
+ BeforeEach(func() {
+ // shorten the list a bit for expediency
+ remoteItems = remoteItems[:7]
+ })
+ It("should sort local & remote by version", func() {
+ env.Version = versions.AnyVersion
+ env.Platform.Platform = versions.Platform{OS: "*", Arch: "*"}
+ wf.List{}.Do(env)
+
+ Expect(listFields()).To(Equal([][]string{
+ {"(installed)", "v1.17.9", "linux/amd64"},
+ {"(installed)", "v1.16.2", "ifonlysingularitywasstillathing/amd64"},
+ {"(installed)", "v1.16.2", "linux/yourimagination"},
+ {"(installed)", "v1.16.1", "linux/amd64"},
+ {"(installed)", "v1.16.0", "linux/amd64"},
+ {"(installed)", "v1.14.26", "hyperwarp/pixiedust"},
+ {"(installed)", "v1.14.26", "linux/amd64"},
+ {"(available)", "v1.11.1", "potato/cherrypie"},
+ {"(available)", "v1.11.0", "darwin/amd64"},
+ {"(available)", "v1.11.0", "linux/amd64"},
+ {"(available)", "v1.10.1", "darwin/amd64"},
+ {"(available)", "v1.10.1", "linux/amd64"},
+ }))
+
+ })
+ })
+ It("should skip non-matching remote contents", func() {
+ env.Version.Selector = versions.PatchSelector{
+ Major: 1, Minor: 16, Patch: versions.AnyPoint,
+ }
+ env.Platform.Arch = "*"
+ wf.List{}.Do(env)
+
+ Expect(listFields()).To(Equal([][]string{
+ {"(installed)", "v1.16.2", "linux/yourimagination"},
+ {"(installed)", "v1.16.1", "linux/amd64"},
+ {"(installed)", "v1.16.0", "linux/amd64"},
+ {"(available)", "v1.16.4", "linux/amd64"},
+ }))
+
+ })
+ })
+ })
+
+ Describe("cleanup", func() {
+ BeforeEach(func() {
+ server.Close() // ensure no network
+ flow := wf.Cleanup{}
+ env.Version = versions.AnyVersion
+ env.Platform.Arch = "*"
+ flow.Do(env)
+ })
+
+ It("should remove matching versions from the store & keep non-matching ones", func() {
+ entries, err := env.FS.ReadDir(".teststore/k8s")
+ Expect(err).NotTo(HaveOccurred(), "should be able to read the store")
+ Expect(entries).To(ConsistOf(
+ WithTransform(fs.FileInfo.Name, Equal("1.16.2-ifonlysingularitywasstillathing-amd64")),
+ WithTransform(fs.FileInfo.Name, Equal("1.14.26-hyperwarp-pixiedust")),
+ ))
+ })
+ })
+
+ Describe("sideload", func() {
+ var (
+ flow wf.Sideload
+ // remote version fake contents are prefixed by the
+ // name for easier debugging, so we can use that here
+ expectedPrefix = remoteVersions[0].meta.Name
+ )
+ BeforeEach(func() {
+ server.Close() // ensure no network
+ flow.Input = bytes.NewReader(remoteVersions[0].contents)
+ flow.PrintFormat = envp.PrintPath
+ })
+ It("should initialize the store if it doesn't exist", func() {
+ env.Version.Selector = ver(1, 10, 0)
+ Expect(env.FS.RemoveAll(testStorePath)).To(Succeed())
+ flow.Do(env)
+ Expect(env.FS.Stat(testStorePath)).NotTo(BeNil())
+ })
+ It("should fail if a non-concrete version is given", func() {
+ defer shouldHaveError()
+ env.Version = versions.LatestVersion
+ flow.Do(env)
+ })
+ It("should fail if a non-concrete platform is given", func() {
+ defer shouldHaveError()
+ env.Version.Selector = ver(1, 10, 0)
+ env.Platform.Arch = "*"
+ flow.Do(env)
+ })
+ It("should load the given gizipped tarball into our store as the given version", func() {
+ env.Version.Selector = ver(1, 10, 0)
+ flow.Do(env)
+ baseName := env.Platform.BaseName(*env.Version.AsConcrete())
+ expectedPath := filepath.Join(".teststore/k8s", baseName, "some-file")
+ outContents, err := env.FS.ReadFile(expectedPath)
+ Expect(err).NotTo(HaveOccurred(), "should be able to load the unzipped file")
+ Expect(string(outContents)).To(HavePrefix(expectedPrefix), "should have the debugging prefix")
+ })
+ })
+})
diff --git a/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows/workflows_testutils_test.go b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows/workflows_testutils_test.go
new file mode 100644
index 00000000000..f236ce460e4
--- /dev/null
+++ b/third_party/sigs.k8s.io/controller-runtime/tools/setup-envtest/workflows/workflows_testutils_test.go
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2021 The Kubernetes Authors
+
+package workflows_test
+
+import (
+ "archive/tar"
+ "bytes"
+ "compress/gzip"
+ "crypto/md5" //nolint:gosec
+ "crypto/rand"
+ "encoding/base64"
+ "net/http"
+ "path/filepath"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/onsi/gomega/ghttp"
+ "github.com/spf13/afero"
+
+ "sigs.k8s.io/controller-runtime/tools/setup-envtest/versions"
+)
+
+var (
+ remoteNames = []string{
+ "kubebuilder-tools-1.10-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.10-linux-amd64.tar.gz",
+ "kubebuilder-tools-1.10.1-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.10.1-linux-amd64.tar.gz",
+ "kubebuilder-tools-1.11.0-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.11.0-linux-amd64.tar.gz",
+ "kubebuilder-tools-1.11.1-potato-cherrypie.tar.gz",
+ "kubebuilder-tools-1.12.3-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.12.3-linux-amd64.tar.gz",
+ "kubebuilder-tools-1.13.1-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.13.1-linux-amd64.tar.gz",
+ "kubebuilder-tools-1.14.1-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.14.1-linux-amd64.tar.gz",
+ "kubebuilder-tools-1.15.5-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.15.5-linux-amd64.tar.gz",
+ "kubebuilder-tools-1.16.4-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.16.4-linux-amd64.tar.gz",
+ "kubebuilder-tools-1.17.9-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.17.9-linux-amd64.tar.gz",
+ "kubebuilder-tools-1.19.0-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.19.0-linux-amd64.tar.gz",
+ "kubebuilder-tools-1.19.2-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.19.2-linux-amd64.tar.gz",
+ "kubebuilder-tools-1.19.2-linux-arm64.tar.gz",
+ "kubebuilder-tools-1.19.2-linux-ppc64le.tar.gz",
+ "kubebuilder-tools-1.20.2-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.20.2-linux-amd64.tar.gz",
+ "kubebuilder-tools-1.20.2-linux-arm64.tar.gz",
+ "kubebuilder-tools-1.20.2-linux-ppc64le.tar.gz",
+ "kubebuilder-tools-1.9-darwin-amd64.tar.gz",
+ "kubebuilder-tools-1.9-linux-amd64.tar.gz",
+ "kubebuilder-tools-v1.19.2-darwin-amd64.tar.gz",
+ "kubebuilder-tools-v1.19.2-linux-amd64.tar.gz",
+ "kubebuilder-tools-v1.19.2-linux-arm64.tar.gz",
+ "kubebuilder-tools-v1.19.2-linux-ppc64le.tar.gz",
+ }
+
+ remoteVersions = makeContents(remoteNames)
+
+ // keep this sorted.
+ localVersions = []versions.Set{
+ {Version: ver(1, 17, 9), Platforms: []versions.PlatformItem{
+ {Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ }},
+ {Version: ver(1, 16, 2), Platforms: []versions.PlatformItem{
+ {Platform: versions.Platform{OS: "linux", Arch: "yourimagination"}},
+ {Platform: versions.Platform{OS: "ifonlysingularitywasstillathing", Arch: "amd64"}},
+ }},
+ {Version: ver(1, 16, 1), Platforms: []versions.PlatformItem{
+ {Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ }},
+ {Version: ver(1, 16, 0), Platforms: []versions.PlatformItem{
+ {Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ }},
+ {Version: ver(1, 14, 26), Platforms: []versions.PlatformItem{
+ {Platform: versions.Platform{OS: "linux", Arch: "amd64"}},
+ {Platform: versions.Platform{OS: "hyperwarp", Arch: "pixiedust"}},
+ }},
+ }
+)
+
+type item struct {
+ meta bucketObject
+ contents []byte
+}
+
+// objectList is the parts we need of the GCS "list-objects-in-bucket" endpoint.
+type objectList struct {
+ Items []bucketObject `json:"items"`
+}
+
+// bucketObject is the parts we need of the GCS object metadata.
+type bucketObject struct {
+ Name string `json:"name"`
+ Hash string `json:"md5Hash"`
+}
+
+func makeContents(names []string) []item {
+ res := make([]item, len(names))
+ for i, name := range names {
+ var chunk [1024 * 48]byte // 1.5 times our chunk read size in GetVersion
+ copy(chunk[:], name)
+ if _, err := rand.Read(chunk[len(name):]); err != nil {
+ panic(err)
+ }
+ res[i] = verWith(name, chunk[:])
+ }
+ return res
+}
+
+func verWith(name string, contents []byte) item {
+ out := new(bytes.Buffer)
+ gzipWriter := gzip.NewWriter(out)
+ tarWriter := tar.NewWriter(gzipWriter)
+ err := tarWriter.WriteHeader(&tar.Header{
+ Name: "kubebuilder/bin/some-file",
+ Size: int64(len(contents)),
+ Mode: 0777, // so we can check that we fix this later
+ })
+ if err != nil {
+ panic(err)
+ }
+ _, err = tarWriter.Write(contents)
+ if err != nil {
+ panic(err)
+ }
+ tarWriter.Close()
+ gzipWriter.Close()
+ res := item{
+ meta: bucketObject{Name: name},
+ contents: out.Bytes(),
+ }
+ hash := md5.Sum(res.contents) //nolint:gosec
+ res.meta.Hash = base64.StdEncoding.EncodeToString(hash[:])
+ return res
+}
+
+func handleRemoteVersions(server *ghttp.Server, versions []item) {
+ list := objectList{Items: make([]bucketObject, len(versions))}
+ for i, ver := range versions {
+ ver := ver // copy to avoid capturing the iteration variable
+ list.Items[i] = ver.meta
+ server.RouteToHandler("GET", "/storage/v1/b/kubebuilder-tools-test/o/"+ver.meta.Name, func(resp http.ResponseWriter, req *http.Request) {
+ if req.URL.Query().Get("alt") == "media" {
+ resp.WriteHeader(http.StatusOK)
+ Expect(resp.Write(ver.contents)).To(Equal(len(ver.contents)))
+ } else {
+ ghttp.RespondWithJSONEncoded(
+ http.StatusOK,
+ ver.meta,
+ )(resp, req)
+ }
+ })
+ }
+ server.RouteToHandler("GET", "/storage/v1/b/kubebuilder-tools-test/o", ghttp.RespondWithJSONEncoded(
+ http.StatusOK,
+ list,
+ ))
+}
+
+func fakeStore(fs afero.Afero, dir string) {
+ By("making the unpacked directory")
+ unpackedBase := filepath.Join(dir, "k8s")
+ Expect(fs.Mkdir(unpackedBase, 0755)).To(Succeed())
+
+ By("making some fake (empty) versions")
+ for _, set := range localVersions {
+ for _, plat := range set.Platforms {
+ Expect(fs.Mkdir(filepath.Join(unpackedBase, plat.BaseName(set.Version)), 0755)).To(Succeed())
+ }
+ }
+
+ By("making some fake non-store paths")
+ Expect(fs.Mkdir(filepath.Join(dir, "missing-binaries"), 0755))
+
+ Expect(fs.Mkdir(filepath.Join(dir, "wrong-version"), 0755))
+ Expect(fs.WriteFile(filepath.Join(dir, "wrong-version", "kube-apiserver"), nil, 0755)).To(Succeed())
+ Expect(fs.WriteFile(filepath.Join(dir, "wrong-version", "kubectl"), nil, 0755)).To(Succeed())
+ Expect(fs.WriteFile(filepath.Join(dir, "wrong-version", "etcd"), nil, 0755)).To(Succeed())
+
+ Expect(fs.Mkdir(filepath.Join(dir, "good-version"), 0755))
+ Expect(fs.WriteFile(filepath.Join(dir, "good-version", "kube-apiserver"), nil, 0755)).To(Succeed())
+ Expect(fs.WriteFile(filepath.Join(dir, "good-version", "kubectl"), nil, 0755)).To(Succeed())
+ Expect(fs.WriteFile(filepath.Join(dir, "good-version", "etcd"), nil, 0755)).To(Succeed())
+ // TODO: put the right files
+}
diff --git a/vendor/cloud.google.com/go/compute/internal/version.go b/vendor/cloud.google.com/go/compute/internal/version.go
new file mode 100644
index 00000000000..b1672963f6c
--- /dev/null
+++ b/vendor/cloud.google.com/go/compute/internal/version.go
@@ -0,0 +1,18 @@
+// Copyright 2022 Google LLC
+//
+// 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 internal
+
+// Version is the current tagged release of the library.
+const Version = "1.21.0"
diff --git a/vendor/cloud.google.com/go/compute/metadata/CHANGES.md b/vendor/cloud.google.com/go/compute/metadata/CHANGES.md
new file mode 100644
index 00000000000..06b957349af
--- /dev/null
+++ b/vendor/cloud.google.com/go/compute/metadata/CHANGES.md
@@ -0,0 +1,19 @@
+# Changes
+
+## [0.2.3](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.2.2...compute/metadata/v0.2.3) (2022-12-15)
+
+
+### Bug Fixes
+
+* **compute/metadata:** Switch DNS lookup to an absolute lookup ([119b410](https://github.com/googleapis/google-cloud-go/commit/119b41060c7895e45e48aee5621ad35607c4d021)), refs [#7165](https://github.com/googleapis/google-cloud-go/issues/7165)
+
+## [0.2.2](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.2.1...compute/metadata/v0.2.2) (2022-12-01)
+
+
+### Bug Fixes
+
+* **compute/metadata:** Set IdleConnTimeout for http.Client ([#7084](https://github.com/googleapis/google-cloud-go/issues/7084)) ([766516a](https://github.com/googleapis/google-cloud-go/commit/766516aaf3816bfb3159efeea65aa3d1d205a3e2)), refs [#5430](https://github.com/googleapis/google-cloud-go/issues/5430)
+
+## [0.1.0] (2022-10-26)
+
+Initial release of metadata being it's own module.
diff --git a/vendor/cloud.google.com/go/compute/metadata/LICENSE b/vendor/cloud.google.com/go/compute/metadata/LICENSE
new file mode 100644
index 00000000000..d6456956733
--- /dev/null
+++ b/vendor/cloud.google.com/go/compute/metadata/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/cloud.google.com/go/compute/metadata/README.md b/vendor/cloud.google.com/go/compute/metadata/README.md
new file mode 100644
index 00000000000..f940fb2c85b
--- /dev/null
+++ b/vendor/cloud.google.com/go/compute/metadata/README.md
@@ -0,0 +1,27 @@
+# Compute API
+
+[](https://pkg.go.dev/cloud.google.com/go/compute/metadata)
+
+This is a utility library for communicating with Google Cloud metadata service
+on Google Cloud.
+
+## Install
+
+```bash
+go get cloud.google.com/go/compute/metadata
+```
+
+## Go Version Support
+
+See the [Go Versions Supported](https://github.com/googleapis/google-cloud-go#go-versions-supported)
+section in the root directory's README.
+
+## Contributing
+
+Contributions are welcome. Please, see the [CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md)
+document for details.
+
+Please note that this project is released with a Contributor Code of Conduct.
+By participating in this project you agree to abide by its terms. See
+[Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md#contributor-code-of-conduct)
+for more information.
diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata.go b/vendor/cloud.google.com/go/compute/metadata/metadata.go
index 111309f3d8b..c17faa142a4 100644
--- a/vendor/cloud.google.com/go/compute/metadata/metadata.go
+++ b/vendor/cloud.google.com/go/compute/metadata/metadata.go
@@ -16,7 +16,7 @@
// metadata and API service accounts.
//
// This package is a wrapper around the GCE metadata service,
-// as documented at https://developers.google.com/compute/docs/metadata.
+// as documented at https://cloud.google.com/compute/docs/metadata/overview.
package metadata // import "cloud.google.com/go/compute/metadata"
import (
@@ -70,7 +70,9 @@ func newDefaultHTTPClient() *http.Client {
Timeout: 2 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
+ IdleConnTimeout: 60 * time.Second,
},
+ Timeout: 5 * time.Second,
}
}
@@ -145,7 +147,7 @@ func testOnGCE() bool {
go func() {
resolver := &net.Resolver{}
- addrs, err := resolver.LookupHost(ctx, "metadata.google.internal")
+ addrs, err := resolver.LookupHost(ctx, "metadata.google.internal.")
if err != nil || len(addrs) == 0 {
resc <- false
return
diff --git a/vendor/cloud.google.com/go/compute/metadata/tidyfix.go b/vendor/cloud.google.com/go/compute/metadata/tidyfix.go
new file mode 100644
index 00000000000..4cef4850081
--- /dev/null
+++ b/vendor/cloud.google.com/go/compute/metadata/tidyfix.go
@@ -0,0 +1,23 @@
+// Copyright 2022 Google LLC
+//
+// 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.
+
+// This file, and the {{.RootMod}} import, won't actually become part of
+// the resultant binary.
+//go:build modhack
+// +build modhack
+
+package metadata
+
+// Necessary for safely adding multi-module repo. See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository
+import _ "cloud.google.com/go/compute/internal"
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/alert_policy_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/alert_policy_client.go
index 813b9deae35..84496844a2d 100644
--- a/vendor/cloud.google.com/go/monitoring/apiv3/v2/alert_policy_client.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/alert_policy_client.go
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -23,12 +23,12 @@ import (
"net/url"
"time"
+ monitoringpb "cloud.google.com/go/monitoring/apiv3/v2/monitoringpb"
gax "github.com/googleapis/gax-go/v2"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
"google.golang.org/api/option/internaloption"
gtransport "google.golang.org/api/transport/grpc"
- monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
@@ -61,6 +61,7 @@ func defaultAlertPolicyGRPCClientOptions() []option.ClientOption {
func defaultAlertPolicyCallOptions() *AlertPolicyCallOptions {
return &AlertPolicyCallOptions{
ListAlertPolicies: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -72,6 +73,7 @@ func defaultAlertPolicyCallOptions() *AlertPolicyCallOptions {
}),
},
GetAlertPolicy: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -82,8 +84,11 @@ func defaultAlertPolicyCallOptions() *AlertPolicyCallOptions {
})
}),
},
- CreateAlertPolicy: []gax.CallOption{},
+ CreateAlertPolicy: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
DeleteAlertPolicy: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -94,11 +99,13 @@ func defaultAlertPolicyCallOptions() *AlertPolicyCallOptions {
})
}),
},
- UpdateAlertPolicy: []gax.CallOption{},
+ UpdateAlertPolicy: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
}
}
-// internalAlertPolicyClient is an interface that defines the methods availaible from Cloud Monitoring API.
+// internalAlertPolicyClient is an interface that defines the methods available from Cloud Monitoring API.
type internalAlertPolicyClient interface {
Close() error
setGoogleClientInfo(...string)
@@ -114,14 +121,14 @@ type internalAlertPolicyClient interface {
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
//
// The AlertPolicyService API is used to manage (list, create, delete,
-// edit) alert policies in Stackdriver Monitoring. An alerting policy is
+// edit) alert policies in Cloud Monitoring. An alerting policy is
// a description of the conditions under which some aspect of your
// system is considered to be “unhealthy” and the ways to notify
// people or services about this state. In addition to using this API, alert
// policies can also be managed through
-// Stackdriver Monitoring (at https://cloud.google.com/monitoring/docs/),
+// Cloud Monitoring (at https://cloud.google.com/monitoring/docs/),
// which can be reached by clicking the “Monitoring” tab in
-// Cloud Console (at https://console.cloud.google.com/).
+// Cloud console (at https://console.cloud.google.com/).
type AlertPolicyClient struct {
// The internal transport-dependent client.
internalClient internalAlertPolicyClient
@@ -147,7 +154,8 @@ func (c *AlertPolicyClient) setGoogleClientInfo(keyval ...string) {
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *AlertPolicyClient) Connection() *grpc.ClientConn {
return c.internalClient.Connection()
}
@@ -187,9 +195,6 @@ type alertPolicyGRPCClient struct {
// Connection pool of gRPC connections to the service.
connPool gtransport.ConnPool
- // flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE
- disableDeadlines bool
-
// Points back to the CallOptions field of the containing AlertPolicyClient
CallOptions **AlertPolicyCallOptions
@@ -204,14 +209,14 @@ type alertPolicyGRPCClient struct {
// The returned client must be Closed when it is done being used to clean up its underlying connections.
//
// The AlertPolicyService API is used to manage (list, create, delete,
-// edit) alert policies in Stackdriver Monitoring. An alerting policy is
+// edit) alert policies in Cloud Monitoring. An alerting policy is
// a description of the conditions under which some aspect of your
// system is considered to be “unhealthy” and the ways to notify
// people or services about this state. In addition to using this API, alert
// policies can also be managed through
-// Stackdriver Monitoring (at https://cloud.google.com/monitoring/docs/),
+// Cloud Monitoring (at https://cloud.google.com/monitoring/docs/),
// which can be reached by clicking the “Monitoring” tab in
-// Cloud Console (at https://console.cloud.google.com/).
+// Cloud console (at https://console.cloud.google.com/).
func NewAlertPolicyClient(ctx context.Context, opts ...option.ClientOption) (*AlertPolicyClient, error) {
clientOpts := defaultAlertPolicyGRPCClientOptions()
if newAlertPolicyClientHook != nil {
@@ -222,11 +227,6 @@ func NewAlertPolicyClient(ctx context.Context, opts ...option.ClientOption) (*Al
clientOpts = append(clientOpts, hookOpts...)
}
- disableDeadlines, err := checkDisableDeadlines()
- if err != nil {
- return nil, err
- }
-
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
if err != nil {
return nil, err
@@ -235,7 +235,6 @@ func NewAlertPolicyClient(ctx context.Context, opts ...option.ClientOption) (*Al
c := &alertPolicyGRPCClient{
connPool: connPool,
- disableDeadlines: disableDeadlines,
alertPolicyClient: monitoringpb.NewAlertPolicyServiceClient(connPool),
CallOptions: &client.CallOptions,
}
@@ -248,7 +247,8 @@ func NewAlertPolicyClient(ctx context.Context, opts ...option.ClientOption) (*Al
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *alertPolicyGRPCClient) Connection() *grpc.ClientConn {
return c.connPool.Conn()
}
@@ -257,7 +257,7 @@ func (c *alertPolicyGRPCClient) Connection() *grpc.ClientConn {
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *alertPolicyGRPCClient) setGoogleClientInfo(keyval ...string) {
- kv := append([]string{"gl-go", versionGo()}, keyval...)
+ kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version)
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
}
@@ -314,11 +314,6 @@ func (c *alertPolicyGRPCClient) ListAlertPolicies(ctx context.Context, req *moni
}
func (c *alertPolicyGRPCClient) GetAlertPolicy(ctx context.Context, req *monitoringpb.GetAlertPolicyRequest, opts ...gax.CallOption) (*monitoringpb.AlertPolicy, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -336,11 +331,6 @@ func (c *alertPolicyGRPCClient) GetAlertPolicy(ctx context.Context, req *monitor
}
func (c *alertPolicyGRPCClient) CreateAlertPolicy(ctx context.Context, req *monitoringpb.CreateAlertPolicyRequest, opts ...gax.CallOption) (*monitoringpb.AlertPolicy, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -358,11 +348,6 @@ func (c *alertPolicyGRPCClient) CreateAlertPolicy(ctx context.Context, req *moni
}
func (c *alertPolicyGRPCClient) DeleteAlertPolicy(ctx context.Context, req *monitoringpb.DeleteAlertPolicyRequest, opts ...gax.CallOption) error {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -376,11 +361,6 @@ func (c *alertPolicyGRPCClient) DeleteAlertPolicy(ctx context.Context, req *moni
}
func (c *alertPolicyGRPCClient) UpdateAlertPolicy(ctx context.Context, req *monitoringpb.UpdateAlertPolicyRequest, opts ...gax.CallOption) (*monitoringpb.AlertPolicy, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "alert_policy.name", url.QueryEscape(req.GetAlertPolicy().GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/doc.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/doc.go
index 8844a492f92..63c5feb8bf2 100644
--- a/vendor/cloud.google.com/go/monitoring/apiv3/v2/doc.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -19,67 +19,80 @@
//
// Manages your Cloud Monitoring data and configurations.
//
-// Example usage
+// # General documentation
+//
+// For information about setting deadlines, reusing contexts, and more
+// please visit https://pkg.go.dev/cloud.google.com/go.
+//
+// # Example usage
//
// To get started with this package, create a client.
-// ctx := context.Background()
-// c, err := monitoring.NewAlertPolicyClient(ctx)
-// if err != nil {
-// // TODO: Handle error.
-// }
-// defer c.Close()
+//
+// ctx := context.Background()
+// // This snippet has been automatically generated and should be regarded as a code template only.
+// // It will require modifications to work:
+// // - It may require correct/in-range values for request initialization.
+// // - It may require specifying regional endpoints when creating the service client as shown in:
+// // https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
+// c, err := monitoring.NewAlertPolicyClient(ctx)
+// if err != nil {
+// // TODO: Handle error.
+// }
+// defer c.Close()
//
// The client will use your default application credentials. Clients should be reused instead of created as needed.
// The methods of Client are safe for concurrent use by multiple goroutines.
// The returned client must be Closed when it is done being used.
//
-// Using the Client
+// # Using the Client
//
// The following is an example of making an API call with the newly created client.
//
-// ctx := context.Background()
-// c, err := monitoring.NewAlertPolicyClient(ctx)
-// if err != nil {
-// // TODO: Handle error.
-// }
-// defer c.Close()
-//
-// req := &monitoringpb.ListAlertPoliciesRequest{
-// // TODO: Fill request struct fields.
-// // See https://pkg.go.dev/google.golang.org/genproto/googleapis/monitoring/v3#ListAlertPoliciesRequest.
-// }
-// it := c.ListAlertPolicies(ctx, req)
-// for {
-// resp, err := it.Next()
-// if err == iterator.Done {
-// break
-// }
-// if err != nil {
-// // TODO: Handle error.
-// }
-// // TODO: Use resp.
-// _ = resp
-// }
-//
-// Use of Context
-//
-// The ctx passed to NewClient is used for authentication requests and
+// ctx := context.Background()
+// // This snippet has been automatically generated and should be regarded as a code template only.
+// // It will require modifications to work:
+// // - It may require correct/in-range values for request initialization.
+// // - It may require specifying regional endpoints when creating the service client as shown in:
+// // https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
+// c, err := monitoring.NewAlertPolicyClient(ctx)
+// if err != nil {
+// // TODO: Handle error.
+// }
+// defer c.Close()
+//
+// req := &monitoringpb.ListAlertPoliciesRequest{
+// // TODO: Fill request struct fields.
+// // See https://pkg.go.dev/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb#ListAlertPoliciesRequest.
+// }
+// it := c.ListAlertPolicies(ctx, req)
+// for {
+// resp, err := it.Next()
+// if err == iterator.Done {
+// break
+// }
+// if err != nil {
+// // TODO: Handle error.
+// }
+// // TODO: Use resp.
+// _ = resp
+// }
+//
+// # Inspecting errors
+//
+// To see examples of how to inspect errors returned by this package please reference
+// [Inspecting errors](https://pkg.go.dev/cloud.google.com/go#hdr-Inspecting_errors).
+//
+// # Use of Context
+//
+// The ctx passed to NewAlertPolicyClient is used for authentication requests and
// for creating the underlying connection, but is not used for subsequent calls.
// Individual methods on the client use the ctx given to them.
//
// To close the open connection, use the Close() method.
-//
-// For information about setting deadlines, reusing contexts, and more
-// please visit https://pkg.go.dev/cloud.google.com/go.
package monitoring // import "cloud.google.com/go/monitoring/apiv3/v2"
import (
"context"
- "os"
- "runtime"
- "strconv"
- "strings"
- "unicode"
"google.golang.org/api/option"
"google.golang.org/grpc/metadata"
@@ -110,16 +123,6 @@ func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context {
return metadata.NewOutgoingContext(ctx, out)
}
-func checkDisableDeadlines() (bool, error) {
- raw, ok := os.LookupEnv("GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE")
- if !ok {
- return false, nil
- }
-
- b, err := strconv.ParseBool(raw)
- return b, err
-}
-
// DefaultAuthScopes reports the default set of authentication scopes to use with this package.
func DefaultAuthScopes() []string {
return []string{
@@ -129,40 +132,3 @@ func DefaultAuthScopes() []string {
"https://www.googleapis.com/auth/monitoring.write",
}
}
-
-// versionGo returns the Go runtime version. The returned string
-// has no whitespace, suitable for reporting in header.
-func versionGo() string {
- const develPrefix = "devel +"
-
- s := runtime.Version()
- if strings.HasPrefix(s, develPrefix) {
- s = s[len(develPrefix):]
- if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
- s = s[:p]
- }
- return s
- }
-
- notSemverRune := func(r rune) bool {
- return !strings.ContainsRune("0123456789.", r)
- }
-
- if strings.HasPrefix(s, "go1") {
- s = s[2:]
- var prerelease string
- if p := strings.IndexFunc(s, notSemverRune); p >= 0 {
- s, prerelease = s[:p], s[p:]
- }
- if strings.HasSuffix(s, ".") {
- s += "0"
- } else if strings.Count(s, ".") < 2 {
- s += ".0"
- }
- if prerelease != "" {
- s += "-" + prerelease
- }
- return s
- }
- return "UNKNOWN"
-}
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/gapic_metadata.json b/vendor/cloud.google.com/go/monitoring/apiv3/v2/gapic_metadata.json
index ad03f6ffbcf..a33cb6fcf53 100644
--- a/vendor/cloud.google.com/go/monitoring/apiv3/v2/gapic_metadata.json
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/gapic_metadata.json
@@ -264,6 +264,35 @@
}
}
},
+ "SnoozeService": {
+ "clients": {
+ "grpc": {
+ "libraryClient": "SnoozeClient",
+ "rpcs": {
+ "CreateSnooze": {
+ "methods": [
+ "CreateSnooze"
+ ]
+ },
+ "GetSnooze": {
+ "methods": [
+ "GetSnooze"
+ ]
+ },
+ "ListSnoozes": {
+ "methods": [
+ "ListSnoozes"
+ ]
+ },
+ "UpdateSnooze": {
+ "methods": [
+ "UpdateSnooze"
+ ]
+ }
+ }
+ }
+ }
+ },
"UptimeCheckService": {
"clients": {
"grpc": {
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/group_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/group_client.go
index d2a94a73f13..e754d57c7bb 100644
--- a/vendor/cloud.google.com/go/monitoring/apiv3/v2/group_client.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/group_client.go
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -23,13 +23,13 @@ import (
"net/url"
"time"
+ monitoringpb "cloud.google.com/go/monitoring/apiv3/v2/monitoringpb"
gax "github.com/googleapis/gax-go/v2"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
"google.golang.org/api/option/internaloption"
gtransport "google.golang.org/api/transport/grpc"
monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
- monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
@@ -63,6 +63,7 @@ func defaultGroupGRPCClientOptions() []option.ClientOption {
func defaultGroupCallOptions() *GroupCallOptions {
return &GroupCallOptions{
ListGroups: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -74,6 +75,7 @@ func defaultGroupCallOptions() *GroupCallOptions {
}),
},
GetGroup: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -84,8 +86,11 @@ func defaultGroupCallOptions() *GroupCallOptions {
})
}),
},
- CreateGroup: []gax.CallOption{},
+ CreateGroup: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
UpdateGroup: []gax.CallOption{
+ gax.WithTimeout(180000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -97,6 +102,7 @@ func defaultGroupCallOptions() *GroupCallOptions {
}),
},
DeleteGroup: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -108,6 +114,7 @@ func defaultGroupCallOptions() *GroupCallOptions {
}),
},
ListGroupMembers: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -121,7 +128,7 @@ func defaultGroupCallOptions() *GroupCallOptions {
}
}
-// internalGroupClient is an interface that defines the methods availaible from Cloud Monitoring API.
+// internalGroupClient is an interface that defines the methods available from Cloud Monitoring API.
type internalGroupClient interface {
Close() error
setGoogleClientInfo(...string)
@@ -174,7 +181,8 @@ func (c *GroupClient) setGoogleClientInfo(keyval ...string) {
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *GroupClient) Connection() *grpc.ClientConn {
return c.internalClient.Connection()
}
@@ -217,9 +225,6 @@ type groupGRPCClient struct {
// Connection pool of gRPC connections to the service.
connPool gtransport.ConnPool
- // flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE
- disableDeadlines bool
-
// Points back to the CallOptions field of the containing GroupClient
CallOptions **GroupCallOptions
@@ -255,11 +260,6 @@ func NewGroupClient(ctx context.Context, opts ...option.ClientOption) (*GroupCli
clientOpts = append(clientOpts, hookOpts...)
}
- disableDeadlines, err := checkDisableDeadlines()
- if err != nil {
- return nil, err
- }
-
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
if err != nil {
return nil, err
@@ -267,10 +267,9 @@ func NewGroupClient(ctx context.Context, opts ...option.ClientOption) (*GroupCli
client := GroupClient{CallOptions: defaultGroupCallOptions()}
c := &groupGRPCClient{
- connPool: connPool,
- disableDeadlines: disableDeadlines,
- groupClient: monitoringpb.NewGroupServiceClient(connPool),
- CallOptions: &client.CallOptions,
+ connPool: connPool,
+ groupClient: monitoringpb.NewGroupServiceClient(connPool),
+ CallOptions: &client.CallOptions,
}
c.setGoogleClientInfo()
@@ -281,7 +280,8 @@ func NewGroupClient(ctx context.Context, opts ...option.ClientOption) (*GroupCli
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *groupGRPCClient) Connection() *grpc.ClientConn {
return c.connPool.Conn()
}
@@ -290,7 +290,7 @@ func (c *groupGRPCClient) Connection() *grpc.ClientConn {
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *groupGRPCClient) setGoogleClientInfo(keyval ...string) {
- kv := append([]string{"gl-go", versionGo()}, keyval...)
+ kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version)
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
}
@@ -347,11 +347,6 @@ func (c *groupGRPCClient) ListGroups(ctx context.Context, req *monitoringpb.List
}
func (c *groupGRPCClient) GetGroup(ctx context.Context, req *monitoringpb.GetGroupRequest, opts ...gax.CallOption) (*monitoringpb.Group, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -369,11 +364,6 @@ func (c *groupGRPCClient) GetGroup(ctx context.Context, req *monitoringpb.GetGro
}
func (c *groupGRPCClient) CreateGroup(ctx context.Context, req *monitoringpb.CreateGroupRequest, opts ...gax.CallOption) (*monitoringpb.Group, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -391,11 +381,6 @@ func (c *groupGRPCClient) CreateGroup(ctx context.Context, req *monitoringpb.Cre
}
func (c *groupGRPCClient) UpdateGroup(ctx context.Context, req *monitoringpb.UpdateGroupRequest, opts ...gax.CallOption) (*monitoringpb.Group, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 180000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "group.name", url.QueryEscape(req.GetGroup().GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -413,11 +398,6 @@ func (c *groupGRPCClient) UpdateGroup(ctx context.Context, req *monitoringpb.Upd
}
func (c *groupGRPCClient) DeleteGroup(ctx context.Context, req *monitoringpb.DeleteGroupRequest, opts ...gax.CallOption) error {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/metric_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/metric_client.go
index 49e1a69e477..e702afd25d8 100644
--- a/vendor/cloud.google.com/go/monitoring/apiv3/v2/metric_client.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/metric_client.go
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ import (
"net/url"
"time"
+ monitoringpb "cloud.google.com/go/monitoring/apiv3/v2/monitoringpb"
gax "github.com/googleapis/gax-go/v2"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
@@ -30,7 +31,6 @@ import (
gtransport "google.golang.org/api/transport/grpc"
metricpb "google.golang.org/genproto/googleapis/api/metric"
monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
- monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
@@ -67,6 +67,7 @@ func defaultMetricGRPCClientOptions() []option.ClientOption {
func defaultMetricCallOptions() *MetricCallOptions {
return &MetricCallOptions{
ListMonitoredResourceDescriptors: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -78,6 +79,7 @@ func defaultMetricCallOptions() *MetricCallOptions {
}),
},
GetMonitoredResourceDescriptor: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -89,6 +91,7 @@ func defaultMetricCallOptions() *MetricCallOptions {
}),
},
ListMetricDescriptors: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -100,6 +103,7 @@ func defaultMetricCallOptions() *MetricCallOptions {
}),
},
GetMetricDescriptor: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -110,8 +114,11 @@ func defaultMetricCallOptions() *MetricCallOptions {
})
}),
},
- CreateMetricDescriptor: []gax.CallOption{},
+ CreateMetricDescriptor: []gax.CallOption{
+ gax.WithTimeout(12000 * time.Millisecond),
+ },
DeleteMetricDescriptor: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -123,6 +130,7 @@ func defaultMetricCallOptions() *MetricCallOptions {
}),
},
ListTimeSeries: []gax.CallOption{
+ gax.WithTimeout(90000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -133,12 +141,14 @@ func defaultMetricCallOptions() *MetricCallOptions {
})
}),
},
- CreateTimeSeries: []gax.CallOption{},
+ CreateTimeSeries: []gax.CallOption{
+ gax.WithTimeout(12000 * time.Millisecond),
+ },
CreateServiceTimeSeries: []gax.CallOption{},
}
}
-// internalMetricClient is an interface that defines the methods availaible from Cloud Monitoring API.
+// internalMetricClient is an interface that defines the methods available from Cloud Monitoring API.
type internalMetricClient interface {
Close() error
setGoogleClientInfo(...string)
@@ -184,7 +194,8 @@ func (c *MetricClient) setGoogleClientInfo(keyval ...string) {
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *MetricClient) Connection() *grpc.ClientConn {
return c.internalClient.Connection()
}
@@ -258,9 +269,6 @@ type metricGRPCClient struct {
// Connection pool of gRPC connections to the service.
connPool gtransport.ConnPool
- // flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE
- disableDeadlines bool
-
// Points back to the CallOptions field of the containing MetricClient
CallOptions **MetricCallOptions
@@ -286,11 +294,6 @@ func NewMetricClient(ctx context.Context, opts ...option.ClientOption) (*MetricC
clientOpts = append(clientOpts, hookOpts...)
}
- disableDeadlines, err := checkDisableDeadlines()
- if err != nil {
- return nil, err
- }
-
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
if err != nil {
return nil, err
@@ -298,10 +301,9 @@ func NewMetricClient(ctx context.Context, opts ...option.ClientOption) (*MetricC
client := MetricClient{CallOptions: defaultMetricCallOptions()}
c := &metricGRPCClient{
- connPool: connPool,
- disableDeadlines: disableDeadlines,
- metricClient: monitoringpb.NewMetricServiceClient(connPool),
- CallOptions: &client.CallOptions,
+ connPool: connPool,
+ metricClient: monitoringpb.NewMetricServiceClient(connPool),
+ CallOptions: &client.CallOptions,
}
c.setGoogleClientInfo()
@@ -312,7 +314,8 @@ func NewMetricClient(ctx context.Context, opts ...option.ClientOption) (*MetricC
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *metricGRPCClient) Connection() *grpc.ClientConn {
return c.connPool.Conn()
}
@@ -321,7 +324,7 @@ func (c *metricGRPCClient) Connection() *grpc.ClientConn {
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *metricGRPCClient) setGoogleClientInfo(keyval ...string) {
- kv := append([]string{"gl-go", versionGo()}, keyval...)
+ kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version)
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
}
@@ -378,11 +381,6 @@ func (c *metricGRPCClient) ListMonitoredResourceDescriptors(ctx context.Context,
}
func (c *metricGRPCClient) GetMonitoredResourceDescriptor(ctx context.Context, req *monitoringpb.GetMonitoredResourceDescriptorRequest, opts ...gax.CallOption) (*monitoredrespb.MonitoredResourceDescriptor, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -445,11 +443,6 @@ func (c *metricGRPCClient) ListMetricDescriptors(ctx context.Context, req *monit
}
func (c *metricGRPCClient) GetMetricDescriptor(ctx context.Context, req *monitoringpb.GetMetricDescriptorRequest, opts ...gax.CallOption) (*metricpb.MetricDescriptor, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -467,11 +460,6 @@ func (c *metricGRPCClient) GetMetricDescriptor(ctx context.Context, req *monitor
}
func (c *metricGRPCClient) CreateMetricDescriptor(ctx context.Context, req *monitoringpb.CreateMetricDescriptorRequest, opts ...gax.CallOption) (*metricpb.MetricDescriptor, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 12000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -489,11 +477,6 @@ func (c *metricGRPCClient) CreateMetricDescriptor(ctx context.Context, req *moni
}
func (c *metricGRPCClient) DeleteMetricDescriptor(ctx context.Context, req *monitoringpb.DeleteMetricDescriptorRequest, opts ...gax.CallOption) error {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -552,11 +535,6 @@ func (c *metricGRPCClient) ListTimeSeries(ctx context.Context, req *monitoringpb
}
func (c *metricGRPCClient) CreateTimeSeries(ctx context.Context, req *monitoringpb.CreateTimeSeriesRequest, opts ...gax.CallOption) error {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 12000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/alert.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/alert.pb.go
similarity index 77%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/alert.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/alert.pb.go
index f413955f84d..845924be0f3 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/alert.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/alert.pb.go
@@ -1,4 +1,4 @@
-// Copyright 2021 Google LLC
+// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/alert.proto
-package monitoring
+package monitoringpb
import (
reflect "reflect"
@@ -102,6 +102,68 @@ func (AlertPolicy_ConditionCombinerType) EnumDescriptor() ([]byte, []int) {
return file_google_monitoring_v3_alert_proto_rawDescGZIP(), []int{0, 0}
}
+// A condition control that determines how metric-threshold conditions
+// are evaluated when data stops arriving.
+// This control doesn't affect metric-absence policies.
+type AlertPolicy_Condition_EvaluationMissingData int32
+
+const (
+ // An unspecified evaluation missing data option. Equivalent to
+ // EVALUATION_MISSING_DATA_NO_OP.
+ AlertPolicy_Condition_EVALUATION_MISSING_DATA_UNSPECIFIED AlertPolicy_Condition_EvaluationMissingData = 0
+ // If there is no data to evaluate the condition, then evaluate the
+ // condition as false.
+ AlertPolicy_Condition_EVALUATION_MISSING_DATA_INACTIVE AlertPolicy_Condition_EvaluationMissingData = 1
+ // If there is no data to evaluate the condition, then evaluate the
+ // condition as true.
+ AlertPolicy_Condition_EVALUATION_MISSING_DATA_ACTIVE AlertPolicy_Condition_EvaluationMissingData = 2
+ // Do not evaluate the condition to any value if there is no data.
+ AlertPolicy_Condition_EVALUATION_MISSING_DATA_NO_OP AlertPolicy_Condition_EvaluationMissingData = 3
+)
+
+// Enum value maps for AlertPolicy_Condition_EvaluationMissingData.
+var (
+ AlertPolicy_Condition_EvaluationMissingData_name = map[int32]string{
+ 0: "EVALUATION_MISSING_DATA_UNSPECIFIED",
+ 1: "EVALUATION_MISSING_DATA_INACTIVE",
+ 2: "EVALUATION_MISSING_DATA_ACTIVE",
+ 3: "EVALUATION_MISSING_DATA_NO_OP",
+ }
+ AlertPolicy_Condition_EvaluationMissingData_value = map[string]int32{
+ "EVALUATION_MISSING_DATA_UNSPECIFIED": 0,
+ "EVALUATION_MISSING_DATA_INACTIVE": 1,
+ "EVALUATION_MISSING_DATA_ACTIVE": 2,
+ "EVALUATION_MISSING_DATA_NO_OP": 3,
+ }
+)
+
+func (x AlertPolicy_Condition_EvaluationMissingData) Enum() *AlertPolicy_Condition_EvaluationMissingData {
+ p := new(AlertPolicy_Condition_EvaluationMissingData)
+ *p = x
+ return p
+}
+
+func (x AlertPolicy_Condition_EvaluationMissingData) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (AlertPolicy_Condition_EvaluationMissingData) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_alert_proto_enumTypes[1].Descriptor()
+}
+
+func (AlertPolicy_Condition_EvaluationMissingData) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_alert_proto_enumTypes[1]
+}
+
+func (x AlertPolicy_Condition_EvaluationMissingData) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use AlertPolicy_Condition_EvaluationMissingData.Descriptor instead.
+func (AlertPolicy_Condition_EvaluationMissingData) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_alert_proto_rawDescGZIP(), []int{0, 1, 0}
+}
+
// A description of the conditions under which some aspect of your system is
// considered to be "unhealthy" and the ways to notify people or services about
// this state. For an overview of alert policies, see
@@ -116,7 +178,7 @@ type AlertPolicy struct {
//
// projects/[PROJECT_ID_OR_NUMBER]/alertPolicies/[ALERT_POLICY_ID]
//
- // `[ALERT_POLICY_ID]` is assigned by Stackdriver Monitoring when the policy
+ // `[ALERT_POLICY_ID]` is assigned by Cloud Monitoring when the policy
// is created. When calling the
// [alertPolicies.create][google.monitoring.v3.AlertPolicyService.CreateAlertPolicy]
// method, do not include the `name` field in the alerting policy passed as
@@ -309,7 +371,8 @@ type AlertPolicy_Documentation struct {
// The text of the documentation, interpreted according to `mime_type`.
// The content may not exceed 8,192 Unicode characters and may not exceed
// more than 10,240 bytes when encoded in UTF-8 format, whichever is
- // smaller.
+ // smaller. This text can be [templatized by using
+ // variables](https://cloud.google.com/monitoring/alerts/doc-variables).
Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
// The format of the `content` field. Presently, only the value
// `"text/markdown"` is supported. See
@@ -376,13 +439,13 @@ type AlertPolicy_Condition struct {
//
// projects/[PROJECT_ID_OR_NUMBER]/alertPolicies/[POLICY_ID]/conditions/[CONDITION_ID]
//
- // `[CONDITION_ID]` is assigned by Stackdriver Monitoring when the
+ // `[CONDITION_ID]` is assigned by Cloud Monitoring when the
// condition is created as part of a new or updated alerting policy.
//
// When calling the
// [alertPolicies.create][google.monitoring.v3.AlertPolicyService.CreateAlertPolicy]
// method, do not include the `name` field in the conditions of the
- // requested alerting policy. Stackdriver Monitoring creates the
+ // requested alerting policy. Cloud Monitoring creates the
// condition identifiers and includes them in the new policy.
//
// When calling the
@@ -755,6 +818,9 @@ type AlertPolicy_Condition_MetricThreshold struct {
// or by the ratio, if `denominator_filter` and `denominator_aggregations`
// are specified.
Trigger *AlertPolicy_Condition_Trigger `protobuf:"bytes,7,opt,name=trigger,proto3" json:"trigger,omitempty"`
+ // A condition control that determines how metric-threshold conditions
+ // are evaluated when data stops arriving.
+ EvaluationMissingData AlertPolicy_Condition_EvaluationMissingData `protobuf:"varint,11,opt,name=evaluation_missing_data,json=evaluationMissingData,proto3,enum=google.monitoring.v3.AlertPolicy_Condition_EvaluationMissingData" json:"evaluation_missing_data,omitempty"`
}
func (x *AlertPolicy_Condition_MetricThreshold) Reset() {
@@ -845,6 +911,13 @@ func (x *AlertPolicy_Condition_MetricThreshold) GetTrigger() *AlertPolicy_Condit
return nil
}
+func (x *AlertPolicy_Condition_MetricThreshold) GetEvaluationMissingData() AlertPolicy_Condition_EvaluationMissingData {
+ if x != nil {
+ return x.EvaluationMissingData
+ }
+ return AlertPolicy_Condition_EVALUATION_MISSING_DATA_UNSPECIFIED
+}
+
// A condition type that checks that monitored resources
// are reporting data. The configuration defines a metric and
// a set of monitored resources. The predicate is considered in violation
@@ -1054,6 +1127,9 @@ type AlertPolicy_Condition_MonitoringQueryLanguageCondition struct {
// or by the ratio, if `denominator_filter` and `denominator_aggregations`
// are specified.
Trigger *AlertPolicy_Condition_Trigger `protobuf:"bytes,3,opt,name=trigger,proto3" json:"trigger,omitempty"`
+ // A condition control that determines how metric-threshold conditions
+ // are evaluated when data stops arriving.
+ EvaluationMissingData AlertPolicy_Condition_EvaluationMissingData `protobuf:"varint,4,opt,name=evaluation_missing_data,json=evaluationMissingData,proto3,enum=google.monitoring.v3.AlertPolicy_Condition_EvaluationMissingData" json:"evaluation_missing_data,omitempty"`
}
func (x *AlertPolicy_Condition_MonitoringQueryLanguageCondition) Reset() {
@@ -1109,6 +1185,13 @@ func (x *AlertPolicy_Condition_MonitoringQueryLanguageCondition) GetTrigger() *A
return nil
}
+func (x *AlertPolicy_Condition_MonitoringQueryLanguageCondition) GetEvaluationMissingData() AlertPolicy_Condition_EvaluationMissingData {
+ if x != nil {
+ return x.EvaluationMissingData
+ }
+ return AlertPolicy_Condition_EVALUATION_MISSING_DATA_UNSPECIFIED
+}
+
// Control over the rate of notifications sent to this alert policy's
// notification channels.
type AlertPolicy_AlertStrategy_NotificationRateLimit struct {
@@ -1179,7 +1262,7 @@ var file_google_monitoring_v3_alert_proto_rawDesc = []byte{
0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f,
- 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa1, 0x1c, 0x0a,
+ 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc7, 0x1f, 0x0a,
0x0b, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x12, 0x0a, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
@@ -1234,7 +1317,7 @@ var file_google_monitoring_v3_alert_proto_rawDesc = []byte{
0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09,
0x6d, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, 0x1a, 0xaf, 0x10, 0x0a, 0x09, 0x43, 0x6f,
+ 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, 0x1a, 0xd5, 0x13, 0x0a, 0x09, 0x43, 0x6f,
0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64,
0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28,
@@ -1273,7 +1356,7 @@ var file_google_monitoring_v3_alert_proto_rawDesc = []byte{
0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x05,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74,
0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e,
- 0x74, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x1a, 0xf7, 0x03, 0x0a, 0x0f, 0x4d, 0x65,
+ 0x74, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x1a, 0xf2, 0x04, 0x0a, 0x0f, 0x4d, 0x65,
0x74, 0x72, 0x69, 0x63, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x1b, 0x0a,
0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0,
0x41, 0x02, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x45, 0x0a, 0x0c, 0x61, 0x67,
@@ -1305,14 +1388,48 @@ var file_google_monitoring_v3_alert_proto_rawDesc = []byte{
0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x6c, 0x65,
0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69,
0x6f, 0x6e, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, 0x07, 0x74, 0x72, 0x69, 0x67,
- 0x67, 0x65, 0x72, 0x1a, 0xf9, 0x01, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x41, 0x62,
- 0x73, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74,
- 0x65, 0x72, 0x12, 0x45, 0x0a, 0x0c, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
- 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e,
- 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x67, 0x67,
- 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72,
+ 0x67, 0x65, 0x72, 0x12, 0x79, 0x0a, 0x17, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0b,
+ 0x20, 0x01, 0x28, 0x0e, 0x32, 0x41, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f,
+ 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x6c, 0x65, 0x72,
+ 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f,
+ 0x6e, 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x73, 0x73,
+ 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x52, 0x15, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x1a, 0xf9,
+ 0x01, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x41, 0x62, 0x73, 0x65, 0x6e, 0x63, 0x65,
+ 0x12, 0x1b, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x45, 0x0a,
+ 0x0c, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65,
+ 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x07, 0x74,
+ 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
+ 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65,
+ 0x72, 0x52, 0x07, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x1a, 0xe1, 0x01, 0x0a, 0x08, 0x4c,
+ 0x6f, 0x67, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x1b, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65,
+ 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x66, 0x69,
+ 0x6c, 0x74, 0x65, 0x72, 0x12, 0x74, 0x0a, 0x10, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x65, 0x78,
+ 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x49,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
+ 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63,
+ 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x4d,
+ 0x61, 0x74, 0x63, 0x68, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63,
+ 0x74, 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x6c, 0x61, 0x62, 0x65, 0x6c,
+ 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x1a, 0x42, 0x0a, 0x14, 0x4c, 0x61,
+ 0x62, 0x65, 0x6c, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74,
+ 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xb9,
+ 0x02, 0x0a, 0x20, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x51, 0x75, 0x65,
+ 0x72, 0x79, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74,
+ 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
@@ -1320,105 +1437,98 @@ var file_google_monitoring_v3_alert_proto_rawDesc = []byte{
0x0b, 0x32, 0x33, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f,
0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54,
- 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, 0x07, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x1a,
- 0xe1, 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x1b, 0x0a, 0x06,
- 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41,
- 0x02, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x74, 0x0a, 0x10, 0x6c, 0x61, 0x62,
- 0x65, 0x6c, 0x5f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20,
- 0x03, 0x28, 0x0b, 0x32, 0x49, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e,
- 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74,
- 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
- 0x2e, 0x4c, 0x6f, 0x67, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x45,
- 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f,
- 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x1a,
- 0x42, 0x0a, 0x14, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f,
- 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
- 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
- 0x02, 0x38, 0x01, 0x1a, 0xbe, 0x01, 0x0a, 0x20, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
- 0x6e, 0x67, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x43,
- 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72,
- 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x35,
- 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
- 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x07, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72,
- 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
- 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x6c,
- 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74,
- 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, 0x07, 0x74, 0x72, 0x69,
- 0x67, 0x67, 0x65, 0x72, 0x3a, 0x97, 0x02, 0xea, 0x41, 0x93, 0x02, 0x0a, 0x2e, 0x6d, 0x6f, 0x6e,
- 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
- 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69,
- 0x63, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x70, 0x72, 0x6f,
- 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f,
- 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x61,
- 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x7d, 0x2f, 0x63, 0x6f, 0x6e,
- 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69,
- 0x6f, 0x6e, 0x7d, 0x12, 0x50, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x7d, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2f,
- 0x7b, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x7d, 0x2f, 0x63,
- 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x63, 0x6f, 0x6e, 0x64, 0x69,
- 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x12, 0x44, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x7b,
- 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x7d, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c,
+ 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, 0x07, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x12,
+ 0x79, 0x0a, 0x17, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x69,
+ 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e,
+ 0x32, 0x41, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
+ 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c,
+ 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x76,
+ 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x44,
+ 0x61, 0x74, 0x61, 0x52, 0x15, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d,
+ 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x22, 0xad, 0x01, 0x0a, 0x15, 0x45,
+ 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67,
+ 0x44, 0x61, 0x74, 0x61, 0x12, 0x27, 0x0a, 0x23, 0x45, 0x56, 0x41, 0x4c, 0x55, 0x41, 0x54, 0x49,
+ 0x4f, 0x4e, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f,
+ 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x24, 0x0a,
+ 0x20, 0x45, 0x56, 0x41, 0x4c, 0x55, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x49, 0x53, 0x53,
+ 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x49, 0x4e, 0x41, 0x43, 0x54, 0x49, 0x56,
+ 0x45, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x45, 0x56, 0x41, 0x4c, 0x55, 0x41, 0x54, 0x49, 0x4f,
+ 0x4e, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x41,
+ 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x56, 0x41, 0x4c, 0x55,
+ 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x41,
+ 0x54, 0x41, 0x5f, 0x4e, 0x4f, 0x5f, 0x4f, 0x50, 0x10, 0x03, 0x3a, 0x97, 0x02, 0xea, 0x41, 0x93,
+ 0x02, 0x0a, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6c, 0x65,
+ 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f,
+ 0x6e, 0x12, 0x46, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f,
+ 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63,
+ 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63,
+ 0x79, 0x7d, 0x2f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x63,
+ 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x12, 0x50, 0x6f, 0x72, 0x67, 0x61, 0x6e,
+ 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69,
+ 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c,
0x69, 0x63, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c,
0x69, 0x63, 0x79, 0x7d, 0x2f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f,
- 0x7b, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x12, 0x01, 0x2a, 0x42, 0x0b,
- 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x94, 0x02, 0x0a, 0x0d,
- 0x41, 0x6c, 0x65, 0x72, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x7d, 0x0a,
- 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x61,
- 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45,
- 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
- 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63,
- 0x79, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e,
+ 0x7b, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x12, 0x44, 0x66, 0x6f, 0x6c,
+ 0x64, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x7d, 0x2f, 0x61, 0x6c,
+ 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x61, 0x6c, 0x65,
+ 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x7d, 0x2f, 0x63, 0x6f, 0x6e, 0x64, 0x69,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+ 0x7d, 0x12, 0x01, 0x2a, 0x42, 0x0b, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f,
+ 0x6e, 0x1a, 0x94, 0x02, 0x0a, 0x0d, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74,
+ 0x65, 0x67, 0x79, 0x12, 0x7d, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f,
+ 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x6c, 0x65, 0x72,
+ 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x53, 0x74, 0x72,
+ 0x61, 0x74, 0x65, 0x67, 0x79, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x15, 0x6e, 0x6f, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d,
+ 0x69, 0x74, 0x12, 0x38, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x52, 0x09, 0x61, 0x75, 0x74, 0x6f, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x1a, 0x4a, 0x0a, 0x15,
0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x65,
- 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x15, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x38, 0x0a, 0x0a,
- 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
- 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x61, 0x75, 0x74,
- 0x6f, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x1a, 0x4a, 0x0a, 0x15, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12,
- 0x31, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
- 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x70, 0x65, 0x72, 0x69,
- 0x6f, 0x64, 0x1a, 0x3d, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73,
- 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
- 0x01, 0x22, 0x61, 0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f,
- 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f,
- 0x4d, 0x42, 0x49, 0x4e, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45,
- 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4e, 0x44, 0x10, 0x01, 0x12, 0x06, 0x0a, 0x02,
- 0x4f, 0x52, 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, 0x41, 0x4e, 0x44, 0x5f, 0x57, 0x49, 0x54, 0x48,
- 0x5f, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x49, 0x4e, 0x47, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52,
- 0x43, 0x45, 0x10, 0x03, 0x3a, 0xc9, 0x01, 0xea, 0x41, 0xc5, 0x01, 0x0a, 0x25, 0x6d, 0x6f, 0x6e,
- 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
- 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69,
- 0x63, 0x79, 0x12, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72,
- 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69,
+ 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x31, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x52, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x1a, 0x3d, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72,
+ 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
+ 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x61, 0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x64, 0x69,
+ 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65,
+ 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4d, 0x42, 0x49, 0x4e, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50,
+ 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4e, 0x44,
+ 0x10, 0x01, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, 0x41, 0x4e,
+ 0x44, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x49, 0x4e, 0x47, 0x5f,
+ 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x10, 0x03, 0x3a, 0xc9, 0x01, 0xea, 0x41, 0xc5,
+ 0x01, 0x0a, 0x25, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6c, 0x65,
+ 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+ 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x61, 0x6c, 0x65,
+ 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x61, 0x6c, 0x65, 0x72,
+ 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x7d, 0x12, 0x39, 0x6f, 0x72, 0x67, 0x61, 0x6e,
+ 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69,
+ 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c,
+ 0x69, 0x63, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c,
+ 0x69, 0x63, 0x79, 0x7d, 0x12, 0x2d, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x66,
+ 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x7d, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69,
0x63, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69,
- 0x63, 0x79, 0x7d, 0x12, 0x39, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x7d, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2f,
- 0x7b, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x7d, 0x12, 0x2d,
- 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x7d,
- 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2f, 0x7b,
- 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x7d, 0x12, 0x01, 0x2a,
- 0x42, 0xc2, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
- 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x0a, 0x41,
- 0x6c, 0x65, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x6f, 0x6f,
- 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67,
- 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
- 0x69, 0x73, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33,
- 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x1a, 0x47, 0x6f,
- 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74,
- 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
- 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
- 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a,
- 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
- 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x63, 0x79, 0x7d, 0x12, 0x01, 0x2a, 0x42, 0xc5, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x2e, 0x76, 0x33, 0x42, 0x0a, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50,
+ 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
+ 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
+ 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c,
+ 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56,
+ 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64,
+ 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02,
+ 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a,
+ 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1433,62 +1543,65 @@ func file_google_monitoring_v3_alert_proto_rawDescGZIP() []byte {
return file_google_monitoring_v3_alert_proto_rawDescData
}
-var file_google_monitoring_v3_alert_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_google_monitoring_v3_alert_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_google_monitoring_v3_alert_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
var file_google_monitoring_v3_alert_proto_goTypes = []interface{}{
(AlertPolicy_ConditionCombinerType)(0), // 0: google.monitoring.v3.AlertPolicy.ConditionCombinerType
- (*AlertPolicy)(nil), // 1: google.monitoring.v3.AlertPolicy
- (*AlertPolicy_Documentation)(nil), // 2: google.monitoring.v3.AlertPolicy.Documentation
- (*AlertPolicy_Condition)(nil), // 3: google.monitoring.v3.AlertPolicy.Condition
- (*AlertPolicy_AlertStrategy)(nil), // 4: google.monitoring.v3.AlertPolicy.AlertStrategy
- nil, // 5: google.monitoring.v3.AlertPolicy.UserLabelsEntry
- (*AlertPolicy_Condition_Trigger)(nil), // 6: google.monitoring.v3.AlertPolicy.Condition.Trigger
- (*AlertPolicy_Condition_MetricThreshold)(nil), // 7: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold
- (*AlertPolicy_Condition_MetricAbsence)(nil), // 8: google.monitoring.v3.AlertPolicy.Condition.MetricAbsence
- (*AlertPolicy_Condition_LogMatch)(nil), // 9: google.monitoring.v3.AlertPolicy.Condition.LogMatch
- (*AlertPolicy_Condition_MonitoringQueryLanguageCondition)(nil), // 10: google.monitoring.v3.AlertPolicy.Condition.MonitoringQueryLanguageCondition
- nil, // 11: google.monitoring.v3.AlertPolicy.Condition.LogMatch.LabelExtractorsEntry
- (*AlertPolicy_AlertStrategy_NotificationRateLimit)(nil), // 12: google.monitoring.v3.AlertPolicy.AlertStrategy.NotificationRateLimit
- (*wrapperspb.BoolValue)(nil), // 13: google.protobuf.BoolValue
- (*status.Status)(nil), // 14: google.rpc.Status
- (*MutationRecord)(nil), // 15: google.monitoring.v3.MutationRecord
- (*durationpb.Duration)(nil), // 16: google.protobuf.Duration
- (*Aggregation)(nil), // 17: google.monitoring.v3.Aggregation
- (ComparisonType)(0), // 18: google.monitoring.v3.ComparisonType
+ (AlertPolicy_Condition_EvaluationMissingData)(0), // 1: google.monitoring.v3.AlertPolicy.Condition.EvaluationMissingData
+ (*AlertPolicy)(nil), // 2: google.monitoring.v3.AlertPolicy
+ (*AlertPolicy_Documentation)(nil), // 3: google.monitoring.v3.AlertPolicy.Documentation
+ (*AlertPolicy_Condition)(nil), // 4: google.monitoring.v3.AlertPolicy.Condition
+ (*AlertPolicy_AlertStrategy)(nil), // 5: google.monitoring.v3.AlertPolicy.AlertStrategy
+ nil, // 6: google.monitoring.v3.AlertPolicy.UserLabelsEntry
+ (*AlertPolicy_Condition_Trigger)(nil), // 7: google.monitoring.v3.AlertPolicy.Condition.Trigger
+ (*AlertPolicy_Condition_MetricThreshold)(nil), // 8: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold
+ (*AlertPolicy_Condition_MetricAbsence)(nil), // 9: google.monitoring.v3.AlertPolicy.Condition.MetricAbsence
+ (*AlertPolicy_Condition_LogMatch)(nil), // 10: google.monitoring.v3.AlertPolicy.Condition.LogMatch
+ (*AlertPolicy_Condition_MonitoringQueryLanguageCondition)(nil), // 11: google.monitoring.v3.AlertPolicy.Condition.MonitoringQueryLanguageCondition
+ nil, // 12: google.monitoring.v3.AlertPolicy.Condition.LogMatch.LabelExtractorsEntry
+ (*AlertPolicy_AlertStrategy_NotificationRateLimit)(nil), // 13: google.monitoring.v3.AlertPolicy.AlertStrategy.NotificationRateLimit
+ (*wrapperspb.BoolValue)(nil), // 14: google.protobuf.BoolValue
+ (*status.Status)(nil), // 15: google.rpc.Status
+ (*MutationRecord)(nil), // 16: google.monitoring.v3.MutationRecord
+ (*durationpb.Duration)(nil), // 17: google.protobuf.Duration
+ (*Aggregation)(nil), // 18: google.monitoring.v3.Aggregation
+ (ComparisonType)(0), // 19: google.monitoring.v3.ComparisonType
}
var file_google_monitoring_v3_alert_proto_depIdxs = []int32{
- 2, // 0: google.monitoring.v3.AlertPolicy.documentation:type_name -> google.monitoring.v3.AlertPolicy.Documentation
- 5, // 1: google.monitoring.v3.AlertPolicy.user_labels:type_name -> google.monitoring.v3.AlertPolicy.UserLabelsEntry
- 3, // 2: google.monitoring.v3.AlertPolicy.conditions:type_name -> google.monitoring.v3.AlertPolicy.Condition
+ 3, // 0: google.monitoring.v3.AlertPolicy.documentation:type_name -> google.monitoring.v3.AlertPolicy.Documentation
+ 6, // 1: google.monitoring.v3.AlertPolicy.user_labels:type_name -> google.monitoring.v3.AlertPolicy.UserLabelsEntry
+ 4, // 2: google.monitoring.v3.AlertPolicy.conditions:type_name -> google.monitoring.v3.AlertPolicy.Condition
0, // 3: google.monitoring.v3.AlertPolicy.combiner:type_name -> google.monitoring.v3.AlertPolicy.ConditionCombinerType
- 13, // 4: google.monitoring.v3.AlertPolicy.enabled:type_name -> google.protobuf.BoolValue
- 14, // 5: google.monitoring.v3.AlertPolicy.validity:type_name -> google.rpc.Status
- 15, // 6: google.monitoring.v3.AlertPolicy.creation_record:type_name -> google.monitoring.v3.MutationRecord
- 15, // 7: google.monitoring.v3.AlertPolicy.mutation_record:type_name -> google.monitoring.v3.MutationRecord
- 4, // 8: google.monitoring.v3.AlertPolicy.alert_strategy:type_name -> google.monitoring.v3.AlertPolicy.AlertStrategy
- 7, // 9: google.monitoring.v3.AlertPolicy.Condition.condition_threshold:type_name -> google.monitoring.v3.AlertPolicy.Condition.MetricThreshold
- 8, // 10: google.monitoring.v3.AlertPolicy.Condition.condition_absent:type_name -> google.monitoring.v3.AlertPolicy.Condition.MetricAbsence
- 9, // 11: google.monitoring.v3.AlertPolicy.Condition.condition_matched_log:type_name -> google.monitoring.v3.AlertPolicy.Condition.LogMatch
- 10, // 12: google.monitoring.v3.AlertPolicy.Condition.condition_monitoring_query_language:type_name -> google.monitoring.v3.AlertPolicy.Condition.MonitoringQueryLanguageCondition
- 12, // 13: google.monitoring.v3.AlertPolicy.AlertStrategy.notification_rate_limit:type_name -> google.monitoring.v3.AlertPolicy.AlertStrategy.NotificationRateLimit
- 16, // 14: google.monitoring.v3.AlertPolicy.AlertStrategy.auto_close:type_name -> google.protobuf.Duration
- 17, // 15: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold.aggregations:type_name -> google.monitoring.v3.Aggregation
- 17, // 16: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold.denominator_aggregations:type_name -> google.monitoring.v3.Aggregation
- 18, // 17: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold.comparison:type_name -> google.monitoring.v3.ComparisonType
- 16, // 18: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold.duration:type_name -> google.protobuf.Duration
- 6, // 19: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold.trigger:type_name -> google.monitoring.v3.AlertPolicy.Condition.Trigger
- 17, // 20: google.monitoring.v3.AlertPolicy.Condition.MetricAbsence.aggregations:type_name -> google.monitoring.v3.Aggregation
- 16, // 21: google.monitoring.v3.AlertPolicy.Condition.MetricAbsence.duration:type_name -> google.protobuf.Duration
- 6, // 22: google.monitoring.v3.AlertPolicy.Condition.MetricAbsence.trigger:type_name -> google.monitoring.v3.AlertPolicy.Condition.Trigger
- 11, // 23: google.monitoring.v3.AlertPolicy.Condition.LogMatch.label_extractors:type_name -> google.monitoring.v3.AlertPolicy.Condition.LogMatch.LabelExtractorsEntry
- 16, // 24: google.monitoring.v3.AlertPolicy.Condition.MonitoringQueryLanguageCondition.duration:type_name -> google.protobuf.Duration
- 6, // 25: google.monitoring.v3.AlertPolicy.Condition.MonitoringQueryLanguageCondition.trigger:type_name -> google.monitoring.v3.AlertPolicy.Condition.Trigger
- 16, // 26: google.monitoring.v3.AlertPolicy.AlertStrategy.NotificationRateLimit.period:type_name -> google.protobuf.Duration
- 27, // [27:27] is the sub-list for method output_type
- 27, // [27:27] is the sub-list for method input_type
- 27, // [27:27] is the sub-list for extension type_name
- 27, // [27:27] is the sub-list for extension extendee
- 0, // [0:27] is the sub-list for field type_name
+ 14, // 4: google.monitoring.v3.AlertPolicy.enabled:type_name -> google.protobuf.BoolValue
+ 15, // 5: google.monitoring.v3.AlertPolicy.validity:type_name -> google.rpc.Status
+ 16, // 6: google.monitoring.v3.AlertPolicy.creation_record:type_name -> google.monitoring.v3.MutationRecord
+ 16, // 7: google.monitoring.v3.AlertPolicy.mutation_record:type_name -> google.monitoring.v3.MutationRecord
+ 5, // 8: google.monitoring.v3.AlertPolicy.alert_strategy:type_name -> google.monitoring.v3.AlertPolicy.AlertStrategy
+ 8, // 9: google.monitoring.v3.AlertPolicy.Condition.condition_threshold:type_name -> google.monitoring.v3.AlertPolicy.Condition.MetricThreshold
+ 9, // 10: google.monitoring.v3.AlertPolicy.Condition.condition_absent:type_name -> google.monitoring.v3.AlertPolicy.Condition.MetricAbsence
+ 10, // 11: google.monitoring.v3.AlertPolicy.Condition.condition_matched_log:type_name -> google.monitoring.v3.AlertPolicy.Condition.LogMatch
+ 11, // 12: google.monitoring.v3.AlertPolicy.Condition.condition_monitoring_query_language:type_name -> google.monitoring.v3.AlertPolicy.Condition.MonitoringQueryLanguageCondition
+ 13, // 13: google.monitoring.v3.AlertPolicy.AlertStrategy.notification_rate_limit:type_name -> google.monitoring.v3.AlertPolicy.AlertStrategy.NotificationRateLimit
+ 17, // 14: google.monitoring.v3.AlertPolicy.AlertStrategy.auto_close:type_name -> google.protobuf.Duration
+ 18, // 15: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold.aggregations:type_name -> google.monitoring.v3.Aggregation
+ 18, // 16: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold.denominator_aggregations:type_name -> google.monitoring.v3.Aggregation
+ 19, // 17: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold.comparison:type_name -> google.monitoring.v3.ComparisonType
+ 17, // 18: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold.duration:type_name -> google.protobuf.Duration
+ 7, // 19: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold.trigger:type_name -> google.monitoring.v3.AlertPolicy.Condition.Trigger
+ 1, // 20: google.monitoring.v3.AlertPolicy.Condition.MetricThreshold.evaluation_missing_data:type_name -> google.monitoring.v3.AlertPolicy.Condition.EvaluationMissingData
+ 18, // 21: google.monitoring.v3.AlertPolicy.Condition.MetricAbsence.aggregations:type_name -> google.monitoring.v3.Aggregation
+ 17, // 22: google.monitoring.v3.AlertPolicy.Condition.MetricAbsence.duration:type_name -> google.protobuf.Duration
+ 7, // 23: google.monitoring.v3.AlertPolicy.Condition.MetricAbsence.trigger:type_name -> google.monitoring.v3.AlertPolicy.Condition.Trigger
+ 12, // 24: google.monitoring.v3.AlertPolicy.Condition.LogMatch.label_extractors:type_name -> google.monitoring.v3.AlertPolicy.Condition.LogMatch.LabelExtractorsEntry
+ 17, // 25: google.monitoring.v3.AlertPolicy.Condition.MonitoringQueryLanguageCondition.duration:type_name -> google.protobuf.Duration
+ 7, // 26: google.monitoring.v3.AlertPolicy.Condition.MonitoringQueryLanguageCondition.trigger:type_name -> google.monitoring.v3.AlertPolicy.Condition.Trigger
+ 1, // 27: google.monitoring.v3.AlertPolicy.Condition.MonitoringQueryLanguageCondition.evaluation_missing_data:type_name -> google.monitoring.v3.AlertPolicy.Condition.EvaluationMissingData
+ 17, // 28: google.monitoring.v3.AlertPolicy.AlertStrategy.NotificationRateLimit.period:type_name -> google.protobuf.Duration
+ 29, // [29:29] is the sub-list for method output_type
+ 29, // [29:29] is the sub-list for method input_type
+ 29, // [29:29] is the sub-list for extension type_name
+ 29, // [29:29] is the sub-list for extension extendee
+ 0, // [0:29] is the sub-list for field type_name
}
func init() { file_google_monitoring_v3_alert_proto_init() }
@@ -1635,7 +1748,7 @@ func file_google_monitoring_v3_alert_proto_init() {
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_google_monitoring_v3_alert_proto_rawDesc,
- NumEnums: 1,
+ NumEnums: 2,
NumMessages: 12,
NumExtensions: 0,
NumServices: 0,
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/alert_service.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/alert_service.pb.go
similarity index 93%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/alert_service.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/alert_service.pb.go
index 18340450b6c..5a2718de868 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/alert_service.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/alert_service.pb.go
@@ -1,4 +1,4 @@
-// Copyright 2021 Google LLC
+// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/alert_service.proto
-package monitoring
+package monitoringpb
import (
context "context"
@@ -55,7 +55,7 @@ type CreateAlertPolicyRequest struct {
//
// Note that this field names the parent container in which the alerting
// policy will be written, not the name of the created policy. |name| must be
- // a host project of a workspace, otherwise INVALID_ARGUMENT error will
+ // a host project of a Metrics Scope, otherwise INVALID_ARGUMENT error will
// return. The alerting policy that is returned will have a name that contains
// a normalized representation of this name as a prefix but adds a suffix of
// the form `/alertPolicies/[ALERT_POLICY_ID]`, identifying the policy in the
@@ -558,54 +558,54 @@ var file_google_monitoring_v3_alert_service_proto_rawDesc = []byte{
0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63,
- 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32, 0x82, 0xd3, 0xe4,
- 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70,
- 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74,
- 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
+ 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32, 0xda, 0x41, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x76, 0x33, 0x2f,
+ 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a,
+ 0x7d, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12,
0x96, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69,
0x63, 0x79, 0x12, 0x2b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x65,
0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69,
- 0x63, 0x79, 0x22, 0x34, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x12, 0x25, 0x2f, 0x76, 0x33, 0x2f,
- 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a,
- 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2f, 0x2a,
- 0x7d, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0xb5, 0x01, 0x0a, 0x11, 0x43, 0x72, 0x65,
+ 0x63, 0x79, 0x22, 0x34, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02,
+ 0x27, 0x12, 0x25, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f,
+ 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c,
+ 0x69, 0x63, 0x69, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xb5, 0x01, 0x0a, 0x11, 0x43, 0x72, 0x65,
0x61, 0x74, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2e,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x6c, 0x65, 0x72,
0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63,
- 0x79, 0x22, 0x4d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x33, 0x22, 0x23, 0x2f, 0x76, 0x33, 0x2f, 0x7b,
- 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d,
- 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x3a, 0x0c,
- 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0xda, 0x41, 0x11, 0x6e,
- 0x61, 0x6d, 0x65, 0x2c, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
+ 0x79, 0x22, 0x4d, 0xda, 0x41, 0x11, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x61, 0x6c, 0x65, 0x72, 0x74,
+ 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x33, 0x3a, 0x0c, 0x61,
+ 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x23, 0x2f, 0x76, 0x33,
+ 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f,
+ 0x2a, 0x7d, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73,
0x12, 0x91, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74,
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x34,
- 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x2a, 0x25, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d,
- 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x6c, 0x65,
- 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0xda, 0x41, 0x04,
- 0x6e, 0x61, 0x6d, 0x65, 0x12, 0xcb, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41,
+ 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x2a, 0x25, 0x2f,
+ 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+ 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65,
+ 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xcb, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41,
0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2e, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
0x33, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c,
0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
- 0x33, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x63, 0x82,
- 0xd3, 0xe4, 0x93, 0x02, 0x42, 0x32, 0x32, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x61, 0x6c, 0x65, 0x72,
- 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72,
- 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f,
- 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x0c, 0x61, 0x6c, 0x65, 0x72, 0x74,
- 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0xda, 0x41, 0x18, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
- 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2c, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69,
- 0x63, 0x79, 0x1a, 0xa9, 0x01, 0xca, 0x41, 0x19, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
+ 0x33, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x63, 0xda,
+ 0x41, 0x18, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2c, 0x61, 0x6c,
+ 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x42,
+ 0x3a, 0x0c, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x32, 0x32,
+ 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63,
+ 0x79, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f,
+ 0x2a, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2f,
+ 0x2a, 0x7d, 0x1a, 0xa9, 0x01, 0xca, 0x41, 0x19, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f,
0x6d, 0xd2, 0x41, 0x89, 0x01, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
@@ -615,21 +615,21 @@ var file_google_monitoring_v3_alert_service_proto_rawDesc = []byte{
0x75, 0x74, 0x68, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2c, 0x68,
0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x6d,
- 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x42, 0xc9,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x42, 0xcc,
0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f,
0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x11, 0x41, 0x6c, 0x65,
0x72, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01,
- 0x5a, 0x3e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e,
- 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f,
- 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
- 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
- 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e,
- 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a,
- 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e,
- 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f,
- 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69,
- 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x33,
+ 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
+ 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
+ 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f,
+ 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33,
+ 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c,
+ 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d,
+ 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/common.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/common.pb.go
new file mode 100644
index 00000000000..d4fd9cf19d4
--- /dev/null
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/common.pb.go
@@ -0,0 +1,1154 @@
+// Copyright 2021 Google LLC
+//
+// 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 protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
+// source: google/monitoring/v3/common.proto
+
+package monitoringpb
+
+import (
+ reflect "reflect"
+ sync "sync"
+
+ distribution "google.golang.org/genproto/googleapis/api/distribution"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ durationpb "google.golang.org/protobuf/types/known/durationpb"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Specifies an ordering relationship on two arguments, called `left` and
+// `right`.
+type ComparisonType int32
+
+const (
+ // No ordering relationship is specified.
+ ComparisonType_COMPARISON_UNSPECIFIED ComparisonType = 0
+ // True if the left argument is greater than the right argument.
+ ComparisonType_COMPARISON_GT ComparisonType = 1
+ // True if the left argument is greater than or equal to the right argument.
+ ComparisonType_COMPARISON_GE ComparisonType = 2
+ // True if the left argument is less than the right argument.
+ ComparisonType_COMPARISON_LT ComparisonType = 3
+ // True if the left argument is less than or equal to the right argument.
+ ComparisonType_COMPARISON_LE ComparisonType = 4
+ // True if the left argument is equal to the right argument.
+ ComparisonType_COMPARISON_EQ ComparisonType = 5
+ // True if the left argument is not equal to the right argument.
+ ComparisonType_COMPARISON_NE ComparisonType = 6
+)
+
+// Enum value maps for ComparisonType.
+var (
+ ComparisonType_name = map[int32]string{
+ 0: "COMPARISON_UNSPECIFIED",
+ 1: "COMPARISON_GT",
+ 2: "COMPARISON_GE",
+ 3: "COMPARISON_LT",
+ 4: "COMPARISON_LE",
+ 5: "COMPARISON_EQ",
+ 6: "COMPARISON_NE",
+ }
+ ComparisonType_value = map[string]int32{
+ "COMPARISON_UNSPECIFIED": 0,
+ "COMPARISON_GT": 1,
+ "COMPARISON_GE": 2,
+ "COMPARISON_LT": 3,
+ "COMPARISON_LE": 4,
+ "COMPARISON_EQ": 5,
+ "COMPARISON_NE": 6,
+ }
+)
+
+func (x ComparisonType) Enum() *ComparisonType {
+ p := new(ComparisonType)
+ *p = x
+ return p
+}
+
+func (x ComparisonType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ComparisonType) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_common_proto_enumTypes[0].Descriptor()
+}
+
+func (ComparisonType) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_common_proto_enumTypes[0]
+}
+
+func (x ComparisonType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ComparisonType.Descriptor instead.
+func (ComparisonType) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_common_proto_rawDescGZIP(), []int{0}
+}
+
+// The tier of service for a Workspace. Please see the
+// [service tiers
+// documentation](https://cloud.google.com/monitoring/workspaces/tiers) for more
+// details.
+//
+// Deprecated: Marked as deprecated in google/monitoring/v3/common.proto.
+type ServiceTier int32
+
+const (
+ // An invalid sentinel value, used to indicate that a tier has not
+ // been provided explicitly.
+ ServiceTier_SERVICE_TIER_UNSPECIFIED ServiceTier = 0
+ // The Stackdriver Basic tier, a free tier of service that provides basic
+ // features, a moderate allotment of logs, and access to built-in metrics.
+ // A number of features are not available in this tier. For more details,
+ // see [the service tiers
+ // documentation](https://cloud.google.com/monitoring/workspaces/tiers).
+ ServiceTier_SERVICE_TIER_BASIC ServiceTier = 1
+ // The Stackdriver Premium tier, a higher, more expensive tier of service
+ // that provides access to all Stackdriver features, lets you use Stackdriver
+ // with AWS accounts, and has a larger allotments for logs and metrics. For
+ // more details, see [the service tiers
+ // documentation](https://cloud.google.com/monitoring/workspaces/tiers).
+ ServiceTier_SERVICE_TIER_PREMIUM ServiceTier = 2
+)
+
+// Enum value maps for ServiceTier.
+var (
+ ServiceTier_name = map[int32]string{
+ 0: "SERVICE_TIER_UNSPECIFIED",
+ 1: "SERVICE_TIER_BASIC",
+ 2: "SERVICE_TIER_PREMIUM",
+ }
+ ServiceTier_value = map[string]int32{
+ "SERVICE_TIER_UNSPECIFIED": 0,
+ "SERVICE_TIER_BASIC": 1,
+ "SERVICE_TIER_PREMIUM": 2,
+ }
+)
+
+func (x ServiceTier) Enum() *ServiceTier {
+ p := new(ServiceTier)
+ *p = x
+ return p
+}
+
+func (x ServiceTier) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ServiceTier) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_common_proto_enumTypes[1].Descriptor()
+}
+
+func (ServiceTier) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_common_proto_enumTypes[1]
+}
+
+func (x ServiceTier) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ServiceTier.Descriptor instead.
+func (ServiceTier) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_common_proto_rawDescGZIP(), []int{1}
+}
+
+// The `Aligner` specifies the operation that will be applied to the data
+// points in each alignment period in a time series. Except for
+// `ALIGN_NONE`, which specifies that no operation be applied, each alignment
+// operation replaces the set of data values in each alignment period with
+// a single value: the result of applying the operation to the data values.
+// An aligned time series has a single data value at the end of each
+// `alignment_period`.
+//
+// An alignment operation can change the data type of the values, too. For
+// example, if you apply a counting operation to boolean values, the data
+// `value_type` in the original time series is `BOOLEAN`, but the `value_type`
+// in the aligned result is `INT64`.
+type Aggregation_Aligner int32
+
+const (
+ // No alignment. Raw data is returned. Not valid if cross-series reduction
+ // is requested. The `value_type` of the result is the same as the
+ // `value_type` of the input.
+ Aggregation_ALIGN_NONE Aggregation_Aligner = 0
+ // Align and convert to
+ // [DELTA][google.api.MetricDescriptor.MetricKind.DELTA].
+ // The output is `delta = y1 - y0`.
+ //
+ // This alignment is valid for
+ // [CUMULATIVE][google.api.MetricDescriptor.MetricKind.CUMULATIVE] and
+ // `DELTA` metrics. If the selected alignment period results in periods
+ // with no data, then the aligned value for such a period is created by
+ // interpolation. The `value_type` of the aligned result is the same as
+ // the `value_type` of the input.
+ Aggregation_ALIGN_DELTA Aggregation_Aligner = 1
+ // Align and convert to a rate. The result is computed as
+ // `rate = (y1 - y0)/(t1 - t0)`, or "delta over time".
+ // Think of this aligner as providing the slope of the line that passes
+ // through the value at the start and at the end of the `alignment_period`.
+ //
+ // This aligner is valid for `CUMULATIVE`
+ // and `DELTA` metrics with numeric values. If the selected alignment
+ // period results in periods with no data, then the aligned value for
+ // such a period is created by interpolation. The output is a `GAUGE`
+ // metric with `value_type` `DOUBLE`.
+ //
+ // If, by "rate", you mean "percentage change", see the
+ // `ALIGN_PERCENT_CHANGE` aligner instead.
+ Aggregation_ALIGN_RATE Aggregation_Aligner = 2
+ // Align by interpolating between adjacent points around the alignment
+ // period boundary. This aligner is valid for `GAUGE` metrics with
+ // numeric values. The `value_type` of the aligned result is the same as the
+ // `value_type` of the input.
+ Aggregation_ALIGN_INTERPOLATE Aggregation_Aligner = 3
+ // Align by moving the most recent data point before the end of the
+ // alignment period to the boundary at the end of the alignment
+ // period. This aligner is valid for `GAUGE` metrics. The `value_type` of
+ // the aligned result is the same as the `value_type` of the input.
+ Aggregation_ALIGN_NEXT_OLDER Aggregation_Aligner = 4
+ // Align the time series by returning the minimum value in each alignment
+ // period. This aligner is valid for `GAUGE` and `DELTA` metrics with
+ // numeric values. The `value_type` of the aligned result is the same as
+ // the `value_type` of the input.
+ Aggregation_ALIGN_MIN Aggregation_Aligner = 10
+ // Align the time series by returning the maximum value in each alignment
+ // period. This aligner is valid for `GAUGE` and `DELTA` metrics with
+ // numeric values. The `value_type` of the aligned result is the same as
+ // the `value_type` of the input.
+ Aggregation_ALIGN_MAX Aggregation_Aligner = 11
+ // Align the time series by returning the mean value in each alignment
+ // period. This aligner is valid for `GAUGE` and `DELTA` metrics with
+ // numeric values. The `value_type` of the aligned result is `DOUBLE`.
+ Aggregation_ALIGN_MEAN Aggregation_Aligner = 12
+ // Align the time series by returning the number of values in each alignment
+ // period. This aligner is valid for `GAUGE` and `DELTA` metrics with
+ // numeric or Boolean values. The `value_type` of the aligned result is
+ // `INT64`.
+ Aggregation_ALIGN_COUNT Aggregation_Aligner = 13
+ // Align the time series by returning the sum of the values in each
+ // alignment period. This aligner is valid for `GAUGE` and `DELTA`
+ // metrics with numeric and distribution values. The `value_type` of the
+ // aligned result is the same as the `value_type` of the input.
+ Aggregation_ALIGN_SUM Aggregation_Aligner = 14
+ // Align the time series by returning the standard deviation of the values
+ // in each alignment period. This aligner is valid for `GAUGE` and
+ // `DELTA` metrics with numeric values. The `value_type` of the output is
+ // `DOUBLE`.
+ Aggregation_ALIGN_STDDEV Aggregation_Aligner = 15
+ // Align the time series by returning the number of `True` values in
+ // each alignment period. This aligner is valid for `GAUGE` metrics with
+ // Boolean values. The `value_type` of the output is `INT64`.
+ Aggregation_ALIGN_COUNT_TRUE Aggregation_Aligner = 16
+ // Align the time series by returning the number of `False` values in
+ // each alignment period. This aligner is valid for `GAUGE` metrics with
+ // Boolean values. The `value_type` of the output is `INT64`.
+ Aggregation_ALIGN_COUNT_FALSE Aggregation_Aligner = 24
+ // Align the time series by returning the ratio of the number of `True`
+ // values to the total number of values in each alignment period. This
+ // aligner is valid for `GAUGE` metrics with Boolean values. The output
+ // value is in the range [0.0, 1.0] and has `value_type` `DOUBLE`.
+ Aggregation_ALIGN_FRACTION_TRUE Aggregation_Aligner = 17
+ // Align the time series by using [percentile
+ // aggregation](https://en.wikipedia.org/wiki/Percentile). The resulting
+ // data point in each alignment period is the 99th percentile of all data
+ // points in the period. This aligner is valid for `GAUGE` and `DELTA`
+ // metrics with distribution values. The output is a `GAUGE` metric with
+ // `value_type` `DOUBLE`.
+ Aggregation_ALIGN_PERCENTILE_99 Aggregation_Aligner = 18
+ // Align the time series by using [percentile
+ // aggregation](https://en.wikipedia.org/wiki/Percentile). The resulting
+ // data point in each alignment period is the 95th percentile of all data
+ // points in the period. This aligner is valid for `GAUGE` and `DELTA`
+ // metrics with distribution values. The output is a `GAUGE` metric with
+ // `value_type` `DOUBLE`.
+ Aggregation_ALIGN_PERCENTILE_95 Aggregation_Aligner = 19
+ // Align the time series by using [percentile
+ // aggregation](https://en.wikipedia.org/wiki/Percentile). The resulting
+ // data point in each alignment period is the 50th percentile of all data
+ // points in the period. This aligner is valid for `GAUGE` and `DELTA`
+ // metrics with distribution values. The output is a `GAUGE` metric with
+ // `value_type` `DOUBLE`.
+ Aggregation_ALIGN_PERCENTILE_50 Aggregation_Aligner = 20
+ // Align the time series by using [percentile
+ // aggregation](https://en.wikipedia.org/wiki/Percentile). The resulting
+ // data point in each alignment period is the 5th percentile of all data
+ // points in the period. This aligner is valid for `GAUGE` and `DELTA`
+ // metrics with distribution values. The output is a `GAUGE` metric with
+ // `value_type` `DOUBLE`.
+ Aggregation_ALIGN_PERCENTILE_05 Aggregation_Aligner = 21
+ // Align and convert to a percentage change. This aligner is valid for
+ // `GAUGE` and `DELTA` metrics with numeric values. This alignment returns
+ // `((current - previous)/previous) * 100`, where the value of `previous` is
+ // determined based on the `alignment_period`.
+ //
+ // If the values of `current` and `previous` are both 0, then the returned
+ // value is 0. If only `previous` is 0, the returned value is infinity.
+ //
+ // A 10-minute moving mean is computed at each point of the alignment period
+ // prior to the above calculation to smooth the metric and prevent false
+ // positives from very short-lived spikes. The moving mean is only
+ // applicable for data whose values are `>= 0`. Any values `< 0` are
+ // treated as a missing datapoint, and are ignored. While `DELTA`
+ // metrics are accepted by this alignment, special care should be taken that
+ // the values for the metric will always be positive. The output is a
+ // `GAUGE` metric with `value_type` `DOUBLE`.
+ Aggregation_ALIGN_PERCENT_CHANGE Aggregation_Aligner = 23
+)
+
+// Enum value maps for Aggregation_Aligner.
+var (
+ Aggregation_Aligner_name = map[int32]string{
+ 0: "ALIGN_NONE",
+ 1: "ALIGN_DELTA",
+ 2: "ALIGN_RATE",
+ 3: "ALIGN_INTERPOLATE",
+ 4: "ALIGN_NEXT_OLDER",
+ 10: "ALIGN_MIN",
+ 11: "ALIGN_MAX",
+ 12: "ALIGN_MEAN",
+ 13: "ALIGN_COUNT",
+ 14: "ALIGN_SUM",
+ 15: "ALIGN_STDDEV",
+ 16: "ALIGN_COUNT_TRUE",
+ 24: "ALIGN_COUNT_FALSE",
+ 17: "ALIGN_FRACTION_TRUE",
+ 18: "ALIGN_PERCENTILE_99",
+ 19: "ALIGN_PERCENTILE_95",
+ 20: "ALIGN_PERCENTILE_50",
+ 21: "ALIGN_PERCENTILE_05",
+ 23: "ALIGN_PERCENT_CHANGE",
+ }
+ Aggregation_Aligner_value = map[string]int32{
+ "ALIGN_NONE": 0,
+ "ALIGN_DELTA": 1,
+ "ALIGN_RATE": 2,
+ "ALIGN_INTERPOLATE": 3,
+ "ALIGN_NEXT_OLDER": 4,
+ "ALIGN_MIN": 10,
+ "ALIGN_MAX": 11,
+ "ALIGN_MEAN": 12,
+ "ALIGN_COUNT": 13,
+ "ALIGN_SUM": 14,
+ "ALIGN_STDDEV": 15,
+ "ALIGN_COUNT_TRUE": 16,
+ "ALIGN_COUNT_FALSE": 24,
+ "ALIGN_FRACTION_TRUE": 17,
+ "ALIGN_PERCENTILE_99": 18,
+ "ALIGN_PERCENTILE_95": 19,
+ "ALIGN_PERCENTILE_50": 20,
+ "ALIGN_PERCENTILE_05": 21,
+ "ALIGN_PERCENT_CHANGE": 23,
+ }
+)
+
+func (x Aggregation_Aligner) Enum() *Aggregation_Aligner {
+ p := new(Aggregation_Aligner)
+ *p = x
+ return p
+}
+
+func (x Aggregation_Aligner) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Aggregation_Aligner) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_common_proto_enumTypes[2].Descriptor()
+}
+
+func (Aggregation_Aligner) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_common_proto_enumTypes[2]
+}
+
+func (x Aggregation_Aligner) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Aggregation_Aligner.Descriptor instead.
+func (Aggregation_Aligner) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_common_proto_rawDescGZIP(), []int{2, 0}
+}
+
+// A Reducer operation describes how to aggregate data points from multiple
+// time series into a single time series, where the value of each data point
+// in the resulting series is a function of all the already aligned values in
+// the input time series.
+type Aggregation_Reducer int32
+
+const (
+ // No cross-time series reduction. The output of the `Aligner` is
+ // returned.
+ Aggregation_REDUCE_NONE Aggregation_Reducer = 0
+ // Reduce by computing the mean value across time series for each
+ // alignment period. This reducer is valid for
+ // [DELTA][google.api.MetricDescriptor.MetricKind.DELTA] and
+ // [GAUGE][google.api.MetricDescriptor.MetricKind.GAUGE] metrics with
+ // numeric or distribution values. The `value_type` of the output is
+ // [DOUBLE][google.api.MetricDescriptor.ValueType.DOUBLE].
+ Aggregation_REDUCE_MEAN Aggregation_Reducer = 1
+ // Reduce by computing the minimum value across time series for each
+ // alignment period. This reducer is valid for `DELTA` and `GAUGE` metrics
+ // with numeric values. The `value_type` of the output is the same as the
+ // `value_type` of the input.
+ Aggregation_REDUCE_MIN Aggregation_Reducer = 2
+ // Reduce by computing the maximum value across time series for each
+ // alignment period. This reducer is valid for `DELTA` and `GAUGE` metrics
+ // with numeric values. The `value_type` of the output is the same as the
+ // `value_type` of the input.
+ Aggregation_REDUCE_MAX Aggregation_Reducer = 3
+ // Reduce by computing the sum across time series for each
+ // alignment period. This reducer is valid for `DELTA` and `GAUGE` metrics
+ // with numeric and distribution values. The `value_type` of the output is
+ // the same as the `value_type` of the input.
+ Aggregation_REDUCE_SUM Aggregation_Reducer = 4
+ // Reduce by computing the standard deviation across time series
+ // for each alignment period. This reducer is valid for `DELTA` and
+ // `GAUGE` metrics with numeric or distribution values. The `value_type`
+ // of the output is `DOUBLE`.
+ Aggregation_REDUCE_STDDEV Aggregation_Reducer = 5
+ // Reduce by computing the number of data points across time series
+ // for each alignment period. This reducer is valid for `DELTA` and
+ // `GAUGE` metrics of numeric, Boolean, distribution, and string
+ // `value_type`. The `value_type` of the output is `INT64`.
+ Aggregation_REDUCE_COUNT Aggregation_Reducer = 6
+ // Reduce by computing the number of `True`-valued data points across time
+ // series for each alignment period. This reducer is valid for `DELTA` and
+ // `GAUGE` metrics of Boolean `value_type`. The `value_type` of the output
+ // is `INT64`.
+ Aggregation_REDUCE_COUNT_TRUE Aggregation_Reducer = 7
+ // Reduce by computing the number of `False`-valued data points across time
+ // series for each alignment period. This reducer is valid for `DELTA` and
+ // `GAUGE` metrics of Boolean `value_type`. The `value_type` of the output
+ // is `INT64`.
+ Aggregation_REDUCE_COUNT_FALSE Aggregation_Reducer = 15
+ // Reduce by computing the ratio of the number of `True`-valued data points
+ // to the total number of data points for each alignment period. This
+ // reducer is valid for `DELTA` and `GAUGE` metrics of Boolean `value_type`.
+ // The output value is in the range [0.0, 1.0] and has `value_type`
+ // `DOUBLE`.
+ Aggregation_REDUCE_FRACTION_TRUE Aggregation_Reducer = 8
+ // Reduce by computing the [99th
+ // percentile](https://en.wikipedia.org/wiki/Percentile) of data points
+ // across time series for each alignment period. This reducer is valid for
+ // `GAUGE` and `DELTA` metrics of numeric and distribution type. The value
+ // of the output is `DOUBLE`.
+ Aggregation_REDUCE_PERCENTILE_99 Aggregation_Reducer = 9
+ // Reduce by computing the [95th
+ // percentile](https://en.wikipedia.org/wiki/Percentile) of data points
+ // across time series for each alignment period. This reducer is valid for
+ // `GAUGE` and `DELTA` metrics of numeric and distribution type. The value
+ // of the output is `DOUBLE`.
+ Aggregation_REDUCE_PERCENTILE_95 Aggregation_Reducer = 10
+ // Reduce by computing the [50th
+ // percentile](https://en.wikipedia.org/wiki/Percentile) of data points
+ // across time series for each alignment period. This reducer is valid for
+ // `GAUGE` and `DELTA` metrics of numeric and distribution type. The value
+ // of the output is `DOUBLE`.
+ Aggregation_REDUCE_PERCENTILE_50 Aggregation_Reducer = 11
+ // Reduce by computing the [5th
+ // percentile](https://en.wikipedia.org/wiki/Percentile) of data points
+ // across time series for each alignment period. This reducer is valid for
+ // `GAUGE` and `DELTA` metrics of numeric and distribution type. The value
+ // of the output is `DOUBLE`.
+ Aggregation_REDUCE_PERCENTILE_05 Aggregation_Reducer = 12
+)
+
+// Enum value maps for Aggregation_Reducer.
+var (
+ Aggregation_Reducer_name = map[int32]string{
+ 0: "REDUCE_NONE",
+ 1: "REDUCE_MEAN",
+ 2: "REDUCE_MIN",
+ 3: "REDUCE_MAX",
+ 4: "REDUCE_SUM",
+ 5: "REDUCE_STDDEV",
+ 6: "REDUCE_COUNT",
+ 7: "REDUCE_COUNT_TRUE",
+ 15: "REDUCE_COUNT_FALSE",
+ 8: "REDUCE_FRACTION_TRUE",
+ 9: "REDUCE_PERCENTILE_99",
+ 10: "REDUCE_PERCENTILE_95",
+ 11: "REDUCE_PERCENTILE_50",
+ 12: "REDUCE_PERCENTILE_05",
+ }
+ Aggregation_Reducer_value = map[string]int32{
+ "REDUCE_NONE": 0,
+ "REDUCE_MEAN": 1,
+ "REDUCE_MIN": 2,
+ "REDUCE_MAX": 3,
+ "REDUCE_SUM": 4,
+ "REDUCE_STDDEV": 5,
+ "REDUCE_COUNT": 6,
+ "REDUCE_COUNT_TRUE": 7,
+ "REDUCE_COUNT_FALSE": 15,
+ "REDUCE_FRACTION_TRUE": 8,
+ "REDUCE_PERCENTILE_99": 9,
+ "REDUCE_PERCENTILE_95": 10,
+ "REDUCE_PERCENTILE_50": 11,
+ "REDUCE_PERCENTILE_05": 12,
+ }
+)
+
+func (x Aggregation_Reducer) Enum() *Aggregation_Reducer {
+ p := new(Aggregation_Reducer)
+ *p = x
+ return p
+}
+
+func (x Aggregation_Reducer) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Aggregation_Reducer) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_common_proto_enumTypes[3].Descriptor()
+}
+
+func (Aggregation_Reducer) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_common_proto_enumTypes[3]
+}
+
+func (x Aggregation_Reducer) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Aggregation_Reducer.Descriptor instead.
+func (Aggregation_Reducer) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_common_proto_rawDescGZIP(), []int{2, 1}
+}
+
+// A single strongly-typed value.
+type TypedValue struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The typed value field.
+ //
+ // Types that are assignable to Value:
+ // *TypedValue_BoolValue
+ // *TypedValue_Int64Value
+ // *TypedValue_DoubleValue
+ // *TypedValue_StringValue
+ // *TypedValue_DistributionValue
+ Value isTypedValue_Value `protobuf_oneof:"value"`
+}
+
+func (x *TypedValue) Reset() {
+ *x = TypedValue{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_common_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TypedValue) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TypedValue) ProtoMessage() {}
+
+func (x *TypedValue) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_common_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TypedValue.ProtoReflect.Descriptor instead.
+func (*TypedValue) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_common_proto_rawDescGZIP(), []int{0}
+}
+
+func (m *TypedValue) GetValue() isTypedValue_Value {
+ if m != nil {
+ return m.Value
+ }
+ return nil
+}
+
+func (x *TypedValue) GetBoolValue() bool {
+ if x, ok := x.GetValue().(*TypedValue_BoolValue); ok {
+ return x.BoolValue
+ }
+ return false
+}
+
+func (x *TypedValue) GetInt64Value() int64 {
+ if x, ok := x.GetValue().(*TypedValue_Int64Value); ok {
+ return x.Int64Value
+ }
+ return 0
+}
+
+func (x *TypedValue) GetDoubleValue() float64 {
+ if x, ok := x.GetValue().(*TypedValue_DoubleValue); ok {
+ return x.DoubleValue
+ }
+ return 0
+}
+
+func (x *TypedValue) GetStringValue() string {
+ if x, ok := x.GetValue().(*TypedValue_StringValue); ok {
+ return x.StringValue
+ }
+ return ""
+}
+
+func (x *TypedValue) GetDistributionValue() *distribution.Distribution {
+ if x, ok := x.GetValue().(*TypedValue_DistributionValue); ok {
+ return x.DistributionValue
+ }
+ return nil
+}
+
+type isTypedValue_Value interface {
+ isTypedValue_Value()
+}
+
+type TypedValue_BoolValue struct {
+ // A Boolean value: `true` or `false`.
+ BoolValue bool `protobuf:"varint,1,opt,name=bool_value,json=boolValue,proto3,oneof"`
+}
+
+type TypedValue_Int64Value struct {
+ // A 64-bit integer. Its range is approximately ±9.2x1018.
+ Int64Value int64 `protobuf:"varint,2,opt,name=int64_value,json=int64Value,proto3,oneof"`
+}
+
+type TypedValue_DoubleValue struct {
+ // A 64-bit double-precision floating-point number. Its magnitude
+ // is approximately ±10±300 and it has 16
+ // significant digits of precision.
+ DoubleValue float64 `protobuf:"fixed64,3,opt,name=double_value,json=doubleValue,proto3,oneof"`
+}
+
+type TypedValue_StringValue struct {
+ // A variable-length string value.
+ StringValue string `protobuf:"bytes,4,opt,name=string_value,json=stringValue,proto3,oneof"`
+}
+
+type TypedValue_DistributionValue struct {
+ // A distribution value.
+ DistributionValue *distribution.Distribution `protobuf:"bytes,5,opt,name=distribution_value,json=distributionValue,proto3,oneof"`
+}
+
+func (*TypedValue_BoolValue) isTypedValue_Value() {}
+
+func (*TypedValue_Int64Value) isTypedValue_Value() {}
+
+func (*TypedValue_DoubleValue) isTypedValue_Value() {}
+
+func (*TypedValue_StringValue) isTypedValue_Value() {}
+
+func (*TypedValue_DistributionValue) isTypedValue_Value() {}
+
+// A closed time interval. It extends from the start time to the end time, and includes both: `[startTime, endTime]`. Valid time intervals depend on the [`MetricKind`](https://cloud.google.com/monitoring/api/ref_v3/rest/v3/projects.metricDescriptors#MetricKind) of the metric value. The end time must not be earlier than the start time. When writing data points, the start time must not be more than 25 hours in the past and the end time must not be more than five minutes in the future.
+//
+// - For `GAUGE` metrics, the `startTime` value is technically optional; if
+// no value is specified, the start time defaults to the value of the
+// end time, and the interval represents a single point in time. If both
+// start and end times are specified, they must be identical. Such an
+// interval is valid only for `GAUGE` metrics, which are point-in-time
+// measurements. The end time of a new interval must be at least a
+// millisecond after the end time of the previous interval.
+//
+// - For `DELTA` metrics, the start time and end time must specify a
+// non-zero interval, with subsequent points specifying contiguous and
+// non-overlapping intervals. For `DELTA` metrics, the start time of
+// the next interval must be at least a millisecond after the end time
+// of the previous interval.
+//
+// - For `CUMULATIVE` metrics, the start time and end time must specify a
+// non-zero interval, with subsequent points specifying the same
+// start time and increasing end times, until an event resets the
+// cumulative value to zero and sets a new start time for the following
+// points. The new start time must be at least a millisecond after the
+// end time of the previous interval.
+//
+// - The start time of a new interval must be at least a millisecond after the
+// end time of the previous interval because intervals are closed. If the
+// start time of a new interval is the same as the end time of the previous
+// interval, then data written at the new start time could overwrite data
+// written at the previous end time.
+type TimeInterval struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The end of the time interval.
+ EndTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"`
+ // Optional. The beginning of the time interval. The default value
+ // for the start time is the end time. The start time must not be
+ // later than the end time.
+ StartTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"`
+}
+
+func (x *TimeInterval) Reset() {
+ *x = TimeInterval{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_common_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TimeInterval) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TimeInterval) ProtoMessage() {}
+
+func (x *TimeInterval) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_common_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TimeInterval.ProtoReflect.Descriptor instead.
+func (*TimeInterval) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_common_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *TimeInterval) GetEndTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.EndTime
+ }
+ return nil
+}
+
+func (x *TimeInterval) GetStartTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.StartTime
+ }
+ return nil
+}
+
+// Describes how to combine multiple time series to provide a different view of
+// the data. Aggregation of time series is done in two steps. First, each time
+// series in the set is _aligned_ to the same time interval boundaries, then the
+// set of time series is optionally _reduced_ in number.
+//
+// Alignment consists of applying the `per_series_aligner` operation
+// to each time series after its data has been divided into regular
+// `alignment_period` time intervals. This process takes _all_ of the data
+// points in an alignment period, applies a mathematical transformation such as
+// averaging, minimum, maximum, delta, etc., and converts them into a single
+// data point per period.
+//
+// Reduction is when the aligned and transformed time series can optionally be
+// combined, reducing the number of time series through similar mathematical
+// transformations. Reduction involves applying a `cross_series_reducer` to
+// all the time series, optionally sorting the time series into subsets with
+// `group_by_fields`, and applying the reducer to each subset.
+//
+// The raw time series data can contain a huge amount of information from
+// multiple sources. Alignment and reduction transforms this mass of data into
+// a more manageable and representative collection of data, for example "the
+// 95% latency across the average of all tasks in a cluster". This
+// representative data can be more easily graphed and comprehended, and the
+// individual time series data is still available for later drilldown. For more
+// details, see [Filtering and
+// aggregation](https://cloud.google.com/monitoring/api/v3/aggregation).
+type Aggregation struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The `alignment_period` specifies a time interval, in seconds, that is used
+ // to divide the data in all the
+ // [time series][google.monitoring.v3.TimeSeries] into consistent blocks of
+ // time. This will be done before the per-series aligner can be applied to
+ // the data.
+ //
+ // The value must be at least 60 seconds. If a per-series
+ // aligner other than `ALIGN_NONE` is specified, this field is required or an
+ // error is returned. If no per-series aligner is specified, or the aligner
+ // `ALIGN_NONE` is specified, then this field is ignored.
+ //
+ // The maximum value of the `alignment_period` is 104 weeks (2 years) for
+ // charts, and 90,000 seconds (25 hours) for alerting policies.
+ AlignmentPeriod *durationpb.Duration `protobuf:"bytes,1,opt,name=alignment_period,json=alignmentPeriod,proto3" json:"alignment_period,omitempty"`
+ // An `Aligner` describes how to bring the data points in a single
+ // time series into temporal alignment. Except for `ALIGN_NONE`, all
+ // alignments cause all the data points in an `alignment_period` to be
+ // mathematically grouped together, resulting in a single data point for
+ // each `alignment_period` with end timestamp at the end of the period.
+ //
+ // Not all alignment operations may be applied to all time series. The valid
+ // choices depend on the `metric_kind` and `value_type` of the original time
+ // series. Alignment can change the `metric_kind` or the `value_type` of
+ // the time series.
+ //
+ // Time series data must be aligned in order to perform cross-time
+ // series reduction. If `cross_series_reducer` is specified, then
+ // `per_series_aligner` must be specified and not equal to `ALIGN_NONE`
+ // and `alignment_period` must be specified; otherwise, an error is
+ // returned.
+ PerSeriesAligner Aggregation_Aligner `protobuf:"varint,2,opt,name=per_series_aligner,json=perSeriesAligner,proto3,enum=google.monitoring.v3.Aggregation_Aligner" json:"per_series_aligner,omitempty"`
+ // The reduction operation to be used to combine time series into a single
+ // time series, where the value of each data point in the resulting series is
+ // a function of all the already aligned values in the input time series.
+ //
+ // Not all reducer operations can be applied to all time series. The valid
+ // choices depend on the `metric_kind` and the `value_type` of the original
+ // time series. Reduction can yield a time series with a different
+ // `metric_kind` or `value_type` than the input time series.
+ //
+ // Time series data must first be aligned (see `per_series_aligner`) in order
+ // to perform cross-time series reduction. If `cross_series_reducer` is
+ // specified, then `per_series_aligner` must be specified, and must not be
+ // `ALIGN_NONE`. An `alignment_period` must also be specified; otherwise, an
+ // error is returned.
+ CrossSeriesReducer Aggregation_Reducer `protobuf:"varint,4,opt,name=cross_series_reducer,json=crossSeriesReducer,proto3,enum=google.monitoring.v3.Aggregation_Reducer" json:"cross_series_reducer,omitempty"`
+ // The set of fields to preserve when `cross_series_reducer` is
+ // specified. The `group_by_fields` determine how the time series are
+ // partitioned into subsets prior to applying the aggregation
+ // operation. Each subset contains time series that have the same
+ // value for each of the grouping fields. Each individual time
+ // series is a member of exactly one subset. The
+ // `cross_series_reducer` is applied to each subset of time series.
+ // It is not possible to reduce across different resource types, so
+ // this field implicitly contains `resource.type`. Fields not
+ // specified in `group_by_fields` are aggregated away. If
+ // `group_by_fields` is not specified and all the time series have
+ // the same resource type, then the time series are aggregated into
+ // a single output time series. If `cross_series_reducer` is not
+ // defined, this field is ignored.
+ GroupByFields []string `protobuf:"bytes,5,rep,name=group_by_fields,json=groupByFields,proto3" json:"group_by_fields,omitempty"`
+}
+
+func (x *Aggregation) Reset() {
+ *x = Aggregation{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_common_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Aggregation) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Aggregation) ProtoMessage() {}
+
+func (x *Aggregation) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_common_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Aggregation.ProtoReflect.Descriptor instead.
+func (*Aggregation) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_common_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *Aggregation) GetAlignmentPeriod() *durationpb.Duration {
+ if x != nil {
+ return x.AlignmentPeriod
+ }
+ return nil
+}
+
+func (x *Aggregation) GetPerSeriesAligner() Aggregation_Aligner {
+ if x != nil {
+ return x.PerSeriesAligner
+ }
+ return Aggregation_ALIGN_NONE
+}
+
+func (x *Aggregation) GetCrossSeriesReducer() Aggregation_Reducer {
+ if x != nil {
+ return x.CrossSeriesReducer
+ }
+ return Aggregation_REDUCE_NONE
+}
+
+func (x *Aggregation) GetGroupByFields() []string {
+ if x != nil {
+ return x.GroupByFields
+ }
+ return nil
+}
+
+var File_google_monitoring_v3_common_proto protoreflect.FileDescriptor
+
+var file_google_monitoring_v3_common_proto_rawDesc = []byte{
+ 0x0a, 0x21, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x1a, 0x1d, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69,
+ 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
+ 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xee, 0x01, 0x0a, 0x0a, 0x54, 0x79,
+ 0x70, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c,
+ 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09,
+ 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x69, 0x6e, 0x74,
+ 0x36, 0x34, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00,
+ 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x23, 0x0a, 0x0c,
+ 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01,
+ 0x28, 0x01, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75,
+ 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e,
+ 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x49, 0x0a, 0x12, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69,
+ 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e,
+ 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x11,
+ 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x75,
+ 0x65, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x80, 0x01, 0x0a, 0x0c, 0x54,
+ 0x69, 0x6d, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x35, 0x0a, 0x08, 0x65,
+ 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+ 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69,
+ 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+ 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xf3, 0x07,
+ 0x0a, 0x0b, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a,
+ 0x10, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f,
+ 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x52, 0x0f, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x65, 0x72,
+ 0x69, 0x6f, 0x64, 0x12, 0x57, 0x0a, 0x12, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x65,
+ 0x73, 0x5f, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
+ 0x29, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x2e, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x52, 0x10, 0x70, 0x65, 0x72, 0x53,
+ 0x65, 0x72, 0x69, 0x65, 0x73, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x5b, 0x0a, 0x14,
+ 0x63, 0x72, 0x6f, 0x73, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x64,
+ 0x75, 0x63, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
+ 0x33, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65,
+ 0x64, 0x75, 0x63, 0x65, 0x72, 0x52, 0x12, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x53, 0x65, 0x72, 0x69,
+ 0x65, 0x73, 0x52, 0x65, 0x64, 0x75, 0x63, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x67, 0x72, 0x6f,
+ 0x75, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03,
+ 0x28, 0x09, 0x52, 0x0d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x79, 0x46, 0x69, 0x65, 0x6c, 0x64,
+ 0x73, 0x22, 0x8b, 0x03, 0x0a, 0x07, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x0e, 0x0a,
+ 0x0a, 0x41, 0x4c, 0x49, 0x47, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0f, 0x0a,
+ 0x0b, 0x41, 0x4c, 0x49, 0x47, 0x4e, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x01, 0x12, 0x0e,
+ 0x0a, 0x0a, 0x41, 0x4c, 0x49, 0x47, 0x4e, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 0x15,
+ 0x0a, 0x11, 0x41, 0x4c, 0x49, 0x47, 0x4e, 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x50, 0x4f, 0x4c,
+ 0x41, 0x54, 0x45, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x4c, 0x49, 0x47, 0x4e, 0x5f, 0x4e,
+ 0x45, 0x58, 0x54, 0x5f, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, 0x41,
+ 0x4c, 0x49, 0x47, 0x4e, 0x5f, 0x4d, 0x49, 0x4e, 0x10, 0x0a, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x4c,
+ 0x49, 0x47, 0x4e, 0x5f, 0x4d, 0x41, 0x58, 0x10, 0x0b, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x4c, 0x49,
+ 0x47, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x4e, 0x10, 0x0c, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4c, 0x49,
+ 0x47, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x0d, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x4c,
+ 0x49, 0x47, 0x4e, 0x5f, 0x53, 0x55, 0x4d, 0x10, 0x0e, 0x12, 0x10, 0x0a, 0x0c, 0x41, 0x4c, 0x49,
+ 0x47, 0x4e, 0x5f, 0x53, 0x54, 0x44, 0x44, 0x45, 0x56, 0x10, 0x0f, 0x12, 0x14, 0x0a, 0x10, 0x41,
+ 0x4c, 0x49, 0x47, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x54, 0x52, 0x55, 0x45, 0x10,
+ 0x10, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x4c, 0x49, 0x47, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54,
+ 0x5f, 0x46, 0x41, 0x4c, 0x53, 0x45, 0x10, 0x18, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x4c, 0x49, 0x47,
+ 0x4e, 0x5f, 0x46, 0x52, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x52, 0x55, 0x45, 0x10,
+ 0x11, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x4c, 0x49, 0x47, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x43, 0x45,
+ 0x4e, 0x54, 0x49, 0x4c, 0x45, 0x5f, 0x39, 0x39, 0x10, 0x12, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x4c,
+ 0x49, 0x47, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x43, 0x45, 0x4e, 0x54, 0x49, 0x4c, 0x45, 0x5f, 0x39,
+ 0x35, 0x10, 0x13, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x4c, 0x49, 0x47, 0x4e, 0x5f, 0x50, 0x45, 0x52,
+ 0x43, 0x45, 0x4e, 0x54, 0x49, 0x4c, 0x45, 0x5f, 0x35, 0x30, 0x10, 0x14, 0x12, 0x17, 0x0a, 0x13,
+ 0x41, 0x4c, 0x49, 0x47, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x43, 0x45, 0x4e, 0x54, 0x49, 0x4c, 0x45,
+ 0x5f, 0x30, 0x35, 0x10, 0x15, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x4c, 0x49, 0x47, 0x4e, 0x5f, 0x50,
+ 0x45, 0x52, 0x43, 0x45, 0x4e, 0x54, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x17, 0x22,
+ 0xb1, 0x02, 0x0a, 0x07, 0x52, 0x65, 0x64, 0x75, 0x63, 0x65, 0x72, 0x12, 0x0f, 0x0a, 0x0b, 0x52,
+ 0x45, 0x44, 0x55, 0x43, 0x45, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b,
+ 0x52, 0x45, 0x44, 0x55, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x41, 0x4e, 0x10, 0x01, 0x12, 0x0e, 0x0a,
+ 0x0a, 0x52, 0x45, 0x44, 0x55, 0x43, 0x45, 0x5f, 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x0e, 0x0a,
+ 0x0a, 0x52, 0x45, 0x44, 0x55, 0x43, 0x45, 0x5f, 0x4d, 0x41, 0x58, 0x10, 0x03, 0x12, 0x0e, 0x0a,
+ 0x0a, 0x52, 0x45, 0x44, 0x55, 0x43, 0x45, 0x5f, 0x53, 0x55, 0x4d, 0x10, 0x04, 0x12, 0x11, 0x0a,
+ 0x0d, 0x52, 0x45, 0x44, 0x55, 0x43, 0x45, 0x5f, 0x53, 0x54, 0x44, 0x44, 0x45, 0x56, 0x10, 0x05,
+ 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x44, 0x55, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54,
+ 0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x44, 0x55, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x55,
+ 0x4e, 0x54, 0x5f, 0x54, 0x52, 0x55, 0x45, 0x10, 0x07, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x44,
+ 0x55, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x46, 0x41, 0x4c, 0x53, 0x45, 0x10,
+ 0x0f, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x44, 0x55, 0x43, 0x45, 0x5f, 0x46, 0x52, 0x41, 0x43,
+ 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x52, 0x55, 0x45, 0x10, 0x08, 0x12, 0x18, 0x0a, 0x14, 0x52,
+ 0x45, 0x44, 0x55, 0x43, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x43, 0x45, 0x4e, 0x54, 0x49, 0x4c, 0x45,
+ 0x5f, 0x39, 0x39, 0x10, 0x09, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x44, 0x55, 0x43, 0x45, 0x5f,
+ 0x50, 0x45, 0x52, 0x43, 0x45, 0x4e, 0x54, 0x49, 0x4c, 0x45, 0x5f, 0x39, 0x35, 0x10, 0x0a, 0x12,
+ 0x18, 0x0a, 0x14, 0x52, 0x45, 0x44, 0x55, 0x43, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x43, 0x45, 0x4e,
+ 0x54, 0x49, 0x4c, 0x45, 0x5f, 0x35, 0x30, 0x10, 0x0b, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x44,
+ 0x55, 0x43, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x43, 0x45, 0x4e, 0x54, 0x49, 0x4c, 0x45, 0x5f, 0x30,
+ 0x35, 0x10, 0x0c, 0x2a, 0x9e, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73,
+ 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52,
+ 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44,
+ 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e,
+ 0x5f, 0x47, 0x54, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49,
+ 0x53, 0x4f, 0x4e, 0x5f, 0x47, 0x45, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4f, 0x4d, 0x50,
+ 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4c, 0x54, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x43,
+ 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4c, 0x45, 0x10, 0x04, 0x12, 0x11,
+ 0x0a, 0x0d, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x45, 0x51, 0x10,
+ 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f,
+ 0x4e, 0x45, 0x10, 0x06, 0x2a, 0x61, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54,
+ 0x69, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x54,
+ 0x49, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
+ 0x00, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x54, 0x49, 0x45,
+ 0x52, 0x5f, 0x42, 0x41, 0x53, 0x49, 0x43, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, 0x52,
+ 0x56, 0x49, 0x43, 0x45, 0x5f, 0x54, 0x49, 0x45, 0x52, 0x5f, 0x50, 0x52, 0x45, 0x4d, 0x49, 0x55,
+ 0x4d, 0x10, 0x02, 0x1a, 0x02, 0x18, 0x01, 0x42, 0xc6, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
+ 0x67, 0x2e, 0x76, 0x33, 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74,
+ 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
+ 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f,
+ 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33,
+ 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64,
+ 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33,
+ 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_google_monitoring_v3_common_proto_rawDescOnce sync.Once
+ file_google_monitoring_v3_common_proto_rawDescData = file_google_monitoring_v3_common_proto_rawDesc
+)
+
+func file_google_monitoring_v3_common_proto_rawDescGZIP() []byte {
+ file_google_monitoring_v3_common_proto_rawDescOnce.Do(func() {
+ file_google_monitoring_v3_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_monitoring_v3_common_proto_rawDescData)
+ })
+ return file_google_monitoring_v3_common_proto_rawDescData
+}
+
+var file_google_monitoring_v3_common_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
+var file_google_monitoring_v3_common_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_google_monitoring_v3_common_proto_goTypes = []interface{}{
+ (ComparisonType)(0), // 0: google.monitoring.v3.ComparisonType
+ (ServiceTier)(0), // 1: google.monitoring.v3.ServiceTier
+ (Aggregation_Aligner)(0), // 2: google.monitoring.v3.Aggregation.Aligner
+ (Aggregation_Reducer)(0), // 3: google.monitoring.v3.Aggregation.Reducer
+ (*TypedValue)(nil), // 4: google.monitoring.v3.TypedValue
+ (*TimeInterval)(nil), // 5: google.monitoring.v3.TimeInterval
+ (*Aggregation)(nil), // 6: google.monitoring.v3.Aggregation
+ (*distribution.Distribution)(nil), // 7: google.api.Distribution
+ (*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp
+ (*durationpb.Duration)(nil), // 9: google.protobuf.Duration
+}
+var file_google_monitoring_v3_common_proto_depIdxs = []int32{
+ 7, // 0: google.monitoring.v3.TypedValue.distribution_value:type_name -> google.api.Distribution
+ 8, // 1: google.monitoring.v3.TimeInterval.end_time:type_name -> google.protobuf.Timestamp
+ 8, // 2: google.monitoring.v3.TimeInterval.start_time:type_name -> google.protobuf.Timestamp
+ 9, // 3: google.monitoring.v3.Aggregation.alignment_period:type_name -> google.protobuf.Duration
+ 2, // 4: google.monitoring.v3.Aggregation.per_series_aligner:type_name -> google.monitoring.v3.Aggregation.Aligner
+ 3, // 5: google.monitoring.v3.Aggregation.cross_series_reducer:type_name -> google.monitoring.v3.Aggregation.Reducer
+ 6, // [6:6] is the sub-list for method output_type
+ 6, // [6:6] is the sub-list for method input_type
+ 6, // [6:6] is the sub-list for extension type_name
+ 6, // [6:6] is the sub-list for extension extendee
+ 0, // [0:6] is the sub-list for field type_name
+}
+
+func init() { file_google_monitoring_v3_common_proto_init() }
+func file_google_monitoring_v3_common_proto_init() {
+ if File_google_monitoring_v3_common_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_google_monitoring_v3_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TypedValue); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_common_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TimeInterval); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_common_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Aggregation); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ file_google_monitoring_v3_common_proto_msgTypes[0].OneofWrappers = []interface{}{
+ (*TypedValue_BoolValue)(nil),
+ (*TypedValue_Int64Value)(nil),
+ (*TypedValue_DoubleValue)(nil),
+ (*TypedValue_StringValue)(nil),
+ (*TypedValue_DistributionValue)(nil),
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_google_monitoring_v3_common_proto_rawDesc,
+ NumEnums: 4,
+ NumMessages: 3,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_google_monitoring_v3_common_proto_goTypes,
+ DependencyIndexes: file_google_monitoring_v3_common_proto_depIdxs,
+ EnumInfos: file_google_monitoring_v3_common_proto_enumTypes,
+ MessageInfos: file_google_monitoring_v3_common_proto_msgTypes,
+ }.Build()
+ File_google_monitoring_v3_common_proto = out.File
+ file_google_monitoring_v3_common_proto_rawDesc = nil
+ file_google_monitoring_v3_common_proto_goTypes = nil
+ file_google_monitoring_v3_common_proto_depIdxs = nil
+}
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/dropped_labels.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/dropped_labels.pb.go
similarity index 87%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/dropped_labels.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/dropped_labels.pb.go
index f63082179b0..f4a78f6a21d 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/dropped_labels.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/dropped_labels.pb.go
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/dropped_labels.proto
-package monitoring
+package monitoringpb
import (
reflect "reflect"
@@ -115,20 +115,20 @@ var file_google_monitoring_v3_dropped_labels_proto_rawDesc = []byte{
0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
- 0x02, 0x38, 0x01, 0x42, 0xca, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x02, 0x38, 0x01, 0x42, 0xcd, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
0x42, 0x12, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x50,
- 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67,
- 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x6d, 0x6f,
- 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x3b, 0x6d, 0x6f, 0x6e, 0x69,
- 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
- 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
- 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f,
- 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33,
- 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64,
- 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33,
- 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f,
+ 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c,
+ 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c,
+ 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a,
+ 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/group.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/group.pb.go
similarity index 90%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/group.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/group.pb.go
index c001e17df94..f870b23a4dc 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/group.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/group.pb.go
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/group.proto
-package monitoring
+package monitoringpb
import (
reflect "reflect"
@@ -185,20 +185,20 @@ var file_google_monitoring_v3_group_proto_rawDesc = []byte{
0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x7b, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x7d, 0x12, 0x1f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x66,
0x6f, 0x6c, 0x64, 0x65, 0x72, 0x7d, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x7b, 0x67,
- 0x72, 0x6f, 0x75, 0x70, 0x7d, 0x12, 0x01, 0x2a, 0x42, 0xc2, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d,
+ 0x72, 0x6f, 0x75, 0x70, 0x7d, 0x12, 0x01, 0x2a, 0x42, 0xc5, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x0a, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x72, 0x6f, 0x74,
- 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61,
- 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
- 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
- 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
- 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f,
- 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33,
- 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c,
- 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d,
- 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d,
- 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
+ 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f,
+ 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33,
+ 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64,
+ 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33,
+ 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/group_service.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/group_service.pb.go
similarity index 94%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/group_service.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/group_service.pb.go
index cabe69a6e1a..5d7745e9807 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/group_service.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/group_service.pb.go
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/group_service.proto
-package monitoring
+package monitoringpb
import (
context "context"
@@ -783,44 +783,44 @@ var file_google_monitoring_v3_group_service_proto_rawDesc = []byte{
0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x28, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75,
- 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93,
- 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72,
- 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73,
- 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x7d, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x47, 0x72,
+ 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0xda, 0x41, 0x04, 0x6e,
+ 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x33, 0x2f, 0x7b,
+ 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d,
+ 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x7d, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x12, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e,
0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
- 0x33, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x2d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x12,
- 0x1e, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65,
- 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x2a, 0x7d, 0xda,
- 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x8e, 0x01, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74,
+ 0x33, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x2d, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+ 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d,
+ 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x67, 0x72, 0x6f,
+ 0x75, 0x70, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0x8e, 0x01, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74,
0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x28, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x72,
0x65, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
- 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x38, 0x82,
- 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x1c, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65,
- 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x67, 0x72, 0x6f,
- 0x75, 0x70, 0x73, 0x3a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0xda, 0x41, 0x0a, 0x6e, 0x61, 0x6d,
- 0x65, 0x2c, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x91, 0x01, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61,
+ 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x38, 0xda,
+ 0x41, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x82, 0xd3, 0xe4, 0x93,
+ 0x02, 0x25, 0x3a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x1c, 0x2f, 0x76, 0x33, 0x2f, 0x7b,
+ 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d,
+ 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x91, 0x01, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61,
0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x28, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55,
0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x3b,
- 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x1a, 0x24, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x67, 0x72, 0x6f,
- 0x75, 0x70, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73,
- 0x2f, 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x05, 0x67, 0x72,
- 0x6f, 0x75, 0x70, 0xda, 0x41, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x7e, 0x0a, 0x0b, 0x44,
+ 0xda, 0x41, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x3a, 0x05,
+ 0x67, 0x72, 0x6f, 0x75, 0x70, 0x1a, 0x24, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x67, 0x72, 0x6f, 0x75,
+ 0x70, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f,
+ 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0x7e, 0x0a, 0x0b, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x28, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
0x33, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2d, 0x82, 0xd3,
- 0xe4, 0x93, 0x02, 0x20, 0x2a, 0x1e, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d,
- 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70,
- 0x73, 0x2f, 0x2a, 0x7d, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x10,
+ 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2d, 0xda, 0x41,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x2a, 0x1e, 0x2f, 0x76, 0x33,
+ 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f,
+ 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xa8, 0x01, 0x0a, 0x10,
0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73,
0x12, 0x2d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75,
@@ -828,10 +828,10 @@ var file_google_monitoring_v3_group_service_proto_rawDesc = []byte{
0x2e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
- 0x35, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x12, 0x26, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61,
- 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x67, 0x72,
- 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0xda,
- 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x1a, 0xa9, 0x01, 0xca, 0x41, 0x19, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x35, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x12, 0x26,
+ 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+ 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6d,
+ 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x1a, 0xa9, 0x01, 0xca, 0x41, 0x19, 0x6d, 0x6f, 0x6e, 0x69,
0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69,
0x73, 0x2e, 0x63, 0x6f, 0x6d, 0xd2, 0x41, 0x89, 0x01, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f,
0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e,
@@ -842,20 +842,20 @@ var file_google_monitoring_v3_group_service_proto_rawDesc = []byte{
0x6e, 0x67, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75,
0x74, 0x68, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x72, 0x65,
- 0x61, 0x64, 0x42, 0xc9, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x61, 0x64, 0x42, 0xcc, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42,
0x11, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f,
- 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c,
- 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x6d, 0x6f, 0x6e, 0x69,
- 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
- 0x72, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c,
- 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56,
- 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64,
- 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02,
- 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a,
- 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
+ 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x6f,
+ 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
+ 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c,
+ 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56,
+ 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75,
+ 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56,
+ 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/metric.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/metric.pb.go
similarity index 96%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/metric.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/metric.pb.go
index 23a28e07110..e414c4ab70a 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/metric.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/metric.pb.go
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/metric.proto
-package monitoring
+package monitoringpb
import (
reflect "reflect"
@@ -214,14 +214,14 @@ func (x *TimeSeries) GetMetricKind() metric.MetricDescriptor_MetricKind {
if x != nil {
return x.MetricKind
}
- return metric.MetricDescriptor_METRIC_KIND_UNSPECIFIED
+ return metric.MetricDescriptor_MetricKind(0)
}
func (x *TimeSeries) GetValueType() metric.MetricDescriptor_ValueType {
if x != nil {
return x.ValueType
}
- return metric.MetricDescriptor_VALUE_TYPE_UNSPECIFIED
+ return metric.MetricDescriptor_ValueType(0)
}
func (x *TimeSeries) GetPoints() []*Point {
@@ -522,19 +522,19 @@ func (x *QueryError) GetMessage() string {
//
// For example, suppose the request field `text` contains:
//
-// text: "The quick brown fox jumps over the lazy dog."
+// text: "The quick brown fox jumps over the lazy dog."
//
// Then the locator:
//
-// source: "text"
-// start_position {
-// line: 1
-// column: 17
-// }
-// end_position {
-// line: 1
-// column: 19
-// }
+// source: "text"
+// start_position {
+// line: 1
+// column: 17
+// }
+// end_position {
+// line: 1
+// column: 19
+// }
//
// refers to the part of the text: "fox".
type TextLocator struct {
@@ -697,14 +697,14 @@ func (x *TimeSeriesDescriptor_ValueDescriptor) GetValueType() metric.MetricDescr
if x != nil {
return x.ValueType
}
- return metric.MetricDescriptor_VALUE_TYPE_UNSPECIFIED
+ return metric.MetricDescriptor_ValueType(0)
}
func (x *TimeSeriesDescriptor_ValueDescriptor) GetMetricKind() metric.MetricDescriptor_MetricKind {
if x != nil {
return x.MetricKind
}
- return metric.MetricDescriptor_METRIC_KIND_UNSPECIFIED
+ return metric.MetricDescriptor_MetricKind(0)
}
func (x *TimeSeriesDescriptor_ValueDescriptor) GetUnit() string {
@@ -962,20 +962,20 @@ var file_google_monitoring_v3_metric_proto_rawDesc = []byte{
0x65, 0x61, 0x73, 0x6f, 0x6e, 0x1a, 0x36, 0x0a, 0x08, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f,
0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
0x04, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x42, 0xc3, 0x01,
+ 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x42, 0xc6, 0x01,
0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e,
0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x0b, 0x4d, 0x65, 0x74, 0x72,
- 0x69, 0x63, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
- 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73,
- 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x3b, 0x6d,
- 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67,
- 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
- 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c,
- 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
- 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c,
- 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a,
- 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x69, 0x63, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f,
+ 0x76, 0x32, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b,
+ 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a,
+ 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
+ 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/metric_service.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/metric_service.pb.go
similarity index 92%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/metric_service.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/metric_service.pb.go
index d49bc93c7c4..8008083f508 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/metric_service.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/metric_service.pb.go
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/metric_service.proto
-package monitoring
+package monitoringpb
import (
context "context"
@@ -920,11 +920,11 @@ type CreateTimeSeriesError struct {
// DEPRECATED. Time series ID that resulted in the `status` error.
//
- // Deprecated: Do not use.
+ // Deprecated: Marked as deprecated in google/monitoring/v3/metric_service.proto.
TimeSeries *TimeSeries `protobuf:"bytes,1,opt,name=time_series,json=timeSeries,proto3" json:"time_series,omitempty"`
// DEPRECATED. The status of the requested write operation for `time_series`.
//
- // Deprecated: Do not use.
+ // Deprecated: Marked as deprecated in google/monitoring/v3/metric_service.proto.
Status *status.Status `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"`
}
@@ -960,7 +960,7 @@ func (*CreateTimeSeriesError) Descriptor() ([]byte, []int) {
return file_google_monitoring_v3_metric_service_proto_rawDescGZIP(), []int{11}
}
-// Deprecated: Do not use.
+// Deprecated: Marked as deprecated in google/monitoring/v3/metric_service.proto.
func (x *CreateTimeSeriesError) GetTimeSeries() *TimeSeries {
if x != nil {
return x.TimeSeries
@@ -968,7 +968,7 @@ func (x *CreateTimeSeriesError) GetTimeSeries() *TimeSeries {
return nil
}
-// Deprecated: Do not use.
+// Deprecated: Marked as deprecated in google/monitoring/v3/metric_service.proto.
func (x *CreateTimeSeriesError) GetStatus() *status.Status {
if x != nil {
return x.Status
@@ -1559,11 +1559,11 @@ var file_google_monitoring_v3_metric_service_proto_rawDesc = []byte{
0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x6e, 0x69,
0x74, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x22, 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e,
- 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f,
- 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
- 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0xda, 0x41, 0x04, 0x6e,
- 0x61, 0x6d, 0x65, 0x12, 0xcc, 0x01, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x22, 0x41, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12,
+ 0x32, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65,
+ 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64,
+ 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
+ 0x6f, 0x72, 0x73, 0x12, 0xcc, 0x01, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x3b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x65,
@@ -1571,12 +1571,12 @@ var file_google_monitoring_v3_metric_service_proto_rawDesc = []byte{
0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69,
0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
- 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x22, 0x44, 0x82, 0xd3,
- 0xe4, 0x93, 0x02, 0x37, 0x12, 0x35, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d,
- 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
- 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63,
- 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x2a, 0x2a, 0x7d, 0xda, 0x41, 0x04, 0x6e, 0x61,
- 0x6d, 0x65, 0x12, 0xb8, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69,
+ 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x22, 0x44, 0xda, 0x41,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x37, 0x12, 0x35, 0x2f, 0x76, 0x33,
+ 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f,
+ 0x2a, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x2a,
+ 0x2a, 0x7d, 0x12, 0xb8, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69,
0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x32, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65,
@@ -1584,20 +1584,20 @@ var file_google_monitoring_v3_metric_service_proto_rawDesc = []byte{
0x1a, 0x33, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x72,
0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x73,
- 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x12, 0x27, 0x2f,
- 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
- 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72,
- 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0xa0, 0x01,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3,
+ 0xe4, 0x93, 0x02, 0x29, 0x12, 0x27, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d,
+ 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6d, 0x65, 0x74, 0x72,
+ 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x12, 0xa0, 0x01,
0x0a, 0x13, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d,
0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x65, 0x74,
0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72,
- 0x69, 0x70, 0x74, 0x6f, 0x72, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x12, 0x2a, 0x2f,
- 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
- 0x73, 0x2f, 0x2a, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69,
- 0x70, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x2a, 0x2a, 0x7d, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+ 0x69, 0x70, 0x74, 0x6f, 0x72, 0x22, 0x39, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3,
+ 0xe4, 0x93, 0x02, 0x2c, 0x12, 0x2a, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d,
+ 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+ 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x2a, 0x2a, 0x7d,
0x12, 0xc8, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69,
0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x33, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
@@ -1605,59 +1605,59 @@ var file_google_monitoring_v3_metric_service_proto_rawDesc = []byte{
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65,
0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x22, 0x5b,
- 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3c, 0x22, 0x27, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d,
- 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6d, 0x65,
- 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x3a,
+ 0xda, 0x41, 0x16, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x64,
+ 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3c, 0x3a,
0x11, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
- 0x6f, 0x72, 0xda, 0x41, 0x16, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
- 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0xa0, 0x01, 0x0a, 0x16,
+ 0x6f, 0x72, 0x22, 0x27, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72,
+ 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x12, 0xa0, 0x01, 0x0a, 0x16,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x33, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
- 0x70, 0x74, 0x79, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x2a, 0x2a, 0x2f, 0x76, 0x33,
- 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f,
- 0x2a, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
- 0x6f, 0x72, 0x73, 0x2f, 0x2a, 0x2a, 0x7d, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0xfe,
+ 0x70, 0x74, 0x79, 0x22, 0x39, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93,
+ 0x02, 0x2c, 0x2a, 0x2a, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72,
+ 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44,
+ 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x2a, 0x2a, 0x7d, 0x12, 0xfe,
0x01, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65,
0x73, 0x12, 0x2b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x69, 0x6d,
0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65,
- 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x90, 0x01, 0x82,
- 0xd3, 0xe4, 0x93, 0x02, 0x6e, 0x12, 0x20, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65,
- 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x74, 0x69, 0x6d,
- 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x5a, 0x27, 0x12, 0x25, 0x2f, 0x76, 0x33, 0x2f, 0x7b,
- 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73,
- 0x5a, 0x21, 0x12, 0x1f, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x66, 0x6f,
- 0x6c, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72,
- 0x69, 0x65, 0x73, 0xda, 0x41, 0x19, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x66, 0x69, 0x6c, 0x74, 0x65,
- 0x72, 0x2c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x2c, 0x76, 0x69, 0x65, 0x77, 0x12,
+ 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x90, 0x01, 0xda,
+ 0x41, 0x19, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2c, 0x69, 0x6e,
+ 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x2c, 0x76, 0x69, 0x65, 0x77, 0x82, 0xd3, 0xe4, 0x93, 0x02,
+ 0x6e, 0x5a, 0x27, 0x12, 0x25, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x6f,
+ 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x2a, 0x7d, 0x2f,
+ 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x5a, 0x21, 0x12, 0x1f, 0x2f, 0x76,
+ 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x2f,
+ 0x2a, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x20, 0x2f,
+ 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+ 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12,
0x99, 0x01, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65,
0x72, 0x69, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f,
0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x72, 0x65, 0x61,
0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x3e, 0x82, 0xd3, 0xe4,
- 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70,
- 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x53,
- 0x65, 0x72, 0x69, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0xda, 0x41, 0x10, 0x6e, 0x61, 0x6d, 0x65, 0x2c,
- 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0xae, 0x01, 0x0a, 0x17,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x3e, 0xda, 0x41, 0x10,
+ 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73,
+ 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x3a, 0x01, 0x2a, 0x22, 0x20, 0x2f, 0x76, 0x33, 0x2f, 0x7b,
+ 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d,
+ 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0xae, 0x01, 0x0a, 0x17,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x69, 0x6d,
0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x43,
0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x4c,
- 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x33, 0x22, 0x2e, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d,
- 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x74, 0x69,
- 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53,
- 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0xda, 0x41, 0x10, 0x6e, 0x61, 0x6d, 0x65,
- 0x2c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x1a, 0xda, 0x01, 0xca,
+ 0xda, 0x41, 0x10, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72,
+ 0x69, 0x65, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x33, 0x3a, 0x01, 0x2a, 0x22, 0x2e, 0x2f, 0x76,
+ 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73,
+ 0x2f, 0x2a, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x3a, 0x63,
+ 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x1a, 0xda, 0x01, 0xca,
0x41, 0x19, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0xd2, 0x41, 0xba, 0x01, 0x68,
0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
@@ -1671,72 +1671,72 @@ var file_google_monitoring_v3_metric_service_proto_rawDesc = []byte{
0x69, 0x6e, 0x67, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f,
0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
- 0x69, 0x6e, 0x67, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x65, 0x42, 0x86, 0x08, 0x0a, 0x18, 0x63, 0x6f,
- 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
- 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x12, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x53, 0x65,
- 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x6f,
- 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f,
- 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61,
- 0x70, 0x69, 0x73, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76,
- 0x33, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x1a, 0x47,
- 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69,
- 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67,
- 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
- 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a,
- 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
- 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0xea, 0x41, 0xf0, 0x01, 0x0a, 0x2a, 0x6d, 0x6f, 0x6e, 0x69,
- 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69,
- 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63,
- 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x3b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73,
- 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69,
- 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x6d, 0x65,
- 0x74, 0x72, 0x69, 0x63, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x3d,
- 0x2a, 0x2a, 0x7d, 0x12, 0x45, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x7d, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
- 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x64, 0x65, 0x73, 0x63,
- 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x39, 0x66, 0x6f, 0x6c, 0x64,
- 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x7d, 0x2f, 0x6d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b,
- 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f,
- 0x72, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x01, 0x2a, 0x20, 0x01, 0xea, 0x41, 0xb7, 0x02, 0x0a, 0x35,
- 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
- 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
- 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72,
- 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x4f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f,
- 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
+ 0x69, 0x6e, 0x67, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x65, 0x42, 0x89, 0x08, 0xea, 0x41, 0xf0, 0x01,
+ 0x0a, 0x2a, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4d, 0x65, 0x74, 0x72,
+ 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x3b, 0x70, 0x72,
+ 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d,
+ 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f,
+ 0x72, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72,
+ 0x69, 0x70, 0x74, 0x6f, 0x72, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x45, 0x6f, 0x72, 0x67, 0x61, 0x6e,
+ 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69,
+ 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65,
+ 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69,
+ 0x63, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x3d, 0x2a, 0x2a, 0x7d,
+ 0x12, 0x39, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x66, 0x6f, 0x6c, 0x64, 0x65,
+ 0x72, 0x7d, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+ 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x64, 0x65, 0x73,
+ 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x01, 0x2a, 0x20, 0x01,
+ 0xea, 0x41, 0xb7, 0x02, 0x0a, 0x35, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x4f, 0x70, 0x72, 0x6f,
+ 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f,
+ 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x6d, 0x6f,
+ 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x7d, 0x12, 0x59, 0x6f, 0x72,
+ 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67,
+ 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63,
+ 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63,
+ 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x7d, 0x12, 0x4d, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73,
+ 0x2f, 0x7b, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x7d, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65,
0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72,
- 0x69, 0x70, 0x74, 0x6f, 0x72, 0x7d, 0x12, 0x59, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61,
+ 0x69, 0x70, 0x74, 0x6f, 0x72, 0x7d, 0x12, 0x01, 0x2a, 0x20, 0x01, 0xea, 0x41, 0x51, 0x0a, 0x23,
+ 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70,
+ 0x61, 0x63, 0x65, 0x12, 0x12, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70,
+ 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x12, 0x16, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0xea,
+ 0x41, 0xb5, 0x01, 0x0a, 0x24, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54,
+ 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2b, 0x70, 0x72, 0x6f, 0x6a, 0x65,
+ 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x74, 0x69,
+ 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73,
+ 0x65, 0x72, 0x69, 0x65, 0x73, 0x7d, 0x12, 0x35, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x7d, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65,
- 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72,
- 0x73, 0x2f, 0x7b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73,
- 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72,
- 0x7d, 0x12, 0x4d, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x66, 0x6f, 0x6c, 0x64,
- 0x65, 0x72, 0x7d, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73,
- 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73,
- 0x2f, 0x7b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f,
- 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x7d,
- 0x12, 0x01, 0x2a, 0x20, 0x01, 0xea, 0x41, 0x51, 0x0a, 0x23, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
- 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e,
- 0x63, 0x6f, 0x6d, 0x2f, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x70,
- 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
- 0x7d, 0x12, 0x16, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x77,
- 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0xea, 0x41, 0xb5, 0x01, 0x0a, 0x24, 0x6d,
- 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
- 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72,
- 0x69, 0x65, 0x73, 0x12, 0x2b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70,
- 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69,
- 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x7d,
- 0x12, 0x35, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f,
- 0x7b, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x2f, 0x74,
- 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x69, 0x6d, 0x65, 0x5f,
- 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x7d, 0x12, 0x29, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73,
- 0x2f, 0x7b, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65,
- 0x72, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x65,
- 0x73, 0x7d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x69, 0x6f, 0x6e, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f,
+ 0x7b, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x7d, 0x12, 0x29, 0x66,
+ 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x7d, 0x2f,
+ 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x69, 0x6d, 0x65,
+ 0x5f, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x7d, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
+ 0x76, 0x33, 0x42, 0x12, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f,
+ 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76,
+ 0x32, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
+ 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a,
+ 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
+ 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/mutation_record.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/mutation_record.pb.go
similarity index 85%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/mutation_record.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/mutation_record.pb.go
index 0035a1cc766..fca8f5823bc 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/mutation_record.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/mutation_record.pb.go
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/mutation_record.proto
-package monitoring
+package monitoringpb
import (
reflect "reflect"
@@ -110,20 +110,20 @@ var file_google_monitoring_v3_mutation_record_proto_rawDesc = []byte{
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6d, 0x75, 0x74, 0x61, 0x74, 0x65, 0x54, 0x69,
0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x75, 0x74, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x75, 0x74, 0x61, 0x74, 0x65, 0x64, 0x42,
- 0x79, 0x42, 0xcb, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x79, 0x42, 0xce, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x13,
0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72,
- 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f,
- 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x6d, 0x6f, 0x6e,
- 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
- 0x6f, 0x72, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43,
- 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75,
- 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea,
- 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a,
- 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62,
- 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
+ 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43,
+ 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c,
+ 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f,
+ 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a,
+ 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/notification.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/notification.pb.go
similarity index 96%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/notification.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/notification.pb.go
index 563f6cd4008..67dde79c30a 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/notification.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/notification.pb.go
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/notification.proto
-package monitoring
+package monitoringpb
import (
reflect "reflect"
@@ -138,7 +138,7 @@ type NotificationChannelDescriptor struct {
// The tiers that support this notification channel; the project service tier
// must be one of the supported_tiers.
//
- // Deprecated: Do not use.
+ // Deprecated: Marked as deprecated in google/monitoring/v3/notification.proto.
SupportedTiers []ServiceTier `protobuf:"varint,5,rep,packed,name=supported_tiers,json=supportedTiers,proto3,enum=google.monitoring.v3.ServiceTier" json:"supported_tiers,omitempty"`
// The product launch stage for channels of this type.
LaunchStage api.LaunchStage `protobuf:"varint,7,opt,name=launch_stage,json=launchStage,proto3,enum=google.api.LaunchStage" json:"launch_stage,omitempty"`
@@ -211,7 +211,7 @@ func (x *NotificationChannelDescriptor) GetLabels() []*label.LabelDescriptor {
return nil
}
-// Deprecated: Do not use.
+// Deprecated: Marked as deprecated in google/monitoring/v3/notification.proto.
func (x *NotificationChannelDescriptor) GetSupportedTiers() []ServiceTier {
if x != nil {
return x.SupportedTiers
@@ -223,7 +223,7 @@ func (x *NotificationChannelDescriptor) GetLaunchStage() api.LaunchStage {
if x != nil {
return x.LaunchStage
}
- return api.LaunchStage_LAUNCH_STAGE_UNSPECIFIED
+ return api.LaunchStage(0)
}
// A `NotificationChannel` is a medium through which an alert is
@@ -530,20 +530,21 @@ var file_google_monitoring_v3_notification_proto_rawDesc = []byte{
0x64, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x7d, 0x2f, 0x6e, 0x6f,
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65,
0x6c, 0x73, 0x2f, 0x7b, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x7d, 0x12, 0x01, 0x2a, 0x42, 0xc9, 0x01, 0x0a,
+ 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x7d, 0x12, 0x01, 0x2a, 0x42, 0xcc, 0x01, 0x0a,
0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x11, 0x4e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e,
- 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72,
- 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
- 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
- 0x2f, 0x76, 0x33, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0xaa, 0x02,
- 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f,
- 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f,
- 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74,
- 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
- 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
- 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41,
+ 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61,
+ 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
+ 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70,
+ 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64,
+ 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02,
+ 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f,
+ 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/notification_service.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/notification_service.pb.go
similarity index 94%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/notification_service.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/notification_service.pb.go
index 8c136d479cd..c0ce5de2d28 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/notification_service.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/notification_service.pb.go
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/notification_service.proto
-package monitoring
+package monitoringpb
import (
context "context"
@@ -1072,11 +1072,11 @@ var file_google_monitoring_v3_notification_service_proto_rawDesc = []byte{
0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x65, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x36, 0x12, 0x34, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e,
- 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f,
- 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e,
- 0x6e, 0x65, 0x6c, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0xda, 0x41,
- 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0xdd, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74,
+ 0x22, 0x43, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x36, 0x12,
+ 0x34, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65,
+ 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69,
+ 0x70, 0x74, 0x6f, 0x72, 0x73, 0x12, 0xdd, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74,
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x3d, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
@@ -1086,11 +1086,11 @@ var file_google_monitoring_v3_notification_service_proto_rawDesc = []byte{
0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61,
0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x22, 0x45,
- 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x38, 0x12, 0x36, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d,
- 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
- 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x2a, 0x7d, 0xda, 0x41,
- 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0xc4, 0x01, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f,
+ 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x38, 0x12, 0x36, 0x2f,
+ 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+ 0x73, 0x2f, 0x2a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f,
+ 0x72, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xc4, 0x01, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f,
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65,
0x6c, 0x73, 0x12, 0x35, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f,
@@ -1099,10 +1099,10 @@ var file_google_monitoring_v3_notification_service_proto_rawDesc = []byte{
0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x12, 0x2a, 0x2f, 0x76, 0x33, 0x2f, 0x7b,
- 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d,
- 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61,
- 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0xb5, 0x01, 0x0a,
+ 0x65, 0x22, 0x39, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c,
+ 0x12, 0x2a, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a,
+ 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0xb5, 0x01, 0x0a,
0x16, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x33, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47,
@@ -1110,11 +1110,11 @@ var file_google_monitoring_v3_notification_service_proto_rawDesc = []byte{
0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x3b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x12,
- 0x2c, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65,
- 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x2f, 0x2a, 0x7d, 0xda, 0x41, 0x04,
- 0x6e, 0x61, 0x6d, 0x65, 0x12, 0xe4, 0x01, 0x0a, 0x19, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e,
+ 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x3b, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+ 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x12, 0x2c, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d,
+ 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6e, 0x6f, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
+ 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xe4, 0x01, 0x0a, 0x19, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e,
0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e,
0x65, 0x6c, 0x12, 0x36, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
@@ -1122,13 +1122,13 @@ var file_google_monitoring_v3_notification_service_proto_rawDesc = []byte{
0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
0x33, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68,
- 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x64, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x42, 0x22, 0x2a, 0x2f,
- 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
- 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x3a, 0x14, 0x6e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0xda,
- 0x41, 0x19, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x83, 0x02, 0x0a, 0x19,
+ 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x64, 0xda, 0x41, 0x19, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x6e,
+ 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e,
+ 0x6e, 0x65, 0x6c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x42, 0x3a, 0x14, 0x6e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22,
+ 0x2a, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65,
+ 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x83, 0x02, 0x0a, 0x19,
0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x36, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
@@ -1136,27 +1136,27 @@ var file_google_monitoring_v3_notification_service_proto_rawDesc = []byte{
0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x29, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x82, 0x01, 0x82,
- 0xd3, 0xe4, 0x93, 0x02, 0x59, 0x32, 0x41, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x6f, 0x74, 0x69,
- 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
- 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a,
- 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61,
- 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x14, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0xda, 0x41,
- 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2c, 0x6e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65,
- 0x6c, 0x12, 0xae, 0x01, 0x0a, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x69,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x82, 0x01, 0xda,
+ 0x41, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2c, 0x6e, 0x6f,
+ 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e,
+ 0x65, 0x6c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x59, 0x3a, 0x14, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x32, 0x41,
+ 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70,
+ 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x2f, 0x2a,
+ 0x7d, 0x12, 0xae, 0x01, 0x0a, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12,
0x36, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x74,
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
- 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x2a, 0x2c, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61,
- 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65,
- 0x6c, 0x73, 0x2f, 0x2a, 0x7d, 0xda, 0x41, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x66, 0x6f, 0x72,
- 0x63, 0x65, 0x12, 0xdc, 0x01, 0x0a, 0x27, 0x53, 0x65, 0x6e, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66,
+ 0x41, 0xda, 0x41, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x82, 0xd3,
+ 0xe4, 0x93, 0x02, 0x2e, 0x2a, 0x2c, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d,
+ 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x2f,
+ 0x2a, 0x7d, 0x12, 0xdc, 0x01, 0x0a, 0x27, 0x53, 0x65, 0x6e, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66,
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x56, 0x65,
0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x44,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
@@ -1164,12 +1164,12 @@ var file_google_monitoring_v3_notification_service_proto_rawDesc = []byte{
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x56, 0x65, 0x72,
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x53, 0x82, 0xd3,
- 0xe4, 0x93, 0x02, 0x46, 0x22, 0x41, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d,
- 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x2f,
- 0x2a, 0x7d, 0x3a, 0x73, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x3a, 0x01, 0x2a, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d,
+ 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x53, 0xda, 0x41,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x46, 0x3a, 0x01, 0x2a, 0x22, 0x41,
+ 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+ 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x73, 0x65, 0x6e,
+ 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64,
0x65, 0x12, 0x87, 0x02, 0x0a, 0x26, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x56, 0x65, 0x72, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x43, 0x2e, 0x67,
@@ -1181,12 +1181,12 @@ var file_google_monitoring_v3_notification_service_proto_rawDesc = []byte{
0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x56,
0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x22,
- 0x40, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65,
- 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x67, 0x65,
- 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64,
- 0x65, 0x3a, 0x01, 0x2a, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0xca, 0x01, 0x0a, 0x19,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+ 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x3a, 0x01, 0x2a, 0x22, 0x40, 0x2f, 0x76, 0x33, 0x2f, 0x7b,
+ 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f,
+ 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e,
+ 0x6e, 0x65, 0x6c, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x67, 0x65, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0xca, 0x01, 0x0a, 0x19,
0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x36, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
@@ -1194,12 +1194,12 @@ var file_google_monitoring_v3_notification_service_proto_rawDesc = []byte{
0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x29, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x4a, 0x82, 0xd3,
- 0xe4, 0x93, 0x02, 0x38, 0x22, 0x33, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d,
- 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x2f,
- 0x2a, 0x7d, 0x3a, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x3a, 0x01, 0x2a, 0xda, 0x41, 0x09, 0x6e,
- 0x61, 0x6d, 0x65, 0x2c, 0x63, 0x6f, 0x64, 0x65, 0x1a, 0xa9, 0x01, 0xca, 0x41, 0x19, 0x6d, 0x6f,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x4a, 0xda, 0x41,
+ 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x63, 0x6f, 0x64, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x38,
+ 0x3a, 0x01, 0x2a, 0x22, 0x33, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70,
+ 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x2f, 0x2a,
+ 0x7d, 0x3a, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x1a, 0xa9, 0x01, 0xca, 0x41, 0x19, 0x6d, 0x6f,
0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61,
0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0xd2, 0x41, 0x89, 0x01, 0x68, 0x74, 0x74, 0x70, 0x73,
0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69,
@@ -1210,20 +1210,21 @@ var file_google_monitoring_v3_notification_service_proto_rawDesc = []byte{
0x72, 0x69, 0x6e, 0x67, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x61, 0x75, 0x74, 0x68, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x72, 0x65, 0x61, 0x64, 0x42, 0xd0, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x72, 0x65, 0x61, 0x64, 0x42, 0xd3, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
0x33, 0x42, 0x18, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
- 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67,
- 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67,
- 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
- 0x61, 0x70, 0x69, 0x73, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f,
- 0x76, 0x33, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x1a,
- 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e,
- 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f,
- 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
- 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
- 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
- 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63,
+ 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70,
+ 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
+ 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62,
+ 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e,
+ 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a,
+ 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x33,
}
var (
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/query_service.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/query_service.pb.go
similarity index 86%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/query_service.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/query_service.pb.go
index 062a1787abb..4e65aa33222 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/query_service.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/query_service.pb.go
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/query_service.proto
-package monitoring
+package monitoringpb
import (
context "context"
@@ -60,10 +60,10 @@ var file_google_monitoring_v3_query_service_proto_rawDesc = []byte{
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d,
0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x51, 0x75, 0x65,
0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22, 0x26, 0x2f, 0x76,
- 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73,
- 0x2f, 0x2a, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x3a, 0x71,
- 0x75, 0x65, 0x72, 0x79, 0x3a, 0x01, 0x2a, 0x1a, 0xa9, 0x01, 0xca, 0x41, 0x19, 0x6d, 0x6f, 0x6e,
+ 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x3a, 0x01, 0x2a, 0x22,
+ 0x26, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65,
+ 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65,
+ 0x73, 0x3a, 0x71, 0x75, 0x65, 0x72, 0x79, 0x1a, 0xa9, 0x01, 0xca, 0x41, 0x19, 0x6d, 0x6f, 0x6e,
0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0xd2, 0x41, 0x89, 0x01, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a,
0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73,
@@ -74,20 +74,20 @@ var file_google_monitoring_v3_query_service_proto_rawDesc = []byte{
0x69, 0x6e, 0x67, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61,
0x75, 0x74, 0x68, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x72,
- 0x65, 0x61, 0x64, 0x42, 0xc9, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x65, 0x61, 0x64, 0x42, 0xcc, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
0x42, 0x11, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72,
- 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f,
- 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x6d, 0x6f, 0x6e,
- 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
- 0x6f, 0x72, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43,
- 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75,
- 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea,
- 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a,
- 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62,
- 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
+ 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43,
+ 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c,
+ 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f,
+ 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a,
+ 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var file_google_monitoring_v3_query_service_proto_goTypes = []interface{}{
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/service.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/service.pb.go
similarity index 98%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/service.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/service.pb.go
index de42fc917f8..12b275bb2d4 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/service.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/service.pb.go
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/service.proto
-package monitoring
+package monitoringpb
import (
reflect "reflect"
@@ -409,7 +409,7 @@ func (x *ServiceLevelObjective) GetCalendarPeriod() calendarperiod.CalendarPerio
if x, ok := x.GetPeriod().(*ServiceLevelObjective_CalendarPeriod); ok {
return x.CalendarPeriod
}
- return calendarperiod.CalendarPeriod_CALENDAR_PERIOD_UNSPECIFIED
+ return calendarperiod.CalendarPeriod(0)
}
func (x *ServiceLevelObjective) GetUserLabels() map[string]string {
@@ -2071,21 +2071,21 @@ var file_google_monitoring_v3_service_proto_rawDesc = []byte{
0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e,
0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65,
0x52, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x12, 0x0a, 0x10, 0x77, 0x69, 0x6e, 0x64, 0x6f,
- 0x77, 0x5f, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x6f, 0x6e, 0x42, 0xce, 0x01, 0x0a, 0x18,
+ 0x77, 0x5f, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x6f, 0x6e, 0x42, 0xd1, 0x01, 0x0a, 0x18,
0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x16, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f,
- 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e,
- 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67,
- 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
- 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
- 0x6e, 0x67, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75,
- 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca,
- 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d,
- 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47,
- 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f,
- 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x33,
+ 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
+ 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43,
+ 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
+ 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75,
+ 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea,
+ 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a,
+ 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62,
+ 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/service_service.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/service_service.pb.go
similarity index 93%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/service_service.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/service_service.pb.go
index da1bce02fea..2d4f9fd3bb1 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/service_service.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/service_service.pb.go
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/service_service.proto
-package monitoring
+package monitoringpb
import (
context "context"
@@ -991,46 +991,46 @@ var file_google_monitoring_v3_service_service_proto_rawDesc = []byte{
0x76, 0x33, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x53,
- 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x3b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x22, 0x19,
- 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x2a, 0x2f, 0x2a, 0x7d,
- 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69,
- 0x63, 0x65, 0xda, 0x41, 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x73, 0x65, 0x72, 0x76,
- 0x69, 0x63, 0x65, 0x12, 0x7e, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x3b, 0xda, 0x41, 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e,
+ 0x74, 0x2c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x3a,
+ 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x19, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x70,
+ 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x2a, 0x2f, 0x2a, 0x7d, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69,
+ 0x63, 0x65, 0x73, 0x12, 0x7e, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x12, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
- 0x33, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02,
- 0x1b, 0x12, 0x19, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x2a, 0x2f, 0x2a,
- 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0xda, 0x41, 0x04, 0x6e,
- 0x61, 0x6d, 0x65, 0x12, 0x91, 0x01, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76,
+ 0x33, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x28, 0xda, 0x41, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e,
+ 0x61, 0x6d, 0x65, 0x3d, 0x2a, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
+ 0x2f, 0x2a, 0x7d, 0x12, 0x91, 0x01, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f,
0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69,
- 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4,
- 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
- 0x3d, 0x2a, 0x2f, 0x2a, 0x7d, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0xda, 0x41,
- 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x98, 0x01, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61,
+ 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0xda, 0x41, 0x06,
+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x76,
+ 0x33, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x2a, 0x2f, 0x2a, 0x7d, 0x2f, 0x73,
+ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x98, 0x01, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61,
0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d,
0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x72,
- 0x76, 0x69, 0x63, 0x65, 0x22, 0x3c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x32, 0x21, 0x2f, 0x76,
- 0x33, 0x2f, 0x7b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3d,
- 0x2a, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x3a,
- 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0xda, 0x41, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69,
- 0x63, 0x65, 0x12, 0x7d, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76,
+ 0x76, 0x69, 0x63, 0x65, 0x22, 0x3c, 0xda, 0x41, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+ 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x3a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x32,
+ 0x21, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x6e, 0x61,
+ 0x6d, 0x65, 0x3d, 0x2a, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f,
+ 0x2a, 0x7d, 0x12, 0x7d, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x12, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e,
0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
- 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x2a,
- 0x19, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x2a, 0x2f, 0x2a, 0x2f, 0x73,
- 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d,
- 0x65, 0x12, 0xfa, 0x01, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76,
+ 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x28, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+ 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x2a, 0x19, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d,
+ 0x65, 0x3d, 0x2a, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x2a,
+ 0x7d, 0x12, 0xfa, 0x01, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76,
0x65, 0x12, 0x38, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53,
@@ -1038,14 +1038,14 @@ var file_google_monitoring_v3_service_service_proto_rawDesc = []byte{
0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
0x76, 0x33, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f,
- 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x22, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4d,
- 0x22, 0x32, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x2a, 0x2f,
- 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x73, 0x65,
- 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
- 0x69, 0x76, 0x65, 0x73, 0x3a, 0x17, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x65,
- 0x76, 0x65, 0x6c, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0xda, 0x41, 0x1e,
- 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c,
- 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0xc1,
+ 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x22, 0x74, 0xda, 0x41, 0x1e, 0x70, 0x61, 0x72,
+ 0x65, 0x6e, 0x74, 0x2c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x65, 0x76, 0x65,
+ 0x6c, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02,
+ 0x4d, 0x3a, 0x17, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c,
+ 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x22, 0x32, 0x2f, 0x76, 0x33, 0x2f,
+ 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x2a, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76,
+ 0x69, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c,
+ 0x65, 0x76, 0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x73, 0x12, 0xc1,
0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76,
0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x35, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
@@ -1054,11 +1054,11 @@ var file_google_monitoring_v3_service_service_proto_rawDesc = []byte{
0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x22,
- 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61,
- 0x6d, 0x65, 0x3d, 0x2a, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f,
- 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f, 0x62,
- 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0xda, 0x41, 0x04, 0x6e, 0x61,
- 0x6d, 0x65, 0x12, 0xd4, 0x01, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69,
+ 0x41, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32,
+ 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x2a, 0x2f, 0x2a, 0x2f, 0x73, 0x65,
+ 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+ 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2f,
+ 0x2a, 0x7d, 0x12, 0xd4, 0x01, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65,
0x73, 0x12, 0x37, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72,
@@ -1067,11 +1067,11 @@ var file_google_monitoring_v3_service_service_proto_rawDesc = []byte{
0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76,
0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, 0x76,
- 0x33, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x2a, 0x2f, 0x2a, 0x2f, 0x73, 0x65,
- 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
- 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x73,
- 0xda, 0x41, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x8c, 0x02, 0x0a, 0x1b, 0x55, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x43, 0xda, 0x41, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x82,
+ 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65,
+ 0x6e, 0x74, 0x3d, 0x2a, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f,
+ 0x2a, 0x7d, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f,
+ 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x73, 0x12, 0x8c, 0x02, 0x0a, 0x1b, 0x55, 0x70,
0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c,
0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x38, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
@@ -1080,26 +1080,26 @@ var file_google_monitoring_v3_service_service_proto_rawDesc = []byte{
0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e,
0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65,
- 0x22, 0x85, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x65, 0x32, 0x4a, 0x2f, 0x76, 0x33, 0x2f, 0x7b,
- 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x6f, 0x62,
- 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x2a, 0x2f, 0x2a,
- 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76,
- 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76,
- 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x17, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c,
- 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0xda, 0x41,
- 0x17, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x6f,
- 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0xb2, 0x01, 0x0a, 0x1b, 0x44, 0x65, 0x6c,
+ 0x22, 0x85, 0x01, 0xda, 0x41, 0x17, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x65,
+ 0x76, 0x65, 0x6c, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x82, 0xd3, 0xe4,
+ 0x93, 0x02, 0x65, 0x3a, 0x17, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x65, 0x76,
+ 0x65, 0x6c, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x32, 0x4a, 0x2f, 0x76,
+ 0x33, 0x2f, 0x7b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c,
+ 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3d,
+ 0x2a, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x73,
+ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63,
+ 0x74, 0x69, 0x76, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xb2, 0x01, 0x0a, 0x1b, 0x44, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x38, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76,
0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x41, 0x82, 0xd3, 0xe4, 0x93,
- 0x02, 0x34, 0x2a, 0x32, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x2a, 0x2f,
- 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72,
- 0x76, 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69,
- 0x76, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x1a, 0xa9, 0x01,
+ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x41, 0xda, 0x41, 0x04, 0x6e,
+ 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x2a, 0x32, 0x2f, 0x76, 0x33, 0x2f, 0x7b,
+ 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x2a, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+ 0x73, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c,
+ 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x1a, 0xa9, 0x01,
0xca, 0x41, 0x19, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0xd2, 0x41, 0x89, 0x01,
0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
@@ -1110,21 +1110,21 @@ var file_google_monitoring_v3_service_service_proto_rawDesc = []byte{
0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a,
0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
- 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x42, 0xd5, 0x01, 0x0a, 0x18, 0x63, 0x6f,
+ 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x42, 0xd8, 0x01, 0x0a, 0x18, 0x63, 0x6f,
0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x1d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d,
0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
- 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
- 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x6d,
- 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x3b, 0x6d, 0x6f, 0x6e,
- 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
- 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
- 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c,
- 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56,
- 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75,
- 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56,
- 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32,
+ 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f,
+ 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
+ 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
+ 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43,
+ 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/snooze.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/snooze.pb.go
new file mode 100644
index 00000000000..c619aff1f94
--- /dev/null
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/snooze.pb.go
@@ -0,0 +1,315 @@
+// Copyright 2022 Google LLC
+//
+// 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 protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
+// source: google/monitoring/v3/snooze.proto
+
+package monitoringpb
+
+import (
+ reflect "reflect"
+ sync "sync"
+
+ _ "google.golang.org/genproto/googleapis/api/annotations"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// A `Snooze` will prevent any alerts from being opened, and close any that
+// are already open. The `Snooze` will work on alerts that match the
+// criteria defined in the `Snooze`. The `Snooze` will be active from
+// `interval.start_time` through `interval.end_time`.
+type Snooze struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the `Snooze`. The format is:
+ //
+ // projects/[PROJECT_ID_OR_NUMBER]/snoozes/[SNOOZE_ID]
+ //
+ // The ID of the `Snooze` will be generated by the system.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Required. This defines the criteria for applying the `Snooze`. See
+ // `Criteria` for more information.
+ Criteria *Snooze_Criteria `protobuf:"bytes,3,opt,name=criteria,proto3" json:"criteria,omitempty"`
+ // Required. The `Snooze` will be active from `interval.start_time` through
+ // `interval.end_time`.
+ // `interval.start_time` cannot be in the past. There is a 15 second clock
+ // skew to account for the time it takes for a request to reach the API from
+ // the UI.
+ Interval *TimeInterval `protobuf:"bytes,4,opt,name=interval,proto3" json:"interval,omitempty"`
+ // Required. A display name for the `Snooze`. This can be, at most, 512
+ // unicode characters.
+ DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
+}
+
+func (x *Snooze) Reset() {
+ *x = Snooze{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_snooze_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Snooze) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Snooze) ProtoMessage() {}
+
+func (x *Snooze) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_snooze_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Snooze.ProtoReflect.Descriptor instead.
+func (*Snooze) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_snooze_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Snooze) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *Snooze) GetCriteria() *Snooze_Criteria {
+ if x != nil {
+ return x.Criteria
+ }
+ return nil
+}
+
+func (x *Snooze) GetInterval() *TimeInterval {
+ if x != nil {
+ return x.Interval
+ }
+ return nil
+}
+
+func (x *Snooze) GetDisplayName() string {
+ if x != nil {
+ return x.DisplayName
+ }
+ return ""
+}
+
+// Criteria specific to the `AlertPolicy`s that this `Snooze` applies to. The
+// `Snooze` will suppress alerts that come from one of the `AlertPolicy`s
+// whose names are supplied.
+type Snooze_Criteria struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The specific `AlertPolicy` names for the alert that should be snoozed.
+ // The format is:
+ //
+ // projects/[PROJECT_ID_OR_NUMBER]/alertPolicies/[POLICY_ID]
+ //
+ // There is a limit of 10 policies per snooze. This limit is checked during
+ // snooze creation.
+ Policies []string `protobuf:"bytes,1,rep,name=policies,proto3" json:"policies,omitempty"`
+}
+
+func (x *Snooze_Criteria) Reset() {
+ *x = Snooze_Criteria{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_snooze_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Snooze_Criteria) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Snooze_Criteria) ProtoMessage() {}
+
+func (x *Snooze_Criteria) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_snooze_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Snooze_Criteria.ProtoReflect.Descriptor instead.
+func (*Snooze_Criteria) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_snooze_proto_rawDescGZIP(), []int{0, 0}
+}
+
+func (x *Snooze_Criteria) GetPolicies() []string {
+ if x != nil {
+ return x.Policies
+ }
+ return nil
+}
+
+var File_google_monitoring_v3_snooze_proto protoreflect.FileDescriptor
+
+var file_google_monitoring_v3_snooze_proto_rawDesc = []byte{
+ 0x0a, 0x21, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61,
+ 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x6d, 0x6f,
+ 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
+ 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf6, 0x02, 0x0a, 0x06, 0x53, 0x6e, 0x6f,
+ 0x6f, 0x7a, 0x65, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x08,
+ 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
+ 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x2e, 0x43, 0x72, 0x69,
+ 0x74, 0x65, 0x72, 0x69, 0x61, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x08, 0x63, 0x72, 0x69, 0x74,
+ 0x65, 0x72, 0x69, 0x61, 0x12, 0x43, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x54, 0x69,
+ 0x6d, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52,
+ 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x26, 0x0a, 0x0c, 0x64, 0x69, 0x73,
+ 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42,
+ 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d,
+ 0x65, 0x1a, 0x52, 0x0a, 0x08, 0x43, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x12, 0x46, 0x0a,
+ 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42,
+ 0x2a, 0xfa, 0x41, 0x27, 0x0a, 0x25, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x41, 0x6c, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c,
+ 0x69, 0x63, 0x69, 0x65, 0x73, 0x3a, 0x4a, 0xea, 0x41, 0x47, 0x0a, 0x20, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69,
+ 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x12, 0x23, 0x70, 0x72,
+ 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d,
+ 0x2f, 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65,
+ 0x7d, 0x42, 0xc6, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x0b,
+ 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63,
+ 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70,
+ 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
+ 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62,
+ 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e,
+ 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a,
+ 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x33,
+}
+
+var (
+ file_google_monitoring_v3_snooze_proto_rawDescOnce sync.Once
+ file_google_monitoring_v3_snooze_proto_rawDescData = file_google_monitoring_v3_snooze_proto_rawDesc
+)
+
+func file_google_monitoring_v3_snooze_proto_rawDescGZIP() []byte {
+ file_google_monitoring_v3_snooze_proto_rawDescOnce.Do(func() {
+ file_google_monitoring_v3_snooze_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_monitoring_v3_snooze_proto_rawDescData)
+ })
+ return file_google_monitoring_v3_snooze_proto_rawDescData
+}
+
+var file_google_monitoring_v3_snooze_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_google_monitoring_v3_snooze_proto_goTypes = []interface{}{
+ (*Snooze)(nil), // 0: google.monitoring.v3.Snooze
+ (*Snooze_Criteria)(nil), // 1: google.monitoring.v3.Snooze.Criteria
+ (*TimeInterval)(nil), // 2: google.monitoring.v3.TimeInterval
+}
+var file_google_monitoring_v3_snooze_proto_depIdxs = []int32{
+ 1, // 0: google.monitoring.v3.Snooze.criteria:type_name -> google.monitoring.v3.Snooze.Criteria
+ 2, // 1: google.monitoring.v3.Snooze.interval:type_name -> google.monitoring.v3.TimeInterval
+ 2, // [2:2] is the sub-list for method output_type
+ 2, // [2:2] is the sub-list for method input_type
+ 2, // [2:2] is the sub-list for extension type_name
+ 2, // [2:2] is the sub-list for extension extendee
+ 0, // [0:2] is the sub-list for field type_name
+}
+
+func init() { file_google_monitoring_v3_snooze_proto_init() }
+func file_google_monitoring_v3_snooze_proto_init() {
+ if File_google_monitoring_v3_snooze_proto != nil {
+ return
+ }
+ file_google_monitoring_v3_common_proto_init()
+ if !protoimpl.UnsafeEnabled {
+ file_google_monitoring_v3_snooze_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Snooze); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_snooze_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Snooze_Criteria); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_google_monitoring_v3_snooze_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_google_monitoring_v3_snooze_proto_goTypes,
+ DependencyIndexes: file_google_monitoring_v3_snooze_proto_depIdxs,
+ MessageInfos: file_google_monitoring_v3_snooze_proto_msgTypes,
+ }.Build()
+ File_google_monitoring_v3_snooze_proto = out.File
+ file_google_monitoring_v3_snooze_proto_rawDesc = nil
+ file_google_monitoring_v3_snooze_proto_goTypes = nil
+ file_google_monitoring_v3_snooze_proto_depIdxs = nil
+}
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/snooze_service.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/snooze_service.pb.go
new file mode 100644
index 00000000000..9637989da12
--- /dev/null
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/snooze_service.pb.go
@@ -0,0 +1,867 @@
+// Copyright 2022 Google LLC
+//
+// 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 protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
+// source: google/monitoring/v3/snooze_service.proto
+
+package monitoringpb
+
+import (
+ context "context"
+ reflect "reflect"
+ sync "sync"
+
+ _ "google.golang.org/genproto/googleapis/api/annotations"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// The message definition for creating a `Snooze`. Users must provide the body
+// of the `Snooze` to be created but must omit the `Snooze` field, `name`.
+type CreateSnoozeRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The
+ // [project](https://cloud.google.com/monitoring/api/v3#project_name) in which
+ // a `Snooze` should be created. The format is:
+ //
+ // projects/[PROJECT_ID_OR_NUMBER]
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // Required. The `Snooze` to create. Omit the `name` field, as it will be
+ // filled in by the API.
+ Snooze *Snooze `protobuf:"bytes,2,opt,name=snooze,proto3" json:"snooze,omitempty"`
+}
+
+func (x *CreateSnoozeRequest) Reset() {
+ *x = CreateSnoozeRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_snooze_service_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CreateSnoozeRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateSnoozeRequest) ProtoMessage() {}
+
+func (x *CreateSnoozeRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_snooze_service_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreateSnoozeRequest.ProtoReflect.Descriptor instead.
+func (*CreateSnoozeRequest) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_snooze_service_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *CreateSnoozeRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *CreateSnoozeRequest) GetSnooze() *Snooze {
+ if x != nil {
+ return x.Snooze
+ }
+ return nil
+}
+
+// The message definition for listing `Snooze`s associated with the given
+// `parent`, satisfying the optional `filter`.
+type ListSnoozesRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The
+ // [project](https://cloud.google.com/monitoring/api/v3#project_name) whose
+ // `Snooze`s should be listed. The format is:
+ //
+ // projects/[PROJECT_ID_OR_NUMBER]
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // Optional. Optional filter to restrict results to the given criteria. The
+ // following fields are supported.
+ //
+ // * `interval.start_time`
+ // * `interval.end_time`
+ //
+ // For example:
+ //
+ // ```
+ // interval.start_time > "2022-03-11T00:00:00-08:00" AND
+ // interval.end_time < "2022-03-12T00:00:00-08:00"
+ // ```
+ Filter string `protobuf:"bytes,2,opt,name=filter,proto3" json:"filter,omitempty"`
+ // Optional. The maximum number of results to return for a single query. The
+ // server may further constrain the maximum number of results returned in a
+ // single page. The value should be in the range [1, 1000]. If the value given
+ // is outside this range, the server will decide the number of results to be
+ // returned.
+ PageSize int32 `protobuf:"varint,4,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ // Optional. The `next_page_token` from a previous call to
+ // `ListSnoozesRequest` to get the next page of results.
+ PageToken string `protobuf:"bytes,5,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
+}
+
+func (x *ListSnoozesRequest) Reset() {
+ *x = ListSnoozesRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_snooze_service_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListSnoozesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListSnoozesRequest) ProtoMessage() {}
+
+func (x *ListSnoozesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_snooze_service_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListSnoozesRequest.ProtoReflect.Descriptor instead.
+func (*ListSnoozesRequest) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_snooze_service_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ListSnoozesRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *ListSnoozesRequest) GetFilter() string {
+ if x != nil {
+ return x.Filter
+ }
+ return ""
+}
+
+func (x *ListSnoozesRequest) GetPageSize() int32 {
+ if x != nil {
+ return x.PageSize
+ }
+ return 0
+}
+
+func (x *ListSnoozesRequest) GetPageToken() string {
+ if x != nil {
+ return x.PageToken
+ }
+ return ""
+}
+
+// The results of a successful `ListSnoozes` call, containing the matching
+// `Snooze`s.
+type ListSnoozesResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // `Snooze`s matching this list call.
+ Snoozes []*Snooze `protobuf:"bytes,1,rep,name=snoozes,proto3" json:"snoozes,omitempty"`
+ // Page token for repeated calls to `ListSnoozes`, to fetch additional pages
+ // of results. If this is empty or missing, there are no more pages.
+ NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
+}
+
+func (x *ListSnoozesResponse) Reset() {
+ *x = ListSnoozesResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_snooze_service_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListSnoozesResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListSnoozesResponse) ProtoMessage() {}
+
+func (x *ListSnoozesResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_snooze_service_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListSnoozesResponse.ProtoReflect.Descriptor instead.
+func (*ListSnoozesResponse) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_snooze_service_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ListSnoozesResponse) GetSnoozes() []*Snooze {
+ if x != nil {
+ return x.Snoozes
+ }
+ return nil
+}
+
+func (x *ListSnoozesResponse) GetNextPageToken() string {
+ if x != nil {
+ return x.NextPageToken
+ }
+ return ""
+}
+
+// The message definition for retrieving a `Snooze`. Users must specify the
+// field, `name`, which identifies the `Snooze`.
+type GetSnoozeRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The ID of the `Snooze` to retrieve. The format is:
+ //
+ // projects/[PROJECT_ID_OR_NUMBER]/snoozes/[SNOOZE_ID]
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *GetSnoozeRequest) Reset() {
+ *x = GetSnoozeRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_snooze_service_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetSnoozeRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetSnoozeRequest) ProtoMessage() {}
+
+func (x *GetSnoozeRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_snooze_service_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetSnoozeRequest.ProtoReflect.Descriptor instead.
+func (*GetSnoozeRequest) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_snooze_service_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *GetSnoozeRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+// The message definition for updating a `Snooze`. The field, `snooze.name`
+// identifies the `Snooze` to be updated. The remainder of `snooze` gives the
+// content the `Snooze` in question will be assigned.
+//
+// What fields can be updated depends on the start time and end time of the
+// `Snooze`.
+//
+// - end time is in the past: These `Snooze`s are considered
+// read-only and cannot be updated.
+// - start time is in the past and end time is in the future: `display_name`
+// and `interval.end_time` can be updated.
+// - start time is in the future: `display_name`, `interval.start_time` and
+// `interval.end_time` can be updated.
+type UpdateSnoozeRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The `Snooze` to update. Must have the name field present.
+ Snooze *Snooze `protobuf:"bytes,1,opt,name=snooze,proto3" json:"snooze,omitempty"`
+ // Required. The fields to update.
+ //
+ // For each field listed in `update_mask`:
+ //
+ // * If the `Snooze` object supplied in the `UpdateSnoozeRequest` has a
+ // value for that field, the value of the field in the existing `Snooze`
+ // will be set to the value of the field in the supplied `Snooze`.
+ // * If the field does not have a value in the supplied `Snooze`, the field
+ // in the existing `Snooze` is set to its default value.
+ //
+ // Fields not listed retain their existing value.
+ //
+ // The following are the field names that are accepted in `update_mask`:
+ //
+ // * `display_name`
+ // * `interval.start_time`
+ // * `interval.end_time`
+ //
+ // That said, the start time and end time of the `Snooze` determines which
+ // fields can legally be updated. Before attempting an update, users should
+ // consult the documentation for `UpdateSnoozeRequest`, which talks about
+ // which fields can be updated.
+ UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"`
+}
+
+func (x *UpdateSnoozeRequest) Reset() {
+ *x = UpdateSnoozeRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_snooze_service_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UpdateSnoozeRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateSnoozeRequest) ProtoMessage() {}
+
+func (x *UpdateSnoozeRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_snooze_service_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateSnoozeRequest.ProtoReflect.Descriptor instead.
+func (*UpdateSnoozeRequest) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_snooze_service_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *UpdateSnoozeRequest) GetSnooze() *Snooze {
+ if x != nil {
+ return x.Snooze
+ }
+ return nil
+}
+
+func (x *UpdateSnoozeRequest) GetUpdateMask() *fieldmaskpb.FieldMask {
+ if x != nil {
+ return x.UpdateMask
+ }
+ return nil
+}
+
+var File_google_monitoring_v3_snooze_service_proto protoreflect.FileDescriptor
+
+var file_google_monitoring_v3_snooze_service_proto_rawDesc = []byte{
+ 0x0a, 0x29, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x5f, 0x73, 0x65,
+ 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
+ 0x33, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e,
+ 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
+ 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6c, 0x69, 0x65,
+ 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76,
+ 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x73, 0x6e, 0x6f, 0x6f, 0x7a,
+ 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d,
+ 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x92, 0x01, 0x0a, 0x13, 0x43, 0x72,
+ 0x65, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x40, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x42, 0x28, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x22, 0x12, 0x20, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72,
+ 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x06, 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x6e, 0x6f, 0x6f, 0x7a,
+ 0x65, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x22, 0xb9,
+ 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x73, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x28, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x22, 0x12, 0x20, 0x6d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x52,
+ 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65,
+ 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x06, 0x66, 0x69,
+ 0x6c, 0x74, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a,
+ 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x08, 0x70, 0x61,
+ 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74,
+ 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52,
+ 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x75, 0x0a, 0x13, 0x4c, 0x69,
+ 0x73, 0x74, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x36, 0x0a, 0x07, 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65,
+ 0x52, 0x07, 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78,
+ 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65,
+ 0x6e, 0x22, 0x50, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x42, 0x28, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x22, 0x0a, 0x20, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
+ 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x52, 0x04, 0x6e,
+ 0x61, 0x6d, 0x65, 0x22, 0x92, 0x01, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x6e,
+ 0x6f, 0x6f, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x06, 0x73,
+ 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
+ 0x76, 0x33, 0x2e, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06,
+ 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
+ 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69,
+ 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0a, 0x75, 0x70,
+ 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x32, 0x98, 0x06, 0x0a, 0x0d, 0x53, 0x6e, 0x6f,
+ 0x6f, 0x7a, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x98, 0x01, 0x0a, 0x0c, 0x43,
+ 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x12, 0x29, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
+ 0x76, 0x33, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x6e,
+ 0x6f, 0x6f, 0x7a, 0x65, 0x22, 0x3f, 0xda, 0x41, 0x0d, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2c,
+ 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x3a, 0x06, 0x73, 0x6e,
+ 0x6f, 0x6f, 0x7a, 0x65, 0x22, 0x1f, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e,
+ 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x73, 0x6e,
+ 0x6f, 0x6f, 0x7a, 0x65, 0x73, 0x12, 0x94, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e,
+ 0x6f, 0x6f, 0x7a, 0x65, 0x73, 0x12, 0x28, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73,
+ 0x74, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+ 0x29, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x6f, 0x6f, 0x7a,
+ 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0xda, 0x41, 0x06, 0x70,
+ 0x61, 0x72, 0x65, 0x6e, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x12, 0x1f, 0x2f, 0x76, 0x33,
+ 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+ 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x73, 0x12, 0x81, 0x01, 0x0a,
+ 0x09, 0x47, 0x65, 0x74, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x12, 0x26, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
+ 0x33, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65,
+ 0x22, 0x2e, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x12,
+ 0x1f, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65,
+ 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x73, 0x2f, 0x2a, 0x7d,
+ 0x12, 0xa4, 0x01, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x6f, 0x6f, 0x7a,
+ 0x65, 0x12, 0x29, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53,
+ 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x22, 0x4b, 0xda, 0x41, 0x12, 0x73,
+ 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x2c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73,
+ 0x6b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x30, 0x3a, 0x06, 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x32,
+ 0x26, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x73, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x2e, 0x6e, 0x61, 0x6d,
+ 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x73, 0x6e, 0x6f,
+ 0x6f, 0x7a, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x1a, 0xa9, 0x01, 0xca, 0x41, 0x19, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
+ 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0xd2, 0x41, 0x89, 0x01, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a,
+ 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d,
+ 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f,
+ 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61,
+ 0x75, 0x74, 0x68, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x72,
+ 0x65, 0x61, 0x64, 0x42, 0xcd, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
+ 0x42, 0x12, 0x53, 0x6e, 0x6f, 0x6f, 0x7a, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50,
+ 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f,
+ 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c,
+ 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c,
+ 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a,
+ 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_google_monitoring_v3_snooze_service_proto_rawDescOnce sync.Once
+ file_google_monitoring_v3_snooze_service_proto_rawDescData = file_google_monitoring_v3_snooze_service_proto_rawDesc
+)
+
+func file_google_monitoring_v3_snooze_service_proto_rawDescGZIP() []byte {
+ file_google_monitoring_v3_snooze_service_proto_rawDescOnce.Do(func() {
+ file_google_monitoring_v3_snooze_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_monitoring_v3_snooze_service_proto_rawDescData)
+ })
+ return file_google_monitoring_v3_snooze_service_proto_rawDescData
+}
+
+var file_google_monitoring_v3_snooze_service_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
+var file_google_monitoring_v3_snooze_service_proto_goTypes = []interface{}{
+ (*CreateSnoozeRequest)(nil), // 0: google.monitoring.v3.CreateSnoozeRequest
+ (*ListSnoozesRequest)(nil), // 1: google.monitoring.v3.ListSnoozesRequest
+ (*ListSnoozesResponse)(nil), // 2: google.monitoring.v3.ListSnoozesResponse
+ (*GetSnoozeRequest)(nil), // 3: google.monitoring.v3.GetSnoozeRequest
+ (*UpdateSnoozeRequest)(nil), // 4: google.monitoring.v3.UpdateSnoozeRequest
+ (*Snooze)(nil), // 5: google.monitoring.v3.Snooze
+ (*fieldmaskpb.FieldMask)(nil), // 6: google.protobuf.FieldMask
+}
+var file_google_monitoring_v3_snooze_service_proto_depIdxs = []int32{
+ 5, // 0: google.monitoring.v3.CreateSnoozeRequest.snooze:type_name -> google.monitoring.v3.Snooze
+ 5, // 1: google.monitoring.v3.ListSnoozesResponse.snoozes:type_name -> google.monitoring.v3.Snooze
+ 5, // 2: google.monitoring.v3.UpdateSnoozeRequest.snooze:type_name -> google.monitoring.v3.Snooze
+ 6, // 3: google.monitoring.v3.UpdateSnoozeRequest.update_mask:type_name -> google.protobuf.FieldMask
+ 0, // 4: google.monitoring.v3.SnoozeService.CreateSnooze:input_type -> google.monitoring.v3.CreateSnoozeRequest
+ 1, // 5: google.monitoring.v3.SnoozeService.ListSnoozes:input_type -> google.monitoring.v3.ListSnoozesRequest
+ 3, // 6: google.monitoring.v3.SnoozeService.GetSnooze:input_type -> google.monitoring.v3.GetSnoozeRequest
+ 4, // 7: google.monitoring.v3.SnoozeService.UpdateSnooze:input_type -> google.monitoring.v3.UpdateSnoozeRequest
+ 5, // 8: google.monitoring.v3.SnoozeService.CreateSnooze:output_type -> google.monitoring.v3.Snooze
+ 2, // 9: google.monitoring.v3.SnoozeService.ListSnoozes:output_type -> google.monitoring.v3.ListSnoozesResponse
+ 5, // 10: google.monitoring.v3.SnoozeService.GetSnooze:output_type -> google.monitoring.v3.Snooze
+ 5, // 11: google.monitoring.v3.SnoozeService.UpdateSnooze:output_type -> google.monitoring.v3.Snooze
+ 8, // [8:12] is the sub-list for method output_type
+ 4, // [4:8] is the sub-list for method input_type
+ 4, // [4:4] is the sub-list for extension type_name
+ 4, // [4:4] is the sub-list for extension extendee
+ 0, // [0:4] is the sub-list for field type_name
+}
+
+func init() { file_google_monitoring_v3_snooze_service_proto_init() }
+func file_google_monitoring_v3_snooze_service_proto_init() {
+ if File_google_monitoring_v3_snooze_service_proto != nil {
+ return
+ }
+ file_google_monitoring_v3_snooze_proto_init()
+ if !protoimpl.UnsafeEnabled {
+ file_google_monitoring_v3_snooze_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CreateSnoozeRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_snooze_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListSnoozesRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_snooze_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListSnoozesResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_snooze_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetSnoozeRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_snooze_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UpdateSnoozeRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_google_monitoring_v3_snooze_service_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 5,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_google_monitoring_v3_snooze_service_proto_goTypes,
+ DependencyIndexes: file_google_monitoring_v3_snooze_service_proto_depIdxs,
+ MessageInfos: file_google_monitoring_v3_snooze_service_proto_msgTypes,
+ }.Build()
+ File_google_monitoring_v3_snooze_service_proto = out.File
+ file_google_monitoring_v3_snooze_service_proto_rawDesc = nil
+ file_google_monitoring_v3_snooze_service_proto_goTypes = nil
+ file_google_monitoring_v3_snooze_service_proto_depIdxs = nil
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConnInterface
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion6
+
+// SnoozeServiceClient is the client API for SnoozeService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type SnoozeServiceClient interface {
+ // Creates a `Snooze` that will prevent alerts, which match the provided
+ // criteria, from being opened. The `Snooze` applies for a specific time
+ // interval.
+ CreateSnooze(ctx context.Context, in *CreateSnoozeRequest, opts ...grpc.CallOption) (*Snooze, error)
+ // Lists the `Snooze`s associated with a project. Can optionally pass in
+ // `filter`, which specifies predicates to match `Snooze`s.
+ ListSnoozes(ctx context.Context, in *ListSnoozesRequest, opts ...grpc.CallOption) (*ListSnoozesResponse, error)
+ // Retrieves a `Snooze` by `name`.
+ GetSnooze(ctx context.Context, in *GetSnoozeRequest, opts ...grpc.CallOption) (*Snooze, error)
+ // Updates a `Snooze`, identified by its `name`, with the parameters in the
+ // given `Snooze` object.
+ UpdateSnooze(ctx context.Context, in *UpdateSnoozeRequest, opts ...grpc.CallOption) (*Snooze, error)
+}
+
+type snoozeServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewSnoozeServiceClient(cc grpc.ClientConnInterface) SnoozeServiceClient {
+ return &snoozeServiceClient{cc}
+}
+
+func (c *snoozeServiceClient) CreateSnooze(ctx context.Context, in *CreateSnoozeRequest, opts ...grpc.CallOption) (*Snooze, error) {
+ out := new(Snooze)
+ err := c.cc.Invoke(ctx, "/google.monitoring.v3.SnoozeService/CreateSnooze", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *snoozeServiceClient) ListSnoozes(ctx context.Context, in *ListSnoozesRequest, opts ...grpc.CallOption) (*ListSnoozesResponse, error) {
+ out := new(ListSnoozesResponse)
+ err := c.cc.Invoke(ctx, "/google.monitoring.v3.SnoozeService/ListSnoozes", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *snoozeServiceClient) GetSnooze(ctx context.Context, in *GetSnoozeRequest, opts ...grpc.CallOption) (*Snooze, error) {
+ out := new(Snooze)
+ err := c.cc.Invoke(ctx, "/google.monitoring.v3.SnoozeService/GetSnooze", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *snoozeServiceClient) UpdateSnooze(ctx context.Context, in *UpdateSnoozeRequest, opts ...grpc.CallOption) (*Snooze, error) {
+ out := new(Snooze)
+ err := c.cc.Invoke(ctx, "/google.monitoring.v3.SnoozeService/UpdateSnooze", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// SnoozeServiceServer is the server API for SnoozeService service.
+type SnoozeServiceServer interface {
+ // Creates a `Snooze` that will prevent alerts, which match the provided
+ // criteria, from being opened. The `Snooze` applies for a specific time
+ // interval.
+ CreateSnooze(context.Context, *CreateSnoozeRequest) (*Snooze, error)
+ // Lists the `Snooze`s associated with a project. Can optionally pass in
+ // `filter`, which specifies predicates to match `Snooze`s.
+ ListSnoozes(context.Context, *ListSnoozesRequest) (*ListSnoozesResponse, error)
+ // Retrieves a `Snooze` by `name`.
+ GetSnooze(context.Context, *GetSnoozeRequest) (*Snooze, error)
+ // Updates a `Snooze`, identified by its `name`, with the parameters in the
+ // given `Snooze` object.
+ UpdateSnooze(context.Context, *UpdateSnoozeRequest) (*Snooze, error)
+}
+
+// UnimplementedSnoozeServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedSnoozeServiceServer struct {
+}
+
+func (*UnimplementedSnoozeServiceServer) CreateSnooze(context.Context, *CreateSnoozeRequest) (*Snooze, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method CreateSnooze not implemented")
+}
+func (*UnimplementedSnoozeServiceServer) ListSnoozes(context.Context, *ListSnoozesRequest) (*ListSnoozesResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method ListSnoozes not implemented")
+}
+func (*UnimplementedSnoozeServiceServer) GetSnooze(context.Context, *GetSnoozeRequest) (*Snooze, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetSnooze not implemented")
+}
+func (*UnimplementedSnoozeServiceServer) UpdateSnooze(context.Context, *UpdateSnoozeRequest) (*Snooze, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method UpdateSnooze not implemented")
+}
+
+func RegisterSnoozeServiceServer(s *grpc.Server, srv SnoozeServiceServer) {
+ s.RegisterService(&_SnoozeService_serviceDesc, srv)
+}
+
+func _SnoozeService_CreateSnooze_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(CreateSnoozeRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(SnoozeServiceServer).CreateSnooze(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/google.monitoring.v3.SnoozeService/CreateSnooze",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(SnoozeServiceServer).CreateSnooze(ctx, req.(*CreateSnoozeRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _SnoozeService_ListSnoozes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ListSnoozesRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(SnoozeServiceServer).ListSnoozes(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/google.monitoring.v3.SnoozeService/ListSnoozes",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(SnoozeServiceServer).ListSnoozes(ctx, req.(*ListSnoozesRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _SnoozeService_GetSnooze_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetSnoozeRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(SnoozeServiceServer).GetSnooze(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/google.monitoring.v3.SnoozeService/GetSnooze",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(SnoozeServiceServer).GetSnooze(ctx, req.(*GetSnoozeRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _SnoozeService_UpdateSnooze_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UpdateSnoozeRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(SnoozeServiceServer).UpdateSnooze(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/google.monitoring.v3.SnoozeService/UpdateSnooze",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(SnoozeServiceServer).UpdateSnooze(ctx, req.(*UpdateSnoozeRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+var _SnoozeService_serviceDesc = grpc.ServiceDesc{
+ ServiceName: "google.monitoring.v3.SnoozeService",
+ HandlerType: (*SnoozeServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "CreateSnooze",
+ Handler: _SnoozeService_CreateSnooze_Handler,
+ },
+ {
+ MethodName: "ListSnoozes",
+ Handler: _SnoozeService_ListSnoozes_Handler,
+ },
+ {
+ MethodName: "GetSnooze",
+ Handler: _SnoozeService_GetSnooze_Handler,
+ },
+ {
+ MethodName: "UpdateSnooze",
+ Handler: _SnoozeService_UpdateSnooze_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "google/monitoring/v3/snooze_service.proto",
+}
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/span_context.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/span_context.pb.go
similarity index 84%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/span_context.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/span_context.pb.go
index 762ff15ee06..42e60c86de6 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/span_context.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/span_context.pb.go
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/span_context.proto
-package monitoring
+package monitoringpb
import (
reflect "reflect"
@@ -41,7 +41,7 @@ const (
//
// It contains the name of a span with format:
//
-// projects/[PROJECT_ID_OR_NUMBER]/traces/[TRACE_ID]/spans/[SPAN_ID]
+// projects/[PROJECT_ID_OR_NUMBER]/traces/[TRACE_ID]/spans/[SPAN_ID]
type SpanContext struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -107,20 +107,21 @@ var file_google_monitoring_v3_span_context_proto_rawDesc = []byte{
0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x22,
0x2a, 0x0a, 0x0b, 0x53, 0x70, 0x61, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1b,
0x0a, 0x09, 0x73, 0x70, 0x61, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x08, 0x73, 0x70, 0x61, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x42, 0xc8, 0x01, 0x0a, 0x18,
+ 0x09, 0x52, 0x08, 0x73, 0x70, 0x61, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x42, 0xcb, 0x01, 0x0a, 0x18,
0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x10, 0x53, 0x70, 0x61, 0x6e, 0x43, 0x6f,
- 0x6e, 0x74, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x6f,
- 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f,
- 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61,
- 0x70, 0x69, 0x73, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76,
- 0x33, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x1a, 0x47,
- 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69,
- 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67,
- 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
- 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a,
- 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
- 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x6e, 0x74, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c,
+ 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67,
+ 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69,
+ 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa,
+ 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x33,
}
var (
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/uptime.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/uptime.pb.go
new file mode 100644
index 00000000000..ad3cc26e1d8
--- /dev/null
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/uptime.pb.go
@@ -0,0 +1,2320 @@
+// Copyright 2023 Google LLC
+//
+// 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 protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
+// source: google/monitoring/v3/uptime.proto
+
+package monitoringpb
+
+import (
+ reflect "reflect"
+ sync "sync"
+
+ _ "google.golang.org/genproto/googleapis/api/annotations"
+ monitoredres "google.golang.org/genproto/googleapis/api/monitoredres"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ durationpb "google.golang.org/protobuf/types/known/durationpb"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// The regions from which an Uptime check can be run.
+type UptimeCheckRegion int32
+
+const (
+ // Default value if no region is specified. Will result in Uptime checks
+ // running from all regions.
+ UptimeCheckRegion_REGION_UNSPECIFIED UptimeCheckRegion = 0
+ // Allows checks to run from locations within the United States of America.
+ UptimeCheckRegion_USA UptimeCheckRegion = 1
+ // Allows checks to run from locations within the continent of Europe.
+ UptimeCheckRegion_EUROPE UptimeCheckRegion = 2
+ // Allows checks to run from locations within the continent of South
+ // America.
+ UptimeCheckRegion_SOUTH_AMERICA UptimeCheckRegion = 3
+ // Allows checks to run from locations within the Asia Pacific area (ex:
+ // Singapore).
+ UptimeCheckRegion_ASIA_PACIFIC UptimeCheckRegion = 4
+ // Allows checks to run from locations within the western United States of
+ // America
+ UptimeCheckRegion_USA_OREGON UptimeCheckRegion = 5
+ // Allows checks to run from locations within the central United States of
+ // America
+ UptimeCheckRegion_USA_IOWA UptimeCheckRegion = 6
+ // Allows checks to run from locations within the eastern United States of
+ // America
+ UptimeCheckRegion_USA_VIRGINIA UptimeCheckRegion = 7
+)
+
+// Enum value maps for UptimeCheckRegion.
+var (
+ UptimeCheckRegion_name = map[int32]string{
+ 0: "REGION_UNSPECIFIED",
+ 1: "USA",
+ 2: "EUROPE",
+ 3: "SOUTH_AMERICA",
+ 4: "ASIA_PACIFIC",
+ 5: "USA_OREGON",
+ 6: "USA_IOWA",
+ 7: "USA_VIRGINIA",
+ }
+ UptimeCheckRegion_value = map[string]int32{
+ "REGION_UNSPECIFIED": 0,
+ "USA": 1,
+ "EUROPE": 2,
+ "SOUTH_AMERICA": 3,
+ "ASIA_PACIFIC": 4,
+ "USA_OREGON": 5,
+ "USA_IOWA": 6,
+ "USA_VIRGINIA": 7,
+ }
+)
+
+func (x UptimeCheckRegion) Enum() *UptimeCheckRegion {
+ p := new(UptimeCheckRegion)
+ *p = x
+ return p
+}
+
+func (x UptimeCheckRegion) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (UptimeCheckRegion) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_uptime_proto_enumTypes[0].Descriptor()
+}
+
+func (UptimeCheckRegion) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_uptime_proto_enumTypes[0]
+}
+
+func (x UptimeCheckRegion) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use UptimeCheckRegion.Descriptor instead.
+func (UptimeCheckRegion) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{0}
+}
+
+// The supported resource types that can be used as values of
+// `group_resource.resource_type`.
+// `INSTANCE` includes `gce_instance` and `aws_ec2_instance` resource types.
+// The resource types `gae_app` and `uptime_url` are not valid here because
+// group checks on App Engine modules and URLs are not allowed.
+type GroupResourceType int32
+
+const (
+ // Default value (not valid).
+ GroupResourceType_RESOURCE_TYPE_UNSPECIFIED GroupResourceType = 0
+ // A group of instances from Google Cloud Platform (GCP) or
+ // Amazon Web Services (AWS).
+ GroupResourceType_INSTANCE GroupResourceType = 1
+ // A group of Amazon ELB load balancers.
+ GroupResourceType_AWS_ELB_LOAD_BALANCER GroupResourceType = 2
+)
+
+// Enum value maps for GroupResourceType.
+var (
+ GroupResourceType_name = map[int32]string{
+ 0: "RESOURCE_TYPE_UNSPECIFIED",
+ 1: "INSTANCE",
+ 2: "AWS_ELB_LOAD_BALANCER",
+ }
+ GroupResourceType_value = map[string]int32{
+ "RESOURCE_TYPE_UNSPECIFIED": 0,
+ "INSTANCE": 1,
+ "AWS_ELB_LOAD_BALANCER": 2,
+ }
+)
+
+func (x GroupResourceType) Enum() *GroupResourceType {
+ p := new(GroupResourceType)
+ *p = x
+ return p
+}
+
+func (x GroupResourceType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (GroupResourceType) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_uptime_proto_enumTypes[1].Descriptor()
+}
+
+func (GroupResourceType) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_uptime_proto_enumTypes[1]
+}
+
+func (x GroupResourceType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use GroupResourceType.Descriptor instead.
+func (GroupResourceType) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1}
+}
+
+// Operational states for an internal checker.
+type InternalChecker_State int32
+
+const (
+ // An internal checker should never be in the unspecified state.
+ InternalChecker_UNSPECIFIED InternalChecker_State = 0
+ // The checker is being created, provisioned, and configured. A checker in
+ // this state can be returned by `ListInternalCheckers` or
+ // `GetInternalChecker`, as well as by examining the [long running
+ // Operation](https://cloud.google.com/apis/design/design_patterns#long_running_operations)
+ // that created it.
+ InternalChecker_CREATING InternalChecker_State = 1
+ // The checker is running and available for use. A checker in this state
+ // can be returned by `ListInternalCheckers` or `GetInternalChecker` as
+ // well as by examining the [long running
+ // Operation](https://cloud.google.com/apis/design/design_patterns#long_running_operations)
+ // that created it.
+ // If a checker is being torn down, it is neither visible nor usable, so
+ // there is no "deleting" or "down" state.
+ InternalChecker_RUNNING InternalChecker_State = 2
+)
+
+// Enum value maps for InternalChecker_State.
+var (
+ InternalChecker_State_name = map[int32]string{
+ 0: "UNSPECIFIED",
+ 1: "CREATING",
+ 2: "RUNNING",
+ }
+ InternalChecker_State_value = map[string]int32{
+ "UNSPECIFIED": 0,
+ "CREATING": 1,
+ "RUNNING": 2,
+ }
+)
+
+func (x InternalChecker_State) Enum() *InternalChecker_State {
+ p := new(InternalChecker_State)
+ *p = x
+ return p
+}
+
+func (x InternalChecker_State) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (InternalChecker_State) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_uptime_proto_enumTypes[2].Descriptor()
+}
+
+func (InternalChecker_State) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_uptime_proto_enumTypes[2]
+}
+
+func (x InternalChecker_State) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use InternalChecker_State.Descriptor instead.
+func (InternalChecker_State) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{0, 0}
+}
+
+// What kind of checkers are available to be used by the check.
+type UptimeCheckConfig_CheckerType int32
+
+const (
+ // The default checker type. Currently converted to `STATIC_IP_CHECKERS`
+ // on creation, the default conversion behavior may change in the future.
+ UptimeCheckConfig_CHECKER_TYPE_UNSPECIFIED UptimeCheckConfig_CheckerType = 0
+ // `STATIC_IP_CHECKERS` are used for uptime checks that perform egress
+ // across the public internet. `STATIC_IP_CHECKERS` use the static IP
+ // addresses returned by `ListUptimeCheckIps`.
+ UptimeCheckConfig_STATIC_IP_CHECKERS UptimeCheckConfig_CheckerType = 1
+ // `VPC_CHECKERS` are used for uptime checks that perform egress using
+ // Service Directory and private network access. When using `VPC_CHECKERS`,
+ // the monitored resource type must be `servicedirectory_service`.
+ UptimeCheckConfig_VPC_CHECKERS UptimeCheckConfig_CheckerType = 3
+)
+
+// Enum value maps for UptimeCheckConfig_CheckerType.
+var (
+ UptimeCheckConfig_CheckerType_name = map[int32]string{
+ 0: "CHECKER_TYPE_UNSPECIFIED",
+ 1: "STATIC_IP_CHECKERS",
+ 3: "VPC_CHECKERS",
+ }
+ UptimeCheckConfig_CheckerType_value = map[string]int32{
+ "CHECKER_TYPE_UNSPECIFIED": 0,
+ "STATIC_IP_CHECKERS": 1,
+ "VPC_CHECKERS": 3,
+ }
+)
+
+func (x UptimeCheckConfig_CheckerType) Enum() *UptimeCheckConfig_CheckerType {
+ p := new(UptimeCheckConfig_CheckerType)
+ *p = x
+ return p
+}
+
+func (x UptimeCheckConfig_CheckerType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (UptimeCheckConfig_CheckerType) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_uptime_proto_enumTypes[3].Descriptor()
+}
+
+func (UptimeCheckConfig_CheckerType) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_uptime_proto_enumTypes[3]
+}
+
+func (x UptimeCheckConfig_CheckerType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_CheckerType.Descriptor instead.
+func (UptimeCheckConfig_CheckerType) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 0}
+}
+
+// The HTTP request method options.
+type UptimeCheckConfig_HttpCheck_RequestMethod int32
+
+const (
+ // No request method specified.
+ UptimeCheckConfig_HttpCheck_METHOD_UNSPECIFIED UptimeCheckConfig_HttpCheck_RequestMethod = 0
+ // GET request.
+ UptimeCheckConfig_HttpCheck_GET UptimeCheckConfig_HttpCheck_RequestMethod = 1
+ // POST request.
+ UptimeCheckConfig_HttpCheck_POST UptimeCheckConfig_HttpCheck_RequestMethod = 2
+)
+
+// Enum value maps for UptimeCheckConfig_HttpCheck_RequestMethod.
+var (
+ UptimeCheckConfig_HttpCheck_RequestMethod_name = map[int32]string{
+ 0: "METHOD_UNSPECIFIED",
+ 1: "GET",
+ 2: "POST",
+ }
+ UptimeCheckConfig_HttpCheck_RequestMethod_value = map[string]int32{
+ "METHOD_UNSPECIFIED": 0,
+ "GET": 1,
+ "POST": 2,
+ }
+)
+
+func (x UptimeCheckConfig_HttpCheck_RequestMethod) Enum() *UptimeCheckConfig_HttpCheck_RequestMethod {
+ p := new(UptimeCheckConfig_HttpCheck_RequestMethod)
+ *p = x
+ return p
+}
+
+func (x UptimeCheckConfig_HttpCheck_RequestMethod) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (UptimeCheckConfig_HttpCheck_RequestMethod) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_uptime_proto_enumTypes[4].Descriptor()
+}
+
+func (UptimeCheckConfig_HttpCheck_RequestMethod) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_uptime_proto_enumTypes[4]
+}
+
+func (x UptimeCheckConfig_HttpCheck_RequestMethod) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_HttpCheck_RequestMethod.Descriptor instead.
+func (UptimeCheckConfig_HttpCheck_RequestMethod) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 2, 0}
+}
+
+// Header options corresponding to the content type of a HTTP request body.
+type UptimeCheckConfig_HttpCheck_ContentType int32
+
+const (
+ // No content type specified.
+ UptimeCheckConfig_HttpCheck_TYPE_UNSPECIFIED UptimeCheckConfig_HttpCheck_ContentType = 0
+ // `body` is in URL-encoded form. Equivalent to setting the `Content-Type`
+ // to `application/x-www-form-urlencoded` in the HTTP request.
+ UptimeCheckConfig_HttpCheck_URL_ENCODED UptimeCheckConfig_HttpCheck_ContentType = 1
+ // `body` is in `custom_content_type` form. Equivalent to setting the
+ // `Content-Type` to the contents of `custom_content_type` in the HTTP
+ // request.
+ UptimeCheckConfig_HttpCheck_USER_PROVIDED UptimeCheckConfig_HttpCheck_ContentType = 2
+)
+
+// Enum value maps for UptimeCheckConfig_HttpCheck_ContentType.
+var (
+ UptimeCheckConfig_HttpCheck_ContentType_name = map[int32]string{
+ 0: "TYPE_UNSPECIFIED",
+ 1: "URL_ENCODED",
+ 2: "USER_PROVIDED",
+ }
+ UptimeCheckConfig_HttpCheck_ContentType_value = map[string]int32{
+ "TYPE_UNSPECIFIED": 0,
+ "URL_ENCODED": 1,
+ "USER_PROVIDED": 2,
+ }
+)
+
+func (x UptimeCheckConfig_HttpCheck_ContentType) Enum() *UptimeCheckConfig_HttpCheck_ContentType {
+ p := new(UptimeCheckConfig_HttpCheck_ContentType)
+ *p = x
+ return p
+}
+
+func (x UptimeCheckConfig_HttpCheck_ContentType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (UptimeCheckConfig_HttpCheck_ContentType) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_uptime_proto_enumTypes[5].Descriptor()
+}
+
+func (UptimeCheckConfig_HttpCheck_ContentType) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_uptime_proto_enumTypes[5]
+}
+
+func (x UptimeCheckConfig_HttpCheck_ContentType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_HttpCheck_ContentType.Descriptor instead.
+func (UptimeCheckConfig_HttpCheck_ContentType) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 2, 1}
+}
+
+// An HTTP status code class.
+type UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass int32
+
+const (
+ // Default value that matches no status codes.
+ UptimeCheckConfig_HttpCheck_ResponseStatusCode_STATUS_CLASS_UNSPECIFIED UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass = 0
+ // The class of status codes between 100 and 199.
+ UptimeCheckConfig_HttpCheck_ResponseStatusCode_STATUS_CLASS_1XX UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass = 100
+ // The class of status codes between 200 and 299.
+ UptimeCheckConfig_HttpCheck_ResponseStatusCode_STATUS_CLASS_2XX UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass = 200
+ // The class of status codes between 300 and 399.
+ UptimeCheckConfig_HttpCheck_ResponseStatusCode_STATUS_CLASS_3XX UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass = 300
+ // The class of status codes between 400 and 499.
+ UptimeCheckConfig_HttpCheck_ResponseStatusCode_STATUS_CLASS_4XX UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass = 400
+ // The class of status codes between 500 and 599.
+ UptimeCheckConfig_HttpCheck_ResponseStatusCode_STATUS_CLASS_5XX UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass = 500
+ // The class of all status codes.
+ UptimeCheckConfig_HttpCheck_ResponseStatusCode_STATUS_CLASS_ANY UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass = 1000
+)
+
+// Enum value maps for UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass.
+var (
+ UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass_name = map[int32]string{
+ 0: "STATUS_CLASS_UNSPECIFIED",
+ 100: "STATUS_CLASS_1XX",
+ 200: "STATUS_CLASS_2XX",
+ 300: "STATUS_CLASS_3XX",
+ 400: "STATUS_CLASS_4XX",
+ 500: "STATUS_CLASS_5XX",
+ 1000: "STATUS_CLASS_ANY",
+ }
+ UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass_value = map[string]int32{
+ "STATUS_CLASS_UNSPECIFIED": 0,
+ "STATUS_CLASS_1XX": 100,
+ "STATUS_CLASS_2XX": 200,
+ "STATUS_CLASS_3XX": 300,
+ "STATUS_CLASS_4XX": 400,
+ "STATUS_CLASS_5XX": 500,
+ "STATUS_CLASS_ANY": 1000,
+ }
+)
+
+func (x UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass) Enum() *UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass {
+ p := new(UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass)
+ *p = x
+ return p
+}
+
+func (x UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_uptime_proto_enumTypes[6].Descriptor()
+}
+
+func (UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_uptime_proto_enumTypes[6]
+}
+
+func (x UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass.Descriptor instead.
+func (UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 2, 1, 0}
+}
+
+// Options to perform content matching.
+type UptimeCheckConfig_ContentMatcher_ContentMatcherOption int32
+
+const (
+ // No content matcher type specified (maintained for backward
+ // compatibility, but deprecated for future use).
+ // Treated as `CONTAINS_STRING`.
+ UptimeCheckConfig_ContentMatcher_CONTENT_MATCHER_OPTION_UNSPECIFIED UptimeCheckConfig_ContentMatcher_ContentMatcherOption = 0
+ // Selects substring matching. The match succeeds if the output contains
+ // the `content` string. This is the default value for checks without
+ // a `matcher` option, or where the value of `matcher` is
+ // `CONTENT_MATCHER_OPTION_UNSPECIFIED`.
+ UptimeCheckConfig_ContentMatcher_CONTAINS_STRING UptimeCheckConfig_ContentMatcher_ContentMatcherOption = 1
+ // Selects negation of substring matching. The match succeeds if the
+ // output does _NOT_ contain the `content` string.
+ UptimeCheckConfig_ContentMatcher_NOT_CONTAINS_STRING UptimeCheckConfig_ContentMatcher_ContentMatcherOption = 2
+ // Selects regular-expression matching. The match succeeds if the output
+ // matches the regular expression specified in the `content` string.
+ // Regex matching is only supported for HTTP/HTTPS checks.
+ UptimeCheckConfig_ContentMatcher_MATCHES_REGEX UptimeCheckConfig_ContentMatcher_ContentMatcherOption = 3
+ // Selects negation of regular-expression matching. The match succeeds if
+ // the output does _NOT_ match the regular expression specified in the
+ // `content` string. Regex matching is only supported for HTTP/HTTPS
+ // checks.
+ UptimeCheckConfig_ContentMatcher_NOT_MATCHES_REGEX UptimeCheckConfig_ContentMatcher_ContentMatcherOption = 4
+ // Selects JSONPath matching. See `JsonPathMatcher` for details on when
+ // the match succeeds. JSONPath matching is only supported for HTTP/HTTPS
+ // checks.
+ UptimeCheckConfig_ContentMatcher_MATCHES_JSON_PATH UptimeCheckConfig_ContentMatcher_ContentMatcherOption = 5
+ // Selects JSONPath matching. See `JsonPathMatcher` for details on when
+ // the match succeeds. Succeeds when output does _NOT_ match as specified.
+ // JSONPath is only supported for HTTP/HTTPS checks.
+ UptimeCheckConfig_ContentMatcher_NOT_MATCHES_JSON_PATH UptimeCheckConfig_ContentMatcher_ContentMatcherOption = 6
+)
+
+// Enum value maps for UptimeCheckConfig_ContentMatcher_ContentMatcherOption.
+var (
+ UptimeCheckConfig_ContentMatcher_ContentMatcherOption_name = map[int32]string{
+ 0: "CONTENT_MATCHER_OPTION_UNSPECIFIED",
+ 1: "CONTAINS_STRING",
+ 2: "NOT_CONTAINS_STRING",
+ 3: "MATCHES_REGEX",
+ 4: "NOT_MATCHES_REGEX",
+ 5: "MATCHES_JSON_PATH",
+ 6: "NOT_MATCHES_JSON_PATH",
+ }
+ UptimeCheckConfig_ContentMatcher_ContentMatcherOption_value = map[string]int32{
+ "CONTENT_MATCHER_OPTION_UNSPECIFIED": 0,
+ "CONTAINS_STRING": 1,
+ "NOT_CONTAINS_STRING": 2,
+ "MATCHES_REGEX": 3,
+ "NOT_MATCHES_REGEX": 4,
+ "MATCHES_JSON_PATH": 5,
+ "NOT_MATCHES_JSON_PATH": 6,
+ }
+)
+
+func (x UptimeCheckConfig_ContentMatcher_ContentMatcherOption) Enum() *UptimeCheckConfig_ContentMatcher_ContentMatcherOption {
+ p := new(UptimeCheckConfig_ContentMatcher_ContentMatcherOption)
+ *p = x
+ return p
+}
+
+func (x UptimeCheckConfig_ContentMatcher_ContentMatcherOption) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (UptimeCheckConfig_ContentMatcher_ContentMatcherOption) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_uptime_proto_enumTypes[7].Descriptor()
+}
+
+func (UptimeCheckConfig_ContentMatcher_ContentMatcherOption) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_uptime_proto_enumTypes[7]
+}
+
+func (x UptimeCheckConfig_ContentMatcher_ContentMatcherOption) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_ContentMatcher_ContentMatcherOption.Descriptor instead.
+func (UptimeCheckConfig_ContentMatcher_ContentMatcherOption) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 4, 0}
+}
+
+// Options to perform JSONPath content matching.
+type UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption int32
+
+const (
+ // No JSONPath matcher type specified (not valid).
+ UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JSON_PATH_MATCHER_OPTION_UNSPECIFIED UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption = 0
+ // Selects 'exact string' matching. The match succeeds if the content at
+ // the `json_path` within the output is exactly the same as the
+ // `content` string.
+ UptimeCheckConfig_ContentMatcher_JsonPathMatcher_EXACT_MATCH UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption = 1
+ // Selects regular-expression matching. The match succeeds if the
+ // content at the `json_path` within the output matches the regular
+ // expression specified in the `content` string.
+ UptimeCheckConfig_ContentMatcher_JsonPathMatcher_REGEX_MATCH UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption = 2
+)
+
+// Enum value maps for UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption.
+var (
+ UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption_name = map[int32]string{
+ 0: "JSON_PATH_MATCHER_OPTION_UNSPECIFIED",
+ 1: "EXACT_MATCH",
+ 2: "REGEX_MATCH",
+ }
+ UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption_value = map[string]int32{
+ "JSON_PATH_MATCHER_OPTION_UNSPECIFIED": 0,
+ "EXACT_MATCH": 1,
+ "REGEX_MATCH": 2,
+ }
+)
+
+func (x UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption) Enum() *UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption {
+ p := new(UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption)
+ *p = x
+ return p
+}
+
+func (x UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_monitoring_v3_uptime_proto_enumTypes[8].Descriptor()
+}
+
+func (UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption) Type() protoreflect.EnumType {
+ return &file_google_monitoring_v3_uptime_proto_enumTypes[8]
+}
+
+func (x UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption.Descriptor instead.
+func (UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption) EnumDescriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 4, 0, 0}
+}
+
+// An internal checker allows Uptime checks to run on private/internal GCP
+// resources.
+//
+// Deprecated: Marked as deprecated in google/monitoring/v3/uptime.proto.
+type InternalChecker struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // A unique resource name for this InternalChecker. The format is:
+ //
+ // projects/[PROJECT_ID_OR_NUMBER]/internalCheckers/[INTERNAL_CHECKER_ID]
+ //
+ // `[PROJECT_ID_OR_NUMBER]` is the Cloud Monitoring Metrics Scope project for
+ // the Uptime check config associated with the internal checker.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // The checker's human-readable name. The display name
+ // should be unique within a Cloud Monitoring Metrics Scope in order to make
+ // it easier to identify; however, uniqueness is not enforced.
+ DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
+ // The [GCP VPC network](https://cloud.google.com/vpc/docs/vpc) where the
+ // internal resource lives (ex: "default").
+ Network string `protobuf:"bytes,3,opt,name=network,proto3" json:"network,omitempty"`
+ // The GCP zone the Uptime check should egress from. Only respected for
+ // internal Uptime checks, where internal_network is specified.
+ GcpZone string `protobuf:"bytes,4,opt,name=gcp_zone,json=gcpZone,proto3" json:"gcp_zone,omitempty"`
+ // The GCP project ID where the internal checker lives. Not necessary
+ // the same as the Metrics Scope project.
+ PeerProjectId string `protobuf:"bytes,6,opt,name=peer_project_id,json=peerProjectId,proto3" json:"peer_project_id,omitempty"`
+ // The current operational state of the internal checker.
+ State InternalChecker_State `protobuf:"varint,7,opt,name=state,proto3,enum=google.monitoring.v3.InternalChecker_State" json:"state,omitempty"`
+}
+
+func (x *InternalChecker) Reset() {
+ *x = InternalChecker{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *InternalChecker) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InternalChecker) ProtoMessage() {}
+
+func (x *InternalChecker) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use InternalChecker.ProtoReflect.Descriptor instead.
+func (*InternalChecker) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *InternalChecker) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *InternalChecker) GetDisplayName() string {
+ if x != nil {
+ return x.DisplayName
+ }
+ return ""
+}
+
+func (x *InternalChecker) GetNetwork() string {
+ if x != nil {
+ return x.Network
+ }
+ return ""
+}
+
+func (x *InternalChecker) GetGcpZone() string {
+ if x != nil {
+ return x.GcpZone
+ }
+ return ""
+}
+
+func (x *InternalChecker) GetPeerProjectId() string {
+ if x != nil {
+ return x.PeerProjectId
+ }
+ return ""
+}
+
+func (x *InternalChecker) GetState() InternalChecker_State {
+ if x != nil {
+ return x.State
+ }
+ return InternalChecker_UNSPECIFIED
+}
+
+// This message configures which resources and services to monitor for
+// availability.
+type UptimeCheckConfig struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // A unique resource name for this Uptime check configuration. The format is:
+ //
+ // projects/[PROJECT_ID_OR_NUMBER]/uptimeCheckConfigs/[UPTIME_CHECK_ID]
+ //
+ // `[PROJECT_ID_OR_NUMBER]` is the Workspace host project associated with the
+ // Uptime check.
+ //
+ // This field should be omitted when creating the Uptime check configuration;
+ // on create, the resource name is assigned by the server and included in the
+ // response.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // A human-friendly name for the Uptime check configuration. The display name
+ // should be unique within a Cloud Monitoring Workspace in order to make it
+ // easier to identify; however, uniqueness is not enforced. Required.
+ DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
+ // The resource the check is checking. Required.
+ //
+ // Types that are assignable to Resource:
+ // *UptimeCheckConfig_MonitoredResource
+ // *UptimeCheckConfig_ResourceGroup_
+ Resource isUptimeCheckConfig_Resource `protobuf_oneof:"resource"`
+ // The type of Uptime check request.
+ //
+ // Types that are assignable to CheckRequestType:
+ // *UptimeCheckConfig_HttpCheck_
+ // *UptimeCheckConfig_TcpCheck_
+ CheckRequestType isUptimeCheckConfig_CheckRequestType `protobuf_oneof:"check_request_type"`
+ // How often, in seconds, the Uptime check is performed.
+ // Currently, the only supported values are `60s` (1 minute), `300s`
+ // (5 minutes), `600s` (10 minutes), and `900s` (15 minutes). Optional,
+ // defaults to `60s`.
+ Period *durationpb.Duration `protobuf:"bytes,7,opt,name=period,proto3" json:"period,omitempty"`
+ // The maximum amount of time to wait for the request to complete (must be
+ // between 1 and 60 seconds). Required.
+ Timeout *durationpb.Duration `protobuf:"bytes,8,opt,name=timeout,proto3" json:"timeout,omitempty"`
+ // The content that is expected to appear in the data returned by the target
+ // server against which the check is run. Currently, only the first entry
+ // in the `content_matchers` list is supported, and additional entries will
+ // be ignored. This field is optional and should only be specified if a
+ // content match is required as part of the/ Uptime check.
+ ContentMatchers []*UptimeCheckConfig_ContentMatcher `protobuf:"bytes,9,rep,name=content_matchers,json=contentMatchers,proto3" json:"content_matchers,omitempty"`
+ // The type of checkers to use to execute the Uptime check.
+ CheckerType UptimeCheckConfig_CheckerType `protobuf:"varint,17,opt,name=checker_type,json=checkerType,proto3,enum=google.monitoring.v3.UptimeCheckConfig_CheckerType" json:"checker_type,omitempty"`
+ // The list of regions from which the check will be run.
+ // Some regions contain one location, and others contain more than one.
+ // If this field is specified, enough regions must be provided to include a
+ // minimum of 3 locations. Not specifying this field will result in Uptime
+ // checks running from all available regions.
+ SelectedRegions []UptimeCheckRegion `protobuf:"varint,10,rep,packed,name=selected_regions,json=selectedRegions,proto3,enum=google.monitoring.v3.UptimeCheckRegion" json:"selected_regions,omitempty"`
+ // If this is `true`, then checks are made only from the 'internal_checkers'.
+ // If it is `false`, then checks are made only from the 'selected_regions'.
+ // It is an error to provide 'selected_regions' when is_internal is `true`,
+ // or to provide 'internal_checkers' when is_internal is `false`.
+ //
+ // Deprecated: Marked as deprecated in google/monitoring/v3/uptime.proto.
+ IsInternal bool `protobuf:"varint,15,opt,name=is_internal,json=isInternal,proto3" json:"is_internal,omitempty"`
+ // The internal checkers that this check will egress from. If `is_internal` is
+ // `true` and this list is empty, the check will egress from all the
+ // InternalCheckers configured for the project that owns this
+ // `UptimeCheckConfig`.
+ //
+ // Deprecated: Marked as deprecated in google/monitoring/v3/uptime.proto.
+ InternalCheckers []*InternalChecker `protobuf:"bytes,14,rep,name=internal_checkers,json=internalCheckers,proto3" json:"internal_checkers,omitempty"`
+ // User-supplied key/value data to be used for organizing and
+ // identifying the `UptimeCheckConfig` objects.
+ //
+ // The field can contain up to 64 entries. Each key and value is limited to
+ // 63 Unicode characters or 128 bytes, whichever is smaller. Labels and
+ // values can contain only lowercase letters, numerals, underscores, and
+ // dashes. Keys must begin with a letter.
+ UserLabels map[string]string `protobuf:"bytes,20,rep,name=user_labels,json=userLabels,proto3" json:"user_labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *UptimeCheckConfig) Reset() {
+ *x = UptimeCheckConfig{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UptimeCheckConfig) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UptimeCheckConfig) ProtoMessage() {}
+
+func (x *UptimeCheckConfig) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UptimeCheckConfig.ProtoReflect.Descriptor instead.
+func (*UptimeCheckConfig) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *UptimeCheckConfig) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *UptimeCheckConfig) GetDisplayName() string {
+ if x != nil {
+ return x.DisplayName
+ }
+ return ""
+}
+
+func (m *UptimeCheckConfig) GetResource() isUptimeCheckConfig_Resource {
+ if m != nil {
+ return m.Resource
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig) GetMonitoredResource() *monitoredres.MonitoredResource {
+ if x, ok := x.GetResource().(*UptimeCheckConfig_MonitoredResource); ok {
+ return x.MonitoredResource
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig) GetResourceGroup() *UptimeCheckConfig_ResourceGroup {
+ if x, ok := x.GetResource().(*UptimeCheckConfig_ResourceGroup_); ok {
+ return x.ResourceGroup
+ }
+ return nil
+}
+
+func (m *UptimeCheckConfig) GetCheckRequestType() isUptimeCheckConfig_CheckRequestType {
+ if m != nil {
+ return m.CheckRequestType
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig) GetHttpCheck() *UptimeCheckConfig_HttpCheck {
+ if x, ok := x.GetCheckRequestType().(*UptimeCheckConfig_HttpCheck_); ok {
+ return x.HttpCheck
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig) GetTcpCheck() *UptimeCheckConfig_TcpCheck {
+ if x, ok := x.GetCheckRequestType().(*UptimeCheckConfig_TcpCheck_); ok {
+ return x.TcpCheck
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig) GetPeriod() *durationpb.Duration {
+ if x != nil {
+ return x.Period
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig) GetTimeout() *durationpb.Duration {
+ if x != nil {
+ return x.Timeout
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig) GetContentMatchers() []*UptimeCheckConfig_ContentMatcher {
+ if x != nil {
+ return x.ContentMatchers
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig) GetCheckerType() UptimeCheckConfig_CheckerType {
+ if x != nil {
+ return x.CheckerType
+ }
+ return UptimeCheckConfig_CHECKER_TYPE_UNSPECIFIED
+}
+
+func (x *UptimeCheckConfig) GetSelectedRegions() []UptimeCheckRegion {
+ if x != nil {
+ return x.SelectedRegions
+ }
+ return nil
+}
+
+// Deprecated: Marked as deprecated in google/monitoring/v3/uptime.proto.
+func (x *UptimeCheckConfig) GetIsInternal() bool {
+ if x != nil {
+ return x.IsInternal
+ }
+ return false
+}
+
+// Deprecated: Marked as deprecated in google/monitoring/v3/uptime.proto.
+func (x *UptimeCheckConfig) GetInternalCheckers() []*InternalChecker {
+ if x != nil {
+ return x.InternalCheckers
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig) GetUserLabels() map[string]string {
+ if x != nil {
+ return x.UserLabels
+ }
+ return nil
+}
+
+type isUptimeCheckConfig_Resource interface {
+ isUptimeCheckConfig_Resource()
+}
+
+type UptimeCheckConfig_MonitoredResource struct {
+ // The [monitored
+ // resource](https://cloud.google.com/monitoring/api/resources) associated
+ // with the configuration.
+ // The following monitored resource types are valid for this field:
+ // `uptime_url`,
+ // `gce_instance`,
+ // `gae_app`,
+ // `aws_ec2_instance`,
+ // `aws_elb_load_balancer`
+ // `k8s_service`
+ // `servicedirectory_service`
+ // `cloud_run_revision`
+ MonitoredResource *monitoredres.MonitoredResource `protobuf:"bytes,3,opt,name=monitored_resource,json=monitoredResource,proto3,oneof"`
+}
+
+type UptimeCheckConfig_ResourceGroup_ struct {
+ // The group resource associated with the configuration.
+ ResourceGroup *UptimeCheckConfig_ResourceGroup `protobuf:"bytes,4,opt,name=resource_group,json=resourceGroup,proto3,oneof"`
+}
+
+func (*UptimeCheckConfig_MonitoredResource) isUptimeCheckConfig_Resource() {}
+
+func (*UptimeCheckConfig_ResourceGroup_) isUptimeCheckConfig_Resource() {}
+
+type isUptimeCheckConfig_CheckRequestType interface {
+ isUptimeCheckConfig_CheckRequestType()
+}
+
+type UptimeCheckConfig_HttpCheck_ struct {
+ // Contains information needed to make an HTTP or HTTPS check.
+ HttpCheck *UptimeCheckConfig_HttpCheck `protobuf:"bytes,5,opt,name=http_check,json=httpCheck,proto3,oneof"`
+}
+
+type UptimeCheckConfig_TcpCheck_ struct {
+ // Contains information needed to make a TCP check.
+ TcpCheck *UptimeCheckConfig_TcpCheck `protobuf:"bytes,6,opt,name=tcp_check,json=tcpCheck,proto3,oneof"`
+}
+
+func (*UptimeCheckConfig_HttpCheck_) isUptimeCheckConfig_CheckRequestType() {}
+
+func (*UptimeCheckConfig_TcpCheck_) isUptimeCheckConfig_CheckRequestType() {}
+
+// Contains the region, location, and list of IP
+// addresses where checkers in the location run from.
+type UptimeCheckIp struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // A broad region category in which the IP address is located.
+ Region UptimeCheckRegion `protobuf:"varint,1,opt,name=region,proto3,enum=google.monitoring.v3.UptimeCheckRegion" json:"region,omitempty"`
+ // A more specific location within the region that typically encodes
+ // a particular city/town/metro (and its containing state/province or country)
+ // within the broader umbrella region category.
+ Location string `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"`
+ // The IP address from which the Uptime check originates. This is a fully
+ // specified IP address (not an IP address range). Most IP addresses, as of
+ // this publication, are in IPv4 format; however, one should not rely on the
+ // IP addresses being in IPv4 format indefinitely, and should support
+ // interpreting this field in either IPv4 or IPv6 format.
+ IpAddress string `protobuf:"bytes,3,opt,name=ip_address,json=ipAddress,proto3" json:"ip_address,omitempty"`
+}
+
+func (x *UptimeCheckIp) Reset() {
+ *x = UptimeCheckIp{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UptimeCheckIp) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UptimeCheckIp) ProtoMessage() {}
+
+func (x *UptimeCheckIp) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UptimeCheckIp.ProtoReflect.Descriptor instead.
+func (*UptimeCheckIp) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *UptimeCheckIp) GetRegion() UptimeCheckRegion {
+ if x != nil {
+ return x.Region
+ }
+ return UptimeCheckRegion_REGION_UNSPECIFIED
+}
+
+func (x *UptimeCheckIp) GetLocation() string {
+ if x != nil {
+ return x.Location
+ }
+ return ""
+}
+
+func (x *UptimeCheckIp) GetIpAddress() string {
+ if x != nil {
+ return x.IpAddress
+ }
+ return ""
+}
+
+// The resource submessage for group checks. It can be used instead of a
+// monitored resource, when multiple resources are being monitored.
+type UptimeCheckConfig_ResourceGroup struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The group of resources being monitored. Should be only the `[GROUP_ID]`,
+ // and not the full-path
+ // `projects/[PROJECT_ID_OR_NUMBER]/groups/[GROUP_ID]`.
+ GroupId string `protobuf:"bytes,1,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"`
+ // The resource type of the group members.
+ ResourceType GroupResourceType `protobuf:"varint,2,opt,name=resource_type,json=resourceType,proto3,enum=google.monitoring.v3.GroupResourceType" json:"resource_type,omitempty"`
+}
+
+func (x *UptimeCheckConfig_ResourceGroup) Reset() {
+ *x = UptimeCheckConfig_ResourceGroup{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UptimeCheckConfig_ResourceGroup) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UptimeCheckConfig_ResourceGroup) ProtoMessage() {}
+
+func (x *UptimeCheckConfig_ResourceGroup) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_ResourceGroup.ProtoReflect.Descriptor instead.
+func (*UptimeCheckConfig_ResourceGroup) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 0}
+}
+
+func (x *UptimeCheckConfig_ResourceGroup) GetGroupId() string {
+ if x != nil {
+ return x.GroupId
+ }
+ return ""
+}
+
+func (x *UptimeCheckConfig_ResourceGroup) GetResourceType() GroupResourceType {
+ if x != nil {
+ return x.ResourceType
+ }
+ return GroupResourceType_RESOURCE_TYPE_UNSPECIFIED
+}
+
+// Information involved in sending ICMP pings alongside public HTTP/TCP
+// checks. For HTTP, the pings are performed for each part of the redirect
+// chain.
+type UptimeCheckConfig_PingConfig struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Number of ICMP pings. A maximum of 3 ICMP pings is currently supported.
+ PingsCount int32 `protobuf:"varint,1,opt,name=pings_count,json=pingsCount,proto3" json:"pings_count,omitempty"`
+}
+
+func (x *UptimeCheckConfig_PingConfig) Reset() {
+ *x = UptimeCheckConfig_PingConfig{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UptimeCheckConfig_PingConfig) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UptimeCheckConfig_PingConfig) ProtoMessage() {}
+
+func (x *UptimeCheckConfig_PingConfig) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_PingConfig.ProtoReflect.Descriptor instead.
+func (*UptimeCheckConfig_PingConfig) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 1}
+}
+
+func (x *UptimeCheckConfig_PingConfig) GetPingsCount() int32 {
+ if x != nil {
+ return x.PingsCount
+ }
+ return 0
+}
+
+// Information involved in an HTTP/HTTPS Uptime check request.
+type UptimeCheckConfig_HttpCheck struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The HTTP request method to use for the check. If set to
+ // `METHOD_UNSPECIFIED` then `request_method` defaults to `GET`.
+ RequestMethod UptimeCheckConfig_HttpCheck_RequestMethod `protobuf:"varint,8,opt,name=request_method,json=requestMethod,proto3,enum=google.monitoring.v3.UptimeCheckConfig_HttpCheck_RequestMethod" json:"request_method,omitempty"`
+ // If `true`, use HTTPS instead of HTTP to run the check.
+ UseSsl bool `protobuf:"varint,1,opt,name=use_ssl,json=useSsl,proto3" json:"use_ssl,omitempty"`
+ // Optional (defaults to "/"). The path to the page against which to run
+ // the check. Will be combined with the `host` (specified within the
+ // `monitored_resource`) and `port` to construct the full URL. If the
+ // provided path does not begin with "/", a "/" will be prepended
+ // automatically.
+ Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
+ // Optional (defaults to 80 when `use_ssl` is `false`, and 443 when
+ // `use_ssl` is `true`). The TCP port on the HTTP server against which to
+ // run the check. Will be combined with host (specified within the
+ // `monitored_resource`) and `path` to construct the full URL.
+ Port int32 `protobuf:"varint,3,opt,name=port,proto3" json:"port,omitempty"`
+ // The authentication information. Optional when creating an HTTP check;
+ // defaults to empty.
+ AuthInfo *UptimeCheckConfig_HttpCheck_BasicAuthentication `protobuf:"bytes,4,opt,name=auth_info,json=authInfo,proto3" json:"auth_info,omitempty"`
+ // Boolean specifying whether to encrypt the header information.
+ // Encryption should be specified for any headers related to authentication
+ // that you do not wish to be seen when retrieving the configuration. The
+ // server will be responsible for encrypting the headers.
+ // On Get/List calls, if `mask_headers` is set to `true` then the headers
+ // will be obscured with `******.`
+ MaskHeaders bool `protobuf:"varint,5,opt,name=mask_headers,json=maskHeaders,proto3" json:"mask_headers,omitempty"`
+ // The list of headers to send as part of the Uptime check request.
+ // If two headers have the same key and different values, they should
+ // be entered as a single header, with the value being a comma-separated
+ // list of all the desired values as described at
+ // https://www.w3.org/Protocols/rfc2616/rfc2616.txt (page 31).
+ // Entering two separate headers with the same key in a Create call will
+ // cause the first to be overwritten by the second.
+ // The maximum number of headers allowed is 100.
+ Headers map[string]string `protobuf:"bytes,6,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // The content type header to use for the check. The following
+ // configurations result in errors:
+ // 1. Content type is specified in both the `headers` field and the
+ // `content_type` field.
+ // 2. Request method is `GET` and `content_type` is not `TYPE_UNSPECIFIED`
+ // 3. Request method is `POST` and `content_type` is `TYPE_UNSPECIFIED`.
+ // 4. Request method is `POST` and a "Content-Type" header is provided via
+ // `headers` field. The `content_type` field should be used instead.
+ ContentType UptimeCheckConfig_HttpCheck_ContentType `protobuf:"varint,9,opt,name=content_type,json=contentType,proto3,enum=google.monitoring.v3.UptimeCheckConfig_HttpCheck_ContentType" json:"content_type,omitempty"`
+ // A user provided content type header to use for the check. The invalid
+ // configurations outlined in the `content_type` field apply to
+ // `custom_content_type`, as well as the following:
+ // 1. `content_type` is `URL_ENCODED` and `custom_content_type` is set.
+ // 2. `content_type` is `USER_PROVIDED` and `custom_content_type` is not
+ // set.
+ CustomContentType string `protobuf:"bytes,13,opt,name=custom_content_type,json=customContentType,proto3" json:"custom_content_type,omitempty"`
+ // Boolean specifying whether to include SSL certificate validation as a
+ // part of the Uptime check. Only applies to checks where
+ // `monitored_resource` is set to `uptime_url`. If `use_ssl` is `false`,
+ // setting `validate_ssl` to `true` has no effect.
+ ValidateSsl bool `protobuf:"varint,7,opt,name=validate_ssl,json=validateSsl,proto3" json:"validate_ssl,omitempty"`
+ // The request body associated with the HTTP POST request. If `content_type`
+ // is `URL_ENCODED`, the body passed in must be URL-encoded. Users can
+ // provide a `Content-Length` header via the `headers` field or the API will
+ // do so. If the `request_method` is `GET` and `body` is not empty, the API
+ // will return an error. The maximum byte size is 1 megabyte.
+ //
+ // Note: If client libraries aren't used (which performs the conversion
+ // automatically) base64 encode your `body` data since the field is of
+ // `bytes` type.
+ Body []byte `protobuf:"bytes,10,opt,name=body,proto3" json:"body,omitempty"`
+ // If present, the check will only pass if the HTTP response status code is
+ // in this set of status codes. If empty, the HTTP status code will only
+ // pass if the HTTP status code is 200-299.
+ AcceptedResponseStatusCodes []*UptimeCheckConfig_HttpCheck_ResponseStatusCode `protobuf:"bytes,11,rep,name=accepted_response_status_codes,json=acceptedResponseStatusCodes,proto3" json:"accepted_response_status_codes,omitempty"`
+ // Contains information needed to add pings to an HTTP check.
+ PingConfig *UptimeCheckConfig_PingConfig `protobuf:"bytes,12,opt,name=ping_config,json=pingConfig,proto3" json:"ping_config,omitempty"`
+}
+
+func (x *UptimeCheckConfig_HttpCheck) Reset() {
+ *x = UptimeCheckConfig_HttpCheck{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UptimeCheckConfig_HttpCheck) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UptimeCheckConfig_HttpCheck) ProtoMessage() {}
+
+func (x *UptimeCheckConfig_HttpCheck) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_HttpCheck.ProtoReflect.Descriptor instead.
+func (*UptimeCheckConfig_HttpCheck) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 2}
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetRequestMethod() UptimeCheckConfig_HttpCheck_RequestMethod {
+ if x != nil {
+ return x.RequestMethod
+ }
+ return UptimeCheckConfig_HttpCheck_METHOD_UNSPECIFIED
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetUseSsl() bool {
+ if x != nil {
+ return x.UseSsl
+ }
+ return false
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetPath() string {
+ if x != nil {
+ return x.Path
+ }
+ return ""
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetPort() int32 {
+ if x != nil {
+ return x.Port
+ }
+ return 0
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetAuthInfo() *UptimeCheckConfig_HttpCheck_BasicAuthentication {
+ if x != nil {
+ return x.AuthInfo
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetMaskHeaders() bool {
+ if x != nil {
+ return x.MaskHeaders
+ }
+ return false
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetHeaders() map[string]string {
+ if x != nil {
+ return x.Headers
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetContentType() UptimeCheckConfig_HttpCheck_ContentType {
+ if x != nil {
+ return x.ContentType
+ }
+ return UptimeCheckConfig_HttpCheck_TYPE_UNSPECIFIED
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetCustomContentType() string {
+ if x != nil {
+ return x.CustomContentType
+ }
+ return ""
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetValidateSsl() bool {
+ if x != nil {
+ return x.ValidateSsl
+ }
+ return false
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetBody() []byte {
+ if x != nil {
+ return x.Body
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetAcceptedResponseStatusCodes() []*UptimeCheckConfig_HttpCheck_ResponseStatusCode {
+ if x != nil {
+ return x.AcceptedResponseStatusCodes
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig_HttpCheck) GetPingConfig() *UptimeCheckConfig_PingConfig {
+ if x != nil {
+ return x.PingConfig
+ }
+ return nil
+}
+
+// Information required for a TCP Uptime check request.
+type UptimeCheckConfig_TcpCheck struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The TCP port on the server against which to run the check. Will be
+ // combined with host (specified within the `monitored_resource`) to
+ // construct the full URL. Required.
+ Port int32 `protobuf:"varint,1,opt,name=port,proto3" json:"port,omitempty"`
+ // Contains information needed to add pings to a TCP check.
+ PingConfig *UptimeCheckConfig_PingConfig `protobuf:"bytes,2,opt,name=ping_config,json=pingConfig,proto3" json:"ping_config,omitempty"`
+}
+
+func (x *UptimeCheckConfig_TcpCheck) Reset() {
+ *x = UptimeCheckConfig_TcpCheck{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UptimeCheckConfig_TcpCheck) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UptimeCheckConfig_TcpCheck) ProtoMessage() {}
+
+func (x *UptimeCheckConfig_TcpCheck) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_TcpCheck.ProtoReflect.Descriptor instead.
+func (*UptimeCheckConfig_TcpCheck) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 3}
+}
+
+func (x *UptimeCheckConfig_TcpCheck) GetPort() int32 {
+ if x != nil {
+ return x.Port
+ }
+ return 0
+}
+
+func (x *UptimeCheckConfig_TcpCheck) GetPingConfig() *UptimeCheckConfig_PingConfig {
+ if x != nil {
+ return x.PingConfig
+ }
+ return nil
+}
+
+// Optional. Used to perform content matching. This allows matching based on
+// substrings and regular expressions, together with their negations. Only the
+// first 4 MB of an HTTP or HTTPS check's response (and the first
+// 1 MB of a TCP check's response) are examined for purposes of content
+// matching.
+type UptimeCheckConfig_ContentMatcher struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // String, regex or JSON content to match. Maximum 1024 bytes. An empty
+ // `content` string indicates no content matching is to be performed.
+ Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
+ // The type of content matcher that will be applied to the server output,
+ // compared to the `content` string when the check is run.
+ Matcher UptimeCheckConfig_ContentMatcher_ContentMatcherOption `protobuf:"varint,2,opt,name=matcher,proto3,enum=google.monitoring.v3.UptimeCheckConfig_ContentMatcher_ContentMatcherOption" json:"matcher,omitempty"`
+ // Certain `ContentMatcherOption` types require additional information.
+ // `MATCHES_JSON_PATH` or `NOT_MATCHES_JSON_PATH` require a
+ // `JsonPathMatcher`; not used for other options.
+ //
+ // Types that are assignable to AdditionalMatcherInfo:
+ // *UptimeCheckConfig_ContentMatcher_JsonPathMatcher_
+ AdditionalMatcherInfo isUptimeCheckConfig_ContentMatcher_AdditionalMatcherInfo `protobuf_oneof:"additional_matcher_info"`
+}
+
+func (x *UptimeCheckConfig_ContentMatcher) Reset() {
+ *x = UptimeCheckConfig_ContentMatcher{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UptimeCheckConfig_ContentMatcher) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UptimeCheckConfig_ContentMatcher) ProtoMessage() {}
+
+func (x *UptimeCheckConfig_ContentMatcher) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_ContentMatcher.ProtoReflect.Descriptor instead.
+func (*UptimeCheckConfig_ContentMatcher) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 4}
+}
+
+func (x *UptimeCheckConfig_ContentMatcher) GetContent() string {
+ if x != nil {
+ return x.Content
+ }
+ return ""
+}
+
+func (x *UptimeCheckConfig_ContentMatcher) GetMatcher() UptimeCheckConfig_ContentMatcher_ContentMatcherOption {
+ if x != nil {
+ return x.Matcher
+ }
+ return UptimeCheckConfig_ContentMatcher_CONTENT_MATCHER_OPTION_UNSPECIFIED
+}
+
+func (m *UptimeCheckConfig_ContentMatcher) GetAdditionalMatcherInfo() isUptimeCheckConfig_ContentMatcher_AdditionalMatcherInfo {
+ if m != nil {
+ return m.AdditionalMatcherInfo
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig_ContentMatcher) GetJsonPathMatcher() *UptimeCheckConfig_ContentMatcher_JsonPathMatcher {
+ if x, ok := x.GetAdditionalMatcherInfo().(*UptimeCheckConfig_ContentMatcher_JsonPathMatcher_); ok {
+ return x.JsonPathMatcher
+ }
+ return nil
+}
+
+type isUptimeCheckConfig_ContentMatcher_AdditionalMatcherInfo interface {
+ isUptimeCheckConfig_ContentMatcher_AdditionalMatcherInfo()
+}
+
+type UptimeCheckConfig_ContentMatcher_JsonPathMatcher_ struct {
+ // Matcher information for `MATCHES_JSON_PATH` and `NOT_MATCHES_JSON_PATH`
+ JsonPathMatcher *UptimeCheckConfig_ContentMatcher_JsonPathMatcher `protobuf:"bytes,3,opt,name=json_path_matcher,json=jsonPathMatcher,proto3,oneof"`
+}
+
+func (*UptimeCheckConfig_ContentMatcher_JsonPathMatcher_) isUptimeCheckConfig_ContentMatcher_AdditionalMatcherInfo() {
+}
+
+// The authentication parameters to provide to the specified resource or
+// URL that requires a username and password. Currently, only
+// [Basic HTTP authentication](https://tools.ietf.org/html/rfc7617) is
+// supported in Uptime checks.
+type UptimeCheckConfig_HttpCheck_BasicAuthentication struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The username to use when authenticating with the HTTP server.
+ Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
+ // The password to use when authenticating with the HTTP server.
+ Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
+}
+
+func (x *UptimeCheckConfig_HttpCheck_BasicAuthentication) Reset() {
+ *x = UptimeCheckConfig_HttpCheck_BasicAuthentication{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UptimeCheckConfig_HttpCheck_BasicAuthentication) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UptimeCheckConfig_HttpCheck_BasicAuthentication) ProtoMessage() {}
+
+func (x *UptimeCheckConfig_HttpCheck_BasicAuthentication) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_HttpCheck_BasicAuthentication.ProtoReflect.Descriptor instead.
+func (*UptimeCheckConfig_HttpCheck_BasicAuthentication) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 2, 0}
+}
+
+func (x *UptimeCheckConfig_HttpCheck_BasicAuthentication) GetUsername() string {
+ if x != nil {
+ return x.Username
+ }
+ return ""
+}
+
+func (x *UptimeCheckConfig_HttpCheck_BasicAuthentication) GetPassword() string {
+ if x != nil {
+ return x.Password
+ }
+ return ""
+}
+
+// A status to accept. Either a status code class like "2xx", or an integer
+// status code like "200".
+type UptimeCheckConfig_HttpCheck_ResponseStatusCode struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Either a specific value or a class of status codes.
+ //
+ // Types that are assignable to StatusCode:
+ // *UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusValue
+ // *UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass_
+ StatusCode isUptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusCode `protobuf_oneof:"status_code"`
+}
+
+func (x *UptimeCheckConfig_HttpCheck_ResponseStatusCode) Reset() {
+ *x = UptimeCheckConfig_HttpCheck_ResponseStatusCode{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UptimeCheckConfig_HttpCheck_ResponseStatusCode) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UptimeCheckConfig_HttpCheck_ResponseStatusCode) ProtoMessage() {}
+
+func (x *UptimeCheckConfig_HttpCheck_ResponseStatusCode) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[10]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_HttpCheck_ResponseStatusCode.ProtoReflect.Descriptor instead.
+func (*UptimeCheckConfig_HttpCheck_ResponseStatusCode) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 2, 1}
+}
+
+func (m *UptimeCheckConfig_HttpCheck_ResponseStatusCode) GetStatusCode() isUptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusCode {
+ if m != nil {
+ return m.StatusCode
+ }
+ return nil
+}
+
+func (x *UptimeCheckConfig_HttpCheck_ResponseStatusCode) GetStatusValue() int32 {
+ if x, ok := x.GetStatusCode().(*UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusValue); ok {
+ return x.StatusValue
+ }
+ return 0
+}
+
+func (x *UptimeCheckConfig_HttpCheck_ResponseStatusCode) GetStatusClass() UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass {
+ if x, ok := x.GetStatusCode().(*UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass_); ok {
+ return x.StatusClass
+ }
+ return UptimeCheckConfig_HttpCheck_ResponseStatusCode_STATUS_CLASS_UNSPECIFIED
+}
+
+type isUptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusCode interface {
+ isUptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusCode()
+}
+
+type UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusValue struct {
+ // A status code to accept.
+ StatusValue int32 `protobuf:"varint,1,opt,name=status_value,json=statusValue,proto3,oneof"`
+}
+
+type UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass_ struct {
+ // A class of status codes to accept.
+ StatusClass UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass `protobuf:"varint,2,opt,name=status_class,json=statusClass,proto3,enum=google.monitoring.v3.UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass,oneof"`
+}
+
+func (*UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusValue) isUptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusCode() {
+}
+
+func (*UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass_) isUptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusCode() {
+}
+
+// Information needed to perform a JSONPath content match.
+// Used for `ContentMatcherOption::MATCHES_JSON_PATH` and
+// `ContentMatcherOption::NOT_MATCHES_JSON_PATH`.
+type UptimeCheckConfig_ContentMatcher_JsonPathMatcher struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // JSONPath within the response output pointing to the expected
+ // `ContentMatcher::content` to match against.
+ JsonPath string `protobuf:"bytes,1,opt,name=json_path,json=jsonPath,proto3" json:"json_path,omitempty"`
+ // The type of JSONPath match that will be applied to the JSON output
+ // (`ContentMatcher.content`)
+ JsonMatcher UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption `protobuf:"varint,2,opt,name=json_matcher,json=jsonMatcher,proto3,enum=google.monitoring.v3.UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption" json:"json_matcher,omitempty"`
+}
+
+func (x *UptimeCheckConfig_ContentMatcher_JsonPathMatcher) Reset() {
+ *x = UptimeCheckConfig_ContentMatcher_JsonPathMatcher{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UptimeCheckConfig_ContentMatcher_JsonPathMatcher) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UptimeCheckConfig_ContentMatcher_JsonPathMatcher) ProtoMessage() {}
+
+func (x *UptimeCheckConfig_ContentMatcher_JsonPathMatcher) ProtoReflect() protoreflect.Message {
+ mi := &file_google_monitoring_v3_uptime_proto_msgTypes[12]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UptimeCheckConfig_ContentMatcher_JsonPathMatcher.ProtoReflect.Descriptor instead.
+func (*UptimeCheckConfig_ContentMatcher_JsonPathMatcher) Descriptor() ([]byte, []int) {
+ return file_google_monitoring_v3_uptime_proto_rawDescGZIP(), []int{1, 4, 0}
+}
+
+func (x *UptimeCheckConfig_ContentMatcher_JsonPathMatcher) GetJsonPath() string {
+ if x != nil {
+ return x.JsonPath
+ }
+ return ""
+}
+
+func (x *UptimeCheckConfig_ContentMatcher_JsonPathMatcher) GetJsonMatcher() UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption {
+ if x != nil {
+ return x.JsonMatcher
+ }
+ return UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JSON_PATH_MATCHER_OPTION_UNSPECIFIED
+}
+
+var File_google_monitoring_v3_uptime_proto protoreflect.FileDescriptor
+
+var file_google_monitoring_v3_uptime_proto_rawDesc = []byte{
+ 0x0a, 0x21, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61,
+ 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x23, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64,
+ 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
+ 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f,
+ 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa1, 0x02, 0x0a, 0x0f, 0x49,
+ 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x12,
+ 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61,
+ 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61,
+ 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12,
+ 0x19, 0x0a, 0x08, 0x67, 0x63, 0x70, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x07, 0x67, 0x63, 0x70, 0x5a, 0x6f, 0x6e, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65,
+ 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+ 0x49, 0x64, 0x12, 0x41, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28,
+ 0x0e, 0x32, 0x2b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
+ 0x6c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05,
+ 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x33, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0f,
+ 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12,
+ 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x45, 0x41, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0b, 0x0a,
+ 0x07, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x3a, 0x02, 0x18, 0x01, 0x22, 0x8b,
+ 0x1f, 0x0a, 0x11, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70,
+ 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
+ 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4e, 0x0a, 0x12, 0x6d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x00, 0x52, 0x11, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
+ 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x5e, 0x0a, 0x0e, 0x72,
+ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x04, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d,
+ 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x48, 0x00, 0x52, 0x0d, 0x72, 0x65,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x52, 0x0a, 0x0a, 0x68,
+ 0x74, 0x74, 0x70, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65,
+ 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x43, 0x68, 0x65,
+ 0x63, 0x6b, 0x48, 0x01, 0x52, 0x09, 0x68, 0x74, 0x74, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12,
+ 0x4f, 0x0a, 0x09, 0x74, 0x63, 0x70, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65,
+ 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x54, 0x63, 0x70, 0x43,
+ 0x68, 0x65, 0x63, 0x6b, 0x48, 0x01, 0x52, 0x08, 0x74, 0x63, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b,
+ 0x12, 0x31, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+ 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x70, 0x65, 0x72,
+ 0x69, 0x6f, 0x64, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x08,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+ 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x61, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x73, 0x18, 0x09, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65,
+ 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x6f, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x73, 0x12, 0x56, 0x0a, 0x0c, 0x63,
+ 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28,
+ 0x0e, 0x32, 0x33, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43,
+ 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b,
+ 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x54,
+ 0x79, 0x70, 0x65, 0x12, 0x52, 0x0a, 0x10, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f,
+ 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x27, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
+ 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b,
+ 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64,
+ 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x69, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01,
+ 0x52, 0x0a, 0x69, 0x73, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x56, 0x0a, 0x11,
+ 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72,
+ 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x49,
+ 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x42, 0x02,
+ 0x18, 0x01, 0x52, 0x10, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x68, 0x65, 0x63,
+ 0x6b, 0x65, 0x72, 0x73, 0x12, 0x58, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x61, 0x62,
+ 0x65, 0x6c, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
+ 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74,
+ 0x72, 0x79, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x78,
+ 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12,
+ 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x4c, 0x0a, 0x0d, 0x72, 0x65,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x0e, 0x32, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f,
+ 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x1a, 0x2d, 0x0a, 0x0a, 0x50, 0x69, 0x6e, 0x67,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x5f,
+ 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x70, 0x69, 0x6e,
+ 0x67, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0xc8, 0x0b, 0x0a, 0x09, 0x48, 0x74, 0x74, 0x70,
+ 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x66, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3f, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
+ 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b,
+ 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0d,
+ 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x17, 0x0a,
+ 0x07, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x73, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06,
+ 0x75, 0x73, 0x65, 0x53, 0x73, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f,
+ 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x62,
+ 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x45, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43,
+ 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x43,
+ 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e,
+ 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x49, 0x6e,
+ 0x66, 0x6f, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x73, 0x6b, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65,
+ 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6d, 0x61, 0x73, 0x6b, 0x48, 0x65,
+ 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x58, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
+ 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70,
+ 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
+ 0x48, 0x74, 0x74, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72,
+ 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12,
+ 0x60, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
+ 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74,
+ 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48,
+ 0x74, 0x74, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
+ 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
+ 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x63, 0x6f, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11,
+ 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
+ 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x73,
+ 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74,
+ 0x65, 0x53, 0x73, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x0a, 0x20, 0x01,
+ 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x89, 0x01, 0x0a, 0x1e, 0x61, 0x63, 0x63,
+ 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x73,
+ 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28,
+ 0x0b, 0x32, 0x44, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43,
+ 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x43,
+ 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x74, 0x61,
+ 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x1b, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65,
+ 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43,
+ 0x6f, 0x64, 0x65, 0x73, 0x12, 0x53, 0x0a, 0x0b, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
+ 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0a, 0x70,
+ 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x4d, 0x0a, 0x13, 0x42, 0x61, 0x73,
+ 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08,
+ 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+ 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x1a, 0xf6, 0x02, 0x0a, 0x12, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12,
+ 0x23, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56,
+ 0x61, 0x6c, 0x75, 0x65, 0x12, 0x75, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63,
+ 0x6c, 0x61, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x50, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
+ 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65,
+ 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x48, 0x00, 0x52, 0x0b,
+ 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x22, 0xb4, 0x01, 0x0a, 0x0b,
+ 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x18, 0x53,
+ 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50,
+ 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x54, 0x41,
+ 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x31, 0x58, 0x58, 0x10, 0x64, 0x12,
+ 0x15, 0x0a, 0x10, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f,
+ 0x32, 0x58, 0x58, 0x10, 0xc8, 0x01, 0x12, 0x15, 0x0a, 0x10, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
+ 0x5f, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x33, 0x58, 0x58, 0x10, 0xac, 0x02, 0x12, 0x15, 0x0a,
+ 0x10, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x34, 0x58,
+ 0x58, 0x10, 0x90, 0x03, 0x12, 0x15, 0x0a, 0x10, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43,
+ 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x35, 0x58, 0x58, 0x10, 0xf4, 0x03, 0x12, 0x15, 0x0a, 0x10, 0x53,
+ 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x41, 0x4e, 0x59, 0x10,
+ 0xe8, 0x07, 0x42, 0x0d, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x64,
+ 0x65, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+ 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x3a, 0x0a,
+ 0x0d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x16,
+ 0x0a, 0x12, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
+ 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x45, 0x54, 0x10, 0x01, 0x12,
+ 0x08, 0x0a, 0x04, 0x50, 0x4f, 0x53, 0x54, 0x10, 0x02, 0x22, 0x47, 0x0a, 0x0b, 0x43, 0x6f, 0x6e,
+ 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45,
+ 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f,
+ 0x0a, 0x0b, 0x55, 0x52, 0x4c, 0x5f, 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12,
+ 0x11, 0x0a, 0x0d, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, 0x45, 0x44,
+ 0x10, 0x02, 0x1a, 0x73, 0x0a, 0x08, 0x54, 0x63, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x12,
+ 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f,
+ 0x72, 0x74, 0x12, 0x53, 0x0a, 0x0b, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55,
+ 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x69, 0x6e,
+ 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x84, 0x06, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f,
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e,
+ 0x74, 0x65, 0x6e, 0x74, 0x12, 0x65, 0x0a, 0x07, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x4b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74,
+ 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43,
+ 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f,
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x4f, 0x70, 0x74, 0x69,
+ 0x6f, 0x6e, 0x52, 0x07, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x74, 0x0a, 0x11, 0x6a,
+ 0x73, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70,
+ 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
+ 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x4a,
+ 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x48, 0x00,
+ 0x52, 0x0f, 0x6a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65,
+ 0x72, 0x1a, 0x94, 0x02, 0x0a, 0x0f, 0x4a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61,
+ 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x70, 0x61,
+ 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6a, 0x73, 0x6f, 0x6e, 0x50, 0x61,
+ 0x74, 0x68, 0x12, 0x7f, 0x0a, 0x0c, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68,
+ 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x5c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e,
+ 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
+ 0x2e, 0x4a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
+ 0x2e, 0x4a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72,
+ 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x6a, 0x73, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63,
+ 0x68, 0x65, 0x72, 0x22, 0x63, 0x0a, 0x15, 0x4a, 0x73, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x4d,
+ 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x24,
+ 0x4a, 0x53, 0x4f, 0x4e, 0x5f, 0x50, 0x41, 0x54, 0x48, 0x5f, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x45,
+ 0x52, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
+ 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x45, 0x58, 0x41, 0x43, 0x54, 0x5f,
+ 0x4d, 0x41, 0x54, 0x43, 0x48, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x45, 0x47, 0x45, 0x58,
+ 0x5f, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x10, 0x02, 0x22, 0xc8, 0x01, 0x0a, 0x14, 0x43, 0x6f, 0x6e,
+ 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x4f, 0x70, 0x74, 0x69, 0x6f,
+ 0x6e, 0x12, 0x26, 0x0a, 0x22, 0x43, 0x4f, 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x5f, 0x4d, 0x41, 0x54,
+ 0x43, 0x48, 0x45, 0x52, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50,
+ 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4f, 0x4e,
+ 0x54, 0x41, 0x49, 0x4e, 0x53, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x17,
+ 0x0a, 0x13, 0x4e, 0x4f, 0x54, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, 0x53, 0x5f, 0x53,
+ 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x41, 0x54, 0x43, 0x48,
+ 0x45, 0x53, 0x5f, 0x52, 0x45, 0x47, 0x45, 0x58, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x4e, 0x4f,
+ 0x54, 0x5f, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x47, 0x45, 0x58, 0x10,
+ 0x04, 0x12, 0x15, 0x0a, 0x11, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x45, 0x53, 0x5f, 0x4a, 0x53, 0x4f,
+ 0x4e, 0x5f, 0x50, 0x41, 0x54, 0x48, 0x10, 0x05, 0x12, 0x19, 0x0a, 0x15, 0x4e, 0x4f, 0x54, 0x5f,
+ 0x4d, 0x41, 0x54, 0x43, 0x48, 0x45, 0x53, 0x5f, 0x4a, 0x53, 0x4f, 0x4e, 0x5f, 0x50, 0x41, 0x54,
+ 0x48, 0x10, 0x06, 0x42, 0x19, 0x0a, 0x17, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61,
+ 0x6c, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x1a, 0x3d,
+ 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+ 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x55, 0x0a,
+ 0x0b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x18,
+ 0x43, 0x48, 0x45, 0x43, 0x4b, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53,
+ 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x54,
+ 0x41, 0x54, 0x49, 0x43, 0x5f, 0x49, 0x50, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x45, 0x52, 0x53,
+ 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x56, 0x50, 0x43, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x45,
+ 0x52, 0x53, 0x10, 0x03, 0x3a, 0xf3, 0x01, 0xea, 0x41, 0xef, 0x01, 0x0a, 0x2b, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
+ 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65,
+ 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+ 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x75, 0x70, 0x74,
+ 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x2f,
+ 0x7b, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x7d, 0x12, 0x45, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x7d, 0x2f, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x2f, 0x7b, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63,
+ 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x7d, 0x12, 0x39, 0x66, 0x6f,
+ 0x6c, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x7d, 0x2f, 0x75,
+ 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x73, 0x2f, 0x7b, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f,
+ 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x7d, 0x12, 0x01, 0x2a, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x14, 0x0a, 0x12, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f,
+ 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x8b, 0x01, 0x0a,
+ 0x0d, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x70, 0x12, 0x3f,
+ 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
+ 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63,
+ 0x6b, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12,
+ 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x69,
+ 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x09, 0x69, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2a, 0x95, 0x01, 0x0a, 0x11, 0x55,
+ 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e,
+ 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x47, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45,
+ 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x53, 0x41, 0x10,
+ 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x55, 0x52, 0x4f, 0x50, 0x45, 0x10, 0x02, 0x12, 0x11, 0x0a,
+ 0x0d, 0x53, 0x4f, 0x55, 0x54, 0x48, 0x5f, 0x41, 0x4d, 0x45, 0x52, 0x49, 0x43, 0x41, 0x10, 0x03,
+ 0x12, 0x10, 0x0a, 0x0c, 0x41, 0x53, 0x49, 0x41, 0x5f, 0x50, 0x41, 0x43, 0x49, 0x46, 0x49, 0x43,
+ 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x53, 0x41, 0x5f, 0x4f, 0x52, 0x45, 0x47, 0x4f, 0x4e,
+ 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x41, 0x5f, 0x49, 0x4f, 0x57, 0x41, 0x10, 0x06,
+ 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x53, 0x41, 0x5f, 0x56, 0x49, 0x52, 0x47, 0x49, 0x4e, 0x49, 0x41,
+ 0x10, 0x07, 0x2a, 0x5b, 0x0a, 0x11, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x53, 0x4f, 0x55,
+ 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
+ 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4e,
+ 0x43, 0x45, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x57, 0x53, 0x5f, 0x45, 0x4c, 0x42, 0x5f,
+ 0x4c, 0x4f, 0x41, 0x44, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x52, 0x10, 0x02, 0x42,
+ 0xc6, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x0b, 0x55, 0x70,
+ 0x74, 0x69, 0x6d, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x63, 0x6c, 0x6f,
+ 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f,
+ 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x76,
+ 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70,
+ 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x70, 0x62, 0xaa, 0x02,
+ 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f,
+ 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
+ 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_google_monitoring_v3_uptime_proto_rawDescOnce sync.Once
+ file_google_monitoring_v3_uptime_proto_rawDescData = file_google_monitoring_v3_uptime_proto_rawDesc
+)
+
+func file_google_monitoring_v3_uptime_proto_rawDescGZIP() []byte {
+ file_google_monitoring_v3_uptime_proto_rawDescOnce.Do(func() {
+ file_google_monitoring_v3_uptime_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_monitoring_v3_uptime_proto_rawDescData)
+ })
+ return file_google_monitoring_v3_uptime_proto_rawDescData
+}
+
+var file_google_monitoring_v3_uptime_proto_enumTypes = make([]protoimpl.EnumInfo, 9)
+var file_google_monitoring_v3_uptime_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
+var file_google_monitoring_v3_uptime_proto_goTypes = []interface{}{
+ (UptimeCheckRegion)(0), // 0: google.monitoring.v3.UptimeCheckRegion
+ (GroupResourceType)(0), // 1: google.monitoring.v3.GroupResourceType
+ (InternalChecker_State)(0), // 2: google.monitoring.v3.InternalChecker.State
+ (UptimeCheckConfig_CheckerType)(0), // 3: google.monitoring.v3.UptimeCheckConfig.CheckerType
+ (UptimeCheckConfig_HttpCheck_RequestMethod)(0), // 4: google.monitoring.v3.UptimeCheckConfig.HttpCheck.RequestMethod
+ (UptimeCheckConfig_HttpCheck_ContentType)(0), // 5: google.monitoring.v3.UptimeCheckConfig.HttpCheck.ContentType
+ (UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass)(0), // 6: google.monitoring.v3.UptimeCheckConfig.HttpCheck.ResponseStatusCode.StatusClass
+ (UptimeCheckConfig_ContentMatcher_ContentMatcherOption)(0), // 7: google.monitoring.v3.UptimeCheckConfig.ContentMatcher.ContentMatcherOption
+ (UptimeCheckConfig_ContentMatcher_JsonPathMatcher_JsonPathMatcherOption)(0), // 8: google.monitoring.v3.UptimeCheckConfig.ContentMatcher.JsonPathMatcher.JsonPathMatcherOption
+ (*InternalChecker)(nil), // 9: google.monitoring.v3.InternalChecker
+ (*UptimeCheckConfig)(nil), // 10: google.monitoring.v3.UptimeCheckConfig
+ (*UptimeCheckIp)(nil), // 11: google.monitoring.v3.UptimeCheckIp
+ (*UptimeCheckConfig_ResourceGroup)(nil), // 12: google.monitoring.v3.UptimeCheckConfig.ResourceGroup
+ (*UptimeCheckConfig_PingConfig)(nil), // 13: google.monitoring.v3.UptimeCheckConfig.PingConfig
+ (*UptimeCheckConfig_HttpCheck)(nil), // 14: google.monitoring.v3.UptimeCheckConfig.HttpCheck
+ (*UptimeCheckConfig_TcpCheck)(nil), // 15: google.monitoring.v3.UptimeCheckConfig.TcpCheck
+ (*UptimeCheckConfig_ContentMatcher)(nil), // 16: google.monitoring.v3.UptimeCheckConfig.ContentMatcher
+ nil, // 17: google.monitoring.v3.UptimeCheckConfig.UserLabelsEntry
+ (*UptimeCheckConfig_HttpCheck_BasicAuthentication)(nil), // 18: google.monitoring.v3.UptimeCheckConfig.HttpCheck.BasicAuthentication
+ (*UptimeCheckConfig_HttpCheck_ResponseStatusCode)(nil), // 19: google.monitoring.v3.UptimeCheckConfig.HttpCheck.ResponseStatusCode
+ nil, // 20: google.monitoring.v3.UptimeCheckConfig.HttpCheck.HeadersEntry
+ (*UptimeCheckConfig_ContentMatcher_JsonPathMatcher)(nil), // 21: google.monitoring.v3.UptimeCheckConfig.ContentMatcher.JsonPathMatcher
+ (*monitoredres.MonitoredResource)(nil), // 22: google.api.MonitoredResource
+ (*durationpb.Duration)(nil), // 23: google.protobuf.Duration
+}
+var file_google_monitoring_v3_uptime_proto_depIdxs = []int32{
+ 2, // 0: google.monitoring.v3.InternalChecker.state:type_name -> google.monitoring.v3.InternalChecker.State
+ 22, // 1: google.monitoring.v3.UptimeCheckConfig.monitored_resource:type_name -> google.api.MonitoredResource
+ 12, // 2: google.monitoring.v3.UptimeCheckConfig.resource_group:type_name -> google.monitoring.v3.UptimeCheckConfig.ResourceGroup
+ 14, // 3: google.monitoring.v3.UptimeCheckConfig.http_check:type_name -> google.monitoring.v3.UptimeCheckConfig.HttpCheck
+ 15, // 4: google.monitoring.v3.UptimeCheckConfig.tcp_check:type_name -> google.monitoring.v3.UptimeCheckConfig.TcpCheck
+ 23, // 5: google.monitoring.v3.UptimeCheckConfig.period:type_name -> google.protobuf.Duration
+ 23, // 6: google.monitoring.v3.UptimeCheckConfig.timeout:type_name -> google.protobuf.Duration
+ 16, // 7: google.monitoring.v3.UptimeCheckConfig.content_matchers:type_name -> google.monitoring.v3.UptimeCheckConfig.ContentMatcher
+ 3, // 8: google.monitoring.v3.UptimeCheckConfig.checker_type:type_name -> google.monitoring.v3.UptimeCheckConfig.CheckerType
+ 0, // 9: google.monitoring.v3.UptimeCheckConfig.selected_regions:type_name -> google.monitoring.v3.UptimeCheckRegion
+ 9, // 10: google.monitoring.v3.UptimeCheckConfig.internal_checkers:type_name -> google.monitoring.v3.InternalChecker
+ 17, // 11: google.monitoring.v3.UptimeCheckConfig.user_labels:type_name -> google.monitoring.v3.UptimeCheckConfig.UserLabelsEntry
+ 0, // 12: google.monitoring.v3.UptimeCheckIp.region:type_name -> google.monitoring.v3.UptimeCheckRegion
+ 1, // 13: google.monitoring.v3.UptimeCheckConfig.ResourceGroup.resource_type:type_name -> google.monitoring.v3.GroupResourceType
+ 4, // 14: google.monitoring.v3.UptimeCheckConfig.HttpCheck.request_method:type_name -> google.monitoring.v3.UptimeCheckConfig.HttpCheck.RequestMethod
+ 18, // 15: google.monitoring.v3.UptimeCheckConfig.HttpCheck.auth_info:type_name -> google.monitoring.v3.UptimeCheckConfig.HttpCheck.BasicAuthentication
+ 20, // 16: google.monitoring.v3.UptimeCheckConfig.HttpCheck.headers:type_name -> google.monitoring.v3.UptimeCheckConfig.HttpCheck.HeadersEntry
+ 5, // 17: google.monitoring.v3.UptimeCheckConfig.HttpCheck.content_type:type_name -> google.monitoring.v3.UptimeCheckConfig.HttpCheck.ContentType
+ 19, // 18: google.monitoring.v3.UptimeCheckConfig.HttpCheck.accepted_response_status_codes:type_name -> google.monitoring.v3.UptimeCheckConfig.HttpCheck.ResponseStatusCode
+ 13, // 19: google.monitoring.v3.UptimeCheckConfig.HttpCheck.ping_config:type_name -> google.monitoring.v3.UptimeCheckConfig.PingConfig
+ 13, // 20: google.monitoring.v3.UptimeCheckConfig.TcpCheck.ping_config:type_name -> google.monitoring.v3.UptimeCheckConfig.PingConfig
+ 7, // 21: google.monitoring.v3.UptimeCheckConfig.ContentMatcher.matcher:type_name -> google.monitoring.v3.UptimeCheckConfig.ContentMatcher.ContentMatcherOption
+ 21, // 22: google.monitoring.v3.UptimeCheckConfig.ContentMatcher.json_path_matcher:type_name -> google.monitoring.v3.UptimeCheckConfig.ContentMatcher.JsonPathMatcher
+ 6, // 23: google.monitoring.v3.UptimeCheckConfig.HttpCheck.ResponseStatusCode.status_class:type_name -> google.monitoring.v3.UptimeCheckConfig.HttpCheck.ResponseStatusCode.StatusClass
+ 8, // 24: google.monitoring.v3.UptimeCheckConfig.ContentMatcher.JsonPathMatcher.json_matcher:type_name -> google.monitoring.v3.UptimeCheckConfig.ContentMatcher.JsonPathMatcher.JsonPathMatcherOption
+ 25, // [25:25] is the sub-list for method output_type
+ 25, // [25:25] is the sub-list for method input_type
+ 25, // [25:25] is the sub-list for extension type_name
+ 25, // [25:25] is the sub-list for extension extendee
+ 0, // [0:25] is the sub-list for field type_name
+}
+
+func init() { file_google_monitoring_v3_uptime_proto_init() }
+func file_google_monitoring_v3_uptime_proto_init() {
+ if File_google_monitoring_v3_uptime_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_google_monitoring_v3_uptime_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*InternalChecker); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UptimeCheckConfig); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UptimeCheckIp); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UptimeCheckConfig_ResourceGroup); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UptimeCheckConfig_PingConfig); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UptimeCheckConfig_HttpCheck); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UptimeCheckConfig_TcpCheck); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UptimeCheckConfig_ContentMatcher); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UptimeCheckConfig_HttpCheck_BasicAuthentication); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UptimeCheckConfig_HttpCheck_ResponseStatusCode); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UptimeCheckConfig_ContentMatcher_JsonPathMatcher); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[1].OneofWrappers = []interface{}{
+ (*UptimeCheckConfig_MonitoredResource)(nil),
+ (*UptimeCheckConfig_ResourceGroup_)(nil),
+ (*UptimeCheckConfig_HttpCheck_)(nil),
+ (*UptimeCheckConfig_TcpCheck_)(nil),
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[7].OneofWrappers = []interface{}{
+ (*UptimeCheckConfig_ContentMatcher_JsonPathMatcher_)(nil),
+ }
+ file_google_monitoring_v3_uptime_proto_msgTypes[10].OneofWrappers = []interface{}{
+ (*UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusValue)(nil),
+ (*UptimeCheckConfig_HttpCheck_ResponseStatusCode_StatusClass_)(nil),
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_google_monitoring_v3_uptime_proto_rawDesc,
+ NumEnums: 9,
+ NumMessages: 13,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_google_monitoring_v3_uptime_proto_goTypes,
+ DependencyIndexes: file_google_monitoring_v3_uptime_proto_depIdxs,
+ EnumInfos: file_google_monitoring_v3_uptime_proto_enumTypes,
+ MessageInfos: file_google_monitoring_v3_uptime_proto_msgTypes,
+ }.Build()
+ File_google_monitoring_v3_uptime_proto = out.File
+ file_google_monitoring_v3_uptime_proto_rawDesc = nil
+ file_google_monitoring_v3_uptime_proto_goTypes = nil
+ file_google_monitoring_v3_uptime_proto_depIdxs = nil
+}
diff --git a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/uptime_service.pb.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/uptime_service.pb.go
similarity index 75%
rename from vendor/google.golang.org/genproto/googleapis/monitoring/v3/uptime_service.pb.go
rename to vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/uptime_service.pb.go
index e2514194d52..838cec626d7 100644
--- a/vendor/google.golang.org/genproto/googleapis/monitoring/v3/uptime_service.pb.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/monitoringpb/uptime_service.pb.go
@@ -1,4 +1,4 @@
-// Copyright 2021 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,11 +14,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.26.0
-// protoc v3.12.2
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
// source: google/monitoring/v3/uptime_service.proto
-package monitoring
+package monitoringpb
import (
context "context"
@@ -54,6 +54,12 @@ type ListUptimeCheckConfigsRequest struct {
//
// projects/[PROJECT_ID_OR_NUMBER]
Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // If provided, this field specifies the criteria that must be met by
+ // uptime checks to be included in the response.
+ //
+ // For more details, see [Filtering
+ // syntax](https://cloud.google.com/monitoring/api/v3/sorting-and-filtering#filter_syntax).
+ Filter string `protobuf:"bytes,2,opt,name=filter,proto3" json:"filter,omitempty"`
// The maximum number of results to return in a single response. The server
// may further constrain the maximum number of results returned in a single
// page. If the page_size is <=0, the server will decide the number of results
@@ -104,6 +110,13 @@ func (x *ListUptimeCheckConfigsRequest) GetParent() string {
return ""
}
+func (x *ListUptimeCheckConfigsRequest) GetFilter() string {
+ if x != nil {
+ return x.Filter
+ }
+ return ""
+}
+
func (x *ListUptimeCheckConfigsRequest) GetPageSize() int32 {
if x != nil {
return x.PageSize
@@ -318,7 +331,7 @@ type UpdateUptimeCheckConfigRequest struct {
// the values for the set of fields mentioned in the `updateMask`. If an
// `updateMask` has not been given, this Uptime check configuration replaces
// the current configuration. If a field is mentioned in `updateMask` but
- // the corresonding field is omitted in this partial Uptime check
+ // the corresponding field is omitted in this partial Uptime check
// configuration, it has the effect of deleting/clearing the field from the
// configuration on the server.
//
@@ -574,180 +587,182 @@ var file_google_monitoring_v3_uptime_service_proto_rawDesc = []byte{
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b,
- 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa8, 0x01, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x55,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc0, 0x01, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x55,
0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65,
0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x2d,
0x12, 0x2b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x70, 0x74, 0x69,
0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x70,
- 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69,
- 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69,
- 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
- 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65,
- 0x6e, 0x22, 0xc2, 0x01, 0x0a, 0x1e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65,
- 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x14, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63,
- 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03,
- 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
- 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65,
- 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x12, 0x75, 0x70, 0x74,
- 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12,
- 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b,
- 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61,
- 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c,
- 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x6f, 0x74,
- 0x61, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x66, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x55, 0x70, 0x74,
- 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x47, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x2d, 0x0a, 0x2b, 0x6d, 0x6f, 0x6e,
- 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
- 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65,
- 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xcb,
- 0x01, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43,
- 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x12, 0x4b, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x42, 0x33, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x2d, 0x12, 0x2b, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
- 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73,
- 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b,
- 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x5c,
- 0x0a, 0x13, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63,
- 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x67, 0x6f,
- 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f,
- 0x6e, 0x66, 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x11, 0x75, 0x70, 0x74, 0x69, 0x6d,
- 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xbb, 0x01, 0x0a,
- 0x1e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65,
- 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b,
- 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x5c, 0x0a, 0x13,
- 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
- 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
- 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66,
- 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x11, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43,
- 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x69, 0x0a, 0x1e, 0x44, 0x65,
- 0x6c, 0x65, 0x74, 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43,
- 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x47, 0x0a, 0x04,
- 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x02, 0xfa,
- 0x41, 0x2d, 0x0a, 0x2b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67,
- 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x70,
- 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
- 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x57, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x74,
- 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
- 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12,
- 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x93,
- 0x01, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65,
- 0x63, 0x6b, 0x49, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a,
- 0x10, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x69, 0x70,
- 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
- 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55,
- 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x70, 0x52, 0x0e, 0x75, 0x70,
- 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x70, 0x73, 0x12, 0x26, 0x0a, 0x0f,
- 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54,
- 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0xbd, 0x0a, 0x0a, 0x12, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43,
- 0x68, 0x65, 0x63, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xc0, 0x01, 0x0a, 0x16,
- 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43,
- 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x33, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
- 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69,
+ 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1b, 0x0a,
+ 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05,
+ 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61,
+ 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
+ 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xc2, 0x01, 0x0a, 0x1e, 0x4c, 0x69,
0x73, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x67, 0x6f,
- 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65,
- 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x22, 0x3b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x12, 0x2a, 0x2f, 0x76, 0x33, 0x2f, 0x7b,
- 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f,
- 0x2a, 0x7d, 0x2f, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f,
- 0x6e, 0x66, 0x69, 0x67, 0x73, 0xda, 0x41, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0xad,
- 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63,
- 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
- 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47,
- 0x65, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x14,
+ 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x12, 0x2a, 0x2f, 0x76, 0x33,
- 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f,
- 0x2a, 0x2f, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x73, 0x2f, 0x2a, 0x7d, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0xde,
- 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43,
- 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x6f,
- 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
- 0x33, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68,
- 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x1a, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
- 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68,
- 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x64, 0x82, 0xd3, 0xe4, 0x93, 0x02,
- 0x41, 0x22, 0x2a, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70,
- 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x75, 0x70, 0x74, 0x69, 0x6d,
- 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x3a, 0x13, 0x75,
- 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
- 0x69, 0x67, 0xda, 0x41, 0x1a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x75, 0x70, 0x74, 0x69,
- 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
- 0xeb, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65,
- 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x2e, 0x67, 0x6f,
- 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x76, 0x33, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43,
- 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x1a, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x66, 0x69, 0x67, 0x52, 0x12, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f,
+ 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12,
+ 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x66,
+ 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x47, 0x0a,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x02,
+ 0xfa, 0x41, 0x2d, 0x0a, 0x2b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55,
+ 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xcb, 0x01, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74,
+ 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x06, 0x70, 0x61, 0x72,
+ 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x02, 0xfa, 0x41,
+ 0x2d, 0x12, 0x2b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x70, 0x74,
+ 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06,
+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x5c, 0x0a, 0x13, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
+ 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d,
+ 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41,
+ 0x02, 0x52, 0x11, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x22, 0xbb, 0x01, 0x0a, 0x1e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55,
+ 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46,
+ 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
+ 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x5c, 0x0a, 0x13, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63,
+ 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43,
- 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x71, 0x82, 0xd3, 0xe4, 0x93,
- 0x02, 0x55, 0x32, 0x3e, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f,
- 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x6e, 0x61, 0x6d,
- 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x75, 0x70, 0x74,
- 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x2f,
- 0x2a, 0x7d, 0x3a, 0x13, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b,
- 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0xda, 0x41, 0x13, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
- 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0xa2, 0x01,
- 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68,
- 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
- 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
- 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65,
- 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
- 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
- 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x2a,
- 0x2a, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65,
- 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63,
- 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x2f, 0x2a, 0x7d, 0xda, 0x41, 0x04, 0x6e, 0x61,
- 0x6d, 0x65, 0x12, 0x93, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d,
- 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x70, 0x73, 0x12, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52,
+ 0x11, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x22, 0x69, 0x0a, 0x1e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x70, 0x74, 0x69,
+ 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x12, 0x47, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x2d, 0x0a, 0x2b, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69,
+ 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63,
+ 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x57, 0x0a,
+ 0x19, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b,
+ 0x49, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61,
+ 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70,
+ 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f,
+ 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67,
+ 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x93, 0x01, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x55,
+ 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x70, 0x73, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x10, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f,
+ 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x23, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65,
+ 0x63, 0x6b, 0x49, 0x70, 0x52, 0x0e, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63,
+ 0x6b, 0x49, 0x70, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67,
+ 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e,
+ 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0xbd, 0x0a, 0x0a,
+ 0x12, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x65, 0x72, 0x76,
+ 0x69, 0x63, 0x65, 0x12, 0xc0, 0x01, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x74, 0x69,
+ 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x33,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
+ 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65,
+ 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55,
+ 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3b, 0xda, 0x41, 0x06, 0x70, 0x61,
+ 0x72, 0x65, 0x6e, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x12, 0x2a, 0x2f, 0x76, 0x33, 0x2f,
+ 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73,
+ 0x2f, 0x2a, 0x7d, 0x2f, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0xad, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x55, 0x70,
+ 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
+ 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65,
+ 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65,
+ 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x39, 0xda, 0x41, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x12, 0x2a, 0x2f, 0x76, 0x33, 0x2f,
+ 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a,
+ 0x2f, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xde, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74,
+ 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
+ 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e,
+ 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x22, 0x64, 0xda, 0x41, 0x1a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x75, 0x70, 0x74,
+ 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x3a, 0x13, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63,
+ 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x2a, 0x2f, 0x76, 0x33,
+ 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+ 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0xeb, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61,
+ 0x74, 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
- 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b,
- 0x49, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x67, 0x6f, 0x6f,
- 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
- 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63,
- 0x6b, 0x49, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3,
- 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76, 0x33, 0x2f, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
- 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x70, 0x73, 0x1a, 0xa9, 0x01, 0xca, 0x41, 0x19, 0x6d, 0x6f,
- 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61,
- 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0xd2, 0x41, 0x89, 0x01, 0x68, 0x74, 0x74, 0x70, 0x73,
- 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69,
- 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64,
- 0x2d, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a,
- 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73,
- 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
- 0x72, 0x69, 0x6e, 0x67, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
- 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
- 0x61, 0x75, 0x74, 0x68, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x72, 0x65, 0x61, 0x64, 0x42, 0xca, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f,
- 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76,
- 0x33, 0x42, 0x12, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
- 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
- 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x6d,
- 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x3b, 0x6d, 0x6f, 0x6e,
- 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
- 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
- 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c,
- 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56,
- 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75,
- 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56,
- 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x2e, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x22, 0x71, 0xda, 0x41, 0x13, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x68,
+ 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x55,
+ 0x3a, 0x13, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32, 0x3e, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x75, 0x70, 0x74, 0x69,
+ 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
+ 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f,
+ 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xa2, 0x01, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
+ 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55,
+ 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
+ 0x39, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x2a, 0x2a,
+ 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+ 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0x93, 0x01, 0x0a, 0x12, 0x4c,
+ 0x69, 0x73, 0x74, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x70,
+ 0x73, 0x12, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
+ 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x74,
+ 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70,
+ 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76,
+ 0x33, 0x2f, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x70, 0x73,
+ 0x1a, 0xa9, 0x01, 0xca, 0x41, 0x19, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0xd2,
+ 0x41, 0x89, 0x01, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75,
+ 0x74, 0x68, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72,
+ 0x6d, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74,
+ 0x68, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2c, 0x68, 0x74, 0x74,
+ 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61,
+ 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x6d, 0x6f, 0x6e,
+ 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x42, 0xcd, 0x01, 0x0a,
+ 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
+ 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x12, 0x55, 0x70, 0x74, 0x69, 0x6d,
+ 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a,
+ 0x41, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f,
+ 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+ 0x69, 0x6e, 0x67, 0x70, 0x62, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x70, 0x62, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75,
+ 0x64, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca,
+ 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d,
+ 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f,
+ 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/notification_channel_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/notification_channel_client.go
index d732affec53..04836724bcb 100644
--- a/vendor/cloud.google.com/go/monitoring/apiv3/v2/notification_channel_client.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/notification_channel_client.go
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -23,12 +23,12 @@ import (
"net/url"
"time"
+ monitoringpb "cloud.google.com/go/monitoring/apiv3/v2/monitoringpb"
gax "github.com/googleapis/gax-go/v2"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
"google.golang.org/api/option/internaloption"
gtransport "google.golang.org/api/transport/grpc"
- monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
@@ -66,6 +66,7 @@ func defaultNotificationChannelGRPCClientOptions() []option.ClientOption {
func defaultNotificationChannelCallOptions() *NotificationChannelCallOptions {
return &NotificationChannelCallOptions{
ListNotificationChannelDescriptors: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -77,6 +78,7 @@ func defaultNotificationChannelCallOptions() *NotificationChannelCallOptions {
}),
},
GetNotificationChannelDescriptor: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -88,6 +90,7 @@ func defaultNotificationChannelCallOptions() *NotificationChannelCallOptions {
}),
},
ListNotificationChannels: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -99,6 +102,7 @@ func defaultNotificationChannelCallOptions() *NotificationChannelCallOptions {
}),
},
GetNotificationChannel: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -109,9 +113,14 @@ func defaultNotificationChannelCallOptions() *NotificationChannelCallOptions {
})
}),
},
- CreateNotificationChannel: []gax.CallOption{},
- UpdateNotificationChannel: []gax.CallOption{},
+ CreateNotificationChannel: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
+ UpdateNotificationChannel: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
DeleteNotificationChannel: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -122,8 +131,11 @@ func defaultNotificationChannelCallOptions() *NotificationChannelCallOptions {
})
}),
},
- SendNotificationChannelVerificationCode: []gax.CallOption{},
+ SendNotificationChannelVerificationCode: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
GetNotificationChannelVerificationCode: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -135,6 +147,7 @@ func defaultNotificationChannelCallOptions() *NotificationChannelCallOptions {
}),
},
VerifyNotificationChannel: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -148,7 +161,7 @@ func defaultNotificationChannelCallOptions() *NotificationChannelCallOptions {
}
}
-// internalNotificationChannelClient is an interface that defines the methods availaible from Cloud Monitoring API.
+// internalNotificationChannelClient is an interface that defines the methods available from Cloud Monitoring API.
type internalNotificationChannelClient interface {
Close() error
setGoogleClientInfo(...string)
@@ -195,7 +208,8 @@ func (c *NotificationChannelClient) setGoogleClientInfo(keyval ...string) {
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *NotificationChannelClient) Connection() *grpc.ClientConn {
return c.internalClient.Connection()
}
@@ -288,9 +302,6 @@ type notificationChannelGRPCClient struct {
// Connection pool of gRPC connections to the service.
connPool gtransport.ConnPool
- // flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE
- disableDeadlines bool
-
// Points back to the CallOptions field of the containing NotificationChannelClient
CallOptions **NotificationChannelCallOptions
@@ -316,11 +327,6 @@ func NewNotificationChannelClient(ctx context.Context, opts ...option.ClientOpti
clientOpts = append(clientOpts, hookOpts...)
}
- disableDeadlines, err := checkDisableDeadlines()
- if err != nil {
- return nil, err
- }
-
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
if err != nil {
return nil, err
@@ -329,7 +335,6 @@ func NewNotificationChannelClient(ctx context.Context, opts ...option.ClientOpti
c := ¬ificationChannelGRPCClient{
connPool: connPool,
- disableDeadlines: disableDeadlines,
notificationChannelClient: monitoringpb.NewNotificationChannelServiceClient(connPool),
CallOptions: &client.CallOptions,
}
@@ -342,7 +347,8 @@ func NewNotificationChannelClient(ctx context.Context, opts ...option.ClientOpti
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *notificationChannelGRPCClient) Connection() *grpc.ClientConn {
return c.connPool.Conn()
}
@@ -351,7 +357,7 @@ func (c *notificationChannelGRPCClient) Connection() *grpc.ClientConn {
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *notificationChannelGRPCClient) setGoogleClientInfo(keyval ...string) {
- kv := append([]string{"gl-go", versionGo()}, keyval...)
+ kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version)
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
}
@@ -408,11 +414,6 @@ func (c *notificationChannelGRPCClient) ListNotificationChannelDescriptors(ctx c
}
func (c *notificationChannelGRPCClient) GetNotificationChannelDescriptor(ctx context.Context, req *monitoringpb.GetNotificationChannelDescriptorRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannelDescriptor, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -475,11 +476,6 @@ func (c *notificationChannelGRPCClient) ListNotificationChannels(ctx context.Con
}
func (c *notificationChannelGRPCClient) GetNotificationChannel(ctx context.Context, req *monitoringpb.GetNotificationChannelRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannel, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -497,11 +493,6 @@ func (c *notificationChannelGRPCClient) GetNotificationChannel(ctx context.Conte
}
func (c *notificationChannelGRPCClient) CreateNotificationChannel(ctx context.Context, req *monitoringpb.CreateNotificationChannelRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannel, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -519,11 +510,6 @@ func (c *notificationChannelGRPCClient) CreateNotificationChannel(ctx context.Co
}
func (c *notificationChannelGRPCClient) UpdateNotificationChannel(ctx context.Context, req *monitoringpb.UpdateNotificationChannelRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannel, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "notification_channel.name", url.QueryEscape(req.GetNotificationChannel().GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -541,11 +527,6 @@ func (c *notificationChannelGRPCClient) UpdateNotificationChannel(ctx context.Co
}
func (c *notificationChannelGRPCClient) DeleteNotificationChannel(ctx context.Context, req *monitoringpb.DeleteNotificationChannelRequest, opts ...gax.CallOption) error {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -559,11 +540,6 @@ func (c *notificationChannelGRPCClient) DeleteNotificationChannel(ctx context.Co
}
func (c *notificationChannelGRPCClient) SendNotificationChannelVerificationCode(ctx context.Context, req *monitoringpb.SendNotificationChannelVerificationCodeRequest, opts ...gax.CallOption) error {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -577,11 +553,6 @@ func (c *notificationChannelGRPCClient) SendNotificationChannelVerificationCode(
}
func (c *notificationChannelGRPCClient) GetNotificationChannelVerificationCode(ctx context.Context, req *monitoringpb.GetNotificationChannelVerificationCodeRequest, opts ...gax.CallOption) (*monitoringpb.GetNotificationChannelVerificationCodeResponse, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -599,11 +570,6 @@ func (c *notificationChannelGRPCClient) GetNotificationChannelVerificationCode(c
}
func (c *notificationChannelGRPCClient) VerifyNotificationChannel(ctx context.Context, req *monitoringpb.VerifyNotificationChannelRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannel, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/query_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/query_client.go
index e2e2b916df7..5dd3b8f16d5 100644
--- a/vendor/cloud.google.com/go/monitoring/apiv3/v2/query_client.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/query_client.go
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -22,12 +22,12 @@ import (
"math"
"net/url"
+ monitoringpb "cloud.google.com/go/monitoring/apiv3/v2/monitoringpb"
gax "github.com/googleapis/gax-go/v2"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
"google.golang.org/api/option/internaloption"
gtransport "google.golang.org/api/transport/grpc"
- monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/proto"
@@ -58,7 +58,7 @@ func defaultQueryCallOptions() *QueryCallOptions {
}
}
-// internalQueryClient is an interface that defines the methods availaible from Cloud Monitoring API.
+// internalQueryClient is an interface that defines the methods available from Cloud Monitoring API.
type internalQueryClient interface {
Close() error
setGoogleClientInfo(...string)
@@ -97,7 +97,8 @@ func (c *QueryClient) setGoogleClientInfo(keyval ...string) {
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *QueryClient) Connection() *grpc.ClientConn {
return c.internalClient.Connection()
}
@@ -114,9 +115,6 @@ type queryGRPCClient struct {
// Connection pool of gRPC connections to the service.
connPool gtransport.ConnPool
- // flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE
- disableDeadlines bool
-
// Points back to the CallOptions field of the containing QueryClient
CallOptions **QueryCallOptions
@@ -143,11 +141,6 @@ func NewQueryClient(ctx context.Context, opts ...option.ClientOption) (*QueryCli
clientOpts = append(clientOpts, hookOpts...)
}
- disableDeadlines, err := checkDisableDeadlines()
- if err != nil {
- return nil, err
- }
-
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
if err != nil {
return nil, err
@@ -155,10 +148,9 @@ func NewQueryClient(ctx context.Context, opts ...option.ClientOption) (*QueryCli
client := QueryClient{CallOptions: defaultQueryCallOptions()}
c := &queryGRPCClient{
- connPool: connPool,
- disableDeadlines: disableDeadlines,
- queryClient: monitoringpb.NewQueryServiceClient(connPool),
- CallOptions: &client.CallOptions,
+ connPool: connPool,
+ queryClient: monitoringpb.NewQueryServiceClient(connPool),
+ CallOptions: &client.CallOptions,
}
c.setGoogleClientInfo()
@@ -169,7 +161,8 @@ func NewQueryClient(ctx context.Context, opts ...option.ClientOption) (*QueryCli
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *queryGRPCClient) Connection() *grpc.ClientConn {
return c.connPool.Conn()
}
@@ -178,7 +171,7 @@ func (c *queryGRPCClient) Connection() *grpc.ClientConn {
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *queryGRPCClient) setGoogleClientInfo(keyval ...string) {
- kv := append([]string{"gl-go", versionGo()}, keyval...)
+ kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version)
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
}
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/service_monitoring_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/service_monitoring_client.go
index 693f4b625b1..c371e993773 100644
--- a/vendor/cloud.google.com/go/monitoring/apiv3/v2/service_monitoring_client.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/service_monitoring_client.go
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -23,12 +23,12 @@ import (
"net/url"
"time"
+ monitoringpb "cloud.google.com/go/monitoring/apiv3/v2/monitoringpb"
gax "github.com/googleapis/gax-go/v2"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
"google.golang.org/api/option/internaloption"
gtransport "google.golang.org/api/transport/grpc"
- monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
@@ -65,8 +65,11 @@ func defaultServiceMonitoringGRPCClientOptions() []option.ClientOption {
func defaultServiceMonitoringCallOptions() *ServiceMonitoringCallOptions {
return &ServiceMonitoringCallOptions{
- CreateService: []gax.CallOption{},
+ CreateService: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
GetService: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -78,6 +81,7 @@ func defaultServiceMonitoringCallOptions() *ServiceMonitoringCallOptions {
}),
},
ListServices: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -88,8 +92,11 @@ func defaultServiceMonitoringCallOptions() *ServiceMonitoringCallOptions {
})
}),
},
- UpdateService: []gax.CallOption{},
+ UpdateService: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
DeleteService: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -100,8 +107,11 @@ func defaultServiceMonitoringCallOptions() *ServiceMonitoringCallOptions {
})
}),
},
- CreateServiceLevelObjective: []gax.CallOption{},
+ CreateServiceLevelObjective: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
GetServiceLevelObjective: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -113,6 +123,7 @@ func defaultServiceMonitoringCallOptions() *ServiceMonitoringCallOptions {
}),
},
ListServiceLevelObjectives: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -123,8 +134,11 @@ func defaultServiceMonitoringCallOptions() *ServiceMonitoringCallOptions {
})
}),
},
- UpdateServiceLevelObjective: []gax.CallOption{},
+ UpdateServiceLevelObjective: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
DeleteServiceLevelObjective: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -138,7 +152,7 @@ func defaultServiceMonitoringCallOptions() *ServiceMonitoringCallOptions {
}
}
-// internalServiceMonitoringClient is an interface that defines the methods availaible from Cloud Monitoring API.
+// internalServiceMonitoringClient is an interface that defines the methods available from Cloud Monitoring API.
type internalServiceMonitoringClient interface {
Close() error
setGoogleClientInfo(...string)
@@ -187,7 +201,8 @@ func (c *ServiceMonitoringClient) setGoogleClientInfo(keyval ...string) {
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *ServiceMonitoringClient) Connection() *grpc.ClientConn {
return c.internalClient.Connection()
}
@@ -249,9 +264,6 @@ type serviceMonitoringGRPCClient struct {
// Connection pool of gRPC connections to the service.
connPool gtransport.ConnPool
- // flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE
- disableDeadlines bool
-
// Points back to the CallOptions field of the containing ServiceMonitoringClient
CallOptions **ServiceMonitoringCallOptions
@@ -279,11 +291,6 @@ func NewServiceMonitoringClient(ctx context.Context, opts ...option.ClientOption
clientOpts = append(clientOpts, hookOpts...)
}
- disableDeadlines, err := checkDisableDeadlines()
- if err != nil {
- return nil, err
- }
-
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
if err != nil {
return nil, err
@@ -292,7 +299,6 @@ func NewServiceMonitoringClient(ctx context.Context, opts ...option.ClientOption
c := &serviceMonitoringGRPCClient{
connPool: connPool,
- disableDeadlines: disableDeadlines,
serviceMonitoringClient: monitoringpb.NewServiceMonitoringServiceClient(connPool),
CallOptions: &client.CallOptions,
}
@@ -305,7 +311,8 @@ func NewServiceMonitoringClient(ctx context.Context, opts ...option.ClientOption
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *serviceMonitoringGRPCClient) Connection() *grpc.ClientConn {
return c.connPool.Conn()
}
@@ -314,7 +321,7 @@ func (c *serviceMonitoringGRPCClient) Connection() *grpc.ClientConn {
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *serviceMonitoringGRPCClient) setGoogleClientInfo(keyval ...string) {
- kv := append([]string{"gl-go", versionGo()}, keyval...)
+ kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version)
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
}
@@ -326,11 +333,6 @@ func (c *serviceMonitoringGRPCClient) Close() error {
}
func (c *serviceMonitoringGRPCClient) CreateService(ctx context.Context, req *monitoringpb.CreateServiceRequest, opts ...gax.CallOption) (*monitoringpb.Service, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -348,11 +350,6 @@ func (c *serviceMonitoringGRPCClient) CreateService(ctx context.Context, req *mo
}
func (c *serviceMonitoringGRPCClient) GetService(ctx context.Context, req *monitoringpb.GetServiceRequest, opts ...gax.CallOption) (*monitoringpb.Service, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -415,11 +412,6 @@ func (c *serviceMonitoringGRPCClient) ListServices(ctx context.Context, req *mon
}
func (c *serviceMonitoringGRPCClient) UpdateService(ctx context.Context, req *monitoringpb.UpdateServiceRequest, opts ...gax.CallOption) (*monitoringpb.Service, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "service.name", url.QueryEscape(req.GetService().GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -437,11 +429,6 @@ func (c *serviceMonitoringGRPCClient) UpdateService(ctx context.Context, req *mo
}
func (c *serviceMonitoringGRPCClient) DeleteService(ctx context.Context, req *monitoringpb.DeleteServiceRequest, opts ...gax.CallOption) error {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -455,11 +442,6 @@ func (c *serviceMonitoringGRPCClient) DeleteService(ctx context.Context, req *mo
}
func (c *serviceMonitoringGRPCClient) CreateServiceLevelObjective(ctx context.Context, req *monitoringpb.CreateServiceLevelObjectiveRequest, opts ...gax.CallOption) (*monitoringpb.ServiceLevelObjective, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -477,11 +459,6 @@ func (c *serviceMonitoringGRPCClient) CreateServiceLevelObjective(ctx context.Co
}
func (c *serviceMonitoringGRPCClient) GetServiceLevelObjective(ctx context.Context, req *monitoringpb.GetServiceLevelObjectiveRequest, opts ...gax.CallOption) (*monitoringpb.ServiceLevelObjective, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -544,11 +521,6 @@ func (c *serviceMonitoringGRPCClient) ListServiceLevelObjectives(ctx context.Con
}
func (c *serviceMonitoringGRPCClient) UpdateServiceLevelObjective(ctx context.Context, req *monitoringpb.UpdateServiceLevelObjectiveRequest, opts ...gax.CallOption) (*monitoringpb.ServiceLevelObjective, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "service_level_objective.name", url.QueryEscape(req.GetServiceLevelObjective().GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -566,11 +538,6 @@ func (c *serviceMonitoringGRPCClient) UpdateServiceLevelObjective(ctx context.Co
}
func (c *serviceMonitoringGRPCClient) DeleteServiceLevelObjective(ctx context.Context, req *monitoringpb.DeleteServiceLevelObjectiveRequest, opts ...gax.CallOption) error {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/snooze_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/snooze_client.go
new file mode 100644
index 00000000000..6142e667156
--- /dev/null
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/snooze_client.go
@@ -0,0 +1,382 @@
+// Copyright 2023 Google LLC
+//
+// 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
+//
+// https://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 protoc-gen-go_gapic. DO NOT EDIT.
+
+package monitoring
+
+import (
+ "context"
+ "fmt"
+ "math"
+ "net/url"
+ "time"
+
+ monitoringpb "cloud.google.com/go/monitoring/apiv3/v2/monitoringpb"
+ gax "github.com/googleapis/gax-go/v2"
+ "google.golang.org/api/iterator"
+ "google.golang.org/api/option"
+ "google.golang.org/api/option/internaloption"
+ gtransport "google.golang.org/api/transport/grpc"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/metadata"
+ "google.golang.org/protobuf/proto"
+)
+
+var newSnoozeClientHook clientHook
+
+// SnoozeCallOptions contains the retry settings for each method of SnoozeClient.
+type SnoozeCallOptions struct {
+ CreateSnooze []gax.CallOption
+ ListSnoozes []gax.CallOption
+ GetSnooze []gax.CallOption
+ UpdateSnooze []gax.CallOption
+}
+
+func defaultSnoozeGRPCClientOptions() []option.ClientOption {
+ return []option.ClientOption{
+ internaloption.WithDefaultEndpoint("monitoring.googleapis.com:443"),
+ internaloption.WithDefaultMTLSEndpoint("monitoring.mtls.googleapis.com:443"),
+ internaloption.WithDefaultAudience("https://monitoring.googleapis.com/"),
+ internaloption.WithDefaultScopes(DefaultAuthScopes()...),
+ internaloption.EnableJwtWithScope(),
+ option.WithGRPCDialOption(grpc.WithDefaultCallOptions(
+ grpc.MaxCallRecvMsgSize(math.MaxInt32))),
+ }
+}
+
+func defaultSnoozeCallOptions() *SnoozeCallOptions {
+ return &SnoozeCallOptions{
+ CreateSnooze: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
+ ListSnoozes: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ }, gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 30000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ GetSnooze: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ }, gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 30000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ UpdateSnooze: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
+ }
+}
+
+// internalSnoozeClient is an interface that defines the methods available from Cloud Monitoring API.
+type internalSnoozeClient interface {
+ Close() error
+ setGoogleClientInfo(...string)
+ Connection() *grpc.ClientConn
+ CreateSnooze(context.Context, *monitoringpb.CreateSnoozeRequest, ...gax.CallOption) (*monitoringpb.Snooze, error)
+ ListSnoozes(context.Context, *monitoringpb.ListSnoozesRequest, ...gax.CallOption) *SnoozeIterator
+ GetSnooze(context.Context, *monitoringpb.GetSnoozeRequest, ...gax.CallOption) (*monitoringpb.Snooze, error)
+ UpdateSnooze(context.Context, *monitoringpb.UpdateSnoozeRequest, ...gax.CallOption) (*monitoringpb.Snooze, error)
+}
+
+// SnoozeClient is a client for interacting with Cloud Monitoring API.
+// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
+//
+// The SnoozeService API is used to temporarily prevent an alert policy from
+// generating alerts. A Snooze is a description of the criteria under which one
+// or more alert policies should not fire alerts for the specified duration.
+type SnoozeClient struct {
+ // The internal transport-dependent client.
+ internalClient internalSnoozeClient
+
+ // The call options for this service.
+ CallOptions *SnoozeCallOptions
+}
+
+// Wrapper methods routed to the internal client.
+
+// Close closes the connection to the API service. The user should invoke this when
+// the client is no longer required.
+func (c *SnoozeClient) Close() error {
+ return c.internalClient.Close()
+}
+
+// setGoogleClientInfo sets the name and version of the application in
+// the `x-goog-api-client` header passed on each request. Intended for
+// use by Google-written clients.
+func (c *SnoozeClient) setGoogleClientInfo(keyval ...string) {
+ c.internalClient.setGoogleClientInfo(keyval...)
+}
+
+// Connection returns a connection to the API service.
+//
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
+func (c *SnoozeClient) Connection() *grpc.ClientConn {
+ return c.internalClient.Connection()
+}
+
+// CreateSnooze creates a Snooze that will prevent alerts, which match the provided
+// criteria, from being opened. The Snooze applies for a specific time
+// interval.
+func (c *SnoozeClient) CreateSnooze(ctx context.Context, req *monitoringpb.CreateSnoozeRequest, opts ...gax.CallOption) (*monitoringpb.Snooze, error) {
+ return c.internalClient.CreateSnooze(ctx, req, opts...)
+}
+
+// ListSnoozes lists the Snoozes associated with a project. Can optionally pass in
+// filter, which specifies predicates to match Snoozes.
+func (c *SnoozeClient) ListSnoozes(ctx context.Context, req *monitoringpb.ListSnoozesRequest, opts ...gax.CallOption) *SnoozeIterator {
+ return c.internalClient.ListSnoozes(ctx, req, opts...)
+}
+
+// GetSnooze retrieves a Snooze by name.
+func (c *SnoozeClient) GetSnooze(ctx context.Context, req *monitoringpb.GetSnoozeRequest, opts ...gax.CallOption) (*monitoringpb.Snooze, error) {
+ return c.internalClient.GetSnooze(ctx, req, opts...)
+}
+
+// UpdateSnooze updates a Snooze, identified by its name, with the parameters in the
+// given Snooze object.
+func (c *SnoozeClient) UpdateSnooze(ctx context.Context, req *monitoringpb.UpdateSnoozeRequest, opts ...gax.CallOption) (*monitoringpb.Snooze, error) {
+ return c.internalClient.UpdateSnooze(ctx, req, opts...)
+}
+
+// snoozeGRPCClient is a client for interacting with Cloud Monitoring API over gRPC transport.
+//
+// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
+type snoozeGRPCClient struct {
+ // Connection pool of gRPC connections to the service.
+ connPool gtransport.ConnPool
+
+ // Points back to the CallOptions field of the containing SnoozeClient
+ CallOptions **SnoozeCallOptions
+
+ // The gRPC API client.
+ snoozeClient monitoringpb.SnoozeServiceClient
+
+ // The x-goog-* metadata to be sent with each request.
+ xGoogMetadata metadata.MD
+}
+
+// NewSnoozeClient creates a new snooze service client based on gRPC.
+// The returned client must be Closed when it is done being used to clean up its underlying connections.
+//
+// The SnoozeService API is used to temporarily prevent an alert policy from
+// generating alerts. A Snooze is a description of the criteria under which one
+// or more alert policies should not fire alerts for the specified duration.
+func NewSnoozeClient(ctx context.Context, opts ...option.ClientOption) (*SnoozeClient, error) {
+ clientOpts := defaultSnoozeGRPCClientOptions()
+ if newSnoozeClientHook != nil {
+ hookOpts, err := newSnoozeClientHook(ctx, clientHookParams{})
+ if err != nil {
+ return nil, err
+ }
+ clientOpts = append(clientOpts, hookOpts...)
+ }
+
+ connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
+ if err != nil {
+ return nil, err
+ }
+ client := SnoozeClient{CallOptions: defaultSnoozeCallOptions()}
+
+ c := &snoozeGRPCClient{
+ connPool: connPool,
+ snoozeClient: monitoringpb.NewSnoozeServiceClient(connPool),
+ CallOptions: &client.CallOptions,
+ }
+ c.setGoogleClientInfo()
+
+ client.internalClient = c
+
+ return &client, nil
+}
+
+// Connection returns a connection to the API service.
+//
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
+func (c *snoozeGRPCClient) Connection() *grpc.ClientConn {
+ return c.connPool.Conn()
+}
+
+// setGoogleClientInfo sets the name and version of the application in
+// the `x-goog-api-client` header passed on each request. Intended for
+// use by Google-written clients.
+func (c *snoozeGRPCClient) setGoogleClientInfo(keyval ...string) {
+ kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
+ kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version)
+ c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
+}
+
+// Close closes the connection to the API service. The user should invoke this when
+// the client is no longer required.
+func (c *snoozeGRPCClient) Close() error {
+ return c.connPool.Close()
+}
+
+func (c *snoozeGRPCClient) CreateSnooze(ctx context.Context, req *monitoringpb.CreateSnoozeRequest, opts ...gax.CallOption) (*monitoringpb.Snooze, error) {
+ md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent())))
+
+ ctx = insertMetadata(ctx, c.xGoogMetadata, md)
+ opts = append((*c.CallOptions).CreateSnooze[0:len((*c.CallOptions).CreateSnooze):len((*c.CallOptions).CreateSnooze)], opts...)
+ var resp *monitoringpb.Snooze
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.snoozeClient.CreateSnooze(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *snoozeGRPCClient) ListSnoozes(ctx context.Context, req *monitoringpb.ListSnoozesRequest, opts ...gax.CallOption) *SnoozeIterator {
+ md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent())))
+
+ ctx = insertMetadata(ctx, c.xGoogMetadata, md)
+ opts = append((*c.CallOptions).ListSnoozes[0:len((*c.CallOptions).ListSnoozes):len((*c.CallOptions).ListSnoozes)], opts...)
+ it := &SnoozeIterator{}
+ req = proto.Clone(req).(*monitoringpb.ListSnoozesRequest)
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.Snooze, string, error) {
+ resp := &monitoringpb.ListSnoozesResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.snoozeClient.ListSnoozes(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+
+ it.Response = resp
+ return resp.GetSnoozes(), resp.GetNextPageToken(), nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+func (c *snoozeGRPCClient) GetSnooze(ctx context.Context, req *monitoringpb.GetSnoozeRequest, opts ...gax.CallOption) (*monitoringpb.Snooze, error) {
+ md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
+
+ ctx = insertMetadata(ctx, c.xGoogMetadata, md)
+ opts = append((*c.CallOptions).GetSnooze[0:len((*c.CallOptions).GetSnooze):len((*c.CallOptions).GetSnooze)], opts...)
+ var resp *monitoringpb.Snooze
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.snoozeClient.GetSnooze(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *snoozeGRPCClient) UpdateSnooze(ctx context.Context, req *monitoringpb.UpdateSnoozeRequest, opts ...gax.CallOption) (*monitoringpb.Snooze, error) {
+ md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "snooze.name", url.QueryEscape(req.GetSnooze().GetName())))
+
+ ctx = insertMetadata(ctx, c.xGoogMetadata, md)
+ opts = append((*c.CallOptions).UpdateSnooze[0:len((*c.CallOptions).UpdateSnooze):len((*c.CallOptions).UpdateSnooze)], opts...)
+ var resp *monitoringpb.Snooze
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.snoozeClient.UpdateSnooze(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// SnoozeIterator manages a stream of *monitoringpb.Snooze.
+type SnoozeIterator struct {
+ items []*monitoringpb.Snooze
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+
+ // Response is the raw response for the current page.
+ // It must be cast to the RPC response type.
+ // Calling Next() or InternalFetch() updates this value.
+ Response interface{}
+
+ // InternalFetch is for use by the Google Cloud Libraries only.
+ // It is not part of the stable interface of this package.
+ //
+ // InternalFetch returns results from a single call to the underlying RPC.
+ // The number of results is no greater than pageSize.
+ // If there are no more results, nextPageToken is empty and err is nil.
+ InternalFetch func(pageSize int, pageToken string) (results []*monitoringpb.Snooze, nextPageToken string, err error)
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *SnoozeIterator) PageInfo() *iterator.PageInfo {
+ return it.pageInfo
+}
+
+// Next returns the next result. Its second return value is iterator.Done if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *SnoozeIterator) Next() (*monitoringpb.Snooze, error) {
+ var item *monitoringpb.Snooze
+ if err := it.nextFunc(); err != nil {
+ return item, err
+ }
+ item = it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *SnoozeIterator) bufLen() int {
+ return len(it.items)
+}
+
+func (it *SnoozeIterator) takeBuf() interface{} {
+ b := it.items
+ it.items = nil
+ return b
+}
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/uptime_check_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/uptime_check_client.go
index 9203c54e639..6d8f6feddb9 100644
--- a/vendor/cloud.google.com/go/monitoring/apiv3/v2/uptime_check_client.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/uptime_check_client.go
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -23,12 +23,12 @@ import (
"net/url"
"time"
+ monitoringpb "cloud.google.com/go/monitoring/apiv3/v2/monitoringpb"
gax "github.com/googleapis/gax-go/v2"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
"google.golang.org/api/option/internaloption"
gtransport "google.golang.org/api/transport/grpc"
- monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
@@ -62,6 +62,7 @@ func defaultUptimeCheckGRPCClientOptions() []option.ClientOption {
func defaultUptimeCheckCallOptions() *UptimeCheckCallOptions {
return &UptimeCheckCallOptions{
ListUptimeCheckConfigs: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -73,6 +74,7 @@ func defaultUptimeCheckCallOptions() *UptimeCheckCallOptions {
}),
},
GetUptimeCheckConfig: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -83,9 +85,14 @@ func defaultUptimeCheckCallOptions() *UptimeCheckCallOptions {
})
}),
},
- CreateUptimeCheckConfig: []gax.CallOption{},
- UpdateUptimeCheckConfig: []gax.CallOption{},
+ CreateUptimeCheckConfig: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
+ UpdateUptimeCheckConfig: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
DeleteUptimeCheckConfig: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -97,6 +104,7 @@ func defaultUptimeCheckCallOptions() *UptimeCheckCallOptions {
}),
},
ListUptimeCheckIps: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -110,7 +118,7 @@ func defaultUptimeCheckCallOptions() *UptimeCheckCallOptions {
}
}
-// internalUptimeCheckClient is an interface that defines the methods availaible from Cloud Monitoring API.
+// internalUptimeCheckClient is an interface that defines the methods available from Cloud Monitoring API.
type internalUptimeCheckClient interface {
Close() error
setGoogleClientInfo(...string)
@@ -127,13 +135,13 @@ type internalUptimeCheckClient interface {
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
//
// The UptimeCheckService API is used to manage (list, create, delete, edit)
-// Uptime check configurations in the Stackdriver Monitoring product. An Uptime
+// Uptime check configurations in the Cloud Monitoring product. An Uptime
// check is a piece of configuration that determines which resources and
// services to monitor for availability. These configurations can also be
-// configured interactively by navigating to the [Cloud Console]
-// (http://console.cloud.google.com (at http://console.cloud.google.com)), selecting the appropriate project,
-// clicking on “Monitoring” on the left-hand side to navigate to Stackdriver,
-// and then clicking on “Uptime”.
+// configured interactively by navigating to the [Cloud console]
+// (https://console.cloud.google.com (at https://console.cloud.google.com)), selecting the appropriate project,
+// clicking on “Monitoring” on the left-hand side to navigate to Cloud
+// Monitoring, and then clicking on “Uptime”.
type UptimeCheckClient struct {
// The internal transport-dependent client.
internalClient internalUptimeCheckClient
@@ -159,7 +167,8 @@ func (c *UptimeCheckClient) setGoogleClientInfo(keyval ...string) {
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *UptimeCheckClient) Connection() *grpc.ClientConn {
return c.internalClient.Connection()
}
@@ -207,9 +216,6 @@ type uptimeCheckGRPCClient struct {
// Connection pool of gRPC connections to the service.
connPool gtransport.ConnPool
- // flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE
- disableDeadlines bool
-
// Points back to the CallOptions field of the containing UptimeCheckClient
CallOptions **UptimeCheckCallOptions
@@ -224,13 +230,13 @@ type uptimeCheckGRPCClient struct {
// The returned client must be Closed when it is done being used to clean up its underlying connections.
//
// The UptimeCheckService API is used to manage (list, create, delete, edit)
-// Uptime check configurations in the Stackdriver Monitoring product. An Uptime
+// Uptime check configurations in the Cloud Monitoring product. An Uptime
// check is a piece of configuration that determines which resources and
// services to monitor for availability. These configurations can also be
-// configured interactively by navigating to the [Cloud Console]
-// (http://console.cloud.google.com (at http://console.cloud.google.com)), selecting the appropriate project,
-// clicking on “Monitoring” on the left-hand side to navigate to Stackdriver,
-// and then clicking on “Uptime”.
+// configured interactively by navigating to the [Cloud console]
+// (https://console.cloud.google.com (at https://console.cloud.google.com)), selecting the appropriate project,
+// clicking on “Monitoring” on the left-hand side to navigate to Cloud
+// Monitoring, and then clicking on “Uptime”.
func NewUptimeCheckClient(ctx context.Context, opts ...option.ClientOption) (*UptimeCheckClient, error) {
clientOpts := defaultUptimeCheckGRPCClientOptions()
if newUptimeCheckClientHook != nil {
@@ -241,11 +247,6 @@ func NewUptimeCheckClient(ctx context.Context, opts ...option.ClientOption) (*Up
clientOpts = append(clientOpts, hookOpts...)
}
- disableDeadlines, err := checkDisableDeadlines()
- if err != nil {
- return nil, err
- }
-
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
if err != nil {
return nil, err
@@ -254,7 +255,6 @@ func NewUptimeCheckClient(ctx context.Context, opts ...option.ClientOption) (*Up
c := &uptimeCheckGRPCClient{
connPool: connPool,
- disableDeadlines: disableDeadlines,
uptimeCheckClient: monitoringpb.NewUptimeCheckServiceClient(connPool),
CallOptions: &client.CallOptions,
}
@@ -267,7 +267,8 @@ func NewUptimeCheckClient(ctx context.Context, opts ...option.ClientOption) (*Up
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *uptimeCheckGRPCClient) Connection() *grpc.ClientConn {
return c.connPool.Conn()
}
@@ -276,7 +277,7 @@ func (c *uptimeCheckGRPCClient) Connection() *grpc.ClientConn {
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *uptimeCheckGRPCClient) setGoogleClientInfo(keyval ...string) {
- kv := append([]string{"gl-go", versionGo()}, keyval...)
+ kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version)
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
}
@@ -333,11 +334,6 @@ func (c *uptimeCheckGRPCClient) ListUptimeCheckConfigs(ctx context.Context, req
}
func (c *uptimeCheckGRPCClient) GetUptimeCheckConfig(ctx context.Context, req *monitoringpb.GetUptimeCheckConfigRequest, opts ...gax.CallOption) (*monitoringpb.UptimeCheckConfig, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -355,11 +351,6 @@ func (c *uptimeCheckGRPCClient) GetUptimeCheckConfig(ctx context.Context, req *m
}
func (c *uptimeCheckGRPCClient) CreateUptimeCheckConfig(ctx context.Context, req *monitoringpb.CreateUptimeCheckConfigRequest, opts ...gax.CallOption) (*monitoringpb.UptimeCheckConfig, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -377,11 +368,6 @@ func (c *uptimeCheckGRPCClient) CreateUptimeCheckConfig(ctx context.Context, req
}
func (c *uptimeCheckGRPCClient) UpdateUptimeCheckConfig(ctx context.Context, req *monitoringpb.UpdateUptimeCheckConfigRequest, opts ...gax.CallOption) (*monitoringpb.UptimeCheckConfig, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "uptime_check_config.name", url.QueryEscape(req.GetUptimeCheckConfig().GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -399,11 +385,6 @@ func (c *uptimeCheckGRPCClient) UpdateUptimeCheckConfig(ctx context.Context, req
}
func (c *uptimeCheckGRPCClient) DeleteUptimeCheckConfig(ctx context.Context, req *monitoringpb.DeleteUptimeCheckConfigRequest, opts ...gax.CallOption) error {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/v2/version.go b/vendor/cloud.google.com/go/monitoring/apiv3/v2/version.go
index bb4981e0fb4..accff0f5e47 100644
--- a/vendor/cloud.google.com/go/monitoring/apiv3/v2/version.go
+++ b/vendor/cloud.google.com/go/monitoring/apiv3/v2/version.go
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/vendor/cloud.google.com/go/monitoring/internal/version.go b/vendor/cloud.google.com/go/monitoring/internal/version.go
index e93235c2032..7dd6a0aa86f 100644
--- a/vendor/cloud.google.com/go/monitoring/internal/version.go
+++ b/vendor/cloud.google.com/go/monitoring/internal/version.go
@@ -15,4 +15,4 @@
package internal
// Version is the current tagged release of the library.
-const Version = "1.5.0"
+const Version = "1.15.1"
diff --git a/vendor/cloud.google.com/go/trace/apiv2/doc.go b/vendor/cloud.google.com/go/trace/apiv2/doc.go
index b58f874c37e..4c1ce50139e 100644
--- a/vendor/cloud.google.com/go/trace/apiv2/doc.go
+++ b/vendor/cloud.google.com/go/trace/apiv2/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -21,61 +21,77 @@
// is collected for all App Engine applications by default. Trace data from
// other applications can be provided using this API. This library is used to
// interact with the Trace API directly. If you are looking to instrument
-// your application for Stackdriver Trace, we recommend using OpenCensus.
+// your application for Stackdriver Trace, we recommend using OpenTelemetry.
//
-// Example usage
+// NOTE: This package is in beta. It is not stable, and may be subject to changes.
+//
+// # General documentation
+//
+// For information about setting deadlines, reusing contexts, and more
+// please visit https://pkg.go.dev/cloud.google.com/go.
+//
+// # Example usage
//
// To get started with this package, create a client.
-// ctx := context.Background()
-// c, err := trace.NewClient(ctx)
-// if err != nil {
-// // TODO: Handle error.
-// }
-// defer c.Close()
+//
+// ctx := context.Background()
+// // This snippet has been automatically generated and should be regarded as a code template only.
+// // It will require modifications to work:
+// // - It may require correct/in-range values for request initialization.
+// // - It may require specifying regional endpoints when creating the service client as shown in:
+// // https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
+// c, err := trace.NewClient(ctx)
+// if err != nil {
+// // TODO: Handle error.
+// }
+// defer c.Close()
//
// The client will use your default application credentials. Clients should be reused instead of created as needed.
// The methods of Client are safe for concurrent use by multiple goroutines.
// The returned client must be Closed when it is done being used.
//
-// Using the Client
+// # Using the Client
//
// The following is an example of making an API call with the newly created client.
//
-// ctx := context.Background()
-// c, err := trace.NewClient(ctx)
-// if err != nil {
-// // TODO: Handle error.
-// }
-// defer c.Close()
+// ctx := context.Background()
+// // This snippet has been automatically generated and should be regarded as a code template only.
+// // It will require modifications to work:
+// // - It may require correct/in-range values for request initialization.
+// // - It may require specifying regional endpoints when creating the service client as shown in:
+// // https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
+// c, err := trace.NewClient(ctx)
+// if err != nil {
+// // TODO: Handle error.
+// }
+// defer c.Close()
//
-// req := &cloudtracepb.BatchWriteSpansRequest{
-// // TODO: Fill request struct fields.
-// // See https://pkg.go.dev/google.golang.org/genproto/googleapis/devtools/cloudtrace/v2#BatchWriteSpansRequest.
-// }
-// err = c.BatchWriteSpans(ctx, req)
-// if err != nil {
-// // TODO: Handle error.
-// }
+// req := &tracepb.BatchWriteSpansRequest{
+// // TODO: Fill request struct fields.
+// // See https://pkg.go.dev/cloud.google.com/go/trace/apiv2/tracepb#BatchWriteSpansRequest.
+// }
+// err = c.BatchWriteSpans(ctx, req)
+// if err != nil {
+// // TODO: Handle error.
+// }
//
-// Use of Context
+// # Inspecting errors
+//
+// To see examples of how to inspect errors returned by this package please reference
+// [Inspecting errors](https://pkg.go.dev/cloud.google.com/go#hdr-Inspecting_errors).
+//
+// # Use of Context
//
// The ctx passed to NewClient is used for authentication requests and
// for creating the underlying connection, but is not used for subsequent calls.
// Individual methods on the client use the ctx given to them.
//
// To close the open connection, use the Close() method.
-//
-// For information about setting deadlines, reusing contexts, and more
-// please visit https://pkg.go.dev/cloud.google.com/go.
package trace // import "cloud.google.com/go/trace/apiv2"
import (
"context"
- "os"
- "runtime"
- "strconv"
- "strings"
- "unicode"
+ "net/http"
"google.golang.org/api/option"
"google.golang.org/grpc/metadata"
@@ -106,16 +122,6 @@ func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context {
return metadata.NewOutgoingContext(ctx, out)
}
-func checkDisableDeadlines() (bool, error) {
- raw, ok := os.LookupEnv("GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE")
- if !ok {
- return false, nil
- }
-
- b, err := strconv.ParseBool(raw)
- return b, err
-}
-
// DefaultAuthScopes reports the default set of authentication scopes to use with this package.
func DefaultAuthScopes() []string {
return []string{
@@ -124,39 +130,12 @@ func DefaultAuthScopes() []string {
}
}
-// versionGo returns the Go runtime version. The returned string
-// has no whitespace, suitable for reporting in header.
-func versionGo() string {
- const develPrefix = "devel +"
-
- s := runtime.Version()
- if strings.HasPrefix(s, develPrefix) {
- s = s[len(develPrefix):]
- if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
- s = s[:p]
- }
- return s
- }
-
- notSemverRune := func(r rune) bool {
- return !strings.ContainsRune("0123456789.", r)
- }
-
- if strings.HasPrefix(s, "go1") {
- s = s[2:]
- var prerelease string
- if p := strings.IndexFunc(s, notSemverRune); p >= 0 {
- s, prerelease = s[:p], s[p:]
- }
- if strings.HasSuffix(s, ".") {
- s += "0"
- } else if strings.Count(s, ".") < 2 {
- s += ".0"
- }
- if prerelease != "" {
- s += "-" + prerelease
- }
- return s
+// buildHeaders extracts metadata from the outgoing context, joins it with any other
+// given metadata, and converts them into a http.Header.
+func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header {
+ if cmd, ok := metadata.FromOutgoingContext(ctx); ok {
+ mds = append(mds, cmd)
}
- return "UNKNOWN"
+ md := metadata.Join(mds...)
+ return http.Header(md)
}
diff --git a/vendor/cloud.google.com/go/trace/apiv2/gapic_metadata.json b/vendor/cloud.google.com/go/trace/apiv2/gapic_metadata.json
index ef3c8d6d045..566e48c5cb8 100644
--- a/vendor/cloud.google.com/go/trace/apiv2/gapic_metadata.json
+++ b/vendor/cloud.google.com/go/trace/apiv2/gapic_metadata.json
@@ -21,6 +21,21 @@
]
}
}
+ },
+ "rest": {
+ "libraryClient": "Client",
+ "rpcs": {
+ "BatchWriteSpans": {
+ "methods": [
+ "BatchWriteSpans"
+ ]
+ },
+ "CreateSpan": {
+ "methods": [
+ "CreateSpan"
+ ]
+ }
+ }
}
}
}
diff --git a/vendor/cloud.google.com/go/trace/apiv2/path_funcs.go b/vendor/cloud.google.com/go/trace/apiv2/path_funcs.go
index 80b8d40b58e..e8a8a2b0767 100644
--- a/vendor/cloud.google.com/go/trace/apiv2/path_funcs.go
+++ b/vendor/cloud.google.com/go/trace/apiv2/path_funcs.go
@@ -17,7 +17,9 @@ package trace
// ProjectPath returns the path for the project resource.
//
// Deprecated: Use
-// fmt.Sprintf("projects/%s", project)
+//
+// fmt.Sprintf("projects/%s", project)
+//
// instead.
func ProjectPath(project string) string {
return "" +
@@ -29,7 +31,9 @@ func ProjectPath(project string) string {
// SpanPath returns the path for the span resource.
//
// Deprecated: Use
-// fmt.Sprintf("projects/%s/traces/%s/spans/%s", project, trace, span)
+//
+// fmt.Sprintf("projects/%s/traces/%s/spans/%s", project, trace, span)
+//
// instead.
func SpanPath(project, trace, span string) string {
return "" +
diff --git a/vendor/cloud.google.com/go/trace/apiv2/trace_client.go b/vendor/cloud.google.com/go/trace/apiv2/trace_client.go
index b5b265eb444..aaf81a55e0f 100644
--- a/vendor/cloud.google.com/go/trace/apiv2/trace_client.go
+++ b/vendor/cloud.google.com/go/trace/apiv2/trace_client.go
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -17,20 +17,26 @@
package trace
import (
+ "bytes"
"context"
"fmt"
+ "io"
"math"
+ "net/http"
"net/url"
"time"
+ tracepb "cloud.google.com/go/trace/apiv2/tracepb"
gax "github.com/googleapis/gax-go/v2"
+ "google.golang.org/api/googleapi"
"google.golang.org/api/option"
"google.golang.org/api/option/internaloption"
gtransport "google.golang.org/api/transport/grpc"
- cloudtracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v2"
+ httptransport "google.golang.org/api/transport/http"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
+ "google.golang.org/protobuf/encoding/protojson"
)
var newClientHook clientHook
@@ -55,8 +61,21 @@ func defaultGRPCClientOptions() []option.ClientOption {
func defaultCallOptions() *CallOptions {
return &CallOptions{
- BatchWriteSpans: []gax.CallOption{},
+ BatchWriteSpans: []gax.CallOption{
+ gax.WithTimeout(120000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 30000 * time.Millisecond,
+ Multiplier: 2.00,
+ })
+ }),
+ },
CreateSpan: []gax.CallOption{
+ gax.WithTimeout(120000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.Unavailable,
@@ -71,23 +90,54 @@ func defaultCallOptions() *CallOptions {
}
}
-// internalClient is an interface that defines the methods availaible from Stackdriver Trace API.
+func defaultRESTCallOptions() *CallOptions {
+ return &CallOptions{
+ BatchWriteSpans: []gax.CallOption{
+ gax.WithTimeout(120000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 30000 * time.Millisecond,
+ Multiplier: 2.00,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ CreateSpan: []gax.CallOption{
+ gax.WithTimeout(120000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 1000 * time.Millisecond,
+ Multiplier: 1.20,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ }
+}
+
+// internalClient is an interface that defines the methods available from Stackdriver Trace API.
type internalClient interface {
Close() error
setGoogleClientInfo(...string)
Connection() *grpc.ClientConn
- BatchWriteSpans(context.Context, *cloudtracepb.BatchWriteSpansRequest, ...gax.CallOption) error
- CreateSpan(context.Context, *cloudtracepb.Span, ...gax.CallOption) (*cloudtracepb.Span, error)
+ BatchWriteSpans(context.Context, *tracepb.BatchWriteSpansRequest, ...gax.CallOption) error
+ CreateSpan(context.Context, *tracepb.Span, ...gax.CallOption) (*tracepb.Span, error)
}
// Client is a client for interacting with Stackdriver Trace API.
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
//
-// This file describes an API for collecting and viewing traces and spans
-// within a trace. A Trace is a collection of spans corresponding to a single
-// operation or set of operations for an application. A span is an individual
-// timed event which forms a node of the trace tree. A single trace may
-// contain span(s) from multiple services.
+// Service for collecting and viewing traces and spans within a trace.
+//
+// A trace is a collection of spans corresponding to a single
+// operation or a set of operations in an application.
+//
+// A span is an individual timed event which forms a node of the trace tree.
+// A single trace can contain spans from multiple services.
type Client struct {
// The internal transport-dependent client.
internalClient internalClient
@@ -113,19 +163,20 @@ func (c *Client) setGoogleClientInfo(keyval ...string) {
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *Client) Connection() *grpc.ClientConn {
return c.internalClient.Connection()
}
-// BatchWriteSpans sends new spans to new or existing traces. You cannot update
+// BatchWriteSpans batch writes new spans to new or existing traces. You cannot update
// existing spans.
-func (c *Client) BatchWriteSpans(ctx context.Context, req *cloudtracepb.BatchWriteSpansRequest, opts ...gax.CallOption) error {
+func (c *Client) BatchWriteSpans(ctx context.Context, req *tracepb.BatchWriteSpansRequest, opts ...gax.CallOption) error {
return c.internalClient.BatchWriteSpans(ctx, req, opts...)
}
// CreateSpan creates a new span.
-func (c *Client) CreateSpan(ctx context.Context, req *cloudtracepb.Span, opts ...gax.CallOption) (*cloudtracepb.Span, error) {
+func (c *Client) CreateSpan(ctx context.Context, req *tracepb.Span, opts ...gax.CallOption) (*tracepb.Span, error) {
return c.internalClient.CreateSpan(ctx, req, opts...)
}
@@ -136,14 +187,11 @@ type gRPCClient struct {
// Connection pool of gRPC connections to the service.
connPool gtransport.ConnPool
- // flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE
- disableDeadlines bool
-
// Points back to the CallOptions field of the containing Client
CallOptions **CallOptions
// The gRPC API client.
- client cloudtracepb.TraceServiceClient
+ client tracepb.TraceServiceClient
// The x-goog-* metadata to be sent with each request.
xGoogMetadata metadata.MD
@@ -152,11 +200,13 @@ type gRPCClient struct {
// NewClient creates a new trace service client based on gRPC.
// The returned client must be Closed when it is done being used to clean up its underlying connections.
//
-// This file describes an API for collecting and viewing traces and spans
-// within a trace. A Trace is a collection of spans corresponding to a single
-// operation or set of operations for an application. A span is an individual
-// timed event which forms a node of the trace tree. A single trace may
-// contain span(s) from multiple services.
+// Service for collecting and viewing traces and spans within a trace.
+//
+// A trace is a collection of spans corresponding to a single
+// operation or a set of operations in an application.
+//
+// A span is an individual timed event which forms a node of the trace tree.
+// A single trace can contain spans from multiple services.
func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) {
clientOpts := defaultGRPCClientOptions()
if newClientHook != nil {
@@ -167,11 +217,6 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
clientOpts = append(clientOpts, hookOpts...)
}
- disableDeadlines, err := checkDisableDeadlines()
- if err != nil {
- return nil, err
- }
-
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
if err != nil {
return nil, err
@@ -179,10 +224,9 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
client := Client{CallOptions: defaultCallOptions()}
c := &gRPCClient{
- connPool: connPool,
- disableDeadlines: disableDeadlines,
- client: cloudtracepb.NewTraceServiceClient(connPool),
- CallOptions: &client.CallOptions,
+ connPool: connPool,
+ client: tracepb.NewTraceServiceClient(connPool),
+ CallOptions: &client.CallOptions,
}
c.setGoogleClientInfo()
@@ -193,7 +237,8 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
// Connection returns a connection to the API service.
//
-// Deprecated.
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
func (c *gRPCClient) Connection() *grpc.ClientConn {
return c.connPool.Conn()
}
@@ -202,7 +247,7 @@ func (c *gRPCClient) Connection() *grpc.ClientConn {
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *gRPCClient) setGoogleClientInfo(keyval ...string) {
- kv := append([]string{"gl-go", versionGo()}, keyval...)
+ kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version)
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
}
@@ -213,12 +258,81 @@ func (c *gRPCClient) Close() error {
return c.connPool.Close()
}
-func (c *gRPCClient) BatchWriteSpans(ctx context.Context, req *cloudtracepb.BatchWriteSpansRequest, opts ...gax.CallOption) error {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 120000*time.Millisecond)
- defer cancel()
- ctx = cctx
+// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
+type restClient struct {
+ // The http endpoint to connect to.
+ endpoint string
+
+ // The http client.
+ httpClient *http.Client
+
+ // The x-goog-* metadata to be sent with each request.
+ xGoogMetadata metadata.MD
+
+ // Points back to the CallOptions field of the containing Client
+ CallOptions **CallOptions
+}
+
+// NewRESTClient creates a new trace service rest client.
+//
+// Service for collecting and viewing traces and spans within a trace.
+//
+// A trace is a collection of spans corresponding to a single
+// operation or a set of operations in an application.
+//
+// A span is an individual timed event which forms a node of the trace tree.
+// A single trace can contain spans from multiple services.
+func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) {
+ clientOpts := append(defaultRESTClientOptions(), opts...)
+ httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...)
+ if err != nil {
+ return nil, err
+ }
+
+ callOpts := defaultRESTCallOptions()
+ c := &restClient{
+ endpoint: endpoint,
+ httpClient: httpClient,
+ CallOptions: &callOpts,
+ }
+ c.setGoogleClientInfo()
+
+ return &Client{internalClient: c, CallOptions: callOpts}, nil
+}
+
+func defaultRESTClientOptions() []option.ClientOption {
+ return []option.ClientOption{
+ internaloption.WithDefaultEndpoint("https://cloudtrace.googleapis.com"),
+ internaloption.WithDefaultMTLSEndpoint("https://cloudtrace.mtls.googleapis.com"),
+ internaloption.WithDefaultAudience("https://cloudtrace.googleapis.com/"),
+ internaloption.WithDefaultScopes(DefaultAuthScopes()...),
}
+}
+
+// setGoogleClientInfo sets the name and version of the application in
+// the `x-goog-api-client` header passed on each request. Intended for
+// use by Google-written clients.
+func (c *restClient) setGoogleClientInfo(keyval ...string) {
+ kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
+ kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN")
+ c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
+}
+
+// Close closes the connection to the API service. The user should invoke this when
+// the client is no longer required.
+func (c *restClient) Close() error {
+ // Replace httpClient with nil to force cleanup.
+ c.httpClient = nil
+ return nil
+}
+
+// Connection returns a connection to the API service.
+//
+// Deprecated: This method always returns nil.
+func (c *restClient) Connection() *grpc.ClientConn {
+ return nil
+}
+func (c *gRPCClient) BatchWriteSpans(ctx context.Context, req *tracepb.BatchWriteSpansRequest, opts ...gax.CallOption) error {
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
@@ -231,17 +345,12 @@ func (c *gRPCClient) BatchWriteSpans(ctx context.Context, req *cloudtracepb.Batc
return err
}
-func (c *gRPCClient) CreateSpan(ctx context.Context, req *cloudtracepb.Span, opts ...gax.CallOption) (*cloudtracepb.Span, error) {
- if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines {
- cctx, cancel := context.WithTimeout(ctx, 120000*time.Millisecond)
- defer cancel()
- ctx = cctx
- }
+func (c *gRPCClient) CreateSpan(ctx context.Context, req *tracepb.Span, opts ...gax.CallOption) (*tracepb.Span, error) {
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
opts = append((*c.CallOptions).CreateSpan[0:len((*c.CallOptions).CreateSpan):len((*c.CallOptions).CreateSpan)], opts...)
- var resp *cloudtracepb.Span
+ var resp *tracepb.Span
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
var err error
resp, err = c.client.CreateSpan(ctx, req, settings.GRPC...)
@@ -252,3 +361,114 @@ func (c *gRPCClient) CreateSpan(ctx context.Context, req *cloudtracepb.Span, opt
}
return resp, nil
}
+
+// BatchWriteSpans batch writes new spans to new or existing traces. You cannot update
+// existing spans.
+func (c *restClient) BatchWriteSpans(ctx context.Context, req *tracepb.BatchWriteSpansRequest, opts ...gax.CallOption) error {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ jsonReq, err := m.Marshal(req)
+ if err != nil {
+ return err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return err
+ }
+ baseUrl.Path += fmt.Sprintf("/v2/%v/traces:batchWrite", req.GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
+
+ headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json"))
+ return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ // Returns nil if there is no error, otherwise wraps
+ // the response code and body into a non-nil error
+ return googleapi.CheckResponse(httpRsp)
+ }, opts...)
+}
+
+// CreateSpan creates a new span.
+func (c *restClient) CreateSpan(ctx context.Context, req *tracepb.Span, opts ...gax.CallOption) (*tracepb.Span, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ jsonReq, err := m.Marshal(req)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v2/%v", req.GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
+
+ headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json"))
+ opts = append((*c.CallOptions).CreateSpan[0:len((*c.CallOptions).CreateSpan):len((*c.CallOptions).CreateSpan)], opts...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &tracepb.Span{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+ return resp, nil
+}
diff --git a/vendor/cloud.google.com/go/trace/apiv2/tracepb/trace.pb.go b/vendor/cloud.google.com/go/trace/apiv2/tracepb/trace.pb.go
new file mode 100644
index 00000000000..1ea77774460
--- /dev/null
+++ b/vendor/cloud.google.com/go/trace/apiv2/tracepb/trace.pb.go
@@ -0,0 +1,1961 @@
+// Copyright 2022 Google LLC
+//
+// 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 protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
+// source: google/devtools/cloudtrace/v2/trace.proto
+
+package tracepb
+
+import (
+ reflect "reflect"
+ sync "sync"
+
+ _ "google.golang.org/genproto/googleapis/api/annotations"
+ status "google.golang.org/genproto/googleapis/rpc/status"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+ wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Type of span. Can be used to specify additional relationships between spans
+// in addition to a parent/child relationship.
+type Span_SpanKind int32
+
+const (
+ // Unspecified. Do NOT use as default.
+ // Implementations MAY assume SpanKind.INTERNAL to be default.
+ Span_SPAN_KIND_UNSPECIFIED Span_SpanKind = 0
+ // Indicates that the span is used internally. Default value.
+ Span_INTERNAL Span_SpanKind = 1
+ // Indicates that the span covers server-side handling of an RPC or other
+ // remote network request.
+ Span_SERVER Span_SpanKind = 2
+ // Indicates that the span covers the client-side wrapper around an RPC or
+ // other remote request.
+ Span_CLIENT Span_SpanKind = 3
+ // Indicates that the span describes producer sending a message to a broker.
+ // Unlike client and server, there is no direct critical path latency
+ // relationship between producer and consumer spans (e.g. publishing a
+ // message to a pubsub service).
+ Span_PRODUCER Span_SpanKind = 4
+ // Indicates that the span describes consumer receiving a message from a
+ // broker. Unlike client and server, there is no direct critical path
+ // latency relationship between producer and consumer spans (e.g. receiving
+ // a message from a pubsub service subscription).
+ Span_CONSUMER Span_SpanKind = 5
+)
+
+// Enum value maps for Span_SpanKind.
+var (
+ Span_SpanKind_name = map[int32]string{
+ 0: "SPAN_KIND_UNSPECIFIED",
+ 1: "INTERNAL",
+ 2: "SERVER",
+ 3: "CLIENT",
+ 4: "PRODUCER",
+ 5: "CONSUMER",
+ }
+ Span_SpanKind_value = map[string]int32{
+ "SPAN_KIND_UNSPECIFIED": 0,
+ "INTERNAL": 1,
+ "SERVER": 2,
+ "CLIENT": 3,
+ "PRODUCER": 4,
+ "CONSUMER": 5,
+ }
+)
+
+func (x Span_SpanKind) Enum() *Span_SpanKind {
+ p := new(Span_SpanKind)
+ *p = x
+ return p
+}
+
+func (x Span_SpanKind) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Span_SpanKind) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_devtools_cloudtrace_v2_trace_proto_enumTypes[0].Descriptor()
+}
+
+func (Span_SpanKind) Type() protoreflect.EnumType {
+ return &file_google_devtools_cloudtrace_v2_trace_proto_enumTypes[0]
+}
+
+func (x Span_SpanKind) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Span_SpanKind.Descriptor instead.
+func (Span_SpanKind) EnumDescriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{0, 0}
+}
+
+// Indicates whether the message was sent or received.
+type Span_TimeEvent_MessageEvent_Type int32
+
+const (
+ // Unknown event type.
+ Span_TimeEvent_MessageEvent_TYPE_UNSPECIFIED Span_TimeEvent_MessageEvent_Type = 0
+ // Indicates a sent message.
+ Span_TimeEvent_MessageEvent_SENT Span_TimeEvent_MessageEvent_Type = 1
+ // Indicates a received message.
+ Span_TimeEvent_MessageEvent_RECEIVED Span_TimeEvent_MessageEvent_Type = 2
+)
+
+// Enum value maps for Span_TimeEvent_MessageEvent_Type.
+var (
+ Span_TimeEvent_MessageEvent_Type_name = map[int32]string{
+ 0: "TYPE_UNSPECIFIED",
+ 1: "SENT",
+ 2: "RECEIVED",
+ }
+ Span_TimeEvent_MessageEvent_Type_value = map[string]int32{
+ "TYPE_UNSPECIFIED": 0,
+ "SENT": 1,
+ "RECEIVED": 2,
+ }
+)
+
+func (x Span_TimeEvent_MessageEvent_Type) Enum() *Span_TimeEvent_MessageEvent_Type {
+ p := new(Span_TimeEvent_MessageEvent_Type)
+ *p = x
+ return p
+}
+
+func (x Span_TimeEvent_MessageEvent_Type) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Span_TimeEvent_MessageEvent_Type) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_devtools_cloudtrace_v2_trace_proto_enumTypes[1].Descriptor()
+}
+
+func (Span_TimeEvent_MessageEvent_Type) Type() protoreflect.EnumType {
+ return &file_google_devtools_cloudtrace_v2_trace_proto_enumTypes[1]
+}
+
+func (x Span_TimeEvent_MessageEvent_Type) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Span_TimeEvent_MessageEvent_Type.Descriptor instead.
+func (Span_TimeEvent_MessageEvent_Type) EnumDescriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{0, 1, 1, 0}
+}
+
+// The relationship of the current span relative to the linked span: child,
+// parent, or unspecified.
+type Span_Link_Type int32
+
+const (
+ // The relationship of the two spans is unknown.
+ Span_Link_TYPE_UNSPECIFIED Span_Link_Type = 0
+ // The linked span is a child of the current span.
+ Span_Link_CHILD_LINKED_SPAN Span_Link_Type = 1
+ // The linked span is a parent of the current span.
+ Span_Link_PARENT_LINKED_SPAN Span_Link_Type = 2
+)
+
+// Enum value maps for Span_Link_Type.
+var (
+ Span_Link_Type_name = map[int32]string{
+ 0: "TYPE_UNSPECIFIED",
+ 1: "CHILD_LINKED_SPAN",
+ 2: "PARENT_LINKED_SPAN",
+ }
+ Span_Link_Type_value = map[string]int32{
+ "TYPE_UNSPECIFIED": 0,
+ "CHILD_LINKED_SPAN": 1,
+ "PARENT_LINKED_SPAN": 2,
+ }
+)
+
+func (x Span_Link_Type) Enum() *Span_Link_Type {
+ p := new(Span_Link_Type)
+ *p = x
+ return p
+}
+
+func (x Span_Link_Type) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Span_Link_Type) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_devtools_cloudtrace_v2_trace_proto_enumTypes[2].Descriptor()
+}
+
+func (Span_Link_Type) Type() protoreflect.EnumType {
+ return &file_google_devtools_cloudtrace_v2_trace_proto_enumTypes[2]
+}
+
+func (x Span_Link_Type) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Span_Link_Type.Descriptor instead.
+func (Span_Link_Type) EnumDescriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{0, 3, 0}
+}
+
+// A span represents a single operation within a trace. Spans can be
+// nested to form a trace tree. Often, a trace contains a root span
+// that describes the end-to-end latency, and one or more subspans for
+// its sub-operations.
+//
+// A trace can also contain multiple root spans, or none at all.
+// Spans do not need to be contiguous. There might be
+// gaps or overlaps between spans in a trace.
+type Span struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The resource name of the span in the following format:
+ //
+ // * `projects/[PROJECT_ID]/traces/[TRACE_ID]/spans/[SPAN_ID]`
+ //
+ // `[TRACE_ID]` is a unique identifier for a trace within a project;
+ // it is a 32-character hexadecimal encoding of a 16-byte array. It should
+ // not be zero.
+ //
+ // `[SPAN_ID]` is a unique identifier for a span within a trace; it
+ // is a 16-character hexadecimal encoding of an 8-byte array. It should not
+ // be zero.
+ // .
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Required. The `[SPAN_ID]` portion of the span's resource name.
+ SpanId string `protobuf:"bytes,2,opt,name=span_id,json=spanId,proto3" json:"span_id,omitempty"`
+ // The `[SPAN_ID]` of this span's parent span. If this is a root span,
+ // then this field must be empty.
+ ParentSpanId string `protobuf:"bytes,3,opt,name=parent_span_id,json=parentSpanId,proto3" json:"parent_span_id,omitempty"`
+ // Required. A description of the span's operation (up to 128 bytes).
+ // Cloud Trace displays the description in the
+ // Cloud console.
+ // For example, the display name can be a qualified method name or a file name
+ // and a line number where the operation is called. A best practice is to use
+ // the same display name within an application and at the same call point.
+ // This makes it easier to correlate spans in different traces.
+ DisplayName *TruncatableString `protobuf:"bytes,4,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
+ // Required. The start time of the span. On the client side, this is the time
+ // kept by the local machine where the span execution starts. On the server
+ // side, this is the time when the server's application handler starts
+ // running.
+ StartTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"`
+ // Required. The end time of the span. On the client side, this is the time
+ // kept by the local machine where the span execution ends. On the server
+ // side, this is the time when the server application handler stops running.
+ EndTime *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"`
+ // A set of attributes on the span. You can have up to 32 attributes per
+ // span.
+ Attributes *Span_Attributes `protobuf:"bytes,7,opt,name=attributes,proto3" json:"attributes,omitempty"`
+ // Stack trace captured at the start of the span.
+ StackTrace *StackTrace `protobuf:"bytes,8,opt,name=stack_trace,json=stackTrace,proto3" json:"stack_trace,omitempty"`
+ // A set of time events. You can have up to 32 annotations and 128 message
+ // events per span.
+ TimeEvents *Span_TimeEvents `protobuf:"bytes,9,opt,name=time_events,json=timeEvents,proto3" json:"time_events,omitempty"`
+ // Links associated with the span. You can have up to 128 links per Span.
+ Links *Span_Links `protobuf:"bytes,10,opt,name=links,proto3" json:"links,omitempty"`
+ // Optional. The final status for this span.
+ Status *status.Status `protobuf:"bytes,11,opt,name=status,proto3" json:"status,omitempty"`
+ // Optional. Set this parameter to indicate whether this span is in
+ // the same process as its parent. If you do not set this parameter,
+ // Trace is unable to take advantage of this helpful information.
+ SameProcessAsParentSpan *wrapperspb.BoolValue `protobuf:"bytes,12,opt,name=same_process_as_parent_span,json=sameProcessAsParentSpan,proto3" json:"same_process_as_parent_span,omitempty"`
+ // Optional. The number of child spans that were generated while this span
+ // was active. If set, allows implementation to detect missing child spans.
+ ChildSpanCount *wrapperspb.Int32Value `protobuf:"bytes,13,opt,name=child_span_count,json=childSpanCount,proto3" json:"child_span_count,omitempty"`
+ // Optional. Distinguishes between spans generated in a particular context.
+ // For example, two spans with the same name may be distinguished using
+ // `CLIENT` (caller) and `SERVER` (callee) to identify an RPC call.
+ SpanKind Span_SpanKind `protobuf:"varint,14,opt,name=span_kind,json=spanKind,proto3,enum=google.devtools.cloudtrace.v2.Span_SpanKind" json:"span_kind,omitempty"`
+}
+
+func (x *Span) Reset() {
+ *x = Span{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Span) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Span) ProtoMessage() {}
+
+func (x *Span) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Span.ProtoReflect.Descriptor instead.
+func (*Span) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Span) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *Span) GetSpanId() string {
+ if x != nil {
+ return x.SpanId
+ }
+ return ""
+}
+
+func (x *Span) GetParentSpanId() string {
+ if x != nil {
+ return x.ParentSpanId
+ }
+ return ""
+}
+
+func (x *Span) GetDisplayName() *TruncatableString {
+ if x != nil {
+ return x.DisplayName
+ }
+ return nil
+}
+
+func (x *Span) GetStartTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.StartTime
+ }
+ return nil
+}
+
+func (x *Span) GetEndTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.EndTime
+ }
+ return nil
+}
+
+func (x *Span) GetAttributes() *Span_Attributes {
+ if x != nil {
+ return x.Attributes
+ }
+ return nil
+}
+
+func (x *Span) GetStackTrace() *StackTrace {
+ if x != nil {
+ return x.StackTrace
+ }
+ return nil
+}
+
+func (x *Span) GetTimeEvents() *Span_TimeEvents {
+ if x != nil {
+ return x.TimeEvents
+ }
+ return nil
+}
+
+func (x *Span) GetLinks() *Span_Links {
+ if x != nil {
+ return x.Links
+ }
+ return nil
+}
+
+func (x *Span) GetStatus() *status.Status {
+ if x != nil {
+ return x.Status
+ }
+ return nil
+}
+
+func (x *Span) GetSameProcessAsParentSpan() *wrapperspb.BoolValue {
+ if x != nil {
+ return x.SameProcessAsParentSpan
+ }
+ return nil
+}
+
+func (x *Span) GetChildSpanCount() *wrapperspb.Int32Value {
+ if x != nil {
+ return x.ChildSpanCount
+ }
+ return nil
+}
+
+func (x *Span) GetSpanKind() Span_SpanKind {
+ if x != nil {
+ return x.SpanKind
+ }
+ return Span_SPAN_KIND_UNSPECIFIED
+}
+
+// The allowed types for `[VALUE]` in a `[KEY]:[VALUE]` attribute.
+type AttributeValue struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The type of the value.
+ //
+ // Types that are assignable to Value:
+ // *AttributeValue_StringValue
+ // *AttributeValue_IntValue
+ // *AttributeValue_BoolValue
+ Value isAttributeValue_Value `protobuf_oneof:"value"`
+}
+
+func (x *AttributeValue) Reset() {
+ *x = AttributeValue{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *AttributeValue) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AttributeValue) ProtoMessage() {}
+
+func (x *AttributeValue) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use AttributeValue.ProtoReflect.Descriptor instead.
+func (*AttributeValue) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{1}
+}
+
+func (m *AttributeValue) GetValue() isAttributeValue_Value {
+ if m != nil {
+ return m.Value
+ }
+ return nil
+}
+
+func (x *AttributeValue) GetStringValue() *TruncatableString {
+ if x, ok := x.GetValue().(*AttributeValue_StringValue); ok {
+ return x.StringValue
+ }
+ return nil
+}
+
+func (x *AttributeValue) GetIntValue() int64 {
+ if x, ok := x.GetValue().(*AttributeValue_IntValue); ok {
+ return x.IntValue
+ }
+ return 0
+}
+
+func (x *AttributeValue) GetBoolValue() bool {
+ if x, ok := x.GetValue().(*AttributeValue_BoolValue); ok {
+ return x.BoolValue
+ }
+ return false
+}
+
+type isAttributeValue_Value interface {
+ isAttributeValue_Value()
+}
+
+type AttributeValue_StringValue struct {
+ // A string up to 256 bytes long.
+ StringValue *TruncatableString `protobuf:"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof"`
+}
+
+type AttributeValue_IntValue struct {
+ // A 64-bit signed integer.
+ IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof"`
+}
+
+type AttributeValue_BoolValue struct {
+ // A Boolean value represented by `true` or `false`.
+ BoolValue bool `protobuf:"varint,3,opt,name=bool_value,json=boolValue,proto3,oneof"`
+}
+
+func (*AttributeValue_StringValue) isAttributeValue_Value() {}
+
+func (*AttributeValue_IntValue) isAttributeValue_Value() {}
+
+func (*AttributeValue_BoolValue) isAttributeValue_Value() {}
+
+// A call stack appearing in a trace.
+type StackTrace struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Stack frames in this stack trace. A maximum of 128 frames are allowed.
+ StackFrames *StackTrace_StackFrames `protobuf:"bytes,1,opt,name=stack_frames,json=stackFrames,proto3" json:"stack_frames,omitempty"`
+ // The hash ID is used to conserve network bandwidth for duplicate
+ // stack traces within a single trace.
+ //
+ // Often multiple spans will have identical stack traces.
+ // The first occurrence of a stack trace should contain both the
+ // `stackFrame` content and a value in `stackTraceHashId`.
+ //
+ // Subsequent spans within the same request can refer
+ // to that stack trace by only setting `stackTraceHashId`.
+ StackTraceHashId int64 `protobuf:"varint,2,opt,name=stack_trace_hash_id,json=stackTraceHashId,proto3" json:"stack_trace_hash_id,omitempty"`
+}
+
+func (x *StackTrace) Reset() {
+ *x = StackTrace{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *StackTrace) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StackTrace) ProtoMessage() {}
+
+func (x *StackTrace) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StackTrace.ProtoReflect.Descriptor instead.
+func (*StackTrace) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *StackTrace) GetStackFrames() *StackTrace_StackFrames {
+ if x != nil {
+ return x.StackFrames
+ }
+ return nil
+}
+
+func (x *StackTrace) GetStackTraceHashId() int64 {
+ if x != nil {
+ return x.StackTraceHashId
+ }
+ return 0
+}
+
+// Binary module.
+type Module struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // For example: main binary, kernel modules, and dynamic libraries
+ // such as libc.so, sharedlib.so (up to 256 bytes).
+ Module *TruncatableString `protobuf:"bytes,1,opt,name=module,proto3" json:"module,omitempty"`
+ // A unique identifier for the module, usually a hash of its
+ // contents (up to 128 bytes).
+ BuildId *TruncatableString `protobuf:"bytes,2,opt,name=build_id,json=buildId,proto3" json:"build_id,omitempty"`
+}
+
+func (x *Module) Reset() {
+ *x = Module{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Module) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Module) ProtoMessage() {}
+
+func (x *Module) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Module.ProtoReflect.Descriptor instead.
+func (*Module) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *Module) GetModule() *TruncatableString {
+ if x != nil {
+ return x.Module
+ }
+ return nil
+}
+
+func (x *Module) GetBuildId() *TruncatableString {
+ if x != nil {
+ return x.BuildId
+ }
+ return nil
+}
+
+// Represents a string that might be shortened to a specified length.
+type TruncatableString struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The shortened string. For example, if the original string is 500
+ // bytes long and the limit of the string is 128 bytes, then
+ // `value` contains the first 128 bytes of the 500-byte string.
+ //
+ // Truncation always happens on a UTF8 character boundary. If there
+ // are multi-byte characters in the string, then the length of the
+ // shortened string might be less than the size limit.
+ Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
+ // The number of bytes removed from the original string. If this
+ // value is 0, then the string was not shortened.
+ TruncatedByteCount int32 `protobuf:"varint,2,opt,name=truncated_byte_count,json=truncatedByteCount,proto3" json:"truncated_byte_count,omitempty"`
+}
+
+func (x *TruncatableString) Reset() {
+ *x = TruncatableString{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TruncatableString) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TruncatableString) ProtoMessage() {}
+
+func (x *TruncatableString) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TruncatableString.ProtoReflect.Descriptor instead.
+func (*TruncatableString) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *TruncatableString) GetValue() string {
+ if x != nil {
+ return x.Value
+ }
+ return ""
+}
+
+func (x *TruncatableString) GetTruncatedByteCount() int32 {
+ if x != nil {
+ return x.TruncatedByteCount
+ }
+ return 0
+}
+
+// A set of attributes as key-value pairs.
+type Span_Attributes struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // A set of attributes. Each attribute's key can be up to 128 bytes
+ // long. The value can be a string up to 256 bytes, a signed 64-bit integer,
+ // or the boolean values `true` or `false`. For example:
+ //
+ // "/instance_id": { "string_value": { "value": "my-instance" } }
+ // "/http/request_bytes": { "int_value": 300 }
+ // "abc.com/myattribute": { "bool_value": false }
+ AttributeMap map[string]*AttributeValue `protobuf:"bytes,1,rep,name=attribute_map,json=attributeMap,proto3" json:"attribute_map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // The number of attributes that were discarded. Attributes can be discarded
+ // because their keys are too long or because there are too many attributes.
+ // If this value is 0 then all attributes are valid.
+ DroppedAttributesCount int32 `protobuf:"varint,2,opt,name=dropped_attributes_count,json=droppedAttributesCount,proto3" json:"dropped_attributes_count,omitempty"`
+}
+
+func (x *Span_Attributes) Reset() {
+ *x = Span_Attributes{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Span_Attributes) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Span_Attributes) ProtoMessage() {}
+
+func (x *Span_Attributes) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Span_Attributes.ProtoReflect.Descriptor instead.
+func (*Span_Attributes) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{0, 0}
+}
+
+func (x *Span_Attributes) GetAttributeMap() map[string]*AttributeValue {
+ if x != nil {
+ return x.AttributeMap
+ }
+ return nil
+}
+
+func (x *Span_Attributes) GetDroppedAttributesCount() int32 {
+ if x != nil {
+ return x.DroppedAttributesCount
+ }
+ return 0
+}
+
+// A time-stamped annotation or message event in the Span.
+type Span_TimeEvent struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The timestamp indicating the time the event occurred.
+ Time *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=time,proto3" json:"time,omitempty"`
+ // A `TimeEvent` can contain either an `Annotation` object or a
+ // `MessageEvent` object, but not both.
+ //
+ // Types that are assignable to Value:
+ // *Span_TimeEvent_Annotation_
+ // *Span_TimeEvent_MessageEvent_
+ Value isSpan_TimeEvent_Value `protobuf_oneof:"value"`
+}
+
+func (x *Span_TimeEvent) Reset() {
+ *x = Span_TimeEvent{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Span_TimeEvent) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Span_TimeEvent) ProtoMessage() {}
+
+func (x *Span_TimeEvent) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Span_TimeEvent.ProtoReflect.Descriptor instead.
+func (*Span_TimeEvent) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{0, 1}
+}
+
+func (x *Span_TimeEvent) GetTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Time
+ }
+ return nil
+}
+
+func (m *Span_TimeEvent) GetValue() isSpan_TimeEvent_Value {
+ if m != nil {
+ return m.Value
+ }
+ return nil
+}
+
+func (x *Span_TimeEvent) GetAnnotation() *Span_TimeEvent_Annotation {
+ if x, ok := x.GetValue().(*Span_TimeEvent_Annotation_); ok {
+ return x.Annotation
+ }
+ return nil
+}
+
+func (x *Span_TimeEvent) GetMessageEvent() *Span_TimeEvent_MessageEvent {
+ if x, ok := x.GetValue().(*Span_TimeEvent_MessageEvent_); ok {
+ return x.MessageEvent
+ }
+ return nil
+}
+
+type isSpan_TimeEvent_Value interface {
+ isSpan_TimeEvent_Value()
+}
+
+type Span_TimeEvent_Annotation_ struct {
+ // Text annotation with a set of attributes.
+ Annotation *Span_TimeEvent_Annotation `protobuf:"bytes,2,opt,name=annotation,proto3,oneof"`
+}
+
+type Span_TimeEvent_MessageEvent_ struct {
+ // An event describing a message sent/received between Spans.
+ MessageEvent *Span_TimeEvent_MessageEvent `protobuf:"bytes,3,opt,name=message_event,json=messageEvent,proto3,oneof"`
+}
+
+func (*Span_TimeEvent_Annotation_) isSpan_TimeEvent_Value() {}
+
+func (*Span_TimeEvent_MessageEvent_) isSpan_TimeEvent_Value() {}
+
+// A collection of `TimeEvent`s. A `TimeEvent` is a time-stamped annotation
+// on the span, consisting of either user-supplied key:value pairs, or
+// details of a message sent/received between Spans.
+type Span_TimeEvents struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // A collection of `TimeEvent`s.
+ TimeEvent []*Span_TimeEvent `protobuf:"bytes,1,rep,name=time_event,json=timeEvent,proto3" json:"time_event,omitempty"`
+ // The number of dropped annotations in all the included time events.
+ // If the value is 0, then no annotations were dropped.
+ DroppedAnnotationsCount int32 `protobuf:"varint,2,opt,name=dropped_annotations_count,json=droppedAnnotationsCount,proto3" json:"dropped_annotations_count,omitempty"`
+ // The number of dropped message events in all the included time events.
+ // If the value is 0, then no message events were dropped.
+ DroppedMessageEventsCount int32 `protobuf:"varint,3,opt,name=dropped_message_events_count,json=droppedMessageEventsCount,proto3" json:"dropped_message_events_count,omitempty"`
+}
+
+func (x *Span_TimeEvents) Reset() {
+ *x = Span_TimeEvents{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Span_TimeEvents) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Span_TimeEvents) ProtoMessage() {}
+
+func (x *Span_TimeEvents) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Span_TimeEvents.ProtoReflect.Descriptor instead.
+func (*Span_TimeEvents) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{0, 2}
+}
+
+func (x *Span_TimeEvents) GetTimeEvent() []*Span_TimeEvent {
+ if x != nil {
+ return x.TimeEvent
+ }
+ return nil
+}
+
+func (x *Span_TimeEvents) GetDroppedAnnotationsCount() int32 {
+ if x != nil {
+ return x.DroppedAnnotationsCount
+ }
+ return 0
+}
+
+func (x *Span_TimeEvents) GetDroppedMessageEventsCount() int32 {
+ if x != nil {
+ return x.DroppedMessageEventsCount
+ }
+ return 0
+}
+
+// A pointer from the current span to another span in the same trace or in a
+// different trace. For example, this can be used in batching operations,
+// where a single batch handler processes multiple requests from different
+// traces or when the handler receives a request from a different project.
+type Span_Link struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The `[TRACE_ID]` for a trace within a project.
+ TraceId string `protobuf:"bytes,1,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"`
+ // The `[SPAN_ID]` for a span within a trace.
+ SpanId string `protobuf:"bytes,2,opt,name=span_id,json=spanId,proto3" json:"span_id,omitempty"`
+ // The relationship of the current span relative to the linked span.
+ Type Span_Link_Type `protobuf:"varint,3,opt,name=type,proto3,enum=google.devtools.cloudtrace.v2.Span_Link_Type" json:"type,omitempty"`
+ // A set of attributes on the link. Up to 32 attributes can be
+ // specified per link.
+ Attributes *Span_Attributes `protobuf:"bytes,4,opt,name=attributes,proto3" json:"attributes,omitempty"`
+}
+
+func (x *Span_Link) Reset() {
+ *x = Span_Link{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Span_Link) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Span_Link) ProtoMessage() {}
+
+func (x *Span_Link) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[8]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Span_Link.ProtoReflect.Descriptor instead.
+func (*Span_Link) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{0, 3}
+}
+
+func (x *Span_Link) GetTraceId() string {
+ if x != nil {
+ return x.TraceId
+ }
+ return ""
+}
+
+func (x *Span_Link) GetSpanId() string {
+ if x != nil {
+ return x.SpanId
+ }
+ return ""
+}
+
+func (x *Span_Link) GetType() Span_Link_Type {
+ if x != nil {
+ return x.Type
+ }
+ return Span_Link_TYPE_UNSPECIFIED
+}
+
+func (x *Span_Link) GetAttributes() *Span_Attributes {
+ if x != nil {
+ return x.Attributes
+ }
+ return nil
+}
+
+// A collection of links, which are references from this span to a span
+// in the same or different trace.
+type Span_Links struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // A collection of links.
+ Link []*Span_Link `protobuf:"bytes,1,rep,name=link,proto3" json:"link,omitempty"`
+ // The number of dropped links after the maximum size was enforced. If
+ // this value is 0, then no links were dropped.
+ DroppedLinksCount int32 `protobuf:"varint,2,opt,name=dropped_links_count,json=droppedLinksCount,proto3" json:"dropped_links_count,omitempty"`
+}
+
+func (x *Span_Links) Reset() {
+ *x = Span_Links{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Span_Links) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Span_Links) ProtoMessage() {}
+
+func (x *Span_Links) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Span_Links.ProtoReflect.Descriptor instead.
+func (*Span_Links) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{0, 4}
+}
+
+func (x *Span_Links) GetLink() []*Span_Link {
+ if x != nil {
+ return x.Link
+ }
+ return nil
+}
+
+func (x *Span_Links) GetDroppedLinksCount() int32 {
+ if x != nil {
+ return x.DroppedLinksCount
+ }
+ return 0
+}
+
+// Text annotation with a set of attributes.
+type Span_TimeEvent_Annotation struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // A user-supplied message describing the event. The maximum length for
+ // the description is 256 bytes.
+ Description *TruncatableString `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"`
+ // A set of attributes on the annotation. You can have up to 4 attributes
+ // per Annotation.
+ Attributes *Span_Attributes `protobuf:"bytes,2,opt,name=attributes,proto3" json:"attributes,omitempty"`
+}
+
+func (x *Span_TimeEvent_Annotation) Reset() {
+ *x = Span_TimeEvent_Annotation{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Span_TimeEvent_Annotation) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Span_TimeEvent_Annotation) ProtoMessage() {}
+
+func (x *Span_TimeEvent_Annotation) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[11]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Span_TimeEvent_Annotation.ProtoReflect.Descriptor instead.
+func (*Span_TimeEvent_Annotation) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{0, 1, 0}
+}
+
+func (x *Span_TimeEvent_Annotation) GetDescription() *TruncatableString {
+ if x != nil {
+ return x.Description
+ }
+ return nil
+}
+
+func (x *Span_TimeEvent_Annotation) GetAttributes() *Span_Attributes {
+ if x != nil {
+ return x.Attributes
+ }
+ return nil
+}
+
+// An event describing a message sent/received between Spans.
+type Span_TimeEvent_MessageEvent struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Type of MessageEvent. Indicates whether the message was sent or
+ // received.
+ Type Span_TimeEvent_MessageEvent_Type `protobuf:"varint,1,opt,name=type,proto3,enum=google.devtools.cloudtrace.v2.Span_TimeEvent_MessageEvent_Type" json:"type,omitempty"`
+ // An identifier for the MessageEvent's message that can be used to match
+ // `SENT` and `RECEIVED` MessageEvents.
+ Id int64 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"`
+ // The number of uncompressed bytes sent or received.
+ UncompressedSizeBytes int64 `protobuf:"varint,3,opt,name=uncompressed_size_bytes,json=uncompressedSizeBytes,proto3" json:"uncompressed_size_bytes,omitempty"`
+ // The number of compressed bytes sent or received. If missing, the
+ // compressed size is assumed to be the same size as the uncompressed
+ // size.
+ CompressedSizeBytes int64 `protobuf:"varint,4,opt,name=compressed_size_bytes,json=compressedSizeBytes,proto3" json:"compressed_size_bytes,omitempty"`
+}
+
+func (x *Span_TimeEvent_MessageEvent) Reset() {
+ *x = Span_TimeEvent_MessageEvent{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Span_TimeEvent_MessageEvent) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Span_TimeEvent_MessageEvent) ProtoMessage() {}
+
+func (x *Span_TimeEvent_MessageEvent) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[12]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Span_TimeEvent_MessageEvent.ProtoReflect.Descriptor instead.
+func (*Span_TimeEvent_MessageEvent) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{0, 1, 1}
+}
+
+func (x *Span_TimeEvent_MessageEvent) GetType() Span_TimeEvent_MessageEvent_Type {
+ if x != nil {
+ return x.Type
+ }
+ return Span_TimeEvent_MessageEvent_TYPE_UNSPECIFIED
+}
+
+func (x *Span_TimeEvent_MessageEvent) GetId() int64 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *Span_TimeEvent_MessageEvent) GetUncompressedSizeBytes() int64 {
+ if x != nil {
+ return x.UncompressedSizeBytes
+ }
+ return 0
+}
+
+func (x *Span_TimeEvent_MessageEvent) GetCompressedSizeBytes() int64 {
+ if x != nil {
+ return x.CompressedSizeBytes
+ }
+ return 0
+}
+
+// Represents a single stack frame in a stack trace.
+type StackTrace_StackFrame struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The fully-qualified name that uniquely identifies the function or
+ // method that is active in this frame (up to 1024 bytes).
+ FunctionName *TruncatableString `protobuf:"bytes,1,opt,name=function_name,json=functionName,proto3" json:"function_name,omitempty"`
+ // An un-mangled function name, if `function_name` is mangled.
+ // To get information about name mangling, run
+ // [this search](https://www.google.com/search?q=cxx+name+mangling).
+ // The name can be fully-qualified (up to 1024 bytes).
+ OriginalFunctionName *TruncatableString `protobuf:"bytes,2,opt,name=original_function_name,json=originalFunctionName,proto3" json:"original_function_name,omitempty"`
+ // The name of the source file where the function call appears (up to 256
+ // bytes).
+ FileName *TruncatableString `protobuf:"bytes,3,opt,name=file_name,json=fileName,proto3" json:"file_name,omitempty"`
+ // The line number in `file_name` where the function call appears.
+ LineNumber int64 `protobuf:"varint,4,opt,name=line_number,json=lineNumber,proto3" json:"line_number,omitempty"`
+ // The column number where the function call appears, if available.
+ // This is important in JavaScript because of its anonymous functions.
+ ColumnNumber int64 `protobuf:"varint,5,opt,name=column_number,json=columnNumber,proto3" json:"column_number,omitempty"`
+ // The binary module from where the code was loaded.
+ LoadModule *Module `protobuf:"bytes,6,opt,name=load_module,json=loadModule,proto3" json:"load_module,omitempty"`
+ // The version of the deployed source code (up to 128 bytes).
+ SourceVersion *TruncatableString `protobuf:"bytes,7,opt,name=source_version,json=sourceVersion,proto3" json:"source_version,omitempty"`
+}
+
+func (x *StackTrace_StackFrame) Reset() {
+ *x = StackTrace_StackFrame{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *StackTrace_StackFrame) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StackTrace_StackFrame) ProtoMessage() {}
+
+func (x *StackTrace_StackFrame) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[13]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StackTrace_StackFrame.ProtoReflect.Descriptor instead.
+func (*StackTrace_StackFrame) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{2, 0}
+}
+
+func (x *StackTrace_StackFrame) GetFunctionName() *TruncatableString {
+ if x != nil {
+ return x.FunctionName
+ }
+ return nil
+}
+
+func (x *StackTrace_StackFrame) GetOriginalFunctionName() *TruncatableString {
+ if x != nil {
+ return x.OriginalFunctionName
+ }
+ return nil
+}
+
+func (x *StackTrace_StackFrame) GetFileName() *TruncatableString {
+ if x != nil {
+ return x.FileName
+ }
+ return nil
+}
+
+func (x *StackTrace_StackFrame) GetLineNumber() int64 {
+ if x != nil {
+ return x.LineNumber
+ }
+ return 0
+}
+
+func (x *StackTrace_StackFrame) GetColumnNumber() int64 {
+ if x != nil {
+ return x.ColumnNumber
+ }
+ return 0
+}
+
+func (x *StackTrace_StackFrame) GetLoadModule() *Module {
+ if x != nil {
+ return x.LoadModule
+ }
+ return nil
+}
+
+func (x *StackTrace_StackFrame) GetSourceVersion() *TruncatableString {
+ if x != nil {
+ return x.SourceVersion
+ }
+ return nil
+}
+
+// A collection of stack frames, which can be truncated.
+type StackTrace_StackFrames struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Stack frames in this call stack.
+ Frame []*StackTrace_StackFrame `protobuf:"bytes,1,rep,name=frame,proto3" json:"frame,omitempty"`
+ // The number of stack frames that were dropped because there
+ // were too many stack frames.
+ // If this value is 0, then no stack frames were dropped.
+ DroppedFramesCount int32 `protobuf:"varint,2,opt,name=dropped_frames_count,json=droppedFramesCount,proto3" json:"dropped_frames_count,omitempty"`
+}
+
+func (x *StackTrace_StackFrames) Reset() {
+ *x = StackTrace_StackFrames{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *StackTrace_StackFrames) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StackTrace_StackFrames) ProtoMessage() {}
+
+func (x *StackTrace_StackFrames) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[14]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StackTrace_StackFrames.ProtoReflect.Descriptor instead.
+func (*StackTrace_StackFrames) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP(), []int{2, 1}
+}
+
+func (x *StackTrace_StackFrames) GetFrame() []*StackTrace_StackFrame {
+ if x != nil {
+ return x.Frame
+ }
+ return nil
+}
+
+func (x *StackTrace_StackFrames) GetDroppedFramesCount() int32 {
+ if x != nil {
+ return x.DroppedFramesCount
+ }
+ return 0
+}
+
+var File_google_devtools_cloudtrace_v2_trace_proto protoreflect.FileDescriptor
+
+var file_google_devtools_cloudtrace_v2_trace_proto_rawDesc = []byte{
+ 0x0a, 0x29, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c,
+ 0x73, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x76, 0x32, 0x2f,
+ 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1d, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f,
+ 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68,
+ 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
+ 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72,
+ 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
+ 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x22, 0xb0, 0x15, 0x0a, 0x04, 0x53, 0x70, 0x61, 0x6e, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x73, 0x70, 0x61, 0x6e, 0x49, 0x64,
+ 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x70, 0x61, 0x6e, 0x5f,
+ 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
+ 0x53, 0x70, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x58, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61,
+ 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63,
+ 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x72, 0x75,
+ 0x6e, 0x63, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x42, 0x03,
+ 0xe0, 0x41, 0x02, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65,
+ 0x12, 0x3e, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
+ 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65,
+ 0x12, 0x3a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03,
+ 0xe0, 0x41, 0x02, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4e, 0x0a, 0x0a,
+ 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x2e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f,
+ 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32,
+ 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
+ 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x0b,
+ 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x29, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f,
+ 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76,
+ 0x32, 0x2e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x52, 0x0a, 0x73, 0x74,
+ 0x61, 0x63, 0x6b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x12, 0x4f, 0x0a, 0x0b, 0x74, 0x69, 0x6d, 0x65,
+ 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e,
+ 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70,
+ 0x61, 0x6e, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x0a, 0x74,
+ 0x69, 0x6d, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3f, 0x0a, 0x05, 0x6c, 0x69, 0x6e,
+ 0x6b, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64,
+ 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x2e, 0x4c, 0x69,
+ 0x6e, 0x6b, 0x73, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x74,
+ 0x61, 0x74, 0x75, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x03,
+ 0xe0, 0x41, 0x01, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x5d, 0x0a, 0x1b, 0x73,
+ 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x61, 0x73, 0x5f, 0x70,
+ 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x70, 0x61, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+ 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x03, 0xe0, 0x41,
+ 0x01, 0x52, 0x17, 0x73, 0x61, 0x6d, 0x65, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x41, 0x73,
+ 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x70, 0x61, 0x6e, 0x12, 0x4a, 0x0a, 0x10, 0x63, 0x68,
+ 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x70, 0x61, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0d,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75,
+ 0x65, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x0e, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x53, 0x70, 0x61,
+ 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x4e, 0x0a, 0x09, 0x73, 0x70, 0x61, 0x6e, 0x5f, 0x6b,
+ 0x69, 0x6e, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75,
+ 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x2e, 0x53,
+ 0x70, 0x61, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x08, 0x73, 0x70,
+ 0x61, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x1a, 0x9d, 0x02, 0x0a, 0x0a, 0x41, 0x74, 0x74, 0x72, 0x69,
+ 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x65, 0x0a, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
+ 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63,
+ 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61,
+ 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x41, 0x74, 0x74,
+ 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c,
+ 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x4d, 0x61, 0x70, 0x12, 0x38, 0x0a, 0x18,
+ 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
+ 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x16,
+ 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
+ 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0x6e, 0x0a, 0x11, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62,
+ 0x75, 0x74, 0x65, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
+ 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x43, 0x0a,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63,
+ 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x41, 0x74, 0x74,
+ 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c,
+ 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xce, 0x05, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x45,
+ 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04,
+ 0x74, 0x69, 0x6d, 0x65, 0x12, 0x5a, 0x0a, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64,
+ 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x2e, 0x54, 0x69,
+ 0x6d, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x12, 0x61, 0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e,
+ 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74,
+ 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x2e, 0x54, 0x69, 0x6d,
+ 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76,
+ 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76,
+ 0x65, 0x6e, 0x74, 0x1a, 0xb0, 0x01, 0x0a, 0x0a, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x12, 0x52, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+ 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74,
+ 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x61,
+ 0x62, 0x6c, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
+ 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62,
+ 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f,
+ 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x2e,
+ 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72,
+ 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x95, 0x02, 0x0a, 0x0c, 0x4d, 0x65, 0x73, 0x73, 0x61,
+ 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x53, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64,
+ 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61,
+ 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x45,
+ 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e,
+ 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02,
+ 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x17,
+ 0x75, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x5f, 0x73, 0x69, 0x7a,
+ 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x75,
+ 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x42,
+ 0x79, 0x74, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73,
+ 0x65, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20,
+ 0x01, 0x28, 0x03, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53,
+ 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x34, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65,
+ 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
+ 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x45, 0x4e, 0x54, 0x10, 0x01,
+ 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x43, 0x45, 0x49, 0x56, 0x45, 0x44, 0x10, 0x02, 0x42, 0x07,
+ 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0xd7, 0x01, 0x0a, 0x0a, 0x54, 0x69, 0x6d, 0x65,
+ 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x4c, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x65,
+ 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f,
+ 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x2e,
+ 0x54, 0x69, 0x6d, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x45,
+ 0x76, 0x65, 0x6e, 0x74, 0x12, 0x3a, 0x0a, 0x19, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x5f,
+ 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e,
+ 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64,
+ 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74,
+ 0x12, 0x3f, 0x0a, 0x1c, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73,
+ 0x61, 0x67, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x19, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x4d,
+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x43, 0x6f, 0x75, 0x6e,
+ 0x74, 0x1a, 0x9a, 0x02, 0x0a, 0x04, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x72,
+ 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x72,
+ 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x6e, 0x5f, 0x69, 0x64,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x70, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x41,
+ 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63,
+ 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61,
+ 0x6e, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70,
+ 0x65, 0x12, 0x4e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18,
+ 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64,
+ 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61,
+ 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69,
+ 0x62, 0x75, 0x74, 0x65, 0x73, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
+ 0x73, 0x22, 0x4b, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50,
+ 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12,
+ 0x15, 0x0a, 0x11, 0x43, 0x48, 0x49, 0x4c, 0x44, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, 0x5f,
+ 0x53, 0x50, 0x41, 0x4e, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x41, 0x52, 0x45, 0x4e, 0x54,
+ 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, 0x5f, 0x53, 0x50, 0x41, 0x4e, 0x10, 0x02, 0x1a, 0x75,
+ 0x0a, 0x05, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x3c, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18,
+ 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64,
+ 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61,
+ 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x52,
+ 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64,
+ 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x05, 0x52, 0x11, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x4c, 0x69, 0x6e, 0x6b, 0x73,
+ 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x67, 0x0a, 0x08, 0x53, 0x70, 0x61, 0x6e, 0x4b, 0x69, 0x6e,
+ 0x64, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55,
+ 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08,
+ 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x45,
+ 0x52, 0x56, 0x45, 0x52, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54,
+ 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x45, 0x52, 0x10, 0x04,
+ 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x4f, 0x4e, 0x53, 0x55, 0x4d, 0x45, 0x52, 0x10, 0x05, 0x3a, 0x53,
+ 0xea, 0x41, 0x50, 0x0a, 0x1e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53,
+ 0x70, 0x61, 0x6e, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70,
+ 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x2f, 0x7b,
+ 0x74, 0x72, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x73, 0x2f, 0x7b, 0x73, 0x70,
+ 0x61, 0x6e, 0x7d, 0x22, 0xb0, 0x01, 0x0a, 0x0e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
+ 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x55, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+ 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63,
+ 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x72, 0x75,
+ 0x6e, 0x63, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x48, 0x00,
+ 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a,
+ 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,
+ 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a, 0x0a,
+ 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
+ 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x07, 0x0a,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xa7, 0x06, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x63, 0x6b,
+ 0x54, 0x72, 0x61, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x66,
+ 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c,
+ 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, 0x63,
+ 0x6b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d,
+ 0x65, 0x73, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12,
+ 0x2d, 0x0a, 0x13, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x68,
+ 0x61, 0x73, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x73, 0x74,
+ 0x61, 0x63, 0x6b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x48, 0x61, 0x73, 0x68, 0x49, 0x64, 0x1a, 0x81,
+ 0x04, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x55, 0x0a,
+ 0x0d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65,
+ 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63,
+ 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x66, 0x0a, 0x16, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
+ 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65,
+ 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63,
+ 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x14, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c,
+ 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4d, 0x0a, 0x09,
+ 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c,
+ 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e,
+ 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e,
+ 0x67, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c,
+ 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03,
+ 0x52, 0x0a, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d,
+ 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x05, 0x20,
+ 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65,
+ 0x72, 0x12, 0x46, 0x0a, 0x0b, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
+ 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72,
+ 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x0a, 0x6c,
+ 0x6f, 0x61, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x57, 0x0a, 0x0e, 0x73, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f,
+ 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76,
+ 0x32, 0x2e, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x72,
+ 0x69, 0x6e, 0x67, 0x52, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69,
+ 0x6f, 0x6e, 0x1a, 0x8b, 0x01, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d,
+ 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28,
+ 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f,
+ 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76,
+ 0x32, 0x2e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61,
+ 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x30,
+ 0x0a, 0x14, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73,
+ 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x64, 0x72,
+ 0x6f, 0x70, 0x70, 0x65, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74,
+ 0x22, 0x9f, 0x01, 0x0a, 0x06, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x48, 0x0a, 0x06, 0x6d,
+ 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c,
+ 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x72, 0x75, 0x6e,
+ 0x63, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x06, 0x6d,
+ 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69,
+ 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74,
+ 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x61,
+ 0x62, 0x6c, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64,
+ 0x49, 0x64, 0x22, 0x5b, 0x0a, 0x11, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x61, 0x62, 0x6c,
+ 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x30, 0x0a,
+ 0x14, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x5f,
+ 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x74, 0x72, 0x75,
+ 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42,
+ 0xad, 0x01, 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64,
+ 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61,
+ 0x63, 0x65, 0x2e, 0x76, 0x32, 0x42, 0x0a, 0x54, 0x72, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74,
+ 0x6f, 0x50, 0x01, 0x5a, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x61,
+ 0x70, 0x69, 0x76, 0x32, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x62, 0x3b, 0x74, 0x72, 0x61,
+ 0x63, 0x65, 0x70, 0x62, 0xaa, 0x02, 0x15, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c,
+ 0x6f, 0x75, 0x64, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x15, 0x47,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x54, 0x72, 0x61, 0x63,
+ 0x65, 0x5c, 0x56, 0x32, 0xea, 0x02, 0x18, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43,
+ 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x54, 0x72, 0x61, 0x63, 0x65, 0x3a, 0x3a, 0x56, 0x32, 0x62,
+ 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_google_devtools_cloudtrace_v2_trace_proto_rawDescOnce sync.Once
+ file_google_devtools_cloudtrace_v2_trace_proto_rawDescData = file_google_devtools_cloudtrace_v2_trace_proto_rawDesc
+)
+
+func file_google_devtools_cloudtrace_v2_trace_proto_rawDescGZIP() []byte {
+ file_google_devtools_cloudtrace_v2_trace_proto_rawDescOnce.Do(func() {
+ file_google_devtools_cloudtrace_v2_trace_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_devtools_cloudtrace_v2_trace_proto_rawDescData)
+ })
+ return file_google_devtools_cloudtrace_v2_trace_proto_rawDescData
+}
+
+var file_google_devtools_cloudtrace_v2_trace_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
+var file_google_devtools_cloudtrace_v2_trace_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
+var file_google_devtools_cloudtrace_v2_trace_proto_goTypes = []interface{}{
+ (Span_SpanKind)(0), // 0: google.devtools.cloudtrace.v2.Span.SpanKind
+ (Span_TimeEvent_MessageEvent_Type)(0), // 1: google.devtools.cloudtrace.v2.Span.TimeEvent.MessageEvent.Type
+ (Span_Link_Type)(0), // 2: google.devtools.cloudtrace.v2.Span.Link.Type
+ (*Span)(nil), // 3: google.devtools.cloudtrace.v2.Span
+ (*AttributeValue)(nil), // 4: google.devtools.cloudtrace.v2.AttributeValue
+ (*StackTrace)(nil), // 5: google.devtools.cloudtrace.v2.StackTrace
+ (*Module)(nil), // 6: google.devtools.cloudtrace.v2.Module
+ (*TruncatableString)(nil), // 7: google.devtools.cloudtrace.v2.TruncatableString
+ (*Span_Attributes)(nil), // 8: google.devtools.cloudtrace.v2.Span.Attributes
+ (*Span_TimeEvent)(nil), // 9: google.devtools.cloudtrace.v2.Span.TimeEvent
+ (*Span_TimeEvents)(nil), // 10: google.devtools.cloudtrace.v2.Span.TimeEvents
+ (*Span_Link)(nil), // 11: google.devtools.cloudtrace.v2.Span.Link
+ (*Span_Links)(nil), // 12: google.devtools.cloudtrace.v2.Span.Links
+ nil, // 13: google.devtools.cloudtrace.v2.Span.Attributes.AttributeMapEntry
+ (*Span_TimeEvent_Annotation)(nil), // 14: google.devtools.cloudtrace.v2.Span.TimeEvent.Annotation
+ (*Span_TimeEvent_MessageEvent)(nil), // 15: google.devtools.cloudtrace.v2.Span.TimeEvent.MessageEvent
+ (*StackTrace_StackFrame)(nil), // 16: google.devtools.cloudtrace.v2.StackTrace.StackFrame
+ (*StackTrace_StackFrames)(nil), // 17: google.devtools.cloudtrace.v2.StackTrace.StackFrames
+ (*timestamppb.Timestamp)(nil), // 18: google.protobuf.Timestamp
+ (*status.Status)(nil), // 19: google.rpc.Status
+ (*wrapperspb.BoolValue)(nil), // 20: google.protobuf.BoolValue
+ (*wrapperspb.Int32Value)(nil), // 21: google.protobuf.Int32Value
+}
+var file_google_devtools_cloudtrace_v2_trace_proto_depIdxs = []int32{
+ 7, // 0: google.devtools.cloudtrace.v2.Span.display_name:type_name -> google.devtools.cloudtrace.v2.TruncatableString
+ 18, // 1: google.devtools.cloudtrace.v2.Span.start_time:type_name -> google.protobuf.Timestamp
+ 18, // 2: google.devtools.cloudtrace.v2.Span.end_time:type_name -> google.protobuf.Timestamp
+ 8, // 3: google.devtools.cloudtrace.v2.Span.attributes:type_name -> google.devtools.cloudtrace.v2.Span.Attributes
+ 5, // 4: google.devtools.cloudtrace.v2.Span.stack_trace:type_name -> google.devtools.cloudtrace.v2.StackTrace
+ 10, // 5: google.devtools.cloudtrace.v2.Span.time_events:type_name -> google.devtools.cloudtrace.v2.Span.TimeEvents
+ 12, // 6: google.devtools.cloudtrace.v2.Span.links:type_name -> google.devtools.cloudtrace.v2.Span.Links
+ 19, // 7: google.devtools.cloudtrace.v2.Span.status:type_name -> google.rpc.Status
+ 20, // 8: google.devtools.cloudtrace.v2.Span.same_process_as_parent_span:type_name -> google.protobuf.BoolValue
+ 21, // 9: google.devtools.cloudtrace.v2.Span.child_span_count:type_name -> google.protobuf.Int32Value
+ 0, // 10: google.devtools.cloudtrace.v2.Span.span_kind:type_name -> google.devtools.cloudtrace.v2.Span.SpanKind
+ 7, // 11: google.devtools.cloudtrace.v2.AttributeValue.string_value:type_name -> google.devtools.cloudtrace.v2.TruncatableString
+ 17, // 12: google.devtools.cloudtrace.v2.StackTrace.stack_frames:type_name -> google.devtools.cloudtrace.v2.StackTrace.StackFrames
+ 7, // 13: google.devtools.cloudtrace.v2.Module.module:type_name -> google.devtools.cloudtrace.v2.TruncatableString
+ 7, // 14: google.devtools.cloudtrace.v2.Module.build_id:type_name -> google.devtools.cloudtrace.v2.TruncatableString
+ 13, // 15: google.devtools.cloudtrace.v2.Span.Attributes.attribute_map:type_name -> google.devtools.cloudtrace.v2.Span.Attributes.AttributeMapEntry
+ 18, // 16: google.devtools.cloudtrace.v2.Span.TimeEvent.time:type_name -> google.protobuf.Timestamp
+ 14, // 17: google.devtools.cloudtrace.v2.Span.TimeEvent.annotation:type_name -> google.devtools.cloudtrace.v2.Span.TimeEvent.Annotation
+ 15, // 18: google.devtools.cloudtrace.v2.Span.TimeEvent.message_event:type_name -> google.devtools.cloudtrace.v2.Span.TimeEvent.MessageEvent
+ 9, // 19: google.devtools.cloudtrace.v2.Span.TimeEvents.time_event:type_name -> google.devtools.cloudtrace.v2.Span.TimeEvent
+ 2, // 20: google.devtools.cloudtrace.v2.Span.Link.type:type_name -> google.devtools.cloudtrace.v2.Span.Link.Type
+ 8, // 21: google.devtools.cloudtrace.v2.Span.Link.attributes:type_name -> google.devtools.cloudtrace.v2.Span.Attributes
+ 11, // 22: google.devtools.cloudtrace.v2.Span.Links.link:type_name -> google.devtools.cloudtrace.v2.Span.Link
+ 4, // 23: google.devtools.cloudtrace.v2.Span.Attributes.AttributeMapEntry.value:type_name -> google.devtools.cloudtrace.v2.AttributeValue
+ 7, // 24: google.devtools.cloudtrace.v2.Span.TimeEvent.Annotation.description:type_name -> google.devtools.cloudtrace.v2.TruncatableString
+ 8, // 25: google.devtools.cloudtrace.v2.Span.TimeEvent.Annotation.attributes:type_name -> google.devtools.cloudtrace.v2.Span.Attributes
+ 1, // 26: google.devtools.cloudtrace.v2.Span.TimeEvent.MessageEvent.type:type_name -> google.devtools.cloudtrace.v2.Span.TimeEvent.MessageEvent.Type
+ 7, // 27: google.devtools.cloudtrace.v2.StackTrace.StackFrame.function_name:type_name -> google.devtools.cloudtrace.v2.TruncatableString
+ 7, // 28: google.devtools.cloudtrace.v2.StackTrace.StackFrame.original_function_name:type_name -> google.devtools.cloudtrace.v2.TruncatableString
+ 7, // 29: google.devtools.cloudtrace.v2.StackTrace.StackFrame.file_name:type_name -> google.devtools.cloudtrace.v2.TruncatableString
+ 6, // 30: google.devtools.cloudtrace.v2.StackTrace.StackFrame.load_module:type_name -> google.devtools.cloudtrace.v2.Module
+ 7, // 31: google.devtools.cloudtrace.v2.StackTrace.StackFrame.source_version:type_name -> google.devtools.cloudtrace.v2.TruncatableString
+ 16, // 32: google.devtools.cloudtrace.v2.StackTrace.StackFrames.frame:type_name -> google.devtools.cloudtrace.v2.StackTrace.StackFrame
+ 33, // [33:33] is the sub-list for method output_type
+ 33, // [33:33] is the sub-list for method input_type
+ 33, // [33:33] is the sub-list for extension type_name
+ 33, // [33:33] is the sub-list for extension extendee
+ 0, // [0:33] is the sub-list for field type_name
+}
+
+func init() { file_google_devtools_cloudtrace_v2_trace_proto_init() }
+func file_google_devtools_cloudtrace_v2_trace_proto_init() {
+ if File_google_devtools_cloudtrace_v2_trace_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Span); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*AttributeValue); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*StackTrace); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Module); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TruncatableString); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Span_Attributes); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Span_TimeEvent); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Span_TimeEvents); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Span_Link); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Span_Links); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Span_TimeEvent_Annotation); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Span_TimeEvent_MessageEvent); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*StackTrace_StackFrame); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*StackTrace_StackFrames); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[1].OneofWrappers = []interface{}{
+ (*AttributeValue_StringValue)(nil),
+ (*AttributeValue_IntValue)(nil),
+ (*AttributeValue_BoolValue)(nil),
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_msgTypes[6].OneofWrappers = []interface{}{
+ (*Span_TimeEvent_Annotation_)(nil),
+ (*Span_TimeEvent_MessageEvent_)(nil),
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_google_devtools_cloudtrace_v2_trace_proto_rawDesc,
+ NumEnums: 3,
+ NumMessages: 15,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_google_devtools_cloudtrace_v2_trace_proto_goTypes,
+ DependencyIndexes: file_google_devtools_cloudtrace_v2_trace_proto_depIdxs,
+ EnumInfos: file_google_devtools_cloudtrace_v2_trace_proto_enumTypes,
+ MessageInfos: file_google_devtools_cloudtrace_v2_trace_proto_msgTypes,
+ }.Build()
+ File_google_devtools_cloudtrace_v2_trace_proto = out.File
+ file_google_devtools_cloudtrace_v2_trace_proto_rawDesc = nil
+ file_google_devtools_cloudtrace_v2_trace_proto_goTypes = nil
+ file_google_devtools_cloudtrace_v2_trace_proto_depIdxs = nil
+}
diff --git a/vendor/cloud.google.com/go/trace/apiv2/tracepb/tracing.pb.go b/vendor/cloud.google.com/go/trace/apiv2/tracepb/tracing.pb.go
new file mode 100644
index 00000000000..83517327a5c
--- /dev/null
+++ b/vendor/cloud.google.com/go/trace/apiv2/tracepb/tracing.pb.go
@@ -0,0 +1,367 @@
+// Copyright 2022 Google LLC
+//
+// 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 protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.30.0
+// protoc v4.23.2
+// source: google/devtools/cloudtrace/v2/tracing.proto
+
+package tracepb
+
+import (
+ context "context"
+ reflect "reflect"
+ sync "sync"
+
+ _ "google.golang.org/genproto/googleapis/api/annotations"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ emptypb "google.golang.org/protobuf/types/known/emptypb"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// The request message for the `BatchWriteSpans` method.
+type BatchWriteSpansRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the project where the spans belong. The format is
+ // `projects/[PROJECT_ID]`.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Required. A list of new spans. The span names must not match existing
+ // spans, otherwise the results are undefined.
+ Spans []*Span `protobuf:"bytes,2,rep,name=spans,proto3" json:"spans,omitempty"`
+}
+
+func (x *BatchWriteSpansRequest) Reset() {
+ *x = BatchWriteSpansRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_devtools_cloudtrace_v2_tracing_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BatchWriteSpansRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BatchWriteSpansRequest) ProtoMessage() {}
+
+func (x *BatchWriteSpansRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_devtools_cloudtrace_v2_tracing_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BatchWriteSpansRequest.ProtoReflect.Descriptor instead.
+func (*BatchWriteSpansRequest) Descriptor() ([]byte, []int) {
+ return file_google_devtools_cloudtrace_v2_tracing_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *BatchWriteSpansRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *BatchWriteSpansRequest) GetSpans() []*Span {
+ if x != nil {
+ return x.Spans
+ }
+ return nil
+}
+
+var File_google_devtools_cloudtrace_v2_tracing_proto protoreflect.FileDescriptor
+
+var file_google_devtools_cloudtrace_v2_tracing_proto_rawDesc = []byte{
+ 0x0a, 0x2b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c,
+ 0x73, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x76, 0x32, 0x2f,
+ 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1d, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63,
+ 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x1a, 0x1c, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f,
+ 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69,
+ 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
+ 0x29, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73,
+ 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x76, 0x32, 0x2f, 0x74,
+ 0x72, 0x61, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74,
+ 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa1, 0x01, 0x0a, 0x16, 0x42, 0x61, 0x74, 0x63,
+ 0x68, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x47, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x42, 0x33, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x2d, 0x0a, 0x2b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x72,
+ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x72,
+ 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x05, 0x73,
+ 0x70, 0x61, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f,
+ 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x42,
+ 0x03, 0xe0, 0x41, 0x02, 0x52, 0x05, 0x73, 0x70, 0x61, 0x6e, 0x73, 0x32, 0xba, 0x03, 0x0a, 0x0c,
+ 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xa1, 0x01, 0x0a,
+ 0x0f, 0x42, 0x61, 0x74, 0x63, 0x68, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73,
+ 0x12, 0x35, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f,
+ 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32,
+ 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
+ 0x3f, 0xda, 0x41, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x73, 0x70, 0x61, 0x6e, 0x73, 0x82, 0xd3,
+ 0xe4, 0x93, 0x02, 0x2c, 0x3a, 0x01, 0x2a, 0x22, 0x27, 0x2f, 0x76, 0x32, 0x2f, 0x7b, 0x6e, 0x61,
+ 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x74,
+ 0x72, 0x61, 0x63, 0x65, 0x73, 0x3a, 0x62, 0x61, 0x74, 0x63, 0x68, 0x57, 0x72, 0x69, 0x74, 0x65,
+ 0x12, 0x89, 0x01, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x12,
+ 0x23, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c,
+ 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x2e,
+ 0x53, 0x70, 0x61, 0x6e, 0x1a, 0x23, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65,
+ 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63,
+ 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02,
+ 0x2b, 0x3a, 0x01, 0x2a, 0x22, 0x26, 0x2f, 0x76, 0x32, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d,
+ 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65,
+ 0x73, 0x2f, 0x2a, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x73, 0x2f, 0x2a, 0x7d, 0x1a, 0x7a, 0xca, 0x41,
+ 0x19, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0xd2, 0x41, 0x5b, 0x68, 0x74, 0x74,
+ 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61,
+ 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x63, 0x6c, 0x6f,
+ 0x75, 0x64, 0x2d, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2c, 0x68, 0x74, 0x74, 0x70,
+ 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
+ 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x74, 0x72, 0x61, 0x63,
+ 0x65, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x42, 0xaf, 0x01, 0x0a, 0x21, 0x63, 0x6f, 0x6d,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x74, 0x6f, 0x6f, 0x6c, 0x73,
+ 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x32, 0x42, 0x0c,
+ 0x54, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2f,
+ 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f,
+ 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x62, 0x3b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x62, 0xaa,
+ 0x02, 0x15, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x54,
+ 0x72, 0x61, 0x63, 0x65, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x15, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x54, 0x72, 0x61, 0x63, 0x65, 0x5c, 0x56, 0x32, 0xea,
+ 0x02, 0x18, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a,
+ 0x3a, 0x54, 0x72, 0x61, 0x63, 0x65, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x33,
+}
+
+var (
+ file_google_devtools_cloudtrace_v2_tracing_proto_rawDescOnce sync.Once
+ file_google_devtools_cloudtrace_v2_tracing_proto_rawDescData = file_google_devtools_cloudtrace_v2_tracing_proto_rawDesc
+)
+
+func file_google_devtools_cloudtrace_v2_tracing_proto_rawDescGZIP() []byte {
+ file_google_devtools_cloudtrace_v2_tracing_proto_rawDescOnce.Do(func() {
+ file_google_devtools_cloudtrace_v2_tracing_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_devtools_cloudtrace_v2_tracing_proto_rawDescData)
+ })
+ return file_google_devtools_cloudtrace_v2_tracing_proto_rawDescData
+}
+
+var file_google_devtools_cloudtrace_v2_tracing_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_google_devtools_cloudtrace_v2_tracing_proto_goTypes = []interface{}{
+ (*BatchWriteSpansRequest)(nil), // 0: google.devtools.cloudtrace.v2.BatchWriteSpansRequest
+ (*Span)(nil), // 1: google.devtools.cloudtrace.v2.Span
+ (*emptypb.Empty)(nil), // 2: google.protobuf.Empty
+}
+var file_google_devtools_cloudtrace_v2_tracing_proto_depIdxs = []int32{
+ 1, // 0: google.devtools.cloudtrace.v2.BatchWriteSpansRequest.spans:type_name -> google.devtools.cloudtrace.v2.Span
+ 0, // 1: google.devtools.cloudtrace.v2.TraceService.BatchWriteSpans:input_type -> google.devtools.cloudtrace.v2.BatchWriteSpansRequest
+ 1, // 2: google.devtools.cloudtrace.v2.TraceService.CreateSpan:input_type -> google.devtools.cloudtrace.v2.Span
+ 2, // 3: google.devtools.cloudtrace.v2.TraceService.BatchWriteSpans:output_type -> google.protobuf.Empty
+ 1, // 4: google.devtools.cloudtrace.v2.TraceService.CreateSpan:output_type -> google.devtools.cloudtrace.v2.Span
+ 3, // [3:5] is the sub-list for method output_type
+ 1, // [1:3] is the sub-list for method input_type
+ 1, // [1:1] is the sub-list for extension type_name
+ 1, // [1:1] is the sub-list for extension extendee
+ 0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_google_devtools_cloudtrace_v2_tracing_proto_init() }
+func file_google_devtools_cloudtrace_v2_tracing_proto_init() {
+ if File_google_devtools_cloudtrace_v2_tracing_proto != nil {
+ return
+ }
+ file_google_devtools_cloudtrace_v2_trace_proto_init()
+ if !protoimpl.UnsafeEnabled {
+ file_google_devtools_cloudtrace_v2_tracing_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*BatchWriteSpansRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_google_devtools_cloudtrace_v2_tracing_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 1,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_google_devtools_cloudtrace_v2_tracing_proto_goTypes,
+ DependencyIndexes: file_google_devtools_cloudtrace_v2_tracing_proto_depIdxs,
+ MessageInfos: file_google_devtools_cloudtrace_v2_tracing_proto_msgTypes,
+ }.Build()
+ File_google_devtools_cloudtrace_v2_tracing_proto = out.File
+ file_google_devtools_cloudtrace_v2_tracing_proto_rawDesc = nil
+ file_google_devtools_cloudtrace_v2_tracing_proto_goTypes = nil
+ file_google_devtools_cloudtrace_v2_tracing_proto_depIdxs = nil
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConnInterface
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion6
+
+// TraceServiceClient is the client API for TraceService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type TraceServiceClient interface {
+ // Batch writes new spans to new or existing traces. You cannot update
+ // existing spans.
+ BatchWriteSpans(ctx context.Context, in *BatchWriteSpansRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Creates a new span.
+ CreateSpan(ctx context.Context, in *Span, opts ...grpc.CallOption) (*Span, error)
+}
+
+type traceServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewTraceServiceClient(cc grpc.ClientConnInterface) TraceServiceClient {
+ return &traceServiceClient{cc}
+}
+
+func (c *traceServiceClient) BatchWriteSpans(ctx context.Context, in *BatchWriteSpansRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/google.devtools.cloudtrace.v2.TraceService/BatchWriteSpans", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *traceServiceClient) CreateSpan(ctx context.Context, in *Span, opts ...grpc.CallOption) (*Span, error) {
+ out := new(Span)
+ err := c.cc.Invoke(ctx, "/google.devtools.cloudtrace.v2.TraceService/CreateSpan", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// TraceServiceServer is the server API for TraceService service.
+type TraceServiceServer interface {
+ // Batch writes new spans to new or existing traces. You cannot update
+ // existing spans.
+ BatchWriteSpans(context.Context, *BatchWriteSpansRequest) (*emptypb.Empty, error)
+ // Creates a new span.
+ CreateSpan(context.Context, *Span) (*Span, error)
+}
+
+// UnimplementedTraceServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedTraceServiceServer struct {
+}
+
+func (*UnimplementedTraceServiceServer) BatchWriteSpans(context.Context, *BatchWriteSpansRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method BatchWriteSpans not implemented")
+}
+func (*UnimplementedTraceServiceServer) CreateSpan(context.Context, *Span) (*Span, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method CreateSpan not implemented")
+}
+
+func RegisterTraceServiceServer(s *grpc.Server, srv TraceServiceServer) {
+ s.RegisterService(&_TraceService_serviceDesc, srv)
+}
+
+func _TraceService_BatchWriteSpans_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(BatchWriteSpansRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(TraceServiceServer).BatchWriteSpans(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/google.devtools.cloudtrace.v2.TraceService/BatchWriteSpans",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(TraceServiceServer).BatchWriteSpans(ctx, req.(*BatchWriteSpansRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _TraceService_CreateSpan_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(Span)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(TraceServiceServer).CreateSpan(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/google.devtools.cloudtrace.v2.TraceService/CreateSpan",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(TraceServiceServer).CreateSpan(ctx, req.(*Span))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+var _TraceService_serviceDesc = grpc.ServiceDesc{
+ ServiceName: "google.devtools.cloudtrace.v2.TraceService",
+ HandlerType: (*TraceServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "BatchWriteSpans",
+ Handler: _TraceService_BatchWriteSpans_Handler,
+ },
+ {
+ MethodName: "CreateSpan",
+ Handler: _TraceService_CreateSpan_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "google/devtools/cloudtrace/v2/tracing.proto",
+}
diff --git a/vendor/cloud.google.com/go/trace/apiv2/version.go b/vendor/cloud.google.com/go/trace/apiv2/version.go
index b52392b7872..ac7a1bda595 100644
--- a/vendor/cloud.google.com/go/trace/apiv2/version.go
+++ b/vendor/cloud.google.com/go/trace/apiv2/version.go
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/vendor/cloud.google.com/go/trace/internal/version.go b/vendor/cloud.google.com/go/trace/internal/version.go
index d0e4a6fd16b..c7287740734 100644
--- a/vendor/cloud.google.com/go/trace/internal/version.go
+++ b/vendor/cloud.google.com/go/trace/internal/version.go
@@ -15,4 +15,4 @@
package internal
// Version is the current tagged release of the library.
-const Version = "1.2.0"
+const Version = "1.10.1"
diff --git a/vendor/go.opentelemetry.io/contrib/LICENSE b/vendor/github.com/AdaLogics/go-fuzz-headers/LICENSE
similarity index 100%
rename from vendor/go.opentelemetry.io/contrib/LICENSE
rename to vendor/github.com/AdaLogics/go-fuzz-headers/LICENSE
diff --git a/vendor/github.com/AdaLogics/go-fuzz-headers/README.md b/vendor/github.com/AdaLogics/go-fuzz-headers/README.md
new file mode 100644
index 00000000000..0a0d60c746d
--- /dev/null
+++ b/vendor/github.com/AdaLogics/go-fuzz-headers/README.md
@@ -0,0 +1,93 @@
+# go-fuzz-headers
+This repository contains various helper functions for go fuzzing. It is mostly used in combination with [go-fuzz](https://github.com/dvyukov/go-fuzz), but compatibility with fuzzing in the standard library will also be supported. Any coverage guided fuzzing engine that provides an array or slice of bytes can be used with go-fuzz-headers.
+
+
+## Usage
+Using go-fuzz-headers is easy. First create a new consumer with the bytes provided by the fuzzing engine:
+
+```go
+import (
+ fuzz "github.com/AdaLogics/go-fuzz-headers"
+)
+data := []byte{'R', 'a', 'n', 'd', 'o', 'm'}
+f := fuzz.NewConsumer(data)
+
+```
+
+This creates a `Consumer` that consumes the bytes of the input as it uses them to fuzz different types.
+
+After that, `f` can be used to easily create fuzzed instances of different types. Below are some examples:
+
+### Structs
+One of the most useful features of go-fuzz-headers is its ability to fill structs with the data provided by the fuzzing engine. This is done with a single line:
+```go
+type Person struct {
+ Name string
+ Age int
+}
+p := Person{}
+// Fill p with values based on the data provided by the fuzzing engine:
+err := f.GenerateStruct(&p)
+```
+
+This includes nested structs too. In this example, the fuzz Consumer will also insert values in `p.BestFriend`:
+```go
+type PersonI struct {
+ Name string
+ Age int
+ BestFriend PersonII
+}
+type PersonII struct {
+ Name string
+ Age int
+}
+p := PersonI{}
+err := f.GenerateStruct(&p)
+```
+
+If the consumer should insert values for unexported fields as well as exported, this can be enabled with:
+
+```go
+f.AllowUnexportedFields()
+```
+
+...and disabled with:
+
+```go
+f.DisallowUnexportedFields()
+```
+
+### Other types:
+
+Other useful APIs:
+
+```go
+createdString, err := f.GetString() // Gets a string
+createdInt, err := f.GetInt() // Gets an integer
+createdByte, err := f.GetByte() // Gets a byte
+createdBytes, err := f.GetBytes() // Gets a byte slice
+createdBool, err := f.GetBool() // Gets a boolean
+err := f.FuzzMap(target_map) // Fills a map
+createdTarBytes, err := f.TarBytes() // Gets bytes of a valid tar archive
+err := f.CreateFiles(inThisDir) // Fills inThisDir with files
+createdString, err := f.GetStringFrom("anyCharInThisString", ofThisLength) // Gets a string that consists of chars from "anyCharInThisString" and has the exact length "ofThisLength"
+```
+
+Most APIs are added as they are needed.
+
+## Projects that use go-fuzz-headers
+- [runC](https://github.com/opencontainers/runc)
+- [Istio](https://github.com/istio/istio)
+- [Vitess](https://github.com/vitessio/vitess)
+- [Containerd](https://github.com/containerd/containerd)
+
+Feel free to add your own project to the list, if you use go-fuzz-headers to fuzz it.
+
+
+
+
+## Status
+The project is under development and will be updated regularly.
+
+## References
+go-fuzz-headers' approach to fuzzing structs is strongly inspired by [gofuzz](https://github.com/google/gofuzz).
\ No newline at end of file
diff --git a/vendor/github.com/AdaLogics/go-fuzz-headers/consumer.go b/vendor/github.com/AdaLogics/go-fuzz-headers/consumer.go
new file mode 100644
index 00000000000..adfeedf5e8a
--- /dev/null
+++ b/vendor/github.com/AdaLogics/go-fuzz-headers/consumer.go
@@ -0,0 +1,914 @@
+// Copyright 2023 The go-fuzz-headers Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package gofuzzheaders
+
+import (
+ "archive/tar"
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "os"
+ "path/filepath"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+ "unsafe"
+)
+
+var (
+ MaxTotalLen uint32 = 2000000
+ maxDepth = 100
+)
+
+func SetMaxTotalLen(newLen uint32) {
+ MaxTotalLen = newLen
+}
+
+type ConsumeFuzzer struct {
+ data []byte
+ dataTotal uint32
+ CommandPart []byte
+ RestOfArray []byte
+ NumberOfCalls int
+ position uint32
+ fuzzUnexportedFields bool
+ curDepth int
+ Funcs map[reflect.Type]reflect.Value
+}
+
+func IsDivisibleBy(n int, divisibleby int) bool {
+ return (n % divisibleby) == 0
+}
+
+func NewConsumer(fuzzData []byte) *ConsumeFuzzer {
+ return &ConsumeFuzzer{
+ data: fuzzData,
+ dataTotal: uint32(len(fuzzData)),
+ Funcs: make(map[reflect.Type]reflect.Value),
+ curDepth: 0,
+ }
+}
+
+func (f *ConsumeFuzzer) Split(minCalls, maxCalls int) error {
+ if f.dataTotal == 0 {
+ return errors.New("could not split")
+ }
+ numberOfCalls := int(f.data[0])
+ if numberOfCalls < minCalls || numberOfCalls > maxCalls {
+ return errors.New("bad number of calls")
+ }
+ if int(f.dataTotal) < numberOfCalls+numberOfCalls+1 {
+ return errors.New("length of data does not match required parameters")
+ }
+
+ // Define part 2 and 3 of the data array
+ commandPart := f.data[1 : numberOfCalls+1]
+ restOfArray := f.data[numberOfCalls+1:]
+
+ // Just a small check. It is necessary
+ if len(commandPart) != numberOfCalls {
+ return errors.New("length of commandPart does not match number of calls")
+ }
+
+ // Check if restOfArray is divisible by numberOfCalls
+ if !IsDivisibleBy(len(restOfArray), numberOfCalls) {
+ return errors.New("length of commandPart does not match number of calls")
+ }
+ f.CommandPart = commandPart
+ f.RestOfArray = restOfArray
+ f.NumberOfCalls = numberOfCalls
+ return nil
+}
+
+func (f *ConsumeFuzzer) AllowUnexportedFields() {
+ f.fuzzUnexportedFields = true
+}
+
+func (f *ConsumeFuzzer) DisallowUnexportedFields() {
+ f.fuzzUnexportedFields = false
+}
+
+func (f *ConsumeFuzzer) GenerateStruct(targetStruct interface{}) error {
+ e := reflect.ValueOf(targetStruct).Elem()
+ return f.fuzzStruct(e, false)
+}
+
+func (f *ConsumeFuzzer) setCustom(v reflect.Value) error {
+ // First: see if we have a fuzz function for it.
+ doCustom, ok := f.Funcs[v.Type()]
+ if !ok {
+ return fmt.Errorf("could not find a custom function")
+ }
+
+ switch v.Kind() {
+ case reflect.Ptr:
+ if v.IsNil() {
+ if !v.CanSet() {
+ return fmt.Errorf("could not use a custom function")
+ }
+ v.Set(reflect.New(v.Type().Elem()))
+ }
+ case reflect.Map:
+ if v.IsNil() {
+ if !v.CanSet() {
+ return fmt.Errorf("could not use a custom function")
+ }
+ v.Set(reflect.MakeMap(v.Type()))
+ }
+ default:
+ return fmt.Errorf("could not use a custom function")
+ }
+
+ verr := doCustom.Call([]reflect.Value{v, reflect.ValueOf(Continue{
+ F: f,
+ })})
+
+ // check if we return an error
+ if verr[0].IsNil() {
+ return nil
+ }
+ return fmt.Errorf("could not use a custom function")
+}
+
+func (f *ConsumeFuzzer) fuzzStruct(e reflect.Value, customFunctions bool) error {
+ if f.curDepth >= maxDepth {
+ // return err or nil here?
+ return nil
+ }
+ f.curDepth++
+ defer func() { f.curDepth-- }()
+
+ // We check if we should check for custom functions
+ if customFunctions && e.IsValid() && e.CanAddr() {
+ err := f.setCustom(e.Addr())
+ if err != nil {
+ return err
+ }
+ }
+
+ switch e.Kind() {
+ case reflect.Struct:
+ for i := 0; i < e.NumField(); i++ {
+ var v reflect.Value
+ if !e.Field(i).CanSet() {
+ if f.fuzzUnexportedFields {
+ v = reflect.NewAt(e.Field(i).Type(), unsafe.Pointer(e.Field(i).UnsafeAddr())).Elem()
+ }
+ if err := f.fuzzStruct(v, customFunctions); err != nil {
+ return err
+ }
+ } else {
+ v = e.Field(i)
+ if err := f.fuzzStruct(v, customFunctions); err != nil {
+ return err
+ }
+ }
+ }
+ case reflect.String:
+ str, err := f.GetString()
+ if err != nil {
+ return err
+ }
+ if e.CanSet() {
+ e.SetString(str)
+ }
+ case reflect.Slice:
+ var maxElements uint32
+ // Byte slices should not be restricted
+ if e.Type().String() == "[]uint8" {
+ maxElements = 10000000
+ } else {
+ maxElements = 50
+ }
+
+ randQty, err := f.GetUint32()
+ if err != nil {
+ return err
+ }
+ numOfElements := randQty % maxElements
+ if (f.dataTotal - f.position) < numOfElements {
+ numOfElements = f.dataTotal - f.position
+ }
+
+ uu := reflect.MakeSlice(e.Type(), int(numOfElements), int(numOfElements))
+
+ for i := 0; i < int(numOfElements); i++ {
+ // If we have more than 10, then we can proceed with that.
+ if err := f.fuzzStruct(uu.Index(i), customFunctions); err != nil {
+ if i >= 10 {
+ if e.CanSet() {
+ e.Set(uu)
+ }
+ return nil
+ } else {
+ return err
+ }
+ }
+ }
+ if e.CanSet() {
+ e.Set(uu)
+ }
+ case reflect.Uint16:
+ newInt, err := f.GetUint16()
+ if err != nil {
+ return err
+ }
+ if e.CanSet() {
+ e.SetUint(uint64(newInt))
+ }
+ case reflect.Uint32:
+ newInt, err := f.GetUint32()
+ if err != nil {
+ return err
+ }
+ if e.CanSet() {
+ e.SetUint(uint64(newInt))
+ }
+ case reflect.Uint64:
+ newInt, err := f.GetInt()
+ if err != nil {
+ return err
+ }
+ if e.CanSet() {
+ e.SetUint(uint64(newInt))
+ }
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ newInt, err := f.GetInt()
+ if err != nil {
+ return err
+ }
+ if e.CanSet() {
+ e.SetInt(int64(newInt))
+ }
+ case reflect.Float32:
+ newFloat, err := f.GetFloat32()
+ if err != nil {
+ return err
+ }
+ if e.CanSet() {
+ e.SetFloat(float64(newFloat))
+ }
+ case reflect.Float64:
+ newFloat, err := f.GetFloat64()
+ if err != nil {
+ return err
+ }
+ if e.CanSet() {
+ e.SetFloat(float64(newFloat))
+ }
+ case reflect.Map:
+ if e.CanSet() {
+ e.Set(reflect.MakeMap(e.Type()))
+ const maxElements = 50
+ randQty, err := f.GetInt()
+ if err != nil {
+ return err
+ }
+ numOfElements := randQty % maxElements
+ for i := 0; i < numOfElements; i++ {
+ key := reflect.New(e.Type().Key()).Elem()
+ if err := f.fuzzStruct(key, customFunctions); err != nil {
+ return err
+ }
+ val := reflect.New(e.Type().Elem()).Elem()
+ if err = f.fuzzStruct(val, customFunctions); err != nil {
+ return err
+ }
+ e.SetMapIndex(key, val)
+ }
+ }
+ case reflect.Ptr:
+ if e.CanSet() {
+ e.Set(reflect.New(e.Type().Elem()))
+ if err := f.fuzzStruct(e.Elem(), customFunctions); err != nil {
+ return err
+ }
+ return nil
+ }
+ case reflect.Uint8:
+ b, err := f.GetByte()
+ if err != nil {
+ return err
+ }
+ if e.CanSet() {
+ e.SetUint(uint64(b))
+ }
+ }
+ return nil
+}
+
+func (f *ConsumeFuzzer) GetStringArray() (reflect.Value, error) {
+ // The max size of the array:
+ const max uint32 = 20
+
+ arraySize := f.position
+ if arraySize > max {
+ arraySize = max
+ }
+ stringArray := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf("string")), int(arraySize), int(arraySize))
+ if f.position+arraySize >= f.dataTotal {
+ return stringArray, errors.New("could not make string array")
+ }
+
+ for i := 0; i < int(arraySize); i++ {
+ stringSize := uint32(f.data[f.position])
+ if f.position+stringSize >= f.dataTotal {
+ return stringArray, nil
+ }
+ stringToAppend := string(f.data[f.position : f.position+stringSize])
+ strVal := reflect.ValueOf(stringToAppend)
+ stringArray = reflect.Append(stringArray, strVal)
+ f.position += stringSize
+ }
+ return stringArray, nil
+}
+
+func (f *ConsumeFuzzer) GetInt() (int, error) {
+ if f.position >= f.dataTotal {
+ return 0, errors.New("not enough bytes to create int")
+ }
+ returnInt := int(f.data[f.position])
+ f.position++
+ return returnInt, nil
+}
+
+func (f *ConsumeFuzzer) GetByte() (byte, error) {
+ if f.position >= f.dataTotal {
+ return 0x00, errors.New("not enough bytes to get byte")
+ }
+ returnByte := f.data[f.position]
+ f.position++
+ return returnByte, nil
+}
+
+func (f *ConsumeFuzzer) GetNBytes(numberOfBytes int) ([]byte, error) {
+ if f.position >= f.dataTotal {
+ return nil, errors.New("not enough bytes to get byte")
+ }
+ returnBytes := make([]byte, 0, numberOfBytes)
+ for i := 0; i < numberOfBytes; i++ {
+ newByte, err := f.GetByte()
+ if err != nil {
+ return nil, err
+ }
+ returnBytes = append(returnBytes, newByte)
+ }
+ return returnBytes, nil
+}
+
+func (f *ConsumeFuzzer) GetUint16() (uint16, error) {
+ u16, err := f.GetNBytes(2)
+ if err != nil {
+ return 0, err
+ }
+ littleEndian, err := f.GetBool()
+ if err != nil {
+ return 0, err
+ }
+ if littleEndian {
+ return binary.LittleEndian.Uint16(u16), nil
+ }
+ return binary.BigEndian.Uint16(u16), nil
+}
+
+func (f *ConsumeFuzzer) GetUint32() (uint32, error) {
+ u32, err := f.GetNBytes(4)
+ if err != nil {
+ return 0, err
+ }
+ return binary.BigEndian.Uint32(u32), nil
+}
+
+func (f *ConsumeFuzzer) GetUint64() (uint64, error) {
+ u64, err := f.GetNBytes(8)
+ if err != nil {
+ return 0, err
+ }
+ littleEndian, err := f.GetBool()
+ if err != nil {
+ return 0, err
+ }
+ if littleEndian {
+ return binary.LittleEndian.Uint64(u64), nil
+ }
+ return binary.BigEndian.Uint64(u64), nil
+}
+
+func (f *ConsumeFuzzer) GetBytes() ([]byte, error) {
+ var length uint32
+ var err error
+ length, err = f.GetUint32()
+ if err != nil {
+ return nil, errors.New("not enough bytes to create byte array")
+ }
+
+ if length == 0 {
+ length = 30
+ }
+ bytesLeft := f.dataTotal - f.position
+ if bytesLeft <= 0 {
+ return nil, errors.New("not enough bytes to create byte array")
+ }
+
+ // If the length is the same as bytes left, we will not overflow
+ // the remaining bytes.
+ if length != bytesLeft {
+ length = length % bytesLeft
+ }
+ byteBegin := f.position
+ if byteBegin+length < byteBegin {
+ return nil, errors.New("numbers overflow")
+ }
+ f.position = byteBegin + length
+ return f.data[byteBegin:f.position], nil
+}
+
+func (f *ConsumeFuzzer) GetString() (string, error) {
+ if f.position >= f.dataTotal {
+ return "nil", errors.New("not enough bytes to create string")
+ }
+ length, err := f.GetUint32()
+ if err != nil {
+ return "nil", errors.New("not enough bytes to create string")
+ }
+ if f.position > MaxTotalLen {
+ return "nil", errors.New("created too large a string")
+ }
+ byteBegin := f.position
+ if byteBegin >= f.dataTotal {
+ return "nil", errors.New("not enough bytes to create string")
+ }
+ if byteBegin+length > f.dataTotal {
+ return "nil", errors.New("not enough bytes to create string")
+ }
+ if byteBegin > byteBegin+length {
+ return "nil", errors.New("numbers overflow")
+ }
+ f.position = byteBegin + length
+ return string(f.data[byteBegin:f.position]), nil
+}
+
+func (f *ConsumeFuzzer) GetBool() (bool, error) {
+ if f.position >= f.dataTotal {
+ return false, errors.New("not enough bytes to create bool")
+ }
+ if IsDivisibleBy(int(f.data[f.position]), 2) {
+ f.position++
+ return true, nil
+ } else {
+ f.position++
+ return false, nil
+ }
+}
+
+func (f *ConsumeFuzzer) FuzzMap(m interface{}) error {
+ return f.GenerateStruct(m)
+}
+
+func returnTarBytes(buf []byte) ([]byte, error) {
+ return buf, nil
+ // Count files
+ var fileCounter int
+ tr := tar.NewReader(bytes.NewReader(buf))
+ for {
+ _, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return nil, err
+ }
+ fileCounter++
+ }
+ if fileCounter >= 1 {
+ return buf, nil
+ }
+ return nil, fmt.Errorf("not enough files were created\n")
+}
+
+func setTarHeaderFormat(hdr *tar.Header, f *ConsumeFuzzer) error {
+ ind, err := f.GetInt()
+ if err != nil {
+ hdr.Format = tar.FormatGNU
+ //return nil
+ }
+ switch ind % 4 {
+ case 0:
+ hdr.Format = tar.FormatUnknown
+ case 1:
+ hdr.Format = tar.FormatUSTAR
+ case 2:
+ hdr.Format = tar.FormatPAX
+ case 3:
+ hdr.Format = tar.FormatGNU
+ }
+ return nil
+}
+
+func setTarHeaderTypeflag(hdr *tar.Header, f *ConsumeFuzzer) error {
+ ind, err := f.GetInt()
+ if err != nil {
+ return err
+ }
+ switch ind % 13 {
+ case 0:
+ hdr.Typeflag = tar.TypeReg
+ case 1:
+ hdr.Typeflag = tar.TypeLink
+ linkname, err := f.GetString()
+ if err != nil {
+ return err
+ }
+ hdr.Linkname = linkname
+ case 2:
+ hdr.Typeflag = tar.TypeSymlink
+ linkname, err := f.GetString()
+ if err != nil {
+ return err
+ }
+ hdr.Linkname = linkname
+ case 3:
+ hdr.Typeflag = tar.TypeChar
+ case 4:
+ hdr.Typeflag = tar.TypeBlock
+ case 5:
+ hdr.Typeflag = tar.TypeDir
+ case 6:
+ hdr.Typeflag = tar.TypeFifo
+ case 7:
+ hdr.Typeflag = tar.TypeCont
+ case 8:
+ hdr.Typeflag = tar.TypeXHeader
+ case 9:
+ hdr.Typeflag = tar.TypeXGlobalHeader
+ case 10:
+ hdr.Typeflag = tar.TypeGNUSparse
+ case 11:
+ hdr.Typeflag = tar.TypeGNULongName
+ case 12:
+ hdr.Typeflag = tar.TypeGNULongLink
+ }
+ return nil
+}
+
+func (f *ConsumeFuzzer) createTarFileBody() ([]byte, error) {
+ return f.GetBytes()
+ /*length, err := f.GetUint32()
+ if err != nil {
+ return nil, errors.New("not enough bytes to create byte array")
+ }
+
+ // A bit of optimization to attempt to create a file body
+ // when we don't have as many bytes left as "length"
+ remainingBytes := f.dataTotal - f.position
+ if remainingBytes <= 0 {
+ return nil, errors.New("created too large a string")
+ }
+ if f.position+length > MaxTotalLen {
+ return nil, errors.New("created too large a string")
+ }
+ byteBegin := f.position
+ if byteBegin >= f.dataTotal {
+ return nil, errors.New("not enough bytes to create byte array")
+ }
+ if length == 0 {
+ return nil, errors.New("zero-length is not supported")
+ }
+ if byteBegin+length >= f.dataTotal {
+ return nil, errors.New("not enough bytes to create byte array")
+ }
+ if byteBegin+length < byteBegin {
+ return nil, errors.New("numbers overflow")
+ }
+ f.position = byteBegin + length
+ return f.data[byteBegin:f.position], nil*/
+}
+
+// getTarFileName is similar to GetString(), but creates string based
+// on the length of f.data to reduce the likelihood of overflowing
+// f.data.
+func (f *ConsumeFuzzer) getTarFilename() (string, error) {
+ return f.GetString()
+ /*length, err := f.GetUint32()
+ if err != nil {
+ return "nil", errors.New("not enough bytes to create string")
+ }
+
+ // A bit of optimization to attempt to create a file name
+ // when we don't have as many bytes left as "length"
+ remainingBytes := f.dataTotal - f.position
+ if remainingBytes <= 0 {
+ return "nil", errors.New("created too large a string")
+ }
+ if f.position > MaxTotalLen {
+ return "nil", errors.New("created too large a string")
+ }
+ byteBegin := f.position
+ if byteBegin >= f.dataTotal {
+ return "nil", errors.New("not enough bytes to create string")
+ }
+ if byteBegin+length > f.dataTotal {
+ return "nil", errors.New("not enough bytes to create string")
+ }
+ if byteBegin > byteBegin+length {
+ return "nil", errors.New("numbers overflow")
+ }
+ f.position = byteBegin + length
+ return string(f.data[byteBegin:f.position]), nil*/
+}
+
+type TarFile struct {
+ Hdr *tar.Header
+ Body []byte
+}
+
+// TarBytes returns valid bytes for a tar archive
+func (f *ConsumeFuzzer) TarBytes() ([]byte, error) {
+ numberOfFiles, err := f.GetInt()
+ if err != nil {
+ return nil, err
+ }
+ var tarFiles []*TarFile
+ tarFiles = make([]*TarFile, 0)
+
+ const maxNoOfFiles = 100
+ for i := 0; i < numberOfFiles%maxNoOfFiles; i++ {
+ var filename string
+ var filebody []byte
+ var sec, nsec int
+ var err error
+
+ filename, err = f.getTarFilename()
+ if err != nil {
+ var sb strings.Builder
+ sb.WriteString("file-")
+ sb.WriteString(strconv.Itoa(i))
+ filename = sb.String()
+ }
+ filebody, err = f.createTarFileBody()
+ if err != nil {
+ var sb strings.Builder
+ sb.WriteString("filebody-")
+ sb.WriteString(strconv.Itoa(i))
+ filebody = []byte(sb.String())
+ }
+
+ sec, err = f.GetInt()
+ if err != nil {
+ sec = 1672531200 // beginning of 2023
+ }
+ nsec, err = f.GetInt()
+ if err != nil {
+ nsec = 1703980800 // end of 2023
+ }
+
+ hdr := &tar.Header{
+ Name: filename,
+ Size: int64(len(filebody)),
+ Mode: 0o600,
+ ModTime: time.Unix(int64(sec), int64(nsec)),
+ }
+ if err := setTarHeaderTypeflag(hdr, f); err != nil {
+ return []byte(""), err
+ }
+ if err := setTarHeaderFormat(hdr, f); err != nil {
+ return []byte(""), err
+ }
+ tf := &TarFile{
+ Hdr: hdr,
+ Body: filebody,
+ }
+ tarFiles = append(tarFiles, tf)
+ }
+
+ var buf bytes.Buffer
+ tw := tar.NewWriter(&buf)
+ defer tw.Close()
+
+ for _, tf := range tarFiles {
+ tw.WriteHeader(tf.Hdr)
+ tw.Write(tf.Body)
+ }
+ return buf.Bytes(), nil
+}
+
+// This is similar to TarBytes, but it returns a series of
+// files instead of raw tar bytes. The advantage of this
+// api is that it is cheaper in terms of cpu power to
+// modify or check the files in the fuzzer with TarFiles()
+// because it avoids creating a tar reader.
+func (f *ConsumeFuzzer) TarFiles() ([]*TarFile, error) {
+ numberOfFiles, err := f.GetInt()
+ if err != nil {
+ return nil, err
+ }
+ var tarFiles []*TarFile
+ tarFiles = make([]*TarFile, 0)
+
+ const maxNoOfFiles = 100
+ for i := 0; i < numberOfFiles%maxNoOfFiles; i++ {
+ filename, err := f.getTarFilename()
+ if err != nil {
+ return tarFiles, err
+ }
+ filebody, err := f.createTarFileBody()
+ if err != nil {
+ return tarFiles, err
+ }
+
+ sec, err := f.GetInt()
+ if err != nil {
+ return tarFiles, err
+ }
+ nsec, err := f.GetInt()
+ if err != nil {
+ return tarFiles, err
+ }
+
+ hdr := &tar.Header{
+ Name: filename,
+ Size: int64(len(filebody)),
+ Mode: 0o600,
+ ModTime: time.Unix(int64(sec), int64(nsec)),
+ }
+ if err := setTarHeaderTypeflag(hdr, f); err != nil {
+ hdr.Typeflag = tar.TypeReg
+ }
+ if err := setTarHeaderFormat(hdr, f); err != nil {
+ return tarFiles, err // should not happend
+ }
+ tf := &TarFile{
+ Hdr: hdr,
+ Body: filebody,
+ }
+ tarFiles = append(tarFiles, tf)
+ }
+ return tarFiles, nil
+}
+
+// CreateFiles creates pseudo-random files in rootDir.
+// It creates subdirs and places the files there.
+// It is the callers responsibility to ensure that
+// rootDir exists.
+func (f *ConsumeFuzzer) CreateFiles(rootDir string) error {
+ numberOfFiles, err := f.GetInt()
+ if err != nil {
+ return err
+ }
+ maxNumberOfFiles := numberOfFiles % 4000 // This is completely arbitrary
+ if maxNumberOfFiles == 0 {
+ return errors.New("maxNumberOfFiles is nil")
+ }
+
+ var noOfCreatedFiles int
+ for i := 0; i < maxNumberOfFiles; i++ {
+ // The file to create:
+ fileName, err := f.GetString()
+ if err != nil {
+ if noOfCreatedFiles > 0 {
+ // If files have been created, we don't return an error.
+ break
+ } else {
+ return errors.New("could not get fileName")
+ }
+ }
+ if strings.Contains(fileName, "..") || (len(fileName) > 0 && fileName[0] == 47) || strings.Contains(fileName, "\\") {
+ continue
+ }
+ fullFilePath := filepath.Join(rootDir, fileName)
+
+ // Find the subdirectory of the file
+ if subDir := filepath.Dir(fileName); subDir != "" && subDir != "." {
+ // create the dir first; avoid going outside the root dir
+ if strings.Contains(subDir, "../") || (len(subDir) > 0 && subDir[0] == 47) || strings.Contains(subDir, "\\") {
+ continue
+ }
+ dirPath := filepath.Join(rootDir, subDir)
+ if _, err := os.Stat(dirPath); os.IsNotExist(err) {
+ err2 := os.MkdirAll(dirPath, 0o777)
+ if err2 != nil {
+ continue
+ }
+ }
+ fullFilePath = filepath.Join(dirPath, fileName)
+ } else {
+ // Create symlink
+ createSymlink, err := f.GetBool()
+ if err != nil {
+ if noOfCreatedFiles > 0 {
+ break
+ } else {
+ return errors.New("could not create the symlink")
+ }
+ }
+ if createSymlink {
+ symlinkTarget, err := f.GetString()
+ if err != nil {
+ return err
+ }
+ err = os.Symlink(symlinkTarget, fullFilePath)
+ if err != nil {
+ return err
+ }
+ // stop loop here, since a symlink needs no further action
+ noOfCreatedFiles++
+ continue
+ }
+ // We create a normal file
+ fileContents, err := f.GetBytes()
+ if err != nil {
+ if noOfCreatedFiles > 0 {
+ break
+ } else {
+ return errors.New("could not create the file")
+ }
+ }
+ err = os.WriteFile(fullFilePath, fileContents, 0o666)
+ if err != nil {
+ continue
+ }
+ noOfCreatedFiles++
+ }
+ }
+ return nil
+}
+
+// GetStringFrom returns a string that can only consist of characters
+// included in possibleChars. It returns an error if the created string
+// does not have the specified length.
+func (f *ConsumeFuzzer) GetStringFrom(possibleChars string, length int) (string, error) {
+ if (f.dataTotal - f.position) < uint32(length) {
+ return "", errors.New("not enough bytes to create a string")
+ }
+ output := make([]byte, 0, length)
+ for i := 0; i < length; i++ {
+ charIndex, err := f.GetInt()
+ if err != nil {
+ return string(output), err
+ }
+ output = append(output, possibleChars[charIndex%len(possibleChars)])
+ }
+ return string(output), nil
+}
+
+func (f *ConsumeFuzzer) GetRune() ([]rune, error) {
+ stringToConvert, err := f.GetString()
+ if err != nil {
+ return []rune("nil"), err
+ }
+ return []rune(stringToConvert), nil
+}
+
+func (f *ConsumeFuzzer) GetFloat32() (float32, error) {
+ u32, err := f.GetNBytes(4)
+ if err != nil {
+ return 0, err
+ }
+ littleEndian, err := f.GetBool()
+ if err != nil {
+ return 0, err
+ }
+ if littleEndian {
+ u32LE := binary.LittleEndian.Uint32(u32)
+ return math.Float32frombits(u32LE), nil
+ }
+ u32BE := binary.BigEndian.Uint32(u32)
+ return math.Float32frombits(u32BE), nil
+}
+
+func (f *ConsumeFuzzer) GetFloat64() (float64, error) {
+ u64, err := f.GetNBytes(8)
+ if err != nil {
+ return 0, err
+ }
+ littleEndian, err := f.GetBool()
+ if err != nil {
+ return 0, err
+ }
+ if littleEndian {
+ u64LE := binary.LittleEndian.Uint64(u64)
+ return math.Float64frombits(u64LE), nil
+ }
+ u64BE := binary.BigEndian.Uint64(u64)
+ return math.Float64frombits(u64BE), nil
+}
+
+func (f *ConsumeFuzzer) CreateSlice(targetSlice interface{}) error {
+ return f.GenerateStruct(targetSlice)
+}
diff --git a/vendor/github.com/AdaLogics/go-fuzz-headers/funcs.go b/vendor/github.com/AdaLogics/go-fuzz-headers/funcs.go
new file mode 100644
index 00000000000..8ca3a61b878
--- /dev/null
+++ b/vendor/github.com/AdaLogics/go-fuzz-headers/funcs.go
@@ -0,0 +1,62 @@
+// Copyright 2023 The go-fuzz-headers Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package gofuzzheaders
+
+import (
+ "fmt"
+ "reflect"
+)
+
+type Continue struct {
+ F *ConsumeFuzzer
+}
+
+func (f *ConsumeFuzzer) AddFuncs(fuzzFuncs []interface{}) {
+ for i := range fuzzFuncs {
+ v := reflect.ValueOf(fuzzFuncs[i])
+ if v.Kind() != reflect.Func {
+ panic("Need only funcs!")
+ }
+ t := v.Type()
+ if t.NumIn() != 2 || t.NumOut() != 1 {
+ fmt.Println(t.NumIn(), t.NumOut())
+
+ panic("Need 2 in and 1 out params. In must be the type. Out must be an error")
+ }
+ argT := t.In(0)
+ switch argT.Kind() {
+ case reflect.Ptr, reflect.Map:
+ default:
+ panic("fuzzFunc must take pointer or map type")
+ }
+ if t.In(1) != reflect.TypeOf(Continue{}) {
+ panic("fuzzFunc's second parameter must be type Continue")
+ }
+ f.Funcs[argT] = v
+ }
+}
+
+func (f *ConsumeFuzzer) GenerateWithCustom(targetStruct interface{}) error {
+ e := reflect.ValueOf(targetStruct).Elem()
+ return f.fuzzStruct(e, true)
+}
+
+func (c Continue) GenerateStruct(targetStruct interface{}) error {
+ return c.F.GenerateStruct(targetStruct)
+}
+
+func (c Continue) GenerateStructWithCustom(targetStruct interface{}) error {
+ return c.F.GenerateWithCustom(targetStruct)
+}
diff --git a/vendor/github.com/AdaLogics/go-fuzz-headers/sql.go b/vendor/github.com/AdaLogics/go-fuzz-headers/sql.go
new file mode 100644
index 00000000000..2afd49f8481
--- /dev/null
+++ b/vendor/github.com/AdaLogics/go-fuzz-headers/sql.go
@@ -0,0 +1,556 @@
+// Copyright 2023 The go-fuzz-headers Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package gofuzzheaders
+
+import (
+ "fmt"
+ "strings"
+)
+
+// returns a keyword by index
+func getKeyword(f *ConsumeFuzzer) (string, error) {
+ index, err := f.GetInt()
+ if err != nil {
+ return keywords[0], err
+ }
+ for i, k := range keywords {
+ if i == index {
+ return k, nil
+ }
+ }
+ return keywords[0], fmt.Errorf("could not get a kw")
+}
+
+// Simple utility function to check if a string
+// slice contains a string.
+func containsString(s []string, e string) bool {
+ for _, a := range s {
+ if a == e {
+ return true
+ }
+ }
+ return false
+}
+
+// These keywords are used specifically for fuzzing Vitess
+var keywords = []string{
+ "accessible", "action", "add", "after", "against", "algorithm",
+ "all", "alter", "always", "analyze", "and", "as", "asc", "asensitive",
+ "auto_increment", "avg_row_length", "before", "begin", "between",
+ "bigint", "binary", "_binary", "_utf8mb4", "_utf8", "_latin1", "bit",
+ "blob", "bool", "boolean", "both", "by", "call", "cancel", "cascade",
+ "cascaded", "case", "cast", "channel", "change", "char", "character",
+ "charset", "check", "checksum", "coalesce", "code", "collate", "collation",
+ "column", "columns", "comment", "committed", "commit", "compact", "complete",
+ "compressed", "compression", "condition", "connection", "constraint", "continue",
+ "convert", "copy", "cume_dist", "substr", "substring", "create", "cross",
+ "csv", "current_date", "current_time", "current_timestamp", "current_user",
+ "cursor", "data", "database", "databases", "day", "day_hour", "day_microsecond",
+ "day_minute", "day_second", "date", "datetime", "dec", "decimal", "declare",
+ "default", "definer", "delay_key_write", "delayed", "delete", "dense_rank",
+ "desc", "describe", "deterministic", "directory", "disable", "discard",
+ "disk", "distinct", "distinctrow", "div", "double", "do", "drop", "dumpfile",
+ "duplicate", "dynamic", "each", "else", "elseif", "empty", "enable",
+ "enclosed", "encryption", "end", "enforced", "engine", "engines", "enum",
+ "error", "escape", "escaped", "event", "exchange", "exclusive", "exists",
+ "exit", "explain", "expansion", "export", "extended", "extract", "false",
+ "fetch", "fields", "first", "first_value", "fixed", "float", "float4",
+ "float8", "flush", "for", "force", "foreign", "format", "from", "full",
+ "fulltext", "function", "general", "generated", "geometry", "geometrycollection",
+ "get", "global", "gtid_executed", "grant", "group", "grouping", "groups",
+ "group_concat", "having", "header", "high_priority", "hosts", "hour", "hour_microsecond",
+ "hour_minute", "hour_second", "if", "ignore", "import", "in", "index", "indexes",
+ "infile", "inout", "inner", "inplace", "insensitive", "insert", "insert_method",
+ "int", "int1", "int2", "int3", "int4", "int8", "integer", "interval",
+ "into", "io_after_gtids", "is", "isolation", "iterate", "invoker", "join",
+ "json", "json_table", "key", "keys", "keyspaces", "key_block_size", "kill", "lag",
+ "language", "last", "last_value", "last_insert_id", "lateral", "lead", "leading",
+ "leave", "left", "less", "level", "like", "limit", "linear", "lines",
+ "linestring", "load", "local", "localtime", "localtimestamp", "lock", "logs",
+ "long", "longblob", "longtext", "loop", "low_priority", "manifest",
+ "master_bind", "match", "max_rows", "maxvalue", "mediumblob", "mediumint",
+ "mediumtext", "memory", "merge", "microsecond", "middleint", "min_rows", "minute",
+ "minute_microsecond", "minute_second", "mod", "mode", "modify", "modifies",
+ "multilinestring", "multipoint", "multipolygon", "month", "name",
+ "names", "natural", "nchar", "next", "no", "none", "not", "no_write_to_binlog",
+ "nth_value", "ntile", "null", "numeric", "of", "off", "offset", "on",
+ "only", "open", "optimize", "optimizer_costs", "option", "optionally",
+ "or", "order", "out", "outer", "outfile", "over", "overwrite", "pack_keys",
+ "parser", "partition", "partitioning", "password", "percent_rank", "plugins",
+ "point", "polygon", "precision", "primary", "privileges", "processlist",
+ "procedure", "query", "quarter", "range", "rank", "read", "reads", "read_write",
+ "real", "rebuild", "recursive", "redundant", "references", "regexp", "relay",
+ "release", "remove", "rename", "reorganize", "repair", "repeat", "repeatable",
+ "replace", "require", "resignal", "restrict", "return", "retry", "revert",
+ "revoke", "right", "rlike", "rollback", "row", "row_format", "row_number",
+ "rows", "s3", "savepoint", "schema", "schemas", "second", "second_microsecond",
+ "security", "select", "sensitive", "separator", "sequence", "serializable",
+ "session", "set", "share", "shared", "show", "signal", "signed", "slow",
+ "smallint", "spatial", "specific", "sql", "sqlexception", "sqlstate",
+ "sqlwarning", "sql_big_result", "sql_cache", "sql_calc_found_rows",
+ "sql_no_cache", "sql_small_result", "ssl", "start", "starting",
+ "stats_auto_recalc", "stats_persistent", "stats_sample_pages", "status",
+ "storage", "stored", "straight_join", "stream", "system", "vstream",
+ "table", "tables", "tablespace", "temporary", "temptable", "terminated",
+ "text", "than", "then", "time", "timestamp", "timestampadd", "timestampdiff",
+ "tinyblob", "tinyint", "tinytext", "to", "trailing", "transaction", "tree",
+ "traditional", "trigger", "triggers", "true", "truncate", "uncommitted",
+ "undefined", "undo", "union", "unique", "unlock", "unsigned", "update",
+ "upgrade", "usage", "use", "user", "user_resources", "using", "utc_date",
+ "utc_time", "utc_timestamp", "validation", "values", "variables", "varbinary",
+ "varchar", "varcharacter", "varying", "vgtid_executed", "virtual", "vindex",
+ "vindexes", "view", "vitess", "vitess_keyspaces", "vitess_metadata",
+ "vitess_migration", "vitess_migrations", "vitess_replication_status",
+ "vitess_shards", "vitess_tablets", "vschema", "warnings", "when",
+ "where", "while", "window", "with", "without", "work", "write", "xor",
+ "year", "year_month", "zerofill",
+}
+
+// Keywords that could get an additional keyword
+var needCustomString = []string{
+ "DISTINCTROW", "FROM", // Select keywords:
+ "GROUP BY", "HAVING", "WINDOW",
+ "FOR",
+ "ORDER BY", "LIMIT",
+ "INTO", "PARTITION", "AS", // Insert Keywords:
+ "ON DUPLICATE KEY UPDATE",
+ "WHERE", "LIMIT", // Delete keywords
+ "INFILE", "INTO TABLE", "CHARACTER SET", // Load keywords
+ "TERMINATED BY", "ENCLOSED BY",
+ "ESCAPED BY", "STARTING BY",
+ "TERMINATED BY", "STARTING BY",
+ "IGNORE",
+ "VALUE", "VALUES", // Replace tokens
+ "SET", // Update tokens
+ "ENGINE =", // Drop tokens
+ "DEFINER =", "ON SCHEDULE", "RENAME TO", // Alter tokens
+ "COMMENT", "DO", "INITIAL_SIZE = ", "OPTIONS",
+}
+
+var alterTableTokens = [][]string{
+ {"CUSTOM_FUZZ_STRING"},
+ {"CUSTOM_ALTTER_TABLE_OPTIONS"},
+ {"PARTITION_OPTIONS_FOR_ALTER_TABLE"},
+}
+
+var alterTokens = [][]string{
+ {
+ "DATABASE", "SCHEMA", "DEFINER = ", "EVENT", "FUNCTION", "INSTANCE",
+ "LOGFILE GROUP", "PROCEDURE", "SERVER",
+ },
+ {"CUSTOM_FUZZ_STRING"},
+ {
+ "ON SCHEDULE", "ON COMPLETION PRESERVE", "ON COMPLETION NOT PRESERVE",
+ "ADD UNDOFILE", "OPTIONS",
+ },
+ {"RENAME TO", "INITIAL_SIZE = "},
+ {"ENABLE", "DISABLE", "DISABLE ON SLAVE", "ENGINE"},
+ {"COMMENT"},
+ {"DO"},
+}
+
+var setTokens = [][]string{
+ {"CHARACTER SET", "CHARSET", "CUSTOM_FUZZ_STRING", "NAMES"},
+ {"CUSTOM_FUZZ_STRING", "DEFAULT", "="},
+ {"CUSTOM_FUZZ_STRING"},
+}
+
+var dropTokens = [][]string{
+ {"TEMPORARY", "UNDO"},
+ {
+ "DATABASE", "SCHEMA", "EVENT", "INDEX", "LOGFILE GROUP",
+ "PROCEDURE", "FUNCTION", "SERVER", "SPATIAL REFERENCE SYSTEM",
+ "TABLE", "TABLESPACE", "TRIGGER", "VIEW",
+ },
+ {"IF EXISTS"},
+ {"CUSTOM_FUZZ_STRING"},
+ {"ON", "ENGINE = ", "RESTRICT", "CASCADE"},
+}
+
+var renameTokens = [][]string{
+ {"TABLE"},
+ {"CUSTOM_FUZZ_STRING"},
+ {"TO"},
+ {"CUSTOM_FUZZ_STRING"},
+}
+
+var truncateTokens = [][]string{
+ {"TABLE"},
+ {"CUSTOM_FUZZ_STRING"},
+}
+
+var createTokens = [][]string{
+ {"OR REPLACE", "TEMPORARY", "UNDO"}, // For create spatial reference system
+ {
+ "UNIQUE", "FULLTEXT", "SPATIAL", "ALGORITHM = UNDEFINED", "ALGORITHM = MERGE",
+ "ALGORITHM = TEMPTABLE",
+ },
+ {
+ "DATABASE", "SCHEMA", "EVENT", "FUNCTION", "INDEX", "LOGFILE GROUP",
+ "PROCEDURE", "SERVER", "SPATIAL REFERENCE SYSTEM", "TABLE", "TABLESPACE",
+ "TRIGGER", "VIEW",
+ },
+ {"IF NOT EXISTS"},
+ {"CUSTOM_FUZZ_STRING"},
+}
+
+/*
+// For future use.
+var updateTokens = [][]string{
+ {"LOW_PRIORITY"},
+ {"IGNORE"},
+ {"SET"},
+ {"WHERE"},
+ {"ORDER BY"},
+ {"LIMIT"},
+}
+*/
+
+var replaceTokens = [][]string{
+ {"LOW_PRIORITY", "DELAYED"},
+ {"INTO"},
+ {"PARTITION"},
+ {"CUSTOM_FUZZ_STRING"},
+ {"VALUES", "VALUE"},
+}
+
+var loadTokens = [][]string{
+ {"DATA"},
+ {"LOW_PRIORITY", "CONCURRENT", "LOCAL"},
+ {"INFILE"},
+ {"REPLACE", "IGNORE"},
+ {"INTO TABLE"},
+ {"PARTITION"},
+ {"CHARACTER SET"},
+ {"FIELDS", "COLUMNS"},
+ {"TERMINATED BY"},
+ {"OPTIONALLY"},
+ {"ENCLOSED BY"},
+ {"ESCAPED BY"},
+ {"LINES"},
+ {"STARTING BY"},
+ {"TERMINATED BY"},
+ {"IGNORE"},
+ {"LINES", "ROWS"},
+ {"CUSTOM_FUZZ_STRING"},
+}
+
+// These Are everything that comes after "INSERT"
+var insertTokens = [][]string{
+ {"LOW_PRIORITY", "DELAYED", "HIGH_PRIORITY", "IGNORE"},
+ {"INTO"},
+ {"PARTITION"},
+ {"CUSTOM_FUZZ_STRING"},
+ {"AS"},
+ {"ON DUPLICATE KEY UPDATE"},
+}
+
+// These are everything that comes after "SELECT"
+var selectTokens = [][]string{
+ {"*", "CUSTOM_FUZZ_STRING", "DISTINCTROW"},
+ {"HIGH_PRIORITY"},
+ {"STRAIGHT_JOIN"},
+ {"SQL_SMALL_RESULT", "SQL_BIG_RESULT", "SQL_BUFFER_RESULT"},
+ {"SQL_NO_CACHE", "SQL_CALC_FOUND_ROWS"},
+ {"CUSTOM_FUZZ_STRING"},
+ {"FROM"},
+ {"WHERE"},
+ {"GROUP BY"},
+ {"HAVING"},
+ {"WINDOW"},
+ {"ORDER BY"},
+ {"LIMIT"},
+ {"CUSTOM_FUZZ_STRING"},
+ {"FOR"},
+}
+
+// These are everything that comes after "DELETE"
+var deleteTokens = [][]string{
+ {"LOW_PRIORITY", "QUICK", "IGNORE", "FROM", "AS"},
+ {"PARTITION"},
+ {"WHERE"},
+ {"ORDER BY"},
+ {"LIMIT"},
+}
+
+var alter_table_options = []string{
+ "ADD", "COLUMN", "FIRST", "AFTER", "INDEX", "KEY", "FULLTEXT", "SPATIAL",
+ "CONSTRAINT", "UNIQUE", "FOREIGN KEY", "CHECK", "ENFORCED", "DROP", "ALTER",
+ "NOT", "INPLACE", "COPY", "SET", "VISIBLE", "INVISIBLE", "DEFAULT", "CHANGE",
+ "CHARACTER SET", "COLLATE", "DISABLE", "ENABLE", "KEYS", "TABLESPACE", "LOCK",
+ "FORCE", "MODIFY", "SHARED", "EXCLUSIVE", "NONE", "ORDER BY", "RENAME COLUMN",
+ "AS", "=", "ASC", "DESC", "WITH", "WITHOUT", "VALIDATION", "ADD PARTITION",
+ "DROP PARTITION", "DISCARD PARTITION", "IMPORT PARTITION", "TRUNCATE PARTITION",
+ "COALESCE PARTITION", "REORGANIZE PARTITION", "EXCHANGE PARTITION",
+ "ANALYZE PARTITION", "CHECK PARTITION", "OPTIMIZE PARTITION", "REBUILD PARTITION",
+ "REPAIR PARTITION", "REMOVE PARTITIONING", "USING", "BTREE", "HASH", "COMMENT",
+ "KEY_BLOCK_SIZE", "WITH PARSER", "AUTOEXTEND_SIZE", "AUTO_INCREMENT", "AVG_ROW_LENGTH",
+ "CHECKSUM", "INSERT_METHOD", "ROW_FORMAT", "DYNAMIC", "FIXED", "COMPRESSED", "REDUNDANT",
+ "COMPACT", "SECONDARY_ENGINE_ATTRIBUTE", "STATS_AUTO_RECALC", "STATS_PERSISTENT",
+ "STATS_SAMPLE_PAGES", "ZLIB", "LZ4", "ENGINE_ATTRIBUTE", "KEY_BLOCK_SIZE", "MAX_ROWS",
+ "MIN_ROWS", "PACK_KEYS", "PASSWORD", "COMPRESSION", "CONNECTION", "DIRECTORY",
+ "DELAY_KEY_WRITE", "ENCRYPTION", "STORAGE", "DISK", "MEMORY", "UNION",
+}
+
+// Creates an 'alter table' statement. 'alter table' is an exception
+// in that it has its own function. The majority of statements
+// are created by 'createStmt()'.
+func createAlterTableStmt(f *ConsumeFuzzer) (string, error) {
+ maxArgs, err := f.GetInt()
+ if err != nil {
+ return "", err
+ }
+ maxArgs = maxArgs % 30
+ if maxArgs == 0 {
+ return "", fmt.Errorf("could not create alter table stmt")
+ }
+
+ var stmt strings.Builder
+ stmt.WriteString("ALTER TABLE ")
+ for i := 0; i < maxArgs; i++ {
+ // Calculate if we get existing token or custom string
+ tokenType, err := f.GetInt()
+ if err != nil {
+ return "", err
+ }
+ if tokenType%4 == 1 {
+ customString, err := f.GetString()
+ if err != nil {
+ return "", err
+ }
+ stmt.WriteString(" " + customString)
+ } else {
+ tokenIndex, err := f.GetInt()
+ if err != nil {
+ return "", err
+ }
+ stmt.WriteString(" " + alter_table_options[tokenIndex%len(alter_table_options)])
+ }
+ }
+ return stmt.String(), nil
+}
+
+func chooseToken(tokens []string, f *ConsumeFuzzer) (string, error) {
+ index, err := f.GetInt()
+ if err != nil {
+ return "", err
+ }
+ var token strings.Builder
+ token.WriteString(tokens[index%len(tokens)])
+ if token.String() == "CUSTOM_FUZZ_STRING" {
+ customFuzzString, err := f.GetString()
+ if err != nil {
+ return "", err
+ }
+ return customFuzzString, nil
+ }
+
+ // Check if token requires an argument
+ if containsString(needCustomString, token.String()) {
+ customFuzzString, err := f.GetString()
+ if err != nil {
+ return "", err
+ }
+ token.WriteString(" " + customFuzzString)
+ }
+ return token.String(), nil
+}
+
+var stmtTypes = map[string][][]string{
+ "DELETE": deleteTokens,
+ "INSERT": insertTokens,
+ "SELECT": selectTokens,
+ "LOAD": loadTokens,
+ "REPLACE": replaceTokens,
+ "CREATE": createTokens,
+ "DROP": dropTokens,
+ "RENAME": renameTokens,
+ "TRUNCATE": truncateTokens,
+ "SET": setTokens,
+ "ALTER": alterTokens,
+ "ALTER TABLE": alterTableTokens, // ALTER TABLE has its own set of tokens
+}
+
+var stmtTypeEnum = map[int]string{
+ 0: "DELETE",
+ 1: "INSERT",
+ 2: "SELECT",
+ 3: "LOAD",
+ 4: "REPLACE",
+ 5: "CREATE",
+ 6: "DROP",
+ 7: "RENAME",
+ 8: "TRUNCATE",
+ 9: "SET",
+ 10: "ALTER",
+ 11: "ALTER TABLE",
+}
+
+func createStmt(f *ConsumeFuzzer) (string, error) {
+ stmtIndex, err := f.GetInt()
+ if err != nil {
+ return "", err
+ }
+ stmtIndex = stmtIndex % len(stmtTypes)
+
+ queryType := stmtTypeEnum[stmtIndex]
+ tokens := stmtTypes[queryType]
+
+ // We have custom creator for ALTER TABLE
+ if queryType == "ALTER TABLE" {
+ query, err := createAlterTableStmt(f)
+ if err != nil {
+ return "", err
+ }
+ return query, nil
+ }
+
+ // Here we are creating a query that is not
+ // an 'alter table' query. For available
+ // queries, see "stmtTypes"
+
+ // First specify the first query keyword:
+ var query strings.Builder
+ query.WriteString(queryType)
+
+ // Next create the args for the
+ queryArgs, err := createStmtArgs(tokens, f)
+ if err != nil {
+ return "", err
+ }
+ query.WriteString(" " + queryArgs)
+ return query.String(), nil
+}
+
+// Creates the arguments of a statements. In a select statement
+// that would be everything after "select".
+func createStmtArgs(tokenslice [][]string, f *ConsumeFuzzer) (string, error) {
+ var query, token strings.Builder
+
+ // We go through the tokens in the tokenslice,
+ // create the respective token and add it to
+ // "query"
+ for _, tokens := range tokenslice {
+ // For extra randomization, the fuzzer can
+ // choose to not include this token.
+ includeThisToken, err := f.GetBool()
+ if err != nil {
+ return "", err
+ }
+ if !includeThisToken {
+ continue
+ }
+
+ // There may be several tokens to choose from:
+ if len(tokens) > 1 {
+ chosenToken, err := chooseToken(tokens, f)
+ if err != nil {
+ return "", err
+ }
+ query.WriteString(" " + chosenToken)
+ } else {
+ token.WriteString(tokens[0])
+
+ // In case the token is "CUSTOM_FUZZ_STRING"
+ // we will then create a non-structured string
+ if token.String() == "CUSTOM_FUZZ_STRING" {
+ customFuzzString, err := f.GetString()
+ if err != nil {
+ return "", err
+ }
+ query.WriteString(" " + customFuzzString)
+ continue
+ }
+
+ // Check if token requires an argument.
+ // Tokens that take an argument can be found
+ // in 'needCustomString'. If so, we add a
+ // non-structured string to the token.
+ if containsString(needCustomString, token.String()) {
+ customFuzzString, err := f.GetString()
+ if err != nil {
+ return "", err
+ }
+ token.WriteString(fmt.Sprintf(" %s", customFuzzString))
+ }
+ query.WriteString(fmt.Sprintf(" %s", token.String()))
+ }
+ }
+ return query.String(), nil
+}
+
+// Creates a semi-structured query. It creates a string
+// that is a combination of the keywords and random strings.
+func createQuery(f *ConsumeFuzzer) (string, error) {
+ queryLen, err := f.GetInt()
+ if err != nil {
+ return "", err
+ }
+ maxLen := queryLen % 60
+ if maxLen == 0 {
+ return "", fmt.Errorf("could not create a query")
+ }
+ var query strings.Builder
+ for i := 0; i < maxLen; i++ {
+ // Get a new token:
+ useKeyword, err := f.GetBool()
+ if err != nil {
+ return "", err
+ }
+ if useKeyword {
+ keyword, err := getKeyword(f)
+ if err != nil {
+ return "", err
+ }
+ query.WriteString(" " + keyword)
+ } else {
+ customString, err := f.GetString()
+ if err != nil {
+ return "", err
+ }
+ query.WriteString(" " + customString)
+ }
+ }
+ if query.String() == "" {
+ return "", fmt.Errorf("could not create a query")
+ }
+ return query.String(), nil
+}
+
+// GetSQLString is the API that users interact with.
+//
+// Usage:
+//
+// f := NewConsumer(data)
+// sqlString, err := f.GetSQLString()
+func (f *ConsumeFuzzer) GetSQLString() (string, error) {
+ var query string
+ veryStructured, err := f.GetBool()
+ if err != nil {
+ return "", err
+ }
+ if veryStructured {
+ query, err = createStmt(f)
+ if err != nil {
+ return "", err
+ }
+ } else {
+ query, err = createQuery(f)
+ if err != nil {
+ return "", err
+ }
+ }
+ return query, nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/LICENSE b/vendor/github.com/Microsoft/hcsshim/LICENSE
new file mode 100644
index 00000000000..49d21669aee
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Microsoft
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/vendor/github.com/Microsoft/hcsshim/osversion/osversion_windows.go b/vendor/github.com/Microsoft/hcsshim/osversion/osversion_windows.go
new file mode 100644
index 00000000000..6c435d2b649
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/osversion/osversion_windows.go
@@ -0,0 +1,59 @@
+package osversion
+
+import (
+ "fmt"
+ "sync"
+
+ "golang.org/x/sys/windows"
+)
+
+// OSVersion is a wrapper for Windows version information
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
+type OSVersion struct {
+ Version uint32
+ MajorVersion uint8
+ MinorVersion uint8
+ Build uint16
+}
+
+var (
+ osv OSVersion
+ once sync.Once
+)
+
+// Get gets the operating system version on Windows.
+// The calling application must be manifested to get the correct version information.
+func Get() OSVersion {
+ once.Do(func() {
+ var err error
+ osv = OSVersion{}
+ osv.Version, err = windows.GetVersion()
+ if err != nil {
+ // GetVersion never fails.
+ panic(err)
+ }
+ osv.MajorVersion = uint8(osv.Version & 0xFF)
+ osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF)
+ osv.Build = uint16(osv.Version >> 16)
+ })
+ return osv
+}
+
+// Build gets the build-number on Windows
+// The calling application must be manifested to get the correct version information.
+func Build() uint16 {
+ return Get().Build
+}
+
+// String returns the OSVersion formatted as a string. It implements the
+// [fmt.Stringer] interface.
+func (osv OSVersion) String() string {
+ return fmt.Sprintf("%d.%d.%d", osv.MajorVersion, osv.MinorVersion, osv.Build)
+}
+
+// ToString returns the OSVersion formatted as a string.
+//
+// Deprecated: use [OSVersion.String].
+func (osv OSVersion) ToString() string {
+ return osv.String()
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/osversion/platform_compat_windows.go b/vendor/github.com/Microsoft/hcsshim/osversion/platform_compat_windows.go
new file mode 100644
index 00000000000..f8d411ad7e2
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/osversion/platform_compat_windows.go
@@ -0,0 +1,35 @@
+package osversion
+
+// List of stable ABI compliant ltsc releases
+// Note: List must be sorted in ascending order
+var compatLTSCReleases = []uint16{
+ V21H2Server,
+}
+
+// CheckHostAndContainerCompat checks if given host and container
+// OS versions are compatible.
+// It includes support for stable ABI compliant versions as well.
+// Every release after WS 2022 will support the previous ltsc
+// container image. Stable ABI is in preview mode for windows 11 client.
+// Refer: https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-2022%2Cwindows-10#windows-server-host-os-compatibility
+func CheckHostAndContainerCompat(host, ctr OSVersion) bool {
+ // check major minor versions of host and guest
+ if host.MajorVersion != ctr.MajorVersion ||
+ host.MinorVersion != ctr.MinorVersion {
+ return false
+ }
+
+ // If host is < WS 2022, exact version match is required
+ if host.Build < V21H2Server {
+ return host.Build == ctr.Build
+ }
+
+ var supportedLtscRelease uint16
+ for i := len(compatLTSCReleases) - 1; i >= 0; i-- {
+ if host.Build >= compatLTSCReleases[i] {
+ supportedLtscRelease = compatLTSCReleases[i]
+ break
+ }
+ }
+ return ctr.Build >= supportedLtscRelease && ctr.Build <= host.Build
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go b/vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go
new file mode 100644
index 00000000000..446369591a8
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go
@@ -0,0 +1,84 @@
+package osversion
+
+// Windows Client and Server build numbers.
+//
+// See:
+// https://learn.microsoft.com/en-us/windows/release-health/release-information
+// https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info
+// https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information
+const (
+ // RS1 (version 1607, codename "Redstone 1") corresponds to Windows Server
+ // 2016 (ltsc2016) and Windows 10 (Anniversary Update).
+ RS1 = 14393
+ // V1607 (version 1607, codename "Redstone 1") is an alias for [RS1].
+ V1607 = RS1
+ // LTSC2016 (Windows Server 2016) is an alias for [RS1].
+ LTSC2016 = RS1
+
+ // RS2 (version 1703, codename "Redstone 2") was a client-only update, and
+ // corresponds to Windows 10 (Creators Update).
+ RS2 = 15063
+ // V1703 (version 1703, codename "Redstone 2") is an alias for [RS2].
+ V1703 = RS2
+
+ // RS3 (version 1709, codename "Redstone 3") corresponds to Windows Server
+ // 1709 (Semi-Annual Channel (SAC)), and Windows 10 (Fall Creators Update).
+ RS3 = 16299
+ // V1709 (version 1709, codename "Redstone 3") is an alias for [RS3].
+ V1709 = RS3
+
+ // RS4 (version 1803, codename "Redstone 4") corresponds to Windows Server
+ // 1803 (Semi-Annual Channel (SAC)), and Windows 10 (April 2018 Update).
+ RS4 = 17134
+ // V1803 (version 1803, codename "Redstone 4") is an alias for [RS4].
+ V1803 = RS4
+
+ // RS5 (version 1809, codename "Redstone 5") corresponds to Windows Server
+ // 2019 (ltsc2019), and Windows 10 (October 2018 Update).
+ RS5 = 17763
+ // V1809 (version 1809, codename "Redstone 5") is an alias for [RS5].
+ V1809 = RS5
+ // LTSC2019 (Windows Server 2019) is an alias for [RS5].
+ LTSC2019 = RS5
+
+ // V19H1 (version 1903, codename 19H1) corresponds to Windows Server 1903 (semi-annual
+ // channel).
+ V19H1 = 18362
+ // V1903 (version 1903) is an alias for [V19H1].
+ V1903 = V19H1
+
+ // V19H2 (version 1909, codename 19H2) corresponds to Windows Server 1909 (semi-annual
+ // channel).
+ V19H2 = 18363
+ // V1909 (version 1909) is an alias for [V19H2].
+ V1909 = V19H2
+
+ // V20H1 (version 2004, codename 20H1) corresponds to Windows Server 2004 (semi-annual
+ // channel).
+ V20H1 = 19041
+ // V2004 (version 2004) is an alias for [V20H1].
+ V2004 = V20H1
+
+ // V20H2 corresponds to Windows Server 20H2 (semi-annual channel).
+ V20H2 = 19042
+
+ // V21H1 corresponds to Windows Server 21H1 (semi-annual channel).
+ V21H1 = 19043
+
+ // V21H2Win10 corresponds to Windows 10 (November 2021 Update).
+ V21H2Win10 = 19044
+
+ // V21H2Server corresponds to Windows Server 2022 (ltsc2022).
+ V21H2Server = 20348
+ // LTSC2022 (Windows Server 2022) is an alias for [V21H2Server]
+ LTSC2022 = V21H2Server
+
+ // V21H2Win11 corresponds to Windows 11 (original release).
+ V21H2Win11 = 22000
+
+ // V22H2Win10 corresponds to Windows 10 (2022 Update).
+ V22H2Win10 = 19045
+
+ // V22H2Win11 corresponds to Windows 11 (2022 Update).
+ V22H2Win11 = 22621
+)
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn.go
index 1592212e146..a4e2079e656 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn.go
@@ -4,6 +4,8 @@
package antlr
+import "sync"
+
var ATNInvalidAltNumber int
type ATN struct {
@@ -37,6 +39,10 @@ type ATN struct {
ruleToTokenType []int
states []ATNState
+
+ mu sync.Mutex
+ stateMu sync.RWMutex
+ edgeMu sync.RWMutex
}
func NewATN(grammarType int, maxTokenType int) *ATN {
@@ -59,14 +65,15 @@ func (a *ATN) NextTokensInContext(s ATNState, ctx RuleContext) *IntervalSet {
// in s and staying in same rule. Token.EPSILON is in set if we reach end of
// rule.
func (a *ATN) NextTokensNoContext(s ATNState) *IntervalSet {
- if s.GetNextTokenWithinRule() != nil {
- return s.GetNextTokenWithinRule()
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ iset := s.GetNextTokenWithinRule()
+ if iset == nil {
+ iset = a.NextTokensInContext(s, nil)
+ iset.readOnly = true
+ s.SetNextTokenWithinRule(iset)
}
-
- s.SetNextTokenWithinRule(a.NextTokensInContext(s, nil))
- s.GetNextTokenWithinRule().readOnly = true
-
- return s.GetNextTokenWithinRule()
+ return iset
}
func (a *ATN) NextTokens(s ATNState, ctx RuleContext) *IntervalSet {
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_config.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_config.go
index 0535d5246c5..97ba417f74f 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_config.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_config.go
@@ -251,7 +251,7 @@ func (l *LexerATNConfig) hash() int {
f = 0
}
h := murmurInit(7)
- h = murmurUpdate(h, l.state.hash())
+ h = murmurUpdate(h, l.state.GetStateNumber())
h = murmurUpdate(h, l.alt)
h = murmurUpdate(h, l.context.hash())
h = murmurUpdate(h, l.semanticContext.hash())
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_config_set.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_config_set.go
index d9f74755fa7..49ad4a7197a 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_config_set.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_config_set.go
@@ -11,7 +11,7 @@ type ATNConfigSet interface {
Add(ATNConfig, *DoubleDict) bool
AddAll([]ATNConfig) bool
- GetStates() *Set
+ GetStates() Set
GetPredicates() []SemanticContext
GetItems() []ATNConfig
@@ -35,6 +35,8 @@ type ATNConfigSet interface {
GetConflictingAlts() *BitSet
SetConflictingAlts(*BitSet)
+ Alts() *BitSet
+
FullContext() bool
GetUniqueAlt() int
@@ -55,7 +57,7 @@ type BaseATNConfigSet struct {
// effectively doubles the number of objects associated with ATNConfigs. All
// keys are hashed by (s, i, _, pi), not including the context. Wiped out when
// read-only because a set becomes a DFA state.
- configLookup *Set
+ configLookup Set
// configs is the added elements.
configs []ATNConfig
@@ -91,11 +93,19 @@ type BaseATNConfigSet struct {
uniqueAlt int
}
+func (b *BaseATNConfigSet) Alts() *BitSet {
+ alts := NewBitSet()
+ for _, it := range b.configs {
+ alts.add(it.GetAlt())
+ }
+ return alts
+}
+
func NewBaseATNConfigSet(fullCtx bool) *BaseATNConfigSet {
return &BaseATNConfigSet{
- cachedHash: -1,
- configLookup: NewSet(nil, equalATNConfigs),
- fullCtx: fullCtx,
+ cachedHash: -1,
+ configLookup: newArray2DHashSetWithCap(hashATNConfig, equalATNConfigs, 16, 2),
+ fullCtx: fullCtx,
}
}
@@ -116,12 +126,11 @@ func (b *BaseATNConfigSet) Add(config ATNConfig, mergeCache *DoubleDict) bool {
b.dipsIntoOuterContext = true
}
- existing := b.configLookup.add(config).(ATNConfig)
+ existing := b.configLookup.Add(config).(ATNConfig)
if existing == config {
b.cachedHash = -1
b.configs = append(b.configs, config) // Track order here
-
return true
}
@@ -145,11 +154,11 @@ func (b *BaseATNConfigSet) Add(config ATNConfig, mergeCache *DoubleDict) bool {
return true
}
-func (b *BaseATNConfigSet) GetStates() *Set {
- states := NewSet(nil, nil)
+func (b *BaseATNConfigSet) GetStates() Set {
+ states := newArray2DHashSet(nil, nil)
for i := 0; i < len(b.configs); i++ {
- states.add(b.configs[i].GetState())
+ states.Add(b.configs[i].GetState())
}
return states
@@ -186,7 +195,7 @@ func (b *BaseATNConfigSet) OptimizeConfigs(interpreter *BaseATNSimulator) {
panic("set is read-only")
}
- if b.configLookup.length() == 0 {
+ if b.configLookup.Len() == 0 {
return
}
@@ -236,13 +245,11 @@ func (b *BaseATNConfigSet) hash() int {
}
func (b *BaseATNConfigSet) hashCodeConfigs() int {
- h := murmurInit(1)
- for _, c := range b.configs {
- if c != nil {
- h = murmurUpdate(h, c.hash())
- }
+ h := 1
+ for _, config := range b.configs {
+ h = 31*h + config.hash()
}
- return murmurFinish(h, len(b.configs))
+ return h
}
func (b *BaseATNConfigSet) Length() int {
@@ -258,7 +265,7 @@ func (b *BaseATNConfigSet) Contains(item ATNConfig) bool {
panic("not implemented for read-only sets")
}
- return b.configLookup.contains(item)
+ return b.configLookup.Contains(item)
}
func (b *BaseATNConfigSet) ContainsFast(item ATNConfig) bool {
@@ -266,7 +273,7 @@ func (b *BaseATNConfigSet) ContainsFast(item ATNConfig) bool {
panic("not implemented for read-only sets")
}
- return b.configLookup.contains(item) // TODO: containsFast is not implemented for Set
+ return b.configLookup.Contains(item) // TODO: containsFast is not implemented for Set
}
func (b *BaseATNConfigSet) Clear() {
@@ -276,7 +283,7 @@ func (b *BaseATNConfigSet) Clear() {
b.configs = make([]ATNConfig, 0)
b.cachedHash = -1
- b.configLookup = NewSet(nil, equalATNConfigs)
+ b.configLookup = newArray2DHashSet(nil, equalATNConfigs)
}
func (b *BaseATNConfigSet) FullContext() bool {
@@ -358,11 +365,20 @@ type OrderedATNConfigSet struct {
func NewOrderedATNConfigSet() *OrderedATNConfigSet {
b := NewBaseATNConfigSet(false)
- b.configLookup = NewSet(nil, nil)
+ b.configLookup = newArray2DHashSet(nil, nil)
return &OrderedATNConfigSet{BaseATNConfigSet: b}
}
+func hashATNConfig(i interface{}) int {
+ o := i.(ATNConfig)
+ hash := 7
+ hash = 31*hash + o.GetState().GetStateNumber()
+ hash = 31*hash + o.GetAlt()
+ hash = 31*hash + o.GetSemanticContext().hash()
+ return hash
+}
+
func equalATNConfigs(a, b interface{}) bool {
if a == nil || b == nil {
return false
@@ -379,9 +395,13 @@ func equalATNConfigs(a, b interface{}) bool {
return false
}
- nums := ai.GetState().GetStateNumber() == bi.GetState().GetStateNumber()
- alts := ai.GetAlt() == bi.GetAlt()
- cons := ai.GetSemanticContext().equals(bi.GetSemanticContext())
+ if ai.GetState().GetStateNumber() != bi.GetState().GetStateNumber() {
+ return false
+ }
+
+ if ai.GetAlt() != bi.GetAlt() {
+ return false
+ }
- return nums && alts && cons
+ return ai.GetSemanticContext().equals(bi.GetSemanticContext())
}
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_deserialization_options.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_deserialization_options.go
index 18b89efafb2..cb8eafb0b2a 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_deserialization_options.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_deserialization_options.go
@@ -4,7 +4,9 @@
package antlr
-var ATNDeserializationOptionsdefaultOptions = &ATNDeserializationOptions{true, false, false}
+import "errors"
+
+var defaultATNDeserializationOptions = ATNDeserializationOptions{true, true, false}
type ATNDeserializationOptions struct {
readOnly bool
@@ -12,14 +14,48 @@ type ATNDeserializationOptions struct {
generateRuleBypassTransitions bool
}
-func NewATNDeserializationOptions(CopyFrom *ATNDeserializationOptions) *ATNDeserializationOptions {
- o := new(ATNDeserializationOptions)
+func (opts *ATNDeserializationOptions) ReadOnly() bool {
+ return opts.readOnly
+}
+
+func (opts *ATNDeserializationOptions) SetReadOnly(readOnly bool) {
+ if opts.readOnly {
+ panic(errors.New("Cannot mutate read only ATNDeserializationOptions"))
+ }
+ opts.readOnly = readOnly
+}
+
+func (opts *ATNDeserializationOptions) VerifyATN() bool {
+ return opts.verifyATN
+}
+
+func (opts *ATNDeserializationOptions) SetVerifyATN(verifyATN bool) {
+ if opts.readOnly {
+ panic(errors.New("Cannot mutate read only ATNDeserializationOptions"))
+ }
+ opts.verifyATN = verifyATN
+}
- if CopyFrom != nil {
- o.readOnly = CopyFrom.readOnly
- o.verifyATN = CopyFrom.verifyATN
- o.generateRuleBypassTransitions = CopyFrom.generateRuleBypassTransitions
+func (opts *ATNDeserializationOptions) GenerateRuleBypassTransitions() bool {
+ return opts.generateRuleBypassTransitions
+}
+
+func (opts *ATNDeserializationOptions) SetGenerateRuleBypassTransitions(generateRuleBypassTransitions bool) {
+ if opts.readOnly {
+ panic(errors.New("Cannot mutate read only ATNDeserializationOptions"))
}
+ opts.generateRuleBypassTransitions = generateRuleBypassTransitions
+}
+func DefaultATNDeserializationOptions() *ATNDeserializationOptions {
+ return NewATNDeserializationOptions(&defaultATNDeserializationOptions)
+}
+
+func NewATNDeserializationOptions(other *ATNDeserializationOptions) *ATNDeserializationOptions {
+ o := new(ATNDeserializationOptions)
+ if other != nil {
+ *o = *other
+ o.readOnly = false
+ }
return o
}
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_deserializer.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_deserializer.go
index 884d39cf7cd..aea9bbfa936 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_deserializer.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_deserializer.go
@@ -5,50 +5,34 @@
package antlr
import (
- "encoding/hex"
"fmt"
"strconv"
- "strings"
- "unicode/utf16"
)
-// This is the earliest supported serialized UUID.
-// stick to serialized version for now, we don't need a UUID instance
-var BaseSerializedUUID = "AADB8D7E-AEEF-4415-AD2B-8204D6CF042E"
-var AddedUnicodeSMP = "59627784-3BE5-417A-B9EB-8131A7286089"
+const serializedVersion = 4
-// This list contains all of the currently supported UUIDs, ordered by when
-// the feature first appeared in this branch.
-var SupportedUUIDs = []string{BaseSerializedUUID, AddedUnicodeSMP}
-
-var SerializedVersion = 3
-
-// This is the current serialized UUID.
-var SerializedUUID = AddedUnicodeSMP
-
-type LoopEndStateIntPair struct {
+type loopEndStateIntPair struct {
item0 *LoopEndState
item1 int
}
-type BlockStartStateIntPair struct {
+type blockStartStateIntPair struct {
item0 BlockStartState
item1 int
}
type ATNDeserializer struct {
- deserializationOptions *ATNDeserializationOptions
- data []rune
- pos int
- uuid string
+ options *ATNDeserializationOptions
+ data []int32
+ pos int
}
func NewATNDeserializer(options *ATNDeserializationOptions) *ATNDeserializer {
if options == nil {
- options = ATNDeserializationOptionsdefaultOptions
+ options = &defaultATNDeserializationOptions
}
- return &ATNDeserializer{deserializationOptions: options}
+ return &ATNDeserializer{options: options}
}
func stringInSlice(a string, list []string) int {
@@ -61,30 +45,10 @@ func stringInSlice(a string, list []string) int {
return -1
}
-// isFeatureSupported determines if a particular serialized representation of an
-// ATN supports a particular feature, identified by the UUID used for
-// serializing the ATN at the time the feature was first introduced. Feature is
-// the UUID marking the first time the feature was supported in the serialized
-// ATN. ActualUuid is the UUID of the actual serialized ATN which is currently
-// being deserialized. It returns true if actualUuid represents a serialized ATN
-// at or after the feature identified by feature was introduced, and otherwise
-// false.
-func (a *ATNDeserializer) isFeatureSupported(feature, actualUUID string) bool {
- idx1 := stringInSlice(feature, SupportedUUIDs)
-
- if idx1 < 0 {
- return false
- }
-
- idx2 := stringInSlice(actualUUID, SupportedUUIDs)
-
- return idx2 >= idx1
-}
-
-func (a *ATNDeserializer) DeserializeFromUInt16(data []uint16) *ATN {
- a.reset(utf16.Decode(data))
+func (a *ATNDeserializer) Deserialize(data []int32) *ATN {
+ a.data = data
+ a.pos = 0
a.checkVersion()
- a.checkUUID()
atn := a.readATN()
@@ -92,15 +56,7 @@ func (a *ATNDeserializer) DeserializeFromUInt16(data []uint16) *ATN {
a.readRules(atn)
a.readModes(atn)
- sets := make([]*IntervalSet, 0)
-
- // First, deserialize sets with 16-bit arguments <= U+FFFF.
- sets = a.readSets(atn, sets, a.readInt)
- // Next, if the ATN was serialized with the Unicode SMP feature,
- // deserialize sets with 32-bit arguments <= U+10FFFF.
- if (a.isFeatureSupported(AddedUnicodeSMP, a.uuid)) {
- sets = a.readSets(atn, sets, a.readInt32)
- }
+ sets := a.readSets(atn, nil)
a.readEdges(atn, sets)
a.readDecisions(atn)
@@ -108,7 +64,7 @@ func (a *ATNDeserializer) DeserializeFromUInt16(data []uint16) *ATN {
a.markPrecedenceDecisions(atn)
a.verifyATN(atn)
- if a.deserializationOptions.generateRuleBypassTransitions && atn.grammarType == ATNTypeParser {
+ if a.options.GenerateRuleBypassTransitions() && atn.grammarType == ATNTypeParser {
a.generateRuleBypassTransitions(atn)
// Re-verify after modification
a.verifyATN(atn)
@@ -118,42 +74,14 @@ func (a *ATNDeserializer) DeserializeFromUInt16(data []uint16) *ATN {
}
-func (a *ATNDeserializer) reset(data []rune) {
- temp := make([]rune, len(data))
-
- for i, c := range data {
- // Don't adjust the first value since that's the version number
- if i == 0 {
- temp[i] = c
- } else if c > 1 {
- temp[i] = c - 2
- } else {
- temp[i] = c + 65533
- }
- }
-
- a.data = temp
- a.pos = 0
-}
-
func (a *ATNDeserializer) checkVersion() {
version := a.readInt()
- if version != SerializedVersion {
- panic("Could not deserialize ATN with version " + strconv.Itoa(version) + " (expected " + strconv.Itoa(SerializedVersion) + ").")
+ if version != serializedVersion {
+ panic("Could not deserialize ATN with version " + strconv.Itoa(version) + " (expected " + strconv.Itoa(serializedVersion) + ").")
}
}
-func (a *ATNDeserializer) checkUUID() {
- uuid := a.readUUID()
-
- if stringInSlice(uuid, SupportedUUIDs) < 0 {
- panic("Could not deserialize ATN with UUID: " + uuid + " (expected " + SerializedUUID + " or a legacy UUID).")
- }
-
- a.uuid = uuid
-}
-
func (a *ATNDeserializer) readATN() *ATN {
grammarType := a.readInt()
maxTokenType := a.readInt()
@@ -162,37 +90,36 @@ func (a *ATNDeserializer) readATN() *ATN {
}
func (a *ATNDeserializer) readStates(atn *ATN) {
- loopBackStateNumbers := make([]LoopEndStateIntPair, 0)
- endStateNumbers := make([]BlockStartStateIntPair, 0)
-
nstates := a.readInt()
+ // Allocate worst case size.
+ loopBackStateNumbers := make([]loopEndStateIntPair, 0, nstates)
+ endStateNumbers := make([]blockStartStateIntPair, 0, nstates)
+
+ // Preallocate states slice.
+ atn.states = make([]ATNState, 0, nstates)
+
for i := 0; i < nstates; i++ {
stype := a.readInt()
// Ignore bad types of states
if stype == ATNStateInvalidType {
atn.addState(nil)
-
continue
}
ruleIndex := a.readInt()
- if ruleIndex == 0xFFFF {
- ruleIndex = -1
- }
-
s := a.stateFactory(stype, ruleIndex)
if stype == ATNStateLoopEnd {
loopBackStateNumber := a.readInt()
- loopBackStateNumbers = append(loopBackStateNumbers, LoopEndStateIntPair{s.(*LoopEndState), loopBackStateNumber})
+ loopBackStateNumbers = append(loopBackStateNumbers, loopEndStateIntPair{s.(*LoopEndState), loopBackStateNumber})
} else if s2, ok := s.(BlockStartState); ok {
endStateNumber := a.readInt()
- endStateNumbers = append(endStateNumbers, BlockStartStateIntPair{s2, endStateNumber})
+ endStateNumbers = append(endStateNumbers, blockStartStateIntPair{s2, endStateNumber})
}
atn.addState(s)
@@ -200,20 +127,15 @@ func (a *ATNDeserializer) readStates(atn *ATN) {
// Delay the assignment of loop back and end states until we know all the state
// instances have been initialized
- for j := 0; j < len(loopBackStateNumbers); j++ {
- pair := loopBackStateNumbers[j]
-
+ for _, pair := range loopBackStateNumbers {
pair.item0.loopBackState = atn.states[pair.item1]
}
- for j := 0; j < len(endStateNumbers); j++ {
- pair := endStateNumbers[j]
-
+ for _, pair := range endStateNumbers {
pair.item0.setEndState(atn.states[pair.item1].(*BlockEndState))
}
numNonGreedyStates := a.readInt()
-
for j := 0; j < numNonGreedyStates; j++ {
stateNumber := a.readInt()
@@ -221,7 +143,6 @@ func (a *ATNDeserializer) readStates(atn *ATN) {
}
numPrecedenceStates := a.readInt()
-
for j := 0; j < numPrecedenceStates; j++ {
stateNumber := a.readInt()
@@ -233,12 +154,12 @@ func (a *ATNDeserializer) readRules(atn *ATN) {
nrules := a.readInt()
if atn.grammarType == ATNTypeLexer {
- atn.ruleToTokenType = make([]int, nrules) // TODO: initIntArray(nrules, 0)
+ atn.ruleToTokenType = make([]int, nrules)
}
- atn.ruleToStartState = make([]*RuleStartState, nrules) // TODO: initIntArray(nrules, 0)
+ atn.ruleToStartState = make([]*RuleStartState, nrules)
- for i := 0; i < nrules; i++ {
+ for i := range atn.ruleToStartState {
s := a.readInt()
startState := atn.states[s].(*RuleStartState)
@@ -247,19 +168,13 @@ func (a *ATNDeserializer) readRules(atn *ATN) {
if atn.grammarType == ATNTypeLexer {
tokenType := a.readInt()
- if tokenType == 0xFFFF {
- tokenType = TokenEOF
- }
-
atn.ruleToTokenType[i] = tokenType
}
}
- atn.ruleToStopState = make([]*RuleStopState, nrules) //initIntArray(nrules, 0)
-
- for i := 0; i < len(atn.states); i++ {
- state := atn.states[i]
+ atn.ruleToStopState = make([]*RuleStopState, nrules)
+ for _, state := range atn.states {
if s2, ok := state.(*RuleStopState); ok {
atn.ruleToStopState[s2.ruleIndex] = s2
atn.ruleToStartState[s2.ruleIndex].stopState = s2
@@ -269,17 +184,25 @@ func (a *ATNDeserializer) readRules(atn *ATN) {
func (a *ATNDeserializer) readModes(atn *ATN) {
nmodes := a.readInt()
+ atn.modeToStartState = make([]*TokensStartState, nmodes)
- for i := 0; i < nmodes; i++ {
+ for i := range atn.modeToStartState {
s := a.readInt()
- atn.modeToStartState = append(atn.modeToStartState, atn.states[s].(*TokensStartState))
+ atn.modeToStartState[i] = atn.states[s].(*TokensStartState)
}
}
-func (a *ATNDeserializer) readSets(atn *ATN, sets []*IntervalSet, readUnicode func() int) []*IntervalSet {
+func (a *ATNDeserializer) readSets(atn *ATN, sets []*IntervalSet) []*IntervalSet {
m := a.readInt()
+ // Preallocate the needed capacity.
+ if cap(sets)-len(sets) < m {
+ isets := make([]*IntervalSet, len(sets), len(sets)+m)
+ copy(isets, sets)
+ sets = isets
+ }
+
for i := 0; i < m; i++ {
iset := NewIntervalSet()
@@ -293,8 +216,8 @@ func (a *ATNDeserializer) readSets(atn *ATN, sets []*IntervalSet, readUnicode fu
}
for j := 0; j < n; j++ {
- i1 := readUnicode()
- i2 := readUnicode()
+ i1 := a.readInt()
+ i2 := a.readInt()
iset.addRange(i1, i2)
}
@@ -322,11 +245,9 @@ func (a *ATNDeserializer) readEdges(atn *ATN, sets []*IntervalSet) {
}
// Edges for rule stop states can be derived, so they are not serialized
- for i := 0; i < len(atn.states); i++ {
- state := atn.states[i]
-
- for j := 0; j < len(state.GetTransitions()); j++ {
- var t, ok = state.GetTransitions()[j].(*RuleTransition)
+ for _, state := range atn.states {
+ for _, t := range state.GetTransitions() {
+ var rt, ok = t.(*RuleTransition)
if !ok {
continue
@@ -334,48 +255,42 @@ func (a *ATNDeserializer) readEdges(atn *ATN, sets []*IntervalSet) {
outermostPrecedenceReturn := -1
- if atn.ruleToStartState[t.getTarget().GetRuleIndex()].isPrecedenceRule {
- if t.precedence == 0 {
- outermostPrecedenceReturn = t.getTarget().GetRuleIndex()
+ if atn.ruleToStartState[rt.getTarget().GetRuleIndex()].isPrecedenceRule {
+ if rt.precedence == 0 {
+ outermostPrecedenceReturn = rt.getTarget().GetRuleIndex()
}
}
- trans := NewEpsilonTransition(t.followState, outermostPrecedenceReturn)
+ trans := NewEpsilonTransition(rt.followState, outermostPrecedenceReturn)
- atn.ruleToStopState[t.getTarget().GetRuleIndex()].AddTransition(trans, -1)
+ atn.ruleToStopState[rt.getTarget().GetRuleIndex()].AddTransition(trans, -1)
}
}
- for i := 0; i < len(atn.states); i++ {
- state := atn.states[i]
-
- if s2, ok := state.(*BaseBlockStartState); ok {
+ for _, state := range atn.states {
+ if s2, ok := state.(BlockStartState); ok {
// We need to know the end state to set its start state
- if s2.endState == nil {
+ if s2.getEndState() == nil {
panic("IllegalState")
}
// Block end states can only be associated to a single block start state
- if s2.endState.startState != nil {
+ if s2.getEndState().startState != nil {
panic("IllegalState")
}
- s2.endState.startState = state
+ s2.getEndState().startState = state
}
if s2, ok := state.(*PlusLoopbackState); ok {
- for j := 0; j < len(s2.GetTransitions()); j++ {
- target := s2.GetTransitions()[j].getTarget()
-
- if t2, ok := target.(*PlusBlockStartState); ok {
+ for _, t := range s2.GetTransitions() {
+ if t2, ok := t.getTarget().(*PlusBlockStartState); ok {
t2.loopBackState = state
}
}
} else if s2, ok := state.(*StarLoopbackState); ok {
- for j := 0; j < len(s2.GetTransitions()); j++ {
- target := s2.GetTransitions()[j].getTarget()
-
- if t2, ok := target.(*StarLoopEntryState); ok {
+ for _, t := range s2.GetTransitions() {
+ if t2, ok := t.getTarget().(*StarLoopEntryState); ok {
t2.loopBackState = state
}
}
@@ -399,25 +314,13 @@ func (a *ATNDeserializer) readLexerActions(atn *ATN) {
if atn.grammarType == ATNTypeLexer {
count := a.readInt()
- atn.lexerActions = make([]LexerAction, count) // initIntArray(count, nil)
+ atn.lexerActions = make([]LexerAction, count)
- for i := 0; i < count; i++ {
+ for i := range atn.lexerActions {
actionType := a.readInt()
data1 := a.readInt()
-
- if data1 == 0xFFFF {
- data1 = -1
- }
-
data2 := a.readInt()
-
- if data2 == 0xFFFF {
- data2 = -1
- }
-
- lexerAction := a.lexerActionFactory(actionType, data1, data2)
-
- atn.lexerActions[i] = lexerAction
+ atn.lexerActions[i] = a.lexerActionFactory(actionType, data1, data2)
}
}
}
@@ -565,14 +468,12 @@ func (a *ATNDeserializer) markPrecedenceDecisions(atn *ATN) {
}
func (a *ATNDeserializer) verifyATN(atn *ATN) {
- if !a.deserializationOptions.verifyATN {
+ if !a.options.VerifyATN() {
return
}
// Verify assumptions
- for i := 0; i < len(atn.states); i++ {
- state := atn.states[i]
-
+ for _, state := range atn.states {
if state == nil {
continue
}
@@ -587,18 +488,18 @@ func (a *ATNDeserializer) verifyATN(atn *ATN) {
a.checkCondition(s2.loopBackState != nil, "")
a.checkCondition(len(s2.GetTransitions()) == 2, "")
- switch s2 := state.(type) {
+ switch s2.transitions[0].getTarget().(type) {
case *StarBlockStartState:
- var _, ok2 = s2.GetTransitions()[1].getTarget().(*LoopEndState)
+ _, ok := s2.transitions[1].getTarget().(*LoopEndState)
- a.checkCondition(ok2, "")
+ a.checkCondition(ok, "")
a.checkCondition(!s2.nonGreedy, "")
case *LoopEndState:
- var s3, ok2 = s2.GetTransitions()[1].getTarget().(*StarBlockStartState)
+ var _, ok = s2.transitions[1].getTarget().(*StarBlockStartState)
- a.checkCondition(ok2, "")
- a.checkCondition(s3.nonGreedy, "")
+ a.checkCondition(ok, "")
+ a.checkCondition(s2.nonGreedy, "")
default:
panic("IllegalState")
@@ -607,9 +508,9 @@ func (a *ATNDeserializer) verifyATN(atn *ATN) {
case *StarLoopbackState:
a.checkCondition(len(state.GetTransitions()) == 1, "")
- var _, ok2 = state.GetTransitions()[0].getTarget().(*StarLoopEntryState)
+ var _, ok = state.GetTransitions()[0].getTarget().(*StarLoopEntryState)
- a.checkCondition(ok2, "")
+ a.checkCondition(ok, "")
case *LoopEndState:
a.checkCondition(s2.loopBackState != nil, "")
@@ -617,8 +518,8 @@ func (a *ATNDeserializer) verifyATN(atn *ATN) {
case *RuleStartState:
a.checkCondition(s2.stopState != nil, "")
- case *BaseBlockStartState:
- a.checkCondition(s2.endState != nil, "")
+ case BlockStartState:
+ a.checkCondition(s2.getEndState() != nil, "")
case *BlockEndState:
a.checkCondition(s2.startState != nil, "")
@@ -649,53 +550,7 @@ func (a *ATNDeserializer) readInt() int {
a.pos++
- return int(v)
-}
-
-func (a *ATNDeserializer) readInt32() int {
- var low = a.readInt()
- var high = a.readInt()
- return low | (high << 16)
-}
-
-//TODO
-//func (a *ATNDeserializer) readLong() int64 {
-// panic("Not implemented")
-// var low = a.readInt32()
-// var high = a.readInt32()
-// return (low & 0x00000000FFFFFFFF) | (high << int32)
-//}
-
-func createByteToHex() []string {
- bth := make([]string, 256)
-
- for i := 0; i < 256; i++ {
- bth[i] = strings.ToUpper(hex.EncodeToString([]byte{byte(i)}))
- }
-
- return bth
-}
-
-var byteToHex = createByteToHex()
-
-func (a *ATNDeserializer) readUUID() string {
- bb := make([]int, 16)
-
- for i := 7; i >= 0; i-- {
- integer := a.readInt()
-
- bb[(2*i)+1] = integer & 0xFF
- bb[2*i] = (integer >> 8) & 0xFF
- }
-
- return byteToHex[bb[0]] + byteToHex[bb[1]] +
- byteToHex[bb[2]] + byteToHex[bb[3]] + "-" +
- byteToHex[bb[4]] + byteToHex[bb[5]] + "-" +
- byteToHex[bb[6]] + byteToHex[bb[7]] + "-" +
- byteToHex[bb[8]] + byteToHex[bb[9]] + "-" +
- byteToHex[bb[10]] + byteToHex[bb[11]] +
- byteToHex[bb[12]] + byteToHex[bb[13]] +
- byteToHex[bb[14]] + byteToHex[bb[15]]
+ return int(v) // data is 32 bits but int is at least that big
}
func (a *ATNDeserializer) edgeFactory(atn *ATN, typeIndex, src, trg, arg1, arg2, arg3 int, sets []*IntervalSet) Transition {
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_state.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_state.go
index 563d5db38d4..3835bb2e931 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_state.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn_state.go
@@ -243,6 +243,8 @@ func NewBasicBlockStartState() *BasicBlockStartState {
return &BasicBlockStartState{BaseBlockStartState: b}
}
+var _ BlockStartState = &BasicBlockStartState{}
+
// BlockEndState is a terminal node of a simple (a|b|c) block.
type BlockEndState struct {
*BaseATNState
@@ -318,6 +320,8 @@ func NewPlusBlockStartState() *PlusBlockStartState {
return &PlusBlockStartState{BaseBlockStartState: b}
}
+var _ BlockStartState = &PlusBlockStartState{}
+
// StarBlockStartState is the block that begins a closure loop.
type StarBlockStartState struct {
*BaseBlockStartState
@@ -331,6 +335,8 @@ func NewStarBlockStartState() *StarBlockStartState {
return &StarBlockStartState{BaseBlockStartState: b}
}
+var _ BlockStartState = &StarBlockStartState{}
+
type StarLoopbackState struct {
*BaseATNState
}
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa.go
index 770c32a6bb5..d55a2a87d5d 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa.go
@@ -6,7 +6,6 @@ package antlr
import (
"sort"
- "sync"
)
type DFA struct {
@@ -18,23 +17,27 @@ type DFA struct {
// states is all the DFA states. Use Map to get the old state back; Set can only
// indicate whether it is there.
states map[int]*DFAState
- statesMu sync.RWMutex
s0 *DFAState
- s0Mu sync.RWMutex
// precedenceDfa is the backing field for isPrecedenceDfa and setPrecedenceDfa.
// True if the DFA is for a precedence decision and false otherwise.
precedenceDfa bool
- precedenceDfaMu sync.RWMutex
}
func NewDFA(atnStartState DecisionState, decision int) *DFA {
- return &DFA{
+ dfa := &DFA{
atnStartState: atnStartState,
decision: decision,
states: make(map[int]*DFAState),
}
+ if s, ok := atnStartState.(*StarLoopEntryState); ok && s.precedenceRuleDecision {
+ dfa.precedenceDfa = true
+ dfa.s0 = NewDFAState(-1, NewBaseATNConfigSet(false))
+ dfa.s0.isAcceptState = false
+ dfa.s0.requiresFullContext = false
+ }
+ return dfa
}
// getPrecedenceStartState gets the start state for the current precedence and
@@ -79,8 +82,6 @@ func (d *DFA) setPrecedenceStartState(precedence int, startState *DFAState) {
}
func (d *DFA) getPrecedenceDfa() bool {
- d.precedenceDfaMu.RLock()
- defer d.precedenceDfaMu.RUnlock()
return d.precedenceDfa
}
@@ -104,46 +105,32 @@ func (d *DFA) setPrecedenceDfa(precedenceDfa bool) {
d.setS0(nil)
}
- d.precedenceDfaMu.Lock()
- defer d.precedenceDfaMu.Unlock()
d.precedenceDfa = precedenceDfa
}
}
func (d *DFA) getS0() *DFAState {
- d.s0Mu.RLock()
- defer d.s0Mu.RUnlock()
return d.s0
}
func (d *DFA) setS0(s *DFAState) {
- d.s0Mu.Lock()
- defer d.s0Mu.Unlock()
d.s0 = s
}
func (d *DFA) getState(hash int) (*DFAState, bool) {
- d.statesMu.RLock()
- defer d.statesMu.RUnlock()
s, ok := d.states[hash]
return s, ok
}
func (d *DFA) setStates(states map[int]*DFAState) {
- d.statesMu.Lock()
- defer d.statesMu.Unlock()
d.states = states
}
func (d *DFA) setState(hash int, state *DFAState) {
- d.statesMu.Lock()
- defer d.statesMu.Unlock()
d.states[hash] = state
}
func (d *DFA) numStates() int {
- d.statesMu.RLock()
- defer d.statesMu.RUnlock()
return len(d.states)
}
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa_serializer.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa_serializer.go
index fcfef975c2e..bf2ccc06cd1 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa_serializer.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa_serializer.go
@@ -7,6 +7,7 @@ package antlr
import (
"fmt"
"strconv"
+ "strings"
)
// DFASerializer is a DFA walker that knows how to dump them to serialized
@@ -112,7 +113,12 @@ func NewLexerDFASerializer(dfa *DFA) *LexerDFASerializer {
}
func (l *LexerDFASerializer) getEdgeLabel(i int) string {
- return "'" + string(i) + "'"
+ var sb strings.Builder
+ sb.Grow(6)
+ sb.WriteByte('\'')
+ sb.WriteRune(rune(i))
+ sb.WriteByte('\'')
+ return sb.String()
}
func (l *LexerDFASerializer) String() string {
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa_state.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa_state.go
index 680ce9ace4a..970ed19865a 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa_state.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa_state.go
@@ -6,7 +6,6 @@ package antlr
import (
"fmt"
- "sync"
)
// PredPrediction maps a predicate to a predicted alternative.
@@ -51,7 +50,6 @@ type DFAState struct {
// edges elements point to the target of the symbol. Shift up by 1 so (-1)
// Token.EOF maps to the first element.
edges []*DFAState
- edgesMu sync.RWMutex
isAcceptState bool
@@ -92,16 +90,16 @@ func NewDFAState(stateNumber int, configs ATNConfigSet) *DFAState {
}
// GetAltSet gets the set of all alts mentioned by all ATN configurations in d.
-func (d *DFAState) GetAltSet() *Set {
- alts := NewSet(nil, nil)
+func (d *DFAState) GetAltSet() Set {
+ alts := newArray2DHashSet(nil, nil)
if d.configs != nil {
for _, c := range d.configs.GetItems() {
- alts.add(c.GetAlt())
+ alts.Add(c.GetAlt())
}
}
- if alts.length() == 0 {
+ if alts.Len() == 0 {
return nil
}
@@ -109,32 +107,22 @@ func (d *DFAState) GetAltSet() *Set {
}
func (d *DFAState) getEdges() []*DFAState {
- d.edgesMu.RLock()
- defer d.edgesMu.RUnlock()
return d.edges
}
func (d *DFAState) numEdges() int {
- d.edgesMu.RLock()
- defer d.edgesMu.RUnlock()
return len(d.edges)
}
func (d *DFAState) getIthEdge(i int) *DFAState {
- d.edgesMu.RLock()
- defer d.edgesMu.RUnlock()
return d.edges[i]
}
func (d *DFAState) setEdges(newEdges []*DFAState) {
- d.edgesMu.Lock()
- defer d.edgesMu.Unlock()
d.edges = newEdges
}
func (d *DFAState) setIthEdge(i int, edge *DFAState) {
- d.edgesMu.Lock()
- defer d.edgesMu.Unlock()
d.edges[i] = edge
}
@@ -173,26 +161,11 @@ func (d *DFAState) String() string {
}
}
- return fmt.Sprintf("%d:%s%s", fmt.Sprint(d.configs), s)
+ return fmt.Sprintf("%d:%s%s", d.stateNumber, fmt.Sprint(d.configs), s)
}
func (d *DFAState) hash() int {
- h := murmurInit(11)
-
- c := 1
- if d.isAcceptState {
- if d.predicates != nil {
- for _, p := range d.predicates {
- h = murmurUpdate(h, p.alt)
- h = murmurUpdate(h, p.pred.hash())
- c += 2
- }
- } else {
- h = murmurUpdate(h, d.prediction)
- c += 1
- }
- }
-
+ h := murmurInit(7)
h = murmurUpdate(h, d.configs.hash())
- return murmurFinish(h, c)
-}
\ No newline at end of file
+ return murmurFinish(h, 1)
+}
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/error_strategy.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/error_strategy.go
index 977a6e45496..c4080dbfd18 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/error_strategy.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/error_strategy.go
@@ -16,7 +16,7 @@ type ErrorStrategy interface {
RecoverInline(Parser) Token
Recover(Parser, RecognitionException)
Sync(Parser)
- inErrorRecoveryMode(Parser) bool
+ InErrorRecoveryMode(Parser) bool
ReportError(Parser, RecognitionException)
ReportMatch(Parser)
}
@@ -40,7 +40,7 @@ func NewDefaultErrorStrategy() *DefaultErrorStrategy {
// error". This is used to suppress Reporting multiple error messages while
// attempting to recover from a detected syntax error.
//
- // @see //inErrorRecoveryMode
+ // @see //InErrorRecoveryMode
//
d.errorRecoveryMode = false
@@ -71,7 +71,7 @@ func (d *DefaultErrorStrategy) beginErrorCondition(recognizer Parser) {
d.errorRecoveryMode = true
}
-func (d *DefaultErrorStrategy) inErrorRecoveryMode(recognizer Parser) bool {
+func (d *DefaultErrorStrategy) InErrorRecoveryMode(recognizer Parser) bool {
return d.errorRecoveryMode
}
@@ -118,7 +118,7 @@ func (d *DefaultErrorStrategy) ReportMatch(recognizer Parser) {
func (d *DefaultErrorStrategy) ReportError(recognizer Parser, e RecognitionException) {
// if we've already Reported an error and have not Matched a token
// yet successfully, don't Report any errors.
- if d.inErrorRecoveryMode(recognizer) {
+ if d.InErrorRecoveryMode(recognizer) {
return // don't Report spurious errors
}
d.beginErrorCondition(recognizer)
@@ -209,7 +209,7 @@ func (d *DefaultErrorStrategy) Recover(recognizer Parser, e RecognitionException
//
func (d *DefaultErrorStrategy) Sync(recognizer Parser) {
// If already recovering, don't try to Sync
- if d.inErrorRecoveryMode(recognizer) {
+ if d.InErrorRecoveryMode(recognizer) {
return
}
@@ -312,7 +312,7 @@ func (d *DefaultErrorStrategy) ReportFailedPredicate(recognizer Parser, e *Faile
// @param recognizer the parser instance
//
func (d *DefaultErrorStrategy) ReportUnwantedToken(recognizer Parser) {
- if d.inErrorRecoveryMode(recognizer) {
+ if d.InErrorRecoveryMode(recognizer) {
return
}
d.beginErrorCondition(recognizer)
@@ -341,7 +341,7 @@ func (d *DefaultErrorStrategy) ReportUnwantedToken(recognizer Parser) {
// @param recognizer the parser instance
//
func (d *DefaultErrorStrategy) ReportMissingToken(recognizer Parser) {
- if d.inErrorRecoveryMode(recognizer) {
+ if d.InErrorRecoveryMode(recognizer) {
return
}
d.beginErrorCondition(recognizer)
@@ -738,7 +738,11 @@ func (b *BailErrorStrategy) Recover(recognizer Parser, e RecognitionException) {
context := recognizer.GetParserRuleContext()
for context != nil {
context.SetException(e)
- context = context.GetParent().(ParserRuleContext)
+ if parent, ok := context.GetParent().(ParserRuleContext); ok {
+ context = parent
+ } else {
+ context = nil
+ }
}
panic(NewParseCancellationException()) // TODO we don't emit e properly
}
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/interval_set.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/interval_set.go
index 510d9091141..1e9393adb60 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/interval_set.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/interval_set.go
@@ -226,16 +226,28 @@ func (i *IntervalSet) StringVerbose(literalNames []string, symbolicNames []strin
func (i *IntervalSet) toCharString() string {
names := make([]string, len(i.intervals))
+ var sb strings.Builder
+
for j := 0; j < len(i.intervals); j++ {
v := i.intervals[j]
if v.Stop == v.Start+1 {
if v.Start == TokenEOF {
names = append(names, "")
} else {
- names = append(names, ("'" + string(v.Start) + "'"))
+ sb.WriteByte('\'')
+ sb.WriteRune(rune(v.Start))
+ sb.WriteByte('\'')
+ names = append(names, sb.String())
+ sb.Reset()
}
} else {
- names = append(names, "'"+string(v.Start)+"'..'"+string(v.Stop-1)+"'")
+ sb.WriteByte('\'')
+ sb.WriteRune(rune(v.Start))
+ sb.WriteString("'..'")
+ sb.WriteRune(rune(v.Stop - 1))
+ sb.WriteByte('\'')
+ names = append(names, sb.String())
+ sb.Reset()
}
}
if len(names) > 1 {
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/lexer_action.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/lexer_action.go
index 20df84f9437..5a325be1372 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/lexer_action.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/lexer_action.go
@@ -414,10 +414,9 @@ func (l *LexerIndexedCustomAction) execute(lexer Lexer) {
func (l *LexerIndexedCustomAction) hash() int {
h := murmurInit(0)
- h = murmurUpdate(h, l.actionType)
h = murmurUpdate(h, l.offset)
h = murmurUpdate(h, l.lexerAction.hash())
- return murmurFinish(h, 3)
+ return murmurFinish(h, 2)
}
func (l *LexerIndexedCustomAction) equals(other LexerAction) bool {
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/lexer_action_executor.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/lexer_action_executor.go
index 80b949a1a54..056941dd6e7 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/lexer_action_executor.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/lexer_action_executor.go
@@ -161,10 +161,13 @@ func (l *LexerActionExecutor) hash() int {
func (l *LexerActionExecutor) equals(other interface{}) bool {
if l == other {
return true
- } else if _, ok := other.(*LexerActionExecutor); !ok {
+ }
+ othert, ok := other.(*LexerActionExecutor)
+ if !ok {
+ return false
+ }
+ if othert == nil {
return false
- } else {
- return l.cachedHash == other.(*LexerActionExecutor).cachedHash &&
- &l.lexerActions == &other.(*LexerActionExecutor).lexerActions
}
+ return l.cachedHash == othert.cachedHash && &l.lexerActions == &othert.lexerActions
}
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/lexer_atn_simulator.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/lexer_atn_simulator.go
index 32d69e1b87c..dc05153ea44 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/lexer_atn_simulator.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/lexer_atn_simulator.go
@@ -7,6 +7,7 @@ package antlr
import (
"fmt"
"strconv"
+ "strings"
)
var (
@@ -90,11 +91,16 @@ func (l *LexerATNSimulator) Match(input CharStream, mode int) int {
dfa := l.decisionToDFA[mode]
- if dfa.getS0() == nil {
+ var s0 *DFAState
+ l.atn.stateMu.RLock()
+ s0 = dfa.getS0()
+ l.atn.stateMu.RUnlock()
+
+ if s0 == nil {
return l.MatchATN(input)
}
- return l.execATN(input, dfa.getS0())
+ return l.execATN(input, s0)
}
func (l *LexerATNSimulator) reset() {
@@ -116,11 +122,7 @@ func (l *LexerATNSimulator) MatchATN(input CharStream) int {
suppressEdge := s0Closure.hasSemanticContext
s0Closure.hasSemanticContext = false
- next := l.addDFAState(s0Closure)
-
- if !suppressEdge {
- l.decisionToDFA[l.mode].setS0(next)
- }
+ next := l.addDFAState(s0Closure, suppressEdge)
predict := l.execATN(input, next)
@@ -202,11 +204,16 @@ func (l *LexerATNSimulator) execATN(input CharStream, ds0 *DFAState) int {
// {@code t}, or {@code nil} if the target state for l edge is not
// already cached
func (l *LexerATNSimulator) getExistingTargetState(s *DFAState, t int) *DFAState {
- if s.getEdges() == nil || t < LexerATNSimulatorMinDFAEdge || t > LexerATNSimulatorMaxDFAEdge {
+ if t < LexerATNSimulatorMinDFAEdge || t > LexerATNSimulatorMaxDFAEdge {
return nil
}
- target := s.getIthEdge(t-LexerATNSimulatorMinDFAEdge)
+ l.atn.edgeMu.RLock()
+ defer l.atn.edgeMu.RUnlock()
+ if s.getEdges() == nil {
+ return nil
+ }
+ target := s.getIthEdge(t - LexerATNSimulatorMinDFAEdge)
if LexerATNSimulatorDebug && target != nil {
fmt.Println("reuse state " + strconv.Itoa(s.stateNumber) + " edge to " + strconv.Itoa(target.stateNumber))
}
@@ -299,7 +306,7 @@ func (l *LexerATNSimulator) getReachableConfigSet(input CharStream, closure ATNC
func (l *LexerATNSimulator) accept(input CharStream, lexerActionExecutor *LexerActionExecutor, startIndex, index, line, charPos int) {
if LexerATNSimulatorDebug {
- fmt.Printf("ACTION %s\n", lexerActionExecutor)
+ fmt.Printf("ACTION %v\n", lexerActionExecutor)
}
// seek to after last char in token
input.Seek(index)
@@ -536,7 +543,7 @@ func (l *LexerATNSimulator) addDFAEdge(from *DFAState, tk int, to *DFAState, cfg
suppressEdge := cfgs.HasSemanticContext()
cfgs.SetHasSemanticContext(false)
- to = l.addDFAState(cfgs)
+ to = l.addDFAState(cfgs, true)
if suppressEdge {
return to
@@ -550,6 +557,8 @@ func (l *LexerATNSimulator) addDFAEdge(from *DFAState, tk int, to *DFAState, cfg
if LexerATNSimulatorDebug {
fmt.Println("EDGE " + from.String() + " -> " + to.String() + " upon " + strconv.Itoa(tk))
}
+ l.atn.edgeMu.Lock()
+ defer l.atn.edgeMu.Unlock()
if from.getEdges() == nil {
// make room for tokens 1..n and -1 masquerading as index 0
from.setEdges(make([]*DFAState, LexerATNSimulatorMaxDFAEdge-LexerATNSimulatorMinDFAEdge+1))
@@ -563,7 +572,7 @@ func (l *LexerATNSimulator) addDFAEdge(from *DFAState, tk int, to *DFAState, cfg
// configurations already. This method also detects the first
// configuration containing an ATN rule stop state. Later, when
// traversing the DFA, we will know which rule to accept.
-func (l *LexerATNSimulator) addDFAState(configs ATNConfigSet) *DFAState {
+func (l *LexerATNSimulator) addDFAState(configs ATNConfigSet, suppressEdge bool) *DFAState {
proposed := NewDFAState(-1, configs)
var firstConfigWithRuleStopState ATNConfig
@@ -584,16 +593,22 @@ func (l *LexerATNSimulator) addDFAState(configs ATNConfigSet) *DFAState {
}
hash := proposed.hash()
dfa := l.decisionToDFA[l.mode]
+
+ l.atn.stateMu.Lock()
+ defer l.atn.stateMu.Unlock()
existing, ok := dfa.getState(hash)
if ok {
- return existing
- }
- newState := proposed
- newState.stateNumber = dfa.numStates()
- configs.SetReadOnly(true)
- newState.configs = configs
- dfa.setState(hash, newState)
- return newState
+ proposed = existing
+ } else {
+ proposed.stateNumber = dfa.numStates()
+ configs.SetReadOnly(true)
+ proposed.configs = configs
+ dfa.setState(hash, proposed)
+ }
+ if !suppressEdge {
+ dfa.setS0(proposed)
+ }
+ return proposed
}
func (l *LexerATNSimulator) getDFA(mode int) *DFA {
@@ -630,7 +645,13 @@ func (l *LexerATNSimulator) GetTokenName(tt int) string {
return "EOF"
}
- return "'" + string(tt) + "'"
+ var sb strings.Builder
+ sb.Grow(6)
+ sb.WriteByte('\'')
+ sb.WriteRune(rune(tt))
+ sb.WriteByte('\'')
+
+ return sb.String()
}
func resetSimState(sim *SimState) {
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/ll1_analyzer.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/ll1_analyzer.go
index 3ebc40a76b8..6ffb37de694 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/ll1_analyzer.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/ll1_analyzer.go
@@ -38,7 +38,7 @@ func (la *LL1Analyzer) getDecisionLookahead(s ATNState) []*IntervalSet {
look := make([]*IntervalSet, count)
for alt := 0; alt < count; alt++ {
look[alt] = NewIntervalSet()
- lookBusy := NewSet(nil, nil)
+ lookBusy := newArray2DHashSet(nil, nil)
seeThruPreds := false // fail to get lookahead upon pred
la.look1(s.GetTransitions()[alt].getTarget(), nil, BasePredictionContextEMPTY, look[alt], lookBusy, NewBitSet(), seeThruPreds, false)
// Wipe out lookahead for la alternative if we found nothing
@@ -75,7 +75,7 @@ func (la *LL1Analyzer) Look(s, stopState ATNState, ctx RuleContext) *IntervalSet
if ctx != nil {
lookContext = predictionContextFromRuleContext(s.GetATN(), ctx)
}
- la.look1(s, stopState, lookContext, r, NewSet(nil, nil), NewBitSet(), seeThruPreds, true)
+ la.look1(s, stopState, lookContext, r, newArray2DHashSet(nil, nil), NewBitSet(), seeThruPreds, true)
return r
}
@@ -109,22 +109,22 @@ func (la *LL1Analyzer) Look(s, stopState ATNState, ctx RuleContext) *IntervalSet
// outermost context is reached. This parameter has no effect if {@code ctx}
// is {@code nil}.
-func (la *LL1Analyzer) look2(s, stopState ATNState, ctx PredictionContext, look *IntervalSet, lookBusy *Set, calledRuleStack *BitSet, seeThruPreds, addEOF bool, i int) {
+func (la *LL1Analyzer) look2(s, stopState ATNState, ctx PredictionContext, look *IntervalSet, lookBusy Set, calledRuleStack *BitSet, seeThruPreds, addEOF bool, i int) {
returnState := la.atn.states[ctx.getReturnState(i)]
la.look1(returnState, stopState, ctx.GetParent(i), look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
}
-func (la *LL1Analyzer) look1(s, stopState ATNState, ctx PredictionContext, look *IntervalSet, lookBusy *Set, calledRuleStack *BitSet, seeThruPreds, addEOF bool) {
+func (la *LL1Analyzer) look1(s, stopState ATNState, ctx PredictionContext, look *IntervalSet, lookBusy Set, calledRuleStack *BitSet, seeThruPreds, addEOF bool) {
c := NewBaseATNConfig6(s, 0, ctx)
- if lookBusy.contains(c) {
+ if lookBusy.Contains(c) {
return
}
- lookBusy.add(c)
+ lookBusy.Add(c)
if s == stopState {
if ctx == nil {
@@ -148,13 +148,13 @@ func (la *LL1Analyzer) look1(s, stopState ATNState, ctx PredictionContext, look
}
if ctx != BasePredictionContextEMPTY {
- removed := calledRuleStack.contains(s.GetRuleIndex())
- defer func() {
- if removed {
- calledRuleStack.add(s.GetRuleIndex())
- }
- }()
- calledRuleStack.remove(s.GetRuleIndex())
+ removed := calledRuleStack.contains(s.GetRuleIndex())
+ defer func() {
+ if removed {
+ calledRuleStack.add(s.GetRuleIndex())
+ }
+ }()
+ calledRuleStack.remove(s.GetRuleIndex())
// run thru all possible stack tops in ctx
for i := 0; i < ctx.length(); i++ {
returnState := la.atn.states[ctx.getReturnState(i)]
@@ -198,7 +198,7 @@ func (la *LL1Analyzer) look1(s, stopState ATNState, ctx PredictionContext, look
}
}
-func (la *LL1Analyzer) look3(stopState ATNState, ctx PredictionContext, look *IntervalSet, lookBusy *Set, calledRuleStack *BitSet, seeThruPreds, addEOF bool, t1 *RuleTransition) {
+func (la *LL1Analyzer) look3(stopState ATNState, ctx PredictionContext, look *IntervalSet, lookBusy Set, calledRuleStack *BitSet, seeThruPreds, addEOF bool, t1 *RuleTransition) {
newContext := SingletonBasePredictionContextCreate(ctx, t1.followState.GetStateNumber())
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/parser.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/parser.go
index fb60258e331..2ab2f560521 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/parser.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/parser.go
@@ -425,7 +425,7 @@ func (p *BaseParser) Consume() Token {
}
hasListener := p.parseListeners != nil && len(p.parseListeners) > 0
if p.BuildParseTrees || hasListener {
- if p.errHandler.inErrorRecoveryMode(p) {
+ if p.errHandler.InErrorRecoveryMode(p) {
node := p.ctx.AddErrorNode(o)
if p.parseListeners != nil {
for _, l := range p.parseListeners {
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/parser_atn_simulator.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/parser_atn_simulator.go
index c83e8137b6c..888d512975a 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/parser_atn_simulator.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/parser_atn_simulator.go
@@ -15,6 +15,7 @@ var (
ParserATNSimulatorListATNDecisions = false
ParserATNSimulatorDFADebug = false
ParserATNSimulatorRetryDebug = false
+ TurnOffLRLoopEntryBranchOpt = false
)
type ParserATNSimulator struct {
@@ -95,14 +96,18 @@ func (p *ParserATNSimulator) AdaptivePredict(input TokenStream, decision int, ou
// Now we are certain to have a specific decision's DFA
// But, do we still need an initial state?
var s0 *DFAState
+ p.atn.stateMu.RLock()
if dfa.getPrecedenceDfa() {
+ p.atn.edgeMu.RLock()
// the start state for a precedence DFA depends on the current
// parser precedence, and is provided by a DFA method.
s0 = dfa.getPrecedenceStartState(p.parser.GetPrecedence())
+ p.atn.edgeMu.RUnlock()
} else {
// the start state for a "regular" DFA is just s0
s0 = dfa.getS0()
}
+ p.atn.stateMu.RUnlock()
if s0 == nil {
if outerContext == nil {
@@ -113,21 +118,10 @@ func (p *ParserATNSimulator) AdaptivePredict(input TokenStream, decision int, ou
" exec LA(1)==" + p.getLookaheadName(input) +
", outerContext=" + outerContext.String(p.parser.GetRuleNames(), nil))
}
- // If p is not a precedence DFA, we check the ATN start state
- // to determine if p ATN start state is the decision for the
- // closure block that determines whether a precedence rule
- // should continue or complete.
-
- t2 := dfa.atnStartState
- t, ok := t2.(*StarLoopEntryState)
- if !dfa.getPrecedenceDfa() && ok {
- if t.precedenceRuleDecision {
- dfa.setPrecedenceDfa(true)
- }
- }
fullCtx := false
s0Closure := p.computeStartState(dfa.atnStartState, RuleContextEmpty, fullCtx)
+ p.atn.stateMu.Lock()
if dfa.getPrecedenceDfa() {
// If p is a precedence DFA, we use applyPrecedenceFilter
// to convert the computed start state to a precedence start
@@ -135,14 +129,19 @@ func (p *ParserATNSimulator) AdaptivePredict(input TokenStream, decision int, ou
// appropriate start state for the precedence level rather
// than simply setting DFA.s0.
//
+ dfa.s0.configs = s0Closure
s0Closure = p.applyPrecedenceFilter(s0Closure)
s0 = p.addDFAState(dfa, NewDFAState(-1, s0Closure))
+ p.atn.edgeMu.Lock()
dfa.setPrecedenceStartState(p.parser.GetPrecedence(), s0)
+ p.atn.edgeMu.Unlock()
} else {
s0 = p.addDFAState(dfa, NewDFAState(-1, s0Closure))
dfa.setS0(s0)
}
+ p.atn.stateMu.Unlock()
}
+
alt := p.execATN(dfa, s0, input, index, outerContext)
if ParserATNSimulatorDebug {
fmt.Println("DFA after predictATN: " + dfa.String(p.parser.GetLiteralNames(), nil))
@@ -259,11 +258,13 @@ func (p *ParserATNSimulator) execATN(dfa *DFA, s0 *DFAState, input TokenStream,
stopIndex := input.Index()
input.Seek(startIndex)
alts := p.evalSemanticContext(D.predicates, outerContext, true)
- if alts.length() == 0 {
+
+ switch alts.length() {
+ case 0:
panic(p.noViableAlt(input, outerContext, D.configs, startIndex))
- } else if alts.length() == 1 {
+ case 1:
return alts.minValue()
- } else {
+ default:
// Report ambiguity after predicate evaluation to make sure the correct set of ambig alts is Reported.
p.ReportAmbiguity(dfa, D, startIndex, stopIndex, false, alts, D.configs)
return alts.minValue()
@@ -291,12 +292,17 @@ func (p *ParserATNSimulator) execATN(dfa *DFA, s0 *DFAState, input TokenStream,
// already cached
func (p *ParserATNSimulator) getExistingTargetState(previousD *DFAState, t int) *DFAState {
- edges := previousD.getEdges()
- if edges == nil {
+ if t+1 < 0 {
return nil
}
- return previousD.getIthEdge(t+1)
+ p.atn.edgeMu.RLock()
+ defer p.atn.edgeMu.RUnlock()
+ edges := previousD.getEdges()
+ if edges == nil || t+1 >= len(edges) {
+ return nil
+ }
+ return previousD.getIthEdge(t + 1)
}
// Compute a target state for an edge in the DFA, and attempt to add the
@@ -422,7 +428,8 @@ func (p *ParserATNSimulator) execATNWithFullContext(dfa *DFA, D *DFAState, s0 AT
if reach.GetUniqueAlt() != ATNInvalidAltNumber {
predictedAlt = reach.GetUniqueAlt()
break
- } else if p.predictionMode != PredictionModeLLExactAmbigDetection {
+ }
+ if p.predictionMode != PredictionModeLLExactAmbigDetection {
predictedAlt = PredictionModeresolvesToJustOneViableAlt(altSubSets)
if predictedAlt != ATNInvalidAltNumber {
break
@@ -479,7 +486,7 @@ func (p *ParserATNSimulator) execATNWithFullContext(dfa *DFA, D *DFAState, s0 AT
// the fact that we should predict alternative 1. We just can't say for
// sure that there is an ambiguity without looking further.
- p.ReportAmbiguity(dfa, D, startIndex, input.Index(), foundExactAmbig, nil, reach)
+ p.ReportAmbiguity(dfa, D, startIndex, input.Index(), foundExactAmbig, reach.Alts(), reach)
return predictedAlt
}
@@ -503,7 +510,7 @@ func (p *ParserATNSimulator) computeReachSet(closure ATNConfigSet, t int, fullCt
// ensure that the alternative Matching the longest overall sequence is
// chosen when multiple such configurations can Match the input.
- var SkippedStopStates []*BaseATNConfig
+ var skippedStopStates []*BaseATNConfig
// First figure out where we can reach on input t
for _, c := range closure.GetItems() {
@@ -511,14 +518,9 @@ func (p *ParserATNSimulator) computeReachSet(closure ATNConfigSet, t int, fullCt
fmt.Println("testing " + p.GetTokenName(t) + " at " + c.String())
}
- _, ok := c.GetState().(*RuleStopState)
-
- if ok {
+ if _, ok := c.GetState().(*RuleStopState); ok {
if fullCtx || t == TokenEOF {
- if SkippedStopStates == nil {
- SkippedStopStates = make([]*BaseATNConfig, 0)
- }
- SkippedStopStates = append(SkippedStopStates, c.(*BaseATNConfig))
+ skippedStopStates = append(skippedStopStates, c.(*BaseATNConfig))
if ParserATNSimulatorDebug {
fmt.Println("added " + c.String() + " to SkippedStopStates")
}
@@ -526,8 +528,7 @@ func (p *ParserATNSimulator) computeReachSet(closure ATNConfigSet, t int, fullCt
continue
}
- for j := 0; j < len(c.GetState().GetTransitions()); j++ {
- trans := c.GetState().GetTransitions()[j]
+ for _, trans := range c.GetState().GetTransitions() {
target := p.getReachableTarget(trans, t)
if target != nil {
cfg := NewBaseATNConfig4(c, target)
@@ -538,6 +539,7 @@ func (p *ParserATNSimulator) computeReachSet(closure ATNConfigSet, t int, fullCt
}
}
}
+
// Now figure out where the reach operation can take us...
var reach ATNConfigSet
@@ -550,7 +552,7 @@ func (p *ParserATNSimulator) computeReachSet(closure ATNConfigSet, t int, fullCt
// condition is not true when one or more configurations have been
// withheld in SkippedStopStates, or when the current symbol is EOF.
//
- if SkippedStopStates == nil && t != TokenEOF {
+ if skippedStopStates == nil && t != TokenEOF {
if len(intermediate.configs) == 1 {
// Don't pursue the closure if there is just one state.
// It can only have one alternative just add to result
@@ -568,9 +570,10 @@ func (p *ParserATNSimulator) computeReachSet(closure ATNConfigSet, t int, fullCt
//
if reach == nil {
reach = NewBaseATNConfigSet(fullCtx)
- closureBusy := NewSet(nil, nil)
+ closureBusy := newArray2DHashSet(nil, nil)
treatEOFAsEpsilon := t == TokenEOF
- for k := 0; k < len(intermediate.configs); k++ {
+ amount := len(intermediate.configs)
+ for k := 0; k < amount; k++ {
p.closure(intermediate.configs[k], reach, closureBusy, false, fullCtx, treatEOFAsEpsilon)
}
}
@@ -602,9 +605,9 @@ func (p *ParserATNSimulator) computeReachSet(closure ATNConfigSet, t int, fullCt
// chooses an alternative Matching the longest overall sequence when
// multiple alternatives are viable.
//
- if SkippedStopStates != nil && ((!fullCtx) || (!PredictionModehasConfigInRuleStopState(reach))) {
- for l := 0; l < len(SkippedStopStates); l++ {
- reach.Add(SkippedStopStates[l], p.mergeCache)
+ if skippedStopStates != nil && ((!fullCtx) || (!PredictionModehasConfigInRuleStopState(reach))) {
+ for l := 0; l < len(skippedStopStates); l++ {
+ reach.Add(skippedStopStates[l], p.mergeCache)
}
}
if len(reach.GetItems()) == 0 {
@@ -640,10 +643,7 @@ func (p *ParserATNSimulator) removeAllConfigsNotInRuleStopState(configs ATNConfi
}
result := NewBaseATNConfigSet(configs.FullContext())
for _, config := range configs.GetItems() {
-
- _, ok := config.GetState().(*RuleStopState)
-
- if ok {
+ if _, ok := config.GetState().(*RuleStopState); ok {
result.Add(config, p.mergeCache)
continue
}
@@ -665,7 +665,7 @@ func (p *ParserATNSimulator) computeStartState(a ATNState, ctx RuleContext, full
for i := 0; i < len(a.GetTransitions()); i++ {
target := a.GetTransitions()[i].getTarget()
c := NewBaseATNConfig6(target, i+1, initialContext)
- closureBusy := NewSet(nil, nil)
+ closureBusy := newArray2DHashSet(nil, nil)
p.closure(c, configs, closureBusy, true, fullCtx, false)
}
return configs
@@ -787,7 +787,7 @@ func (p *ParserATNSimulator) getPredsForAmbigAlts(ambigAlts *BitSet, configs ATN
}
}
nPredAlts := 0
- for i := 1; i < nalts+1; i++ {
+ for i := 1; i <= nalts; i++ {
pred := altToPred[i]
if pred == nil {
altToPred[i] = SemanticContextNone
@@ -972,14 +972,13 @@ func (p *ParserATNSimulator) evalSemanticContext(predPredictions []*PredPredicti
return predictions
}
-func (p *ParserATNSimulator) closure(config ATNConfig, configs ATNConfigSet, closureBusy *Set, collectPredicates, fullCtx, treatEOFAsEpsilon bool) {
+func (p *ParserATNSimulator) closure(config ATNConfig, configs ATNConfigSet, closureBusy Set, collectPredicates, fullCtx, treatEOFAsEpsilon bool) {
initialDepth := 0
p.closureCheckingStopState(config, configs, closureBusy, collectPredicates,
fullCtx, initialDepth, treatEOFAsEpsilon)
}
-func (p *ParserATNSimulator) closureCheckingStopState(config ATNConfig, configs ATNConfigSet, closureBusy *Set, collectPredicates, fullCtx bool, depth int, treatEOFAsEpsilon bool) {
-
+func (p *ParserATNSimulator) closureCheckingStopState(config ATNConfig, configs ATNConfigSet, closureBusy Set, collectPredicates, fullCtx bool, depth int, treatEOFAsEpsilon bool) {
if ParserATNSimulatorDebug {
fmt.Println("closure(" + config.String() + ")")
fmt.Println("configs(" + configs.String() + ")")
@@ -988,8 +987,7 @@ func (p *ParserATNSimulator) closureCheckingStopState(config ATNConfig, configs
}
}
- _, ok := config.GetState().(*RuleStopState)
- if ok {
+ if _, ok := config.GetState().(*RuleStopState); ok {
// We hit rule end. If we have context info, use it
// run thru all possible stack tops in ctx
if !config.GetContext().isEmpty() {
@@ -1033,7 +1031,7 @@ func (p *ParserATNSimulator) closureCheckingStopState(config ATNConfig, configs
}
// Do the actual work of walking epsilon edges//
-func (p *ParserATNSimulator) closureWork(config ATNConfig, configs ATNConfigSet, closureBusy *Set, collectPredicates, fullCtx bool, depth int, treatEOFAsEpsilon bool) {
+func (p *ParserATNSimulator) closureWork(config ATNConfig, configs ATNConfigSet, closureBusy Set, collectPredicates, fullCtx bool, depth int, treatEOFAsEpsilon bool) {
state := config.GetState()
// optimization
if !state.GetEpsilonOnlyTransitions() {
@@ -1042,30 +1040,24 @@ func (p *ParserATNSimulator) closureWork(config ATNConfig, configs ATNConfigSet,
// both epsilon transitions and non-epsilon transitions.
}
for i := 0; i < len(state.GetTransitions()); i++ {
+ if i == 0 && p.canDropLoopEntryEdgeInLeftRecursiveRule(config) {
+ continue
+ }
+
t := state.GetTransitions()[i]
_, ok := t.(*ActionTransition)
continueCollecting := collectPredicates && !ok
c := p.getEpsilonTarget(config, t, continueCollecting, depth == 0, fullCtx, treatEOFAsEpsilon)
if ci, ok := c.(*BaseATNConfig); ok && ci != nil {
- if !t.getIsEpsilon() && closureBusy.add(c) != c {
- // avoid infinite recursion for EOF* and EOF+
- continue
- }
newDepth := depth
if _, ok := config.GetState().(*RuleStopState); ok {
-
// target fell off end of rule mark resulting c as having dipped into outer context
// We can't get here if incoming config was rule stop and we had context
// track how far we dip into outer context. Might
// come in handy and we avoid evaluating context dependent
// preds if p is > 0.
- if closureBusy.add(c) != c {
- // avoid infinite recursion for right-recursive rules
- continue
- }
-
if p.dfa != nil && p.dfa.getPrecedenceDfa() {
if t.(*EpsilonTransition).outermostPrecedenceReturn == p.dfa.atnStartState.GetRuleIndex() {
c.setPrecedenceFilterSuppressed(true)
@@ -1073,15 +1065,27 @@ func (p *ParserATNSimulator) closureWork(config ATNConfig, configs ATNConfigSet,
}
c.SetReachesIntoOuterContext(c.GetReachesIntoOuterContext() + 1)
+
+ if closureBusy.Add(c) != c {
+ // avoid infinite recursion for right-recursive rules
+ continue
+ }
+
configs.SetDipsIntoOuterContext(true) // TODO: can remove? only care when we add to set per middle of p method
newDepth--
if ParserATNSimulatorDebug {
fmt.Println("dips into outer ctx: " + c.String())
}
- } else if _, ok := t.(*RuleTransition); ok {
- // latch when newDepth goes negative - once we step out of the entry context we can't return
- if newDepth >= 0 {
- newDepth++
+ } else {
+ if !t.getIsEpsilon() && closureBusy.Add(c) != c {
+ // avoid infinite recursion for EOF* and EOF+
+ continue
+ }
+ if _, ok := t.(*RuleTransition); ok {
+ // latch when newDepth goes negative - once we step out of the entry context we can't return
+ if newDepth >= 0 {
+ newDepth++
+ }
}
}
p.closureCheckingStopState(c, configs, closureBusy, continueCollecting, fullCtx, newDepth, treatEOFAsEpsilon)
@@ -1089,12 +1093,93 @@ func (p *ParserATNSimulator) closureWork(config ATNConfig, configs ATNConfigSet,
}
}
+func (p *ParserATNSimulator) canDropLoopEntryEdgeInLeftRecursiveRule(config ATNConfig) bool {
+ if TurnOffLRLoopEntryBranchOpt {
+ return false
+ }
+
+ _p := config.GetState()
+
+ // First check to see if we are in StarLoopEntryState generated during
+ // left-recursion elimination. For efficiency, also check if
+ // the context has an empty stack case. If so, it would mean
+ // global FOLLOW so we can't perform optimization
+ if startLoop, ok := _p.(StarLoopEntryState); !ok || !startLoop.precedenceRuleDecision || config.GetContext().isEmpty() || config.GetContext().hasEmptyPath() {
+ return false
+ }
+
+ // Require all return states to return back to the same rule
+ // that p is in.
+ numCtxs := config.GetContext().length()
+ for i := 0; i < numCtxs; i++ {
+ returnState := p.atn.states[config.GetContext().getReturnState(i)]
+ if returnState.GetRuleIndex() != _p.GetRuleIndex() {
+ return false
+ }
+ }
+
+ decisionStartState := _p.(BlockStartState).GetTransitions()[0].getTarget().(BlockStartState)
+ blockEndStateNum := decisionStartState.getEndState().stateNumber
+ blockEndState := p.atn.states[blockEndStateNum].(*BlockEndState)
+
+ // Verify that the top of each stack context leads to loop entry/exit
+ // state through epsilon edges and w/o leaving rule.
+
+ for i := 0; i < numCtxs; i++ { // for each stack context
+ returnStateNumber := config.GetContext().getReturnState(i)
+ returnState := p.atn.states[returnStateNumber]
+
+ // all states must have single outgoing epsilon edge
+ if len(returnState.GetTransitions()) != 1 || !returnState.GetTransitions()[0].getIsEpsilon() {
+ return false
+ }
+
+ // Look for prefix op case like 'not expr', (' type ')' expr
+ returnStateTarget := returnState.GetTransitions()[0].getTarget()
+ if returnState.GetStateType() == ATNStateBlockEnd && returnStateTarget == _p {
+ continue
+ }
+
+ // Look for 'expr op expr' or case where expr's return state is block end
+ // of (...)* internal block; the block end points to loop back
+ // which points to p but we don't need to check that
+ if returnState == blockEndState {
+ continue
+ }
+
+ // Look for ternary expr ? expr : expr. The return state points at block end,
+ // which points at loop entry state
+ if returnStateTarget == blockEndState {
+ continue
+ }
+
+ // Look for complex prefix 'between expr and expr' case where 2nd expr's
+ // return state points at block end state of (...)* internal block
+ if returnStateTarget.GetStateType() == ATNStateBlockEnd &&
+ len(returnStateTarget.GetTransitions()) == 1 &&
+ returnStateTarget.GetTransitions()[0].getIsEpsilon() &&
+ returnStateTarget.GetTransitions()[0].getTarget() == _p {
+ continue
+ }
+
+ // anything else ain't conforming
+ return false
+ }
+
+ return true
+}
+
func (p *ParserATNSimulator) getRuleName(index int) string {
if p.parser != nil && index >= 0 {
return p.parser.GetRuleNames()[index]
}
+ var sb strings.Builder
+ sb.Grow(32)
- return ""
+ sb.WriteString("')
+ return sb.String()
}
func (p *ParserATNSimulator) getEpsilonTarget(config ATNConfig, t Transition, collectPredicates, inContext, fullCtx, treatEOFAsEpsilon bool) ATNConfig {
@@ -1110,25 +1195,7 @@ func (p *ParserATNSimulator) getEpsilonTarget(config ATNConfig, t Transition, co
return p.actionTransition(config, t.(*ActionTransition))
case TransitionEPSILON:
return NewBaseATNConfig4(config, t.getTarget())
- case TransitionATOM:
- // EOF transitions act like epsilon transitions after the first EOF
- // transition is traversed
- if treatEOFAsEpsilon {
- if t.Matches(TokenEOF, 0, 1) {
- return NewBaseATNConfig4(config, t.getTarget())
- }
- }
- return nil
- case TransitionRANGE:
- // EOF transitions act like epsilon transitions after the first EOF
- // transition is traversed
- if treatEOFAsEpsilon {
- if t.Matches(TokenEOF, 0, 1) {
- return NewBaseATNConfig4(config, t.getTarget())
- }
- }
- return nil
- case TransitionSET:
+ case TransitionATOM, TransitionRANGE, TransitionSET:
// EOF transitions act like epsilon transitions after the first EOF
// transition is traversed
if treatEOFAsEpsilon {
@@ -1196,7 +1263,7 @@ func (p *ParserATNSimulator) predTransition(config ATNConfig, pt *PredicateTrans
}
}
var c *BaseATNConfig
- if collectPredicates && ((pt.isCtxDependent && inContext) || !pt.isCtxDependent) {
+ if collectPredicates && (!pt.isCtxDependent || inContext) {
if fullCtx {
// In full context mode, we can evaluate predicates on-the-fly
// during closure, which dramatically reduces the size of
@@ -1381,14 +1448,18 @@ func (p *ParserATNSimulator) addDFAEdge(dfa *DFA, from *DFAState, t int, to *DFA
if to == nil {
return nil
}
+ p.atn.stateMu.Lock()
to = p.addDFAState(dfa, to) // used existing if possible not incoming
+ p.atn.stateMu.Unlock()
if from == nil || t < -1 || t > p.atn.maxTokenType {
return to
}
+ p.atn.edgeMu.Lock()
if from.getEdges() == nil {
from.setEdges(make([]*DFAState, p.atn.maxTokenType+1+1))
}
from.setIthEdge(t+1, to) // connect
+ p.atn.edgeMu.Unlock()
if ParserATNSimulatorDebug {
var names []string
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/prediction_context.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/prediction_context.go
index 99acb333fa2..9fdfd52b26c 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/prediction_context.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/prediction_context.go
@@ -58,9 +58,15 @@ func calculateHash(parent PredictionContext, returnState int) int {
return murmurFinish(h, 2)
}
+var _emptyPredictionContextHash int
+
+func init() {
+ _emptyPredictionContextHash = murmurInit(1)
+ _emptyPredictionContextHash = murmurFinish(_emptyPredictionContextHash, 0)
+}
+
func calculateEmptyHash() int {
- h := murmurInit(1)
- return murmurFinish(h, 0)
+ return _emptyPredictionContextHash
}
// Used to cache {@link BasePredictionContext} objects. Its used for the shared
@@ -113,16 +119,16 @@ type BaseSingletonPredictionContext struct {
}
func NewBaseSingletonPredictionContext(parent PredictionContext, returnState int) *BaseSingletonPredictionContext {
-
- s := new(BaseSingletonPredictionContext)
- s.BasePredictionContext = NewBasePredictionContext(37)
-
+ var cachedHash int
if parent != nil {
- s.cachedHash = calculateHash(parent, returnState)
+ cachedHash = calculateHash(parent, returnState)
} else {
- s.cachedHash = calculateEmptyHash()
+ cachedHash = calculateEmptyHash()
}
+ s := new(BaseSingletonPredictionContext)
+ s.BasePredictionContext = NewBasePredictionContext(cachedHash)
+
s.parentCtx = parent
s.returnState = returnState
@@ -175,15 +181,7 @@ func (b *BaseSingletonPredictionContext) equals(other PredictionContext) bool {
}
func (b *BaseSingletonPredictionContext) hash() int {
- h := murmurInit(1)
-
- if b.parentCtx == nil {
- return murmurFinish(h, 0)
- }
-
- h = murmurUpdate(h, b.parentCtx.hash())
- h = murmurUpdate(h, b.returnState)
- return murmurFinish(h, 2)
+ return b.cachedHash
}
func (b *BaseSingletonPredictionContext) String() string {
@@ -253,14 +251,21 @@ func NewArrayPredictionContext(parents []PredictionContext, returnStates []int)
// from {@link //EMPTY} and non-empty. We merge {@link //EMPTY} by using
// nil parent and
// returnState == {@link //EmptyReturnState}.
+ hash := murmurInit(1)
- c := new(ArrayPredictionContext)
- c.BasePredictionContext = NewBasePredictionContext(37)
+ for _, parent := range parents {
+ hash = murmurUpdate(hash, parent.hash())
+ }
- for i := range parents {
- c.cachedHash += calculateHash(parents[i], returnStates[i])
+ for _, returnState := range returnStates {
+ hash = murmurUpdate(hash, returnState)
}
+ hash = murmurFinish(hash, len(parents)<<1)
+
+ c := new(ArrayPredictionContext)
+ c.BasePredictionContext = NewBasePredictionContext(hash)
+
c.parents = parents
c.returnStates = returnStates
@@ -305,17 +310,7 @@ func (a *ArrayPredictionContext) equals(other PredictionContext) bool {
}
func (a *ArrayPredictionContext) hash() int {
- h := murmurInit(1)
-
- for _, p := range a.parents {
- h = murmurUpdate(h, p.hash())
- }
-
- for _, r := range a.returnStates {
- h = murmurUpdate(h, r)
- }
-
- return murmurFinish(h, 2 * len(a.parents))
+ return a.BasePredictionContext.cachedHash
}
func (a *ArrayPredictionContext) String() string {
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/recognizer.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/recognizer.go
index 89d35244a2e..93efcf355d8 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/recognizer.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/recognizer.go
@@ -49,7 +49,7 @@ var tokenTypeMapCache = make(map[string]int)
var ruleIndexMapCache = make(map[string]int)
func (b *BaseRecognizer) checkVersion(toolVersion string) {
- runtimeVersion := "4.9.2"
+ runtimeVersion := "4.10.1"
if runtimeVersion != toolVersion {
fmt.Println("ANTLR runtime and generated code versions disagree: " + runtimeVersion + "!=" + toolVersion)
}
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/semantic_context.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/semantic_context.go
index 49205a16240..9ada430779c 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/semantic_context.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/semantic_context.go
@@ -108,7 +108,15 @@ func (p *Predicate) equals(other interface{}) bool {
}
func (p *Predicate) hash() int {
- return p.ruleIndex*43 + p.predIndex*47
+ h := murmurInit(0)
+ h = murmurUpdate(h, p.ruleIndex)
+ h = murmurUpdate(h, p.predIndex)
+ if p.isCtxDependent {
+ h = murmurUpdate(h, 1)
+ } else {
+ h = murmurUpdate(h, 0)
+ }
+ return murmurFinish(h, 3)
}
func (p *Predicate) String() string {
@@ -154,21 +162,24 @@ func (p *PrecedencePredicate) equals(other interface{}) bool {
}
func (p *PrecedencePredicate) hash() int {
- return p.precedence * 51
+ h := uint32(1)
+ h = 31*h + uint32(p.precedence)
+ return int(h)
}
func (p *PrecedencePredicate) String() string {
return "{" + strconv.Itoa(p.precedence) + ">=prec}?"
}
-func PrecedencePredicatefilterPrecedencePredicates(set *Set) []*PrecedencePredicate {
+func PrecedencePredicatefilterPrecedencePredicates(set Set) []*PrecedencePredicate {
result := make([]*PrecedencePredicate, 0)
- for _, v := range set.values() {
+ set.Each(func(v interface{}) bool {
if c2, ok := v.(*PrecedencePredicate); ok {
result = append(result, c2)
}
- }
+ return true
+ })
return result
}
@@ -182,21 +193,21 @@ type AND struct {
func NewAND(a, b SemanticContext) *AND {
- operands := NewSet(nil, nil)
+ operands := newArray2DHashSet(nil, nil)
if aa, ok := a.(*AND); ok {
for _, o := range aa.opnds {
- operands.add(o)
+ operands.Add(o)
}
} else {
- operands.add(a)
+ operands.Add(a)
}
if ba, ok := b.(*AND); ok {
for _, o := range ba.opnds {
- operands.add(o)
+ operands.Add(o)
}
} else {
- operands.add(b)
+ operands.Add(b)
}
precedencePredicates := PrecedencePredicatefilterPrecedencePredicates(operands)
if len(precedencePredicates) > 0 {
@@ -209,10 +220,10 @@ func NewAND(a, b SemanticContext) *AND {
}
}
- operands.add(reduced)
+ operands.Add(reduced)
}
- vs := operands.values()
+ vs := operands.Values()
opnds := make([]SemanticContext, len(vs))
for i, v := range vs {
opnds[i] = v.(SemanticContext)
@@ -334,21 +345,21 @@ type OR struct {
func NewOR(a, b SemanticContext) *OR {
- operands := NewSet(nil, nil)
+ operands := newArray2DHashSet(nil, nil)
if aa, ok := a.(*OR); ok {
for _, o := range aa.opnds {
- operands.add(o)
+ operands.Add(o)
}
} else {
- operands.add(a)
+ operands.Add(a)
}
if ba, ok := b.(*OR); ok {
for _, o := range ba.opnds {
- operands.add(o)
+ operands.Add(o)
}
} else {
- operands.add(b)
+ operands.Add(b)
}
precedencePredicates := PrecedencePredicatefilterPrecedencePredicates(operands)
if len(precedencePredicates) > 0 {
@@ -361,10 +372,10 @@ func NewOR(a, b SemanticContext) *OR {
}
}
- operands.add(reduced)
+ operands.Add(reduced)
}
- vs := operands.values()
+ vs := operands.Values()
opnds := make([]SemanticContext, len(vs))
for i, v := range vs {
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/transition.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/transition.go
index eb7e57e9aa0..53056bd74f4 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/transition.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/transition.go
@@ -7,6 +7,7 @@ package antlr
import (
"fmt"
"strconv"
+ "strings"
)
// atom, set, epsilon, action, predicate, rule transitions.
@@ -236,7 +237,13 @@ func (t *RangeTransition) Matches(symbol, minVocabSymbol, maxVocabSymbol int) bo
}
func (t *RangeTransition) String() string {
- return "'" + string(t.start) + "'..'" + string(t.stop) + "'"
+ var sb strings.Builder
+ sb.WriteByte('\'')
+ sb.WriteRune(rune(t.start))
+ sb.WriteString("'..'")
+ sb.WriteRune(rune(t.stop))
+ sb.WriteByte('\'')
+ return sb.String()
}
type AbstractPredicateTransition interface {
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/tree.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/tree.go
index bdeb6d78811..08ce22bba39 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/tree.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/tree.go
@@ -64,7 +64,7 @@ type BaseParseTreeVisitor struct{}
var _ ParseTreeVisitor = &BaseParseTreeVisitor{}
-func (v *BaseParseTreeVisitor) Visit(tree ParseTree) interface{} { return nil }
+func (v *BaseParseTreeVisitor) Visit(tree ParseTree) interface{} { return tree.Accept(v) }
func (v *BaseParseTreeVisitor) VisitChildren(node RuleNode) interface{} { return nil }
func (v *BaseParseTreeVisitor) VisitTerminal(node TerminalNode) interface{} { return nil }
func (v *BaseParseTreeVisitor) VisitErrorNode(node ErrorNode) interface{} { return nil }
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/utils.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/utils.go
index bba2ffae793..ec219df983a 100644
--- a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/utils.go
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/utils.go
@@ -8,7 +8,7 @@ import (
"bytes"
"errors"
"fmt"
- "sort"
+ "math/bits"
"strconv"
"strings"
)
@@ -47,35 +47,6 @@ func (s *IntStack) Push(e int) {
*s = append(*s, e)
}
-type Set struct {
- data map[int][]interface{}
- hashcodeFunction func(interface{}) int
- equalsFunction func(interface{}, interface{}) bool
-}
-
-func NewSet(
- hashcodeFunction func(interface{}) int,
- equalsFunction func(interface{}, interface{}) bool) *Set {
-
- s := new(Set)
-
- s.data = make(map[int][]interface{})
-
- if hashcodeFunction != nil {
- s.hashcodeFunction = hashcodeFunction
- } else {
- s.hashcodeFunction = standardHashFunction
- }
-
- if equalsFunction == nil {
- s.equalsFunction = standardEqualsFunction
- } else {
- s.equalsFunction = equalsFunction
- }
-
- return s
-}
-
func standardEqualsFunction(a interface{}, b interface{}) bool {
ac, oka := a.(comparable)
@@ -100,125 +71,92 @@ type hasher interface {
hash() int
}
-func (s *Set) length() int {
- return len(s.data)
-}
-
-func (s *Set) add(value interface{}) interface{} {
-
- key := s.hashcodeFunction(value)
+const bitsPerWord = 64
- values := s.data[key]
-
- if s.data[key] != nil {
- for i := 0; i < len(values); i++ {
- if s.equalsFunction(value, values[i]) {
- return values[i]
- }
- }
-
- s.data[key] = append(s.data[key], value)
- return value
- }
-
- v := make([]interface{}, 1, 10)
- v[0] = value
- s.data[key] = v
-
- return value
+func indexForBit(bit int) int {
+ return bit / bitsPerWord
}
-func (s *Set) contains(value interface{}) bool {
-
- key := s.hashcodeFunction(value)
-
- values := s.data[key]
-
- if s.data[key] != nil {
- for i := 0; i < len(values); i++ {
- if s.equalsFunction(value, values[i]) {
- return true
- }
- }
+func wordForBit(data []uint64, bit int) uint64 {
+ idx := indexForBit(bit)
+ if idx >= len(data) {
+ return 0
}
- return false
+ return data[idx]
}
-func (s *Set) values() []interface{} {
- var l []interface{}
-
- for _, v := range s.data {
- l = append(l, v...)
- }
-
- return l
+func maskForBit(bit int) uint64 {
+ return uint64(1) << (bit % bitsPerWord)
}
-func (s *Set) String() string {
- r := ""
-
- for _, av := range s.data {
- for _, v := range av {
- r += fmt.Sprint(v)
- }
- }
-
- return r
+func wordsNeeded(bit int) int {
+ return indexForBit(bit) + 1
}
type BitSet struct {
- data map[int]bool
+ data []uint64
}
func NewBitSet() *BitSet {
- b := new(BitSet)
- b.data = make(map[int]bool)
- return b
+ return &BitSet{}
}
func (b *BitSet) add(value int) {
- b.data[value] = true
+ idx := indexForBit(value)
+ if idx >= len(b.data) {
+ size := wordsNeeded(value)
+ data := make([]uint64, size)
+ copy(data, b.data)
+ b.data = data
+ }
+ b.data[idx] |= maskForBit(value)
}
func (b *BitSet) clear(index int) {
- delete(b.data, index)
+ idx := indexForBit(index)
+ if idx >= len(b.data) {
+ return
+ }
+ b.data[idx] &= ^maskForBit(index)
}
func (b *BitSet) or(set *BitSet) {
- for k := range set.data {
- b.add(k)
+ // Get min size necessary to represent the bits in both sets.
+ bLen := b.minLen()
+ setLen := set.minLen()
+ maxLen := intMax(bLen, setLen)
+ if maxLen > len(b.data) {
+ // Increase the size of len(b.data) to repesent the bits in both sets.
+ data := make([]uint64, maxLen)
+ copy(data, b.data)
+ b.data = data
+ }
+ // len(b.data) is at least setLen.
+ for i := 0; i < setLen; i++ {
+ b.data[i] |= set.data[i]
}
}
func (b *BitSet) remove(value int) {
- delete(b.data, value)
+ b.clear(value)
}
func (b *BitSet) contains(value int) bool {
- return b.data[value]
-}
-
-func (b *BitSet) values() []int {
- ks := make([]int, len(b.data))
- i := 0
- for k := range b.data {
- ks[i] = k
- i++
+ idx := indexForBit(value)
+ if idx >= len(b.data) {
+ return false
}
- sort.Ints(ks)
- return ks
+ return (b.data[idx] & maskForBit(value)) != 0
}
func (b *BitSet) minValue() int {
- min := 2147483647
-
- for k := range b.data {
- if k < min {
- min = k
+ for i, v := range b.data {
+ if v == 0 {
+ continue
}
+ return i*bitsPerWord + bits.TrailingZeros64(v)
}
-
- return min
+ return 2147483647
}
func (b *BitSet) equals(other interface{}) bool {
@@ -227,12 +165,22 @@ func (b *BitSet) equals(other interface{}) bool {
return false
}
- if len(b.data) != len(otherBitSet.data) {
+ if b == otherBitSet {
+ return true
+ }
+
+ // We only compare set bits, so we cannot rely on the two slices having the same size. Its
+ // possible for two BitSets to have different slice lengths but the same set bits. So we only
+ // compare the relavent words and ignore the trailing zeros.
+ bLen := b.minLen()
+ otherLen := otherBitSet.minLen()
+
+ if bLen != otherLen {
return false
}
- for k, v := range b.data {
- if otherBitSet.data[k] != v {
+ for i := 0; i < bLen; i++ {
+ if b.data[i] != otherBitSet.data[i] {
return false
}
}
@@ -240,18 +188,35 @@ func (b *BitSet) equals(other interface{}) bool {
return true
}
+func (b *BitSet) minLen() int {
+ for i := len(b.data); i > 0; i-- {
+ if b.data[i-1] != 0 {
+ return i
+ }
+ }
+ return 0
+}
+
func (b *BitSet) length() int {
- return len(b.data)
+ cnt := 0
+ for _, val := range b.data {
+ cnt += bits.OnesCount64(val)
+ }
+ return cnt
}
func (b *BitSet) String() string {
- vals := b.values()
- valsS := make([]string, len(vals))
+ vals := make([]string, 0, b.length())
- for i, val := range vals {
- valsS[i] = strconv.Itoa(val)
+ for i, v := range b.data {
+ for v != 0 {
+ n := bits.TrailingZeros64(v)
+ vals = append(vals, strconv.Itoa(i*bitsPerWord+n))
+ v &= ^(uint64(1) << n)
+ }
}
- return "{" + strings.Join(valsS, ", ") + "}"
+
+ return "{" + strings.Join(vals, ", ") + "}"
}
type AltDict struct {
@@ -353,65 +318,38 @@ func PrintArrayJavaStyle(sa []string) string {
return buffer.String()
}
-// The following routines were lifted from bits.rotate* available in Go 1.9.
-
-const uintSize = 32 << (^uint(0) >> 32 & 1) // 32 or 64
-
-// rotateLeft returns the value of x rotated left by (k mod UintSize) bits.
-// To rotate x right by k bits, call RotateLeft(x, -k).
-func rotateLeft(x uint, k int) uint {
- if uintSize == 32 {
- return uint(rotateLeft32(uint32(x), k))
- }
- return uint(rotateLeft64(uint64(x), k))
-}
-
-// rotateLeft32 returns the value of x rotated left by (k mod 32) bits.
-func rotateLeft32(x uint32, k int) uint32 {
- const n = 32
- s := uint(k) & (n - 1)
- return x<>(n-s)
-}
-
-// rotateLeft64 returns the value of x rotated left by (k mod 64) bits.
-func rotateLeft64(x uint64, k int) uint64 {
- const n = 64
- s := uint(k) & (n - 1)
- return x<>(n-s)
-}
-
-
// murmur hash
-const (
- c1_32 uint = 0xCC9E2D51
- c2_32 uint = 0x1B873593
- n1_32 uint = 0xE6546B64
-)
-
func murmurInit(seed int) int {
return seed
}
-func murmurUpdate(h1 int, k1 int) int {
- var k1u uint
- k1u = uint(k1) * c1_32
- k1u = rotateLeft(k1u, 15)
- k1u *= c2_32
+func murmurUpdate(h int, value int) int {
+ const c1 uint32 = 0xCC9E2D51
+ const c2 uint32 = 0x1B873593
+ const r1 uint32 = 15
+ const r2 uint32 = 13
+ const m uint32 = 5
+ const n uint32 = 0xE6546B64
+
+ k := uint32(value)
+ k *= c1
+ k = (k << r1) | (k >> (32 - r1))
+ k *= c2
- var h1u = uint(h1) ^ k1u
- k1u = rotateLeft(k1u, 13)
- h1u = h1u*5 + 0xe6546b64
- return int(h1u)
+ hash := uint32(h) ^ k
+ hash = (hash << r2) | (hash >> (32 - r2))
+ hash = hash*m + n
+ return int(hash)
}
-func murmurFinish(h1 int, numberOfWords int) int {
- var h1u uint = uint(h1)
- h1u ^= uint(numberOfWords * 4)
- h1u ^= h1u >> 16
- h1u *= uint(0x85ebca6b)
- h1u ^= h1u >> 13
- h1u *= 0xc2b2ae35
- h1u ^= h1u >> 16
+func murmurFinish(h int, numberOfWords int) int {
+ var hash = uint32(h)
+ hash ^= uint32(numberOfWords) << 2
+ hash ^= hash >> 16
+ hash *= 0x85ebca6b
+ hash ^= hash >> 13
+ hash *= 0xc2b2ae35
+ hash ^= hash >> 16
- return int(h1u)
+ return int(hash)
}
diff --git a/vendor/github.com/antlr/antlr4/runtime/Go/antlr/utils_set.go b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/utils_set.go
new file mode 100644
index 00000000000..0d4eac698dc
--- /dev/null
+++ b/vendor/github.com/antlr/antlr4/runtime/Go/antlr/utils_set.go
@@ -0,0 +1,237 @@
+package antlr
+
+import "math"
+
+const (
+ _initalCapacity = 16
+ _initalBucketCapacity = 8
+ _loadFactor = 0.75
+)
+
+var _ Set = (*array2DHashSet)(nil)
+
+type Set interface {
+ Add(value interface{}) (added interface{})
+ Len() int
+ Get(value interface{}) (found interface{})
+ Contains(value interface{}) bool
+ Values() []interface{}
+ Each(f func(interface{}) bool)
+}
+
+type array2DHashSet struct {
+ buckets [][]interface{}
+ hashcodeFunction func(interface{}) int
+ equalsFunction func(interface{}, interface{}) bool
+
+ n int // How many elements in set
+ threshold int // when to expand
+
+ currentPrime int // jump by 4 primes each expand or whatever
+ initialBucketCapacity int
+}
+
+func (as *array2DHashSet) Each(f func(interface{}) bool) {
+ if as.Len() < 1 {
+ return
+ }
+
+ for _, bucket := range as.buckets {
+ for _, o := range bucket {
+ if o == nil {
+ break
+ }
+ if !f(o) {
+ return
+ }
+ }
+ }
+}
+
+func (as *array2DHashSet) Values() []interface{} {
+ if as.Len() < 1 {
+ return nil
+ }
+
+ values := make([]interface{}, 0, as.Len())
+ as.Each(func(i interface{}) bool {
+ values = append(values, i)
+ return true
+ })
+ return values
+}
+
+func (as *array2DHashSet) Contains(value interface{}) bool {
+ return as.Get(value) != nil
+}
+
+func (as *array2DHashSet) Add(value interface{}) interface{} {
+ if as.n > as.threshold {
+ as.expand()
+ }
+ return as.innerAdd(value)
+}
+
+func (as *array2DHashSet) expand() {
+ old := as.buckets
+
+ as.currentPrime += 4
+
+ var (
+ newCapacity = len(as.buckets) << 1
+ newTable = as.createBuckets(newCapacity)
+ newBucketLengths = make([]int, len(newTable))
+ )
+
+ as.buckets = newTable
+ as.threshold = int(float64(newCapacity) * _loadFactor)
+
+ for _, bucket := range old {
+ if bucket == nil {
+ continue
+ }
+
+ for _, o := range bucket {
+ if o == nil {
+ break
+ }
+
+ b := as.getBuckets(o)
+ bucketLength := newBucketLengths[b]
+ var newBucket []interface{}
+ if bucketLength == 0 {
+ // new bucket
+ newBucket = as.createBucket(as.initialBucketCapacity)
+ newTable[b] = newBucket
+ } else {
+ newBucket = newTable[b]
+ if bucketLength == len(newBucket) {
+ // expand
+ newBucketCopy := make([]interface{}, len(newBucket)<<1)
+ copy(newBucketCopy[:bucketLength], newBucket)
+ newBucket = newBucketCopy
+ newTable[b] = newBucket
+ }
+ }
+
+ newBucket[bucketLength] = o
+ newBucketLengths[b]++
+ }
+ }
+}
+
+func (as *array2DHashSet) Len() int {
+ return as.n
+}
+
+func (as *array2DHashSet) Get(o interface{}) interface{} {
+ if o == nil {
+ return nil
+ }
+
+ b := as.getBuckets(o)
+ bucket := as.buckets[b]
+ if bucket == nil { // no bucket
+ return nil
+ }
+
+ for _, e := range bucket {
+ if e == nil {
+ return nil // empty slot; not there
+ }
+ if as.equalsFunction(e, o) {
+ return e
+ }
+ }
+
+ return nil
+}
+
+func (as *array2DHashSet) innerAdd(o interface{}) interface{} {
+ b := as.getBuckets(o)
+
+ bucket := as.buckets[b]
+
+ // new bucket
+ if bucket == nil {
+ bucket = as.createBucket(as.initialBucketCapacity)
+ bucket[0] = o
+
+ as.buckets[b] = bucket
+ as.n++
+ return o
+ }
+
+ // look for it in bucket
+ for i := 0; i < len(bucket); i++ {
+ existing := bucket[i]
+ if existing == nil { // empty slot; not there, add.
+ bucket[i] = o
+ as.n++
+ return o
+ }
+
+ if as.equalsFunction(existing, o) { // found existing, quit
+ return existing
+ }
+ }
+
+ // full bucket, expand and add to end
+ oldLength := len(bucket)
+ bucketCopy := make([]interface{}, oldLength<<1)
+ copy(bucketCopy[:oldLength], bucket)
+ bucket = bucketCopy
+ as.buckets[b] = bucket
+ bucket[oldLength] = o
+ as.n++
+ return o
+}
+
+func (as *array2DHashSet) getBuckets(value interface{}) int {
+ hash := as.hashcodeFunction(value)
+ return hash & (len(as.buckets) - 1)
+}
+
+func (as *array2DHashSet) createBuckets(cap int) [][]interface{} {
+ return make([][]interface{}, cap)
+}
+
+func (as *array2DHashSet) createBucket(cap int) []interface{} {
+ return make([]interface{}, cap)
+}
+
+func newArray2DHashSetWithCap(
+ hashcodeFunction func(interface{}) int,
+ equalsFunction func(interface{}, interface{}) bool,
+ initCap int,
+ initBucketCap int,
+) *array2DHashSet {
+ if hashcodeFunction == nil {
+ hashcodeFunction = standardHashFunction
+ }
+
+ if equalsFunction == nil {
+ equalsFunction = standardEqualsFunction
+ }
+
+ ret := &array2DHashSet{
+ hashcodeFunction: hashcodeFunction,
+ equalsFunction: equalsFunction,
+
+ n: 0,
+ threshold: int(math.Floor(_initalCapacity * _loadFactor)),
+
+ currentPrime: 1,
+ initialBucketCapacity: initBucketCap,
+ }
+
+ ret.buckets = ret.createBuckets(initCap)
+ return ret
+}
+
+func newArray2DHashSet(
+ hashcodeFunction func(interface{}) int,
+ equalsFunction func(interface{}, interface{}) bool,
+) *array2DHashSet {
+ return newArray2DHashSetWithCap(hashcodeFunction, equalsFunction, _initalCapacity, _initalBucketCapacity)
+}
diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
index a4fa6e67c0b..e3208828bd6 100644
--- a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
+++ b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
@@ -548,9 +548,6 @@ var awsPartition = partition{
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
- endpointKey{
- Region: "ap-southeast-3",
- }: endpoint{},
endpointKey{
Region: "ca-central-1",
}: endpoint{},
@@ -2229,183 +2226,63 @@ var awsPartition = partition{
endpointKey{
Region: "af-south-1",
}: endpoint{},
- endpointKey{
- Region: "af-south-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.af-south-1.api.aws",
- },
endpointKey{
Region: "ap-east-1",
}: endpoint{},
- endpointKey{
- Region: "ap-east-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.ap-east-1.api.aws",
- },
endpointKey{
Region: "ap-northeast-1",
}: endpoint{},
- endpointKey{
- Region: "ap-northeast-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.ap-northeast-1.api.aws",
- },
endpointKey{
Region: "ap-northeast-2",
}: endpoint{},
- endpointKey{
- Region: "ap-northeast-2",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.ap-northeast-2.api.aws",
- },
endpointKey{
Region: "ap-south-1",
}: endpoint{},
- endpointKey{
- Region: "ap-south-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.ap-south-1.api.aws",
- },
endpointKey{
Region: "ap-southeast-1",
}: endpoint{},
- endpointKey{
- Region: "ap-southeast-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.ap-southeast-1.api.aws",
- },
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
- endpointKey{
- Region: "ap-southeast-2",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.ap-southeast-2.api.aws",
- },
endpointKey{
Region: "ca-central-1",
}: endpoint{},
- endpointKey{
- Region: "ca-central-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.ca-central-1.api.aws",
- },
endpointKey{
Region: "eu-central-1",
}: endpoint{},
- endpointKey{
- Region: "eu-central-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.eu-central-1.api.aws",
- },
endpointKey{
Region: "eu-north-1",
}: endpoint{},
- endpointKey{
- Region: "eu-north-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.eu-north-1.api.aws",
- },
endpointKey{
Region: "eu-south-1",
}: endpoint{},
- endpointKey{
- Region: "eu-south-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.eu-south-1.api.aws",
- },
endpointKey{
Region: "eu-west-1",
}: endpoint{},
- endpointKey{
- Region: "eu-west-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.eu-west-1.api.aws",
- },
endpointKey{
Region: "eu-west-2",
}: endpoint{},
- endpointKey{
- Region: "eu-west-2",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.eu-west-2.api.aws",
- },
endpointKey{
Region: "eu-west-3",
}: endpoint{},
- endpointKey{
- Region: "eu-west-3",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.eu-west-3.api.aws",
- },
endpointKey{
Region: "me-south-1",
}: endpoint{},
- endpointKey{
- Region: "me-south-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.me-south-1.api.aws",
- },
endpointKey{
Region: "sa-east-1",
}: endpoint{},
- endpointKey{
- Region: "sa-east-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.sa-east-1.api.aws",
- },
endpointKey{
Region: "us-east-1",
}: endpoint{},
- endpointKey{
- Region: "us-east-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.us-east-1.api.aws",
- },
endpointKey{
Region: "us-east-2",
}: endpoint{},
- endpointKey{
- Region: "us-east-2",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.us-east-2.api.aws",
- },
endpointKey{
Region: "us-west-1",
}: endpoint{},
- endpointKey{
- Region: "us-west-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.us-west-1.api.aws",
- },
endpointKey{
Region: "us-west-2",
}: endpoint{},
- endpointKey{
- Region: "us-west-2",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.us-west-2.api.aws",
- },
},
},
"apprunner": service{
@@ -2645,9 +2522,6 @@ var awsPartition = partition{
endpointKey{
Region: "eu-west-1",
}: endpoint{},
- endpointKey{
- Region: "eu-west-2",
- }: endpoint{},
endpointKey{
Region: "us-east-1",
}: endpoint{},
@@ -3046,73 +2920,6 @@ var awsPartition = partition{
}: endpoint{},
},
},
- "backup-gateway": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "af-south-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-east-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-northeast-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-northeast-2",
- }: endpoint{},
- endpointKey{
- Region: "ap-northeast-3",
- }: endpoint{},
- endpointKey{
- Region: "ap-south-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-southeast-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-southeast-2",
- }: endpoint{},
- endpointKey{
- Region: "ca-central-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-central-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-north-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-south-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-2",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-3",
- }: endpoint{},
- endpointKey{
- Region: "me-south-1",
- }: endpoint{},
- endpointKey{
- Region: "sa-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-2",
- }: endpoint{},
- endpointKey{
- Region: "us-west-1",
- }: endpoint{},
- endpointKey{
- Region: "us-west-2",
- }: endpoint{},
- },
- },
"batch": service{
Defaults: endpointDefaults{
defaultKey{}: endpoint{},
@@ -3716,6 +3523,9 @@ var awsPartition = partition{
},
"cloudhsm": service{
Endpoints: serviceEndpoints{
+ endpointKey{
+ Region: "eu-west-1",
+ }: endpoint{},
endpointKey{
Region: "us-east-1",
}: endpoint{},
@@ -5863,9 +5673,6 @@ var awsPartition = partition{
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
- endpointKey{
- Region: "ap-southeast-3",
- }: endpoint{},
endpointKey{
Region: "ca-central-1",
}: endpoint{},
@@ -6966,7 +6773,7 @@ var awsPartition = partition{
Region: "ap-south-1",
Variant: dualStackVariant,
}: endpoint{
- Hostname: "ec2.ap-south-1.api.aws",
+ Hostname: "api.ec2.ap-south-1.aws",
},
endpointKey{
Region: "ap-southeast-1",
@@ -7002,7 +6809,7 @@ var awsPartition = partition{
Region: "eu-west-1",
Variant: dualStackVariant,
}: endpoint{
- Hostname: "ec2.eu-west-1.api.aws",
+ Hostname: "api.ec2.eu-west-1.aws",
},
endpointKey{
Region: "eu-west-2",
@@ -7065,7 +6872,7 @@ var awsPartition = partition{
Region: "sa-east-1",
Variant: dualStackVariant,
}: endpoint{
- Hostname: "ec2.sa-east-1.api.aws",
+ Hostname: "api.ec2.sa-east-1.aws",
},
endpointKey{
Region: "us-east-1",
@@ -7074,7 +6881,7 @@ var awsPartition = partition{
Region: "us-east-1",
Variant: dualStackVariant,
}: endpoint{
- Hostname: "ec2.us-east-1.api.aws",
+ Hostname: "api.ec2.us-east-1.aws",
},
endpointKey{
Region: "us-east-1",
@@ -7089,7 +6896,7 @@ var awsPartition = partition{
Region: "us-east-2",
Variant: dualStackVariant,
}: endpoint{
- Hostname: "ec2.us-east-2.api.aws",
+ Hostname: "api.ec2.us-east-2.aws",
},
endpointKey{
Region: "us-east-2",
@@ -7113,7 +6920,7 @@ var awsPartition = partition{
Region: "us-west-2",
Variant: dualStackVariant,
}: endpoint{
- Hostname: "ec2.us-west-2.api.aws",
+ Hostname: "api.ec2.us-west-2.aws",
},
endpointKey{
Region: "us-west-2",
@@ -7290,9 +7097,6 @@ var awsPartition = partition{
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
- endpointKey{
- Region: "ap-southeast-3",
- }: endpoint{},
endpointKey{
Region: "ca-central-1",
}: endpoint{},
@@ -8381,96 +8185,24 @@ var awsPartition = partition{
},
"email": service{
Endpoints: serviceEndpoints{
- endpointKey{
- Region: "af-south-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-northeast-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-northeast-2",
- }: endpoint{},
- endpointKey{
- Region: "ap-northeast-3",
- }: endpoint{},
endpointKey{
Region: "ap-south-1",
}: endpoint{},
- endpointKey{
- Region: "ap-southeast-1",
- }: endpoint{},
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
- endpointKey{
- Region: "ca-central-1",
- }: endpoint{},
endpointKey{
Region: "eu-central-1",
}: endpoint{},
- endpointKey{
- Region: "eu-north-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-south-1",
- }: endpoint{},
endpointKey{
Region: "eu-west-1",
}: endpoint{},
- endpointKey{
- Region: "eu-west-2",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-3",
- }: endpoint{},
- endpointKey{
- Region: "fips-us-east-1",
- }: endpoint{
- Hostname: "email-fips.us-east-1.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-east-1",
- },
- Deprecated: boxedTrue,
- },
- endpointKey{
- Region: "fips-us-west-2",
- }: endpoint{
- Hostname: "email-fips.us-west-2.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-west-2",
- },
- Deprecated: boxedTrue,
- },
- endpointKey{
- Region: "me-south-1",
- }: endpoint{},
- endpointKey{
- Region: "sa-east-1",
- }: endpoint{},
endpointKey{
Region: "us-east-1",
}: endpoint{},
- endpointKey{
- Region: "us-east-1",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "email-fips.us-east-1.amazonaws.com",
- },
- endpointKey{
- Region: "us-east-2",
- }: endpoint{},
- endpointKey{
- Region: "us-west-1",
- }: endpoint{},
endpointKey{
Region: "us-west-2",
}: endpoint{},
- endpointKey{
- Region: "us-west-2",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "email-fips.us-west-2.amazonaws.com",
- },
},
},
"emr-containers": service{
@@ -8600,52 +8332,6 @@ var awsPartition = partition{
},
},
},
- "emr-serverless": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "ap-northeast-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-1",
- }: endpoint{},
- endpointKey{
- Region: "fips-us-east-1",
- }: endpoint{
- Hostname: "emr-serverless-fips.us-east-1.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-east-1",
- },
- Deprecated: boxedTrue,
- },
- endpointKey{
- Region: "fips-us-west-2",
- }: endpoint{
- Hostname: "emr-serverless-fips.us-west-2.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-west-2",
- },
- Deprecated: boxedTrue,
- },
- endpointKey{
- Region: "us-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-1",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "emr-serverless-fips.us-east-1.amazonaws.com",
- },
- endpointKey{
- Region: "us-west-2",
- }: endpoint{},
- endpointKey{
- Region: "us-west-2",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "emr-serverless-fips.us-west-2.amazonaws.com",
- },
- },
- },
"entitlement.marketplace": service{
Defaults: endpointDefaults{
defaultKey{}: endpoint{
@@ -9042,9 +8728,6 @@ var awsPartition = partition{
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
- endpointKey{
- Region: "ap-southeast-3",
- }: endpoint{},
endpointKey{
Region: "ca-central-1",
}: endpoint{},
@@ -10776,9 +10459,6 @@ var awsPartition = partition{
},
"identity-chime": service{
Endpoints: serviceEndpoints{
- endpointKey{
- Region: "eu-central-1",
- }: endpoint{},
endpointKey{
Region: "us-east-1",
}: endpoint{},
@@ -11449,83 +11129,15 @@ var awsPartition = partition{
endpointKey{
Region: "us-west-2",
}: endpoint{},
- endpointKey{
- Region: "us-west-2",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "api.tunneling.iot-fips.us-west-2.amazonaws.com",
- },
- },
- },
- "iotsitewise": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "ap-northeast-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-northeast-2",
- }: endpoint{},
- endpointKey{
- Region: "ap-south-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-southeast-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-southeast-2",
- }: endpoint{},
- endpointKey{
- Region: "eu-central-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-1",
- }: endpoint{},
- endpointKey{
- Region: "fips-us-east-1",
- }: endpoint{
- Hostname: "iotsitewise-fips.us-east-1.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-east-1",
- },
- Deprecated: boxedTrue,
- },
- endpointKey{
- Region: "fips-us-west-2",
- }: endpoint{
- Hostname: "iotsitewise-fips.us-west-2.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-west-2",
- },
- Deprecated: boxedTrue,
- },
- endpointKey{
- Region: "us-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-1",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "iotsitewise-fips.us-east-1.amazonaws.com",
- },
- endpointKey{
- Region: "us-west-2",
- }: endpoint{},
- endpointKey{
- Region: "us-west-2",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "iotsitewise-fips.us-west-2.amazonaws.com",
- },
- },
- },
- "iotthingsgraph": service{
- Defaults: endpointDefaults{
- defaultKey{}: endpoint{
- CredentialScope: credentialScope{
- Service: "iotthingsgraph",
- },
+ endpointKey{
+ Region: "us-west-2",
+ Variant: fipsVariant,
+ }: endpoint{
+ Hostname: "api.tunneling.iot-fips.us-west-2.amazonaws.com",
},
},
+ },
+ "iotsitewise": service{
Endpoints: serviceEndpoints{
endpointKey{
Region: "ap-northeast-1",
@@ -11533,9 +11145,18 @@ var awsPartition = partition{
endpointKey{
Region: "ap-northeast-2",
}: endpoint{},
+ endpointKey{
+ Region: "ap-south-1",
+ }: endpoint{},
+ endpointKey{
+ Region: "ap-southeast-1",
+ }: endpoint{},
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
+ endpointKey{
+ Region: "eu-central-1",
+ }: endpoint{},
endpointKey{
Region: "eu-west-1",
}: endpoint{},
@@ -11547,16 +11168,23 @@ var awsPartition = partition{
}: endpoint{},
},
},
- "iottwinmaker": service{
+ "iotthingsgraph": service{
+ Defaults: endpointDefaults{
+ defaultKey{}: endpoint{
+ CredentialScope: credentialScope{
+ Service: "iotthingsgraph",
+ },
+ },
+ },
Endpoints: serviceEndpoints{
endpointKey{
- Region: "ap-southeast-1",
+ Region: "ap-northeast-1",
}: endpoint{},
endpointKey{
- Region: "ap-southeast-2",
+ Region: "ap-northeast-2",
}: endpoint{},
endpointKey{
- Region: "eu-central-1",
+ Region: "ap-southeast-2",
}: endpoint{},
endpointKey{
Region: "eu-west-1",
@@ -11638,19 +11266,6 @@ var awsPartition = partition{
}: endpoint{},
},
},
- "ivschat": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "eu-west-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-west-2",
- }: endpoint{},
- },
- },
"kafka": service{
Endpoints: serviceEndpoints{
endpointKey{
@@ -12901,9 +12516,6 @@ var awsPartition = partition{
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
- endpointKey{
- Region: "ap-southeast-3",
- }: endpoint{},
endpointKey{
Region: "ca-central-1",
}: endpoint{},
@@ -13456,52 +13068,6 @@ var awsPartition = partition{
}: endpoint{},
},
},
- "media-pipelines-chime": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "ap-southeast-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-central-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-1",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "media-pipelines-chime-fips.us-east-1.amazonaws.com",
- },
- endpointKey{
- Region: "us-east-1-fips",
- }: endpoint{
- Hostname: "media-pipelines-chime-fips.us-east-1.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-east-1",
- },
- Deprecated: boxedTrue,
- },
- endpointKey{
- Region: "us-west-2",
- }: endpoint{},
- endpointKey{
- Region: "us-west-2",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "media-pipelines-chime-fips.us-west-2.amazonaws.com",
- },
- endpointKey{
- Region: "us-west-2-fips",
- }: endpoint{
- Hostname: "media-pipelines-chime-fips.us-west-2.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-west-2",
- },
- Deprecated: boxedTrue,
- },
- },
- },
"mediaconnect": service{
Endpoints: serviceEndpoints{
endpointKey{
@@ -13949,9 +13515,6 @@ var awsPartition = partition{
},
"messaging-chime": service{
Endpoints: serviceEndpoints{
- endpointKey{
- Region: "eu-central-1",
- }: endpoint{},
endpointKey{
Region: "us-east-1",
}: endpoint{},
@@ -14867,9 +14430,6 @@ var awsPartition = partition{
},
"nimble": service{
Endpoints: serviceEndpoints{
- endpointKey{
- Region: "ap-northeast-1",
- }: endpoint{},
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
@@ -15598,14 +15158,6 @@ var awsPartition = partition{
Region: "ap-northeast-2",
},
},
- endpointKey{
- Region: "ap-northeast-3",
- }: endpoint{
- Hostname: "portal.sso.ap-northeast-3.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "ap-northeast-3",
- },
- },
endpointKey{
Region: "ap-south-1",
}: endpoint{
@@ -15771,25 +15323,6 @@ var awsPartition = partition{
}: endpoint{},
},
},
- "proton": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "ap-northeast-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-2",
- }: endpoint{},
- endpointKey{
- Region: "us-west-2",
- }: endpoint{},
- },
- },
"qldb": service{
Endpoints: serviceEndpoints{
endpointKey{
@@ -15807,12 +15340,6 @@ var awsPartition = partition{
endpointKey{
Region: "ca-central-1",
}: endpoint{},
- endpointKey{
- Region: "ca-central-1",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "qldb-fips.ca-central-1.amazonaws.com",
- },
endpointKey{
Region: "eu-central-1",
}: endpoint{},
@@ -15822,15 +15349,6 @@ var awsPartition = partition{
endpointKey{
Region: "eu-west-2",
}: endpoint{},
- endpointKey{
- Region: "fips-ca-central-1",
- }: endpoint{
- Hostname: "qldb-fips.ca-central-1.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "ca-central-1",
- },
- Deprecated: boxedTrue,
- },
endpointKey{
Region: "fips-us-east-1",
}: endpoint{
@@ -15959,9 +15477,6 @@ var awsPartition = partition{
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
- endpointKey{
- Region: "ap-southeast-3",
- }: endpoint{},
endpointKey{
Region: "ca-central-1",
}: endpoint{},
@@ -16826,70 +16341,6 @@ var awsPartition = partition{
},
},
},
- "resiliencehub": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "af-south-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-east-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-northeast-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-northeast-2",
- }: endpoint{},
- endpointKey{
- Region: "ap-south-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-southeast-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-southeast-2",
- }: endpoint{},
- endpointKey{
- Region: "ca-central-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-central-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-north-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-south-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-2",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-3",
- }: endpoint{},
- endpointKey{
- Region: "me-south-1",
- }: endpoint{},
- endpointKey{
- Region: "sa-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-2",
- }: endpoint{},
- endpointKey{
- Region: "us-west-1",
- }: endpoint{},
- endpointKey{
- Region: "us-west-2",
- }: endpoint{},
- },
- },
"resource-groups": service{
Endpoints: serviceEndpoints{
endpointKey{
@@ -17127,9 +16578,6 @@ var awsPartition = partition{
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
- endpointKey{
- Region: "ap-southeast-3",
- }: endpoint{},
endpointKey{
Region: "ca-central-1",
}: endpoint{},
@@ -19070,9 +18518,6 @@ var awsPartition = partition{
endpointKey{
Region: "ap-northeast-2",
}: endpoint{},
- endpointKey{
- Region: "ap-northeast-3",
- }: endpoint{},
endpointKey{
Region: "ap-south-1",
}: endpoint{},
@@ -19082,9 +18527,6 @@ var awsPartition = partition{
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
- endpointKey{
- Region: "ap-southeast-3",
- }: endpoint{},
endpointKey{
Region: "ca-central-1",
}: endpoint{},
@@ -19686,40 +19128,6 @@ var awsPartition = partition{
},
},
},
- "sms-voice": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "ap-northeast-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-south-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-southeast-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-southeast-2",
- }: endpoint{},
- endpointKey{
- Region: "ca-central-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-central-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-2",
- }: endpoint{},
- endpointKey{
- Region: "us-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-west-2",
- }: endpoint{},
- },
- },
"snowball": service{
Endpoints: serviceEndpoints{
endpointKey{
@@ -21188,52 +20596,16 @@ var awsPartition = partition{
}: endpoint{},
endpointKey{
Region: "eu-south-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-2",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-3",
- }: endpoint{},
- endpointKey{
- Region: "fips-us-east-1",
- }: endpoint{
- Hostname: "synthetics-fips.us-east-1.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-east-1",
- },
- Deprecated: boxedTrue,
- },
+ }: endpoint{},
endpointKey{
- Region: "fips-us-east-2",
- }: endpoint{
- Hostname: "synthetics-fips.us-east-2.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-east-2",
- },
- Deprecated: boxedTrue,
- },
+ Region: "eu-west-1",
+ }: endpoint{},
endpointKey{
- Region: "fips-us-west-1",
- }: endpoint{
- Hostname: "synthetics-fips.us-west-1.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-west-1",
- },
- Deprecated: boxedTrue,
- },
+ Region: "eu-west-2",
+ }: endpoint{},
endpointKey{
- Region: "fips-us-west-2",
- }: endpoint{
- Hostname: "synthetics-fips.us-west-2.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-west-2",
- },
- Deprecated: boxedTrue,
- },
+ Region: "eu-west-3",
+ }: endpoint{},
endpointKey{
Region: "me-south-1",
}: endpoint{},
@@ -21243,39 +20615,15 @@ var awsPartition = partition{
endpointKey{
Region: "us-east-1",
}: endpoint{},
- endpointKey{
- Region: "us-east-1",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "synthetics-fips.us-east-1.amazonaws.com",
- },
endpointKey{
Region: "us-east-2",
}: endpoint{},
- endpointKey{
- Region: "us-east-2",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "synthetics-fips.us-east-2.amazonaws.com",
- },
endpointKey{
Region: "us-west-1",
}: endpoint{},
- endpointKey{
- Region: "us-west-1",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "synthetics-fips.us-west-1.amazonaws.com",
- },
endpointKey{
Region: "us-west-2",
}: endpoint{},
- endpointKey{
- Region: "us-west-2",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "synthetics-fips.us-west-2.amazonaws.com",
- },
},
},
"tagging": service{
@@ -22224,23 +21572,6 @@ var awsPartition = partition{
Region: "ap-southeast-2",
},
},
- endpointKey{
- Region: "ap-southeast-3",
- }: endpoint{
- Hostname: "waf-regional.ap-southeast-3.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "ap-southeast-3",
- },
- },
- endpointKey{
- Region: "ap-southeast-3",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "waf-regional-fips.ap-southeast-3.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "ap-southeast-3",
- },
- },
endpointKey{
Region: "ca-central-1",
}: endpoint{
@@ -22432,15 +21763,6 @@ var awsPartition = partition{
},
Deprecated: boxedTrue,
},
- endpointKey{
- Region: "fips-ap-southeast-3",
- }: endpoint{
- Hostname: "waf-regional-fips.ap-southeast-3.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "ap-southeast-3",
- },
- Deprecated: boxedTrue,
- },
endpointKey{
Region: "fips-ca-central-1",
}: endpoint{
@@ -22662,64 +21984,6 @@ var awsPartition = partition{
},
},
},
- "wellarchitected": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "ap-east-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-northeast-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-northeast-2",
- }: endpoint{},
- endpointKey{
- Region: "ap-south-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-southeast-1",
- }: endpoint{},
- endpointKey{
- Region: "ap-southeast-2",
- }: endpoint{},
- endpointKey{
- Region: "ca-central-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-central-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-north-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-1",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-2",
- }: endpoint{},
- endpointKey{
- Region: "eu-west-3",
- }: endpoint{},
- endpointKey{
- Region: "me-south-1",
- }: endpoint{},
- endpointKey{
- Region: "sa-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-east-2",
- }: endpoint{},
- endpointKey{
- Region: "us-west-1",
- }: endpoint{},
- endpointKey{
- Region: "us-west-2",
- }: endpoint{},
- },
- },
"wisdom": service{
Endpoints: serviceEndpoints{
endpointKey{
@@ -23207,21 +22471,9 @@ var awscnPartition = partition{
endpointKey{
Region: "cn-north-1",
}: endpoint{},
- endpointKey{
- Region: "cn-north-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.cn-north-1.api.amazonwebservices.com.cn",
- },
endpointKey{
Region: "cn-northwest-1",
}: endpoint{},
- endpointKey{
- Region: "cn-northwest-1",
- Variant: dualStackVariant,
- }: endpoint{
- Hostname: "appmesh.cn-northwest-1.api.amazonwebservices.com.cn",
- },
},
},
"appsync": service{
@@ -25244,16 +24496,6 @@ var awsusgovPartition = partition{
}: endpoint{},
},
},
- "backup-gateway": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "us-gov-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-gov-west-1",
- }: endpoint{},
- },
- },
"batch": service{
Defaults: endpointDefaults{
defaultKey{}: endpoint{},
@@ -27152,24 +26394,9 @@ var awsusgovPartition = partition{
},
"iotsitewise": service{
Endpoints: serviceEndpoints{
- endpointKey{
- Region: "fips-us-gov-west-1",
- }: endpoint{
- Hostname: "iotsitewise-fips.us-gov-west-1.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-gov-west-1",
- },
- Deprecated: boxedTrue,
- },
endpointKey{
Region: "us-gov-west-1",
}: endpoint{},
- endpointKey{
- Region: "us-gov-west-1",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "iotsitewise-fips.us-gov-west-1.amazonaws.com",
- },
},
},
"kafka": service{
@@ -28057,13 +27284,6 @@ var awsusgovPartition = partition{
},
},
},
- "robomaker": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "us-gov-west-1",
- }: endpoint{},
- },
- },
"route53": service{
PartitionEndpoint: "aws-us-gov-global",
IsRegionalized: boxedFalse,
@@ -28761,13 +27981,6 @@ var awsusgovPartition = partition{
},
},
},
- "sms-voice": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "us-gov-west-1",
- }: endpoint{},
- },
- },
"snowball": service{
Endpoints: serviceEndpoints{
endpointKey{
@@ -29183,42 +28396,12 @@ var awsusgovPartition = partition{
},
"synthetics": service{
Endpoints: serviceEndpoints{
- endpointKey{
- Region: "fips-us-gov-east-1",
- }: endpoint{
- Hostname: "synthetics-fips.us-gov-east-1.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-gov-east-1",
- },
- Deprecated: boxedTrue,
- },
- endpointKey{
- Region: "fips-us-gov-west-1",
- }: endpoint{
- Hostname: "synthetics-fips.us-gov-west-1.amazonaws.com",
- CredentialScope: credentialScope{
- Region: "us-gov-west-1",
- },
- Deprecated: boxedTrue,
- },
endpointKey{
Region: "us-gov-east-1",
}: endpoint{},
- endpointKey{
- Region: "us-gov-east-1",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "synthetics-fips.us-gov-east-1.amazonaws.com",
- },
endpointKey{
Region: "us-gov-west-1",
}: endpoint{},
- endpointKey{
- Region: "us-gov-west-1",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "synthetics-fips.us-gov-west-1.amazonaws.com",
- },
},
},
"tagging": service{
@@ -29583,13 +28766,6 @@ var awsisoPartition = partition{
}: endpoint{},
},
},
- "appconfigdata": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "us-iso-west-1",
- }: endpoint{},
- },
- },
"application-autoscaling": service{
Defaults: endpointDefaults{
defaultKey{}: endpoint{
@@ -29807,18 +28983,6 @@ var awsisoPartition = partition{
}: endpoint{},
},
},
- "eks": service{
- Defaults: endpointDefaults{
- defaultKey{}: endpoint{
- Protocols: []string{"http", "https"},
- },
- },
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "us-iso-east-1",
- }: endpoint{},
- },
- },
"elasticache": service{
Endpoints: serviceEndpoints{
endpointKey{
@@ -30488,18 +29652,6 @@ var awsisobPartition = partition{
}: endpoint{},
},
},
- "eks": service{
- Defaults: endpointDefaults{
- defaultKey{}: endpoint{
- Protocols: []string{"http", "https"},
- },
- },
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "us-isob-east-1",
- }: endpoint{},
- },
- },
"elasticache": service{
Endpoints: serviceEndpoints{
endpointKey{
@@ -30507,28 +29659,6 @@ var awsisobPartition = partition{
}: endpoint{},
},
},
- "elasticfilesystem": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "fips-us-isob-east-1",
- }: endpoint{
- Hostname: "elasticfilesystem-fips.us-isob-east-1.sc2s.sgov.gov",
- CredentialScope: credentialScope{
- Region: "us-isob-east-1",
- },
- Deprecated: boxedTrue,
- },
- endpointKey{
- Region: "us-isob-east-1",
- }: endpoint{},
- endpointKey{
- Region: "us-isob-east-1",
- Variant: fipsVariant,
- }: endpoint{
- Hostname: "elasticfilesystem-fips.us-isob-east-1.sc2s.sgov.gov",
- },
- },
- },
"elasticloadbalancing": service{
Endpoints: serviceEndpoints{
endpointKey{
@@ -30653,13 +29783,6 @@ var awsisobPartition = partition{
}: endpoint{},
},
},
- "ram": service{
- Endpoints: serviceEndpoints{
- endpointKey{
- Region: "us-isob-east-1",
- }: endpoint{},
- },
- },
"rds": service{
Endpoints: serviceEndpoints{
endpointKey{
diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go b/vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go
index 9556332b65e..e819ab6c0e8 100644
--- a/vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go
+++ b/vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go
@@ -330,9 +330,6 @@ func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) {
// WithSetRequestHeaders updates the operation request's HTTP header to contain
// the header key value pairs provided. If the header key already exists in the
// request's HTTP header set, the existing value(s) will be replaced.
-//
-// Header keys added will be added as canonical format with title casing
-// applied via http.Header.Set method.
func WithSetRequestHeaders(h map[string]string) Option {
return withRequestHeader(h).SetRequestHeaders
}
@@ -341,6 +338,6 @@ type withRequestHeader map[string]string
func (h withRequestHeader) SetRequestHeaders(r *Request) {
for k, v := range h {
- r.HTTPRequest.Header.Set(k, v)
+ r.HTTPRequest.Header[k] = []string{v}
}
}
diff --git a/vendor/github.com/aws/aws-sdk-go/aws/version.go b/vendor/github.com/aws/aws-sdk-go/aws/version.go
index 47386c4c985..c771b8c7cd9 100644
--- a/vendor/github.com/aws/aws-sdk-go/aws/version.go
+++ b/vendor/github.com/aws/aws-sdk-go/aws/version.go
@@ -5,4 +5,4 @@ package aws
const SDKName = "aws-sdk-go"
// SDKVersion is the version of this SDK
-const SDKVersion = "1.44.23"
+const SDKVersion = "1.43.31"
diff --git a/vendor/github.com/aws/aws-sdk-go/service/sts/api.go b/vendor/github.com/aws/aws-sdk-go/service/sts/api.go
index f1a7bfdd47b..718409b5498 100644
--- a/vendor/github.com/aws/aws-sdk-go/service/sts/api.go
+++ b/vendor/github.com/aws/aws-sdk-go/service/sts/api.go
@@ -1279,12 +1279,6 @@ func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request.
// and Comparing the Amazon Web Services STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison)
// in the IAM User Guide.
//
-// No permissions are required for users to perform this operation. The purpose
-// of the sts:GetSessionToken operation is to authenticate the user using MFA.
-// You cannot use policies to control authentication operations. For more information,
-// see Permissions for GetSessionToken (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_getsessiontoken.html)
-// in the IAM User Guide.
-//
// Session Duration
//
// The GetSessionToken operation must be called by using the long-term Amazon
diff --git a/vendor/github.com/cenkalti/backoff/v4/.gitignore b/vendor/github.com/cenkalti/backoff/v4/.gitignore
new file mode 100644
index 00000000000..50d95c548b6
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/.gitignore
@@ -0,0 +1,25 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+# IDEs
+.idea/
diff --git a/vendor/github.com/cenkalti/backoff/v4/LICENSE b/vendor/github.com/cenkalti/backoff/v4/LICENSE
new file mode 100644
index 00000000000..89b81799655
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Cenk Altı
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/cenkalti/backoff/v4/README.md b/vendor/github.com/cenkalti/backoff/v4/README.md
new file mode 100644
index 00000000000..16abdfc084f
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/README.md
@@ -0,0 +1,32 @@
+# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Build Status][travis image]][travis] [![Coverage Status][coveralls image]][coveralls]
+
+This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
+
+[Exponential backoff][exponential backoff wiki]
+is an algorithm that uses feedback to multiplicatively decrease the rate of some process,
+in order to gradually find an acceptable rate.
+The retries exponentially increase and stop increasing when a certain threshold is met.
+
+## Usage
+
+Import path is `github.com/cenkalti/backoff/v4`. Please note the version part at the end.
+
+Use https://pkg.go.dev/github.com/cenkalti/backoff/v4 to view the documentation.
+
+## Contributing
+
+* I would like to keep this library as small as possible.
+* Please don't send a PR without opening an issue and discussing it first.
+* If proposed change is not a common use case, I will probably not accept it.
+
+[godoc]: https://pkg.go.dev/github.com/cenkalti/backoff/v4
+[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
+[travis]: https://travis-ci.org/cenkalti/backoff
+[travis image]: https://travis-ci.org/cenkalti/backoff.png?branch=master
+[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
+[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
+
+[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java
+[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff
+
+[advanced example]: https://pkg.go.dev/github.com/cenkalti/backoff/v4?tab=doc#pkg-examples
diff --git a/vendor/github.com/cenkalti/backoff/v4/backoff.go b/vendor/github.com/cenkalti/backoff/v4/backoff.go
new file mode 100644
index 00000000000..3676ee405d8
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/backoff.go
@@ -0,0 +1,66 @@
+// Package backoff implements backoff algorithms for retrying operations.
+//
+// Use Retry function for retrying operations that may fail.
+// If Retry does not meet your needs,
+// copy/paste the function into your project and modify as you wish.
+//
+// There is also Ticker type similar to time.Ticker.
+// You can use it if you need to work with channels.
+//
+// See Examples section below for usage examples.
+package backoff
+
+import "time"
+
+// BackOff is a backoff policy for retrying an operation.
+type BackOff interface {
+ // NextBackOff returns the duration to wait before retrying the operation,
+ // or backoff. Stop to indicate that no more retries should be made.
+ //
+ // Example usage:
+ //
+ // duration := backoff.NextBackOff();
+ // if (duration == backoff.Stop) {
+ // // Do not retry operation.
+ // } else {
+ // // Sleep for duration and retry operation.
+ // }
+ //
+ NextBackOff() time.Duration
+
+ // Reset to initial state.
+ Reset()
+}
+
+// Stop indicates that no more retries should be made for use in NextBackOff().
+const Stop time.Duration = -1
+
+// ZeroBackOff is a fixed backoff policy whose backoff time is always zero,
+// meaning that the operation is retried immediately without waiting, indefinitely.
+type ZeroBackOff struct{}
+
+func (b *ZeroBackOff) Reset() {}
+
+func (b *ZeroBackOff) NextBackOff() time.Duration { return 0 }
+
+// StopBackOff is a fixed backoff policy that always returns backoff.Stop for
+// NextBackOff(), meaning that the operation should never be retried.
+type StopBackOff struct{}
+
+func (b *StopBackOff) Reset() {}
+
+func (b *StopBackOff) NextBackOff() time.Duration { return Stop }
+
+// ConstantBackOff is a backoff policy that always returns the same backoff delay.
+// This is in contrast to an exponential backoff policy,
+// which returns a delay that grows longer as you call NextBackOff() over and over again.
+type ConstantBackOff struct {
+ Interval time.Duration
+}
+
+func (b *ConstantBackOff) Reset() {}
+func (b *ConstantBackOff) NextBackOff() time.Duration { return b.Interval }
+
+func NewConstantBackOff(d time.Duration) *ConstantBackOff {
+ return &ConstantBackOff{Interval: d}
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/context.go b/vendor/github.com/cenkalti/backoff/v4/context.go
new file mode 100644
index 00000000000..48482330eb7
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/context.go
@@ -0,0 +1,62 @@
+package backoff
+
+import (
+ "context"
+ "time"
+)
+
+// BackOffContext is a backoff policy that stops retrying after the context
+// is canceled.
+type BackOffContext interface { // nolint: golint
+ BackOff
+ Context() context.Context
+}
+
+type backOffContext struct {
+ BackOff
+ ctx context.Context
+}
+
+// WithContext returns a BackOffContext with context ctx
+//
+// ctx must not be nil
+func WithContext(b BackOff, ctx context.Context) BackOffContext { // nolint: golint
+ if ctx == nil {
+ panic("nil context")
+ }
+
+ if b, ok := b.(*backOffContext); ok {
+ return &backOffContext{
+ BackOff: b.BackOff,
+ ctx: ctx,
+ }
+ }
+
+ return &backOffContext{
+ BackOff: b,
+ ctx: ctx,
+ }
+}
+
+func getContext(b BackOff) context.Context {
+ if cb, ok := b.(BackOffContext); ok {
+ return cb.Context()
+ }
+ if tb, ok := b.(*backOffTries); ok {
+ return getContext(tb.delegate)
+ }
+ return context.Background()
+}
+
+func (b *backOffContext) Context() context.Context {
+ return b.ctx
+}
+
+func (b *backOffContext) NextBackOff() time.Duration {
+ select {
+ case <-b.ctx.Done():
+ return Stop
+ default:
+ return b.BackOff.NextBackOff()
+ }
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/exponential.go b/vendor/github.com/cenkalti/backoff/v4/exponential.go
new file mode 100644
index 00000000000..2c56c1e7189
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/exponential.go
@@ -0,0 +1,161 @@
+package backoff
+
+import (
+ "math/rand"
+ "time"
+)
+
+/*
+ExponentialBackOff is a backoff implementation that increases the backoff
+period for each retry attempt using a randomization function that grows exponentially.
+
+NextBackOff() is calculated using the following formula:
+
+ randomized interval =
+ RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])
+
+In other words NextBackOff() will range between the randomization factor
+percentage below and above the retry interval.
+
+For example, given the following parameters:
+
+ RetryInterval = 2
+ RandomizationFactor = 0.5
+ Multiplier = 2
+
+the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
+multiplied by the exponential, that is, between 2 and 6 seconds.
+
+Note: MaxInterval caps the RetryInterval and not the randomized interval.
+
+If the time elapsed since an ExponentialBackOff instance is created goes past the
+MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop.
+
+The elapsed time can be reset by calling Reset().
+
+Example: Given the following default arguments, for 10 tries the sequence will be,
+and assuming we go over the MaxElapsedTime on the 10th try:
+
+ Request # RetryInterval (seconds) Randomized Interval (seconds)
+
+ 1 0.5 [0.25, 0.75]
+ 2 0.75 [0.375, 1.125]
+ 3 1.125 [0.562, 1.687]
+ 4 1.687 [0.8435, 2.53]
+ 5 2.53 [1.265, 3.795]
+ 6 3.795 [1.897, 5.692]
+ 7 5.692 [2.846, 8.538]
+ 8 8.538 [4.269, 12.807]
+ 9 12.807 [6.403, 19.210]
+ 10 19.210 backoff.Stop
+
+Note: Implementation is not thread-safe.
+*/
+type ExponentialBackOff struct {
+ InitialInterval time.Duration
+ RandomizationFactor float64
+ Multiplier float64
+ MaxInterval time.Duration
+ // After MaxElapsedTime the ExponentialBackOff returns Stop.
+ // It never stops if MaxElapsedTime == 0.
+ MaxElapsedTime time.Duration
+ Stop time.Duration
+ Clock Clock
+
+ currentInterval time.Duration
+ startTime time.Time
+}
+
+// Clock is an interface that returns current time for BackOff.
+type Clock interface {
+ Now() time.Time
+}
+
+// Default values for ExponentialBackOff.
+const (
+ DefaultInitialInterval = 500 * time.Millisecond
+ DefaultRandomizationFactor = 0.5
+ DefaultMultiplier = 1.5
+ DefaultMaxInterval = 60 * time.Second
+ DefaultMaxElapsedTime = 15 * time.Minute
+)
+
+// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
+func NewExponentialBackOff() *ExponentialBackOff {
+ b := &ExponentialBackOff{
+ InitialInterval: DefaultInitialInterval,
+ RandomizationFactor: DefaultRandomizationFactor,
+ Multiplier: DefaultMultiplier,
+ MaxInterval: DefaultMaxInterval,
+ MaxElapsedTime: DefaultMaxElapsedTime,
+ Stop: Stop,
+ Clock: SystemClock,
+ }
+ b.Reset()
+ return b
+}
+
+type systemClock struct{}
+
+func (t systemClock) Now() time.Time {
+ return time.Now()
+}
+
+// SystemClock implements Clock interface that uses time.Now().
+var SystemClock = systemClock{}
+
+// Reset the interval back to the initial retry interval and restarts the timer.
+// Reset must be called before using b.
+func (b *ExponentialBackOff) Reset() {
+ b.currentInterval = b.InitialInterval
+ b.startTime = b.Clock.Now()
+}
+
+// NextBackOff calculates the next backoff interval using the formula:
+// Randomized interval = RetryInterval * (1 ± RandomizationFactor)
+func (b *ExponentialBackOff) NextBackOff() time.Duration {
+ // Make sure we have not gone over the maximum elapsed time.
+ elapsed := b.GetElapsedTime()
+ next := getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
+ b.incrementCurrentInterval()
+ if b.MaxElapsedTime != 0 && elapsed+next > b.MaxElapsedTime {
+ return b.Stop
+ }
+ return next
+}
+
+// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
+// is created and is reset when Reset() is called.
+//
+// The elapsed time is computed using time.Now().UnixNano(). It is
+// safe to call even while the backoff policy is used by a running
+// ticker.
+func (b *ExponentialBackOff) GetElapsedTime() time.Duration {
+ return b.Clock.Now().Sub(b.startTime)
+}
+
+// Increments the current interval by multiplying it with the multiplier.
+func (b *ExponentialBackOff) incrementCurrentInterval() {
+ // Check for overflow, if overflow is detected set the current interval to the max interval.
+ if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {
+ b.currentInterval = b.MaxInterval
+ } else {
+ b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)
+ }
+}
+
+// Returns a random value from the following interval:
+// [currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].
+func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
+ if randomizationFactor == 0 {
+ return currentInterval // make sure no randomness is used when randomizationFactor is 0.
+ }
+ var delta = randomizationFactor * float64(currentInterval)
+ var minInterval = float64(currentInterval) - delta
+ var maxInterval = float64(currentInterval) + delta
+
+ // Get a random value from the range [minInterval, maxInterval].
+ // The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
+ // we want a 33% chance for selecting either 1, 2 or 3.
+ return time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/retry.go b/vendor/github.com/cenkalti/backoff/v4/retry.go
new file mode 100644
index 00000000000..b9c0c51cd75
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/retry.go
@@ -0,0 +1,146 @@
+package backoff
+
+import (
+ "errors"
+ "time"
+)
+
+// An OperationWithData is executing by RetryWithData() or RetryNotifyWithData().
+// The operation will be retried using a backoff policy if it returns an error.
+type OperationWithData[T any] func() (T, error)
+
+// An Operation is executing by Retry() or RetryNotify().
+// The operation will be retried using a backoff policy if it returns an error.
+type Operation func() error
+
+func (o Operation) withEmptyData() OperationWithData[struct{}] {
+ return func() (struct{}, error) {
+ return struct{}{}, o()
+ }
+}
+
+// Notify is a notify-on-error function. It receives an operation error and
+// backoff delay if the operation failed (with an error).
+//
+// NOTE that if the backoff policy stated to stop retrying,
+// the notify function isn't called.
+type Notify func(error, time.Duration)
+
+// Retry the operation o until it does not return error or BackOff stops.
+// o is guaranteed to be run at least once.
+//
+// If o returns a *PermanentError, the operation is not retried, and the
+// wrapped error is returned.
+//
+// Retry sleeps the goroutine for the duration returned by BackOff after a
+// failed operation returns.
+func Retry(o Operation, b BackOff) error {
+ return RetryNotify(o, b, nil)
+}
+
+// RetryWithData is like Retry but returns data in the response too.
+func RetryWithData[T any](o OperationWithData[T], b BackOff) (T, error) {
+ return RetryNotifyWithData(o, b, nil)
+}
+
+// RetryNotify calls notify function with the error and wait duration
+// for each failed attempt before sleep.
+func RetryNotify(operation Operation, b BackOff, notify Notify) error {
+ return RetryNotifyWithTimer(operation, b, notify, nil)
+}
+
+// RetryNotifyWithData is like RetryNotify but returns data in the response too.
+func RetryNotifyWithData[T any](operation OperationWithData[T], b BackOff, notify Notify) (T, error) {
+ return doRetryNotify(operation, b, notify, nil)
+}
+
+// RetryNotifyWithTimer calls notify function with the error and wait duration using the given Timer
+// for each failed attempt before sleep.
+// A default timer that uses system timer is used when nil is passed.
+func RetryNotifyWithTimer(operation Operation, b BackOff, notify Notify, t Timer) error {
+ _, err := doRetryNotify(operation.withEmptyData(), b, notify, t)
+ return err
+}
+
+// RetryNotifyWithTimerAndData is like RetryNotifyWithTimer but returns data in the response too.
+func RetryNotifyWithTimerAndData[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
+ return doRetryNotify(operation, b, notify, t)
+}
+
+func doRetryNotify[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
+ var (
+ err error
+ next time.Duration
+ res T
+ )
+ if t == nil {
+ t = &defaultTimer{}
+ }
+
+ defer func() {
+ t.Stop()
+ }()
+
+ ctx := getContext(b)
+
+ b.Reset()
+ for {
+ res, err = operation()
+ if err == nil {
+ return res, nil
+ }
+
+ var permanent *PermanentError
+ if errors.As(err, &permanent) {
+ return res, permanent.Err
+ }
+
+ if next = b.NextBackOff(); next == Stop {
+ if cerr := ctx.Err(); cerr != nil {
+ return res, cerr
+ }
+
+ return res, err
+ }
+
+ if notify != nil {
+ notify(err, next)
+ }
+
+ t.Start(next)
+
+ select {
+ case <-ctx.Done():
+ return res, ctx.Err()
+ case <-t.C():
+ }
+ }
+}
+
+// PermanentError signals that the operation should not be retried.
+type PermanentError struct {
+ Err error
+}
+
+func (e *PermanentError) Error() string {
+ return e.Err.Error()
+}
+
+func (e *PermanentError) Unwrap() error {
+ return e.Err
+}
+
+func (e *PermanentError) Is(target error) bool {
+ _, ok := target.(*PermanentError)
+ return ok
+}
+
+// Permanent wraps the given err in a *PermanentError.
+func Permanent(err error) error {
+ if err == nil {
+ return nil
+ }
+ return &PermanentError{
+ Err: err,
+ }
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/ticker.go b/vendor/github.com/cenkalti/backoff/v4/ticker.go
new file mode 100644
index 00000000000..df9d68bce52
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/ticker.go
@@ -0,0 +1,97 @@
+package backoff
+
+import (
+ "context"
+ "sync"
+ "time"
+)
+
+// Ticker holds a channel that delivers `ticks' of a clock at times reported by a BackOff.
+//
+// Ticks will continue to arrive when the previous operation is still running,
+// so operations that take a while to fail could run in quick succession.
+type Ticker struct {
+ C <-chan time.Time
+ c chan time.Time
+ b BackOff
+ ctx context.Context
+ timer Timer
+ stop chan struct{}
+ stopOnce sync.Once
+}
+
+// NewTicker returns a new Ticker containing a channel that will send
+// the time at times specified by the BackOff argument. Ticker is
+// guaranteed to tick at least once. The channel is closed when Stop
+// method is called or BackOff stops. It is not safe to manipulate the
+// provided backoff policy (notably calling NextBackOff or Reset)
+// while the ticker is running.
+func NewTicker(b BackOff) *Ticker {
+ return NewTickerWithTimer(b, &defaultTimer{})
+}
+
+// NewTickerWithTimer returns a new Ticker with a custom timer.
+// A default timer that uses system timer is used when nil is passed.
+func NewTickerWithTimer(b BackOff, timer Timer) *Ticker {
+ if timer == nil {
+ timer = &defaultTimer{}
+ }
+ c := make(chan time.Time)
+ t := &Ticker{
+ C: c,
+ c: c,
+ b: b,
+ ctx: getContext(b),
+ timer: timer,
+ stop: make(chan struct{}),
+ }
+ t.b.Reset()
+ go t.run()
+ return t
+}
+
+// Stop turns off a ticker. After Stop, no more ticks will be sent.
+func (t *Ticker) Stop() {
+ t.stopOnce.Do(func() { close(t.stop) })
+}
+
+func (t *Ticker) run() {
+ c := t.c
+ defer close(c)
+
+ // Ticker is guaranteed to tick at least once.
+ afterC := t.send(time.Now())
+
+ for {
+ if afterC == nil {
+ return
+ }
+
+ select {
+ case tick := <-afterC:
+ afterC = t.send(tick)
+ case <-t.stop:
+ t.c = nil // Prevent future ticks from being sent to the channel.
+ return
+ case <-t.ctx.Done():
+ return
+ }
+ }
+}
+
+func (t *Ticker) send(tick time.Time) <-chan time.Time {
+ select {
+ case t.c <- tick:
+ case <-t.stop:
+ return nil
+ }
+
+ next := t.b.NextBackOff()
+ if next == Stop {
+ t.Stop()
+ return nil
+ }
+
+ t.timer.Start(next)
+ return t.timer.C()
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/timer.go b/vendor/github.com/cenkalti/backoff/v4/timer.go
new file mode 100644
index 00000000000..8120d0213c5
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/timer.go
@@ -0,0 +1,35 @@
+package backoff
+
+import "time"
+
+type Timer interface {
+ Start(duration time.Duration)
+ Stop()
+ C() <-chan time.Time
+}
+
+// defaultTimer implements Timer interface using time.Timer
+type defaultTimer struct {
+ timer *time.Timer
+}
+
+// C returns the timers channel which receives the current time when the timer fires.
+func (t *defaultTimer) C() <-chan time.Time {
+ return t.timer.C
+}
+
+// Start starts the timer to fire after the given duration
+func (t *defaultTimer) Start(duration time.Duration) {
+ if t.timer == nil {
+ t.timer = time.NewTimer(duration)
+ } else {
+ t.timer.Reset(duration)
+ }
+}
+
+// Stop is called when the timer is not used anymore and resources may be freed.
+func (t *defaultTimer) Stop() {
+ if t.timer != nil {
+ t.timer.Stop()
+ }
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/tries.go b/vendor/github.com/cenkalti/backoff/v4/tries.go
new file mode 100644
index 00000000000..28d58ca37c6
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/tries.go
@@ -0,0 +1,38 @@
+package backoff
+
+import "time"
+
+/*
+WithMaxRetries creates a wrapper around another BackOff, which will
+return Stop if NextBackOff() has been called too many times since
+the last time Reset() was called
+
+Note: Implementation is not thread-safe.
+*/
+func WithMaxRetries(b BackOff, max uint64) BackOff {
+ return &backOffTries{delegate: b, maxTries: max}
+}
+
+type backOffTries struct {
+ delegate BackOff
+ maxTries uint64
+ numTries uint64
+}
+
+func (b *backOffTries) NextBackOff() time.Duration {
+ if b.maxTries == 0 {
+ return Stop
+ }
+ if b.maxTries > 0 {
+ if b.maxTries <= b.numTries {
+ return Stop
+ }
+ b.numTries++
+ }
+ return b.delegate.NextBackOff()
+}
+
+func (b *backOffTries) Reset() {
+ b.numTries = 0
+ b.delegate.Reset()
+}
diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1/common.pb.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1/common.pb.go
index 875b06813e4..9cacb32acb9 100644
--- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1/common.pb.go
+++ b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1/common.pb.go
@@ -14,8 +14,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.25.0
-// protoc v3.12.3
+// protoc-gen-go v1.26.0
+// protoc v3.17.3
// source: opencensus/proto/agent/common/v1/common.proto
// NOTE: This proto is experimental and is subject to change at this point.
@@ -24,10 +24,9 @@
package v1
import (
- proto "github.com/golang/protobuf/proto"
- timestamp "github.com/golang/protobuf/ptypes/timestamp"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
)
@@ -39,10 +38,6 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
type LibraryInfo_Language int32
const (
@@ -207,7 +202,7 @@ type ProcessIdentifier struct {
// Process id.
Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"`
// Start time of this ProcessIdentifier. Represented in epoch time.
- StartTimestamp *timestamp.Timestamp `protobuf:"bytes,3,opt,name=start_timestamp,json=startTimestamp,proto3" json:"start_timestamp,omitempty"`
+ StartTimestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=start_timestamp,json=startTimestamp,proto3" json:"start_timestamp,omitempty"`
}
func (x *ProcessIdentifier) Reset() {
@@ -256,7 +251,7 @@ func (x *ProcessIdentifier) GetPid() uint32 {
return 0
}
-func (x *ProcessIdentifier) GetStartTimestamp() *timestamp.Timestamp {
+func (x *ProcessIdentifier) GetStartTimestamp() *timestamppb.Timestamp {
if x != nil {
return x.StartTimestamp
}
@@ -447,7 +442,7 @@ var file_opencensus_proto_agent_common_v1_common_proto_rawDesc = []byte{
0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x57, 0x45, 0x42, 0x5f, 0x4a, 0x53, 0x10, 0x0a, 0x22, 0x21,
0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
- 0x65, 0x42, 0xa2, 0x01, 0x0a, 0x23, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x65, 0x6e,
+ 0x65, 0x42, 0xa6, 0x01, 0x0a, 0x23, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x65, 0x6e,
0x73, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x49, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
@@ -455,9 +450,10 @@ var file_opencensus_proto_agent_common_v1_common_proto_rawDesc = []byte{
0x72, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x65, 0x6e,
0x63, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e,
0x2d, 0x67, 0x6f, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
- 0x2f, 0x76, 0x31, 0xea, 0x02, 0x20, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x65, 0x6e, 0x73, 0x75, 0x73,
- 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6d,
- 0x6d, 0x6f, 0x6e, 0x2e, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x2f, 0x76, 0x31, 0xea, 0x02, 0x24, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x65, 0x6e, 0x73, 0x75, 0x73,
+ 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3a, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x3a,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x33,
}
var (
@@ -475,13 +471,13 @@ func file_opencensus_proto_agent_common_v1_common_proto_rawDescGZIP() []byte {
var file_opencensus_proto_agent_common_v1_common_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_opencensus_proto_agent_common_v1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_opencensus_proto_agent_common_v1_common_proto_goTypes = []interface{}{
- (LibraryInfo_Language)(0), // 0: opencensus.proto.agent.common.v1.LibraryInfo.Language
- (*Node)(nil), // 1: opencensus.proto.agent.common.v1.Node
- (*ProcessIdentifier)(nil), // 2: opencensus.proto.agent.common.v1.ProcessIdentifier
- (*LibraryInfo)(nil), // 3: opencensus.proto.agent.common.v1.LibraryInfo
- (*ServiceInfo)(nil), // 4: opencensus.proto.agent.common.v1.ServiceInfo
- nil, // 5: opencensus.proto.agent.common.v1.Node.AttributesEntry
- (*timestamp.Timestamp)(nil), // 6: google.protobuf.Timestamp
+ (LibraryInfo_Language)(0), // 0: opencensus.proto.agent.common.v1.LibraryInfo.Language
+ (*Node)(nil), // 1: opencensus.proto.agent.common.v1.Node
+ (*ProcessIdentifier)(nil), // 2: opencensus.proto.agent.common.v1.ProcessIdentifier
+ (*LibraryInfo)(nil), // 3: opencensus.proto.agent.common.v1.LibraryInfo
+ (*ServiceInfo)(nil), // 4: opencensus.proto.agent.common.v1.ServiceInfo
+ nil, // 5: opencensus.proto.agent.common.v1.Node.AttributesEntry
+ (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp
}
var file_opencensus_proto_agent_common_v1_common_proto_depIdxs = []int32{
2, // 0: opencensus.proto.agent.common.v1.Node.identifier:type_name -> opencensus.proto.agent.common.v1.ProcessIdentifier
diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1/metrics_service.pb.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1/metrics_service.pb.go
index bfb4389384c..4f9faffd9cc 100644
--- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1/metrics_service.pb.go
+++ b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1/metrics_service.pb.go
@@ -14,17 +14,20 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.25.0
-// protoc v3.12.3
+// protoc-gen-go v1.26.0
+// protoc v3.17.3
// source: opencensus/proto/agent/metrics/v1/metrics_service.proto
package v1
import (
+ context "context"
v1 "github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1"
v11 "github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1"
v12 "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1"
- proto "github.com/golang/protobuf/proto"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
@@ -38,10 +41,6 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
type ExportMetricsServiceRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -195,7 +194,7 @@ var file_opencensus_proto_agent_metrics_v1_metrics_service_proto_rawDesc = []byt
0x6f, 0x74, 0x6f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69,
0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0xad, 0x01, 0x0a, 0x24, 0x69, 0x6f, 0x2e, 0x6f,
+ 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0xb1, 0x01, 0x0a, 0x24, 0x69, 0x6f, 0x2e, 0x6f,
0x70, 0x65, 0x6e, 0x63, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31,
0x42, 0x13, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
@@ -204,9 +203,10 @@ var file_opencensus_proto_agent_metrics_v1_metrics_service_proto_rawDesc = []byt
0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63,
0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2d,
0x67, 0x6f, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
- 0x2f, 0x76, 0x31, 0xea, 0x02, 0x21, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x65, 0x6e, 0x73, 0x75, 0x73,
- 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x73, 0x2e, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x2f, 0x76, 0x31, 0xea, 0x02, 0x25, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x65, 0x6e, 0x73, 0x75, 0x73,
+ 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3a, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x3a,
+ 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
}
var (
@@ -292,3 +292,119 @@ func file_opencensus_proto_agent_metrics_v1_metrics_service_proto_init() {
file_opencensus_proto_agent_metrics_v1_metrics_service_proto_goTypes = nil
file_opencensus_proto_agent_metrics_v1_metrics_service_proto_depIdxs = nil
}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConnInterface
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion6
+
+// MetricsServiceClient is the client API for MetricsService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type MetricsServiceClient interface {
+ // For performance reasons, it is recommended to keep this RPC
+ // alive for the entire life of the application.
+ Export(ctx context.Context, opts ...grpc.CallOption) (MetricsService_ExportClient, error)
+}
+
+type metricsServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewMetricsServiceClient(cc grpc.ClientConnInterface) MetricsServiceClient {
+ return &metricsServiceClient{cc}
+}
+
+func (c *metricsServiceClient) Export(ctx context.Context, opts ...grpc.CallOption) (MetricsService_ExportClient, error) {
+ stream, err := c.cc.NewStream(ctx, &_MetricsService_serviceDesc.Streams[0], "/opencensus.proto.agent.metrics.v1.MetricsService/Export", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &metricsServiceExportClient{stream}
+ return x, nil
+}
+
+type MetricsService_ExportClient interface {
+ Send(*ExportMetricsServiceRequest) error
+ Recv() (*ExportMetricsServiceResponse, error)
+ grpc.ClientStream
+}
+
+type metricsServiceExportClient struct {
+ grpc.ClientStream
+}
+
+func (x *metricsServiceExportClient) Send(m *ExportMetricsServiceRequest) error {
+ return x.ClientStream.SendMsg(m)
+}
+
+func (x *metricsServiceExportClient) Recv() (*ExportMetricsServiceResponse, error) {
+ m := new(ExportMetricsServiceResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+// MetricsServiceServer is the server API for MetricsService service.
+type MetricsServiceServer interface {
+ // For performance reasons, it is recommended to keep this RPC
+ // alive for the entire life of the application.
+ Export(MetricsService_ExportServer) error
+}
+
+// UnimplementedMetricsServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedMetricsServiceServer struct {
+}
+
+func (*UnimplementedMetricsServiceServer) Export(MetricsService_ExportServer) error {
+ return status.Errorf(codes.Unimplemented, "method Export not implemented")
+}
+
+func RegisterMetricsServiceServer(s *grpc.Server, srv MetricsServiceServer) {
+ s.RegisterService(&_MetricsService_serviceDesc, srv)
+}
+
+func _MetricsService_Export_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(MetricsServiceServer).Export(&metricsServiceExportServer{stream})
+}
+
+type MetricsService_ExportServer interface {
+ Send(*ExportMetricsServiceResponse) error
+ Recv() (*ExportMetricsServiceRequest, error)
+ grpc.ServerStream
+}
+
+type metricsServiceExportServer struct {
+ grpc.ServerStream
+}
+
+func (x *metricsServiceExportServer) Send(m *ExportMetricsServiceResponse) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func (x *metricsServiceExportServer) Recv() (*ExportMetricsServiceRequest, error) {
+ m := new(ExportMetricsServiceRequest)
+ if err := x.ServerStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+var _MetricsService_serviceDesc = grpc.ServiceDesc{
+ ServiceName: "opencensus.proto.agent.metrics.v1.MetricsService",
+ HandlerType: (*MetricsServiceServer)(nil),
+ Methods: []grpc.MethodDesc{},
+ Streams: []grpc.StreamDesc{
+ {
+ StreamName: "Export",
+ Handler: _MetricsService_Export_Handler,
+ ServerStreams: true,
+ ClientStreams: true,
+ },
+ },
+ Metadata: "opencensus/proto/agent/metrics/v1/metrics_service.proto",
+}
diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1/metrics_service.pb.gw.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1/metrics_service.pb.gw.go
index 722e8efde42..3cc9bae4b93 100644
--- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1/metrics_service.pb.gw.go
+++ b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1/metrics_service.pb.gw.go
@@ -13,14 +13,14 @@ import (
"io"
"net/http"
- "github.com/golang/protobuf/descriptor"
- "github.com/golang/protobuf/proto"
- "github.com/grpc-ecosystem/grpc-gateway/runtime"
- "github.com/grpc-ecosystem/grpc-gateway/utilities"
+ "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
+ "github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
+ "google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
+ "google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
@@ -29,7 +29,7 @@ var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
-var _ = descriptor.ForMessage
+var _ = metadata.Join
func request_MetricsService_Export_0(ctx context.Context, marshaler runtime.Marshaler, client MetricsServiceClient, req *http.Request, pathParams map[string]string) (MetricsService_ExportClient, runtime.ServerMetadata, error) {
var metadata runtime.ServerMetadata
@@ -55,15 +55,6 @@ func request_MetricsService_Export_0(ctx context.Context, marshaler runtime.Mars
}
return nil
}
- if err := handleSend(); err != nil {
- if cerr := stream.CloseSend(); cerr != nil {
- grpclog.Infof("Failed to terminate client stream: %v", cerr)
- }
- if err == io.EOF {
- return stream, metadata, nil
- }
- return nil, metadata, err
- }
go func() {
for {
if err := handleSend(); err != nil {
@@ -86,6 +77,7 @@ func request_MetricsService_Export_0(ctx context.Context, marshaler runtime.Mars
// RegisterMetricsServiceHandlerServer registers the http handlers for service MetricsService to "mux".
// UnaryRPC :call MetricsServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
+// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterMetricsServiceHandlerFromEndpoint instead.
func RegisterMetricsServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server MetricsServiceServer) error {
mux.Handle("POST", pattern_MetricsService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
@@ -140,7 +132,7 @@ func RegisterMetricsServiceHandlerClient(ctx context.Context, mux *runtime.Serve
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
- rctx, err := runtime.AnnotateContext(ctx, mux, req)
+ rctx, err := runtime.AnnotateContext(ctx, mux, req, "/opencensus.proto.agent.metrics.v1.MetricsService/Export", runtime.WithHTTPPathPattern("/v1/metrics"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@@ -160,7 +152,7 @@ func RegisterMetricsServiceHandlerClient(ctx context.Context, mux *runtime.Serve
}
var (
- pattern_MetricsService_Export_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "metrics"}, "", runtime.AssumeColonVerbOpt(true)))
+ pattern_MetricsService_Export_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "metrics"}, ""))
)
var (
diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1/metrics_service_grpc.pb.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1/metrics_service_grpc.pb.go
deleted file mode 100644
index 0a600256e99..00000000000
--- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1/metrics_service_grpc.pb.go
+++ /dev/null
@@ -1,126 +0,0 @@
-// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
-
-package v1
-
-import (
- context "context"
- grpc "google.golang.org/grpc"
- codes "google.golang.org/grpc/codes"
- status "google.golang.org/grpc/status"
-)
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-const _ = grpc.SupportPackageIsVersion6
-
-// MetricsServiceClient is the client API for MetricsService service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
-type MetricsServiceClient interface {
- // For performance reasons, it is recommended to keep this RPC
- // alive for the entire life of the application.
- Export(ctx context.Context, opts ...grpc.CallOption) (MetricsService_ExportClient, error)
-}
-
-type metricsServiceClient struct {
- cc grpc.ClientConnInterface
-}
-
-func NewMetricsServiceClient(cc grpc.ClientConnInterface) MetricsServiceClient {
- return &metricsServiceClient{cc}
-}
-
-func (c *metricsServiceClient) Export(ctx context.Context, opts ...grpc.CallOption) (MetricsService_ExportClient, error) {
- stream, err := c.cc.NewStream(ctx, &_MetricsService_serviceDesc.Streams[0], "/opencensus.proto.agent.metrics.v1.MetricsService/Export", opts...)
- if err != nil {
- return nil, err
- }
- x := &metricsServiceExportClient{stream}
- return x, nil
-}
-
-type MetricsService_ExportClient interface {
- Send(*ExportMetricsServiceRequest) error
- Recv() (*ExportMetricsServiceResponse, error)
- grpc.ClientStream
-}
-
-type metricsServiceExportClient struct {
- grpc.ClientStream
-}
-
-func (x *metricsServiceExportClient) Send(m *ExportMetricsServiceRequest) error {
- return x.ClientStream.SendMsg(m)
-}
-
-func (x *metricsServiceExportClient) Recv() (*ExportMetricsServiceResponse, error) {
- m := new(ExportMetricsServiceResponse)
- if err := x.ClientStream.RecvMsg(m); err != nil {
- return nil, err
- }
- return m, nil
-}
-
-// MetricsServiceServer is the server API for MetricsService service.
-// All implementations must embed UnimplementedMetricsServiceServer
-// for forward compatibility
-type MetricsServiceServer interface {
- // For performance reasons, it is recommended to keep this RPC
- // alive for the entire life of the application.
- Export(MetricsService_ExportServer) error
- mustEmbedUnimplementedMetricsServiceServer()
-}
-
-// UnimplementedMetricsServiceServer must be embedded to have forward compatible implementations.
-type UnimplementedMetricsServiceServer struct {
-}
-
-func (*UnimplementedMetricsServiceServer) Export(MetricsService_ExportServer) error {
- return status.Errorf(codes.Unimplemented, "method Export not implemented")
-}
-func (*UnimplementedMetricsServiceServer) mustEmbedUnimplementedMetricsServiceServer() {}
-
-func RegisterMetricsServiceServer(s *grpc.Server, srv MetricsServiceServer) {
- s.RegisterService(&_MetricsService_serviceDesc, srv)
-}
-
-func _MetricsService_Export_Handler(srv interface{}, stream grpc.ServerStream) error {
- return srv.(MetricsServiceServer).Export(&metricsServiceExportServer{stream})
-}
-
-type MetricsService_ExportServer interface {
- Send(*ExportMetricsServiceResponse) error
- Recv() (*ExportMetricsServiceRequest, error)
- grpc.ServerStream
-}
-
-type metricsServiceExportServer struct {
- grpc.ServerStream
-}
-
-func (x *metricsServiceExportServer) Send(m *ExportMetricsServiceResponse) error {
- return x.ServerStream.SendMsg(m)
-}
-
-func (x *metricsServiceExportServer) Recv() (*ExportMetricsServiceRequest, error) {
- m := new(ExportMetricsServiceRequest)
- if err := x.ServerStream.RecvMsg(m); err != nil {
- return nil, err
- }
- return m, nil
-}
-
-var _MetricsService_serviceDesc = grpc.ServiceDesc{
- ServiceName: "opencensus.proto.agent.metrics.v1.MetricsService",
- HandlerType: (*MetricsServiceServer)(nil),
- Methods: []grpc.MethodDesc{},
- Streams: []grpc.StreamDesc{
- {
- StreamName: "Export",
- Handler: _MetricsService_Export_Handler,
- ServerStreams: true,
- ClientStreams: true,
- },
- },
- Metadata: "opencensus/proto/agent/metrics/v1/metrics_service.proto",
-}
diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1/trace_service.pb.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1/trace_service.pb.go
index 0eed170b80c..c713bfb4f7e 100644
--- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1/trace_service.pb.go
+++ b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1/trace_service.pb.go
@@ -14,8 +14,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.25.0
-// protoc v3.12.3
+// protoc-gen-go v1.26.0
+// protoc v3.17.3
// source: opencensus/proto/agent/trace/v1/trace_service.proto
// NOTE: This proto is experimental and is subject to change at this point.
@@ -24,10 +24,13 @@
package v1
import (
+ context "context"
v1 "github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1"
v12 "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1"
v11 "github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1"
- proto "github.com/golang/protobuf/proto"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
@@ -41,10 +44,6 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
type CurrentLibraryConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -342,7 +341,7 @@ var file_opencensus_proto_agent_trace_v1_trace_service_proto_rawDesc = []byte{
0x6e, 0x63, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x61, 0x67,
0x65, 0x6e, 0x74, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70,
0x6f, 0x72, 0x74, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0xa5, 0x01,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0xa9, 0x01,
0x0a, 0x22, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x74, 0x72, 0x61, 0x63,
0x65, 0x2e, 0x76, 0x31, 0x42, 0x11, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69,
@@ -351,9 +350,10 @@ var file_opencensus_proto_agent_trace_v1_trace_service_proto_rawDesc = []byte{
0x74, 0x72, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x65,
0x6e, 0x63, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65,
0x6e, 0x2d, 0x67, 0x6f, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65,
- 0x2f, 0x76, 0x31, 0xea, 0x02, 0x1f, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x65, 0x6e, 0x73, 0x75, 0x73,
- 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x72, 0x61,
- 0x63, 0x65, 0x2e, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x2f, 0x76, 0x31, 0xea, 0x02, 0x23, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x65, 0x6e, 0x73, 0x75, 0x73,
+ 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3a, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x3a,
+ 0x54, 0x72, 0x61, 0x63, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x33,
}
var (
@@ -472,3 +472,193 @@ func file_opencensus_proto_agent_trace_v1_trace_service_proto_init() {
file_opencensus_proto_agent_trace_v1_trace_service_proto_goTypes = nil
file_opencensus_proto_agent_trace_v1_trace_service_proto_depIdxs = nil
}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConnInterface
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion6
+
+// TraceServiceClient is the client API for TraceService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type TraceServiceClient interface {
+ // After initialization, this RPC must be kept alive for the entire life of
+ // the application. The agent pushes configs down to applications via a
+ // stream.
+ Config(ctx context.Context, opts ...grpc.CallOption) (TraceService_ConfigClient, error)
+ // For performance reasons, it is recommended to keep this RPC
+ // alive for the entire life of the application.
+ Export(ctx context.Context, opts ...grpc.CallOption) (TraceService_ExportClient, error)
+}
+
+type traceServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewTraceServiceClient(cc grpc.ClientConnInterface) TraceServiceClient {
+ return &traceServiceClient{cc}
+}
+
+func (c *traceServiceClient) Config(ctx context.Context, opts ...grpc.CallOption) (TraceService_ConfigClient, error) {
+ stream, err := c.cc.NewStream(ctx, &_TraceService_serviceDesc.Streams[0], "/opencensus.proto.agent.trace.v1.TraceService/Config", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &traceServiceConfigClient{stream}
+ return x, nil
+}
+
+type TraceService_ConfigClient interface {
+ Send(*CurrentLibraryConfig) error
+ Recv() (*UpdatedLibraryConfig, error)
+ grpc.ClientStream
+}
+
+type traceServiceConfigClient struct {
+ grpc.ClientStream
+}
+
+func (x *traceServiceConfigClient) Send(m *CurrentLibraryConfig) error {
+ return x.ClientStream.SendMsg(m)
+}
+
+func (x *traceServiceConfigClient) Recv() (*UpdatedLibraryConfig, error) {
+ m := new(UpdatedLibraryConfig)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (c *traceServiceClient) Export(ctx context.Context, opts ...grpc.CallOption) (TraceService_ExportClient, error) {
+ stream, err := c.cc.NewStream(ctx, &_TraceService_serviceDesc.Streams[1], "/opencensus.proto.agent.trace.v1.TraceService/Export", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &traceServiceExportClient{stream}
+ return x, nil
+}
+
+type TraceService_ExportClient interface {
+ Send(*ExportTraceServiceRequest) error
+ Recv() (*ExportTraceServiceResponse, error)
+ grpc.ClientStream
+}
+
+type traceServiceExportClient struct {
+ grpc.ClientStream
+}
+
+func (x *traceServiceExportClient) Send(m *ExportTraceServiceRequest) error {
+ return x.ClientStream.SendMsg(m)
+}
+
+func (x *traceServiceExportClient) Recv() (*ExportTraceServiceResponse, error) {
+ m := new(ExportTraceServiceResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+// TraceServiceServer is the server API for TraceService service.
+type TraceServiceServer interface {
+ // After initialization, this RPC must be kept alive for the entire life of
+ // the application. The agent pushes configs down to applications via a
+ // stream.
+ Config(TraceService_ConfigServer) error
+ // For performance reasons, it is recommended to keep this RPC
+ // alive for the entire life of the application.
+ Export(TraceService_ExportServer) error
+}
+
+// UnimplementedTraceServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedTraceServiceServer struct {
+}
+
+func (*UnimplementedTraceServiceServer) Config(TraceService_ConfigServer) error {
+ return status.Errorf(codes.Unimplemented, "method Config not implemented")
+}
+func (*UnimplementedTraceServiceServer) Export(TraceService_ExportServer) error {
+ return status.Errorf(codes.Unimplemented, "method Export not implemented")
+}
+
+func RegisterTraceServiceServer(s *grpc.Server, srv TraceServiceServer) {
+ s.RegisterService(&_TraceService_serviceDesc, srv)
+}
+
+func _TraceService_Config_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(TraceServiceServer).Config(&traceServiceConfigServer{stream})
+}
+
+type TraceService_ConfigServer interface {
+ Send(*UpdatedLibraryConfig) error
+ Recv() (*CurrentLibraryConfig, error)
+ grpc.ServerStream
+}
+
+type traceServiceConfigServer struct {
+ grpc.ServerStream
+}
+
+func (x *traceServiceConfigServer) Send(m *UpdatedLibraryConfig) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func (x *traceServiceConfigServer) Recv() (*CurrentLibraryConfig, error) {
+ m := new(CurrentLibraryConfig)
+ if err := x.ServerStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func _TraceService_Export_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(TraceServiceServer).Export(&traceServiceExportServer{stream})
+}
+
+type TraceService_ExportServer interface {
+ Send(*ExportTraceServiceResponse) error
+ Recv() (*ExportTraceServiceRequest, error)
+ grpc.ServerStream
+}
+
+type traceServiceExportServer struct {
+ grpc.ServerStream
+}
+
+func (x *traceServiceExportServer) Send(m *ExportTraceServiceResponse) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func (x *traceServiceExportServer) Recv() (*ExportTraceServiceRequest, error) {
+ m := new(ExportTraceServiceRequest)
+ if err := x.ServerStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+var _TraceService_serviceDesc = grpc.ServiceDesc{
+ ServiceName: "opencensus.proto.agent.trace.v1.TraceService",
+ HandlerType: (*TraceServiceServer)(nil),
+ Methods: []grpc.MethodDesc{},
+ Streams: []grpc.StreamDesc{
+ {
+ StreamName: "Config",
+ Handler: _TraceService_Config_Handler,
+ ServerStreams: true,
+ ClientStreams: true,
+ },
+ {
+ StreamName: "Export",
+ Handler: _TraceService_Export_Handler,
+ ServerStreams: true,
+ ClientStreams: true,
+ },
+ },
+ Metadata: "opencensus/proto/agent/trace/v1/trace_service.proto",
+}
diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1/trace_service.pb.gw.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1/trace_service.pb.gw.go
index 4733c404d0c..7808e9fb83b 100644
--- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1/trace_service.pb.gw.go
+++ b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1/trace_service.pb.gw.go
@@ -13,14 +13,14 @@ import (
"io"
"net/http"
- "github.com/golang/protobuf/descriptor"
- "github.com/golang/protobuf/proto"
- "github.com/grpc-ecosystem/grpc-gateway/runtime"
- "github.com/grpc-ecosystem/grpc-gateway/utilities"
+ "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
+ "github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
+ "google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
+ "google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
@@ -29,7 +29,7 @@ var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
-var _ = descriptor.ForMessage
+var _ = metadata.Join
func request_TraceService_Export_0(ctx context.Context, marshaler runtime.Marshaler, client TraceServiceClient, req *http.Request, pathParams map[string]string) (TraceService_ExportClient, runtime.ServerMetadata, error) {
var metadata runtime.ServerMetadata
@@ -55,15 +55,6 @@ func request_TraceService_Export_0(ctx context.Context, marshaler runtime.Marsha
}
return nil
}
- if err := handleSend(); err != nil {
- if cerr := stream.CloseSend(); cerr != nil {
- grpclog.Infof("Failed to terminate client stream: %v", cerr)
- }
- if err == io.EOF {
- return stream, metadata, nil
- }
- return nil, metadata, err
- }
go func() {
for {
if err := handleSend(); err != nil {
@@ -86,6 +77,7 @@ func request_TraceService_Export_0(ctx context.Context, marshaler runtime.Marsha
// RegisterTraceServiceHandlerServer registers the http handlers for service TraceService to "mux".
// UnaryRPC :call TraceServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
+// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterTraceServiceHandlerFromEndpoint instead.
func RegisterTraceServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server TraceServiceServer) error {
mux.Handle("POST", pattern_TraceService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
@@ -140,7 +132,7 @@ func RegisterTraceServiceHandlerClient(ctx context.Context, mux *runtime.ServeMu
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
- rctx, err := runtime.AnnotateContext(ctx, mux, req)
+ rctx, err := runtime.AnnotateContext(ctx, mux, req, "/opencensus.proto.agent.trace.v1.TraceService/Export", runtime.WithHTTPPathPattern("/v1/trace"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@@ -160,7 +152,7 @@ func RegisterTraceServiceHandlerClient(ctx context.Context, mux *runtime.ServeMu
}
var (
- pattern_TraceService_Export_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "trace"}, "", runtime.AssumeColonVerbOpt(true)))
+ pattern_TraceService_Export_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "trace"}, ""))
)
var (
diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1/trace_service_grpc.pb.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1/trace_service_grpc.pb.go
deleted file mode 100644
index 90bda0aaa4a..00000000000
--- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1/trace_service_grpc.pb.go
+++ /dev/null
@@ -1,200 +0,0 @@
-// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
-
-package v1
-
-import (
- context "context"
- grpc "google.golang.org/grpc"
- codes "google.golang.org/grpc/codes"
- status "google.golang.org/grpc/status"
-)
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-const _ = grpc.SupportPackageIsVersion6
-
-// TraceServiceClient is the client API for TraceService service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
-type TraceServiceClient interface {
- // After initialization, this RPC must be kept alive for the entire life of
- // the application. The agent pushes configs down to applications via a
- // stream.
- Config(ctx context.Context, opts ...grpc.CallOption) (TraceService_ConfigClient, error)
- // For performance reasons, it is recommended to keep this RPC
- // alive for the entire life of the application.
- Export(ctx context.Context, opts ...grpc.CallOption) (TraceService_ExportClient, error)
-}
-
-type traceServiceClient struct {
- cc grpc.ClientConnInterface
-}
-
-func NewTraceServiceClient(cc grpc.ClientConnInterface) TraceServiceClient {
- return &traceServiceClient{cc}
-}
-
-func (c *traceServiceClient) Config(ctx context.Context, opts ...grpc.CallOption) (TraceService_ConfigClient, error) {
- stream, err := c.cc.NewStream(ctx, &_TraceService_serviceDesc.Streams[0], "/opencensus.proto.agent.trace.v1.TraceService/Config", opts...)
- if err != nil {
- return nil, err
- }
- x := &traceServiceConfigClient{stream}
- return x, nil
-}
-
-type TraceService_ConfigClient interface {
- Send(*CurrentLibraryConfig) error
- Recv() (*UpdatedLibraryConfig, error)
- grpc.ClientStream
-}
-
-type traceServiceConfigClient struct {
- grpc.ClientStream
-}
-
-func (x *traceServiceConfigClient) Send(m *CurrentLibraryConfig) error {
- return x.ClientStream.SendMsg(m)
-}
-
-func (x *traceServiceConfigClient) Recv() (*UpdatedLibraryConfig, error) {
- m := new(UpdatedLibraryConfig)
- if err := x.ClientStream.RecvMsg(m); err != nil {
- return nil, err
- }
- return m, nil
-}
-
-func (c *traceServiceClient) Export(ctx context.Context, opts ...grpc.CallOption) (TraceService_ExportClient, error) {
- stream, err := c.cc.NewStream(ctx, &_TraceService_serviceDesc.Streams[1], "/opencensus.proto.agent.trace.v1.TraceService/Export", opts...)
- if err != nil {
- return nil, err
- }
- x := &traceServiceExportClient{stream}
- return x, nil
-}
-
-type TraceService_ExportClient interface {
- Send(*ExportTraceServiceRequest) error
- Recv() (*ExportTraceServiceResponse, error)
- grpc.ClientStream
-}
-
-type traceServiceExportClient struct {
- grpc.ClientStream
-}
-
-func (x *traceServiceExportClient) Send(m *ExportTraceServiceRequest) error {
- return x.ClientStream.SendMsg(m)
-}
-
-func (x *traceServiceExportClient) Recv() (*ExportTraceServiceResponse, error) {
- m := new(ExportTraceServiceResponse)
- if err := x.ClientStream.RecvMsg(m); err != nil {
- return nil, err
- }
- return m, nil
-}
-
-// TraceServiceServer is the server API for TraceService service.
-// All implementations must embed UnimplementedTraceServiceServer
-// for forward compatibility
-type TraceServiceServer interface {
- // After initialization, this RPC must be kept alive for the entire life of
- // the application. The agent pushes configs down to applications via a
- // stream.
- Config(TraceService_ConfigServer) error
- // For performance reasons, it is recommended to keep this RPC
- // alive for the entire life of the application.
- Export(TraceService_ExportServer) error
- mustEmbedUnimplementedTraceServiceServer()
-}
-
-// UnimplementedTraceServiceServer must be embedded to have forward compatible implementations.
-type UnimplementedTraceServiceServer struct {
-}
-
-func (*UnimplementedTraceServiceServer) Config(TraceService_ConfigServer) error {
- return status.Errorf(codes.Unimplemented, "method Config not implemented")
-}
-func (*UnimplementedTraceServiceServer) Export(TraceService_ExportServer) error {
- return status.Errorf(codes.Unimplemented, "method Export not implemented")
-}
-func (*UnimplementedTraceServiceServer) mustEmbedUnimplementedTraceServiceServer() {}
-
-func RegisterTraceServiceServer(s *grpc.Server, srv TraceServiceServer) {
- s.RegisterService(&_TraceService_serviceDesc, srv)
-}
-
-func _TraceService_Config_Handler(srv interface{}, stream grpc.ServerStream) error {
- return srv.(TraceServiceServer).Config(&traceServiceConfigServer{stream})
-}
-
-type TraceService_ConfigServer interface {
- Send(*UpdatedLibraryConfig) error
- Recv() (*CurrentLibraryConfig, error)
- grpc.ServerStream
-}
-
-type traceServiceConfigServer struct {
- grpc.ServerStream
-}
-
-func (x *traceServiceConfigServer) Send(m *UpdatedLibraryConfig) error {
- return x.ServerStream.SendMsg(m)
-}
-
-func (x *traceServiceConfigServer) Recv() (*CurrentLibraryConfig, error) {
- m := new(CurrentLibraryConfig)
- if err := x.ServerStream.RecvMsg(m); err != nil {
- return nil, err
- }
- return m, nil
-}
-
-func _TraceService_Export_Handler(srv interface{}, stream grpc.ServerStream) error {
- return srv.(TraceServiceServer).Export(&traceServiceExportServer{stream})
-}
-
-type TraceService_ExportServer interface {
- Send(*ExportTraceServiceResponse) error
- Recv() (*ExportTraceServiceRequest, error)
- grpc.ServerStream
-}
-
-type traceServiceExportServer struct {
- grpc.ServerStream
-}
-
-func (x *traceServiceExportServer) Send(m *ExportTraceServiceResponse) error {
- return x.ServerStream.SendMsg(m)
-}
-
-func (x *traceServiceExportServer) Recv() (*ExportTraceServiceRequest, error) {
- m := new(ExportTraceServiceRequest)
- if err := x.ServerStream.RecvMsg(m); err != nil {
- return nil, err
- }
- return m, nil
-}
-
-var _TraceService_serviceDesc = grpc.ServiceDesc{
- ServiceName: "opencensus.proto.agent.trace.v1.TraceService",
- HandlerType: (*TraceServiceServer)(nil),
- Methods: []grpc.MethodDesc{},
- Streams: []grpc.StreamDesc{
- {
- StreamName: "Config",
- Handler: _TraceService_Config_Handler,
- ServerStreams: true,
- ClientStreams: true,
- },
- {
- StreamName: "Export",
- Handler: _TraceService_Export_Handler,
- ServerStreams: true,
- ClientStreams: true,
- },
- },
- Metadata: "opencensus/proto/agent/trace/v1/trace_service.proto",
-}
diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1/metrics.pb.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1/metrics.pb.go
index 30f758322b1..0cac88b2a54 100644
--- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1/metrics.pb.go
+++ b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1/metrics.pb.go
@@ -19,19 +19,18 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.25.0
-// protoc v3.12.3
+// protoc-gen-go v1.26.0
+// protoc v3.17.3
// source: opencensus/proto/metrics/v1/metrics.proto
package v1
import (
v1 "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1"
- proto "github.com/golang/protobuf/proto"
- timestamp "github.com/golang/protobuf/ptypes/timestamp"
- wrappers "github.com/golang/protobuf/ptypes/wrappers"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+ wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
reflect "reflect"
sync "sync"
)
@@ -43,10 +42,6 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
// The kind of metric. It describes how the data is reported.
//
// A gauge is an instantaneous measurement of a value.
@@ -364,7 +359,7 @@ type TimeSeries struct {
// was reset to zero. Exclusive. The cumulative value is over the time interval
// (start_timestamp, timestamp]. If not specified, the backend can use the
// previous recorded value.
- StartTimestamp *timestamp.Timestamp `protobuf:"bytes,1,opt,name=start_timestamp,json=startTimestamp,proto3" json:"start_timestamp,omitempty"`
+ StartTimestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=start_timestamp,json=startTimestamp,proto3" json:"start_timestamp,omitempty"`
// The set of label values that uniquely identify this timeseries. Applies to
// all points. The order of label values must match that of label keys in the
// metric descriptor.
@@ -406,7 +401,7 @@ func (*TimeSeries) Descriptor() ([]byte, []int) {
return file_opencensus_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{3}
}
-func (x *TimeSeries) GetStartTimestamp() *timestamp.Timestamp {
+func (x *TimeSeries) GetStartTimestamp() *timestamppb.Timestamp {
if x != nil {
return x.StartTimestamp
}
@@ -493,7 +488,7 @@ type Point struct {
// The moment when this point was recorded. Inclusive.
// If not specified, the timestamp will be decided by the backend.
- Timestamp *timestamp.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+ Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
// The actual point value.
//
// Types that are assignable to Value:
@@ -536,7 +531,7 @@ func (*Point) Descriptor() ([]byte, []int) {
return file_opencensus_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{5}
}
-func (x *Point) GetTimestamp() *timestamp.Timestamp {
+func (x *Point) GetTimestamp() *timestamppb.Timestamp {
if x != nil {
return x.Timestamp
}
@@ -721,11 +716,11 @@ type SummaryValue struct {
// The total number of recorded values since start_time. Optional since
// some systems don't expose this.
- Count *wrappers.Int64Value `protobuf:"bytes,1,opt,name=count,proto3" json:"count,omitempty"`
+ Count *wrapperspb.Int64Value `protobuf:"bytes,1,opt,name=count,proto3" json:"count,omitempty"`
// The total sum of recorded values since start_time. Optional since some
// systems don't expose this. If count is zero then this field must be zero.
// This field must be unset if the sum is not available.
- Sum *wrappers.DoubleValue `protobuf:"bytes,2,opt,name=sum,proto3" json:"sum,omitempty"`
+ Sum *wrapperspb.DoubleValue `protobuf:"bytes,2,opt,name=sum,proto3" json:"sum,omitempty"`
// Values calculated over an arbitrary time window.
Snapshot *SummaryValue_Snapshot `protobuf:"bytes,3,opt,name=snapshot,proto3" json:"snapshot,omitempty"`
}
@@ -762,14 +757,14 @@ func (*SummaryValue) Descriptor() ([]byte, []int) {
return file_opencensus_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{7}
}
-func (x *SummaryValue) GetCount() *wrappers.Int64Value {
+func (x *SummaryValue) GetCount() *wrapperspb.Int64Value {
if x != nil {
return x.Count
}
return nil
}
-func (x *SummaryValue) GetSum() *wrappers.DoubleValue {
+func (x *SummaryValue) GetSum() *wrapperspb.DoubleValue {
if x != nil {
return x.Sum
}
@@ -926,7 +921,7 @@ type DistributionValue_Exemplar struct {
// belongs to.
Value float64 `protobuf:"fixed64,1,opt,name=value,proto3" json:"value,omitempty"`
// The observation (sampling) time of the above value.
- Timestamp *timestamp.Timestamp `protobuf:"bytes,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+ Timestamp *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
// Contextual information about the example value.
Attachments map[string]string `protobuf:"bytes,3,rep,name=attachments,proto3" json:"attachments,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
@@ -970,7 +965,7 @@ func (x *DistributionValue_Exemplar) GetValue() float64 {
return 0
}
-func (x *DistributionValue_Exemplar) GetTimestamp() *timestamp.Timestamp {
+func (x *DistributionValue_Exemplar) GetTimestamp() *timestamppb.Timestamp {
if x != nil {
return x.Timestamp
}
@@ -1048,11 +1043,11 @@ type SummaryValue_Snapshot struct {
// The number of values in the snapshot. Optional since some systems don't
// expose this.
- Count *wrappers.Int64Value `protobuf:"bytes,1,opt,name=count,proto3" json:"count,omitempty"`
+ Count *wrapperspb.Int64Value `protobuf:"bytes,1,opt,name=count,proto3" json:"count,omitempty"`
// The sum of values in the snapshot. Optional since some systems don't
// expose this. If count is zero then this field must be zero or not set
// (if not supported).
- Sum *wrappers.DoubleValue `protobuf:"bytes,2,opt,name=sum,proto3" json:"sum,omitempty"`
+ Sum *wrapperspb.DoubleValue `protobuf:"bytes,2,opt,name=sum,proto3" json:"sum,omitempty"`
// A list of values at different percentiles of the distribution calculated
// from the current snapshot. The percentiles must be strictly increasing.
PercentileValues []*SummaryValue_Snapshot_ValueAtPercentile `protobuf:"bytes,3,rep,name=percentile_values,json=percentileValues,proto3" json:"percentile_values,omitempty"`
@@ -1090,14 +1085,14 @@ func (*SummaryValue_Snapshot) Descriptor() ([]byte, []int) {
return file_opencensus_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{7, 0}
}
-func (x *SummaryValue_Snapshot) GetCount() *wrappers.Int64Value {
+func (x *SummaryValue_Snapshot) GetCount() *wrapperspb.Int64Value {
if x != nil {
return x.Count
}
return nil
}
-func (x *SummaryValue_Snapshot) GetSum() *wrappers.DoubleValue {
+func (x *SummaryValue_Snapshot) GetSum() *wrapperspb.DoubleValue {
if x != nil {
return x.Sum
}
@@ -1351,7 +1346,7 @@ var file_opencensus_proto_metrics_v1_metrics_proto_rawDesc = []byte{
0x6c, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x69, 0x6c, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x69,
0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x94, 0x01, 0x0a, 0x1e, 0x69, 0x6f, 0x2e,
+ 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x97, 0x01, 0x0a, 0x1e, 0x69, 0x6f, 0x2e,
0x6f, 0x70, 0x65, 0x6e, 0x63, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x4d, 0x65, 0x74,
0x72, 0x69, 0x63, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74,
@@ -1359,9 +1354,9 @@ var file_opencensus_proto_metrics_v1_metrics_proto_rawDesc = []byte{
0x6e, 0x73, 0x74, 0x72, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f,
0x70, 0x65, 0x6e, 0x63, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x76,
- 0x31, 0xea, 0x02, 0x1b, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2e, 0x50,
- 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x56, 0x31, 0x62,
- 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x31, 0xea, 0x02, 0x1e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x3a, 0x3a,
+ 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3a, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x3a, 0x3a,
+ 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1396,9 +1391,9 @@ var file_opencensus_proto_metrics_v1_metrics_proto_goTypes = []interface{}{
(*SummaryValue_Snapshot)(nil), // 14: opencensus.proto.metrics.v1.SummaryValue.Snapshot
(*SummaryValue_Snapshot_ValueAtPercentile)(nil), // 15: opencensus.proto.metrics.v1.SummaryValue.Snapshot.ValueAtPercentile
(*v1.Resource)(nil), // 16: opencensus.proto.resource.v1.Resource
- (*timestamp.Timestamp)(nil), // 17: google.protobuf.Timestamp
- (*wrappers.Int64Value)(nil), // 18: google.protobuf.Int64Value
- (*wrappers.DoubleValue)(nil), // 19: google.protobuf.DoubleValue
+ (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp
+ (*wrapperspb.Int64Value)(nil), // 18: google.protobuf.Int64Value
+ (*wrapperspb.DoubleValue)(nil), // 19: google.protobuf.DoubleValue
}
var file_opencensus_proto_metrics_v1_metrics_proto_depIdxs = []int32{
2, // 0: opencensus.proto.metrics.v1.Metric.metric_descriptor:type_name -> opencensus.proto.metrics.v1.MetricDescriptor
diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1/resource.pb.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1/resource.pb.go
index 692746c049f..194dd70dfbd 100644
--- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1/resource.pb.go
+++ b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1/resource.pb.go
@@ -14,14 +14,13 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.25.0
-// protoc v3.12.3
+// protoc-gen-go v1.26.0
+// protoc v3.17.3
// source: opencensus/proto/resource/v1/resource.proto
package v1
import (
- proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
@@ -35,10 +34,6 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
// Resource information.
type Resource struct {
state protoimpl.MessageState
@@ -115,7 +110,7 @@ var file_opencensus_proto_resource_v1_resource_proto_rawDesc = []byte{
0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
- 0x02, 0x38, 0x01, 0x42, 0x98, 0x01, 0x0a, 0x1f, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63,
+ 0x02, 0x38, 0x01, 0x42, 0x9b, 0x01, 0x0a, 0x1f, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63,
0x65, 0x6e, 0x73, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
@@ -123,9 +118,9 @@ var file_opencensus_proto_resource_v1_resource_proto_rawDesc = []byte{
0x72, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x65, 0x6e,
0x63, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e,
0x2d, 0x67, 0x6f, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x76, 0x31, 0xea,
- 0x02, 0x1c, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2e, 0x50, 0x72, 0x6f,
- 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x56, 0x31, 0x62, 0x06,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x02, 0x1f, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x3a, 0x3a, 0x50, 0x72,
+ 0x6f, 0x74, 0x6f, 0x3a, 0x3a, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x3a, 0x56,
+ 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1/trace.pb.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1/trace.pb.go
index 66664fe11ee..d35612ca058 100644
--- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1/trace.pb.go
+++ b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1/trace.pb.go
@@ -14,19 +14,18 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.25.0
-// protoc v3.12.3
+// protoc-gen-go v1.26.0
+// protoc v3.17.3
// source: opencensus/proto/trace/v1/trace.proto
package v1
import (
v1 "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1"
- proto "github.com/golang/protobuf/proto"
- timestamp "github.com/golang/protobuf/ptypes/timestamp"
- wrappers "github.com/golang/protobuf/ptypes/wrappers"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+ wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
reflect "reflect"
sync "sync"
)
@@ -38,10 +37,6 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
// Type of span. Can be used to specify additional relationships between spans
// in addition to a parent/child relationship.
type Span_SpanKind int32
@@ -272,7 +267,7 @@ type Span struct {
// keep end_time > start_time for consistency.
//
// This field is required.
- StartTime *timestamp.Timestamp `protobuf:"bytes,5,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"`
+ StartTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"`
// The end time of the span. On the client side, this is the time kept by
// the local machine where the span execution ends. On the server side, this
// is the time when the server application handler stops running.
@@ -282,7 +277,7 @@ type Span struct {
// keep end_time > start_time for consistency.
//
// This field is required.
- EndTime *timestamp.Timestamp `protobuf:"bytes,6,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"`
+ EndTime *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"`
// A set of attributes on the span.
Attributes *Span_Attributes `protobuf:"bytes,7,opt,name=attributes,proto3" json:"attributes,omitempty"`
// A stack trace captured at the start of the span.
@@ -304,10 +299,10 @@ type Span struct {
// to the same process as the current span. This flag is most commonly
// used to indicate the need to adjust time as clocks in different
// processes may not be synchronized.
- SameProcessAsParentSpan *wrappers.BoolValue `protobuf:"bytes,12,opt,name=same_process_as_parent_span,json=sameProcessAsParentSpan,proto3" json:"same_process_as_parent_span,omitempty"`
+ SameProcessAsParentSpan *wrapperspb.BoolValue `protobuf:"bytes,12,opt,name=same_process_as_parent_span,json=sameProcessAsParentSpan,proto3" json:"same_process_as_parent_span,omitempty"`
// An optional number of child spans that were generated while this span
// was active. If set, allows an implementation to detect missing child spans.
- ChildSpanCount *wrappers.UInt32Value `protobuf:"bytes,13,opt,name=child_span_count,json=childSpanCount,proto3" json:"child_span_count,omitempty"`
+ ChildSpanCount *wrapperspb.UInt32Value `protobuf:"bytes,13,opt,name=child_span_count,json=childSpanCount,proto3" json:"child_span_count,omitempty"`
}
func (x *Span) Reset() {
@@ -384,14 +379,14 @@ func (x *Span) GetKind() Span_SpanKind {
return Span_SPAN_KIND_UNSPECIFIED
}
-func (x *Span) GetStartTime() *timestamp.Timestamp {
+func (x *Span) GetStartTime() *timestamppb.Timestamp {
if x != nil {
return x.StartTime
}
return nil
}
-func (x *Span) GetEndTime() *timestamp.Timestamp {
+func (x *Span) GetEndTime() *timestamppb.Timestamp {
if x != nil {
return x.EndTime
}
@@ -440,14 +435,14 @@ func (x *Span) GetResource() *v1.Resource {
return nil
}
-func (x *Span) GetSameProcessAsParentSpan() *wrappers.BoolValue {
+func (x *Span) GetSameProcessAsParentSpan() *wrapperspb.BoolValue {
if x != nil {
return x.SameProcessAsParentSpan
}
return nil
}
-func (x *Span) GetChildSpanCount() *wrappers.UInt32Value {
+func (x *Span) GetChildSpanCount() *wrapperspb.UInt32Value {
if x != nil {
return x.ChildSpanCount
}
@@ -952,7 +947,7 @@ type Span_TimeEvent struct {
unknownFields protoimpl.UnknownFields
// The time the event occurred.
- Time *timestamp.Timestamp `protobuf:"bytes,1,opt,name=time,proto3" json:"time,omitempty"`
+ Time *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=time,proto3" json:"time,omitempty"`
// A `TimeEvent` can contain either an `Annotation` object or a
// `MessageEvent` object, but not both.
//
@@ -994,7 +989,7 @@ func (*Span_TimeEvent) Descriptor() ([]byte, []int) {
return file_opencensus_proto_trace_v1_trace_proto_rawDescGZIP(), []int{0, 2}
}
-func (x *Span_TimeEvent) GetTime() *timestamp.Timestamp {
+func (x *Span_TimeEvent) GetTime() *timestamppb.Timestamp {
if x != nil {
return x.Time
}
@@ -1899,16 +1894,16 @@ var file_opencensus_proto_trace_v1_trace_proto_rawDesc = []byte{
0x6c, 0x75, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64,
0x5f, 0x62, 0x79, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
0x05, 0x52, 0x12, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65,
- 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x8c, 0x01, 0x0a, 0x1c, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65,
+ 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x8f, 0x01, 0x0a, 0x1c, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65,
0x6e, 0x63, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72,
0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x54, 0x72, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f,
0x74, 0x6f, 0x50, 0x01, 0x5a, 0x42, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x63, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x6d, 0x65,
0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x65, 0x6e, 0x73,
0x75, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2f,
- 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x76, 0x31, 0xea, 0x02, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x43,
- 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x72, 0x61, 0x63,
- 0x65, 0x2e, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x76, 0x31, 0xea, 0x02, 0x1c, 0x4f, 0x70, 0x65, 0x6e, 0x43,
+ 0x65, 0x6e, 0x73, 0x75, 0x73, 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3a, 0x54, 0x72,
+ 0x61, 0x63, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1947,10 +1942,10 @@ var file_opencensus_proto_trace_v1_trace_proto_goTypes = []interface{}{
(*Span_TimeEvent_MessageEvent)(nil), // 18: opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent
(*StackTrace_StackFrame)(nil), // 19: opencensus.proto.trace.v1.StackTrace.StackFrame
(*StackTrace_StackFrames)(nil), // 20: opencensus.proto.trace.v1.StackTrace.StackFrames
- (*timestamp.Timestamp)(nil), // 21: google.protobuf.Timestamp
+ (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp
(*v1.Resource)(nil), // 22: opencensus.proto.resource.v1.Resource
- (*wrappers.BoolValue)(nil), // 23: google.protobuf.BoolValue
- (*wrappers.UInt32Value)(nil), // 24: google.protobuf.UInt32Value
+ (*wrapperspb.BoolValue)(nil), // 23: google.protobuf.BoolValue
+ (*wrapperspb.UInt32Value)(nil), // 24: google.protobuf.UInt32Value
}
var file_opencensus_proto_trace_v1_trace_proto_depIdxs = []int32{
9, // 0: opencensus.proto.trace.v1.Span.tracestate:type_name -> opencensus.proto.trace.v1.Span.Tracestate
diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1/trace_config.pb.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1/trace_config.pb.go
index 0c19a4d2c9a..ee62b2e358e 100644
--- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1/trace_config.pb.go
+++ b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1/trace_config.pb.go
@@ -14,14 +14,13 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.25.0
-// protoc v3.12.3
+// protoc-gen-go v1.26.0
+// protoc v3.17.3
// source: opencensus/proto/trace/v1/trace_config.proto
package v1
import (
- proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
@@ -35,10 +34,6 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
// How spans should be sampled:
// - Always off
// - Always on
@@ -432,7 +427,7 @@ var file_opencensus_proto_trace_v1_trace_config_proto_rawDesc = []byte{
0x12, 0x11, 0x0a, 0x0d, 0x41, 0x4c, 0x57, 0x41, 0x59, 0x53, 0x5f, 0x50, 0x41, 0x52, 0x45, 0x4e,
0x54, 0x10, 0x02, 0x22, 0x27, 0x0a, 0x13, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74,
0x69, 0x6e, 0x67, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x71, 0x70,
- 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x71, 0x70, 0x73, 0x42, 0x92, 0x01, 0x0a,
+ 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x71, 0x70, 0x73, 0x42, 0x95, 0x01, 0x0a,
0x1c, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x10, 0x54,
0x72, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50,
@@ -440,9 +435,9 @@ var file_opencensus_proto_trace_v1_trace_config_proto_rawDesc = []byte{
0x6e, 0x73, 0x75, 0x73, 0x2d, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2f, 0x74, 0x72, 0x61,
- 0x63, 0x65, 0x2f, 0x76, 0x31, 0xea, 0x02, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x65, 0x6e, 0x73,
- 0x75, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x56,
- 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x63, 0x65, 0x2f, 0x76, 0x31, 0xea, 0x02, 0x1c, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x65, 0x6e, 0x73,
+ 0x75, 0x73, 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3a, 0x54, 0x72, 0x61, 0x63, 0x65,
+ 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/github.com/cespare/xxhash/v2/README.md b/vendor/github.com/cespare/xxhash/v2/README.md
index 792b4a60b34..8bf0e5b7815 100644
--- a/vendor/github.com/cespare/xxhash/v2/README.md
+++ b/vendor/github.com/cespare/xxhash/v2/README.md
@@ -3,8 +3,7 @@
[](https://pkg.go.dev/github.com/cespare/xxhash/v2)
[](https://github.com/cespare/xxhash/actions/workflows/test.yml)
-xxhash is a Go implementation of the 64-bit
-[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
+xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a
high-quality hashing algorithm that is much faster than anything in the Go
standard library.
@@ -25,8 +24,11 @@ func (*Digest) WriteString(string) (int, error)
func (*Digest) Sum64() uint64
```
-This implementation provides a fast pure-Go implementation and an even faster
-assembly implementation for amd64.
+The package is written with optimized pure Go and also contains even faster
+assembly implementations for amd64 and arm64. If desired, the `purego` build tag
+opts into using the Go code even on those architectures.
+
+[xxHash]: http://cyan4973.github.io/xxHash/
## Compatibility
@@ -45,19 +47,20 @@ I recommend using the latest release of Go.
Here are some quick benchmarks comparing the pure-Go and assembly
implementations of Sum64.
-| input size | purego | asm |
-| --- | --- | --- |
-| 5 B | 979.66 MB/s | 1291.17 MB/s |
-| 100 B | 7475.26 MB/s | 7973.40 MB/s |
-| 4 KB | 17573.46 MB/s | 17602.65 MB/s |
-| 10 MB | 17131.46 MB/s | 17142.16 MB/s |
+| input size | purego | asm |
+| ---------- | --------- | --------- |
+| 4 B | 1.3 GB/s | 1.2 GB/s |
+| 16 B | 2.9 GB/s | 3.5 GB/s |
+| 100 B | 6.9 GB/s | 8.1 GB/s |
+| 4 KB | 11.7 GB/s | 16.7 GB/s |
+| 10 MB | 12.0 GB/s | 17.3 GB/s |
-These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using
-the following commands under Go 1.11.2:
+These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
+CPU using the following commands under Go 1.19.2:
```
-$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes'
-$ go test -benchtime 10s -bench '/xxhash,direct,bytes'
+benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
+benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
```
## Projects using this package
diff --git a/vendor/github.com/cespare/xxhash/v2/testall.sh b/vendor/github.com/cespare/xxhash/v2/testall.sh
new file mode 100644
index 00000000000..94b9c443987
--- /dev/null
+++ b/vendor/github.com/cespare/xxhash/v2/testall.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -eu -o pipefail
+
+# Small convenience script for running the tests with various combinations of
+# arch/tags. This assumes we're running on amd64 and have qemu available.
+
+go test ./...
+go test -tags purego ./...
+GOARCH=arm64 go test
+GOARCH=arm64 go test -tags purego
diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash.go b/vendor/github.com/cespare/xxhash/v2/xxhash.go
index 15c835d5417..a9e0d45c9dc 100644
--- a/vendor/github.com/cespare/xxhash/v2/xxhash.go
+++ b/vendor/github.com/cespare/xxhash/v2/xxhash.go
@@ -16,19 +16,11 @@ const (
prime5 uint64 = 2870177450012600261
)
-// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where
-// possible in the Go code is worth a small (but measurable) performance boost
-// by avoiding some MOVQs. Vars are needed for the asm and also are useful for
-// convenience in the Go code in a few places where we need to intentionally
-// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the
-// result overflows a uint64).
-var (
- prime1v = prime1
- prime2v = prime2
- prime3v = prime3
- prime4v = prime4
- prime5v = prime5
-)
+// Store the primes in an array as well.
+//
+// The consts are used when possible in Go code to avoid MOVs but we need a
+// contiguous array of the assembly code.
+var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
// Digest implements hash.Hash64.
type Digest struct {
@@ -50,10 +42,10 @@ func New() *Digest {
// Reset clears the Digest's state so that it can be reused.
func (d *Digest) Reset() {
- d.v1 = prime1v + prime2
+ d.v1 = primes[0] + prime2
d.v2 = prime2
d.v3 = 0
- d.v4 = -prime1v
+ d.v4 = -primes[0]
d.total = 0
d.n = 0
}
@@ -69,21 +61,23 @@ func (d *Digest) Write(b []byte) (n int, err error) {
n = len(b)
d.total += uint64(n)
+ memleft := d.mem[d.n&(len(d.mem)-1):]
+
if d.n+n < 32 {
// This new data doesn't even fill the current block.
- copy(d.mem[d.n:], b)
+ copy(memleft, b)
d.n += n
return
}
if d.n > 0 {
// Finish off the partial block.
- copy(d.mem[d.n:], b)
+ c := copy(memleft, b)
d.v1 = round(d.v1, u64(d.mem[0:8]))
d.v2 = round(d.v2, u64(d.mem[8:16]))
d.v3 = round(d.v3, u64(d.mem[16:24]))
d.v4 = round(d.v4, u64(d.mem[24:32]))
- b = b[32-d.n:]
+ b = b[c:]
d.n = 0
}
@@ -133,21 +127,20 @@ func (d *Digest) Sum64() uint64 {
h += d.total
- i, end := 0, d.n
- for ; i+8 <= end; i += 8 {
- k1 := round(0, u64(d.mem[i:i+8]))
+ b := d.mem[:d.n&(len(d.mem)-1)]
+ for ; len(b) >= 8; b = b[8:] {
+ k1 := round(0, u64(b[:8]))
h ^= k1
h = rol27(h)*prime1 + prime4
}
- if i+4 <= end {
- h ^= uint64(u32(d.mem[i:i+4])) * prime1
+ if len(b) >= 4 {
+ h ^= uint64(u32(b[:4])) * prime1
h = rol23(h)*prime2 + prime3
- i += 4
+ b = b[4:]
}
- for i < end {
- h ^= uint64(d.mem[i]) * prime5
+ for ; len(b) > 0; b = b[1:] {
+ h ^= uint64(b[0]) * prime5
h = rol11(h) * prime1
- i++
}
h ^= h >> 33
diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go b/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go
deleted file mode 100644
index ad14b807f4d..00000000000
--- a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// +build !appengine
-// +build gc
-// +build !purego
-
-package xxhash
-
-// Sum64 computes the 64-bit xxHash digest of b.
-//
-//go:noescape
-func Sum64(b []byte) uint64
-
-//go:noescape
-func writeBlocks(d *Digest, b []byte) int
diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s b/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
index be8db5bf796..3e8b132579e 100644
--- a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
+++ b/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
@@ -1,215 +1,209 @@
+//go:build !appengine && gc && !purego
// +build !appengine
// +build gc
// +build !purego
#include "textflag.h"
-// Register allocation:
-// AX h
-// SI pointer to advance through b
-// DX n
-// BX loop end
-// R8 v1, k1
-// R9 v2
-// R10 v3
-// R11 v4
-// R12 tmp
-// R13 prime1v
-// R14 prime2v
-// DI prime4v
-
-// round reads from and advances the buffer pointer in SI.
-// It assumes that R13 has prime1v and R14 has prime2v.
-#define round(r) \
- MOVQ (SI), R12 \
- ADDQ $8, SI \
- IMULQ R14, R12 \
- ADDQ R12, r \
- ROLQ $31, r \
- IMULQ R13, r
-
-// mergeRound applies a merge round on the two registers acc and val.
-// It assumes that R13 has prime1v, R14 has prime2v, and DI has prime4v.
-#define mergeRound(acc, val) \
- IMULQ R14, val \
- ROLQ $31, val \
- IMULQ R13, val \
- XORQ val, acc \
- IMULQ R13, acc \
- ADDQ DI, acc
+// Registers:
+#define h AX
+#define d AX
+#define p SI // pointer to advance through b
+#define n DX
+#define end BX // loop end
+#define v1 R8
+#define v2 R9
+#define v3 R10
+#define v4 R11
+#define x R12
+#define prime1 R13
+#define prime2 R14
+#define prime4 DI
+
+#define round(acc, x) \
+ IMULQ prime2, x \
+ ADDQ x, acc \
+ ROLQ $31, acc \
+ IMULQ prime1, acc
+
+// round0 performs the operation x = round(0, x).
+#define round0(x) \
+ IMULQ prime2, x \
+ ROLQ $31, x \
+ IMULQ prime1, x
+
+// mergeRound applies a merge round on the two registers acc and x.
+// It assumes that prime1, prime2, and prime4 have been loaded.
+#define mergeRound(acc, x) \
+ round0(x) \
+ XORQ x, acc \
+ IMULQ prime1, acc \
+ ADDQ prime4, acc
+
+// blockLoop processes as many 32-byte blocks as possible,
+// updating v1, v2, v3, and v4. It assumes that there is at least one block
+// to process.
+#define blockLoop() \
+loop: \
+ MOVQ +0(p), x \
+ round(v1, x) \
+ MOVQ +8(p), x \
+ round(v2, x) \
+ MOVQ +16(p), x \
+ round(v3, x) \
+ MOVQ +24(p), x \
+ round(v4, x) \
+ ADDQ $32, p \
+ CMPQ p, end \
+ JLE loop
// func Sum64(b []byte) uint64
-TEXT ·Sum64(SB), NOSPLIT, $0-32
+TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
// Load fixed primes.
- MOVQ ·prime1v(SB), R13
- MOVQ ·prime2v(SB), R14
- MOVQ ·prime4v(SB), DI
+ MOVQ ·primes+0(SB), prime1
+ MOVQ ·primes+8(SB), prime2
+ MOVQ ·primes+24(SB), prime4
// Load slice.
- MOVQ b_base+0(FP), SI
- MOVQ b_len+8(FP), DX
- LEAQ (SI)(DX*1), BX
+ MOVQ b_base+0(FP), p
+ MOVQ b_len+8(FP), n
+ LEAQ (p)(n*1), end
// The first loop limit will be len(b)-32.
- SUBQ $32, BX
+ SUBQ $32, end
// Check whether we have at least one block.
- CMPQ DX, $32
+ CMPQ n, $32
JLT noBlocks
// Set up initial state (v1, v2, v3, v4).
- MOVQ R13, R8
- ADDQ R14, R8
- MOVQ R14, R9
- XORQ R10, R10
- XORQ R11, R11
- SUBQ R13, R11
-
- // Loop until SI > BX.
-blockLoop:
- round(R8)
- round(R9)
- round(R10)
- round(R11)
-
- CMPQ SI, BX
- JLE blockLoop
-
- MOVQ R8, AX
- ROLQ $1, AX
- MOVQ R9, R12
- ROLQ $7, R12
- ADDQ R12, AX
- MOVQ R10, R12
- ROLQ $12, R12
- ADDQ R12, AX
- MOVQ R11, R12
- ROLQ $18, R12
- ADDQ R12, AX
-
- mergeRound(AX, R8)
- mergeRound(AX, R9)
- mergeRound(AX, R10)
- mergeRound(AX, R11)
+ MOVQ prime1, v1
+ ADDQ prime2, v1
+ MOVQ prime2, v2
+ XORQ v3, v3
+ XORQ v4, v4
+ SUBQ prime1, v4
+
+ blockLoop()
+
+ MOVQ v1, h
+ ROLQ $1, h
+ MOVQ v2, x
+ ROLQ $7, x
+ ADDQ x, h
+ MOVQ v3, x
+ ROLQ $12, x
+ ADDQ x, h
+ MOVQ v4, x
+ ROLQ $18, x
+ ADDQ x, h
+
+ mergeRound(h, v1)
+ mergeRound(h, v2)
+ mergeRound(h, v3)
+ mergeRound(h, v4)
JMP afterBlocks
noBlocks:
- MOVQ ·prime5v(SB), AX
+ MOVQ ·primes+32(SB), h
afterBlocks:
- ADDQ DX, AX
-
- // Right now BX has len(b)-32, and we want to loop until SI > len(b)-8.
- ADDQ $24, BX
-
- CMPQ SI, BX
- JG fourByte
-
-wordLoop:
- // Calculate k1.
- MOVQ (SI), R8
- ADDQ $8, SI
- IMULQ R14, R8
- ROLQ $31, R8
- IMULQ R13, R8
-
- XORQ R8, AX
- ROLQ $27, AX
- IMULQ R13, AX
- ADDQ DI, AX
-
- CMPQ SI, BX
- JLE wordLoop
-
-fourByte:
- ADDQ $4, BX
- CMPQ SI, BX
- JG singles
-
- MOVL (SI), R8
- ADDQ $4, SI
- IMULQ R13, R8
- XORQ R8, AX
-
- ROLQ $23, AX
- IMULQ R14, AX
- ADDQ ·prime3v(SB), AX
-
-singles:
- ADDQ $4, BX
- CMPQ SI, BX
+ ADDQ n, h
+
+ ADDQ $24, end
+ CMPQ p, end
+ JG try4
+
+loop8:
+ MOVQ (p), x
+ ADDQ $8, p
+ round0(x)
+ XORQ x, h
+ ROLQ $27, h
+ IMULQ prime1, h
+ ADDQ prime4, h
+
+ CMPQ p, end
+ JLE loop8
+
+try4:
+ ADDQ $4, end
+ CMPQ p, end
+ JG try1
+
+ MOVL (p), x
+ ADDQ $4, p
+ IMULQ prime1, x
+ XORQ x, h
+
+ ROLQ $23, h
+ IMULQ prime2, h
+ ADDQ ·primes+16(SB), h
+
+try1:
+ ADDQ $4, end
+ CMPQ p, end
JGE finalize
-singlesLoop:
- MOVBQZX (SI), R12
- ADDQ $1, SI
- IMULQ ·prime5v(SB), R12
- XORQ R12, AX
+loop1:
+ MOVBQZX (p), x
+ ADDQ $1, p
+ IMULQ ·primes+32(SB), x
+ XORQ x, h
+ ROLQ $11, h
+ IMULQ prime1, h
- ROLQ $11, AX
- IMULQ R13, AX
-
- CMPQ SI, BX
- JL singlesLoop
+ CMPQ p, end
+ JL loop1
finalize:
- MOVQ AX, R12
- SHRQ $33, R12
- XORQ R12, AX
- IMULQ R14, AX
- MOVQ AX, R12
- SHRQ $29, R12
- XORQ R12, AX
- IMULQ ·prime3v(SB), AX
- MOVQ AX, R12
- SHRQ $32, R12
- XORQ R12, AX
-
- MOVQ AX, ret+24(FP)
+ MOVQ h, x
+ SHRQ $33, x
+ XORQ x, h
+ IMULQ prime2, h
+ MOVQ h, x
+ SHRQ $29, x
+ XORQ x, h
+ IMULQ ·primes+16(SB), h
+ MOVQ h, x
+ SHRQ $32, x
+ XORQ x, h
+
+ MOVQ h, ret+24(FP)
RET
-// writeBlocks uses the same registers as above except that it uses AX to store
-// the d pointer.
-
// func writeBlocks(d *Digest, b []byte) int
-TEXT ·writeBlocks(SB), NOSPLIT, $0-40
+TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
// Load fixed primes needed for round.
- MOVQ ·prime1v(SB), R13
- MOVQ ·prime2v(SB), R14
+ MOVQ ·primes+0(SB), prime1
+ MOVQ ·primes+8(SB), prime2
// Load slice.
- MOVQ b_base+8(FP), SI
- MOVQ b_len+16(FP), DX
- LEAQ (SI)(DX*1), BX
- SUBQ $32, BX
+ MOVQ b_base+8(FP), p
+ MOVQ b_len+16(FP), n
+ LEAQ (p)(n*1), end
+ SUBQ $32, end
// Load vN from d.
- MOVQ d+0(FP), AX
- MOVQ 0(AX), R8 // v1
- MOVQ 8(AX), R9 // v2
- MOVQ 16(AX), R10 // v3
- MOVQ 24(AX), R11 // v4
+ MOVQ s+0(FP), d
+ MOVQ 0(d), v1
+ MOVQ 8(d), v2
+ MOVQ 16(d), v3
+ MOVQ 24(d), v4
// We don't need to check the loop condition here; this function is
// always called with at least one block of data to process.
-blockLoop:
- round(R8)
- round(R9)
- round(R10)
- round(R11)
-
- CMPQ SI, BX
- JLE blockLoop
+ blockLoop()
// Copy vN back to d.
- MOVQ R8, 0(AX)
- MOVQ R9, 8(AX)
- MOVQ R10, 16(AX)
- MOVQ R11, 24(AX)
-
- // The number of bytes written is SI minus the old base pointer.
- SUBQ b_base+8(FP), SI
- MOVQ SI, ret+32(FP)
+ MOVQ v1, 0(d)
+ MOVQ v2, 8(d)
+ MOVQ v3, 16(d)
+ MOVQ v4, 24(d)
+
+ // The number of bytes written is p minus the old base pointer.
+ SUBQ b_base+8(FP), p
+ MOVQ p, ret+32(FP)
RET
diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s b/vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s
new file mode 100644
index 00000000000..7e3145a2218
--- /dev/null
+++ b/vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s
@@ -0,0 +1,183 @@
+//go:build !appengine && gc && !purego
+// +build !appengine
+// +build gc
+// +build !purego
+
+#include "textflag.h"
+
+// Registers:
+#define digest R1
+#define h R2 // return value
+#define p R3 // input pointer
+#define n R4 // input length
+#define nblocks R5 // n / 32
+#define prime1 R7
+#define prime2 R8
+#define prime3 R9
+#define prime4 R10
+#define prime5 R11
+#define v1 R12
+#define v2 R13
+#define v3 R14
+#define v4 R15
+#define x1 R20
+#define x2 R21
+#define x3 R22
+#define x4 R23
+
+#define round(acc, x) \
+ MADD prime2, acc, x, acc \
+ ROR $64-31, acc \
+ MUL prime1, acc
+
+// round0 performs the operation x = round(0, x).
+#define round0(x) \
+ MUL prime2, x \
+ ROR $64-31, x \
+ MUL prime1, x
+
+#define mergeRound(acc, x) \
+ round0(x) \
+ EOR x, acc \
+ MADD acc, prime4, prime1, acc
+
+// blockLoop processes as many 32-byte blocks as possible,
+// updating v1, v2, v3, and v4. It assumes that n >= 32.
+#define blockLoop() \
+ LSR $5, n, nblocks \
+ PCALIGN $16 \
+ loop: \
+ LDP.P 16(p), (x1, x2) \
+ LDP.P 16(p), (x3, x4) \
+ round(v1, x1) \
+ round(v2, x2) \
+ round(v3, x3) \
+ round(v4, x4) \
+ SUB $1, nblocks \
+ CBNZ nblocks, loop
+
+// func Sum64(b []byte) uint64
+TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
+ LDP b_base+0(FP), (p, n)
+
+ LDP ·primes+0(SB), (prime1, prime2)
+ LDP ·primes+16(SB), (prime3, prime4)
+ MOVD ·primes+32(SB), prime5
+
+ CMP $32, n
+ CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 }
+ BLT afterLoop
+
+ ADD prime1, prime2, v1
+ MOVD prime2, v2
+ MOVD $0, v3
+ NEG prime1, v4
+
+ blockLoop()
+
+ ROR $64-1, v1, x1
+ ROR $64-7, v2, x2
+ ADD x1, x2
+ ROR $64-12, v3, x3
+ ROR $64-18, v4, x4
+ ADD x3, x4
+ ADD x2, x4, h
+
+ mergeRound(h, v1)
+ mergeRound(h, v2)
+ mergeRound(h, v3)
+ mergeRound(h, v4)
+
+afterLoop:
+ ADD n, h
+
+ TBZ $4, n, try8
+ LDP.P 16(p), (x1, x2)
+
+ round0(x1)
+
+ // NOTE: here and below, sequencing the EOR after the ROR (using a
+ // rotated register) is worth a small but measurable speedup for small
+ // inputs.
+ ROR $64-27, h
+ EOR x1 @> 64-27, h, h
+ MADD h, prime4, prime1, h
+
+ round0(x2)
+ ROR $64-27, h
+ EOR x2 @> 64-27, h, h
+ MADD h, prime4, prime1, h
+
+try8:
+ TBZ $3, n, try4
+ MOVD.P 8(p), x1
+
+ round0(x1)
+ ROR $64-27, h
+ EOR x1 @> 64-27, h, h
+ MADD h, prime4, prime1, h
+
+try4:
+ TBZ $2, n, try2
+ MOVWU.P 4(p), x2
+
+ MUL prime1, x2
+ ROR $64-23, h
+ EOR x2 @> 64-23, h, h
+ MADD h, prime3, prime2, h
+
+try2:
+ TBZ $1, n, try1
+ MOVHU.P 2(p), x3
+ AND $255, x3, x1
+ LSR $8, x3, x2
+
+ MUL prime5, x1
+ ROR $64-11, h
+ EOR x1 @> 64-11, h, h
+ MUL prime1, h
+
+ MUL prime5, x2
+ ROR $64-11, h
+ EOR x2 @> 64-11, h, h
+ MUL prime1, h
+
+try1:
+ TBZ $0, n, finalize
+ MOVBU (p), x4
+
+ MUL prime5, x4
+ ROR $64-11, h
+ EOR x4 @> 64-11, h, h
+ MUL prime1, h
+
+finalize:
+ EOR h >> 33, h
+ MUL prime2, h
+ EOR h >> 29, h
+ MUL prime3, h
+ EOR h >> 32, h
+
+ MOVD h, ret+24(FP)
+ RET
+
+// func writeBlocks(d *Digest, b []byte) int
+TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
+ LDP ·primes+0(SB), (prime1, prime2)
+
+ // Load state. Assume v[1-4] are stored contiguously.
+ MOVD d+0(FP), digest
+ LDP 0(digest), (v1, v2)
+ LDP 16(digest), (v3, v4)
+
+ LDP b_base+8(FP), (p, n)
+
+ blockLoop()
+
+ // Store updated state.
+ STP (v1, v2), 0(digest)
+ STP (v3, v4), 16(digest)
+
+ BIC $31, n
+ MOVD n, ret+32(FP)
+ RET
diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go b/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go
new file mode 100644
index 00000000000..9216e0a40c1
--- /dev/null
+++ b/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go
@@ -0,0 +1,15 @@
+//go:build (amd64 || arm64) && !appengine && gc && !purego
+// +build amd64 arm64
+// +build !appengine
+// +build gc
+// +build !purego
+
+package xxhash
+
+// Sum64 computes the 64-bit xxHash digest of b.
+//
+//go:noescape
+func Sum64(b []byte) uint64
+
+//go:noescape
+func writeBlocks(d *Digest, b []byte) int
diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_other.go b/vendor/github.com/cespare/xxhash/v2/xxhash_other.go
index 4a5a821603e..26df13bba4b 100644
--- a/vendor/github.com/cespare/xxhash/v2/xxhash_other.go
+++ b/vendor/github.com/cespare/xxhash/v2/xxhash_other.go
@@ -1,4 +1,5 @@
-// +build !amd64 appengine !gc purego
+//go:build (!amd64 && !arm64) || appengine || !gc || purego
+// +build !amd64,!arm64 appengine !gc purego
package xxhash
@@ -14,10 +15,10 @@ func Sum64(b []byte) uint64 {
var h uint64
if n >= 32 {
- v1 := prime1v + prime2
+ v1 := primes[0] + prime2
v2 := prime2
v3 := uint64(0)
- v4 := -prime1v
+ v4 := -primes[0]
for len(b) >= 32 {
v1 = round(v1, u64(b[0:8:len(b)]))
v2 = round(v2, u64(b[8:16:len(b)]))
@@ -36,19 +37,18 @@ func Sum64(b []byte) uint64 {
h += uint64(n)
- i, end := 0, len(b)
- for ; i+8 <= end; i += 8 {
- k1 := round(0, u64(b[i:i+8:len(b)]))
+ for ; len(b) >= 8; b = b[8:] {
+ k1 := round(0, u64(b[:8]))
h ^= k1
h = rol27(h)*prime1 + prime4
}
- if i+4 <= end {
- h ^= uint64(u32(b[i:i+4:len(b)])) * prime1
+ if len(b) >= 4 {
+ h ^= uint64(u32(b[:4])) * prime1
h = rol23(h)*prime2 + prime3
- i += 4
+ b = b[4:]
}
- for ; i < end; i++ {
- h ^= uint64(b[i]) * prime5
+ for ; len(b) > 0; b = b[1:] {
+ h ^= uint64(b[0]) * prime5
h = rol11(h) * prime1
}
diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
index fc9bea7a31f..e86f1b5fd8e 100644
--- a/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
+++ b/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
@@ -1,3 +1,4 @@
+//go:build appengine
// +build appengine
// This file contains the safe implementations of otherwise unsafe-using code.
diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
index 376e0ca2e49..1c1638fd88a 100644
--- a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
+++ b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
@@ -1,3 +1,4 @@
+//go:build !appengine
// +build !appengine
// This file encapsulates usage of unsafe.
@@ -11,7 +12,7 @@ import (
// In the future it's possible that compiler optimizations will make these
// XxxString functions unnecessary by realizing that calls such as
-// Sum64([]byte(s)) don't need to copy s. See https://golang.org/issue/2205.
+// Sum64([]byte(s)) don't need to copy s. See https://go.dev/issue/2205.
// If that happens, even if we keep these functions they can be replaced with
// the trivial safe code.
diff --git a/vendor/github.com/common-nighthawk/go-figure/.travis.yml b/vendor/github.com/common-nighthawk/go-figure/.travis.yml
new file mode 100644
index 00000000000..4f2ee4d9733
--- /dev/null
+++ b/vendor/github.com/common-nighthawk/go-figure/.travis.yml
@@ -0,0 +1 @@
+language: go
diff --git a/vendor/github.com/common-nighthawk/go-figure/LICENSE b/vendor/github.com/common-nighthawk/go-figure/LICENSE
new file mode 100644
index 00000000000..7d44d62aba7
--- /dev/null
+++ b/vendor/github.com/common-nighthawk/go-figure/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Daniel Deutsch
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/common-nighthawk/go-figure/README.md b/vendor/github.com/common-nighthawk/go-figure/README.md
new file mode 100644
index 00000000000..ddf8d7a1ce9
--- /dev/null
+++ b/vendor/github.com/common-nighthawk/go-figure/README.md
@@ -0,0 +1,437 @@
+[](https://travis-ci.com/common-nighthawk/go-figure)
+
+# Go Figure
+
+## Description
+Go Figure prints beautiful ASCII art from text.
+It supports [FIGlet](http://www.figlet.org/) files,
+and most of its features.
+
+This package was inspired by the Ruby gem [artii](https://github.com/miketierney/artii),
+but built from scratch and with a different feature set.
+
+## Installation
+`go get github.com/common-nighthawk/go-figure`
+
+## Basic Example
+```go
+package main
+
+import("github.com/common-nighthawk/go-figure")
+
+func main() {
+ myFigure := figure.NewFigure("Hello World", "", true)
+ myFigure.Print()
+}
+```
+
+```txt
+ _ _ _ _ __ __ _ _
+ | | | | ___ | | | | ___ \ \ / / ___ _ __ | | __| |
+ | |_| | / _ \ | | | | / _ \ \ \ /\ / / / _ \ | '__| | | / _` |
+ | _ | | __/ | | | | | (_) | \ V V / | (_) | | | | | | (_| |
+ |_| |_| \___| |_| |_| \___/ \_/\_/ \___/ |_| |_| \__,_|
+```
+
+You can also make colorful figures:
+
+```go
+func main() {
+ myFigure := figure.NewColorFigure("Hello World", "", "green", true)
+ myFigure.Print()
+}
+```
+
+## Documentation
+### Create a Figure
+There are three ways to create a Figure. These are--
+the method `func NewFigure`,
+the method `func NewColorFigure`, and
+the method `func NewFigureWithFont`.
+
+Each constructor takes the arguments: the text, font, and strict mode.
+The "color" constructor takes a color as an additional arg.
+The "with font" specifies the font differently.
+The method signature are:
+```
+func NewFigure(phrase, fontName string, strict bool) figure
+func NewColorFigure(phrase, fontName string, color string, strict bool) figure
+func NewFigureWithFont(phrase string, reader io.Reader, strict bool) figure
+```
+
+`NewFigure` requires only the name of the font, and uses the font file shipped
+with this package stored in bindata.
+
+If passed an empty string for the font name, a default is provided.
+That is, these are both valid--
+
+`myFigure := figure.NewFigure("Foo Bar", "", true)`
+
+`myFigure := figure.NewFigure("Foo Bar", "alphabet", true)`
+
+Please note that font names are case sensitive.
+
+`NewFigureWithFont`, on the other hand, accepts the font file directly.
+This allows you to BYOF (bring your own font).
+Provide the absolute path to the flf.
+You can point to a file the comes with this project
+or you can store the file anywhere you'd like and use that location.
+
+The font files are available in the [fonts folder](https://github.com/common-nighthawk/go-figure/tree/master/fonts)
+and on [figlet.org](http://www.figlet.org/fontdb.cgi).
+
+Here are two examples--
+
+`myFigure := figure.NewFigureWithFont("Foo Bar", "/home/ubuntu/go/src/github.com/common-nighthawk/go-figure/fonts/alphabet.flf", true)`
+
+`myFigure := figure.NewFigureWithFont("Foo Bar", "/home/lib/fonts/alaphabet.flf", true)`
+
+You can also make colorful figures! The current supported colors are:
+blue, cyan, gray, green, purple, red, white, yellow.
+
+An example--
+
+`myFigure := figure.NewColorFigure("Foo Bar", "", "green", true)
+
+Strict mode dictates how to handle characters outside of standard ASCII.
+When set to true, a non-ASCII character (outside character codes 32-127)
+will cause the program to panic.
+When set to false, these characters are replaced with a question mark ('?').
+Examples of each--
+
+`figure.NewFigure("Foo 👍 Bar", "alphabet", true).Print()`
+
+```txt
+2016/12/01 19:35:38 invalid input.
+```
+
+`figure.NewFigure("Foo 👍 Bar", "alphabet", false).Print()`
+
+```txt
+ _____ ___ ____
+ | ___| ___ ___ |__ \ | __ ) __ _ _ __
+ | |_ / _ \ / _ \ / / | _ \ / _` | | '__|
+ | _| | (_) | | (_) | |_| | |_) | | (_| | | |
+ |_| \___/ \___/ (_) |____/ \__,_| |_|
+```
+
+### Methods: stdout
+#### Print()
+The most basic, and common, method is func Print.
+A figure responds to Print(), and will write the output to the terminal.
+There is no return value.
+
+`myFigure.Print()`
+
+But if you're feeling adventurous,
+explore the methods below.
+
+#### Blink(duration, timeOn, timeOff int)
+A figure responds to the func Blink, taking three arguments.
+`duration` is the total time the banner will display, in milliseconds.
+`timeOn` is the length of time the text will blink on (also in ms).
+`timeOff` is the length of time the text will blink off (ms).
+For an even blink, set `timeOff` to -1
+(same as setting `timeOff` to the value of `timeOn`).
+There is no return value.
+
+`myFigure.Blink(5000, 1000, 500)`
+
+`myFigure.Blink(5000, 1000, -1)`
+
+#### Scroll(duration, stillness int, direction string)
+A figure responds to the func Scroll, taking three arguments.
+`duration` is the total time the banner will display, in milliseconds.
+`stillness` is the length of time the text will not move (also in ms).
+Therefore, the lower the stillness the faster the scroll speed.
+`direction` can be either "right" or "left" (case insensitive).
+The direction will be left if an invalid option (e.g. "foo") is passed.
+There is no return value.
+
+`myFigure.Scroll(5000, 200, "right")`
+
+`myFigure.Scroll(5000, 100, "left")`
+
+#### Dance(duration, freeze int)
+A figure responds to the func Dance, taking two arguments.
+`duration` is the total time the banner will display, in milliseconds.
+`freeze` is the length of time between dance moves (also in ms).
+Therefore, the lower the freeze the faster the dancing.
+There is no return value.
+
+`myFigure.Dance(5000, 800)`
+
+### Methods: Writers
+#### Write(w io.Writer, fig figure)
+Unlike the above methods that operate on a figure value,
+func Write is a function that takes two arguments.
+`w` is a value that implements all the methods in the io.Writer interface.
+`fig` is the figure that will be written.
+
+`figure.Write(w, myFigure)`
+
+This method would be useful, for example, to add a nifty banner to a web page--
+```go
+func landingPage(w http.ResponseWriter, r *http.Request) {
+ figure.Write(w, myFigure)
+}
+```
+
+### Methods: Misc
+#### Slicify() ([]string)
+If you want to do something outside of the created methods,
+you can grab the internal slice.
+This gives you a good start to build anything
+with the ASCII art, if manually.
+
+A figure responds to the func Slicify,
+and will return the slice of strings.
+
+`myFigure.Slicify()`
+
+returns
+
+```txt
+["FFFF BBBB ",
+ "F B B ",
+ "FFF ooo ooo BBBB aa rrr",
+ "F o o o o B B a a r ",
+ "F ooo ooo BBBB aaa r "]
+```
+
+## More Examples
+`figure.NewFigure("Go-Figure", "isometric1", true).Print()`
+
+```
+ ___ ___ ___ ___ ___ ___ ___
+ /\ \ /\ \ /\ \ ___ /\ \ /\__\ /\ \ /\ \
+ /::\ \ /::\ \ /::\ \ /\ \ /::\ \ /:/ / /::\ \ /::\ \
+ /:/\:\ \ /:/\:\ \ /:/\:\ \ \:\ \ /:/\:\ \ /:/ / /:/\:\ \ /:/\:\ \
+ /:/ \:\ \ /:/ \:\ \ /::\~\:\ \ /::\__\ /:/ \:\ \ /:/ / ___ /::\~\:\ \ /::\~\:\ \
+ /:/__/_\:\__\ /:/__/ \:\__\ /:/\:\ \:\__\ __/:/\/__/ /:/__/_\:\__\ /:/__/ /\__\ /:/\:\ \:\__\ /:/\:\ \:\__\
+ \:\ /\ \/__/ \:\ \ /:/ / \/__\:\ \/__/ /\/:/ / \:\ /\ \/__/ \:\ \ /:/ / \/_|::\/:/ / \:\~\:\ \/__/
+ \:\ \:\__\ \:\ /:/ / \:\__\ \::/__/ \:\ \:\__\ \:\ /:/ / |:|::/ / \:\ \:\__\
+ \:\/:/ / \:\/:/ / \/__/ \:\__\ \:\/:/ / \:\/:/ / |:|\/__/ \:\ \/__/
+ \::/ / \::/ / \/__/ \::/ / \::/ / |:| | \:\__\
+ \/__/ \/__/ \/__/ \/__/ \|__| \/__/
+```
+
+`figure.NewFigure("Foo Bar Pop", "smkeyboard", true).Print()`
+
+```
+ ____ ____ ____ ____ ____ ____ ____ ____ ____
+||F ||||o ||||o ||||B ||||a ||||r ||||P ||||o ||||p ||
+||__||||__||||__||||__||||__||||__||||__||||__||||__||
+|/__\||/__\||/__\||/__\||/__\||/__\||/__\||/__\||/__\|
+```
+
+`figure.NewFigure("Keep Your Eyes On Me", "rectangles", true).Print()`
+
+```
+
+ _____ __ __ _____ _____ _____
+| | | ___ ___ ___ | | | ___ _ _ ___ | __| _ _ ___ ___ | | ___ | | ___
+| -|| -_|| -_|| . ||_ _|| . || | || _|| __|| | || -_||_ -|| | || || | | || -_|
+|__|__||___||___|| _| |_| |___||___||_| |_____||_ ||___||___||_____||_|_||_|_|_||___|
+ |_| |___|
+```
+
+`figure.NewFigure("ABCDEFGHIJ", "eftichess", true).Print()`
+
+```
+######### ######### ___ ######### #########
+##[`'`']# \`~'/ ##'\v/`## /\*/\ ##|`+'|## '\v/` ##\`~'/## [`'`'] '\v/` \`~'/
+###| |## (o o) ##(o 0)## /(o o)\ ##(o o)## (o 0) ##(o o)## | | (o 0) (o o)
+###|__|## \ / \ ###(_)### (_) ###(_)### (_) ###\ / \# |__| (_) \ / \
+######### " ######### ######### ####"#### "
+```
+
+`figure.NewFigure("Give your reasons", "doom", true).Blink(10000, 500, -1)`
+
+
+
+`figure.NewFigure("I mean, I could...", "basic", true).Scroll(10000, 200, "right")`
+
+`figure.NewFigure("But why would I want to?", "basic", true).Scroll(10000, 200, "left")`
+
+
+
+`figure.NewFigure("It's been waiting for you", "larry3d", true).Dance(10000, 500)`
+
+
+
+`figure.Write(w, figure.NewFigure("Hello, It's Me", "puffy", true))`
+
+
+
+
+## Supported Fonts
+* 3-d
+* 3x5
+* 5lineoblique
+* acrobatic
+* alligator
+* alligator2
+* alphabet
+* avatar
+* banner
+* banner3-D
+* banner3
+* banner4
+* barbwire
+* basic
+* bell
+* big
+* bigchief
+* binary
+* block
+* bubble
+* bulbhead
+* calgphy2
+* caligraphy
+* catwalk
+* chunky
+* coinstak
+* colossal
+* computer
+* contessa
+* contrast
+* cosmic
+* cosmike
+* cricket
+* cursive
+* cyberlarge
+* cybermedium
+* cybersmall
+* diamond
+* digital
+* doh
+* doom
+* dotmatrix
+* drpepper
+* eftichess
+* eftifont
+* eftipiti
+* eftirobot
+* eftitalic
+* eftiwall
+* eftiwater
+* epic
+* fender
+* fourtops
+* fuzzy
+* goofy
+* gothic
+* graffiti
+* hollywood
+* invita
+* isometric1
+* isometric2
+* isometric3
+* isometric4
+* italic
+* ivrit
+* jazmine
+* jerusalem
+* katakana
+* kban
+* larry3d
+* lcd
+* lean
+* letters
+* linux
+* lockergnome
+* madrid
+* marquee
+* maxfour
+* mike
+* mini
+* mirror
+* mnemonic
+* morse
+* moscow
+* nancyj-fancy
+* nancyj-underlined
+* nancyj
+* nipples
+* ntgreek
+* o8
+* ogre
+* pawp
+* peaks
+* pebbles
+* pepper
+* poison
+* puffy
+* pyramid
+* rectangles
+* relief
+* relief2
+* rev
+* roman
+* rot13
+* rounded
+* rowancap
+* rozzo
+* runic
+* runyc
+* sblood
+* script
+* serifcap
+* shadow
+* short
+* slant
+* slide
+* slscript
+* small
+* smisome1
+* smkeyboard
+* smscript
+* smshadow
+* smslant
+* smtengwar
+* speed
+* stampatello
+* standard
+* starwars
+* stellar
+* stop
+* straight
+* tanja
+* tengwar
+* term
+* thick
+* thin
+* threepoint
+* ticks
+* ticksslant
+* tinker-toy
+* tombstone
+* trek
+* tsalagi
+* twopoint
+* univers
+* usaflag
+* wavy
+* weird
+
+## Contributing
+Because this project is small, we can dispense with formality.
+Submit a pull request, open an issue, request a change.
+All good!
+
+## Wanna Say Thanks?
+GitHub stars are helpful.
+Most importantly, they help with discoverability.
+Projects with more stars are displayed higher
+in search results when people are looking for packages.
+Also--they make contributors feel good :)
+
+If you are feeling especially generous,
+give a shout to [@cmmn_nighthawk](https://twitter.com/cmmn_nighthawk).
+
+## TODO
+* Add proper support for spaces
+* More animations
+* Implement graceful line-wrapping and smushing
+* Deep-copy font for Dance (current implementation is destructive)
diff --git a/vendor/github.com/common-nighthawk/go-figure/bindata.go b/vendor/github.com/common-nighthawk/go-figure/bindata.go
new file mode 100644
index 00000000000..f85d3bb57af
--- /dev/null
+++ b/vendor/github.com/common-nighthawk/go-figure/bindata.go
@@ -0,0 +1,3641 @@
+// Code generated by go-bindata.
+// sources:
+// fonts/3-d.flf
+// fonts/3x5.flf
+// fonts/5lineoblique.flf
+// fonts/acrobatic.flf
+// fonts/alligator.flf
+// fonts/alligator2.flf
+// fonts/alphabet.flf
+// fonts/avatar.flf
+// fonts/banner.flf
+// fonts/banner3-D.flf
+// fonts/banner3.flf
+// fonts/banner4.flf
+// fonts/barbwire.flf
+// fonts/basic.flf
+// fonts/bell.flf
+// fonts/big.flf
+// fonts/bigchief.flf
+// fonts/binary.flf
+// fonts/block.flf
+// fonts/bubble.flf
+// fonts/bulbhead.flf
+// fonts/calgphy2.flf
+// fonts/caligraphy.flf
+// fonts/catwalk.flf
+// fonts/chunky.flf
+// fonts/coinstak.flf
+// fonts/colossal.flf
+// fonts/computer.flf
+// fonts/contessa.flf
+// fonts/contrast.flf
+// fonts/cosmic.flf
+// fonts/cosmike.flf
+// fonts/cricket.flf
+// fonts/cursive.flf
+// fonts/cyberlarge.flf
+// fonts/cybermedium.flf
+// fonts/cybersmall.flf
+// fonts/diamond.flf
+// fonts/digital.flf
+// fonts/doh.flf
+// fonts/doom.flf
+// fonts/dotmatrix.flf
+// fonts/drpepper.flf
+// fonts/eftichess.flf
+// fonts/eftifont.flf
+// fonts/eftipiti.flf
+// fonts/eftirobot.flf
+// fonts/eftitalic.flf
+// fonts/eftiwall.flf
+// fonts/eftiwater.flf
+// fonts/elite.flf
+// fonts/epic.flf
+// fonts/fender.flf
+// fonts/fourtops.flf
+// fonts/fuzzy.flf
+// fonts/goofy.flf
+// fonts/gothic.flf
+// fonts/graffiti.flf
+// fonts/hollywood.flf
+// fonts/invita.flf
+// fonts/isometric1.flf
+// fonts/isometric2.flf
+// fonts/isometric3.flf
+// fonts/isometric4.flf
+// fonts/italic.flf
+// fonts/ivrit.flf
+// fonts/jazmine.flf
+// fonts/jerusalem.flf
+// fonts/katakana.flf
+// fonts/kban.flf
+// fonts/larry3d.flf
+// fonts/lcd.flf
+// fonts/lean.flf
+// fonts/letters.flf
+// fonts/linux.flf
+// fonts/lockergnome.flf
+// fonts/madrid.flf
+// fonts/marquee.flf
+// fonts/maxfour.flf
+// fonts/mike.flf
+// fonts/mini.flf
+// fonts/mirror.flf
+// fonts/mnemonic.flf
+// fonts/morse.flf
+// fonts/moscow.flf
+// fonts/nancyj-fancy.flf
+// fonts/nancyj-underlined.flf
+// fonts/nancyj.flf
+// fonts/nipples.flf
+// fonts/ntgreek.flf
+// fonts/o8.flf
+// fonts/ogre.flf
+// fonts/pawp.flf
+// fonts/peaks.flf
+// fonts/pebbles.flf
+// fonts/pepper.flf
+// fonts/poison.flf
+// fonts/puffy.flf
+// fonts/pyramid.flf
+// fonts/rectangles.flf
+// fonts/relief.flf
+// fonts/relief2.flf
+// fonts/rev.flf
+// fonts/roman.flf
+// fonts/rot13.flf
+// fonts/rounded.flf
+// fonts/rowancap.flf
+// fonts/rozzo.flf
+// fonts/runic.flf
+// fonts/runyc.flf
+// fonts/sblood.flf
+// fonts/script.flf
+// fonts/serifcap.flf
+// fonts/shadow.flf
+// fonts/short.flf
+// fonts/slant.flf
+// fonts/slide.flf
+// fonts/slscript.flf
+// fonts/small.flf
+// fonts/smisome1.flf
+// fonts/smkeyboard.flf
+// fonts/smscript.flf
+// fonts/smshadow.flf
+// fonts/smslant.flf
+// fonts/smtengwar.flf
+// fonts/speed.flf
+// fonts/stampatello.flf
+// fonts/standard.flf
+// fonts/starwars.flf
+// fonts/stellar.flf
+// fonts/stop.flf
+// fonts/straight.flf
+// fonts/tanja.flf
+// fonts/tengwar.flf
+// fonts/term.flf
+// fonts/thick.flf
+// fonts/thin.flf
+// fonts/threepoint.flf
+// fonts/ticks.flf
+// fonts/ticksslant.flf
+// fonts/tinker-toy.flf
+// fonts/tombstone.flf
+// fonts/trek.flf
+// fonts/tsalagi.flf
+// fonts/twopoint.flf
+// fonts/univers.flf
+// fonts/usaflag.flf
+// fonts/wavy.flf
+// fonts/weird.flf
+// DO NOT EDIT!
+
+package figure
+
+import (
+ "bytes"
+ "compress/gzip"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+)
+
+func bindataRead(data []byte, name string) ([]byte, error) {
+ gz, err := gzip.NewReader(bytes.NewBuffer(data))
+ if err != nil {
+ return nil, fmt.Errorf("Read %q: %v", name, err)
+ }
+
+ var buf bytes.Buffer
+ _, err = io.Copy(&buf, gz)
+ clErr := gz.Close()
+
+ if err != nil {
+ return nil, fmt.Errorf("Read %q: %v", name, err)
+ }
+ if clErr != nil {
+ return nil, err
+ }
+
+ return buf.Bytes(), nil
+}
+
+type asset struct {
+ bytes []byte
+ info os.FileInfo
+}
+
+type bindataFileInfo struct {
+ name string
+ size int64
+ mode os.FileMode
+ modTime time.Time
+}
+
+func (fi bindataFileInfo) Name() string {
+ return fi.name
+}
+func (fi bindataFileInfo) Size() int64 {
+ return fi.size
+}
+func (fi bindataFileInfo) Mode() os.FileMode {
+ return fi.mode
+}
+func (fi bindataFileInfo) ModTime() time.Time {
+ return fi.modTime
+}
+func (fi bindataFileInfo) IsDir() bool {
+ return false
+}
+func (fi bindataFileInfo) Sys() interface{} {
+ return nil
+}
+
+var _fonts3DFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\xb9\x8e\x1c\x37\x10\xcd\xf7\x2b\x2a\xd8\xa8\x00\xa9\x2c\x39\x51\x60\x18\x13\x28\xf0\x6f\xac\xb5\xb3\xb6\x00\x61\x04\xe8\x08\xfc\xf7\x06\x59\xd7\x2b\x92\x7d\xcc\x1a\xf0\x0a\xd3\x4d\x76\xb3\xc9\x3a\x5e\x3d\xbe\x6e\xbd\x7c\x79\x79\xff\xf4\x48\x1f\xe8\x03\xbd\xff\x85\xde\xbc\xa3\x77\x0f\xbf\xbe\xf9\x48\x2f\x5f\x6f\x3f\xe8\xd3\xb7\xeb\xd3\x8f\xeb\x33\xfd\xf9\x0f\x7d\x7c\xba\x7d\xbe\x7e\xa1\x3f\xae\xb7\xdb\xe7\xdb\x5f\xd7\x6f\xf4\xdb\xf3\xd3\xdf\xbd\x73\xb9\x7e\xfd\xfe\xf6\xf6\xe9\xfb\xcf\xb7\xd7\xe7\x9f\xbf\x3f\x3c\x3e\x5e\xf6\x7e\x97\x07\x62\xbe\x3c\xc8\xea\x20\xe4\x77\x85\xfa\x40\xa2\x7e\x8f\xa4\x9d\x88\xfa\xfd\xf6\xb7\x7b\xb2\xb3\xff\xf5\x2e\x33\xd9\xb1\xaf\x90\x7f\x6d\x2d\x61\x16\x3d\xf6\xc1\xd2\x07\xcb\xc9\xc1\xd2\x26\xee\x47\x5d\x18\x9e\x6a\xa6\x4b\x1f\x27\xf0\x78\xf3\x85\xb0\xaf\xf3\x0c\x96\xf7\x31\x6a\x72\x0f\x47\x18\xef\xce\x80\x5b\xad\xa9\xad\xc5\x63\xed\x70\xc9\xc1\x7d\xac\x98\x95\x32\x5c\x63\x8d\x79\x6b\xf6\xb0\xb7\x28\xb4\x56\x37\xb7\xdf\x6d\xae\x93\x25\xa7\xdb\xdf\x2f\xaa\x31\xcb\x83\xad\x6c\x26\x9a\x79\x3d\x20\x78\x12\xbd\x27\xa2\x23\x3d\xfd\xeb\x9b\xe5\x54\x26\xad\x41\xb4\x90\x44\x78\x24\x23\xd3\x27\xd3\x0b\x8b\x34\x43\xa2\xed\x57\xe6\x48\x83\x1c\x26\x3d\xc6\xb6\xac\x02\x62\xc2\xa1\x77\x18\x3a\x02\xd9\x8b\x85\x7b\x88\xa5\x61\x6c\x1e\x46\x8a\x93\x9c\x0d\x16\xda\x38\x94\x2c\xf9\x63\x8b\x73\xba\x9d\x0b\xcf\xe7\xc3\x95\xa0\x78\x3d\x09\xe1\x39\xfb\x3c\x77\x21\x99\x22\xb3\x61\x41\x47\x63\xbb\x2f\x62\xe4\xd1\xf0\xab\x0d\xe3\x0a\xcd\x55\x80\x38\x30\xec\x10\xf6\x89\xcc\x75\x84\xd9\xea\x94\xc1\x99\x2d\x20\xe5\x26\x5d\xa6\x7b\xc2\x56\x51\x8a\x0a\x77\x47\x18\x63\x7c\xc7\x44\x76\x8b\x76\x5d\xc9\xf8\xb2\xd8\xfa\x5a\xbc\x54\x96\xf5\x1c\x2c\x1a\x64\x35\x17\xcc\xa5\x48\x50\xb3\xc9\xa1\xc1\x01\xca\x23\x8b\x26\xd7\xfa\xe8\x32\x63\xbd\xb5\x31\x51\x0d\x5b\x59\x5f\x0b\xca\xdc\x77\x20\x39\x8c\x0c\x44\xb2\xc6\xcd\xc6\xb2\xa7\x2c\x3a\x39\xfa\x84\x45\x9b\x05\x3b\x6c\x84\x07\x63\x86\xf2\xce\xa2\x73\xea\xea\x0d\x7b\x54\xb2\xa6\xb2\xe8\xac\x63\x50\x10\x28\xdb\x52\xcd\xd8\x18\xe1\xbc\xba\x32\x3e\x35\x16\xf5\x09\x03\x0e\x5c\x58\xd1\x02\x3b\x2d\x30\x39\x21\x65\x75\x30\xe5\xbe\xbd\xb8\xb2\x91\x5e\x36\x7e\x71\x2d\xc2\x62\x5b\x2c\x1b\xf9\x0b\x15\xfe\x8e\x98\x31\x90\x77\x9f\x37\x56\x15\x57\x18\xba\xb1\x00\xd3\x64\x0d\xb2\x81\xde\x29\x8d\x28\x3d\x82\xe4\xe8\x03\xe4\x25\x25\x0c\xfb\x37\x27\xf5\xe4\x00\x72\xda\xf4\xf9\x6c\x4d\x2f\x73\x14\x0d\x1c\x84\xc6\x6e\x8b\x79\xe5\xfc\x10\x69\x2e\x6d\x71\xcd\x65\xdb\x2d\x03\x9f\x0d\xc5\xed\x5a\x00\x6c\x2f\xb6\xed\xb5\xd1\x41\x53\x01\x36\x3f\x2e\x00\xd1\x44\x3b\xab\xe7\x3a\x80\xd6\x03\x02\xd7\x25\xe6\xff\x6d\xe2\xf5\xf6\x16\x53\x43\xd4\x4b\xdc\xa7\xc8\xc3\x74\x61\xaa\x82\xca\x9e\x13\x29\x73\x8a\xd4\x1c\x24\x6b\x54\x94\x0d\x9d\x53\xc8\xdc\x85\xe9\x86\xee\x5f\x4a\x07\x4e\xaa\x3f\x6e\x99\x36\x53\xc7\x81\xb0\xd1\xc5\x30\x2f\x20\x16\xc0\xb3\xba\x6c\x6e\x01\x18\x63\x9c\xa4\x37\x20\x4d\xe7\x34\xde\xd7\xdc\x84\x15\x79\x22\xd3\xa2\x4e\x40\x9c\x76\x05\xb5\x99\x75\x8c\xe1\x17\x2f\x7d\x5f\x51\xa6\xf4\x8c\x19\xaa\x5c\x82\x70\x88\xb7\xa1\x5c\xbc\x2e\x5d\x17\x66\x5c\x56\xc2\x09\xf2\x2e\x82\x42\x2a\xde\x09\xf1\x9e\xba\xde\x9e\x04\xdb\x57\x3d\x09\xab\x09\xf1\x4e\x88\xf7\x4a\x09\x48\x39\x61\xf1\x48\x86\xaf\xab\x5c\x1a\x5d\x19\x7c\xa1\x6a\x3e\x56\xaf\xa4\x18\x85\x3d\x31\xfd\xf1\x17\x24\x75\xa8\x72\xd1\x9a\x45\x65\x66\x48\xe6\x30\x4b\x60\xf3\xc9\xac\x85\x63\xa8\x53\x6d\x7f\xf3\xd2\x9f\xb9\x7f\x42\x74\xaa\x88\x28\xd3\x71\x9f\xa9\xfb\x00\x08\x55\x78\x03\x12\xdc\x44\x5f\xd5\x49\xc9\x55\xc1\x3d\xa2\xe9\x7c\x1b\x40\x42\xaf\x61\x53\xdc\xbd\x34\xfe\x20\x44\x00\x43\x24\x07\x9e\xd4\x95\x70\xa9\xc2\x09\x8c\x85\xda\x61\x96\x58\xc7\x42\x55\x8e\xab\xdc\x50\x39\x0f\xcc\x07\xeb\x8b\xf1\x20\x72\x40\xe3\x94\xa2\x5e\xa1\x2c\x05\x83\x24\x4f\x47\x38\x7c\xf6\x08\xcc\x61\x53\x68\x16\x01\x40\x2e\x74\xd7\xab\xe8\xb6\x08\xb0\x82\x8a\x7a\xd8\x3d\xe3\x5b\xf6\xa0\x86\x73\x35\xcc\x79\x71\x59\x18\x34\x72\x7a\x81\x95\x36\x58\x96\x55\xb8\x7f\x9e\x2c\xa3\x2a\x5e\x99\x85\x90\xc8\x5c\x43\xc2\x0e\xbf\xfa\xdc\x71\xd4\xd9\xf9\x22\xb1\x75\x5e\xc4\xb0\x6b\xd9\xfe\xf2\xbc\xfd\x81\x02\xd7\x1d\xdb\xb0\x57\x14\x80\x40\x8d\x23\xad\xc2\xde\x4d\x03\x1c\x3c\x99\xeb\x56\xd9\x55\x72\xd7\x84\x4d\x27\xde\xb3\x8b\xc5\xb5\x55\x6d\x82\xcd\x37\x96\xdb\x16\x42\x51\xc1\x49\x16\xd8\xaa\x24\x3f\x58\x28\x83\xd3\x77\x5a\x88\xb5\xa2\xb6\x6e\x4c\x68\xd7\xc8\x3f\xbc\x41\xe5\x95\x4f\xb4\x1b\x8d\x45\xec\xb6\x22\xb6\x72\x0b\x02\xb1\x12\x91\xaf\xce\x2e\x0a\x2e\x04\x6e\xbe\xc6\xef\xea\x61\x2f\x56\xa1\xda\x1f\x8a\x38\x5d\x32\xe3\xd1\xf4\xb0\x37\xf6\x84\x90\xc1\xa1\x82\x43\xf3\x85\xdc\x53\x9b\x53\x08\xe8\x57\xb1\x9d\xa3\x27\x6b\xfc\x12\x3f\xf5\x72\xd3\x37\x34\x48\x2c\x49\x26\x2c\x69\xd5\x63\xec\x89\x59\x47\xc3\x82\xb5\x39\xae\x93\xd3\xd2\xd4\x04\x35\x8d\xd9\x5a\x4f\x4c\x33\x45\x8c\x62\x72\xd4\x0c\x49\x33\x23\x50\xcf\x32\x84\x8a\xa3\x8a\x3f\x23\xe2\x05\xf2\x29\x3f\x8a\xf8\xfb\x0c\xf2\x98\x9b\xc3\xf9\x49\xd0\x69\x41\x4e\x7c\xfc\xe9\x13\x7b\x8a\xc8\x23\x69\x80\x32\xd3\x64\x61\xd9\x18\xc1\x08\xe0\x6c\x19\x6a\xc7\x50\x8e\xf8\xbf\x1a\x48\x00\xe7\xd8\x22\xbc\x9d\x93\x80\x4e\xa2\xba\xda\x29\xe9\x1d\x62\x9c\x70\x48\x45\xb1\xa5\x18\x94\x03\xb5\x33\xc6\x70\xb1\xaf\xf2\xa4\xd0\xb0\x7e\xd8\xd8\xa1\xe7\x97\x25\x62\xce\x92\x82\x4f\xe6\xac\x6f\x85\x24\x88\xc3\x25\x9f\xbd\xf1\x84\xc6\x9b\x5f\x9a\x6b\xd2\xf1\xdb\x10\xc5\x87\x89\x98\x0a\x95\xdc\x4a\x91\xcd\x80\x5f\xe3\x33\x53\x0d\x52\x74\x1a\x83\x44\xcb\x21\x78\x06\x5c\x39\x9a\x97\x70\x72\x7e\x36\x6a\x6f\x09\xb6\x1f\x4d\xfd\xd3\xd3\xed\x18\x41\xf0\x1a\x90\xcc\x16\xf4\xe9\x8c\xb8\xc9\x5b\xfb\xcd\xcb\xc3\xf0\xef\xff\xba\xf0\x6f\x00\x00\x00\xff\xff\x99\xec\xf4\xdf\x8e\x1e\x00\x00")
+
+func fonts3DFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fonts3DFlf,
+ "fonts/3-d.flf",
+ )
+}
+
+func fonts3DFlf() (*asset, error) {
+ bytes, err := fonts3DFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/3-d.flf", size: 7822, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fonts3x5Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x56\xcd\x8e\xdb\x3c\x0c\xbc\xe7\x29\x06\xe0\x77\x48\x80\x6f\x0d\xb4\xdd\xee\xa1\xa7\x00\x2d\xd0\x43\x2f\x45\xdf\x40\x89\xed\x44\x88\x37\x5e\xd8\x0e\xda\x14\xe8\xbb\xf7\x90\x1f\x4b\xe4\xd0\x4e\x2f\x82\xe2\x50\x24\x35\x1c\x0e\x55\x37\xf5\xfb\xf0\x1f\x5e\xf0\x8c\x17\x3c\xbd\xc3\xf3\xe2\xc3\xaf\x8f\xa8\xdb\xe3\x80\xcd\x19\x3f\xe2\x76\x1f\xba\x12\xdf\x62\x77\xc0\xb2\x0b\x87\xf5\xb6\x6b\xfb\x3a\x56\x4d\x59\x6c\xdb\xe2\x74\x58\x15\x8b\xef\x6d\x37\x54\x25\x86\x16\x75\xdc\x35\xd5\xf0\x3f\xc2\xb1\x44\xdf\xc4\xdd\x7e\x68\xce\xd8\xee\xc3\x71\x57\x95\x58\xfe\x8c\xc3\xbe\x3d\x0d\x78\xab\xba\xd7\xd8\xf7\xb1\x3d\xe2\xd3\xd3\x9f\xd5\x62\x73\xc6\x97\x70\x8c\x55\x83\xcf\x61\x53\xfd\x0e\xf8\xda\x85\x1e\xcb\x4d\xe8\xca\x76\x5d\xc6\x50\xd4\xb1\x38\xbd\xbd\x16\x55\xbf\x5a\x2c\x00\x60\x3d\xbd\xde\x7f\x88\x59\xc7\xef\xb7\x1f\x02\xb9\xaf\xae\xa7\xab\x91\x08\xdb\x8f\x6e\x2f\x7f\xe0\xfe\x77\xf2\x25\xf7\x84\xcb\x7a\x31\x1d\xbf\xe7\x89\x4b\xea\x75\x0c\x3a\x26\xa8\x7d\x30\x08\x12\xa3\x1c\x08\x49\x73\xe2\x68\x89\x05\xf3\x76\x2f\xb5\x57\xd0\x19\x53\x95\x93\x59\x49\xb8\x64\xbd\x7a\x62\xb7\x9b\xf0\xa7\x20\x20\x88\xa7\x65\x49\x51\x86\x87\xf8\xf5\x5e\x06\xa7\xd4\xe8\x96\x6c\x4a\x92\x49\x23\xe8\x03\x8c\x99\xd9\x01\x18\x4f\xc2\x43\xfb\x46\xe4\x76\x26\xc4\x54\x38\xda\x0e\xbe\x11\xc9\x29\x6b\x51\xbd\x9f\x33\x12\x8f\xe3\x19\x95\x61\xc2\xa5\x4c\x4a\xf6\xb4\x11\xb4\xd7\xa9\xda\x59\x55\xc9\xf8\xe4\x84\xbb\x39\x37\x60\xe6\x88\xa7\x46\x6a\xaf\xa4\x07\x8a\xdd\x97\xef\xd4\x53\xc6\x2d\x92\x78\x7a\xc0\xa1\x2f\x31\x82\x9b\x53\x22\xb2\xd3\x1c\xa7\x10\x70\x11\x53\xcd\xa9\x89\x2b\x30\xfa\x64\xae\x4d\xc3\x79\x2b\x49\x5c\x1e\x48\x9c\x20\xce\xc4\x5e\x1b\x29\x3e\x59\x16\x78\x12\xad\xb1\xd6\x1d\xec\xf0\x89\x8c\x32\xd3\x0e\x84\x2a\x64\xb6\xb8\x88\x7b\xc2\xea\x19\x4d\xd4\xce\x99\xc1\xe6\x34\x2f\xb0\x36\x62\x89\x8b\x33\x36\x08\xe9\x08\x04\x0e\x9f\x32\x6d\xb1\x65\x61\x1c\x77\x0a\xec\xbf\x7a\x9c\x55\x6c\x4e\x79\x36\xae\xfa\x5a\x35\x37\x9a\xc9\x24\xdf\x78\x62\xb3\xca\xe8\xf8\xbf\x78\x12\x57\x58\xc5\x79\xb1\xb8\x39\x8d\xdd\x42\x70\xb2\x7d\xcc\xde\x99\x50\xf5\x9f\x37\xb2\xb3\x05\xbc\x39\xe7\x9e\xb5\x73\x38\x79\x89\x3b\x73\x61\xa2\x76\x0f\x15\x58\xf2\x62\xcf\x7b\x72\x06\x75\xd6\x39\x1e\x33\xb3\x57\x19\x91\xc3\xac\x45\xbd\xc4\xc9\x53\x6b\xd2\xc8\x7d\xab\x58\x7d\x72\x8d\x4c\x37\xfb\x9e\xdc\xf7\x93\xcc\xb0\xc0\x22\x64\xf5\xc9\x51\x70\x36\x80\xb2\x40\xac\xa5\x54\xe5\x99\xaa\x10\x71\x76\x75\xdc\xce\x4f\x3b\x36\x9c\x0a\xea\x70\x33\x22\xf6\x80\xf4\x90\x70\xc4\x48\xcc\x60\x4d\xdb\xfc\x6f\x00\x00\x00\xff\xff\x6e\x78\x13\xbb\x6d\x0f\x00\x00")
+
+func fonts3x5FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fonts3x5Flf,
+ "fonts/3x5.flf",
+ )
+}
+
+func fonts3x5Flf() (*asset, error) {
+ bytes, err := fonts3x5FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/3x5.flf", size: 3949, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fonts5lineobliqueFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x59\xcd\x8e\x1b\x37\x0c\xbe\xfb\x29\x78\xe0\x41\x03\xb4\x56\xbd\xed\xb6\x0d\x10\x2c\x9c\xfe\x9c\x7a\x2b\xd0\x9b\x00\xc1\xe9\xda\xc0\x22\x8b\x4d\xd0\x6c\x0e\x01\xf4\xf0\x85\x48\x51\xa2\x34\x9a\xf1\x8c\xed\x2c\x12\x8f\x38\x92\x48\xf1\x13\xff\xa4\x39\x3d\x9f\xee\x0e\x08\xbf\xc0\x3d\xdc\xfd\x00\xbb\x7b\xb8\xdb\xdc\x3f\x3f\xbd\x1c\x3f\xbe\x7f\xde\x9e\x9e\x4f\xb0\xdb\xd9\x37\x3f\xc1\xa7\x0f\x3f\xff\xba\xdb\x7d\xde\x1f\xfe\x3d\x3c\x6e\x1f\xff\x3b\x7c\x38\x6e\x8f\x8f\x5f\xbe\x83\x2f\x9f\x1e\x0f\xaf\xc7\x47\x80\x9d\x7d\x73\x0f\x9f\xbf\xbe\xff\x71\xff\xee\xb7\x3f\xff\xde\xbe\xfb\x7d\xfb\xcf\x5f\x9b\x3f\x8e\xa7\xa7\x97\xa7\xd7\xe3\xf3\x57\x38\xc0\xfd\xf7\x91\x2d\x9c\x3e\xbe\xbc\x6e\x37\x88\xfb\xa9\xff\xfb\x0d\xf0\x5f\x6a\x20\x37\xd0\x5a\x8c\x8d\xf8\x8c\x6f\xe8\x09\xfb\x0d\xc6\x11\xb1\x41\x34\x80\xcc\xcf\x0f\x0c\x10\xe2\x4c\x44\x9e\x37\x7e\x64\x89\x65\x9a\xcc\x05\xef\x6d\xfc\x17\x97\x26\x4d\x7a\x6f\x01\x2c\x60\x3b\x5e\xb5\x35\x51\x77\x65\xca\x7b\x6b\xbd\x50\x06\xac\x05\x18\x30\xf5\x39\x27\x23\x0d\x0d\x1b\x50\xe6\xc5\x61\x8d\x08\xdd\x30\x03\x24\xa4\x68\x64\x6c\xd0\x8c\xfd\x26\x3e\x4d\x16\x00\x73\x7a\x03\x18\x03\x00\x43\x1a\xed\x5c\xe6\x85\xd6\x39\x9b\xf6\xc4\x5a\x5e\x66\x94\x6a\xbc\xf7\xce\x65\x30\x09\xda\x08\x14\xaf\x25\x81\x0d\xe5\xb7\x96\x3f\x6a\x79\xc8\x2a\x64\x59\x28\x4a\x30\x14\xc6\x00\x9e\x63\x23\x0a\x40\x32\x1a\x6e\x24\x86\x28\xa8\xe0\x34\x9a\x64\x7f\xfa\x0d\x7a\xe7\xd8\x1c\xc0\x5a\x87\x6a\x8c\x0c\x1a\x3f\x89\x3f\x59\x50\x08\x3c\x35\x04\xa2\xf9\x7d\x46\x4c\xe1\x36\x7e\x43\x48\x2a\x9e\xd1\x72\x3b\x4f\xef\x3d\x61\xd7\xbc\xa7\x89\xf2\x83\xf9\x87\x47\x44\x30\x87\x69\x00\x72\x63\xda\xae\x70\xb1\xc5\x7b\xa8\xec\x78\x48\x16\x4f\x84\x05\x2b\x5b\x9c\x08\xda\x66\xef\xbd\x85\xc5\x22\x34\x15\xbd\xcb\x62\x59\x3f\x58\xd5\x97\x08\xd6\x84\x87\x5d\xab\x05\x75\x89\x16\x60\x23\xe5\x05\x23\xb0\x91\xba\x1a\xa8\xd8\x95\x81\xe2\xbf\x01\x86\xe2\x83\xac\xc9\x72\xa0\x12\xfa\x6a\xdd\xb4\x4e\x48\xe8\x83\xc2\x2d\x83\xd8\xba\xdd\xb4\x08\xb1\x46\x50\x71\x2b\xe9\xc4\x0a\x5e\xaf\x05\xa3\x7a\x4e\x84\x60\x78\x81\x08\xde\x0a\x84\x91\x99\x2a\x6c\x6e\x00\x94\x9a\x68\xd5\x76\x1b\xa3\xb6\x3b\xf5\x94\x90\xbb\xdc\x2f\x7c\x0b\x06\x4d\x55\x60\x2c\xd3\xa2\xfb\x4b\x49\xc5\x0c\x58\xc7\xf5\xe9\xa1\x90\xf3\xf5\x28\x59\x83\x84\x3f\x8e\x35\x6f\xdf\xf2\x4b\xe7\x50\xfa\x3a\x61\x35\x3f\xa3\x29\xc4\x48\xe9\xbd\xd5\x4f\x50\x61\x56\x89\xe2\x00\x19\x53\x18\x31\x7f\x78\xc0\x94\x5e\xa4\x4f\xe1\xd8\x36\xf3\x7e\xc5\x3c\x59\x7c\xb3\x98\x86\x29\x88\x9a\x61\xbc\x47\x1d\xa2\x31\xb3\xc8\x54\x82\xa1\x85\x94\x06\x9d\x8b\xf9\x5d\xe4\x39\x97\x2c\xe0\x2c\x6f\x6b\x21\x55\x41\xec\x17\x01\x42\x09\x51\xc0\x04\x3b\x0f\xf7\x24\x47\xa2\x39\xb5\x35\x41\x97\xac\x43\x54\x15\x4e\x48\x46\xc4\x03\x4a\x6c\xcf\x46\x4c\x23\x27\xac\x78\x99\x24\xdd\x5b\xa8\x22\x49\x48\x32\xf3\x29\x49\xad\xa8\x2a\x9c\x34\xc2\x2a\x67\x54\xfe\xaf\xc9\x56\xb3\x15\xaa\xc5\x19\x05\xc4\x1c\x15\x38\x97\xf4\x55\xbb\x10\xc4\x5a\x12\x56\x92\x00\x27\x24\x69\x56\xb7\xd8\xae\x94\x13\x1b\xfc\xae\xd9\xae\x5a\x2d\xa8\xb3\x31\xc0\xe4\x76\xc1\x74\xc8\x16\x97\xf7\xfc\x8b\x75\xec\x6f\xc2\x66\x53\x6b\x34\xc5\x06\x55\x68\x5c\x0b\x74\x25\x4d\xa8\x96\xe5\xa1\xa2\xeb\x2a\xa0\xce\x44\x6a\x71\xa8\x2b\xa8\x4b\xed\x43\x9b\xbd\x57\x55\x15\x8d\x74\xe0\x34\x8a\x91\x5e\x98\xbd\xad\x3e\x44\xcd\x96\x67\x65\x5e\xaa\xa4\x68\x79\x2d\x5a\x63\xfc\x32\xf3\xc0\x8a\xa9\x30\x18\x72\x60\x14\x73\x0c\xac\x7a\x28\x01\x31\xb0\x86\x2a\x2a\x86\x1c\x27\xc7\xe2\x27\xec\x32\x40\x0d\x67\x68\xc2\x48\x68\xc2\x48\x68\xec\x32\xac\xdf\xbc\xda\xe5\xea\x98\x55\x87\xac\x2c\xea\x42\x33\x99\x89\xfa\xd1\x6c\x70\x6d\x18\xb9\x55\x2c\x8e\x46\xa9\x35\xf3\x6c\x95\xb7\x52\x0d\x0c\x28\xd5\xa2\x7d\x28\xd5\xa2\x71\x5c\x26\x89\x8e\xdd\x7a\x70\xba\x07\xa8\xea\x64\xcc\x4a\xe5\xdd\x9b\x2d\x00\xc8\x63\x3d\x17\x43\x8d\x9f\x69\x37\xd3\x5e\x96\x1c\x73\x1d\x5e\xca\xc4\xaf\x36\xba\xaa\x19\x42\xe6\x1e\x42\xe6\x1c\x42\xe6\x1a\x42\xe6\x18\x60\xc2\x84\x3b\x86\x95\xf8\x86\x9a\xb9\xf8\x9f\x48\x10\xe6\x22\x86\x07\x89\x2c\x1a\x3e\xbf\x7c\xbe\x40\x11\x70\x1c\xe4\xb8\x5d\x42\xb6\x05\x1b\x77\x5a\x76\x21\xd6\xbb\x7a\xb9\x75\x9b\x6d\x22\x31\x74\x4e\x41\xed\x9c\xca\x02\x2a\x3d\x4d\x20\x8c\xe9\x6c\xc3\xb7\x32\x2a\xbf\xd8\xf1\x12\xb1\xb0\x93\xfc\x35\x57\x20\x53\xaa\xc4\xb1\x96\x8d\xad\x91\xa5\x35\xc7\xe2\xfa\x89\x49\x61\xa9\x7f\x51\x0e\x04\xdc\xdf\x20\xd5\x34\x59\x41\x2c\xd9\x86\x9b\x28\x87\x1f\x41\x26\x65\xe5\xde\x32\xe8\x50\x00\x94\x35\x54\xf6\x28\x4c\x21\x81\x07\xcd\xe5\x0c\x2e\x78\x7a\x2a\x7f\xe4\x72\x26\x9d\x7c\x30\xea\x8b\xa9\x95\x3b\x66\x1d\xbc\x25\x74\xe1\xa8\xc2\x8b\x76\x4b\x72\x3c\x03\x66\x94\xa8\xcf\x10\x16\x16\xf2\xee\x9d\xaf\xaf\x59\x77\x1a\xc6\xb1\x7c\x79\x20\x97\x3f\xd4\x12\x2c\x6a\x19\x3a\x47\x89\x11\xcc\x65\xc3\x55\x5a\x78\xef\x57\x69\xd1\xa3\xd4\x85\x00\xdd\x05\x7b\x40\x85\x12\xca\xc8\x42\xa4\x44\x84\xc2\x65\x3a\x94\x34\xed\xb2\x74\x85\x7f\xb9\x21\xa0\xf7\xe4\x51\xdf\xc0\x6a\x14\xfe\x73\x57\xba\xd2\x32\xe9\x7c\x9c\x3d\x58\x15\x4d\x6b\x6e\x5e\x1a\x2a\xb3\x05\x15\x1c\x84\x80\xb4\x79\x13\x27\x85\xd9\x36\x55\x0d\x62\x77\x5c\x31\xab\x4a\x25\x97\x0e\xb1\x4a\x99\xb9\x89\x95\xfc\x9a\x2f\x49\x12\x97\xee\x27\x90\x09\x5d\xa7\x68\x5f\xdd\x43\x59\xcb\xa7\xf4\xb2\x53\x16\xac\xde\x2c\x21\x57\x7b\xf9\xc5\xb6\x70\xc3\xc8\x77\x53\xde\xc5\x3d\x92\x8f\x2f\xba\xef\x59\xc2\xbb\x72\x3d\x20\xf3\x1c\x45\xec\xf9\x76\xcd\xb7\x0d\x45\xb4\xe2\x6e\x9d\xb7\x62\xc1\xfc\xa9\x48\x2a\xd8\x74\x18\x14\x30\x52\xb9\x3a\x5f\x29\x70\x33\x55\xa9\x98\x8b\x0d\x1c\x55\x0a\xa3\x2f\x3e\x4b\xcc\xad\x10\xba\x4a\x3d\x9f\x0c\xcf\xb5\x82\xae\x1b\x73\xc5\xd8\xbd\x57\xee\xf8\xdc\xc2\x17\x72\xfd\xa7\x97\xad\x1d\x31\x2e\xdd\x80\xe9\x58\xf4\xd9\x96\x2a\x4a\x9d\x3a\xdc\x58\xb7\xb6\xdc\x98\x40\x78\x64\xbc\x0b\x97\x88\xd9\xb6\xb0\x5c\x53\xab\x03\x04\x17\x8c\xe7\x4c\x2a\x5f\xd3\xa4\x1b\x5d\xa0\xcb\xe4\xfc\x15\x50\xae\x1d\x8c\x51\xc5\xe7\x5e\x8a\x2e\xda\xd3\xd1\xcf\x44\x58\x2e\x15\xe6\x30\xd4\xf1\x19\x1e\x1e\xe4\x0e\xf7\x7c\xb4\xf1\x65\xdd\xd6\x46\x37\xf2\x79\xe5\xf4\x0d\x4f\xe6\x54\x44\x66\xd0\xe5\xed\xc1\x77\x37\x6c\xd5\x75\x70\x7b\xcd\x51\x31\x2f\x21\xfd\x5b\x7c\xd8\xab\x44\xe8\xbe\xea\xb8\x79\x89\x88\x6e\x5a\x52\xd2\x6e\x5d\x41\x5f\xc2\x7b\x69\x8e\xea\xa0\x74\x36\xd8\xf5\xa3\x54\x97\x1c\x5f\x85\x68\xa7\x24\x5d\x8c\x14\x33\x51\x35\xb9\xa0\xc8\x49\x26\xa1\xff\x7f\x00\x00\x00\xff\xff\xf8\xbb\xf0\xab\x69\x22\x00\x00")
+
+func fonts5lineobliqueFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fonts5lineobliqueFlf,
+ "fonts/5lineoblique.flf",
+ )
+}
+
+func fonts5lineobliqueFlf() (*asset, error) {
+ bytes, err := fonts5lineobliqueFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/5lineoblique.flf", size: 8809, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsAcrobaticFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xe4\x5b\xef\x6e\xe3\x36\x12\xff\xee\xa7\x18\x04\x04\xda\xe2\x76\xab\x4d\xae\x05\x6e\x0b\x41\xd8\x02\x77\xf7\x00\xf7\x99\x80\x4e\xb1\xe5\xc4\xa8\x63\x16\xfe\xd7\x2d\xa0\x87\x3f\x90\x9c\x19\xce\x50\x74\x2c\x25\xd9\xee\x02\xe7\x00\xb1\x48\x53\xe2\xfc\xe3\xcc\x6f\x86\xd4\x7a\xbb\xbe\xeb\x0c\xdc\xde\xc1\x47\xb8\xfb\x19\x3e\xc0\xed\xcf\xf0\x61\xf1\xeb\x72\xef\xee\xbb\xe3\x66\x09\xf7\x7f\xc2\x7f\xba\xdd\x2a\xfc\x3f\xb8\x27\xf8\x47\xf5\xf1\x27\xa8\xf7\xa1\xf1\xe9\xb0\x5c\xff\x78\x3a\x2c\x7f\xec\x57\xa7\x66\xf1\xef\xcd\xc3\xb6\x3f\xc2\xbe\xdf\xf6\xdd\xa1\x87\xbb\x1f\x6f\xe1\xfd\x7b\xf8\xf5\xf4\x70\x3a\x1c\xe1\xf6\xee\x1d\xdc\x7e\xfc\xf8\xd3\xe2\x9f\xdd\xb1\xff\x05\xee\xfe\xee\x7f\x88\x3d\x8b\x7f\x7d\xfe\x7d\xdb\xed\xba\xe3\xc6\xed\xc0\xad\x61\xbd\xd9\x1f\x8e\xb0\xdd\xec\xfa\x5f\x16\x9e\x3a\x78\x0f\x37\x4f\xdd\xc3\x66\x09\xbb\xd3\xd3\x7d\xbf\xbf\x81\xb5\xdb\xc3\x7a\xb3\xed\x61\xb3\xea\x77\xc7\xcd\x7a\xb3\x0c\x37\x2f\x3a\x00\x80\xf7\x70\x78\x74\xa7\xed\x0a\xba\xed\x1f\xdd\x9f\x07\xb8\xef\xe1\xbf\xdd\x77\xef\xc2\x4d\x3b\xf7\xc7\xc2\xc4\x41\xc7\xc7\x1e\x6e\x1e\xbb\xfd\xea\x7e\xdb\xed\x7e\xbb\xf1\xa4\xfe\xbe\xdf\xec\x8e\x07\xe8\x0e\xd0\x41\xe8\x7d\x07\xf7\xa7\x23\x2c\xbb\xdd\x77\x47\xff\x98\xc3\xd3\xe9\xf0\xd8\xaf\x16\xb7\x77\xe1\x09\x8f\xfd\xe6\xe1\xf1\xe8\x29\xee\x60\xf9\xd8\xed\xbb\xe5\xb1\xdf\x2f\x3e\xc2\xe5\x1f\xdf\xc1\xce\x1d\x61\xb3\x5b\x6e\x4f\xab\xcd\xee\x01\x56\xfd\x61\xd9\xef\x56\xfd\xfe\xb0\xb8\xfb\x39\xdc\xf6\xd4\x7d\x0e\x9c\xc3\xb6\xdf\x3d\x1c\x1f\xe1\xfb\xfe\x33\x0d\x5e\xba\xa7\xa7\x7e\x17\x05\x73\xf8\x01\xfe\x06\x1d\xac\x4f\xab\x87\x1e\xd6\xdd\xf2\xe8\xf6\x8b\x0f\x71\xe2\x55\xbf\xee\x4e\xdb\x63\x24\xf6\xc9\xad\xfa\xc0\xf8\xf1\x71\x73\x80\xb5\xdb\x1d\xe1\xfb\xed\xe6\xb7\x1e\x6e\xde\x3f\xc1\x87\x1b\x70\xbb\xf0\xd8\x6e\xb7\x0a\x8f\xfd\x61\x71\x1b\xc9\x88\x82\xf6\xd4\xab\x59\x69\x8e\xfd\xd1\x6d\x17\x0b\x63\x8c\xf9\xf4\xfa\xff\x9f\xbc\x46\x1c\x80\x6f\x43\x3d\x34\xf1\xa2\x02\x1b\x2f\xac\xab\xe2\x05\x0c\x34\x06\x70\x8c\xff\x18\x79\x7b\x5b\x0f\x4d\x6b\x3e\x2d\x20\x7e\x0a\x17\x7e\xb4\x03\x7f\x83\x1f\xef\x67\xab\x87\x26\x5c\x42\xe3\x1f\xcc\xcf\x05\x78\xf9\x25\x40\x3e\xaf\xbe\x24\x6e\x20\xf1\x14\x88\x4a\x7c\xb4\x43\xd3\x42\x5b\x0f\x6d\x6b\x66\x0f\xae\x5d\x03\x10\xfe\x97\xee\xf5\x72\x05\x92\x2e\xc8\xcf\x95\xa6\x6c\x5f\xbe\xf6\x52\x18\x5a\x47\x74\x57\x00\xa4\x47\xb0\x4e\x48\xea\x6c\x85\xd4\x6a\x8b\x9c\x58\xd7\xb6\x55\xea\x1f\x32\x71\xea\xb9\x48\x95\x51\x16\x15\xe9\x33\x7c\xaa\x33\x90\x52\x43\xb3\x91\x2a\x72\x95\x52\x59\x75\x56\x2a\xac\x1a\xa9\xd2\x38\x96\xec\x85\xc6\x92\xd1\xd0\x58\xb4\x1c\x78\x4e\x80\xe3\xb6\xef\x30\x7e\x06\x94\x0c\x8e\x31\xb5\xe7\x3b\x72\x62\xb0\x0b\xac\x85\x0a\x49\x31\xb1\xcb\x55\x2d\xb4\xf1\xce\xc0\x3c\x18\xfc\xdd\x2b\xb8\x3a\xfb\x51\x82\x3e\x5b\x35\xe1\x59\xc6\xf2\xfc\x95\x75\xb1\x8b\xa5\xe8\xbc\x5e\xc2\xe3\x4d\x6d\xdb\x16\xda\x36\x3c\xa0\xb6\x23\xde\x0a\xec\x5c\xe8\x42\x29\x92\xf4\x48\x6a\x24\xed\x19\xdf\x7a\x0e\xfe\x8e\x17\x06\xa2\xcd\x85\x4b\x3f\x0f\xca\xad\x6a\x50\x86\xc6\x6b\x32\x8a\x38\x08\xd8\xe0\x43\x8c\xb5\x42\xf4\x60\x59\xe6\x10\xe4\x62\x70\xa2\x20\x90\xcb\xb6\x98\xd9\x65\xdb\xba\x34\x81\xb7\xf5\x34\x41\x6d\xc5\x04\xe0\x55\x40\x0c\xc0\xd0\x10\x03\x50\x55\xc4\x00\x54\xc4\x40\x30\xc2\xc8\x80\x57\x8c\x79\x96\x88\x7c\xa1\x58\xd6\x31\x79\xd3\x73\xb4\x04\x6f\xd1\x28\xe4\xda\x92\xf9\xf3\x02\xb4\xae\x1a\x48\x0d\xad\xf5\x6c\x0d\x5e\xd0\x55\xcb\x23\x2a\xb0\x83\x50\x54\x58\x2f\x61\x32\x74\x00\x71\xc1\x9c\x2d\xb9\x9f\x64\x91\x23\x07\x54\x30\xa0\x71\x47\x5a\xc5\xf1\x8b\x97\x31\xad\xfd\xd4\x01\x59\x47\x74\x7d\x92\x19\xd0\xcc\x80\x85\x2a\x7b\x86\xcb\x9e\x81\xde\xb4\x38\xcb\x4b\x98\xc9\x7f\x9a\x76\x61\x92\x47\x22\x57\x04\x29\x7a\x91\x8a\x71\x19\x18\x5c\x03\x33\xc3\x59\x90\x50\x2b\x65\xf3\x36\xa1\x4f\x76\x3d\xff\x65\x52\x94\x46\x67\x6e\xca\x23\xd3\x04\xe4\x6b\x52\x33\x7a\xc2\xd4\x6c\x0c\xdf\x17\x7c\xaf\xe1\xe7\xa0\xc0\x80\x57\x67\x94\x1b\xad\x5c\xf2\x1f\xb8\xaa\xc3\xba\x49\x0a\x09\x3e\xad\xc0\xf0\xb4\xb6\xf0\x61\x20\x7d\x07\x12\x05\x71\x05\x25\x27\xa2\x56\x51\x72\x6f\xfc\x89\x6e\x25\x06\x92\xf4\x89\xfe\x25\x38\x3c\xfe\x24\x47\x23\x02\x83\x76\x81\xe1\xe3\xa4\xa0\x38\x38\x8c\x7c\xd0\x45\x16\x9f\xe9\x44\x7f\xc9\x58\x26\x47\x7b\x6e\xd4\x03\x79\x8f\x82\x42\x57\xf0\x9f\xe7\xaa\x6d\x1d\xbb\x67\x2f\x38\x1f\xf5\xa2\x1a\x87\x28\xd5\x18\x18\x63\xc4\x0d\x46\xa2\xc0\x82\x86\x0a\x1a\x28\x28\x98\x40\xe1\x2e\xac\xa4\xaa\xcd\x7c\xc4\xb3\xad\x28\x7f\x34\x08\xd6\x3c\x1b\x03\x6a\x5d\x18\x42\xa2\x11\x80\xfd\x3c\xdb\x64\x5b\x0f\x90\x8d\xc0\x15\x2d\xac\x81\x6e\x91\x4a\x8f\x88\x44\x28\xfc\xa5\x4e\x9b\x30\x6b\xc2\x69\x04\xa2\x82\x07\xad\xc1\x06\x6a\x90\xe3\x00\x18\xec\x10\x1a\x83\xe4\x24\x36\x62\xab\x76\x29\x62\xf2\x2f\x18\x34\x33\xcc\xf2\x4c\x23\x10\x17\x67\xf5\x4a\x42\x02\x83\x98\xe3\x08\x89\x24\xb9\x23\x60\xd5\xb6\x4d\x1d\x51\xa4\xb9\xd7\x94\x92\xd6\x4b\xec\x4b\x49\xfa\x25\x66\x43\x61\x2e\x31\xe3\x25\x0f\x92\x99\xe1\xab\x30\x43\x51\x88\x4d\x22\xf2\x01\x01\x79\x28\x21\x57\xca\xbc\x1d\xfa\x30\x6c\xa3\x63\xe7\x45\xdc\x90\x87\x25\xc8\x42\x7e\x1e\x11\x0b\xfb\xf9\xe8\x6a\xcd\x05\x0a\xa7\xf9\xf5\xf9\x8b\x38\x03\x6b\x60\xc0\x67\x78\x72\x11\x57\x5f\x45\x1b\xaf\x63\x26\x2e\x50\x03\x36\x30\x13\x01\x58\xb6\x4e\x86\xbf\xd2\xb4\x4a\xe8\xc2\xa4\xc5\x2c\xbf\x66\xe0\x10\x1c\x1c\xd2\xb8\x06\x2f\xf0\x06\x43\x10\xa9\x74\x71\xf9\x2e\x17\x43\xb4\xf1\x48\x26\x42\x0d\xa3\x30\x43\x95\xd2\x9e\x94\xf5\x24\x54\x90\x72\x1e\x99\xf2\x88\x8c\xc7\xa5\x68\x8f\xd9\x1f\xc4\x44\x65\x6a\x25\x23\x7c\xe6\x02\xc9\x19\xf0\x72\x02\x11\x56\xe4\x5b\x12\x29\xa9\x6c\x4b\x26\x5b\x29\xd7\x62\x04\xe4\x38\xd3\x4a\xee\x22\x79\x8a\xeb\x44\xa8\xc5\x41\x10\x11\x28\xa5\x56\x0b\x43\x5a\xbd\x53\x7e\x0c\x53\x64\x6a\xa9\xba\x85\x16\x8d\xaa\x62\x84\xea\x4f\x21\x0b\xb9\xd2\xcc\x70\xa7\x29\xa0\x4e\x53\xc0\x9c\x46\x20\x4e\xbc\xb5\x49\x51\xb3\xc6\xa8\x5d\x25\xb4\x59\x83\xd4\xe6\x78\x81\xe7\x48\xb3\x80\x33\x0b\xd8\x71\x62\x97\xc8\x0e\xdc\x18\xa2\x87\x05\x97\x75\x62\xf5\x51\x75\x1a\xcc\x6c\x8d\xe8\x34\xc4\x6a\xa3\x00\x3b\x3e\x4d\x98\xa1\x00\xe7\x36\xb3\x0e\x60\x39\x4b\x1b\x61\x49\xbf\x01\xb8\x06\x69\x95\x94\x13\xd0\x84\xa8\x8a\x1a\xc1\x57\xa4\x13\x4d\x32\x62\x80\x1a\x9d\x32\x01\x80\x30\x92\x01\x43\x25\x7f\x8b\x6e\x32\x3c\x33\x6a\x6d\x2e\xde\x05\x4d\x6c\x6e\x89\x63\x43\x1c\x65\x3e\x26\x4f\x7b\x0c\x8c\x72\x9e\xb1\x11\x16\x6c\x70\x6c\x82\x63\x01\x4f\xea\x11\x1a\x60\xd4\xc1\x4a\x60\x3f\xc3\x7a\x40\xdc\x62\x99\x2b\xcc\xe5\x04\x00\x23\xd8\x4c\x0c\x44\x0f\x96\x6e\x61\xec\x93\xd4\x22\x66\xb9\x9c\xb7\x4d\x0d\x9b\x09\x2b\x67\x50\x39\x62\x49\x46\xca\x9a\x0a\x46\x60\x11\x65\x27\x04\x96\xfd\x9e\xb0\x68\x76\x3f\x3e\x3f\x32\x61\x4b\x09\xd5\x24\x44\xf6\xa5\x18\x60\x08\x19\x19\x10\x10\x72\x00\x5d\x2a\x48\xbe\xe5\xf5\xa5\x82\x62\xa5\xa0\x58\x28\x28\xd5\x09\x40\x97\x09\x52\x4c\xd6\x2b\x66\x28\x3b\xee\x62\x8d\xa0\xe0\xba\x8b\xae\x69\x72\x9f\x2a\xf3\xab\xfc\x11\x52\x0e\x99\x74\x46\x38\x4e\x2c\x17\xc4\x70\x41\x6b\x02\x76\xe6\x23\x92\xe1\xc5\xbc\x72\x3c\x42\x2c\xb9\x3c\xbf\x2c\x92\x5f\xce\x68\x12\xec\x91\x7b\x32\x11\xf8\x3e\xb3\xd7\xf5\xb2\x5a\x07\x44\xdb\x63\xbd\x02\xdb\xe2\x00\x22\x5f\x56\x5b\x42\x68\x9c\x48\x8c\xa8\x6b\xe1\x2d\xdc\x66\xe2\xec\x68\xc4\x17\x2c\x21\xc0\x78\xbb\x87\xf7\x3b\xc8\x0c\x78\xb7\x83\x72\x47\x5e\xbc\x5c\x52\x00\xed\x7e\xec\xc8\xff\xf0\xf6\x08\x9b\x41\x16\x34\x2f\x44\xe8\xe9\xd9\x47\x1a\x10\x58\xc9\x7c\x84\x70\x21\xd1\xb5\xa7\x24\x55\x78\x1c\x41\x8f\x01\x1d\x3a\x72\xf2\x99\xf8\x0b\xde\xf3\x2a\x58\x94\x1a\xe0\x95\xc8\xb2\xa8\x38\x2e\xd1\xae\x54\x05\x0c\x2b\xce\x61\x53\xca\xdb\x14\xaf\xac\xda\x06\xef\x94\x2f\x2d\x10\x77\x01\x69\xa2\xca\xd6\xe3\xa5\xbb\xe0\x9a\xe8\x2f\x46\xe8\x67\x18\xab\x33\xc6\x14\x89\xb8\x8d\xa2\x19\x1b\x93\xe8\xef\xcc\x18\x3b\xdb\x11\x63\xb5\x1d\x33\x56\xbf\x86\x31\xf8\xbf\x2e\x2b\xbf\x1a\xf9\x6a\xed\xa8\x52\x99\xc9\x57\x22\x3f\xb3\x40\xfd\x1c\xe4\xfb\x55\xb5\x64\x5d\x49\x4b\xc3\x48\x4b\x40\x19\xd2\xdb\x6a\x09\x20\xd7\x14\xe4\xf8\x98\x9c\x9e\xd0\x18\x08\xd7\x8e\x35\xb2\x0c\x5a\x8e\x9d\x7b\xc1\xbb\x17\xdc\x7b\x39\x03\x9b\xbe\xf6\x66\x57\xcb\xbe\xd9\xaa\xb2\xf1\x64\x31\x70\x46\x52\xe2\xe9\x0e\x7d\xca\x03\xd0\x8a\x88\x83\x54\xb7\x8f\x3d\xc0\x88\x02\x31\x9b\xd8\x0d\xc7\x51\x72\x4b\x2e\xee\xf3\xca\x25\x65\x80\xb7\xef\x53\xc2\xee\x5d\xeb\x25\x55\x4c\xaf\x13\x4c\x00\x9a\x39\x04\x54\x89\x5a\x1e\xa5\x06\x28\x63\xd3\xbf\xac\xbe\xa9\x3e\x39\x47\x92\x2d\xb5\xbd\xc1\xc7\x59\x8c\x55\x8f\x70\xe4\x2e\xce\x72\xcf\xe8\xcc\x0a\xac\x53\x30\x6e\xa4\x0e\x09\x0e\x64\x6a\x44\x48\x90\x69\x32\xc2\x82\xcb\xca\x9c\xdb\x3b\x53\x10\x72\xf1\x17\xb1\x08\x94\xf1\x08\x14\xd4\x1d\x9f\xab\x44\xe9\x2a\x3e\xb1\x93\x44\xe9\x9d\xc2\xd9\x66\xa2\x8c\x9e\x01\xcf\xed\xbc\x91\x20\xc4\xbe\x82\xc1\x4a\x29\x40\xda\x22\x37\x78\x00\x44\x56\x4c\xf5\x06\xf9\xa0\x83\xd3\xa8\xc4\x95\x17\xb7\x8a\xa5\xcf\xe7\x88\x2d\x60\xce\x37\x25\x3a\x79\x0a\x6c\x5a\x8e\x1f\xd7\x07\xcf\x20\xfa\xca\xb6\x55\x82\xfe\x95\xf4\x88\xa0\xa2\xaf\xd8\xb6\xc2\x66\xc3\xee\x52\x6e\x38\xa7\x6d\x2b\xec\xa0\x6d\xab\x57\x15\x49\x80\xe2\x4d\xfd\xba\x2c\x15\x8f\x25\xe6\x53\xc9\x2c\x35\xa8\x58\x56\x44\x82\x8e\x65\x51\x36\x28\x59\xfa\x84\xe0\x54\x54\x29\x96\x30\x92\x08\x13\x16\x8c\xf2\x2c\x62\xab\x03\x3b\xd2\x7e\x07\x76\x14\xe2\xfd\x14\x69\xf1\xf9\x85\x70\x6e\xef\xcb\xe6\xf4\x86\xbc\x08\x9f\x34\x38\x5b\x3a\x67\x30\xda\x5d\x78\xe5\x75\x99\x6b\x75\x2d\x1a\x2f\xbe\xbc\xb4\x71\xd4\x26\xd4\x93\x43\x0c\x7d\x49\x36\xe4\xfb\xce\x34\x2c\x49\x62\xc6\xb7\xa6\x8e\xbf\xe7\x39\x00\x09\xfd\x62\x6d\x99\x1c\x22\x1e\x65\x40\x87\x88\xd1\x85\x42\x8e\x45\x0f\x47\xf1\x8a\x8e\x3a\x44\xc4\x5d\x48\x70\x27\x26\xec\x12\x58\x37\xb2\x8e\x50\x31\x02\x53\xc5\x12\xa3\xd0\xf3\x99\x0e\xc3\x08\x08\x9e\x55\x9b\xb3\x5a\x73\x56\x69\x9e\x4b\xf4\xa5\x1f\xc7\x0d\x23\xea\x5a\xd1\xe5\xc5\x12\x96\x91\x87\x71\x6a\x89\x3c\x39\xff\x89\xf7\x04\x0f\x59\x57\x33\x8e\x8a\x00\x30\x2c\x15\xd5\xb3\x7a\x90\x07\x51\x28\x63\x57\x26\xa0\x2c\x20\x33\x00\xa5\xff\x4c\xfd\x17\xb5\x3f\x21\xa7\x9c\x2a\x73\xa2\x15\xb0\x36\x9a\x36\xa7\xf4\x31\xe7\x2a\xea\x9a\xf1\x1c\x02\x7c\xc4\x30\xde\x72\xd0\x5e\xc3\x91\xa7\x6a\x74\x24\x7a\x82\xea\xe7\x6c\xa1\x26\x74\x8a\x3b\x24\x4d\x4b\xea\x11\x16\xa9\x33\x3f\x9d\x1a\xea\xfc\xb2\x0c\x3a\xe7\xd8\xeb\xd5\xb4\xff\x2d\x4c\xc2\x47\x36\xaf\x2c\xfd\xb6\x02\xfe\xe6\x30\x79\x44\x8c\xcb\xa7\xb8\x4d\xe6\x0d\xb4\x33\xd0\xbe\x40\xbb\x02\xed\x09\xae\x56\x4e\xe2\x4f\xaa\x8a\x35\xdb\x76\xc7\x2f\x74\x44\xa2\x55\xac\x9c\xf4\xaa\x88\x7e\xcf\xa1\x18\x4f\xe3\x05\x3f\x17\x9b\xfa\x4d\x12\x9e\xbe\x3c\x98\x48\xa1\x1f\xc5\xac\x46\x16\xd2\xb3\xca\x7b\x6c\x21\x1a\x60\xbc\x83\xa4\x0b\x45\x82\xd4\xa4\x49\x8e\xdd\x08\x3d\x4a\x1f\x9d\xfc\x73\x52\x0a\x17\xc8\xd3\x8b\x00\xae\x92\x35\x10\xa9\xdc\xc9\x47\x3f\xd4\xb9\x98\x94\x2b\xe1\xa4\x57\x3a\xe5\x13\xe9\xab\x90\xbb\x4c\xed\x62\x9b\xa5\x32\x5a\x32\x47\xfc\x2f\x12\x3c\xfe\x9f\x4c\x98\xff\x8f\x6f\x84\xf2\x8d\x2f\x25\x75\x72\x88\x63\x96\x14\x33\x9a\x0d\xc5\x80\x22\x3d\x1f\x36\x6d\xd2\x97\x45\x8e\xa9\x1e\x9b\xef\x54\x6e\x0d\x83\xe9\x33\x9b\xed\x6f\x05\x1a\xbc\x44\x73\xbf\xa6\xdd\x9a\xf6\x6a\x52\xa2\xe9\x74\x03\x91\x48\xc3\x4c\x16\x52\x54\x40\x19\xd9\xf4\x94\x76\x8a\x13\x4a\xaa\x03\xad\xf3\x14\x2b\x00\x74\xb4\x00\xd0\xf1\x22\xde\x9f\x22\x06\x88\x74\x93\x7f\xe7\xfc\x13\x40\xbc\x8f\x02\x10\x5f\x7a\x79\x3b\x7b\xc5\x90\x45\xd2\x35\xba\x84\xae\x2a\xe8\x2f\xb2\xd7\x6b\x0d\x23\xf6\x41\x4d\xc2\x8b\x80\xe5\x19\x4e\xc5\xcf\x36\xe5\xd9\xe9\x38\x38\xa1\xc5\x39\xc4\xa1\x2a\x52\xc1\x29\x95\x88\x92\x8c\x0c\xef\x4f\x67\x7d\xe2\x57\x20\xb4\x15\x54\x29\x96\x73\xf1\x6a\xe6\x2a\xce\x56\x22\xd7\xc6\xb2\xea\x60\xbe\xb7\x3e\xc0\x78\x15\x23\x3a\x41\xd0\xf1\xc5\xa0\x14\xcf\xaa\x08\xd6\xf4\xe6\xa5\x37\x55\x72\x53\xa5\xb6\x71\x89\x6d\x0e\xba\x2e\xb3\x73\xa5\xf7\xed\xca\xb3\x5f\xb5\xa6\x58\x1e\xa2\xaf\x8d\x7a\x4b\xf1\x6c\x55\xf1\x8e\x53\x44\xc3\x78\x24\xba\x3b\x15\x41\xb2\xba\xcc\xc5\xeb\xaf\x6f\x42\xf4\xc6\x1e\xb9\x8f\x54\xa6\x4a\x6f\xed\x4d\x2b\x9b\xd0\x66\x10\xc1\x5f\x2c\x15\x1a\x50\x07\x55\x55\x44\x88\x41\xa9\x49\xa7\x78\x00\x20\x7b\xd3\x57\x43\x38\x48\x2f\x4e\x86\x4a\x1f\x16\x13\xeb\x81\xe2\x48\xc5\x20\x93\x4f\x50\x58\x7a\x59\xc6\x7b\x00\x3e\x65\x8f\x3b\x17\x79\xc1\xef\x92\x7b\x9a\x0e\x13\x27\x77\xa6\xf7\x2e\xf1\xc8\x3c\x19\xd6\x90\x8a\xc3\xe2\x08\x30\xa7\xec\xbc\x0b\x3a\x00\x4b\x18\x45\x19\xeb\x71\x65\x1e\x14\x37\x88\x3b\xc3\x87\x92\x39\x9b\xea\xaf\x72\xd7\x0e\xbe\xbd\xf6\xa7\xc5\x85\xbf\x6f\xf5\x87\xff\x05\x00\x00\xff\xff\x10\xbf\x87\x51\xb4\x42\x00\x00")
+
+func fontsAcrobaticFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsAcrobaticFlf,
+ "fonts/acrobatic.flf",
+ )
+}
+
+func fontsAcrobaticFlf() (*asset, error) {
+ bytes, err := fontsAcrobaticFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/acrobatic.flf", size: 17076, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsAlligatorFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x4d\x6f\xdc\x36\x10\xbd\xeb\x57\x0c\x20\xde\x54\x04\x88\x5d\xd4\x08\x51\x14\x6a\x8f\xbd\xf6\x17\xd8\xad\xd3\x06\x75\x13\xc0\x4d\x0e\xfe\xf7\xc5\x8a\xe4\xcc\x7b\x33\xd4\x7a\x65\xd9\x40\x0f\xda\x0d\x16\xa2\xb2\xcb\xf9\xe0\x9b\x37\x1f\xf2\xc7\x87\x8f\x57\xb7\x49\x6e\xe4\x46\xae\x7e\x90\xeb\x2b\xb9\x1e\x7e\x7e\x78\xf8\xf4\xe7\xed\xd7\x2f\x8f\x72\xf7\x24\xbf\x7d\xfa\xe7\xcb\x67\xf9\xe5\xf1\xf6\x8f\x87\xfb\x27\xf9\xf1\xdf\xa7\xbb\xeb\xf9\xf6\xee\xfe\xf1\xdd\xed\xef\xef\xbe\xfd\xfd\xd3\xf0\xfe\xe6\xeb\x5f\xf2\xeb\xb7\xcf\xf7\xdf\xc9\xfb\x0f\x1f\xbe\x1f\x86\x34\xc7\x7f\xf3\x20\xcb\x2b\xe7\x9c\xea\x75\x9e\x72\x92\x72\x3d\xe5\x29\x49\xb9\x9e\xc6\xd3\xe5\x72\x5d\x2f\x4f\xd7\x49\x52\xf9\xfd\x3c\x8c\xe3\xd8\xae\x61\x53\xb7\x31\x6e\x5e\xbe\xdd\x36\x85\xe5\xb2\x86\x65\x11\x64\x4b\x99\x07\x5a\x9a\xc0\x45\x62\x31\x46\x54\x89\x29\x37\xa3\x8a\xf6\x99\xde\x55\xb9\x69\x9c\xd4\xde\xd3\xf7\xa6\x91\xde\xf5\xb7\xe3\x34\xca\xf2\xa9\x8a\xc8\x38\x2e\xb7\xd4\x78\x50\xa6\xe8\x51\x15\x51\x89\xa9\x2a\x01\xc2\x16\xf1\x53\x9e\x4c\x50\x51\xa8\xad\x55\x0f\xfd\x3e\xc8\x5b\x04\x92\xdd\xde\x62\x33\x4c\xb7\xd6\x8d\x74\xe1\xec\x63\xcb\xc8\xc1\x19\xdd\x0b\xb2\x4c\x14\x8b\x2b\xc6\x89\x4c\x65\x5b\x35\xad\xd8\x73\x12\xd4\xa4\xaa\x5a\xa3\xbe\x92\x07\x94\x81\x49\xad\x4b\x66\x4d\x32\x5b\x92\x9d\x51\xd2\xb3\x19\x12\xb9\xcd\x6d\x4a\x20\x69\x9b\x82\x83\xf4\xb2\x9c\xc9\x33\xd0\x4f\x80\x40\xbd\x36\xc4\x95\x8d\xf1\x44\xea\x09\xa4\xd5\x4d\x93\x86\x41\x22\xf7\x07\x11\x78\x00\x0a\xad\xd3\x67\x0a\xe8\x12\x38\x02\x14\x0f\xb2\x02\xae\x93\xc0\xe9\x36\xb7\x09\x9a\xa8\xfe\x02\xd1\x0c\xbe\xfa\x7d\x73\x63\x8d\x7a\x3d\x1f\x32\xbb\x5e\x9e\xfe\xbb\x91\x47\x52\xde\x48\xfc\xe3\x62\x8e\x7a\x31\x3a\xd1\x5e\xb6\x2f\xdc\x23\x7a\xd2\xdf\x34\xe4\xa2\x2f\x81\xa8\x60\x6f\x65\x2b\x94\xd7\x28\x8b\x74\x78\x25\x0b\xab\x89\x70\x40\xe2\x10\x28\x9e\x0f\xe8\x98\xea\x9a\x0f\x06\xd6\x8c\xcc\x76\x07\x29\x48\x1c\xf4\x33\xc5\x14\xe2\xf3\x04\xce\x2a\xbb\x82\x13\xd3\x4c\x5d\xb6\x54\xc3\x74\xbb\x88\x1c\x3b\x61\xe1\xb3\x17\x90\x11\x66\x30\xca\x61\x8e\x05\xd5\x38\x16\x12\x78\x2f\xbb\xc0\xb3\xb8\x4b\x5e\x5c\xf2\xe4\x9a\x2e\x71\x29\x99\xe8\x5d\xca\x3e\x35\xe1\x09\x6c\x6d\x90\x5c\x40\x9a\x08\x8e\xce\xaf\xd1\xb1\xe7\x3d\x4b\x08\x6a\x24\xa3\x87\x58\x85\x63\xce\xac\xbf\xab\x62\xca\xca\x7b\x36\xe7\x75\xdb\x04\x10\x03\x95\x02\xe6\xca\x8e\x79\xd1\xbe\x68\xe0\xc5\x9e\x45\xe1\x41\xb6\x02\x76\xa3\x67\x33\x1b\x8d\x1c\x6e\xf1\x19\x52\xa8\x01\x09\x71\x04\x54\x60\xa6\x22\xa8\xb6\x19\xaa\x10\x52\x4b\xf7\x18\xba\x47\x6e\x8d\xa3\x17\x43\x97\x72\x64\xda\x46\xa9\x31\xe7\xed\xd9\xed\x5c\x71\xd0\xab\x38\x90\x88\x37\x54\x1c\x97\xe6\x35\xae\x7e\xb1\xf6\xb6\x7d\x2a\xd4\xa9\xfe\x7d\x49\x5e\xbb\xa0\x0a\x12\x63\x8a\x4b\xaa\xa0\xd5\xc8\x71\x81\xe3\xe2\x66\x1e\x7c\xd4\x50\xa5\xc1\x41\x13\x59\x1f\x2a\xde\xda\xc4\xf4\xaa\x79\xa6\xc5\xa5\xc4\xca\x53\x2b\xb6\x94\x1e\x2d\xc9\x61\x7d\x2f\xec\x6b\xab\x82\x29\xc7\x72\x8e\xa7\x36\x47\xbb\x2b\x28\xc3\xc1\xd1\x50\xb9\x18\x67\x43\x11\xca\x05\xe0\xe2\x90\xb2\x2e\x1a\x84\x70\x5e\x4f\x84\x67\x23\x1a\x92\x3e\x64\xe3\xd5\xa0\x7e\x21\x9b\x20\x5d\x13\xa8\x69\xfd\x12\x16\xdb\x66\x36\xc3\xf1\x15\xcc\x76\x4d\xba\xa1\x19\xea\x39\xbb\x85\x14\x1e\x42\x40\x3a\xc9\xa3\x5b\x84\xec\xd5\x22\x8f\x39\x4f\x39\x6f\xd7\x62\x05\xf9\x1b\x21\x90\xc7\xdc\x81\xc0\xa4\x45\xc9\x16\x08\x48\x28\x35\x25\xcc\x4b\x24\x8c\x4d\x6a\xdc\xf5\xd1\xdf\xc1\x81\x45\xdf\xd9\x33\xa0\xea\x5e\x0f\x22\xd6\xf7\x70\x8f\x19\xd0\xdf\x12\xae\xd7\x22\x1e\xbc\x32\x7d\x5d\xa2\x2a\x51\x93\xa8\x08\xeb\x51\x09\x31\xa8\x91\x56\x00\xd1\x3d\x18\x5f\xae\x72\xc7\x63\x4d\x9c\xe0\xc1\x50\x17\x14\xc7\x3d\x67\x0f\x06\x87\x22\xc9\x05\x04\xd5\x6d\x14\x04\x04\x7f\x0a\x3f\x2e\xc3\x63\x3a\x6d\x99\x28\x51\x49\x0e\x85\xb9\x56\xe6\x30\x6c\x50\x0a\xb4\x74\xdb\xb8\x1f\x4a\xf5\x46\xff\xb1\x60\x5f\x4e\x3d\xfa\xdb\x8f\x81\x4a\x7a\xf4\xa1\x50\x74\x74\x99\x80\x47\x5b\x36\x0c\xea\x44\xc3\xde\xea\xd2\x73\xf2\xee\xaa\x76\x67\x1a\xa4\xee\xcf\xb3\xe0\xf3\x2d\xf6\x9b\x9b\xfd\x8a\xd9\x3f\x6f\xca\xfe\x14\x64\xbb\x9b\xb5\x3d\xbd\x44\x87\xe4\x1c\xc3\x39\x7a\x73\xdc\xe6\x08\xf6\xa2\x66\x2d\x44\xd8\x5a\x53\x1c\x8b\x8b\xdc\xef\x4c\x37\x34\xc5\x55\xb8\x4a\xf7\xed\x69\xf3\x72\x93\xad\x95\x64\x13\x4d\x43\x1c\xb1\xf1\x35\x78\xa5\x6b\x76\x13\x0c\x86\x37\xd9\x60\xba\x1e\xb2\x83\xb3\xb1\x9c\x58\x9d\x0d\x53\xce\xaa\x06\x32\x8b\x42\xcd\x4f\xd3\xfb\x87\xd0\xc9\xf7\x94\x57\x2c\x93\x29\x22\x80\x84\xe3\xb0\xf5\xf9\x7c\xcf\xac\xef\x38\xb6\x37\xe6\xed\xd6\x58\x0e\x75\x6b\xcd\x4e\xb7\xae\x78\x8b\xa9\xe1\x39\x46\xf5\x21\xe6\x22\xcc\x05\xd8\x05\x86\x92\xa4\x22\xa0\xf0\x45\xc9\x91\xa5\xf9\x2c\x9f\xe5\xb1\x07\x25\xde\x7e\x71\x33\x77\x5b\x4d\x9e\x2e\xf2\x78\x31\x46\x9d\x37\xbf\x41\x4d\x62\x43\xc7\xb5\xa5\x25\x77\xf3\x6b\x98\x44\x27\x71\xed\x7a\x55\xc5\xdd\xe8\x0c\x0f\xc2\xe4\x20\x8c\xc3\x71\xbe\x89\xc2\xf8\x06\x89\xf7\x84\xe3\x89\xdd\x3d\xd6\xa9\x02\xd5\x99\xf6\x7c\xc7\x1e\xef\xd8\xd3\x9d\xc4\xf4\x85\xbe\x0c\xae\x9c\x8f\xde\xf8\xe8\x8d\xe7\xa3\x37\x3e\x7a\xe3\xa3\x37\x3e\x7a\xe3\xa3\x37\x3e\x7a\xe3\xa3\x37\x3e\x7a\xe3\xa3\x37\x3e\x7a\xe3\x2e\xe8\xfe\x4f\xbd\x31\x3d\x30\x56\xa0\x57\x79\x6c\x51\xff\xa1\x71\x15\xd0\xcb\xcd\x18\xbb\x18\xb7\xf3\x20\xf8\x48\xdb\xd5\x65\x29\xb8\xac\xa7\xb0\xc4\x27\xbf\x5c\x74\x91\x6f\x96\x05\x93\x8e\xdf\xbb\x9e\xc6\x4a\x55\x83\x7f\x8a\x66\xce\x05\xc4\xf9\x9b\x9d\xce\xb9\xde\x8d\x37\x3b\x1d\x74\x55\x8d\xde\x6f\xb9\xfc\x2f\x00\x00\xff\xff\xbc\x12\x7c\xa7\x15\x2c\x00\x00")
+
+func fontsAlligatorFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsAlligatorFlf,
+ "fonts/alligator.flf",
+ )
+}
+
+func fontsAlligatorFlf() (*asset, error) {
+ bytes, err := fontsAlligatorFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/alligator.flf", size: 11285, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsAlligator2Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x5f\x8f\xe3\x34\x10\x7f\xcf\xa7\x18\xc9\x96\x78\x30\xaa\xc4\x72\x62\x75\x16\x42\xad\x00\x1d\xcb\x9f\x17\x58\x09\x78\xec\xd1\x94\x46\x97\x6d\x4f\x6d\xf6\x8e\xe5\xd3\x23\x7b\x3c\xe3\x19\x27\xd9\xa4\x3d\x4e\xba\x87\xb6\x2b\x37\x76\x9c\x99\xf1\xf8\x37\x3f\x8f\x9d\xdd\xb6\xdb\x9b\xb5\x85\x5b\xb8\x85\x9b\xaf\xe0\xcb\x1b\x78\x51\xad\xda\xb6\xf9\x7b\xdd\x1d\x8e\x37\xf0\xfa\x09\xbe\x5b\xef\x9b\xba\x85\xdf\x9b\x7f\x17\xb0\xfa\x69\x05\xbf\xd4\xc7\xb6\xd9\xc3\xab\x63\xfd\xf4\xfe\xd0\x6e\xe1\xeb\x87\xd8\xb0\x7c\x7d\x5c\xef\x1e\x4e\x8b\xc7\x4d\xdd\x2e\xea\xcd\xe3\x37\xd5\xcd\x6d\xb7\x83\x1f\x1f\xdb\xa7\xcf\xe1\x8b\x97\x2f\x5f\x54\xf7\xbb\xe6\x04\xcd\x09\xba\x5d\x0d\xbf\xdd\xff\xba\xba\x7b\xf5\xc3\x3d\xbc\xab\x8f\xa7\xe6\xb0\x87\xc3\x36\xb6\x1f\xeb\x77\xcd\xa9\xde\x00\x9b\x00\xdb\xc3\xbe\x83\x3b\xa8\x37\x4d\x57\x6f\x16\xd5\x5d\xf7\xd9\x09\xbe\xff\x63\xf5\xed\xfd\xcf\x7f\x42\xdb\xbc\xa9\xe1\xe1\x09\x0e\xdd\xae\x3e\xc2\xdb\xc3\xa9\xab\x37\xf8\x40\xfd\xcf\x5f\xf5\xdb\x2e\x8a\xec\x9a\xb6\x83\xf7\xeb\x13\x74\xeb\x37\xf5\x1e\x0e\x8f\xdd\x62\x51\xd9\x65\xff\x6f\x59\x79\xef\xed\xb2\xf2\x2e\x94\xce\xbb\x50\x9a\x5c\x5a\xb0\xb0\xac\x8c\x31\xa9\x2b\x70\x77\xc0\x47\x2c\x84\x4f\xe8\x34\xf3\x6a\x59\x01\x04\x29\x58\x86\x66\x6c\x71\x1e\x4b\x6c\x71\x5e\x7d\x6d\xec\xe3\x8c\x0b\xa5\x77\xa9\x8f\x51\x5f\xec\x63\x9c\xc1\x92\x25\x1b\x63\xb0\x8c\x2d\xb1\x89\x55\xc7\x1e\xac\xc6\xa2\x62\x56\x11\xef\x3a\xe3\x9c\x77\x41\x3e\xa4\x67\x83\x19\xa4\x8f\xd5\xf3\xdd\xa4\x08\x92\xbf\xb2\xaa\x20\x4e\x8d\x92\x0c\xcc\x63\x92\x2d\x66\xba\x25\x8f\x95\x5b\x78\xac\x61\xa0\x1e\x3f\x76\x40\xf7\xb2\x0a\x3a\xfb\x03\x05\x70\x28\x2e\x0d\x32\x8d\x8c\x35\x85\xee\xcb\x2a\x68\x48\x1f\x0b\x02\x43\x71\xa2\x63\x8f\x91\x32\xba\x3b\x76\x86\xec\x6f\x9b\x26\x53\xfd\x02\xfb\x34\x83\x0f\x6f\xa4\x07\xd1\x69\xc9\x70\xf9\x4b\x26\xc7\x79\x08\x1a\x03\x86\x11\x7c\x2c\x00\x31\x40\x82\xa4\x2b\xa2\x05\x38\xe1\xa1\xcc\xc0\x4b\xee\x47\x05\xe4\xfe\xf8\xbc\x96\x9f\xa6\x82\x1a\x69\xb2\x78\xce\x09\x44\x34\xe3\x83\x0a\xc5\x6c\x13\xac\x10\xd1\x5c\xcf\xf2\x29\x48\xc7\x4a\xc4\x47\x9a\xa9\xf4\x50\x11\x96\xe3\xf5\xd2\xb6\x33\x9f\x9f\x6b\x1b\xe2\x95\x23\x53\xfa\x0c\xaf\x09\x26\xd9\x33\x34\xe3\x00\x19\x2e\x78\x4d\x11\x88\x93\xc1\x41\x20\x23\x20\xc5\xb9\x67\xc2\x03\x07\x7c\x6d\x08\x4a\x2a\xbe\x24\xde\x29\xa8\xa3\x48\x97\x70\x29\x6c\x64\x10\x8b\x2b\x34\x30\x5a\x67\x8a\x00\x15\xc6\x29\x56\x75\x29\xa2\xe4\xa0\xad\x42\x06\x8f\x3a\x0b\x9e\x29\x3b\x0d\x37\xc9\x46\x47\xdb\x4c\x34\x34\xf8\x62\xf4\x34\x7c\x4d\xa0\x1a\xdc\x39\x98\x12\x8d\x80\x88\x71\x4d\xd6\x90\xdd\xc2\xfc\x65\x89\x3a\xc9\xfe\xc2\xfc\x38\x71\x3d\x78\x9e\x65\xfe\xa8\x6b\xc6\x65\xe3\xd2\x33\x2d\xdb\x0f\x19\x9e\xa4\x03\xc8\x59\x05\x11\xe6\x3a\xe6\xb1\x46\x53\x9b\x6a\x79\x55\x99\x34\x3f\xf1\x22\xd9\x7f\x8e\xf9\xe7\xca\x16\x94\x30\x29\x1b\x23\x9e\x30\x38\xcc\x04\x16\x66\x77\xcd\x58\x24\xc6\x20\xba\xd0\x4b\x4a\x42\xa1\x8c\x42\x4a\x0b\xec\x0c\x42\x2c\xd3\x90\x01\x82\x54\xa8\x9e\x24\xc4\x22\xef\x81\xcc\x1f\x43\xd8\x90\xc8\x90\xb8\xa0\x85\xb1\xc4\x84\x9c\xb8\x99\xb0\x13\x24\x2a\xd6\x95\x3e\xec\x00\x24\xb8\x81\x97\x52\xe1\x20\x4a\xa0\x10\x2c\x44\x04\x89\x60\xb1\xcd\xa8\x36\xe3\x74\x3e\x15\xe0\x23\xdc\x99\x33\x38\xa6\xf4\x9c\xc3\x15\x29\x5c\x76\x24\x6b\x2f\x16\x30\xcb\x71\xa0\xc1\x0a\xbc\x0a\x31\x07\xc9\x48\x7e\x3e\x14\x66\xb2\x84\xb9\x90\x81\x46\x2a\x73\x18\x68\xd2\xee\x7e\x65\xca\xee\x92\xdc\x68\x4e\x28\x8d\xa3\x0a\x33\x4f\x8e\x42\xbc\x93\xd7\xab\xde\x82\x35\x53\xb6\x37\xde\x3b\xef\x67\xc8\xb6\x02\x2e\xf3\xfc\xed\x8d\x2f\xfd\xed\x92\x1b\x9e\xf5\x37\x30\x09\xcd\xc0\xc9\xa4\xbf\x87\x30\xc8\x39\x11\x39\x46\x66\x45\xc3\x81\xac\x6b\x79\x35\x31\x63\x6e\xff\x10\x15\x29\x6e\x39\x19\xcb\x01\x3b\xec\xa1\xfe\x66\x8b\x3d\xc4\x49\x78\x66\x29\xb1\xa7\x1b\xf0\x90\xc0\xc6\x73\x88\x1c\xa9\x4c\x20\x32\x19\xee\xf3\x52\x00\xbc\x14\x24\x7e\x53\x2c\x87\xe4\xc3\x3b\xe8\x24\x59\xd3\x4d\x49\x38\x6a\xba\x95\xa7\x44\xbe\x8a\x5a\xa1\x20\x54\xa1\x28\x6d\xd6\xe4\x5e\x4d\x03\x6a\x22\x2d\xbc\x84\x1d\x2e\x65\x1e\xc5\x98\xe7\x46\xb0\x16\x0e\x4a\x3a\x28\xd3\xa9\x66\x68\xfd\x44\xe3\x43\x9b\xcd\xbb\xd8\x0b\x09\xdf\x4f\x12\x3e\xf4\xb7\xe2\x73\x53\xce\x73\xf2\xaa\x8f\x41\x12\x30\x74\x90\x31\x87\xe3\x2e\x42\x0d\xf4\x84\x17\xce\x51\x12\x45\x0e\x2a\x33\x23\x3e\x87\x19\x35\xbf\xa7\xa4\x37\x07\xcf\x04\x72\x94\x2e\xd2\x14\x4a\x54\xf8\x8c\xa2\xd8\xbd\x8c\xf8\x0b\x32\xe5\xe5\xc3\x25\xb9\x55\x92\x40\x1d\x5b\x13\x06\xc8\x54\x9e\xe7\xb0\xe0\x81\x1d\x73\x79\x32\x66\x41\x6f\xb7\x3e\x7c\xeb\x5d\x2e\x2d\x79\x35\x67\x4e\x16\xa9\x39\x5f\xb0\x5d\xea\xf9\x7c\x86\x52\x6e\x31\x33\x50\xd5\xae\x49\xed\xa7\xe4\xb1\x1c\x94\x46\xc9\xfc\x58\x9e\x30\x16\x17\x32\x0d\xb2\x13\x99\xa7\x86\x6b\x4e\x58\xf5\x3e\x60\xa2\x26\xaa\xea\xde\xa5\x95\xde\x9a\x86\x87\x6f\xa1\xb4\x78\x7c\x35\x58\x5e\x73\xec\x6b\x8e\x7d\xcd\xb1\xaf\x39\xf6\x35\xc7\xbe\xe6\xd8\xd7\x1c\xfb\x9a\x63\x5f\x73\xec\x4f\x32\xc7\x26\xea\xe4\xf3\x6f\xf5\x26\x4a\x42\xaf\xff\x26\x4a\x50\x56\xff\x9f\x00\x2c\x05\x8b\x2d\xde\xd2\x79\x71\x7a\x3d\xf4\xee\x4b\xbf\x8f\x85\xde\xbb\x2f\x0b\xf9\x3d\xf0\x90\x9b\x93\x48\x99\x13\xff\x0f\xf5\x65\xa5\xbe\x1f\xb3\xfa\x5f\x00\x00\x00\xff\xff\x2d\x9b\xb0\x75\x5d\x22\x00\x00")
+
+func fontsAlligator2FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsAlligator2Flf,
+ "fonts/alligator2.flf",
+ )
+}
+
+func fontsAlligator2Flf() (*asset, error) {
+ bytes, err := fontsAlligator2FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/alligator2.flf", size: 8797, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsAlphabetFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x57\x69\x5b\xda\x5a\x17\xfd\x7e\x7e\xc5\xaa\x55\xd4\x2a\x15\x50\xac\x76\xf2\x60\x9d\xaa\x75\xc2\x3a\x4f\x0d\x90\x40\x24\x24\x48\x42\x95\x7a\xbd\xbf\xfd\x7d\xf6\x3e\x09\x19\xe1\xf6\x4d\x1e\xf7\xda\x6b\xad\xb3\xcf\x94\x09\x0d\xcb\x28\xe1\x03\xca\x28\x16\x90\x2f\xa2\x58\x12\x15\xab\xdb\xd2\x6a\xba\x87\xda\x00\xe7\xba\xdd\xd0\x2d\x0b\x3b\x66\xbd\xad\xdb\x28\x16\x17\x56\x17\x31\xf3\xd4\x62\x2a\xbb\x5a\x4f\x73\x1d\xc3\x7b\x5f\x77\x3a\xb3\x42\x6c\x3e\x77\x2d\xcd\xd6\x3c\xd3\xb1\xe1\x18\x30\xcc\x9e\xeb\xc1\x32\x6d\xfd\xa3\xe0\x51\xf2\x98\xe8\x68\x4d\xb3\x0e\xbb\xdf\xa9\xe9\xbd\x09\x18\x4e\x0f\x86\x69\xe9\x30\x1b\xba\xed\x99\x86\x59\xe7\x62\xa1\x01\x40\x1e\x6e\xcb\xe9\x5b\x0d\x68\xd6\x93\x36\x70\x51\xd3\xf1\x4b\x9b\x9e\xe7\x22\xdb\x79\x12\x93\xaa\x91\xd7\xd2\x31\xd1\xd2\x7a\x8d\x9a\xa5\xd9\xed\x09\xe4\xf3\xe8\xf6\x4c\xdb\x73\xa1\xb9\xd0\xc0\xea\x3c\x6a\x7d\x0f\x75\xcd\x9e\xf6\xa8\x1b\xb7\xd3\x77\x5b\x7a\x43\x2c\xab\x1e\x5a\xba\xd9\x6c\x79\x34\x63\x0d\xf5\x96\xd6\xd3\xea\x9e\xde\x13\xe5\x31\xe6\x3c\x6c\xc7\x83\x69\xd7\xad\x7e\xc3\xb4\x9b\x68\xe8\x6e\x9d\x36\xaa\xe7\x8a\x52\x81\xcb\x3a\xda\x33\xaf\x1c\x96\x6e\x37\xbd\x16\x66\xf4\xe7\xa0\x71\xdd\xe9\x74\x74\x5b\x6d\x8c\x3b\x8b\x39\x68\x30\xfa\x8d\xa6\x0e\x43\xab\x7b\x4e\x4f\x14\xcb\xdc\x43\x43\x37\xb4\xbe\xe5\xa9\xc9\x76\x9c\x86\xce\x0b\xf7\x5a\xa6\x0b\xc3\xb1\x3d\xcc\x58\x66\x5b\xc7\x44\xbe\x83\x62\x79\x02\x8e\xcd\xfd\x6a\x76\x83\xfb\x9d\x15\xc5\x12\xf7\xa2\x76\x9a\xa6\x1f\x1b\x56\x48\xff\x10\x6f\xde\xbc\x41\x3c\xd2\xba\xe3\x39\x47\x29\xa6\xa7\x31\x3d\x8d\x10\x81\xd0\x1e\x83\x52\xe0\x2d\xde\x92\xf0\x96\x0e\x8c\xe6\xe9\x42\x4c\x62\x52\x49\x93\x74\x50\x36\x99\xa1\xa9\x76\x93\x19\x1a\x77\x33\x05\x60\x6a\x4a\x75\x3c\x35\xa5\x4c\x42\x4a\x18\x21\x05\xe3\xd4\x70\xf0\x48\x22\x05\x72\x39\x56\x72\x40\x8e\x9d\x5c\x2e\x87\x1c\x71\x3a\x15\xcf\x65\xcd\x3f\xd8\x2e\x96\x32\x83\x14\x98\x99\x81\x14\x33\x33\x48\x44\xa5\xc7\x2e\xc0\xec\x2c\x93\xd9\xd9\x44\xf4\xf5\x68\xd3\x60\x2a\xef\x40\xa7\x14\x78\xf7\xee\x1d\x73\x3a\xa2\x3c\xf0\x11\x29\x94\x02\x73\x14\xe7\xe6\xe6\x86\x79\xa4\xf7\xc8\x18\xa9\x30\x3f\x4f\xd9\x7c\xb8\xba\x48\x59\x3e\x9f\xcf\xea\x68\x44\x77\xef\xdf\x07\x21\xba\x59\x00\x16\x16\x18\x17\x16\x58\x5d\x58\x60\x97\x00\x52\x30\x64\xde\x49\x85\x42\x81\x84\x02\x50\x28\x30\xd2\x29\x05\xa9\x84\x81\x9f\x2e\x2c\x16\x89\x17\x15\x20\x06\xc5\xa2\x55\x0c\xda\x06\x20\x05\x4a\x25\xa2\x25\xa0\xc4\x2a\x33\x8a\x24\x96\x4a\xa5\x74\xc5\xe2\xe2\xa2\x4f\x17\x09\x62\x2c\xf4\xa2\x15\x4b\xc0\x12\x42\x58\x5a\x5a\x52\x66\x1c\xa2\x15\xe5\x72\xb9\x0c\xa9\xde\x6a\xcc\x7c\xb3\x1c\x63\xb1\x75\x60\x59\xf1\x65\xa5\x2f\x2f\x2f\x2f\x33\x82\x1c\xd2\x15\x4f\x6d\xd9\x07\x3a\x94\xf0\x41\x19\x1f\x90\x8d\xc9\xbd\x5e\x59\x59\x21\x61\x05\xc0\x0a\x46\xf3\x74\xe1\xea\xea\xea\x2a\xa4\x58\x05\x40\x18\x70\xa6\x8c\xab\x23\x46\x24\xf6\xf1\x23\x52\x59\xfc\x9e\x93\xe2\xd3\x27\xc4\xb2\x4f\xc9\x36\x9f\x3f\x13\xf9\xfc\x99\x34\x8a\x21\x0b\xbc\xe4\xee\x12\xfb\xf2\xe5\x0b\xb2\xf2\xd8\x83\xf1\xf5\xab\x62\x84\x24\x7e\xfd\x1a\xb2\xc0\x4b\x74\xbe\xb6\xb6\x46\x7c\x0d\xc0\x9a\xd2\xd7\x94\xbf\x86\x38\x26\xf7\x43\x4a\x49\x82\x24\xaa\x50\xfa\xa8\x1a\xfa\x7e\xba\xb0\x52\x21\x5e\x01\x2a\x04\x95\x4a\x25\xc2\x14\x24\xe6\xb8\xbe\xbe\xbe\x4e\x7c\x1d\xc0\x3a\x46\xf3\xf4\x50\xdf\xbe\x7d\x83\x14\xdf\x94\x1c\x07\xdf\x4b\x0c\xb5\xb1\xb1\x41\x74\x03\xd8\x48\x83\xf2\x12\x15\x9b\x9b\x9b\x9b\x90\x62\x53\xa9\x44\x62\x6c\x33\x5d\xb1\xb5\xb5\xb5\x05\x29\xb6\x94\x4a\x24\xc2\x90\x79\x91\xb6\xb7\xb7\x89\x6f\xfb\xfa\x36\xb0\xbd\xed\x73\xc2\xc0\x4f\x6d\xc0\x0e\xb0\x83\x10\x76\x76\xa2\x4c\x41\x62\xa8\xef\xdf\xbf\x13\xfb\x8e\x44\xf4\xf5\xe4\x87\x63\x17\x69\xdc\x0d\xf8\xee\xee\x6e\xe6\xac\xf6\x80\x3d\x10\xec\x91\xbc\xb7\xc7\x6e\xc0\x94\x97\x98\xd5\x0f\x45\xb3\xe1\xc7\x8f\x1f\xe9\x8a\x7d\x00\xfb\x90\x62\x7f\x1f\xfb\x8c\xd8\x57\x3c\xd0\x7d\x4c\x4d\xee\x00\xc0\x01\xa4\x38\x38\xf0\x11\x07\x3e\xe2\xc0\x47\xe6\xe9\x9b\xed\xf0\xf0\x90\x84\x43\x00\x87\x19\x18\xf8\xa9\xc2\xa3\xa3\xa3\x23\x12\x8e\x00\x1c\x21\xce\xa3\x98\x1e\xf1\xf8\xf8\x98\x15\x8a\xc7\xc9\xe4\x98\x13\x6a\x73\x3c\xac\x3a\x1e\x96\x53\x7d\xb5\x5a\xad\x92\x55\x05\x50\x45\x94\x57\xe1\xeb\xd5\x6a\xe6\xc0\x27\x27\x27\x24\x9c\x04\x86\xcf\x89\x9d\x90\x1e\xe1\xb1\xc2\x9f\x7c\xb0\xf2\xf3\xa7\x6f\x8d\x49\x62\xe5\x54\x7f\x0a\xe0\x14\xa3\x11\xa7\xa7\xa7\x99\x03\x9f\x71\x72\x86\x68\x86\x33\x4e\xb8\xd9\x19\x13\x2e\x38\x8b\x0d\x1a\xcd\xa4\x38\xe7\xe4\x1c\x89\xec\x5c\x65\x38\xe7\x93\x4b\x38\x19\xd5\xcd\x05\x80\x0b\x92\x2e\x70\xa1\xac\x0b\xd5\xc4\xe7\x43\x3f\xb9\x8c\x4b\x00\x97\x24\x5c\xe2\x52\x19\x97\xc8\xc6\x44\xe1\x15\x1d\x4a\xb8\x52\xc6\x95\x6a\x70\xa5\x1a\x46\xfc\x78\xe1\xf5\xf5\xf5\x35\x08\x58\x4e\x02\x7b\x89\x27\xef\xe6\xc6\xe7\x9c\x90\x4e\x09\xfb\x37\x37\x7e\xbb\x9b\x9b\x8c\xa1\x6e\x6f\x6f\x6f\x99\x67\xc0\xd0\x8b\xbf\x17\xef\xee\x88\xde\x01\x77\x49\x33\x13\x32\xbe\x99\x7e\xbc\xbf\xbf\xbf\x0f\xa2\xdf\xf4\xd7\x2f\x24\xbf\xf0\x59\x1f\xfc\xb0\x23\x4d\x83\x14\x1a\x38\x72\x8e\xe8\xdb\xb2\xa6\x58\x00\xb5\x9a\xcf\x6a\x21\xcb\x98\x6b\x44\xad\xd7\xeb\x90\xa2\x1e\x63\xe9\x8a\x06\x42\x68\x34\x08\x1a\x31\x36\x66\x3f\x74\x5d\xa7\x08\x8e\x3a\x52\xaf\x7b\xc3\x20\x62\x90\x64\x44\x72\x3f\x26\xbf\x0c\x41\x6c\x36\x9b\x14\xd1\x1c\xe6\x08\x73\x29\x5a\xaa\x55\x00\xad\x96\xcf\x5a\x21\xa4\xa7\x2c\x85\x69\x22\x9a\x85\x34\xb9\x75\x0f\xc8\x60\x04\x0f\x3e\x7b\x78\xe0\x8a\xb6\x6a\xd3\x46\x9b\xa1\x1d\x63\x40\x3b\x3d\x0f\x0b\xe9\x3f\xe5\xcb\xd4\xcd\x2d\x3a\x9d\x4e\x87\x11\x74\x86\x98\x7a\x08\xe2\x17\xdd\xb6\x6d\x06\xc0\x0e\x61\xcc\x25\x74\x1c\x87\x22\x9c\x61\x9e\xba\x2e\x61\x07\xdd\x6e\x97\x01\xe8\xc6\x58\x08\xe9\x75\xe0\xf1\xf1\x91\xf0\x11\x78\x8c\x72\x04\x1c\x78\x7c\x4c\xce\xaa\xd7\xeb\x51\x54\x79\xf2\xd1\x4b\x3c\x44\xae\xcb\x91\x72\xd7\x4d\x37\xf5\x98\x70\xf4\x3c\x0f\xa1\xe2\x8d\x5f\x6b\x1f\xe8\x87\x80\x7e\xbf\x3f\x7e\x23\x7f\xe3\xf7\x30\xe2\x77\xe6\x94\xa3\xdb\xf2\x04\xe0\x89\xf1\x89\x91\x61\xd4\xe5\x0d\xe2\x33\x9e\x29\x7f\x8e\xe4\xa3\x17\x30\x00\x06\x21\x60\x30\x18\x28\x8f\xc5\xc1\x20\xd5\xf9\x9f\x3f\x9c\xfb\xf1\x4f\xba\xf3\x97\x17\x62\x2f\x2f\x24\x52\x0c\x59\xe0\xc5\x77\xe7\x9f\x7f\xb2\xff\xd8\x7c\x7d\x55\x6d\x09\x49\x7a\x7d\x0d\x59\xe0\x65\xbf\xdc\xfe\xc5\xbf\x90\x82\xe2\x7f\xbd\xba\x1d\xf0\x6d\x3d\xee\xdf\x87\x74\x85\x2a\x19\xf1\xcb\x6c\xe4\x2f\xb2\xa0\xf0\xff\xfe\x99\xa1\x9e\x3c\xfc\xcd\xf7\x20\xda\xf4\x3f\x1e\xdb\x60\xe5\x7f\x7f\x2b\xff\xed\x7f\x4c\xeb\xc9\x05\xfc\x2f\x00\x00\xff\xff\x82\x19\xcc\xe4\xe3\x15\x00\x00")
+
+func fontsAlphabetFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsAlphabetFlf,
+ "fonts/alphabet.flf",
+ )
+}
+
+func fontsAlphabetFlf() (*asset, error) {
+ bytes, err := fontsAlphabetFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/alphabet.flf", size: 5603, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsAvatarFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x58\xcd\x6e\xdb\x46\x10\xbe\xef\x53\x7c\x30\x04\x38\x41\x6d\x8f\x65\xd4\x06\xdc\x13\x83\xa2\xbd\x15\xe8\x03\x0c\xb0\x5d\x89\x4b\x89\x28\x45\x1a\x24\x95\xd8\xc0\x3e\x7c\xb1\x33\xa4\x44\x51\xa4\x63\xb7\x87\xe6\xe0\x83\xb2\x12\x39\x7f\xdf\x37\x3f\x3b\x71\x56\x64\x77\x6e\x81\x07\xdc\x63\x79\x8b\xe5\x03\x96\x0f\xe6\xcb\x57\xd7\xba\x1a\xab\x17\xfc\x5a\xb8\x7d\xea\xf1\x87\xab\xdb\xbc\x6c\x70\x7b\x47\x8f\xf7\xc6\xfc\x9e\x6f\x0a\xdf\xa2\xf6\x85\x77\x8d\xc7\xdd\xcd\x12\xd7\xd7\x58\xde\xe1\xcb\x7e\x83\xe5\xe3\xe3\xcf\xe6\x4f\x5f\xef\xf2\xa6\xc9\xab\x12\x79\x83\xad\xaf\xfd\xea\x05\x9b\xfc\xab\x2f\xd1\x56\xd8\x55\x69\x9e\xbd\xa0\xdd\xe6\x0d\xb2\xaa\x6c\xaf\xe0\x1a\x14\x55\xb9\x89\x67\xbb\xf5\x46\x04\x72\x5f\x5f\x36\x28\xdd\xce\x47\x1b\x4f\x85\x5b\xfb\x14\x55\x09\x87\x75\xb5\xdb\xf9\xb2\x45\x91\x97\xfe\xc6\x98\xdf\x9e\x9f\x0a\x57\xba\x36\x7a\xab\x32\x64\x79\xdd\xe8\xbb\x5f\x4c\x44\x87\x6b\x5c\xec\xdc\x26\x5f\xa3\xdc\xef\x56\xbe\xbe\x40\x56\xd5\xc8\xf2\xc2\x23\x4f\x7d\xd9\xe6\x59\xbe\x16\x65\xe3\x00\xe0\x1a\xcd\xb6\xda\x17\x29\x5c\xf1\xcd\xbd\x34\x58\x79\xfc\xe5\x2e\xaf\x44\xa9\xac\xbe\x99\x85\x0a\xb5\x5b\x8f\x8b\xad\xab\xd3\x55\xe1\xca\xbf\x2f\x22\x01\x4f\x75\x5e\xb6\x4d\xc4\xe0\x20\x4f\xaf\xb0\xda\xb7\x58\xbb\xf2\xb2\x8d\x66\x9a\xdd\xbe\xd9\xfa\xd4\x3c\xa8\x85\xad\xcf\x37\xdb\x36\x46\xec\xb0\xde\xba\xda\xad\x5b\x5f\x9b\xfb\x57\x5e\x5e\xa1\xac\x5a\xe4\xe5\xba\xd8\xa7\x79\xb9\x41\xea\x9b\xb5\x2f\x53\x5f\x37\x66\x79\xab\x7a\x3b\xf7\x2c\xd0\x51\xf8\x72\xd3\x6e\xf1\xc9\x3f\xf7\xd2\x43\xd6\x9a\xcf\xf8\x09\x0e\xd9\x3e\xdd\x78\x64\x6e\xdd\x56\xb5\x59\x3e\x88\x85\xd4\x67\x6e\x5f\xb4\x1a\xed\xae\x4a\xbd\x20\x3f\xe4\xaa\x17\x53\x2e\x63\x80\x27\x76\x8d\x59\x2c\x92\xa9\x4f\x62\x60\x91\x18\x02\x27\x26\x20\x24\x86\x2d\x25\xe6\x93\xfd\x9c\x18\x00\x49\x62\x2c\x60\x13\xc3\x21\x90\x3c\xc1\xc4\xbf\x7a\xc8\x6f\x4b\xc1\x06\x8e\x0a\x80\x05\x28\x5a\x8e\x5f\x38\x31\xe0\x80\x40\x38\x0a\x27\x06\x14\xc4\xb7\xe5\xa8\xc0\x51\x9f\x21\xdf\xa3\xa6\x48\x4b\x00\xd1\x32\x07\x8a\x02\x20\x90\xe8\x50\x0c\x9b\x09\x1c\x3a\x8b\x0a\x25\x8a\xd2\x0d\x8b\x06\x6c\x8c\x84\x02\x45\x6b\x6c\x2d\xf1\x50\x34\x31\x0a\xe9\xe4\x13\x5f\x58\x2b\x31\x51\x14\x88\x8f\x03\x8b\x2b\x6b\xf9\x80\xd7\x5a\x7d\x24\xb8\x34\x04\x4b\x21\x31\x64\x2d\x8d\x48\x11\x4e\x7a\x4a\x7a\x46\x7a\x42\x06\x7c\xa8\x82\x02\x80\x0d\x08\xd1\x43\x88\xbf\xad\x20\x0c\x36\x60\x40\xde\x90\x45\x8c\x3e\x0a\xed\x18\xc0\x21\x10\xdb\xc7\x6d\x0f\x60\x70\x1a\xc0\xf1\x13\x59\x60\xea\x49\xe9\xe4\x84\x41\x52\x10\xa4\xfc\x0f\x8a\xa0\x33\x2f\x19\x97\x72\xd2\xec\x04\xb0\x90\x23\x6e\x69\xe8\xee\xb4\xf2\x8e\xe5\x37\xb2\x67\x3b\xbe\xe8\xc8\x1f\xd9\x09\x7b\x03\x7c\xaa\x10\x35\x24\x37\x2c\x27\x9d\x05\x20\x8c\x27\x86\x18\xa4\xce\x59\x82\x00\xd0\x9f\x6c\xc3\x49\xc4\x3d\x44\x65\x30\x74\xa9\x8c\xa1\x60\x12\x62\xe7\x01\xd6\x0a\x50\x8a\xa1\x45\xac\xac\xa1\x4d\x70\x72\xf0\xa0\x96\x09\xe7\x21\xcd\x28\xd8\xbe\x8f\x48\x13\x64\x99\x5f\xf3\xd0\xb1\x34\x08\x05\xd3\x1e\x06\xd5\x30\xaa\x8a\x51\xa9\x1c\x0b\x4f\x9a\x08\xda\x45\xb1\x54\xa4\x1d\xa5\x8f\x70\x6c\xa4\x93\x26\x19\xd5\xe6\x4c\xad\x6a\xeb\x75\xbd\x27\xee\x65\x60\xc0\x6a\x51\x46\x96\x87\x3d\x7e\xc6\x25\x77\x08\x45\x3c\x22\xed\xe4\x99\xc6\x15\xac\xe9\x25\x1b\xb9\x0c\x60\x9e\xac\xb8\xf9\x92\x0f\xd7\x41\xab\xf9\x38\xa0\xa6\x3d\x04\xa8\x87\xf0\x9d\x6c\xc5\x42\xd2\x8a\xd3\xa1\x14\xb3\xf4\xb6\x90\x42\x1f\xd2\x5c\x17\xda\x6e\xe4\x41\x5e\x44\xcb\x9d\x07\x9a\xcc\xc0\x40\x41\xfa\x31\x0c\xb0\x68\x6a\x68\x34\x56\xce\x3c\x04\xb9\x54\x24\x24\x9a\xf4\xa0\x45\x11\xf3\x45\x5d\xec\x41\x4f\xcc\xd0\xfa\xfa\x24\xe9\xbb\x10\xda\xe7\x7d\x33\x11\xdb\x30\xd3\x85\x31\xd4\x68\x52\x2f\x8f\x20\x9a\x7a\xb2\x40\x0c\x3c\x1b\xb1\x92\x17\xfa\x53\xae\x9d\x49\x0f\xbd\x86\xb5\x1d\x48\xa6\x1e\xe5\x01\xe6\x00\xe7\x58\x0d\x3d\x37\x8c\x5e\x8d\x67\xd5\xde\x3d\x9a\xc7\x75\x0a\x56\x6f\x9a\xc2\xe9\x1c\xcf\x78\xe0\x30\x57\x45\xd3\x1e\xa0\xf7\x35\x8d\x29\x7e\xef\xec\xb5\x83\x49\xd7\x39\x27\xad\x6d\xc9\xbf\x7e\x11\x24\xe7\x14\x77\xc5\xc7\xc7\xa2\x7b\xed\x1a\x3b\x28\x84\x93\x9e\x66\x22\x6d\x20\x1a\x71\x35\x91\x44\xf4\x49\xa4\xb9\x24\xca\xe4\xd3\x3d\x82\xa3\x7d\x51\xd6\x95\x48\x8a\x32\x4e\x3f\x3e\x1b\x95\xd3\x0a\x12\x10\xcd\x26\xf1\xad\x37\xee\xc9\xb2\x24\x84\x86\x70\xb6\x2c\x75\x58\xbb\x9d\x4c\xa6\x36\x77\x8b\x13\xcd\x6c\x54\x41\x6e\xed\x30\xde\xa8\x62\x3a\xa6\x77\xd8\x8e\xd0\xb9\x73\x74\x9b\xc4\xa5\x32\x6e\x94\x33\xeb\xdf\xbf\x9e\xe8\xf8\xcf\x13\x1d\x1f\x13\xfd\x63\xa2\x7f\x4c\xf4\x8f\x89\xfe\x7f\x4d\x74\xed\x6b\xd6\xc5\x5d\xf7\x76\xee\x18\x1f\x4c\x74\x8b\x93\x96\x3c\xf6\xaa\x0d\x47\x1b\x56\x77\x6c\xd6\xfd\x9c\x46\x36\x48\x00\x2c\x98\x16\xc9\x2b\x7f\x57\x60\x62\x7a\xd7\x34\x9e\x55\x98\x4b\xf5\x41\xe1\xad\xb5\xf1\x03\x86\xf4\xdd\x2b\x88\x4e\xff\x47\xf7\x4f\x00\x00\x00\xff\xff\xc5\xb1\xe1\x30\x5d\x14\x00\x00")
+
+func fontsAvatarFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsAvatarFlf,
+ "fonts/avatar.flf",
+ )
+}
+
+func fontsAvatarFlf() (*asset, error) {
+ bytes, err := fontsAvatarFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/avatar.flf", size: 5213, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBannerFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x5d\x6d\x73\xe2\x38\xb6\xfe\xce\xaf\x78\x6a\x95\x0f\x3d\x55\x28\x03\x04\xd2\xc9\xd6\xd4\x14\x06\x4c\xc2\x86\x40\x86\x97\xce\x66\xea\x7e\xb8\x4e\xe2\x04\x6f\x88\x9d\xc1\xa6\xbb\x33\x75\xeb\xfe\xf6\x2d\x8c\x5f\x24\x59\x92\x65\xd2\xdd\x5b\x3b\x1c\x40\x3e\xcf\xd1\x79\x3f\xb2\x93\x3c\xad\x9f\x5a\xce\x11\xce\xf0\x19\x9d\x36\x1a\x68\xb6\xd0\xc0\x69\xbb\x76\xef\xf8\xbe\xbb\x39\x7e\x5a\x3f\xe1\xab\xbb\x09\xbd\xc0\x47\x0b\xf7\xef\x98\xbd\x3b\x3e\xee\x82\xed\xc3\x0b\x3e\xbd\xef\x5e\xba\x0f\xe1\xf1\x76\xe3\x3e\x7b\xbe\x73\xfc\xe0\xfc\x52\xfb\x34\xdc\x04\xaf\x70\xb0\xf5\xbd\xef\x78\xdb\x04\xcf\x1b\xe7\x15\x0f\xce\x7a\xed\x3e\x62\xcf\xf4\x97\xda\x08\xce\x2b\xfc\x20\xc2\xc6\x0d\xdf\x02\x3f\xf4\xee\xd7\x2e\x9e\x82\x0d\xb6\xa1\x8b\xe0\x09\xd1\xca\x0b\xf1\x14\xf8\x11\x50\x5b\xac\x1c\xff\x25\x44\x14\xe0\x62\xed\xfa\x3e\xfa\x2b\xe7\xed\xcd\x5d\xaf\xe3\xf5\xbb\x75\x2b\x77\xfd\x56\xbb\x72\x22\xe7\xc5\xf1\x1d\x3c\xac\x9c\x8d\xf3\x10\xb9\x9b\x70\x27\xed\x17\xcf\xf7\xdd\x77\x2c\x56\x8e\x87\xdf\xc2\xf0\xc9\xf3\xa2\xae\xbb\xf1\xc2\xe3\x9d\xd0\xaf\xf7\xc7\xee\xe3\xf6\xf7\x5a\xff\x7d\xe3\xad\xd7\xde\x03\x7b\xed\xd3\x6e\x13\xff\x78\x09\xbc\xb3\xef\x67\xff\x40\x6f\x30\x8c\xc5\x39\xae\x0d\x9c\xc8\xfd\x27\xac\xed\xf3\x36\x8c\xd0\x6c\xd6\xd1\x3c\x3f\x6f\xd7\x6a\xd7\xee\xe6\x79\xb7\xbf\x77\xfc\x2b\x58\xf9\xe8\x07\xdf\x1c\x1f\xbf\x3d\xec\x5e\xba\x0f\x0f\xde\xfa\x38\xd8\x3c\xff\x5e\xbb\x0e\x1e\xbd\x27\x6f\xbf\xee\xc6\xd9\xae\xd1\xdb\x6e\xa2\xc0\xc7\x6f\x61\xb0\xde\x46\x5e\xe0\x77\x5d\x67\x13\xad\xd6\x9e\xff\x72\xec\xbb\xd1\xef\x68\xb6\x7e\x3d\x3f\xdd\x6d\xdd\xf3\x1f\xd6\xdb\x47\x17\xbe\xfb\x0d\x6f\xce\xc6\x79\x75\x23\x77\x53\x0b\xb7\x6f\x6f\xc1\x26\xda\x33\x1c\x8e\x2e\xd6\x6e\x04\xc7\x7f\xdc\x91\xb7\x9e\x7f\x0c\x5c\x3b\xef\x70\xd6\x61\x80\x7b\x17\xe1\xda\x7b\x5e\x45\xeb\x77\xbc\xa6\x52\xec\x14\x78\xef\x46\x91\x1b\xeb\xbd\x16\x3c\xc5\xec\x9f\xb6\xeb\x35\xfd\xe6\x3d\x46\xab\x5f\x5f\xdc\x8d\xff\x6b\xf8\xba\x0d\x57\x70\xd6\x91\xbb\xf1\x9d\xc8\xfb\xea\x86\x75\xdc\x6f\x23\x3c\xba\x4f\xce\x76\x1d\x21\xd8\x46\x6f\xdb\x08\x5e\x88\xc9\x74\xb1\x53\xa1\xff\xec\x3e\x1e\xd7\x70\x84\xa3\xae\xf9\x7f\xbb\x35\x10\x42\x8e\x0a\x2f\x20\xf1\x12\x00\x92\xef\x90\x5d\xc8\x7c\xc3\x5c\x99\x5e\x7d\x04\xa4\x1c\x18\x12\x7a\x32\xa6\xc9\x8e\xcb\x11\x4f\x92\xfd\x3f\xa3\x4f\x39\x92\x61\x1c\xaf\xdd\x5f\x17\x0b\x4a\x72\x72\xbf\x38\x5f\x00\x71\x01\x29\x2e\xe0\x54\x91\x2d\x26\xe9\xfe\x63\xad\x80\xe1\x96\xcb\x96\xeb\x8a\x64\x18\x8c\x7e\x59\x55\xe4\xb2\x81\xd9\x1e\x2b\x71\x6a\x25\x70\xdc\x52\x13\xc6\x0b\x0a\x8c\xa5\xe6\xce\x85\x55\xbc\x24\xd8\xa9\x38\x29\x94\xec\x95\x95\x35\x05\x4f\x90\x73\x3d\xa4\xaa\x91\xbf\xa6\x5a\xcc\x0d\x99\x48\x90\x7b\x0d\x61\xd8\x94\xf9\x04\xbb\x56\xe1\x77\x8c\x89\x78\x82\x63\x28\xae\x01\x47\x68\x15\xa8\x53\xbc\x84\x17\x43\x30\x12\x28\xd7\x1c\x22\x81\x10\xd4\xfb\x7f\x39\x50\xae\x30\xb9\x27\xb3\x86\xc8\x1d\x40\x1e\xd4\xa4\x68\x09\x92\xc3\xc9\x49\xde\xc2\x44\x16\xd4\xb9\x81\x33\x97\x2c\xda\x48\x63\x50\x79\x76\xe0\xb4\x50\x08\x7e\x66\x93\x44\xb0\x91\x24\x88\x2b\x30\x86\x42\x0b\xf2\xb4\x23\x48\x41\x74\xa4\x20\x1b\xc3\x4d\x9a\xcf\xd2\xc5\xba\x9d\x56\x97\x58\xae\x0a\x39\x63\x95\x43\xa8\x32\x30\x27\xb1\xa9\xdf\x2a\x48\x33\x89\xe5\x5e\xf1\x03\x54\xc1\x5c\x27\xfa\x8a\x09\x63\x14\x33\x4c\x1e\xa7\x8a\xef\x94\x19\xca\x2c\x6d\x71\x29\x5b\xac\x0d\x50\xa7\x7c\x55\xde\x2b\xa6\xbb\xf2\x04\x68\x84\xa8\x90\xd0\x3c\x56\xf7\x69\xa8\xe0\x52\xac\x30\x85\x4f\x35\xe6\x8e\x9b\x04\x19\x59\x48\x34\x2a\x73\x0b\xad\x85\x36\xc7\x8a\x71\x5d\x70\xa9\x42\x48\xe9\xd2\x74\x85\x05\xa6\x9e\xaf\xcb\xae\xa5\x9e\x5f\x2e\x50\x29\x69\x96\x5d\xe4\xf9\x50\x2b\xbc\xbc\x34\xfc\x00\xc6\x42\x18\x54\xd0\x71\x89\x2b\xe8\x6a\x4e\xa9\x0a\xcd\xd4\x2d\xa8\x82\xcd\x49\x9a\x97\x92\x96\x45\x47\x56\xdf\x6a\xde\x9d\x67\x6a\xcb\x2c\xc3\xa8\x32\x37\x06\x5b\x79\x73\x8e\xd2\x7a\x7d\x00\xa9\x70\x23\x56\xfd\x59\xcb\x4d\xf6\xff\xcb\x45\x3c\xc0\x28\x02\x63\x66\xc6\x91\x32\xe6\xe6\x8f\xf2\xe4\x52\x3d\x3e\xa5\x7e\x56\x64\x5c\x25\x6b\xfd\x80\x88\x92\x91\xf2\x51\x8c\x7c\x3c\xcf\x12\x79\xc7\x57\x64\x5c\x9a\x03\x0e\xee\x3b\x39\xd5\x13\x69\xe1\xab\x42\x4a\xdd\xed\x30\xf2\xe0\xac\xc5\xb2\x80\x64\xa8\x34\x92\x58\x72\x62\x50\x4a\x22\x3e\x3b\xd1\x31\x36\x10\xa8\xa4\xee\x1f\xce\xb8\x8a\xf1\x84\x80\x3c\x60\x74\xd4\x84\x74\xb6\x23\x63\x82\x14\x26\x3c\xce\xf5\x73\x92\x91\x85\xdf\x19\x3b\x6d\x16\xc2\x44\x2a\x21\xf7\x6d\x19\x21\x91\x90\x19\x66\x19\x2b\xea\xdb\x5e\x69\x23\x0c\xe1\xc3\x0f\x91\x99\x5d\xba\xca\x73\x42\x76\x56\x90\xbc\x30\x75\x30\x5e\xcd\x78\xab\x58\x2f\x85\xc2\x20\x50\x85\x2d\x66\x97\xc8\xd8\x88\x9f\x49\xbe\x95\x32\x84\xea\x62\x48\x28\xc2\x5f\x61\x2e\xa1\x9e\x32\x60\x28\xca\x25\xa4\x7b\xc9\xb7\x25\x3a\xac\xc6\x50\x70\x95\xaa\x3a\x2c\x58\xb9\x4c\x87\x2a\x2d\x19\x68\x93\x65\x18\x7f\xa3\xfd\x4f\xd1\x61\x39\x3e\x4a\xea\xc0\xad\xe4\x07\x34\x15\xfb\x49\x68\xad\x52\x42\x95\xb8\x03\xd8\xbe\x2f\xeb\x27\x89\x89\xeb\x1a\x30\x64\xfa\xc8\xbc\x1e\xe6\x0a\x31\x61\xa8\xf4\x2f\xb5\x5c\x1f\x8a\x51\x6d\x2c\x1c\x26\x21\x11\x7d\x00\x42\x83\xf8\x01\x09\x8d\xdc\x46\x3c\x67\x90\x68\xc9\x58\x87\x47\xdd\x92\x63\x72\x0d\x61\x18\xec\x1f\xb2\xae\x31\x1b\xf6\xbc\x59\x63\xdd\x32\x86\x59\xac\x10\x43\x87\x2e\x93\x41\x57\x34\xa5\xc6\x60\xd8\x91\x8f\x19\x83\xef\x6f\x98\x56\x29\xbb\x94\x69\xaa\x34\xd9\x85\xbd\x47\xc8\x11\xa4\xf0\x09\xdb\x2a\x16\xfa\xb8\x23\x31\x5d\x2b\x52\x38\x7b\xc3\x80\x14\x09\x22\xff\x8a\xbf\xcd\x90\x8e\x52\x8c\x5a\xd9\x1b\x6a\x62\xeb\x5e\x85\x14\xb9\xfd\xd0\xd3\x3b\xf0\x91\x51\xfd\x58\xac\x7c\x94\x12\x9d\xf7\x63\x8c\xe5\x91\xa0\xe8\xec\x0e\x2d\x3e\xa6\x55\xc3\x38\x9b\xc8\x3e\x33\x66\x58\xfd\xb0\xa2\x74\x41\xcc\xb8\x79\xda\x00\x26\x53\xda\x9b\xd9\xd6\x15\xe6\x37\x56\xdf\xce\x74\xcd\xea\x5d\x4b\x13\x61\xcc\x67\x26\x23\x09\xbd\x03\x3d\x07\xfa\xd3\x9b\xbb\xd9\xe8\xe2\x72\x81\xf9\xe8\x62\x52\x8b\x17\xa9\xff\xdf\xad\x35\x3f\x9f\x02\x03\xfb\x62\x66\xdb\xc9\x15\x1f\x14\xb3\x64\xfd\x0e\xf1\x0c\x98\x2f\x6f\xec\xd9\xbc\x3f\x1b\xdd\x2c\xb0\xb8\x9d\x9a\x6c\x90\xa7\x2b\x2b\xe7\xec\x04\xb8\x1e\x0d\x06\x63\x1b\x83\xe9\xa2\xc6\x72\x12\x8b\xa7\xf6\x13\x9e\xe8\xd6\x9a\xe7\xa7\xc0\xd8\x5a\x8c\x26\xe8\x5b\x37\xa3\x85\x35\xc6\xd8\x5e\x2c\xec\x19\x2c\xdc\x8e\x16\x97\x18\x8c\x2c\x7b\x66\xcf\x47\xf3\x9f\x97\x6c\x5a\xcd\xb6\x42\x86\xa9\x4c\x86\x9f\x92\x97\x5a\xad\x86\x42\x86\xa5\x56\x06\x21\x7e\x3f\x28\xc3\x49\x2a\xc3\xfc\xda\x1a\x67\x12\xcc\x2f\xad\xd9\x0d\xe6\x3f\x2f\xde\x5b\xad\x33\x29\x70\xd1\x05\x84\xed\x7e\x38\xc9\xb6\xda\xa7\x52\xe4\xa2\xe1\x8d\x91\x65\x78\x92\xe4\xd9\x6a\x7f\x06\x06\xa3\x2f\xa3\xf9\x68\x3a\x49\x72\x47\xce\x4e\x4f\x10\xed\x9a\x6e\xad\xd5\x69\x49\x77\x55\x74\x25\xe9\xae\x24\x9f\x99\xee\xaa\xf1\xbd\xd1\x6e\x34\x81\xfe\xdd\x6c\x34\x1e\x8f\xfa\xa2\x33\x8f\xa6\x7c\xee\xf9\xf1\xf4\x5e\x86\x66\x43\x2d\x83\x95\xa4\xb6\xac\xd5\x27\xd9\x33\x41\x79\xaf\xcb\xcc\x71\x84\xcf\x63\x05\x52\xd8\x7e\x53\xb3\xfd\x9e\x5d\xe4\xc7\x24\x44\x36\x37\x43\x0d\x48\xa4\xd1\x1b\x63\xb7\xd4\xd8\x5f\xec\x6a\xac\x2b\x63\x9f\xa8\xb1\x2f\x2e\xcd\x36\x6e\x4e\x8a\xe0\x6d\x35\xf8\xc0\x4e\xba\xf0\x6c\x48\x85\x29\x29\xb7\xbd\x88\xdd\xd1\xf8\xfb\x21\x06\x57\x2c\x90\x62\x9f\xaa\xb1\xff\xdc\x2b\x1d\xb9\x7b\xb3\x93\x14\x3b\x98\xb1\x87\xb6\x44\x24\x59\x0e\x02\xf8\x67\x0d\xb8\xcd\x17\x48\x41\x7b\x5c\xe7\x21\x7c\xca\xae\x55\x7b\xdb\x99\x46\xe9\x05\xe7\x25\x32\x92\xe4\x2e\x2d\x75\x74\xa5\xbd\xcf\xd5\xd0\xf3\xcb\xe9\x6c\x91\x08\xc0\x4e\xd0\x52\x59\x0e\x16\xc0\x52\x0b\x70\x65\x49\x00\x33\x3b\xb2\x4f\x8f\xe5\x5e\xa6\x0d\x78\x11\xbb\xa7\xc6\xb6\xc7\x69\xa0\x89\xe9\xb4\x0a\xa9\xc1\xee\x6b\xb0\xaf\x35\x19\x4b\xaa\x73\xf9\x5a\x25\xf6\x40\x83\x3d\x31\xe0\x57\x5a\x46\x34\xd8\xb6\x1a\x7b\xaa\x0a\xb3\x2a\xa4\x26\xcc\x86\x6a\xe8\x1b\x49\x6e\xfb\x10\x29\x60\xb7\x34\x35\xdc\x9e\x1d\x50\xcc\x2a\xd4\x93\x96\xa6\x88\xdb\x73\xad\xce\x4b\x0b\x58\x99\xce\x5b\x9a\x22\xbe\xb0\x85\x12\xcc\x4c\x6b\x07\x92\x3c\xb6\xa6\x88\x2f\x8d\x3d\x49\xcc\xf3\x66\xdb\xd6\x94\x70\x7b\x98\x9e\xd8\x41\x60\xc2\x87\xb4\x84\xe4\x01\x55\xdb\xd6\x94\xf0\x4b\x4b\xdc\x00\x88\xb6\x8a\xb2\x05\x95\x48\x92\xab\x88\xad\x29\xe1\x8b\xb9\x5d\x48\xd1\x07\x91\x42\xff\x90\xf5\xc9\x2d\x4d\x09\xef\x27\xfd\xc3\x21\x16\xd7\x90\xcc\xce\x35\x35\x7c\x9e\xa8\x5d\x6f\x5c\x03\x52\xd5\x39\xb5\xb4\x55\xbc\xff\x93\xe0\x73\xc5\x6b\x6a\xf8\xa5\x35\x1b\xe4\x13\x61\x9e\x3b\x32\x12\x1c\xc9\x36\xb6\xd2\xca\xaa\x0a\x38\x4d\x29\xbf\xb3\x67\x26\xe1\xbe\xef\x23\xf2\x4e\x43\x42\x12\xc9\x8f\x6f\xc4\xe8\x9a\x62\x3e\x9f\x0e\x17\x99\x02\x4a\x53\xea\xc1\x13\x4b\x4b\x57\xd3\x8d\xda\xd7\xc3\x93\x9d\xa6\xa4\xdf\x2d\x0b\x7d\x9b\xdc\xb3\xca\xbc\x10\x0a\x6c\x4d\x4d\xbf\xb3\x4c\x5a\x38\xee\x46\x99\x7e\x7a\x16\xb0\x4f\xd8\x9a\xce\x9f\xf5\x28\x6f\x37\x10\xee\x86\x06\x21\x92\x12\xc0\x7f\x2a\x05\x6e\xaa\x80\x7b\x76\x01\x99\xe5\x66\xe8\x70\x6a\x53\x9f\xb4\x54\xc8\x5f\x8a\xc8\xd0\x37\xe8\x72\x57\x57\x22\x9f\xa8\x90\xe3\x79\x5c\xa3\x6e\x22\xce\x64\x62\x2c\xa0\x4c\xdd\x6d\x15\xf4\x40\x44\x96\xc2\x49\x5d\xd0\x4c\xdd\x1d\x15\xf2\xc8\x64\xcf\xa5\xed\xa3\x06\xf9\x54\x85\xfc\xa7\x5a\xdd\xe5\xf3\xb9\xc9\x24\x7e\xf2\x59\x09\x5d\x71\xd3\x09\xb4\xb9\xba\xcf\x94\xea\xd6\x6c\x19\x07\xcc\xc3\x22\xf0\xb9\x0a\x38\x9b\xc1\x79\x78\x2e\x94\x3f\x0e\x6f\xa9\xe0\xaf\x94\x99\x4c\x35\x97\x97\x0c\xe3\x22\x72\x4f\x85\xbc\x9f\xbf\xa5\xb6\xae\x30\x95\x6b\x90\xfb\x4a\xe4\x6b\xa3\x3d\x9b\x0f\xe2\x22\xf2\x40\x89\x3c\x31\xd4\xb6\xe9\x18\x2e\x22\xdb\x2a\xe4\x69\xd5\x6c\x52\xad\x43\x38\x19\xaa\x80\x6f\xf4\x65\xa3\xfa\x49\x80\x80\xdc\x56\xd6\xe8\xdd\xd4\x5d\x0d\xb9\x64\x00\x17\x91\x95\x45\xda\x9e\x9b\x6a\x5b\x3b\xe4\x2b\xb5\xdd\x56\x16\xe9\x85\x89\xb6\xa1\x98\xad\x0d\x26\xee\xb6\xb2\x48\x2f\xab\x7a\x76\xd9\x4c\x96\xca\x9b\x00\x2b\x4b\x74\x32\x6d\x33\xc8\xc6\x83\xb7\xd1\xb4\xdd\x56\x96\xe8\x4b\x93\xdc\xa9\x98\xc0\x4d\x66\xed\xb6\xb2\x44\xc7\x93\xf6\x81\xea\x16\x1a\x50\x48\x07\xbe\xb6\xb2\x44\xf7\xb5\xdd\x81\xb9\x79\xa1\xdc\xb5\xb2\x46\xcf\xb5\x0a\xff\x01\x53\x76\x5b\x53\xa5\xfb\x3f\x09\x3c\x57\xb9\xb2\x46\x33\x13\xb6\x32\xb6\x51\x61\xd8\x56\x65\x15\x65\xa9\xde\xcf\xd7\xd5\xfc\x4d\x3e\x6a\xab\xe6\xeb\xb6\xb2\x58\x33\xd3\xb5\x46\x00\xe3\x41\x5b\xb9\x79\x75\xcd\x36\xca\xa8\xa5\x63\xb6\x12\x58\x59\xb2\xef\xd4\x3a\x67\xda\x5e\x10\xd9\x90\xcd\x7c\x9a\xaf\x15\x91\x95\x35\xfb\x4e\x3d\xde\xca\x5b\xb3\xd2\x01\x88\x47\xee\x28\x2b\xe7\x28\xef\x53\x58\x68\x46\xdf\x1c\x43\x30\xfb\x66\x27\x7c\xa8\xe9\x9d\x04\xad\x56\xf3\x1c\xe8\x2d\xc7\x63\x7b\x81\xe9\x8d\x3d\xb3\x16\xd3\x19\x7f\x3c\x50\x46\xca\x92\x88\x9c\x4c\x00\x2d\x60\xfe\xc7\xd2\x9a\xd9\x98\x4d\xa7\x8b\xb4\xc7\x3f\xea\xb2\x14\x5f\x8e\x24\x9f\x71\xbc\x59\x6a\x0f\xb2\x4b\x9d\xd6\xf8\x7a\x3a\x5f\xc0\xfe\x63\x69\x8d\xb1\x98\xea\x2f\xab\x89\xea\x15\xc0\x8b\xd4\x1e\xe8\xb4\x0d\x8c\xed\xf9\x9c\x2e\x2e\xad\x09\xa6\x33\x06\x2e\xeb\x1c\xb4\x44\xf9\x4f\x97\xc7\x30\x1d\xe0\x62\x66\x5b\x0b\x7b\x26\x41\x12\xda\x94\x52\x5a\xe5\x3f\x72\x3a\x96\xe0\xa4\xd5\x00\x16\xd3\x1b\x5c\x5a\xe3\x21\x46\x93\x85\x7d\x31\xb3\x94\x73\x8b\xc8\xbf\x10\x96\x25\x5e\x95\x40\x36\x81\xde\x74\xb1\x98\x5e\x8b\xa8\x95\x54\xab\x5c\x13\xa3\x74\x1a\x8d\x1d\xca\xbf\x31\x98\x59\xb7\xa3\xc9\xc5\x1c\xe3\xf8\x39\xc2\xcb\xe9\x6c\xf4\xe7\x74\xb2\xb0\xc6\x35\x66\x08\xe5\xe3\x9f\x2d\x34\x79\xd6\xcd\x5b\x8b\xac\xca\x14\x3d\xb4\xd3\x68\x49\x61\xbf\xd8\xb3\xc5\xa8\x9f\x6b\x56\xeb\xa3\xa4\x08\xaa\x0d\x8b\x4e\xa3\x2f\x05\x1d\x4c\x6f\x27\xb0\x26\x03\xc4\x8f\x50\x9a\x43\x83\x4b\x6b\xac\x3f\x15\xa1\x9b\x72\x35\x67\xd0\x63\x7b\x98\x3e\x9e\xc8\x67\x4d\x46\x9f\x79\x93\xc1\x37\xf0\x5c\xc2\x2d\xac\x47\x92\x95\x33\x49\xda\x52\x49\x96\x37\xac\x0a\x8c\x05\xe1\x5d\x97\x69\x74\xb9\xa3\x0a\xb6\xcd\xc9\x05\x39\xd3\x09\x92\x29\x24\x61\x93\x70\x60\xde\x49\x5f\x58\x95\xcb\xad\x9d\xba\x58\xd1\xe2\x30\xd7\x29\x77\x4c\xcd\xd6\x3f\x65\x06\xe9\xb4\xe4\x7a\xe7\xc4\xd9\x6f\x9a\x4f\x25\x06\xa8\x1a\xcb\x2b\xa5\x29\x09\x05\x2e\xfe\xf3\x5f\x90\x91\xc8\x51\xe5\xfd\x1e\xef\x44\xeb\x75\x22\x1a\xcb\x41\x78\xb6\xe7\x83\x9f\x27\xd2\x18\xb8\x06\x2b\x13\xe7\xea\xc2\x81\x10\xe1\xcf\x89\x8a\xa1\x51\xba\x7e\x2f\x53\x47\xcc\x10\x83\xe9\xb2\x37\xb6\x25\x72\xe4\x9c\xf2\x7c\x20\xa6\x42\x42\x54\xf9\x48\xcc\x4c\x9d\xa6\x1c\x57\x9f\x8a\x15\x09\x98\xdb\xa7\x9c\x4a\x50\xc5\xfc\x1f\x7b\xde\x7c\x34\xb9\x18\xdb\x79\x64\x26\xb2\xa8\xdb\x39\xbe\xe5\x13\xc5\xab\x54\xe2\x3b\x9d\x13\x99\x48\x89\x36\x72\x91\xf6\x32\xd6\x40\x74\xcf\xb8\x16\x8b\xb0\xf2\xa9\xd7\x18\x5a\x8c\x8e\x04\x55\x5e\x99\xaa\x75\xc4\x95\xd5\xd0\x29\xb1\xcc\x2e\x49\x71\x86\x61\x4f\x35\x14\x77\xee\x8b\x9f\xca\x2e\x83\xa0\x95\xd3\x12\x83\xc4\x92\xa4\xf6\xa8\xda\xed\x1d\xa4\x9b\xcf\x25\x76\x4a\x13\x78\xd9\xf0\x51\xf4\xe2\xca\xa2\x88\xd5\x73\x79\xa3\x0b\x9f\x0f\xf9\x4d\x49\x47\x9d\x08\x74\x5e\x14\x48\x19\x3c\xe5\xbb\xd4\x09\x64\x34\xda\x75\x3a\x96\xdc\x58\x85\x4e\x47\x99\xaa\x6a\x05\x1b\x19\xa6\xd4\x9e\xd6\x36\x5c\x00\x99\x75\xee\x46\x63\x52\xa7\x23\x96\x35\xde\x04\x62\xb8\x08\xac\xb4\xe9\x4b\x3b\x43\x74\x06\x5a\x4d\xb3\x5d\x4d\x99\x02\x85\xca\x52\x56\x45\x6c\x01\x38\xab\xe0\x95\x2b\x89\x59\x6c\x1a\x7a\xde\x50\x25\x96\x2e\x20\x4c\xb2\x57\xe9\xe7\xba\x08\x3d\x55\x74\x18\x8a\x8e\xd8\xe0\x10\xa0\xd2\xa9\x44\xe7\x54\xec\x34\x64\xd6\x12\xaa\x8b\xc2\xdf\x4b\xdc\x56\xe6\xa4\xa7\x62\xc7\x21\x33\x4a\x31\x44\x0e\x4c\x52\xe5\x74\x22\x55\xb1\xe9\x28\xda\x24\x9d\x85\x08\xf3\x20\xf4\x47\xa9\x04\xbe\xd8\x78\xf0\xc5\x3e\xef\x3e\x99\x8c\x95\x6f\xa5\xfa\x6b\x82\x2b\x6d\x32\x18\x43\x30\xb8\x6c\xc3\x65\xae\xde\xaa\xe6\x4b\xe4\x2a\xb6\x1c\x7c\x81\xe7\x27\x15\x7e\x14\xe6\x29\x10\xd9\xa9\x49\x69\x8c\x88\x1d\x06\x5f\x3a\x24\xe6\xc8\xd9\x1c\xa9\x46\x64\xc9\x92\x04\x4d\xd2\x44\xe8\x8d\x20\x45\xe3\x41\xd5\x68\x62\x87\xc0\x97\x09\xfe\xc8\x89\x3f\x37\xe0\x0f\x33\x8a\x34\x61\x7e\x4c\x00\x2c\xcd\x78\x7e\x7e\xdb\x2d\x11\x47\xec\x0f\x64\xe9\x48\xe1\xff\x6a\xb3\x4b\x5d\xa1\xdc\xec\x62\xc7\x20\x4b\x4e\xf2\x98\x60\x4e\x2d\xd2\xdd\x17\xfb\x09\x7d\x12\x4d\x64\x10\xbb\x07\x59\x2a\x12\x8d\x54\xcc\xc5\x65\x84\x1c\xfc\xac\x01\x2c\x6f\x6e\xe2\x9b\x5c\xe3\x21\x7a\xe3\x69\xff\x4a\x7f\xd2\xa3\x7e\x49\x38\xb6\x81\xf1\xf4\x56\xe0\x78\x50\x5d\xd3\x1f\x82\x77\xce\xce\x80\xe1\x72\x3c\xd6\x61\xc8\xf8\x55\xc2\xe8\x63\x5f\x9c\xf8\xcd\x10\x6e\x9e\x52\x51\x7c\x07\xa3\xa2\xf6\x40\xe7\x0d\x24\xad\x89\xa0\x36\x21\x65\xaa\xc9\x62\xc3\xa4\x22\x13\xc4\x26\x92\xf3\x97\xf9\xa5\x95\x3f\x67\x77\x54\xec\x0a\x3f\xa0\xbf\xf3\x16\x70\x6d\x0f\x46\xcb\xeb\x1c\x45\xaf\x28\xe0\x00\xe5\x9d\x00\x03\x6b\x76\x95\x62\xfc\x88\x52\x69\xed\xba\xb6\xb1\xd5\xbf\x4a\x6e\x1b\xa9\xb4\x4a\x84\x7b\xf8\x87\xdc\x9e\x3a\x69\x58\x2d\xc0\xca\xeb\x28\x7f\x72\xcb\x04\x30\x77\xd6\xce\x3d\x19\x43\x58\xde\x84\x45\x22\x12\x5c\x16\xba\x8d\xfc\xf1\x37\x59\xea\x27\xcc\xef\x9a\x87\xf8\x7b\xe2\xca\x69\x16\xea\x14\xe9\x73\x2a\xe2\x9d\xe2\xcc\x04\xe9\x35\xac\xee\xf8\xbb\xbc\x42\x9b\x9d\x57\x1f\xed\x2e\xcf\xc0\xdc\x49\x06\x5b\xa6\xd4\x0a\x36\x7b\x27\x33\x1a\x07\x6d\x81\x79\xfc\x8b\xa8\x2f\x12\x2a\x2c\xff\xf7\x0f\xb8\x47\x8b\x85\xa3\x66\xa2\xdc\x75\x0f\xf9\x13\x86\x1a\x81\x09\xa7\x71\xee\x1d\x61\xad\xb1\x17\x84\xb0\x7e\xa5\xc6\x1e\x00\x57\xa3\xe4\xf7\x5e\x31\xae\x98\x24\x91\x0a\xbf\xdb\xb1\xe8\x10\x19\xc6\x10\xb8\x5a\x4a\xfc\x9f\xdd\x1f\x61\x19\x90\x1f\xe6\x51\xbd\x26\x70\x65\x9b\x60\x67\x1d\x41\xc1\x89\x0c\x23\xb8\x88\x7d\x02\x5c\x4d\x45\x77\x56\x38\x62\xc5\x77\x19\x13\x15\x76\x07\x98\x5b\x99\x8c\x0a\x7f\x26\x45\xdf\xe0\xde\x11\x55\x60\x11\xed\xbe\x3f\x03\xf3\x11\x3e\xcd\x2f\x47\xbf\xb0\x5a\x4a\x4d\x9b\xba\x24\x6b\x77\x1e\x96\xc5\x65\x8d\xcd\x5b\x3b\x7b\x23\x0a\x92\x4b\x72\x0e\xcc\x97\xd2\xc9\x87\x8d\x68\x49\xf7\xcc\x44\x36\x61\xe3\xa1\x68\x8f\x0c\xab\x07\xec\x1f\x38\xe3\xbd\x82\x68\x6c\xcf\x69\x42\x73\x5d\xe6\xb0\x2a\x8d\x0f\x80\xf9\xb4\x26\x0d\x22\x3e\x47\xf3\xc6\xe5\x74\xcc\x69\x98\xd3\x2f\x07\x9a\x61\x0e\x81\x85\xc5\x78\x03\x17\x58\x5c\xee\x49\x53\x09\x8b\x49\x0e\xc1\xec\x37\x81\xc5\x08\x9f\xfa\x89\x67\xa5\xc2\x27\x76\x22\x84\xc8\x3d\x56\x12\x73\xea\xa2\xc1\x39\x5c\x41\x82\x36\xb0\x58\xe2\xd3\x62\xbe\xfc\x25\xcb\x9a\xf9\x7d\xb4\x9f\xa8\xef\xfe\x29\x92\x07\x57\xd3\x8d\x8a\x12\x56\xdc\x27\x64\x81\xa5\xd8\xf5\x19\xf6\x8f\xad\x30\x39\x32\x95\x38\xdd\x7a\x1a\xdc\xdc\xf7\x0c\xc7\x8c\x97\x05\x4c\x0c\xaa\x9d\xa9\xe4\x5c\x2e\x2a\xa9\x06\xfd\x1e\x30\x19\x15\x1b\x0c\xfe\x9d\x5a\xbf\xa5\xda\xd6\x61\xf7\x81\xc9\xb2\x34\xff\x27\x29\x39\xdf\xa9\x38\xd1\xb3\x16\x23\xbc\xe7\x28\xab\x7c\x7f\x00\x4c\x6c\xb3\x96\x88\xab\xb9\x44\xa6\x93\xb4\xd3\x51\xda\x8a\xc7\xb6\x81\x09\x53\x05\x79\xb0\x9f\x14\x2b\x43\xb0\xcf\x1d\x17\x56\xa5\x9a\xe6\x7e\x5d\xa0\x58\x91\xd8\x1c\x2a\x65\xc0\x63\x0e\x5a\xc0\xe5\xa8\xc6\xe7\x7b\xe4\x93\x01\x61\x7f\xee\x53\x58\x23\xa3\x25\xd3\x49\x8e\xd5\x01\x2e\x97\xf8\x34\x8c\x93\x90\xb6\xb8\x19\x14\x3a\x41\xa5\x52\xc0\x33\xe0\x52\xd2\x99\xf3\xef\x38\x0e\x84\xe3\x2d\xa0\x26\xf2\x18\x05\xce\xa0\x07\x5c\x4e\xab\x25\x0c\x52\xec\x51\xd9\x5f\x5e\x4d\x38\xbd\x68\x9c\x77\x60\x03\xd7\x96\x59\xe0\x13\x45\x1b\x45\xd4\x6d\x94\xd8\x62\xf1\xd8\x43\xe0\x7a\x54\xe3\x0f\xe9\xd8\x9f\x67\x62\x4a\x69\xce\xa1\xec\xdb\x3d\x6f\xbb\x01\x5c\x2f\x2b\xa5\x56\xd9\xb8\x2a\xb6\x95\x90\xa6\x34\x11\xbb\x09\x5c\xdb\xfa\x1c\x20\xf4\x0a\x9c\x96\xf8\x1c\xc8\xa7\x40\x31\x03\x66\x98\x2d\xe0\x7a\x2a\x4b\xee\x44\x63\x55\xbe\x11\xd0\xbd\x83\xa6\x39\xb3\xdb\x88\x9f\x15\x16\x62\x80\x08\x4d\x26\xa3\x6b\x52\x68\xb0\x45\x34\x53\x1f\xb2\x4f\xc1\x3e\x21\xad\x2b\x71\x06\xef\xaa\x15\x3c\xfb\x0c\xb8\x2b\x8c\x3f\x32\x6c\x4d\x7c\x94\x14\x2b\x25\xf6\x39\x30\xb3\xaa\x34\x4b\x59\xa6\xaf\x7a\xa4\x51\xc4\xb6\x80\xd9\x88\xf9\x65\xb7\x1a\x82\x77\xf9\x23\xf6\x64\x9a\xe7\xd9\x03\x66\x4b\x26\x18\xf8\xd0\xd0\xbd\x23\x4c\x46\x64\x4b\x5c\x7e\x5e\x24\xee\x4e\xdc\x4f\x1f\x98\xd9\x66\x45\x2b\xf5\x71\x36\xd3\xee\x69\xb3\x3a\x63\x0f\x80\xd9\xb4\xa6\x30\xd4\x91\x38\xd5\x68\xde\x48\xbd\x45\x9e\x1b\x86\xc0\x6d\xe1\x58\x4f\xea\x0f\xca\x1c\xcf\xfb\xb0\xd8\xa6\xa9\x7d\x65\xd8\x00\x6e\x47\x92\xfa\xc5\xe7\x53\xa5\x95\xf5\x55\x50\x5f\xdb\x86\x4d\xe0\xd6\x56\xa8\xaa\xf8\x46\x96\xe3\x25\x6f\xe4\xa5\x20\xc3\x6c\x01\xb7\x53\xb3\x43\x10\x81\x5f\xa9\x76\x89\xbc\x59\xcb\xb1\x4f\x80\x89\xb8\x29\x0e\x98\x14\x36\xf5\x81\x3e\x94\x36\xbe\x37\x1a\x8d\x36\x70\x65\x2d\xac\x6b\xeb\x86\x15\xc9\xf8\x5f\xb7\xe6\x50\x0b\x1e\xed\x61\x4b\xfb\x70\xe9\x00\x01\xb5\xf1\xe2\xd0\x21\x5e\x3c\x7a\x81\x97\x2d\xbd\xc4\x8b\x4b\x47\x78\x09\xe8\xbf\xf2\xab\x42\x87\x5e\x21\x5c\x79\x74\x8c\x70\x4b\xaf\x11\xba\x74\x82\x30\xa0\x53\x44\x0e\xbd\xc1\xc3\xca\xa3\x7f\x20\x0a\xb7\x74\x86\xc8\xa5\x73\x44\x01\x5d\x74\x6b\xbe\x43\x97\xf0\x3d\xfa\x05\xfe\x96\xde\xc2\x77\xe9\xbf\xe1\x07\xf4\x0e\x2b\x87\xfe\x89\x95\x47\x1d\x3c\x6d\xe9\x3d\x56\x2e\x7d\xc0\x2a\xa0\x8f\x31\xd6\xab\x43\x5d\xbc\x7a\xf4\x09\xaf\x5b\xfa\x8c\x57\x97\xae\xf0\x1a\x50\x0f\xef\x0e\xfd\x0f\xde\xb7\xf4\x05\xdf\x5c\xba\xc6\x7b\x40\x5f\x73\x09\x37\x0e\xf5\xb1\xf1\x68\x80\xcd\x96\xbe\x61\xe3\xd2\xbf\xb0\x09\xe8\x06\xdf\x1c\x1a\xe2\x9b\x47\x23\x7c\x0b\xe8\x56\xd0\x86\x4f\xbf\x1e\xa0\xc3\x83\x34\x9f\x5a\xf0\x74\xd7\x39\xcc\xfb\xd3\xdb\x9d\x0d\x1d\xea\xd4\x71\x4f\xef\xeb\xf8\x4a\xbf\xd6\xf1\x4c\x9f\xeb\x78\xa4\x8f\x75\xb8\xd4\xad\xe3\xef\x15\xfd\x4f\x1d\x7f\xd3\xbf\xeb\xf0\xa8\xd7\xad\x85\xab\x60\x13\xc1\xa3\xbf\xd7\xf1\x42\x5f\xea\x58\xd3\x75\x1d\xaf\xf4\xb5\x0e\x9f\xfa\x75\x04\x34\xa8\xe3\x8d\xbe\xd5\xb1\xa1\x9b\x6e\x2d\xa4\x61\x1d\x11\x8d\xea\xd8\xd2\x6d\x1d\x4f\xf4\xa9\x8e\x97\x15\x5d\xd5\x11\x85\xf4\xaf\x3a\x1e\x56\xf4\xa1\x8e\x70\x45\xbf\xc5\x16\x5e\x3d\xac\xe8\xf7\x3a\x56\xce\xe6\x91\xfe\x4f\x1d\xef\xee\x66\x4b\xff\xaf\x8e\x30\x78\x8a\xe8\xaf\x75\x6c\xdc\xaf\xee\x26\x74\xe1\xd2\xff\x47\xb7\xf6\xbe\xa5\xff\x5b\xdf\x19\xe4\xdd\x44\x5f\x7d\xe7\xcd\x8b\x9c\x75\x18\xff\x11\xee\xb1\x13\x79\x3e\x1e\xf6\x1f\x61\x1d\xff\x95\xe8\xb0\x0e\xf7\xfb\x83\xfb\x16\xfd\x13\xdd\xda\x2c\x41\xb2\xe9\x6f\x75\xdc\x6d\x69\x57\xcb\x7b\x12\xec\x78\x85\xf1\x9f\x9c\x4e\xf4\xb3\xdf\xc4\x7e\x0b\xfb\x0d\x1c\x67\x36\xf8\x6f\x00\x00\x00\xff\xff\xf9\xa0\x34\x27\x95\x7c\x00\x00")
+
+func fontsBannerFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBannerFlf,
+ "fonts/banner.flf",
+ )
+}
+
+func fontsBannerFlf() (*asset, error) {
+ bytes, err := fontsBannerFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/banner.flf", size: 31893, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBanner3DFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x59\xcd\x8a\x23\x37\x10\xbe\xfb\x29\x0a\x14\xd0\x25\x2b\xb2\xbb\x39\xec\xd4\xc9\x81\x40\x4e\x79\x88\x19\xd6\x93\x04\xbc\x13\xf0\xc4\x84\x79\xfb\x60\xa9\x54\xf5\x95\x24\xb7\xd5\x63\x12\x08\xf4\x2e\x4c\x4b\xad\x9f\xfa\xff\xaa\xaa\xfd\x7c\x7c\xfe\xf4\xf8\x1d\x7d\xa1\x2f\xf4\xe9\x07\xfa\xf0\x91\x3e\xef\x9e\x1e\x5f\x5e\x0e\xa7\xcf\x1f\x7e\xa6\xa7\x37\xfa\xf5\x70\x3a\xfe\xf1\x42\xbf\x9c\x0e\x6f\x7f\xff\x79\x7c\xa6\x6f\x79\xbe\x7f\x3a\x3d\xfe\xfe\xed\x35\x9d\xbf\x1e\x8e\xe9\xf0\xf5\xbc\xfb\xe9\xfc\xdb\xf9\xf5\x2f\x7a\xf8\x9e\x3e\x3e\x3c\xfc\xb8\xdb\x31\xf3\x7e\xe2\xcf\x7e\x17\x43\x08\x81\xf7\x3b\x6a\x9e\x4c\x21\xe4\x5d\x29\xe5\xdd\xed\xbe\x94\x2e\x0b\xf5\x02\xb7\xaa\x5b\x2e\x57\x24\x77\x8f\x5c\xc6\xf6\x6f\x76\x72\x99\xc5\x4c\x48\x96\x28\x13\x32\xde\x82\x32\x56\x56\xd2\xf2\x8a\xbb\x20\x33\x96\x79\xcb\x84\xf4\x94\x5c\x71\x39\x97\xe5\xc8\x02\x66\xcd\x64\xe1\xb3\x84\xb6\x93\x53\x82\x9d\x51\x76\x92\xea\xc2\xef\x4c\x45\x83\xaa\xc2\x90\xe5\xcb\xec\x08\x67\x65\x5a\xb5\x2a\xa2\xb3\xe8\x3e\xd5\xa9\xe8\x29\x8a\x11\x42\x99\x0b\x75\x92\x79\xde\x4c\xb6\x2e\xc6\xa8\x36\xe4\x22\xb2\xdc\x26\x12\x97\x49\x61\xdc\x56\x94\x09\xd9\x15\x55\x2d\x7a\xa6\x1c\x11\x35\x70\x21\x82\xce\x82\x5e\x44\xaa\x64\x91\x0c\x2d\xdf\x3d\x2b\xa7\xc2\x0b\xdb\x51\xe1\xc1\x0f\x1a\x29\x44\x72\xe3\x44\x48\x56\x0f\x65\xae\xea\xea\x07\xb2\x87\xec\x94\x7a\x8b\xf3\xd8\xa8\x76\x14\xaa\xf1\xa6\x8f\xf2\x54\x98\xd8\x4c\xed\x69\x8c\xd9\xfd\xf5\xf2\xe4\x57\x99\xbd\x66\xe1\xc2\xfe\x39\x69\x24\xe0\xef\xda\x30\xa2\xc8\xe2\xf1\xb7\x8f\xc9\x78\xf9\x11\x8d\xc7\x6a\x0e\xe5\x28\x56\xeb\x99\x29\x18\x75\x66\x91\xa5\x43\xf3\x28\x74\x2a\x10\xd7\xf9\x5f\xbd\xe9\x12\x03\x5e\x3b\x6c\x30\x31\x9e\x94\xed\x04\x1e\x12\xc0\x46\xce\xad\x22\x90\x51\x47\x36\x9f\x46\xeb\x0e\x87\xe6\x12\x9c\x20\xd6\x63\x03\x6e\x05\xb5\x4c\x50\xd2\xf8\xc2\x6d\x66\x28\x6a\x26\xbd\x8d\xdf\x4f\x48\x18\x35\x04\x75\x7a\xeb\xf0\x53\xe1\xb3\xe5\x2e\x6a\xb8\x32\xc6\xae\x9b\xb4\x7c\x1b\x0c\xd8\xb6\x32\xf1\x38\xad\x8e\x57\x45\x05\x8d\xd8\xc5\xec\xee\xad\x4c\x7a\x59\x18\x4d\xb3\xac\x32\x21\xa1\xf4\x6c\x1b\x0d\xb6\xcd\xa8\xcc\x4b\x42\x66\x99\xce\x95\x00\x49\x96\xc7\x35\x52\x66\x24\x21\xad\x32\x26\xb6\x2d\x48\xb2\x96\x50\x78\xaf\x97\x55\x9f\x8a\x0d\x2a\x2a\x58\x2f\xaf\x5f\xad\xa0\xae\xc2\xad\xa6\x53\xf6\x90\xa0\xa8\x35\x4a\x82\x3e\xe5\x89\x59\x34\x9b\x39\x94\x64\x18\x44\x17\x0a\xe3\x37\xdd\xa9\x59\xb2\xf5\x0d\x59\x79\xe3\x90\x75\x02\x2b\x20\x1c\x29\x38\xff\xb4\xb4\xa6\xde\x07\x08\xdf\xac\xdc\x70\x97\x18\x6a\xc5\x54\xd2\xb3\x9f\xb8\x70\x4b\x50\xe9\x8c\xdd\x45\x2a\x15\x4b\x33\x88\xcb\xec\xb3\x86\xb1\xd0\x01\xcc\x28\x1a\x92\xa2\x92\x0b\xe5\xc5\x43\x93\x98\xe1\xb6\xa5\x61\xa4\x99\xe6\xf0\xfc\x10\x09\x9b\xf1\x0d\xf4\x9b\x97\x64\x72\x72\x4d\x92\x15\x38\xce\xc6\xcb\x50\xaa\xe0\xc2\x24\x75\x36\xb9\x9b\x80\x8e\x7d\x19\x12\xe1\xb4\x19\xc3\x59\xa3\x4e\x00\x5f\xae\x24\xc3\x84\xbc\x98\x49\x20\xc2\xe3\xac\xb2\x97\x3d\xf7\x96\x1b\x23\x6c\xde\x78\xc6\xd0\xf4\xa1\x45\x37\x50\xfa\x59\x11\x3f\x1c\x63\x42\x9e\x75\x4f\xaf\x09\x28\x32\xa0\x73\xd3\xa0\x27\x68\xa3\x08\x42\x3e\x3f\x1c\xba\x99\x0a\x16\x82\x67\xd5\xf8\xaa\x5b\x3a\x63\x06\xed\xa6\xf2\x11\x70\x14\x07\x7e\x89\x02\xe8\x29\xcd\x19\xd3\xb9\x86\x73\x13\x46\x54\x45\x22\xc1\xb5\x92\x61\x49\x55\x93\x59\x7f\x72\x32\x55\x28\xad\x46\xd7\x34\xac\x96\x79\x10\xd0\xf7\x48\x14\x41\x87\x9c\x30\x7a\xd4\x84\xd2\x57\xdc\x9b\x2f\x5c\xfa\x6e\xe0\x66\xe4\x04\x33\xf9\xa2\x0f\xb6\x3e\x38\x27\xf2\x45\xf6\xf3\xcc\x64\x5f\xb8\xae\x1e\x5b\x55\x32\x0f\x7e\xf7\x7b\xd9\x6a\x42\x7d\x23\x49\x5a\x18\x25\x0a\x4e\xa0\x56\x22\xa0\x14\x31\x20\xe1\x83\xd5\xfc\x2c\x13\x13\x8a\x45\xb0\x4a\xb2\x95\x2c\x21\x6c\xba\xaf\x23\x0d\xcb\x28\x4c\x07\x9d\x63\x6f\x43\x74\x4e\x0a\xc9\xf8\x01\x4b\x6b\xd2\x77\x3b\x83\x47\xd5\xaa\xfa\x51\xf7\xdd\xb6\x46\x1a\xf8\xb7\x8b\x06\x28\x07\x0c\x30\x26\x46\xee\xca\x2e\x9f\x24\xe0\x40\xb5\xd0\xab\x04\xbf\x2e\xb0\xeb\x88\xad\x89\xe8\x4a\x4f\xa1\x6a\x1b\x66\x46\x71\xc4\xb1\xd6\xcc\x05\x3d\x48\xc1\xc3\xd9\xdc\xb5\x23\x33\xc3\x55\x9b\xa7\x3f\x65\x2d\x7e\xd0\x34\x7d\x21\xb7\xc3\x0f\x9a\x5b\x9f\xb0\xf5\x09\x5b\x9f\xb0\x90\xe8\xb6\x3e\x61\xeb\x13\x68\xeb\x13\xfe\x8d\x3e\x21\x6d\x7d\x02\x6f\x7d\xc2\xd6\x27\xfc\x9f\xfa\x04\xcb\xd4\xe5\xf7\x47\x3c\xa8\xbf\x6b\x43\xc9\x8f\xab\xac\xf0\xc9\xee\xa7\x70\xd1\x59\xfd\xab\x3f\x01\x8c\xde\xd7\x9c\xca\x1a\x4e\x28\x52\x1d\x85\xc1\x3b\xcb\xc7\xac\x19\x19\x20\xa0\x4a\x7e\x81\xaa\x6a\x99\x42\xb3\xda\xa6\xf6\x22\x15\x34\x19\xfe\xad\x98\xed\x77\xcd\xff\xff\xea\xc5\x3f\x01\x00\x00\xff\xff\x31\xb1\xff\x2e\xed\x23\x00\x00")
+
+func fontsBanner3DFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBanner3DFlf,
+ "fonts/banner3-D.flf",
+ )
+}
+
+func fontsBanner3DFlf() (*asset, error) {
+ bytes, err := fontsBanner3DFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/banner3-D.flf", size: 9197, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBanner3Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x59\xcd\x6e\x13\x31\x10\xbe\xef\x53\x7c\x92\x7d\x84\x8a\xb6\x48\x55\x6f\xcb\x89\x13\x0f\xd1\xa8\x09\x20\xa5\x41\x4a\x89\x50\xdf\x1e\x35\xeb\x9f\x6f\xc6\x63\xaf\x37\x81\xdb\xa6\x52\x3c\xde\x1d\x8f\xe7\xf7\xf3\x38\xdd\xed\x77\x77\x4f\x1e\x0f\x78\xc0\xdd\x27\x7c\xbc\xc5\x3d\x86\xcd\xd3\xe1\xb0\x3d\xde\x63\xf3\x86\x6f\xdb\xe3\xfe\xe7\x01\x5f\x8f\xdb\xb7\x3f\xbf\xf6\x3b\xbc\x9c\xe7\xe3\xe6\xf8\xf4\xe3\xe5\xf5\xe6\xf4\xbc\xdd\xdf\x6c\x9f\x4f\xc3\x97\xd3\xf7\xd3\xeb\x6f\x3c\x7e\xc0\xed\xe3\xe3\xe7\x61\xf0\xde\x8f\xed\xaf\x71\x70\xce\x39\xaf\x07\x38\x87\xf7\x01\x80\x7e\x37\x8d\xa0\x67\xa0\x45\x08\x2b\x3d\xc2\x47\xd1\xb0\xe9\xf7\xc9\x59\x50\x78\x91\x69\x17\x3f\x9d\xcf\x89\x3e\x6b\x34\x7d\xa6\x15\xe7\x77\x08\x7a\x4f\x93\x69\x0d\xb3\x01\x06\x5b\xb4\x2f\xb1\x05\x05\x02\xef\xc4\x99\x64\x46\xf5\x68\x87\x28\x35\x4f\x83\xdf\x26\xfd\xe3\xda\x6c\x0e\xe2\xdb\x69\x1e\xe5\xa6\x4d\x7c\xf1\x3c\x6d\xc6\xb2\x58\xc5\xc0\x93\x83\x58\xc4\x3b\x09\x2e\x87\xb0\x5d\x54\x21\x8a\x36\x46\xa1\x5e\xd8\x2a\x87\x26\x9a\x6b\x8e\x51\x8b\x18\x3e\x4e\x16\x4a\xae\xae\x3c\x10\xfc\x22\xd1\x92\x5d\xac\x57\x96\x65\xbe\x92\xeb\x0b\x1f\x35\xbc\x99\xb6\xf7\x36\xc5\xea\x37\xf8\xce\xa4\xaf\x7f\x27\x05\xf2\x8e\x59\xa8\xcc\xec\x9c\x71\xd9\x44\xf2\x59\x0e\x26\x07\xde\x70\x6b\xe0\xc9\x79\x66\xd0\x3a\x6c\x1c\x5b\x99\x96\x5e\x3c\x6b\x53\x2e\xd7\x86\x2a\x70\x61\xb6\xaa\x5b\xb6\xab\xa4\xdd\xe5\x42\xf9\xb9\x32\x9e\xf1\x42\xef\xcc\x1b\x58\xb4\xce\x0c\xde\x8c\x41\xc8\xf1\xc6\xd0\xa4\xd2\x92\x78\x59\x47\xb4\xec\xb6\x1c\xd5\x4a\x00\x14\x38\xe9\x8a\x6d\x67\x73\xd1\x22\x67\x55\xac\xc5\xbb\xad\xe2\x92\x05\x3a\x0f\x5a\x42\x51\x3b\x50\xad\x77\x05\x88\xf4\x21\x8b\x40\x4e\x0d\xcd\xb0\x91\x37\x58\xe0\xf3\x28\x2c\x33\xe6\x09\x0b\x66\x24\xd7\x34\x99\xab\x29\x06\x28\x99\x15\x46\xd3\xd0\x95\x0d\x8e\x4e\x40\x45\x97\x48\x20\x03\x17\x94\xd0\x27\x4d\x1d\xfa\x8a\x22\xd4\x74\x5f\xd9\x2c\xe4\xe1\xda\xe5\xd2\xaa\x01\x41\x81\x3e\xaa\xfa\xfb\xb6\xef\xa1\x5b\xd5\x6f\x03\x54\x53\xdb\x28\xe1\xdf\x48\x03\x54\xf6\x54\x10\x99\xf8\x15\x7c\x69\x7e\x92\xb3\xcc\x43\x9d\x1e\x2d\x40\xa4\x31\xb8\x4a\x07\xd0\x22\x8b\xdc\x31\x52\x43\x72\xc8\x86\x3a\xb5\xbb\x28\x9e\x16\xfe\xe2\x93\xb0\x3f\x57\xdb\x39\x21\x1c\x8b\xd8\xa6\x3a\x71\x4b\x11\x18\xd0\xe3\xf0\x42\x66\x14\x49\x48\xc2\x77\x04\x76\x8e\x53\x06\xf7\x9c\x2f\x9d\xcd\xd4\xd2\x72\x2d\x78\x8c\xce\x07\x45\x49\x2c\xd2\x54\x3a\x96\x4b\xe2\x1a\xec\xab\xd7\xa5\xf0\x69\x1d\xfb\x88\xc1\xce\x75\x0b\xfb\x74\x3b\x72\x09\x79\x2d\x7a\x56\xe3\xbd\x78\xb1\xe8\xbc\x45\xbb\xa5\x34\x35\x2e\xbb\x97\x4c\x10\xea\xa3\x54\xb8\x43\x99\x9e\xb3\x56\xc7\x0f\xe2\x66\x71\x49\xa0\x38\xec\xb8\xe8\x9e\xa4\x4f\xa7\xa4\x71\x37\xa1\x90\x4c\xed\x20\xfb\x20\xb2\x42\x5c\x4d\x75\xa2\x8f\x83\xb0\xac\x9b\xc8\xda\x00\x7c\xe7\x13\x95\x39\x77\x57\x55\xb7\xd6\x1e\xc6\xf6\xd5\x78\xac\xfd\x3c\xc5\x9d\x32\xf4\xcf\x15\x6b\x1b\x77\x1d\x10\xd9\xf8\xd8\x3a\x91\xd7\x36\x6e\x6d\xe3\xd6\x36\x6e\x6d\xe3\xd6\x36\xae\x11\xef\xc5\x8b\xd7\x36\x6e\x36\x50\x1c\x76\x5c\xd9\xc6\x41\xfe\x3f\x8b\x09\x57\x3c\x11\x72\xa3\x6d\x9e\xbf\xc2\x42\xfe\x8a\x10\x94\x34\x2b\x08\x67\xbe\xca\xc7\x53\xfa\x77\x0f\x8a\xe0\x21\x9c\x74\xd4\x4a\xa9\x5f\xd1\x9a\x93\x71\x10\x7f\xff\x73\xfa\x37\x00\x00\xff\xff\x81\xfa\x12\x5c\xf4\x1c\x00\x00")
+
+func fontsBanner3FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBanner3Flf,
+ "fonts/banner3.flf",
+ )
+}
+
+func fontsBanner3Flf() (*asset, error) {
+ bytes, err := fontsBanner3FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/banner3.flf", size: 7412, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBanner4Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x59\x4d\x8f\x13\x3d\x0c\xbe\xcf\xaf\x88\x94\xf7\xf8\x62\xb1\xcb\x4a\xab\xde\x86\x13\x27\x7e\x44\xab\x6d\x01\xa9\x5b\xa4\x2e\x15\xda\x7f\x8f\xd4\x49\xe2\xc7\x1f\xc9\x64\x5a\xb8\x4d\x11\x13\x67\xc6\xb1\x1d\x7f\x3c\x71\xe0\x70\x3c\x3c\x6e\xff\x0b\xcf\xe1\x39\x3c\x7e\x0c\x1f\x1e\xc2\xa7\x30\xec\xb6\xa7\xd3\xfe\xfc\x14\x76\xef\xe1\xeb\xfe\x7c\xfc\x71\x0a\x5f\xce\xfb\xf7\xdf\x3f\x8f\x87\xf0\x7a\x9d\x8f\xbb\xf3\xf6\xfb\xeb\x1b\x5d\x5e\xf6\x47\xda\xbf\x5c\x86\xcf\x97\x6f\x97\xb7\x5f\x61\xf3\x7f\x78\xd8\x6c\x9e\x86\x81\x88\xc6\xf6\x63\x1c\x28\xc6\x18\xcd\x40\x31\x4e\x1c\x57\x46\xfc\x96\x46\x7c\x87\x8b\x70\x65\x5e\x3e\x4f\x5f\x27\x57\x41\xe9\x03\xd3\x31\xff\x3a\xdf\x33\x3d\x59\x34\xfd\xa6\x15\x94\xfe\xc2\x64\x5a\x83\x6c\x44\x0e\x5b\xde\x5f\x66\xcb\x06\x24\xde\x89\xb3\xc8\x2c\x5f\x59\x43\x96\xca\xd3\xe4\xb7\xc9\xfe\xbc\x96\xb7\x93\xb4\x65\xd7\x64\xb9\x45\x89\x7d\x5f\x94\xa1\x2c\x34\x31\xf1\x70\x10\x4d\xbc\x8b\x60\x33\x64\x75\xd9\x84\x2c\xda\x19\x85\x79\x49\x15\x87\x26\x6f\xd7\x1d\xb3\x15\x39\x7c\x98\x2c\x22\xb9\x3a\xf2\xc0\x4d\xc6\x32\x29\x6e\x46\x42\x0a\x52\x3c\xb8\xde\x0c\x75\x6f\xb2\xfa\x0a\x85\xe6\xd7\xf9\x26\xb2\xf1\x2c\x06\xb0\x46\x16\x2a\x33\x9b\x33\x8e\xb7\x08\x3e\xe3\x60\x62\xe0\x1d\xb7\x26\x1e\xce\x33\x87\xd6\x61\xc3\xd8\xca\xb4\x94\xef\xda\x54\xe4\xda\x50\x05\x2e\xb6\xad\xea\x16\xf7\x65\xe9\x78\xbb\x50\x7c\xaf\x36\x8f\x78\xa1\x35\xa3\x02\x8f\xd6\x99\x81\xca\x10\x84\x22\x2a\x26\x4d\x2a\x2b\x81\x17\x6d\xa4\xd6\xbe\x3d\x47\xb5\x12\x80\x0c\x4e\x46\xa3\x76\x36\x17\x1d\x72\xde\xc4\x5a\xbc\xdb\x26\x2e\x59\xa0\xf3\xa0\x25\x94\x6a\x07\xaa\xf3\xcd\x82\x48\x1f\xb2\x08\xe4\xd4\xd0\x4c\x2e\xf2\xe6\x1d\xc0\x28\x76\xe6\xcc\x0b\x16\xb4\x25\xd7\x2c\x99\xad\x29\x04\x28\x99\x15\x4e\xd3\xd0\x95\x0d\x11\x4e\x40\x45\x5b\x24\x90\x81\x4b\x46\xe8\x93\xa6\x0e\x7d\xa6\x08\x15\xdd\x59\x36\xcb\x78\xb0\x76\x45\x69\xd5\x80\x40\x91\xa6\xfa\xfb\xd4\xf7\xd0\xad\xea\xf7\x01\xaa\x69\x6d\x92\xf0\x97\xa4\x71\x2e\x5b\xee\xca\x19\xa1\xe0\x4b\xf3\xb3\x9c\x85\x1e\xea\xf3\xa8\x05\x91\xc6\x10\x2b\x1d\x40\x8b\x34\xb9\xe3\xa4\x86\xe4\x90\x0d\x75\x69\x77\xc9\xbc\x35\xfe\x1a\xfb\x13\xb4\x3b\x27\x84\x63\x4b\x9b\x1a\xc5\x2d\x45\x60\x40\x8f\xc3\x8d\xcc\x2c\x12\x90\x04\xef\x08\xe8\x9c\xa8\x36\xdc\x73\xbe\x74\x36\x53\x4b\xcb\xd5\xf0\x38\x9d\x0f\x99\x92\x58\x64\xa9\x74\x2c\x96\xc4\x3d\xd8\x57\xaf\x4b\xe1\xd3\x3a\xf6\x01\x83\x9f\xeb\x1e\xf6\xe9\x76\xe4\x06\xf2\x6e\xf4\xac\xc6\x7b\xf1\x62\x38\x58\xf1\x82\x9c\x8f\x37\xf0\x17\x06\xf3\xf6\x09\xa5\xfa\xb0\x06\xcf\x1b\xd3\x73\xd6\x9a\xf8\xa1\xc8\xe8\x74\x93\xf3\x81\xc2\xb0\xb3\x34\x22\x4f\x5a\x8c\xe4\xdc\x93\xf4\xe9\x54\x8c\xec\x26\x14\x92\x29\x0d\xa8\x57\xec\x02\x6c\x44\xcb\x89\x94\x35\x84\x90\x3f\x47\xb0\x35\x44\x78\xe7\x13\x95\x39\xce\xdd\x69\x11\x51\xba\x18\xdb\x57\x63\x3e\x01\xd5\x41\x48\xd8\x29\x93\xfe\xe7\x8a\xb5\x8d\xbb\x0f\x88\x7c\x7c\x6c\x9d\xc8\x6b\x1b\xb7\xb6\x71\x6b\x1b\xb7\xb6\x71\x6b\x1b\xd7\x88\xf7\xe2\xc5\x6b\x1b\x37\x1b\x28\x0c\x3b\x4b\x23\xf2\xa4\xc5\x99\x36\x8e\x10\xa7\x81\xb1\x80\x88\xfb\x89\x88\x91\x4c\x3c\xd2\x42\x78\x14\x08\x2a\x96\x19\x22\xba\x9f\xf8\x78\x4a\xa4\x84\x6a\x74\x80\xfa\x8f\x8f\xee\xc9\x38\x88\x3f\xff\x72\xfa\x27\x00\x00\xff\xff\xb5\x05\x67\x1b\xf4\x1c\x00\x00")
+
+func fontsBanner4FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBanner4Flf,
+ "fonts/banner4.flf",
+ )
+}
+
+func fontsBanner4Flf() (*asset, error) {
+ bytes, err := fontsBanner4FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/banner4.flf", size: 7412, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBarbwireFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\x4d\x8f\x1c\x35\x10\xbd\xcf\xaf\xa8\x43\xae\x40\x58\x21\x11\x24\xcb\x6a\x22\x11\x89\xeb\x5e\xb8\x26\x48\x1b\x14\x69\x05\x12\xe4\x02\xbf\x1e\xcd\x8c\x3f\xde\x7b\xf5\xdc\x3d\xb3\x44\x6c\x36\x6d\xbb\xdb\xae\x72\x7d\xbd\x2a\x7b\x3f\x3e\x7f\x7c\xf8\xf0\x2a\xde\xc4\xf7\xf1\xf0\x3a\xbe\xfa\x36\x1e\x4e\x6f\x7f\x7c\x7c\xfb\xcb\xcf\x8f\x3f\xc5\xaf\x7f\xc7\xe3\x1f\xbf\xc7\xbb\x3f\x3f\x7d\xfe\x27\xde\x7c\xf3\xc3\x77\xa7\x77\x9f\x7e\x7b\x7e\xfa\x1c\x8f\x4f\xcf\x4f\x1f\xfe\x7a\x8a\x87\xaf\x5f\x9f\x5e\x6d\xe6\x37\xb6\xed\x54\x4b\xe1\x47\xb4\x47\x44\xb4\x77\xe7\xde\xe5\x65\x2d\xa3\x89\xb8\x7c\x3f\x6e\x5a\xdb\x7f\xce\xc3\x5a\x4a\xb4\xe7\x85\xc3\xf9\x27\x2e\x6d\xfa\x7a\xe7\x64\x64\x74\x19\xf7\x2f\x97\x5d\x5f\x45\x2b\xb2\x8f\xb6\xae\xab\xa0\xcd\xcb\x54\x51\x92\x46\x67\x4c\x85\xb9\x93\x68\x63\x75\xe1\x5e\xfc\x32\xda\xe9\x9c\x3b\xf6\x32\xd7\x97\xb9\x5c\xe6\xc1\xda\x49\xf0\xfa\xa5\x19\x6a\xfd\x68\xdb\x6c\xe4\x1a\x7d\x6d\xc6\x7e\x3b\xbb\xce\xc1\x7d\xa4\x86\x88\xb2\x12\x45\x92\xf1\xe8\xf2\x34\x83\x75\x9b\x47\xb3\xbc\xf9\x6e\xd6\x33\x7d\xe3\x16\xe8\x8d\x91\x1d\xa1\xeb\xba\xb3\xdd\x9b\x96\xa9\x21\xa3\x9d\xc7\x30\x51\x5f\x96\x5b\xe2\x6e\xbe\xdf\xc5\x89\x95\x0f\x52\xbc\xc0\x83\x45\x5a\x09\x72\x20\x88\x84\xd0\xab\x06\xeb\x41\x6e\x7a\x0c\x6e\xab\x79\xbe\xda\x71\x1b\x20\x23\x6e\xe8\x9a\x0a\x4a\xa4\x9d\x8e\x28\x6a\x94\x8c\x6e\x50\x23\xa8\x87\x89\x45\x1c\xcb\x06\x25\x8c\x62\xd9\x39\x09\x67\x7a\xe8\x17\x75\x2f\xab\x63\x76\xc3\x8a\xa3\x1e\x20\x1c\x21\x10\x4f\x39\x5a\xbc\x8e\x49\x92\xc2\x1e\x20\xe6\xf1\x92\x78\xbc\xb3\xce\x82\xda\x46\x0f\x9c\xf6\xc9\x4e\xd4\xa7\xe5\x24\x20\xc6\xae\x23\x77\xa0\xd8\xc9\xd8\xac\xd2\x45\x7f\x4f\x92\x3e\xf0\x4e\x1f\x73\xbf\xe1\x25\x01\x55\xec\x19\x3f\x19\x78\xea\x9c\xa5\xab\xc5\x42\x17\x2b\xdb\x1a\x7f\x8d\x24\x82\x29\x87\x13\x01\xe6\x86\xfe\x25\xc5\x2b\xb6\xe0\x2e\x8d\x67\x19\xdd\x40\xa7\x16\x82\x4e\xfb\x26\x75\xee\xdf\xc0\x81\x08\x44\x58\x88\x6d\xa7\x4c\x6a\x5a\x72\xae\xb6\xef\x24\xab\x0d\x0a\x18\x38\xc1\xe5\x0f\x64\xc8\x16\x2d\x95\x41\xf7\xfd\xfb\xf7\x09\xbb\x7d\x51\x35\xbd\x1c\x5c\x2a\x04\x09\x9c\x9b\x51\x66\xe9\xc1\xc8\xb8\xaa\x69\x21\x99\x9b\x6c\x35\x31\x0d\x97\xce\x55\x0d\x7e\x12\xbe\xcf\x10\x81\xfa\xc2\x85\xb6\x44\x18\x15\x66\x64\x6e\xe9\xe3\xfc\x18\x51\x2d\x0c\x06\xcc\x8f\xc5\x24\x3c\x32\x5b\xf4\x21\xc1\x25\xd0\xd8\x20\x45\x29\x68\x43\xb7\xef\x6c\x77\x82\x06\xdc\x17\x21\x9c\x3c\x6c\x43\x5d\x75\xb7\x35\x1e\x61\x07\x3d\xcb\x0f\x25\x81\x9f\x19\x38\x15\xc4\xdc\x19\xcc\xa4\x71\xe3\x9a\xc4\xe8\xe8\x01\x81\x45\xd5\xc7\x51\xaf\x16\xac\x9b\x8a\x9e\x56\x20\xe6\xe0\xe0\x41\x65\x49\x8b\x8b\xca\x66\xc1\x69\xab\x8c\xeb\x74\x79\x8b\xb1\xef\x75\xb3\x36\xe8\xf2\x4e\x5b\x4f\x29\x2a\xd8\x80\x41\x6e\xe0\x90\x21\x45\xc3\x88\x24\x51\xf1\x7c\x41\x79\xcc\x95\x99\x72\xbc\x06\xb1\x4c\x1c\x27\xd6\xe4\xca\x47\xb4\x9f\xf7\xef\xc7\x81\x25\x41\x38\xfa\x46\x62\x89\x58\x87\x39\x39\xaa\xf7\x40\x70\x29\xa1\x08\x78\x64\x9e\x64\xad\x3a\x2a\x58\x48\x58\x1a\xe7\x67\xdb\x93\x64\x2c\x9b\x1b\x85\xba\xa7\xe6\x75\x35\x87\xb7\x65\xdf\x0d\xab\x4f\xb2\xaa\x64\xf5\x0c\xfd\x48\x27\xd9\x2a\xb8\x9e\x61\x62\x5f\x66\x44\x0c\xb3\x31\x5e\x3c\xb8\x01\x95\x8d\xce\x86\xb1\xd1\xb1\x7d\x71\x31\x02\x92\x45\x13\xe7\x77\x19\xc8\x6d\x64\x27\xde\x2a\xd7\x04\x09\x24\x10\x18\x66\x32\xf3\xf1\xba\xda\x00\xaa\x61\x88\x5c\xa1\xf6\x41\x59\xd2\x37\x0b\xe1\xd6\x6b\x2d\x43\x52\xfa\x8a\xe1\x3d\x23\x66\x98\x0e\x64\x60\x54\x63\xd1\x08\x73\x68\xa9\x52\x0a\x14\x93\x4a\x80\x61\x13\xf4\xb0\x49\x57\x5d\xc2\x4e\x0f\x08\x69\xaf\x10\x52\xcb\x73\x0b\x5e\x63\xee\x37\xe6\x0e\xa3\x32\x94\xd6\x83\x34\xfd\x92\x41\x1f\xdd\xdf\xb6\x9b\xab\x51\xe5\xe4\x13\x22\x3f\x08\xe1\xb4\x3f\x25\x1d\x61\xe6\x0a\x66\xf1\xd5\x92\x51\x13\x76\xb7\xe8\x92\x16\xb9\xd0\xa6\x09\x59\x47\x72\xa0\xac\x58\x8d\x0e\x36\xf0\x66\xce\x61\x42\xeb\xba\x0f\xc1\xc4\x56\x80\x6c\xf4\xdb\x75\xaa\x07\x09\x3a\x22\xc5\xac\xa3\x97\x49\x7d\xeb\x07\xce\xf3\xb2\xf1\x07\x02\x42\xab\x45\x27\xed\x54\xbb\x8c\x64\x6a\x11\x78\xdb\x15\x45\x91\x09\xda\x38\xcd\xc8\xc5\x1e\x5d\xc3\x24\xed\x96\x70\x3a\xc5\x9b\xf5\x83\x7a\x7e\x08\x61\xc7\xb6\xbd\xd6\x9e\xdb\x6a\xc3\x72\x88\x6f\x2a\x2f\xe4\xc1\xab\xad\x0f\x9d\xad\x9f\xd3\x27\xfd\x25\x43\x90\x42\x47\x86\x03\x0b\x89\x69\xfc\xf0\x2a\x64\xd5\x4d\xee\xbb\x43\xd5\x0b\x83\xe4\x03\xa4\x9e\x44\xfc\xc5\x28\x23\xd4\x6d\xfd\x96\xfc\x0d\xf7\x3d\x71\x65\x12\x56\x54\xb1\x06\xf7\x04\x03\x70\x05\x09\x4e\x43\x54\xaa\x8c\x47\xaf\x2c\x2e\xcb\x14\xae\x72\xa7\x4a\xfc\x7b\xdc\xab\x85\xae\x88\x3b\x72\x04\x20\x85\xe2\xd4\xe6\x80\xe1\x36\x14\xa1\xe4\xba\x56\xbe\x1e\xd5\x7c\x2f\x9a\xda\x16\x00\xaa\x69\x92\xf3\xac\x4d\x40\x63\x93\xa6\x8e\xf1\x79\xd6\x70\x62\x56\x83\x57\x61\xd8\x9f\xa3\xeb\x2f\x84\x40\xa4\x5c\x78\x10\x61\x88\xe8\xe0\xec\x31\xb3\x85\x24\xdd\x45\x84\x2d\x09\x57\xf9\x23\x6b\xc9\x75\x93\xb8\xdf\x3e\x61\x72\x28\x09\xcf\x4d\xee\x66\xdd\x2d\x43\xc8\xa1\x19\x3a\x7a\x5c\x95\xdc\x25\x7e\x7c\xbd\x4d\xbc\xfe\xbf\xf2\xa3\xb1\x86\x45\x26\x57\xab\x0f\x06\x76\x99\x6d\xb8\xed\x84\xae\x84\xa3\xff\xa9\xbf\x9d\xe4\xdf\xff\xf5\xe2\xdf\x00\x00\x00\xff\xff\xef\x0e\xd2\x08\xe7\x20\x00\x00")
+
+func fontsBarbwireFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBarbwireFlf,
+ "fonts/barbwire.flf",
+ )
+}
+
+func fontsBarbwireFlf() (*asset, error) {
+ bytes, err := fontsBarbwireFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/barbwire.flf", size: 8423, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBasicFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x59\x4b\x6b\xe4\x38\x10\xbe\xfb\x57\xd4\xc1\xe0\x4b\x56\x90\x61\x61\x6a\x60\x59\x1c\xba\x59\x18\x58\x58\x9f\x04\xba\x39\x1a\x4d\x66\x13\xc2\x1a\x66\x92\xc3\x5c\xfc\xdb\x97\x7a\x48\xb2\xec\xb6\xba\x33\x0b\x0b\x03\x9d\xf4\xa3\x2c\xdb\xa5\x7a\x7e\xfa\xe4\x7e\x78\x7e\x78\x77\xdf\x02\x02\xc2\xed\x7b\xf8\xe5\x16\xde\x35\xfe\xfe\xdb\xe3\x27\xf3\xf0\xfc\x00\xfe\x3b\x1c\xbe\xde\x3f\x7e\x81\xbf\xba\x3f\x9e\xef\xff\xfe\xfc\xf5\xe5\x3b\xfc\xf6\x69\x7a\x78\xee\x1f\x5f\xcc\x3f\x2f\xaf\xe6\x73\x78\x35\xf7\xaf\xbf\x37\x77\xaf\x5f\x5e\xbf\xbd\xc0\xed\xfb\x1b\xb8\xfd\xf0\xe1\xd7\xa6\x6d\xfb\xda\xbb\x6f\x82\x6f\xfb\x06\xb1\xed\x1b\x37\xb4\x7d\x03\xd0\xea\x58\x3e\xa4\x8f\xbe\x31\x93\x01\x33\x99\xb6\x6f\x46\xec\x60\xc4\x8e\xcf\xf0\xdf\x8f\x48\xc5\x60\xf0\xf4\x6a\xfb\xe6\x80\xf4\x77\xa4\x31\x44\x7a\x95\x63\x6e\xa0\x57\x45\xe1\x9d\x0c\x9a\x40\xb7\x18\xf6\xac\x43\x60\x57\x46\xf4\x68\xf4\x96\xd1\xa2\x37\xec\x28\xc5\xfb\xc8\x67\x11\xd1\xa9\x4f\x56\x15\x06\x0f\x00\xe1\xc8\xc1\x00\x08\xd1\xe5\x80\x9d\xa8\x21\x41\xec\xc7\x0e\x38\x68\x3c\xa2\x91\x3b\x61\x21\xdb\xe5\x0d\x8d\xe2\x00\x00\x78\x24\x71\xb4\x3e\xe9\x0c\x88\x07\x99\xf2\x40\x3a\xf5\x02\x44\x1c\xc0\xf9\xac\x0c\x0a\xb1\x6f\x0e\x74\x6e\xe4\x18\x75\xcb\xb4\xad\x3e\xe4\x26\x56\x0f\x8b\x29\x45\xdf\x01\x55\x00\x1b\x05\xb0\x68\xe2\x54\xf6\x98\xe6\x94\x19\xa3\x19\x23\xfa\x68\x0f\xfa\x28\xa0\x5e\x8d\x92\x2e\x43\xee\xd2\x1c\x43\x61\x7c\x59\x06\x68\xe0\x0e\x0c\xb2\xc3\x06\x8d\x86\x1b\xc9\x2c\xce\x69\x87\x23\x67\x0d\x3b\xb0\x30\x62\xbd\xae\xc4\xc5\x68\x99\xea\x38\xa4\x4a\x8a\x23\x00\x76\x28\x0c\x2a\x2c\xdb\x46\x91\xb3\x6c\x79\xee\xa1\x08\xea\x69\x25\xcb\x19\x77\xaf\xb9\x64\xc6\x61\x9b\xc6\x98\xc7\xb3\x95\xa9\x86\x74\xd5\x66\xa4\xd2\x94\xca\xe4\x5c\xc5\xee\x01\x08\x1d\xa3\x03\x22\x84\x0e\x50\xb2\x83\x69\xce\xd1\x21\x0e\x1d\xec\x57\xa6\xf4\xc5\xc4\x37\xc2\xf6\x53\x1d\x83\xf8\x99\x7a\x84\x9d\x06\x18\x63\xf0\xa6\x70\xec\xa4\x92\xd4\xb5\x27\xa4\x76\xe6\xba\xc1\x32\xc8\x2b\xd7\x18\x0b\x36\x0a\xa7\x69\xd2\x76\x9f\xe7\x39\x82\x01\x08\x18\x38\xba\x63\xd8\x01\x38\x12\x9f\x50\x1a\x13\x9e\x70\x16\x90\x7a\xc2\x4e\xe1\xca\x16\xd6\xc8\x18\xf7\x4f\x0d\xb8\x26\xfa\xe3\xa8\x0c\xf3\x3c\xcf\x64\xcd\x10\x2f\xb4\xc9\x7e\x1a\x10\xfb\x11\xa7\xc9\xbb\x8a\x85\x10\x8e\xb0\x57\x0a\x39\x20\xc8\x48\x9e\xf0\x6f\xdf\xc2\x90\x9c\xb2\xe7\x91\x50\x27\xa9\xd6\x5b\xce\x32\xa3\x8e\xd8\x60\x63\x52\x4c\x88\x49\x59\x9c\x75\xd5\xa4\x2c\x15\x26\xa7\x2c\x4e\x78\x81\xad\x3b\x31\xdc\x36\xdf\x4e\x2f\xee\x5d\x58\x81\x09\x13\x78\xdc\x04\x81\xa1\x9b\x88\x8b\x63\x86\x55\x9b\x60\x75\xb4\xfe\x04\x64\x9e\x44\x97\xb7\xe2\x4d\xac\xb1\xd3\xd3\x9a\x68\xac\xb4\x5e\x10\xa8\x0c\x5b\x10\x3f\xd3\xb4\x40\x18\x01\xda\x77\xb0\x00\xde\x0a\x1e\x4d\x51\xa3\xa4\xc9\xa1\x2c\x9a\x44\x15\x28\x74\xe8\x81\xb2\x3b\x70\xbb\x12\x10\x40\x88\x78\x54\x54\xc9\x06\x8f\x4c\x50\x9c\x0b\x5c\x27\x5e\xbb\x69\x52\x94\x9b\xe7\x39\xe2\x1d\x80\xf2\x22\xa8\xad\xe9\xcb\x6e\x5a\xb6\xa7\x54\x32\x2b\x5c\x55\xf2\x39\x78\x21\xd7\xd5\xf3\x21\x3b\xae\x17\xa2\x8f\x92\x23\x31\x60\x46\xe1\xb7\x59\x18\xdd\x2b\x25\x93\x2d\x3c\xd6\x15\x6a\xe4\x62\x97\xb3\xcb\x8c\x61\xec\x32\x63\x98\x20\x34\x44\x85\x58\x8f\xe1\x29\x85\x2a\xcd\xf3\xac\x52\x72\x7e\xd8\xa8\x29\x62\xc8\xf5\x08\xaa\xd0\xa9\xea\x14\x43\x64\xc4\x55\x0b\x67\x24\x5b\xc1\xd5\x01\x90\xa9\xa0\x5f\xc5\xeb\xbf\x96\x8d\xf8\x4c\x39\x89\x98\x24\xc4\x64\x23\x1a\x54\xee\x2a\x81\x5c\x46\x72\x53\xe0\x54\x14\xaa\x17\xc6\x5c\x16\x79\x25\x12\x29\x78\xa3\x92\x3b\x83\xfd\x89\x05\x23\xc2\x8d\x28\x44\xbc\x51\x46\x87\x18\xf9\x1f\x22\xf9\x61\x92\xeb\xfb\x0b\xb2\x5f\x26\xa2\x26\xf9\x69\xe2\x1d\xc7\x99\xf2\x31\x28\xad\x10\x19\xbf\xf3\x61\x18\x53\x3a\xe4\x5d\x3d\x20\x83\xe5\xbd\x08\x66\x11\xd9\x98\xb4\x45\x19\xe0\x94\x54\x59\x9c\x92\x56\x5e\x73\x74\x02\x5a\xba\x15\x13\xc1\x56\x93\xb6\xa2\x5f\x2e\xd1\xaf\x65\x97\x46\xfa\xe5\x2f\xa7\x5f\x7b\xe8\x24\xc0\x7c\xaa\xb3\xb2\x74\xba\xb3\xde\x64\xe9\x50\x58\xda\x39\x7c\xbb\xa5\x5e\x71\x74\x5b\x66\x3c\xd3\x7e\x99\x15\x9b\x40\x48\x9b\xc0\x29\x6d\x02\x1d\xae\x78\x5f\xb1\x09\xac\xb6\xec\x48\xed\x3e\xcf\x5d\xa5\x65\x97\xa2\x1b\xd6\xfe\x96\xae\x73\x43\x64\x74\xd9\x04\xb2\x10\xa5\xd4\xdb\xbe\x99\x37\x0b\xc9\x65\x8a\x9d\x88\xc3\xba\x96\xd0\x27\x8e\x74\x91\xc5\x45\x37\x00\xc0\x47\xfc\x58\x18\xbc\x38\x76\xab\x63\x9a\x37\x60\x27\x9f\x3a\x39\x2f\xc7\xd9\x82\x9d\x36\xdc\x7a\xb6\xe3\x83\x09\x83\xdb\xd4\xa9\x2c\x1b\xae\xd2\x89\xe7\x15\xff\x68\x92\x13\x85\xbe\xfc\x61\xc2\xb9\x45\x33\xae\xe4\x7b\x5f\x7f\x66\x2e\x98\xbe\xe2\xd6\x1d\xa2\x87\xca\xfb\x58\xd4\xd5\x28\x53\xc0\xb4\xa3\xcf\xa4\x6e\x6b\xc9\x21\x6f\xaa\xf7\xbe\x0e\x88\xb8\xb5\x04\x64\x8b\x1e\xf3\x65\x95\x98\x11\x59\x5c\x72\xde\xfd\xb0\x56\x16\xc1\xb5\x99\x67\xa4\xc3\x99\x4d\x24\x3f\x92\x91\x52\x68\xfb\xda\x03\x96\x2b\xbf\xbc\xf2\xcb\x2b\xbf\xbc\xf2\xcb\x2b\xbf\xbc\xf2\xcb\x2b\xbf\xbc\xf2\xcb\x9f\x96\x5f\x02\x2d\x0b\x7a\x36\xfb\x1c\xc9\x52\xa4\x8d\x2e\xff\xf8\x63\x32\x69\x4c\x9a\x48\x11\x27\x4c\xdf\xd0\x6e\x8e\xfb\xc6\xc6\x27\xf9\x30\xe6\x5f\x9e\xbc\x49\x21\xd0\xdf\xab\x14\x88\x4c\xfa\xbd\xaa\x78\x7c\xab\xd4\x86\xda\x8f\x32\x21\x1c\x72\xbf\x78\xdf\xc6\x27\x57\xff\xff\xd7\xc0\xbf\x01\x00\x00\xff\xff\x8d\x92\x02\x2a\x14\x1e\x00\x00")
+
+func fontsBasicFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBasicFlf,
+ "fonts/basic.flf",
+ )
+}
+
+func fontsBasicFlf() (*asset, error) {
+ bytes, err := fontsBasicFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/basic.flf", size: 7700, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBellFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x58\x7b\x6f\xe4\xb6\x11\xff\x5f\x9f\xe2\x87\x60\x01\x25\x80\x44\x9e\xbd\x97\x1e\x6e\x71\x48\x37\x0f\x5c\x7b\xed\xf9\x02\xc4\x09\x8a\x02\x44\x29\x5a\x4b\xef\x2a\xb7\x96\x0c\x49\x7b\x86\x03\xa2\x9f\xbd\x18\xbe\x44\x69\xed\xa4\x3d\xd4\xde\x95\x28\x8a\xf3\xfa\xcd\x70\x66\xb8\xb7\xc7\xdb\x4b\xb5\xc2\x9f\xf0\x35\x2e\xbe\x46\x79\x81\xcb\x75\x76\xa3\x8f\x47\x76\x7b\xbc\xcd\xde\x77\x0f\xba\x47\xad\x06\x8d\xa3\x1e\x47\xdd\x0f\x05\xee\x4f\x6d\x3d\x9e\xd4\xd8\x74\x6d\x01\xd5\xee\x70\xd7\x0c\xb5\x3e\x1e\x55\xab\xbb\xd3\x80\xfa\xa0\xda\xbd\x1e\x70\xf3\x88\xbf\xeb\x76\xc4\x07\x35\x0c\xba\x2d\x90\xe1\xb3\xfe\x3e\xea\x76\x6c\xb7\xf5\xe3\x8d\xee\x87\x7b\x55\x6b\xd6\xf5\xfb\xcf\x63\xf5\x5e\x0d\xa3\xd7\x6e\x83\x8b\x17\xfc\xe2\x82\xbf\x7e\x99\xfd\x72\x7f\xbf\xb0\x10\x5d\xdf\xec\x9b\x56\x1d\x8f\x8f\x64\xc4\xdf\xba\xe1\x70\x52\xf8\x4e\x1f\x8f\x9b\x2c\xfb\xa0\x1f\x86\x7d\xdf\x9d\xee\x87\x0d\xd4\x71\x64\x6a\xa8\x9b\xa6\x54\xfd\x98\xbd\xed\xbb\xbb\x0d\x7e\x1d\x08\xbb\xad\xaa\x07\x76\xaa\xd5\x71\xaf\xfa\x47\x56\x2b\x7c\x99\x70\xf9\x2a\xbb\x3e\xdd\xfc\xaa\xeb\x71\x83\x7f\xea\x11\xdf\xb6\xdd\x78\xd0\x3d\x3e\x74\x6d\xf9\xb6\xd9\x1f\xf5\x88\xb7\x5d\x3b\x66\x57\x7a\x18\xd4\x5e\x97\xef\x7e\xd8\xe0\xcd\x95\xea\x2f\xd6\xec\xc5\xab\xf5\xcb\xf5\x25\xbb\x5c\xaf\x5f\xad\x97\x22\xbe\xc9\x7e\x50\xa3\xde\xe0\xfa\xd4\x16\xb8\x58\xe3\x4a\xf5\xb8\x78\xfd\xfa\x25\x5e\xbc\xda\xac\x5f\x6e\xd6\x97\xf8\xcb\xd5\xcf\xd9\x8f\xfd\x5e\xb5\xcd\x6f\xd6\x79\x1b\xfc\x7c\xd0\xf8\xa5\x6d\x3e\xe9\x7e\x68\xc6\x47\x74\xb7\xf8\xde\xf1\xcb\xde\x37\xad\x1e\x36\x58\xbf\xc8\xae\x47\x35\x9e\x86\x0d\x7e\xfa\x31\xcb\xde\xe5\x9f\x34\x0e\x6a\x87\xf1\xd0\x0c\xf8\xd8\xd4\x1f\x9b\x76\x0f\xd5\x77\xa7\x76\x87\xdb\xae\x87\xc2\xc3\xa1\x39\x6a\x86\x77\xb7\x50\xed\x63\xd7\x6a\x3c\xa8\x76\x1c\x30\x76\x50\xbb\x5d\xd6\xb4\x70\xc6\xd6\x07\xd5\xab\xda\xa2\x4d\x11\xe4\xec\x2e\x9b\xdf\x34\x9a\xb1\xc0\xbe\x43\xdf\xec\x0f\x23\xd4\x41\xab\x1d\xcb\x32\x87\x5e\x56\x96\x99\x09\xde\xfc\xe2\xaf\x6a\x40\x33\xe2\x46\xeb\x16\x0a\x37\x6a\x87\x47\xad\xfa\x02\x5d\x8f\x87\x83\x1a\xff\xfc\x05\xad\x2a\x71\xa5\xfb\x46\xed\xba\x1a\xdf\xf5\xaa\xdd\x3d\xde\x9c\xea\x8f\x45\xe0\x61\x26\x76\x00\x4e\xf7\x5d\x8b\x5e\x8f\xa7\xbe\x25\xb3\xc6\x0e\xe3\x41\xe3\xfa\xd0\xf4\x1a\xea\x76\xd4\xbd\x7d\xfe\x87\xea\x09\x28\x1a\xfe\xd4\xb4\x7b\x96\x30\x20\x76\xcf\xf8\x1f\xdf\xd6\x6a\xa7\xef\x9a\x1a\xdf\x77\x77\xf7\xa7\x91\x04\x5c\xeb\xfe\x53\x53\xeb\xa1\x78\xda\x07\x30\xd9\x0a\xc0\x6a\xfb\x5f\xdc\xb6\xd9\x8a\x6f\xb3\x95\x49\xbe\xd5\x36\x5b\xe5\xf4\xa2\x28\xe8\x2d\xbd\x76\xeb\xd3\x8b\xa5\x67\xf4\xb1\x13\xa5\x29\xe9\x63\x67\x0d\x7d\x68\xb6\x74\xb3\x4e\x56\x4e\x1f\x2f\x16\x5e\x74\xf2\x4f\x2f\x24\x80\x82\x96\x70\x08\x70\xbb\x58\x48\xce\x21\x1d\x19\x07\x87\xa0\x11\x07\x84\x24\xb5\xf2\xa7\x39\xa1\xd8\x66\xe0\xdb\x8c\x38\x24\x5f\x22\xb5\x16\x81\x0c\x8d\x17\x46\x17\x54\xdb\x38\xb4\x32\x4c\xbc\x14\x56\x90\x33\x98\x2c\x26\x84\x18\x0c\x2c\x2e\x10\x65\x6e\x89\x0a\x23\xec\x2b\x0e\x03\x81\x60\xa6\xc7\xa9\x08\x80\x1b\x37\x60\x65\x59\x96\x79\x3a\x03\x54\x98\xd0\xb1\x64\xab\xc5\xd7\xaa\xee\xd5\x88\x4b\x03\xb7\xfc\x89\xf9\x67\x39\x71\x7b\x9f\x05\x82\x33\x86\xdb\xa7\x22\xb7\xe2\xe6\x41\x02\x48\x69\x31\x67\x39\xc0\x85\x05\x0f\xdc\x22\x64\x8a\x1c\x76\xc0\xab\x44\x13\x4f\xc6\xac\x40\x63\x59\x25\x57\x69\xa4\x5d\xe7\x16\x49\x29\x9d\xdb\xe1\xc0\x87\x74\x6c\x68\x82\xe6\xa5\x94\x45\x60\xfb\xbb\x04\x70\xd8\x0b\x29\xe5\x57\x33\x82\x80\x09\xed\x5a\xab\x40\xc5\xa4\x34\x01\xa5\xf3\xc1\xa4\x98\xf4\x54\xd6\xef\x65\x59\xb2\xb0\xd4\xc9\x61\x79\x8a\x34\xa1\xb4\xf2\x20\xd9\x00\xf3\x04\xc6\x13\x54\x6c\x49\xe0\x2d\xc9\x27\x4b\x24\xf7\x2e\xa9\x7c\xd4\xaf\x96\x04\x48\x4c\xff\xa6\x2c\xcb\x37\x9e\x41\xe5\x55\x3c\x93\x90\x12\xd0\x02\x93\xd8\x70\x46\x30\x8f\x92\x24\x5a\x96\x2f\x42\x40\x2e\x76\x31\xd2\xf8\x73\xa3\xa2\x2c\xd3\xc8\x78\x66\xee\x3c\x1f\x48\x78\x2f\x57\x04\x62\x05\xc0\xaf\x77\x81\x8a\x02\x21\xb7\x10\xb5\x0d\x51\x6b\x2c\x38\xa4\x64\x64\xae\xa1\x18\x32\x64\xa8\x81\x90\xd2\x8f\x08\x2b\x12\x8d\xca\x2a\x01\x4b\xec\x76\x37\xdc\x90\x9b\x30\xa4\x64\xe3\x86\x9c\xf4\xa5\xf8\x2a\x5c\xde\x21\xfe\x31\x83\x93\xc2\x56\x7a\x8c\x4b\xeb\xff\x42\x96\x6f\x10\x22\x28\xf8\x67\xb9\x47\x82\x8b\x58\x88\x02\x57\x5b\xd2\x01\x28\x5e\xe3\x1e\xb0\xd2\x58\x2a\xad\x8a\xab\x4d\x3a\x20\x95\xf9\x3c\x1b\x11\x59\xdc\x3c\x6e\x4f\x10\x56\x61\x73\x38\x8e\xa4\x24\x3f\x93\x26\x03\x55\x20\x4a\xb6\x46\x98\x4f\xb6\x5c\xd0\xcf\x99\x15\x05\x4c\xa2\x5c\x5e\x27\xcb\xa4\x99\x0a\x83\x43\x92\xc8\xc3\xc6\xf1\xf2\xa4\x41\x3a\xc3\xad\x73\x66\xb6\xc9\x45\x25\x9b\x12\x9d\x74\x7f\x7e\xa3\xf0\x49\x57\x73\x3e\xac\x08\xb3\xc9\x98\x80\x5b\x62\xa8\xad\x98\xd2\x65\x7e\xe3\x5d\x3d\xe5\xa2\x80\xd8\x02\x19\xb3\xb8\xf3\x14\xe3\x60\xf4\x64\xb5\x37\x5b\xd8\x58\xb4\x73\x82\x4f\x86\x27\x96\x27\xc4\x90\x9e\x04\x81\x24\x8e\x20\xe2\x08\xc2\x2c\x88\x9d\xaf\x62\x08\x56\x2c\xfa\xca\xcc\x46\xd6\x57\x2c\x9f\x13\xb3\x45\x82\xa1\x98\xcf\xff\x38\x32\x52\x71\x53\xa8\x07\x1d\x0b\xe9\x86\x24\x91\x55\x31\xe9\x3e\x2b\x53\x46\x99\x4f\x3b\xc3\xe7\x06\x1a\x7d\x19\xf7\x14\x79\x9a\x45\xd5\x4c\xa8\x1c\x2c\x5f\xc2\xf3\xbf\x44\xcf\x7c\xc1\x2c\x18\xc0\x02\x1c\x2e\x82\x9e\x41\xf8\x4c\xbe\xf7\xad\x9c\xa3\x44\xce\x8d\x71\x20\xac\x54\x5f\x02\x9f\x95\xef\x99\x70\xff\x60\x26\xdc\xa7\x07\x2e\x02\x57\x5b\xd7\x05\x5d\x12\x66\x5e\x23\x84\x68\xab\x58\xa2\x44\x58\x5b\xe4\x62\xf2\xbd\xc0\xd2\x1c\x44\x6a\xa4\xe4\xa8\x58\xb4\xa1\xf0\x05\x94\x36\x19\xce\xcd\x09\x1e\x41\x6c\x02\x23\x13\x56\x96\x41\x63\x6f\x27\x15\x9b\xdc\xad\xe7\xa9\x25\x0e\xda\x59\x2f\x38\x5d\xca\x32\x14\x33\x8a\x0a\xaf\x81\x08\xb9\xd8\x87\x4f\x08\xcb\xc8\x29\x69\x1b\xe3\xc5\x72\xfa\xe3\x1a\xf9\xd4\xc8\x29\x5d\xcc\x3a\x5d\x5b\x76\xc5\x59\x57\x97\x36\x39\x08\x5d\x85\x45\xa0\x4a\x0b\x02\x6d\x60\x6e\xe6\x49\x33\x90\x89\x50\x87\x0c\x4f\xeb\x90\xad\x5a\xa4\xc6\xb2\x6a\xa5\xd2\xa6\xcd\xbc\xac\x5a\xec\x09\x32\x99\x36\x94\x56\x49\x63\x9d\x14\x94\x9c\x49\xab\x9e\xb6\x6d\x92\x16\x2a\xaa\x2d\x24\xc5\x4c\x5a\x11\x4b\x5d\xe5\xb2\x84\xaf\x3d\xc9\x8d\xa7\x8a\x21\x48\x60\x67\xf6\x18\x5f\x1a\x5c\xf3\x24\xac\xf2\x29\x7a\x3c\xd0\x9b\x22\x34\x7d\x81\x9e\x47\xfa\x09\x06\x7f\xce\x3a\xaf\x54\x69\x14\xb0\x30\x10\xb3\x06\x95\x57\x7e\x60\xb5\xb0\xf8\x88\xa4\xae\x16\xa1\x39\xb7\xe0\xbc\x09\x1b\x51\xc8\x59\x5b\xe8\x4e\x32\x94\xb6\xce\x6e\x5c\x48\x99\x44\x76\xd8\x2f\xee\x54\x20\x41\xdf\x95\xb3\xaf\xa2\x6f\x6c\x70\x43\xd3\x01\x7b\xda\x03\x9f\xd1\xa6\xb6\x15\xa1\xb5\x23\x88\xa6\x6a\x63\x9e\xc1\x2a\xf5\x3d\x3b\x6f\x94\xcc\xef\x44\x9a\x45\xa9\xf0\x71\x61\x57\xcf\xc8\x4c\xe8\x7e\xc5\x9c\x6c\x0a\x35\x36\xc5\x5a\xec\x5b\xdc\x29\xc1\xc6\x42\x2c\x4c\x66\x76\x34\x63\x8b\x03\x8a\xf1\xad\x2b\x5f\x1e\xcd\xe6\xc2\xa6\xfa\xe4\x05\xb0\x55\xac\x49\x73\xdb\x98\x4f\x10\x5c\x46\xc7\xcd\xee\x62\xca\x75\xab\x54\xb1\xc2\x57\x21\x93\x54\x1e\x9f\x17\x62\x5a\x98\x2b\x36\x6b\x4a\x6c\x4c\x55\xf1\x50\x22\xf8\xf2\xd0\x8a\x29\xe5\x82\xce\xf3\xbe\xce\x19\x2f\x05\xf8\x97\xef\xe1\x05\x87\xe0\x69\xb6\x4b\x94\x94\x94\xc5\xed\x22\x77\x14\xa5\x9a\xe4\xd1\x14\xe7\xe8\x45\xbb\xdc\x76\x71\x39\xeb\x59\x5f\xd9\x2d\x33\x97\x16\x92\x65\x3c\xff\x3a\xeb\xb8\x47\xbd\x9a\x4e\x52\xfe\xc7\x03\x39\x95\x09\xb7\xa9\x5c\x83\xb8\x68\x3e\xdd\x4f\x29\xdb\xcc\x46\xba\x55\x1c\x74\xe8\xb5\x1a\x49\x1e\x7f\x46\xc1\xfc\xf3\xef\x65\xb1\xf8\xff\x3e\xfc\x27\x00\x00\xff\xff\xd8\x43\x60\x70\xb3\x15\x00\x00")
+
+func fontsBellFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBellFlf,
+ "fonts/bell.flf",
+ )
+}
+
+func fontsBellFlf() (*asset, error) {
+ bytes, err := fontsBellFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/bell.flf", size: 5555, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBigFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x7c\x6b\x73\xe2\xb8\xd2\xff\x7b\x3e\x45\xbf\x48\xd5\x42\x15\x13\x83\x73\xff\xd7\x4c\x0a\x07\x9c\xc4\x67\x00\x73\xb8\x64\x77\xfe\xe5\x5a\xad\x93\x38\x09\x67\xb9\xe4\x01\x32\xb3\x39\xe5\x0f\xff\x94\xee\x92\x2d\x19\x13\xf2\xa4\x66\x40\x18\xac\x6e\xa9\xbb\x7f\xdd\x2d\xb5\xfc\x34\x7b\x72\xe3\x03\x38\x87\x53\x38\xb9\x80\xe6\x09\x34\x1b\xd0\x00\xf7\xf8\xf8\xf4\xa8\x72\x35\x7d\x86\xfb\x77\xb8\x99\x25\x8b\x05\xb4\x5f\xe2\xd7\xd7\x64\x36\x83\x63\xe7\xe2\x08\xbe\x7c\x81\xfb\x78\x9d\x3c\xc2\x72\x01\xa3\x4d\xbc\x78\x8c\x57\x8f\x95\x60\xf1\x30\x7b\x7b\x4c\xd6\x10\x8c\x42\xe8\xc6\x9b\xe9\xe2\x4b\xb3\x72\xb3\x4a\x92\xbf\xe1\xe1\x25\x5e\xc5\x0f\x9b\x64\xb5\xc6\x3d\x5e\xad\xde\x1e\x12\xf8\x57\xfc\x77\xf2\x2b\x7e\x87\xaf\xaf\xf7\xff\xa1\xcd\xd6\x22\x79\x9b\xc7\x8b\xc5\xe1\xdb\xaf\x78\x93\xac\x66\xcb\xe5\xe1\x43\x7c\x59\x79\x9a\x3e\xcf\x92\x0d\xac\x92\x59\x12\xaf\x13\x70\x0f\x5d\x4c\xbf\xbf\xfc\x99\xcc\xef\x93\x15\x34\x2f\x2e\x4e\x2b\x83\x64\x35\x9f\xae\xd7\xd3\xe5\x02\xa6\x6b\x78\x49\x56\xc9\xfd\x3b\x3c\x4f\x7f\x26\x0b\xd8\x2c\x61\xbe\x7c\x9c\x3e\xbd\xc3\xe6\x65\xba\x86\xa7\xe5\x62\x53\x87\x78\x0d\xb3\xe5\xe2\x19\xbf\x6f\x5e\x92\x0a\xf9\xc1\x34\x59\xfd\xb6\x86\x45\x3c\x4f\x70\x1f\xaf\xb3\xf8\x81\x0e\x30\x86\x87\xe5\x7c\x9e\x2c\x36\x30\x9b\x2e\x92\xc3\x4a\xa5\x47\x7f\xfd\x88\xc7\x32\x88\xdf\x66\x70\xf5\xb6\xda\x2c\x17\xf0\x75\xbd\x9c\xbd\x6d\xa6\xcb\x45\x2b\x89\x57\x9b\x97\xd9\x74\xf1\xf7\xe1\x22\xd9\x5c\x42\xd3\x75\x2e\x4e\x31\x23\x53\x3a\x45\xb0\x48\x7e\xc1\x6b\xbc\x8a\xe7\xc9\x26\x59\x55\xd6\x6f\xaf\xaf\xcb\xd5\x86\x76\x78\x1d\xdc\xe0\xd1\xc6\x8b\x47\xdc\xfc\x7d\xba\x38\x04\xe8\xc5\xef\x10\xcf\xd6\x4b\xb8\x4f\x60\x3d\x9b\x3e\xbf\x6c\x66\xef\x30\xe7\x5c\x3c\x2d\x57\x70\x9f\x6c\x36\xc9\x0a\xde\xd6\x49\x65\xf9\x44\xba\x7f\x7a\x9b\xcd\xbe\xfc\x9a\x3e\x6e\x5e\x9c\xbf\x93\xd5\xc2\x59\xcf\xdf\xd6\x2f\x10\xcf\x36\xc9\x6a\x11\x6f\xa6\x3f\x93\x75\x1d\xee\xdf\x36\xf0\x98\x3c\xc5\x6f\xb3\x0d\x2c\xdf\x36\xaf\x6f\x1b\x3c\xf2\x7e\x38\xc6\x02\x5b\x3c\x27\x8f\x87\x15\x38\x68\x15\xfd\x6f\x55\x00\x10\xb4\x2a\x90\x42\x9a\x7d\x45\xf8\xb5\x8a\x6a\xf8\x37\x00\xec\x95\xde\x40\x6e\xa9\x42\x0a\xe4\xcb\x3b\xb8\xa3\x5f\x1f\x80\xf9\x1d\x94\x77\xda\x40\xe4\x1f\xb9\x8a\x52\x48\x53\x48\x29\x17\xf8\x3a\xfe\x9f\x16\x7f\x83\x99\x4b\x51\x2a\xbb\xd5\x68\x28\x84\x10\xbd\x9a\x42\x8a\xdf\x1d\x40\x64\x38\x11\x42\x10\x91\x11\x00\x38\xe4\x7b\x94\x9a\x39\xc5\x4c\x22\x44\xe7\x01\x1c\xfa\x63\xc0\x0d\xfa\x33\xdc\x20\x2d\xdc\x20\x7c\x3a\xc8\x91\x73\xa6\x33\xd5\x52\xf8\xa3\xcc\x21\x3e\x07\x55\x40\x50\xe3\x3d\x21\x88\x9c\x88\x88\xa1\x8a\x2e\x01\xbe\xe2\xab\x11\x42\xc8\x89\x9c\x6c\x0f\x1a\xa7\x64\x40\x98\x72\x4a\xb9\x3b\xc8\xbd\x6a\x52\xa4\xe3\x62\x83\x62\x13\x64\x7c\x83\x08\x45\x8c\x1a\xbe\x11\xd1\x39\x8d\x20\xe2\x53\x6b\x7b\xc3\x73\xa1\xdc\xc8\xe4\xce\x86\x19\xa5\x90\x3a\xb4\x8b\x08\xfe\x82\xdf\xe8\x94\xa6\x88\xfe\x2c\xa5\xac\xd5\xe1\x90\x91\x89\x9c\x14\xa5\x91\xa3\xc9\x58\x6b\x67\x67\x5c\x55\x2f\xa1\x41\x8a\xfa\xf0\xdf\x1d\xe8\x32\xca\x4a\xcb\xfc\x9a\x9f\x6c\x83\x78\x65\x13\x91\x3f\xca\x04\xf9\x4b\xd9\x0f\x14\xe2\x07\xf9\xdb\xca\x73\x62\x30\x52\x10\x12\x06\xd8\xa6\xb9\xc0\x35\xb7\x70\x2e\x10\x93\x3c\x55\x51\xae\x20\x02\x32\x64\x0b\x31\x2d\x20\x4a\x6b\xef\x10\x31\x83\xb1\x2b\x10\xc3\x20\xe5\x5e\x76\x23\x65\x24\x45\x8c\x0f\x80\x83\x1a\xbd\x41\x0c\xd0\xc1\x1d\xf3\x09\x4f\x05\x65\xd9\xe0\x72\xe1\x3d\x89\xae\x10\xaa\x71\xe2\x08\xbe\x72\xf9\xd5\x18\x26\x6e\x19\x92\xd0\x3b\x0a\x5d\x4a\x93\x73\x23\x95\x10\xf8\x0f\x74\x85\x34\x8a\x5f\x2a\x10\xf0\x01\xa5\xb4\x37\x9d\xfb\xd2\x9c\x02\xb7\x63\x5d\x15\x58\x87\xf0\x9b\x90\x70\x95\x4f\xc7\x56\x69\x6a\x3a\x0e\x4c\x1e\x70\x20\x54\x4e\x12\x92\x4a\x97\xd7\xba\xbc\xe6\x9b\xf4\x4e\x70\x75\x09\x4c\x48\xe5\x39\x2d\xee\x30\x42\xa8\xce\x79\x97\xd6\x82\x9c\xad\x28\xa1\x5a\xe2\xc1\x36\xdb\x2c\xba\xc1\x08\x2b\xcc\x94\x99\x21\x33\xc6\xbe\xc2\x57\x60\x08\xca\x94\x57\x42\x75\xd6\xe3\x8a\x6b\x66\x30\xb2\x42\x54\xb1\x74\xb8\x07\xc3\x0c\xe8\x9c\x5c\xc2\xa5\xc2\xa9\x36\x81\x1a\x67\x06\x63\x86\xac\x31\x0b\xeb\xc0\x52\x02\x8b\x31\xeb\x1c\x0a\xd3\x26\x52\xe6\x5d\x13\x37\xfd\x97\x40\xac\xaa\x40\x2a\x22\x76\x36\xe6\x28\x6b\x3a\x19\x02\xfc\x1b\x27\x92\x1f\x1c\xdc\x87\x54\x6e\x31\x1d\x0e\x65\x24\x52\x00\x56\x11\x51\x76\x46\x73\xb0\x04\x0a\xd2\x72\xc3\x06\xa9\xf1\x69\x59\x63\x17\xc2\x65\x0c\xf1\x09\x38\x10\x60\xa5\x34\xc5\x6f\xa3\x42\x45\x90\xb0\xc4\x59\x55\xbc\x82\xe2\x16\x14\xbf\x80\x52\xc9\xae\x3e\xc3\xc6\x8e\x91\xe8\x58\x43\x3c\x71\x35\xcd\x72\xbc\x45\x75\x77\xef\x98\x77\x41\x14\x70\x3b\x4c\x19\xe7\x18\x38\x39\xe2\x04\x32\x53\x51\x66\x8e\x89\x3a\xe7\x27\x56\xcc\x26\x85\xf2\xec\x74\x63\x8e\xd3\x12\xc2\xcb\x46\x46\xc2\x27\x89\x96\x12\x41\x65\x78\xcd\xe1\x20\xe7\x94\xfc\xa5\x90\x66\x9a\x08\x0c\xfc\x1b\xec\xcd\x30\x05\x04\xff\x70\xc8\xc8\xc2\x55\x1e\x2f\x02\x83\xc0\x94\x47\x8a\x38\x4c\x54\x2c\x4c\xc7\x08\x24\x2e\xaa\xc2\xb5\x35\x77\x52\x2b\x29\x67\x88\x1c\x2e\x8e\x08\x2b\x03\x1b\x6f\xe4\xe4\x6d\xa2\x84\x90\xa4\xf0\x23\x31\x77\x10\xf1\xd6\x21\x08\x34\x8b\x40\xf4\x19\x15\x09\x09\xa9\xee\xaf\xac\xc9\x96\x11\x92\x05\x0b\x90\x02\x5c\xac\x8b\x0f\x58\xd6\xc7\x38\xd6\xb1\xf6\x23\x1c\x03\x08\x8e\x23\xa1\x60\x59\x10\x2f\x89\x05\x55\x31\x8e\x48\x8b\xd8\x54\x14\x2f\x03\x8b\x6a\x28\xa9\xc5\x92\xb0\xa5\x8d\xd2\x6c\xd6\x94\xf5\x71\x36\xb0\xd9\x57\x3b\x10\xb3\x3c\x62\xc6\xc4\x3b\x8a\x58\x26\xa2\x56\xc2\xee\x8e\xb0\xf5\x88\x58\x81\x7c\x23\x3a\x8b\xb2\xa1\xa2\xc1\x79\x72\x42\x59\x62\x39\x82\x39\xa2\x39\xc2\x79\xe2\x06\x06\xcc\x17\x38\x23\x82\x03\x41\xfa\x8e\xd3\xbc\xe4\xb1\x9b\xc3\x91\x0b\xc7\x07\x9a\x5e\xe9\x96\xcb\x46\xa6\x0c\x4a\x8e\x07\x29\x43\x01\x39\x8a\x5d\x85\x4f\xfe\x78\x42\xc1\x52\xc6\x03\x63\xca\xc8\x73\xb7\x62\x87\xa0\x78\x5a\xa1\x3c\xe6\x77\x81\xb3\xa2\x33\x65\xc8\x52\x8a\x42\x7c\x42\x6e\x52\x60\x91\x90\x94\x7d\x0e\x41\xf1\x78\xc2\xdf\x99\xde\x95\x48\x45\xe3\x08\xe8\x92\x45\xea\x44\xf4\x32\x5b\x57\x31\xbe\xe9\x49\x6b\x7e\xd2\xcb\x36\x0f\xec\x81\x7b\x4b\x4f\x1a\x80\x72\xb5\x6d\xe1\x27\x3b\x31\x14\xb1\x40\x00\x16\x77\x29\x55\xc5\xbc\xeb\x45\x62\xe6\x17\x19\xae\xeb\xc9\xa9\x92\x4b\xca\x78\xf5\x70\x4b\x72\x0a\xd9\x30\x5f\xc5\x53\x81\xa6\x02\x4b\x6d\x09\x3e\xa8\x01\x09\x17\xb1\x40\xad\x0f\x0c\xb5\x98\x33\x88\xb8\x2f\x71\xb6\x72\x26\xef\x4a\x55\x13\xc8\x9a\x8a\xba\x2e\xa0\x29\xe2\xc7\xa4\x28\xa6\xc0\x11\x6b\x1c\x58\x10\xbb\x49\x51\x89\x5e\xd2\x42\xb5\x90\xf9\x6d\x7e\x8d\x99\xdf\xa8\x29\x26\x93\x95\xc8\x99\xd9\x67\x9b\x91\x3a\xdc\x48\xd5\x21\x88\x11\xb0\x46\x36\x72\x04\x96\x3d\x15\xc7\x89\x59\x76\xb7\xb2\x9e\x9f\x04\xfe\x09\x11\xb1\xa8\x13\xf9\x57\x66\x01\x4d\x9f\xd0\x4c\x44\x98\xef\xd3\x26\x7e\x04\x7b\x48\xcb\xa2\x4f\xc5\x2b\x25\x5b\x8d\xb8\x14\x87\x22\xdc\x3a\xd4\xe3\x43\x19\x1e\xee\xaf\xf1\x6a\x3a\x92\x32\xe4\xcc\x08\x9e\xf3\xc7\xd8\x93\x76\x28\x19\x29\x80\x19\xf5\x9d\x41\x02\xc7\x2a\xbe\xdd\x40\x8c\xcd\x68\xcc\x08\xcc\x0e\x11\x90\x86\x0e\xb8\xa7\xb4\x34\x1a\x20\x35\x94\x33\x2d\xce\x6e\x05\x3a\xbd\xc3\x6d\x11\x4d\xb4\x65\x91\x2c\x77\x5d\xe9\x56\xeb\x59\xeb\x5c\xeb\x3f\x43\xc2\x14\x00\xe6\xa5\x8a\x90\xec\x9c\x75\x7c\xc9\x40\xc0\xc1\x5d\xda\x40\xe0\x63\x73\x5a\x80\xb0\x06\x35\x41\x2c\x18\x51\x57\xf5\x1c\x64\x97\xb2\xbe\x0c\x28\xb6\xb5\x1c\x19\x24\x29\xd7\xf5\xe5\xc0\xed\xb8\x96\xc1\x38\xd3\xf2\x9e\xec\x19\x22\x13\x27\xda\x32\x1f\x19\x53\xe4\xa4\x34\x60\x62\x52\xb4\xed\x11\x5a\xf7\x0a\x91\xdc\xc6\xab\xa2\x1a\xc2\xf0\x43\x7f\xe0\xa8\x4b\x6e\x48\x5b\x71\x53\x17\xdc\x32\xeb\x6d\x5a\x5b\x13\x29\xeb\xbd\x65\xdd\xe1\x28\xbb\xaf\xa1\x74\xc8\x5c\xd9\x9e\x1b\x25\xf9\x0e\xf7\x0f\xd8\x0c\x1d\x7e\x1c\xeb\x4d\x1d\xee\x07\x3f\xe6\xcd\x26\xee\x28\xd2\xaf\x62\x09\x54\x5e\x4b\x99\xf3\x40\x69\xae\xc3\xe6\x69\x03\xa0\x1f\x7e\xb9\x1a\xfa\xde\x77\x18\x0d\xbc\xb6\xbf\x7d\x67\xbc\x79\xda\x04\x08\xfa\x77\xfe\x70\xec\x77\xc0\xff\xa3\xdd\xf5\x7a\xde\x38\x08\xfb\xd0\xf3\x86\xdf\xf5\x00\xa7\x4c\x94\xd0\x3c\x75\x01\xda\x7e\x7f\x0c\xa3\xe0\xa6\xaf\x63\x0e\x5f\xab\xe6\xf6\xc5\x77\xaa\x95\x30\x17\x80\xc6\xf8\xda\x66\x35\xed\xf7\x08\x60\x10\x4e\xfa\x1d\xa5\x63\xb9\xb7\x4c\xf6\x51\x11\xb3\x0e\xba\x96\xc7\x5d\x1a\xa2\x6b\x9d\x82\xb4\x58\xb5\xa8\xa2\x7a\x6e\xc9\x2b\x8f\xb5\xcd\xd3\x63\x80\xf6\x64\x38\xf4\xfb\xed\x1f\xda\xa0\x88\xf5\xd1\x3d\x6b\x82\x1e\xc0\x20\x4e\x6a\x14\x33\x53\xfc\x2d\x31\x52\xc7\xa2\x0a\xcd\xd3\x13\x80\x1f\x7e\x9f\x77\xcf\x9c\x10\x9b\x92\x48\xe4\xf0\x88\x38\x22\x91\x1d\x01\x5f\x74\x51\xda\x65\x92\xe0\xe6\xe9\x29\xc0\xd5\x30\xfc\xee\xf7\xe1\xca\x1b\x16\x44\xae\xc6\xeb\xb8\x83\x33\x80\x91\xdf\x26\x7a\x22\xa6\x84\x31\x8c\x1c\x20\x52\x75\x78\xba\x1a\x41\xc4\x80\x94\x24\xf1\x44\x9d\x34\x17\xa7\xcb\xf9\x1c\xa0\x13\x78\xfe\xd0\x1f\x05\x23\x8b\xd5\x1d\x80\xcc\xfc\x8a\x5a\xc6\xa9\xbe\x00\x68\x87\x83\x1f\xc3\xe0\xe6\x76\xac\x32\xcf\x32\x4f\x01\xb6\x6c\x45\x4e\x20\x2e\x95\x66\x0a\xdc\x50\xc5\x02\x1f\x5f\x07\x65\xca\xc5\x2f\xe0\x3b\xc9\x92\x51\x0a\xd2\xb9\xb3\xbf\xac\x83\xe7\xcc\x9d\x35\x00\xae\xfd\x5e\xd0\x0f\xfa\x3e\x84\xc3\x4e\xd0\xf7\xba\x10\xf4\x3b\x41\xdb\x1b\x87\xc3\xf2\x88\xa8\x2d\x62\x17\x6c\xfe\x37\xcf\x9a\x00\x5d\xff\x7a\xfc\x65\x10\x06\xfd\x71\xd0\xbf\x81\x4e\x38\xb9\xea\xfa\xe0\xf5\x6f\xba\x3e\xfc\x7b\x12\x8e\x35\x34\x10\xfe\x9c\x3a\x72\xe1\xd1\xc5\x4e\x9d\xb2\x57\x27\x77\xeb\xac\x6b\x15\xcd\x33\x17\x48\x29\x8f\x66\x57\xea\xdc\xb4\x0a\x76\x5d\xd5\x65\xe5\xc2\xca\x82\xe6\xd9\x11\xc0\x28\xbc\x1e\xc3\xed\x8f\xc1\xad\xdf\xb7\xc5\x3d\xfa\xd2\x43\x6e\xfa\x0a\x27\xf2\x18\x60\xe8\xdf\x04\xa3\xb1\x3f\xf4\x3b\x3b\xe9\x15\xdb\x00\x13\x7a\xc5\xb3\x05\xa1\x57\x7c\x3b\x4c\xea\x15\x5d\xff\x8e\xca\xeb\xd5\x09\x40\xcf\x6b\x0f\xc3\xfe\xee\x85\x1a\x65\xcb\x37\x9a\x67\xa7\x00\x1d\xff\x66\xe8\xfb\x62\xf8\xd2\xbf\x09\x67\x2b\x7d\xad\x23\xa7\x35\xd3\xc8\x62\xc2\xd9\x19\xc0\xa0\x3b\x19\x7d\xe9\x05\xfd\xc9\x48\x99\x5c\x50\x01\xbf\x65\x29\x7f\x31\x8b\xd5\x20\xc2\x73\x80\xd1\x64\xe0\x0f\x47\xed\x61\x30\x18\xc3\xf8\xf7\x50\x5f\x4c\xab\xb5\x4c\xf1\x6b\x71\x6c\xd7\x3c\xbb\xc8\xf4\x7a\x3b\xf4\x7d\x35\x2e\x46\xbc\x3a\x2b\x93\x3e\x6d\xe9\xf7\xbc\x01\xe0\xb5\x27\x63\x1f\xbc\x36\xf6\xb7\x15\x16\x37\x3b\xf4\xf6\xfc\xf2\x58\x6e\x91\xac\x79\xde\x04\xe8\x05\xed\x61\x98\x73\x6b\xaa\x51\x14\x45\x38\x38\x9b\xad\x2b\x39\x24\x68\xd9\x6c\xf3\xdc\x05\x18\x04\xdd\xf6\x30\xfc\x5d\x51\x09\x65\xdb\x80\x1a\x31\x55\x0c\x5a\x41\xc2\x74\x43\xb4\x89\x35\xc8\x36\xa9\x88\x2b\x72\x6d\xe7\x47\x78\x4c\x9d\x4e\xd7\x87\x4e\x38\x56\x07\x6c\x2c\x46\x30\x4c\x0a\x76\xf7\x7e\x27\xe8\x76\xbd\xcc\xdd\xf9\x57\xd2\x5f\x4d\xd4\x3e\xe0\xbb\x4f\x74\x69\x87\x7d\x9f\xff\xce\xc9\xbb\x57\x2b\x0f\xa7\xd8\x5c\x47\xed\x49\xb7\xc0\x0f\x94\x09\x64\x4b\xfb\x81\xf3\x33\x00\xe2\x11\x4b\x3a\x02\x09\x69\x91\x5e\x16\x21\x0b\x23\x64\x69\x04\x2f\x8e\x28\x48\x9d\x9b\xe7\xe7\x00\x77\x93\xee\x8d\x37\x84\xeb\xa1\x47\x23\x8b\xb0\x8f\x09\x7b\xc3\xb1\x3f\x14\x55\x8a\x2c\xec\x82\x54\x96\xd7\xd0\x65\x2f\xe0\x15\x16\x0e\xf9\x96\x47\x98\x4e\xca\xeb\x29\x69\xa2\xa4\xc5\x95\x59\x05\xa2\x9c\x5c\x98\x39\xb9\xf5\xba\xd7\x0a\x1b\x2a\x17\x82\x09\x8e\x15\xb4\xc8\xa8\x26\x27\x40\xd4\x87\x38\xd9\x80\x33\xab\xc0\x17\x8d\x3c\x79\x82\x19\x7c\x2a\x46\xa2\x78\x42\x6c\xe7\x63\x0c\x51\xca\x8d\x30\x94\xa8\x33\x82\xb4\x39\xd1\x67\x05\x6c\xf3\x92\xf3\x24\x84\x39\x35\x59\xf8\xf7\xc4\x1f\x65\x62\x03\x76\x93\x48\x5f\x15\x39\x00\x94\x5c\xd0\x6e\x5e\xb8\x00\x5d\x6f\x1c\xf4\xa1\xed\x0d\x82\xb1\xd7\x85\xae\x3f\x1e\xfb\x43\xf0\xe0\xf7\x60\x7c\x0b\x37\x43\xef\xce\xe7\x11\xa7\xb8\x19\xbb\x43\x99\x0b\x7c\x42\xd2\xdc\xbc\x38\x2a\xe6\x83\xa0\x2f\x4f\x44\x24\x6d\xe4\x7c\x36\x1f\xc7\xc5\x7c\xb4\x83\x61\x7b\xd2\xbb\xee\xfa\x7f\x50\xa2\x8e\x20\x9a\x3a\x28\x4a\x3f\x99\x99\x93\x62\x66\xc6\x41\xb7\x43\x27\xc5\x89\x1c\x51\x65\xe1\x44\x9f\x3e\x29\xa7\xc5\x7c\xa8\x29\xc4\xff\xf1\xea\x4a\xf3\xe2\xac\x98\x97\x21\x86\x53\xef\x2a\xbc\xe3\xda\x22\x3b\xa9\x2e\x6b\x9f\x3d\x31\xe7\x36\x66\x18\x75\x75\x7f\x9d\x92\x95\x35\x42\xec\x63\xaa\xc6\xab\x8e\x52\x2d\xc4\xb8\x11\x39\x34\xe1\xc8\x50\x39\x92\xe3\x4c\x70\x77\x61\xe1\xae\xcd\x74\x59\x7a\x5e\x5b\xa9\xd1\x0e\xe5\x5c\x35\xad\x92\x8e\x70\xe0\x36\x1a\x16\x0e\xfc\x0c\xba\x88\x39\xc0\xf9\x4b\xae\x2c\x15\xb4\xc2\xac\xed\xd1\xa5\xdb\x68\x16\xd3\x95\x68\xc2\x3d\x3b\x76\x98\x9f\x40\xd7\x86\xa6\xbe\x09\x3d\x08\x78\x10\x1f\xe2\x40\x94\xee\x4f\xdc\x06\xa1\x7e\xde\x4a\x8d\x2b\x8a\xfb\xd0\xb6\xc1\x66\xa0\x0b\x5a\x96\xab\xb0\xca\x17\xe6\x18\xb9\xef\xe2\xe7\x04\x2c\x0b\xd6\x6e\xc3\x86\x88\x41\x46\xb0\x5c\x9b\x79\x68\xb6\x2b\x1d\x1b\xe2\x05\x06\x41\x3a\x7c\x0b\x1f\x45\xe9\x87\x88\xd9\x20\x2d\x28\x16\x1c\x5f\x5b\x26\x04\x65\x0c\x90\x69\x11\xb2\xb6\x50\xd0\x6d\xd8\x10\xcc\x1f\xdf\x56\x04\x80\x89\x3e\x65\xe1\x2b\x4d\x03\x45\x51\x03\x46\x2d\x65\x33\x55\xec\x88\x9b\x6a\x90\xf2\x71\xa0\xdb\xb0\x41\x55\x3f\xe3\xe9\x88\xa3\xa3\x36\x13\x39\x05\x65\x6c\xe5\x8a\xd7\xdc\xa6\x0d\xa0\x42\x1b\x40\xd1\xd8\xa7\xb5\xdf\x92\xbe\xdb\xb4\x01\x54\x68\x03\x28\xb9\x13\xb2\x17\x5d\x1b\x40\x85\x5b\x00\x0a\x45\xe9\xfe\xc4\x6d\x00\x15\x16\x09\xf9\x13\x06\x6d\x03\xa7\xb0\x9c\x7d\xed\x45\xfb\x04\xa0\x37\xe9\x8e\x83\x41\x17\xe7\x93\xda\x1a\x2e\xff\x29\x59\xda\x26\xeb\xda\xec\x70\x56\xc4\x0f\x66\x19\xea\x7e\xdc\xa6\x0d\x9a\xd8\x68\x46\xe3\x61\xf8\xdd\xcf\x3b\x75\x47\x6c\x84\x3b\x22\x3b\x76\x44\x05\xa9\xe3\x88\x1a\x16\xa7\xb8\xf2\xce\x6d\xda\xe0\x6a\x52\xc2\xa9\x7f\x7c\xd7\xca\x6d\xda\xa0\x6a\x52\xc2\xa9\xef\x43\xd7\x86\x4d\x93\xb2\x4e\x7d\x0f\xe2\xae\x0d\xa0\x26\x25\x9d\xfa\x3e\xb4\x6d\x20\xf5\xc3\x32\xe1\x88\x4c\xb8\x7d\x3f\x5f\xf1\x4e\xfa\xe9\xa4\x0c\x5d\x1b\x48\x8d\x6f\xc3\x61\x3f\x5b\x74\x5d\xbe\x46\x78\x5b\x61\xb0\xeb\x0a\x80\x1a\xf5\xbc\xae\x20\x3b\xba\xf5\x86\x03\x18\x55\x3e\x7d\x13\xd1\x75\x8f\x8d\x04\xb3\xb9\xb7\xc1\xf9\xec\xb1\x5b\xeb\xba\x27\x45\x54\x8b\x5c\xcf\x5e\x54\x4f\x8b\xa8\x6e\x33\xa2\xfd\x48\x9f\x15\x91\x2e\x72\x3b\x7b\x51\x3d\x2f\xa2\xba\x6d\xdb\x6d\x2f\xca\x17\x45\x94\x33\x19\xb2\x90\x72\xb5\x5a\xab\xed\x3d\xe8\xa3\x86\x99\xb4\x6f\x0f\xff\x38\x45\xc5\x59\xfd\x05\xa2\xf4\x11\xd3\x55\xca\x1f\xeb\xdb\x37\x91\xdd\xa3\xa6\x91\x87\x7c\xd6\xab\xdd\xdd\xaa\x94\x2c\x0a\xad\x89\x15\x0d\x4e\xcf\x35\xd2\x33\xe5\xb8\xc2\x88\xb3\xd4\x4a\x17\x7a\xba\x47\x66\x90\x32\x65\xb6\xc2\x78\xf7\xa0\x66\x46\x28\x6b\x3e\x2b\x8c\x76\x0f\x92\x66\x78\x2a\x97\xc5\x9a\x21\x1a\xb8\x9b\x8b\x0a\x93\xa1\x23\x33\x44\xe9\x39\x2c\x1d\x12\x5b\x18\x2a\x51\x85\xea\x1e\x99\xd1\x27\x93\xb1\xaa\xfb\x49\xa5\x7a\x35\xa3\x4b\x61\x7e\x2a\xc4\xc2\xc0\x55\xcf\x4f\x6d\xcf\x2c\x70\x8f\xcc\x70\xb2\x25\x3b\x55\x6b\x6e\xb3\x39\x69\xd9\x48\xe0\xd8\x8c\x26\x34\x37\xc5\x31\x33\xbd\xe1\x12\xc4\x56\xb8\x13\x89\x83\x99\x0a\x74\x95\xa9\x39\x72\x8f\xcd\xb0\x51\x98\x81\xb2\x38\xf3\xe3\x65\xb2\xee\xb1\x19\x3c\x4a\xe4\x9f\x7b\xd4\x57\xb9\xc7\x66\x10\x29\x91\x7d\xee\x45\xd5\x0c\x26\xdb\x72\x4f\x25\x04\xf8\x38\x69\x33\xa8\x94\xc8\x3c\xf7\xa2\x6a\x06\x94\x2d\x79\xe7\x27\x14\xd0\xb9\xc7\x67\x00\x9d\xe0\x2e\x18\xe9\x19\xa7\xba\x1a\x8e\xf8\x6a\x38\xca\x15\x29\x08\x75\x35\xfe\x3e\x4f\x91\xd1\x34\x43\x52\x2e\x2f\xcd\xdd\xcd\x07\x2b\x47\xcb\x21\x0b\xaa\x8e\xc3\xc7\x8b\x13\xd3\xa2\xbc\xf4\xd8\x0c\x53\xd6\xac\x54\x5a\xd2\x1e\x85\x85\xee\x89\x19\xa2\xac\x39\xa9\xb4\xa4\xbd\xa8\x9a\xb1\xaa\x64\x46\xba\x1f\x69\x33\x60\x95\xcb\x47\xf7\xa3\x6c\x06\x2d\x5b\x36\xba\xd3\x54\x5b\x8b\xac\xdd\x13\x33\x68\xe9\xb9\xa8\x5e\x94\x51\x7c\x54\xa9\xf0\x50\x82\x7b\x62\x06\xaa\x1f\x9f\x35\xbd\xd6\x81\x36\xfe\x69\xb8\x57\x6d\x80\x5e\xd8\x09\xae\x03\x7f\x28\x42\xf7\x41\x88\x4d\x77\x70\x4b\x26\xb7\xc5\x5e\x6a\xb5\x96\xfa\x51\x7b\x61\x7d\x75\xf2\x7d\x0d\xfd\x3b\x7f\x38\xf2\x3b\xd0\x0e\x7b\x3d\x4f\xbd\xad\x5a\xdd\xd2\xdf\xd1\x99\x07\x70\x33\xf4\xfd\xef\xf0\x63\x10\xde\xf8\x37\x43\xaf\xd7\xf3\xfb\x81\xf5\x2e\xf5\x25\x4d\x59\x27\xe7\x67\xbc\x13\xaf\x1f\xc2\xd8\xef\xfa\x81\xac\x3c\xb1\x3d\x63\x23\x57\x33\x82\x7b\xba\x68\xf2\x9e\xb2\x5b\x7f\xdd\xc1\xad\x67\x43\xef\x54\x39\x62\x0f\xd9\x75\x99\xc2\x40\x81\xd0\x74\x2d\x34\xaf\xfc\xb1\x57\xf4\x98\x87\x1a\xbf\x56\xcd\x5c\xcb\xae\xcd\xe7\x49\x1e\x59\x48\xde\x78\x54\x82\xd2\x75\x90\x36\x5b\x74\x92\x9b\x85\x07\x39\xeb\xc8\x2d\x84\xe4\x68\x1e\x5b\x68\x76\xfc\xee\xd8\x33\xa4\x7e\xe5\x9e\x9b\xe1\x20\x14\xf1\xbd\x5d\xf6\x57\xfc\xdc\x0c\xc2\xcb\x89\x85\x17\x7f\x30\x0a\xba\xb2\xc4\x2f\x37\x03\xca\xd3\x1f\x6a\xea\x52\x95\x70\xb2\xb6\x27\x7a\x11\xaa\xa7\x16\xaa\xff\x5f\x0a\x9a\x3d\x44\x4c\x9e\xab\x35\x3f\x8a\x49\x3d\x57\x5b\x48\xf2\xcc\x36\x50\x4a\xb1\xb8\x32\xed\x43\xda\x7c\x6e\xa1\x38\xbe\xa5\x34\x6d\xc7\xf4\xcd\xcf\xa9\x28\x7d\x74\x9c\xd0\xbe\xb0\xd0\x0e\x42\x3e\xc1\xc0\x1e\xe7\x46\xb7\xd8\xb2\xa9\x12\x7d\xaf\xaa\x93\xda\xaa\xe8\x24\x3c\x0b\x89\xef\xde\x60\xe0\xa9\x4f\x82\x4b\x69\x69\x53\x4b\x54\x57\xd1\xb1\x89\xe7\x50\xa4\xca\x73\x02\xec\xe5\xbd\x84\xe6\x95\x85\x66\xd7\xeb\x75\xf6\xb0\x1c\x71\x1a\xba\xe4\x13\x67\x08\x2f\x6d\x0b\x2f\xbd\x89\x5e\x75\x4f\xaa\xbc\x1d\x59\x80\xfb\x53\x94\x29\xa6\x11\x52\x1f\x71\xa1\x68\x56\xf6\x21\x17\xd9\x58\x94\x30\xd0\xb1\x30\xd0\x9f\x6c\x7f\x0c\x06\x28\x4c\x94\xd9\x49\x24\x04\x7d\x0b\xc1\x3f\x02\x15\x26\xaa\x8a\x2d\x0a\x05\x27\x9a\x24\xa3\xf1\xec\xef\x2c\x04\xaf\x2d\x04\x43\x52\x69\xda\xb7\x7a\xa1\x0f\xef\x09\x60\xaa\x5e\xc3\x42\x75\x10\xe8\xc9\x44\x95\x25\x10\xc2\x82\x54\xeb\x31\xb6\xd9\x71\xd5\x2d\x82\xf5\x6c\xae\x77\x78\x1b\x96\xf1\x82\xb6\xe8\xab\x60\xc8\x36\x2f\x38\x0a\x6e\xb0\x17\x94\x63\x8e\x84\x0f\x50\x1f\x2b\x70\x09\x97\x3b\x03\xb2\x67\xf3\x82\x63\x6f\xa2\xab\x09\x9e\x66\x76\x90\xc7\xb4\xc0\x52\x6a\xa9\x85\x50\xb4\xf9\xba\x89\xe2\xeb\x84\xd9\x56\x11\x31\x5b\x46\x39\x82\x9f\x96\xa7\x44\xec\xf2\xc4\x08\xc2\x85\xcd\xf7\x0d\x6e\x83\x6c\x52\xca\x0e\x1f\xb5\x44\x7d\x73\x44\xf5\xae\x9a\x42\x5a\x63\x0f\x30\x20\x1c\x3b\x3b\x71\x60\x73\x85\x6d\xcc\x81\xe5\xd0\xea\x4f\xc3\x63\x38\xfe\x2c\xf3\x18\x0e\x42\xd1\xe6\x0a\x07\xa3\x40\x3c\x04\x90\xbb\x5f\x51\xa3\x9d\x12\xb8\x72\xb8\xd9\x6a\xe3\xdc\x79\xd6\x6d\x0e\x31\xec\xf9\x37\x1e\x4b\xab\xd4\x4a\x35\x84\xd4\x13\x9c\x9a\x39\x8b\x0f\x88\x9e\x8f\x15\x68\x96\xa6\xba\xce\x5b\x3c\xc7\x95\xb0\x6f\x7d\x0f\x81\x07\xd6\xb9\x3b\x5b\x3c\xaf\xe7\x0f\x20\xe5\xc7\x72\xab\x50\xad\xb1\x83\xb9\xe4\x10\x44\xd1\x43\x76\x08\x65\xd7\x48\xf9\x4a\xc6\x23\x86\x88\x5e\x09\xaf\xbf\x96\x07\x1b\x46\xf0\xc8\x48\x90\x07\xd7\x39\x75\xd1\xd2\x3e\xa2\x7e\xb5\x8c\xfa\xd9\x0d\x9f\x51\x3c\x36\x52\x94\xa1\xb5\xfa\x94\x3b\xb6\xd1\xa1\x3e\x7c\x4e\x98\x18\x12\x06\xb6\xc5\x5f\x5c\x9d\x18\x29\xca\x00\x5a\xbd\xab\xa5\x1f\x76\xaf\x91\xa2\x08\xca\x47\x54\x10\x6c\x5d\x9d\x1a\x69\xd0\x70\x59\x96\x30\x45\xf8\xbd\x96\x0f\x92\xb3\x79\x3b\x3d\x60\xcf\x89\xb0\x81\x62\x27\xed\x08\x82\x67\xe6\x41\x8d\xed\x62\xdb\xb6\x46\x2c\x4e\x5a\x65\x9f\x2b\x40\xe8\x9d\x1b\xe9\xa9\xa1\x72\xb9\x64\xb3\xb4\x9b\xbf\xba\x30\x52\x64\x01\xb2\xbc\x83\xe9\x24\x1b\x8f\x7c\x83\x48\x48\x8b\xbf\xb1\x8e\x3d\x63\xc7\x3c\x2c\xd6\xb9\x69\x99\x1f\xd6\xb6\xfd\x91\x1b\x84\xd2\x95\x91\x12\x0b\x86\xb7\x3d\x0b\xe8\x52\x6a\x7d\x69\x20\xbf\x6a\x1b\x29\x92\x90\xb7\xd0\x98\x77\x3f\xf0\x43\xc8\x75\x8c\xe4\xfa\x93\xb2\xf3\xc8\xb3\x0d\xfb\x19\x51\x42\xc6\x37\x92\xc1\x61\x6d\xf4\x2d\xe2\x9a\x77\x09\x2c\x84\xad\xd2\x98\x84\x5d\xa3\xd9\x6f\x95\x6c\xa4\x96\xb4\xad\x6b\x23\x39\x25\xa8\x35\xcc\xa4\xc1\x02\x76\x01\xa9\x76\xc3\x48\x73\x10\x58\x1d\x8e\x16\xe7\x22\x24\xc3\x5c\x25\x9a\xcd\x04\xb3\x79\x87\xd3\x36\xbb\x3a\x1a\xc8\x96\x1c\xe6\x2e\xfe\xa6\x6d\x76\x70\xd7\xe4\xcc\x13\x0b\x66\xad\x74\x95\x02\xf1\x9a\x5d\xa4\x7c\xca\xe9\xc1\x63\x4e\xd7\xec\xe7\xca\x52\x84\x43\x4e\xb1\xc6\xe0\x3b\x42\x05\x07\x9c\x08\x45\xb3\x9f\xa3\xc1\x33\x98\x3d\x4e\x2e\xdd\x57\x30\x2c\xeb\x71\xda\x66\xaf\x36\xd1\xbc\xda\x4e\xe6\x5e\x42\x49\xcd\x5e\xce\x10\x18\xab\x01\xe0\xee\x41\x72\x3e\x78\x64\xf4\xcd\x4e\xaf\x7d\x1b\x98\xc7\xfb\xf1\x50\x99\xd1\x33\x3b\x3d\x1a\x14\x1b\x8c\x4a\xa0\xdc\xde\xc1\x32\xa3\x6f\x76\x81\x32\x24\x36\xf1\xa0\x84\xa3\xca\x91\x5c\x6a\xad\xc2\x5e\xf1\x28\x15\xa9\xff\x99\x2f\x91\xce\x7e\xa2\x1c\x75\x04\x5e\x10\xcf\x0f\xa3\x1f\xbd\xab\xb0\xcb\xa4\xaf\x9e\xd0\x62\x87\x5a\xe8\xa7\x2a\xad\xde\x61\x8f\x0c\x80\x08\x44\xca\x98\xb2\xf2\xf0\x54\xd8\x31\x3d\xd8\x5c\x8a\x17\x61\x01\x83\xdb\x40\xe3\xc4\x26\x17\x19\x02\xa5\xca\x29\x65\x2a\xa3\x5d\xf4\xb0\x23\xec\x60\x60\x20\x6c\x62\x1e\x21\x94\xc1\x6b\xc4\x21\xfb\xa3\xe2\xf8\xd2\xf8\xa7\xd1\x68\x9c\x00\x54\xe2\xd9\xeb\x4b\x0c\xdf\x20\xae\xc3\x7d\xb2\xc1\xad\xfb\x3a\x3c\xc7\xf3\x39\x6e\x3e\xd7\xe1\x31\x99\x91\xab\x8f\x75\x48\x5e\xd7\xd3\xd9\x72\x01\xdf\x20\x21\x7d\xfe\x97\xfe\xfe\xbf\x75\xa0\x8d\x97\x3a\x6c\x5e\x68\xf3\x7f\xea\x30\x5d\x92\xd6\xb4\x0e\xb3\x78\xfe\x88\x9b\xb3\x3a\xcc\xdf\xe0\x1b\xcc\x5b\x95\x05\x7e\x5f\xd4\xe1\x9f\x29\x7c\x83\x7f\xea\xb0\x9c\x4f\x1f\x56\xa4\xeb\x65\x1d\x5e\xf1\xc5\xd7\x3a\xac\x5e\x96\xf0\x0d\x56\x75\x58\x4f\x9f\x09\x3b\x6b\x4c\xf5\xf5\x05\x7f\xfd\x54\x87\x07\xd2\x78\xa8\xc3\xeb\x1a\x37\xde\x71\x2f\xc9\x33\xfe\xdd\xaf\x3a\x3c\x4d\x17\xf1\x4c\xdc\x78\xa7\x4c\xc2\xeb\x14\xd6\xef\xf3\xfb\xe5\x0c\xbe\xc1\x4f\xce\xb1\xb8\xf2\xaf\x3a\x60\x02\xe2\xf3\x7f\xd4\xf9\x9b\x4f\x1f\x1f\x67\x09\x3c\x2e\x37\xf0\x0d\xfe\x5f\x1d\xde\x5f\x97\xcf\xc9\xf3\x2a\x9e\xcf\x93\x05\x66\x01\x41\xfe\x8f\xdd\xba\x5a\xbe\x3d\xbf\xc0\xfd\x2a\x89\x37\x2f\xd3\xc5\x33\x7c\x83\x6a\x1d\xd6\xf3\xe5\x72\xa3\x5f\xad\xe5\x6f\x8d\x1f\xde\x36\x09\xc4\x0f\x0f\xc9\x02\xd3\xfd\xad\x0e\xcf\xab\xf8\xa7\x72\xe5\xaf\x3a\x3c\x4e\xe3\xd9\xfb\x66\xfa\x37\x1e\xec\x9f\x54\xc4\xff\x1b\x00\x00\xff\xff\x3b\x67\x12\x3d\x0c\x67\x00\x00")
+
+func fontsBigFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBigFlf,
+ "fonts/big.flf",
+ )
+}
+
+func fontsBigFlf() (*asset, error) {
+ bytes, err := fontsBigFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/big.flf", size: 26380, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBigchiefFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x58\x5b\x8b\x1b\x47\x13\x7d\x9f\x5f\x51\x1f\x0c\xec\x0c\x4c\xab\xbc\xfb\xc5\xc6\x06\xaf\x19\x27\xe4\x29\x04\x87\x84\x40\x1e\x06\x2a\xb2\x25\x25\xc6\x8e\xb5\xac\xb2\x0f\x81\xfe\xf1\xa1\x6f\xd5\xd5\x33\x3d\x37\x49\x8e\x59\xef\x4a\x3d\x3d\xa7\xaa\x4f\x9f\xba\x74\x1f\x3e\x1f\xee\xb6\x25\xbc\x84\x17\x70\xf7\x0c\x6e\x9f\xc3\x5d\xf1\xfe\xe3\x1f\x1f\xfe\x3c\x6c\x0e\x9f\x0f\x70\xfb\x0c\x5f\x7d\x03\x0f\x9f\x5e\xbc\xbc\xbd\x3d\xb5\xdb\x0f\xdb\xdd\x66\xf7\xb8\xfd\xb4\xdf\xec\x77\x4f\x0d\x3c\x3d\xec\xb6\x7f\xef\xe1\x16\x5f\x3d\x87\xd3\x3f\xef\xff\xdf\xbe\xfd\xf6\xfb\x9f\x37\x6f\xbf\xdb\xfc\xfa\x43\xf1\xe3\xe3\x69\x03\x3f\xed\xbf\xec\xf6\x8f\xa7\xe3\x17\xf8\x78\x82\x5f\xde\xc1\xc3\xe3\xf1\x69\x07\xc7\x03\xfc\xb5\xff\x5f\x41\x44\xd4\x16\x00\x00\x6d\x51\x96\x65\xd9\x16\x4a\x29\x15\x3e\xcb\xa7\xf6\xb7\x1b\xe2\x51\x40\xff\x00\xcd\x0c\xa5\x14\xda\x97\xed\x77\x33\x42\x47\x39\x39\xa0\x44\x20\xc6\x46\x84\x60\xd9\xbf\x39\x6a\xd9\x8d\x1b\x4b\xa8\xcc\x43\xff\xc9\xbf\xaf\x22\x08\x44\xa4\xd4\x0b\xe1\x47\x0a\xcc\x73\x88\x90\xc2\xac\xca\x2c\xa6\x0e\xf0\x5d\x30\x50\x99\x39\x35\x9b\xc0\xa1\x91\xc4\x4c\x34\xe4\x07\x0d\x44\xed\x56\x8d\x16\x10\xab\x1a\x06\x53\x7a\x1e\xda\x11\x22\xff\xac\x32\x7e\x39\xc7\xba\x48\x7c\xe7\x5c\xaa\x88\xa0\x8b\xfe\xd4\xc2\x19\x07\x68\xbf\x1b\xbb\x0e\xc1\x7f\x15\x0f\x86\xa4\x9b\x7f\x1b\x05\xbc\xf7\x81\x74\x64\xd2\x91\x49\x47\x7e\x0d\x23\x1b\x6a\x48\xba\x07\x53\x1b\x76\x30\x48\xc1\xf3\xc2\x96\x02\xcb\xac\x2f\x81\xc8\x80\x01\x24\xfe\x55\xd4\x21\x39\x6e\xba\xa8\x87\xc1\xbc\x3c\xf5\x85\x22\xed\x5e\xd6\x30\xb9\x3b\x89\x56\x7b\x4a\x46\xcf\x42\xaa\xe4\x81\x25\x1f\x78\xf7\xf7\xf7\x53\x96\xda\x02\x4a\xf0\xbf\x7c\xa4\xba\x40\x13\x0f\x98\xdd\x92\x37\xbd\x94\x4c\xca\x2d\xe3\x1d\xc3\xbe\x80\xfb\x82\xe9\x09\x81\x38\x42\x2c\x44\x1d\x61\x31\x02\x63\xd0\xa2\xdb\x3b\x19\x10\xc9\xe7\xac\x81\x38\x09\xa3\xd6\x84\xd8\x84\xda\x86\xde\xcf\x1b\xe0\x38\xf2\x0b\xf0\x06\x0c\x98\xa4\x26\x92\xb3\x76\x05\x23\x06\x80\x00\x45\x8e\xaa\x2f\xa0\x08\x12\x03\x3e\x9b\x50\x5c\x01\xc8\xe0\x11\xe1\xb3\x7c\x05\x44\x90\x72\xad\x9c\x05\x75\xa5\x15\xcc\x19\xc0\xcb\x0c\xd8\x05\x0c\x28\x4a\xb3\xcb\x65\x14\xe5\xe3\xc0\xa8\x08\xd4\x95\xe2\x20\x67\xc0\x40\x01\xc6\x3d\x58\x65\x40\x64\x78\x9f\x43\x8e\x65\xc8\x21\x49\xea\x1f\x4c\x14\x35\x02\x93\x1a\x11\xf3\x9f\xa5\xf8\xb5\x9b\xdc\x8d\x57\x72\x1e\xb2\x02\x50\x44\x73\xa5\x9f\x87\x3a\xe7\xcd\x1b\x15\xb2\xea\xc8\x0b\x14\x0b\xa6\x63\xb0\x02\x11\x85\x98\x94\x2c\xf3\xc6\x71\x49\xfe\xf3\xb2\xe2\xb5\x7a\x40\x54\xea\x9d\x03\xec\xcc\xbe\xc8\xbe\x63\x19\xa0\xd8\x63\xcd\x41\xa0\x59\x40\x9a\x93\x90\x5e\x9a\xa1\x85\xf4\xa3\x9f\x16\x16\x70\x10\x5b\x67\xe5\xb7\x89\x12\x30\x48\xa0\xe7\x06\x2f\x2d\xad\x31\xe7\xac\x60\x60\xe0\x26\x50\x94\x59\x81\x35\x50\x7e\x6d\x03\xd7\x49\x3f\xe9\x1e\x28\xd5\x9c\xb1\x07\x42\xea\x00\x24\x4c\x60\x4c\xd2\x89\x92\xb0\x57\x2a\x17\xf4\xc2\xa2\xd0\x84\x4a\x1f\xc3\x93\xa3\xb3\x2d\x4a\x42\x43\x3d\x63\xc4\x0f\xf9\xaa\x28\x3f\x4f\xa6\xfc\xea\x8c\x94\x4f\x29\x21\xcd\x4d\xe0\x63\x73\x13\x39\xef\xe4\xa6\x76\xcb\x0c\xa4\xb9\x65\xbe\x59\xc3\xc5\xa9\xc0\xfe\x67\x50\x0c\x19\x46\x03\xaa\x90\x63\x34\xc6\x2c\x83\xbd\x3c\xb3\x56\x25\x5a\xa8\x44\x69\x50\x51\x25\x5a\xaa\x44\x2f\x56\xc9\x7f\xd7\x76\xf6\xb3\x66\x30\x60\xa1\xbe\x76\xc4\x62\x54\x8f\x58\xc1\x6f\xd2\x40\x77\xc9\x0a\x40\xac\x40\x8b\x15\xe8\xab\xb4\x3c\x9d\x3c\x7b\x07\xfd\xaf\xd9\x03\x33\x2c\x0d\x5d\xe1\xb0\x32\x9b\xc4\x44\x5a\x90\x49\xac\x5a\x95\xc4\x9c\xe7\x6c\x22\xca\x5f\x33\x38\x0b\x7f\xa0\xfa\x89\xc8\x25\x00\x09\xaa\x23\x2c\x6a\x06\x76\xa1\x1b\xce\xdc\x7a\x99\x1c\x5d\x5f\x14\x28\xd1\x81\x0e\x1d\x78\xd6\x81\x66\x3d\x75\x7d\x33\xce\xb1\x16\x1c\x5b\x54\x4e\xbd\x5a\xb6\xdb\x3a\xe1\x98\x0f\xf5\x15\x85\x28\x1b\x39\x94\xc8\x65\xcd\xb5\xf4\x55\x4f\x51\x66\x3c\x6b\x20\xaa\x3b\xfa\x33\xd6\x2b\x62\x78\x03\xed\x21\x2f\xb7\x89\x61\xc8\x75\xac\x0e\xaa\x0b\x40\x7c\x13\xd1\x8d\xde\x44\xe4\x3c\x02\xc0\xb0\x58\xee\xfd\xb9\xd9\xf4\x51\x46\x84\x59\x8f\x5a\xee\x90\x6d\xfa\x47\x3d\x7f\xd7\x36\x70\xad\x48\xef\xd7\xe2\xbc\xde\x78\x72\x78\xe8\x96\x5c\x30\x65\x34\xe6\xcf\x51\x1c\x9b\xb5\x8f\xcb\x6a\x52\x90\xbd\x67\x18\x8f\x94\x03\x20\x5c\x03\x94\xf3\xe8\xc6\x03\x95\x33\x21\x22\x62\x50\xe8\x96\xe1\x62\x56\xc6\xa4\x29\xc9\xbe\xb6\xc2\x43\x22\xaa\x97\x79\xc8\x42\x8b\xac\xfd\x6e\xb0\xc8\x76\xaa\xeb\x33\xef\x8a\xdd\x44\x12\x1b\xe5\xe3\x72\xf5\x6e\xe2\xcc\x6e\xfa\x01\xf7\xa7\xe1\xbb\x36\x79\x76\x48\xa6\xcc\xef\x5e\x93\xb9\x6e\x8e\xc7\x3e\x4c\x33\x8e\x48\x38\x19\xd2\x33\xed\x5e\x58\x5e\x25\x48\xef\xa6\x49\x4f\xfc\x47\x8f\xb3\x70\x89\x59\x5c\x83\x40\xe6\xc7\x81\x60\x60\x1a\xe7\x1b\xcf\x85\xdb\x3f\xb7\x6b\x67\xe9\x68\x55\x0c\x72\x46\xe3\xeb\x87\x00\x49\xc2\x3b\xe4\xd7\xf0\x1a\x1e\x86\x9b\xe0\x8a\x16\x00\xd5\x19\xce\x26\x2b\x72\x36\x67\x7b\x90\x8a\x4c\x58\x1b\x67\xea\xf1\xb2\x93\x03\x20\x8c\x5e\x58\x80\x32\x33\x6f\x81\x9e\x92\x9b\x01\x04\x4e\xe8\xd3\x7a\x9a\x2a\x43\xae\x75\x71\x5d\xd5\x25\x1e\x69\xd3\xf3\x58\x28\x8d\x09\xd8\x6c\xac\xf9\xce\x09\xdb\x22\xdc\xd3\x10\xda\xc3\x13\xe6\x62\x6d\x4c\x2f\x92\x97\x73\x32\x63\x5f\x78\xe0\x81\x24\xbd\x79\xa0\x88\x34\xda\xf7\xbc\xf6\xf8\xa2\xef\xa9\x72\x7d\x4f\x5b\xe8\xf4\xa7\x34\x3f\xe3\x65\x26\x9e\x1d\x44\x3f\x03\x6f\x7a\xfd\x0c\xe4\xfb\x19\xd1\x23\x3b\xb6\x3b\xc2\x94\x4c\xf6\x7a\x2e\x66\xc2\xc3\x06\x1a\xff\xd4\xb5\x98\x97\xdc\xc2\x85\xd1\xc6\x94\x0a\x48\x31\x8d\x83\x75\x5b\x88\xa3\x08\x1f\x38\xe6\x6a\x7e\x98\x10\x61\x41\xa0\xe2\xea\xd8\xea\xd3\xd2\x84\xca\x26\xea\xfe\x59\x8d\xd7\x14\xd0\xaa\xa4\xdf\x88\x5a\xdb\x0f\x91\x69\x8f\xa8\x77\x0f\x17\x8a\xa3\x3c\x15\x9b\xfe\xbd\xf1\x85\x52\xde\x87\xca\xeb\x44\xcc\x6d\x89\x35\xf4\x6f\x00\x00\x00\xff\xff\x11\x0a\x3c\x45\xb8\x1f\x00\x00")
+
+func fontsBigchiefFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBigchiefFlf,
+ "fonts/bigchief.flf",
+ )
+}
+
+func fontsBigchiefFlf() (*asset, error) {
+ bytes, err := fontsBigchiefFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/bigchief.flf", size: 8120, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBinaryFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x5c\x95\x5d\x6b\xdc\x48\x13\x85\xef\xfb\x57\x14\x43\x2e\x12\x88\x27\x7d\x5a\xdf\x77\x86\xbc\x37\x81\x97\xdd\x85\x2c\x7b\x2f\xdb\x9a\x8c\x60\x22\x65\x25\x39\xb3\xfe\xf7\x8b\xba\xaa\x74\xc8\xc6\x10\xeb\xd1\xd3\x55\x73\xda\xaa\x51\x5f\x6e\x97\xd4\xbf\x13\xec\x3f\x90\x87\xfc\x7f\x0c\xe1\x69\x9c\xfa\xe5\xed\x7c\xb9\x5d\xe4\xfd\xe7\x0f\x82\xae\x2b\xe5\xe9\x4d\xfe\x1a\x9f\xb7\x79\x91\x3f\xfa\xa5\x7f\xe9\xe5\xfd\xcf\x1f\xf9\xe2\x71\x9c\x2e\xe7\xd7\xed\xb2\x7e\x3f\x3f\xdf\x3e\x48\x57\x7e\x42\xfa\x14\xab\x10\x2e\xe3\xb7\xdb\xb0\x49\x3a\x43\x2e\xf3\xb4\x7d\x94\x71\x7a\xbe\xbd\xbe\x0c\xab\x7c\xf9\xfa\xbb\xfc\xbf\xdf\xc6\xe9\x01\x1f\x65\xf8\xc7\xee\x9e\x1e\xfe\x77\x92\xf9\xc7\x36\xce\x93\x3c\x5f\xfb\x65\x3d\x87\xf0\xf5\x47\xff\x3c\xac\xd2\x2f\x83\x4c\xf3\x26\xeb\x75\xbe\x4f\xd2\xaf\x62\x09\x45\xbe\x5c\x64\xbb\x8e\xab\x8c\xab\x2c\xc3\xdf\xaf\xe3\x32\xbc\x7c\xdc\xab\xa7\x6f\x83\x9c\xde\x3d\x9e\xe4\x69\xb8\xcd\xf7\xb0\xcd\x72\x8a\x11\x71\xff\x27\x8f\xa7\xb3\xc8\x67\x5d\xb3\x8b\xc7\xd3\xfe\x6b\x19\xbe\xcf\x3f\x07\xd9\xae\x83\x5c\xfb\xe5\x65\xdd\x3f\x59\x9e\x86\xed\x3e\x0c\x93\xdc\xe7\xe5\x65\x3d\x87\xdf\xe6\x6d\x5f\xd1\x6f\x62\x9b\xeb\x6f\xf7\xfe\x6d\xb5\xda\x55\x56\x8d\x7b\xbf\x0e\x93\x8c\x9b\xe8\xcd\x5c\xbb\x7f\x42\x2f\xd3\x70\x97\xdb\x38\x0d\xe7\x10\xfe\x5c\xde\x7c\xb3\xa7\x87\xef\x12\xff\x9b\xe1\xd7\xcf\xbf\x0d\xdb\x36\x2c\xab\xbc\x9f\x9f\xb7\x61\x5b\x3f\x9c\x43\x78\xf7\x18\x6c\x47\x10\xbf\x44\xe4\xe5\x71\x17\x31\xf2\x92\x77\xb9\x16\xc7\x5a\xc4\x63\x2d\xd8\x17\xec\x0b\xf6\x05\xfb\x82\x7d\xc1\xbe\x38\xfa\x22\x1e\x7d\xc1\xbc\x60\x5e\x30\x2f\x98\x17\xcc\x0b\xe6\x05\xf3\x82\x79\xc1\xbc\x60\x5e\x30\x2f\x98\x17\xcc\x0b\xe6\x85\xe7\xd5\x29\x89\xbc\xe4\x5d\xf0\x2e\xd7\x82\x6b\xc1\xb5\xe0\x5a\xf6\x05\xfb\x82\x7d\xc1\xbe\x60\x5f\xb0\x2f\xd8\x17\xec\xcb\xbc\x60\x5e\x30\x2f\x98\x17\xcc\x0b\xe6\x05\xf3\x82\x79\xc1\xbc\x60\x5e\x30\x2f\x98\x17\xcc\x0b\xe6\x05\xf3\x82\x79\xf9\xf7\x05\xff\xbe\x9c\x5f\x70\x7e\xc1\xf9\x05\xe7\x17\x9c\x5f\x70\x7e\xc1\xf9\x05\xe7\x17\x9c\x5f\x70\x7e\xc1\xf9\x05\xe7\x17\x9c\x5f\x70\x7e\xc1\xf9\x05\xe7\x17\x9c\x5f\x70\x7e\xc1\xf9\x05\xe7\x17\x9c\x5f\x70\x7e\xc1\xf9\x05\xe7\x17\x9c\x5f\x70\x7e\xc1\xf9\x05\xe7\x17\x9c\x5f\x1c\xf3\xfb\xeb\x0f\x52\xe3\x72\x5f\x87\xd4\x06\x1b\xea\x98\xb1\x73\xcc\xb6\x88\x86\xb9\x13\x0a\x38\xaa\x4d\xc1\x46\x5f\x6d\xe1\xa8\xb6\x34\xb4\xda\xca\x51\x6d\x1d\xec\x0b\xa2\xb6\x71\x54\xdb\x1a\x5a\x6d\xe7\x98\x6d\xa9\xa9\x6c\xd7\x28\xe1\xa8\x36\x19\x6a\x6d\x59\x38\xaa\xcd\xa9\xfc\xa9\xa1\xac\x1c\xd5\xd6\x86\x56\xdb\x38\xaa\x6d\x83\x7d\x25\xd5\x76\x8e\xd9\x56\xd1\x50\x6b\x2b\x38\xaa\xcd\xa9\xfc\xa9\xa2\x2a\x1c\xd5\x96\x86\x56\x5b\x39\xaa\xd5\x54\xbe\xdf\xaa\x71\x54\xdb\x1a\x5a\x6d\xe7\x98\x6d\xbd\xa7\x3a\xbe\x55\xa8\xe1\xa8\x36\x19\x6a\x6d\x5d\x38\xaa\x2d\x03\x78\x4a\xa0\xae\x1c\xd5\xd6\x86\x56\xdb\x38\xaa\x6d\x03\x78\x6a\xa0\xee\x1c\xb3\x6d\xa2\xa1\xd6\x36\x70\x54\xab\xa9\x7c\xbf\x4d\xe1\xa8\xb6\x34\xb4\xda\xca\x51\x6d\x4e\x75\x3c\xdf\xa6\x71\x54\xdb\x1a\x5a\x6d\xe7\x98\x6d\x1b\x03\x78\xca\xa0\x85\xa3\xda\x64\xa8\xb5\x6d\xe1\xa8\x36\xa7\x3a\x9e\x6f\x5b\x39\xaa\xad\x0d\xad\xb6\x71\x54\xab\xa9\x7c\xbf\x6d\xe7\x98\x6d\x17\x0d\xb5\xb6\x83\xa3\xda\x14\xc0\x53\x09\x5d\xe1\xa8\xb6\x34\xb4\xda\xca\x51\x6d\x1d\xc0\x53\x0a\x5d\xe3\xa8\xb6\x35\xb4\xda\xce\x71\xb7\x29\xc6\x00\x9e\x5a\x29\xc2\x51\x6d\x32\x84\xda\xc2\x51\xad\xa6\xb2\xfd\xa6\x58\x39\xaa\xad\x0d\xad\xb6\x71\x54\x9b\x53\xf9\xf3\x4d\xb1\x73\xcc\x16\xd1\x50\x6b\x01\x47\xb5\x29\x80\xa7\x5c\x42\xe1\xa8\xb6\x34\xb4\xda\xca\x51\x6d\x4e\xe5\xcf\x37\xa1\x71\x54\xdb\x1a\x5a\x6d\xe7\x98\x6d\xd2\x54\xbe\xdf\x04\x47\xb5\xc9\x50\x6b\x53\xe1\xa8\x76\x4f\x75\x7c\x7f\x53\xaa\x1c\xd5\xd6\x86\x56\xdb\x38\xaa\x6d\x03\x78\x4a\xa6\xfd\xdd\xce\x93\x32\xed\xef\x76\x9e\x96\x69\x7f\xb7\xf3\xc4\x4c\xfb\xbb\x9d\xa7\x66\xda\xdf\xed\x3c\x39\x53\x51\x1a\x5a\x6d\xe5\xa8\x56\x53\xf9\x7e\x8b\xc6\x51\x6d\x6b\x68\xb5\x9d\x63\xb6\x65\x4e\x75\x3c\xdf\x12\x8e\x6a\x93\xa1\xd6\x96\x85\xa3\xda\x32\x80\xa7\x6c\x2a\x2b\x47\xb5\xb5\xa1\xd5\x36\x8e\x6a\x73\xaa\xe3\xf9\x96\x9d\x63\xb6\x55\x34\xd4\xda\x0a\x8e\x6a\x35\x95\xef\xb7\x2a\x1c\xd5\x96\x86\x56\x5b\x39\xee\xf6\xdf\x00\x00\x00\xff\xff\xbf\x19\x3e\xf0\x66\x0d\x00\x00")
+
+func fontsBinaryFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBinaryFlf,
+ "fonts/binary.flf",
+ )
+}
+
+func fontsBinaryFlf() (*asset, error) {
+ bytes, err := fontsBinaryFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/binary.flf", size: 3430, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBlockFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x5b\x5b\x6f\xa3\xc8\xd6\x7d\xf7\xaf\x58\x0f\x48\xdf\xcb\xa4\xdb\x76\x2e\x8e\xa5\x4f\x47\x21\x36\x49\x50\x3b\xe0\xc1\xb8\x7b\xfa\xc9\x72\x77\x48\xc7\x1a\x07\x47\x36\xee\x51\x4b\xfd\xe3\x8f\xf0\xb5\xaa\xf6\xae\xa2\xc0\xe4\x1c\x9d\x1e\x69\x02\x01\x6a\xaf\x7d\xa9\xb5\x2f\x90\xe7\xf9\x73\x7b\xea\xe0\x1a\x57\x68\x77\xd0\x44\xab\x89\x26\x2e\x3b\x57\x8d\xdb\xf9\xe2\xfb\xdf\xf8\xf6\x0b\xf7\xf3\x24\x4d\xd1\x7b\x99\xbe\xbd\x25\xf3\x39\x2e\x3e\x76\xcf\x71\x76\x86\x55\xb6\x9c\xce\x7e\xbc\x64\xf8\x99\x2c\x57\xb3\x45\x8a\xc5\x33\x06\xc9\x34\x6d\xf8\xe9\xf7\xf9\xfa\x29\x59\xc1\x1f\x85\x18\x4c\xb3\x59\x7a\xd6\x6a\x3c\xcf\x7e\xcc\x93\x0c\xcb\x64\x9e\x4c\x57\x09\xda\x1f\x5a\xf9\x1a\xad\x36\xdc\xf5\x0f\xb4\xba\xdd\x8b\xc6\x30\x59\xbe\xce\x56\x9b\x95\x66\x2b\xbc\x24\xcb\xe4\xdb\x2f\xfc\x98\xfd\x4c\x52\x64\x0b\xbc\x2e\x9e\x66\xcf\xbf\x90\xbd\xcc\x56\x78\x5e\xa4\xd9\x1f\x98\xae\x30\x5f\xa4\x3f\xf2\x9f\xd9\x4b\xd2\xd8\xdc\x30\x4b\x96\xff\xb7\x42\x3a\x7d\x4d\xf2\x35\xde\xe6\xd3\xef\xc9\x13\x16\x29\xa6\xf8\xbe\x78\x7d\x4d\xd2\x0c\xf3\x59\x9a\x7c\x68\x34\x1e\xb7\x77\x3f\xe5\xfa\x0d\xa7\xeb\x39\x6e\xd7\xcb\x6c\x91\xe2\xff\x57\x8b\xf9\x3a\x9b\x2d\xd2\x9b\x64\xba\xcc\x5e\xe6\xb3\xf4\xef\x0f\x69\x92\xfd\x0b\xad\xf6\xc7\xee\x55\x0e\x64\xb6\xd5\x0e\x69\xf2\x0f\xde\xa6\xcb\xe9\x6b\x92\x25\xcb\xc6\x6a\xfd\xf6\xb6\x58\x66\xdb\x05\xef\xfc\xfb\x5c\xd7\x69\xfa\x94\x1f\x7e\x99\xa5\x1f\x80\xc7\xe9\x2f\x4c\xe7\xab\x05\xbe\x25\x58\xcd\x73\xbb\xcd\x7f\xe1\x75\x8f\xe2\x79\xb1\xc4\xb7\x24\xcb\x92\x25\xd6\xab\xa4\xb1\x78\xde\x2c\xff\xbc\x9e\xcf\xcf\xfe\x99\x3d\x65\x2f\x1f\xff\x4e\x96\xe9\xc7\xd5\xeb\x7a\xf5\x82\xe9\x3c\x4b\x96\xe9\x34\x9b\xfd\x4c\x56\x7f\xe0\xdb\x3a\xc3\x53\xf2\x3c\x5d\xcf\x33\x2c\xd6\xd9\xdb\x3a\xcb\x35\x0f\xc2\x18\xdf\x5f\xa6\xe9\x8f\xe4\xe9\x43\xa3\xe1\x00\xce\x8d\xfd\xff\x6f\x1a\x00\x1c\xe7\xa6\x81\xc9\x6f\xd0\x1f\xf2\xb5\xdd\x59\xfe\xef\x66\xfb\x5b\xe1\xf6\xe3\x4d\x38\xde\xe8\x38\x9b\x9b\xf5\x87\xdb\x7f\xe2\xa1\x70\x9c\xdf\xb7\x39\xdd\x2d\x8f\x9d\xac\xfd\x7f\x3b\x79\x25\xae\x92\x95\x41\x04\x4b\x42\x85\x25\x0f\x87\x87\xa5\xa4\xdf\x4a\xf2\x0e\xb2\x36\x8b\x49\x82\x1c\x61\x19\x48\xab\x4a\x0f\x6e\xaf\x4b\x2a\x08\xa6\x16\x4e\x95\x95\x75\x1a\x1d\xac\xbc\x95\xb2\x3b\x3d\x88\x95\x54\x82\x22\x89\xbf\x5a\x28\x58\x5c\xe5\x18\x0d\x37\x8d\xa3\xfb\xe9\x81\x12\x0e\xfc\x42\xf9\xf9\x1e\x3e\x3d\x10\x8c\x76\xf4\xc2\x8d\xe6\x5a\xf1\x81\x0a\x9f\x73\x26\xe4\xf8\xdf\x85\x83\x36\x1e\xa5\xab\xa0\x7b\xc7\xe8\x4c\x65\xf7\x6c\x35\x17\x4f\xa1\x13\xac\xb8\x9a\x3c\xcb\xec\x4b\x59\x70\xf1\x81\x63\x6f\x3a\x2a\x87\xdd\x25\x8a\x06\x3a\xe3\x98\x4f\xf7\x9c\xa5\xfd\x61\x20\x39\x8d\x54\x09\x13\xdd\xb9\x8e\x6e\xb7\x41\xdc\x8b\xfb\x8d\x59\x8a\x8b\x38\xce\x55\xc2\x4f\x25\x20\xca\xae\xaa\xa3\x6c\x36\x84\x64\x01\x39\x1c\x05\x76\x90\x99\x43\x36\xca\x11\x9e\x1c\xa2\x0a\x35\x4b\xc6\x20\x82\xa4\xfd\xa3\x38\x43\x77\x85\x79\x86\x64\x00\x46\x10\x64\x62\x21\x7b\x9a\x53\x4f\x78\xa6\x50\x90\x12\xe7\x82\xe9\xe4\xcc\x73\xb2\x46\x82\xc3\x2d\x04\x29\xde\x2b\x27\xc8\xbc\x77\xab\x6c\x1b\xa8\x29\xcc\xe0\x33\x53\x14\xd6\xa3\xa1\xa5\x20\x55\xd1\xb2\x3e\xd3\xd3\x52\x21\x57\xb1\x5b\x1c\xe2\xbd\x96\x34\xed\x88\x11\x4d\x69\x08\x84\x9c\x88\x87\xa5\xbd\x6c\xe4\x7f\x0b\xc2\xaf\x9e\x0e\x04\xb2\xb5\xc3\xce\xeb\x49\xcb\x56\x99\x64\x15\xef\x72\x25\xa3\x48\x2e\xa6\x7a\x58\xd1\x40\x0a\x14\xc1\x0e\x0a\xa7\xca\x62\x21\x14\x1b\x72\x9e\x00\xd4\xe4\x71\x5c\x95\x5d\x53\xd2\x4a\xf2\x83\xfd\xbe\x60\x58\x8e\x3b\xd1\x38\xd5\x9c\x06\x18\x41\x85\x57\x88\x5d\xa9\xe9\x0b\x49\x53\x4d\xee\x90\x4a\xe5\x1a\x35\xd2\x9f\x54\xd0\xa8\x30\xdf\x38\x54\xa3\x72\xa9\xba\x92\x20\x79\x63\x28\x25\xd2\x29\x3e\xe2\xa3\xae\x9c\x8f\x84\x5a\xdf\xe4\x89\x3a\xc2\xdb\xd0\x50\x0a\xa5\x05\xd7\x9d\x32\x4b\x33\xa6\x22\x68\xf8\x5c\x45\x4c\x55\x3a\xca\x94\xe5\x24\xc4\xa2\xbf\xa1\xaf\x1b\xb5\xa6\x12\xe2\x42\x8a\x18\xe3\x89\x18\x16\xe5\x9c\x2f\xe9\x44\xfa\x76\x45\x49\x25\x0e\xf9\x53\xe8\xc4\xda\x0b\x26\xd6\xe5\x27\x04\x55\x04\x5b\xb0\xb9\xee\xa4\x52\x39\x55\x8a\xcd\x2b\x31\x85\x90\x63\x49\xfc\x91\x3a\x5f\xa1\xa6\x49\xd5\x11\x48\x55\x0d\x2b\x31\x47\x21\x17\xd6\xd5\x1f\xc1\x50\x91\x4d\x8c\x23\x06\xf3\x69\xe1\x00\xc2\x82\x84\xf5\xd6\xab\xa8\xa1\x62\x27\xd3\x29\x64\x32\x83\xda\xd5\x58\x69\xc8\x08\x67\x24\x72\x6a\x72\x40\x08\x18\x02\x48\x0b\xca\xce\x22\x45\x3a\x33\xf4\x5e\x0f\x05\x16\x1b\xfb\xe4\x60\x33\xf5\x1d\x66\x8d\xb7\x0f\x97\xeb\x59\xc4\x39\x8c\x68\xb1\xc2\x51\xa7\xb4\xba\xe3\xc8\xf9\x91\x1f\x3c\x4d\xd4\xfe\x9a\x84\x85\xb2\x57\x6c\x7d\x36\xb1\x9a\x24\xa9\x07\xac\x06\x52\xd4\x70\x05\xce\x69\xef\x16\x38\xdf\xef\x01\x54\x3f\x15\x00\xaa\x6d\x92\x52\xc6\x1d\xb5\x6d\x88\x5c\x44\x0f\x40\x07\xe2\x0c\x7e\x1d\xf5\x9f\x56\xf9\x3a\xa4\x7c\x2a\xd9\xaa\x94\x25\x5d\xfb\x64\x76\x42\xbf\xc5\x57\xc2\x35\x9b\x8e\x68\xc4\x97\x54\xe6\x5c\x5d\x41\x23\xb5\x71\x60\xeb\x5d\x29\x4b\x2b\xc4\xc8\xd0\xe2\x7b\x45\x1d\xcd\xcd\xf5\x44\x1d\xac\x9b\x88\x1d\xa1\x92\x33\xf9\x07\x33\x66\xd3\x4e\xd7\x6c\xd8\xce\x46\x55\xa9\x26\xad\xa3\x5f\xd2\x29\x57\xa8\x2a\x78\xdf\x83\xd6\xb6\x9c\x7b\x8c\x85\x0a\x5b\xbb\xc8\x02\x0a\xab\x12\x75\x83\xd5\x1e\x25\x3a\x41\x96\xcd\x51\xf9\xca\xb3\xb2\x46\x16\x9d\xd2\x7b\xef\xe4\xc3\x89\x51\xd0\x44\x6e\x9b\x25\xa2\x82\x34\x53\x2b\x35\x0b\x2a\xd4\x88\x74\x27\x15\x12\x95\xd4\x48\x0a\xb8\xf7\x6b\xb0\x04\xcb\x4a\x55\x90\xda\x69\x54\xaa\xdf\x29\x23\x88\xaf\x61\x00\x22\xe1\x3d\xfa\x1d\x06\x80\x0e\x88\x06\x10\x0f\x8c\x07\xc8\x01\x85\x09\x30\x0f\xdc\xe8\x1a\x6b\x76\x10\x16\xa8\x24\xa8\x8e\x8c\xab\x17\xc4\xb5\xf7\x45\xd5\x85\x51\x23\xb9\x06\x51\x0e\x69\x23\x45\xee\xa5\xbd\x80\x5d\x62\x63\x7e\x94\x16\x58\x08\x79\x17\x3c\x62\x08\x3a\x6a\xce\x3e\x86\x19\x57\x70\xe9\x4f\x88\x87\x8e\x1f\x61\xe9\xa2\xc9\x3c\x71\x2a\x19\x8e\xd5\x04\xf1\x41\x67\x24\x59\xbd\xa0\x52\x71\x7f\x8a\xa0\x9a\xbb\x81\xff\x35\xd3\xd9\x72\x93\x55\x21\x64\x7d\x45\xd9\x45\x1b\x41\xad\xab\x26\x10\x84\x67\xb7\x91\xe7\x7e\xc2\x68\xe8\xf6\xbc\x06\xb6\x9f\x2f\x96\xfd\x91\x2f\xd6\x02\xfc\xe0\xb3\x17\xc5\x5e\x1f\xde\x5f\xbd\x81\xfb\xe8\xc6\x7e\x18\xe0\xd1\x8d\x3e\xa9\x55\xb2\x7d\x43\xd0\xba\x6a\x03\x3d\x2f\x88\x31\xf2\xef\x03\xc6\x41\x12\x6f\x4c\xd4\xd7\x05\x1c\x45\xe8\x69\xf7\xb0\x74\x2e\xf7\x1c\x18\x86\xe3\xa0\x2f\x09\x86\xfa\x85\x18\x25\x39\x48\xbd\x85\x62\xfe\x7d\x8a\x84\xf2\x69\x08\xa4\x32\x8a\x04\xa4\x10\x1e\xad\xab\x0b\xa0\x37\x8e\x22\x2f\xe8\x7d\x55\xb0\x41\x4d\xe9\x24\xf6\x48\x8e\x99\xfc\xd6\xa1\x27\x8f\x30\x8b\x4a\x62\x73\x6c\x97\xc0\x57\x2f\x20\xb0\x2c\x86\x8c\xe6\x79\xb7\xf9\xaa\xe4\x99\x1c\xc6\x15\x70\x1b\x85\x9f\xbc\x00\xb7\x6e\x54\x14\x67\xba\x50\xcc\x17\xea\x00\x23\xaf\xb7\x89\xe3\xbd\x4e\xea\x4c\x81\xc9\x59\x5c\x52\x53\x5c\x7c\xf8\xed\x21\xde\xae\x81\xbe\xef\x7a\x91\x37\xf2\x47\x26\xb6\xd9\x6d\xe0\xdd\xe7\x9e\x76\x27\x42\x04\x35\xd4\x70\xea\x02\xbd\x70\xf8\x35\xf2\xef\x1f\xc4\x4d\x26\x3a\x9f\x04\x2f\xe1\x9d\x09\xff\x25\x04\x18\x52\x52\x7f\x49\x1e\x67\x05\x31\x90\x6e\x1a\xad\x4e\x13\xb8\xf3\x1e\xfd\xc0\x0f\x3c\x84\x51\xdf\x0f\xdc\x01\xfc\xa0\xef\xf7\xdc\x38\x8c\xac\x13\x8f\x9e\x99\xd9\xea\x8b\xb1\x62\xa7\x05\x0c\xbc\xbb\xf8\x6c\x18\xfa\x41\xec\x07\xf7\xe8\x87\xe3\xdb\x81\x07\x37\xb8\x1f\x78\xf8\x73\x1c\xc6\x32\x1b\x2a\xc8\x40\xe3\x86\xa1\x2f\x6e\xee\x4f\x9e\x25\x2b\x4b\x38\xdb\xd8\x7c\xd3\x4e\x79\xc3\xa2\x5f\x61\x8d\x61\x21\x97\x81\x71\x0e\x8c\xc2\xbb\x18\x0f\x5f\x87\x0f\x5e\xa0\x37\xad\x8d\x3b\x1c\xc7\xbe\xa4\x6b\x75\x2e\x80\xc8\xbb\xf7\x47\xb1\x17\x79\xfd\x4a\xf1\xce\x90\xb6\x40\x9e\xf2\x2f\x6d\xee\x2c\x13\xef\x97\xc0\xa3\xdb\x8b\xc2\x40\xeb\x0f\x62\x8f\x53\x86\xed\xbc\xf3\xae\x80\xbe\x77\x1f\x79\x9e\xc0\x89\x85\xec\xe7\x30\x5f\x7a\x15\xbc\x4f\x68\x75\x3a\xc0\x70\x30\x1e\x9d\x3d\xfa\xc1\x78\x44\x2a\x00\xc3\xdb\x28\x54\xcd\x2a\x8a\x09\x25\x34\xd7\xc0\x68\x3c\xf4\xa2\x51\x2f\xf2\x87\x31\xe2\x2f\xa1\xa4\x9a\x42\xec\xd4\x0c\x44\x94\xfc\x35\x89\xa2\x7b\x57\x91\xf6\x10\x79\x9e\xf4\xe0\x44\xf3\x21\x8b\x31\xd3\x68\xe5\x5d\x37\x01\xb7\x37\x8e\x3d\xb8\xbd\xbc\xde\x6a\x28\x2c\xed\x1c\x3c\x56\xf6\xaf\x0c\x5a\xd7\x2d\xe0\xd1\xef\x45\x21\xa1\x9d\x8a\x95\x34\xd3\x63\x41\x7c\xa7\x77\x10\xdc\x06\x86\xfe\xa0\x17\x85\x5f\xf8\x92\x04\xea\x52\x24\x11\x29\xd4\x6a\x3e\x35\x04\xcf\xf5\x79\x6e\x83\x7e\x7f\xe0\xa1\x1f\xc6\x0d\x51\x7b\x52\x84\xec\x13\xbd\x23\xdf\xb2\x5b\x28\x2f\xff\xbc\xbe\x3f\x18\xb8\xd4\xd8\x85\x07\xec\xb7\xe9\xf9\xaa\x97\x72\xb4\x85\x81\x67\x78\xa0\xa1\x84\xb7\x23\xaf\x4e\x03\xe0\x2a\xa7\xad\x51\x6f\x3c\x30\xe6\xe9\x72\xdf\x19\x2b\x81\x63\x97\xa7\xaf\x3b\xc0\xa6\xd2\x29\x95\xa8\x1d\xf2\x37\x3d\x76\xa9\xd8\x9c\xc6\xc1\xa7\xac\x1d\xd0\x6b\xe0\xf3\x78\x70\xef\x46\xb8\x8b\xdc\x6d\x05\x1a\x06\x39\x40\x37\x8a\xbd\x48\x7e\x00\xea\x5f\x3b\x28\x09\x05\x80\xfc\xba\x43\xc0\xc6\x35\x00\x54\x31\xb1\x7a\xd3\x31\xaa\x28\x91\xb6\x2e\x8a\x8b\xf9\x7f\x1b\xcd\xbb\xbc\xe6\x0f\xee\xe0\x4e\xa7\x36\xaf\x34\xaf\x32\xd7\x02\x1d\x9f\xa3\xea\x32\x0e\x16\xed\x60\x50\x55\xab\x68\xae\x66\xb7\x49\xd5\xdc\x70\xfc\xde\xc5\x23\xa3\x8f\x85\xde\x52\xf5\xb1\xe8\x29\xe2\x63\xd0\x1a\x04\x52\xe7\x29\xea\xf6\x6e\x3e\xee\x8a\xc3\x82\x3f\xc7\xde\x88\xd9\x72\x6a\x1a\x85\x32\xd7\x61\x5a\x30\x43\x72\xcd\x85\xb6\x81\x81\x1b\xfb\x01\x7a\xee\xd0\x8f\xdd\x01\x06\x5e\x1c\x7b\x11\x5c\x7c\xf1\xe3\x07\xdc\x47\xee\x67\xef\x98\x4b\x95\xea\xc2\x48\x4c\x55\x86\x7e\xad\xee\xb9\x19\xcf\x26\x1b\x33\x10\x24\x47\xd7\x89\xe7\xc2\x8c\xa7\xe7\x47\xbd\xf1\xe3\xdd\xc0\xfb\xcb\xcc\xd1\xd4\x55\xda\x17\xf2\x16\xa0\x2e\xcd\xa0\x62\x7f\xd0\xf7\x1a\x5c\xe9\x4d\xa7\x3a\xb5\xe0\xb9\x32\xe3\xb1\x6a\xe1\xeb\x76\x5c\xc7\x8c\x29\xca\xd3\x9c\x7b\x1b\xee\xa3\xdb\x22\xb9\xd6\x00\xea\x5a\x07\xca\xa3\xc4\x26\x95\x62\x54\xd4\xee\x36\xa9\x62\x9f\x30\x9f\x91\x82\x99\x4a\xb0\x0c\xad\x7b\xf5\xdd\xea\x76\x35\xa8\x7b\xbb\x3d\x20\x57\x5e\xfa\xc9\x02\xf8\x57\xae\xc7\x2b\x24\x7f\x4c\x7e\x2b\x4c\xb6\x41\xd4\x6e\x36\x35\x88\xbc\x42\xd6\x62\xc3\x9c\x58\x8e\xbb\x4d\xef\xd7\x76\xb3\x65\xc6\x63\x60\xad\xf7\xc1\xa3\x63\x75\xaf\x0c\x6b\xd5\x0d\x4a\x47\xed\x5e\x09\x96\xa8\x1b\x93\x8e\xde\x7d\x29\x90\x48\x79\x4b\x5b\x57\xb5\x82\x22\x37\x10\x04\x1b\xf9\x3a\x26\xf7\xd9\xc0\xa9\x5f\xbe\x8e\xb9\x7d\x3e\x50\xe8\x44\xa3\x0e\x10\x3a\xaa\xf6\xd9\xc0\xa0\x8b\xd5\x81\x41\xc7\xcc\x5e\xfc\x20\x46\x90\xf4\x16\x80\xd6\xcc\x0e\xdf\x30\x43\xcd\x28\x4c\xc3\xc6\x75\x3c\xed\xa6\x8e\x7a\x03\xcb\x4c\x4f\x90\x29\xb7\x95\x4b\x60\xed\x96\x8e\x78\xc3\x1a\xca\x45\x62\x25\xbe\x5a\x91\xf0\xe8\x88\x37\xac\xa1\x5c\xac\x82\x47\x47\xbc\x61\xb9\x72\xb1\x5e\x50\x3a\xe2\x0d\xad\xcb\xc5\x7a\xf1\xe8\x48\x37\xac\xa9\x5c\xac\x82\xe9\x12\x78\x1c\x0f\x62\x7f\x38\xf0\x7b\xae\xf4\x6e\x6b\x77\x93\xc2\x38\x3c\x21\xf3\xad\x99\xb2\xc2\x4e\xa2\x8e\x7a\x77\x56\x18\xc5\x51\xf8\x49\x2a\x0b\xf9\xe9\x1c\xd4\xde\x4f\x21\x67\x30\x09\xdd\x8a\x7b\x5a\x3a\x5a\x1e\x5b\xef\x75\xc5\x62\x27\xba\x48\x47\xd1\x63\xeb\xbd\x5e\x2f\x1e\x1d\x37\x8f\x2b\xb7\x86\xa7\x83\x6a\xeb\x08\x7a\x5c\xaa\xc8\xd2\xc1\xa8\x86\x49\x47\xd2\x5f\x89\xe3\x94\xe8\x91\x2a\xe4\xe3\xf5\x9b\x86\x3a\xa8\x81\x2e\x0c\x2d\xc6\x8a\xed\xb6\x8e\xb4\xe3\x87\x30\xda\x50\x40\x95\x0f\xc4\xc9\x15\xfa\xb9\x09\x31\xd4\x81\xa8\x47\x8f\xee\xe0\x00\x63\xf4\xe0\x46\x43\x8c\x88\x8d\x4d\x04\x68\x7d\x85\xfb\x08\xa6\xdd\xbe\x60\x81\xd8\xcf\x84\x84\x60\x62\xfa\x40\xb5\x14\x2a\x28\x3a\xda\x97\x26\x34\x24\x7a\x68\xeb\x58\x2f\x9a\x2b\x13\x1a\x79\xd3\x93\x6a\x54\x9f\xc9\x4e\x82\xd4\x31\x41\xb2\x9c\x06\xd5\x87\xe6\xda\x84\xa6\x44\x72\xb7\x24\x20\x0b\x44\x5d\x13\x22\x79\x12\x64\x72\x99\x52\x10\x9d\x02\xe9\xbc\xc9\x43\x22\x73\x20\x50\xce\x62\xfa\x10\x86\x0a\x74\x65\xc2\x6e\x05\xf2\x38\x3b\x13\xd2\x4e\xec\x37\x3a\xb4\x58\x1d\x74\x53\x21\x2b\x6a\x50\xd8\x9e\xb7\xa9\x5a\x98\xee\xa6\x42\xe7\x6d\x16\x0f\x3b\x13\x92\xdf\x0b\x5b\xcd\x41\x75\x68\x74\x1e\xe6\xc9\x9c\x4e\x84\x4c\x21\x56\x1f\x1a\x9e\xd1\x4b\xcd\x83\xea\x86\xc4\xd3\x7a\x99\x69\x50\xdd\x88\x78\x6a\xe7\x66\x41\x7b\x7a\xd8\x2f\x52\xfc\xc7\x58\xf2\x9b\xe0\x5c\x1a\xcf\xda\xea\xe4\x47\x54\xc8\x39\x64\xea\xed\x6f\x74\x07\x4a\x21\xb6\x91\xc6\xb3\xb2\xf5\x9c\x07\xaa\x9a\xc7\xfa\x9a\x39\xa4\x1f\x56\xe4\x10\x78\x1a\xb6\x9d\xf2\x58\x88\x2d\x42\x70\xc1\xb3\xee\x66\xc6\x33\x61\xde\xfb\x32\x7f\x01\x57\x44\xfd\xc5\xe5\xf0\x05\x4f\x9b\xb6\x13\x1d\x69\x65\x53\x01\xaa\xdf\x34\x12\x1a\x9e\x34\xed\xe7\x39\xb0\x29\x49\xad\x6d\xc3\x93\xa6\xfd\x34\xa7\x5e\x34\x3c\x69\x96\x9c\xe5\x28\x21\x7c\x22\x24\x9e\x34\xe9\x24\x87\x8c\x04\xb8\x95\x4f\x46\xc3\x13\xe6\x7f\x71\x8e\x73\xd1\x01\xfa\xfe\x67\x7f\xa4\x4e\x70\x4c\xdf\xc6\x09\x70\x26\x85\x5f\xbf\xd9\xf7\x95\x17\x3c\xe5\x6a\xe7\x3b\x85\xe5\xd1\xe4\x37\x3f\xc8\xb5\x34\x0d\x4f\xbf\x63\xf6\x4d\x87\x44\xa8\xe5\xa7\x27\xc5\xbc\x73\xc9\x53\x31\x9d\xe5\x58\x34\x75\x35\xa0\xe1\x39\xf9\xfd\x26\x39\x16\x90\x78\x62\x7e\xb7\x39\x8e\x05\x22\x9e\x9c\xe9\x14\xa7\x86\xf1\x9b\x84\x86\x72\x40\x8e\x86\x27\xe7\x93\x66\x36\xd2\x89\x6e\x80\x33\x11\x3f\xa7\x6c\x5f\xf2\x84\xfc\xf5\x3f\xe2\x26\xce\x30\xff\x0e\x00\x00\xff\xff\x3f\x39\x52\x57\x73\x5f\x00\x00")
+
+func fontsBlockFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBlockFlf,
+ "fonts/block.flf",
+ )
+}
+
+func fontsBlockFlf() (*asset, error) {
+ bytes, err := fontsBlockFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/block.flf", size: 24435, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBubbleFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x9b\xe9\x9b\x23\x55\xf5\xc7\xdf\xf7\x5f\x71\x7e\x3f\x17\x40\xa7\x97\x24\x9d\xa4\x5b\x11\xa7\xba\x52\x9d\x2e\x26\x5d\x15\x2a\x95\x19\x7a\x44\x31\xdd\x5d\xdd\x1d\x49\x57\xda\x2c\x33\xb4\x1b\xee\xfb\xbe\xef\x0b\x08\xca\x22\x08\x08\x28\xbb\x82\x80\x88\xb2\x09\x82\xac\xca\x2a\xa2\x6c\x82\x20\x8b\x3e\x09\x6b\xce\x3d\xa7\xbe\xf5\xf8\xc2\xa7\xf5\x79\x3e\xe7\x33\x37\xa7\xce\x3d\x75\xee\x4d\x5c\x6b\xad\x65\x1b\xc7\xd0\x34\xe5\x68\x86\x32\x79\xca\x64\x68\x8a\x32\x53\x99\x6c\x71\x6c\xae\xbf\xbc\xdc\x8a\x68\x79\x9b\xca\xad\x28\x8e\xc9\xde\x68\x6c\x6d\x45\xad\x16\x4d\x4f\xce\xe6\xc6\xdc\x78\xa5\xd5\x5f\x8d\xba\xb4\xb2\xd1\xe8\x34\x56\x7a\x51\xa7\x4b\x99\xec\xcc\x78\x36\x9f\x1f\x73\xe2\x8d\x46\xbc\x12\xad\xd2\x5a\xbb\x43\x95\x46\xaf\x19\x8f\x67\x77\xe4\x76\x4c\x0f\x5c\x87\xb6\x37\x62\xb2\xdb\xfb\x1b\x31\x1d\xbc\x32\xf8\xb3\x73\x65\xa5\xd9\x9a\x68\x77\xd6\x0f\x19\x1b\xa2\x2f\x0b\xa9\x1b\xf5\xba\xd4\xed\x6f\x6d\xb5\x3b\xbd\x68\x95\xda\x71\x6b\x9b\x9a\x6b\xb4\xdd\xee\x77\xa8\xbb\xd2\x89\xa2\x98\xd6\xda\x71\x8f\x56\xdb\x51\x77\x6c\xad\xb9\xde\x8a\x7a\xd4\x89\x5a\x51\xa3\x1b\x51\x76\x22\x4b\xe3\xe3\xe4\xb5\xf7\x45\x9b\xcb\x51\x87\x32\xb3\xb3\x85\xb1\x6a\xd4\xd9\x6c\x76\xbb\xcd\x76\x4c\xcd\x2e\x6d\x44\x9d\x68\x79\x9b\xd6\x9b\xfb\xa2\x98\x7a\x6d\xda\x6c\xaf\x36\xd7\xb6\xa9\xb7\xd1\xec\x0e\xbd\x3b\xa8\xd1\xa5\x56\x3b\x5e\x1f\xfc\xed\x6d\x44\x63\x43\xa0\x19\x75\x0e\xe8\x52\xdc\xd8\x8c\x06\x8e\xad\x56\x63\x65\xb8\x34\x6a\xd0\x4a\x7b\x73\x33\x8a\x7b\xd4\x6a\xc6\xd1\xc4\xd8\xd8\xe2\xf3\xf4\xea\xe0\x53\x57\x1b\xfd\x16\xcd\xf5\x3b\xbd\x76\x4c\x07\x77\xdb\xad\x7e\xaf\xd9\x8e\x77\x46\x8d\x4e\x6f\xa3\xd5\x8c\x8f\x9a\x88\xa3\xde\x21\x94\xc9\x4e\xce\x16\x06\x0b\x69\x3e\x9f\x5b\x8a\xa3\xfd\xb4\xd5\xe8\x34\x36\xa3\x5e\xd4\x19\x7b\x39\x11\xcb\xdb\x34\xef\x96\x07\x9f\xb6\x11\xaf\x0e\xfe\xeb\x9e\x66\x3c\x41\xb4\xd8\xd8\xa6\x46\xab\xdb\xa6\xe5\x88\xba\xad\xe6\xfa\x46\xaf\xb5\x4d\x9b\x2f\xae\x62\xf0\x2c\x96\xa3\xde\x20\xaf\xfd\x6e\x34\xd6\x5e\x1b\xea\xd7\xfa\xad\xd6\xf8\xfe\xe6\x6a\x6f\x63\xf2\xa8\xa8\x13\x4f\x76\x37\xfb\xdd\x0d\x6a\xb4\x7a\x51\x27\x6e\xf4\x9a\xfb\xa2\xee\x0e\x5a\xee\xf7\x68\x35\x5a\x6b\xf4\x5b\x3d\x6a\xf7\x7b\x5b\xfd\xde\xe0\x93\x7b\x7e\x38\x78\x54\xf1\x7a\xb4\x3a\x31\x46\xc7\xec\x7c\xe5\x7f\x76\x8e\x11\xd1\x91\x44\x83\xbf\x93\x74\xc4\xe0\xef\x81\xf4\x7f\x74\xd0\xe0\x7f\x1f\x71\xe4\x24\xc9\xc0\xff\x23\xe0\x55\x08\x78\x35\x02\x5e\x83\x80\xd7\x22\xe0\x00\x04\x1c\x88\x80\x83\x10\xf0\x3a\x04\xbc\x1e\x01\x3b\x10\x30\x8e\x80\x09\x04\x4c\x22\x60\x0a\x01\x19\x04\x64\x11\x90\x43\xc0\x34\x02\xf2\x08\x28\x20\xa0\x88\x80\x19\x04\xcc\x22\xe0\x0d\x08\x78\x23\x02\x0e\x46\xc0\x9b\x10\x70\x08\x02\xde\x8c\x80\x9d\x08\xb0\x10\x30\x87\x00\x1b\x01\x25\x04\x38\x08\x98\x47\x40\x19\x01\x0b\x08\x70\x11\x70\x28\x02\x76\x21\xa0\x82\x80\x45\x04\x78\x08\xf0\x11\x50\x45\xc0\x61\x08\x08\x10\x50\x43\x40\x88\x80\x3a\x02\x76\x23\x60\x0f\x02\x0e\x47\xc0\x12\x02\xf6\x22\xe0\x2d\x08\x38\x02\x01\x6f\x45\xc0\xdb\x10\x70\x24\x02\xde\x8e\x80\x06\x02\x96\x11\xb0\x82\x80\x55\x04\x44\x08\x58\x43\xc0\x3a\x02\x36\x10\xd0\x44\xc0\x3b\x10\x70\x14\x02\x5a\x08\xd8\x44\x40\x8c\x80\x36\x02\xb6\x10\xf0\x4e\x04\x74\x10\xd0\x45\x40\x0f\x01\x7d\x04\xec\x43\xc0\x7e\x04\x1c\x8d\x80\x6d\x04\xbc\x0b\x01\xef\x46\xc0\x7b\x10\xf0\x5e\x04\xbc\x0f\x01\x97\x22\xe0\x46\x04\xdc\x8a\x80\xbb\x11\xf0\x04\x02\x9e\x41\xc0\x1d\x23\x40\x26\x3b\x23\x41\xef\x67\xd0\xac\x04\x7d\x60\x14\xca\x4d\x49\xd0\x07\x19\x94\x91\xa0\x0f\x31\x28\x2b\x41\x1f\x66\x50\x4e\x82\x3e\xc2\xa0\x69\x09\xfa\x28\x83\xf2\x12\xf4\x31\x06\x15\x24\xe8\xe3\x0c\x2a\x4a\xd0\x27\x18\x24\x66\xfc\x93\x0c\x12\x33\xfe\xa9\x51\x68\x5a\xcc\xf8\xa7\x19\x24\x66\xfc\x33\x0c\x12\x33\xfe\x59\x06\x89\x19\xff\x1c\x83\xc4\x8c\x7f\x9e\x41\x62\xc6\xbf\xc0\x20\x31\xe3\x5f\x64\x90\x98\xf1\x2f\x31\x48\xcc\xf8\x97\x19\x24\x66\xfc\x2b\xa3\x50\x5e\xcc\xf8\x57\x19\x24\x66\xfc\x6b\x0c\x12\x33\xfe\x75\x06\x89\x19\xff\x06\x83\xc4\x8c\x7f\x93\x41\x62\xc6\xbf\xc5\x20\x31\xe3\xdf\x66\x90\x98\xf1\xef\x30\x48\xcc\xf8\x77\x19\x24\x66\xfc\x7b\xa3\x50\x61\x8a\xc8\xf3\xc7\xe7\x02\xc7\xda\x45\xb5\xaa\x65\x3b\x52\xd0\xf7\x59\x50\x86\xc8\xf5\x76\x3b\x41\xe8\x94\xc8\x39\xdc\xae\x58\x8b\x56\xe8\xfa\x1e\x2d\x5a\xc1\x2e\x29\xfe\x07\x2c\x3e\x4b\x64\x3b\x5e\x48\x35\xb7\xec\x49\xfc\xb1\x8c\xcf\x11\x55\xfd\xba\x57\x52\x03\x8e\x63\x01\xd3\x44\x76\x3d\x08\x1c\xcf\x5e\x52\x63\x7e\xc8\x62\xf2\x44\x4b\x8e\xa7\xe2\xc7\x33\xbc\x40\x34\x17\xf8\xbb\x1c\x8f\xe6\xac\x40\x0a\x38\x81\x05\x14\x89\x6a\x8e\x3d\xcc\x93\xf6\x6f\xfc\x88\x85\xcc\x10\x95\x5c\xcb\x09\x9c\x9a\x5b\x93\xf8\x1f\x33\x7e\x96\xc8\xf6\xab\x4b\x81\x5b\x5e\xd0\x93\x7b\xe2\x68\x50\x71\x8a\x68\xde\x59\x74\x3d\xd7\x73\xc8\x0f\x4a\xae\x67\x55\xc8\xf5\x4a\xae\x6d\x85\xbe\xf8\xc1\x4e\x62\x82\x0c\x51\xc5\x99\x0f\xc7\xab\xbe\xeb\x85\xae\x57\xa6\x92\x5f\x9f\xab\x38\x64\x79\xe5\x8a\x43\x87\xd5\xfd\x30\xb9\x3a\x4e\x66\xbe\x2c\x0d\xaf\x16\xb5\xf5\x9f\xc2\xf0\x1c\x51\xcd\x9f\x0f\x69\x61\xa9\xba\xe0\x88\x11\x3f\x61\x11\xd3\x44\x81\x53\x76\x6b\xa1\x13\x38\x7a\x4d\x9d\xca\xa2\xf2\x44\x8b\x96\x1d\xf8\x22\x7c\x1a\x83\x0b\x44\x25\xa7\x1c\x38\x8e\xaa\xff\x29\x8b\x28\x12\x55\x2b\xf5\xda\xf8\xa2\xeb\xd5\x6b\x6a\xd4\xe9\x2c\x6a\x86\xa8\x56\xaf\x3a\x41\xcd\x0e\xdc\x6a\x48\xe1\x1e\x5f\x8a\x3a\x83\x45\xcd\xb2\xa8\x85\xc0\x11\xf7\xfd\x99\xa3\x71\x33\x53\x44\x96\x5d\x0f\x1d\xb2\xec\xc1\xfe\x95\x42\x7e\xc6\x42\x32\x44\x8b\xae\x1d\xf8\xea\x27\x3a\x8b\x05\x64\x89\xaa\x6e\xc5\x0e\xfc\x3d\x6a\xc8\xd9\x2c\x24\x37\xf8\x37\x4a\xa5\x8a\x43\x25\x5f\x5c\xd4\x39\x2c\x60\xd0\x1e\x9c\x92\x5b\xa9\x58\x12\xfd\x73\x46\xe7\x47\xb3\xe5\x7b\x62\xae\x7e\xc1\xa2\x0a\x83\x72\xa9\xd9\xf5\x4a\xea\x7d\x75\x2e\x33\x14\x89\x86\x3b\xf9\x7f\xde\x58\xe7\x31\xe1\x0c\xd1\xee\x7a\xa5\x6c\x05\x34\x1f\x58\xcf\x77\x22\xdf\x1b\x88\xac\x20\x74\xc4\x25\x9d\xcf\x0c\xb3\xb2\x61\xc1\xaa\xcc\x4b\xe1\x17\x8c\x86\xcf\x4e\x99\xe1\xc3\xda\x7b\x71\x09\x62\x93\xbb\x90\x49\x5e\xf9\xf2\x39\xac\xee\xd4\x12\x53\x70\x11\x0b\xce\x12\x55\xac\xd0\xf5\xc8\xb6\xaa\x6e\x68\x55\xa8\xe2\x84\xa1\x13\x90\x45\x7b\xdc\x70\x81\xca\x81\xb5\x5b\x7c\xba\x17\x33\x4f\x2e\xd9\x33\xdc\x25\x92\xe7\x97\xcc\x33\x9d\xec\xb1\xdd\xc0\xae\x2f\xce\x57\x9c\xc3\x25\xd9\xaf\x98\x2c\x9f\x2c\x0b\xdd\x4a\x49\x5c\xd4\x25\xcc\x53\x48\xf6\x24\xbe\x92\x2e\x65\xae\x62\xb2\x2b\x18\x94\xb5\x35\xe7\xcb\x59\xff\x35\x93\xcd\x68\x32\x31\xfa\x32\x16\x3d\xab\x44\xdb\x2f\xe4\x5a\xef\x08\x97\x8f\x98\xb2\x53\x53\x8a\xc9\x01\x55\x74\x05\xf3\x64\x92\x3d\x6a\x15\xfd\x86\x79\xb4\xaa\x76\xd2\x54\xd1\x95\x4c\xa6\x95\xb6\x93\xe2\xe9\xff\x96\xb9\xb4\xf2\x76\x41\xa2\xae\x62\x1e\xad\xb2\x5d\x90\xa8\xdf\x31\x8f\x56\xd9\x6e\x9a\x44\xfd\x9e\xc9\xb4\xd2\x76\x53\x24\xea\x6a\xe6\xd2\x2a\xdb\x09\x17\xa4\xf0\x6b\x58\xb8\x56\xda\x1e\xd8\xf9\xd7\x8e\x7a\x32\x5a\x61\xfb\xe0\x79\x5d\xc7\x3c\x5a\x61\xfb\xe0\x79\x5d\xcf\x3c\x5a\x61\xfb\x69\x9e\xd7\x1f\x98\x4c\x2b\x6c\x1f\x24\xe9\x06\xe6\xd1\x8a\xda\x4f\xf1\xdc\x6f\x64\xae\xc1\x50\x59\xaf\x84\x6e\xb5\x32\x98\x0b\x92\xce\x06\x7f\x64\x91\x5a\x29\xbf\xb0\x8a\x5a\x38\x38\x9c\x48\xa2\x9b\x98\x48\x2b\xe3\x3a\x78\xe6\x37\x33\x8f\x56\xc2\x75\xf0\xcc\xff\xc4\x3c\x5a\x2d\xd7\xd3\x3c\xf3\x5b\x46\x65\x59\xad\xa0\xeb\x29\x9e\xd5\xad\xcc\xa5\x15\xf5\x12\xf8\x80\xb7\x31\x8f\x56\xd4\xe1\x82\x1f\x88\x8f\xfe\x76\x26\x78\xa9\x90\x6b\x8b\x56\xe5\xa5\xf0\xda\x82\x15\x54\x49\xfc\x24\x77\x30\xc1\xb4\x28\x40\x33\xd0\x9d\xcc\x92\x4f\xb2\xa8\xd9\xf8\x33\xb3\x14\x92\x2c\xc9\x0f\xfb\x2f\x4c\x55\x4c\x52\xa9\xdb\xfb\x2e\x66\x99\x49\xb2\x24\x16\xcc\xdd\xcc\x34\x9b\x64\x4a\x9e\x7c\xee\x19\x55\xe5\xa6\x64\x95\x18\x7b\x2f\x8b\xcd\x88\xb1\x78\xea\xb9\x8f\x79\xb2\xa2\x07\xcd\x3c\xf7\x33\x8b\x5c\xbc\x68\xe2\xf9\x2b\xb3\xc8\x15\x9c\x6a\xde\x79\x80\xa9\xe4\x32\x4e\x33\xed\xfc\x8d\x99\xe4\x52\x46\xb3\xce\x83\xcc\x22\x57\x31\x9a\x74\xfe\xce\x2c\x72\x15\xa7\x9a\x73\xfe\xc1\x54\x72\x19\xa7\x99\x72\x1e\x1a\x35\x4d\xcb\x55\xac\xcc\x38\x0f\xb3\x60\xb9\x8c\xd1\x84\xf3\x08\xb3\xc8\x45\x8c\xe6\x9b\x47\x99\x45\x2e\x62\x34\xdd\x3c\xc6\x2c\x72\x11\xa7\x9a\x6d\xfe\xc9\x54\x72\x11\xa3\xc9\xe6\x71\x66\x91\x0b\x38\xcd\x5c\xf3\x04\x33\x15\x89\x4a\xee\x6e\xb7\x96\x34\xd1\xfc\x8b\xc5\xc8\x25\x0b\xe7\x99\x27\x99\x46\x2e\x57\x34\xcd\x3c\x35\x6a\xc9\xcb\xa5\x8a\x66\x99\x7f\x33\x8b\x5c\xb3\xa9\x26\x99\xa7\x99\x4a\x2e\xdc\x34\x73\xcc\x33\xcc\x24\x17\x2f\x9a\x62\x9e\x65\x16\xb9\x78\xd5\x19\xe6\x39\x16\x2e\x17\xec\x52\x8a\x8f\xf3\x9f\x11\xd3\xd4\xd1\x53\x19\xf5\x3c\xfe\xc2\xab\x56\xbf\xb6\xbd\xd8\x74\xc9\x8f\x0c\x9a\xee\x34\x4d\xe0\xae\x69\x2e\x70\xe4\x52\xbc\xc4\x54\xc9\x8f\x0c\x89\xee\x32\x45\xe0\xbe\xc9\x2f\xfb\x9e\x93\xe2\x2b\x9c\xa1\x2b\x71\xfe\xd3\x4d\xa7\x9b\x26\xed\x2c\x63\x83\x9a\xbc\xcc\x54\xc9\x6f\x4f\x24\xba\xd7\x14\x69\xc7\x19\x3b\xcd\xe6\x15\x16\x26\xb7\xa5\x54\x36\x61\x75\x56\xf2\xea\x4a\x7e\x98\xf6\x56\x6d\xa8\x9b\x4b\x5a\x5c\xa2\xec\x1e\x53\x66\x83\xcc\x59\xca\x16\xba\xc2\x54\x95\x12\x93\xa6\x89\xee\x37\x45\x8e\xb2\xa6\x12\x50\x5d\x6d\xaa\xe6\xc5\x35\x21\xd1\x43\x86\x48\xbd\x6c\x29\xa1\x37\xde\x35\xa6\x4b\xee\x5a\xd0\xf4\xb0\x69\x02\x77\x89\x7a\x07\x3c\xc9\x74\x25\xce\xfa\xba\xe9\x5c\xd3\xa4\x75\x08\x27\x45\x89\x5e\x65\xea\xe4\x2e\x91\x46\xf6\xa0\x29\x53\xef\xee\x50\x27\xbc\xd2\x74\xc9\x5d\x02\x9a\x1e\x30\x4d\x5a\x87\x70\x40\xa1\x0a\xd9\x92\xbb\x03\x12\x09\x99\xd2\x3a\x43\x39\x4d\x17\xbc\xc9\xf4\xc9\xed\x21\x95\xed\x49\xd3\xa6\xf5\x88\x32\x78\xcd\x9e\x6c\xaa\xe4\x1e\x81\x44\xe7\x19\x22\xf5\xfe\xaa\x9c\xa2\x54\x6f\x30\x75\x72\x9b\x48\x23\x7b\xdc\x94\x69\x9d\xa2\x0c\x6f\x16\xcc\x8c\x29\x77\x5a\x58\x25\xe4\x4c\x9b\x71\x16\xd2\xd4\xc5\x09\xa6\x4f\x9e\x73\x52\xd9\xce\x36\x6d\x5a\x27\x5b\x40\xbd\xda\x9c\xc0\x94\x0b\x2f\x68\x32\x27\xb0\xac\xd6\xc3\x5c\x70\x82\x3c\xde\x54\x25\x5e\x17\xa8\xa2\xb3\x4c\x91\xd6\xc1\x5c\xf4\xfe\x30\x5f\xda\x59\xb9\x85\x41\x93\xf9\xd6\xce\x6a\x5d\xc2\x45\x3d\xfa\x72\xd3\x25\xb7\x09\x68\xba\xcf\x30\xe5\xb4\x3e\xe1\xa6\xd8\xda\x27\x9a\x3a\x65\x9c\xf0\xc3\x8a\x53\xab\x91\x8b\x7f\xff\x30\xb4\x68\x1b\xf1\xd0\x34\x5b\xe7\x14\xd3\x27\x6f\xc4\x54\xb6\xf3\x4d\x9b\xb6\x11\x77\xc1\x9e\x73\xbd\x29\x93\x77\x22\x56\x3d\x66\xaa\xe4\x6b\x90\x5d\x81\x18\x7f\xac\x19\xaf\x7d\x7f\x52\x01\x67\x20\xf3\x58\x90\xb3\xc4\xa5\x20\x91\x79\x24\xc8\xcd\x25\xaf\x29\x21\x41\x66\x3f\xce\xd9\x49\xab\x4a\x50\x99\xcd\x38\x57\x02\xeb\xd2\x66\x1b\xb3\xed\xe5\x9c\xc4\x55\x69\x22\xb3\xed\x4d\x6b\x5f\x33\x55\x50\x5b\x3f\xce\x74\xc9\x97\x46\xd0\x74\xa6\x69\xd2\xbe\x3c\xf5\x40\x31\x5c\x6b\xaa\xe4\x9b\x23\x24\x7a\xc4\x14\x69\xbf\x0a\xf0\x60\x29\x08\xab\x92\xef\x3e\xb1\x4a\x58\x97\xf6\x8d\xaa\x07\x8a\xe1\x3a\x53\x25\x37\x03\x24\x7a\xd4\x14\xa9\xc7\x01\xaf\x2c\x19\x2e\x30\x0d\xca\x29\x40\x8e\xbf\xc8\x8c\xd7\x86\x7f\x1f\xbd\x84\x85\xb4\xc8\x83\x3f\x34\x99\x79\xc9\x83\x5f\x3c\xbc\xf8\x8b\x3b\xad\x2a\xcd\x19\x5b\xb9\xf3\x4d\xe9\x33\xc7\xec\xbc\xf6\x16\x0d\xc0\x86\x31\xef\x36\x95\x4b\x57\x24\x32\xaf\x36\xf3\xda\xbb\x33\x80\xdb\xc5\x6c\x52\x79\xf9\xdd\x89\x55\x66\x97\xca\x6b\x63\x6c\x00\x36\x8c\x79\xb6\xcc\xcb\x63\x2c\x12\x99\xc7\xca\xbc\xb6\xf3\x6a\x20\xed\xe6\x9b\x2f\x2f\x6f\x41\x24\x32\xdf\x7b\x79\x6d\x2f\xd6\xd2\xcc\x52\xb7\x9b\x3e\x79\x3f\xa6\xb2\x3d\x67\xda\xb4\x11\xbb\x06\x4b\xc2\xbc\x83\xca\xcb\x33\x36\x56\x99\x97\x50\x05\xad\x57\xd4\x40\x51\x98\x03\x76\x41\x6e\x12\x48\x64\xce\xd8\x05\xf5\xc7\x24\xf0\x03\x9a\x8f\xb1\x20\x1f\xc2\xb1\xca\x7c\x86\x05\xad\x6b\x85\xe0\x23\x9a\x57\x03\x05\xb9\x6b\x21\x91\x79\x31\x50\xd0\xba\x56\x88\xe6\x21\xf3\x2c\x52\x90\x9b\x16\x34\x99\xe7\x90\x02\xf8\xdd\x94\x7a\x62\xbe\xcd\x54\x25\x7e\xf5\xa9\x8a\x9e\x35\x45\x5a\xcf\xaa\xa3\x37\xac\x50\x54\x72\xd3\x82\x26\xa1\xa6\xb4\xae\x55\x07\xf7\x6a\x42\xa6\xe4\x86\x85\x44\x42\xa6\xb4\x5e\x55\x4f\xf3\x2b\x9f\x9b\x4d\x9f\xdc\xae\x52\xd9\x9e\x32\x6c\x45\xf4\xf3\x37\x30\x8d\xdc\x62\x1a\x13\xbf\xd1\x46\xbe\xa7\x4d\x9f\xd6\xbf\xea\xe8\x12\xc4\xcc\x5d\x51\x6e\x5f\xd0\x24\xe4\x4d\x3b\x43\xef\x05\xaf\x5a\xb3\x51\x14\xe5\x33\x34\x12\x99\x7d\xa2\xa8\x9d\xa1\xf7\xa6\xb8\xe2\x39\xcd\xd4\xc9\xa7\xe8\x34\x32\x73\xb6\x2f\x6a\xe7\xe8\xbd\xa0\x49\x9f\x6a\xaa\xe4\x73\x34\x12\x5d\xc8\x45\x59\xbb\x48\x3a\x7e\x8e\x81\x97\x66\x48\xdf\xf7\xc6\x2d\x4b\xb6\x34\x4b\xc9\x49\x32\x7e\xa5\x90\x2d\xcd\x51\x42\x11\x9e\x61\xf2\x25\x1a\xd9\x50\x09\xff\xa7\xab\xd1\xd3\xda\x7f\x03\x00\x00\xff\xff\x72\xcc\xde\x1a\xd2\x4d\x00\x00")
+
+func fontsBubbleFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBubbleFlf,
+ "fonts/bubble.flf",
+ )
+}
+
+func fontsBubbleFlf() (*asset, error) {
+ bytes, err := fontsBubbleFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/bubble.flf", size: 19922, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsBulbheadFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x56\x4d\x8f\xdb\x36\x13\xbe\xf3\x57\x3c\x30\x16\x88\x88\xd7\x5a\x6e\x92\x7d\x51\xb8\x08\x02\xb6\x40\x7b\xe8\xa9\x3f\x80\xe8\x84\xb6\x28\x5b\x8d\x2c\x05\x96\x8c\x6c\x0a\xfd\xf8\x82\x33\xa4\x2d\xab\xd9\x3d\xf5\xd0\xc3\x02\x4b\xad\xc9\xf9\x7e\xe6\x83\xac\xdb\xfa\x9d\xbf\xc3\x23\x1e\xb1\xd9\xe0\x01\x6f\x7f\x50\x3f\x9f\xdb\xed\x21\xf8\x0a\xdb\x6f\xf8\x2d\xd4\xf8\xbd\x1f\x3e\xfb\xee\xaf\x70\x5a\xe3\xdd\xfb\x3f\xcf\xdd\xe6\x51\xfd\xda\xec\xdb\x30\xe2\x14\xda\xe0\x87\x80\x77\xf7\x0f\x28\x4b\xfc\x74\xde\x9f\x87\x11\xff\x5f\xe3\xed\x66\xf3\x5e\x81\x88\x08\x98\x2f\xe4\x33\xf0\x92\xcd\x9c\xa4\x8a\x48\x70\x05\xa0\xf3\x02\xf2\x99\xa6\x22\x1e\x11\x91\x06\x0c\x91\xcb\x24\x05\x0d\xc2\x07\xe8\x82\x48\xe4\xa2\xc6\x74\x06\x8a\x5c\x9a\xa5\x4c\x64\x70\xcc\xa0\xa1\x55\x11\x4d\x1a\xfe\x46\xc1\xeb\xd7\x44\x7a\x31\x3b\xca\x8b\xc8\x28\xf5\xcb\xd3\x97\xd6\x77\x7e\x6c\xfa\x0e\x7d\x8d\xba\x39\x0d\x23\xda\xa6\x0b\x3f\xaa\x08\x27\x4a\xac\x8e\x7e\xdf\xec\xd0\x9d\x8f\xdb\x70\x5a\xa1\xee\x4f\xa8\x9b\x36\xa0\xa9\x42\x37\x36\x75\xb3\x63\x61\xe5\x63\xd8\x25\x86\x43\x7f\x6e\x2b\xf8\xf6\xab\xff\x36\x60\x1b\xf0\xc9\xbf\x59\xb3\x50\xd7\x7f\x55\x77\xc2\x34\x1e\x02\x56\x07\x7f\xaa\xb6\xad\xef\x3e\xaf\x22\xde\x5f\x4e\x4d\x37\x0e\xf0\x03\x3c\xf8\x74\x8d\xed\x79\xc4\xce\x77\x6f\xc6\xa8\x66\x38\x9e\x87\x43\xa8\xd4\xa3\x68\x38\x84\x66\x7f\x18\xa3\xc7\x1e\xbb\x83\x3f\xf9\xdd\x18\x4e\x2f\x12\xd7\xe8\xfa\x11\x4d\xb7\x6b\xcf\x55\xd3\xed\x51\x85\x61\x17\xba\x2a\x9c\x06\xb5\xd9\xb0\xd8\xd1\x3f\x71\xe4\x68\x43\xb7\x1f\x0f\x28\xc2\x53\x66\xde\xf5\xc7\x63\xe8\x04\x98\x41\xe3\x7f\xf0\xa8\xcf\xd5\x3e\xa0\xf6\xbb\xb1\x3f\xa9\x07\x31\x5c\x85\xda\x9f\xdb\x51\x9c\x3d\xf6\x55\xe0\xc0\xc7\x43\x33\xa0\xee\xbb\x11\x45\xdb\x7c\x0e\x58\x95\x47\x3c\xac\xd0\x77\xac\xd6\x77\x15\xab\xd5\xea\xed\x7b\x56\x22\x40\x47\xef\x6f\xac\x2a\x75\x77\x67\xe7\xcb\x2a\xe3\xac\xd2\x85\x55\xce\x58\x55\x68\x6b\xd5\x34\x59\x05\x5c\x96\x55\x98\x30\xc1\xaa\x72\x2a\xa7\xf2\xf2\x4f\x0e\xad\x02\x4d\x04\xab\x0c\x26\xd2\x56\x39\x9a\xe0\xac\x2a\x68\x22\xc3\x44\xae\xea\x78\xa0\x0d\x34\x2b\x34\x30\x51\x00\x05\xd7\x54\x64\x12\x16\x14\xc2\x60\x88\x3d\x21\x32\x2e\x7a\x67\x15\xd2\x9f\x70\x46\x0e\x68\xab\x0a\x14\xf1\xb7\x13\x15\x62\x04\x2e\x1e\x69\x26\x93\x11\x09\x58\xe5\x26\x63\x95\x99\x9c\x6c\xf9\x4b\x4c\x00\x4d\x60\xef\x0b\x6e\x3f\x1d\x49\x13\x4d\x89\x49\x56\xa1\x63\x70\x22\x25\x32\x24\x12\x24\xfc\xb8\xe1\x4e\x12\xc9\x86\x84\xab\xd9\x65\x03\x71\x2a\xc5\x41\x12\xb3\x89\xcd\xca\xae\x73\xff\x71\x40\x94\x5d\xa7\x14\x2d\x9f\xc7\x3e\x67\xd4\x52\xc0\x94\x70\x15\xf9\xa8\xc8\x24\xb7\xae\x0c\x42\xd7\x2c\x26\x69\x21\x49\x0b\xb2\xf9\x7b\xce\x6c\x0c\x5f\xa2\x89\x5e\x5c\xa5\x27\x70\x90\x13\x2d\xa5\x93\xef\x9a\x13\xcf\x44\x97\x89\xb7\x76\x17\x71\x27\x22\x98\xf8\x7d\xc9\xcb\x29\x60\xa4\x4a\x32\xbe\x85\x9e\xe1\x3b\xdb\xa8\x0b\x5c\x62\xd0\xaa\x0f\xf8\x20\xb5\xe1\xec\x3f\x12\x36\xdf\x59\x25\x38\x38\xc1\xf0\x23\x3e\x5a\x65\x92\xc1\x25\x7e\x46\xd0\xd7\x8b\xd4\xb8\x88\x52\xa1\x8d\x64\x2e\x57\x57\x2a\xaf\x34\x92\x23\xa7\x8c\x59\x56\xa8\x67\x39\x14\x38\x24\x64\x19\xcf\x29\x87\xe6\x52\x26\x92\x5c\x92\x92\x97\xbd\xa3\xb9\x86\x8b\x0a\x2e\xfe\x54\x47\xa2\x04\x37\x66\x12\x02\x3a\xce\xfd\x45\xa9\x3c\xc3\xa0\x67\xe5\x7a\xeb\x47\x79\x9f\x6b\x35\xb5\x1f\x44\x05\xdf\x48\x29\x96\x42\x1a\x1f\xc5\xad\x99\x5c\x6c\x11\x88\x1b\x3f\x32\x07\x32\xcb\x7d\xc9\x97\x97\xd4\x48\xae\xcc\x8b\x25\x93\x0c\x65\x3b\x79\x14\x08\xf8\x72\x51\x0a\x22\xb4\x08\x37\xe5\xaf\x00\x5c\xea\x2e\x1d\xfb\x58\xf4\x18\x67\xae\x43\x45\xd8\x5c\xf1\x9c\xa9\x59\x06\x85\x25\x5e\x91\xd9\xda\x33\x59\x66\xd0\x66\xe8\xbe\xac\xc5\x38\xf7\xfd\x5a\xe1\xfe\xb8\xf1\x45\xba\x47\xc6\xf0\x6d\xc7\x2e\xa1\x87\xc0\xca\xd3\x04\x4b\x4c\xf8\xbd\x90\x80\x9b\x05\xb3\xc4\x44\xe0\x77\xe0\x0e\x17\x24\x73\x29\x5c\x58\x9c\x59\xa2\x4b\xc6\x3d\xa3\x49\x5f\x13\xf0\xb2\xa9\x99\xd3\x97\xa8\xf2\xb0\x59\x66\x3a\x76\x27\xf2\x87\x28\x3b\x28\x77\x05\xb7\x92\xb4\x4d\xba\x47\xa4\xfc\x30\xa5\x0f\xd1\x64\x59\xaf\x74\xee\x1f\xd7\x89\x3f\x1b\xfc\xb3\xed\x72\xba\xb8\xdb\xcb\xeb\x75\x2e\xbc\xce\x85\xd7\xb9\xf0\x1f\x98\x0b\xeb\xd2\x2a\x8a\x0f\x1f\x7e\xfd\xe0\x53\x99\x9e\xc1\xf1\xe5\x1b\x97\x8b\xe0\x94\xf7\xcc\x40\x89\xab\x7c\x73\x79\x4f\x9a\xf8\x40\xcd\x6d\x6f\xaf\x3d\xae\xfe\xfd\xcd\xdf\x01\x00\x00\xff\xff\xd8\x64\xdc\x2f\x8d\x0e\x00\x00")
+
+func fontsBulbheadFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsBulbheadFlf,
+ "fonts/bulbhead.flf",
+ )
+}
+
+func fontsBulbheadFlf() (*asset, error) {
+ bytes, err := fontsBulbheadFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/bulbhead.flf", size: 3725, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsCalgphy2Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xe4\x5c\xeb\x8f\xdc\xb6\x11\xff\xae\xbf\x62\x6c\x0a\x48\x53\x38\x47\x3b\x4e\x9c\xc6\x48\x82\x6d\x81\xba\x4d\xd1\x22\x05\x12\x34\x5f\xfa\x85\x27\x71\x77\x85\xd3\x4a\x6b\x3d\x7c\x39\xa0\xe8\xdf\x5e\x50\x7c\xcd\x90\xd4\xde\x3e\xb4\x57\xa7\xbd\x60\x1d\x72\x28\x51\xe4\x3c\x7f\x33\xd4\xee\xba\x5e\x7f\x2e\x72\xf8\xfc\x25\xbc\x7a\x03\xaf\xbf\x80\x97\xf0\xfa\x25\xbc\xcc\xfe\xd6\x96\xd5\xba\x92\x25\xdc\x3e\xc0\xdf\xc5\x58\xc3\x1f\xc6\x6e\x68\x1b\xf8\x51\xee\x07\xb9\xbb\x95\x1d\x7c\xfd\x06\xd6\x5d\xbb\x83\x42\xd4\xd5\xa6\x13\xfb\xed\xc3\xcd\xba\x5e\x83\xe8\x41\x40\x29\x77\x6d\xd3\x0f\x9d\x18\xaa\xb6\x81\x76\x0d\xd9\xbb\x6a\xf3\x73\xd5\xc0\x5a\x8a\x61\xec\x64\x7f\x03\xa0\x9f\x50\xe8\x4b\x86\xb6\xbd\x03\x71\xdb\x8e\x03\x7c\x09\xbb\xaa\x19\x07\xd9\xc3\xd8\x57\xcd\x06\xf4\x9d\x9f\xf4\xf0\xbc\x93\xc5\x20\x9a\x4d\x2d\x21\xeb\xa5\xe8\x8a\x2d\x88\xa6\x84\x4e\xee\x6b\x51\xc8\xe7\x76\xee\x1b\x80\x9f\xb6\x12\x8a\xad\xe8\x44\x31\xc8\xae\x87\x7d\x27\x3f\x54\xed\xd8\xd7\x0f\x50\xb4\x4d\x5f\xf5\x83\x2c\xd5\xa2\xda\xa6\x7e\x80\xe7\xbf\x7d\x0e\x99\xbf\x58\xdf\xdd\x4f\xf7\x37\x1b\xd9\x43\x27\xdf\x8f\x55\x27\x4b\x18\xee\x5b\xe8\x07\xb9\xef\xdf\x66\xd9\xbb\xaa\xeb\x87\x17\x20\xea\x1a\xaa\xa6\x1f\x44\x53\xc8\x5e\xcd\xa8\x26\xbb\x97\x9d\xb4\x8b\x2a\xe1\xbe\x1a\xb6\xf0\x9c\x3d\x87\xa1\x85\x4d\xf5\x41\xc2\xb0\x95\xb0\x6e\x9b\x41\x71\x49\x74\x77\xb2\x83\x4c\xec\xf7\x52\x74\x6a\x92\x1b\x80\x2c\x83\xb9\x3f\x96\x26\xf3\xec\xa7\xad\x6c\xe2\xd5\xbc\x55\x37\xc4\xab\x79\x0b\x1c\x00\x7e\xf3\x47\x51\x6c\xd5\x92\x87\x69\xb7\x95\x92\x5a\xe6\x19\xdc\xae\x61\xdd\x8e\x1d\xf4\xef\x47\xd1\xc9\xfe\x05\x54\x4d\x51\x8f\xa5\x92\x87\xe2\xc3\x6d\x2d\x9a\xbb\xfe\xe6\xd3\x2c\xfb\x7d\xdd\xb7\x20\xca\x52\x96\x20\x60\x2f\xbb\xaa\x2d\x5f\x80\xfc\xa5\xa8\xc5\x4e\x4b\x76\xdf\x56\x8d\x62\x55\x53\xc2\xfb\x51\xf6\x13\x6d\x27\xba\xbb\x89\xa2\x99\x5c\x4e\x4c\xc9\x4a\xb9\x16\x63\x3d\x40\xbf\x1b\xfb\xed\xae\x2d\xe5\x4d\x96\xfd\xd0\x55\x9b\xaa\x11\x75\xa8\x65\x45\xbb\xdb\xb7\xbd\x56\xcf\x7f\x54\x4d\x23\x1f\xe0\xa7\xad\xa8\xe0\x87\x62\x68\x27\xe5\xfc\x22\x83\xcf\x0e\xfd\x7d\xfb\xcd\x37\x46\xb3\xe0\xcf\x0f\x7b\x09\xdf\x7d\xf7\xed\xc1\xeb\x3f\xcb\xac\x5e\xb4\xbb\x9d\x6c\x86\x5e\x73\x76\x23\x1b\xd9\x09\xa5\x4f\x62\x1c\x5a\xb5\xe5\x42\xd4\xf5\x83\x5a\x96\x9e\xfd\x05\x34\xed\x30\xed\x4f\x8c\xc3\xb6\xed\x0c\xcb\xb3\x49\x07\x6e\xc0\xae\xa1\xea\xa7\x6b\x7e\xae\x9a\xb2\xbd\xef\xa1\xa8\xdb\x66\x12\xc2\xbb\xef\xff\x54\xcb\x41\x6b\x91\x80\xf5\x58\xd7\x56\xcd\x4b\xad\x45\xb2\xac\x86\xb6\x7b\x96\xc1\xbb\xb6\xdb\xc8\xc1\xd8\x50\xd9\x4e\x92\xda\x4a\xd8\x89\x61\xab\x74\x6f\x5d\x6d\xc6\x4e\x82\x1a\x54\x64\xc7\x63\x68\x46\x65\xcd\xcf\x00\xfe\x32\xf6\x03\x14\x5b\x59\xdc\x81\xc8\x60\x2d\xef\xe1\xb6\xfd\x45\xf6\xb0\x6e\x3b\x90\x4a\x59\xa6\x7b\xd4\xbc\xdd\x58\x2b\x4d\x25\x4f\x94\x4d\xa9\xa4\xda\x3f\x03\xf8\xab\xd4\xcf\x50\x32\x1a\x07\xd9\x65\xf8\xe1\xdb\xf6\x1e\x06\xa5\xa9\x4a\xfc\xaa\x73\x5f\x95\x12\x1e\x94\xae\x4d\xfb\xa9\x94\x05\x4e\x4b\x29\x3b\x71\x3f\xd1\x7a\xbd\xfd\x69\x37\xed\xd8\xcb\x6c\xba\xf7\xbe\xda\x4b\xbb\x95\x72\x23\xa7\x87\x43\xbb\x5e\xeb\xb9\xfa\xa2\x93\xb2\xd1\x0e\x4a\x3d\x6d\xd8\x8a\x01\x8a\x76\x6c\x86\xaa\xd9\x3c\xcb\x32\xc4\xf7\x89\xa9\x4a\xdf\x8d\x6b\x7a\x01\xb7\xe3\x00\xd5\xf0\x49\x0f\xa5\xec\xab\x4d\x33\xb1\xba\x83\xb1\x97\x4a\xac\x62\xda\x57\x2d\x07\x09\x55\x59\xb5\x4a\x86\xdf\xaf\x33\xf5\x54\x78\x3f\x8a\xba\x5a\x3f\xbc\x80\x0f\x55\x5f\x69\x1e\x98\xc7\xdc\xcb\xdb\xbe\x1a\x14\xd3\x7e\xd4\x0b\xeb\xb7\xed\xd0\x83\xe8\xa4\x6a\xdd\x37\xda\x3e\x5a\xa5\xd7\x63\xa7\x76\xa8\xa6\xbb\xaf\xea\x1a\x6e\x25\x88\xdb\x5a\x2a\x11\x96\xed\x7d\x53\xb7\xa2\x84\x6a\xb8\x99\xf3\x12\xdb\x61\xd8\xbf\xe5\x7c\xdb\xee\xe4\x8d\x14\xdd\xb0\xad\xab\xe6\xee\xa6\x91\x03\xff\x77\xdf\xd6\xa3\xb2\xbe\x2c\xcb\x21\x5f\x5d\xf9\x9f\x95\x5f\xdf\x2a\xcb\x19\x63\xb9\x69\x82\x69\xab\x26\x2c\xdc\x64\xc0\xa7\xc7\xab\x36\xcf\x35\xd5\xad\x41\x51\xf1\xb5\x79\x40\x45\xeb\x7d\xac\xa9\xda\x8f\x7f\xca\x7c\x95\xb5\xf9\x2a\x1b\xf3\x55\x76\x9b\xaf\xb2\x3a\x5f\x65\x32\x5f\x65\xef\x0d\x4d\x8d\x0d\x9a\x76\xdc\x84\x73\x9f\x3d\x7a\x50\x93\x4f\x0f\x3e\x7f\x32\xbb\xea\xda\x7c\x44\xbe\xca\xba\x73\x27\xdc\x9b\x2d\x77\xf9\x2a\x2b\x4c\xbb\xd1\xdb\x3e\x6d\x22\xb5\x8a\x5d\x4e\x27\xec\xcd\xea\x4e\xda\xb2\xba\xa9\x32\x37\x6d\xce\x15\x4a\x8b\x56\xd2\x98\xb6\xe1\x13\xde\x62\xb6\x35\x7d\xf5\xd0\x87\xb9\x09\x0b\xb3\x8a\xd6\x5c\x28\x2f\x9d\xf0\x31\x3e\xf6\x7e\x8b\xd3\x03\x2a\x4f\xbb\x4c\x0f\xad\xc4\x6b\xc3\xcb\xfe\xd2\x09\x0b\xc3\x96\x9d\xf9\x88\x4b\x27\xdc\x21\xe9\xa3\x15\x7a\xf3\x5e\xfa\x7f\x39\xcb\xad\xff\x73\xbd\x03\x37\x5c\xb6\xbb\x1e\x99\x6c\xaf\xb5\xe5\xbc\x89\x2c\x7b\x76\xc6\x73\x59\x4d\x79\xb9\xf4\x84\xaf\x96\x9e\xf0\xf3\xa5\x27\x7c\xbd\xf4\x84\x5f\x2c\x3d\xe1\x97\x4b\x4f\xf8\x66\xe9\x09\xbf\x5a\x7a\xc2\xdf\x2d\x3d\xe1\xd7\x4b\x79\x2a\xeb\xc8\x9b\x53\x27\xb4\x9e\xdf\x7a\xa8\x8b\x27\xc4\x9f\x1a\x85\x8d\xde\x6f\xfb\xb2\x2d\xe3\xa8\x29\xf4\x4a\xcf\x9b\x68\x83\x02\x9d\xa0\xb1\x69\x45\x50\xae\xea\x31\xfd\x37\x81\xb7\x29\x8f\x05\x0d\xe6\x56\x19\x77\x59\xb2\xea\x31\x9b\x2b\x7b\x97\xab\x32\x65\x7d\x9f\xef\xb8\x1e\xcf\x91\x1f\xd6\x1d\xd3\x33\x1d\xd3\x63\xa4\x07\x0e\xd7\x6a\x6a\x4e\xc6\x70\x8f\xd1\x2b\xc9\x58\x02\x62\x3e\xd6\xbb\x4c\x74\xf8\x23\x7c\xe4\x0f\xff\x3c\x8d\xd9\x6d\x3b\x0e\x31\x16\xd2\xb8\xdf\x24\xbe\x97\xc7\x34\x8e\x26\x3c\x40\xe3\xf8\xc9\xf3\x34\x0e\xb1\x24\x38\xf3\x7a\x62\x68\x9c\xee\x65\xa2\xb1\x98\x36\xdd\x89\x88\x46\xcb\x2c\xd5\xa4\x18\xdc\x5c\x60\x2e\x9c\x72\x0d\xb7\x4d\xcc\x3f\x16\x52\x0f\xf3\x19\xd1\x62\xa2\x53\x39\xb5\x16\xbb\x38\x63\x10\x96\xcf\x6a\xb9\x4c\xef\x96\xdb\x6b\x38\x58\x82\xbf\xcb\x12\x90\x11\x4c\x93\x12\x43\xd0\x14\x6c\x0c\x13\x85\x18\x84\xbe\x86\x61\xa6\xea\x79\x34\xcd\xb2\xd9\xb0\x4a\xc3\x20\xa0\x62\x33\x6c\xb7\x3c\xd5\x77\x71\x67\xea\x66\x66\x37\xec\x84\x9f\x60\x6d\xc0\xee\x59\x1e\x1e\x64\xb4\x25\xd0\x6d\x4d\x0c\xd3\x9c\xce\xad\x42\xe9\x45\x72\xbd\x4d\x0e\x76\xdf\x4e\x6d\x88\x3d\xf8\xc1\x05\x09\xd3\x23\xa9\x85\x29\xfe\x1b\x16\x5b\xfe\x1b\xee\x7b\xef\xa7\x19\x4b\x1c\x20\x63\x49\x9f\x74\x26\xe1\x90\x9a\x23\x05\x36\xa6\x49\x54\x78\xe2\x9d\xd7\x59\x86\xb5\xd8\x6a\xad\xd7\x2d\x47\xb2\x61\x00\x90\x0a\x62\x8d\x5b\x9c\x06\x31\x0d\xb9\x19\xab\x14\xcc\x2a\xb6\x63\x3f\x07\xaf\xda\x1c\xeb\xf6\x61\xed\x5e\xdc\x9d\x24\xfc\x49\xe8\x50\xb4\xb3\x23\x1e\x45\x6b\x3b\x27\xb2\x20\x3e\x25\x27\xd3\xbb\x99\x1f\x27\x51\x77\x6d\x49\xa1\xf3\x09\x6e\x84\x88\x04\x78\x0d\x40\x7c\x8b\x1e\xa3\xce\x05\x6f\x88\x2e\x22\x12\x40\x82\xff\xf3\x5c\xbd\x02\xf3\x21\xc1\x7c\xf8\xe8\x98\xcf\x22\xe6\x33\x4a\xb2\xcc\xf7\x3e\xcb\x04\x75\x3c\xd7\x93\x30\xdf\x7b\xf8\x84\x8f\xf7\xb0\xc1\x79\x79\x88\xfd\x7c\xc2\xd3\x27\xfc\x34\x22\xf9\x9d\x22\x92\x8f\x2b\x96\x84\x22\x8b\x21\x79\xe4\xe3\xbc\xbe\xe7\x77\xe4\xf7\x21\xf6\xfc\x09\xdf\x9f\xf0\xfe\x47\xb3\xf5\x6c\xe6\x87\xca\x4f\xe0\x97\xd3\x7f\x03\xb9\x42\x13\x00\x96\x72\x41\x4a\x90\x34\x50\x7b\xd6\x04\xa8\xe4\x68\x2a\x4b\x5a\xc0\xa1\x19\xb0\x01\x41\x8a\x8a\xc2\x03\x01\x9c\x31\x34\xe5\x88\x39\x40\x70\x5c\x60\x05\xa9\x38\x91\x8e\x14\xe9\xb8\x30\x4b\x3d\x28\x5f\xb3\x36\x17\xf6\x9c\xd4\xbc\x33\x62\xc8\x23\x79\xfc\xcd\x83\x44\x0b\x7b\x2d\xaf\x8a\x21\xe8\x8f\x49\x9c\x85\xa4\x29\x36\x3d\x72\xa3\x35\x2e\x14\x64\x35\x89\x24\x79\x86\xed\x9c\x62\x2a\x6f\x32\xd8\x90\xf2\x43\x6c\xbc\x92\xd5\xa4\x10\x54\x2a\x70\x60\x29\x20\x98\x0a\x33\xb1\x3b\x19\x41\xd2\x8e\x7f\x86\x4a\x84\x92\x96\xcb\x59\xf3\x9e\x48\x8d\x42\x10\xf1\x81\x96\x6a\xac\x0b\x11\xad\xdd\x01\xe3\xd4\xc2\x48\xce\x49\x9f\x16\x46\xa4\xb4\xe0\x20\x10\x53\x1c\xc6\x58\x82\x0e\x10\xb8\x3e\x88\x62\x26\xf2\x89\x41\xcd\xc2\x7a\x1a\x9e\x4c\xd7\xc0\x65\x87\xf1\x48\xb0\x79\xef\x0e\x79\xcc\x00\x92\xfc\x25\x46\x52\x36\xe2\x5c\x23\x4b\x21\x37\xd3\x67\xa4\x16\x40\x00\x1c\x76\xca\xd4\x4d\x9a\x70\xe7\xf2\x73\x34\x00\x0e\x3c\xa5\xdc\x25\xcc\xba\x4c\x98\x75\x90\x8f\x8c\x24\x87\x48\xd8\xc3\x62\xc1\xfe\xd3\xed\x8d\xc5\x16\x49\x7d\x28\x9a\x93\x47\x9a\x1c\x9a\xc7\x35\x89\x90\x20\xa6\x34\x89\xc8\x31\x05\xc5\x13\x60\xdc\x83\xa5\x58\x38\x49\x99\x1d\xe2\x7c\x40\x3c\xce\x5a\xc1\x2b\x6c\x5c\x72\x41\x48\x39\xc4\xea\x7e\x2c\xb0\x56\x8d\xde\xc0\xa7\xb0\x1e\xc5\x80\xf3\x29\xd4\x5a\x9f\x78\x84\x54\xc8\x66\x46\x9c\xb5\x06\xd5\x32\x24\xe5\xb8\x8e\x46\xac\xd5\x0c\xa5\x81\x0d\xcc\x82\x1b\x78\x22\x6b\x85\x50\x0f\x42\x16\x78\x35\x00\x48\xc3\x55\xe7\xe8\x42\xc4\x6a\x79\x1a\x95\xe3\x8c\xd7\x4c\x89\x66\x6e\x40\xab\xd3\x49\x03\x53\xf3\x98\x01\x17\x3c\x21\x2c\x60\xe3\x7a\xaa\x1f\xa0\x16\x1e\x66\x48\x71\xe4\x9b\x91\xfc\xac\xe0\x67\xe5\xfe\x98\x04\x13\x03\xd1\x48\x94\x15\x92\x9c\x10\x03\x59\x97\xf0\xd1\x7c\x10\x57\x2e\x2d\x67\x70\xe2\x07\xb0\x18\x81\x64\x80\x1a\x87\x7f\xb4\x75\xbf\x13\x90\x6b\x9c\x3f\x00\xaa\xf5\xd1\x94\x2f\xa8\xba\xd1\x7a\x32\x84\x6a\x7d\x90\x6a\x90\x2b\xe5\x9e\x45\xae\x01\x0b\xc1\xa7\x87\x01\x1f\xa3\x32\xca\xa5\x78\x36\xcc\x57\xd2\x29\x4b\x3a\x6b\x49\x27\x2e\xe9\xdc\xe5\x7f\xc6\x1a\x8c\x6e\x21\x6b\x60\xe8\x14\xc2\x8a\x12\x95\x75\x27\xee\x50\xed\x60\x54\x5d\x22\xfd\xa1\x4a\x82\xfa\x84\xa0\x55\x23\xb6\x06\x0a\x01\xed\xda\x7c\xd5\xc3\x72\x8d\x91\x23\x9b\xb8\xe0\x4a\x83\x86\x7b\x3a\x01\xf1\x98\x12\x9e\xea\xb0\xe8\x54\x07\x0b\x11\x47\x9d\xf0\x0c\x07\x55\xde\xc1\xbb\xef\x20\xf0\x6b\x7e\xd9\x22\x0e\x0d\xf4\xa8\x88\x72\xbd\x33\x1c\xe2\xdf\x58\xa8\xc1\x6e\x91\xc8\xaf\x00\xdd\xae\xcf\x29\xf2\xa4\xcd\x20\x56\xd2\xc2\x19\x63\x51\x55\x91\x10\x89\x2f\xf4\x2a\xe0\x88\x1c\x29\xa8\xa7\xc5\x1a\x89\x4e\x18\x2c\x8d\x53\x9c\x15\x9e\x2f\x90\x82\xd6\xbf\x12\xb8\xf9\x9f\x9f\xc6\x99\xe9\x0c\x57\x31\x69\x16\x71\x73\x0a\xf6\x4e\xc4\xfb\xfa\x1e\x9c\x63\x1b\x43\xe7\x90\xa8\x3d\x40\x9c\x4f\x86\x45\xd8\x25\x88\xc0\x92\x55\x6f\x5a\x7b\xa5\xce\x24\x78\xd1\x80\xd4\x5f\x11\xeb\x68\xca\x7b\x0c\xe3\x97\xc8\x75\xa8\x3f\x02\x8c\xe3\xbd\x53\x9a\x49\x71\x9c\x4a\x79\xf7\x64\x6d\x9b\xfa\x28\xc6\x52\x19\x07\xc0\xd3\x92\x21\x2c\x9a\xc7\xc2\x0b\x63\x37\xae\xa7\x87\x02\x0c\x2b\xe8\x2e\xd8\x1c\x90\xc2\x52\xe4\xe3\xf2\x15\xfc\x62\x44\x20\xd0\x03\x22\x9d\x15\x2a\x0a\x4f\x54\xac\xe1\x1b\x02\xfe\x0e\x36\x37\x30\x77\x47\x58\xab\x0a\x04\xf6\xd8\x1d\x48\xc4\x3c\x0f\x59\x02\x74\xa6\xb4\x95\xc2\x9c\xa5\xc2\x9c\xb5\xc2\x79\xd9\xc7\x02\xf9\x4a\xea\x3e\x62\xc8\x7e\x9d\x29\x7b\xf6\xdb\x48\x9b\xb5\x0f\x91\x09\xeb\xb6\x5c\xc8\x63\x23\x77\x4b\xb2\xa3\x44\x8e\x1f\xcd\x28\x71\x07\xf1\x28\xf6\x0a\x6e\x14\xa1\x3e\xaf\xfc\x2c\xe1\xf9\x9d\x8f\x00\x96\x48\x15\xc0\xe3\x22\x60\xf3\xf9\x17\xf9\xbb\xe2\xe8\xdc\xb0\x51\x1a\x4f\x40\xf9\x3c\xaa\xe3\x30\x5b\xba\xd4\x8a\x82\x19\xa3\xf7\xed\x55\x13\x00\x1d\x3b\x50\x56\x46\x25\x4d\x3d\x10\x55\x35\xed\x40\x92\xce\xd3\x47\x32\x29\x70\x00\x28\x8d\xa4\x74\x1e\x3e\x83\xc2\xc6\x00\xdc\x91\x72\x07\xb3\x28\x07\x93\x01\x1c\xd0\xa1\x64\xc0\x88\x3b\xf1\xb7\x18\xfd\xb1\x1b\x52\xd1\x7f\x26\xfc\xcf\xc4\x7f\x38\x00\x00\x66\x10\xc0\xc1\x30\x7d\x4d\xfa\x2c\x0e\x98\x05\x02\x5e\xa7\x03\x3a\xc5\xac\x14\xc7\x27\x21\x3f\x1a\x0d\x6a\x32\xde\x1d\xf8\x17\x87\x98\x1f\xe2\x8c\xbc\xf1\x6a\xaf\x35\xc8\x64\x69\x04\x6e\x72\x33\x32\x9d\xf5\x60\x78\xc2\x08\xc4\x42\x74\x9a\x8b\x69\x84\x18\x87\xdb\xd4\xe9\x63\xda\x31\xa4\xbc\xc2\x52\xa7\x0d\xb3\x16\xb9\x04\x02\x7f\xfc\x63\x5f\xd5\x5e\x9b\x17\xa1\x6f\xcd\xcb\xd1\xc2\xbc\x13\x7e\x67\xc6\x4f\xfe\xb2\xce\x6d\x30\xc9\x59\x5f\x16\xb1\x5f\x17\xda\x98\xef\x22\x2d\xba\xc2\xf0\x53\x04\x5f\x82\x3a\x69\x42\xf4\x5d\x38\xf2\x85\x31\xfb\x5e\x7d\x77\xce\x17\xef\x42\xe1\xcc\x7c\x69\x2c\xad\x08\x67\x77\x70\xbd\x8d\x83\x7f\x05\x95\x3b\x1f\x60\x5f\x77\xb7\x86\x7b\x4a\xc7\x7a\x16\x0b\x57\x72\x14\xf7\xc3\xaa\xc3\xb1\x9d\x68\x08\x19\x3b\xc1\xd3\x41\x65\x73\xbe\x83\x98\x60\x50\x15\x79\x5f\x6a\x51\x26\x38\xa7\x96\x86\x66\x67\x33\xe1\xf2\xce\x71\x9a\x70\x0e\x7f\x5d\x0a\x64\x98\xe0\x91\x1b\x2a\xc9\x2c\xc4\x84\x10\xfd\xe5\x27\x75\xf0\xcb\xef\xde\x67\x7b\x4d\x60\x1f\xb7\x26\x5c\xdc\xe6\x81\x0a\x90\x97\x8a\xf1\xde\x35\x53\x6c\x4c\x73\xed\x9c\x4a\x5f\xd3\xc1\x06\x48\x14\x17\x29\xee\x3b\x69\x9d\xa8\x83\xd6\xac\xa6\xe7\x64\x95\x76\x91\xb9\x5f\x4b\x8e\x97\xe5\x56\x8b\x8c\x3f\x7d\xed\x59\xcd\xe8\x75\xb1\xa3\x9a\xab\x20\xba\x5f\xa7\xcf\xa3\x34\xc3\xa7\x59\x3e\x75\xe1\xfe\x75\x50\x6c\x58\x97\xf6\x01\xc3\xda\x95\x45\xa9\x71\xba\x42\x0e\x57\xbc\x40\x2d\x78\xd5\xd6\x84\x10\x56\x7c\x2a\x82\x83\x03\x8e\x0d\xa1\x8a\xce\xb5\xbd\x6e\x4d\x19\x8c\x53\x2e\x8e\xb4\xcb\xee\xed\xb2\xb6\x3f\xfe\x58\x21\x18\xba\x42\xe8\xd3\xb4\x51\xaa\x1f\xc1\x73\xda\x72\x59\x03\xae\xd2\xe4\xe1\x75\x28\xbb\x20\xd5\x9c\x4b\x5a\xee\x15\x41\xff\x5a\x60\x62\x7d\x51\xcb\x35\x49\xc3\x6b\x91\xf3\xd1\x39\xbd\x86\xb1\xc4\x35\x2e\xa3\x34\x43\xd6\xdb\xa6\x2f\x46\x8a\xe6\xea\x37\x61\xc3\x9d\xdc\x92\x99\xaf\x00\x46\xbc\x13\xf6\x5a\xe7\xd4\x8e\xbb\x11\x40\x7b\x42\x89\x51\xf8\x06\x2a\xfa\xca\x81\x3b\x85\x43\x1e\xd2\x3a\xe6\x58\x5a\x67\x85\xa0\xeb\x28\xd4\xd3\xab\xe0\xcc\x4e\xaf\x41\x32\x07\x75\x18\x84\x82\x41\xa1\x5c\xd7\xff\xb8\x3d\x73\x06\x5b\xf4\x73\x21\xd4\x57\x22\x9c\x2e\x2f\x49\x62\xfe\x1f\x7c\xce\xed\x68\x8b\x72\x22\xa0\x2d\xda\xc5\xef\x80\x18\xd5\xd4\xd5\x53\xc4\xdc\x90\xb1\x01\x6f\xce\xee\xb2\x30\x96\x41\x92\x79\xa7\x75\xcf\xb2\xd3\xff\x66\x26\x48\x51\x35\x86\x02\x71\x99\xe7\x74\xbf\xf3\xeb\x62\x02\xc1\x3f\x81\x8f\x3e\x2a\x4a\xa0\x43\xe2\x5f\x2d\x13\x80\x56\xc4\xa2\xf2\xd8\x91\x1d\x5d\x54\xf8\xa8\x7c\x07\xa9\x33\x5e\xd6\x65\xa4\x8e\x39\x7b\x8a\xff\xf1\xf9\x0e\x04\x2c\xbc\xc6\x90\xe5\x07\x59\x6f\x50\x07\x70\x6f\x78\x99\x58\xa3\x91\x3e\xb3\xef\xb6\x5b\x76\x84\x27\x5f\xe7\xf9\x8e\xc3\x6d\xe4\xa0\x58\xb2\x4d\xea\x04\x3e\x25\x9e\xbd\xfe\xb2\x76\x50\xe1\x78\x7c\xfd\x89\x0d\x47\xec\x58\xa4\x8f\x8a\x24\x96\x31\x60\x23\x9e\x87\x99\xc8\x56\x98\x3f\xe9\x85\x4b\xfa\x9c\x3a\x11\x0e\x24\x73\x4c\xd5\x1a\xcf\xd9\xdf\xa5\x5e\x24\x3f\xd0\xf5\xac\x0a\x50\x04\xc3\x80\xc4\xc1\x06\xc4\x88\xb3\xbb\x1c\xb3\x88\x05\x6f\xf1\x46\x66\x75\x91\x8f\x39\x70\xe1\x65\x03\x84\x8b\x47\x0d\x60\x9d\x0c\xe0\x07\x19\x41\x5a\x0b\x98\x92\x80\x89\x10\xe9\xe5\x35\x06\xb8\x17\x1b\x10\xc1\x21\x01\x12\x11\x62\x51\x2e\xcc\xf6\xb9\x81\x68\xe4\x5a\x04\x8e\xcd\xc5\x46\x06\x70\xe1\xc1\xb2\x47\xff\x40\x02\xd2\x6c\x1e\x78\x4f\x1e\x04\x54\x0e\xf1\xf9\x3b\x56\x11\xf4\x2b\x22\x7a\x1d\x66\x49\x8c\xfc\x72\x0b\x24\x93\xe9\x73\x77\xfb\x54\x4c\xa5\xde\x3b\x72\xdf\x10\xfa\xef\xc8\x21\x2f\x45\x00\x96\x2c\x10\x26\x2a\x84\x41\x89\x30\xae\x11\x06\x45\xc2\x74\x95\x70\x19\x08\x84\xf1\x2b\x47\x28\x00\xbd\x27\xe7\xee\xc1\x2f\xf3\x60\x04\x13\x02\x60\x7c\x0f\xcd\x18\xe7\x3b\xfc\x88\xe7\xa0\xca\xe1\xea\xe0\x11\x64\x61\x8e\x20\x3b\x73\x9c\xfb\x70\xcd\x13\x59\x30\x3f\xf0\x58\xf9\xdf\xbf\x5c\x3d\x7a\x3e\x5c\x98\xd5\x8c\x4f\xb1\xc2\xc1\x2c\xa0\xf4\x3f\xed\xb9\xca\x8e\xfc\xef\xff\xf5\xc2\x57\x6f\x5e\x3e\xcd\x2f\x02\xbf\xfa\xea\xf5\x45\xc2\x4d\xfe\x7a\xe7\x7f\x02\x00\x00\xff\xff\xda\x71\xad\x47\xbf\x5e\x00\x00")
+
+func fontsCalgphy2FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsCalgphy2Flf,
+ "fonts/calgphy2.flf",
+ )
+}
+
+func fontsCalgphy2Flf() (*asset, error) {
+ bytes, err := fontsCalgphy2FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/calgphy2.flf", size: 24255, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsCaligraphyFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5c\x4b\x6f\xe3\xc8\x11\xbe\xf3\x57\x14\x0c\x02\xbb\xdb\xb1\x8d\xb1\x67\x36\xc9\x2c\x16\x0b\x5e\x72\xd9\xcb\x02\x41\x90\x73\x68\x89\xb2\x98\x91\x48\x47\xa4\xb0\xe3\x7f\x1f\x48\xec\xc7\x57\xd5\x45\x3d\xf8\xf0\xac\x83\x08\xa3\x31\xbb\xaa\xbb\xd8\x5d\x55\x5d\x2f\x36\xb5\xda\xac\x1e\xf3\x94\x1e\x1f\xe8\xe1\x33\x7d\xfc\x40\x77\x0f\xf4\xf0\x29\x59\xe4\x9b\xf2\x79\x97\xbf\xac\x5f\xef\x57\x9b\x15\x2d\xea\xed\x4b\xdd\x14\x4b\xa2\xa7\x57\xfa\x67\x59\x55\xc5\x2b\xfd\x63\x9d\x97\xf4\x73\xd3\xac\xca\xb2\xcd\x8a\x5d\xd9\xdc\x2f\x16\xf7\xfb\xed\xd3\x7d\xb1\xdc\xff\x02\x04\x68\x55\x57\x2d\x7d\xff\xeb\x2d\xfd\x76\x4b\x7f\xff\x21\xd0\x7a\x7a\xa5\x5f\xeb\x5d\x45\x3f\xff\xbb\xde\x55\x59\x55\x2f\x8b\xfb\xa6\x6c\x8b\xfb\x45\xde\xfe\x92\x2c\xf3\xb6\xf8\x89\x7e\x5b\xb4\xf4\xf8\xf1\x96\x1e\x3e\x7f\xfe\x94\x24\x7f\xfb\xfa\xb2\xc9\xab\xbc\x2d\xeb\x8a\xea\x15\xad\xca\x5d\xd3\xd2\xa6\xac\x8a\x9f\x92\xc3\x2a\xe8\x8e\x6e\xb6\xf9\x73\xb9\xa0\x6a\xbf\x7d\x2a\x76\x37\xb4\xaa\x77\xb4\x2a\x37\x05\x95\xcb\xa2\x6a\xcb\x55\xb9\x38\x0e\x4e\x72\x22\xa2\x3b\x6a\xd6\xf5\x7e\xb3\xa4\x7c\xf3\x7b\xfe\xda\xd0\x53\x41\xff\xca\xbf\xbb\x3d\x0e\xaa\xea\xdf\x93\xb4\xeb\xd4\xae\x0b\xba\x59\xe7\xbb\xe5\xd3\x26\xaf\xbe\xdc\xd0\xdd\x1d\xbd\xec\xca\xaa\x6d\x28\x6f\x28\xa7\x23\xf4\x96\x9e\xf6\x2d\x2d\xf2\xea\xbb\xf6\x40\xa6\xd9\xee\x9b\x75\xb1\x4c\x1e\x1f\x8e\x14\xd6\x45\xf9\xbc\x6e\x0f\x33\xce\x69\xb1\xce\x77\xf9\xa2\x2d\x76\xc9\xc3\xe7\x7e\xe4\x2d\x55\x75\x4b\x65\xb5\xd8\xec\x97\x65\xf5\x4c\xcb\xa2\x59\x14\xd5\xb2\xd8\x35\xc9\xe3\x87\xe3\xb0\x6d\xfe\xf5\xb8\x72\xda\x14\xd5\x73\xbb\xa6\xef\x8b\xaf\xae\xf3\xa2\xde\x6e\x8b\xaa\x63\x4c\xf3\x03\xfd\x89\x72\x5a\xed\x97\xcf\x05\xad\xf2\x45\x5b\xef\x92\xbb\x6e\x56\xcb\x62\x95\xef\x37\x6d\x37\xd9\x6d\xbd\x2c\x8e\x0b\x6f\xd7\x65\x63\x05\xb6\x29\xbf\x14\x74\x73\xb7\xa5\x0f\x37\x54\x57\x47\xb2\x79\xb5\x3c\x92\xfd\x21\x79\xf8\xf1\x48\xa4\x63\xf4\x61\xf6\xec\xae\x49\x92\x52\x9a\xbd\xc5\x7f\x59\x42\x74\xfe\x5b\xa4\x59\xf2\x35\xcd\x92\x45\x9a\x25\x9b\x34\x4b\xf2\x34\x4b\xb6\xf6\x6f\x9b\x66\x49\x99\x66\x49\x9d\x66\x49\x95\x1e\xfb\x5f\x46\x74\x69\x07\xed\xd3\x2c\x79\xb2\x84\x0f\x37\xfa\x8f\x85\xd5\x96\x78\x71\x0d\xd1\xbe\xef\x0b\xdc\xec\x30\xcb\xe5\x58\xa2\x6e\xf6\x1b\x60\xc9\x6e\x0c\xd1\x17\xbb\xd4\x9d\xe5\x73\x61\x67\xda\x0e\x21\xea\x04\x84\x44\x1b\x3b\xcb\xab\x97\xdf\x58\x09\x1f\x06\x3e\x8f\x11\x54\x0d\x33\xaa\xec\xb5\xe3\x1b\x2e\x77\x6d\xdb\x87\x1b\xbf\x9e\x22\xea\xf4\xb1\xb6\x9d\x8b\x29\x88\x9e\xe3\x6b\x03\xcb\xdd\x59\xd6\x34\x43\x05\xd5\xa7\x09\x1b\xcb\xdb\x66\x0a\xa2\x0b\xcb\xa2\x2d\x6c\xdb\xd1\x44\xb7\xa0\x15\x93\xcc\xf4\x45\xf0\xb4\x9e\x62\x9b\x3a\xfd\x75\x5b\xb4\xb1\x9a\x30\x98\xa8\x5b\xee\xd6\x5a\x2d\x37\xe3\x0f\x73\x10\x7d\x98\x83\xe8\xe3\x1c\x44\x3f\xce\x41\xf4\xd3\x1c\x44\x7f\x9c\x83\xe8\x9f\xe7\x20\xfa\x97\x39\x88\xfe\x75\x0e\xa2\x9f\xa7\xb4\x52\x9b\x21\xc1\x84\xfb\x3a\x2f\xe0\xac\xd3\x24\x44\xf1\xbb\x01\x37\xd2\x00\x0b\x46\x2f\x1f\x3d\x6a\x6e\x67\x3c\x98\xe8\x33\x38\xc0\x5c\xf8\xab\x41\x44\xdd\xcc\x0a\x70\x76\x83\xa2\xbe\x4b\xbe\x39\xf7\xa6\xf2\x13\x60\xc6\xa4\x1c\x66\x0e\x1f\x0e\x33\x47\x68\x2a\xc7\x2a\x30\x03\x04\x4f\xc0\x0c\xde\xb9\x1f\x66\xd8\x14\x2d\xcc\x7d\x02\xcc\xf0\xb5\xf4\xc1\x8e\xa3\x00\x98\x25\xc7\x5e\x0e\x6a\x0c\x99\x34\x4b\x8c\xed\x10\x3a\x66\x89\x5f\x26\xf2\xcf\x48\xe8\x69\x3e\x9f\x81\xc5\x40\x14\x87\x9f\xb0\x5d\xbe\xe3\xfd\x71\x1a\x96\xc5\xae\x8f\x71\x3c\x0f\xcb\xf4\x00\x02\x06\x99\xe3\x50\x64\xa3\xe9\x78\x40\x1c\xc2\x44\x67\xfb\x98\x88\x4e\x07\x73\xac\x37\x8e\x8b\x29\x28\x01\x40\xbc\x24\xdc\x28\x13\x04\xdb\x51\xf6\x68\x3f\x1f\x85\xdd\x42\x04\xbd\x3c\x3c\x0d\x89\x40\x61\xce\xb8\x50\x37\x47\x22\xbb\x2a\xe3\x41\xdd\xc2\xdd\xba\x41\xb9\xd8\x0e\x09\xc8\x09\x01\x9d\x10\xd9\x3e\x3c\x48\xc4\x2e\xc0\x49\xc4\x71\x3b\x15\xbb\x28\xc5\xd5\x8a\xfd\x78\x82\x67\x43\x00\xa7\x76\x02\xe8\xb8\x9f\x30\x68\xb9\x57\x73\xa7\xe7\xa0\xe8\x5e\xb1\xbd\xfa\x79\x50\x07\x74\xeb\xc5\x2d\x3d\x13\x8c\x62\x18\x58\x22\xa7\x25\xc1\x0a\x91\xb0\x42\x91\xfa\x9f\xde\x00\x6f\x62\x85\x14\x33\x24\xed\x50\x67\x37\x99\x21\xb2\x66\x93\x50\x3e\xcc\x14\xa5\x8c\xbc\xa7\x7c\x1e\x24\x2c\xbf\x41\x77\xd5\x3b\x90\x22\x10\xe1\x1c\x88\x99\xa4\x0e\xc7\x6d\x12\x2e\x88\x4f\x22\x12\x8a\x22\x93\x7e\xae\x9e\x03\x4d\x23\x0f\x52\xe4\x41\xef\x41\x1e\x1c\x64\xa2\xd8\xc4\xfa\x6d\xa4\xf5\xad\xe4\x41\x46\x1a\x50\x70\x17\xb0\xee\xb0\xa5\x23\x97\xa1\x38\x0d\xc5\xe4\x03\x88\xc0\x40\x7a\x50\x70\x51\x0e\x04\x4e\xca\x8d\x21\x74\x53\xe0\xaf\x53\xcd\x85\x50\xec\x44\x14\x37\xa2\x38\x92\x31\x9c\x1e\x2c\x0f\xb9\x45\xe2\x10\x30\x88\x21\xda\x28\x64\x34\xdb\x45\x86\x44\x18\x00\x8c\xe0\x51\xd0\xc5\xd0\x88\x71\x67\x29\xf0\x80\x57\x81\xa2\xaf\x61\x2b\x26\x09\x35\x5a\x30\xcc\x08\x7a\x4e\xc6\x4e\x47\x77\x3b\xba\x43\xb9\x12\x7a\x52\xea\x86\x05\x5f\x20\x4b\x08\x6a\xc0\x9a\x85\x2c\x80\x47\xb9\x0c\x02\x3a\x2b\xd3\x91\x18\x04\x16\xd7\x93\x8f\x40\xd1\x40\xbf\x0b\x83\x1f\x67\xf3\x74\xbd\xbc\x51\xf6\xb4\x0c\x37\x81\x7e\x12\xe9\x29\x36\xbe\xdd\xf6\xd2\xe2\x36\xcd\x0f\xa1\x60\x20\x5a\xa6\x9e\xe8\x40\x75\x48\xba\x1f\xe9\x81\x32\x39\xe9\xa2\x1a\x44\xf7\x4a\xa8\xe2\xd1\x3a\x04\x77\x6a\x56\x1b\x52\xc6\xdf\x90\xcf\x01\x94\x25\xc8\xfc\x6e\xe7\x1d\x5c\xbf\x38\x49\x08\x2f\x26\x65\x14\x38\xe8\xb6\x48\xdd\x29\x8a\xfc\x44\x56\xc9\xe2\x73\x25\xbb\x24\xbe\x78\x86\x11\x2c\x89\x42\x8e\x78\x8c\x91\x6c\x44\x6a\xd1\x66\xf2\x96\x35\xde\x79\x68\x5d\x71\xd6\x3c\x70\xc4\x9d\xcf\x83\x7d\x0a\x8e\x99\xc0\x9d\xc2\x38\xdd\xda\x52\xaf\xc5\xa5\x5e\x51\x0f\xc6\xa8\x28\x1e\x72\x8a\xa5\x1b\xc3\xcd\x96\x34\x6e\x4c\x1d\xa4\xe9\x32\x91\xe6\xcb\xed\x34\x27\x90\x14\xa0\xa6\x63\x46\xc8\x2a\x4e\x0e\xe2\xf4\x20\x04\x66\xb1\xd8\x54\x69\x9e\xe2\xfc\x25\xc0\xcb\x36\x37\x05\xfd\x8e\x0b\x4a\xb0\x95\xa2\xfc\xc1\xe3\xc4\xe6\xee\xc2\x47\x0a\xd9\x77\x88\x99\x88\x94\xf2\xd2\xdb\x63\x58\x34\xd0\x83\x09\x30\xa2\x88\x3b\xa4\x61\xe4\xe6\xb6\x28\x3d\x8c\xa2\xde\x50\x8a\xbe\xf9\xe6\xa6\x68\x83\xdb\xeb\x38\xb3\x24\xd2\xc3\xe6\x80\x49\x65\xfd\xb1\xbb\x36\xb2\x0c\x89\xc6\x5c\x08\xad\x0f\xa1\x57\x2b\x4f\x22\x42\x39\xf3\x0c\xc2\xfb\xe6\x60\xc0\xa5\xcd\x67\x08\x2e\x78\x99\xbc\xc5\x2e\xb4\x47\x27\x7a\x55\xa2\x57\x23\xce\x49\xf0\x1a\x44\x84\x89\x32\x59\x96\xc7\xb2\x5d\x44\xa1\xfe\x0c\x39\x2c\x96\x72\xc9\x42\x30\x59\x25\x9a\x0c\xc0\xb2\x56\x57\x53\x7e\x2f\x65\xcf\x2b\x42\xe8\x38\xb7\x21\xd2\x43\x68\x28\x76\x62\x88\xc5\x6a\xf0\x4a\xd1\x52\x87\xda\x49\x09\x76\x92\xe1\x49\x2a\xa3\xa0\x30\x36\x2a\x0f\x45\x9e\xf8\x4a\xa8\xcc\xa5\xf4\x74\x4a\xcf\xa8\x7a\x63\x59\x25\xaf\xba\x22\x84\x7e\x8f\x9b\xc6\x6a\x1c\x6c\x1a\x4c\xcb\xfc\x08\x54\x06\x18\x42\xbe\x13\x2a\x1c\xdc\x05\x01\x29\x67\x24\x4b\xf3\x08\x33\xf5\xd3\x5c\x16\x1e\xca\x60\x2d\x1d\xe3\x0f\xb6\x4b\xb4\x12\xb4\xf0\x42\xa9\x96\x5e\x20\x44\xba\x0f\xad\x64\x03\xdb\x14\xdc\x98\x7c\x18\x66\x80\x17\xc1\x1f\x88\x18\xc3\x60\x6c\x49\x3c\xa6\x60\x1b\x2f\x76\x25\x73\x3d\x0c\x63\x96\xd2\x48\x25\xf7\xd3\x06\x83\x44\x9c\x01\xc1\x83\xa6\xea\x66\x03\xe6\xf2\xb2\xa1\x31\x51\x4d\x95\x01\x99\x11\x25\x7c\x00\x64\x81\xdc\x24\x7a\x98\xd4\x51\x78\x32\x23\xa6\x8a\x41\x7e\xca\x3c\xf9\xa9\xc7\x32\x73\x57\x9c\xa7\x48\x4a\xec\xca\x29\x32\xaf\x5a\x6d\x5e\xd4\xa4\x83\x58\x27\x06\xda\xdd\x24\xfd\x00\x2f\x46\x73\x13\x24\x4d\x88\x51\x5c\x0e\x53\xb8\xb1\x69\xd6\xe8\x84\x2c\x8e\xb5\xe3\x54\x8c\x7a\xf2\x30\xaf\x7a\x60\xd8\x9c\x28\xb9\x75\x8b\x6b\xf5\xcc\x1b\xbc\x0d\x98\x05\x69\x29\xf5\x49\x34\x96\x69\x54\xaf\x45\xb1\x0a\xb9\x0a\xa3\x71\x99\x70\xa6\x02\x9f\x0b\xbb\x31\xa3\x52\xe5\x7c\x42\xd2\xbd\xb2\xee\x95\xb6\x7c\x72\x40\x34\x18\x61\x44\x59\xee\x4a\x04\x48\x5e\xca\x27\x64\x98\x52\x70\xc6\xf4\x20\xd8\xae\xa6\xbe\x9d\x4d\x13\xe7\x47\x13\x64\x54\xda\x38\xb6\xf1\xc3\x02\xb4\xfd\x4f\x04\xc1\x85\x62\x06\x82\xeb\x55\xac\x01\xd9\x7e\x69\x6c\x14\xfc\x94\x1c\x96\xc9\xf1\x0f\x83\x65\xe6\x23\xc6\xa2\x15\x09\xd8\x54\x31\x26\x46\x71\x1f\xde\xa6\x90\x51\x72\x17\x02\xff\xaa\x1a\x1e\xe5\xf3\xcd\xb0\x7d\x68\x11\xd3\x10\x16\x2a\x20\x7a\x30\xae\x84\xdb\xa9\x11\xb2\x0d\x13\x50\x9f\x9f\x78\x42\x8c\xd1\x32\xa0\x23\x61\x9d\x65\xbc\xd6\x07\x57\xe9\x28\xf1\x07\x41\xd6\xcb\xe1\x46\xde\x83\x07\xab\x22\xa4\x64\xec\xe9\x52\x00\x9b\x9f\x31\x44\x48\xd3\x04\x22\xed\x17\xcf\xec\xf0\x73\x03\xb4\x18\xa3\x27\xc8\xe8\x89\x32\xe8\x44\x98\xd1\x13\x67\x9c\x0c\x06\xe6\x84\xf7\x46\x1b\xbd\xe1\x46\x6f\xbc\xc1\xc3\x65\x91\x55\x68\x09\x08\x60\x65\xad\xc9\x04\x44\xb0\xf1\x1e\x05\xe5\x64\x76\x8b\xe8\xbe\x4c\xbe\x53\x27\x05\x06\x0e\x00\x84\xb1\x50\x73\x21\x9d\x4d\x44\xd1\x83\x74\x84\x71\xc6\x29\x71\x9a\xe6\xd1\x55\x03\x30\xe3\x53\x9a\xde\x1d\x3c\x5b\x52\x70\xfe\xeb\x0e\xc8\xaf\xec\x21\xee\x27\x7b\xec\x3c\xb7\xa7\xf1\xbf\x58\xfc\xa0\xd7\xa5\x9e\x04\xa1\xc1\xaf\xf6\xb8\x97\x8c\x9e\xed\xa0\xc9\x67\x2a\xbf\x0b\xf1\x5a\xda\xd5\x44\xf1\xcd\x45\x7c\xa5\xcf\xbd\xe1\xb0\x1b\xfa\xaa\xa4\x14\xd8\x89\xd7\xfa\x74\x05\x19\xdc\x30\xec\x34\x59\x38\x21\x63\x3c\xce\x16\x02\xfd\x31\x9f\x01\x0d\xa8\x52\x67\x3e\xa8\x90\x85\x94\x41\x8d\x08\x05\x66\x42\x54\x79\x2f\x6c\x00\x47\xac\xa9\x66\xa7\xe1\x26\xe5\x08\x3e\x10\x52\xcc\xe0\x34\x1c\x19\xdf\xb8\x4c\x47\x86\x30\xdb\x7b\x5b\xc7\x11\x9e\xe3\x46\x4e\x72\x32\x8e\xc8\x08\x34\xbd\xaa\x81\x6f\x54\x04\x3f\xf0\x3e\x75\x64\xf4\xb5\x54\x0e\x76\x26\x1d\x19\xd1\x71\x08\x1c\x29\xc6\x0e\x6c\xdf\xba\xcc\x1f\xb5\x02\x95\x62\xd4\x9c\xa1\x01\xf3\xef\x22\x15\x71\xcc\x35\x85\x89\x89\x4b\x98\x39\xd8\x0b\xbd\xef\xa0\xcb\xe8\x58\xe0\xb5\x97\x99\x08\x20\xe6\x69\x9b\x28\x1d\x0a\xe9\x20\x54\xa8\xa0\x06\x01\x9b\x6f\x6c\x5b\xc9\xbd\x43\x78\x9d\xb1\x5c\x3c\x3c\x9d\x0a\xb2\x25\x16\x46\xcb\x77\x86\xa2\xf5\x4a\x8d\x52\xc4\x76\xf1\x75\x50\xbb\x63\x72\x11\x76\x04\x28\x9e\x5b\xeb\xb8\xeb\xf0\xf8\x28\x83\x70\x38\x83\x28\xd8\x99\x44\x60\x62\x14\xa7\xc3\xe2\xf9\x15\x96\x04\x52\x09\x83\x05\xab\xfd\x46\x5d\xf9\xe3\xa1\xe2\xc9\xcd\xc5\x57\xfe\x92\x5d\x04\x5d\xf3\xd6\x3e\xe5\x7d\x8c\x51\xfa\xc8\xce\x6e\xbd\x7a\x67\x50\x47\x5f\xab\x8a\x2e\x5c\x1f\x7d\x1a\x33\x44\x3e\x04\x96\x0c\xdf\x93\xb2\x75\x0d\xdf\x0d\x16\x07\xf9\x9b\x3c\xa3\x1c\x64\x2e\x49\x83\xf4\xb0\x08\x29\xd6\x73\x75\x63\x6e\x85\xfb\x96\x2a\xda\xb3\xe6\x39\x40\xae\xa6\x89\x86\x10\x61\xbe\xc4\x65\x08\xfb\x65\x09\x96\x56\x40\xd7\xa7\x04\x99\xf0\x1f\x1e\x37\xf0\xb0\xb9\x99\x23\x60\x93\x36\xf1\xcc\x0e\xb9\x93\xdd\x26\x28\x11\x0b\x2e\x89\x78\xa8\x38\xb2\x69\xa4\x93\x24\x95\x9f\xa3\x9a\xe3\x37\xf8\xe5\xb9\x08\x4d\x11\x79\xb3\x28\x23\xae\x5c\x4d\x69\xb0\xfe\xf0\x1c\x61\x71\x96\x30\xee\x17\xb9\x17\xc2\xf8\xe7\x7f\x81\x23\x5a\xbe\x6a\xae\x4b\x23\x7d\xeb\x52\x8e\xbc\xb9\x89\x61\xf5\xd5\x71\x4d\x2e\xfe\xde\x03\x15\xef\xc0\xe2\x40\xe8\x82\xa9\x6c\xaa\xac\x36\x73\x39\x09\xaf\x36\x84\x82\x47\x48\x3d\x8c\x7b\x39\x22\xba\xe9\xf8\x25\xa8\x1c\x89\xaf\xc1\xc8\x19\xf5\x9a\x95\x3a\x30\x31\xef\xe9\x3f\xee\x9a\x62\x16\x8c\xba\x96\x0e\x7d\x7c\x1b\xf6\x8b\x63\x10\xf9\x98\x24\xc5\x84\xd5\xc0\xf9\x42\x66\x43\xc6\xb5\x7d\x06\x8b\xbe\x5b\xad\xae\x4e\xb2\x5e\xd1\xbe\xda\xfa\xa4\x27\x9a\x81\x77\x22\x48\x61\xf1\x8e\x8f\x4a\x80\x13\xc3\x9b\xc8\x33\xb0\xca\x7a\xed\x71\x46\xdb\x74\xa2\xe3\x45\x08\xc6\xca\x8b\x10\xa8\xa9\x22\xc0\x61\x18\x19\xf0\x73\x0c\x17\x8d\xa6\x9d\xf3\x21\x52\xb4\xcf\x86\x1f\x21\x47\x39\xfa\xbf\x71\x04\x77\x21\x77\xdf\x00\x11\x61\x26\x02\xb0\x43\x40\xce\xcd\x90\xf7\x35\x8e\x7f\x14\xe9\xbf\x30\xbe\xf1\x61\x88\xf8\x14\x04\xd3\x21\x62\xb7\xc5\x13\x69\xf0\x23\x49\xa4\xe6\xfe\x13\x2e\x5f\x00\x66\xba\x0d\xf7\x02\x91\x1b\x20\xe9\x07\x22\x43\x3e\x15\xc0\xfb\x67\xc3\xea\xa1\x4a\x41\x54\x54\x44\xe3\x92\xa8\xa8\x89\xf6\x16\x45\xcf\x71\x79\x68\x03\x2d\x32\x86\x1a\xb0\x64\x3f\x86\xc5\xd6\x91\xd2\xca\xa8\x2b\xb4\xc2\x4d\x4f\x34\x2e\xb9\xcf\xb9\xdc\x30\x3b\xfb\xbc\x77\x61\x9f\xf7\xee\xec\xb3\xf4\xd7\xb9\x1f\x85\x93\xfd\xb1\xcf\x12\x7e\x0e\x36\x22\xaa\x3d\xa0\x5f\xd8\x59\xed\xdf\x6a\xa6\xee\x57\xee\x96\xf0\xab\xb7\x1d\xd1\x51\xff\xfe\x3f\xfe\x5b\x8f\xff\x6f\x00\x00\x00\xff\xff\xae\xc6\xd0\x0a\xb5\x5d\x00\x00")
+
+func fontsCaligraphyFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsCaligraphyFlf,
+ "fonts/caligraphy.flf",
+ )
+}
+
+func fontsCaligraphyFlf() (*asset, error) {
+ bytes, err := fontsCaligraphyFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/caligraphy.flf", size: 23989, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsCatwalkFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\x4d\x6f\x24\x35\x10\xbd\xcf\xaf\xa8\xc3\x5e\x91\x97\x11\x12\xcb\xad\x57\x48\x7b\x81\x53\x84\xc4\xd1\x09\xd2\x04\x45\x8a\x40\x82\x5c\xe0\xd7\xa3\x99\xb6\xcb\xef\x55\x3d\x77\xcf\x0c\xd1\x66\x93\x6e\xbb\xbb\x5d\xdf\xf5\xaa\xec\x7d\x7e\x7d\x3e\x3e\x7d\xb0\x4f\xf6\xbd\x1d\x3f\xda\x37\xdf\xda\xf1\xf0\xe3\xe7\x5f\x7e\xfd\xfc\xf3\x4f\xf6\xdb\x3f\xf6\xf0\xe7\x1f\xf6\xe5\xaf\x97\xb7\x7f\xed\x53\xf9\xe1\xbb\xc3\x97\x97\xdf\x5f\x4f\x6f\xf6\x70\x7a\x3d\x3d\xfd\x7d\xb2\x63\xf9\x78\xf8\xb0\x88\x5f\x5b\x96\x43\x2d\x85\x2f\xd6\x2e\x66\xd6\x9e\x9d\x47\x97\x87\xb5\xf8\xcd\xec\xf2\x7e\xff\xd6\xee\xfd\xe7\x3c\xad\xa5\x58\xbb\x5e\x38\x9c\x7f\xec\x72\x4f\x6f\x6f\xfc\x18\x19\x5d\xe6\xfd\x4d\x5d\x17\x5d\x28\x04\x39\xda\x3a\x7f\x7b\xfe\x4b\x6f\xa3\x26\x8d\xa4\x7f\xcc\x42\xc0\xd2\xc6\x6f\x10\x94\x6b\x49\x62\x9b\x4a\x7c\x56\xbb\xbb\x05\x49\x75\x2f\xd5\x24\xf1\xfa\xa6\x39\x6c\x7e\x69\xe2\x35\x72\x8d\x7e\xbc\xa1\x65\xc0\xbb\xe4\xa9\xae\xb3\xba\xb7\xf7\xe4\x2c\x37\xaa\x32\x0e\xea\x55\x0b\xc5\x80\xb5\x48\x10\xef\xc5\x7a\xa6\x2f\xc2\x04\xa3\xd3\x72\x60\x74\x9b\x77\xb6\x5b\x9f\x65\x6a\xc8\x68\xe3\xe2\xae\x72\xdb\xa4\x3b\x71\x17\xef\x6f\xe2\x84\xba\x07\x43\xdd\x1b\xd1\x51\xe9\x90\xfc\x48\x0a\x08\x60\x94\xb9\x00\x4e\x6f\x84\xa5\x71\x88\x29\x7f\xa2\xed\x52\x5c\xea\x7b\xb0\x69\x72\xe0\x9a\x5f\x9d\xa4\xb2\x16\xeb\x85\x76\xe9\x39\xbb\x82\x96\x08\x07\x70\x2c\x90\x72\x63\x73\xd0\x52\xe2\x74\x68\x28\x31\xec\xa4\xcd\x39\x3c\x2b\xbb\x33\xf0\xc3\x78\xef\x79\xa5\xa8\x6c\x6a\x42\x2e\x6c\xb9\xb3\xa7\x49\x04\x44\x95\x9a\x60\xe4\x1c\x48\x9d\x97\x99\x0a\xaa\xe1\xcc\x58\x2c\x02\xb2\x57\xaf\x31\x57\xe7\xc4\x74\xbc\xa5\x49\x9f\xe8\x24\x88\xc1\x97\x35\x01\x53\x6c\x39\x3f\x39\x78\xd8\x9c\xb5\xab\x45\x42\x1a\x1b\x5b\x3a\x7f\x8e\x30\x01\x6b\x76\x3f\x04\xf8\x73\xfb\x87\x56\x80\x23\x8b\xa5\x14\x91\x25\x6c\x03\x83\x5a\x28\xfd\xe5\x93\x34\xb8\x5d\x80\x1d\x15\x88\x70\x20\x36\x7c\x41\xcf\x6a\xf4\xbe\x7c\x16\xaa\x9d\x53\xc0\xc4\x31\x6a\x93\xb0\x72\xb6\x6c\xa9\x0c\xc2\x8f\x8f\x8f\x09\xcb\x63\x59\x05\x27\xb2\xf5\x6a\xb1\x80\x04\x2a\xcc\x46\x14\x42\xc3\xc7\x65\x26\x96\x89\xe4\x6e\xf2\xd5\xc0\x34\x5c\x3a\x56\x35\xf8\x81\x6f\x62\x8a\x40\xdf\xa1\x52\x3b\x64\x18\x35\x6e\xe4\xee\x30\xc6\xef\xcd\xb3\x3a\x30\x70\x98\xf7\xc5\xa4\x3c\x32\x9b\x8c\xb1\xd4\x45\x77\x39\x83\x42\x42\x27\xfc\x2e\x8c\x50\xf2\x83\x98\x70\xef\x42\x38\x45\xd8\x82\xb6\x1a\x75\x39\x45\x84\x9c\xf4\xad\x83\x1b\x09\xe2\x4c\xc0\x69\x40\xcc\x8d\xc9\x28\x1a\x57\xae\x49\x8c\xf6\x2e\x90\x58\x15\x9b\xd0\xbd\x51\x2d\xd8\x47\x71\x80\x2d\x18\x22\xdd\x48\xd0\x02\x20\x62\x79\x36\x8b\xcf\x66\x15\x57\xd9\xf2\x1a\x67\xdf\x1a\x66\x6d\xd2\xf5\x1d\xbe\x1e\x5a\x54\xf0\x01\x83\x9c\xe3\x90\x20\x45\x53\xb3\xa4\x51\xd1\x7c\xc1\x78\xcc\x95\x99\x72\xbe\x1a\xb1\x4c\x1c\x07\xd6\xe4\xce\x27\x58\x3f\xcb\xaf\xe7\x86\x2d\x81\x29\xfa\x42\xe3\x90\xb1\x0a\x73\x72\x56\x6f\x81\xe0\x54\xc3\xa0\xe0\x9e\x7b\x92\xb7\xaa\x77\xb0\x50\xb0\x62\x9e\x9f\x7d\x4f\x9a\xb1\x6e\x6a\x66\x31\x3c\x63\x5d\x8f\xee\xd0\xbe\xec\xd2\xb0\xf9\x42\x55\x0d\x55\x3d\x43\x3f\xd2\x49\xbe\x32\xee\x67\x98\xd8\xfb\xcc\x88\x61\x76\xc6\xdd\x93\x2b\x50\x59\xd8\xcc\x9d\x8d\x81\xad\x9b\x0b\x4f\x48\x56\x2d\x04\xbf\xaa\x40\x4a\x90\x8d\x7c\xab\xdc\x13\x24\x90\x40\x60\x18\xc5\x4c\xe7\xeb\x4c\x00\x34\x83\xab\x5c\xa1\xf7\x41\x5d\xd2\x3b\x09\xe1\x32\x6a\x25\x43\x32\xfa\x8c\xe1\x2d\x33\x66\x98\x36\x64\xe0\x54\xe1\x51\x33\xb1\x69\xa9\xa1\x15\x28\xa2\x94\x00\xc3\xa6\xe8\xee\x0d\x8f\xc2\x14\xbb\xb8\x41\x48\xb2\x42\x4a\x4d\xf7\x2d\x78\xdc\xb9\x7d\x0b\x12\x19\x27\x6b\x2d\x65\xb7\x4c\xdf\x33\xe9\xb3\xdb\xef\xed\xf4\xc5\xbb\x9c\xbc\x43\xe4\x0b\x21\x5c\x1c\x0f\x4d\x3d\xcd\x54\xc3\x1c\x62\xb5\x64\xd4\x04\xe9\x26\x43\xb2\x22\x37\xda\xf4\x41\xb6\x51\xd8\x50\x56\xec\x46\x9d\x0d\x3c\x19\xdf\x30\xa1\x79\xdf\x87\x60\x22\x3b\x40\x76\xfa\xf5\x36\x8d\x1b\x09\xda\x22\xd9\xe8\xa3\xa7\x45\x7d\xe9\x1b\xce\xf3\x32\xff\x8f\x04\x42\xab\xc9\x20\x49\x1a\x87\x8c\x64\xd1\x23\xf0\xb4\x1b\x8a\x32\x13\xac\x71\x18\x99\x8b\x23\x3a\x86\x49\xd6\x2d\xa6\x6c\x8a\x27\xef\x3b\xfd\xbc\x2b\x21\xe7\xf2\xbe\xf6\x9e\xcb\x4c\xe0\xb0\x89\x6f\x26\x2f\x14\xc1\x33\xd1\xdd\x66\xf3\xeb\x88\x49\x7d\xc8\x60\x64\x50\xaf\x70\xe0\xa1\xe0\x1a\x3d\x5d\x95\xac\x51\xc8\xed\x70\xa8\xf1\xc0\x20\xc5\x00\x99\x27\x11\xbf\x1b\x65\x02\x75\xd9\xbf\xa5\x78\x43\xb9\x07\xae\x0c\xc2\x11\x55\xa4\xc3\x35\x41\x03\x5c\x41\x82\xc3\x11\x95\x3a\x63\x1f\x95\xc9\x61\x59\x84\xab\x3c\xa8\x21\xff\x35\xee\xd5\x42\x47\xc4\x1d\x39\x0c\x90\x22\xe2\xd4\xa2\x80\xe1\x3a\x14\xa1\xe2\x3a\x37\x7e\xdc\xaa\xe9\x91\x35\xb3\x4d\x00\x34\x96\x49\xae\xb3\xb2\x00\xb9\x90\xa2\x8f\xd1\x75\x56\x70\x62\x56\xce\xab\x30\xec\x8f\xd9\xfa\x0b\x29\x60\xa9\x16\xee\x64\x18\x22\x3a\x04\xbb\x8d\x6a\x11\x8a\xee\x24\xc3\xa6\x84\x6b\x21\xc2\xa5\xe4\xbe\x29\x84\xdf\x36\x61\x0a\xa8\x90\x9e\x4b\x38\x9b\x55\xa7\x0c\xe0\xc7\xb4\x6a\x58\x51\xbf\xc5\xb5\x4e\x70\x3d\x55\x5c\xff\x56\x12\x34\xc7\x44\x9f\xd1\xac\x65\x43\x9e\x60\x85\xc5\xc3\x78\x40\x59\xc2\xd5\xff\x35\x5e\x0e\xe1\xdf\xd7\x7a\xf0\x5f\x00\x00\x00\xff\xff\x77\x4b\x9c\x34\x1e\x21\x00\x00")
+
+func fontsCatwalkFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsCatwalkFlf,
+ "fonts/catwalk.flf",
+ )
+}
+
+func fontsCatwalkFlf() (*asset, error) {
+ bytes, err := fontsCatwalkFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/catwalk.flf", size: 8478, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsChunkyFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x57\x4d\x4b\x1c\x4d\x10\xbe\xcf\xaf\x78\x0e\xc2\x5c\xa6\x7b\xd4\x57\x0f\x2f\x48\x18\xc8\x21\xc1\x43\x2e\x21\xb7\x85\xde\x95\xa8\x11\x44\x89\x92\x43\xa0\x7f\x7c\xe8\xea\xaf\xea\xee\xea\x9d\x59\x02\x91\x45\xc7\xd9\xfa\x7c\xea\xa9\xea\xea\x87\xe7\x87\xcb\xc3\x19\xae\x71\x85\xcb\x73\x5c\x5c\xe3\x62\xf8\xfa\xf3\xd7\xe1\xed\x1e\x77\xbf\xf1\xf1\xc7\xdb\xd3\x3b\x3e\x3d\x3d\x3f\x4f\xf8\xef\x5c\xdd\x7e\xfb\xa2\xfe\xbf\x82\x52\xb8\x3b\xbc\xdf\x7f\xc7\xeb\x0b\xf4\xfb\xd3\x23\x5e\x1f\x70\x7b\x7f\x87\xcf\x87\xc7\xc3\x8b\x1e\xce\x16\xfe\x59\x06\x18\x83\x65\xb0\x80\x5d\x06\x6b\x4c\xfa\x0d\x00\xfe\xeb\x20\xe0\x45\x60\x8d\x8d\x5f\x03\xe9\x2f\x3d\x18\x92\xa5\xb7\xc6\x49\x03\x96\x54\x8d\x17\x82\x37\xce\xfe\x71\x02\xc6\x7d\xa2\xab\x49\x4d\x31\x9c\x11\x63\x8c\x86\xe4\xfd\x23\xfd\x78\xf7\xd6\xa9\x05\x3d\x84\x20\xc9\x14\x89\x92\x8b\xa0\x6f\x72\x46\x39\x2b\xc9\x15\x0a\xad\x8e\xab\x08\x16\x12\x0e\x19\xac\x10\xc7\x34\x86\x64\x09\x04\xff\xd7\xbd\xdf\x6b\x32\xe9\x51\x45\x80\x66\xaf\x09\x08\x6f\xd3\xa4\x42\x98\x69\x8c\xb9\x65\xaf\x51\xec\x03\x45\x7a\x13\x52\xae\xf2\x4b\xd5\x60\xa5\xc8\x75\xc8\xb8\xe7\xf2\x45\x15\xa4\xdf\x75\x9e\x4c\xd2\x53\x22\xe2\x9d\x41\x2a\x08\xd1\xb3\x58\x50\xcb\x53\x86\x1e\x66\x60\x5e\x06\x4c\xa3\xfb\x2c\xc3\x6c\xcc\xcc\xad\x2d\x85\x57\x24\x42\xc0\xb1\x9d\x51\xa3\xa9\x72\x00\x81\x52\xb7\x35\x1c\x3d\x95\x18\x2a\x24\x2e\x6d\x53\xe1\x4f\x3d\x95\xc8\x0c\xf7\xe1\x2a\x08\xe5\xe9\x79\xe1\xe1\xac\x7b\xa9\x54\x3c\x2f\x36\xaa\x04\x41\xa4\xc0\xec\x8a\x4a\xb4\x7d\x82\x97\x2c\xb8\x92\x4b\xa6\x8f\x40\xa5\xf6\xeb\x8a\xbb\xf4\xd2\x91\xcb\x89\xcc\x44\xb8\x65\xd8\x01\x3b\x7a\xef\x1a\x73\x9d\xe4\xdd\xc8\x02\xc5\xf6\x9a\x6a\xe6\xac\xba\xf7\x9e\xd3\xd6\x75\x72\x31\x20\x03\x90\x11\xd3\x71\x02\x26\x35\xfa\xba\x2b\x15\xdb\x72\x54\x6a\xe4\x68\xe5\xb2\x98\xa8\xeb\xc9\xc3\xfe\xa9\x23\x65\xd3\x86\xeb\x33\x5a\x67\xc8\xad\x69\x87\x48\xe5\xd6\xa5\x15\x9e\x6e\x92\x8f\x79\x9d\x40\x70\x6d\xaa\x36\x35\x03\x1c\x7c\x6d\x63\xcf\x62\x33\x30\x6a\x1b\x5b\x3e\x9a\xc6\xd3\x66\x3d\x8b\x62\x8e\x49\x7a\xc8\x7a\x56\x38\x99\x7a\x7a\xf6\x44\xe0\xd9\xe1\x69\xe2\xe1\x50\xcc\x2e\x71\xea\x07\x8a\xf9\x3c\x04\x7f\x72\x9c\xc8\x6d\x33\x33\xad\x78\xc4\xec\x7a\x55\x4b\x90\x58\x56\xf4\xbf\x84\x44\x3c\xd0\xaa\x12\x58\x51\x6f\xbd\xe4\x8c\x92\x5b\xe2\x6c\xb8\x0f\x62\x7c\xe4\xc9\x51\x56\x16\xae\xd6\x59\xd9\xba\x42\x6c\x33\x69\x7f\x91\x08\xd9\x5b\x95\xd6\x88\x05\x9b\x8e\x47\x84\xd4\xb6\x56\xcd\xae\xfa\xc3\x31\x3d\xec\x9a\xfe\x2e\x66\x1e\x3b\x22\xf3\xc4\x2b\x7b\xae\xf0\x79\xc4\xa9\xa2\xef\xd5\xf1\xae\x6b\xf5\xdc\x38\xa7\x05\x65\x13\x38\xac\x02\x45\x5d\xba\xc5\x88\x55\x17\xb6\xc5\x40\xe7\x65\xf0\x8d\x16\xce\x2b\xcf\xba\xbd\x8e\xa7\x8d\x43\x70\xd7\x2c\x4a\x69\xe7\x91\x77\xcb\x7c\x2c\xa4\x7e\x72\x5f\xcc\xbb\xde\x6a\x5f\xbc\xaa\x9e\x78\xf6\xcc\x36\xbb\x55\x58\x34\x8b\x72\x50\xd6\x4a\x29\xad\xb4\xdf\x04\x52\x78\x9a\x41\x95\x8e\xd8\x60\x4f\x35\xd2\xa6\x92\x66\xa6\xa3\xac\xc9\x79\x97\x69\x51\x98\x9a\x4e\x5d\xbb\xc5\x6c\xb4\x1b\x0c\x2b\x56\xdf\x4a\xda\x43\xa2\xf3\x4d\x20\x8e\x00\x2b\x61\x5b\x9a\xcd\x41\x14\xd1\x74\x90\xe0\xf3\xaf\xc1\x2d\x5d\xea\xd8\x05\x8f\xc5\x08\xda\x91\xe8\x65\xdc\x98\xf2\xc1\xd4\x77\x98\x6e\x1e\xa2\xc3\xd4\xaa\xc2\xc2\x5f\xa6\xab\x58\x0e\x45\x1a\x42\x57\x4b\x40\xf5\x53\x3f\x0e\xeb\x09\xd2\xac\x89\xed\x16\xdb\xc5\x0e\x2f\xd3\x71\x33\x13\x8c\x01\xdb\x9b\x84\x9e\x60\xc3\x02\xec\x8c\xa9\x59\x1e\xcd\xea\x18\x81\xdd\x82\x44\x25\x4d\xa3\x7a\x86\x20\xcd\x15\xb8\xce\xca\x98\x6e\x5d\x99\x9c\x84\xde\x1e\x98\xd4\x27\x2d\x96\x4a\x61\xad\x59\x69\x9b\x96\xae\x07\x56\x9a\x6a\x35\xcb\xcb\x5b\xbd\x95\xaf\x02\x6e\x14\x16\x0e\x47\xaf\x3f\xb1\xfb\x1e\x2b\x5e\x4e\x96\xf2\x08\x57\xde\x1e\xe9\x45\xe9\x2e\xe9\xb9\xb4\x8d\xd2\x5d\x62\x14\xb6\x75\x63\x5b\xff\xbb\x48\xda\x25\x9e\xed\x66\xb4\x31\x85\x9b\xd0\x9c\x9a\x96\xf4\xfe\x04\x00\x00\xff\xff\x9e\x93\x6b\xf8\x4b\x13\x00\x00")
+
+func fontsChunkyFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsChunkyFlf,
+ "fonts/chunky.flf",
+ )
+}
+
+func fontsChunkyFlf() (*asset, error) {
+ bytes, err := fontsChunkyFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/chunky.flf", size: 4939, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsCoinstakFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\x5d\xab\x1c\x45\x10\x7d\x9f\x5f\x51\x0f\x79\xe9\x07\x49\x5c\x04\xe3\xdb\x88\x10\x10\xc1\x86\xe8\x0f\xb8\x11\x36\x12\xb8\x28\x68\x5e\xf4\xd7\xcb\xee\x74\x57\x9f\x73\xaa\x7a\x66\x77\xbd\x24\x5e\x67\xba\x67\xa6\xeb\xbb\x4e\x55\xf7\x7e\x7c\xfe\x78\xfa\xf0\xca\xde\xda\xb7\x76\x7a\x63\x5f\x7d\x6d\xa7\xe5\x87\xfa\xe3\xcf\xbf\xfc\xfa\xfd\x4f\xf6\xdb\x3f\xf6\xfe\xcf\x3f\xec\xdd\x5f\x9f\x3e\xff\x6b\x6f\x5f\x7f\xf7\xcd\xf2\xee\xd3\xef\xcf\xe7\xcf\xf6\xfe\xfc\x7c\xfe\xf0\xf7\xd9\x4e\xaf\xdf\x2c\xaf\xd6\xe4\xcf\xd6\x75\xa9\xa5\xf0\xc5\xda\xc5\xcc\xda\xb3\xcb\xe8\xfa\xb0\x16\xbf\x99\x5d\xdf\x1f\xdf\xda\xbd\xff\xbb\x4c\x6b\x29\xd6\xae\x57\x0e\x97\x7f\x76\xbd\x87\xb7\x77\x7e\x8c\x8c\xfc\xf5\xba\xd8\x55\xe8\x4d\xc5\x26\xc4\x36\xba\xae\xb9\x0c\xb7\x57\x15\x88\x3a\x39\xd4\xa0\x51\xd8\x56\x18\x71\x1e\x04\x95\x49\xb2\x0c\x08\xd7\x32\xbe\x45\x19\xdb\xb3\x32\x96\xcb\x77\xb0\x76\x10\xdc\xde\x34\x07\xcd\x2f\x4d\xcc\x46\xae\xd1\xd7\x9b\xcb\xdb\xd9\x75\x0e\xd9\x4b\xba\x11\x51\x36\xa2\x68\xe2\x97\xae\xcf\xe6\x29\xf7\xb5\x35\x8f\x27\xef\x93\xf5\x4c\x3f\x86\x03\x45\x21\xf9\x0c\x26\x75\xb0\xdd\xfb\x2c\x52\x43\x46\x3b\x17\x77\x51\x5f\x16\xef\xc4\x3d\x79\x7f\x17\x27\x36\x3e\x68\xf1\x40\x04\x8b\xb6\x92\xdc\x40\x10\x09\x61\x54\x51\xba\x81\x4c\x6d\xea\x62\xb5\xc8\x57\x3f\xae\x0e\x2e\x12\x86\xd9\xad\x82\x11\x39\x89\x29\xca\x26\x86\x71\x6b\x90\x09\x0a\x79\x26\x45\x87\xc4\xa0\x1c\x94\x04\x2f\x3d\xe5\x8b\x86\x55\x6a\x5b\x0e\xbf\xca\x28\x26\xfc\x30\x9e\x8b\x23\x60\xa4\xb2\xab\x49\x61\xcf\x8b\x5b\x72\x4d\x72\x9c\x4b\x83\x04\xcc\x44\x91\x47\x9e\x91\xe0\xe9\x9f\x45\xd0\x27\x46\x6e\x55\x51\x1b\xd3\x18\x65\xd9\x1f\xa7\x0c\xac\x43\x30\xd9\x1c\x85\x1d\xb2\x5a\xf6\x7c\x9f\x01\xfb\x95\x92\xa4\x5b\x67\x6a\x10\x29\x6f\x76\x23\x4a\x39\x62\x08\x76\x1c\x7e\x08\x70\xe6\xf6\x96\x12\xae\x18\x82\x21\x90\x44\x52\x62\x13\x18\x54\x49\xc4\xec\x49\x18\xdc\x2f\xc0\x81\x0a\x44\x58\x88\x0d\x47\xd0\x33\x62\x6a\x04\x0f\xeb\x92\x87\x01\x50\xc5\x44\x41\xf9\x2a\x55\xc2\x16\x0c\x95\xc1\xf5\xe9\xe9\x29\x60\x74\xda\x34\x99\x87\x35\x56\x3d\x93\xcc\xcf\x72\x98\x2a\x48\x4f\x3e\x42\xc0\x00\xff\xc1\xdd\xe4\xab\x81\x61\xb8\x74\xac\x6a\x70\x03\xdf\x68\x76\x40\x1f\x91\x65\x9a\x40\x34\x35\x60\xe4\x6e\x19\xe3\xf7\xe6\xb9\x2c\x0c\x1c\xd6\x7d\x31\x29\x8f\xcc\x26\x63\x28\x64\x45\xdd\xb5\x52\x41\x62\x90\x86\x61\x97\x6c\xf7\x03\x4d\xb8\x17\x21\x1c\x22\x6c\x45\x5b\xf5\xb0\x4d\x22\x22\x9d\xf4\x6a\xee\x46\x82\x38\x4b\xd0\x8d\x0a\xc6\xee\x64\x14\x89\x1b\xd7\x04\x46\x47\x17\x48\x2c\x6a\x34\x8e\x46\xb5\x60\x7f\xc4\x01\xb6\x62\x88\xe0\x06\x83\xda\x90\x96\x17\x95\xdd\x82\x9f\xcd\x2a\x6c\x66\xcb\x5b\x9c\x7d\x6f\x98\xb5\x49\xd7\x77\xf8\x7a\x68\x51\xc1\x07\x0c\x72\x8e\x43\x09\x29\x9a\x9a\x05\x8d\x4a\xce\x17\x8c\xc7\x5c\x99\x29\xe7\xab\x11\xcb\xc0\x71\x60\x4d\xec\x74\xc4\xfa\x51\xfe\x7c\x3e\x20\xbc\x62\x27\x9f\x95\x7a\xce\x68\xdb\xc7\x9f\x98\xd5\x7b\x20\x38\xd5\x50\x14\x3c\x72\x4f\xf0\x56\xf5\x8e\x15\x0a\x96\xe6\xf9\xb5\xa9\x42\xa9\x59\xb7\x6c\x66\x1a\x9e\x5a\xd7\xd5\x1d\xb9\x2f\xab\xb6\x74\xb4\x89\xe1\xbe\x8b\x7b\x4f\xfa\x1e\xe8\x04\x5f\x19\xf7\x33\x4c\xec\x65\x66\xc4\x30\x3a\xe3\xe1\xc9\x0d\xa8\x9c\xd8\xcc\x9d\x8d\x81\x9d\x37\x17\x9e\x90\xac\x9a\x04\x7f\x56\x81\x32\x41\x76\xf2\xad\x72\x4f\x10\x40\x02\x81\x61\x14\xb3\x3c\x5f\x67\x02\xa0\x19\x5c\xe5\x0a\xbd\x8f\x49\x0f\x4f\xef\x52\x08\x4f\xa3\x36\x65\x48\x46\x9f\x31\xbc\x67\xc6\x0c\xc3\x06\x0c\x9c\x9a\x78\xd4\x24\x75\xa4\x73\xc4\x3a\x52\x72\x0d\xdd\xf4\x87\xb7\x70\xa4\x25\xec\x74\x83\x10\x64\x85\x94\x9a\xee\x5b\xf0\x98\x72\xff\x96\x9c\x55\x54\x86\xd2\x7a\x50\xa6\x1f\x99\xf4\xd9\xfd\xf7\x76\x42\xe5\x5d\x4e\xdc\x21\xf2\x85\x10\x4e\xc7\x43\x53\x4f\xb3\xac\x61\x96\x58\x2d\x11\x35\x41\xba\xc9\x90\xac\xc8\x8d\x36\x7d\x10\x6d\x24\x1b\xca\x8a\xdd\xa8\xb3\x09\x07\xcb\xb0\x1f\x3d\xec\xfb\x10\x4c\xd2\x0e\x90\x9d\x7e\xbb\x4d\x75\x23\x41\x5b\x24\x1b\x7d\xf4\xb4\xa8\xaf\x7d\xc3\x79\x59\xe6\x3f\x00\x10\x5a\x4d\x06\x41\x52\x1d\x32\x92\xa9\x47\xe0\x69\x37\x14\x65\x26\x58\x63\x19\x99\x8b\xa3\x21\x77\x09\x36\x15\xe2\x06\xa7\x1d\x95\x8e\x37\xe6\xfd\xbc\x2b\x91\xce\xd3\xfb\xd6\x7b\xae\x33\x81\x65\x13\xdf\x4c\x5e\x28\x82\x67\xa2\xbb\xcd\xe6\xd7\x11\x93\xf9\x21\x83\x91\x41\xbd\xc2\x81\x87\xc4\x35\xf9\x74\x53\xb2\xaa\x90\xfb\xe1\x50\xf5\xc0\x20\xc4\x00\x99\x27\x10\x7f\x18\x65\x84\x7a\xda\xbf\x85\x78\x43\xb9\x07\xae\x0c\xc2\x8a\x2a\xa9\xc3\x73\x82\x06\xb8\x82\x04\x87\x23\x2a\x75\xc6\x3e\x2a\x93\xc3\x32\x85\xab\x38\xa8\x92\xff\x39\xee\x6d\x30\x81\x70\x67\xed\x90\xd8\x44\x5d\x26\xa4\xc0\x70\x1b\x8a\x50\x71\x9d\x1b\x5f\xb7\x6a\xf9\xc8\x9a\xd9\x26\x00\xaa\x65\x92\xeb\x6c\x5a\x80\x5c\xc8\xa4\x8f\xc9\xeb\x6c\xc2\x89\x59\x39\xaf\xc2\xb0\x3f\x66\xdb\x1f\xa4\x80\x85\x5a\x78\x90\x61\x88\xe8\x10\xec\x36\xaa\x85\x14\xdd\x49\x86\x4d\x09\xd7\x42\x84\x4b\x89\x7d\x93\x84\xdf\x3e\x61\x0a\xa8\x1a\x7e\x9f\x19\x26\xdf\xf9\x7d\x06\x37\xcd\x14\x87\xbc\x5d\x95\xda\x25\x71\xbc\x9d\x26\x6e\xff\x6f\xab\x69\x7e\x2b\xb9\x1d\x21\x06\xa7\x62\xf0\xeb\x6e\x82\xa3\xff\x6b\xbc\x2e\xf2\xdf\x97\x7a\xf0\x5f\x00\x00\x00\xff\xff\x43\xbc\x37\xa4\xc7\x20\x00\x00")
+
+func fontsCoinstakFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsCoinstakFlf,
+ "fonts/coinstak.flf",
+ )
+}
+
+func fontsCoinstakFlf() (*asset, error) {
+ bytes, err := fontsCoinstakFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/coinstak.flf", size: 8391, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsColossalFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x1a\x4b\x8f\xdb\x38\xef\xee\x5f\x41\x18\x02\xa6\xc5\xd7\x31\x3a\x33\xdf\x41\xdd\x53\x80\xc5\x5e\x3a\x17\x1f\x7a\xa8\x6f\xb5\x23\x67\x92\xdd\xc4\xee\x26\x0e\xda\xfd\xf7\x0b\x89\x94\x44\xf9\xed\x3c\xb6\x39\x24\x64\xac\x07\x49\xf1\x6d\x6d\xf6\x9b\xe7\x5c\xc0\xd3\x13\x48\x78\xfe\x08\x2f\xcf\xf0\xf4\x12\xfd\x5e\xef\xeb\xd3\x29\xdf\x27\x9b\xfd\x06\xde\x7d\xae\xab\xbc\xd9\xd6\x15\x3c\xc2\x9f\x75\xb5\x3a\xfc\x9d\x94\xea\x9c\xe4\xe7\xf7\x91\x84\xcf\xe7\xaa\x84\xa7\x4f\x9f\xfe\x1f\x45\x7f\xfc\xfc\xbe\xcf\xab\xbc\xd9\xd5\x15\xd4\x1b\xd8\xec\x8e\xa7\x06\xf6\xbb\xaa\xfc\x2d\xd2\x9b\xc0\x23\xc4\x87\xfc\x6d\xb7\x86\xea\x7c\x28\xca\x63\x0c\x9b\xfa\x08\x9b\xdd\xbe\x84\x9d\x2a\xab\x66\xb7\xd9\xad\xcd\xe4\x28\x07\x00\x78\x84\xd3\xb6\x3e\xef\x15\xe4\xfb\x1f\xf9\x3f\x27\x28\x4a\xf8\x96\x3f\x7c\x30\x93\xaa\xfa\x47\x24\x70\x50\xb3\x2d\x21\xde\xe6\x47\x55\xec\xf3\xea\xaf\x18\x1e\x1f\xe1\xfb\x71\x57\x35\x27\xc8\x4f\x90\x83\xf9\xf7\x03\x14\xe7\x06\xd6\x79\xf5\xd0\xe8\x65\x4e\x87\xf3\x69\x5b\xaa\xe8\xe9\xc9\xac\xb0\x2d\x77\x6f\xdb\x46\x53\x9c\xc3\x7a\x9b\x1f\xf3\x75\x53\x1e\x23\x09\xc3\x0f\x3f\x40\x55\x37\xb0\xab\xd6\xfb\xb3\xda\x55\x6f\xa0\xca\xd3\xba\xac\x54\x79\x3c\x45\xcf\x1f\xcd\xb4\x43\xfe\xd3\x70\x0e\xfb\xb2\x7a\x6b\xb6\xf0\xae\xfc\x69\x07\xaf\xeb\xc3\xa1\xac\x50\x30\xa7\xf7\xf0\x3f\xc8\x61\x73\x56\x6f\x25\x6c\xf2\x75\x53\x1f\xa3\x97\x67\xb3\x82\x2a\x37\xf9\x79\xdf\x20\xb1\x87\x5a\x95\x86\xf1\x66\xbb\x3b\xc1\xa6\xae\x9a\xe8\xe9\xc5\x0c\x43\x51\x6a\xfa\x82\x75\x23\x2d\x1e\xb1\xba\xe6\x7b\x15\x49\x29\xc5\xf0\x77\x26\x53\xb1\x8a\x20\x06\xf7\x8f\x96\x58\xf0\xad\x1f\x00\x4e\x49\xc1\x0c\x8f\x01\x27\x80\xde\x02\x2e\xfe\xd5\xeb\x4b\x29\xe9\x4b\x74\x50\xc9\x3e\xdd\xa7\xd7\x0c\x06\xf6\x99\x42\x09\x97\xd2\x3e\x4d\x94\xd9\xa4\x48\x34\xa6\xa4\x16\x8a\x8c\xa5\x2c\x8c\x34\x65\x91\x98\x91\x86\xcd\x38\xa3\x91\x02\xdc\x2a\x6c\x24\x48\x99\x48\x92\x3f\x8e\x4c\x63\x36\x12\xfc\x19\xd8\x4f\x0b\x33\xdb\x17\x00\xa0\x70\x99\x4c\x13\x63\x10\xc7\x06\x22\x34\x91\x10\x3c\x01\x83\x20\x66\x11\xc2\x94\x5d\xa6\xb0\x0c\x02\x64\x44\xe8\x30\x31\x6d\xd2\x48\x4e\x45\x42\xcb\xe2\x42\x9a\x7d\xc4\x8d\xac\x38\x49\x28\x83\x34\xa6\xf1\x7a\x7a\x2a\xe5\x6b\x42\xcc\x49\x29\x63\x43\x87\x1e\x62\x25\x48\x7b\x80\xe0\xf3\xf5\x93\x90\x9c\x36\x79\x3d\xb8\x26\xb0\x30\xdb\xa4\xa8\xe9\x46\xcf\xad\xb6\xce\xfa\xd6\x3f\x9a\x20\x41\x32\x8c\xad\xf8\xf4\x2a\xa8\x7a\x1c\xc8\x50\x14\xab\x48\x18\x51\x18\x7b\xd2\x3c\x78\x31\xf7\x00\x7a\xbe\xd6\x27\x58\x45\x7a\x6c\x81\x47\x9b\xe1\x59\x19\xb5\x91\x21\x40\xd2\x43\x29\x9a\xed\xb5\x92\xf5\x2d\xcd\xf6\xe8\x15\x55\x6d\x0e\x06\x9c\x62\x15\x74\x50\xa4\x59\x88\x23\x59\xf4\x49\x63\xfd\xb4\xa5\xdb\x46\x32\x99\x3d\x34\xa5\xcf\x1b\xf4\xa0\x42\x0c\xec\x3b\x80\x12\xee\x79\xe9\x40\x2d\xd7\x20\xf8\x7f\x53\x73\x3b\x90\x06\x91\x81\xb1\xef\x96\x0e\x81\xf1\x95\xde\x91\xa2\xe3\x83\x79\x80\xa7\x7a\xc1\xac\x25\x64\x66\xce\xa4\x5b\xfe\x9e\x98\x56\xde\xe6\x05\xf7\x2a\x82\x7b\x15\xd1\xe3\x55\x50\x4d\x18\xe2\xbc\x8a\xa0\xa3\x64\xc8\xb8\x1f\x69\x7b\x15\x61\xbd\x8a\x70\x2e\x85\x94\x5f\xa2\xc7\x74\xc1\x6d\x0e\x62\xd4\xd0\xf2\x29\xac\x03\x11\xe1\xb6\x23\x88\x56\x60\xbd\x20\x11\x43\x10\x6a\xd9\x12\x88\x6b\x68\x7b\x1f\x06\x31\xa7\xda\x61\x9f\xa4\xe9\x35\x06\xac\xe3\x84\xa4\x56\xce\x6b\x2a\xf4\xb0\x60\x0d\x03\xe1\x20\x80\xb6\x42\xe0\x38\xfb\xe3\xf4\x38\x12\x84\xa1\x4c\xba\xac\x41\x3b\x05\xe3\xf2\x86\x8f\xc3\xfb\xf3\x25\xf4\x90\x2f\xb2\x4c\x28\x1d\x42\x08\x51\x26\x52\x23\xa2\x61\x8b\x28\x43\x02\x21\xad\x24\x02\xfc\x93\x1e\x64\x9a\x1e\xbf\x1a\x38\x5e\x59\x18\x60\x88\x17\xa3\x39\xc8\x98\xc4\x28\x00\xa6\xe4\xb3\x44\x5d\x27\xcd\xc7\xd1\xa3\xdc\x30\xbd\x89\xa3\xe7\xc6\xe6\xd3\x11\x37\xf7\x3a\xdc\xe9\x30\x9f\x23\xb8\x4c\x43\x8f\xc3\x1d\x4e\xe0\x6f\x66\xeb\xcf\xa0\x7c\x7c\xba\xc2\xf2\x35\xa3\x9b\x89\x92\x69\x7c\x27\x7d\x9e\xe9\xee\x1c\x71\xd2\x1d\x44\x4a\xc8\x6d\xf5\x67\x2a\x94\xcc\x0a\x2e\x3d\x4b\x98\x74\x28\x5d\x10\x46\xad\xd2\x79\x15\x71\xfa\xe1\xe3\x51\xe6\x92\x4d\xf0\xc9\x16\xb8\xdc\x43\xb0\xbc\xa9\xc5\x6d\xe8\x74\x67\xc6\x68\x66\xca\x8b\xa3\x76\x1f\xa9\xe0\x49\xe5\x29\x9e\x33\x90\x31\xd6\x27\x58\x1a\xd6\xab\xb6\xdf\x4e\x94\xd3\x11\x01\x18\x30\x3c\x02\xbe\x9e\x03\x80\xbe\x27\xcb\xf4\x3c\x20\x29\x66\x6e\xd0\xac\x68\x52\x4e\x16\xc5\xed\x17\xc3\x0b\x5f\x2c\x60\xad\xc0\x8a\x85\xc4\x6c\x96\x28\x6f\x23\x36\x2f\xbd\xa0\x58\x20\x7e\x15\x8f\x14\x88\x39\x4f\xa6\x9c\x11\x5a\xcc\x25\xe5\x54\x62\x59\x45\xa1\x1a\x4b\xba\xd2\x81\x39\x45\x7a\xc6\x32\xfb\x41\xba\xba\x19\xb2\x17\xa9\x8d\x38\x31\xd5\x0c\x06\x49\x5c\x4d\x60\x3e\xaf\x89\x7b\xd2\xeb\xee\x11\xf1\x12\xbe\x43\xf8\x09\x72\xb4\xfe\x40\x09\xb7\x0f\x3f\xc5\x2c\xc6\xe7\x21\xc9\x35\xf2\x09\x4e\x9e\xd6\xc6\xd0\xd6\x46\x30\xfe\xf5\x3d\x19\x9f\xd3\xd1\xa2\x5f\x48\x8f\x47\xee\xa5\x3f\xc0\x5c\xc3\xcc\xec\x7f\xa9\x7c\x66\x2a\x46\x47\x8c\x8b\x90\x85\xe7\x25\x2e\xa9\x41\x2e\xa9\x46\x20\x18\x19\xb3\x68\xca\xe6\xcf\x00\xd3\xce\xbf\xbe\x78\x71\xf1\x87\x9c\x39\x17\xbc\x72\xfe\x0b\x11\xef\x23\x94\x0d\x84\x98\xca\xbe\x86\x9a\x5a\x80\xf7\x88\x2e\xdc\xe2\x2a\x36\xe4\xd2\x0e\xad\x0c\xa1\x23\xf4\x6e\x85\x6a\x83\x1f\xdc\x08\xec\xd8\xec\x00\x68\x06\x17\x00\x54\x01\x91\xda\x15\xb6\x20\xb2\x6a\x58\x24\x8a\x69\x22\xb5\x66\xbc\xca\x99\xd4\x91\xab\x60\xe6\x03\x15\xd2\x15\xf7\x98\x59\x4f\x6c\x9a\x13\x44\x2d\xc1\x21\xb9\x9c\x58\x86\x51\xc7\x94\x11\x5a\x04\x64\x06\xe6\x95\x85\xc6\x96\x75\x09\x9c\x38\x45\xe1\xba\xbc\x3e\x1d\x69\xc5\x86\x96\x14\xa6\x31\x4c\x42\x92\xd0\xe1\x74\x23\xc4\x0c\x05\x6b\x05\xad\x11\x27\xd8\x17\x8d\xd0\xce\x69\xf1\x61\x64\x88\x86\xa1\xdc\xed\x7a\x51\x65\xee\x84\x8d\xa8\x32\x7d\xc2\x5c\x54\x92\xd7\x4e\x99\x4b\x8d\xef\x2c\xaa\x2f\x81\x83\xf8\xc2\x13\x28\xc4\x6e\x11\xbf\x5c\x82\x6a\x6a\x14\xc3\x6f\x91\x80\x6d\x07\xc4\xb6\x43\x8c\x87\x13\xdf\xaa\x9c\x93\x9d\xac\xc0\x6a\xc0\xfd\xb0\x81\xc3\xea\x77\xa3\xcb\x8d\xec\xbf\x31\xc0\x05\x1b\xb2\x8a\xcd\xa0\xbe\xa7\x91\x49\x59\xb3\xd7\x33\xe8\x7a\x5d\xf5\x96\xb9\xb6\xc6\x05\xa4\x85\xe4\xd4\x21\xde\xaa\xa3\xb0\x77\xef\x70\x32\x66\xe6\x85\xd3\xc0\xbb\xda\xd7\x41\x16\xc7\xea\xa4\xc7\xc3\xce\x0a\x01\x17\x48\xc8\x62\xec\x9d\x03\xc5\x38\x5b\x37\x2b\xa2\xb9\x80\xe0\x05\xd6\xc2\x40\x7e\xcd\xe1\xdd\xdf\x38\xac\x9b\xba\xa8\x41\x3f\xf2\xda\xcf\xbf\xad\xeb\xaf\x17\x66\x92\x66\x75\xcd\x27\x34\x4b\xa1\x79\x29\xa8\xed\x9b\xe0\x03\xc1\x50\xdf\xea\xa1\x49\x0c\x45\xb9\xb0\x9e\x0b\x43\xad\x3c\x59\xef\x05\xba\xad\xa2\x45\x92\xa0\xf6\xf7\x45\xd0\x82\x64\x1c\xa0\x76\x9a\xa4\x74\x94\x72\x96\x51\x90\x59\xa4\x71\x46\x5c\x08\x00\xdf\x82\xbb\x0a\x74\xed\x1f\xd6\x09\xba\x02\x5c\x94\xf1\x22\x9f\x64\x8e\xb6\x4f\x46\x33\x33\x67\x19\x74\xbe\x8e\xea\xc9\xdf\xe9\xad\xb1\x09\x8d\x57\x00\x84\x2f\x7d\x6c\x17\x8b\x95\x9d\xc2\xbf\x11\x9d\x9b\xc4\x5b\x8d\x1d\x04\x79\x46\x13\xb3\x7c\x26\xf0\xe9\x2e\x97\x69\xc5\xb7\x11\x61\x4e\xf1\x4c\xd9\x8b\x7f\x8d\x24\x78\x21\xef\x92\x18\x9f\xc2\x84\x77\x06\xc6\x77\x1e\x2b\x13\x85\x2f\x5a\x94\xce\x02\x3b\x22\x66\xc5\x81\x0d\xeb\xf3\x77\x9e\xe4\xd9\xe6\x6b\x26\x5d\x2b\x44\xa0\xa4\x19\xb6\xd7\xc0\xf3\x3c\x4f\xda\xc8\x92\x15\x25\x4b\xcb\xed\xea\x22\xfc\x67\x08\x68\x2f\xee\x81\xa5\xdc\xc9\xb4\xab\x4b\xfd\x72\x15\xc0\x32\x9c\x22\xc8\x40\x0d\x2b\xb7\xd2\xe2\x2e\x38\x2d\x57\xfe\xf6\x41\x00\x8c\x5c\x7d\xf2\x2b\x06\xdf\x2b\xec\xcf\x92\x9b\xcc\xdc\xfb\x4b\xbc\x36\x20\x9c\x4b\x8f\x9d\xa7\x9e\x04\x04\xb3\xc7\x05\x02\xe2\xfc\x27\xbc\x38\x79\x1d\x16\xdb\xb4\x80\xc6\xc5\x31\x53\x40\xfc\x33\x8d\xfb\xc6\x43\x70\xe2\x1d\xfa\xa7\xba\xfb\x17\x37\x1a\xa6\xa4\x72\x3f\x75\x9c\xdc\x39\x34\xc1\xb8\xd7\x04\x93\x84\x55\x2c\x37\x73\xe7\x17\x06\x92\x29\xcd\x9d\x1f\x48\x2e\x70\xe7\x02\x46\xc0\x89\x14\xc9\x16\x37\xde\x0e\x19\xdd\xfd\xd0\xe8\x7a\x33\x18\xb5\x01\xd3\x2c\xfa\x6a\xb3\x10\xe4\xc8\xd7\xf3\x5f\x91\x51\x94\xf1\xc3\x92\x2c\x61\x00\x18\x8a\x1e\x99\xbb\x8b\x18\x87\xf5\xda\x65\xd1\x63\xd2\x3c\xee\x16\x95\x07\xb7\xb3\xcd\x64\x91\xc9\x82\x9a\xc3\x26\x75\x4f\x61\xa1\xd1\xb4\x9f\x0d\xe0\x4b\x3d\x97\x95\x48\xeb\xad\x43\x6f\x17\xe2\x66\x9e\xcd\x6e\xfe\x0d\x85\xf2\x60\xf4\xee\x2b\x36\xc5\x8d\x8e\xc6\x31\xbb\xbc\x70\xe7\x43\xba\x30\xb9\x10\x2c\xb9\x98\xb3\x33\x2b\xbd\x6c\x61\xcc\xaf\x90\xf8\x92\x78\x59\xbd\xe1\xb2\x36\xe1\xd2\x36\x41\x55\xeb\x2a\x4a\x1c\x24\xa5\x7c\x87\x50\xec\xfe\xf3\xe3\x84\xb7\x43\xd1\x32\xc4\xd0\xbf\xe0\x9b\x74\x31\x01\x00\xc0\xe4\x18\x19\x5c\x5b\xe2\x56\xce\x1a\x8d\x31\xbb\x19\x61\x27\x18\x08\xef\xa6\xc2\x7b\x9e\xd6\xc4\xc1\x38\x23\x97\x14\xac\x6b\x0d\xac\xad\xdf\x65\x76\xd4\x99\xde\x7c\x63\x47\x53\xf0\x0e\x04\x06\xa0\x94\x9a\x2c\x8b\x9a\x75\xf3\x31\x83\x2a\x7c\x1f\xa1\xe8\xfe\x70\x86\x0d\x91\x4c\xa6\x34\xf8\x9a\x37\xfc\x5e\xcf\x5c\xa7\xa5\x27\x9b\x99\x40\x4d\x15\x5f\x58\x4a\x4d\x57\x2a\xb5\x84\x5e\xde\x89\xbf\x51\x5f\x74\x8c\xb4\x5f\xdc\xb2\x55\xa8\x57\xf6\x9e\x11\xd8\xcb\x46\x6e\xfc\xdd\xea\xf9\xe9\x9d\xef\x95\x00\x4e\xee\x7c\xbf\xf8\x9d\x28\x7f\xed\xc4\x64\x78\x43\xd7\x4e\xe0\x82\x6b\x27\x10\xa4\xa2\x21\x37\x3d\xc7\xbf\x5a\x45\xff\x06\x00\x00\xff\xff\xf0\xe4\xf5\xb7\x1d\x35\x00\x00")
+
+func fontsColossalFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsColossalFlf,
+ "fonts/colossal.flf",
+ )
+}
+
+func fontsColossalFlf() (*asset, error) {
+ bytes, err := fontsColossalFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/colossal.flf", size: 13597, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsComputerFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x58\x5f\x6b\xe4\x36\x10\x7f\xf7\xa7\xf8\x61\x0b\xf2\x72\xac\xae\x81\xf6\xd4\xe3\x38\x0a\x7d\x2e\x84\x3e\x1b\xf6\xd2\x64\xd2\xa4\xc9\x66\x43\xb2\x61\x39\xd8\x0f\x5f\xf4\x67\xa4\x91\x2c\xd9\x5e\xee\xe9\x42\xd6\x33\x5e\x7b\x34\xa3\x99\xdf\xfc\xd1\xde\x3d\xdd\x5d\x5e\x2b\x7c\xc2\x6f\xb8\xfc\x88\x8f\xb8\xec\x6e\xf6\xbb\x97\xf7\x03\xbd\x6e\xee\x9e\xee\xf0\xcf\x77\xfc\xf5\xf0\x48\xf8\x7b\xff\xf6\xfe\x44\x8f\xf8\xb2\xfb\xef\xf5\x8f\x67\x3a\x3c\x3c\xbf\x6d\x9e\xe9\xf0\xf5\x03\x3e\xe9\x5f\x2e\xf5\xef\xbf\x6e\xf0\xe7\x3d\xdd\x3c\x62\xff\x7e\xc0\xee\x7b\x77\xbf\xdf\xd1\xcb\xf5\xbf\x84\xeb\xc3\x67\xdc\x1f\x0e\x2f\x9f\xb5\x3e\x1e\x8f\x9b\x24\xaa\xdf\xee\xf7\xc7\x9b\xeb\x37\xd2\xbb\x87\x47\x3a\xbe\x3e\xdd\xea\x4e\xa9\xa1\xf5\x19\x3a\xa3\x30\x74\xc6\x28\x79\x51\xe0\xef\x00\xf7\x0e\x2c\xdf\xa3\xf7\xcf\xd0\xbc\x5a\x01\x00\xb7\x57\xb8\xbd\xb2\xeb\x02\x86\xff\xdc\x62\xfc\xc4\xaf\xcf\x4f\xec\x5d\x7a\xc2\x8b\xf1\x5f\x71\x37\x74\x44\x86\xc8\x9a\x0a\x38\xbb\x0c\x91\xbb\xb7\xb7\xf6\x9e\x02\x35\x44\x41\xad\x53\x31\x74\xa6\x37\xd6\x02\xf7\xc8\x44\x0b\xbd\x5a\xcb\xb1\x65\xd6\x16\xd3\x5b\xd1\xdb\x2b\xc0\x50\x70\x09\xeb\x47\xda\x90\x35\xe1\x83\x77\x20\x59\xb3\x9c\x03\x9d\x59\xc8\x39\xfb\x54\x21\x5b\x26\xac\xc0\xee\xae\x5c\xac\xc5\x8a\x23\x54\x5c\x48\xf1\x3b\x7d\x5c\xa7\xb8\xb0\xdd\xc3\xd0\x8d\x27\xad\x86\x4e\x9f\xc6\xe5\x00\xe6\x21\x88\xde\x8b\x5e\xe7\xfb\xe2\xbd\xf6\x2e\xd2\x46\xc3\xcb\x25\x09\xe1\xab\x3d\x5b\x5a\x55\x25\xcc\x69\x8f\x00\xe8\x10\x55\x1d\x82\xaa\x43\x4c\x75\x58\x58\x17\x18\x1b\xbc\x01\x11\x51\x1e\x52\x33\x0c\xb9\x58\x4a\x79\x86\x70\x8d\x04\xa4\x04\xa2\x84\xc6\x80\xd8\x44\xc2\xba\x26\xa4\x87\xf4\x4a\x90\x40\x78\x57\x50\x06\x56\x04\x7f\x00\xbd\xca\x8c\x0b\x0e\x63\x86\x13\x24\x65\x48\xf8\x26\x32\x85\x73\xd8\x2c\x64\xd9\x06\x23\x68\xee\x16\x61\xb1\xe1\x24\x28\x16\x90\xe9\x3b\x11\x94\x2f\x00\xa0\x0b\x47\xe9\x42\x09\x44\x16\x48\x1c\x3a\x50\xf4\x52\x4c\x3d\xc4\xd4\xf3\xe9\x68\x54\xce\xe5\xfe\xaa\xea\x67\x03\x85\x93\x32\xda\xca\x80\xa2\x94\xaa\x15\xef\xf8\x2c\xb1\xcb\x91\x4b\x7d\x4f\x5d\x92\x38\x6a\xb9\xde\x90\xe2\xd4\xf4\xbc\x97\xe8\x0d\xe5\xfb\x28\x33\x99\x29\xef\x8f\x64\xe2\x49\x3f\xce\x6b\x98\xb7\x4e\x16\xb8\xbe\xef\x7b\x86\x48\xc4\x08\x85\x2e\x13\x36\xd3\x97\xe8\x4c\xc8\xb3\x64\xbb\x8d\x96\x6c\x2e\x80\x6f\x1b\x6f\x8c\x76\xa1\xc6\x68\xe3\x7a\xb2\x25\x9a\x0c\x70\xb2\xaa\x46\x18\x03\xc3\x55\xe0\xdb\x66\xbb\xdd\x5c\xa8\xa2\x89\x48\xdb\xa6\x79\x6d\x62\xdc\x27\x8c\x2a\xe5\x81\xb8\x42\x84\x76\x68\x4e\x26\xee\x3a\x63\xa9\x28\x1f\x15\x6b\x5c\xcd\xa7\x5a\xd6\x82\x22\x66\x6b\xd6\x64\xbb\x69\x6e\xa2\x25\x5f\xc9\x71\xc3\xb5\x28\xd2\x0c\x31\xe7\x08\xaa\x1c\x62\xb3\x3b\x06\x88\x96\x2c\x16\x65\x59\xe6\xa8\xab\x6d\x15\x9a\x14\xe7\x2d\xb4\x32\xf8\x70\x49\x43\xc9\x90\x2c\x90\x84\x34\x65\x90\xa9\x19\x07\xc9\x14\xd3\xc1\x02\xb8\xd8\x13\xd1\xab\x75\x6f\xd6\xc2\x61\xa2\x5b\x4d\x44\x42\xf2\xc5\x0c\x57\x24\x6e\xee\xdc\xba\x53\xa7\xce\xb5\x82\x4b\xfd\x73\x92\x70\xf3\x38\x2e\x2b\xc6\x94\x99\x95\xaf\x30\xdb\xed\xd6\x2f\x2d\x9b\xb2\xd8\xf8\x0f\x04\x2e\xd3\x0f\xb6\x7f\x35\x70\x5c\xf8\x54\xd6\xe1\x88\xc7\xe8\x1a\x55\xed\x74\x68\x45\xac\xe8\xb5\xf5\x6d\xb9\x77\x7a\x13\x5b\xa8\xe8\xa5\x72\x8a\x65\xc5\x42\xb7\x50\x2f\x34\x57\x58\x57\x27\x27\x75\x70\x12\xad\x34\x9a\xad\xf2\x7f\x1b\x64\xde\x65\xa8\x31\x95\xf8\xcd\x74\x2c\xc1\x54\xf0\xeb\x74\x57\x2e\x69\x5c\x1f\xe3\x60\x3d\xc6\xd6\x36\x86\x19\xd5\x73\x5e\xfd\xc8\x75\x07\x63\x8e\x11\xb3\x3c\xee\xeb\x71\xe6\x54\x91\x06\x91\xea\x74\xb0\x30\x35\xb8\x0d\x38\xe3\xd7\x2c\xde\x1a\xa5\x9a\x15\x84\xf7\xd9\x91\x18\x1f\xdb\xa9\x38\x89\x40\x7e\xa4\x88\x70\x54\x31\x72\x4e\xca\xa8\xec\x80\xd1\x30\x75\x21\x75\x0a\x55\xd9\xd4\x9e\x54\x51\xa9\x6a\x49\x42\x15\xa7\x9f\x86\x71\xdc\x01\xd0\xb7\x8d\x83\xaf\x36\xe7\x06\x60\xe8\xa8\xd5\x24\xf3\xe8\xba\xb5\x8b\x33\x09\x55\x0e\xe0\x95\xe8\xb2\xe8\x9a\x42\x5b\x44\xd7\xdb\xb7\xd0\x20\x8b\xc6\x18\x9b\x5b\x28\x28\x74\x46\x8b\xac\x4c\xd4\xcb\x58\xa9\xc2\x3a\x13\x34\x59\xbd\x6e\x9d\x85\x96\x13\xa9\x31\x60\x35\x05\x45\x1b\x8c\x5d\xf0\x07\x32\xb0\x1d\x23\xa1\xb8\x57\xd3\x5f\x69\x1a\xe0\x48\x82\x4b\x4d\x70\x05\xd6\xd7\x64\xb0\x57\x19\x67\xeb\xb2\x0b\xce\x35\xbf\xd4\xba\xbc\x6e\xa1\x7e\xbe\x0f\x56\x9b\x5f\x96\x1c\xa0\x95\x5d\x70\x62\x4d\x4d\x7e\xa6\x0b\xb6\x03\xd7\x17\x07\x7b\x99\x5c\x99\x1b\x01\xed\x86\x96\x93\x5f\xd9\x93\x2f\xa1\xa5\x65\x5f\x02\xe3\xd6\xff\xe6\x58\xff\x28\xd7\xe0\xb8\x07\x9e\x94\x24\xf8\xaa\xca\x2f\xb7\x9a\xdb\x9d\x5e\xfa\x5d\xcb\x5f\xed\x84\x05\x37\x61\x9d\xdd\x98\x2a\x82\xeb\x32\x38\x0a\x9e\x8b\xce\x9f\xc8\x54\x55\xf9\x1f\xba\xff\x03\x00\x00\xff\xff\x33\x14\x99\x35\x04\x17\x00\x00")
+
+func fontsComputerFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsComputerFlf,
+ "fonts/computer.flf",
+ )
+}
+
+func fontsComputerFlf() (*asset, error) {
+ bytes, err := fontsComputerFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/computer.flf", size: 5892, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsContessaFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\x55\x4d\x4f\x1b\x41\x0c\xbd\xcf\xaf\xf0\x01\x69\x37\x69\xe2\xa1\x69\x25\xa4\x06\xa2\x91\xb8\xf5\xd4\x3b\x13\x39\x40\x83\x88\x84\x08\x4a\xe0\x50\xc9\xe2\xb7\x57\xf6\x7c\xac\x67\x49\x0e\x99\xec\xfa\x8d\x9f\x3d\xcf\x1e\xef\xd3\xcb\xd3\xe2\xfe\x02\x7e\xc2\x0f\x58\x5c\xc2\xfc\x3b\x2c\xdc\xed\xfe\xf5\x7d\x7b\x3c\xde\xc3\xc3\x3f\xb8\x7d\x3e\xec\x8e\xef\xfb\xb7\xe7\xed\x01\x7e\xef\x8f\xdb\xb7\x67\xf8\xb3\x3b\xec\x5e\x5e\xf6\xd0\xbf\xe9\xc3\xe3\xe2\xea\xea\x32\x3c\xee\x1f\x0e\xf7\xf8\xf1\xba\xc3\xed\xdf\x8f\x89\x73\x17\x17\xc1\xfe\x82\x03\x86\xb2\x4c\x65\x01\x08\xc1\x4d\xf5\x79\x03\x9b\x64\x29\x6b\x70\xc4\xc4\x04\xc3\x3f\x30\x70\x81\x75\x03\xd0\x92\x10\x82\xeb\x05\x87\xe0\x90\x98\x26\xba\x61\x53\xa8\xbd\xbc\x7a\x01\x7d\x09\x59\x3c\x93\x5f\x59\xc5\x47\x80\x69\x70\xd0\xc9\xab\xfe\xd4\x39\xb8\x5e\x5f\x63\x4d\x39\x3f\x4e\x32\x9c\x8c\xc8\x33\x08\x6e\x3e\x9d\x43\x70\x1d\x6f\x4c\xb0\x99\xb8\xcf\xbf\x09\x00\x9d\x39\x60\x39\x6c\x91\xa3\xcb\x46\xb5\x10\x11\x0c\x6f\x67\x3c\xb2\xd1\x9e\xd2\xf2\x93\x64\xc4\x28\x82\x33\xf1\x38\x23\xaf\x6a\x22\xe3\xd8\xa3\x53\x15\x3d\x9d\x01\x30\x8b\x9c\x4e\x0d\x33\xc3\x6e\x62\x60\x0a\x9e\x0b\x33\x19\x03\xbd\x02\xbd\x05\x48\x81\xb3\xe7\x48\x7b\x1b\x0f\x0b\x34\xc1\x8d\x44\x56\xa7\xd6\xd8\xd5\xfa\x5e\x8f\xeb\x9b\x55\xbf\xb9\xb9\x31\x7f\xd0\x14\x7f\xd5\x14\x1f\xa4\x58\x9d\x76\xc4\xd2\x18\xf5\x90\xbe\x5f\x4b\x6a\x91\xc8\x1b\x1a\x24\xc2\xe0\xee\x88\xd6\xc1\x31\x00\x1b\x7d\x84\xeb\x8e\x68\x52\x56\x18\xe8\x54\x99\x8d\x92\xe1\xc8\x83\x01\xa2\x08\x4e\xde\x02\xa4\x24\x89\x90\x4e\x02\x6c\xa5\xce\xc1\x21\xc1\x68\xa8\x00\x50\xd9\xf9\x4b\xba\x98\xef\x74\xbe\x47\x59\xc0\x94\x1e\x6b\xaa\xfc\x85\xc6\xd7\x84\x07\xa0\xe6\xc2\x4d\xaa\xc9\x23\xfa\x2f\x81\x33\x00\x0a\xc4\x46\x40\x2c\x7b\xb9\x09\x6e\x94\x1d\x9f\xda\x7a\xc4\x73\x1e\xd1\xd6\x02\xa5\xf3\x48\xbb\xdb\x14\x49\x94\xc5\xd4\x8d\x60\xfe\x9a\x94\x4f\x64\xa6\x40\x04\x10\xc1\xa3\x87\xf1\x21\x93\x87\x37\x87\xcc\x7b\x57\xd7\xa9\x25\x5a\x21\x67\xc2\x82\xfe\x44\x02\x25\x3b\x2d\x00\xfa\xda\x45\x02\xde\x7d\x6a\xe9\xf5\xc0\xb5\x87\x23\xe4\xbb\xa1\x96\x68\xae\xd8\xe7\x5a\x9e\x65\xa1\x75\xd9\xed\x23\x34\x43\xaa\xde\xa6\xb2\x92\x2d\x6d\x9a\xfb\x76\xd8\xa6\xc9\xa7\xca\x56\x4e\x4c\x2d\xa1\x69\x4d\xda\xbb\x9c\x76\xe2\x60\x94\x47\x91\xd5\xb8\xe7\x9d\x32\x27\xfc\xac\x72\x52\x70\x3c\x13\x61\xdb\xc8\x90\x5d\x91\xb8\x8d\x0c\x43\xe4\xe0\xa6\xc1\x49\x21\x86\x79\x3c\x55\xa1\x1b\xb7\xa5\x5c\x43\xce\x75\x11\xa3\xfa\x0c\x6e\x69\x2c\x42\x22\xe7\x4c\x3f\xa4\x82\xe3\xa8\x26\xbf\xd6\x88\x55\x19\x3e\xad\x21\x0f\x3b\x31\xd7\xb7\xe1\xa4\xe0\xca\x4c\x4d\x9f\x06\xfd\x56\x95\xef\xb4\x09\x04\xca\xc9\x6d\x59\x31\x77\x9b\x6f\x86\x6f\x81\x0a\x58\xe1\x81\x2e\xca\x70\xf1\x5d\x6c\xb3\xd1\x6b\x40\x55\xca\xdc\x33\x52\x56\x5f\x87\x8b\x70\xad\x84\xa1\x14\x4f\xbf\x6f\x60\xaa\x19\x75\xa6\xa7\x9d\xa5\x2f\x73\x03\xfb\x13\x1f\xd5\xfd\x1e\x4e\x8e\xb6\x04\xf8\xcd\x26\xa6\xe9\x3d\x02\x7e\x01\x2c\x47\xf7\x38\x13\x2b\xdc\x13\xcf\x46\x1e\x69\x82\xf7\xcd\x50\x57\x20\xa9\xd8\x52\x95\xe1\x9c\x2a\xbb\xaa\xc0\xff\x00\x00\x00\xff\xff\x79\xe8\xd6\x6a\xad\x09\x00\x00")
+
+func fontsContessaFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsContessaFlf,
+ "fonts/contessa.flf",
+ )
+}
+
+func fontsContessaFlf() (*asset, error) {
+ bytes, err := fontsContessaFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/contessa.flf", size: 2477, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsContrastFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x58\xcd\x8e\xd4\x30\x0c\xbe\xcf\x53\xf8\x40\xc4\x05\x0c\x8c\xf8\x11\xb7\x95\x40\x48\x1c\x56\x1c\x78\x82\xee\xd2\x59\xaa\x5d\xa5\xa8\xad\x84\xe6\xed\x11\x9d\x99\xc6\x8e\xed\x38\xd3\xdb\x4a\x1d\xed\x21\x72\xe2\xf8\xef\xb3\xbf\x74\x0f\x4f\x87\x7d\xf3\x02\x3e\xc2\x07\xd8\xbf\x85\xd7\xef\x60\xbf\xfb\xd2\xc7\x69\x68\xc6\x09\xbe\xf5\x71\x82\xbb\x23\x7c\x6d\x63\xec\x46\xb8\xed\xe3\x23\xc0\xa7\x37\x9f\xdf\xef\x7e\x0c\xdd\x43\x17\x9b\x27\x38\xf4\x71\x7a\x05\xdf\x61\xfa\xdd\xc5\x47\x04\xb8\x6d\x8e\x77\x2d\x74\x71\xfc\xd3\x0d\xed\xaf\xff\xca\x7d\x6c\xa1\x3f\xc0\xcf\xfb\x66\x68\xef\x87\xfe\xef\xcb\x11\x70\xec\x1e\x46\xdc\xe1\xf9\x77\x73\xfd\x6a\x5e\x86\x70\x11\x6a\xab\xa4\x92\xcb\x6e\x76\xb3\x28\x04\x64\x2b\x0c\xf3\x5f\x85\xe5\xe5\x60\x98\x7f\xe8\xca\x98\xf2\x65\x3b\x04\xbc\x38\x36\x8b\xce\xce\x2e\x7e\x25\x99\xe6\xf6\x29\x2c\x1e\xdf\xbc\x9d\x05\x25\x2c\x5f\xf6\x97\xa8\x03\x26\xe9\xec\x13\x3f\xeb\xe7\x1c\x95\x9c\xab\x05\xc3\x90\x6c\x9e\xb6\x43\x3a\xb8\xc8\xc8\x39\x1a\x39\xdb\x4e\x77\x07\x2e\x63\xe7\x16\xe5\x73\x29\x4e\x35\x09\xac\x50\x42\x4a\xce\x3a\x91\x13\xfd\x02\x02\xcd\xc4\xd4\xa4\xd2\x50\xa6\x96\xbd\x9c\x9b\xdb\x55\x6e\x87\x90\xe7\x9c\xa1\x2d\xa1\x49\xc5\x39\x62\xd6\x6b\x04\xfb\x09\x7f\x12\xe7\xcc\x4a\xa1\xcb\x65\x1e\xc4\x8d\xb9\x95\xe4\xac\xaa\xcc\x84\x24\xe6\xfc\x42\xb5\x3d\xe9\xb6\x8c\x99\xa5\x53\xb6\x27\x4f\x8e\x1c\x0c\x8e\x65\xad\x2c\xb2\x02\x6a\xb6\xad\x98\x57\xd7\xb9\x2c\xab\x56\xd6\x7c\x30\xb0\x5d\x33\xf6\xd7\x2a\x97\x1b\x23\x41\x51\xbf\x50\xc2\x13\x6d\x00\x96\x3b\xbb\xc2\x8a\xe6\x4d\x39\xdb\x5a\xc5\xd5\x61\x90\x94\x17\x96\xa0\x2b\xa4\xcc\xb1\x76\x18\xa8\xbc\xa5\xe1\xb8\x2c\x73\x2d\x23\x41\xb4\xd7\x18\x8a\xb2\xda\xe3\x76\x57\xf1\x91\x93\x17\xc8\x19\x43\x9e\xb2\x5b\x67\x4c\xdc\x5e\x33\x7a\xcd\xf8\xaa\x4b\x55\x60\xc4\xe2\xdc\x2e\x4f\xca\x6b\xdc\x4e\x6f\x81\x40\xa2\x97\xc8\x97\x5d\xe5\xad\x54\xb7\xe9\x68\x46\xfa\xb8\x23\x15\x14\x4b\xcb\xf9\x40\xc3\xa8\xc9\xb9\x85\xf0\xca\xb4\x79\xbd\x75\x35\xc5\x1b\x38\x5b\xdf\xd5\x6e\xcc\x36\x57\xba\x74\x57\x02\xa9\x3a\x06\xbd\x41\xb0\xa2\xb7\x8a\xc4\x67\xe0\x8c\x2e\xd9\x17\x83\x78\xd4\xeb\xf6\x0d\x92\xf5\x9a\xa4\xe4\xa8\x93\xb6\xda\x27\x46\xf5\x30\xbc\xa6\x3d\xc5\x23\x82\xd2\xbb\x00\x8d\xe1\xb6\x18\x49\x88\xfa\x23\x4f\x7d\xc4\x5a\x99\x5d\xf9\x70\x2f\xc6\x6c\x94\xa5\xe2\xc2\x8d\xab\x37\xae\xde\xb8\x7a\xe3\xea\x8d\xab\x37\xae\x5e\xc5\xd5\x67\x83\xf9\x04\x41\xcd\x72\x2d\x6f\x55\xac\xd8\x04\xc9\xe8\x5d\x7a\xa3\x7f\xdd\xa6\x6f\x5a\xff\xbf\xc0\x56\xb6\x91\x21\xbc\xae\xb7\x0c\xe5\x3a\xd2\x93\xca\x2b\x10\xfe\xac\xdc\xce\x67\x1e\x9b\x65\x8e\xf4\x74\xc5\xbf\x00\x00\x00\xff\xff\x92\x0a\xba\xc5\xf3\x18\x00\x00")
+
+func fontsContrastFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsContrastFlf,
+ "fonts/contrast.flf",
+ )
+}
+
+func fontsContrastFlf() (*asset, error) {
+ bytes, err := fontsContrastFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/contrast.flf", size: 6387, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsCosmicFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x58\x6d\x8b\xdc\xca\xd1\xfd\xde\xbf\xa2\xe8\x6e\xd3\x0f\xa6\xdc\xf3\xd8\x21\x37\x1d\x75\x1c\x42\x0c\x17\x02\x11\x11\x09\x26\x88\x5e\x5b\xf2\xce\xac\xaf\x1d\x7b\x46\x97\xeb\x35\xce\x85\xfb\xe3\x43\x9d\xea\x96\xb4\xf6\x26\x21\xdf\x57\xac\x76\xf4\x32\xaa\xae\x3a\xe7\xd4\x8b\xe6\xed\xc7\xb7\xcf\xde\x3c\xa2\xef\xe8\x3b\x7a\xf6\x94\xfe\x9f\x9e\x99\x17\x7f\xf9\x5b\xff\xa7\x17\xf1\xfb\x3f\x7f\x4f\xd7\x3f\x53\xff\xfe\xc3\x0d\xfd\x75\xf9\xf4\xf9\xe3\xcd\x07\xfa\xdd\xf9\x1f\x3f\xfd\xe1\x72\x73\xfb\xfe\xf2\x29\x5e\x6e\x6e\x7f\xcf\xf4\x9b\xc3\xd3\xa7\x87\xdf\xfe\x3a\xd2\x1f\x3f\xff\xf0\x89\xde\xbe\xff\xe7\xcd\x49\xae\xfd\x4a\xae\x99\x17\xef\x6e\x8e\x1f\x68\xf9\x7c\x4b\xe7\x9f\xe9\xdd\x72\xbe\xf9\xf1\xcd\x0f\x37\xf4\xe6\xb6\xa3\x77\xb7\xb7\x3f\x76\x87\xc3\x97\x2f\x5f\xe2\x66\xee\xf0\xe9\xdd\xf2\xe5\xf8\xe6\xd3\xcd\xe1\xfc\xfe\xc3\xcd\x97\x9f\x3e\x9e\x0e\xe6\xd1\x23\x77\xdf\xee\x0c\xc5\xce\x99\x9c\xb3\x33\xa1\x14\x67\xc8\x7b\x67\xc8\x5a\x67\xa8\xef\x9d\x33\x5d\x47\x5d\xe7\x8c\xcd\x94\xe5\x9a\x6c\xf7\x7f\xe0\xb3\xeb\xb0\x3b\x33\x4d\x9c\x03\x76\x67\x42\x28\x45\x77\x67\x88\xbd\xc5\x4e\xce\x2c\x29\x2d\xd8\xc9\x19\xee\x2d\xc9\x5e\x0d\xc5\x4e\x2d\x73\xce\x39\x92\x33\xa5\x30\x4f\xb3\x5c\x99\xad\xb5\xe3\xe2\x0c\x8d\xcb\xc4\x27\xb8\x14\xfa\xd0\x1e\x8b\x24\xcf\xce\xce\x50\x26\xca\xc4\x19\xcf\xd0\xeb\xd7\xc4\x65\x6e\xbe\x1e\x07\x62\xc6\x31\x27\x4b\x89\x28\x39\xc3\xa7\x41\x6e\x59\x0b\x43\xdd\x95\x2e\x1f\x73\x0e\xe4\xcc\xff\x95\x69\x92\xf3\xa3\xb7\x70\xdc\x8e\x0b\x2f\x03\x8c\xd9\x9e\x01\x92\x33\x2c\xd1\xd1\x9d\x5d\x23\x71\x86\x61\xe5\x52\xe4\xf2\xe8\x71\x33\x2d\x2c\x77\x2d\x20\x8e\xb8\x14\x32\x2e\x95\x8b\xfc\xf7\xa3\x33\xbc\x24\x72\x46\x40\x51\x70\xc9\x99\xab\x5f\x0e\xe4\xcc\xe1\x97\x2b\x6a\x57\x76\xff\xbf\xe5\x05\x2b\x7a\xd9\xe4\x2c\x7d\x45\xd6\x37\xff\x4e\xe9\x1a\x4c\xb8\x7b\x8c\x9b\xe3\xf1\x78\xfc\x76\xb9\xfb\x6d\x8c\xfd\xd0\xbc\x39\x80\x0d\x39\xa8\x5c\xd0\xa5\x04\xfd\xf6\xd1\x5b\x7d\x6e\x49\x56\xed\x9e\xa1\x80\x2d\x94\x6a\x96\x73\x66\x39\x62\x79\xb2\x5c\x10\x93\xdc\x93\xb0\xc6\xc4\xe0\x51\x44\x3b\x9e\xcf\x03\x1e\xee\xa2\x48\x5a\x64\x23\x5f\x75\x26\x25\x67\xa0\x66\xe1\xa3\xab\x78\x73\x0e\xf3\x0c\x75\x51\x08\x44\x5c\x8a\x30\x18\x8f\xde\x0f\x41\x23\x49\x34\xf1\x22\x44\xf5\x7d\xff\x72\x78\x6c\x5f\xbf\xd6\x7c\x11\x03\xf2\x8d\x1c\xe6\x50\x5d\x13\xdd\x5d\x4a\xd1\xc3\x79\xb6\xde\xfb\x08\xd7\x79\x49\x09\xde\xd1\xd8\xf7\xc3\xca\x65\x44\x96\x88\x0f\x39\xd7\xc8\x4a\x91\xc0\x86\x69\xf2\xfe\xe8\x8c\xe8\xbc\x3e\x48\xd4\xf7\x88\xaa\x6e\xce\xcc\x39\xcf\x73\x08\xd9\x19\x2a\x85\x27\x85\x69\xb6\xf6\xf1\x08\x8e\xa6\x89\x97\x53\xd2\x14\x1e\xec\x86\x67\xac\x91\xcb\xb2\x1a\x01\x97\x12\x97\x53\xba\x56\x99\x58\x22\x0b\xa9\x8c\xe9\x9a\xf9\x94\x20\x71\x3b\x36\xb7\x63\x8c\x75\xfd\x10\x04\xba\x1c\xaa\xd9\x12\xd4\xaa\xf7\x95\xd9\x94\x52\xa5\xae\xef\xfb\xba\x3e\x9e\x15\xb4\x05\x73\xf1\x40\xc5\x7e\x29\x48\x45\x48\x41\xe2\xa6\xf1\x9a\x27\xde\x2f\xad\xb4\x31\xc3\x77\xce\x00\x9d\x51\x12\x68\x62\x94\xac\xd1\xfb\x41\x1d\x67\x9e\x58\x23\x27\xbb\x43\x5b\x9e\x63\x29\x70\xe1\x5e\x95\xde\x7f\x7b\x4b\x04\xe5\x97\x25\x3d\x55\x25\x47\x8f\x8b\x36\x5d\xb7\x34\x5e\xf5\x4e\xbb\x4f\x96\x0d\xf7\x2d\x0a\x2a\x2d\xcb\xb2\xac\xe7\xab\x6d\x66\x7c\x84\xa2\x50\x28\x0e\x95\xc1\xb1\xa5\x7f\x7c\x22\xf8\x3d\x81\xb0\xc3\x2c\xe8\x67\xf5\xea\x52\x2a\xfc\x27\x3f\xd4\x7c\x92\x32\x46\x2b\x01\x5b\x46\x09\x05\x41\xb7\x35\x0b\xa4\xc2\x49\x95\xcd\x39\x73\xcc\x34\xe7\xe8\x4c\x27\x42\x2e\x51\xa9\xc5\xb1\x36\x06\x26\x0a\xa3\x97\xfc\x18\x91\x24\x28\xbe\x63\x5a\xa0\x40\x82\xec\x96\x1a\xff\x6c\xc7\x97\x3d\xb6\x97\x63\xa3\xa1\xab\x89\x83\xaf\xe4\x3c\xe7\xdc\x70\x2a\x85\x10\x3d\x6a\xac\xf7\x47\xfc\x43\x99\x84\x90\x52\x4a\x02\xe3\x88\x58\xac\x9d\x77\xc9\xd0\x82\xc8\x21\x68\xad\xa6\x52\xca\x34\x95\x72\x15\xe1\xb2\x20\x3d\x8a\x34\xa6\x94\x16\x16\x50\x07\x67\xac\x3a\xb7\x69\x0b\xd8\x76\x55\x5f\x80\x77\x86\x92\x8b\x04\xbf\x16\x22\xaf\x55\xa7\x9e\xcd\x49\xd8\x97\x98\x95\xb5\x16\xf0\x60\x37\xef\x9e\x34\xf7\x84\x61\x95\x2d\xcd\xd5\x26\x30\x55\x50\xb5\x92\x21\xce\x89\x97\x34\x84\x9a\x39\xfd\x60\x67\xcd\x3c\xee\x56\x0f\x33\x82\x0d\x9a\x69\xa5\x48\x59\x56\x14\x35\x58\x3d\x4e\xd2\x56\x79\x9a\x08\xbd\xbc\xc6\x2b\x86\x34\xd2\x00\x33\xb0\x82\x20\x99\x9f\x3f\x97\x90\xa4\x06\xcc\xf3\x06\x3c\x1e\xef\x7b\x5e\x05\x54\x91\x3a\x54\xa8\x9e\x34\xa8\x56\xac\x0a\xb6\x83\x33\xd6\xfb\x23\xd8\xb6\xde\xa3\x3a\x8d\x02\x17\xca\x21\x52\x80\xe6\x30\xf6\x2f\x07\x3b\xd6\xba\x2c\xc1\xa1\xed\x6b\xd7\x27\x02\x6a\xa8\x50\x85\x59\xfe\x13\x8c\x4a\x90\x5e\x4d\xaa\x8f\x56\x0d\x6a\xa1\xa1\xb1\x0e\x2d\x6d\xa6\x29\xda\x02\xd0\x03\xd0\x04\xfa\x56\x0b\x5b\x35\xeb\x54\x3f\xba\x49\x38\xe8\x07\x33\x09\x51\xb1\x25\x28\x48\x9a\x95\x7f\x98\xba\x5e\x96\xe5\xd4\x30\xb2\x7d\xdd\x6c\x4b\x35\x70\x15\xa9\x89\x53\x06\x09\x8e\x2a\xce\x52\x0e\xe0\x6e\x92\xb6\xcc\xd5\x80\xf4\x08\x11\x28\xd5\x48\x6c\xd5\x91\x1a\xda\xec\xd4\xc3\xa6\x4b\xb0\x1e\xea\x21\x46\x29\x8e\xd3\x24\x02\xdf\x51\xde\x24\xab\x23\x95\x38\x42\x40\x37\x57\xd6\x0a\x4b\x02\x6a\xf1\xf1\x75\xab\x10\x0b\xc2\x63\x92\x21\x09\x20\x03\x63\x19\xb6\x6c\xdf\x60\x86\x2d\xf9\x44\x53\x82\xd0\x5b\x69\x42\xac\x91\x42\x13\xba\x27\x3b\xfa\xe3\xaa\x74\xb0\x25\x9c\xb4\x26\x21\xe4\x6d\xe4\xb4\xf8\x62\x65\x26\xd6\x76\x85\xeb\x57\xa5\x30\x9c\x05\x7e\x04\x7e\x05\x43\x9e\x68\xe2\xb4\x36\x8f\x7e\x4d\xf2\x6e\xdd\xd0\xef\x67\xa5\x3a\x56\x4f\xe7\x57\xaf\x2e\x97\xcb\xab\x57\xa1\x96\x5f\xef\xad\x5d\x4b\xb9\x84\xbe\x15\x76\x31\x7a\x4d\xfb\x96\xa6\x18\xd4\xce\x34\xeb\x40\xb0\x55\x8e\x52\xca\x95\x26\x03\x11\xca\x1a\x06\x95\xc7\x92\x0b\x63\x4a\xd7\xac\x43\xe4\xe3\x71\xb0\x64\xfb\x5d\xe5\x88\x91\x5a\xb2\xa3\xd6\xe7\xc6\x3b\x1f\x4a\xa9\x03\x94\x52\x75\xa4\x35\xe5\xaf\x25\x19\xb4\x25\xf5\x8a\xa9\xfd\xbb\xbd\xeb\x29\x4c\xce\x50\x33\x5a\xce\xf3\xe7\x07\x70\x8f\x52\x1e\x20\x25\x0f\x63\x08\xf2\xd4\x90\x3c\xf7\xe3\x57\x38\xd6\x0c\xcb\xad\x1c\xd5\x6e\xb6\x09\x53\x89\xd9\x9f\xa5\xc4\xbb\xb3\x4a\x3a\xbc\x8b\x4d\x46\x90\x39\x55\x7d\x0a\x8a\xa1\xa1\xd8\x66\xbe\xca\xb6\xea\x27\x9e\x90\xd5\x98\xfc\x90\x7f\x15\x41\xfd\x62\x84\x2c\x75\x42\x43\x8f\x03\xbf\x57\xe2\x62\x2c\xe5\x50\x5d\x19\xfd\x31\x62\xf4\x69\x0c\xa7\x34\xec\x3b\x79\x3f\xb4\x92\xef\x4c\x54\xd3\xfa\x96\x81\x41\x08\xc6\xc5\xe5\x66\x1e\x7d\x4c\xf7\xd0\x2c\x7a\xf4\x33\x3f\xac\x36\x2d\xd2\x3d\xed\xd0\xb0\x92\xf3\x76\xeb\xd4\xbc\x05\x01\x85\x6a\x6a\x45\xc6\xb4\x28\xd7\x65\x1d\xde\xd6\x90\x55\x3c\x56\xd0\xf3\x65\xb0\xf3\x2c\xef\x29\x90\xe6\xd9\xd6\x18\x6c\x7f\x66\x6d\x03\x9a\x60\x3a\x51\x50\x40\x7e\xa1\x0c\x2a\x91\x62\xbd\xec\xad\x1f\xf7\x10\x71\x42\x63\xaa\xa7\x6d\x68\x57\xdf\x77\xf2\x40\x73\x58\x07\x15\xcc\xc7\xa1\xce\x89\x18\xcd\x0c\x27\xed\xa1\x6d\x7a\x7d\xb9\xcd\xb9\x18\x73\x90\x47\x54\xc7\x7d\xe1\x9c\xf1\xf2\x85\xda\x33\xe3\x1d\x4d\x07\xdf\x7c\xd5\x7c\x09\xe5\xd2\x9c\xb4\x92\x19\x0d\xee\x65\xc3\xf9\xbc\xae\x20\x61\x6b\xa1\xd2\x02\x25\x9d\x47\x9b\x84\xd6\xde\xa8\xf9\x12\x68\xce\xdf\xbe\x5a\x7d\xfd\xe6\xbb\xbb\xf0\x5f\x0e\xce\xba\x21\x86\x5a\x8d\xf8\xbe\x17\xae\xd5\xf6\xc3\xdc\xf4\x30\x37\x3d\xcc\x4d\x0f\x73\xd3\xc3\xdc\xf4\x30\x37\x3d\xcc\x4d\x0f\x73\xd3\xbf\x9b\x9b\xf0\x43\xbe\x7c\x53\x48\xb7\xce\x24\x94\x58\xcc\x19\x92\x66\xf7\xfc\x1c\xaa\x3c\x3b\xa3\x3d\x42\xf4\xeb\x0c\xb2\x29\x74\xb1\x0b\x72\x97\xe6\xfd\xfc\xf3\x9f\x27\x1b\xfc\x92\xa5\x79\x8d\xdf\xd7\x43\xa8\xd3\x4a\xa8\xbf\x0f\xee\xc6\x15\xba\x3b\xaf\xdc\x1d\x58\xee\x4e\x2c\xda\x44\xaa\xd6\x99\x61\x77\xab\x6e\x9a\x41\xfb\x02\x47\xb5\x6c\xae\x35\x4e\xc7\x8c\x5d\x99\x6b\x6a\x5a\x2b\x5d\x5d\x66\xcb\xa7\xb6\xce\x96\x54\x75\xa1\x5d\x66\xd5\xd8\x77\xe9\x55\xaf\xec\x72\x6c\x1d\x46\xd7\x44\x7b\x00\xea\x7f\x02\xea\xd1\xd7\x7f\xce\xfc\x2b\x00\x00\xff\xff\xdf\x73\xc9\xcc\x69\x1b\x00\x00")
+
+func fontsCosmicFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsCosmicFlf,
+ "fonts/cosmic.flf",
+ )
+}
+
+func fontsCosmicFlf() (*asset, error) {
+ bytes, err := fontsCosmicFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/cosmic.flf", size: 7017, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsCosmikeFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x58\xdf\x6b\xe4\xc8\x11\x7e\xef\xbf\xa2\xe8\xee\xa1\x2f\x4b\xb9\x27\x7b\x21\x97\x8e\x3a\x1b\x0e\x42\x1e\x05\x22\x60\x82\x68\xef\xaa\x3d\x9a\x71\xec\xd8\x33\x7d\xac\x7d\x31\x07\xf7\xc7\x87\xaa\xea\xd6\xe8\x62\xef\x42\xc8\xbd\xc5\xc2\x9a\x69\x69\xa4\x52\xd5\xf7\x7d\xf5\x43\xbe\x79\xb8\xf9\xf6\x7a\x03\xdf\xc1\x77\xf0\xed\x7b\xf8\x2d\xfc\x4e\xcd\xe5\xf1\x78\x37\xfb\x9b\x87\x1b\xd8\xfd\x04\xfd\xdd\xfd\x01\xfe\x56\x1e\x7f\x7c\x38\xdc\xc3\x9f\x8e\xff\xfc\xfc\xfd\xe9\xf0\x74\x77\x7a\xf4\xa7\xc3\xd3\x9f\x11\xfe\xb0\x7d\xff\x7e\xfb\xc7\xdf\x7b\xf8\xcb\xed\x61\xbe\x87\xf2\xe3\x13\x1c\x7f\x52\xb7\xe5\x78\xf8\xe1\xfa\x1f\x07\xb8\x7e\xea\xe0\xf6\xe9\xe9\x87\x6e\xbb\x7d\x7e\x7e\xf6\xe7\x5b\xb7\x8f\xb7\xe5\x79\xbe\x7e\x3c\x6c\x8f\x77\xf7\x87\xe7\xcf\x0f\xfb\xad\xba\xb8\xb8\xb8\x80\xbe\xec\xef\x6e\xee\x0e\x7b\xb8\x3e\xed\x61\x2e\x9f\x3f\x1f\xe6\xa7\xc3\x5e\x3c\x99\x6f\x0f\x0f\xf0\xd7\x9b\xa7\xbb\xe3\xf5\xfd\xdd\x23\x7c\x23\x67\xfc\x72\xe6\xfb\x7f\x3d\x3c\xde\xf9\xb9\x1c\x7f\x03\x64\x4b\x6d\x36\x9b\x8d\xf9\xfa\xa7\x51\xe0\x3b\xa3\x62\x8c\x46\xb9\x94\x8c\x02\x6b\x8d\x02\xad\x8d\x82\xbe\x37\x46\x6d\xba\x0e\xba\x8e\x2e\xd7\x11\xa2\xde\x18\x05\xb2\x7d\x6d\xc1\xab\xae\xe3\xdd\xa8\x69\xc2\xe8\x78\x37\xca\xb9\x94\x64\x37\x0a\xd0\x6a\xde\xc1\xa8\x12\x42\xe1\x1d\x8c\xc2\x5e\x03\xed\xd5\x90\xef\xc4\x36\xc6\x18\x3d\x18\x95\x12\xe2\x94\xe9\x4c\xd6\x5a\x8f\xc5\x28\x18\xcb\x84\x7b\x72\x19\x5c\xef\xda\x6d\x1e\xe8\xde\x6c\x14\x44\x80\x08\x18\xf9\x1e\xf8\xf4\x09\x30\xe5\xe6\xed\x3c\x00\x22\xaf\x31\x68\x08\x00\xc1\x28\xdc\x0f\xf4\x93\xd6\x6c\xa8\xbb\x92\xc7\xfb\x18\x1d\x18\xf5\x4d\x9a\x26\x3a\x9e\xad\x66\xc7\xf5\x58\xb0\x0c\x6c\x4c\xf7\x68\x8c\xea\x3a\xa3\x90\xa2\x83\x5f\xec\x12\x89\x51\xc8\x56\x4e\x89\x4e\x8f\x96\x7f\x0c\x05\xe9\x57\x4d\x70\x77\x9e\x4f\xb9\xc8\xa7\xd2\x89\x3e\xed\x68\x14\x96\x00\x46\x11\x28\x02\x2e\x18\x75\xf5\xf3\x16\x8c\xda\xfe\x7c\x05\xed\xcc\xea\xf3\x0b\xec\x24\x5e\x6c\x2c\x6d\x42\x65\x78\x49\xdc\x8b\x8f\x7d\xd8\x31\x2b\x8b\xd5\x97\xdf\x9b\x79\x9e\xe7\xcd\x8b\xf3\x5f\xb1\x37\xf6\x43\xb3\xb7\x65\x96\x68\x51\x39\x82\x53\x72\x72\xf5\x6c\xb5\xdc\x57\x82\x16\xcb\x47\x56\xc6\x3a\x44\xa1\x2f\x46\xa4\x15\xd2\x9d\xe9\x04\x46\x59\x4b\xbf\x91\x9c\xc7\x80\xcc\x2f\x09\x7b\x3c\x1e\x07\xbe\xb9\xf3\x24\x7b\x92\x13\x5d\x6a\x54\x08\x46\xb1\xe2\x89\xa7\xae\xf2\x80\xd1\xe5\xcc\xaa\x03\xe7\x00\x30\x25\x62\xd6\xcf\xd6\x0e\x4e\x22\x09\x30\x61\x21\x02\xfb\xbe\xbf\x1c\xde\xe9\x4f\x9f\x24\xa7\xc8\x00\x5d\x11\x5d\x76\xd5\x35\xd2\xe3\x29\x25\x59\xe6\xac\xad\xb5\x9e\x5d\xc7\x12\x02\x7b\x07\x63\xdf\x0f\x0b\xc7\x9e\xb3\x87\x7c\x88\xb1\x46\x96\x12\x05\x36\x4c\x93\xb5\xb3\x51\xa4\xff\x7a\x23\x40\xdf\x73\x54\x75\x33\x2a\xc7\x98\xb3\x73\xd1\x28\x48\x09\x27\x81\x29\x6b\xfd\x6e\x9c\x67\xa3\x60\x9a\xb0\xec\x83\xa4\xf9\xa0\xcf\x78\xfa\x1a\x39\x3d\x56\x22\xc0\x94\x7c\xd9\x87\x1d\x43\x4a\x74\x68\x2e\x11\x63\xd8\x21\xee\x03\x4b\x5f\x8f\xcd\x6d\xef\x7d\x7d\xbe\x73\x04\x5d\x74\xd5\x6c\x72\x62\xd5\xda\xca\x6c\x08\x4d\x7a\x7d\xdf\xd7\xe7\xf3\xbd\x84\x36\x61\x4e\x1e\x48\x12\x9c\x12\xa7\x28\x4b\x81\xe2\x86\x71\x87\x13\xae\x1f\x2d\xb4\x21\xb2\xef\x18\x19\x74\xe4\x52\x01\x13\x72\x59\x1b\xad\x1d\xc4\x71\xc4\x09\x25\x72\xd0\x2b\xb4\xe9\x3e\xa4\x22\xe8\x5e\x55\xe9\xeb\x3f\xaf\x92\x82\xbf\x90\xd2\x56\x54\x32\x5b\x3e\xa9\xc3\xae\xa5\xf7\xf0\x6a\x56\x6e\x90\x36\x2a\xb0\xa0\xb5\xe6\x02\xbb\x29\xa5\x14\x5e\xc8\x99\xe5\x09\x88\xfc\xe5\x92\x00\x22\x68\x54\x1e\xc7\x56\x1c\xfc\x05\xa1\x78\xc1\xf2\x76\x99\x38\x88\xe2\xdb\x29\x55\x12\xf6\x76\xa8\x59\x45\x45\x0e\x16\x1a\xce\x79\x45\x44\x38\xd9\x96\x5c\xa0\xfa\x47\x35\x38\xc6\x88\x3e\x42\x8e\xde\xa8\x8e\xe4\x9c\xbc\x10\xcc\x6b\x69\x21\x08\xe0\x46\x4b\x59\x32\x72\xaa\x70\x69\x1e\x43\x61\x1d\x02\x8b\xaf\x54\x10\xb2\x1e\x2f\x7b\xde\x2e\xc7\x46\x46\x57\xd3\x87\x2f\x89\x31\xc7\x58\x0f\x30\x25\xe0\xe8\xb9\x02\x5b\x3b\xf3\x07\x17\x51\x96\x53\x08\x81\xc0\x1e\x39\x16\xad\xf3\x2a\x25\x5a\x10\xd1\x39\xa9\xe4\x90\x52\x9a\xa6\x94\xae\x3c\xbb\x4c\x50\x8f\x24\x90\x29\x84\x82\x04\xea\x60\x94\x16\xe7\xce\x0a\x63\x6c\xbb\xaa\x32\x86\x37\xb3\x9e\x13\x05\xbf\x70\x6a\xa5\xf6\xd4\xa3\x1c\x48\x03\x14\xb3\xb0\xd6\x02\x1e\xf4\xd9\xbb\x8b\xe6\x1e\x31\x2c\xe2\x85\x5c\x6d\x32\xa6\x02\xaa\xd4\x33\x8e\x73\xc2\x12\x06\x57\xf3\xa7\x1f\x74\x96\xfc\xc3\x6e\xf1\x30\x72\xb0\x4e\xf2\x2d\x25\xaa\xd0\x82\xa2\x04\x2b\xeb\x40\x4d\x17\xa7\x09\xb8\xeb\xd7\x78\xc9\x90\x44\xea\xd8\x0c\x5b\xe1\x20\x11\x3f\x7c\xa0\x90\xa8\x12\xe4\x7c\x06\x9e\x6f\xef\x7b\x5c\x04\x54\x91\xda\x56\xa8\x2e\x1a\x54\x0b\x56\x89\xb7\xad\x51\xda\xda\x99\xd9\xd6\xd6\x72\x8d\x1a\x09\x2e\x2e\x8a\x85\x25\x92\xdd\xd8\x5f\x0e\x7a\xac\xd5\x99\x82\xe3\xa1\x40\x66\x02\x00\x46\x8d\xeb\x54\x42\xa4\x4f\x60\xa3\x14\xa4\x15\x93\xe2\xa3\x16\x83\x52\x6e\x40\xcc\x71\xa9\x8a\xd2\x07\xb8\x11\x70\x27\xe0\x56\xd0\xb7\x8a\xd8\x6a\x5a\x27\xfa\x91\x8d\xc2\xe1\xae\x90\x81\x88\xf2\x2d\x41\x99\xa4\x2c\xfc\xb3\xa9\x5d\x29\x65\xdf\x30\xd2\x7d\xdd\x74\x4b\x35\xe6\xca\x43\x13\x27\x8d\x19\xe8\x45\x9c\x29\x6d\x99\xbb\x89\xba\x35\x56\x03\xd4\x29\x48\xa0\x50\x23\xd1\x55\x47\x62\xe8\x6c\xa7\x2e\x9b\x2e\x99\x75\x57\x97\x3c\x68\xa1\x9f\x26\x12\xf8\x8a\xf2\x26\x59\x19\xb8\xc8\x11\x60\x74\x63\x65\x2d\x21\x25\xa0\x14\x1f\x5b\xb7\x0a\x31\x21\x3c\x06\x1a\xa1\x18\x64\xc6\x98\x46\x31\xdd\x37\x98\xd9\x16\x7d\x73\x6b\x62\xa1\xb7\xd2\xc4\xb1\x7a\x70\x4d\xe8\x16\xf4\x68\xe7\x45\xe9\xcc\x16\x71\xd2\x5a\x05\x91\x77\x26\xa7\xc5\xe7\x2b\x33\xbe\x36\x2d\x3e\x7f\x95\x12\xb2\xb3\x8c\x1f\x30\xbf\x84\x21\x4e\x30\x61\x58\x5a\x48\xbf\x24\x79\xb7\x6c\xdc\xf5\xb3\x50\xed\xab\xa7\xf9\xe3\xc7\xd3\xe9\xf4\xf1\xa3\xab\xe5\xd7\x5a\xad\x97\x7a\x4e\xa1\x9f\xab\x3b\x19\xdd\xc1\xba\xb1\x09\x06\xb5\x3f\x65\x19\x0b\xce\x95\x23\xa5\x74\x25\xc9\x00\xc0\x65\x8d\xc7\x95\x77\x94\x0b\x63\x08\x3b\x94\x11\xf3\xdd\x38\x68\xd0\xfd\xaa\x72\x78\x0f\x2d\xd9\xb9\xd6\xc7\xc6\x3b\x6e\x53\xaa\x63\x94\x50\x35\xc3\x92\xf2\x3b\x4a\x06\x69\x4c\xbd\x60\xaa\xff\xae\x7f\xe9\x29\x9b\xcc\xac\x66\x6e\x39\x1f\x3e\x6c\x99\x7b\x2e\xe5\x8e\xa5\x64\xd9\x18\x07\xb9\x6f\x48\x1e\xfb\xf1\x3f\x70\xac\x19\x16\x5b\x39\xaa\xdd\xec\x2c\x4c\x21\x66\x7d\x14\x02\xae\x8e\x2a\xe9\xec\x9d\x6f\x32\x62\x99\x43\xd5\x27\xa1\xe8\x1a\x8a\x6d\xf2\xab\x6c\x8b\x7e\xfc\x9e\xb3\x9a\xe7\x3f\xce\xbf\x8a\xa0\x5c\xe8\x59\x96\x32\xa7\x71\x8f\x63\x7e\xaf\xc8\x45\x9f\xd2\xb6\xba\x32\xda\xd9\xf3\x00\xd4\x18\x0e\x61\x58\xb7\xf3\x7e\x68\x25\xdf\x28\x2f\xa6\xe5\x1d\x84\xc7\x21\x36\x4e\x2e\x37\xf3\xdc\xc7\x64\x77\xcd\xa2\xe5\x7e\x66\x87\xc5\xa6\xe6\x74\x0f\x2b\x34\x34\xe5\xbc\x3e\x77\x6a\x3c\x07\xc1\x0a\x95\xd4\xf2\xc8\x33\x23\x9d\xa7\xe7\xe0\xf9\x19\xf4\x14\xcb\x4f\x90\xe3\x32\xe8\x9c\xe9\x2d\x86\xa5\x79\xd4\x35\x06\xdd\x1f\x51\xda\x80\x24\x98\x4c\x14\xe0\x38\xbf\xb8\x0c\x0a\x91\x64\x3d\xad\xad\xcf\x6b\x88\x30\x70\x63\xaa\x87\x6d\x74\x17\xdf\x57\xf2\xe0\xe6\xb0\x0c\x2a\x3c\x25\xbb\x3a\x2d\xf2\x80\xa6\x30\x48\x0f\x6d\x33\xec\xe5\x79\xda\xe5\x31\x87\xf3\x08\xea\xd0\x4f\x9c\x23\xbf\x9a\x71\xed\xc9\xfc\x06\x27\xe3\x6f\xbc\x6a\xbe\xb8\x74\x6a\x4e\x6a\xca\x8c\x06\x77\x39\xe3\x7c\x5c\x9e\x40\x61\x4b\xa1\x92\x02\x45\x9d\x47\x9a\x84\xd4\x5e\x2f\xf9\xe2\x20\xc7\xf5\x34\xf8\xe2\xeb\x0b\x6f\x65\x5f\x5a\x1c\x65\xe3\x18\x6a\x35\xc2\x57\xde\xf5\xce\x6f\x7c\x6f\x73\xd3\xdb\xdc\xf4\x36\x37\xbd\xcd\x4d\x6f\x73\xd3\xdb\xdc\xf4\x36\x37\xbd\xcd\x4d\x5f\x9a\x9b\xf8\x5f\xfe\x74\x25\x91\xae\x8d\x0a\x5c\x62\x79\xce\xa0\x34\x7b\xe5\x9f\xa2\xc2\xb3\x51\xd2\x23\x48\xbf\x46\x71\x36\xb9\xce\x77\x8e\x7e\x85\xbc\x9e\x7f\xbe\x3e\xd9\x50\x10\x40\xc9\x22\x0d\xf7\x7f\x9f\x55\xc8\x10\x69\xbc\xda\xfb\x75\x4a\x1a\x50\xff\x02\xfe\xfb\x75\xb2\xe6\xff\x30\xe4\xff\x6e\x84\x84\xd5\x08\x09\x7d\x9f\xc7\xe6\xd7\xbf\x03\x00\x00\xff\xff\x16\x77\xec\x28\xa6\x1b\x00\x00")
+
+func fontsCosmikeFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsCosmikeFlf,
+ "fonts/cosmike.flf",
+ )
+}
+
+func fontsCosmikeFlf() (*asset, error) {
+ bytes, err := fontsCosmikeFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/cosmike.flf", size: 7078, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsCricketFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x59\x5d\x8b\xe3\x38\x16\x7d\xf7\xaf\x38\x03\x0d\xe9\x86\xd8\x9e\x34\xb3\xcd\x76\x18\x96\xcc\x0c\x53\x45\x0d\xfb\xb0\xec\x3c\x34\x0b\x01\x95\x2b\x96\xcb\xa2\x1c\xab\xc7\x92\xdb\x5b\x60\xf6\xb7\x2f\xfa\xb2\xe5\xc4\x29\x3b\x1f\xb3\x6c\x68\x2a\x72\x2c\x9d\x7b\xef\xb9\x57\x47\x1f\x9d\x15\xd9\xc7\xe4\x1d\xfe\x8a\x1f\xb0\xfa\x01\xdf\xe3\xe3\x0a\xdf\x63\xf5\xe9\xe3\x5f\x3e\x05\xbf\x54\x6c\xf7\x42\x25\x9e\x5e\xf1\x77\x2a\x0a\x46\xf1\x73\x22\xa9\x80\xfd\xfc\x96\x94\x11\x56\x4b\xac\x3e\x7f\xfe\x14\xec\x4c\xdf\xcf\x9b\xa4\xe2\x22\x2a\xa9\xb4\x9d\x72\x29\xbf\xae\xe3\xb8\x69\x9a\xc8\xbd\x89\xff\xe3\x3a\x07\x0f\x68\x98\xc8\x21\x39\x64\x9e\x94\x2f\xf8\x92\xa4\x14\x77\xac\xdc\xe5\xb4\x42\xc6\x2b\xc8\x9c\xe2\xf7\x87\x7b\xf5\x5a\xa2\x49\x04\x6a\x41\x53\x24\x02\x09\x9e\x12\x41\x75\x1f\xe7\x66\x22\x82\x86\x16\x85\x7a\xfb\x4b\x5e\x31\x81\x7b\x56\x14\x68\x72\x8e\x94\x0a\xf6\x5c\xd2\xd4\xc0\xfd\x51\x27\x95\x1a\x59\xca\x25\x04\xdf\x53\xf0\x0c\x4d\xce\x76\x79\x6f\x80\x95\x70\xd1\x47\xf8\xa9\x4c\x91\xb1\x32\x29\x8a\x57\x1c\x3a\xfc\x8f\xa4\x2e\xf0\x73\x5d\x49\x5e\x2e\xb5\x29\x96\x81\x19\x4f\x4b\x2e\xb5\x7b\x39\x13\x08\x94\x07\x15\x55\xe3\x76\x15\x4d\x24\xc5\xdd\xc3\xfd\x17\x56\x2e\xf1\x80\x7d\xf2\x8a\x92\x7e\xa3\x15\xf2\xe4\x1b\x45\x9e\x18\x37\xf7\x5c\xb2\x6f\x89\x64\xbc\xf4\x46\x25\x08\xee\x1e\xee\x95\xeb\x51\x60\x21\xc0\x84\xee\xff\x85\x95\x29\x6f\x04\x76\x05\x2f\x75\x48\x77\x0f\xf7\x05\x95\x68\x98\xcc\x91\x20\xab\x8b\x02\x19\x4d\x64\x5d\xd1\x14\x16\x04\x34\x65\x92\x57\xdf\x05\xb8\xe3\xd5\xb3\xa2\xf0\x89\xd7\x12\x29\x67\xe5\xb3\x71\x22\x91\x3a\xd8\x8c\x3d\xd7\x15\x85\x7a\xa9\x7e\x16\xfb\x5a\xe4\x7b\x9e\x52\x94\xf5\xfe\x89\x56\x11\xf0\x5b\x2d\x24\x76\x39\xdd\xbd\x20\x09\x90\xd1\x06\x4f\xfc\xdf\x54\x68\x06\x68\xb2\xcb\xcd\x18\x85\x5b\xd5\x05\x8d\x30\xb4\x48\xcb\x74\x9f\x54\x2f\x02\x61\x08\xe5\xb4\x32\xb2\xe3\xfb\xaf\xb5\xa4\x55\xe0\x5b\xcf\x79\x03\x99\xa8\x24\x97\xa9\x7e\x68\x58\x4a\xf1\xca\xeb\x4a\x27\x14\x4c\x38\x5f\xd2\x2a\x69\x5c\x9c\xc2\xb0\x20\x73\x1a\x60\xcf\x6b\x41\xf5\xf0\x86\x7d\xa5\x2e\x9c\xf4\x99\x1a\x07\x78\x96\x19\x38\xb1\xab\x28\x2d\x91\x55\x7c\x0f\x65\x50\x57\xe0\x8e\xd7\xa5\x64\xe5\xf3\x77\x81\x4f\xbf\xe6\x96\x67\x8e\x5e\xb1\xc4\x53\x2d\xc1\xe4\x42\xf4\x95\xa7\x78\x50\x86\x9f\x5e\x91\xe8\xd0\x0a\x2a\x29\x58\xca\xb8\x8c\x80\x87\x2c\x50\x56\xf1\x47\x9d\x14\x2c\x7b\x5d\xe2\x1b\x13\xcc\xd0\x60\xcd\x34\xf4\x49\x30\xa9\x88\xfb\xdd\x38\x26\x72\x2e\x05\x54\x25\x8b\x9c\x37\xe5\x52\x87\xc4\x33\xe5\x62\x25\xa8\x81\xdb\x25\x25\x52\xde\x94\x05\x4f\x52\x30\x65\xe8\xfd\xdd\x3f\x7f\xfd\xf5\xbb\x0f\x41\x80\xd1\x8f\x9d\xad\x39\xdf\xd3\x88\x26\x95\xcc\x0b\x56\xbe\x98\x39\x2b\x78\x51\xab\x6a\x0c\x02\xfc\x54\x08\x0e\x41\xa9\xf3\x4f\x97\x99\xf1\x6f\xdd\x61\x08\x19\xaa\x49\xbf\x13\x51\xcd\xea\x5d\x44\xd3\x3a\xae\x05\xad\x44\xbc\xcb\x13\x16\x67\xec\xb9\xa0\x32\xca\xe5\xbe\x08\x02\xbc\x7b\xb7\x19\xff\x03\x78\x7f\xd4\x5f\x42\xd4\x43\x0b\xb4\xea\x8b\x10\xef\x0b\xae\xe3\xd1\x97\x19\xe8\x86\xda\xc1\x68\x49\xdb\x8d\xeb\xfa\xbe\xdd\x30\x2d\xa2\xb1\xcc\xef\x44\xa1\x29\x2c\x8d\x4d\x6c\x47\xeb\x96\xff\x04\xed\x26\x51\xfd\x37\x03\xf2\xdf\x7c\x32\x9e\x2f\xc3\x65\x17\xf7\x02\x8b\x2e\x6a\xdd\xc7\xb6\xf5\xc7\x86\xd3\x2a\x2b\x03\xa8\x93\x6d\xcb\xa9\x23\x47\xfb\x67\x20\x4d\xa4\x0e\xdd\xe3\xf8\x00\xe3\x44\xf3\x2d\xcf\x31\xc4\xbe\xca\xf3\xbe\x1a\xd0\x4e\x94\x81\x57\x0d\x2e\xe0\xe5\xc2\x25\x4b\xa7\xd1\x36\xf4\xab\xc7\x88\x90\xb7\xeb\xc3\x96\x15\x5c\xea\x1f\x23\x93\x67\xeb\x0e\xe9\xab\x94\x2c\x17\xd3\x40\x20\x5e\x3c\x1d\xca\xdf\x74\x97\x1f\x5d\x76\x0e\x13\x31\x9f\x2b\x6d\xc2\x2b\x5a\xaf\x62\xbd\x02\x9d\x93\xda\xe0\x10\xd8\x67\x78\x66\x4a\x0e\xf0\x4c\x11\xa0\x2f\x88\xf3\x8a\x6d\x8e\x47\x73\x44\xc2\x14\x86\x69\xc5\x40\xac\x5a\xcb\x85\xfa\xb7\x09\x10\x13\x12\x0f\x8c\x4d\xb4\xfa\xb8\x1c\x25\x20\x6e\x72\x45\xba\x4c\x8e\xdb\x6b\x60\xd5\xb5\xd7\x51\x84\x48\xb7\x1f\x43\xf3\x59\x8c\xcc\x80\x0e\xbe\x07\x77\x70\x8f\xa1\x06\x37\xc9\x5d\xf7\xad\x75\x64\x5a\x8f\x43\xc8\x31\x8f\xe1\x29\x8c\x83\x55\xd4\x10\x45\x46\xef\xf1\x16\xe7\x79\x3c\x42\x89\x6f\x80\xbc\x27\xe4\x1a\x4a\xe0\x19\xf8\x97\x27\x68\xad\xaf\x97\xce\xd8\x80\x1c\x9f\x9e\x23\x82\x26\x22\x00\xb0\x22\x9e\xac\x5d\x97\xd4\x09\x03\x91\xee\xbe\xc5\x4d\x0d\xf8\x39\xd0\x69\x46\x0c\xa7\x69\x70\xda\xe0\xb7\x35\x41\xa3\xc2\x3c\xab\xee\xff\x14\x8a\xba\x08\xb6\xd7\xe5\xc0\x57\x8d\x33\x34\x64\x74\xe0\x3c\x39\x34\x9d\x95\xdc\xe8\x7e\xb1\x4e\xc1\x26\xc0\x56\xc5\xa2\x5f\xa9\x45\x69\x72\x4d\xf2\x7e\x1c\xd5\xd5\x8b\x24\xd6\x06\xe3\x16\xbb\xc7\xc8\xbc\x55\xae\xe9\x57\x56\x2e\x5b\xb5\xd6\x4d\xee\xa1\x7c\xaf\x6c\x56\x16\x4b\x60\x19\xea\x7e\x6d\x18\xda\xfa\x5a\x84\xe1\x59\x3a\xeb\x15\x04\xf1\x4a\xa2\x1d\x14\xc8\x31\x13\x07\x64\xcc\xdb\x94\x9d\x2c\xf0\xd5\x89\x02\x6f\xbd\xfa\x6b\xd7\x7d\xfd\xe1\xcd\x02\xf7\x2d\x98\xd9\x6e\x4d\xc4\xf0\x6c\x0c\x74\x40\x67\xc4\x55\xb9\xce\x4a\x57\xe6\xc3\x50\x26\x23\xf1\xc4\xa6\x75\x7d\x2e\x9c\xaa\xf0\x23\xd9\x02\x9e\x1a\x6c\xfd\x07\xeb\xbc\x8d\x24\xf6\xac\xe8\x80\x1f\x5d\x20\x97\x47\x42\xc8\x87\xab\x22\x99\x63\x00\xf0\x92\xee\xd6\x46\xd7\xb6\xa2\x79\xa6\x6c\xfa\xb9\xb8\xf9\xda\x78\xcb\xb2\x75\xe0\x9d\xb7\xfe\xf7\xda\x03\x73\x54\x38\x90\xb9\x4b\xd3\x6d\x28\xf0\x39\xf8\xe0\x4d\xac\x18\xde\xc4\xda\x0e\x12\xb9\xed\x33\x19\x01\x1f\x7c\x22\xc6\xcb\xd1\xa9\x87\x5b\x96\x06\x85\x7e\x8b\x89\x75\x2a\x99\xe8\xdb\x5b\x25\xcd\xd7\x68\xd0\x70\xe2\x4e\xec\x5e\x07\x06\xba\x6d\xe8\x94\xc8\xfd\xb9\xdb\xe3\x19\x32\xed\x26\xd7\x4d\x67\xec\xac\x08\x7a\x8a\xc2\xb6\xdf\x78\xaa\x1f\x16\xa7\x0c\x6c\x2d\x68\xe1\x04\xd2\xce\xd8\xd5\x55\x0b\xcd\xff\x6a\x37\x8b\xe1\x31\xc5\x3f\xa8\xd8\xc1\x36\x86\xfe\xb0\x32\xbd\xd9\x3c\x35\x0f\x6e\x2b\x19\x17\x18\xc0\x56\x1b\x88\x6f\x11\x41\xac\xe4\xc8\x19\xc0\x59\x49\x1e\xa8\x1e\xde\xfb\xb2\xa7\x45\xae\xd3\x3d\x73\xb8\x73\xc2\x87\xd8\x57\xbe\xf7\x6b\x65\x67\x6d\xa5\xef\x94\xf6\x4d\x1e\xc2\x7a\x6a\x54\x4d\x11\x77\xc2\x38\x3f\xe9\x93\x47\x98\xab\xcf\xa9\x1d\x7a\xbf\x91\xdc\x04\xfe\x7d\xdf\x8c\x2b\x22\xbb\x0c\xd8\x6d\xbc\x7d\xfb\x18\x75\x3b\x68\x75\x4c\xd9\x4e\x6c\x71\x8f\x37\xbb\x76\x1b\xde\x9d\xe9\x47\xee\x9c\x66\x5d\x5e\xf5\xd3\xd2\x0c\x8b\xb7\x97\xdd\x89\x1e\xf8\x79\xd8\x1c\x3d\x87\x4c\x0c\xdb\x1c\x5f\xf7\xb6\x27\xce\x5d\xa7\xee\x96\x36\x01\xa2\x30\x0c\xa3\x30\x32\x28\xa4\x67\x27\xf2\x5d\x98\x45\x3a\xba\xb5\xbc\x0d\x47\x00\xc9\x99\x80\xbe\x83\x1d\x1c\x99\x97\xbc\x43\xf2\x0d\x4d\x91\x3e\x37\xb5\xb7\xf1\xac\x73\xcd\xf9\x16\xfa\x47\xa6\x33\x01\x6d\xee\x23\xef\xb6\x15\xdd\xd5\xfd\xd9\x75\x76\xe8\x99\x17\xea\x39\x41\x9f\xce\x6a\xaf\x25\xed\xb9\xa1\x0e\x4e\xff\xc3\xff\xa6\xc0\xdb\x05\x6b\x0f\xff\xae\x73\x77\x65\xe0\xe9\x9a\xb3\x75\xf4\xfd\x56\x28\xfd\xd5\xf1\x65\xa1\xf4\xe7\xe6\xd9\xa1\x1c\x25\x2a\xf4\xa9\x1d\xb2\x7b\x78\xf4\x9e\xfb\x70\xba\x1c\xae\xc8\xde\x38\xe0\xcd\xa7\x12\xe9\x17\x43\xe2\x4d\x83\x5b\x78\xd8\xdf\xde\xcd\x08\xfe\x94\x0c\xdd\x6c\x6e\x12\x82\x30\xbc\x94\x3b\xef\xce\xa0\x3d\x58\x89\xcf\x16\xc8\xce\xb3\xa8\x0b\xb2\xbd\x4d\x56\x8f\x00\xf5\xb5\x63\x3c\x05\x33\x06\x38\xc0\x1c\xc0\xfa\xae\x1e\x5d\x56\x5d\x3a\x63\x9c\x09\xe2\xd1\x1a\xdd\x94\x8a\x4b\x14\xd9\x07\x74\x65\x14\x86\xb8\x7e\xf1\xd1\xf3\xa4\x1d\xbf\x56\x6d\xe7\xed\x96\x46\xf4\x70\x4a\x16\x37\x07\xff\x47\x68\x77\x30\x23\xd7\xa6\xfd\xe6\xe6\x74\x21\xf7\xa1\x2c\xac\xdd\xe5\xc4\xb0\x51\x20\x2f\x57\x9a\x64\x1b\x49\x78\xb1\x70\x9e\x00\xbc\x5c\x38\x07\x80\x6d\x07\x78\xf9\x9c\x1d\x7a\x18\x8d\x78\x78\xe6\x86\xf0\xff\x3f\xe4\xa3\x83\x37\x21\xe6\xea\xc0\xb6\x7f\xdc\xf4\xd7\xe1\x71\xbf\x08\x0d\x65\xe3\x64\x7b\x13\xfc\x37\x00\x00\xff\xff\x78\x67\xe6\x4a\x39\x26\x00\x00")
+
+func fontsCricketFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsCricketFlf,
+ "fonts/cricket.flf",
+ )
+}
+
+func fontsCricketFlf() (*asset, error) {
+ bytes, err := fontsCricketFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/cricket.flf", size: 9785, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsCursiveFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x57\x5d\x6f\xa3\x56\x13\xbe\xe7\x57\xcc\x45\x24\x40\x32\x4c\x12\x65\x57\x1b\xc9\xb2\xc8\x7b\xf1\xaa\x5d\xa9\x52\x2f\x5a\xed\x5e\x20\x9d\x10\x38\x89\x69\x6d\xb0\x00\xaf\xeb\xca\x3f\xbe\x9a\x99\x73\xf8\x26\x71\xeb\xc4\x98\x8f\xf9\x3a\xcf\x3c\x33\x73\x78\xdd\xbd\xde\x27\x37\xf0\x19\x1e\xe0\xfe\x16\x6e\xe1\xee\xce\x71\xfe\x97\xd4\x3a\x83\xb2\x80\xf4\x58\xd5\xf9\x0f\xed\x7d\xf6\xe1\xe5\x0c\x5f\x93\x02\xbe\x95\xbb\x46\x57\x40\x9f\xf5\x1f\x49\x91\x46\x69\x95\xef\x43\xad\xd3\x3a\x3c\xee\xf3\x74\x1b\xea\xec\xb8\x21\xd5\xfb\x07\xf8\x7a\xdc\xc1\xdd\xe3\x97\x4f\xce\xff\xf3\xb7\x9d\x6e\x82\xfc\x6f\x9d\x41\x52\x64\xac\xfd\x72\x86\x6f\xba\xc8\xf4\x6e\x07\x3f\xe5\xe9\x9f\xba\x80\xf5\x69\xcb\x27\xd1\x21\xa9\x92\xba\x7c\x6d\xc2\xb4\xdc\x6f\x58\xb8\x2c\x00\x3e\xc1\x2f\x49\x05\x77\x8f\x8f\x0f\x0e\xdd\x7a\xca\x32\x9d\xc1\x3e\xaf\xeb\xbc\x78\x83\xc3\xb1\x48\x9b\x63\xd2\xe4\x65\xc1\x1e\x8a\xe3\xfe\x45\x57\xb5\xf3\xb4\xdf\x93\x13\x71\x69\x3e\xb4\x12\x5d\x55\x49\x06\xbf\xe6\xba\x4a\x35\xad\xe4\xc0\x67\x51\x7a\x48\x8a\xb0\xac\xde\x36\xad\x30\x79\xfe\x02\x4f\xc7\x37\xb8\xbf\xbd\xbd\x67\xcf\xbf\x17\x99\xae\xea\xb4\xac\x34\xbb\xca\x92\x7a\x0b\xdb\xe4\x87\x86\x17\xad\x0b\x38\x1e\xb2\xa4\xd1\x19\x34\x25\xec\x49\x24\xdd\x95\xb5\xde\x9d\x61\x9f\x34\xe9\xb6\x07\xa8\xe3\x18\x0f\xbf\x6d\x35\x80\xab\x5c\x48\xb7\x49\x95\xa4\x84\x6e\x5e\x43\x53\x69\x36\x93\x17\x90\x40\x7d\xd0\x69\x9e\xec\xe0\x94\x9c\x43\x80\x9f\x1b\xd8\x27\x67\x78\xd1\xd6\x42\x5e\xd4\xba\x32\xc2\xcd\x56\x43\xa3\xff\x6a\x20\x29\xce\xa7\xad\xae\x34\x9c\xcb\x23\x9c\xf2\x7a\x4b\x11\xed\x74\xf1\xd6\x6c\x35\xd9\x84\xb4\x2c\x02\x6b\xa1\xd0\x69\x43\x30\xee\xf2\x82\x96\xd1\x9c\x68\x25\xcd\x89\x14\x9a\x46\x57\x75\xe8\x38\x37\x37\xd1\xdc\x37\x62\x13\x7c\x44\x3a\x22\x9d\xbb\x74\xa7\xb4\xf7\x41\x84\xe8\x4e\x19\x39\x2e\xb8\xe6\xb2\x3d\x88\x36\xeb\x07\x18\x60\x10\x39\xfc\x03\x91\x83\x80\xad\x95\xde\x2f\x9d\xac\x58\x10\x3c\x85\xf2\x00\xc1\x07\x56\x74\x67\x15\x3c\xbf\x17\x1f\xab\x20\x78\x7e\x2f\x7a\xb6\xea\xf9\x7c\x85\x31\xfd\x78\x00\xdf\xe9\x2a\x46\x88\x8d\x25\xfb\x13\x39\xb4\x9c\xc8\x71\xf9\x84\xff\xe9\x91\xc2\xce\x78\x77\x84\x11\x10\xd8\x1e\x15\x2e\x0a\xf1\x55\xcc\xe1\x06\xc1\xf7\x20\x60\xc3\x31\x4c\xe3\xe8\xe0\x67\x51\x34\xa2\x30\x23\x6a\xff\x6d\xe0\x94\xc0\x1b\x73\x08\x48\xaf\xbb\x94\xcc\xf6\x14\xda\x35\x4e\x61\x9c\x0b\x5f\x29\x93\x14\xf0\x45\x90\x14\x3c\x65\x93\x35\xc9\xa6\x62\x69\x16\x65\x93\x63\x76\x18\x7b\x20\xf6\xc2\x20\x70\xc5\xde\x12\x3b\x46\x0a\x00\x01\x19\x56\xcb\x01\xc8\x35\x72\x10\x6e\xc0\xd2\x00\x38\x87\x22\x28\xa5\x5a\x88\xdd\x20\x08\xc5\xb0\x3f\x9f\x9b\x0e\x2c\x25\x11\x8f\x39\x27\xd6\xc8\x2d\x13\x7a\xba\x76\x59\x89\x67\x56\x8e\x66\xe1\x73\xee\x54\xdf\x45\x97\xa1\x71\x6e\xda\x43\xd9\xd6\x65\x1f\xea\xf9\xc7\xae\x3c\x46\x8a\x30\x72\x98\x88\x5c\x14\xfc\xed\xeb\x31\x91\xf8\xd0\x5b\x45\x2b\x6f\xf4\x7b\x7a\x26\x51\x12\x35\x5a\x87\xb3\xc0\x9b\x4b\x25\xa9\x2a\x63\x59\xad\xe0\x37\x16\x1d\x11\x50\x32\x8a\x00\x9e\x7a\x9f\x30\x9d\xc2\x9a\x14\x88\x31\xea\x2a\x05\x11\x78\x87\xe2\xf3\x35\x81\xe4\xe0\x43\x85\x67\x09\xc9\x78\x50\xab\x45\x85\x16\x0d\x04\xee\xb3\xd4\x25\x57\xa2\x86\x03\x85\xc1\x19\x9d\x52\xeb\x5b\xb1\xbb\xe7\xc0\xbd\x98\x15\x99\x08\x83\x75\x17\x62\xef\x84\x28\x47\x27\x2b\xa2\x87\x6f\x29\x47\x50\xb7\x58\x2f\xa8\xd1\xc7\x9a\xbc\x10\x1c\xab\x20\x08\x2e\xac\x1f\x2b\x84\x58\x2d\xa8\xa9\xb6\x18\x60\x23\xd7\x28\xb5\xc8\x2e\xd7\x0a\x47\x90\xa8\x2e\x3a\x13\xdc\xda\xf6\x2c\x7f\x09\x43\xee\xcb\x5d\x23\x6f\x11\xed\x4a\x48\xf1\x9f\x98\xf5\x4d\x32\xd1\x74\x2e\xb7\xcf\xb0\x31\x56\xca\x6a\x0d\x18\x70\x0d\x29\xdd\xab\xda\xe8\xc4\x83\xf4\xc9\x61\xe6\xaf\x20\xa5\xa7\x62\xeb\xe1\xf9\x5a\x0f\xf1\xc2\x1a\xcc\x48\x35\x33\x95\x1d\x59\xda\xcf\x17\x96\x1a\xb2\x98\x1e\x32\xa5\xae\x61\x31\xd3\x91\x94\x0d\x1f\x6d\x4f\xef\xd5\xe6\x47\xca\x7d\x2e\x7b\xed\x08\x88\x11\x96\xb8\xac\xa0\xaf\x67\xfb\xae\xa1\xa4\xa7\xbc\x01\x29\xe7\x7c\x32\x41\x65\xd4\x03\x6d\x39\x4c\x42\xe2\x59\x78\x66\x0a\x0e\xac\x2b\xea\x24\x7c\xc7\xa2\x85\x56\xad\x1b\x32\xb6\xa4\xa3\xf1\x80\x1d\xce\x0c\x54\x93\xc9\x11\xdb\x3d\x89\x00\x22\x0f\xe2\xe9\x78\x11\xd3\xed\x2e\x41\x4d\x67\x10\x76\x93\xa3\xff\xed\x6d\x38\x54\xb7\xe1\xe0\xdd\xc7\xf3\x70\x9f\x35\x18\x0f\x4a\x85\xc2\x8c\xcb\xec\x20\xe8\x4f\x60\x45\x0b\xf3\xdf\x19\x89\x2a\x64\x1c\xc7\xe0\x58\x61\xde\xb3\x29\xa9\x90\xae\x6b\x0f\xdc\xb5\x96\xa8\x1f\xe1\x8c\x25\x6b\x4a\xf6\x01\x68\x36\x1a\x62\x0d\x37\xfc\x7c\x8d\xa3\xf0\xc5\xe2\x8a\xfd\xfa\xdc\xf0\x2e\x10\x39\x17\x5c\xd8\x65\x20\xe0\xa4\x67\x59\x98\x4b\x6a\x93\xd1\x60\x70\x8f\x66\xad\x8c\x7d\x34\x84\xa0\x89\xee\x2e\x6d\x67\x10\xd6\x53\x47\x86\x4a\x28\x44\x64\x14\x66\x10\x9f\x96\xb1\xd4\xbd\xd9\xf4\x77\x96\xa7\x35\x33\xac\x09\x51\x34\x6a\xeb\x85\x59\xdd\x66\x45\x31\x84\x8b\x59\x31\xbf\x86\xfc\x68\xc0\x96\xfb\xee\x98\x54\xd3\xac\x6c\xa6\x59\x31\x6e\xe5\x7d\x63\x06\xac\x9e\x90\xd4\x9d\xbf\x20\x64\x27\x1d\xcf\xb9\x59\x44\xdb\x63\x08\xa1\x30\x74\x91\xe8\x2b\x4a\x52\x8c\xf0\x3e\x10\x2b\xfa\x33\x3d\x6c\x01\xd8\x41\x21\x86\x2b\x49\x43\x3c\x5f\x88\xa3\xa4\x71\x1b\x23\x50\x8c\x6d\xd3\x27\xdc\x79\xdb\x5c\xe4\x08\x20\x45\xee\x5d\x06\xb6\xe9\xbd\x4b\x5d\xf7\xde\xf5\xd1\x8b\x8b\xc1\x04\x65\x1b\x60\xe5\x66\x4a\x5d\x19\x4f\xb1\xc2\xb9\x2a\x1a\xc4\x57\x2a\x55\x46\xff\x66\x37\xda\x29\x5c\x39\xf8\x4b\xd6\xf9\x6f\x73\xcf\xdc\x29\xa1\xbc\xa2\x9d\x9a\xb7\xf8\xc5\x4a\x12\x43\xef\x93\xb0\x7d\x39\x33\x78\xd8\xdd\xb6\xb2\xdb\x6d\x1c\x85\x19\x45\xce\x3f\x01\x00\x00\xff\xff\xbf\xcb\xeb\x13\xa7\x12\x00\x00")
+
+func fontsCursiveFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsCursiveFlf,
+ "fonts/cursive.flf",
+ )
+}
+
+func fontsCursiveFlf() (*asset, error) {
+ bytes, err := fontsCursiveFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/cursive.flf", size: 4775, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsCyberlargeFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x56\x51\x6f\xab\x36\x14\x7e\xf7\xaf\xf8\x1e\x40\x24\x12\x98\xa4\xcb\x95\x52\xae\x98\x90\x36\xdd\xed\x6e\x77\x57\x57\xea\x1e\xd9\x0c\x49\x4d\x16\x35\x81\x0a\x48\x9b\x48\x28\xbf\x7d\xb2\x0d\x0e\x34\x34\x2d\xd3\xee\x5b\x5c\x81\x4f\xec\xef\x7c\xfe\xce\xf1\xe1\xa8\xc9\x26\xb9\x89\x0d\xcc\xf0\x03\xa6\x13\x38\x53\xdc\x4c\xc8\x4f\x87\x05\xcf\x93\x2c\x2d\xe1\x60\x13\xe7\x2b\x4e\x3e\xad\x57\x1b\x5e\x62\x99\xa5\x4f\x3c\x2f\xd6\x59\x8a\xc5\x01\xbf\xf3\xb4\xc4\xd7\xb8\x28\x78\x6a\xe3\x81\xa7\x65\x1a\x2c\x85\x67\xf1\x18\x2f\x39\xcd\xf2\x95\x8d\xb9\x33\x9d\x38\xb7\x33\xf2\x29\xcf\xb6\x1e\x8a\x32\x5b\x3e\x04\xc9\xf3\x9a\xee\x9e\x62\x9a\x6e\x30\xfa\xc2\xd3\x94\xe7\x25\xee\xc4\xce\x98\xfc\x1c\x97\xdc\xc3\xf4\x03\x7e\xdb\x6d\x30\xbd\xbd\x9d\x61\x32\xf1\x26\x33\xef\xe6\x03\x7e\xf9\xe3\x4f\x42\x7e\xe5\x39\x47\x9c\x73\x14\xd9\x96\x43\x28\x2c\x28\xbe\x66\xa9\x93\x28\x7d\x9f\xad\x2d\xe2\x24\x8f\xd7\xf7\x36\xd6\x09\x0e\xd9\x0e\xcf\x71\x9a\xc6\xb5\xf0\x12\xe5\x3f\x7c\x6b\x63\xc1\xc9\xf6\x80\xd5\x8e\x17\x25\xc5\x67\x3c\x66\x45\xc9\xef\xc5\x1e\xd6\x82\xb8\xcc\xd7\x4b\x45\x8e\x05\x4f\xb2\x9c\x53\x42\x9c\xff\x75\x10\x02\x31\xe8\xde\x94\x63\x4f\x31\x64\x9c\xdc\x24\x8d\x6d\xea\x31\x84\x87\xb6\xdc\x48\x4d\x63\x01\x63\x0b\x08\xc7\x03\x78\xbc\x11\x10\x89\xa7\x26\xb2\xcd\xbd\x39\x66\xf5\x18\x43\xc7\x8c\x2f\xe0\x48\x91\x82\x23\x47\x09\xe0\x0e\x25\x32\x2c\xf1\x50\x13\x8d\xc0\x00\x30\x86\x91\xb9\x97\x4c\x23\xd3\x34\x8f\x7f\xcf\xe7\xdf\x8e\xf3\xf9\xb7\x6a\x80\xa4\xea\xe8\xff\x08\xea\x3b\x47\x98\xa6\x39\x56\x4c\x9e\x47\x41\x3d\x3b\x04\xb5\x06\x30\x45\x14\xae\x2d\x3d\x3d\xc5\x14\x7d\x34\xbd\x28\xa4\x88\x1c\x0b\x43\x24\x01\x95\xf4\xa1\xae\xe5\x99\x9e\x25\x12\x1e\x45\xfb\x88\xc2\xf1\x7d\xbf\x57\xd2\xd9\xc7\xa2\x13\x19\x51\xdf\xf7\x1d\x50\x6b\x6f\x49\x22\xb8\x88\xbc\x88\x32\x46\x3f\x0e\x52\x04\x78\xc2\xc9\xf2\x2c\x84\x04\xf4\x7e\xbe\x50\xf5\x43\x69\x34\xb0\x20\x2d\x5a\x7b\x0a\x0e\x02\x03\x30\x82\xde\x29\x10\x7a\x5d\xf1\x76\x11\x10\x50\x40\xae\xc8\x0d\x4a\x03\x02\xcb\x92\x0b\xea\x15\x90\xfa\xef\xa2\x01\xe9\x27\x3c\xe4\xf3\x4e\x27\xa3\x7e\x94\xb3\xf8\x61\x88\x9f\x8c\x31\x6d\x8b\xf7\x0b\x64\x1d\x81\x0a\x41\xc5\x00\x57\x1e\xec\xbe\x5f\xf0\x7f\x33\xb4\x06\xad\xa3\xbd\x60\xbd\xe1\x2c\x3e\x46\xa9\x96\x31\x56\x89\x39\x6c\xb2\x1c\x75\x75\xa3\xfe\x72\x03\x82\x4a\x1a\x02\xad\x2a\xbd\x52\xb1\x43\x45\x5a\x03\xa1\x81\x7f\x75\xac\x33\x20\xd3\x3c\x86\x06\x1a\x7d\x40\x43\x03\x43\x0d\x74\x5f\x65\xec\xb1\xde\x02\x6a\x11\x2d\x20\xda\xdb\x67\xf1\xb7\x19\xa5\xf5\xde\xf4\xc8\xa5\x0a\xaa\xb2\xaa\x93\xba\x57\x00\x27\x55\x3d\x47\xb9\x3a\x31\xe1\x8b\x28\x0d\x9d\xd5\x6e\x7a\x35\xea\xec\x16\x2a\x25\xf7\x64\x75\x80\xcd\xa9\xa2\x48\x6a\x58\xd8\xca\xc3\x29\x5f\xe8\x04\xdf\x9b\x2f\xf4\x55\xc9\xeb\x37\xd0\x30\xd6\x89\x15\x4b\x61\x2f\x23\xeb\xd4\x46\x6f\x5a\xfa\x2e\x9f\xf5\xde\x69\xbb\x74\x2a\xad\xac\x3a\xd3\xd8\xba\x91\xcb\x51\xb3\x06\x27\x52\xe8\x2a\x96\xd0\x6d\xd1\xd5\x20\xa6\xd9\x2a\xcd\x56\x5d\xa8\x39\x84\x4d\x21\x30\xb7\x37\x62\x99\x3a\x75\x1c\x73\x2f\x04\xa2\x03\x6e\x32\xe8\x9e\x55\xcc\xa9\x25\x34\xbd\x22\xac\x5b\x46\xa8\x26\x84\xfd\xbd\x46\x11\x9c\xe6\x0e\x73\xd3\xb0\xa3\x56\xc3\xbe\xf6\x9c\x6b\xcf\xb9\xf6\x9c\x6b\xcf\xe9\x34\x91\xea\xe5\xeb\x3b\xfc\x4f\xf5\x6f\x00\x00\x00\xff\xff\x7b\x5a\x0e\x33\xfd\x0e\x00\x00")
+
+func fontsCyberlargeFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsCyberlargeFlf,
+ "fonts/cyberlarge.flf",
+ )
+}
+
+func fontsCyberlargeFlf() (*asset, error) {
+ bytes, err := fontsCyberlargeFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/cyberlarge.flf", size: 3837, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsCybermediumFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x55\x51\x6f\xab\x36\x18\x7d\xf7\xaf\x38\x0f\x41\x24\x12\x7c\x24\x5d\x2a\xa5\x54\x4c\x48\x9b\xba\x75\xeb\xaa\x4a\xdd\xdb\xe8\x0c\x49\x4c\x87\x9a\x40\x05\xa4\x4d\x24\x94\xdf\x3e\x19\xbb\x24\xb4\x49\x74\xb9\xba\xf7\xe9\xd6\x89\x01\xe7\xf8\x1c\x1f\x1f\xdb\x24\x5e\xc4\x67\x51\x0f\x63\xfc\x84\x09\xec\x11\xce\x86\xec\x97\xcd\x54\xe4\x71\x96\x96\xb0\xb1\x14\xf3\x64\xb5\x64\x57\xc9\xe3\x42\x94\x98\x65\xe9\x8b\xc8\x8b\x24\x4b\x31\xdd\xe0\x4f\x91\x96\xb8\x8d\x8a\x42\xa4\x16\x9e\x44\x5a\xa6\xfe\x4c\x52\x8b\xe7\x68\x26\x28\xcb\x1f\x2d\x4c\xec\xd1\xc8\xbe\x18\xb3\xab\x3c\x5b\xba\x28\xca\x6c\xf6\xe4\xc7\xaf\x09\xad\x5e\x22\x4a\x17\xe8\xdf\x88\x34\x15\x79\x89\x7b\x89\x0c\xd8\xaf\x51\x29\x5c\x8c\xce\xf1\xc7\x6a\x81\xd1\xc5\xc5\x18\xc3\xa1\x3b\x1c\xbb\x67\xe7\xf8\xed\xaf\xbf\x19\xfb\x5d\xe4\x02\x51\x2e\x50\x64\x4b\x01\x69\xb1\x20\xdc\x66\xa9\x1d\x2b\x7f\xd7\xe6\x12\x51\x9c\x47\xc9\xdc\x42\x12\x63\x93\xad\xf0\x1a\xa5\x69\xa4\x8d\x97\x28\xff\x13\x4b\x0b\x53\xc1\x96\x1b\x3c\xae\x44\x51\x12\xae\xf1\x9c\x15\xa5\x98\x4b\x0c\x89\x14\x2e\xf3\x64\xa6\xc4\x31\x15\x71\x96\x0b\x62\xcc\xfe\xa6\x85\x31\xc8\x42\x6b\xa3\x2e\x6b\x42\x97\xb2\xa3\xd5\x32\x96\xd1\x94\x2e\x3a\xb4\x47\x63\x5a\xc6\x04\x06\x26\x10\x0c\x3a\xe8\xb8\x7d\x20\x94\x55\x0b\x59\xc6\xda\x18\x70\x5d\x06\x68\xe6\x8c\x1b\x08\xa4\x48\x21\x90\xa3\x04\x70\x8f\x12\x19\x66\x78\xd2\x42\x7d\x70\x00\x9c\xa3\x6f\xac\x6b\xa5\xbe\x61\x18\xdb\x7f\x27\x93\xbb\xed\x64\x72\x57\x75\xb0\x54\x6d\xbd\x9f\x41\x9e\xbd\x85\x61\x18\x03\xa5\xe4\xba\x04\x72\xad\x00\x64\x76\x50\x0a\x09\x8e\x55\x33\x5d\xa5\x14\x5e\x1a\x6e\x18\x10\x42\xdb\x44\x17\x4b\x40\x55\x73\xc8\x31\x5d\xc3\x35\x65\xe0\x61\xb8\x0e\x09\xb6\xe7\x79\x07\x2d\x7d\x38\x2c\x4d\x90\x21\x79\x9e\x67\x83\xcc\xb5\x59\x0b\xc1\x41\xe8\x86\xc4\x39\x5d\x76\x72\x04\xb8\x92\x64\xba\x26\x02\x06\x9a\x4f\xa6\x6a\xff\x10\x85\x1d\x37\xa4\x49\x9a\x29\x35\x58\x0f\x3d\xff\xdd\xc5\x67\x80\xe3\x33\x38\xf0\x19\x01\xb2\x09\xdf\x67\x44\x3e\x33\x4d\xd9\xaa\xab\xcf\xf4\xe7\xe4\x03\xc1\x67\x26\x3a\x92\x74\xe7\x37\xb2\x32\xc0\x38\xd7\x56\xb4\x1f\xd4\x5f\x92\xd7\xda\x31\x6a\xcb\xf0\x99\xf3\xd6\xe9\x4b\xc7\xfb\xba\x87\x5e\x3d\xb8\x1e\x5f\x35\x2c\xd5\x38\x41\xe2\x5c\x12\xf8\x83\xcf\x40\xcd\x4c\xf6\xd0\x7a\x92\x15\xe7\x95\xbc\xc9\x7d\xa8\x26\x02\x05\x42\x81\x0f\xbb\xdb\x1e\xc8\x15\x45\xf7\xe1\x07\x98\x40\xa0\x40\xe7\x00\xb3\x75\x3b\x02\xa2\x49\xb6\x35\xe6\x5b\x9f\x96\x21\xe0\xc4\x54\xea\x9f\x54\x55\x6b\x59\x0f\x2a\x9b\xbc\x6a\x62\x69\x24\x1c\xe5\x3e\xe0\x6d\x7d\x1c\x9f\xb0\x66\x06\xce\xc1\xc1\x35\x08\x05\x06\xd5\xc1\x1c\xab\x9d\xfb\x23\x2b\x70\x24\x0d\xcd\x3c\x28\xab\xa2\xd7\x0b\xf1\x0e\xfc\x47\xa9\xf3\x0f\x0b\xab\xa2\xd9\x5d\xdb\xd3\x38\xec\xb4\x05\x22\x70\x5a\x4e\xc1\x35\x5a\x69\x6e\xb5\x23\xef\xb1\x35\x8d\x3b\x1f\x82\x57\x28\xd7\xaa\xd5\x2e\x87\xbd\x94\xa0\x0e\x23\x9c\xd6\xca\x34\x5b\x3d\x50\xa4\x40\x75\x0d\x4e\x1d\xd8\x5d\xce\x4d\x1c\xfa\x8d\x04\x9f\x85\xfb\x2f\x97\xcf\xf3\xf3\x79\x7e\x7e\x90\xf3\x53\xa1\x55\xbf\xc3\xff\xdb\xff\x01\x00\x00\xff\xff\x21\xe3\xee\x74\x6d\x0c\x00\x00")
+
+func fontsCybermediumFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsCybermediumFlf,
+ "fonts/cybermedium.flf",
+ )
+}
+
+func fontsCybermediumFlf() (*asset, error) {
+ bytes, err := fontsCybermediumFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/cybermedium.flf", size: 3181, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsCybersmallFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x53\x61\x6b\xdb\x48\x10\xfd\xbe\xbf\xe2\x7d\x88\x90\x0d\xda\x91\x6d\x12\x70\x36\xa7\x20\xb8\x23\x77\xb9\xa6\x21\x90\x7e\x68\x89\xd2\x95\xec\xac\x52\x13\x7b\x15\x24\x39\xb1\x41\xf8\xb7\x97\x95\xb6\x8e\xd4\x34\x05\x41\xa1\x5f\x3a\x20\x69\x47\x4f\xef\xcd\x9b\xd9\x55\xba\x4c\x27\xc9\x01\x26\x98\x60\x0a\x3e\xc6\x64\xc4\xfe\xde\xce\x54\x9e\x66\xba\x04\x47\xb1\x4a\x96\x4b\x76\xb6\xb8\x5f\xaa\x12\xf3\x4c\x3f\xa9\xbc\x58\x64\x1a\xb3\x2d\xde\x29\x5d\xe2\x32\x29\x0a\xa5\x3d\x3c\x28\x5d\xea\x70\x6e\x98\xc5\x63\x32\x57\x94\xe5\xf7\x1e\xa6\x7c\x3c\xe6\xc7\x87\xec\x2c\xcf\x56\x02\x45\x99\xcd\x1f\xc2\xf4\x79\x41\xeb\xa7\x84\xf4\x12\x83\x0b\xa5\xb5\xca\x4b\x5c\x1b\x64\xc8\xfe\x49\x4a\x25\x30\x3e\xc2\xff\xeb\x25\xc6\xc7\xc7\x87\x18\x8d\xc4\xe8\x50\x4c\x8e\xf0\xef\xfb\x0f\x8c\xfd\xa7\x72\x85\x24\x57\x28\xb2\x95\x82\x71\x58\x10\x2e\x33\xcd\xd3\xc6\xdf\xb9\xbb\x42\x92\xe6\xc9\xe2\xce\xc3\x22\xc5\x36\x5b\xe3\x39\xd1\x3a\xb1\xc6\x4b\x94\x5f\xd4\xca\xc3\x4c\xb1\xd5\x16\xf7\x6b\x55\x94\x84\x73\x3c\x66\x45\xa9\xee\x0c\x86\x85\x11\x2e\xf3\xc5\xbc\x11\xc7\x4c\xa5\x59\xae\x88\x31\xfe\x4b\x83\x31\x98\xa0\x8d\x53\xc7\x86\xd0\x27\x5e\x68\xb5\x8c\xe7\xec\xa3\x8f\x0e\xb5\x68\xcc\xca\xb8\xc0\xd0\x05\xa2\x61\x0f\x1d\x31\x00\x62\x73\x59\x21\xcf\xd9\x38\x43\x69\x63\x88\x7d\xcf\xb8\x80\x82\x86\x86\x42\x8e\x12\xc0\x35\x4a\x64\x98\xe3\xc1\x0a\x0d\x20\x01\x48\x89\x81\xb3\xa9\x95\x06\x8e\xe3\xec\x3e\x4f\xa7\x57\xbb\xe9\xf4\xaa\xea\x61\xa9\xda\x05\xa7\xa0\x80\xef\xe0\x38\xce\xb0\x51\x12\x82\x40\xc2\x8b\x40\x6e\x0f\xa5\x98\xe0\x7b\x35\x53\x34\x4a\xf1\x89\x23\xe2\x88\x10\x73\x17\x7d\x2c\x01\x55\xcd\x21\xdf\x15\x8e\x70\xcd\xc0\xe3\x78\x13\x13\x78\x10\x04\x3f\xb4\xf4\xea\x67\xd9\x0f\x32\xa6\x20\x08\x38\xc8\xdd\xb8\xb5\x10\x7c\xc4\x22\x26\x29\xe9\xa4\x97\x23\x40\x18\x92\x2b\x5c\x44\x0c\x74\x37\x9d\x35\xe7\x87\x28\xee\x79\x20\x5d\xb2\x4c\xa3\xc1\x70\x10\x9a\x2b\x64\xf0\x43\x46\x30\x0b\xd7\x0d\x8d\xd3\x30\x64\x21\x7b\x7d\x43\x8d\xbe\x01\x1e\x20\x64\xf0\xc2\x86\xcf\xc0\x79\x18\x36\x15\xa8\x7e\xe7\x9b\x32\x6f\x71\x7f\x7e\x03\x7d\x53\x21\x5b\xe2\xfb\x0f\xb8\x67\xc0\xbd\x3a\xcc\x91\x0e\x19\x2a\xce\x2b\x9b\x1a\x4b\x55\x10\xdc\xb6\x51\xf3\x68\xa1\x52\x9e\xb6\xd1\x20\x08\xba\x52\xbc\xcb\xad\x5b\x95\x40\xa7\x90\x59\x37\x23\xa8\xd7\x52\xca\xaa\xf3\x99\x90\x36\x45\xdb\x80\x45\x23\xdf\xba\x6d\x52\x44\x55\xab\xe2\x8d\x94\xb7\x6d\xb7\x9c\xbb\x75\xa1\x26\xbd\x91\xde\x6d\xd7\xed\x5f\xad\x34\x78\xe9\xc5\x50\x2a\xb4\xab\x76\x2d\x22\xf2\x3b\xa8\x6f\x4d\x34\xed\x7c\x94\x2f\x09\x3e\xa1\xe5\x07\x7e\xdd\x4b\x33\xfe\xa8\x7e\x13\x75\xf7\xa8\xe9\xd9\xb6\x1c\xdb\x83\xf4\x67\xa7\x7e\xef\x4e\x55\x76\x0c\xbd\xfe\xc7\xaf\x01\x00\x00\xff\xff\x04\xac\x2e\xa0\x8a\x08\x00\x00")
+
+func fontsCybersmallFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsCybersmallFlf,
+ "fonts/cybersmall.flf",
+ )
+}
+
+func fontsCybersmallFlf() (*asset, error) {
+ bytes, err := fontsCybersmallFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/cybersmall.flf", size: 2186, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsDiamondFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\x4d\x8f\x1c\x35\x10\xbd\xcf\xaf\xa8\x43\xae\xe0\xb0\x42\x22\xdc\x1a\x29\x8a\xc4\x01\x90\x72\xf6\x61\x83\xb4\x41\x91\x56\x20\x41\x2e\xf0\xeb\xd1\xcc\xf8\xe3\xbd\x57\xcf\xdd\x33\x4b\xc4\x66\xd3\x6d\x77\xdb\xf5\x5d\xaf\xca\xbd\x1f\x9f\x3f\x3e\x7c\x78\x15\x6f\xe2\xbb\x78\x78\x1d\x5f\x7d\x13\x0f\xa7\xb7\x3f\xfe\xf0\xd3\x2f\x3f\xbf\x8d\x5f\xff\x8e\xf7\x7f\xfc\x1e\xef\xfe\xfc\xf4\xf9\x9f\x78\x53\xbe\xff\xf6\xf4\xee\xd3\x6f\xcf\x4f\x9f\xe3\xfd\xd3\xf3\xd3\x87\xbf\x9e\xe2\xe1\xeb\xd7\xa7\x57\x9b\xf9\x8d\x6d\x3b\x95\x5a\xf9\x12\xed\x12\x11\xed\xd9\x79\x74\x79\x58\xea\xb8\x45\x5c\xde\x1f\xdf\xda\xbd\xff\x9c\xa7\xa5\xd6\x68\xd7\x0b\x87\xf3\x4f\x5c\xee\xe9\xed\x9d\x8b\x91\xd1\x65\xde\xdf\x5c\xa4\xbe\xaa\x56\x45\x8e\xb6\xaf\x9b\xa0\xad\xcb\x54\x51\x93\x46\x67\x2c\x85\xb5\x93\x68\x63\x75\xe1\x5e\xfd\x36\x92\x74\xae\x1d\xb2\xcc\xfd\x75\x6e\x97\x75\xb0\x77\x12\xbc\xbe\x69\x8e\x5a\x5f\x9a\x98\x8d\x5c\xa3\xaf\xb7\x21\x6f\x67\xd7\x39\xb8\x97\x74\x23\xa2\x6c\x44\xd1\x64\x5c\xba\x3e\xcd\x61\xdd\xe7\xd1\x3c\x6f\xde\x9b\xfd\x4c\xdf\x84\x05\x46\x63\xe4\x40\xe8\xb6\xee\x6c\xf7\x96\x65\x6a\xc8\x68\xe7\x32\x5c\xd4\xb7\xe5\x3b\x71\x37\xef\xef\xe2\xc4\xc6\x07\x2d\x5e\x10\xc1\xa2\xad\x24\x39\x10\x44\x42\x18\x55\x83\xf5\x20\x37\x23\x06\xc5\x6a\x91\xaf\x7e\xdc\x06\xc8\x48\x18\xba\x5b\x01\x23\x72\x12\x53\x94\x1d\x59\x83\x4c\x50\xc9\x33\x16\x1d\x76\x49\x84\xe2\x4b\x4f\xf9\xaa\x61\x65\x6d\xcb\xe1\x57\x70\xd6\x55\xe2\xcc\x80\x3c\xca\x59\xe2\x6d\x4b\x9a\x54\xf6\xbc\xb8\xc5\x6b\xe2\x71\xce\x06\x09\x98\x89\x22\x6f\x78\xc6\x04\x4f\x5f\x96\xc1\x9f\x18\x0d\xab\x8a\xda\x98\xc6\x28\xcb\xfe\x78\x4f\x93\x3e\xf1\xc1\x1e\x53\xde\xf0\x9a\x80\x29\xf6\x9c\x9f\x1c\x3c\x6d\xce\xda\x95\x6a\x21\x8b\x8d\x6d\x9d\xbf\x46\x10\xc1\x92\xc3\x85\x00\x6f\xc3\xfe\x52\xda\x15\x53\x50\x4a\x13\x59\xc6\x36\x30\x28\x92\x98\xee\x49\x1a\xdc\x2f\xc0\x81\x0a\x44\x58\x88\x6d\xa7\x4c\x6a\x7a\x72\xee\xb6\xcf\xa4\x9a\x0d\x0a\x98\x38\xc1\x6d\x0f\x54\xc6\x96\x2d\x85\xc1\xf6\xf1\xf1\x31\x61\xb6\x6f\xa6\x66\x94\x43\x48\x85\x20\x81\x0b\x33\xaa\x28\x3d\x19\x29\x80\x53\x39\x48\xee\x26\x5f\x4d\x4c\xc3\xad\x73\x57\x83\x1f\x58\xa3\x29\x02\x7d\x85\x4b\x6d\xc9\x30\x6a\xc8\xc8\xdd\x32\xc6\xf5\x31\xb2\x5a\x18\x0c\x98\x1f\x9b\x49\x79\x64\xb6\x18\x43\x61\x4b\xa0\xb1\x51\x81\x62\xd0\x86\x61\x97\x6c\x77\x81\x26\xdc\x17\x21\x9c\x22\x6c\x43\x5b\xf5\xb0\x35\x11\x61\x27\xbd\xba\x0f\x23\x41\x9c\x19\x38\x15\xc4\xdc\x99\xcc\xa2\x71\xe3\x9e\xc4\xe8\xe8\x02\x89\x45\x1d\xd9\xd1\xa8\x54\xec\x97\xaa\x9e\x52\x20\xe7\xe0\xc0\x41\x6d\x49\xcb\x8b\xc2\x6e\xc1\x65\xab\x8a\xeb\x6c\x79\x8b\xb3\xef\x0d\xb3\x36\xe9\xfa\x4e\x5f\x4f\x2d\x0a\xf8\x80\x41\x6e\xe0\x90\x21\x45\xd3\x88\xa4\x51\xf5\x7c\xc1\x78\xcc\x95\x99\x72\xbe\x06\xb1\x4c\x1c\x27\xd6\xe4\xce\x47\xac\x9f\xe5\xf7\xf3\xc0\x96\x20\x1c\x7d\xa3\xb1\x64\xac\xc3\x9c\x9c\xd5\x7b\x20\xb8\xd4\x50\x14\x3c\x72\x4f\xf2\x56\x19\x1d\x2c\x14\x2c\xcd\xf3\xb3\xef\x49\x33\xd6\xcd\xcd\x42\xc3\x53\xeb\xba\xba\xc3\xfb\xb2\x4b\xc3\xe6\x93\xaa\x2a\x55\x3d\x43\x3f\xd2\x49\xbe\x0a\xee\x67\x98\xd8\x97\x99\x11\xc3\xec\x8c\x17\x4f\x6e\x40\x65\x63\xb3\xe1\x6c\x0c\x6c\xdf\x5c\x8c\x84\x64\xd5\x24\xf8\x5d\x05\x72\x82\xec\xe4\x5b\xe1\x9e\x20\x81\x04\x02\xc3\x2c\x66\x3e\x5f\x57\x02\xa0\x19\x86\xca\x05\x7a\x1f\xd4\x25\xbd\xb3\x10\x6e\xa3\xd6\x32\x24\xa3\xaf\x18\xde\x33\x63\x86\xe9\x40\x06\x4e\x35\x1e\x8d\x30\x87\x96\x22\xad\x40\x35\xa5\x04\x18\x36\x45\x0f\x6f\xe9\x13\x97\xb0\xd3\x03\x42\x92\x15\x52\x6a\x79\x6e\xc1\xcf\x97\xfb\x37\xf3\xed\xa2\x30\x94\x96\x83\x32\xfd\x92\x49\x9f\xdd\x7f\x6f\x5f\xac\x46\x97\x93\x4f\x88\x7c\x21\x84\xd3\xf1\xd4\x74\xa4\x99\x6b\x98\x25\x56\x6b\x46\x4d\x90\x6e\x31\x24\x2b\x72\xa3\x4d\x0b\xb2\x8d\xe4\x40\x59\xb0\x1b\x1d\x6c\xe0\xc9\x5c\xc3\x84\xd6\x7d\x1f\x82\x89\xed\x00\xd9\xe9\xb7\xdb\x54\x0f\x12\x74\x44\x8a\xd9\x47\x2f\x8b\xfa\xd6\x0f\x9c\xe7\x6d\xe3\x0f\x03\x84\x56\x8b\x41\x92\x54\x87\x8c\x64\xea\x11\x78\xda\x0d\x45\x99\x09\xd6\x38\xcd\xcc\xc5\x11\x7d\x86\x49\xd6\xad\xe1\x6c\x8a\x5f\xd4\x0f\xfa\xf9\xa1\x84\x9d\xdb\xfb\xb5\xf7\xdc\x56\x02\xcb\x21\xbe\x99\xbc\x52\x04\xaf\x44\x1f\x36\x5b\x5f\x67\x4c\xfa\x8f\x0c\x41\x06\x1d\x15\x0e\x3c\x24\xae\xf1\xd3\xab\x92\x45\x85\xdc\x0f\x87\xa2\x1f\x0c\x52\x0c\x90\x79\x12\xf1\x17\xa3\x8c\x50\xb7\xfd\x5b\x8a\x37\x94\x7b\xe2\xca\x24\xac\xa8\x62\x1d\xee\x09\x06\xe0\x0a\x12\x9c\x8e\x28\xd4\x19\x8f\x51\x5d\x7c\x2c\x53\xb8\xca\x83\x22\xf9\xef\x71\xef\x0a\x13\x08\x77\xd1\x3e\x1a\x87\xa8\xcb\x84\x14\x18\x6e\x43\x11\x2a\xae\x6b\xe3\xeb\x51\xcd\x8f\xa2\x99\x6d\x01\xa0\x5a\x26\xb9\xce\xda\x02\x34\x84\x34\x7d\x8c\xaf\xb3\x86\x13\xb3\x1a\xbc\x2a\xc3\xfe\x9c\x5d\x7f\x21\x05\x22\xd5\xc2\x83\x0c\x43\x44\x87\x60\x8f\x59\x2d\xa4\xe8\x2e\x32\x6c\x49\xb8\xc8\x1f\x57\x6b\xee\x9b\x24\xfc\xf6\x09\x53\x40\x49\x7a\x6e\xf2\x6d\x76\xf5\xf7\x1a\x3c\x34\x53\x1c\x32\x15\xa9\x5d\x12\xc7\xd7\xaf\x89\xd7\xff\xd7\xdd\x34\xd7\xb4\x58\x91\x33\x42\x84\xa4\xde\x00\xd3\xe9\x1d\xc1\xd1\xff\x34\xde\x4e\xf2\xef\xff\x7a\xf0\x6f\x00\x00\x00\xff\xff\x6c\xcd\x44\x15\xde\x20\x00\x00")
+
+func fontsDiamondFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsDiamondFlf,
+ "fonts/diamond.flf",
+ )
+}
+
+func fontsDiamondFlf() (*asset, error) {
+ bytes, err := fontsDiamondFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/diamond.flf", size: 8414, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsDigitalFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x9a\xf9\x77\x24\x55\x15\xc7\x7f\xef\xbf\xe2\xba\xa2\x32\x99\x49\x77\xa7\xbb\x13\x45\x9c\x4a\x75\xa5\x53\x4c\xa5\xaa\xa9\xae\x9e\x21\xe3\xda\x49\x2a\x49\x4b\xa7\x3a\x76\x57\xcf\x10\x45\x71\xdf\xf7\x7d\x5f\x40\x50\x16\x41\x40\x40\x76\x54\x04\x44\x94\x4d\x10\x64\x55\x56\x11\x65\x13\x04\xd9\x3c\x9d\x99\xa9\xba\x75\x97\xce\xf1\x07\x0f\x73\xbe\xb9\x9f\x57\x75\xdf\xfb\xde\x77\xdf\xab\x76\xb9\xb3\x5c\x68\x9d\x00\x45\x28\x40\x19\xf2\x90\xcf\xc3\x38\xe4\xcb\xa5\x7c\x31\x57\x6d\xaf\xb4\xe3\x56\x07\x16\x36\xa0\xd6\x09\xa3\x08\xcc\xd5\xd6\xfa\x7a\xd8\xe9\x40\x7e\xc7\xd4\x04\x8c\x8d\xc1\x42\xab\x1f\x2e\x41\x37\x82\xe9\xc1\xc2\x42\x27\xcc\xd9\xd1\x62\x67\xb0\x14\xf6\x61\x71\xb5\xd5\x6b\x2d\xc6\x61\xaf\x0f\xf9\xc2\xe4\x58\xa1\x54\xca\x59\xd1\x6a\x2b\x5a\x0c\x97\x60\xb9\xdb\x03\xa7\x15\xb7\xa3\xb1\xc2\xb6\xe2\xb6\x89\xe1\xf0\x47\x75\x57\x23\x30\xbb\xfb\x5b\x11\x1c\xb1\x38\xfc\xcf\xce\xc5\xc5\x76\x67\x7b\xb7\xb7\x72\x64\x6e\x33\x34\x1d\x10\xfa\x61\xdc\x87\xfe\x60\x7d\xbd\xdb\x8b\x37\x1f\xde\xd9\x80\xf6\x32\x6c\x74\x07\x3d\xe8\x2f\xf6\xc2\x30\x82\xe5\x6e\x14\xc3\x52\x37\xec\xe7\x96\xdb\x2b\x9d\x30\x86\x5e\xd8\x09\x5b\xfd\x10\x0a\xdb\x0b\xc3\xd7\x76\xbb\xfb\xc2\xb5\x85\xb0\x07\xf9\xa9\xa9\x72\xae\x1e\xf6\xd6\xda\xfd\x7e\xbb\x1b\x41\xbb\x0f\xab\x61\x2f\x5c\xd8\x80\x95\xf6\xbe\x30\x82\xb8\x0b\x6b\xdd\xa5\xf6\xf2\x06\xc4\xab\xed\xfe\xe6\xb8\xdb\xa0\xd5\x87\x4e\x37\x5a\x19\xfe\x37\x5e\x0d\x73\x9b\x01\xed\xb0\x77\x58\x1f\xa2\xd6\x5a\x38\x1c\x63\xbd\xd3\x5a\x3c\x30\x2f\x2d\x58\xec\xae\xad\x85\x51\x0c\x9d\x76\x14\x6e\xcf\xe5\xe6\x0e\x44\x2f\x0d\xb3\xae\xb7\x06\x1d\x98\x1e\xf4\xe2\x6e\x04\x47\xf4\xbb\x9d\x41\xdc\xee\x46\x3b\xc3\x56\x2f\x5e\xed\xb4\xa3\x63\xb7\x47\x61\x7c\x24\xe4\x0b\x3b\xa6\xca\xc3\x17\x69\x1f\x98\x5b\x88\xc2\xfd\xb0\xde\xea\xb5\xd6\xc2\x38\xec\xe5\xd2\x89\x58\xd8\x80\x19\xbb\x36\xcc\xb6\x15\x2d\x0d\xff\xb9\xa7\x1d\x6d\x07\x98\x6b\x6d\x40\xab\xd3\xef\xc2\x42\x08\xfd\x4e\x7b\x65\x35\xee\x6c\xc0\xda\xa1\xb7\x18\xae\xc5\x42\x18\x0f\xe7\x75\xd0\x0f\x73\xdd\xe5\xcd\xe1\x97\x07\x9d\xce\xd8\xfe\xf6\x52\xbc\xba\xe3\xd8\xb0\x17\xed\xe8\xaf\x0d\xfa\xab\xd0\xea\xc4\x61\x2f\x6a\xc5\xed\x7d\x61\x7f\x1b\x2c\x0c\x62\x58\x0a\x97\x5b\x83\x4e\x0c\xdd\x41\xbc\x3e\x88\x87\x99\xbb\x5e\x30\x5c\xaa\x68\x25\x5c\xda\x9e\x83\x13\x76\x1e\xfa\xdf\xce\x1c\x1c\x3e\x76\xf8\xce\x1c\x1c\xff\x8a\xe3\x0f\xfe\x3b\x95\x5e\xc9\xa5\x57\x71\xe9\xd5\x5c\x7a\x0d\x97\x5e\xcb\xa5\xc3\xb8\xf4\x3a\x2e\xbd\x9e\x4b\x6f\xe0\xd2\xe1\x5c\xda\xc6\xa5\x31\x2e\x6d\xe7\xd2\x0e\x2e\x8d\x73\x29\xcf\xa5\x02\x97\x8a\x5c\x9a\xe0\x52\x89\x4b\x65\x2e\x55\xb8\x34\xc9\xa5\x29\x2e\xbd\x91\x4b\x6f\xe2\xd2\x11\x5c\x7a\x33\x97\x8e\xe4\xd2\x5b\xb8\xb4\x93\x4b\x06\x97\xa6\xb9\x64\x72\xa9\xca\x25\x8b\x4b\x33\x5c\xaa\x71\x69\x96\x4b\x36\x97\x8e\xe2\xd2\x2e\x2e\x39\x5c\x9a\xe3\x92\xcb\x25\x8f\x4b\x75\x2e\x1d\xcd\x25\x9f\x4b\x0d\x2e\x05\x5c\x6a\x72\x69\x37\x97\xf6\x70\xe9\x18\x2e\xcd\x73\x69\x2f\x97\xde\xca\xa5\xb7\x71\xe9\xed\x5c\x7a\x07\x97\xde\xc9\xa5\x77\x71\xa9\xc5\xa5\x05\x2e\x2d\x72\x69\x89\x4b\x21\x97\x96\xb9\xb4\xc2\xa5\x55\x2e\xb5\xb9\xf4\x6e\x2e\x1d\xcb\xa5\x0e\x97\xd6\xb8\x14\x71\xa9\xcb\xa5\x75\x2e\xbd\x87\x4b\x3d\x2e\xf5\xb9\x14\x73\x69\xc0\xa5\x7d\x5c\xda\xcf\xa5\xe3\xb8\xb4\xc1\xa5\xf7\x72\xe9\x7d\x5c\x3a\x9e\x4b\xef\xe7\xd2\x07\xb8\x74\x25\x97\x6e\xe5\xd2\x9d\x5c\xba\x9f\x4b\xcf\x70\xe9\x05\x2e\xdd\x93\x4a\xf9\xc2\x64\x22\x7f\x10\xcb\x53\x89\xfc\x21\x24\x17\xc7\x13\xf9\xc3\x58\xce\x27\xf2\x47\xb0\x5c\x48\xe4\x8f\x62\xb9\x98\xc8\x1f\xc3\xf2\x44\x22\x7f\x1c\xcb\xa5\x44\xfe\x04\x96\xcb\x89\xfc\x49\x2c\x57\x12\xf9\x53\x58\x4e\xb3\xfc\x34\x96\xd3\x2c\x3f\x83\xe4\x89\x34\xcb\xcf\x62\x39\xcd\xf2\x73\x58\x4e\xb3\xfc\x3c\x96\xd3\x2c\xbf\x80\xe5\x34\xcb\x2f\x62\x39\xcd\xf2\x4b\x58\x4e\xb3\xfc\x32\x96\xd3\x2c\xbf\x82\xe5\x34\xcb\xaf\x62\x39\xcd\xf2\x6b\x48\x2e\xa5\x59\x7e\x1d\xcb\x69\x96\xdf\xc0\x72\x9a\xe5\x37\xb1\x9c\x66\xf9\x2d\x2c\xa7\x59\x7e\x1b\xcb\x69\x96\xdf\xc1\x72\x9a\xe5\x77\xb1\x9c\x66\xf9\x3d\x2c\xa7\x59\x7e\x1f\xcb\x69\x96\x3f\x40\x72\x79\x1c\xc0\xf5\xc6\xa6\x7d\xcb\xd8\x05\x8d\xba\x61\x5a\x49\xd8\x0f\x71\x58\x1e\xc0\x76\x77\x5b\x7e\x60\x55\xc1\x3a\xc6\x74\x8c\x39\x23\xb0\x3d\x17\xe6\x0c\x7f\x57\x42\xfc\x08\x13\x05\x00\xd3\x72\x03\x68\xd8\x35\x37\x89\x38\x11\x47\x14\x01\xea\x5e\xd3\xad\x66\x43\x4e\xc2\x21\x13\x00\x66\xd3\xf7\x2d\xd7\x9c\xcf\x46\xfd\x18\x47\x95\x00\xe6\x2d\x37\x1b\x70\x32\x0e\x28\x03\x4c\xfb\xde\x2e\xcb\x85\x69\xc3\x4f\x42\x4e\xc1\x21\x15\x80\x86\x65\x6e\xe6\x94\x19\xe7\x27\x38\x68\x12\xa0\x6a\x1b\x96\x6f\x35\xec\x46\x12\xf1\x53\x1c\x31\x05\x60\x7a\xf5\x79\xdf\xae\xcd\x92\xd4\x4f\x45\x61\x95\x71\x80\x19\x6b\xce\x76\x6d\xd7\x02\xcf\xaf\xda\xae\xe1\x80\xed\x56\x6d\xd3\x08\xbc\xf4\x05\x4f\xc3\x48\x1e\xc0\xb1\x66\x82\xb1\xba\x67\xbb\x81\xed\xd6\xa0\xea\x35\xa7\x1d\x0b\x0c\xb7\xe6\x58\x70\x74\xd3\x0b\x84\x15\x39\x1d\x8f\x50\x80\xcd\x8b\x46\xe6\xad\xce\xc0\x01\x45\x80\x86\x37\x13\xc0\xec\x7c\x7d\xd6\x4a\x63\x7e\x86\x63\x26\x00\x7c\xab\x66\x37\x02\xcb\xb7\xc8\xca\x9d\x89\xe3\x4a\x00\x73\x86\xe9\x7b\xe9\x9f\xcf\xc2\x7f\x2e\x03\x54\xad\x9a\x6f\x59\xd9\x21\x7e\x8e\x63\x2a\x00\x75\xa7\xd9\x18\x9b\xb3\xdd\x66\x23\x1b\x77\x36\x8e\x9b\x04\x68\x34\xeb\x96\xdf\x30\x7d\xbb\x1e\x40\xb0\xc7\x4b\xe2\xce\xc1\x71\x53\x24\x6e\xd6\xb7\x52\xb7\x9f\x8b\x22\x27\xc7\x01\x0c\xb3\x19\x58\x60\x98\x43\x0f\x27\x41\xbf\xc0\x41\x79\x80\x39\xdb\xf4\xbd\xec\x9b\x9d\x87\x43\x0a\x00\x75\xdb\x31\x7d\x6f\x4f\x36\xe8\x7c\x1c\x54\x1c\x8e\x53\xad\x3a\x16\x54\xbd\xf4\x51\x17\xe0\x90\x61\x19\x58\x55\xdb\x71\x8c\xe4\xef\xbf\xc4\x7f\x2f\x65\x33\xf3\xdc\x34\xaf\x0b\x71\x5c\x79\xb8\x28\x0d\xb3\xe9\x8c\xf6\xdd\x45\x98\xa9\x00\x6c\xba\xf9\xff\x33\xde\xc5\x78\x88\x49\x80\xdd\x4d\xa7\x66\xf8\x30\xe3\x1b\x07\x6a\xcc\x73\x87\xa8\xe1\x07\x56\xfa\xd8\x4b\x30\x33\x25\x33\xb3\x86\x33\x93\x00\x97\x22\x60\x6a\x9c\x03\x9b\x2b\x7c\xe8\x31\x69\xc1\x5e\x86\x31\xbc\xb1\x1d\xdd\xb4\x1a\x3c\x95\xcb\x71\x78\x01\xc0\x31\x02\xdb\x05\xd3\xa8\xdb\x81\xe1\x80\x63\x05\x81\xe5\x83\x01\x7b\xec\x60\x16\x6a\xbe\xb1\x3b\x9d\xfb\x2b\x30\x59\x1c\x4d\x6e\xfa\x2d\x21\x7f\x85\xc9\x89\xd1\xa4\x69\xfb\x66\x73\x6e\xc6\xb1\x8e\x49\xf0\x5f\x63\xbc\x34\x1a\x0f\x6c\xa7\x9a\x3e\xf8\x37\x98\x2c\x8f\x26\xf9\x56\x78\x25\xa6\x2b\xa3\x69\x7f\x68\x25\x63\xda\x43\xf3\xf5\x5b\x8c\x4f\x6a\x78\x1a\x7f\x15\x8e\x9f\x52\xe2\xcd\x83\xb3\x44\xea\xe7\xea\x94\x2d\x8c\x8f\x2b\xac\x25\xad\xea\x35\x98\xcc\x8f\x26\xb3\xab\xfa\x3b\x4c\x6a\x4e\xb2\xd4\x55\xbd\x16\xe3\x9a\x9d\x2c\x6d\x6d\x7e\x8f\x69\xcd\x52\xb6\x94\xf0\x75\x98\xd4\xdc\x64\x4b\x09\xff\x01\x93\x9a\x9b\x6c\x35\xe1\x3f\x62\x5c\xb3\x93\xad\x25\x7c\x3d\xa6\x35\x37\x59\xc1\x6c\x02\xdc\x80\x01\xcd\x4e\xae\x54\x35\x37\x22\x32\xaf\x99\xc9\x93\xe6\xf6\x26\x4c\x6a\x66\xf2\xa4\xb9\xbd\x19\x93\x9a\x99\x3c\x75\x6e\xff\x84\x71\xcd\x4c\x9e\x94\xec\x2d\x98\xd4\x8c\xe4\x69\xab\x72\x2b\xa6\x87\x87\x84\xa6\x13\xd8\x75\x67\xd8\x81\xd8\xd9\xeb\xcf\x38\x56\xb3\xcf\xc1\x27\x35\x82\xe1\x01\x2f\x41\x6f\xc3\xa8\x66\x9d\xa6\xb4\x22\xb7\x63\x52\xb3\x4d\x53\x5a\x91\xbf\x60\x52\xf3\x4f\x53\x5d\x91\x3b\x10\x5e\xd0\x4c\xd4\xd4\xe6\xf5\x4e\x4c\x6b\x46\x9a\x97\x5e\xfb\x2e\x4c\x6a\x46\x0a\x66\x3d\x3f\x5d\x98\xbb\x31\x92\x98\xa7\x31\x67\x38\x09\xd0\x98\x35\xfc\x3a\xa4\xef\x77\x0f\x46\x26\x44\x44\xec\xa1\xf7\x62\xae\x34\x8a\xcb\x66\xf5\x57\xcc\x95\x47\x71\xc2\x52\xfc\x0d\xc3\x95\x51\x70\xb6\x34\xee\xc3\xdc\xe4\x28\x8e\x2f\xe0\xfd\x98\x9d\x1a\xc5\x0a\x9d\xf3\x01\x04\x17\xc7\x65\x38\x8d\x7e\x10\x47\xe7\xc5\x68\xa5\x6b\x3e\x84\xc9\x82\x48\x8a\x3d\xf3\x61\xcc\xc9\x86\x11\x3b\xe6\xdf\x31\x27\xbb\x46\xef\x97\x8f\x60\x58\xb6\x8e\xda\x2d\xff\x81\x59\xd9\x3e\x62\xaf\x7c\x14\x73\xb2\x73\xc4\x4e\xf9\x4f\xcc\xc9\xce\xd1\xfb\xe4\xbf\x30\x2c\x5b\x47\xed\x92\x8f\x21\x76\x42\x76\x0e\xee\x91\x8f\xe3\x70\xd9\x3a\x62\x87\x7c\x02\x73\xb2\x71\xc4\xfe\xf8\x24\xe6\x64\xe3\x88\xdd\xf1\x29\xcc\xc9\xc6\xd1\x7b\xe3\xbf\x31\x2c\x1b\x47\xec\x8c\x4f\x63\x4e\x36\x8d\xda\x17\x9f\xc1\x6c\x05\xa0\x6a\xef\xb6\x1b\xac\x23\xfe\x07\x47\xc9\x36\x91\xfb\xe1\xb3\x18\x94\x2d\x22\x76\xc3\xe7\x10\x57\x92\xed\x21\xf6\xc2\xff\x62\x4e\xf6\x89\xde\x09\x9f\xc7\xb0\x6c\x16\xb5\x0f\xbe\x80\x59\xd9\x30\x62\x17\x7c\x11\x73\xb2\x61\xb2\x3d\xf0\x25\x0c\xc8\x26\x99\xd7\x5e\xf2\xe5\x94\x1d\x3f\x6e\x3c\xaf\xde\x3f\x0e\x6e\xf8\xe4\x43\xca\x15\x84\x96\xa7\x57\x66\xef\x25\xec\x16\xf7\xd9\x69\xdf\xda\x2d\x5e\x0e\x37\x61\x79\x7a\x45\xf4\x3e\x82\x6e\x71\xa7\xf5\x6a\x9e\x6b\x89\x1f\x16\x37\xe9\x91\xe7\x00\xc2\x9e\x4d\x58\xed\x1c\x69\x4a\xae\xb8\x8a\xc0\xf2\x8e\x2e\xa2\x0f\x12\x54\x3b\x4a\x9a\x6a\x19\xd0\x87\xcb\x65\xab\xf3\xf4\x0d\x8c\xd1\x6f\x50\xf5\x02\xfd\x3e\xbe\x39\xc0\xf4\xa8\x17\xe0\xf8\x03\x04\x37\xb7\x98\x01\x03\x1b\xf5\x1a\x02\x57\x47\x26\x9f\x41\x1f\x26\xa8\xa5\x3c\xb7\x2a\xc1\xd7\x13\x78\x46\x7c\xae\x88\x3e\x96\x45\xd5\x8b\x60\x55\xdc\xa1\x6f\x20\xb4\x5c\xd5\x32\xfb\x38\x61\xb7\xf8\xb6\x40\xf6\x84\xd3\x08\x3d\xf2\x7c\x46\xd8\x8b\x08\xab\x55\x97\xa5\x99\xe4\x3a\x32\x80\x5c\x61\x2a\xfe\x28\xc1\xd5\x7b\xbe\xb8\x37\x5c\x4b\x68\xb9\xc2\x64\xf6\x11\xc2\x6a\xd5\x65\x49\x56\xa1\x59\xcb\x95\x25\xa2\x34\x63\xad\xaa\x6a\xea\xbe\x70\x1b\x19\x41\x2e\x2d\x9d\x7f\x96\xf0\x5a\x7d\xd5\xa4\x46\x70\x3a\x81\xe5\xfa\x12\xd1\x8b\xb3\xa8\x7a\x47\xae\x69\x66\xb9\x85\x0c\x20\x97\x98\x8a\x3f\x4d\x70\xad\xca\x6a\xf2\xdd\x89\x64\xae\xdc\x9b\x15\x98\xe6\xae\xf5\xcf\x59\x75\xd5\x4e\x21\x23\xc8\x3d\x54\xe7\xcf\x27\xbc\x56\xe9\xb3\xe2\x0e\x45\x3a\xb8\x72\xa9\x96\x59\xd2\xc1\x0b\x5a\x8d\xdb\xd2\x99\xfc\x64\x02\x8f\xbc\x1e\x65\xd1\xf3\x08\xaa\x55\xb8\x2d\xee\x8c\xa4\x91\x14\xe4\x12\x97\x59\xd2\x49\x0a\x5a\x85\xd9\xe2\xce\x74\x35\xa1\xe5\x12\x93\xd9\x87\xb2\x6c\x51\xab\x31\x5b\x2b\x92\x53\xc9\x00\x4a\x1b\xf3\x02\xc7\x6a\x34\xc0\x4e\xb8\x0b\x09\xa7\x19\xfc\x28\xd5\xa0\x67\x90\x11\x64\x83\xeb\xfc\x25\x84\xd7\x0c\xbe\x4b\xae\xd0\x9b\x09\x2e\x3b\x5c\x81\x9f\x22\xb0\x7c\xb5\xdb\xe5\xa7\xc4\x89\x84\xd0\xbe\x37\x3a\xd2\xd9\x94\x1c\xec\x8a\x86\xf8\x38\x11\x25\x87\xba\xe2\xf4\xe8\xe7\xd2\x44\xc9\x2e\x54\x34\x47\x3d\x99\xc2\x64\x0b\x2a\x56\xb7\x78\x76\xa6\x6f\x92\x8d\xa0\x68\x8d\x7c\x72\x06\x25\x1b\xc1\x84\xf6\x79\xd5\x11\xb7\xaf\x93\x08\x2d\x5f\x68\x65\xf6\x5c\xc2\x6a\x1f\xea\x5d\x69\xa9\x6e\x24\xb0\x7c\xab\x15\xd1\x27\x08\xaa\xfd\xea\xe3\xca\x0b\x45\x9f\x2c\x7f\x0b\x51\x60\xfa\x6c\xed\xeb\xbd\x2b\x2d\xd5\x4d\x04\x96\x0b\x49\x44\x9f\x24\xa8\x7a\xa0\x73\x6b\x09\x73\x29\x61\x94\x73\x1c\x22\x2e\x27\x84\x76\x7c\xf3\xc4\xc6\x40\xd3\x93\x8f\x6e\x32\x4b\xf2\x2b\x6d\xf1\x3b\xd5\xa1\x5f\xf9\x33\xbe\x20\x27\x28\xe5\xcb\xce\xa8\x11\xc8\x21\xaa\xa4\xed\xf3\xbe\x64\x4b\xf2\xe5\x43\xf9\xec\x22\xa2\xe4\xc3\x47\x49\xdb\xdd\x7d\xd9\x94\xa4\x88\x4b\xf2\xee\xae\xc0\xa4\x8a\x4b\xda\x01\xc6\x97\x6c\x49\x4e\xeb\x25\xf9\x00\x23\xa2\xe4\xa0\x5e\xd2\x1c\xdd\x90\x26\x8c\xec\xd4\x25\xd9\xda\x22\x4a\xf6\xe9\x92\xe6\xf1\x86\xda\x8b\xef\x26\x23\xc8\x3e\xd7\xf9\x97\x08\xaf\x1d\xa0\x1a\xf2\x82\x91\x1b\x71\x49\x3e\x41\x29\x30\xb9\x12\x97\xb5\x3a\x6b\x48\x4b\x46\x8e\x4f\x65\xb9\xc0\x44\x94\x9c\xa0\xca\xea\x4f\x79\xf2\x6b\x93\x29\x2f\xcb\xd7\x13\x05\x26\xf3\x5d\xd6\xaa\x3a\x90\x5e\x9c\x5c\x8c\xca\x72\x55\x8b\x28\xb9\x16\x95\xb5\xaa\x0e\xc4\xee\x4a\x4e\x8c\x65\xb9\xa8\x65\x96\x9c\x16\xcb\x5b\xfc\x52\x9c\xbd\x59\xdc\x45\xe0\x91\x1f\xe4\xb3\xe8\x8b\x04\xd5\x6a\xba\x29\xf6\x00\xba\xc8\x72\x51\xcb\x2c\x5d\x63\xad\xaa\x9b\xd2\xdd\x9d\x66\x2c\x17\xb4\x88\xd2\x8c\xb5\x5a\x6e\xaa\xbf\x8e\xde\x4e\x46\x90\xcb\x59\xe7\x9f\xcb\xf2\x95\xad\x7e\x9c\x97\xfa\xde\x1d\x64\x8c\x91\xbf\x89\x88\x23\x3c\x4f\x46\xd0\xea\xbb\x29\x5e\xec\xc8\x1c\x54\xe4\xf2\x96\x59\x9a\xbf\x76\xd7\xd8\x2b\x35\x03\x52\x64\x15\xf9\xae\x21\xa2\xa4\xc6\x2a\xda\x5d\x63\xaf\x76\x19\x3d\x8b\x0c\x20\xdf\x36\x54\x9c\x9c\xd5\x2a\xda\x7d\x63\xaf\xb4\x35\x9d\x49\x60\xf9\xbe\x21\xa2\x97\x65\xd0\x82\x59\x01\x12\x70\x41\x36\xa0\x3a\x09\xa4\x66\x4e\x24\x01\x53\x20\xa4\xf7\x32\x09\x9a\x06\xba\xf0\xe7\x90\x88\x2a\x64\xac\x49\xff\xef\xb1\xe8\x34\xfc\xbf\x00\x00\x00\xff\xff\x76\x19\x2f\xf2\x1f\x3b\x00\x00")
+
+func fontsDigitalFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsDigitalFlf,
+ "fonts/digital.flf",
+ )
+}
+
+func fontsDigitalFlf() (*asset, error) {
+ bytes, err := fontsDigitalFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/digital.flf", size: 15135, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsDohFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x9c\x79\x77\x55\x37\x92\xc0\xff\xd7\xa7\x10\x4b\x3c\x90\x99\x10\x56\x07\x6e\xa7\x83\x0c\x13\x48\x48\xb3\x07\x08\x9d\xe0\x34\x8b\x31\x76\x83\x77\x70\x48\x4f\xf0\x57\x9f\x23\xd5\xa2\xaa\xba\xd2\x7d\xef\x3e\xdb\xef\x5d\xe7\xa4\x66\xce\xb8\xea\x57\xa5\xda\x24\xaf\x99\xe4\xf5\xdb\xd7\xe7\x9f\xef\xf9\xf3\x97\xe2\xff\x5e\xbc\xe4\xcf\xfa\x0b\xee\xd5\xfa\x9b\x33\xaf\xdf\xbe\xf6\x2f\x3e\xfa\xeb\xef\xb7\x76\x56\xb6\xfd\x93\xe7\x6b\x6b\x4b\x5b\xfe\xd4\xcb\xdd\xa4\x84\xe7\x2f\xb7\xcf\xbc\x78\x7f\x66\xe9\xd5\xfb\xd3\xee\xed\xf3\x9d\xa5\xed\x1d\xbf\xb5\xf4\x61\x65\x7b\x65\x7d\xcd\x7f\xe1\x2f\x7e\x79\xe5\x92\x73\x7b\x51\xc2\x51\xf9\x10\x9c\x8f\x92\x3f\x1c\x3b\x76\xcc\x07\x77\xec\x58\x73\xec\x58\x70\xc7\x9a\xa6\x99\xe8\x03\x1c\xc7\x64\xc5\xd4\xc6\x37\xee\x87\xe0\x8e\x27\xf1\xde\x83\x12\xdc\xf1\xa6\x69\x9a\x04\x92\x52\x00\x7b\xc7\x05\x38\x1e\x67\x8f\x1a\x82\xe3\x3e\x01\xcf\x49\x3d\x02\x21\x7f\x81\xfe\xc0\x92\xae\xe8\x9e\xbe\x13\x49\xb4\xc6\xbe\x78\xe7\x27\xb4\x36\xc2\x07\x49\x12\x31\x5a\x70\xc9\x28\xc9\x89\xee\x73\x7f\x86\x5e\x46\xee\xfa\x30\xee\x76\x18\x3e\xfc\x72\xe3\xfd\xc9\x28\xa0\x66\xd6\x34\x8d\x64\x29\x26\x32\x08\x0e\xce\x27\x53\xc8\xc9\xe0\x80\x40\xc8\x49\xc9\x4e\xca\x4a\x86\x61\x8d\x2a\xa3\x7c\xa9\xc5\x56\x5d\xe8\x05\x33\x53\xd9\x58\x57\x66\x3a\xd9\xc1\xc4\xf0\x5e\xf7\xac\xf3\xd9\x69\x71\x07\x72\x2d\x62\x7f\x62\x7d\x99\x89\x4a\xba\x97\x29\xb2\x12\xac\x05\x23\xff\x2c\x0a\x83\xcf\x40\x82\xfb\x2c\xed\x81\x1c\x64\x19\xce\x86\xce\x93\x63\x54\x5d\x71\x54\x72\x99\x51\x70\x55\x28\x73\xdd\x17\x73\x8d\x99\x1b\x4c\xdc\x62\xe4\x2d\x0c\x5c\x8f\x9c\xc6\x8c\xbc\xb4\x89\xb8\x87\xd2\xe2\x82\xc3\xc5\xea\x45\x77\xdd\xcb\xb0\x78\xd9\xd1\x4d\xe7\x58\x04\x9d\xcb\x9f\x64\x73\x4c\x13\x9c\x9b\x9b\x23\x9c\xe8\x1c\xc5\xcc\x8d\xa6\x2a\x83\xc9\x9b\x8b\xd9\x1e\xa0\x31\x91\x97\x73\xcf\xcd\xcd\x45\x8a\x0d\xcd\x25\x1a\x8d\x48\xb9\xcb\x39\x70\x35\x73\x8a\x7a\x39\x45\xa6\xb2\xdf\x39\x2a\x3f\xc7\x5a\xaa\x96\x7b\xc0\x41\x70\x8a\xbc\xc5\x39\xea\xac\xef\x5d\x4c\x89\xd2\x77\xa4\xf8\xad\xe9\xbf\x92\x44\x25\xce\xd2\x52\xa2\x2b\x7d\x8c\xc1\x31\x52\x7c\x43\x1b\xb0\x62\x07\xaf\xda\xa7\x92\x90\x7d\xea\x14\xdc\xec\xa9\x64\x93\xd5\x80\x9f\xad\x53\x5e\xda\xa7\x28\xdf\xa9\x6c\x1e\xa2\x6d\xeb\xe5\x7e\x6c\xbf\xad\x79\xda\xf3\x8e\xde\xcf\x41\xd9\x1a\xb4\xac\xd3\x49\xd0\x3a\x0d\x4d\x27\x3b\xfa\x1a\xb6\xe3\xb9\xd3\x6c\x43\x96\xd3\xca\x42\xf3\x40\x2d\x59\x41\x55\x57\x9d\x51\x54\x69\xa2\xce\xd9\x0f\xc2\xaa\x7c\x47\x38\x5c\xfc\x79\x12\x06\x60\x06\xf7\x79\xda\x03\x71\xb4\x52\x74\xd2\x40\x50\x4d\xb9\xc1\x42\x49\x09\x29\xb7\xa0\x32\xb7\x96\xcf\xab\xd1\xf5\xdc\xa5\x4e\xea\x7d\x97\xa6\x9c\xc1\xbe\x0f\x11\x97\x7f\x47\xa9\xfc\xea\x72\xc0\xf8\xbf\x41\x5a\x38\x5d\xc0\x68\x8c\xc7\x01\x83\x24\xdc\x7a\x27\x9d\xb8\x9c\xa4\x5f\x27\x9d\xe3\xcc\x60\xb1\x53\xc4\x33\xff\xbe\xff\x3f\x49\xa2\x12\x2f\xa5\xa5\x44\x57\xfa\x18\x83\x63\xe4\x04\x3f\x51\xd8\xc9\x0b\xcb\x18\x0c\xfa\x42\x4b\x42\xea\xd5\x7f\x51\x89\x1a\x44\xf7\xd3\x46\xcc\xf6\x06\xa6\x9d\x49\x92\xb4\x78\x69\x67\x34\x3b\x88\x1a\xfb\xfe\xd5\xf3\x4b\x10\xcb\xbf\x4c\xaf\xec\x4b\x1b\x4f\xd8\x70\xc6\x9a\x67\xac\xb8\xc0\x92\x4b\x2c\xb8\xc2\x99\x6b\xcc\xdc\x60\xe2\x16\x23\x6f\x61\xe0\x6d\x9c\x78\x01\x47\x5e\xc2\x3e\x38\x5c\xac\xb7\xdc\x17\x65\x70\xbc\xe8\xe8\x82\x67\x49\x32\x3c\x7b\x96\xbf\x5e\x25\x1c\x9c\x44\x88\x83\x3b\xcb\x06\x6b\x0c\xe3\xb1\xb3\x06\x42\x85\xb3\x63\xc1\xd8\xcf\x78\x70\xdc\x9c\xc5\x96\x4c\xf3\xc5\x31\xcb\x0b\xa9\xac\xae\xcf\xe6\xa7\x00\x47\xfd\x2a\x73\x0e\x04\xac\x73\x30\x21\x58\x68\x90\x75\xee\x9c\xb0\xbc\x87\xd8\xf1\xad\xb7\xfb\xb2\xa8\x7a\x73\xee\xdc\xb9\xdc\x59\xb4\x5b\x96\x90\x99\xfd\xfa\x57\xa5\xe7\xb5\x00\x3d\xdf\x68\x89\x9c\x29\x04\x82\x1a\x69\x3e\xe8\x33\x95\x55\xc6\xa6\x94\xf7\x3c\xf5\x9b\x2b\xa5\x16\x12\x3d\x7f\x3e\x77\x75\x9e\xa7\xc8\x9d\xe5\xd9\xa8\x82\x9e\x78\x1c\x0a\x23\x99\x89\x31\xa4\xbd\x1d\xa4\x05\x19\xc4\x5f\xf8\x6a\x7f\xf7\x1b\x37\x36\x38\x7f\x41\x4b\x82\x17\xcc\x0a\x2e\x5c\xc8\x30\x45\xa1\x1a\x5c\x3e\xe5\xfd\x05\x82\xb2\xc2\x68\x48\x95\x81\x61\x9f\xb2\x83\x0b\xd4\x7c\x31\x72\xfc\x42\x2d\x58\x6c\xbe\x3c\x66\x69\x21\xc5\xd5\xf5\xd8\xfc\x94\x60\x89\x76\xb2\x8b\x24\x99\x5d\xa4\xc1\x33\x63\x94\x59\x42\x17\x2f\x4a\x86\x86\x64\xa4\x0b\x46\xaa\x60\x98\x2b\x0a\x6a\xc8\xa4\x44\xc6\xd2\x70\x5c\x9e\xe9\xa2\xee\xb9\x07\xc3\x7c\x8d\xcc\x77\x51\xd4\xf5\x76\x59\x17\x7b\xef\xf9\x30\x59\x9f\x47\x73\xa9\x25\x11\xda\x5d\x8f\x80\xc5\xe3\x97\x4c\xa1\x0e\x98\x0f\xfb\x42\xa1\x4b\xb6\x4f\xae\x2e\x93\x21\xad\xc0\x9c\x5f\xc2\x26\x97\x6f\xf8\xf8\x25\x5d\xff\x12\x16\x12\x18\xfb\x84\x64\x97\x64\xea\xa3\xf2\x25\x60\xd4\xf9\x79\x14\x09\xe7\x61\xf8\x79\x19\x29\x19\x41\xc5\x10\x6a\x06\xd0\xb0\x04\x2d\x8b\x70\x9e\xd6\x4e\x1d\xf9\xe0\xe6\xf5\x0b\x89\x98\x61\x0a\xc3\x34\x04\xe7\x45\x67\xf3\x9d\x50\x1c\x8f\xd0\xcf\xcf\xdb\x4a\xd0\xfc\xbc\x2a\xce\xb3\x8b\xc5\xcd\xfc\xe2\xc7\x7f\x0d\xd5\x9f\x30\xbe\x2a\x48\x70\x5f\x35\x2d\xa9\x53\x21\x99\x8a\x22\x48\xbf\x52\x3d\x30\x94\x34\x43\x41\x05\xcc\x54\x42\xa6\x0a\x12\xd5\x10\xa9\x81\x40\x2d\x4c\xb4\x05\x23\x6d\x43\xb1\xc9\x71\xb6\x3e\x00\xda\xfb\x99\x5d\x26\xc9\xf0\xf2\x65\x7e\x08\x09\x07\x27\x11\xe2\xe0\x2e\x93\x7e\x99\xbc\x97\x09\x42\xb2\xcb\x9d\x90\x34\x3e\x7e\x39\x55\x37\x85\xa0\x7a\x21\x72\xfc\x42\x1d\xd0\x34\x5f\x1c\xb3\xbc\x90\xca\xea\xfa\x6c\x7e\x0a\xb0\xf7\xf9\x2b\x24\x19\x5e\xb9\xc2\xc3\x27\x1c\x9c\x44\x88\x83\xbb\x42\xfa\x15\xf2\x5e\x21\x08\xc9\xae\x74\x42\xd2\xd4\x71\x6f\x2b\x01\xc4\x36\x99\xc9\x89\xe8\xb0\x1c\x33\xb3\x0c\x05\x63\x28\x19\x2f\x44\x32\x84\x9a\xd1\x96\xc4\xde\x66\x7f\xf1\x95\xd7\x70\x40\x7f\xf9\x86\xf9\x6b\xda\xe1\x9d\x9d\x5c\xcb\xff\x60\x61\xef\x60\xd4\xbf\x25\x01\x35\x36\xff\x37\x4b\x27\xcd\x10\xb5\xa4\x26\x0d\x62\x63\xe0\xc1\xb5\x9e\x77\xe2\xa5\x8c\x67\x7e\x0d\x82\xe6\xd7\xe9\xe2\xbe\x46\x2f\x59\x60\xb2\x95\xcc\x6c\x45\x53\x58\x3e\x38\x69\xb5\xbd\xf6\xac\xcd\x6c\xeb\xda\xae\x6c\xcf\xfd\xe6\x3d\x04\x73\x26\xff\x58\xed\xef\x5a\x12\x52\x5f\x59\xff\x5e\x89\x3a\xe4\x5c\x7f\x32\xd4\xf3\x61\x7c\x03\xc2\xde\x6f\xd2\xfa\xbe\xe1\x60\x61\xa7\xb3\xd9\x86\x54\x6c\x63\x66\xb2\xa9\x10\xda\x45\xaf\x3e\xab\x33\xeb\xba\xba\x2b\xdb\x73\x9f\x79\x0f\xcd\x24\xfb\x2a\x88\x88\xb9\x7a\x15\x1f\x65\xa2\x91\x31\x49\x34\xb1\xab\x18\x81\xae\xab\xcc\x52\xa6\xab\x05\x86\x6a\x64\xb9\x22\xb3\x2c\xf9\xac\x45\x92\x71\xde\xcc\x72\x29\x66\xa2\x7a\x37\xbb\x8a\xd3\xaa\x7c\xd4\x64\xf1\x87\x03\x15\x67\xd9\xd5\xab\x4d\xfb\x6c\x21\xae\x98\xef\x10\x59\xf1\xa7\x9c\x13\x7d\x61\x20\xc9\x30\x04\x7e\x1f\x09\x9f\x70\x12\x21\x3e\xe1\x02\x1b\xac\x31\x8c\xc7\x82\x81\x01\x8a\xb5\x61\x63\x8f\x8f\x82\xc1\xe6\x84\xfe\x55\xf5\x3c\xa6\xe8\x93\x06\x2d\x4c\xd4\x9e\x3d\x43\xb1\x25\x3a\x7e\x00\x9b\x3f\x58\x58\xa4\x5a\xca\xbf\x33\x77\x87\x2c\x2c\x2c\x8c\x08\x59\x68\x9a\x66\xa1\x33\x64\x21\x2d\x73\xa1\x23\x64\x01\x17\xbe\x50\x0d\x59\xe0\x4b\x59\xa8\x84\x60\x15\x1b\x23\x42\xc8\x67\x63\x72\x48\xf6\x98\x18\x0e\x91\x5c\xc7\x50\x08\x52\x12\x19\x83\x21\x0b\x4d\x49\x16\x44\x88\xc9\xa1\xf3\xa4\x90\xd2\x4e\x33\x8b\x21\xa5\x08\x41\x83\xab\x44\xe4\x98\xe0\xb0\x76\x2b\x22\xbd\x8b\x28\x93\x3c\xa9\xa3\x1f\xd2\xef\x0f\x55\xd7\xac\x00\xb5\xf7\x7f\x4d\x50\x88\x43\x1c\x33\x50\x84\xf7\x1e\xf5\x58\xed\x5a\x6f\xaa\xf3\x52\x00\xb7\x70\xcd\xfb\x11\xb1\xfb\xe8\x81\x92\xe5\xbc\x89\xb6\x3e\x11\xae\xd5\xb7\x53\xdc\x64\x9f\xbb\x98\x2a\xad\x3c\xa5\x91\xf8\xba\x14\xc4\xd7\xaf\x5f\x97\xeb\x00\xac\x19\x61\x80\x74\x9e\x30\x52\x55\x22\x38\x4d\xb9\x93\x19\xe0\x4a\x83\xb5\x71\x6a\xc3\xd7\x56\x55\x5d\x6c\xef\xdb\x99\x1e\xee\x9b\xe5\x7f\xa5\x08\x2c\xb7\x41\x1e\x83\x93\x87\x92\x50\x20\x69\x50\x92\x8d\xac\x1a\x4c\xfa\xec\x71\x6e\xb0\x32\x4e\x6d\xf8\xca\xaa\xca\x8b\x3d\x88\x3b\x9e\xc1\xfb\xa9\x7e\x8b\x0b\xee\xdb\xa2\x04\xf7\x6d\x53\x90\x2e\x8e\x0e\x4e\x81\xdc\x7b\x70\x7c\x8b\x15\x29\xbf\xe5\xb9\x4f\x9b\xe8\x5b\xcd\x73\xd1\xf1\x78\x25\x4f\xad\xae\xed\xd3\xce\x35\x72\x0f\xd5\xfd\x94\xf7\xdc\xf7\xbe\x66\xc4\xfb\x27\xba\x51\x94\xe0\x6e\x94\x16\xd4\xc5\xd1\xc1\x29\x90\x7b\x0f\x8e\x1b\x58\x91\xf2\x5b\x9e\xfb\xb4\x89\x6e\x68\x9e\x8b\x8e\xc7\x2b\x79\x6a\x75\x2d\xa7\xb9\x9a\x1b\x37\x34\x6f\x7a\x72\xd5\xc7\xe8\x7b\x19\x18\x9f\xf4\xeb\xde\x4d\x29\x88\x6f\xde\xbc\x29\xef\x0b\xb0\x66\x84\x01\xd2\x79\xc2\x48\x55\x89\xe0\x34\xe5\x4e\x46\x63\xd9\xa0\xc4\xa2\x13\x1b\xdd\xc6\x7c\xa2\xd0\xe0\x88\x71\x6a\xc3\xcb\x55\x81\x72\xd3\x2e\x16\x95\x01\x7d\x6b\xeb\xf9\x1d\xaf\xfe\x5b\x5d\x70\xdf\x91\x24\x9b\xad\xe0\xbe\xc3\x2d\xa1\x83\xac\x2e\xc7\x77\x05\x47\x4c\x45\x86\x74\x7c\x07\x5d\x8d\x70\x34\xa9\x99\xa6\xe0\x10\x32\xa6\xa3\x96\x6a\xfc\xae\xaa\x03\x4e\xb2\xab\xca\xda\xfb\xdf\xe0\x2c\x1d\xd2\xa3\xf5\xef\x59\x82\xfb\x9e\x2e\xc4\xea\x68\xc4\x18\xef\x93\xf1\x3d\xe4\x39\x78\x5d\xd6\xaa\xf7\x93\x7b\xae\xcd\xb5\x0f\x7d\xf2\x4f\xf2\x5b\x59\x14\xe6\x97\x3e\x16\x26\xae\x93\x50\xfc\x2d\xdb\xc9\x24\x78\xb5\x23\x1a\x07\x68\x61\x52\x4b\x38\xf1\xac\x32\x6e\x6e\xe5\x69\x52\xc9\x5b\xb7\xd4\x67\x7e\x2a\x93\x3a\x11\x0e\xac\x8d\x0d\xf2\x46\xc7\xbf\x86\x19\xe3\x32\xaf\xd1\x1f\x48\xa2\x89\x6a\x70\x3f\xe0\x2e\x80\x82\x3a\x0e\x45\x3d\xd2\x1f\x98\x62\x64\xcc\xcb\x06\x7f\x84\xce\x28\x38\xa7\x17\x34\xc3\xd1\xb4\x98\x41\x57\x2b\x77\x56\x99\xa2\xcf\x1e\x8a\x9b\xec\x73\x17\x53\xa5\xd5\xaf\xd6\x1d\x7f\xdc\x0d\xee\x1f\x59\xac\x87\x2f\xa5\x87\x87\x5c\xad\x6c\xde\xff\xa3\x70\xe2\xe8\x79\x60\x55\x6a\x52\x14\xb0\xe4\x76\x94\x74\x7b\x2a\x32\xd9\x9d\xce\xdc\x53\x77\x8d\x3c\xcb\x01\xb7\x51\x8c\x83\x70\x70\xb7\x71\x7d\x3a\x82\x69\x0e\x50\x11\x19\x8a\x00\x11\x21\x98\x0c\xe0\x08\x89\x54\x00\x46\x28\x22\x9a\xa4\x88\xdb\x6c\xa9\x80\xdb\xe8\x50\x1f\x74\x80\x38\x7a\xdb\x17\x03\xbc\x5c\x49\x31\x00\xa9\x50\x6d\x80\xcf\x4b\xaf\x04\xb4\x76\x79\x30\x01\xa3\xae\x7b\xe4\x83\xf9\x53\x04\x4c\xf6\x89\x78\x07\x85\x08\xd9\xc1\xdd\xc1\x17\x41\x2e\xb4\x85\x87\x5c\x05\x0f\xba\x4a\x1e\x70\x15\x3d\xc9\xd5\xf6\xdc\x41\x57\xcb\x73\xc7\xdf\x11\x1f\xb4\x07\x5d\x4d\xc1\xe3\x55\x49\xe5\x91\x2e\xe3\x11\x2e\xeb\xc9\xae\x96\xc7\x97\x3b\xb0\xdb\x31\xb7\xe0\xf9\x16\x26\xb9\xd3\x99\x7b\x8a\xae\x2e\x78\x97\x24\xc3\xbb\x77\x79\xdd\x09\x07\x27\x11\xe2\xe0\xee\xb2\xc1\x1a\xc3\x78\xec\xae\x81\x50\xe1\xee\x8c\x60\xb1\x25\xd3\x7c\x71\xcc\xf2\x42\x2a\xab\xeb\xb3\xf9\x29\xc0\x7e\x3f\xa0\xde\xb3\x02\xb4\x31\x72\x4f\x50\x88\x43\x1c\x33\x50\x84\xf7\x1e\xf5\x58\xed\x5e\x6f\xaa\xf3\x52\x00\xb7\x70\xcf\x7b\x13\x0b\xed\x7a\x93\x57\x4c\x3c\x3e\xbd\x77\x2f\x57\x11\x54\xcc\x3f\x92\xaa\x9e\xba\xb7\x3e\x00\x3a\x41\x8a\xfb\x24\x82\xde\xbf\xcf\x17\x04\x3c\x38\xc9\x88\x07\x77\x9f\x2d\xd6\x32\x8d\x9f\x4d\xf7\x2d\x85\x4f\xb1\xfb\xd3\xa3\xf7\xa9\x37\xd5\x19\x0f\x73\x5f\x4d\x21\xa9\x9d\xb8\xb9\xdf\xde\x4e\x82\x76\x93\xb8\x1e\xb3\x75\x6c\xc2\xde\x05\x1c\x19\xf4\x33\x79\x60\x05\x68\x63\xe4\x81\xa0\x10\x87\x38\x66\xa0\x08\xef\x3d\xea\xb1\xda\x83\xde\x54\xe7\xa5\x00\x6e\xe1\x81\xf7\x23\x62\xf7\xd1\x43\x79\x8a\x07\x4d\x0f\x9a\x17\xe8\x3d\xea\x83\xf8\xba\xd1\xe3\x99\xd4\xe1\x43\x2d\x11\x3e\x7c\x68\x1e\xc9\xc3\xe0\x00\x41\x8c\x85\x29\x19\x9e\xd7\x90\x0b\x15\xa1\x7f\x48\x39\x55\x4b\x5c\x80\x3c\xd0\xfc\xc3\xdc\x56\xc4\x3c\x51\xee\xe9\xa1\x19\xf3\x21\xf5\x59\x84\x34\xb0\x86\x8d\x9d\x33\xc3\x46\x94\x4f\x5b\xd2\x8b\x9b\xf9\x4f\x1b\x3d\x7e\x04\xe9\xfa\x21\x36\xb8\x1f\xcb\x12\xdc\x8f\xf6\xab\x47\x92\xd1\x8e\x1f\xc9\x8f\xca\x8f\x54\xc3\x7b\x04\xde\x53\x0d\x6a\x83\x1d\xb6\xdd\x21\x3a\xc4\x80\xc6\x91\x97\x31\xae\x23\xcb\xc8\x8b\x1a\xa4\xa3\xe2\xa9\xe2\x47\x28\xc9\x24\x23\xb8\x47\xb0\x1d\xc4\x68\xd4\xf1\xa3\x16\x8e\x49\x7c\x01\x7b\xc6\xf2\xff\x2d\x6c\xb6\x38\x75\xc8\x6a\xc6\xcd\xa3\x47\xac\xa5\x0d\xb2\x49\x6e\x5a\xac\x70\xc0\x2a\x69\xdf\x8f\xd4\x7e\xeb\xd7\x30\x18\xdc\xf9\xf7\x9e\x11\xce\xc7\x28\x02\x12\x0a\xee\x31\xac\x47\x39\x11\xed\xc7\x89\x6a\xdb\xf9\x38\x75\x6b\xbd\x6c\xa7\x51\xb4\x37\x5b\x30\xa7\xf4\x0a\x1d\x97\x90\x89\x8c\xa3\x0d\x11\x53\x15\x78\x7d\x48\x55\xf5\xbc\xdb\xc7\xfc\x96\x1e\x17\x16\xff\xd8\xfa\xd4\xad\xb4\xb6\xa1\xae\xec\xb1\xd9\x94\xbe\x4f\x7d\x73\xa3\x2e\xfb\x48\x39\x3b\xbd\xbd\x52\xb5\x83\x9f\xa0\x74\x04\x51\x48\x70\x4f\xe0\xf2\x3a\x83\x31\xe4\x30\x83\x51\x7d\x62\x7b\x6c\x05\x3f\x49\xdb\xb0\xd1\x55\x3b\xad\x4e\x7b\xb1\xa8\xb1\x9f\xf0\x9e\x65\xf4\x13\x7e\xf9\x4f\x6c\x1d\xbc\x94\x4c\x50\xb3\xb6\x17\xc1\xcc\x6a\x1f\x55\x70\x2d\xa3\xea\x3e\xbf\x8d\x72\xaf\x6a\x2f\xe2\x21\x95\xb7\x20\x77\x28\x5f\xdd\xa8\x7d\xeb\x27\xfa\xc4\xde\xa4\xb1\xf5\x7b\xb6\x2f\xd5\xd8\x87\xf9\x99\xf2\x67\x0f\xee\xfb\x1d\xf8\x27\x10\xb4\xd1\x0a\xee\xa7\x74\xdb\x8c\xc1\x1a\x81\x91\x93\x91\x72\x33\x47\x2d\xe6\xce\x96\xcf\x7e\x68\x10\xed\x9c\x0d\xfb\xfe\x89\x1f\xf6\x4f\x7e\x24\x2e\x27\x29\x95\xac\x34\x58\x1b\xa7\xdf\x4e\xca\x8b\xed\x77\x3b\xd3\xc7\x7d\xb3\x3c\x05\x41\x1b\xad\xe0\x9e\xa6\x35\x30\x06\x6b\x04\x46\x4e\x46\xca\xcd\x1c\xb5\x98\x3b\x5b\x3e\xfb\xa1\x41\xb4\x73\x36\xec\xfb\x29\x3f\x94\xa7\x6a\x9c\xa7\x8a\xe6\x29\x75\x9f\x07\x88\x9f\xf2\x4c\xb8\x34\xd9\x77\x63\xfb\x7e\x2a\xa5\xf3\x1a\x06\x83\xfb\xfc\xb5\xe2\x9f\x6d\x09\xee\x9f\x8d\x95\x2e\x48\xe7\x80\x51\xce\x94\x9f\x98\xa8\xce\x48\x40\xc1\x18\x4a\x46\x50\x31\x84\x9a\x01\x34\x0c\x5a\x12\x4c\x8f\x29\xfa\xef\x37\x7b\x69\x75\xe3\x6f\x7e\x5a\x50\x50\xa5\xfe\x4c\x12\xdc\xcf\x38\x54\x49\xcd\x01\x3f\xc3\xb1\x03\x57\x9b\xae\x1e\x72\x93\xe5\x29\x26\x53\x6b\xdf\xcf\xeb\xfc\x17\x90\x76\xfc\x2f\xa9\xd5\x5f\xda\x79\x4a\x8e\x94\xbf\xe0\x80\xba\x6d\x07\xf6\xd3\x72\x50\x9f\xd6\xc1\xfd\x1b\x47\x9e\x4b\x3b\xc4\xbc\xca\x21\xf7\x20\x1d\x6a\x3f\xc2\xa1\xf7\x96\x1d\x66\x9f\xec\xb0\x7b\x26\x47\x6b\xff\xb8\xf6\xfe\xf7\x35\x23\x5e\x7b\x7a\xcf\x48\x82\x7b\x86\xaf\xdb\xa8\xcf\x9e\x91\xea\xbd\x7f\x76\x18\xaa\x28\x51\xed\x81\x9a\x2c\x4f\x31\x99\xda\xf3\xbf\x4e\xb4\xb8\xb8\x68\xd0\x62\xd3\x34\x8b\x0a\x2d\xa6\x96\x17\x05\x5a\xc4\x31\x16\x19\x2d\xf2\xd7\xea\x45\x44\x78\x0a\x59\x44\xa4\xe3\xc7\xbd\xe0\x16\x41\xa0\x8f\x28\xc3\xf8\xef\x34\x0d\x15\xb5\x59\x3d\xfa\x2f\xcf\x51\xf1\xfc\x5a\x91\xe0\x7e\x6d\xfd\x20\x94\xe4\xd7\xae\x33\x53\xea\x9a\x5c\x7b\x42\xf9\x57\x92\xa8\xc4\x2e\xb5\xf2\x2f\x54\xf6\x7c\xd2\xd2\xa9\x18\x5d\xca\x33\x0c\xa5\xf4\x5d\x67\x5a\xec\xb9\x14\x62\xf2\x09\x3c\x37\x71\x08\x55\xbe\xe7\x92\xb5\xe3\x9e\x9b\x84\xc1\xe1\x09\x0a\x4b\x0c\x93\x50\xba\x6e\x66\xce\xca\x96\x13\x7f\xae\x67\x03\x7d\x96\x7b\x6e\xb1\xf2\x8f\x1a\xc1\xbd\x40\x31\x14\x66\xdb\x07\xf5\x2f\xba\xa8\xac\xca\x94\x25\xf2\x36\x8d\xc9\x74\x06\xc2\xba\xda\x8b\x22\x25\x7d\x32\x2a\xca\xbd\x18\xd1\x99\x84\x89\x1a\xa9\xfe\xd8\x37\x08\x3a\x88\x26\x12\x7d\x69\x24\xd2\x97\x2f\xcd\x8a\x23\xb5\x2c\x51\x82\x70\xd6\xd0\x97\x5e\x14\x20\xfa\xd2\xf4\xd0\x45\xcb\x19\x6c\xb5\x72\x67\x95\x29\x2a\x13\x0f\xe3\x2e\x5a\x74\x9c\xe0\x57\x28\x86\xc2\xc8\xfb\xa6\xaf\xb0\x1a\x55\x91\x14\x0d\x96\x44\x5f\xd9\xbb\x88\x94\xa0\xce\x40\x75\x75\xb5\x57\x19\xee\x8b\x8a\x62\x4d\xda\x4e\xab\x33\x98\x38\x63\x0c\x87\x3d\xf0\xc0\xa4\x0f\xe2\x41\x0c\xfd\xab\xc9\x92\x10\xa2\x4b\x4b\x72\xe7\x91\x07\xe7\x97\xc8\x5a\x42\xf7\xd2\x52\x70\x04\x53\x42\xc4\x4c\x45\xac\xa4\x22\xb3\xcf\x19\x64\x17\x22\x83\xea\x77\xa9\x69\xe3\xdc\x59\x4e\x52\x9a\xa2\x59\x2a\x4d\xbc\xb4\x34\x90\x07\xd1\xe7\x99\x8c\xfa\xb3\xc9\x6b\x23\xc8\x5f\xdb\xf5\xbf\x4e\xbc\x85\x9b\xe6\xb5\xe0\x98\xc3\xf2\xd7\x58\x11\xbc\x6d\xce\xfd\x50\x7a\x6a\xc5\x72\x75\x6a\x0c\x6e\xf3\xd4\xea\x8e\xec\x67\xbf\x3c\x6f\x77\xdc\x7b\x19\x10\x1f\xc4\xeb\x8e\x74\x99\x84\xf4\x48\x97\xf9\x01\x2c\x2f\x27\x3d\xd2\xe5\xd6\x33\x5d\x0e\x6e\x99\xc3\x96\x59\x25\xba\x9c\xaa\x90\x3e\x09\x05\xdc\xa2\xa2\x5c\xa4\xed\xce\x12\xf5\xcb\xcb\x25\x9a\x47\xd6\x94\x44\x54\xa3\xbd\x94\xfa\x85\x7d\xb5\x7a\xe0\xb4\xe5\x1e\x96\x7d\xee\x81\x0f\xa8\x1b\x92\x45\xfb\x3e\x93\x37\x20\x96\xa6\x3a\xfb\xa1\xfe\x0d\x50\x99\x9d\x29\x1e\x01\x07\xd1\x2c\x91\x0b\xfa\x06\xe3\x9b\x37\x82\xc6\xa3\xa4\x32\x85\x42\x6f\x66\x45\xc5\x2a\x51\x1f\xcc\xa7\x6c\x9b\x66\xac\xb5\x95\x95\x95\x95\xa4\xad\xc4\xb9\x56\x34\xe3\xb8\x15\x90\xa8\x35\x1c\xb7\x32\xb9\x06\x59\x9a\x95\x8a\x86\x52\xeb\xb9\xa7\x36\xe1\x9f\x1e\x56\x57\x57\x57\x0d\x5b\x8d\x0d\xae\x8e\x8e\x2b\xe4\x5b\x05\xd1\xac\x29\xe4\x2b\xd5\x38\xda\x2c\x2d\x48\x33\x50\x56\xd5\x0e\x40\x6b\x56\x57\x49\x81\xb3\xf2\x2b\x05\xed\x39\xc7\xac\xca\xff\x74\x0d\xac\x18\x76\x5f\xfc\x34\xa8\xc0\x7f\xa3\x68\x08\x15\x26\x85\xfe\xdf\x19\x62\x7a\x05\x49\x93\x90\x15\x01\xf3\x09\x86\x8d\x48\x9d\xa1\xe8\x61\x04\x54\xc7\xb9\x79\x59\x28\x4f\x24\x5a\x12\x63\xe6\xe6\xe5\xea\xf2\x98\x63\x6f\x7e\x5a\xb0\xfc\x15\xe2\x2d\x48\xd4\xd2\x40\x35\xcd\xbf\x3d\x58\x0d\x32\x37\x6f\x2b\x1a\xca\x21\x7e\xf5\xeb\x58\xd5\xf4\x3d\xef\x40\xbc\x52\x83\xf3\xef\xde\xe1\xfb\x7d\xe7\x3d\xab\xef\x7c\x70\xef\xf2\xd3\x7e\x27\x75\xe5\x91\xc2\x9e\x77\x14\x4f\x0a\x79\x62\x49\xa3\x0c\xc2\x43\xeb\x30\xca\x40\x6e\xae\xaf\x67\xc2\x6f\xc4\x07\xc0\xd6\xd6\xd6\xd6\xbc\x5f\x43\x41\xd6\x34\xcd\xda\x1a\xbd\x91\x48\x81\x09\x59\x5b\x4b\x67\xcd\x73\x5a\x8b\x35\xd6\x30\x00\xbd\x99\xa5\xec\x6b\xd3\x65\x3c\x15\x68\xb3\xdb\x73\x81\x15\xe0\x34\xd0\x7a\x16\x40\xeb\xeb\xe2\x0a\xd7\xd7\x7d\x70\xeb\xe6\x5e\xd7\x09\xa5\x53\x0a\xad\xa7\xc4\xeb\x07\x82\x0a\xe9\x75\x13\x85\x56\x4b\x03\xcd\x62\xab\x06\x0d\xe2\x37\x1b\xb7\x11\xc5\x7b\xbf\x41\x02\x34\x2e\x6f\x63\x63\x83\x17\xb9\xc1\x54\xc9\x46\xca\x80\xfa\x06\x1f\xd8\x08\xce\x6f\xd0\xb9\x98\x7c\xbf\xb4\x9d\x37\x17\x13\xd4\x74\x66\xe9\x46\x9a\xc2\xcb\x7e\x61\x60\x6f\x7a\xc8\x3b\x2b\xd2\x8d\xbc\x94\x49\xa9\x2c\xde\x7d\x43\xc3\x78\x26\xde\xfb\x4d\x12\xd2\x23\xdd\xe4\xe5\x6e\x6e\x26\x3d\xd2\xcd\xd6\x3b\xd9\x0c\x6e\x93\xc3\x36\x59\x25\xba\x99\xaa\x90\x3e\x09\x05\xdc\xa2\xa2\x5c\xa4\xed\xce\x12\xf5\x9b\x9b\x25\x9a\x47\xd6\x94\x64\x73\x7c\xba\x99\xf7\x30\x29\x25\x19\xf4\x33\xd9\x8a\xe2\xbd\xdf\x22\x01\x1a\xc7\xd9\xda\xda\xe2\xfd\x6e\x31\x55\xb2\x95\x32\xa0\xbe\xc5\x07\xb6\x82\xf3\x5b\x74\x2e\x26\x2f\x53\x10\x43\x73\xbf\x87\x46\x79\xd0\x29\xec\x77\xdf\x74\x56\xdf\xfa\xb6\x59\x10\x6d\x6f\xe7\x7b\xdf\x8e\x48\x82\xc4\x82\x43\x12\x4f\x81\x12\x9c\xdf\xa6\x13\x98\x2d\xa5\xdf\xe6\x3c\xb2\x09\x41\x63\x7a\x2c\xbe\x6d\xd2\x73\xf6\x98\x5e\xf7\x90\xa2\xbc\x64\xdb\xdb\xd4\xbd\x9c\x67\xd0\x3f\x50\x74\xfd\x56\x21\x1c\x3b\x3b\x3b\x3b\x6d\xc7\xce\xce\x4e\xd3\x34\x25\x47\x5a\xc7\x78\x8e\x1d\x10\x70\x80\xa0\xa3\xf5\x15\x60\xa4\x23\x67\xa2\x5c\x93\x76\x35\xbe\x03\xea\x68\x47\x93\x27\xca\xbb\x32\x2d\xe7\xed\x2a\xd7\xce\x8e\xbc\x8f\x9d\x2c\xe3\x5d\xd4\x90\x1c\xb3\xfb\x5d\xe9\x7d\x92\xa8\x93\x16\xdc\xfb\xb8\x5d\x60\xa8\x4d\x91\x35\xb1\x8b\xc6\xb0\x2c\xef\xdf\x07\xe7\x5b\x30\xce\xf6\xfe\x7d\x8e\x21\x46\x53\xc5\xb9\xe2\xff\x1d\xfa\xef\xa4\x5d\xf1\x33\x71\x7d\x00\x11\x0c\x49\x70\xfe\x43\x5a\x76\xf6\x91\x1d\x13\x6a\x1f\x5b\xa9\x96\xf4\x65\x1d\xda\xc8\xb6\x88\xc2\x0e\x89\xc8\xf3\xd4\x3c\x32\x59\x95\xe7\xfa\xc0\xef\xe4\x43\x6b\xe4\x0f\xc6\x23\xb7\x61\xe7\x93\x8b\xfa\xa0\x3c\x7a\x87\x7a\x5f\x83\xb9\xca\x89\x5c\x1d\xbe\x1e\x69\x8e\x76\xe8\x2e\x88\x60\x45\x7b\x77\x37\x38\xbf\x9b\xde\x4c\xf6\xd5\xec\xd8\x80\xf6\xed\xe2\x4b\xdc\xb5\x27\x53\xaf\x32\x76\x97\xdf\xf3\xae\xa9\x01\x63\x65\x1b\x35\x6b\x8b\x0d\x10\xa9\x7d\x94\xcb\xaa\x64\x93\x5d\xf3\x5e\xcb\x3d\xca\xf9\xf2\x15\x94\x27\x17\x5b\x13\xb7\x35\x6a\xbf\xf2\x62\x77\x95\xa7\x65\xab\x37\xa0\xef\xd3\xda\x03\x78\x84\x47\x28\x74\x10\xbf\x9f\xb9\xdf\x40\xc0\x44\x23\x38\xff\x5b\x7a\x30\x09\x93\x1a\x33\x30\x66\x25\xe5\x45\x2b\x1f\x82\x6a\xbf\xf1\x6b\x86\x4c\xd8\xc3\x6f\x0a\x76\xd2\x62\x86\x62\xb5\x62\x67\xc5\x29\x2a\x13\x0f\xe0\x2e\x8a\x74\x28\xdf\xe2\xba\x5c\x1f\x41\x04\x43\x12\x9c\xff\x98\x16\x9f\x7d\x64\xc7\x84\xda\xc7\x56\xaa\x25\x7d\x59\x87\x36\xb2\x2d\xa2\xb0\x43\x22\xf2\x3c\x35\x8f\x4c\x56\xe5\xb9\x3e\xf2\x4b\xfb\xd8\x1a\xf9\xa3\xf1\xc8\x6d\xd8\xf9\xec\xa9\x8f\x85\x1d\xb6\x3c\xb6\xc3\xc2\xe6\x0b\x9e\xd6\x36\xac\xab\xe8\x81\xcd\xb7\x6e\xcc\xce\xd5\xc7\x35\xe6\x1f\x0c\x0e\x14\xfd\x6e\x25\xb8\xdf\x1b\x2d\x6d\xf4\xbb\x38\x48\x84\xd3\x67\x42\x48\x10\x44\x92\x00\x52\x24\x21\x22\xdc\x97\xb7\x5d\x94\x5b\x6d\x0f\x34\xfd\xad\xb6\x91\x62\x64\xfc\x27\x0a\x1a\xff\x89\xfd\xa3\x91\x74\x65\x60\x18\xe8\x98\x40\x1a\x78\x22\x19\xac\xfb\xe0\xb2\x6e\x3d\xfa\x4c\x47\x6a\x8a\x2b\xf5\xa6\xba\xd6\xf3\x14\x56\xb1\x7f\x23\xff\x6b\xa0\x7b\x5a\xfd\x3f\x90\xa4\xa6\x06\xfb\xab\x39\xc3\xcc\x4a\x4c\xa4\x9a\x75\xfd\x11\x85\x8d\x58\xfb\x0f\x69\x80\x15\xc3\x84\xe1\x3d\x5b\x65\x23\x5a\xa9\x0e\x59\x50\x14\xad\x96\x47\x9d\xa9\xa5\xfe\x23\xf7\x63\x7b\x53\x5d\xcb\x79\xa6\xf1\xb2\xb4\x54\xff\xcd\xe3\xa3\xe9\xf8\x44\xe2\xd9\x88\x8e\x4f\x9f\xf8\x4b\xe8\x27\xef\xc1\x88\x0e\xd4\xf4\x87\xbd\xe0\x3e\xe9\x50\xb4\xa2\xc3\x24\x07\x6b\x08\x93\x0f\xce\x11\x5c\xef\xff\xf9\xeb\x48\xff\x23\xff\x1f\x00\x00\xff\xff\xac\xd9\xf0\x1f\x3b\xc1\x00\x00")
+
+func fontsDohFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsDohFlf,
+ "fonts/doh.flf",
+ )
+}
+
+func fontsDohFlf() (*asset, error) {
+ bytes, err := fontsDohFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/doh.flf", size: 49467, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsDoomFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x58\x6d\x6b\xe3\x3a\x16\xfe\xee\x5f\xf1\x50\x02\x69\xd9\x36\x22\xb3\x9d\x32\xb3\x94\x92\x7d\x87\x85\x65\x06\x2e\xf4\x93\xb8\xaa\x9b\x28\x89\xb9\x8e\x53\x6c\x67\xa6\x05\xfd\xf8\x8b\xce\x91\x6c\xf9\x35\x6e\x67\xe8\x44\xc2\x96\x1f\x9d\xf3\x9c\x57\x69\x9b\x6e\x3f\xc5\x33\x7c\xc1\x1d\x96\xb7\x58\x7e\xc6\xf2\x2e\xfa\xd7\xb7\x6f\xff\xc7\xf3\x1b\xfe\x93\xc7\x59\x81\xef\x0b\x6c\x34\x1e\xf3\x44\x17\xb8\xdf\xbe\xfc\x58\xbd\xbe\x1d\x5e\xf6\x8b\x24\xde\x2e\xb2\xf4\x01\x58\x7e\xc1\xff\x4e\x19\x96\x5f\xbf\xde\x45\xcf\x71\xa1\x37\x38\x66\xf8\x47\xb2\xb3\x08\xff\x4d\x75\x96\xe1\x9f\xfb\xf8\xe5\x45\xa7\x29\x6e\xc5\xd7\xbf\xe2\xe6\x06\xd5\xb2\xdf\xca\x38\xdb\xc4\xf9\x26\xda\x26\xbb\x54\x97\xc8\x75\xaa\xe3\x42\xe3\xd3\x62\x69\xd7\x2d\x3f\xe1\xef\xa7\x9d\x85\xbe\x8d\xbe\xeb\xfc\x90\x14\x45\x72\xcc\x90\x14\xd8\xeb\x5c\x3f\xbf\x61\x97\xfc\xd0\x19\xca\x23\x0e\xc7\x4d\xb2\x7d\x43\xb9\x4f\x0a\x6c\x8f\x59\x79\x8d\xb8\x40\x7a\xcc\x76\x76\x2c\xf7\x3a\xa2\x05\x89\xce\xe7\x05\xb2\xf8\xa0\x2d\xc6\x4b\x1a\xaf\x59\x8c\x18\xeb\xe3\xe1\xa0\xb3\x12\x69\x92\xe9\x45\x14\xfd\xfb\xf5\x25\x8d\xb3\xb8\xb4\xbb\x1d\xb7\xd8\x26\x79\xc1\xef\xfe\x16\x59\xc2\x70\x83\x8b\x43\xbc\x4b\xd6\xc8\x4e\x87\x67\x9d\x5f\x60\x7b\xcc\xb1\x4d\x52\x8d\x64\xa3\xb3\x32\xd9\x26\x6b\xfa\x38\x8a\x01\xe0\x06\xc5\xfe\x78\x4a\x37\x88\xd3\x9f\xf1\x5b\x81\x67\x8d\xa7\x78\x7e\x4d\x1f\x65\xc7\x9f\xd1\x8c\x17\x95\x7b\x8d\x8b\x7d\x9c\x6f\x9e\xd3\x38\xfb\xe3\xc2\x12\xf0\x92\x27\x59\x59\x58\x1d\x62\xd0\xd3\x6b\x3c\x9f\x4a\xac\xe3\x6c\x5e\x5a\x98\xe2\x70\x2a\xf6\x7a\x13\x7d\x61\x84\xbd\x4e\x76\xfb\xd2\x4a\x1c\x63\xbd\x8f\xf3\x78\x5d\xea\x3c\xba\x1b\x79\x79\x8d\xec\x58\x22\xc9\xd6\xe9\x69\x93\x64\x3b\x6c\x74\xb1\xd6\xd9\x46\xe7\x45\xb4\xbc\xa5\xcf\x0e\xf1\x2b\x69\x8e\x54\x67\xbb\x72\x8f\x4b\xfd\xea\x17\x87\xa4\x15\x57\xf8\x0b\x62\x6c\x4f\x9b\x9d\xc6\x36\x5e\x97\xc7\x3c\x5a\x7e\x26\x84\x8d\xde\xc6\xa7\xb4\x64\x61\x0f\xc7\x8d\x26\xc5\x2b\x53\x45\xcb\x3b\x5a\xc6\x54\x5a\xf9\x1a\xb8\x51\x34\x5b\xf5\xfe\xad\x22\x28\xac\x22\x03\xd3\xf8\x51\x66\x15\x5d\xaa\xab\x55\x04\x80\x7f\x68\xa1\x5d\x7a\x09\x03\xfb\xe2\x11\x8f\xf4\x6a\x86\x9e\x01\xf5\x40\xa3\xa2\x3f\xfb\x4c\x19\x18\x03\x43\x9b\xda\xa7\xf6\xbf\x19\x79\x0e\xa3\x8c\x51\xa6\xc2\x0b\xb1\xeb\x0d\x14\x3d\x33\x30\x58\x45\x02\xca\x4a\x2e\x95\x82\xb4\xe2\x02\xc2\xbe\x53\xa6\x47\x32\x2b\x94\x52\xa4\x2b\x04\xad\x83\x1d\x69\x89\x1d\xed\xc4\x8e\x56\x2c\xa1\x04\x3c\x27\x0d\x21\x56\xb5\x38\x24\x8b\x72\xaa\x5e\x42\xe1\xca\x41\x28\x48\x21\x2d\xbb\x97\xea\x01\xb8\x5f\x45\x90\x4a\x29\x21\x45\xf3\x5b\x04\x92\x59\xd9\xaf\x56\x91\x21\x69\x66\xcd\x9f\xc0\x2a\x24\x3f\x0b\xcf\xfa\x77\x7f\x21\x95\x64\xf4\xd5\x2a\x52\xc4\x95\x84\x74\x8c\xf5\xfd\x5a\x55\xab\x0f\xc0\xf6\x63\x45\xa4\x81\x11\xf4\xa9\xc4\x13\xe6\x44\x95\xa1\xb7\x6c\x2e\x81\x6b\x2c\x18\x5b\x0a\xa3\x8c\x14\xa1\xb1\xc2\x69\x93\xc7\xc0\x3b\xbc\x0b\xd4\xf6\x77\x6b\x66\x0d\xd2\x9b\xec\x77\x7f\x5a\x04\x76\xcc\x54\xcd\x14\xfd\xa3\x4d\xe9\x9f\xe1\xb7\xf5\x6e\xb3\xf6\x17\x53\x76\x6e\x07\x0f\x9c\xa7\x81\x3d\x6c\xd0\xd3\xe0\x3c\x6d\x50\xd7\x4a\x5a\x22\x8d\x23\x56\xcc\x79\x02\x41\xe6\x93\x30\x8a\xf7\x20\x27\x1b\x04\xa2\xbd\x40\x2e\xf2\xe4\x3c\x85\x07\x32\x03\x85\x90\x12\x3d\x41\xe3\x24\x10\x04\x21\x57\xd1\x93\xf5\x03\x31\x0f\x54\x59\x08\x08\xa5\x1c\x44\x0d\x32\xa4\x0a\x8d\xa6\x41\xce\x0c\xd2\x42\x2f\x48\x01\xe1\x80\x86\x54\xe1\xa0\xe3\xfd\x89\x13\x8b\xc2\x9e\x0c\xa1\x98\x13\x0a\x4b\xb7\x87\x39\x2b\x11\x21\x1a\x16\x8d\xdd\x19\x60\x89\x84\x9c\x24\x91\x03\xb2\xa1\x4f\x40\x4c\x08\x41\x2b\xce\x4c\x06\x52\x09\x2f\xda\x38\x47\xca\x09\xe2\xa8\x69\xf9\xcd\xc2\xfb\x8d\x7c\x97\xdf\x40\xe2\x91\x81\x28\x3d\x71\xb6\xa8\xc9\x3a\x6f\xb5\xc0\x01\x83\xcf\xec\x64\xaa\xd5\x1a\xc1\x32\x1b\x89\x9d\x81\x85\xdd\xf0\xe6\x10\x63\x1f\x62\x9a\xee\x71\x0f\xce\x57\x6c\xc6\x2a\x17\x36\x2b\xd4\x58\x36\x18\xc8\x10\x9d\x4c\x52\xeb\xe6\x4a\x80\xdd\x33\xdc\xfb\x01\x0f\x95\x5c\x14\xe4\xbd\xc1\x05\xde\xc9\xbb\xdd\x15\x7b\xad\x33\xba\x4f\x87\xb6\x62\x55\x7b\x56\x63\x3b\xd7\x2a\x07\x07\xf2\x43\x46\xa4\x7a\xf6\xe4\x0c\x87\x4b\x36\x9d\x15\x51\xa9\x6b\x56\xad\x6d\xb5\xda\xa5\x11\xba\x8b\x75\x69\xc9\x9e\x5c\x7b\x02\x9c\x27\x98\xc1\x20\xab\xd9\xac\x23\xc1\xe5\xab\xee\x93\x51\x07\xaa\x13\x11\xfc\x67\x02\x90\xae\x12\xd2\x6a\x1b\x64\xca\x56\x5e\xa7\xd4\x39\x89\xc0\x19\xad\x52\x24\x9c\x08\x57\xed\x54\x60\xb9\xb3\xf9\x03\xc6\x19\xd4\x3e\x71\x25\x99\xd7\x8c\xa9\xa6\x7a\x81\xe0\x81\x0c\x10\xe8\x68\xc9\x9e\x14\xf6\x9e\xda\x9a\x23\xf7\xca\xb0\x1d\xc7\x38\xe2\x56\x09\x4d\x46\x94\x9b\xbc\xc7\xfc\x41\xd6\xaf\x6b\x3c\x5c\x8d\xf7\x13\xdf\x07\x8c\x16\xb0\x3a\xeb\x1b\x9f\xda\x67\xae\x8b\x01\x5c\x23\x33\x29\x59\xfb\x2e\xd0\xee\xee\x1b\x29\x67\x6c\x50\xda\xa7\x27\x92\x3c\xc3\xaa\x26\xc7\x38\xf2\xa6\x99\x75\x26\xfe\x95\x3a\x5b\x19\x29\xd2\x38\xed\x5b\x5b\x39\x72\x17\xc0\xc2\xd1\x2c\x45\xe5\x9d\x35\xe3\x0d\xca\x3b\xed\xa4\xb7\x9e\xf4\xd6\x83\x34\x1e\xd7\x67\x03\x09\x8f\x35\xac\x62\x4f\xf6\x6f\x85\x8a\xa4\xc2\x76\xa6\xfd\x18\xcd\x02\xe0\xcf\xde\xef\xe1\xc3\x12\x89\xb9\x93\x48\xd4\x05\xe0\x3d\x12\xc1\xf9\x83\xe1\x5c\xce\x1c\x99\x09\x79\x49\xd1\xfe\x4f\x37\x37\x0b\xbb\x88\xc6\xc9\x5d\xc4\x94\x50\xa9\x27\x72\x24\x2f\xf5\x04\x6f\x77\xe2\x4b\xc1\xb9\x50\x19\x07\x9a\x64\x7e\x0e\x15\x8f\x84\x96\x37\xd3\x21\xc3\x81\x41\x48\xee\x7b\x24\xe5\xf6\xd1\x8a\x4b\x71\x05\xe9\xea\x7f\xd0\xdf\xc0\x17\xac\xdf\x29\xd1\x49\x7a\x32\x14\x7b\xc3\x40\xf4\x64\x3a\xe9\xd3\x5a\xb7\x49\x7d\xb2\x4f\xfc\x8e\xa5\x9e\xc1\xf7\x27\xa6\x6e\x26\x94\xcf\x47\xd4\x87\x54\x9d\x88\x13\xdc\xf5\x26\xa8\xba\x93\xb0\x37\xea\x97\xc0\xa7\x59\xd3\x33\xb8\x5a\xd0\x94\x00\x74\x56\xb4\xc6\xe4\xec\xdc\xff\xeb\x37\x1b\x3a\xa1\x9d\x9d\xcd\x86\x7a\xb7\xb0\x51\x04\x09\x31\x72\x90\x6e\xa9\x4d\x1d\x0f\x7c\x13\xef\x52\xe4\x65\x1d\x23\xd7\x83\xe1\xef\x1e\x35\x73\x3e\x4f\xe6\x75\xa7\x7d\xc5\x7c\x2d\xc6\x0a\x1c\x9a\x3d\x5e\x70\xa6\x70\xd2\x54\x45\xd2\x0c\xf5\x82\x0a\x41\x3d\xe4\x26\xc4\xbc\x5b\xa5\x11\x49\x7c\x03\xa8\xc4\xa8\x24\xd5\x7a\x53\x7b\x6b\xd3\xa1\x83\x4b\x9e\x55\xbb\x33\x7f\x87\x55\xbc\x9a\x82\xaf\x33\x38\x05\x4d\xb6\x0a\xfc\xfd\x17\xcc\xb0\x79\xfd\x41\xa4\x75\x73\xe6\x3e\x08\x1c\x8a\xb9\xf7\xe7\x19\x85\xc1\xd8\x11\x2e\x76\x02\x51\xbd\xa4\xbe\x51\xf3\x5d\x09\x57\xa3\x7b\x66\x2c\x08\xd8\x90\xed\xbe\x2b\xbd\x01\x11\xbb\x21\xe5\x8f\x5b\x96\xe6\x80\xa0\x27\x34\x48\x6a\x10\xd5\x20\xab\x8b\xd6\x6b\x46\x85\x0f\xb1\xdf\xeb\x0f\xcd\x73\x89\xa1\xc3\xd1\xb9\x4a\x36\x4d\x22\x17\xa5\x58\xb4\x3a\x12\xe3\x3a\x92\x8f\x7b\x28\x82\x56\x95\x33\x55\x3b\xc8\x94\x6f\xcf\xe7\xaa\x8a\x93\x6a\xeb\xa1\x70\xaf\x87\xfa\x92\xc6\x54\xb7\xa1\x66\xe0\x46\x07\x3d\xb5\x04\x2a\x88\x55\x2b\xb8\x99\x12\x9d\xc3\xc7\x84\xf3\x09\x26\x04\x1a\x2f\xc3\xc3\x45\xb7\xd7\x05\xab\x52\x58\x23\x86\xa0\x21\x6e\x13\xba\x8d\xd3\xb5\x12\x77\xea\xdc\x62\x12\xe0\x03\x07\xa7\x68\x34\x9a\x6d\x2b\xbd\x8b\xb3\xa1\x8c\xd6\x31\xb7\xe2\x12\x2d\x82\x3b\x86\x01\xab\x85\xd7\x24\xfe\xd6\x5c\x20\xb8\xb1\x70\xd7\x81\xe1\x6d\xc9\x58\x5e\x69\x64\x98\xce\xf5\x47\x05\x46\x87\xcc\xe6\xb6\xe1\x2d\x08\xf5\x0b\xc2\x50\xc3\x20\x5c\x7f\x30\x3c\x74\x5d\xd8\x65\x66\xc5\x09\x77\xf8\x9a\x62\xfc\x78\xda\x06\xea\x39\xde\x4e\xee\x70\x1d\x10\x1c\xd0\xaf\xf5\xdc\x15\xd0\xaf\x34\x26\x1d\xa0\x8f\xe4\xce\x2e\xd0\x47\xc3\xbe\xbb\xbf\x81\x4b\xb9\xe6\x9e\xab\x5c\xf0\xc4\x90\x44\x9d\xd3\xe0\x2a\xfa\x33\x00\x00\xff\xff\x1c\xdc\xe5\xe3\x81\x1d\x00\x00")
+
+func fontsDoomFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsDoomFlf,
+ "fonts/doom.flf",
+ )
+}
+
+func fontsDoomFlf() (*asset, error) {
+ bytes, err := fontsDoomFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/doom.flf", size: 7553, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsDotmatrixFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xdc\x5c\x4b\x6f\xdc\x38\x0c\xbe\xcf\xaf\xe0\xc1\x07\xe7\xb0\x69\x9b\x62\x81\xdd\xdb\x00\xfb\x23\xf6\x48\xa4\x6d\x02\x04\xc8\xa6\x40\x1e\xfb\xf8\xf7\x8b\xd8\x7a\xf0\x25\x4b\xb2\x25\xcf\x4c\xa6\xc9\x34\xf9\x2c\x53\xa4\x48\x91\x14\xe9\xc9\xfd\xe3\xfd\xcd\xed\x00\x5f\x3e\xbf\x7f\xdd\x7c\x85\xcf\xf0\xf5\xf0\xe3\xe7\xeb\x5f\xb7\xaf\xcf\x0f\xff\x5e\xdf\x3f\xde\xc3\xb7\xff\xe0\x8f\xb7\xe7\xd7\x87\x17\xf8\xf3\xf6\xe9\xe9\xee\x19\xc6\xef\xff\x4c\x3f\x1c\x6f\xbf\xbf\x5c\x7f\x7b\xbb\xbe\xfb\xf1\x76\x75\x78\xbc\x7d\x79\x85\xe7\xbb\xbf\x1f\x5e\x1e\x7e\x3e\xc1\x2f\xf0\xdb\xa7\x9b\x2f\x9f\x7e\xff\xf5\x70\x80\xe9\x35\xf8\xd7\xfc\xeb\xf1\x83\xc1\x1e\x07\x18\x00\x61\xf0\xbf\x10\x78\xc4\xab\x6e\xb0\xfb\x56\x70\x15\x27\x29\x22\x14\x76\xf8\x00\x80\x30\x7d\x0f\x74\xf8\x00\x23\x5e\x4d\xdf\x9b\x60\x3a\xf5\x69\xe0\x77\x7c\xfa\x11\x21\xbc\x0f\xf3\xf0\x77\xf8\x9d\x67\xff\x1e\x60\x9c\x00\xff\xee\xe1\x11\xaf\xe8\xd7\xca\xd1\x89\x29\x93\x30\x7d\x2d\xc0\x04\x47\x72\xc1\xc3\x9e\xbb\xe9\xa2\x87\x91\x32\x18\xe0\x11\xaf\xcc\xd1\x40\x47\xa3\x49\x7b\x92\xd3\x18\x4d\x39\xf1\x22\x0a\x06\x85\x40\x29\xd8\xaf\x78\x14\x52\xae\xf8\x0c\x92\x15\x0f\x30\x3a\x4e\x18\x71\x74\xb7\x30\x18\x03\x8b\x04\x76\x20\xd2\x29\xc3\x48\xae\xe4\x70\xbb\xd2\x7d\x85\x36\xdd\xda\x06\x49\xdd\xf0\xa8\x37\xe4\xf0\x8c\x08\x79\xa2\x26\xd8\x5a\x79\xab\x45\xbe\x56\x8e\xf3\xf7\x0b\x74\xad\x28\x6d\x34\x69\xf3\xd1\xa6\x98\x16\x1c\x3c\xb0\x17\x94\x6d\xe5\xd9\xab\x28\xa7\x92\x86\x21\xf0\xc1\xe1\xb0\xa7\xc4\x68\xf2\x43\x57\x58\xe0\x68\x0c\x9f\xb4\x21\x61\x34\x19\xf7\xc6\x55\x0c\xa3\xc9\x61\xf0\x56\x8a\x71\x83\x93\x4a\x31\xd1\x1c\xee\xbc\x84\xad\xb6\x2a\x56\x6c\x18\xad\x25\x34\x4d\x22\xb1\x56\xe5\x62\x2e\x6c\x65\xbf\x5d\x91\xc1\x64\xaf\xb1\x38\x13\xf7\x5a\x49\xe4\x40\xb7\xd7\x14\x6d\xbf\x2a\x6b\x22\x47\x3e\xa0\xa4\x86\xa3\x09\x6b\xdf\x89\x2c\xfe\xe4\xc5\x34\x89\x2c\xc1\x1b\xc5\xf4\xbf\x90\xff\x77\x82\x2d\xaf\x17\x22\x56\x21\x6c\x7a\x3d\x97\x91\x95\x1a\x6d\x0d\x8c\x40\xbf\x8a\xb4\xb9\x75\xca\x62\xf8\x23\x68\xb3\x60\xca\x80\x87\x17\xb2\xe1\x1e\x9c\x4d\x80\xc3\x21\xb7\xa1\x70\x4c\x78\x08\x4c\xc0\x08\x33\xd0\xc3\x02\x74\xb0\x04\x35\x83\x19\x98\xe0\x34\xe3\x0b\xac\xf8\x3c\x00\x29\x4c\x73\xaf\x08\x13\x5e\xe8\xa2\xd4\xc1\xd1\x87\x31\xda\x00\x34\xc7\xda\x24\x26\xc9\xdd\xe3\x70\x04\x4b\x11\x6c\x46\x46\xbc\x01\x1c\xdc\xb5\x31\x65\xb8\x61\xad\x98\xc8\xd4\xe9\x2c\x88\x10\x8f\xb6\x4c\x79\xb3\x6c\x39\x2c\x0d\x5f\x42\xcd\xa1\xb5\x84\xf4\x90\xc3\xa6\xe4\x27\x97\xb5\x62\x22\x17\x34\x6e\x14\x72\x86\xb2\x36\xca\xf4\x8b\xd8\xb2\x7e\x87\x31\x58\x10\xa1\xa6\x43\x88\xb8\xcc\x5d\x13\x11\x52\x6e\x31\x5a\x90\xda\xf4\x58\x42\x11\x02\x46\x76\xf4\xa5\x8b\x82\xcc\x12\x8b\xf4\x93\xb0\xce\x6d\x46\x8b\x52\x9d\x4b\xac\x08\xab\xb2\x46\xdb\xee\x9a\xd9\x32\x9a\x30\xa5\xcd\xa5\x6f\xb4\x37\x2d\xa3\x65\x76\x4b\x60\xe9\xf5\xa3\xef\x64\xe2\x07\x98\x19\x7e\xd6\x01\xf7\x13\xb3\x4a\x9b\xf1\x85\xd6\x46\x41\x8b\x15\xba\x30\x6c\x09\x15\x87\xe9\x25\x2c\x92\xa7\xbb\x0b\x4a\x79\x8f\x26\x44\x9a\xb9\xa0\xcd\x01\xa5\x60\x5b\xd9\xb1\x40\x64\x58\x54\x46\xd0\x62\x66\xe4\xc9\x89\x79\x92\x74\x74\xff\x9c\xf6\x82\xc5\x2c\x3c\x88\xb1\xb3\xcb\x5c\xf8\xe0\x70\xa8\x06\x11\x18\x09\x1d\x0f\x23\x3b\x10\x7b\x98\xa6\x6e\x9c\x48\xb8\xa2\xa6\x8c\xd5\x20\xc9\xa0\xe6\x04\x4c\xda\x1c\x3e\x76\x3f\x58\x9e\xc5\x31\x34\x2a\xc2\x5a\x95\x96\x8a\xd8\x6e\x12\x25\x6a\x5b\xd0\xa6\x9f\x32\xb6\x05\xc0\xc1\xc4\xd5\x92\x02\x33\x8f\xec\xba\x08\x8c\x06\x8c\xbc\xfd\xe1\x60\x59\xf4\x89\xa3\x2d\x38\x35\x1a\xcc\xd1\x5a\x9b\x49\x31\x49\xd0\xa3\x75\x74\x57\xbc\x13\xf2\x8c\xae\x8e\xce\xcc\x70\x86\xdd\x0d\x05\xa3\x09\x6d\x56\xba\x07\xc3\xc4\x6b\xc5\x04\xbe\x86\x2c\xfe\x60\x68\x2e\xd0\xd8\x36\xc6\xda\x23\x4b\x26\xfc\xaa\xf3\x28\x6b\x84\xd3\x85\x7c\x99\x58\x4a\xf1\xd9\x4f\xf3\xcd\x61\x9d\xec\x01\xe4\x92\xf1\x85\x7a\x00\x8b\xed\xed\x72\x5a\x99\x03\x9d\x38\x0b\x32\xe6\x2c\x81\xb3\xba\xef\x90\xba\x33\x56\x4c\xe2\x23\x29\x05\x95\x29\x79\x11\x96\xba\x9f\xd9\x60\xc9\x5e\x23\x6d\x56\x9f\x37\x0d\xe2\x51\x11\x12\xb6\x2a\x47\x59\x22\x3d\x8a\x24\x67\x25\x66\x39\x5c\x2b\x66\xc3\xbd\x69\xac\x95\x10\x36\x47\x64\xd5\x31\xa7\x48\x4c\x5a\x7f\xaa\xf2\x35\x79\x0e\x9b\x44\x8e\x46\x01\x25\xa1\xcd\x25\xff\xa6\xcc\xb0\x19\xdc\xb5\x4e\x6b\xd8\x9b\xa6\xcf\xa9\x24\xe6\x2c\x84\xd1\x84\x7d\x12\x24\x47\x37\x39\x56\xe7\x8c\x56\x9a\x21\x18\x75\xcd\x31\x3c\xfd\xc3\xe6\xa4\x5b\x5b\x8c\x06\xad\x36\x1a\xab\xf2\xdb\x67\x8b\x98\xc6\x9c\xfb\xc2\x5d\x03\x4a\x78\xa9\x94\xc4\xd0\x26\x75\x9f\x74\xb4\x6f\xca\x2b\xdd\xd3\xf7\xd3\xb9\xa0\x9c\x98\x72\xce\x90\xb5\x4b\x56\xdc\x05\xcd\x61\x78\x06\xcc\xb0\xce\x1d\x3d\x6d\x93\x02\x66\x13\xb8\x67\x01\x53\x26\xb5\xc1\xed\xd5\x1d\x2e\x72\x27\x14\x30\x89\xc0\x6a\xb8\x56\xcc\xfe\xda\x44\x13\x26\xee\x59\x68\xd3\xef\x18\x1d\x50\xa8\x92\xeb\xc4\xac\x3a\x6f\xae\xcf\x82\x38\xed\xfd\x03\x4a\x23\x6d\x9a\x44\x94\xe9\x6b\xaf\xb7\xd7\xde\x5c\xd1\x2a\xea\x97\xec\xd5\xc2\x55\x62\xc6\xd7\x5e\x2e\x35\x01\xf7\xd5\x26\x93\x72\x65\x08\x0f\x4f\xf8\x31\xdd\xfb\xf1\xdc\xd3\xf2\x94\x81\x72\x18\x1e\xfc\x93\x8c\x6f\xd5\x26\xcf\xf5\xbc\x36\xb9\x13\x0f\x4b\x9b\x81\xd1\x82\x91\xa6\x0d\x01\x0e\xf9\x12\x85\x31\x48\x4f\xb5\x19\x27\xed\xa2\xcd\xa4\x7e\xd0\x7c\xfc\x29\xa5\x88\x16\x55\x50\xb6\xb0\xe7\x29\xe6\xf9\xb8\xa0\x33\x69\xca\xf7\x7d\x2e\x28\x36\xae\x58\x9f\x70\xa0\xf5\x7c\x0e\x83\xbb\xaf\x0b\x5c\xce\x49\x90\x64\x19\x36\x02\x0a\x18\x46\xcb\x17\x4b\x5e\x60\x46\x6b\xc0\xfc\x02\x5b\x71\xb9\x37\xd5\x05\xa5\x9f\x1d\xb5\x19\x26\xec\x01\x93\x1e\x54\x53\x6d\xc6\x0e\x64\xb8\x74\x3c\xb0\x0e\x24\x02\x6f\xe3\xd2\x8c\x54\x7d\x24\x26\xf0\x7e\x3c\xc1\xf3\xc1\xe9\x36\xae\x84\x61\xfe\x10\xd2\xd9\xc3\xa8\x5c\x27\xc2\xf1\x20\xbc\xd5\xfc\x15\x9f\x3d\xa0\x4f\x3b\x78\xe5\x8b\x4f\xd5\x64\x61\xa7\x65\x05\xcf\xb8\x86\x01\xcc\xd1\x1d\xe0\xca\xad\x2c\xcf\x33\x0c\x16\xa7\x36\x35\x9a\x85\x1f\x34\xb3\x54\xde\xf7\x6b\x7d\xde\x54\xae\x56\xa6\x58\x0a\x6e\x52\x6b\x48\xc0\xe5\x25\x88\x5a\x31\x4b\x87\x87\xc8\x6e\xd5\xe8\x71\xb9\x4d\xa8\xd7\xca\x86\x6b\xeb\xff\xeb\xc4\x2c\x8a\x56\x66\x3b\x47\xda\xe1\x4a\x6d\xf6\x6b\x15\x15\x0f\x3f\x30\x21\x4b\x8c\xb6\xa0\x76\xa2\x4e\x73\x99\x12\x44\x9e\xc1\x65\x31\x25\xe3\x33\x68\xec\x08\xde\xcd\x31\xdc\x84\x20\x62\x24\xaf\xcd\xe0\x7a\x31\xcb\xa9\x18\x89\xfe\x89\x8c\xb6\xec\x49\x85\x73\xf4\xb4\xe5\x70\xb1\x7a\x28\x9e\xcc\xba\x35\x6c\x74\xdf\x83\xa0\xc5\x44\x92\xb4\xc7\xae\xfd\x4d\x22\xaa\x3e\x2e\x68\xd8\xdc\xc9\x90\x8e\x6d\x9b\x60\x37\x93\x38\xc9\xf3\x4f\x79\x2f\x2c\xf8\x5a\xa3\x65\x37\x51\x58\xcd\x39\xa9\x46\xab\x8d\x36\x9c\x24\x11\x7d\x6c\x73\xf7\x9b\x95\x09\xcd\xa0\x86\x77\x31\xc3\xf3\x33\xda\xcc\x70\x1a\x37\x65\x6c\x73\xfa\xd1\x59\xaa\x78\x6f\x07\xef\x22\xe6\xa5\x7a\xda\x62\x31\xed\x9c\x76\xf5\x13\x7e\x02\x2e\x8b\x84\xfd\xc5\xcc\xf7\xcf\x10\x2c\x31\xb5\x2d\x9b\x30\x3b\xa0\x68\xda\x60\xd2\x86\x65\x78\x9d\x36\xf3\xfd\xb3\xf5\x62\x9a\xa7\xd3\x6c\x4e\x9b\x81\x57\x6a\x93\x08\x2b\x39\x54\xac\x08\x6f\x4d\x60\x6b\xca\x3a\xb8\x94\xef\x3d\xb4\x59\xd3\xf6\xa4\xb4\x47\xec\xf0\xf9\xcd\x64\xe5\x55\xc3\xec\xef\x02\x99\x9e\xb6\x80\x88\x4c\x33\x28\x2c\xf7\x26\x10\x51\x97\xe5\x69\xeb\x82\xdc\x8b\x8a\x19\x65\x61\x62\x56\xc3\x51\x95\xf4\xf4\x13\x17\x70\xa7\x80\x22\xf3\x42\x9c\x60\x51\x88\x9f\x74\x41\x18\x8f\x20\x65\xbc\x4d\xbf\xa9\x8f\x98\xb0\xaa\x1b\xaa\xdb\x9e\x51\x65\xa2\x91\xe9\x54\x26\x8c\x96\xa6\x40\xfb\x65\x41\x44\x48\x96\xa3\x83\x8e\x05\x69\xfd\x58\x6d\xcf\xf9\xee\x51\x54\x41\x95\x8d\x7f\x5c\xa3\xd5\xc7\x1c\x34\xff\x14\x86\x0c\x60\x8d\x03\xca\xb2\xd3\x47\xe3\x60\xc9\x9e\x4b\x0d\xb4\x27\xac\x4b\xc9\x6b\x20\xdc\x0f\x71\xf8\x00\x31\x1c\x0a\xd8\xf3\xc7\x60\x34\x61\x72\xac\x2a\x21\x12\xdd\xad\xe4\x04\x4c\x4e\xfc\x6b\x11\x0e\xe2\xcf\x6d\x94\x41\xae\xca\xfc\xa1\xad\xcd\x70\x57\xda\xaa\x87\xa2\xe1\xa8\x08\x6b\xc5\x49\x22\x6e\x2d\x6d\x0a\x36\x14\x41\x5a\x96\x19\x22\x71\xc3\x69\x4e\xf2\x6a\x5b\xd0\xe6\x42\x9f\x30\x4a\x2f\xfe\xe4\x5f\x0c\x05\xa2\xbf\xe9\xf9\x39\xbb\xfe\xa6\x17\x03\xc0\xec\x5c\x98\x7f\xac\xe3\xd2\x3e\x08\x58\x20\xa6\x11\x94\x9b\x3c\xc8\x58\x07\x6f\xcb\xe8\x65\xea\xce\x15\x41\xe5\xbc\xe8\x47\xf9\x16\xc5\x54\xea\x54\xda\x64\xa3\xdb\xb4\x71\xfd\x3d\x3d\xda\xb8\x95\x46\x7b\xb1\xb5\x20\x2e\x25\x59\x43\xc6\x52\xb0\x65\xb6\x36\x92\xf1\xb3\x3c\x88\x19\xff\x8e\x87\xff\x03\x00\x00\xff\xff\xd5\x8f\x77\xd0\x99\x5b\x00\x00")
+
+func fontsDotmatrixFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsDotmatrixFlf,
+ "fonts/dotmatrix.flf",
+ )
+}
+
+func fontsDotmatrixFlf() (*asset, error) {
+ bytes, err := fontsDotmatrixFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/dotmatrix.flf", size: 23449, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsDrpepperFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x56\xdd\x6e\xe3\x36\x13\xbd\xe7\x53\x1c\xe4\x33\x3e\xed\xa2\x89\x98\x68\x93\xa0\x5d\x08\xaa\x8a\x76\x0b\xf4\xae\x40\x7b\x49\x60\xc2\x58\x94\x2d\x54\x96\x02\x89\xee\x6e\x00\x3e\x7c\x41\x52\x92\xf5\x67\xaf\x01\x5b\x7f\x3c\x1c\xce\x9c\x19\x1e\x4e\x5e\xe6\x91\xdc\xe0\x09\x8f\x88\xee\x71\x8f\x87\x67\xf6\x7b\x5d\x69\xe0\x33\x7e\x6b\x42\xfc\xa9\xde\xde\x54\x83\x0f\x32\xd7\xaa\x81\x44\x25\x0f\x0a\x45\x85\xba\x52\x68\x8b\x1d\x32\xfb\x50\x54\xd0\xfb\xa2\x45\xab\xdf\x4b\xf5\x31\x64\xbf\x1c\xf5\xbe\x6e\x3e\xe3\x8b\x6a\x6a\xfc\x2d\x0f\x87\xa2\x52\xd5\x2d\xf4\xc3\xd3\xfd\xa7\x87\xa7\x74\xbb\x0d\xf5\x51\x87\x79\x11\x32\xf6\xeb\x5e\x36\x72\xab\x55\xd3\x22\xf8\x5f\x00\x59\x65\x08\xfe\x1f\x40\x36\x0a\x65\x7d\x6c\xdf\xdd\x97\x3f\x82\x03\xaa\x5a\xe3\x5f\xd5\xbc\xa3\x95\xba\x68\xf3\x42\x65\xec\x6b\xa1\xf7\xd0\x7b\x85\x60\x13\xa0\x6e\x10\xe8\x20\x0c\x43\xfc\x75\xdc\xed\x54\xab\x8b\xba\x6a\x7f\x66\xec\xcb\xb7\xb7\x52\x56\xd2\xbe\xa2\xce\x91\x17\x4d\xab\x51\x16\x95\xfa\xcc\x6c\xe8\xb8\xc3\xcd\x41\xee\x8a\x2d\xaa\xe3\xe1\x55\x35\x37\xc8\xeb\x06\x79\x51\x2a\x14\x99\xaa\x74\x91\x17\x5b\x3b\x97\x49\x00\xb8\x43\xbb\xaf\x8f\x65\x06\x59\x7e\x95\xef\x2d\x5e\x15\x5e\x64\x70\xeb\xe6\x54\xf5\x57\xb6\xf1\x20\xeb\xd3\xcd\x5e\x36\xd9\x6b\x29\xab\x7f\x6e\x70\x77\x87\xb7\xa6\xa8\x74\x8b\x16\x12\xee\xe3\x2d\x5e\x8f\x1a\x5b\x59\x05\xda\x5a\x69\x0f\xc7\x76\xaf\x32\xf6\xe4\x0d\xec\x55\xb1\xdb\x6b\xeb\xaf\xc4\xb6\x67\x88\x3d\x5e\x18\xbc\x75\x04\x15\xd5\xb6\x3c\x66\x45\xb5\x43\xa6\xda\xad\xaa\x32\xd5\xb4\x2c\xba\xf7\xf3\x0e\xf2\x9b\x0b\x1c\xa5\xaa\x76\x7a\x8f\x0f\xea\x5b\x8f\xde\xd6\x87\x83\xaa\x3c\x2f\xed\x47\xfc\x00\xe4\xc7\x6c\xa7\x90\xcb\xad\xae\x1b\xd6\x19\xc8\x54\x2e\x8f\xa5\xf6\xce\x1e\xea\x4c\xb9\xb8\x5d\xe6\xf3\xba\xd2\xec\xe1\xd9\xc1\x3c\x91\xd6\xbf\x89\x59\xc6\x36\xe9\xf8\x97\x32\x10\x52\x66\x60\x52\x66\x88\xa7\x2c\xa6\x24\x65\x00\xfc\x08\xa5\xcc\x70\xc3\xdd\x17\x4c\xae\xfe\xe6\xde\x37\x64\xc8\xd0\x66\xf4\x00\x18\x98\x1e\x7a\x42\xa7\x0c\xc6\x90\x5d\xe3\x2e\x4e\x19\x27\xbb\x1e\x8c\xe9\x86\xc9\x8e\x24\x1c\xf6\x23\x07\x87\x45\xf0\x38\xe9\x8c\x78\x7f\xac\x8d\x18\x89\xbd\xf1\x50\xf0\x4d\xca\x04\x71\xb1\x19\x63\xac\xc7\xf6\x7d\xf8\xdb\x8b\xb5\x0d\x67\xda\x3a\xd6\x5f\x21\x48\xa4\x29\x23\xb2\x48\x01\xe1\x1c\xb4\x4c\xf8\x2b\x27\x7e\xf2\x9c\xb8\xa0\x94\x25\x40\x6c\xe7\xf1\x09\x0d\xde\x2f\x90\x81\x71\x64\xda\x77\x32\x8e\x06\x5a\xd0\xd0\xfd\x4f\x7e\xf6\xce\x33\x10\xf9\xe9\xe4\x27\x0f\x64\x77\x98\xfe\x62\x41\xe3\x34\x75\xe1\x61\x46\xdd\x64\x76\x67\x1a\x70\x89\x06\xb7\xb7\x17\x22\x0a\x26\xf4\xa6\x8c\xfb\x71\x57\x0d\xe6\x54\x08\xe4\xd7\x04\x92\x61\x85\x98\x88\x92\xe9\x0a\x2e\xb5\xe4\xbc\x88\x09\xc2\x63\xf8\x38\x06\x4f\x35\x78\xe8\xf8\xe7\x04\x84\x03\x4f\x3d\x4d\x63\x77\x1d\x13\x2f\xe4\x8c\x99\x99\xb1\x13\x26\xb1\xb7\xd0\x62\x5e\xd6\x31\xe4\xc2\xbe\x48\x4d\x8c\xd0\x06\xc7\xbd\x1d\x71\x66\xad\xd0\xf3\x06\xcf\x34\x71\xcc\xe8\xf3\x69\x99\x27\x68\x3a\x62\xba\x59\xb3\xc2\x8c\x11\xf7\x25\xc9\xe6\xee\xfb\x82\x58\x29\x8f\x59\xf1\x26\x2e\x04\x1a\x57\x67\x9f\xba\xd0\xa7\xce\x8f\xc5\x94\xac\x16\xc7\x8d\x4b\xbe\xe8\x48\x3f\xcf\x40\x5f\x47\x64\xc6\xae\x8c\x30\xa7\x8c\x9c\xcb\x1a\x7c\xd6\x62\x4b\xc0\xf9\xb5\x84\xdf\xaa\xe6\xbb\xd9\x77\x01\x99\x65\x49\xae\x60\xcc\x22\xfb\xae\xee\xbb\x61\xc4\xc4\xbb\x42\x1a\xd6\xeb\xc5\x10\x27\x6f\xce\x10\x30\x48\xe9\x7c\x07\xb9\x21\x3f\x97\xdc\x55\x0c\xe6\x3b\xe3\xe4\xf7\xa5\x93\x28\x97\x4d\x43\x43\x2d\x8c\xd4\xaf\x13\xd6\x41\x6a\x68\x96\x01\xf4\xfc\x0a\x78\xf6\x30\x72\x75\xc0\x4e\x43\x12\x93\x90\xc4\x99\x9c\x9a\x21\xfa\x85\x70\x4c\xf3\x05\x1b\xd9\x1a\xcf\x6b\x76\xc4\x05\x3b\x8e\x8c\x39\x0b\xe4\x65\xca\xe5\x54\xd0\xaa\xcc\x0c\xbb\x9e\x3a\x2d\x77\xdc\x9f\x24\x66\x25\x9d\xc1\xba\x20\x2e\x31\x86\xe6\xbb\x7e\x84\x1a\x62\xeb\x91\x27\xec\xb0\x59\xed\xf9\x28\xec\x09\xe2\x76\xbb\x4d\x93\x3f\x5c\x04\xce\x56\x9b\xf0\x54\x2c\x42\x70\x8a\x6b\x7a\x35\xea\xc4\x6d\x5e\x10\xfd\x76\x33\xeb\xb5\xe3\x9d\xea\x24\xa4\x77\xc9\x1a\x58\xa3\xbd\x17\xd2\xee\x94\xa4\x61\x67\x5a\x3b\xe0\x76\x62\xcc\x45\x72\xbe\x5d\xb8\x78\xd6\xa5\xcc\x7e\x12\x66\x71\x7a\x8f\x67\x58\xe9\x32\x3e\xe5\x66\x6d\x73\x8c\x2b\x68\x7e\xfa\x8c\xed\x70\x18\x04\xb6\x82\x0c\x85\x13\x0c\x61\x88\x8c\xfb\x6a\x15\xb3\xb5\x66\x76\xc2\xae\x12\x27\x76\x7a\xde\xdd\x22\x06\xe6\x6e\x45\x7a\xe6\x76\xfc\x5a\x61\x1f\x5e\xb0\x1a\xd7\x19\xd5\x89\xbd\xc4\xad\xaa\x8e\x3f\x7a\x46\x8d\x4d\xbc\x30\x3e\x12\x9f\x85\xea\x9c\x95\xb4\x2e\x80\xf0\xb4\x05\x82\x7e\x8f\x2c\xb5\x66\x84\x1d\xed\x25\x73\x91\xd8\xb5\x93\x78\x5a\x3e\x2b\x92\x73\x96\xd8\xbe\x74\x7d\xb1\xf6\x98\xde\x1f\xc7\xdf\x32\x41\xde\xcc\xac\x65\x9d\x35\x7e\x1b\xd7\xf8\x4d\xdb\xde\x95\xc6\x6f\xba\xe0\x20\x80\x6b\x04\x4c\x74\x67\x26\x38\x18\xa3\xa6\xca\xb3\x14\x1c\x0f\x1d\x7a\x04\x9e\x32\x3e\x69\x30\xd6\x9d\x9a\x96\x60\x97\xb8\x53\xa7\xc2\xfd\xf3\xb2\x85\xe1\x4e\x69\xc5\xb8\xb7\x36\x66\xfa\x5f\xf6\x2c\xc6\x66\x10\xc6\x1b\xe6\x63\xaf\xb8\xe0\x76\x16\x17\x1c\x8b\x76\x38\x4e\x28\x4e\xbe\xd3\x8f\xcc\x31\x6b\x67\xd7\x80\xb9\x74\x0e\xf8\xa5\x3b\xe8\xcb\xba\x00\x4d\x30\x17\x6b\x77\xba\xe4\xbc\x04\x56\x7b\x28\x84\xe3\xfa\x7e\xf8\xe9\xf9\xaa\xf8\xa3\x87\xc7\xab\x38\x88\xa2\xfb\xab\x78\x88\xa2\x4f\x57\xf9\x17\x45\x3f\x5e\xc5\x59\xf4\xf8\x7c\x15\x6f\xd1\x53\x74\x15\x77\xff\x05\x00\x00\xff\xff\xe3\x40\x2f\xeb\x45\x11\x00\x00")
+
+func fontsDrpepperFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsDrpepperFlf,
+ "fonts/drpepper.flf",
+ )
+}
+
+func fontsDrpepperFlf() (*asset, error) {
+ bytes, err := fontsDrpepperFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/drpepper.flf", size: 4421, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsEftichessFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x56\x5b\x6b\xdb\x4a\x10\x7e\xd7\xaf\x98\x68\x03\x92\x4e\xb0\x25\x27\xe4\xe4\x78\x5f\x8e\xd3\x92\xbc\xb5\x0f\x25\xf4\xa5\x2a\x2b\x63\x62\x22\xea\x44\x10\x9b\xd0\xc2\xd2\xdf\x5e\x76\xf6\xae\x9b\xe5\x58\x2d\xb4\x74\x0b\xf1\x74\xf4\xcd\xb7\xb3\xb3\x73\xd9\xf5\x66\x7d\xbe\x3c\x85\x4b\xb8\x84\xab\x39\x64\xf0\x5f\x10\xdc\x3d\x94\x5b\x58\x57\x4f\x3b\x28\xb7\x10\xaf\x12\x78\x57\xae\x1e\xee\x37\x70\xb3\xde\x95\x8f\xcb\x2f\xe5\x16\x66\xf3\xf9\x25\x4c\x26\xf0\xf1\xfe\x79\x5b\x56\x4f\x30\x9b\x66\xe2\xbf\x17\xf0\xb8\xfc\x86\x1f\x03\x60\x47\x2c\x00\x48\x0b\x14\x02\xde\xdc\xbc\xb1\x38\xfe\x0d\xaf\xb7\xab\xb2\x9c\x5c\x3f\xef\xca\xed\x2e\x44\x55\x94\xa7\x0a\x11\x08\x8c\x64\x9a\x1a\xa6\xc5\xcb\x66\x5b\x4e\x57\xd5\xa3\xc7\xe3\xad\x37\x55\x95\x4c\x20\xce\xb2\x44\x22\x24\xd1\xdd\xfd\x06\x28\xc4\x17\x17\x09\xcc\xcf\x61\xfe\x2f\x9c\x5f\xc1\x6c\x5e\x77\xa8\xb9\x62\x56\x44\x2c\xd1\x44\x8c\xc1\xed\xf2\x6b\x83\x28\x9b\xd9\xd8\x71\x0c\xc2\xed\x87\xeb\xf7\x6f\x6f\xdc\x88\x02\x3b\x39\x61\xa8\xe0\x3c\x00\x7e\x4c\xac\xed\x5e\x81\xf1\x73\xb1\x5f\x3c\xd5\x6b\xb1\x08\xcc\xbf\x31\xc4\xd7\x3a\x41\xf4\x3a\x48\x1c\xd5\xe3\x31\x56\x1b\x1d\xeb\x11\x58\x43\xe8\xa0\x4b\x73\x25\x70\x99\x81\x00\xa9\xfe\xc4\x21\xd7\x9f\xa0\x26\x58\x0c\xe3\x2e\x5d\x3a\x99\xe4\x35\xba\xdc\x1a\xeb\xaa\xd3\x4e\x99\x7a\xc8\xd9\xff\x5a\xc3\xfd\x1b\x1c\x63\xe9\xbb\x10\x3f\x29\x97\xce\x72\x30\x4a\x8b\x61\xea\x24\x89\x84\xb2\x1e\x0c\x4b\xdc\x9f\x1a\x06\xa6\xce\x5e\xd1\xa4\x67\x2f\xee\xd3\xd5\x79\x94\xcf\xf8\x13\xb7\x63\x98\xf2\x32\x75\xa0\xed\x7b\x29\x82\x56\x9e\xdf\xaf\xd0\x0c\x85\x71\xc7\xd5\xc8\x61\xd1\x8f\xd1\x87\x20\xe4\x53\x11\x15\xd1\x67\x02\x90\x17\xdf\xa3\x54\xa0\xa2\xfc\x25\x2d\x04\x2a\xcd\xff\x11\x15\x42\x08\x2f\xce\x22\x2e\x34\xf8\x49\x68\x10\x2c\x34\xd2\x1c\x99\x08\x07\x40\x54\x5c\x41\x95\x08\x54\x5c\x41\x96\x10\x02\x29\x6a\x72\xa9\xa9\x12\x85\xc9\x34\x46\x6a\x44\xf6\x73\x50\x4c\x8c\x21\x13\xe4\x90\x82\xb0\x23\x31\x4b\xa4\xe7\x31\xd6\x56\xab\x06\xc1\x44\x16\x99\x66\xb2\x27\x0e\xdb\x63\xd0\xae\x09\xc5\x9f\x46\x11\xe9\x1c\x50\x61\x10\xa2\x3a\x07\x02\xa4\x23\x7e\x66\x78\x76\x2a\xc4\xca\xae\xd2\x76\xf2\x90\xd2\x2e\xfc\xe9\xf3\x03\x2f\xb3\xe9\xc4\x5e\xe7\x39\x3d\xa3\xc6\x8e\x5a\x3b\xda\xb4\xeb\xda\x3a\xa2\x2f\xd4\xc4\x8d\x66\x7d\x14\xa0\xdb\xb6\x87\x10\x77\x4b\x79\x5d\xec\xb1\x63\xd6\x0e\xac\x1d\x6b\xb5\x93\x75\x83\x9d\x44\x26\xfe\x22\x30\x99\x3b\x2c\x44\xa6\x18\x9c\x6c\x76\xd2\x71\x48\x88\x3c\x0a\x4a\x0d\x85\x12\x87\x50\xe4\xc5\xd4\x66\x99\xbd\xa8\x9c\xa6\xb4\x9e\x65\xb5\x53\x53\x7b\x6a\x6a\x4f\xdd\x7f\xc1\x43\x2b\x6a\x48\x2f\xfa\xcb\xd4\xa9\x69\xcd\x71\x0f\x7f\xb8\xc6\x49\xea\x81\x1d\xb6\x4b\xe3\x54\x18\xce\x01\x4e\x54\x47\x3f\x58\xe3\x14\x28\xce\x01\x8d\x3a\x5c\xe3\x64\xec\x91\xb1\x1f\xb7\x07\x1f\xeb\x8c\x6d\x12\x62\x0c\x4f\xe5\x18\x56\x9d\x95\x10\x2c\x62\xa1\x51\xed\x9a\x10\xfc\x44\x88\xe9\x0b\x66\xe4\x3b\x8d\x45\x8c\x61\xaa\x07\x33\x36\x66\xa2\x7a\x00\x31\x4d\x04\x31\x99\xc6\x48\x0d\x11\xe6\xc4\x67\x22\xd8\x68\x88\xe9\x1c\x22\x49\xa8\x4e\x9b\x86\x46\x76\x25\x87\xc9\xbb\xb4\xf0\x90\x38\x85\xf5\x4b\x73\x62\x66\x5e\x35\x42\x54\xcf\x12\x04\xe8\xfc\xed\xb4\x53\x2f\x1d\x65\x57\x69\x3b\xf9\xd6\x90\xd8\x70\xb4\x24\x69\xeb\xab\x42\x54\x0f\xb0\xba\x13\x7b\x9d\xc7\x24\xd0\x76\xd4\xda\xd1\xa6\x5d\xd7\xd6\x2a\x7d\x14\x45\xd6\x47\xe1\xd9\xb9\x08\x4e\x79\x8b\xd8\x65\x67\x0f\xa5\x5b\x82\x53\xd3\x9d\x76\x38\xb3\x51\x54\x33\x7b\x60\x88\x4c\x31\x98\x07\xac\xf3\x02\x1d\x16\x22\x8f\x82\x52\x43\x61\xc5\xbd\x14\xaa\x90\xeb\x17\x25\x4b\xc9\xcf\xb2\xda\xa9\xa9\x3d\x35\xb5\xa7\xee\xbf\xe0\x31\x7b\xd1\x9f\xcc\x34\xe2\x00\xf1\xbe\x1e\x31\xbc\x9d\xeb\x1d\xd8\x61\xbb\x34\x4e\x39\x9a\xb7\xf4\xeb\x34\x23\x33\x1d\x13\xe9\x8e\x47\xea\xaf\x15\x7f\x04\x00\x00\xff\xff\x0d\x6b\x9d\x8e\x3f\x16\x00\x00")
+
+func fontsEftichessFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsEftichessFlf,
+ "fonts/eftichess.flf",
+ )
+}
+
+func fontsEftichessFlf() (*asset, error) {
+ bytes, err := fontsEftichessFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/eftichess.flf", size: 5695, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsEftifontFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x57\xdd\x6b\xdc\xba\x12\x7f\xd7\x5f\x31\x2d\x86\xb5\x21\x89\x6c\x79\xbf\x7c\x29\xc5\xbd\x97\xf6\x69\xef\x5d\xb8\xb4\x0b\xe7\x44\xa9\x36\x84\x86\xee\x39\xa9\x0d\xdd\x9c\x43\x1f\x44\xff\xf6\xc3\x8c\x3e\x2c\x59\xde\xdd\x40\x8d\x23\x67\x3d\x3f\xcd\xb7\x66\xc6\x8f\x4f\x8f\xe2\x3e\x83\x05\xcc\xa1\x2a\x61\x29\x60\xcd\xd8\xc7\xaf\x87\x23\x3c\xf6\xdd\x33\x1c\x8e\x90\x3f\x14\xf0\xdf\xc3\xc3\xd7\x2f\x4f\xf0\xfe\xf1\xf9\xf0\xed\xfe\xcf\xc3\x11\xaa\xa6\x59\xc0\xf5\x35\xec\xbe\x7c\x3f\x1e\xfa\x0e\xc4\x4d\x89\x3f\xc5\x0a\xfe\xb8\xef\x88\xca\x40\xfd\xc2\x05\x00\x7c\x4f\xff\x30\x9d\x4a\x4f\x2e\x4d\xeb\xeb\x77\xc7\x87\xc3\xe1\xfa\xdd\xf7\xe7\xc3\xf1\xf9\x35\xbd\x9a\x49\x6e\x11\x0c\x31\x86\xd3\x8d\xe7\xd4\xfe\x75\x7c\x7e\xb8\xf9\xfb\xe9\x78\xb8\x79\xe8\xbf\x39\x3e\xd1\xf5\xef\xbe\x2f\xae\x21\x2f\xcb\xc2\xf0\x31\x8c\x3e\x7e\x79\x82\x7f\x41\x5e\xd7\x05\x34\x02\x9a\x25\x5a\x5e\x35\x63\x85\xd2\x2b\x57\xfb\x99\x2a\x1c\x23\xa5\xe0\xc3\xfd\x8f\x84\x51\x59\x0d\xbe\xd3\xe4\x84\x0f\xff\x7f\xf7\xbf\xff\xbc\x0f\x3d\x0a\xea\xd5\x2b\x45\x2f\xb4\x66\xa0\x7f\xc5\xd7\x83\x2c\x96\xb5\xe1\xdd\x32\xad\x5b\xb6\xd1\x2d\x03\x68\x59\x5e\xd0\x13\x17\xfc\x79\x7b\x77\x7b\x87\xff\x67\x30\xac\x9e\x4c\x08\xa5\x35\xde\x2d\x03\xad\xf1\x6e\xd9\xf5\x46\xe3\x3d\x60\x90\xb6\x81\x96\x71\x50\xba\x65\x52\x81\x6c\xd1\x2b\xbc\x65\xb0\xd1\x83\xac\xbc\xe0\xab\x96\x01\xe7\x08\xe5\x46\x11\xb3\x5b\x11\xb9\x2f\x90\xd0\xef\x56\xc8\xa3\x93\x01\x19\xf1\x2d\x83\xcc\xfe\x19\x96\x8a\x78\xa1\x75\x99\x5d\x40\xca\xb6\x65\xc4\x4c\x4a\x68\x59\x86\x86\xd3\x82\x32\x5b\x76\x03\x57\x2d\x83\x1f\xd0\xb2\x19\xec\x91\x97\x31\xd7\x5b\x8b\xa2\xb4\x56\x80\xda\x03\xd9\x02\x68\x00\x78\xba\x81\x07\x4b\x5e\x64\x2d\xdb\x05\xfe\x74\x6c\x0c\x13\xc3\xe2\xe4\x46\x4f\x41\x53\xc8\x16\xe7\x1c\x08\x03\x41\x06\x01\x07\x34\x49\x43\x09\xc8\x54\x2a\xee\xd4\x32\x0e\x44\xcf\x39\x6b\x33\x13\x6c\x43\x41\xd2\x6d\x0f\xe8\x6d\x9e\x23\x2c\xd2\x4a\x29\x45\xd6\xf2\x96\x29\x55\x48\xf4\x3c\xc5\xcd\xab\x76\x43\x62\xb8\x26\x15\x7a\x7c\x6c\x94\xe7\x30\x48\xd0\x80\xdb\xa2\xd0\x0f\xea\x7b\xbb\x7a\x48\x24\x28\xab\x01\xa9\x00\x06\x07\x83\x03\x06\x09\x39\xd9\x30\xcd\x22\xe0\x0d\xde\x8b\x5e\x81\x21\xf1\x83\xe4\x8f\x5f\xee\xe2\x94\x7a\xf3\xc6\x66\x53\x98\x1e\x46\x59\x13\x57\x74\x80\x8e\xfd\x10\xa4\xdd\xdb\xb7\x26\xe3\xa2\x18\x68\x1b\x03\x7a\x9f\x11\xbb\xbc\xb0\x62\x8d\x8b\xc8\x79\x79\xde\xa3\x6d\x99\x54\x6a\x15\xb8\x60\x94\x04\x3d\x90\x02\xdd\x28\x10\xca\x12\x0b\xf3\x30\xb1\x70\xae\x8a\x64\x51\x76\xe7\x90\xd3\x2f\x99\x04\x94\xf8\x78\x59\x85\x89\x29\x4c\xc8\x32\x9e\x00\xa5\x21\x71\xc8\x09\x8c\x8e\x42\x3b\xd2\x47\xab\xce\xe8\xc3\xa3\xe4\x36\x7c\x3e\x91\xd1\x58\x74\x27\x6c\x27\x84\x76\x8b\xd2\xe1\xe9\x22\x81\x44\xe8\x14\x3d\xe4\xd8\x1a\x0a\xbd\x06\x4d\xf5\x04\x20\x37\x9a\xda\x04\xf0\x18\x23\xc3\x3e\xd4\x94\xc5\x56\x9a\xa6\xf3\xa9\xc3\x7f\x50\xb0\xc7\x0e\x52\x0d\xd8\x6a\x2e\xa5\x85\xca\x01\x99\x04\x3f\x37\x01\x49\x2a\x80\x0f\xbe\x24\x13\xd0\x83\xa9\xb3\x27\xf9\x5c\xad\xce\xf0\x01\x3e\xe1\x0a\x35\x5d\xec\x63\x16\xca\x54\x50\xf4\x18\x3e\x28\xfc\x49\x4c\xad\xe5\x26\xb4\x89\x37\x23\xcc\x6e\xba\xf0\x05\x28\x87\x73\xc8\x6e\xc0\x9a\x23\x8a\xad\xb6\x65\x12\x76\x54\x25\x0a\x30\xf5\xb0\x53\x81\x71\x23\x8c\x04\x3e\xa5\xbd\xb3\xd0\x54\x2b\x3a\x45\xfc\x44\x59\x34\x39\x99\xf9\x15\x51\x54\x2d\x4c\xb9\xa0\xf3\x27\x89\xb9\x94\xa3\x9a\xa6\x15\x50\x49\x1f\x56\xbb\xdb\xd4\x7b\x6a\x91\x19\xa4\x8d\x2c\x79\x84\x75\x0b\x65\xa3\xe4\xa4\x9f\x1a\x24\x50\x2d\x45\x85\xa4\xba\xba\x8b\xdb\x17\x75\x7f\xdd\x53\xc0\xf9\x20\x71\xe8\xd0\xc6\x02\xdf\xed\xa8\xf3\xf6\x94\x25\xe1\x79\xf4\xfd\x0a\x0b\x76\x3e\x2a\x93\xdc\x7a\xec\x0e\x3b\x8d\x8e\xfa\x60\xbc\x91\x34\x50\x45\xac\x1b\x26\xe3\xa6\xd3\xa1\x6e\x58\xde\x83\x01\x28\x7e\x69\x66\x83\x98\x07\x0e\x29\x1b\x2d\x43\x1e\x0e\x1a\xf0\x70\x0e\xb6\xe9\x87\x67\x0a\x65\xab\x4e\x75\xf1\xd9\x75\x30\x03\x22\xc8\x78\x2a\x18\x19\x35\x45\x21\x87\xfb\x61\x2a\xde\xa3\x69\xce\x8a\x29\x8a\xb4\xcd\x52\x6e\xf9\xc3\x0c\xf7\x14\x11\xc5\x3a\xef\xce\x88\x60\xe3\x89\x45\x7f\xd2\x13\xba\x51\x02\xe3\xb0\x06\xbb\x28\xfd\xdc\x2a\x77\x86\xb8\x1b\xc7\xd0\x6f\xe4\x9d\x8c\x37\x9a\xce\x23\x81\x36\x16\x7e\x14\x0a\x13\x19\xc2\x83\x17\x9f\x38\xdf\xbe\x39\x1a\x2e\x87\x89\x70\xdc\x1d\x5c\x8b\x88\x67\x45\x89\x0b\x77\xb3\xa2\x3d\x09\x9c\x54\x49\xc7\xe3\xbc\x50\x34\x4c\x9c\x6b\xc8\x31\x66\xba\x6e\x5b\xcc\xf9\x42\x48\xb6\x6f\xd5\xf6\xcc\xd1\xdc\xaa\xed\x89\x1c\xda\xc2\x76\x22\x82\xc1\x48\xa2\x4d\xa9\x77\x19\x86\xe4\x6a\x59\x26\x1f\x11\xd5\xb2\x72\xf3\x53\x78\x1e\x90\xb0\xf0\x55\x53\xed\x90\xcb\xad\x52\xea\x2e\xa9\x9a\xd5\x72\x19\x7d\x89\x04\x0c\xd6\xfe\x0b\x81\x24\x64\xa6\xa8\x05\xee\xae\xd6\xb5\x4d\x5f\xca\xdc\x51\xd1\xab\x1a\x41\xe5\xf3\xd2\x84\x54\x35\xb5\x9f\x2d\xcf\xe3\xe6\x0c\xf8\xe7\x17\xf0\x5b\x30\xe0\x92\x5f\xc6\x2d\x5f\x94\x30\x55\xb3\x62\x60\x3e\x83\x2e\xe0\xd6\x34\x39\xb9\xd9\xc9\x4d\x58\xbd\x9b\xb1\xba\x20\x81\xec\x8e\xe6\xc2\xec\xa7\x68\x16\x15\x65\x89\x67\xe6\xe2\x6c\x27\xca\x0a\x3d\xf9\x02\x9c\x70\x9e\xbc\x80\xab\x87\xa3\x70\x16\x37\x37\x73\xf9\xe4\xac\x27\xca\x85\xfd\x24\x9c\xa6\x2e\x19\xff\x7c\x7a\xef\xca\xc7\xc8\x8d\x2c\x53\x93\x8b\x28\x1b\x06\xca\x04\xfd\xe2\xe4\x26\xaa\x72\x94\x98\xd3\x55\x40\x54\xd5\x28\x31\x4f\xe1\xc4\x28\x31\x4f\xe1\xea\x51\x62\x9e\xc2\xcd\x5f\x54\xa5\x44\xb5\x62\xa0\xa4\xbc\x34\xb2\x89\x6a\x3d\xa4\xc5\x59\x5c\x33\xa4\xc5\x39\x9c\x28\x5f\x54\x21\x85\xa8\x2f\x95\x34\x21\xe6\xb6\xa6\xc3\x7e\x3f\x5d\x48\x85\x58\xb8\xcf\xd5\xd9\xec\x14\x64\xe9\x7a\xdc\xe7\x13\x93\x92\x10\x2b\x07\xf9\x79\x12\xb2\xbe\x54\xd4\x85\x68\x1c\x97\xed\x29\x2e\x75\x39\xf4\x45\x3b\x0f\xfc\x66\x3a\xc0\x55\x1e\x06\xaf\xae\xd2\x21\xed\x77\x22\x08\x53\x54\x61\xbf\x4f\xc7\x31\x51\xd7\xb6\xa5\xce\x66\x53\xd4\x39\x73\x7e\x98\xa2\x2e\x92\xb6\x14\x52\x97\x34\x83\xa2\xd4\x68\xaa\x12\xf5\x8a\xb4\x44\x81\x23\xc2\x9a\x4c\x98\xa5\x3b\x1a\x22\x6c\xb7\x63\xc2\xbc\xf2\xc3\xc8\xcf\xe9\xd9\x4b\xcc\x53\xf3\x87\x0e\x29\xe6\xa9\xf9\x21\x35\x35\x3f\xa4\x5a\xf3\x49\x74\x4a\x5d\x9e\xe9\xd9\x62\xde\x04\x5a\x8d\xfb\xb6\x58\x94\x81\x56\x29\xb5\x0a\xb4\x4a\xa9\xe2\xcc\x44\x20\x16\xb5\x4d\x7e\x45\xc9\x3f\x31\x84\x89\xc5\xc2\xcd\x69\xc4\x62\x02\xf2\x4f\x00\x00\x00\xff\xff\x10\xe7\x55\x45\x87\x16\x00\x00")
+
+func fontsEftifontFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsEftifontFlf,
+ "fonts/eftifont.flf",
+ )
+}
+
+func fontsEftifontFlf() (*asset, error) {
+ bytes, err := fontsEftifontFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/eftifont.flf", size: 5767, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsEftipitiFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x95\x51\x73\xdb\x36\x0c\xc7\xdf\xf1\x29\xd0\x9e\x6e\x92\xb7\xd8\x12\x29\xc9\xb6\xda\xf3\x8d\xd9\xae\x7d\xca\xf6\xb0\x75\x7b\x89\x62\xca\xf5\xec\x45\xab\x13\x6d\x91\xd3\x35\x1b\x9b\xcf\xde\x03\x49\xc1\x92\xfc\x58\x5f\xe2\xfb\xfd\x41\x82\x20\x40\x90\xde\x1f\xf6\x72\x13\x60\x8a\x12\x17\x98\xe0\x12\xe0\xdd\x6d\xdd\xe2\xbe\xb9\x3f\x62\xdd\x62\xb4\x9d\xe0\x4f\xf5\xf6\x76\x77\xc0\x37\xfb\x63\x7d\xb7\xf9\x50\xb7\x28\x8a\x22\xc7\xe9\x14\x7f\xdf\x3d\xb4\x75\x73\x8f\x62\x26\x48\x8a\x1c\xf7\xbb\xf7\x76\x14\x50\x7f\xc5\x07\x11\xe3\xca\x02\x98\xf3\xe8\x67\x1f\x63\xbf\x5f\x5e\xb6\xdb\xba\x9e\x5e\x3e\x1c\xeb\xf6\xf8\xd2\x9a\xc2\x32\xf6\x33\x80\xe6\xb8\x95\x66\xbc\x92\x7a\x6c\x8f\xdb\xd9\xc7\x43\x5b\xcf\xb6\xcd\x5d\xb7\xce\xe0\xf3\x43\xd3\x4c\xa6\x18\x25\xc9\xc4\xad\xe3\x16\x7a\xb7\x3b\xe0\x2b\x8c\xd2\x74\x82\x85\xc4\x62\x8e\x72\x81\xa2\x18\x6f\xe8\xfc\x13\xe9\x2a\xd4\x93\x6e\x21\xad\xf1\xed\xe6\xd3\xd9\x42\x89\x38\xd5\xce\xd8\x22\xbc\xfd\xe5\xf2\xe7\x1f\xdf\xf4\x2b\x8a\xfa\xc5\x0b\x6d\x0d\xc6\x00\x9a\xaf\xa9\xf5\x29\x16\x04\x81\xea\xfe\x15\x5c\xdf\x28\x88\x26\x0a\x10\x95\x82\x8b\x0b\x0b\x4e\xd0\xfe\x15\xac\x8c\x59\x79\x56\x60\x14\xfc\x4a\xdf\x0a\x9a\x58\x41\xdc\x74\x33\x15\x7c\x43\xdf\x0a\x2e\x14\x04\x8e\x30\x50\x10\x07\x0a\x2a\x0a\x12\xa0\x82\xa0\x54\x10\x84\x6e\xf6\xb7\x7e\x8e\x82\xef\x98\x2e\x98\xa6\x4c\x33\x4f\x14\x0c\x4f\xc1\x12\x9e\x20\x98\x24\x53\xca\x94\x31\xe5\x4c\x73\xa6\x05\xd3\x92\xa9\x60\x7a\xc5\xf4\xda\x51\xac\xa0\x64\xdb\xca\x51\x69\xcd\xde\xf6\xbd\x27\x8d\x0a\xa2\x8d\x2d\x29\xeb\x38\x2e\x07\xfa\xda\x7c\x3e\x69\x05\x51\xd4\x25\xe7\x06\x7b\xce\x9a\x34\x55\xa4\x9a\x0e\x75\x37\x4e\xd1\x8c\x7e\xcd\x67\xe4\x8e\xed\xfa\x66\x6a\xd8\x44\xe7\x4b\xe7\xec\xc6\xed\x69\x1b\xa3\xe0\x5a\x1b\x37\x9f\x46\x29\x0f\xac\xe8\x8c\x0d\x2a\xb8\xd2\x37\xbd\xfd\xfa\x0c\x7c\x0e\x9d\xd5\xee\xb4\x3c\x45\x71\x89\x47\xc3\xc4\x0d\xe5\x72\x65\xc6\xe3\xd5\x28\x57\xab\xd1\x15\x22\xa4\x26\xa1\x4e\x55\x80\xe4\xd9\x4b\x4c\x81\xf9\xcd\x28\xa8\xa6\x76\x0a\x55\xae\x2c\xe3\x2e\x1e\xed\xd3\x59\xbc\xed\xe4\x65\x67\x85\x61\x35\xf0\x0a\x43\xeb\xe5\x92\xd3\xa7\x5d\x07\x0a\x0c\x75\xaf\xd1\xd4\xba\x25\x6d\xa0\xf4\xb5\x0b\x68\x72\x80\x86\x88\x6a\xb7\x3e\xb5\x3b\xba\x3b\xb5\x5a\x29\xdb\xb6\x01\xb7\xc5\x86\xe9\x3d\xd3\x96\xe9\x0f\xa6\x1d\xd3\x9e\xe9\x4f\xa6\x5b\xa6\x9a\xe9\x2f\xa6\x0f\x4c\x07\xa6\x3b\xa6\x7b\xa6\x86\xe9\x6f\xa6\x7f\x98\x1e\x98\x5a\xa6\x23\xd3\x23\xd3\x47\xa6\x7f\x99\x3e\x31\x3d\x31\xfd\xc7\xf4\xbf\x23\xe3\xff\xac\xed\x33\x8f\x3e\x7b\x9a\xcd\x86\x17\x85\x74\xbf\x9f\x48\xf7\xce\x9f\xe4\xa6\x7b\x15\x48\x34\x7d\xf1\x88\xfd\x2b\x65\xe8\xbe\xb9\x36\x14\xf3\x84\x4e\xc7\xfe\x91\x12\xf6\x7a\xd0\x7d\xb8\x32\xd6\xb0\xb4\xfe\x74\x98\xd6\x5f\x2c\x53\xaa\x9b\x3f\x50\x51\x48\xc0\x6a\x78\xa3\x45\x91\x02\x86\x63\x5b\x06\xb8\x1e\xdb\x72\xc0\xe7\xb1\x6d\x7e\x96\xb8\x28\x16\x80\xcd\x78\xde\xd2\xfd\xd6\x5a\xab\x7f\x00\xec\x93\x20\x8a\x82\xaf\x0e\x52\x5d\x64\x92\x00\x56\x9a\x72\xe2\x77\x43\x26\x02\x30\x1c\xdb\x24\xe0\x7a\x6c\x4b\x7d\x9d\xfb\xb6\x0c\x28\xe3\x2b\xe3\x2b\x22\x93\x9c\x22\xf5\x0d\x73\x58\x0f\x67\x2c\x6c\x11\x7b\x86\x02\x50\x3f\x8f\x9f\x0c\x29\x12\x57\xcd\xde\x31\x4b\x21\x5c\x35\x07\x36\xe9\xaa\x39\xb0\xa5\xae\x9a\x03\x5b\x76\xd6\x36\x52\x2c\x5c\x8c\x5e\xeb\x48\xb1\x74\x31\x06\xb6\xc2\xc5\xe8\xdb\x64\x72\xd6\x76\x52\xa6\x67\x3d\x25\x65\x46\xbf\x5a\xfe\xaa\x4b\x99\xd3\xaf\x19\xab\x39\xbd\x13\xac\x16\xd4\xef\xac\x96\xc3\x36\x96\xb2\xa0\xd7\xa3\x1b\x4e\x85\x7f\x2d\x6c\xe0\x54\x52\x90\x5d\x37\x96\x52\x10\x56\x19\x05\x61\x95\xdb\x65\x77\xbc\x6c\x3a\x27\xd7\xba\x1b\x5e\x90\x2b\xab\x25\xb9\xb2\x2a\xac\x6b\xcd\xae\x99\xa0\x0d\xfb\x37\x44\x66\x76\x0f\x4d\xa7\xec\x1e\x58\xd9\x3d\xb0\xca\xc9\x8f\xd5\x7c\x78\x45\x65\x56\xd0\x42\xfe\x51\x91\x79\x42\x0b\xb1\x12\xb4\x10\x2b\x39\xbc\xd0\x32\xb7\x51\x9f\xba\x61\x97\xeb\x53\x37\xfc\x25\x00\x00\xff\xff\x63\xa2\xf8\x2b\xe9\x0a\x00\x00")
+
+func fontsEftipitiFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsEftipitiFlf,
+ "fonts/eftipiti.flf",
+ )
+}
+
+func fontsEftipitiFlf() (*asset, error) {
+ bytes, err := fontsEftipitiFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/eftipiti.flf", size: 2793, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsEftirobotFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x57\xdf\x6b\x24\x37\x0c\x7e\xf7\x5f\xf1\x5d\x18\x18\x1b\xb2\x71\xb6\x70\xa5\xc7\xbe\xf8\x5a\xae\x4f\xd7\x06\x4a\x9b\x27\x73\xda\x10\x2e\xdc\xd2\xe4\x06\x6e\x43\xa1\x60\xfa\xb7\x17\x49\xf6\xcc\x78\x7e\xec\x6e\xe9\x92\xcc\xce\xac\x25\x59\x96\x3e\x7d\xd2\x3c\x3d\x3f\x7d\xf7\xd0\xe0\x7b\xbc\xc5\x76\x8b\x5b\xfc\x60\xcc\xef\x5f\x0e\x47\x3c\x75\x5f\x5f\x71\x38\xc2\x3e\x3a\xfc\x72\x78\xfc\xf2\xf9\x19\x1f\x9e\x5e\x0f\x2f\x0f\x7f\x1e\x8e\xd8\xbe\x7b\xf7\x16\x9b\x0d\xee\x3f\x7f\x3b\x1e\xba\xaf\xd8\xde\xdc\xf2\xe3\x76\x8b\x97\x87\xbf\x65\xd5\x80\xfe\xc7\x07\x80\xdf\xcb\x8d\x49\xf3\xdd\x67\x9f\x24\xd7\xab\xf7\xc7\xc7\xc3\x61\xf3\xfe\xdb\xeb\xe1\xf8\x7a\x25\x3f\xb5\xd1\x67\x09\xc3\x32\x6a\xe9\xa6\xb7\x14\xfe\x7a\x3e\x1e\x6e\x1e\xbb\x97\xca\x4e\xf5\xf9\xb1\xeb\xdc\x06\xf6\xf6\xd6\xa9\x84\x1a\x3a\xf7\x59\x93\xb1\xb4\x6f\xc9\x15\x43\x17\x04\x42\x64\xf0\xf3\x6f\xef\x7f\xfd\xe9\xc3\x38\xa2\xa0\x37\x6f\x48\x7e\x48\xc9\xe0\x12\x4b\x17\xec\x65\x9a\x30\xf9\x0b\x06\x84\x60\x2c\x5c\x30\x89\x52\x7e\xf4\x14\x83\x01\x10\xe4\xca\xeb\xce\x3a\xbe\x6f\x30\xbd\xf6\x42\x50\x49\x80\x73\x4b\x7c\x4b\x09\x49\xfe\x83\x81\x85\x93\xff\x60\x36\x9e\xd2\x26\x51\xdc\x8c\xd5\xb2\x5e\x16\x0c\xc6\x83\xd8\x99\x48\x40\x0c\xc6\x12\x91\x0f\x46\xac\xa9\xc7\xea\x34\x39\x0f\x71\xcb\xc3\xab\xae\x57\xef\xbd\x25\x57\xcc\x8b\x02\xe9\x29\xd0\x39\xd9\xc4\x59\x79\xf6\xe8\xf6\xad\xe3\x6d\xc8\xc7\x58\x2b\x88\x99\x60\xf4\x94\xc3\xa5\xf7\x35\x18\xc8\xe6\x09\xa9\x91\xf8\x35\x7c\x1f\x9b\x60\x10\x29\x66\x2f\x79\x21\x22\x98\x26\x21\x05\xd3\x48\x94\x1b\xcf\xf7\x9e\xbc\x5a\xba\xe1\x3f\x96\x8e\xfb\xd6\x73\xa4\x1c\x9f\xce\xca\xa9\xda\x7d\x44\x1f\xa5\xe1\xa6\xfe\x49\x8f\x06\x09\xb4\x04\x85\x7f\xd3\xa8\x50\x9c\xa9\x55\x97\x1c\xc4\x60\x7c\xdb\x5b\x1d\xbe\x18\x84\x1a\x7b\x37\x59\x3b\x61\x69\xf0\x8f\x74\x71\x96\x21\x68\x86\x46\x27\x1a\x6f\xad\x20\xf0\x12\x35\x8b\x5b\x51\x8e\xe4\xeb\xad\xd5\x3b\xb1\x33\x8e\x6b\x06\xed\xd8\x1e\x89\xbd\x44\x48\x62\xd6\xaa\x12\x15\xc9\xca\x1e\x89\xa0\x0f\x86\xc8\x65\x50\xcc\xec\xe5\x64\xc1\xab\xbd\xce\x9d\xb1\x07\xb1\xe1\x18\xc4\x7e\x6a\x6f\xc0\x11\x1f\xcf\x76\x2c\xb4\xb8\x29\x15\xdf\x20\x6b\xce\x89\x12\xc5\x95\xa0\xd8\x8e\xc3\xe1\x97\xed\xf5\x91\xcb\xcb\x12\x60\x5f\x0b\xcd\x92\x5a\x67\x76\x79\xb9\x40\x68\xa8\x0c\x0f\x2f\x95\xd1\xd7\x44\xcd\x16\xa3\x6f\x1a\xa0\xa6\xf6\x46\x98\xc3\xb4\x94\x22\x3b\xde\xe8\x0e\x3d\x30\xc2\x08\xaf\xd7\x19\x71\x0a\x38\x92\x68\x35\x99\x5c\xf8\x69\xec\x00\x65\xbc\x91\x02\xce\xde\x39\xde\xb8\x89\xd4\xc7\xad\x14\x7c\x61\x27\x68\xf4\xbb\x8c\x50\x22\x75\x24\xf6\xe8\x1b\x9c\x51\xc6\x11\x05\x6e\x17\xaa\x70\x07\x55\xa0\x01\xd4\x63\xef\xb5\x76\x13\xf7\x17\x61\x95\x25\xc0\xf6\x6c\x06\x61\xb3\x8b\x6c\x17\xe3\xd9\x7a\x76\x0e\x54\x00\x3c\xf3\x7e\x59\x81\xb2\x42\x9c\x94\xef\x5c\xa1\xb4\x15\xa9\xa5\x85\x1d\x50\x04\xb4\xf5\xe0\xa3\x50\xe4\x89\x80\xf6\x5d\x4a\xe5\xdc\xac\x4b\x65\xc2\x91\x25\x70\xc5\xb3\x9c\x25\x9b\x39\x64\x1a\x93\xdc\xd8\xe0\xa0\x95\x9a\x3c\x97\x97\x05\xc1\xea\x11\xa3\xb4\xc3\x4a\x41\xe5\x71\x36\x41\x28\xa7\xdb\x6f\x5a\xf5\x99\x39\x4c\xfd\x46\xf1\x1d\xa3\x13\x4e\xd4\x22\xf2\x51\x63\x2c\xc7\x8d\xb1\xa8\xc5\x89\xda\x0c\x9b\x35\x1c\x16\x8e\x5e\xb0\x89\x8c\xcd\x3b\x94\xd8\xfb\xc5\xec\x5e\xb0\x43\xdf\x3e\xff\x39\xbd\xc3\x5a\x70\x55\xc1\x67\x44\x46\xba\xda\x68\x57\x24\xb7\x0e\xe9\x49\xbb\xcb\x39\x11\x04\xe8\xcd\xbc\x01\xce\x60\x97\x72\x7c\x3f\x26\x5c\x86\xd3\xa2\x10\xfd\x09\x5c\x51\x41\x4a\x51\x22\xca\x6a\x2d\xb0\x2f\x4d\x6d\xd4\xd7\xa6\xbb\x15\xeb\x28\x6d\x53\xa7\x22\xd6\x99\xba\x57\x34\xa8\x57\x51\x9d\x21\x0c\x3c\x36\x4d\xc2\x50\xf8\xb6\xa2\xca\xc5\xee\x58\x0a\xbb\xd4\x75\xa3\x47\x6b\xa0\xa8\x96\xee\xca\xb3\xda\xb8\xa4\x32\x7e\x22\x72\xf8\xa3\xc2\x06\x98\x7a\x5f\xb9\xa1\x43\x12\x9a\x5c\xc0\x52\x2f\xbd\xed\x82\x90\xeb\xdd\x7e\xb7\xdb\x5d\x07\xb3\xdb\xa1\x43\xc7\x31\xdd\x81\xae\x44\x33\x55\xc9\x58\xec\x34\x2b\x9d\x47\xc6\x6b\xde\x47\x9e\xd4\xcb\xe5\xc1\x6f\x69\x42\x82\x36\x5c\xfa\x34\x23\x81\x31\x5f\x14\xd1\x98\xe1\xbc\x38\x4c\xc9\xdc\xc9\x3c\x14\x2b\x6e\xa3\x92\xd0\x3c\xe8\xc9\xe8\x0a\x1d\x52\xa6\xb3\xc7\x92\x7f\x52\x20\xd1\xd6\x13\x1c\xaf\x5d\xb7\x85\xae\x25\xc7\x99\x61\x66\x63\x4a\x35\x37\xe8\xb6\x51\x5c\xf1\xeb\x27\x2d\x3c\x9e\x52\x15\x94\x32\x4d\xf4\x7c\x3e\x66\xf1\x85\xe5\x94\xa7\xe5\x09\x67\x17\x12\xce\x7b\xb5\x6b\x9c\x7d\xae\x69\x8c\xf1\xd0\x4f\x8c\x05\xf2\xfb\xb6\x1c\x82\x67\xf3\x58\xd7\xea\x0a\x94\xd6\x3b\xd8\x09\xec\x2c\x8c\xb8\x8b\xa2\x51\xdf\x8c\xbc\xbc\xab\xad\x8b\x0e\xe0\x40\xcc\x04\xb0\x98\xcc\x3e\xe3\xcd\x89\x8c\x5b\x6a\x95\x16\xdc\x68\xd4\x2a\x69\x38\x83\x9d\xb1\x67\x39\x19\x7f\x14\x9e\x3d\x01\xdb\x2c\x7a\xbf\x16\x1a\x54\x6f\x45\x34\x52\x28\x2a\x9f\x96\x88\xa0\xff\xe2\xb7\x6b\x0a\x26\xe2\x9e\x4b\x6d\x5a\xb8\xa7\x9c\x71\xf0\xe5\xf5\x65\x29\xf8\xd0\x8e\x94\x07\xf4\x89\x55\x2d\x62\x65\x69\x6d\x6b\x56\xdb\x21\x93\xbb\x04\xb7\x7f\x71\x9c\xa1\x36\x71\x22\xd3\x40\xb3\x99\x65\xf9\x4b\x58\x9b\xa7\x18\x27\x4f\x18\xfb\x27\x07\x15\x9f\x6c\x74\x9a\xc0\xa6\xc9\x3e\xcf\x6f\x7a\x5f\xf9\x6d\xff\x3f\x4d\xbb\x33\x85\x73\x23\x48\x56\xb8\xbc\x0f\xe7\x10\xdf\xe1\xee\x2c\xf1\x9e\x10\x5d\xa9\xb3\x22\x7a\x0a\xa2\xe7\x06\x7a\x40\x4c\x4b\x5d\xb2\xc2\xbf\x01\x00\x00\xff\xff\x62\x49\xb5\xa2\x76\x13\x00\x00")
+
+func fontsEftirobotFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsEftirobotFlf,
+ "fonts/eftirobot.flf",
+ )
+}
+
+func fontsEftirobotFlf() (*asset, error) {
+ bytes, err := fontsEftirobotFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/eftirobot.flf", size: 4982, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsEftitalicFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x58\x5f\x6f\xdb\x36\x10\x7f\xd7\xa7\xb8\x16\x02\x28\x01\x8a\x29\xd1\x7f\x14\xaf\x45\xa1\x6e\x68\xdf\xb6\x00\x43\x97\x27\x21\x74\x10\x34\xa8\xb7\xd4\x02\xea\x6c\xe8\x03\xd1\xcf\x3e\xf0\x8e\xa4\x48\x91\xb2\x1d\xd4\x28\xc4\xd8\xfa\xf1\x78\xf7\xbb\xbf\xec\xe3\xd3\xa3\xb8\xcf\x61\x0d\x2b\x68\xd6\x50\xc3\x75\x96\x7d\xfa\xb2\x3f\xc2\xe3\x70\x78\x86\xfd\x11\x8a\x87\x12\x7e\xdf\x3f\x7c\xf9\xfc\x04\x1f\x1e\x9f\xf7\x5f\xef\xff\xd9\x1f\xa1\xd9\x6e\xd7\x70\x75\x05\xb7\x9f\xbf\x1d\xf7\xc3\x01\x9a\x45\xad\xbf\x8a\x16\xfe\xbe\x3f\xe0\xdb\x0c\xe4\x4f\x7c\x00\x80\xef\xf0\x8f\x4c\xc5\xa7\x47\x1f\x85\xcf\xd7\xef\x8f\x0f\xfb\xfd\xd5\xfb\x6f\xcf\xfb\xe3\xf3\x6b\xfc\x89\xf5\xdc\x20\x32\x8d\x21\x49\x0b\x27\xa9\xfb\xf7\xf8\xfc\xb0\xf8\xef\xe9\xb8\x5f\x3c\x0c\x5f\xad\x9c\xe0\xf3\xeb\x30\x94\x57\x50\xd4\x75\x49\x72\x48\xd0\xa7\xcf\x4f\xf0\x0b\x14\xcb\x65\x09\x5b\x01\xdb\x8d\xb6\xbc\xd9\x4e\x15\x8a\x3f\x85\xdc\x31\x59\x5a\x41\x52\xc2\xc7\xfb\xef\x91\xa0\xba\x19\xb9\x53\x48\xc2\xc7\x3f\xdf\xff\xf1\xdb\x07\x9f\x51\x90\xaf\x5e\x49\xfc\x41\xa9\x0c\xd4\xcf\x70\x3d\x9e\x95\x69\xc5\xf2\x4e\x2f\x39\xe8\x25\x07\xbd\xe4\xa0\x17\xfd\x84\x0e\x5f\xf2\x56\x2f\x9c\x23\x06\x5f\x16\x25\x2e\x30\x62\xa0\xcb\x78\x8b\xc0\xdc\xee\x36\xbf\x1b\x18\x98\x5f\x24\x6f\xf5\x3f\x23\x91\x73\xfd\xeb\x15\xe7\xfa\x9f\x13\xe9\xed\x93\x74\x78\xc5\x40\xf2\x2e\x03\xd9\xc3\x6e\xa1\xcf\x92\x52\x56\x4c\xe3\x39\x0f\x94\x28\x4a\xdc\x80\xca\x72\x5e\x94\x9e\x12\x12\xe5\x17\x43\x09\x5d\x56\xb1\xe1\xb6\xed\x32\x25\x0f\x2a\xb0\x43\xe2\x5e\xb4\x02\x8d\xc0\x77\x56\x15\x54\xe4\x0d\x43\x48\x8e\xf2\x11\xa1\x94\x87\x31\xd2\x94\x42\x3e\x89\xb3\x9c\xac\xac\xde\x30\x02\x2e\xa0\xea\x32\xf8\x0e\x5d\xc6\x60\x17\x1d\xa3\xbf\x48\xde\xa2\x91\x20\x8d\x31\x21\xd9\xc1\x43\xdb\xc8\xd9\xc8\x80\x15\x21\x25\xd2\xc4\x7d\x37\xf8\x8f\xa2\xcc\xbd\x63\x8d\x43\x46\xea\x42\xff\xa1\x5d\x15\x83\xbe\xcb\x38\xd4\xc0\xbb\xac\x37\xfc\xc3\x94\x20\xc6\x8d\xc9\x5d\x96\x4f\x35\xd7\x91\xac\x8f\x90\x00\x25\x0a\x7c\xd0\x32\x0a\x29\x65\xeb\x7c\x6f\x0e\x44\xfd\x41\x43\x2b\x86\xe6\xf0\xb7\x48\x36\xfa\x7d\x0c\x14\x4b\xda\x02\x57\x3a\xbc\x62\x03\x4f\x8b\x25\xa1\x9c\x62\x49\x49\x34\x47\x0b\x9c\x86\x32\x54\xac\xed\x32\x3e\x68\x80\x72\xef\x7d\x11\x12\xf8\x98\x14\x91\x83\xc8\x4c\xe0\x83\x36\xb3\x62\x03\x28\xa7\xfa\x44\x1f\x30\xef\xf5\x6b\x48\x0b\xf3\x1d\x5d\x94\x7e\xac\x44\x6f\x6e\x27\x61\xfc\xf6\xad\xf6\x71\xdf\x07\xf1\x05\xc6\x0c\xb2\x03\x23\x04\x17\x5f\x35\xcc\x95\xbe\xd7\x3e\x7c\xf7\x0e\xc3\xc1\x8f\x15\x6b\x1e\xa0\x7d\x00\xd0\x1a\xc3\x72\xb0\x0a\xf9\x61\x41\xe8\x8a\x21\xdf\xa0\x8a\x01\x19\xcd\x75\x15\x6b\xf3\xa9\x27\x09\xbc\xc0\x50\xc3\x13\x50\xbd\x43\xa8\x5e\xa8\xc4\xa2\x34\xd0\x3e\xa8\x0c\x21\x1a\x9d\x8a\xb6\x6a\xe7\xa1\x37\x78\xda\x69\xe0\x8e\x56\x26\x3c\xe2\xa3\x09\x88\x61\xa4\x17\x48\x50\xe8\x07\x31\xc8\x11\x8a\x58\x3e\xe6\xea\x9c\x8e\x07\x13\x31\xa1\x8e\x60\x24\xea\xda\x89\x12\x77\x40\xa7\x1f\x24\x4f\x4b\x04\x8b\xe4\xf6\xe4\x49\xd6\x4a\x2a\xf2\x1a\xa5\x85\x68\x58\x1f\x24\x99\x3d\x1a\x0c\x3f\x9c\x4a\x2c\x56\x65\x14\xd9\xf7\xe7\x8e\x96\x86\xa0\x89\x31\x23\xae\xaf\x98\xc1\xe2\x5f\x46\x55\x1e\x18\xe5\xed\xb3\xdb\x94\x3d\x41\x29\xbb\x49\x85\x7b\x12\xf5\xcb\xa4\xdb\xb4\x7e\xf9\x61\xad\xc8\x5b\xd6\xc0\x94\xb7\x52\x12\x4d\xa6\xcd\x4b\x74\x94\xed\x64\x1f\x15\x31\x13\x2d\xf3\xbd\x6e\x44\x4b\x69\xea\x3b\xd8\x20\xf4\x02\x2b\x2c\x31\xc4\x95\x09\x18\x0e\x7f\xcd\x39\x38\x04\x2a\xb8\x45\xa0\x4a\x01\xc1\x41\x5b\x07\xb6\xf0\x43\x58\x9f\xa7\x2e\x53\xa0\x38\xc5\x34\x07\xd2\xb9\x62\xf2\x20\xfb\x68\x8b\xdd\xe1\x36\x28\x20\xc1\x73\xc9\x63\xb9\x96\x40\x1d\x03\x2a\x46\x1b\x2a\x86\xa9\x19\xe9\x64\x13\xde\x26\xb2\x26\x11\xe7\x20\x5c\x89\x78\xee\xca\x21\xd5\x43\xc0\x72\x8a\xdb\xac\xaf\x43\xe7\xb9\xce\x90\x53\x26\xd1\x1a\x08\x33\xb1\xc3\x17\xfd\xfc\xb4\x14\x2d\xd6\xdf\x3a\x87\xf4\x57\xb0\x75\x3d\x31\xa8\xd8\x23\x2a\x36\x50\x58\xb6\x81\x70\x34\x15\x33\x78\xc0\xfe\x17\xb4\x37\xdb\x1d\xf4\x6e\xfd\xa2\x77\x71\x1a\xb4\x0f\x90\xdc\xeb\xb4\x2a\xe0\x37\x92\x33\xe8\x10\x91\x45\x28\xc7\x35\x05\xd4\x44\xb6\x60\xa6\x8e\xb4\x1c\xdf\x1a\xd6\x65\x52\x37\xa4\xa9\x35\x98\x8a\x87\x70\xe0\xc1\xd7\x38\x05\xd2\x44\xc5\x93\x44\xd3\x98\x88\x08\xd3\x7e\x39\x9f\x60\xec\x4b\xad\x2e\xe7\x7d\x1f\x4d\xbf\x56\x8b\xd4\xf4\xe4\xac\x00\x0a\xaf\x9e\x21\xf1\x07\xa7\xec\x2c\x50\xcb\x4c\x75\xbf\x24\x2b\x91\x5d\x76\x0a\xc1\xda\x83\x10\xdf\xae\xa4\x88\x90\x58\x0a\x54\x54\x82\x52\x23\x76\x2f\x14\x0f\x0c\x03\xb3\x9c\x09\x32\x62\x6c\x3e\xc0\xe9\xda\xc0\xa3\x76\xec\x46\x59\x02\x28\x57\x02\xc3\x40\x74\x10\x02\xdd\x45\xdd\x9a\xd2\x87\x74\xed\x6f\xb5\x91\x15\x3b\xc4\xfe\x23\x44\x7f\x8b\xd9\x5b\x3a\x2f\xc6\x19\x08\x24\x62\xd2\xcc\xec\xc4\xc5\x55\xde\x65\xbd\x32\x63\x57\x17\x75\x58\x30\x8d\x78\x52\xb1\x83\x89\x4b\xf5\xfa\xc1\x69\xec\x42\xe5\xb5\x78\xce\x7b\x4e\x95\x05\xc0\x5b\xac\x02\x45\x29\x29\x8c\xf5\xe8\x04\x76\x76\x9a\x19\x0d\x2c\xb8\x22\x2c\xf6\xa7\x74\xb1\xb7\x48\x6c\x0b\x60\x1b\x88\xeb\x20\x51\x0f\xd3\xcf\x9b\x9b\x93\xb5\x27\x78\x9d\x08\xdb\x1b\xb8\x39\x15\x16\xae\x6a\x9b\xe1\x93\x93\xee\x3a\x37\xa9\xb9\x72\x8b\x6e\x36\x35\xee\x38\x77\xc5\x6d\x36\x0d\xe2\xec\x6d\xd1\x65\xbc\xad\x07\x63\x69\xd2\xe0\x75\xa2\x3b\xe1\x55\x6d\xa6\x3b\x35\x9b\x0d\x7e\xa3\x9b\xac\x77\x8f\xa6\xe8\x9f\x8a\xbf\x76\x4c\x14\x25\x6a\x94\x53\x8f\xc8\xc1\x77\x78\x73\xbd\xb4\xf9\x59\x60\xea\xc5\x8d\xa4\xd9\x0a\xfc\x93\x1a\xd5\x99\x89\xba\xd9\x2e\x49\x49\x7e\x11\x78\x85\x96\xdc\x5d\x26\x79\x8d\xe0\xfe\x32\xc9\x9b\x17\xc6\x72\xb3\x6d\x3d\xe7\x9d\x15\x7f\x6d\x9b\xb5\xe9\xd7\x78\x82\x9d\xa1\x06\x6c\x6c\xf6\x9c\x60\xa0\x77\x02\xb6\xd9\xc9\xeb\x84\x29\x1a\xa2\xc6\xd0\x93\xc4\xfd\x99\x9b\x82\xa8\x9b\xb1\xa5\x9e\x07\x0b\x8f\xfb\xb3\xe0\xa5\x4f\xa7\x81\x79\xf7\x10\x39\xa5\x53\xd4\xe8\x5a\xab\xf7\xec\xcd\x41\xd4\x6b\x2f\x5e\x92\x35\xcd\x57\x43\x7b\xd5\xa9\x7c\x42\x68\x8b\xea\x5a\x6d\xcf\x08\x25\x57\xf0\x9e\xbf\xe4\x32\x20\x9a\xda\x19\x78\xea\x42\x20\x9a\x26\xb3\xf6\x9d\xc6\x09\x67\xdb\x69\x9c\x76\x05\x65\xc1\x69\xdc\xea\xf2\xfa\x2c\x1a\x4d\x98\xec\xfb\x4b\x46\x7c\xd1\x5c\xe3\xff\xbf\xf1\xcb\xc0\x5b\x32\xeb\x22\xb0\xa8\x5f\xd8\x2a\x84\x58\xbe\xb0\x98\x0b\xb1\xb2\x05\x0f\x76\xbb\x64\x83\x11\x02\x63\x12\xa3\x81\xb1\x19\xc8\x66\x9c\x5e\xee\x66\x20\xed\x08\xf9\x31\x03\xb9\x3e\xd7\xec\x84\xd8\x8e\x52\x66\x20\xcb\xda\x31\x32\xb6\x14\x0d\x34\x13\x73\xd5\x2e\x8a\x90\xb5\x65\x33\x19\xad\xc7\x11\xdd\x16\x9e\xa5\x98\xd2\x34\x9d\xbe\xc5\x72\x39\xa5\x29\x86\xac\xa6\x34\xc5\x90\xf5\x94\x83\x18\xb2\x09\x74\x49\xcc\xe0\x62\xd9\x06\xba\x24\x21\x23\xd9\x6c\x4e\xca\x36\xd0\x25\x05\x59\x35\xfe\x80\xfd\xe3\xe4\x80\x2d\x56\x11\x89\xd3\x69\x45\xac\x22\x12\x63\x48\x44\x62\x0c\x59\xa7\x63\xcd\x87\x6c\xce\x4d\x4e\x62\xb5\x1d\xa7\x7d\xcb\x74\x62\x7a\x12\x6b\x0a\x38\x1a\x47\x0d\xdd\x49\x5c\xe3\x0d\xe9\x77\xb3\x43\xba\x58\x8b\x8b\xa6\x36\xb1\xb6\xb3\x8a\x64\x2c\x3d\x64\x8b\xb5\x25\x42\xde\xdc\xa4\x21\xff\x07\x00\x00\xff\xff\x8b\x4c\x56\x74\xb9\x1a\x00\x00")
+
+func fontsEftitalicFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsEftitalicFlf,
+ "fonts/eftitalic.flf",
+ )
+}
+
+func fontsEftitalicFlf() (*asset, error) {
+ bytes, err := fontsEftitalicFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/eftitalic.flf", size: 6841, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsEftiwallFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x58\x6b\x6f\xdb\x36\x17\xfe\xae\x5f\x71\x1c\x19\x15\xa9\x8a\x64\xe2\xf6\x6d\x9a\x20\x0e\x94\x77\x68\xd1\x0f\xcb\x0c\x0c\xdd\x56\x60\x5a\x8e\x32\x43\x5e\x84\x26\x26\x60\xbb\x41\xd6\xb2\xf9\xed\x03\xa9\x1b\x25\x5f\x55\xd2\x86\xad\x23\xf1\x3c\x3c\x97\x47\x87\x97\xd9\xfd\x6c\x74\x3b\x84\xd7\xf0\x1a\x5e\x8d\xe0\xcd\x08\xde\x7a\xde\xc7\xbb\x7c\x09\x33\x39\x5f\x41\xbe\x04\x32\xa5\x70\x9d\x4f\xef\xb2\x7b\x78\x37\x5b\xe5\x0f\xb7\x9f\xf3\x25\x9c\x9c\x9d\xfd\x0f\x18\x83\xdf\xb3\xc5\x32\x97\x73\x38\xe1\x46\x1c\x8d\x60\x96\xfd\x6d\x9e\x7a\x80\x0e\x0d\x00\x44\x6a\x2e\x3c\xb5\x3e\xfa\x5a\x53\xe6\xf7\xe8\x6a\x39\xcd\x73\x76\xb5\x58\xe5\xcb\xd5\x91\xb9\x15\x24\xa2\xec\xe1\xe9\x3e\x05\x12\xaf\x91\xe2\x2f\xcb\xd5\x94\x3f\xde\x2f\x73\x3e\x95\x0f\x15\x4e\xab\xfd\x5f\x4a\xca\x80\x1c\x1f\xd3\x02\xa7\x00\xfa\x98\xdd\xc3\x39\x90\x57\xaf\x28\x9c\x8d\xe0\xec\x0d\x8c\x4e\xe1\xe4\xac\x6b\xd0\x7a\x23\x98\x06\x48\x2b\x20\x44\x78\x7f\xfb\xb4\x06\x74\x7c\xd2\xc4\x4e\x99\x20\xbc\xff\xf5\xea\x97\x9f\xde\xd9\x11\x05\x1c\x0c\xd0\xdc\x50\xca\x03\xe5\x12\xeb\x66\x2c\x6f\x38\x1c\xc6\xd6\x0f\x63\x2c\x8e\xbd\xca\xf6\xcd\x57\xac\x6c\x55\xc7\x44\xe8\xc7\x8f\x76\xc7\xc7\x6e\xc7\x61\xf5\xd5\x02\x2f\xba\xf2\xa2\x77\x08\x40\x00\x20\x8c\x3d\x7d\xc9\xcd\x8d\x46\xb7\x19\x46\x24\xd6\x00\x42\x0f\x9b\x18\x49\xa4\xa2\xbc\xd1\x52\x6b\x14\x0b\x72\x69\x01\x51\x8f\x44\x8d\x40\xca\x10\xd0\xb6\x96\x56\x4a\x01\x10\x20\xd0\x0f\x74\xfe\x28\x00\xd3\xda\x01\x80\x7e\x64\x75\x8f\x63\x2f\x2a\xae\x78\xec\x29\xf8\x90\xc3\x00\x54\xec\xa5\xe6\x16\xc1\xaa\x27\xc0\x96\x8e\x48\xcd\xbd\x40\xa3\xdb\x36\x63\xe5\xa8\x94\x09\x54\xd6\xd2\x64\x2d\xf8\x85\x67\x60\x25\x49\x00\x12\xca\xa0\xfa\x5c\xc6\x1e\x28\x43\xcd\xc1\x60\x3d\x81\x1b\xfc\xd8\xdc\x8c\xd1\x57\xcb\xcf\x30\x93\x0b\x90\xab\xbb\x6c\x01\x41\x36\x5b\xe5\x81\x29\x19\x4b\xcb\x95\xcd\xcd\x72\x70\x73\xb3\x38\x57\x67\x2c\xf6\x2e\x6a\x3f\x18\xa1\x68\xf2\x5b\xf5\x30\xee\x68\xcf\xfa\x7b\x63\x9c\xd9\x5e\xe2\xea\xfc\x6d\x6c\x4d\x52\x37\x36\x93\x69\x6d\x5f\x68\x72\x18\x16\x49\x09\xa1\xa4\x51\x41\x6d\xfd\x47\x40\x02\x0d\x0b\xda\x4b\x39\x29\xd5\x27\x52\x76\x43\x51\xbf\x7a\x9c\x73\x5b\x26\x1c\x38\x2d\x65\x03\x40\x74\x06\xfa\x00\x48\x90\x6e\x00\xcc\x15\x40\x02\x73\xb5\xc0\x11\x20\x84\xd0\x0d\xe0\x09\x9e\x5c\x63\x30\x71\x03\x98\xb8\x66\x01\xe4\x41\x00\xa5\x70\x54\x09\x69\xf9\x9a\x9a\x32\x59\x50\xf8\x20\x25\xd3\xd6\x95\xf6\xbe\xb1\x7f\x2c\xf2\x55\x06\xff\xca\x2f\x0b\x78\xc8\x96\xcb\xdb\x7f\x32\xb8\xcb\x16\x99\x5d\x71\x9d\xde\x58\x80\x79\x63\xb4\x9e\x18\x04\x26\x58\x16\x22\x13\xa7\xaf\xf0\x75\x6b\x9c\xdc\xac\xdf\x55\x3b\xf7\x95\xce\xca\xfa\xee\x1f\xe3\x18\x35\xc9\xb0\xff\x0b\x97\x58\x00\x90\x6e\xe5\x48\x3d\xb1\xfc\x68\xad\x88\xa2\xc8\x0d\x40\x4a\xe9\x06\x30\x1e\x8f\xdd\x00\x5e\xbe\x7c\xe9\x06\xe0\xfb\xbe\x13\x00\x0b\x9f\x43\xe6\x64\x41\x18\x86\x6e\x2e\x28\xa5\xdc\x5c\x48\x6f\x02\x37\x17\xc4\xe9\xe9\xa9\x13\x00\x8a\x53\xb7\x18\x50\x4a\xdd\x00\x08\x21\x6e\x00\x4f\x4f\x4f\x0e\x00\x4d\xa1\x36\x32\xab\xe7\x0c\x76\xb8\x05\x71\xef\x7a\x80\xdd\x18\x38\x16\x94\xcb\x4f\x17\x6e\x00\x41\x98\x3a\x01\x24\xec\x86\x09\x27\x0b\x6e\x6e\x6e\xdc\x5c\xa0\xca\x91\x48\x89\x12\x6e\x00\x2f\x5e\xbc\xe8\x07\x40\x3a\x00\x48\x7b\xf0\xa0\x75\x38\x10\x7b\xea\x67\x29\x3f\xc3\x47\x3d\x6f\xa6\x5c\xcb\xcd\xf3\x28\xa8\x36\x02\x4a\x59\x13\xa3\x05\x50\xa9\xc3\x87\x6c\x91\xa9\x96\xb2\x6a\xab\x96\x5b\x30\x5b\x15\xa2\xa0\x19\x5b\xe9\x75\x0c\x5f\x57\x6f\x01\xe8\x48\x1b\x65\x7d\xa1\x01\xe3\x67\x01\x11\x87\xe4\x39\x2e\xf6\x69\x48\x20\x41\x14\x40\xb1\xda\xb6\x26\x88\xbf\xa1\xa8\x2d\x08\x12\x91\x16\x61\x22\x66\x81\x66\x36\x81\xe6\x28\x41\x77\xc7\xc1\x00\xbb\xdb\x26\xb5\x81\xb4\x49\x92\x94\x4f\x84\x10\x2d\xfa\x16\xcb\x3e\x65\xe0\x61\x2d\x07\x13\xa9\x2f\x3b\xe9\x54\x1d\x78\xc5\xc7\xe3\x31\x6f\xe4\x6f\xdf\x25\xc8\x6f\xdf\x77\xf0\x81\x98\x4f\xa5\x10\x70\x53\x99\x78\x59\x99\x02\x00\x72\x09\x17\xb4\xac\x54\x07\x31\x32\x8a\xaa\x95\x86\x91\x85\x21\x54\xb2\x87\xd2\xed\x15\xb0\x8c\xc2\xc8\xe6\x21\x0c\xdf\x1a\x91\x20\x9d\x48\x39\xac\x90\x0c\x90\x41\xb2\x56\x5d\xea\xa8\x35\x3f\xa2\x42\x85\xfd\x5e\xb0\x76\x9d\xfc\x01\x80\x56\x3c\x10\xaf\xaf\xaf\x11\xfb\x00\x74\x96\x7a\x5c\x29\xc5\x7b\x58\xd0\x9c\xe5\x68\x05\x0e\xc0\xcf\xcf\xcf\x2d\x80\x73\x03\x70\xae\x7b\x1c\x5a\x64\x1e\x1f\x5b\x67\x49\xe4\xf8\xf9\xb8\x97\x0b\x22\xf1\xed\xb3\xa2\xbd\x9c\xc0\x26\x11\xb1\x07\x32\x80\x24\x1a\x73\x01\xa9\xec\x93\x46\xb4\xd3\x06\x02\x13\x48\xc3\xc3\xb3\x80\xb5\x19\x46\x0e\x92\x84\x09\x91\x1e\x9a\x05\xbf\x13\x03\x1f\xe0\x02\x43\xbc\x2c\xe5\xa1\xdf\x06\x60\x6f\x59\x1b\xc0\x87\x6e\xf3\x63\xcf\x1f\x4b\x39\x19\x57\x6d\x22\xe5\xd8\x37\x3d\x75\x41\x29\xd1\x74\x41\xf1\x9b\xdd\x15\x69\xf6\x31\x5b\x32\x13\xe8\xb8\xf4\xa2\xf7\xa0\x3a\xb7\xaa\x56\x32\xd0\x59\xc9\x7c\x9a\xf4\x58\xc9\x18\x80\xa8\x05\x20\x69\xbd\x14\xd2\x1b\xd2\x60\x1f\x3b\x09\x45\x42\x77\xb9\x90\xca\xa0\x03\x20\x6d\x80\xd4\x70\x23\xa8\x64\x56\x02\xb0\x83\xe9\xcd\x03\xf4\x31\xe5\xb5\xac\xfe\x94\x20\xff\x52\x3b\xb8\x51\x7f\x4b\x6e\xf8\x9c\xd7\xb2\xe6\x86\x3f\x01\x9f\x96\xb2\xf4\x27\xcc\x27\xe8\x33\xe6\x6f\x65\xa7\xc6\x2f\x8e\xb3\xfa\x54\x29\xbb\xa8\x44\x0c\x99\xb2\x00\x8d\x0b\x74\x0f\x40\x3b\x0d\x04\x91\xda\x79\x68\xce\xeb\x21\xf6\xe6\x73\xc6\x88\x44\x94\x94\xb1\xf9\x5c\x83\x94\x9f\x9d\x17\x00\x56\x3d\xb6\xc6\x69\x33\x76\xc3\x64\xd9\xb1\xb4\xa5\x00\x1d\x3b\x0f\x3d\x6e\x69\x18\x6b\xaf\xbd\x35\x63\x39\xdf\x6b\x01\x74\x2c\x88\x6b\xca\x1b\x0b\x38\xef\xb7\xfa\x47\xbf\x1d\x03\xca\xc8\x4e\x0b\xcc\xe1\xa6\x0d\x10\xa9\xf6\x69\x40\x0c\x71\x3f\x17\xa6\xd3\x69\x0b\x20\x0c\xb7\xc7\xe0\xbf\x00\x00\x00\xff\xff\x02\x9d\xcc\x12\xdf\x1a\x00\x00")
+
+func fontsEftiwallFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsEftiwallFlf,
+ "fonts/eftiwall.flf",
+ )
+}
+
+func fontsEftiwallFlf() (*asset, error) {
+ bytes, err := fontsEftiwallFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/eftiwall.flf", size: 6879, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsEftiwaterFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x56\x4f\x6b\xeb\x46\x10\xbf\xef\xa7\x98\xf7\x58\x90\x16\x6c\xaf\xdd\xb4\xb8\x81\x24\x6c\x5a\xd2\x93\xdb\x43\x69\x7a\x12\x8c\x8c\xb1\x1b\xd1\x24\x1b\x22\xa7\x27\x7d\xf8\x32\x33\xbb\xd2\xae\x24\x97\x86\x27\xfc\x1e\xd2\xfc\xe6\xef\x6f\x76\x66\x73\x7a\x3e\x7d\xb7\xd7\xf0\x3d\x5c\xc1\x66\x0d\x6b\xf8\x51\xa9\x3f\x9e\x9a\x16\x4e\xfe\xf5\x0c\x4d\x0b\xe5\xc1\xc0\xaf\xcd\xe1\xe9\xf8\x0c\x0f\xa7\x73\xf3\xb2\xff\xbb\x69\x61\x73\x7d\xfd\x03\x2c\x97\xf0\xe7\xf1\xbd\x6d\xfc\x2b\x6c\x56\x6b\xfa\xbc\x5a\xc3\xfe\xe3\x2f\x46\x15\xe0\x37\x3c\x00\x60\x6b\x7e\x51\xdd\x34\x7a\x78\xbe\xde\xb7\x87\xa6\x59\xde\xbf\x9f\x9b\xf6\xfc\x95\x24\x1d\x8c\x9e\xa2\xb2\xf2\xd2\x29\xc2\xc4\xd3\xaa\xf7\xe4\x5a\xff\xf6\xd4\xec\x57\xc7\x8f\x77\xff\x76\x5c\xfd\xf3\xdc\x36\xab\x83\x7f\x49\xfd\xfc\xe4\xbd\x59\x42\xb9\x5e\x1b\xf1\x23\x8e\xfe\xef\x33\xd6\x2d\xb1\x2e\xd0\x44\x47\x9f\x20\x84\x75\xe1\x97\xdf\xef\x7f\xfb\xf9\x81\x98\x05\xfc\xf2\x05\x99\xe2\xae\x53\xf0\x19\x4f\xff\x11\x43\x69\xed\xd2\x7f\x4e\x01\x82\x53\x60\x8c\x53\x65\xa9\x9d\x02\x0f\x24\x04\xa7\x1e\x1f\x45\x0b\x44\x80\xfc\x73\x0a\x96\xc6\xd0\xcf\xa9\x65\x59\xd2\x8f\x55\xe4\x61\x77\xaf\x48\xfe\x4a\x74\x6a\x85\xc6\x12\xf8\x28\x1e\xc0\x29\x6f\xb7\x4e\x59\xeb\xe5\x33\x08\xa1\xa4\xe0\xb8\xed\x85\xe8\x94\x2d\x46\xc1\x9d\x02\x6b\x35\x25\x09\x24\xae\x2a\xd1\x24\x7b\x4d\x1f\x4a\x73\x0d\x60\x6d\xcc\xff\xee\x26\x73\xc1\x91\x80\x8c\x97\x5d\xcc\x39\x68\xb2\x13\x09\x1a\x53\x62\xbd\xa0\x16\x85\x9a\x84\xda\xe7\x42\x90\x8a\x06\x21\x75\x8e\x09\x05\xa6\x14\xcb\xc8\x4f\xe4\xba\x18\xb8\x8e\x16\x64\x80\x22\xc6\x24\xb5\x04\xc0\x68\xd0\x37\x83\x42\x17\x1d\x4c\x62\x48\x7c\x63\x90\x8b\x62\x4e\xfa\xe0\x9c\xd8\x4e\x6c\x06\x00\x11\xd9\xd9\x5c\x56\x66\x67\x46\xda\x02\x04\x11\x66\x59\x41\xa0\x67\xcc\x91\x08\xa9\x32\x5b\xb0\xd0\x5a\xa7\x6e\x6e\xa4\x8f\x99\x26\x62\xce\xbb\x74\xf6\xee\x8e\x28\x86\x3c\xb5\x22\x10\x06\x72\x68\x03\x2f\x81\xfb\x83\x64\x8d\x8b\x84\xfb\x00\x5a\xac\xc5\x2e\x6f\x4c\xb4\xc4\x60\x69\x72\x50\x4b\x4b\xa5\x72\x84\x0c\x14\xc3\x8a\x21\x9b\xf2\x24\x56\xbb\x60\xa5\x61\xc6\x65\x00\x61\x0c\x4a\x2e\xd2\xdc\xb4\x83\xa1\x29\xb3\x25\xe4\x73\x9c\x4e\x8e\x8c\x06\xcb\x57\x44\x5b\x72\x18\xb6\xa4\x5f\x57\x93\x53\x62\x42\xa9\x19\x20\x21\x2a\xbb\xe0\x28\x75\x7f\x26\xf3\xec\xaa\x3a\xc0\xb3\x04\xcf\x8e\x45\xce\xfe\x84\x8d\x19\xcb\xda\xcc\x59\xd6\xd5\x85\x49\xc8\xe6\x07\x47\x0d\xd5\x90\xc5\x8b\x4c\xd6\xb3\x03\x9c\x81\x8b\x62\x0c\xf6\x70\x50\x48\x54\x06\x1a\x25\x38\x0d\x03\x9d\xeb\xaa\x2f\x97\x93\x63\x17\x35\x93\x08\x73\x59\xdb\x45\x31\x77\x0c\xc1\xa9\x0e\x3b\xa7\xba\x4e\xcb\x1b\xb9\xa2\xc2\xaa\x8a\xcb\xe3\x51\x9a\x68\xeb\xae\x8b\xda\xa4\x55\xd4\xb4\xe6\x86\x9d\x99\xfe\x77\x7b\x7b\xcb\x3e\x29\x39\xa7\x20\xdd\xac\xd0\x77\x62\xca\x57\x7a\x9a\x4c\xba\x2c\x20\xd9\x25\xd9\x16\x91\xad\x17\xf7\x61\xe6\x2e\x18\x11\x50\x4c\x36\x55\x2d\xbd\xcc\x62\xcc\x64\x36\x0c\x40\x38\x39\x30\x3d\xad\x1e\x02\x49\xe9\x2c\xe5\xc2\xd1\x1c\x2d\x48\x5c\xe9\x9c\xe2\xe9\x38\xc6\x94\x20\x38\xaa\x37\xf9\x0c\xf5\xb8\xc0\xd5\xa8\x7a\x18\xed\xdf\x8b\x80\x31\x97\x2c\x24\xed\x14\xe8\xf4\x68\x89\x33\xc3\xf1\xea\x18\x6a\xd9\x4d\x6b\xe9\x79\x9c\x36\x8a\xb7\x39\x5d\xe5\x55\x69\x8b\xbc\x27\x01\x12\xb0\xec\xe1\xd4\x92\x43\x9a\xfc\xd2\x9b\xb8\xec\x8b\x64\x39\x27\x91\x2c\xbe\x78\xcf\x94\xe1\x9e\x99\xf6\x84\xa9\xc0\x30\x23\x4e\x69\x13\xee\x99\xe0\x73\x5b\xd1\x9f\x24\x7a\xb8\x77\xc0\xfb\xcb\x37\x88\x47\x7f\x79\xc1\x79\xf0\x97\x77\x4a\x70\x3b\x3f\x40\x11\x9b\xf6\x3c\x20\xb3\xf4\xcf\x5e\x67\xbc\xee\x9c\xfa\x37\x00\x00\xff\xff\x14\x6c\x6e\x6d\x0e\x0c\x00\x00")
+
+func fontsEftiwaterFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsEftiwaterFlf,
+ "fonts/eftiwater.flf",
+ )
+}
+
+func fontsEftiwaterFlf() (*asset, error) {
+ bytes, err := fontsEftiwaterFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/eftiwater.flf", size: 3086, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsEliteFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x56\xbd\x6e\xdb\x30\x10\xde\xf9\x14\x37\x64\x0d\x6d\x07\x09\xda\x78\xa9\xbb\xa4\xc8\xd0\x87\x50\x6d\x29\x76\x7f\xa2\x40\x56\x6b\x74\xd3\xc0\x41\x83\x06\x4d\x7a\x80\x8c\x7c\x01\xed\x7a\x14\x3d\x49\x71\xe4\x91\x3a\x32\x2e\x0a\x14\x05\x9a\x41\xb0\x21\x93\xf2\xf1\xf8\xdd\x77\xdf\x1d\x99\x7d\xcd\xae\x92\x0b\xb8\x81\x1b\x58\xad\xe0\x72\x05\x6f\x60\x89\x1f\x71\x97\x3f\x96\xf0\xfe\x7b\xb9\xcf\x8b\x35\xbc\x13\xe2\x63\x5e\xa4\x70\xff\x98\xe5\x6b\x21\xf6\x65\xf9\x74\x5c\x2f\x16\xa7\xf4\x93\x4c\x8a\xed\xfe\xf0\x23\x95\x79\xf1\x80\xf3\xc5\xd5\x72\x75\xb5\x7c\xbb\xba\x5d\x5e\x5f\x5f\xdf\xdc\x2e\xd0\x14\x2d\x4f\x27\x59\xe4\x3f\x8f\xc9\x56\x6e\xf3\x6f\x8b\x72\x9f\xee\x8a\xe4\x94\xe5\x8f\xe5\xf1\xb2\xdc\x65\x32\x39\x3e\x09\x71\x77\xff\xc1\xec\xba\x2d\xd2\xa4\x4c\x77\x70\x3a\x94\xfb\x35\x90\x87\xa7\xa4\xcc\x8b\xcf\x5f\xcc\xf2\xec\xf0\x80\x4b\x2f\xd3\xdd\xa1\xcc\x0b\x71\x01\x70\xb1\xf9\xdd\x73\x23\xc6\x4e\x8d\x9d\x02\x1c\xd4\xe6\xdb\xe0\xb0\x1d\xbb\x7a\xe8\x37\x42\x8e\x5d\x05\x1b\x01\xe6\x67\x23\xfc\xe7\x3f\x0e\x01\xe0\xe5\xe3\x15\xe1\xfb\x07\x11\xda\x9c\x8c\x9d\x1a\x7a\x70\xd9\xc0\x10\xf1\x87\x32\x56\x9b\xa9\x7f\x43\x16\xda\x8c\x1a\x22\xc4\xb1\xe2\xdd\x9d\xf5\x38\x76\xda\xbd\xf1\x3e\xc7\x4e\x4d\x82\x50\xce\x6f\xbd\x11\x43\xef\x6c\x2a\x72\x0e\xe7\xfc\x36\xe4\xb4\xb6\x53\x45\xfe\x5a\xe7\xd2\xca\x8c\x39\x43\x4f\x38\x9d\x80\x02\x93\xa4\x06\x72\x35\x49\x13\x9c\xb7\xc6\x99\x49\x6e\x54\x05\xdf\xea\x39\xa0\x01\x24\x99\x28\x94\x37\xca\xdc\x38\xb3\xd6\x3a\xc0\x6a\x57\x10\xa1\x67\xa1\x92\xad\xe5\x80\x43\x66\x15\x25\x19\x24\xc6\x19\x18\x60\x2c\x1b\x40\xb4\x29\x9e\x9d\x10\xcd\x1f\x32\x01\x32\x48\x9d\xb7\x76\x2f\xaa\xf8\x45\x63\x43\xe7\x00\x87\xde\x90\xa5\xa7\x0c\x00\x6f\x09\x01\xf1\xb4\xc6\xee\xde\x32\x52\x00\x10\x60\x4d\x7b\x69\x13\xad\x9f\xb6\x6e\xdf\x3a\xe2\x76\xac\x9e\x6d\xa2\x90\x1a\xd6\x96\x1a\x9b\x86\x49\xaa\xd6\x5e\x4d\x78\x64\x20\x2a\x23\x7d\x96\xf2\x86\xa9\xa9\x7a\x0e\xa5\x05\x2c\x24\x57\x3e\x32\x20\x16\x97\xa0\x0f\x04\x34\xf4\x12\xec\x26\xa4\x6d\xae\x69\x1d\x96\xc0\x14\xe6\xa4\x0c\x08\x89\xe7\x3c\x02\xb8\x9c\x85\xac\x02\x11\x81\x8c\x4c\x0b\x27\xd4\xad\x43\xed\x5c\xc7\x7e\x09\x9b\xe9\x95\x60\xe3\xd5\x34\x02\xd6\x4c\x14\x67\x42\xf2\x4e\xe2\xc4\x57\x91\x1b\xd6\x4d\x58\xc4\xca\xa0\xf2\x01\x56\x5c\x2c\x7a\xe8\x31\xb7\xf6\x3c\x01\x24\x55\x46\x95\xde\xda\xf4\xb3\x9e\x86\x30\x86\x5e\x86\x87\x92\xd5\x12\x51\x3a\xd5\x40\x2d\xc3\x0a\x77\x4d\xc0\xa8\x2e\xaa\x70\x16\xa7\xa3\xd4\x01\xb3\xa4\x13\x34\x88\x7a\xa5\x74\xbd\xb7\x8a\xfb\xe4\xcb\xea\x84\xb8\x38\x79\x6b\xb3\xab\x68\xef\x9a\xd2\x40\x22\xd6\x7e\x62\xa2\x8f\x1b\x0f\xae\x36\x6a\x54\x53\xc6\x75\x70\x72\xbf\x90\x96\x07\x17\x17\x1b\xf5\x0c\xd4\x75\x6b\x29\xd2\x86\xac\x78\x29\x31\xc5\x52\x8b\xf9\x91\xf6\x88\x09\x8a\x8c\xc4\xca\xc4\x68\x1a\x75\x28\xda\xa0\x33\x05\xea\xf5\x45\x18\xc9\x38\x24\xd3\xcb\x90\x1a\x8e\xa5\x03\x1c\xbc\xc6\x3d\x91\x49\x57\xa7\x94\x49\xed\xaa\xd1\x87\x48\x82\x23\xaf\x54\x71\xca\xa0\x56\xb1\xea\xea\x98\x18\xcf\x33\x4f\x5a\x35\xf4\x12\x2b\xcd\x38\xb5\x07\x4f\x78\xb0\x19\x2a\x6d\x99\x07\xea\xe6\x87\x7a\x45\x46\x14\x89\xff\x33\x3c\x33\x6d\xb7\x9c\xef\x1b\xf3\x7d\x63\xbe\x6f\xcc\xf7\x8d\xf9\xbe\x31\xdf\x37\xe6\xfb\xc6\x7c\xdf\x78\xfd\xf7\x8d\xbf\x1c\xfe\x0a\x00\x00\xff\xff\x36\xe3\x42\xc2\x8d\x13\x00\x00")
+
+func fontsEliteFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsEliteFlf,
+ "fonts/elite.flf",
+ )
+}
+
+func fontsEliteFlf() (*asset, error) {
+ bytes, err := fontsEliteFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/elite.flf", size: 5005, mode: os.FileMode(420), modTime: time.Unix(1559099119, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsEpicFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\xdd\x6e\xdb\x36\x14\xbe\xd7\x53\x7c\x08\x02\x94\xc4\x92\x12\x4e\x8b\xa2\xd9\x95\x87\xa1\xbb\x1b\xb0\x07\x20\xc0\x29\x36\x6d\x0b\xb3\xe5\xc0\x92\xd7\x06\xe0\xc3\x0f\x3c\x3c\xa4\xfe\x63\x3b\xe9\xdd\xec\xd6\xd6\x11\x75\xc4\xf3\xff\xf1\x50\xca\x6a\xbb\x7a\xc8\x6f\xf1\x88\xaf\x98\x7d\xc2\xec\x0b\x66\x5f\xb2\x6f\xcf\xc5\x02\x4f\x2f\xf8\x7d\x9b\x1f\x97\x16\x7f\xe6\x87\xba\x28\x2b\xcc\x1e\xd4\xe3\xe7\x2c\xfb\xa3\x58\x6f\x6d\x8d\x83\xdd\xda\xbc\xb2\x78\xf8\x38\xc3\xfd\x3d\x66\x0f\xf8\xed\xb8\xc6\xec\xf1\xf1\x73\xf6\x97\x3d\xec\x8a\xaa\x2a\xf6\x25\x8a\x0a\x1b\x7b\xb0\x4f\x2f\x58\x17\xff\xda\x12\xf5\x1e\xbb\xfd\xb2\x58\xbd\xa0\xde\x14\x15\x56\xfb\xb2\xbe\x43\x5e\x61\xbb\x2f\xd7\xfe\x58\x6f\x6c\x46\x0c\x85\x3d\x7c\xa8\x50\xe6\x3b\xeb\xe7\x78\xde\xe6\x0b\xbb\xc4\xbe\x44\x8e\xc5\x7e\xb7\xb3\x65\x8d\x6d\x51\xda\x8f\x59\xf6\xed\xc7\xf3\x36\x2f\xf3\xda\x4b\xdb\xaf\xb0\x2a\x0e\x55\xb8\xf6\x6b\xe6\x6d\xc3\x3d\x6e\x76\xf9\xba\x58\xa0\x3c\xee\x9e\xec\xe1\x06\xab\xfd\x01\xab\x62\x6b\x51\x2c\x6d\x59\x17\xab\x62\x41\x37\x67\x39\x00\xdc\xa3\xda\xec\x8f\xdb\x25\xf2\xed\xf7\xfc\xa5\xc2\x93\xc5\xdf\xf9\x87\x3b\xba\xa9\xdc\x7f\xcf\x6e\x03\x53\xbd\xb1\xb8\xd9\xe4\x87\xe5\xd3\x36\x2f\xff\xb9\xf1\x0e\x78\x3e\x14\x65\x5d\x79\x1b\x72\xd0\xe8\x1d\x9e\x8e\x35\x16\x79\xf9\xa1\xf6\xd3\x54\xbb\x63\xb5\xb1\xcb\xec\x31\xcc\xb0\xb1\xc5\x7a\x53\x7b\x8d\x73\x2c\x36\xf9\x21\x5f\xd4\xf6\x90\x7d\x7d\xe5\xe2\x1d\xca\x7d\x8d\xa2\x5c\x6c\x8f\xcb\xa2\x5c\x63\x69\xab\x85\x2d\x97\xf6\x50\x65\xb3\x4f\x74\xdb\x2e\xff\x41\x96\x63\x6b\xcb\x75\xbd\x81\xb0\x3f\x22\x73\xdb\x69\x95\xc4\x2f\xc8\xb1\x3a\x2e\xd7\x16\xab\x7c\x51\xef\x0f\xd9\xec\x0b\xcd\xb0\xb4\xab\xfc\xb8\xad\x83\xb2\xbb\xfd\xd2\x92\xe1\x29\x54\x91\x2d\xb8\xd2\xeb\xd7\x99\x37\xcb\x6e\x6f\xe7\xa7\xbe\xf3\x0c\x06\xf3\x4c\x40\xce\x33\x07\xd7\xfe\x11\x46\xc6\xab\x44\x01\x81\x3b\xde\x40\xf7\x40\x3b\xa7\x40\x57\x3d\xc3\xb9\x47\x22\x0c\x7f\xfd\x89\x80\xa4\xaf\x3f\x31\x0e\x8e\xbe\x24\x3a\x32\xca\x70\x45\x18\x39\x76\x05\x8e\xff\x85\xd9\x8c\xa4\x6f\x12\xd8\x92\x4a\xf7\x90\x18\xe3\x8c\x33\xc6\x78\x63\x60\xfc\x47\x79\xcb\x05\x8d\x92\x00\xff\x81\xb7\x52\x69\xcf\x2b\xbd\x57\xb4\x09\x9f\xe0\x11\xaf\x67\x47\xca\x3c\xd1\x4c\x28\x3d\xcf\x84\x04\x14\x14\x8d\x28\x04\x77\xf9\xa3\x27\xe8\x88\x79\x46\x47\x21\xe7\x99\x56\x1d\x57\x45\x5f\x45\x47\x29\x63\x34\x51\x02\x5a\x41\xd2\x98\x06\x4f\xe6\x0f\xda\x4b\xf4\xd3\xfa\x51\xb2\xcd\xcf\xe8\xc7\xbc\xea\x4a\xab\x46\xdb\x6e\xf4\x39\x8c\xd3\x3f\x1c\xb4\x20\x47\xb2\xee\xfe\x6e\xe1\x39\xd8\xf9\x7c\x06\x0d\x1d\x74\x63\x4f\xa5\xec\x21\x1e\xdd\xe1\x91\x88\x21\x6c\xce\x78\x6e\xa3\x92\x2b\xe6\xed\x60\x7a\x0e\x1d\xfc\x1b\x67\x8a\xae\xf5\xb1\xf7\xe1\x8f\x39\x92\x52\x24\x8c\x37\x5e\x67\xf1\xc1\xe1\x5a\x75\x92\xa5\x97\x2b\x21\x41\x99\x24\x4b\x39\x83\x90\x72\x85\x82\x24\xbb\x0c\x1d\x92\x12\x72\x98\x2b\xaf\xfd\x74\x82\xd3\xcf\xac\x2e\x11\x92\x35\x66\xad\x7c\x9d\xf9\x22\xf9\xad\xe2\x1f\x64\x36\x70\x66\x66\x7b\x62\x2c\xb3\xb9\x9a\xc0\x45\x08\x04\x20\x12\x3e\x5a\x8c\x44\x74\x3b\x91\x42\x41\xc9\x40\x7a\x31\x0c\x55\x10\xc6\xc8\x00\x58\xa6\x67\x3c\x6b\x1d\x8b\x87\x62\x1e\x42\x2e\xb9\x74\x28\x40\xa3\x84\x21\x0c\xe1\xb2\x31\x6a\x42\x6b\x05\x13\xb5\x26\xf3\x82\xd6\xc1\x2d\x08\x69\xed\x53\x38\xb8\xc6\x13\x21\xa1\x05\xe5\x83\xf1\x2e\x8c\x80\xa2\x7a\x5a\xb3\x88\x46\x86\x8e\x2e\xd4\xa1\x9c\x09\xb4\x64\x70\xbe\x37\x1d\x22\xb9\x56\x7a\x06\x45\xf5\x4e\x20\xc0\x32\xd4\x08\x52\x99\x84\x2c\x60\xfd\x39\x86\x92\xc1\x54\x31\x9a\xc6\xdc\x4a\xe5\x44\xdc\x22\xc5\x33\x81\x6f\x4c\xf5\x7e\x39\xf5\x42\x6d\x8c\x57\x92\x42\xed\xab\x8f\xc8\x68\x31\x43\xaf\x6e\x19\x24\xd9\x20\x43\xe4\xa4\x41\x49\x06\x54\x92\x21\x46\x65\xb8\x60\xbb\x46\x54\x82\x26\x16\xc4\x10\x20\x48\x8f\xcb\x98\x0e\x8c\xe4\x88\x93\x2b\x55\x72\x6a\x83\xcd\x2a\xe5\x21\x97\x04\xb4\xe9\x15\x45\xdb\x0e\x24\x3b\x48\x46\x47\xb7\x50\x82\x03\x86\x0b\xec\x98\x92\xd1\x9f\xc2\xc5\x29\x52\x6a\x7b\x06\x77\x5e\x3c\xc6\xa1\x64\x70\x3a\x0a\x46\x63\xb7\x74\xc1\xd0\x44\x1f\xcb\x08\x3c\x11\x77\xa2\x25\x71\x6d\x08\xcb\x24\x27\x54\xb3\x26\x25\x54\x6b\x0e\x0d\x8c\xca\xc1\x59\x97\x13\xad\x45\x2d\xae\x6a\xe3\x02\xe5\xa8\x82\x46\xf5\x5b\xa2\x13\x11\xa1\xa5\x2a\xc2\xac\x5f\x92\x52\xf5\xb5\x8a\xaf\x5d\x7b\xa9\xb4\x79\x34\xa2\x46\xd3\x4d\xb0\x98\xa8\x96\x61\x9d\xfd\xd4\x0a\x3a\x88\x75\x70\x42\x48\xd5\xac\xf6\x0c\x2c\xc1\x54\x8a\x7b\x5c\xeb\x87\x59\x30\x5e\xfb\x0d\xcc\x83\x01\x3d\xe5\x1a\xd7\x25\x8f\x36\x0c\x92\x2c\x76\x14\x7e\x2a\x67\x37\x59\x97\x62\xb4\xb4\x49\x46\x30\x82\x64\xc4\xb6\x45\xc4\x40\x39\xc8\x98\xcf\x4e\xb1\x91\xa3\x32\x5e\xc3\x30\xc7\xcc\x93\xa4\x08\x0e\x6b\x96\xab\x69\xe0\xe7\x25\x51\x37\x6a\x72\x38\x1a\xaf\x38\x20\xae\x83\xae\xe3\x4c\x45\xbc\x62\xa2\x2e\xcf\xc2\xe2\xa8\x31\x2d\x85\xc9\x57\x17\xda\xf1\x2e\x19\x32\x91\x2a\x4e\xfc\xae\x78\x30\xaf\x27\x75\xca\x41\x73\xaa\x7d\x48\xa2\x1d\xa3\x6e\x2f\x1f\xdf\x9f\xbb\x26\x7e\x08\x49\xa9\x46\x15\x03\x87\x18\xe9\x24\x47\x48\x13\xda\x15\x9e\x61\x2c\x1e\x03\x19\x48\x32\x12\x8e\x38\x24\x1c\x19\x21\x9d\xf6\x31\x92\x69\x81\x56\x23\xf1\x68\x7c\x05\x6e\xcf\xc9\x2b\x9a\xdb\x44\xea\xd6\x52\x0d\x22\xd5\xa0\x07\x15\xce\x73\xee\xcc\xe7\x99\x33\x2a\x86\x71\x42\x86\xe0\x65\xb0\x9f\x36\x3f\xab\x06\x39\xaf\xe8\x13\x72\x85\xb6\x10\xa1\xda\xc2\xff\x80\x8e\x46\xba\x41\x39\x9e\xc6\xab\x96\x1d\xa2\xc9\x2b\x6f\x93\x88\x4d\xae\x8e\xb3\x09\x0d\x9d\x4a\x5e\xc7\x86\x58\x12\x77\x92\x21\x07\xb9\x7b\x1a\x77\x7b\x00\x32\x24\x4f\xd6\xc7\xb0\x06\x93\x0c\xc8\x34\x85\x91\xa9\x3e\x68\x8a\xf7\xd5\xf9\xf9\x76\x28\x9d\xec\xf0\x19\x16\xed\xd0\xea\x9d\x76\xc4\xed\x1e\x85\x46\x24\x3b\x68\x41\x64\x3b\xf4\x1b\x31\xd1\xf4\x1f\x3f\x70\x06\xb6\x7b\xae\xc1\x93\x88\x9f\x88\x25\x5d\x52\x1a\x31\xb6\x6d\x4d\x11\x9b\xc0\xc4\xf7\xe7\xd5\x05\x32\x3a\x3d\x12\xf5\xd4\x2a\x3e\x18\x89\xdd\x37\x77\xda\x6f\x90\x61\x92\xf2\x02\xa9\xce\x9b\xea\x4f\x98\x70\x91\x1d\x82\x75\x0b\x1a\xfb\xee\x4c\xf1\xa3\x10\x93\x1e\x51\x08\xca\x27\xcf\x1b\x76\x7d\x72\x1a\x4b\x2e\x92\xd1\xf6\xca\x78\x52\x8c\xfa\xaa\xc9\xdd\x33\x36\xbd\x48\x9b\x5e\xa6\xe2\xfe\x57\x9c\xc4\xdd\x58\x1c\xa9\xfa\x62\xa8\xc7\x8e\xa2\xa9\x95\x41\x4f\x4f\x5b\x34\xcd\x84\x0e\x6b\x45\x6c\xcf\x53\x7f\xce\x06\xa7\xbd\xa6\xe6\xbd\x75\x67\xe1\x69\xab\xd6\xd4\xa4\x64\xab\xdd\xe8\xb1\x9d\xdd\x1d\xd5\xa8\x59\x16\x4a\xf3\xe0\x59\xbf\xf3\xde\xb3\x97\xcb\x89\x2e\xac\xc8\xce\xa3\xbf\x98\x4f\xd3\x3f\xd7\x16\xfe\xda\xc2\xbf\x4d\xc6\xb5\x85\xbf\xb6\xf0\xd7\x16\xfe\xda\xc2\x5f\x5b\xf8\x6b\x0b\x7f\x6d\xe1\xff\x07\x2d\x3c\xc2\xeb\x17\x11\xde\x12\x49\xf2\x84\x0a\xab\x8f\xe6\xf5\x48\x8a\xc0\x32\x7c\xa8\x3e\xf8\x73\x84\xd6\x1f\x21\xf4\xc6\xa2\x45\x61\x2d\xe3\xd7\x79\x32\xbc\x03\x73\xa1\x89\x77\xf4\x72\xcc\xd0\x20\xbd\x24\x1c\x4a\x4b\x6f\x78\x95\xd1\x46\xf9\x76\x4b\x91\xeb\xde\xd8\x67\xb3\x46\x88\xe5\x2f\xa3\x91\x53\xe8\x37\xda\x76\x9c\xd1\x27\x5f\x22\x63\x14\x61\xcf\x58\x13\xc6\x64\x5c\x84\x1a\x6f\x94\x71\xf5\xd5\xf4\x1a\x3d\xdc\x1b\xa5\xfd\x4e\x18\x55\xcd\x68\x60\x70\x71\x17\x74\x7a\x8d\xfe\x2f\x00\x00\xff\xff\x8c\x73\xa3\xb7\x7e\x26\x00\x00")
+
+func fontsEpicFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsEpicFlf,
+ "fonts/epic.flf",
+ )
+}
+
+func fontsEpicFlf() (*asset, error) {
+ bytes, err := fontsEpicFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/epic.flf", size: 9854, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsFenderFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x18\xdb\x6e\xdb\x36\xfb\x9e\x4f\xf1\x21\x48\x41\x1b\x3f\x45\xfd\x2e\xd6\x75\x5b\x8a\x41\x37\xdb\x0b\xec\x56\x17\x52\x6c\xd9\xd6\x6a\x4b\x85\x2c\x23\x2d\xc2\xbc\xfb\x40\x7e\x3c\x8b\x52\xec\x06\x31\x4f\x22\xbf\xf3\x89\xdc\x9f\xf6\x1f\xeb\x47\xf8\x0c\x9f\x60\xf3\x2b\x64\x1b\xd8\x7c\x24\x7f\x37\xdd\xae\x19\xe0\xf9\x07\xfc\xb3\xed\xfb\xb1\x19\xe0\xb7\xfc\xf7\x5f\x60\xf5\xef\xd7\xa1\x1e\xc7\xa6\x2b\x4e\xf5\x0b\x3f\x34\xfd\x70\x68\xc6\xfe\xa5\xe3\xcd\xee\xba\x26\x40\xfe\xfa\xfe\xed\x54\x77\xf5\xd8\xf6\x1d\xf4\x7b\xd8\xb7\xc3\x65\x84\x53\xdb\x35\x7f\x10\x89\x05\x32\x78\x38\xd7\x87\x76\x0b\xdd\xf5\xfc\xdc\x0c\x0f\xb0\xef\x07\xd8\xb7\xa7\x06\xda\x5d\xd3\x8d\xed\xbe\xdd\xaa\xc3\xa4\x06\x00\xc8\xe0\x72\xec\xaf\xa7\x1d\xd4\xa7\x97\xfa\xc7\x05\x9e\x1b\xa8\x6a\xca\xd4\xa1\xae\x7f\x21\x8f\xb8\x69\x3c\x36\xf0\x70\xac\x87\xdd\xf3\xa9\xee\xbe\x3e\x40\x96\xc1\xb7\xa1\xed\xc6\x0b\xd4\x17\xa8\x41\xad\x32\x78\xbe\x8e\xb0\xad\x3b\x3a\x4a\x30\x97\xf3\xf5\x72\x6c\x76\xe4\x33\x42\x38\x36\xed\xe1\x38\x4a\x8a\x6b\xd8\x1e\xeb\xa1\xde\x8e\xcd\x40\x3e\x2d\x7c\x64\xd0\xf5\x23\xb4\xdd\xf6\x74\xdd\xb5\xdd\x01\x76\xcd\x65\xab\x44\x76\x21\x9b\xff\xab\x63\xe7\xfa\xbb\xe2\x1c\x4e\x4d\x77\x18\x8f\xb0\x6a\xbe\x9b\xcd\xdb\xfe\x7c\x6e\x3a\x14\xcc\x65\x0d\xff\x83\x1a\xf6\xd7\xdd\xa1\x81\x7d\xbd\x1d\xfb\x81\x64\x1b\x05\x61\xd7\xec\xeb\xeb\x69\x44\x62\xcf\xfd\xae\x51\x8c\x8f\xc7\xf6\x02\xfb\xbe\x1b\x61\x75\x6a\xbf\x36\xf0\x90\x9d\x61\xf3\xe9\x01\xfa\x4e\xc1\xad\xbb\x9d\x82\xbb\x26\x9b\x8f\x0a\x0a\x4a\x5a\x92\x1f\xa0\x25\x40\x1e\x1f\x1f\x8b\xe5\xa6\x20\x42\x80\xdf\x00\x04\x23\xd9\x14\x84\x52\xa0\x14\x67\x66\xf5\x96\xbe\x20\x20\x40\xc8\x05\x2a\xff\x60\x7e\x3e\x3d\x88\x5f\xa0\x20\x9c\x0a\x2a\xa8\xa2\xca\xae\x41\x25\xa8\x60\x78\x00\x57\x0b\x02\x76\x9f\x3d\x5b\x90\x0a\x00\x0c\x33\x42\x63\x12\x1a\x86\xea\x91\x59\x00\x66\x91\x7b\x03\x89\x9c\x32\x44\x8d\x74\xf2\x8a\x32\x60\x86\x94\x82\x54\x8c\x89\x84\x60\x94\xc4\x3c\x09\xa6\x1a\x49\x81\xdc\x64\x78\x53\x2d\xf2\x24\xb8\x06\xa5\xdb\x82\x54\x42\xb3\xad\xd9\x2b\x08\x30\xd9\x72\x2b\x3d\xbb\xd5\x90\xc2\x40\x20\x57\x0c\xa1\x66\x99\xc8\x32\x2d\x27\xa5\x02\x10\x40\x43\x91\x23\x72\xb5\x59\x64\x76\xec\x41\xf7\x70\x4c\x1a\x86\xc8\x1c\x77\xde\xb1\x0c\x31\xc7\x80\x96\xc0\x71\x1e\x09\x0b\x00\x28\x55\xbd\x96\x2d\x45\x65\xcb\x4e\x59\xd4\x8c\x09\x72\x2a\x75\x88\x12\x16\x89\xbe\x62\x8c\x25\x55\xa8\x0d\x86\x6a\xbb\x09\x3a\x2e\xac\x8e\x6c\xa7\x68\x11\x4c\x89\xd6\x18\x1d\x47\xeb\xc8\x73\xb5\x6f\xb5\xe2\x9c\xa7\x50\x31\xaa\x4f\x82\xb5\x57\xb9\x22\xfc\x15\xca\x39\xf7\x6c\x2d\x30\x53\x00\xc8\x8d\x59\xe7\xb9\xb1\xf0\x3c\xe7\x92\x4e\xee\xa0\xc0\x74\x18\xc2\x52\xd0\x84\xd0\xde\x89\x1e\x22\x65\x34\xa1\x86\x2f\x51\xc3\x18\x63\xd6\xb3\x10\x90\xe6\x4f\xae\xa8\xf3\x95\x98\x3f\xaf\x82\x43\x8e\x4b\x52\x72\x72\xa0\x25\x88\xbd\xe2\x2d\x3a\xe6\x3b\xad\xa0\x1e\x3a\x2d\xcf\xf5\x3a\x5b\xad\x20\x58\x93\x34\x04\x44\xf8\xa3\x34\x18\x3c\x62\x24\xe1\x82\xa2\xb6\x45\x30\xd6\x08\x81\x6e\xe6\x43\x2b\x59\xd8\x43\xe3\x3d\xda\xc3\x98\xf6\x36\x70\x33\xf3\x2d\x32\x47\xed\x97\xcc\xfa\x1b\xb5\x04\x47\x1e\x98\x06\x17\xa2\x0a\x81\x27\x85\xac\x14\x46\x5d\xb8\xc5\x11\xe7\xa1\x4c\x02\x21\x5b\xef\xe4\xda\x2b\x85\xf2\x46\x6b\x79\xd2\x63\xd2\x09\x42\x22\xe3\xa5\xff\x21\xcf\xa1\x2c\xdd\x5c\xda\x3f\xc7\x05\x6b\x42\x80\x3b\x0a\xc2\xf5\x54\x2e\x70\xdf\x01\x62\x87\xb0\x56\x29\x34\xc7\x36\x77\xd8\x88\xf0\xf4\xf4\xf4\x04\xf1\xba\x72\x3d\x6e\x32\x52\x0a\xb0\x91\x22\x65\xce\xd7\x66\x46\xca\xee\xf8\xac\xa9\x6a\xda\xb8\x4f\xc2\xdc\xd0\xd2\x35\xeb\xff\x08\x8d\xba\x73\x5c\xf3\xa6\x16\xed\x2a\x38\x2e\xb9\xb8\x1d\x1a\x07\x0b\x2d\x48\xc4\x36\xac\xc6\x20\xc8\x54\x60\x54\x97\x2b\xdc\x09\x4a\xe8\x08\x85\xc0\x9c\xb3\xbe\xc7\xa9\xdc\x5b\x19\x2a\xac\x46\xa9\x1f\xf5\xad\x3e\xe5\x90\x2f\xc4\x4d\x4a\x91\x2b\x67\xff\xb3\x43\x81\xa1\x79\x41\x6e\xf7\x40\xa3\x68\x68\x0b\x72\x53\xfc\x68\xdf\x14\xc2\x86\x53\x21\xbe\x7c\x01\xab\x05\xe3\x1a\x72\x6f\xe4\x15\x09\x68\x81\xf2\xd2\x23\x6d\x6b\x0b\x66\x5b\x62\xea\xd2\x1a\x28\x4b\x9e\xe7\x22\xb0\xb1\xd4\x8c\xdb\x59\xec\xb9\xd1\xcc\xa2\xf0\x30\xf8\x20\xcb\xd2\x87\x5f\x96\x3e\xf8\x72\x02\x3d\x9c\x18\x5b\x74\x31\x10\x62\x03\xbc\xd7\x16\x6d\x15\x10\x38\xae\x3d\x17\xf8\xc9\x14\x44\xc2\x4f\x84\x4b\xc3\x9a\xd1\x78\x6c\x78\xd6\xf4\x95\xe5\x52\xb4\xba\x89\xc4\x9b\x8d\x88\xdb\x78\xe2\xc7\x39\x8b\x80\x3b\xf8\x8b\x69\xfa\x1e\x3f\x91\x05\x99\xe0\xef\xfa\x89\x1f\x12\x02\x03\x4c\x8c\xab\x1b\xa2\xbc\x4e\x4a\xd2\xeb\x0a\xa2\x53\x94\x29\x6c\xe4\xcc\x78\xa3\x9c\x99\x02\x47\xb6\x65\x9e\xb0\xbb\xc8\x08\x8d\x2b\x06\x34\x87\xa4\xe6\xce\xe6\x15\x02\x8d\x04\x11\xe6\x06\x4d\x94\xf2\xe2\x69\x41\x28\x92\x5a\x59\x38\x66\xd7\x9f\x26\x84\x80\x84\xed\xb2\xeb\x72\x08\x99\x83\xf6\x53\x6a\x13\x7e\xcd\x68\x65\xeb\x04\x6b\xcb\x46\x1e\x67\xab\xd0\x96\x84\x5f\xf8\xa6\xfa\x99\x02\xde\x95\x1d\xae\xde\xd0\xa2\xd0\x25\x87\xd6\xa8\xe7\x5f\x51\xc9\xeb\x5d\x53\xa7\x7d\x50\x75\x42\x50\x06\x71\xed\x6e\x20\xfc\x5b\x4e\xb4\x31\x5d\x3f\xcd\xb7\x52\x4a\xb6\x38\xac\x50\x49\x0b\x4d\x52\x9c\x78\x87\xe1\x48\x9d\x49\xa8\x15\x26\xbe\x85\x8c\x60\x16\xfd\x91\x1f\x74\x5c\x11\x33\x1f\x13\x62\xae\x25\x7e\xe6\xe9\x51\x52\x91\xbe\xf3\x39\x47\xf2\xb2\x8d\x21\xde\x15\x03\xef\xb0\x31\xd1\x30\x02\x61\xda\x84\x5c\x46\x80\xb4\x39\xc8\x7b\xe3\x93\x15\x02\x06\x5e\xf0\xe6\xe8\x0e\x33\xf4\xcf\x22\xf6\xaf\x5e\xc1\x65\x0e\x2a\x14\xe6\x5d\xf2\xf7\x6a\xfe\x34\xff\xfa\x6e\x7e\xe3\xd5\xd9\xcd\x29\x5d\x70\x04\x9b\x4f\x63\x8a\xc3\x04\x89\x35\x4e\x15\xd5\x38\x5c\xa5\x27\xbe\x1c\xfe\xab\x09\xc5\x37\x10\x1e\x83\xd2\x4a\x5b\x33\xb6\x72\x37\x06\xfc\x77\xe9\xfb\xdd\x02\x23\x49\x24\xa9\xb4\x3e\xe0\xce\xf2\xf4\x66\xdb\x98\x7f\x64\x88\x35\x8d\x15\x41\x64\x1b\xe0\x7c\xd3\x2f\x04\x97\x99\x42\x27\xab\x7c\x2f\x73\xa6\x0a\xce\x58\xdd\x23\x49\x35\xc3\x94\xab\x06\x8c\xb7\xc7\xc9\x63\xca\x94\xeb\x57\xe6\x61\xb2\xa2\x74\xad\xef\x9f\x33\x91\xc2\x65\x27\x5b\x86\x2b\xdc\xe1\x1a\x40\x18\x6c\xd2\x91\x22\x92\xc6\xcc\xbd\x44\x41\xba\x4f\xc5\xba\xbc\x50\x89\xc9\x96\x1c\xf9\xb2\x34\x62\xc0\x8a\x22\x53\xb5\xd8\x84\x1d\x14\x11\x89\x12\x62\xc6\x98\x93\xb4\x61\x09\x81\xaf\x3a\x73\x29\xf2\x7d\x49\x19\x6b\xd1\x1b\xcc\x90\x01\x88\xe0\x79\xc6\x8f\x50\x46\x71\x58\x3b\xa0\x84\x72\x2f\xc9\xfb\x8e\xfe\xfa\x2a\xa7\xaf\xaf\x72\x55\xb6\x6e\x66\xbe\x85\x27\x84\x48\xff\xd4\xc7\xb7\x37\xdc\x2b\x7b\xb9\xf4\xf6\xe6\x66\xe6\x5b\x4c\x00\x4e\x3f\xc0\x07\x28\x88\x6c\xe3\x3d\xd3\x13\xea\xed\xc6\x7b\xc0\x31\x0f\x26\x6a\x66\x9f\x4b\x0a\xe2\x3f\x96\xb8\xb7\x91\xe9\xcb\x48\x34\xd3\xcf\xae\xca\x63\x52\x0f\x42\xe2\xd6\xb7\x36\x07\x26\x75\xf8\x66\x30\x92\x53\xf3\x84\x65\x3f\xdf\x5f\x85\x68\x30\x3f\x1d\x29\x53\x64\x38\x37\xbe\xb9\x8a\x48\x4b\x14\x1f\x9b\xc2\x35\x23\x94\xe9\xb5\xb0\x28\xc8\x7f\x01\x00\x00\xff\xff\x82\xd6\x40\xe2\xfd\x1b\x00\x00")
+
+func fontsFenderFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsFenderFlf,
+ "fonts/fender.flf",
+ )
+}
+
+func fontsFenderFlf() (*asset, error) {
+ bytes, err := fontsFenderFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/fender.flf", size: 7165, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsFourtopsFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x55\x7f\x8b\xdb\x38\x10\xfd\x5f\x9f\xe2\x5d\x08\x24\x4b\x57\xd1\xa6\xcd\xfd\xb1\xa5\x1c\x2a\xdc\xf5\x03\xdc\x5f\x7b\x20\xd0\x2a\xb1\x92\x98\x3a\xf6\xe2\x1f\x74\x0b\xc2\x9f\xfd\xd0\x48\xb2\x95\xb4\xdb\x83\x63\xbd\x8e\x3c\x9a\x79\x7a\xf3\x66\x3c\x3e\x56\xc7\xf7\x66\x89\x1d\x3e\x60\xbb\xc5\x03\xb6\x3b\xf6\xa5\x19\xda\xbe\x79\xe9\xb0\xff\x8e\xbf\x4d\x5d\x98\xaa\xf2\xbf\x5d\x73\xc1\x4e\x3c\xee\xf0\xa9\xa5\x07\x79\x2a\xdb\xde\xec\x37\x43\x77\xd8\xd8\x62\xf8\x83\x7d\x29\x4f\x95\xed\xd1\xda\xca\x9a\xce\xe2\xfd\xe6\x01\x9c\xe3\xf3\x70\x1a\xba\x1e\xbf\xdf\x63\xfb\xf8\xf8\x81\xfd\x69\x7a\xfb\x11\x8f\xf8\xfc\xd2\x7a\xc3\x8e\xb1\xbf\x5e\x5f\x2a\x53\x9b\xbe\x6c\x6a\x34\x47\x1c\xcb\xb6\xeb\x51\x95\xb5\xfd\xc8\x3c\x39\x70\x2c\x2e\xe6\x54\x1e\x50\x0f\x97\xbd\x6d\x17\x38\x36\x2d\x8e\x65\x65\x51\x16\xb6\xee\xcb\x63\x79\xa0\x60\x66\x00\x80\xa3\x3b\x37\x43\x55\xc0\x54\xdf\xcc\xf7\x0e\x7b\x8b\x67\xb3\xba\xa7\xa0\xba\xf9\xc6\x96\xc1\xa9\x3f\x5b\x2c\xce\xa6\x2d\xf6\x95\xa9\xbf\x2e\x3c\xd1\x97\xb6\xac\xfb\x0e\xa6\x83\x01\x59\xef\xb1\x1f\x7a\x1c\x4c\xbd\xea\x3d\x4c\x77\x19\xba\xb3\x2d\xd8\x2e\x20\x9c\x6d\x79\x3a\xf7\x9e\xb1\xc1\xe1\x6c\x5a\x73\xe8\x6d\xcb\x3e\xfc\x62\xf3\x1e\x75\xd3\xa3\xac\x0f\xd5\x50\x94\xf5\x09\x85\xed\x0e\xb6\x2e\x6c\xdb\xb1\xed\x96\xc2\x2e\xe6\x95\x32\x47\x65\xeb\x53\x7f\xc6\xda\xbe\x26\xe7\x43\x73\xb9\xd8\x3a\x08\xd3\xdd\xe1\x1d\x0c\x8e\x43\x71\xb2\x38\x9a\x43\xdf\xb4\xec\x21\x1c\x5c\xd8\xa3\x19\xaa\x3e\x90\xbd\x34\x85\xa5\xc4\xfb\x73\xd9\xe1\xd8\xd4\x3d\xd6\x55\xf9\xd5\x62\xc1\x2f\x78\x58\xa0\xa9\x09\xd6\xd4\x05\xc1\xde\xb1\xed\x8e\x40\x82\xd0\x9e\xfd\xd5\xa9\x8c\x2d\x97\x32\xff\x97\xcc\xd1\xb5\x91\x8c\x1e\xdc\xcd\x2e\x36\xd8\x2c\x25\xe3\x8e\x3b\x3e\xfd\x60\x85\x55\xf2\x5e\x8f\x92\xe9\x3b\x5a\x4b\xb6\x81\x90\x6c\x29\x96\x92\x09\x78\x44\x78\xaf\x65\xf4\x5a\x6b\x5a\x4b\xe6\x7d\xe2\x25\x99\x8f\x70\x08\xff\x50\x52\x32\xe5\x17\x2e\xfc\x0b\x90\x41\x48\xc6\x9f\xb8\x7f\x54\x13\x28\xb1\x7a\xc7\x25\x5b\xae\x96\x93\x31\x5d\x42\x06\x13\xe3\x9c\xc7\x55\xee\x11\x93\x85\x07\x86\x80\x07\xf6\x87\x02\xc4\x67\x1c\x15\xf1\x01\x88\x86\xd2\x5a\x84\xdd\xe0\x20\x88\xa9\xbf\x69\xa7\x53\x94\x18\x95\x64\xb8\x17\x92\x09\x7d\x63\xc4\x27\xc9\x94\x16\x33\xbe\x0f\x15\x31\xd6\x45\x64\x2f\xe6\x38\x4a\xf6\xec\x43\xf4\xec\x2d\xbc\xf1\x1f\x6f\xcc\x20\xc6\xf1\x27\xbc\xd7\xe3\x5d\x3c\x51\xe5\xe1\x4a\xb2\x67\x9e\xdc\x83\x31\x08\x10\x35\x48\x6a\x90\x64\x5e\x0f\xef\xa7\x52\x2d\x66\x0d\x27\x21\xa7\xdd\xe4\x9d\xf2\xa4\x53\x7f\x9b\x4f\xf1\x3a\x2e\xbd\x8e\x6b\xa7\x7d\x57\x29\xad\x43\x1d\x00\x44\xf5\x15\xd1\x17\x5a\xab\x90\x0b\x08\x16\xb3\x20\x4a\x32\xc7\xf9\x27\xc9\x5c\xd2\x24\x95\x28\x14\x28\x94\x27\x97\x30\x95\xce\x85\x98\x54\xb8\xa4\xaf\xf3\x69\xb8\xb9\x44\x99\xf1\xa6\x05\xc8\x42\x8e\x6a\x3a\x9b\x22\x02\x36\xe7\x2e\xad\xe3\xc6\xe8\xc6\x1f\xfb\x62\x0c\x56\x32\x2b\x9d\x57\x9b\xfa\x7e\x4d\x6c\xd5\xc4\x06\x48\xb7\x8c\xa2\x02\x04\x1d\xa6\x04\x5c\xd6\x98\x13\x23\x15\x28\x41\xc5\x6d\xe5\x66\xba\xff\xd9\xce\x51\x65\xca\x31\x4a\xfa\x76\xe4\xd3\x2f\x22\xd5\x14\x19\xe4\x7b\xe6\x7c\xe3\x93\xce\x0a\xe7\xd5\x88\x72\x20\xfb\x99\x92\x4f\xe9\x85\xd3\xc4\xcd\x66\x30\x23\x76\xb2\x12\xb8\x22\x43\x68\x2e\x5b\x78\x0f\x35\xa7\x3a\x4d\x12\x3c\x21\x4e\x92\x64\x0c\x73\x40\x45\xe0\x2b\x52\xd9\xab\x96\x37\xcd\x3c\xb2\x9c\x0e\x10\x04\x40\xbc\xa6\xd2\xbb\x79\x8e\x69\x1a\x7b\xea\x66\xb6\xa6\x07\x8f\x4c\x06\x75\x35\x18\xa9\x18\x62\xf4\x38\x4a\x6b\x97\xb5\x0e\x75\x48\xa6\x7e\xaa\x58\x0c\x20\xff\xa9\x99\x49\x8c\x9f\xc0\x44\x6f\x21\x99\x12\x3a\x6b\x7d\x45\x63\x3e\xcc\x38\xe4\xde\x37\x6c\xe8\x1e\x2b\x23\x99\x13\xf9\xab\x97\xe4\x5b\xa5\xcf\x4b\x84\x58\x25\x3e\xe1\x3e\x43\xf8\x4c\xc4\xf5\xbb\x70\x13\x1a\x8b\x18\x0e\xca\x0e\xcb\x5f\x86\x99\xea\x9b\x8c\x62\x1a\xd7\x63\x12\x3f\x28\xea\xae\xa0\x7c\xda\x08\x74\x83\x22\x4e\xcc\x51\x22\xce\x8a\x5c\xab\xf9\xb3\x18\x0c\x3e\x6c\x9e\x0f\xd7\x34\xe7\x7e\xbf\xa6\x49\x73\x38\x74\xa6\xb8\xae\x43\xdc\x4a\x9b\xea\xea\x7d\xa6\x4d\x11\xba\xed\x0d\x28\x2d\x26\xcf\x91\xbe\x58\x13\xcd\x31\x7e\x52\x42\x43\x53\x6f\xbb\xf9\xf2\x39\xcc\x3d\x2e\x7c\x5b\xcf\x07\x68\xae\x79\x5a\x47\x2a\xf1\xef\xff\x2e\xfe\x0d\x00\x00\xff\xff\x60\x99\xf4\x95\xd7\x0a\x00\x00")
+
+func fontsFourtopsFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsFourtopsFlf,
+ "fonts/fourtops.flf",
+ )
+}
+
+func fontsFourtopsFlf() (*asset, error) {
+ bytes, err := fontsFourtopsFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/fourtops.flf", size: 2775, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsFuzzyFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x58\x4b\x8f\x1c\x35\x10\xbe\xf7\xaf\xf8\x0e\x2d\x19\xa4\x76\xe5\x21\x50\x84\x5b\x23\xb5\x04\xe2\xc0\x81\x1b\x27\x40\xf6\x64\x35\x4b\x36\x4a\x76\xc3\xce\x0e\x28\xe1\xf1\xdb\x51\x55\xd9\xdd\x76\x3f\xa7\x43\x2b\x69\x7b\x3a\x55\xae\xd7\x57\x0f\xe7\xf6\xdd\xed\xcb\x63\x8d\x57\xf8\x1a\x2f\x5e\xe2\x39\x5e\x55\xb7\x97\x4f\x9f\x3e\xd2\xed\xbb\x5b\xbc\xfe\x88\x1f\x2e\xc7\x7b\x7c\x7b\x7c\xc4\x17\x6f\x6f\xba\xb7\x97\xdf\x2e\xa7\xa7\x13\xfd\x7e\xb9\x7b\x4f\x97\x9b\xf7\x74\x3a\x7f\x59\xfd\x71\x7a\x3c\xdf\x3d\xdc\xe3\x05\x3d\x87\xb5\x78\xf9\xec\xfb\xd3\xeb\x67\xdf\x7c\x55\x55\x3f\x9d\x4f\x67\x9c\x3f\x1c\xef\xef\xce\x6f\x70\xf3\xe6\xf8\x78\xbc\x79\x3a\x3d\xe2\x7c\x7a\xc2\x9f\x77\x4f\x6f\x60\xbf\xc3\xc3\x87\xa7\xbb\x87\x7b\x57\xe1\x73\x1e\x3f\xec\xaa\x9f\x71\xc0\xd1\x00\xf8\x05\x07\x9c\x78\x83\x5f\x71\xc0\x9d\xec\xfe\xc2\x01\x0f\xb2\xfb\x1b\x07\x5c\x64\xf7\x0f\x0e\xb8\x17\xe6\x7f\x71\xc0\x8f\x55\x55\xd7\xdd\xd2\xdf\xae\x22\x4b\x5d\xe5\xe0\xd2\xcb\xb7\xf1\x05\x40\x5f\x42\x13\xa9\x98\x24\x58\x63\x4d\x57\xa1\x46\x8d\xf9\x45\xf8\xbc\x9a\xd1\x55\xf0\x0e\xce\xc1\x79\xf0\xc9\x00\x11\xe0\x9d\xee\xc5\x44\xc7\xf4\xce\xb7\xce\xb7\x51\x66\x7c\x8a\x7d\x57\xa1\x71\x8e\x20\x7a\x38\xd6\x20\x90\xfe\x86\x77\xaa\x18\x39\xd7\x18\x39\xcc\x0d\xcc\x5d\x57\x35\x96\x20\x16\x04\x6b\xc8\x90\x90\xf0\xca\x34\xbc\xaa\x66\xac\x62\xdb\x8b\x1c\x36\x4c\x64\x2d\x41\x24\x53\x8b\x96\xff\xad\x05\x94\x0d\xae\x0d\x68\x59\xb8\xf7\xb4\xcc\x4f\x5d\xa5\x92\x83\x15\xb1\x75\x3d\xf7\x66\xa6\x46\x69\xc1\x96\xb0\xc7\xd1\x55\x01\x41\xec\x0c\x83\x80\xb4\x48\x70\x84\x86\x10\x48\x6c\x67\x57\xa0\x31\x60\x7e\xdf\x18\x4c\x38\x06\x0d\x3d\x59\x52\x2b\x02\x0c\xf3\x35\x8c\x20\x23\x9e\x72\x5e\x9c\x3c\x67\x4e\xf6\x29\x0b\x71\x8a\x6f\x1f\x50\x97\xb3\xe5\xfc\x11\x29\xe9\xa5\x1a\xb4\x5d\xd5\x9a\x1e\x72\x13\xb6\x0a\x9e\x1f\x91\xc1\x8f\x9b\xa5\x59\x97\x31\x82\x35\x93\x4a\x64\xa0\x70\x18\xc3\x02\x11\x16\x8b\x32\x04\x16\xac\x7b\x43\x31\x81\x52\x22\xb5\x8a\x47\xef\xa9\x77\x61\x86\xc7\x21\xc8\x12\xab\xa0\x21\x43\x5a\x66\x83\xac\xa2\x02\x2f\x42\xd5\x18\x06\xc8\x80\x5e\xef\x07\xf0\x65\xa2\x98\x51\x91\x6f\xc1\x2e\x06\x19\x88\x81\x3e\x34\x8c\x97\x15\x1d\x49\x24\x26\x8f\x0c\x92\x10\x92\x9e\xae\x5e\x91\xe8\xd8\x3d\x26\x02\x93\x0f\xb0\xa1\xd9\xf0\xca\x58\x22\x0c\xa5\xa4\x5b\x63\x9c\xd8\xc8\xbe\x61\x82\x98\x3e\x25\x14\x73\x89\x7d\x00\x93\x04\x06\xc0\x15\x12\xa7\x8c\xbe\x51\xa7\xa4\x20\xb2\xcc\x59\x1b\x07\x30\xba\x65\x58\x4e\x69\xe6\xd2\x43\x16\x36\xbc\x56\x30\x04\x12\x47\xd7\xb3\x08\x9a\x26\x4b\x63\x53\xa4\x64\x23\x95\x9d\x9f\x95\xa4\x67\x5f\x43\xab\x4d\xa0\x3a\x7a\x5a\xca\x0c\xea\xa9\xc4\xe4\x24\xdf\x14\x98\x45\xaa\xf3\x45\xbd\x1f\x79\xd7\x0e\xa9\x65\x6d\x13\xb3\x8a\xbd\x1d\xcb\x22\x79\xdf\xf8\x58\x76\x0b\xec\x97\x6d\x63\x26\x56\x92\xcf\x79\xb6\x4a\xe3\x59\x80\xd5\x98\x31\x47\x07\xe7\xdc\x16\x3a\xc4\x9b\x02\x43\xed\x15\x52\xc0\x56\x81\x1c\x19\x31\x57\x50\x76\x48\x0c\xed\x5e\x89\x63\x46\x55\x99\x43\xb4\x91\x3a\xbd\x8d\xa9\x1f\x6e\x24\x2b\xa5\x61\x62\x6f\x38\xca\x41\xa5\x9f\x56\xca\xd4\x49\x05\x5d\xf3\xd0\xe3\xba\x8a\x9c\x69\x65\x38\xd5\x58\x2b\xa3\xe6\x10\x97\xc9\x35\xad\x50\x38\x6c\x14\xeb\xc5\x90\x0d\x12\x83\x51\x15\x89\xca\x58\x2f\x4b\x4c\x8c\xd1\x36\x0a\x91\x91\x56\x19\x3f\xbb\x5d\xcd\x24\x82\x27\xb3\x0b\x24\x53\x89\x5e\x25\xee\x4d\xbd\x8d\x70\x8c\x61\x99\x9a\x0f\xb7\xbb\xed\x1e\xa2\x4d\x84\x67\x45\x13\xfb\xb1\xd2\x0c\x9b\x62\x42\xcd\xcb\x63\x06\x20\xb7\xd3\xb9\x4b\x8c\x41\x90\x88\x40\xc3\x0c\x37\x45\x5e\xe2\x25\x4b\x19\xfb\x70\xc2\x70\x48\x71\xce\xa4\x4a\x8e\xe1\x88\xa0\x09\xc0\x33\xca\x56\x02\x14\xfa\xa7\x1e\xca\x83\x46\x8b\x38\x82\xce\xeb\xdf\x77\xed\xcf\x1b\x69\x96\xca\xab\x2b\xc6\xc3\x99\x5c\x0d\x6c\x9c\xcc\xd3\xbc\x61\x02\xde\x08\x61\xd8\x1a\xa2\xa8\x68\xf3\xde\xbb\x54\x97\x17\xda\x3d\x8f\x24\x83\x17\x83\x35\x21\xde\x9d\xd2\x6c\x3a\xb7\xea\xa6\xff\xb2\xb4\x59\x1c\x88\xb5\x4d\xeb\xbd\x81\xcd\x54\x91\x8b\x37\x8e\x11\x98\x87\xeb\x8e\x49\xd7\x9d\x90\xda\xed\x3c\xf2\x47\x95\x2f\x48\x0a\x9a\xcd\x21\xaa\xfc\xd0\xe7\xae\xe1\x2b\xa2\x59\x67\x2c\xab\x3c\x59\xc1\xec\xff\x90\x68\xfc\xba\x44\xea\x11\x97\x9a\x64\x7f\x39\xcb\x6b\xc2\x78\xdc\x9a\x13\xd5\xeb\x48\x3a\x8f\x47\x48\xf1\x07\xb3\xe2\xce\xbe\x3f\x2c\x96\xbe\x7e\x96\xcc\x3a\xe5\xb4\x3f\xfa\x54\xc8\xba\xaa\x77\x63\x7e\xff\x88\xfa\xcc\xa8\xd3\xd7\x87\x38\x04\x6d\xd6\x05\x64\x4e\xea\x97\x34\x8e\x2c\x4e\xa8\x65\x65\xe2\xbb\xbb\xfe\x89\x6d\xa4\xc9\xbc\xe0\xd6\xc6\xbe\x51\x00\x8a\x43\x56\xfd\xb8\x1d\xb9\xeb\xd0\x55\x34\xb1\x20\xeb\x5c\xdb\x9c\x97\xc8\xaa\x4e\xb0\x52\xde\x2e\x46\x0e\xac\x86\xd6\x27\x52\x76\xc1\x32\x90\xb7\x5b\x19\x40\x5a\xc8\xf4\xd6\xa8\x35\x9e\x4d\x89\x83\xfc\xa6\xa8\xf1\xe0\xb7\xc3\x8f\x7d\x6b\xba\x86\x71\x0c\x20\x65\x1f\x4e\xc8\x0e\xc9\xcf\xd9\x04\x10\x45\x00\xf5\x97\x44\xdf\xd0\x55\x00\x9a\x31\x7c\x3e\xf5\x97\x00\x14\xec\x50\x9e\x16\x24\x6a\x7d\xaa\x1d\x1a\x2b\x2d\x54\xd3\xad\x6e\x35\xdf\x90\x27\xdc\xde\x99\x3a\x35\x03\x2e\x43\x7a\xe1\x77\xda\x56\x7c\x2b\xbf\x1d\x7b\x71\x61\xfa\xa3\xf8\xff\x1c\x8d\xba\x4c\xdb\xdf\x46\x57\x8b\x9b\x54\xe6\xf5\xc4\x56\x67\x97\x5d\x8d\x29\x6b\x13\xad\xdc\x3b\x77\x54\x7b\x66\x13\x26\x8a\x39\xe5\x62\xc2\x2a\x59\x7c\xaf\xc9\xd8\x2e\x16\x05\xe3\xf5\xd9\x91\x37\x7d\xb7\xa3\xae\xa5\x21\xa6\x8d\x97\xfd\xab\xef\x0d\xff\x05\x00\x00\xff\xff\x1d\x41\x25\x8d\x47\x17\x00\x00")
+
+func fontsFuzzyFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsFuzzyFlf,
+ "fonts/fuzzy.flf",
+ )
+}
+
+func fontsFuzzyFlf() (*asset, error) {
+ bytes, err := fontsFuzzyFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/fuzzy.flf", size: 5959, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsGoofyFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x59\xdd\x6b\xe4\xc8\x11\x7f\xd7\x5f\x51\x7b\x74\x70\x6b\xe3\x39\x39\x3e\xd8\x87\xc3\x38\xe6\xe0\xc8\x5b\x72\x24\x7b\x84\x80\xa0\xd0\x8c\x7a\x66\x94\x95\x25\x47\xd2\xc4\x6b\xd2\xf9\xdf\x43\x57\x55\x7f\xcd\x87\x77\xf7\x25\x70\x60\x63\x7b\xaa\xbf\x7e\xf5\x5d\x5d\xd2\x6c\xfb\xed\x6d\xa3\xe0\x03\x7c\x80\x1f\x6e\xe0\x06\x6e\x6f\x8b\x9f\x3f\x3f\xf5\xcd\xd0\x2c\xdd\x38\xc0\xb8\x85\x6d\x37\xcd\x0b\xf4\xdd\x60\x7e\x84\x57\x7e\xde\xbf\x7f\x0f\x7f\x1a\xc7\xed\x3f\xe0\xe6\xfb\x3f\xb8\x51\x41\xd0\xb0\x82\xc1\x6c\xcc\x3c\x37\xd3\x0b\xcc\xcb\x61\xbb\x85\x65\x84\xae\x35\xc3\xd2\x6d\x5f\x60\xd9\x1b\xf8\xd4\x0d\x2d\x33\xea\x4d\xa1\x08\x6c\x45\x0b\xdf\xed\x9b\xa9\x5d\xf7\xcd\xf0\xe9\x3b\x58\xad\xe0\x69\xea\x86\x65\x86\x66\x86\x06\x68\xf6\x1a\xd6\x87\x05\x36\xcd\x70\xb5\xc0\xda\xc0\xfc\x78\x98\xf7\xa6\x2d\x3e\x08\xc4\xde\x74\xbb\xfd\xe2\x90\x1b\xd8\xec\x9b\xa9\xd9\x2c\x66\x7a\x7d\xf5\x1a\x86\x71\x81\x6e\xd8\xf4\x87\xb6\x1b\x76\xd0\x9a\x79\x63\x86\xd6\x4c\x73\xf1\xc3\x0d\x9f\x7b\x6c\x3e\x93\x31\xa0\x37\xc3\x6e\xd9\x83\x36\x9f\xfd\xee\xcd\xf8\xf8\x68\x06\xb6\xd5\x5c\xc2\xef\xa1\x81\xed\xa1\xdd\x19\xd8\x36\x9b\x65\x9c\x8a\x1b\x61\xfd\xe4\xa4\xf6\x2c\x67\x58\xc6\x9d\x59\xf6\xcc\x9c\x95\x70\x60\xe3\x04\xcf\xfb\x66\x31\xff\x76\x0b\x4f\xbd\x69\x66\xf3\xae\xb8\xbd\x65\x84\xe1\xf0\xb8\x36\x93\x13\x3e\xe3\x09\x7a\x5e\x9a\x69\x71\xc7\x9f\xbb\x65\x4f\x46\xbc\x4a\xdc\x79\x45\xdb\xca\xa2\xf8\xfb\xd4\x2d\x8b\x19\x60\xfd\x02\x7f\x73\x2c\x06\xb8\x23\xdf\xdd\x43\x6b\xe0\xa7\x69\x3c\x3c\x9b\x09\xb4\x9b\x9a\x4d\xff\xd0\xb6\xf3\xf7\x43\x5f\x16\x3f\x35\xb3\x69\x61\x1c\x08\x77\x5e\x0e\x4f\x5d\x0b\x93\x69\x36\x14\x29\xdb\x69\x7c\x84\x27\x33\x3e\xf5\xc6\x79\xf8\xb9\x59\x36\x22\xc0\x76\x9c\xcc\x6e\x1a\x0f\x43\xbb\x1a\xd7\xff\x34\x9b\x65\xbe\x82\x82\xa3\x4a\x77\xcb\x95\x73\xa7\x0f\x81\xdd\x38\x6e\x5f\xae\xa1\x9b\x9d\x4b\xbb\xe5\x8f\xf0\x63\x09\xc5\xc7\x7d\x37\xc3\x76\x1c\x16\xe8\x66\xf8\xf3\x5f\x3e\x3a\xaf\x74\xbb\xc1\xb4\x8e\xcf\xda\xc0\xc1\x49\xb5\x1d\x27\xd8\xf4\xa6\x99\xae\xa1\x1f\x87\x1d\x2c\xe6\xf3\xf2\xae\xf8\xb8\x37\x93\x71\xfc\xa1\x1f\x9f\xcd\xb4\xda\x34\xb3\x71\x28\xe6\x5f\x87\xa6\x77\xc7\x7f\xfd\xe5\x97\x9f\xff\x4a\xd3\xef\x0a\x00\x40\x44\x94\x78\xc6\x40\x67\x14\xc4\x65\xfa\x1f\xd6\x0b\x80\xca\x2d\x94\x3c\x51\x0a\x0d\x1a\x52\xaa\x96\xb3\xa5\x1b\x69\x9a\xe7\x9d\x05\x6f\xac\xe8\x97\xd9\x38\x38\x8d\xb5\x50\x7c\xd6\xba\x29\x94\x51\x5d\xc9\x52\xe5\xb8\x97\x20\x98\x9a\x16\xb5\x08\xea\x38\xa1\x97\xc1\x12\xf7\xd2\xa3\xf1\x69\x0d\x50\x30\xe5\x30\x69\xb9\x94\x75\x9a\xae\x49\xc4\x4a\xb8\x43\xc0\x15\xb1\xa0\x84\x42\x93\x0d\x18\x98\x24\x64\x5a\x63\x4a\x31\x0b\xde\x59\xf9\x45\x47\x15\x85\x2b\x1e\xbf\xce\x86\xe2\xe5\x77\xe4\xcb\x06\xda\xf1\xb0\xee\xcd\x6a\x04\x3d\x8e\xe5\x35\x34\x43\x4b\xcb\xff\xf9\xaf\xab\x00\x6b\xb3\xeb\x86\x15\x4d\x9a\xa1\x5d\x3d\x36\xd3\x27\x33\xcd\xef\xa8\xee\x20\xe2\x43\xa1\x94\x3a\xf9\xe7\x16\x1e\x0a\x54\x4a\x29\xb7\x45\x3b\xa2\x74\x8b\xb5\x52\x15\xef\xaa\x2b\xd9\x8e\xc8\x47\xb4\x52\x65\x38\x86\xc9\xc9\xd2\x1f\x2e\xb1\xa2\x3f\xe6\x22\x3f\x39\x8d\xe1\xc7\x01\x45\x24\x27\x27\x96\x4a\xd3\x9f\xdb\xa8\xc3\x1a\x41\xbf\xb2\x86\x61\x2d\x2a\x25\xd2\x39\xd1\x50\xb6\x69\xa5\x34\x5a\xcb\x12\xd5\x34\x5f\x13\x8d\xd6\x62\xc9\x1a\x68\x3e\xaa\xa3\x74\x24\x5b\xa4\x9c\x32\x4e\x5d\xde\xe8\xa9\x87\xc2\x19\x4d\x69\xac\x15\x99\x4f\x09\xb4\xc0\xa9\x52\x69\x85\x2a\xb5\xb1\xec\xab\x09\xa2\x52\xa2\x05\x71\xc6\x48\x05\x21\xd8\x60\x85\xd2\x4a\x97\x74\x84\xac\x7a\xaf\xd4\x1d\xe9\x41\xfc\xab\xda\xb9\x8c\xb5\xd0\x84\x71\x47\xb8\xc4\xed\xee\x5e\x95\xc1\x75\xc1\x6d\xe2\xb2\xe0\xa2\xf8\x99\xb8\x88\x8e\xb8\x95\xca\xfd\xb2\xaa\x95\x68\xa7\x83\x35\x6b\x3e\xe5\x28\x77\x4c\x64\x7e\x28\x78\x29\xdd\x44\x66\x2b\x53\x20\xf7\x19\xb8\x85\xf0\x28\xd8\xc7\x28\x82\xa1\x26\xf5\xc4\xff\x62\x15\x82\x51\x1a\xab\x9a\x6c\x96\x03\xc4\x91\xc7\xf2\x40\x11\x25\x42\xe4\xe7\xfd\x61\xb1\x48\xfc\x40\x14\xd5\xd9\xd0\x55\xc2\x27\xb1\x22\xa2\xe7\x20\xf8\xa7\x56\x3d\x83\x7d\xc2\xc2\x6f\x55\xde\x05\x64\xbb\x8a\xf7\x56\x21\x53\x99\x8a\x16\x15\x9b\xea\x3c\xcd\x88\x61\xe5\x43\xd3\x12\x37\x7b\x81\xe2\x40\x4e\xd2\x89\x4e\x57\x48\xcb\xcc\xd4\x9e\x23\xd1\x91\x98\x84\x7e\x99\xc7\x30\x49\x80\x3e\x24\xb4\x2b\x17\xa4\x52\xa2\x50\xd0\x88\xcd\x80\x19\x50\x10\x85\x22\x40\xd2\xd7\xb9\xce\x86\xa8\xb0\xf9\x9c\x8a\x8a\x20\x26\x49\x5c\x45\x55\xc8\x62\x36\x0b\x2c\x76\x5a\xd4\x26\x93\x22\xa9\x2f\x96\xd5\x2a\xc9\x78\x16\xa5\x52\x32\xe1\xa5\xcb\x6b\x4b\x95\x67\x35\xb3\xa7\x3d\x84\xa6\x3d\x44\x2c\x22\x56\x85\xca\xc1\xb9\xcc\x10\x89\x14\x9a\x19\x97\x5f\x13\x17\x9a\x73\xed\x62\x5c\xe8\x58\xa6\xee\x95\x94\x10\x9d\x0b\x70\x56\x85\xbc\xe2\x91\x13\xea\xe8\x8f\xe8\x10\xcc\x3d\x42\x65\x9f\x2d\xcf\x65\x3e\xd2\x49\xaa\x9c\xdd\x44\x02\xd9\xea\x4b\x55\xea\x8e\x94\x38\x5f\xa5\x42\xde\x1e\xe7\xeb\xd1\x38\xe4\xed\xab\x65\xed\xde\xfd\x9e\x2f\x6b\xc1\x51\xa1\xf2\x71\x05\x45\x29\xa0\xe8\x9d\x53\xa6\x55\x3f\x0f\x11\x8c\xf1\xe0\x8a\xbd\x44\x95\x55\x96\x13\xbd\x92\x35\xe9\x2a\x62\xe9\x4f\xd2\xd0\x4d\xc7\xd2\x53\xb1\x0e\x3e\x54\x82\x46\xae\x74\x94\x49\xf0\x05\x37\x72\x7c\x3a\x47\xc6\x00\xf4\xd6\xf0\x01\xa0\x6c\x0c\x20\x22\xef\x8e\x66\xab\x33\x69\x10\xb3\x40\xd4\x93\x1c\xb0\xca\x53\x1c\x4c\x5e\xa5\x98\x86\x28\x59\xf8\x55\x55\xcd\x9e\x64\x8f\x0a\xd2\x7b\xcf\x27\x39\xa8\xac\x0a\xa9\x29\xf3\xa8\x82\x06\x79\x31\xf8\x36\x20\x15\x6a\xb4\xf8\xeb\xd4\xe5\xd4\xb9\xa0\x3f\xc4\x21\x25\x70\x7c\xef\x6a\x6f\x70\x0a\x66\x5f\x64\xb8\x77\x08\x2d\x8c\xe0\xc9\xfd\x51\x73\xc9\xb3\x92\x21\x64\xd5\x8a\xc6\x5e\x46\x95\x8c\x2a\x55\xcb\xc8\xed\x41\x44\xeb\xb3\x26\xad\x3c\x49\xb9\xfc\xa6\x1b\x41\xae\x15\xbe\x7b\x43\x99\x90\x93\x9c\x11\xd6\x97\x70\x8b\x36\xb9\x96\x52\x0f\x26\x9a\x29\x1b\xee\x46\xb7\x3b\x54\x41\x76\xbf\x0e\x8e\xb0\x3e\x61\xe9\x06\x70\xe6\xaa\xd3\x68\x0a\x60\xf1\xc0\x79\x32\x8b\x85\x2c\x14\x48\x22\xeb\x69\x09\x3c\x5b\x57\x36\x0e\x82\x72\x27\x03\x64\x83\x25\x12\xa5\x80\x75\xb6\xb7\x56\x75\x86\x53\xab\x3a\x83\xad\x53\xfe\x48\x65\x8f\xa1\xcf\xf7\xb3\xbe\x90\x1f\xf7\xae\x69\xc7\x9a\xf6\xa9\xaf\xe6\xa0\xa4\x72\xa8\x4b\x31\x95\x2d\xe6\x11\x1f\x2e\x90\x70\x5f\x27\xd7\x47\x0c\x0b\x2b\x75\xd8\xe6\xd6\xb9\xc8\x59\xc4\xb5\x6c\x26\xe1\x5c\x67\x11\x1c\x1f\x11\x24\x69\xb5\x4f\x72\xe1\x9f\xde\xe2\xe7\x1f\x11\xd2\xf4\x3f\xea\x4a\xd3\x80\xb9\x38\x40\xf1\x37\x9e\x49\x57\x1b\xd2\x35\xba\xf4\xe2\x88\x53\x39\xc9\x92\x2c\x51\x8e\x30\xbf\x18\x89\x54\x54\xaa\xe0\x71\x9f\x76\x89\x8c\x47\x42\x1e\xc9\x75\x61\xc8\xb0\xc7\xc0\x29\x34\x86\x9b\x9c\xd3\xd4\xdf\xe6\xa9\x3c\x74\xd3\x86\x5b\xdd\xcd\x26\x29\x5d\x25\xb7\xbb\x57\x5c\x1e\x78\x74\x7c\xf2\xc8\xe1\x6a\x89\x16\x76\x4e\x19\x2e\x20\x0a\xde\xd8\x45\x67\x9e\xfe\x8a\x86\x0b\x4f\xca\x5e\x5e\x1e\x9c\xeb\xa3\x89\x8e\x29\x3e\x2d\x97\x57\x6a\x78\xb6\x8d\xbf\x43\xa4\xff\x08\x8a\xd4\x5e\x8d\xd8\xed\x60\x5e\xe4\x98\x7f\xd2\x9b\x05\xef\x24\xd5\x17\x6d\x76\x79\x9e\x36\x7c\x95\x64\x95\xeb\xe1\x55\x9d\x3c\xe5\xe4\x4f\xfc\xc9\x13\xd9\xb9\xe7\xa4\xa3\x4f\xdf\xb8\x94\x69\xc3\x9f\x3d\xae\xd6\xae\x63\x7a\xfd\x71\xf5\xad\xc7\x79\xeb\x71\xde\x7a\x9c\xb7\x1e\xe7\xad\xc7\x09\x21\xfc\xd6\xe3\xbc\xf5\x38\xea\xff\xd7\xe3\x84\x37\x6c\xf4\xc6\x9a\x8f\x85\x1a\x2f\xaf\x55\xfc\x56\xce\x9b\x0b\xff\x7d\x19\x65\x99\x19\x94\x31\x19\xf2\xa1\xa0\xd4\xe3\x34\xa3\x3f\xe6\x51\x57\xb4\x91\xde\x0b\x1f\x7d\x1d\x71\xb9\x37\xa1\xa8\x64\xcd\xf9\xfb\x04\x7e\x6f\x85\xb1\x6a\xf8\x04\x44\xef\x78\xb7\xcb\x7e\xcb\xe1\xf3\x6f\xd2\xce\x1d\x96\x6f\x38\xd8\x18\xd1\x20\xf6\xf4\xf5\xec\x6f\x53\xec\xb4\x3a\xf3\xb5\x1f\x5f\x6e\x61\x99\xbc\xda\x62\x6f\x3b\x1a\xe3\xbc\x0e\x40\xff\x0b\x00\x00\xff\xff\x7e\x7a\xbc\x62\xb5\x1f\x00\x00")
+
+func fontsGoofyFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsGoofyFlf,
+ "fonts/goofy.flf",
+ )
+}
+
+func fontsGoofyFlf() (*asset, error) {
+ bytes, err := fontsGoofyFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/goofy.flf", size: 8117, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsGothicFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x39\xef\x6e\xe3\xb8\xf1\xdf\xf5\x14\x83\xe0\x00\x4b\xbf\x68\x42\xf8\xf6\x7e\x87\x4d\x63\x07\xc6\x15\x6d\xef\x01\x0e\xed\x17\x02\x34\x6d\xcb\xb6\xba\xb6\x14\x58\x32\x36\xdb\xe5\xe6\xd9\x0b\xce\x90\x12\x25\x4b\x4e\xb6\xb9\xf6\x82\x44\x1c\x51\xc3\xf9\x3f\xc3\x21\xb3\x3d\x6c\x7f\xd4\x3f\xc0\x3d\x7c\x84\xe9\x4f\x80\x53\x98\xfe\x1c\xfd\xad\xac\xf7\xf9\xfa\x6e\x7b\xd8\x02\xc2\x6f\xfa\x53\x56\xc0\xf6\x54\x1e\x41\xc3\x4a\x17\x45\x76\x82\xa7\x53\xb9\x3b\xe9\x23\xac\xf5\xe1\x90\x6d\xe0\x66\x47\x0b\x6e\x60\xf5\x05\x7e\x2d\x3f\xeb\xd3\x06\xfe\xbc\x3f\x47\x7f\xcd\x77\x87\xac\xce\xff\xa5\xeb\xbc\x2c\xa0\x3a\xef\x76\x59\x55\x67\x1b\x58\x9d\xe1\x97\x72\x05\xbf\x9c\xf2\xdd\xbe\x86\x78\x45\xe3\x62\xbd\xbe\x3b\x1f\x75\x91\xd7\xe5\x4a\xdf\xad\x75\xd2\x2c\xb7\x2b\xbe\xc0\x3f\xb2\x62\x93\x1d\x0e\xf0\x6b\xbe\xb6\xf2\x4c\xa7\x62\x7a\x2f\xee\x3f\x40\xfc\x79\x4f\x33\x8b\x27\x7d\xd2\x55\xb9\xad\xef\xd6\xe5\x31\x89\xfe\x9e\x9d\x2a\xcb\x75\x7a\x37\x05\x84\xf3\xd3\x46\x5b\xce\x25\x2d\xfc\xf1\x83\xb8\xff\x10\x62\x0c\xa0\x7c\xb4\xb4\x57\x5f\xac\x90\xba\x80\xdf\x74\x09\x71\xad\xcb\xd5\x22\x2f\xef\xca\xd3\x2e\x89\x20\xfc\x41\xd0\x9b\x7f\x9e\x59\x37\x5d\x65\x87\xbc\xc8\x40\x17\x1b\xd8\xe6\xcf\xd9\x06\xaa\xf2\x98\x41\xf5\xa4\xd7\x79\xb1\xb3\x96\x5b\x1d\xb2\x63\x15\xfd\xe5\xf9\xe9\xa0\x0b\x36\x4d\xb9\x85\x6d\x7e\xaa\x6a\xb0\x2b\xff\x14\x59\x97\x00\xc2\xcd\x51\xef\xf2\x35\x14\xe7\xe3\x2a\x3b\xdd\xc0\xb6\x3c\xc1\x36\x3f\x64\x90\x6f\xb2\xa2\xce\xb7\xf9\x9a\x16\x47\x9a\x25\xa8\xf6\xe5\xf9\xb0\x01\x7d\xf8\xac\xbf\x54\xb0\xca\x60\xa9\x27\x29\x2d\x2a\xca\xcf\xd1\x0f\x8c\x54\xef\x33\xb8\xd9\xeb\xd3\x66\x75\xd0\xc5\xa7\x1b\x40\x84\xa7\x53\x5e\xd4\x15\xe8\xca\x7a\xd7\xce\xa6\xb0\x3a\xd7\xb0\xd6\xc5\xa4\xb6\x64\xaa\xe3\xb9\xda\x67\x9b\xe8\x9e\x29\xec\x33\x72\x5a\xb9\x05\x0d\xeb\xbd\x3e\xe9\x75\x9d\x9d\xa2\x8f\x57\x3e\xa6\x50\x94\x35\xe4\xc5\xfa\x70\xde\x58\x0b\x6c\xb2\x6a\x6d\x7d\x79\xaa\xa2\xe9\x4f\xb4\xec\xa8\x9f\x49\x73\x38\x64\xc5\xae\xde\x43\x9c\x3d\x7b\xe4\x75\x79\x3c\x66\x05\x1b\xa6\x4a\xe0\x16\x34\x6c\xcf\x9b\x5d\x06\x5b\xbd\xae\xcb\x53\x84\x53\xa2\xb0\xc9\xb6\xfa\x7c\xa8\x59\xd8\x63\xb9\xc9\x48\xf1\x7a\x9f\x57\xb0\x2d\x8b\x1a\xe2\x43\xfe\x29\x83\x1b\x3c\xc2\xf4\xff\x6f\xac\x8b\x2d\x5d\xeb\x21\x4b\x37\x89\xa6\x3f\x13\x15\xb6\xb4\x15\xbf\xc3\x36\x72\xce\x5e\xbc\x77\x24\x60\x11\x09\x09\x8b\x48\x0a\x58\x44\xdf\xbe\x7a\x88\x3e\xcc\x1e\x3d\xc4\xd8\xb3\x47\xe0\xa9\x04\x20\x79\x1f\x5b\x26\xc5\x93\xdf\xbe\xda\x5f\x66\x78\x7b\x3b\xbf\xbd\x75\x7c\x5f\x9f\xef\xd2\xf1\x3f\x1d\x78\x11\x81\xba\xbd\x55\x29\x2c\x22\x63\x8c\xa1\xcf\xc6\x20\xde\x11\xde\x0b\xcd\xd9\x05\x0e\x48\x51\x29\x04\x37\x13\xd2\x6a\x81\xae\x3e\x29\xdb\x09\x9c\xd1\x04\xcf\x0b\xfe\x2e\x18\x4f\x00\xdb\x6d\x39\x60\x7e\x87\x28\x79\x94\xa2\x79\xb7\x84\xc5\x44\x4a\x92\x1c\x40\x92\x93\x24\x92\xb3\x2e\x0c\x3a\x7b\xb4\x5e\xb1\x13\xa3\x7f\x24\xce\x22\x12\x82\x0c\xd0\x79\x10\x6d\x90\x5d\x67\x4b\xf0\x5f\x7a\xd8\x44\x41\x40\x17\x3b\xb0\xbd\x73\x89\x9d\x93\xce\x10\xb3\x47\xfc\x3f\x74\xde\x13\x20\x2f\xf0\xfa\x7e\x0b\xa0\x01\x07\xb0\xdb\x9b\xd8\x71\x0c\xb0\x8d\x8e\x1e\xce\x90\xff\xae\x3c\x7c\x88\x77\x55\x1b\x1f\x67\x8f\x9e\xf5\x5b\x92\xed\x15\xb6\x7d\x8b\xf2\xd8\x0b\xae\x5e\x90\x5d\x04\xdb\x68\x90\x49\x8e\x7e\xf0\xce\x1c\x1c\x41\x4a\x31\x26\x3f\xd3\x31\xc4\xc7\xd0\x00\x43\x43\x2a\x70\x02\xed\x82\xfe\x7a\x12\x23\xf6\x35\x84\xe2\xc9\x29\x25\x62\x42\xf9\xaa\x94\xba\x5c\xaf\x78\x76\xd9\x59\x01\xac\x14\x40\x92\x04\x64\x26\xc1\xc2\x80\x7f\x1a\xca\x0f\x34\x28\x65\x2c\x51\x44\x44\xce\x7a\x42\x49\xa9\x60\x0c\xf1\x67\x43\xc1\x92\x46\xc5\xe5\x84\x42\x9a\xf0\x92\x24\xf4\x50\x28\xc6\xa0\x47\x20\x15\xa1\x0b\xe3\x98\x6b\x8f\x31\x4c\x28\x8e\xbd\x47\xc4\xb0\x47\xbc\x44\x4b\x70\x88\x00\x22\x0d\x25\x88\xd9\x9e\x4d\x2d\x33\xaf\x49\xd4\x8b\x11\xce\xe0\x76\x5e\x08\xf0\x25\x61\x28\x56\x5e\x0f\x36\x90\xc2\x4b\xea\xde\xd5\x68\xb0\x8d\x67\xc7\x50\xb2\xbc\x8a\x3d\x9c\xd1\x9d\xd4\x72\x7e\x98\xcd\xdc\x77\x29\x3d\x9e\x77\x30\xc8\x61\x47\x5e\x2f\x09\xaf\x94\x88\x76\x42\xfa\x0f\xd2\x23\xf8\xf0\x86\xc7\xc7\x4e\x68\x8d\x25\x3b\x2a\x9e\x27\x37\x2d\x7d\x58\x98\xd4\x47\x43\x1b\xd5\x41\xf1\xed\xe5\xe8\xa0\xff\x84\x1b\xa5\xf1\x39\xe0\x4c\xd4\xa6\x4a\x57\x23\x8a\x4d\x9a\x43\xdb\xcd\x10\x5a\x0c\xf0\xe2\x0a\x47\x6c\x8d\xee\xaa\x86\x14\xf3\xb9\x03\x85\x02\xd5\x20\x20\xf0\xfe\x07\xfe\x27\x04\x17\x9d\x2d\x5f\xa1\x02\x95\xa6\x1e\x07\x85\x2d\x2f\x04\xbf\x18\xa3\x66\x7e\xde\x98\xd6\xa2\xa9\x40\x74\xf6\x51\x88\x0a\x27\x9c\x32\x03\xbc\x3a\xcc\x28\x6f\x11\xd4\xcb\x1d\xa1\x4f\xa8\x9e\x70\xb6\xfa\x3c\x0b\x40\x88\x81\x2a\x0d\x2d\x43\x9b\xb0\xf8\x36\x85\x08\xd7\x5b\x10\x26\x60\x00\x9b\xf2\x65\x00\xcc\xd2\xe5\xb5\x21\xd3\x2d\xa2\x17\xc3\xf3\x64\xaf\x17\x5a\x9d\x3a\x33\xbe\x55\xa1\xb4\x55\x48\x34\x5a\x88\xf9\x3b\x15\x52\x90\x3a\x0e\x84\xa8\xa8\x6c\x2e\xa2\x49\xdb\x60\xb5\x40\xea\x7c\x29\x3a\xa4\x16\xbd\xde\x4b\x29\x57\xc9\x21\x45\x03\x2f\x4e\xac\x89\x31\x42\x71\x94\xd9\xba\x69\x6d\xd1\xc0\xf3\xb9\x09\x44\x4f\x5b\xd9\x45\xcf\x2c\x23\x26\xe2\x00\xc3\x16\x49\xa4\x2d\x6c\x0c\x28\xde\x09\x6c\xac\xa1\x0d\x5b\x37\x3f\x77\xbe\x81\x18\x6c\x9a\x98\x80\xc1\x72\x98\x19\xf1\x69\x4a\xb8\xa3\xce\x84\xdb\xb7\x06\x65\x20\x75\xc9\xc4\x68\x33\x81\x53\xcc\x29\xe8\x72\x2a\x00\x5c\xee\xd9\x7e\x37\xbd\x62\xeb\x50\xfd\xb4\x55\x5f\x40\xda\xaa\x2f\x7c\x9d\xb4\x52\xce\x06\xe6\x15\x2a\x95\xf6\x52\x79\xcc\xd6\xad\xa5\x6d\xac\x37\x2c\xb9\xe0\xb8\x38\xef\xcf\xc5\xe4\xcd\x90\x7c\x00\x85\x7c\x58\x78\x29\x53\xe1\xa4\x11\x54\xdf\xda\xe6\x25\x7c\x99\x9b\xb9\x7b\x79\xe9\x7e\x49\x6d\x59\x62\x02\x3e\x26\x7a\xfa\x04\x91\x0a\xcd\x06\x83\x69\x1b\xed\x89\x8f\x16\xc4\x00\x4c\xbd\x11\x7d\xab\x67\x52\xd7\xe5\x91\x49\x10\x5f\x86\xf2\x4b\x35\xec\x53\x34\x06\xd3\x36\x1f\x8c\x2b\x82\x9c\x04\x88\x6d\x57\xe1\x5f\x7c\x4a\x24\x9d\x7c\xee\x2b\x33\xa0\x99\xfb\x80\x4a\xf9\xad\x82\x35\xe3\xb3\x84\x30\x46\x29\xb7\xc1\xb7\x20\x21\x18\x36\x9b\x31\xe8\x93\xaf\x75\xe8\x7f\x5d\x33\x29\xbf\x53\xb3\x36\xc5\xa5\xaf\xbe\xc6\x37\xde\xd2\x18\x81\x41\x09\x93\x1c\xbc\x76\x2b\x31\x6f\xd8\xb5\x58\x2a\x74\x8d\x9a\x72\x54\x63\x05\xc8\x7b\x38\x10\x40\xaa\x58\x4b\xb1\x86\x2e\x37\xc6\x02\xdd\xed\x18\x4e\x03\xbb\x0f\x22\xb6\x15\x3a\x76\x35\x97\xde\x9a\x92\xee\x3b\x83\xee\x37\x11\xb6\x16\x3e\x2c\x3a\xe6\xea\xbf\x59\xf6\x40\xec\x15\x55\x58\x5b\xef\x6d\xd4\xfb\x72\x68\xdd\xe6\xab\x0e\x90\xab\x68\xfb\x1d\x7c\x13\x4d\x7d\x72\xdc\xb1\x5f\x3d\x86\xd9\x37\x9a\x23\x78\x79\x13\xf4\x07\x8d\x44\x29\xc5\xc9\xd6\x40\x7c\x93\x41\x7e\xa5\x70\x1c\x37\x6c\x68\x56\xb4\x75\xc9\x35\xda\x89\xa0\x5f\xcf\x20\x09\x58\x24\x5d\x26\x89\x67\x83\xaf\xed\x3a\x3d\x66\xb6\x7a\xd0\x6e\x4f\xad\x4b\x23\x25\xb5\xde\x0c\xcf\xe7\x42\xce\xe7\x4d\xa5\x71\x65\x97\x11\xde\x58\x76\x29\xe2\xc9\x77\xbe\xf2\xa0\xdb\xa3\x6c\xff\xa4\x92\xa4\x07\x82\xb1\xfd\x16\x21\xe0\x04\x5c\xbd\x8e\x6d\xa5\x87\x91\x88\xa7\xc2\xde\x9c\xeb\x3a\x7d\xf7\x5c\xb0\xf0\xbe\xab\xc5\xb0\xa9\x58\x74\x9b\x4a\xdf\x7c\xbe\x71\x08\x0e\x92\x8b\xf1\x36\xbb\x69\xf4\x9b\xd1\x37\x89\xc3\x8d\x7f\x53\xd7\xc3\x6d\xf9\xda\xd0\x94\x40\x2f\xc8\xb3\xdb\xe0\x98\x81\xe8\x32\x78\xeb\xf8\xdd\x0b\x5a\x57\xa8\xe0\x88\xdd\x9c\xa0\xe8\x90\xe2\x0f\x09\xe3\x8f\x21\xb2\xce\x20\x33\x70\xfb\x2a\x77\xd6\xc1\x09\x56\x0e\x5e\x5c\xf9\x89\xd4\xb5\x13\xbe\x06\xd9\xf3\x46\xda\x3b\x3f\x4e\x9a\x98\x1e\x23\x74\x31\xd8\x70\xec\xc7\x84\xdd\xfd\xfb\x98\x01\x41\xd3\x0b\x81\xde\x89\xf7\x6d\xb7\x24\x43\x96\x57\xe8\x6f\x0f\x1c\x41\xd1\x8a\x73\x55\x23\xbe\xf2\xe3\x72\x38\x37\x66\x0e\x17\xb7\x2e\x41\x8e\x0f\x68\xd4\xf7\xd1\x88\x46\x52\x2a\x34\x2e\x0b\xed\xf7\x09\x22\xe2\xf2\xba\x8f\x46\x08\x81\x61\x0b\xab\x8b\xcb\x01\xff\x98\x5c\x5e\x2e\x4a\x79\x11\x63\x57\xb0\xf9\xf1\xe0\xae\x22\x1b\xe5\xdd\x09\xb0\xf1\xb8\xe0\x55\x6a\xe6\xe4\x63\x83\xcb\x41\x6b\xd1\xea\x4b\x1e\x23\xb2\x75\xcd\xdb\x07\xa5\x0d\xf8\xd0\x3c\x81\x85\x3c\x45\xfe\x7d\xa5\x4f\xb8\x1c\xbb\x74\x3b\x66\xbf\x9e\x63\x17\xa3\x98\x8c\x10\xba\x16\x91\x03\x84\xf0\x22\xb4\x3d\x41\x3e\x53\x1b\x57\xd7\x27\xef\x90\xa8\x7b\x6b\x04\x30\x59\x5e\x23\x94\xde\x71\xe6\xb7\x17\x5f\x06\x9a\x4c\xf9\xde\xac\xe5\xa0\x50\xee\x3f\x06\xe0\xff\x4f\x80\xd7\xb3\x36\x85\xdf\x29\x6b\xbd\xd7\xc7\xb2\xf6\x5a\x65\x6d\x86\x87\x36\x76\xda\x4c\x68\x12\x42\x5c\x94\xce\x26\x14\x03\xe0\x21\x8c\xc0\x96\x8e\x09\x01\x8e\x7b\x18\x58\x3e\xe0\xa4\x56\x35\xee\x6f\xfc\x2e\xec\x2f\x1b\x01\xe4\xc3\xb8\xb3\x86\x98\x44\x93\xc6\x1e\xc6\xc0\xc3\x84\x01\xb7\x65\xf8\x30\x8c\x9b\x55\xae\x99\xe6\xf5\xdd\xa7\xa3\x22\x02\xd8\x98\x66\x26\x4e\xfd\x32\xde\x44\xdd\x9e\x99\x04\x03\xfa\xff\x43\x24\x9d\x21\x56\xfd\xa2\x33\x54\x6f\x7a\x0f\xc6\xf6\x9d\x55\xc2\x43\xdc\x19\xe0\x1b\x5e\x4c\xaa\xa4\xeb\x51\x47\x40\xd0\xa5\xeb\xeb\x3d\xc2\xc8\xb8\xf8\x9f\xdd\xed\xfd\x01\x27\xdb\x3f\xf8\x04\xe3\xa7\x97\xfe\x7e\xe8\x9d\x6d\x55\x4b\x08\xde\x59\xf2\x7b\x84\xfe\xb3\x72\xe4\x26\x7f\xc7\xbb\xda\xf0\xee\xc0\xc3\x8b\xe8\xdf\x01\x00\x00\xff\xff\x76\x13\xf5\x69\x44\x22\x00\x00")
+
+func fontsGothicFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsGothicFlf,
+ "fonts/gothic.flf",
+ )
+}
+
+func fontsGothicFlf() (*asset, error) {
+ bytes, err := fontsGothicFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/gothic.flf", size: 8772, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsGraffitiFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x58\xc9\x8a\x1c\x47\x13\xbe\xd7\x53\x7c\x87\x06\x75\x1f\xa6\x02\xe9\x97\x7e\x90\x69\x9a\x3a\x18\x9f\x2c\xf0\x41\x17\x41\xe2\x70\x5b\xd3\x3d\x6a\x98\xc5\x9e\xe5\x60\x93\xe8\xd9\x4d\x6c\x99\x59\x4b\xcf\x48\x20\x7b\xd4\x15\x55\x95\xb1\x64\x2c\x5f\x44\xd6\xf1\xfa\xf8\x66\xbf\xc2\xff\xf1\x0e\xff\x7b\x83\xd7\xef\xf0\xb6\xfb\xe5\xee\xf6\x11\xb7\xfb\x9b\x03\x4e\x0f\xb8\xba\xdf\x1f\x8f\xa7\xc7\x53\x7f\xbc\x3e\x76\x1f\xbf\x9c\x1e\x70\x3c\x5d\x5d\x1f\x1e\x71\x94\x55\x97\x87\x87\xd3\xd5\xed\xe1\x12\x7f\xfe\x83\x5f\x0f\xa7\xab\x2f\xf8\xed\xe9\xfe\xf2\x74\xc0\xfa\x2f\xbd\x0e\xff\x1e\x9e\x1e\xfa\xa7\x87\xbf\xfb\xc3\xe5\x53\xbf\x7f\xda\x74\xaf\x8e\xa7\xab\x0b\xe1\x3d\x5c\xbe\x9a\x71\xed\x6f\x2f\xf1\xf1\x74\x83\x0f\xfb\xab\xab\xd3\x1d\xd6\x8f\xa7\x9b\xe1\xf3\xf5\xfe\xfe\x70\x73\x77\xfb\xd8\x7f\xbe\xbb\xd9\x74\x3f\xef\x1f\x0f\x3f\xe1\x1d\x3e\xec\xef\xf1\xfa\xfd\xfb\xb7\xdd\x6a\x98\xfc\x0d\x5d\xcf\xfd\xd0\x65\x64\xff\x41\x92\x1f\x66\xa1\x68\x18\x3a\x4a\x94\x86\x6e\x43\x1b\x1a\x3a\x00\x58\xf8\xd5\x0b\xeb\x1f\x86\x8e\x39\x23\x67\x64\x11\x91\xe4\x85\x3c\x16\xe6\x0c\x79\x8e\x8c\xa1\x23\x06\xbe\x7e\x05\x38\x09\x6f\xe6\x9c\x39\xbb\x20\x66\x66\x4a\xaa\x9f\x84\x11\xc4\xc2\x9c\x98\x09\x84\x04\x7d\x4e\xfa\x2e\x89\x20\x59\xc0\xa6\x00\x49\x9f\x92\x0a\x52\xad\xb2\x5c\x98\x64\xfd\xd0\x25\x26\x59\xad\x66\x13\x88\x44\x80\xbe\x4a\xa6\x42\xb8\x1b\x2b\x6c\x83\x24\xfb\x4a\x4a\xee\x84\xdc\x8a\x3b\x08\xd8\x72\x12\x07\x75\x49\x96\x0a\x6d\xce\x50\x03\xd4\x6d\xe2\x34\x79\x36\xfa\x37\x74\x2b\x75\x09\xaf\x94\x22\x80\x94\x12\x02\x42\xad\x81\x35\x94\x12\xa5\xc9\x28\xd9\x7d\x92\x58\xad\xcc\x2c\x79\xa8\x6f\x67\x0b\x37\xc0\x66\x2c\x90\xc4\x71\x58\xb9\x66\xfb\xcf\x56\xa4\x9c\xc8\x45\xf0\x46\x1e\xaf\xcd\xac\xc4\xba\x88\xa9\x88\x6c\x0c\x51\xae\x89\x38\x7f\x87\x5e\x8d\xb3\x3b\xc9\x02\xc9\x01\x76\x1b\x54\x62\x88\x94\x17\xb9\xf2\x15\x29\x7a\x3b\xff\x11\x5f\xae\x36\xd4\xe8\x5c\x4d\x48\x8d\x41\xa8\xe2\xaa\x67\xb6\xf6\x39\x0d\xa9\x68\xa0\xe4\x4c\xe4\xe1\xd1\x2c\x71\xbf\x92\x89\xb4\x14\x54\x7f\x51\xc8\x36\x33\x2c\x71\x92\xd5\x84\x66\x8e\x04\x83\x35\x4a\xfa\x3c\xb1\x67\x2f\x92\xaf\xa7\x26\x79\x2c\x7b\xe5\xb1\xd5\x89\x16\x65\x9e\x5e\x99\x39\x07\x53\xd5\xcc\xaa\xd9\xa9\x14\xe9\x2b\x0e\x31\x2b\x4c\x45\x59\xc3\xdc\xa4\xad\xe5\xed\x59\x41\xe0\xb5\xd0\x5b\x17\x6a\x1c\x62\xe1\xb9\x2d\x98\x62\x86\x97\x1b\xbc\xf4\x95\x59\x73\xc3\x2d\xfa\xdd\xe0\x21\xb9\xe7\xb2\xa3\x8a\xe5\x88\x08\xea\xc3\x26\xdf\xbf\xee\xc7\x7d\xd0\x6c\xf3\x1b\x2c\x6a\x04\xb9\x5f\x44\x10\x39\x48\x79\x74\x32\x6b\xa8\x9e\x89\x0e\x17\x27\x15\x47\x22\x1c\xa9\x86\x18\x83\x91\xb6\x7d\x8b\x01\xaa\xb3\xd1\x5a\x54\x80\x26\xb6\xb3\xb3\x25\x5b\x8f\xda\xc5\x85\x6d\x2d\x9d\xdd\x5a\x63\x51\x6c\xa7\x30\x7c\x8f\x45\x2b\x4f\xee\x64\x89\x3d\xa5\x4b\x09\x2d\x2f\xda\x8c\x17\x39\xca\x79\x11\x45\x09\xa5\x00\x93\xc4\x51\x66\x23\x3c\x39\x5f\xd0\x2f\xd7\xb6\x6c\x76\xac\x03\x69\x64\x03\x13\x5a\x9d\xf3\x48\x22\x22\x69\x6e\x54\xbf\x65\xcb\x58\x58\xaf\x32\xe8\x12\x7a\xcb\xcc\xbb\xda\x00\xdb\x6c\xd7\xd2\x8a\x5e\xd5\x5b\x7b\xd8\xc2\x33\x8a\x4a\x6e\xa5\x85\x94\x40\xc5\x10\x58\xf7\xf1\xf6\xd3\xa2\x88\x46\x32\xa3\x89\x72\x1e\xe7\xc5\x34\x55\x47\xb9\xaa\x5b\xcc\x2e\x82\xa9\xb9\xb1\x37\xf3\x34\x9b\x65\xbe\x8a\x33\x63\xab\x41\xc9\xd6\x29\xf6\xf9\x66\xcb\x56\x9f\x13\x07\x34\xd6\xd9\x66\xc3\xa0\x54\x6e\xfe\x18\x95\xf7\xf3\x9b\xe5\x6a\x1d\xd7\xfd\x31\x6f\xb8\x88\xc3\x8f\x10\x57\x4d\x15\xb3\xe1\x9b\xb5\xe4\x71\x71\xd6\x1d\x46\xf0\x83\x16\x7f\xdc\x77\xc9\x5c\xe9\xbe\x4b\x63\x08\x5a\xb2\xce\xd6\x37\xe0\x61\xe1\x8b\x50\x7c\x8d\xdc\x90\xeb\xa7\x80\x80\xa4\x89\x12\x18\x50\xec\xd3\x29\x50\xb5\x7b\x7f\x99\x5c\x9a\x66\x33\xf8\x55\xac\xea\x8d\xb6\x50\x8d\x69\x99\xe0\x82\x8e\x5e\x53\x1b\x56\x08\xb2\xad\xb1\x0d\xa0\xb2\x98\xc0\xae\x56\xd1\x0f\xf1\xdc\x36\x96\x23\xcf\xa7\x4d\xab\x0f\x98\x6b\x18\x96\x69\xdf\x65\x04\x62\x2a\x68\x5e\x7d\x68\xaa\x2f\xd9\x8f\x7b\xf8\xd3\xcb\xd5\x87\x36\xbf\x91\x30\x16\x37\x0e\xd8\x77\x14\x33\xc6\xcd\xf9\x65\x71\x2f\xe5\xf7\x32\x36\xa0\x4d\x76\xf7\xa2\x61\x43\xdc\x8c\xa2\xf9\xbc\x75\x84\x06\xb9\x12\x53\xdf\x58\x97\x7c\x00\x47\xc0\xc6\xee\x5b\xac\x3b\x8b\x5c\xf9\x6c\xb9\x44\x31\x3b\xb8\x8f\xa0\x78\x32\x48\x7c\x1f\x36\x70\xe3\xae\x6a\xd1\xfc\x86\x9b\xee\x31\xaf\x84\x5a\x82\xb1\xa1\x42\x53\xa5\xa9\x26\xf0\xbc\x7f\xbb\x97\xdc\x2e\x78\xce\x5a\xed\x7b\xce\x5a\xed\x5b\x32\x86\x80\x64\xc2\x96\xec\x72\x57\xfb\x64\x91\x9c\xcb\x91\x25\x51\x6a\xc5\xbb\x4c\x95\x2f\xa7\xb8\xaa\x00\x81\x84\xc5\xc6\x6a\x21\xb5\x02\xa8\x06\x41\xb3\x85\x4d\x4e\x29\x54\xc9\x14\x77\x7f\x6f\x10\xa4\xde\x8f\xb9\x38\xea\x20\x47\x5c\xcb\xf3\x0a\x41\x89\xe6\x49\xeb\x61\x6c\x86\x25\x9a\x9a\x43\x8c\x26\x25\xa6\xc8\xb1\x32\x0c\x92\xe1\x42\x67\xd4\xec\x54\x06\xe6\x94\xaf\x53\x83\x56\x7a\x58\x84\x9f\x19\xa2\x8b\x78\xe1\x28\x61\x11\x0a\x8d\x7e\x4a\x51\x07\x98\x14\xd9\xa2\x0d\x35\x79\x4e\x71\x50\x55\x9b\x1c\xfd\xfc\x08\x03\x1f\xe1\x12\xd5\xa9\x68\x7a\x2d\x1b\x7d\x9e\x08\x2f\xfa\x90\xe6\x47\xe0\xb4\x5e\x38\x02\x97\x04\xeb\x46\x80\x51\xd1\x42\xfc\xcb\x43\xb7\x1e\x17\x5f\xa9\xbc\xde\xbd\xc5\xc8\xde\xfe\x32\x62\xde\xca\xda\x3b\x03\x0b\xa6\xcc\x68\x0c\x67\xef\x9d\xac\xb9\x51\x8e\x66\xd6\x9e\xad\x8d\xef\x66\xcc\xbd\xe1\x87\x1e\x6f\xb5\xda\xd5\x58\xfd\xa4\x01\x19\x2e\x73\x80\x55\x3d\xc7\xbc\xa0\x39\x8e\x1d\x3e\x0b\x9c\xd1\x1c\x40\x68\xc6\x72\x8a\x4f\x2b\x31\x1e\xe5\x82\xce\x63\x78\x69\x34\xa3\xb4\xb7\x66\x48\x8d\x19\x55\xaa\x7f\xd7\x8c\x2f\x25\x8e\x31\x1c\xb8\x04\x3b\xd4\x07\xe5\x6d\xd9\x80\x25\xf9\xa0\x30\xf5\x79\x1f\x2d\xd7\x3a\x7b\xfd\x2d\x03\x41\x9d\x29\xdc\xf2\xfa\x2a\xb7\x93\x45\x9d\x2b\xea\x54\x91\x2b\x4a\xb9\x4d\x12\xa0\xac\xb3\x44\x80\xe6\xd6\xf5\xd7\xaa\x8d\xa9\xa1\x72\x4d\xae\x2a\x24\x1a\xc4\xa2\x27\x99\xdb\xd9\xab\x78\xe2\x53\x75\x45\x6e\x7d\xf1\x4c\x1a\x80\x1a\x7e\x75\xea\x19\x4f\x9e\x63\xb6\x1c\x5a\xcb\x81\x64\x87\x4d\x20\x1f\x2d\xa7\x41\x60\x5e\xe9\xd2\xa1\x39\xf3\x4e\x52\xc0\x4e\xd8\xde\x64\xf2\x8c\x19\x68\x9a\xa8\x3b\x68\x8b\xad\x07\x05\xa9\x20\x6e\x84\x71\xae\x99\xfd\xec\xe0\x28\xaa\x6e\x4f\xf4\x42\xf6\x4e\x34\xa3\xe9\xdd\xa5\x51\x2c\xd6\x0d\xbc\xd2\x04\x75\x4b\xd5\x94\xa2\x29\x5a\x2b\x94\x8d\x41\x0d\xd1\x93\x73\x34\x64\x0b\x4b\x9e\xb8\xb8\x65\xf3\xfe\x66\x80\x42\xa5\xb9\x45\x63\xa4\x45\x6d\xc6\x68\xdf\x51\x95\x35\x51\xcb\x5c\xd8\x29\x4d\xda\xfe\xd4\xc3\xb5\xb5\x46\x67\xdd\x45\x11\x90\x7e\x5a\x6d\x9a\x29\x8d\x3d\x6c\x4d\xb5\xd7\xa3\x2a\x6a\x44\xb9\xed\xa1\x79\xf2\xa5\x74\x12\x5b\xef\xa3\xde\x45\xcb\x07\x07\x9a\x74\xcd\xda\xc5\x96\x3e\x0d\x6c\xb1\xc5\xe8\x39\x27\x5e\x59\x93\xb5\x9e\x17\x2d\xcd\x2e\x17\x79\xfa\xd0\xbf\x94\x2e\x7d\x02\xc0\x0e\xbb\xf6\x39\x13\xd3\x2a\x8c\x01\xe2\xe3\x9e\x74\xa0\xf8\xc0\x61\xe3\x51\xfb\xb1\xf2\x3c\x3d\x74\xcd\xff\x3f\xfa\xe6\xbf\x00\x00\x00\xff\xff\xd7\x26\x94\xd0\x7f\x18\x00\x00")
+
+func fontsGraffitiFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsGraffitiFlf,
+ "fonts/graffiti.flf",
+ )
+}
+
+func fontsGraffitiFlf() (*asset, error) {
+ bytes, err := fontsGraffitiFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/graffiti.flf", size: 6271, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsHollywoodFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x5b\x4b\x6f\xe3\xc8\x11\xbe\xeb\x57\xd4\xa1\x01\x4a\x00\xa9\x9e\xdd\x24\x58\x24\x03\x03\x02\x92\x53\x80\xc4\xa7\x9c\xc2\xa0\xe5\x4c\x34\x19\x2f\x66\xed\x8d\x1f\x59\x0c\xc2\xf0\xb7\x2f\xba\xfa\x51\x8f\x6e\x4a\xa4\x46\xf6\xd8\x80\x25\x56\x89\x62\x7d\xf5\x2e\x36\x5b\x1f\x3f\x7f\xfc\xfe\xc6\xc0\x77\xef\xe0\x07\xf8\xfe\x37\xf0\x0e\x7e\x58\x7d\xba\xff\xfc\xf9\xcb\x2f\xf7\xf7\xff\xda\x7e\xfc\xfc\x11\xfe\xf9\x05\xfe\xfc\x7c\x73\x07\x7f\xbc\x79\x80\xf5\x8f\x1f\x76\x3f\x3e\xff\xfb\xf9\xf0\x74\xd8\xfe\xe7\xf9\xf6\xa7\xed\xf3\x87\x9f\xb6\x87\xc7\xcd\xea\xbf\x87\x87\xc7\xdb\xfb\x3b\xf8\x6e\xfb\x0e\xba\x0e\x7e\x67\xff\x72\xf3\x60\x7f\xff\xdb\xd5\xea\x6f\x8f\x87\x47\x78\xfc\xf9\xe6\xee\xf6\xf1\x13\x7c\xf8\x74\xf3\x70\xf3\xe1\xe9\xf0\x00\x8f\x87\x27\xf8\xe5\xf6\xe9\x13\x74\x7f\x82\xfb\x9f\x9f\x6e\xef\xef\xfe\xb0\x82\x73\xfe\x1c\x1d\xad\xfe\x0e\x57\x70\xd3\x00\x40\x0f\x57\x70\xf0\x07\xf0\x0f\xb8\x82\x5b\x3c\xfa\x1f\x5c\xc1\x3d\x1e\x0d\x70\x05\xcf\x78\xf4\x7f\xb8\x82\x3b\xfc\xf2\x08\x57\xf0\xd7\x95\x80\x60\x76\xd3\xa4\xe1\xa4\x01\x03\x90\x48\x24\x12\x19\x89\x40\x66\xc2\x93\x8c\x08\x24\x4c\x93\x02\x87\xe1\x38\x0c\xd8\x26\x93\x9e\xc8\xb0\x02\x11\x71\x24\x02\x49\x22\x50\xd2\x35\xcc\x87\x05\x25\x2c\x13\x2d\x63\x6c\x03\x08\xc6\x78\xc3\x22\x0e\x13\x70\x84\xcb\x44\xe9\xc6\xe8\x4b\x9f\x38\x52\x3e\x50\x7e\x88\xa7\x19\x69\x03\x00\x32\x8b\xe9\x6c\xd3\x75\x9d\x7f\x35\x64\x0b\x3c\x23\x9a\x87\x9f\x11\x85\xf3\x33\x24\x1e\xa3\x6d\x53\x98\xeb\x98\xeb\x7c\xac\x5a\x0e\xdf\x36\xb0\xb7\x0d\x83\x1f\xac\xe8\x36\xe4\xc6\xb5\x73\xd6\x01\x73\x65\x40\x06\x1b\x48\xee\x8c\x0c\xdb\x24\xf8\xf8\x15\xd7\x46\x46\x00\x16\x54\x3a\x1f\xbe\x61\xf1\x9d\x62\x3b\x72\x0d\x5c\x47\xd7\x27\xab\xe1\x21\x4a\x34\xd1\x9a\xd7\x46\x08\x60\x81\xc6\x82\x6c\x77\x24\xc3\x04\x02\xd8\x76\xe3\x86\x50\xbc\x77\xdb\x31\x20\x71\xae\xeb\xc6\x21\xca\x6d\x47\x3c\x7d\x70\x0e\xc9\xfd\x16\x3f\xdd\x6f\x4d\xe1\x50\x65\x0d\x65\x09\x84\x65\x4c\xb0\x22\x06\xb8\x09\x81\x1c\xce\x3b\xf1\xaa\x22\xc0\x68\xf7\x4b\xdf\x53\xfe\x06\x2a\x79\x3d\x51\xc1\xe5\x44\x45\x7f\xb7\xca\xb3\xd2\xad\xc7\x8a\xcb\x71\x80\xd0\xc0\x86\xe5\x16\x06\x59\x8e\xcc\x18\x72\x39\x2c\x73\x00\x72\x2a\x00\xa4\x58\xfc\x2a\x80\xf5\x20\x6c\xd1\x3f\xbd\x97\xe9\x76\x2b\xe3\x9c\xeb\xad\x1b\xf1\xb0\xb3\x4d\x4f\x41\x08\xbd\x01\x2a\x4b\x1c\x08\xc3\x30\x37\xe6\x63\x91\xf1\xe2\xc0\x3a\xe7\xca\x98\x87\xf9\x31\x6f\x8e\xbd\xc6\xd0\xf3\xaf\x8d\x99\x08\x2e\x82\x4a\x48\x09\xa8\x09\x38\x5d\x82\x99\x78\x30\xab\x40\x7b\x87\xd6\xff\xcd\xb5\xff\x82\x3f\x15\xff\x8f\xf5\x4b\xd6\xa7\x30\x7e\x09\x30\xeb\x53\x89\x88\xfd\x52\x14\x60\x22\xbe\xae\x7d\x3a\xd5\x41\x7c\x0e\xf6\xaa\x02\x03\xe4\xb0\x4f\x74\xea\x28\x8c\xa6\xbe\x07\xac\x9f\xf8\xea\xeb\xb0\xfa\xca\xda\xa2\xcb\x4b\xa5\x1a\x9b\x09\xd0\x2c\x29\x8d\x2f\x61\xd4\xdc\x46\xa0\x9e\x6f\x44\x53\x63\xfd\x2b\x45\xe6\x65\x6d\xc9\x0d\x69\x5c\x37\x92\x15\xcd\x1a\xc8\x84\xf1\xeb\xce\x8e\x29\xe0\xfc\x71\x8e\xbf\x70\xec\x4f\xf3\xb0\xc6\x60\x39\x53\x1a\x49\x59\x48\xd5\x90\x85\x2e\x8e\x90\x36\x54\xc9\x42\x6b\x60\x86\xf4\x7f\xef\x03\x2c\x92\x13\x8a\x18\x77\xb1\x51\x46\xd2\x03\x8c\x51\x86\x34\x35\x5b\x7a\xa6\xcb\xa2\xb3\x83\xd1\xd5\xb9\x9f\x76\x68\x1b\xeb\x5c\x2e\x61\xd1\x89\xd2\xbb\xd2\xb9\xd2\xb7\xd2\x97\x8a\x3a\x2b\x49\xf6\x7c\x4a\x71\x8e\xca\x56\xfa\xe2\x86\xa2\xf1\x25\x2d\xb8\x08\x34\x65\xb6\x93\xa0\x53\x26\x27\xd0\x94\xd9\x2f\x05\x9a\x8a\x72\xbe\x50\xc8\x1d\x67\x59\x97\x8d\x29\xc3\x4c\xdb\x63\xda\x30\xdb\x3a\x3b\xf6\x7c\x96\x89\x69\xc5\x32\x7e\x94\xc0\x66\xce\x7f\xb2\x36\x5c\xc0\xe6\x2e\xd9\x50\xda\x7c\x03\xaf\x62\x73\x82\x4b\x40\x19\xc4\x28\x2c\xb4\xda\x0c\x23\x1c\x67\x40\xc0\xa1\x68\x10\xc5\x71\x12\x7c\xfc\xdd\xf7\xd1\xd4\xb2\xcd\x75\xec\x23\xa2\x7b\xe4\xf7\x33\x2e\x08\x36\x94\xd7\xc6\x1c\xb9\x20\x6b\xc8\xe9\x52\xd1\x52\x2e\x54\x23\x8c\x38\x3f\x46\xf7\xb1\x5a\xe3\x38\x45\x56\xc8\x6a\xd3\x01\x0f\x0c\xd6\x38\xf8\x20\xcf\xe6\xaa\x38\xaf\x74\xe1\x8f\x26\x96\x3c\xa9\xb0\x81\x8a\x89\x24\xa9\x46\x5b\x7d\x5a\xa7\x3e\x67\x53\x1f\xa7\x24\xd4\xd2\xb4\x49\x4b\x12\x66\xaa\x3a\x19\xa0\x50\x62\xcd\xaf\x6c\x7d\x3e\x74\x23\x41\xf3\x3d\x1f\x0f\xaf\xa5\x3a\x7c\x48\x28\xb2\xb5\x30\xeb\x79\xf3\x0c\x2e\x99\xb0\x79\xc6\x36\xb0\x11\xf3\xcc\xbe\xeb\xf6\x9d\x9a\x67\x00\x2e\x36\xcf\x40\x1a\xda\xe9\xcf\x36\xfc\xbe\xd8\x83\xb1\xb4\xde\xd0\xe2\xed\x2d\x2d\x40\xd8\x7d\xd7\xb5\x16\x12\x23\xde\xad\x07\xc1\xeb\x36\x2a\xbc\x46\xc8\x5a\xec\x1c\x86\xe6\xb8\xe2\x2c\xb4\x31\x28\xc0\xc0\xac\x1c\x38\xeb\x50\xb9\x32\xec\x54\xeb\x14\xf2\xf4\x1e\xc1\xc7\x6f\x4d\xa0\x5b\xc2\x13\x4c\xa5\x85\x52\x01\xe5\x6d\xf3\x48\x94\xc4\xc7\xaf\x10\x89\x0c\x4e\x22\xec\x3c\xf1\xd6\xb1\xbc\xa6\xcd\xe3\xbb\xb2\x39\xbe\xbf\x71\x9b\x23\x08\xba\xb0\xaf\x2a\x7e\xc4\x82\xa3\x36\x9f\xc4\xf2\x92\x36\x67\x98\xa1\x55\xa1\x12\xd3\xb3\x6b\x39\xaf\x00\xdf\x4a\xce\x2b\xdb\x9c\x62\xa6\x16\xe7\x2e\x33\xc2\xa7\x4d\xc8\xd8\x17\x88\x73\x57\x39\x2d\x49\xdb\x94\x91\x6e\x1b\xd0\x66\xc7\x57\x69\xf7\x88\x4e\x94\xc6\x26\x0b\x52\xe5\xb1\x0a\x72\x21\x53\xab\xe4\x94\x3e\x62\x91\x8b\x25\x9e\xa4\x99\x1a\x2a\xa0\x64\xf1\x59\xb7\x96\xa0\x57\x31\xcd\xe2\x48\xd0\x71\xd0\xe0\xcc\x75\x1b\xc1\x14\x5f\xa6\x52\x52\x53\xc9\x95\x5a\x79\x03\x68\xc5\x54\x28\xd5\x51\x7e\x9d\x1f\xf4\x99\x21\xb2\x9c\xee\xb3\x78\xab\xc0\xbd\x91\x6e\xc9\xb3\x3f\xfa\xc8\x10\x1e\xe9\x19\x9a\x1c\x54\xbd\x6b\xa7\x11\x9e\x97\xce\xa0\x03\x0a\xc0\x8e\xac\xfe\xc0\xd8\xd9\xa6\x1b\x67\x07\x94\x1d\xfb\x56\x64\xb9\x07\xbf\xef\xbd\x37\x36\x13\x90\xce\x08\xa8\xda\x89\x29\xb3\x9d\x4c\x6d\x8b\x77\x6b\x3c\xb7\xfd\x30\xe4\x9d\x20\x93\xbb\x01\x3b\x66\x5d\x44\x66\xd4\xd2\xfb\x54\x7e\x2f\xe3\xce\x0b\x2d\x28\x14\x03\xad\x96\xae\x58\x7e\xcc\x2b\x54\xb2\x15\x85\x8e\xab\xf3\x8a\x9d\x22\x16\x04\x35\x57\x14\x43\xc5\x1b\x9a\x88\xea\x53\x28\x93\xfa\xe6\xbb\x33\xb7\xb9\x53\x36\x6f\x60\xa3\x6c\x1e\x43\xe5\xcd\xd9\xfc\x3d\x97\x2a\x1b\x73\xad\x2f\x7f\xcb\x29\xd4\x15\x17\xde\x14\xd7\xb8\x74\x9c\x3b\x5d\x34\xd7\xbe\xb6\xbb\xa2\xdd\xda\x7d\xe7\x5c\x65\xe6\xff\x46\xe3\x83\x2b\x4f\x4b\x85\x9e\x07\x05\x2b\x10\x45\x70\x83\xba\xcb\xa2\x82\xa8\x38\xf5\xc1\xe1\x02\x81\xa2\x94\x28\x14\xb0\x51\xd7\x78\x4f\x6e\x21\xaf\xe2\x7b\xda\xd2\x32\x3e\x82\x76\x34\x2f\xc0\x6e\xc5\x88\x0a\x88\x93\xb4\x06\x38\x81\x73\x02\x2e\x04\x52\xa0\x26\xf4\x1c\x3c\x53\x82\xe9\xc0\x75\x21\x55\x84\x4a\xf5\x96\xb9\x94\x9d\xf9\x65\x3c\x35\x30\x80\x50\x0f\x70\x0b\x4b\x54\x82\x5d\x70\x88\x60\xe9\x5a\x76\x10\xd7\x0a\x9f\x0f\x89\xb5\x6e\x93\x22\x53\x25\x73\x36\x4b\x79\x29\x7a\xa7\x57\xb0\x7b\x35\x11\xf4\x7a\x18\x80\x32\x6b\x55\xca\x2a\xe1\x27\x48\x96\xa6\x72\xc0\x0f\xd3\xbd\x98\x57\x84\x31\x85\x25\x29\x06\x76\xab\x40\xd0\x8d\x5b\x48\xc7\x38\x3a\x9e\x1b\xdd\xe9\xcf\xc8\x87\x01\xb4\x7a\xc7\x57\x4f\xf3\x46\x8e\xc4\x33\x6c\x6b\x47\xe0\x71\x4e\xe0\x49\x0e\xe0\x13\x01\x14\x56\x3e\xf9\x2b\x1f\xff\xe9\x27\x00\xea\x79\x3d\x29\x62\x76\x2b\x33\xb0\x57\x18\xd8\x2b\x0c\xec\x55\x6e\xa0\x10\x56\x88\xcb\xbe\x95\x5d\x3e\x72\xaf\x53\x62\x01\xdf\x90\x00\xfc\x19\xa8\x66\x21\x53\xb3\x10\x44\x10\xa9\x9f\x8a\x4a\x49\x8c\x59\x79\x42\x3a\xf1\x94\xc4\x38\x3b\xc4\x9d\x29\x3e\x6e\xd0\x12\x29\x9a\x06\xbe\x92\xba\x78\x89\xfb\xc4\x03\x87\x72\xe9\xbb\x38\x30\xb4\x41\x20\x8b\x37\xbb\x15\xad\xbf\x73\x64\x06\x2f\x8d\xf8\x3d\xee\xbd\x78\xee\xaf\xff\xb9\x3f\x4f\x1c\x53\x5a\x86\x08\xdd\xe4\xae\x87\x85\x62\x1d\x27\x3a\x77\xea\x3a\x52\x79\xfd\x09\x0b\x1c\x36\x4e\xd8\xc6\xcf\x1c\x5c\x38\x70\xe9\x42\x3c\x4c\x5d\x5a\x13\x32\xa3\x67\x50\x71\xdc\xe2\x30\xbc\xf5\x41\x74\xf8\x00\x64\xf6\x35\xeb\x60\x2a\x67\xd4\x56\x38\x98\x85\xf8\xac\xc1\x00\xca\xb5\x8d\xca\xca\x46\xb4\xd9\x84\xc4\x85\x5d\xa5\xfc\x7c\x6e\x1c\xa5\x55\xdd\x5c\xa6\xcf\x8a\xa3\xd9\x90\x6d\xb3\x91\x2c\x7c\xb4\xc2\x58\xb8\xd1\x50\x8c\xb3\xac\xcd\x45\xc6\xda\xc9\xf9\x5b\xdc\x8a\xe1\xc0\xd2\x28\x10\xfa\x66\xad\x06\x7f\x31\x47\xdb\x8a\xac\xca\x69\xd6\xcc\xab\x99\xca\x26\x59\xad\xee\x5a\x4f\xb1\xd3\x81\xcc\x6d\xc8\xef\x06\x58\xfe\xf2\x04\x16\x19\x1c\x8f\xcb\x14\x9e\x97\x38\x13\xef\xd7\x29\xd2\x52\x06\xa0\x3e\xd3\xe7\x57\x5c\xb2\x9c\x71\x5d\x04\x97\x34\x92\xf8\x8a\x95\x78\x54\x9c\xc9\xda\x22\x6f\xf7\x4f\x44\x8f\x3f\x97\xaf\x21\xaa\x15\xc4\x56\xaf\x1f\xea\xd5\x43\xbd\x76\x98\x56\x0e\x27\xcd\xb0\xf4\x86\x6c\x5e\xe5\x07\x59\xd1\x00\x44\xc5\x4d\xee\x2c\xa5\xcd\xae\xfc\x13\x40\x8f\xb0\x5a\xe7\x54\x95\x4a\x41\x0d\x29\xf5\x78\xb5\x45\xff\x0b\x86\x6e\x93\xcb\x40\xcc\x55\x93\x81\x95\x30\x05\x40\x91\x79\xdf\xa8\x77\x52\x66\x3a\xf9\x54\x64\x96\x84\x8a\x8d\xaa\x86\x9b\xc5\xe4\x40\xe3\x1f\xc7\x2b\x58\xf2\xa6\xa8\x44\x5f\x34\x80\x82\x55\xed\x0a\x8b\x5d\x0c\x27\x5d\x5c\x14\x7d\xc2\xe9\x5b\x5d\x05\x8a\xb6\xea\x3c\x52\x58\x6f\xc3\xed\x26\x0a\x59\xd1\x2a\xe7\x93\x17\x8b\x3c\x68\xf2\xb3\xcf\xcb\x4c\x6d\xb5\x5a\x86\xbf\x55\xe8\x5e\xab\x96\xcd\x3e\x8e\x91\x71\xa1\x09\x7e\xe2\x68\x8b\x07\xed\x6e\x15\xd6\x31\x70\x6d\x67\x48\xc5\xdd\x0d\xba\xd3\x57\x8f\x16\x79\xdb\x0b\xdc\x42\xcb\x84\x0e\x96\x0b\xe6\xc2\x1b\x28\x00\x9c\x94\x70\x52\xe3\xa0\x72\xd8\x2f\xd3\xe7\xd5\x2c\xe8\x83\x50\x7f\xd7\xda\xbb\x65\x1a\x97\x28\xce\xe0\x90\xb7\x05\xfd\x32\x13\xe1\xb1\x43\x2a\x53\x38\x9a\x84\x24\x71\xb1\x8a\x3a\x3f\x24\xb6\x27\xae\xa0\xc5\xb1\x0d\xb9\x90\xf7\x55\xc7\x67\xd8\x66\xeb\xc2\xb5\xd3\x5d\xf4\x90\x4e\x42\xfa\xd5\x7e\xa8\x01\x46\x3c\xc8\x35\xfc\x57\x44\x71\xe7\x7c\x56\x20\xef\x14\xe6\x54\xa0\xd5\x6e\x61\xbe\x04\x52\xec\xfe\x2c\x00\x5d\xf0\x97\x24\x30\xf0\x35\x9b\xb6\xeb\xf6\x62\x1f\x7b\x5e\x0c\x09\xc3\xaa\xdc\x78\x36\xdf\xa2\xa8\x71\xdc\xf1\xeb\x75\x1d\xf0\x49\x42\x5a\x79\x99\xfd\x83\x88\x05\xbf\x58\x3b\x59\xcb\x43\x23\xe1\x7d\x04\x8e\x2d\x42\x54\x56\xa3\x2a\xc4\x45\x20\xe4\x7c\xe4\xb7\xcf\xe7\x40\xa8\x1d\x66\xe1\xad\xec\x1e\xac\x75\xb1\xc6\xc5\x7f\x2f\x53\x3f\x9c\x59\x70\xa9\x3c\x9d\x31\x3a\x4e\xe7\xc2\xb1\xbd\xf4\x27\xcd\xcf\x3e\x89\xc2\x2f\x1d\x01\x13\xf6\x68\xbb\xce\xb9\xb4\x0f\xb3\x65\x51\x30\xf3\x6e\xfa\x3c\x7b\xb8\x6e\x1c\xbb\x4e\x28\xff\xba\xdb\x07\x8a\xc5\xeb\xf9\xbc\xdd\xea\xd7\x00\x00\x00\xff\xff\x0b\x5d\x3b\xd8\x2d\x3d\x00\x00")
+
+func fontsHollywoodFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsHollywoodFlf,
+ "fonts/hollywood.flf",
+ )
+}
+
+func fontsHollywoodFlf() (*asset, error) {
+ bytes, err := fontsHollywoodFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/hollywood.flf", size: 15661, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsInvitaFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x58\xdd\x6e\x23\x37\x0f\xbd\xf7\x53\xf0\x82\x80\x35\x80\xc7\xcc\x06\x8b\xe0\xfb\x80\xa2\xf0\x6d\xdf\x61\x00\xd6\xdd\x24\x4d\xb0\x69\xbc\x48\xbc\xed\xcd\x3c\x7c\x21\xfe\x48\xd4\xfc\xd8\x69\xbb\x8b\xcd\x8c\x66\x4c\x1d\x1e\x91\x47\x94\x34\x8f\x2f\x8f\xb7\x47\x84\x3b\xf8\x0c\xb7\x37\x70\x03\xb7\x9b\xe7\xd7\x3f\x9f\xcf\xc7\xfd\xe3\xcb\x23\xdc\xdc\xd1\xff\x3f\xc3\xb7\xaf\x77\xff\xfb\xf4\xe9\xfd\x70\xfc\x72\xbc\xdf\xdf\xbf\x1d\xbf\x3e\xec\x1f\xee\xbf\x6f\x8e\x2f\xc7\xf7\x1d\x9c\x9f\x1e\xe0\xcb\xe9\x8f\x6f\xdf\xcf\x0f\x6f\xf0\x74\x7c\x87\xdf\x1e\xce\xda\x7c\xbd\xff\xeb\xed\xf9\xfc\xfc\xfa\x3b\x9c\x9f\x8e\xaf\xf0\x0b\xdc\x9f\x60\x03\xf2\xef\x20\x77\x44\xb9\x23\xca\x33\xa2\xbc\xcf\x37\x38\x6c\xe4\x06\x07\x35\x24\xb5\x44\x52\x13\x20\xc5\xc0\x13\x56\xb0\xa6\x21\xad\xc3\x86\x08\xad\x65\x1d\xed\x52\x0c\xf3\x73\x4f\x7d\x4f\x3d\x1e\x36\xd6\x80\xe6\xd7\x79\x4b\x9b\xcc\xc4\xf6\x3a\x65\x3e\x9d\x7a\x82\x01\x40\x7c\xa5\x6c\xd0\x21\x04\xc2\x0d\x4c\x64\x91\x1b\xa9\xb3\x41\x8a\x6d\x8e\x03\xa5\x0e\xd7\xc6\xc6\x0c\xd9\x38\x99\xdf\xdd\x00\xa8\x3e\x07\x36\xcb\x84\xde\xc3\xfc\x1c\x36\x40\x80\xde\xc6\x02\x69\x57\xcb\x08\xec\x7b\x4b\x4a\xb6\xd6\xbc\x48\x4b\x28\x69\x4b\xba\xa7\x4c\xa1\x19\x90\x43\xf4\x7b\x70\x3f\x15\x24\xa0\x44\x18\xde\x6b\x73\x39\x30\xf5\x8e\x3c\x10\x63\xf6\x4b\x03\xe0\xec\x77\x6b\x08\x45\x35\x1f\xd5\x7a\x2c\xc6\x7e\x53\x32\xed\x15\xf5\x4a\x93\x60\x80\x33\xc7\x10\xf2\x6c\xab\xf1\xc3\x29\x01\x6c\x02\xba\xc1\xd3\xe4\x8d\xc5\x44\x03\x89\x26\x0b\xf1\x6b\x88\x13\x96\xee\x52\x14\x21\x79\x26\x91\x07\x4a\xa6\x6b\x68\x57\x04\xea\x7d\x3d\xeb\x04\x05\x0d\xc1\xc0\x66\x73\x86\xcd\x68\xeb\xca\xea\xfb\x6d\x7e\x43\x2c\xf9\x76\x6b\xbc\xd2\x0d\xa0\x4f\xce\x73\x55\xc5\xec\x48\x32\x2c\x73\x22\x69\x6e\xd9\xce\x49\x32\x97\xdf\xa4\x3f\xab\x7f\x66\xe6\xf5\x39\x03\xb8\xd2\xed\x32\x49\x33\x2a\xa1\xff\x60\x24\xb9\x4e\x51\x0d\xc9\xde\x22\x99\x2e\x93\xb4\x6e\x9e\xf2\xc4\xbc\xab\x6e\x11\xd6\x42\x02\x45\xcb\x5b\x11\xd3\x16\x97\xa6\x37\x84\x89\x72\x2a\x32\xce\x12\xc4\xa9\xf6\xd4\x53\x2e\x49\xf8\x13\x6a\x65\x1a\x70\x6d\x32\x69\x64\x3d\xbe\x8b\xb2\xcf\x4f\x83\xb9\xfe\x19\x7d\x88\x0b\x78\x16\xb8\x1c\x37\xd7\x92\x0f\xfc\xd4\x54\x9c\x65\x09\x7a\xe0\x28\x97\xd4\xfc\x66\xc8\xaa\x20\x5c\x8f\x77\x55\x76\xda\xe5\xee\xa3\x87\x8e\xfa\xbe\xd7\x87\x4e\x63\x3e\xb2\x14\x59\x9a\xcf\xb9\x16\xae\xc5\xab\x6b\x43\x06\x4c\x50\x10\x45\xae\x60\x90\x69\x09\x53\x40\x3b\xb0\xa0\xf8\xaa\xa2\x32\x0f\xcb\x4a\x10\xa1\x42\x24\x36\xa3\x7f\xc1\xd1\x2e\x92\x0a\x99\xf5\xba\xce\x25\x7b\x58\xe6\x08\x0e\xdb\xd5\x35\xcc\x89\x01\x74\x32\x87\x7c\x0d\x9a\xf1\xec\x66\x2b\x40\xcb\xd4\x51\x9d\x6a\x19\x55\x66\xb4\x33\x5c\x4d\x11\x16\xe0\xc6\x0f\xfc\x23\xbe\x14\x02\x6e\xbf\x90\x16\x08\xe1\xab\xd3\x7e\x95\xaf\x5c\x1b\xc2\x14\x18\xf7\x7d\x4f\x3e\x5c\xa5\x9c\xab\xcf\x9c\xf3\x94\x74\xcb\xda\x72\x25\xf8\xb5\x94\x90\x2f\xea\x52\x46\xd9\x23\x0c\x0b\x4b\x6c\x5d\xe2\x22\xde\x14\xb0\x22\x46\xc8\x3a\xa6\x89\x83\x5a\xc1\xf2\xa5\x84\xa0\x6b\x02\x90\xa0\x19\xfe\xb0\x30\xf8\x15\x79\x29\x08\x2a\x13\x4d\xc7\xce\x72\x01\xa5\x1a\x6b\x5b\x75\xd5\x24\xa9\x8b\xec\x1a\x7e\x34\x02\xd0\x58\x19\xc2\x98\xff\xb0\x72\x1c\x49\xa6\x7e\x61\xb9\x6d\x44\x38\xd7\xc0\xa2\x03\x98\x38\x88\xb2\x1d\x43\x34\xd5\x01\x5e\xd3\x80\x2f\x09\x69\xe7\x53\x97\x2c\x61\xae\x59\xf2\x6d\x28\x87\x34\xb6\x40\xb1\x0e\xb8\x58\xbd\x0e\x48\xba\xa9\x94\xc2\x3a\xe4\xae\x3c\x4c\xd3\x56\x41\x03\x66\x80\xac\x04\xd5\xa8\x32\x64\x2d\x7f\xc5\xac\xbb\x50\x9e\x6b\xa5\x2a\x04\x95\xd2\xc0\x70\xb5\x3c\x87\x4d\x55\x2e\xa5\x01\x2c\xa8\x32\x14\x11\x9c\x23\xc5\xd8\x79\xf9\xb0\x79\x53\x0c\x4b\x3e\xd1\xd5\xaf\x4f\x99\xdc\x02\xa4\xef\x34\x82\x70\xa6\xa5\x83\x22\xc7\xfa\x60\xf1\x4b\x7c\x19\xb4\x60\x76\x51\x89\x63\x45\xcc\x1a\x0c\x9a\x1b\x97\x48\x06\x8e\x2d\xe2\x38\x01\x9d\xe0\xb6\xd0\xb4\x82\x1e\x1d\xd4\xe9\xed\x53\x43\x4d\xc7\x58\x3b\x46\xae\x69\x82\xa5\x09\xe3\x07\xa5\x4a\x57\xab\x51\x64\xdb\x84\x55\xca\x06\x39\x6c\xb5\x9c\xd5\xb9\xb0\x0d\x05\x57\x66\x94\x79\x99\x36\x7e\x46\xec\xca\xb1\x2e\x95\x35\x54\x2d\xd0\xf7\xe9\x57\x0f\x5c\xc4\x30\x99\xc6\x87\x72\x68\xc0\xc1\xba\x0e\xd6\x6d\xf0\x03\x58\xbb\xa9\xc3\xb2\x51\xff\xc0\xd9\x0c\x78\xf5\x6c\xa6\xa3\x42\x2a\x7e\xca\xd9\x6b\xf1\x6c\x16\xfe\x73\xbe\x86\xbd\x18\x22\x0e\x88\xcd\xee\x0c\xeb\xc6\x01\xd6\x36\xba\xf9\xca\xba\x22\x27\x3e\xac\x6c\x74\x49\x73\x4e\x79\xd7\x46\x61\xcf\xdd\xc4\xc4\x2f\xac\x9b\xed\xf0\xae\x19\x89\x62\x71\x22\x77\x1a\x46\xb8\x59\xe6\x87\x19\x92\x13\x2d\xf2\x2b\x8b\x81\x6f\x40\x4c\x33\x64\xc8\xd4\x99\xec\x08\x60\x46\xa6\x2c\xca\x5e\xc9\xc4\xc7\xbe\xa7\x5a\x00\xc3\xa1\x5f\x26\x2a\xe9\x19\xa6\x5b\x22\x93\xaf\x3b\xfd\xc0\x92\x33\x94\x18\x2e\x31\xc6\x9d\x67\xcb\xd5\x23\x01\x56\xf7\xb5\x00\xcf\x08\xe4\x68\x90\x47\x78\x35\x5b\x1a\x87\x44\x35\xbe\xad\x82\xeb\x5b\x99\x7d\x87\x0d\x11\xb8\x02\x26\xa6\x7e\x35\x3b\x58\x14\x4a\x55\x53\x66\x96\xb8\x5b\x19\x3b\x4c\x5b\x65\x09\x06\xe2\xae\x84\x3f\xae\x40\x33\x0f\x7a\xfa\x93\x5c\x51\x02\xf3\x36\xa3\x81\x57\xb9\x22\xeb\x89\x7c\x35\x99\x32\x6a\x62\x2b\x37\x97\x46\x6d\xe7\xdf\x8b\xee\x18\x58\x53\xb2\x9a\x3a\x33\x03\x90\x10\x26\x5a\x3c\x26\x36\xa9\xd3\x83\xa5\xca\x81\x16\x4c\x1b\x9d\x23\x5c\xd5\xf9\xf2\xc4\xd8\x86\xcc\x4c\x3a\x2c\x7c\xe8\x42\xe8\xe1\xe3\x1f\xba\x4a\xb1\x2b\x1f\x99\xe6\x8d\x56\x38\xd7\xbe\x8f\x41\xdf\xd6\xff\xcb\xdf\xc7\x24\xdc\x72\xde\x87\x5f\xfb\x6d\xab\x4f\x8c\xd3\x73\xaa\xde\x83\x2d\x5d\x5b\xde\xfe\xb0\x53\x6f\x0e\x35\x6f\xff\xf3\x96\x94\x39\xef\xad\xb7\x3f\x76\x07\xa4\x2f\xf7\xb0\xd7\x2f\x4e\x97\xe4\x6e\x46\x17\x2a\x41\x31\xba\x30\x71\x66\xc7\xeb\x66\xd3\x4a\xf1\x13\x00\xc5\x4f\x00\xcb\x01\xce\xa0\x7f\x07\x00\x00\xff\xff\xd3\x8b\x3b\xc6\xa3\x17\x00\x00")
+
+func fontsInvitaFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsInvitaFlf,
+ "fonts/invita.flf",
+ )
+}
+
+func fontsInvitaFlf() (*asset, error) {
+ bytes, err := fontsInvitaFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/invita.flf", size: 6051, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsIsometric1Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\xdf\x6f\xdb\x36\x10\x7e\xd7\x5f\xf1\x3d\x54\x90\x0d\xd8\x64\xdc\xa5\x80\xc3\xc2\x83\x1f\x86\x6e\xdd\xba\xa2\x40\xf6\x28\x8c\xb2\x1d\x3a\x33\x92\x48\x85\xad\xb4\x0e\x40\xe8\x6f\x1f\x28\xfe\x10\xe9\xa4\x8b\x85\x38\x4e\x30\x88\x6d\xd1\x1c\x7f\x1c\x3f\x7e\xbc\xe3\x9d\x0e\x59\x5e\x2f\xdf\xce\xde\x60\x34\xaa\xff\x8e\x31\x1c\xe1\xed\x4f\xd1\x6a\x53\xdc\x88\x72\xbd\x5a\x8c\xc8\xf2\x7a\x19\x45\x1f\x56\x97\xd7\xa2\xc4\xa2\xc8\xbf\x89\xf5\x66\x55\xe4\x98\xdf\xe1\x0f\x91\x97\xf8\x3c\xdb\x6c\x44\x8e\xde\x95\xc8\xcb\x7c\xba\xb8\x9b\x8b\xf5\xe6\xeb\x6c\x21\x48\xb1\xbe\xec\x0f\x30\x1e\x8e\x4e\x86\x67\xa7\x03\xcc\x67\x1b\x71\x11\x15\x39\xca\x7f\x04\x96\x45\x5e\x6e\xf0\xb5\xd8\x94\xe2\x42\x69\xfa\x24\xf2\x5c\xac\x4b\x9c\x97\xc5\xe2\x8a\x45\xd1\x87\x75\x71\xc3\xb0\x51\xd2\x74\xf9\x7d\x45\x6e\xbf\xcd\x48\x7e\x8d\x5e\x30\xaf\x1f\xfd\x32\x2b\x05\xc3\xe8\x1d\x7e\xbf\xbd\xc6\xe8\xec\xec\x14\x27\x27\xec\xe4\x94\xbd\x7d\x87\x5f\xff\xfc\x2b\x8a\x7e\x13\x6b\x81\xd9\x5a\x40\x9d\x46\x6f\x4a\xf0\xb9\xc8\x87\x4b\x7d\x9c\x8f\xc9\x0d\x66\xcb\xf5\x6c\x75\x31\xc0\x6a\x89\xbb\xe2\x16\xdf\x67\x79\x3e\x33\xe7\x2c\x15\xd6\x9b\x01\xe6\x22\xba\xb9\xc3\xe5\xad\xd8\x94\x04\x1f\x2d\x6c\x75\x0e\x47\x93\x39\xd1\x5c\x2c\x8b\xb5\x20\x51\x34\x3c\x68\x8b\x22\xa8\x46\xb6\x71\xdd\xb6\x04\x6d\x5a\xb3\xac\x56\x33\x88\x5d\x6b\xa3\x87\x78\xcb\x22\xa3\x26\x01\xfa\x09\x90\xf6\x5b\xe8\x61\x3d\x20\x53\xff\x8c\xa2\x41\xbc\x8d\xfb\xdc\xb4\x3e\xdc\x99\xf1\x09\x02\x39\x72\x08\xac\x51\x02\x38\x47\x89\x02\x0b\x5c\x19\x45\x3d\x70\x00\x9c\xa3\x17\x6f\x6b\x4d\xbd\x38\x8e\xab\xbf\xc7\xe3\x2f\xd5\x78\xfc\x45\xb6\x80\x24\xab\xc9\xcf\x20\x93\x61\x85\x38\x8e\xfb\x5a\x13\x63\x04\x84\x0d\x52\x90\xa4\x85\xa6\x8c\x80\x0e\xea\x95\x4c\x6b\xca\xde\xc7\x2c\x4b\x09\xb2\x61\x82\x36\x90\x00\x59\xaf\x21\x34\x61\x31\x4b\x14\xe1\x59\xb6\xcd\x08\x86\x93\xc9\xe4\x41\x48\xf7\x9c\xc5\x11\x99\x91\xc9\x64\x32\x04\x49\xb6\x49\xad\x08\x14\x19\xcb\x08\xe7\xe4\x7d\x2b\x44\x00\x53\x8b\x12\x96\x20\x8d\x40\x2e\xc6\x73\x6d\x3f\x84\x64\x2d\x0d\x32\x21\x66\xa5\xd2\x11\xbd\x31\xdd\x6f\xa6\xc7\xfd\x71\x1a\x3d\xf8\xa7\xeb\xee\xba\xff\x27\xdd\xda\xd2\x39\xe7\xf5\xff\x46\xa6\x29\x90\x36\x32\x65\xcc\x74\xd4\x32\x65\x34\x35\x1d\x4a\x56\xa3\x95\xe9\x98\x46\x76\x34\x65\x29\xe7\xe9\x34\x42\x4a\x39\x4f\x59\x4a\x19\x05\xa8\xdd\x2f\x65\xb5\x68\xf7\x83\x1e\x6d\xf6\x37\xa2\x95\x95\x0e\x5a\xe3\x39\x24\x60\xce\x43\xc0\x92\x73\xa9\x00\xeb\xd1\x06\xb0\x1e\xf5\x00\xbb\x51\xbb\x9f\x1a\xd5\x08\x0d\x9e\xaa\x32\x4f\xc8\x81\x00\x53\x8d\xc2\x31\xac\x36\x6b\x18\x36\x53\x6b\x96\x2c\x60\xad\x1d\x0e\xb0\xed\xb0\x80\xeb\xd3\x3f\x1f\xc3\xd4\xed\xe1\x03\x6e\x18\x56\x53\x43\x86\xed\xa5\xbf\x10\xc3\xff\x6d\xc3\x66\x34\x60\xd8\x72\xe8\x18\x36\x1c\x1e\x89\xe1\x7d\x9c\xae\x01\xec\x43\xb2\x72\x08\xb8\x69\xf7\xe4\x67\xb3\x61\x1e\xda\x30\x7d\x84\xe1\xfb\x26\xd1\xf6\x95\x08\xae\xc4\xbd\x32\x0e\xb0\x59\xef\x18\x56\x60\x95\x8e\x86\x61\xad\xe3\xd9\x9e\xb5\xf0\x02\x34\xfc\x90\x6d\xbb\xd4\x31\x69\xa9\xd7\xb0\xc0\xb9\x42\x6a\x58\xa4\xa9\xbf\x65\xe3\x43\x30\x0c\xfb\x74\xa4\xfe\xd8\x03\x97\x1f\xa2\xd9\x81\xe3\xe3\x51\xf3\x1a\x40\x54\x7b\xb6\x45\xe4\xdd\xa2\x01\x11\x5e\x42\x1a\xdc\xc1\x8f\x8d\x72\x57\x3c\xd4\x8d\x73\x9e\x72\xff\xc6\x55\x6b\x6e\x5c\x32\x59\x55\xb2\x72\xfa\x24\x93\xd0\x39\xfb\x7e\x32\x52\xf5\x02\xde\x03\xec\x83\xf5\x81\x5a\x90\xd6\xa4\x3c\x73\xa2\xde\x73\x98\xfa\x7e\xe7\xfb\x5c\x68\x25\xce\xd7\x9c\xe9\xed\xcd\x9a\x3d\x86\x01\x24\x7d\x99\x32\x2a\xeb\x87\xdd\xb1\x06\x19\xb2\xc6\x69\x55\x85\x7e\x12\xbc\xf5\x07\x09\xff\xad\x01\x03\x01\x60\x19\x38\xb6\x64\x32\x00\x2c\x59\x08\x58\xb2\xe3\xe6\x2b\xfb\x84\xff\xb6\xd1\xf4\x08\x09\xd6\x53\x32\xc2\xa3\x06\x27\x17\xe0\x7d\x67\xd9\x71\x98\x57\x99\xc2\xfe\x98\x61\xc9\x42\xc0\x92\xc9\x00\xb0\x64\x32\x60\x78\xcf\xa7\xaa\x15\x60\x34\x80\x79\xcd\x30\x1c\xe0\x54\x33\x0c\xcf\x86\x1f\x4d\xb0\x0e\x6c\xc3\xe1\xbb\xe9\x77\x34\x57\xba\x13\x65\xa9\x6f\x12\xda\x2d\x5d\x82\xd5\xc4\x96\xdd\x48\xf6\x04\x1b\x7e\x24\x7a\xf9\x1b\x5a\xb1\x89\x5e\xf5\xfe\xf4\xb8\xaf\x44\x3b\xc0\xb5\x3a\x1b\x01\x8d\x05\xba\x28\xa8\xe5\x06\x70\x1d\x65\x42\xc0\xcc\x66\x34\x7a\xbf\xaa\xb2\x5f\x05\x4f\x60\x98\x53\xee\x03\xa6\x8d\x0d\xd6\xa2\x99\x61\x18\x76\x33\x9a\xd4\xc6\x67\xd8\xcc\x38\x20\xc3\x72\xe7\xab\x22\x88\x6c\x0f\xcb\x2e\x34\xab\xc4\x86\xfa\xa1\xb9\xe6\xaf\xaa\xa8\x4d\x68\xaa\x4a\x27\x38\x78\x6a\x42\x73\x20\xc0\xc6\x07\x59\xe8\x74\x1e\xe0\xe7\x71\xba\x96\xaf\x84\x17\x9a\x4d\x89\x3a\x0d\x18\xb6\x56\x6a\x9c\xae\xaa\x52\x6d\xa5\xd3\xe8\x38\x5f\xe6\x8c\x85\x81\xc3\x75\xd4\x36\xcc\xd8\xa7\xf3\xc0\x24\x46\x67\x67\xa7\xcc\xb7\xe1\x1a\xff\x8e\xd3\xed\x6b\xc3\x5d\x41\xeb\x98\xd9\x40\x57\xd0\x7a\xee\x14\xbc\x2b\x68\xbd\xec\x37\x43\x57\xd0\xea\x0a\x5a\x5d\x41\xab\xcd\x8d\x77\x05\xad\xae\xa0\xd5\x15\xb4\x5e\x41\x46\xd8\x15\xb4\xba\x82\x56\x57\xd0\xea\x0a\x5a\x5d\x41\xab\x2b\x68\x75\x05\x2d\x03\xf8\xf5\xfc\x1e\xd4\x0b\x74\xff\x1b\x00\x00\xff\xff\x1f\x45\xa0\xac\x57\x2d\x00\x00")
+
+func fontsIsometric1FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsIsometric1Flf,
+ "fonts/isometric1.flf",
+ )
+}
+
+func fontsIsometric1Flf() (*asset, error) {
+ bytes, err := fontsIsometric1FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/isometric1.flf", size: 11607, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsIsometric2Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x5d\x6f\xdb\x36\x17\xbe\xd7\xaf\x78\x2e\x2a\xc8\x06\x6c\x32\xce\x9b\x02\x0e\x0b\xbf\xf0\xc5\xd0\xad\x5b\x56\x14\xc8\x2e\x85\x51\xb6\x43\x67\x46\x12\xa9\x90\x95\xd6\x01\x04\xfd\xf6\x81\x12\x3f\x6d\x2f\x89\xe2\xc4\x1d\x06\xb1\x2d\x9a\x43\x93\x47\xcf\x79\x74\xbe\x7c\x90\xe5\xed\xf2\x74\xf6\x0e\xa3\x51\xfd\x77\x8c\xe1\x08\xa7\xff\x0b\x56\xeb\xec\x4e\x14\xf9\x6a\x71\x4a\x96\xb7\xcb\x20\xf8\xb8\xba\xbe\x15\x05\x16\x59\xfa\x4d\xe4\xeb\x55\x96\x62\xfe\x80\xdf\x44\x5a\xe0\xf3\x6c\xbd\x16\x29\x7a\x37\x22\x2d\xd2\xe9\xe2\x61\x2e\xf2\xf5\xd7\xd9\x42\x90\x2c\xbf\xee\x0f\x30\x1e\x8e\x4e\x86\xe7\x67\x03\xcc\x67\x6b\x71\x15\x64\x29\x8a\xbf\x04\x96\x59\x5a\xac\xf1\x35\x5b\x17\xe2\x4a\x6a\xba\x10\x69\x2a\xf2\x02\x97\x45\xb6\xb8\x61\x41\xf0\x31\xcf\xee\x18\xd6\x52\x9a\x2e\xbf\xaf\xc8\xfd\xb7\x19\x49\x6f\xd1\xf3\xce\xf5\x83\x9f\x66\x85\x60\x18\xbd\xc7\xaf\xf7\xb7\x18\x9d\x9f\x9f\xe1\xe4\x84\x9d\x9c\xb1\xd3\xf7\xf8\xf9\xf7\x3f\x82\xe0\x17\x91\x0b\xcc\x72\x01\x69\x4d\xf3\x50\x82\xcf\x59\x3a\x5c\x36\xe6\x7c\x8a\xee\x30\x5b\xe6\xb3\xd5\xd5\x00\xab\x25\x1e\xb2\x7b\x7c\x9f\xa5\xe9\x4c\xd9\x59\x48\xac\x77\x03\xcc\x45\x70\xf7\x80\xeb\x7b\xb1\x2e\x08\x3e\x69\xd8\xd2\x0e\x43\x93\xb2\x68\x2e\x96\x59\x2e\x48\x10\x0c\x5f\x75\x05\x01\xe4\x22\x9b\xb0\x5e\x1b\x82\x36\xcb\x5e\xab\xd5\x0c\x42\xb3\xda\xe8\x21\xce\xb5\x40\xa9\x89\x80\x7e\x04\xc4\xfd\x16\x7a\x58\x0f\x48\xe4\x3f\xa5\x68\x10\x6e\xc2\x3e\x57\xab\x0f\x63\x33\x2e\x20\x90\x22\x85\x40\x8e\x02\xc0\x25\x0a\x64\x58\xe0\x46\x29\xea\x81\x03\xe0\x1c\xbd\x70\x53\x6b\xea\x85\x61\x58\xfd\x39\x1e\x7f\xa9\xc6\xe3\x2f\x65\x0b\x48\x65\x35\xf9\x3f\xc8\x64\x58\x21\x0c\xc3\x7e\xa3\x89\x31\x02\xc2\x06\x31\x48\xd4\x42\x53\x42\x40\x07\xf5\x4d\xd6\x68\x4a\x3e\x84\x2c\x89\x09\x92\x61\x84\x36\x90\x80\xb2\xbe\x43\x68\xc4\x42\x16\x49\xc2\x93\x64\x93\x10\x0c\x27\x93\xc9\x5e\x48\x3b\xc1\x62\x88\x4c\xc8\x64\x32\x19\x82\x44\x9b\xa8\x56\x04\x8a\x84\x25\x84\x73\xf2\xa1\x15\x22\x80\xc9\x4b\x11\x8b\x10\x07\x20\x57\xe3\x79\xe3\x3f\x84\x24\x2d\x1d\x32\x22\xea\xa6\xd4\x11\xbc\x53\xdb\xef\xa6\xc7\xfd\x71\x1a\xec\xfd\xd3\x6d\x77\xdb\xff\x91\xed\xc6\xd3\x39\xe7\xf5\xff\x4a\xa6\x31\x10\x5b\x99\x32\xa6\x36\x6a\x99\x32\x1a\xab\x0d\x29\x53\x46\xcd\x89\x69\x20\x45\xde\x9c\xe0\x3c\x9e\x06\x88\x59\x2c\x4f\x20\xa6\x9c\x53\x79\x3e\x66\x4c\xfe\x68\x9f\xa7\x95\x99\xe7\x35\x77\x1d\x3c\xb1\xbe\x60\x00\xeb\xa5\xe4\xba\x32\xb4\x05\x2c\x9f\xe1\x02\x2e\x39\x2f\x2d\xe0\x1a\xb4\x05\xdc\x88\x06\xb0\x12\x0d\x60\x25\xfe\x33\xe0\x1d\x86\x3d\x0b\xb5\x3a\x0b\x58\x89\x06\xb0\x14\xa5\x0e\x05\x58\x6a\xa7\x96\x61\x69\x9b\x0b\x38\x36\x97\x5e\x0c\xf8\x50\x86\xf5\x5b\xb4\x80\x5d\x86\xdf\x00\xf0\xd3\x0c\x73\xca\x5d\x86\xd5\x09\xeb\x12\xcd\x09\xeb\x12\x2e\xc3\x3f\xc4\x25\x9e\x06\xac\x1e\x48\x2d\x9c\x5a\x76\xe0\x34\xe7\x5f\x25\xe8\x5e\x00\xf8\xb1\x2c\xc1\x63\x2f\x4b\x1c\xc3\x25\xbc\xb4\x66\x39\xd0\xe7\x5d\x1f\x96\x77\x5d\xc0\xb1\xf6\xf2\xb7\x4f\x6b\xfb\x24\xcf\x14\x8f\x79\x6a\x9e\x5b\xf3\xca\x1c\x23\x63\x15\x95\x4d\xde\x40\x55\x49\xd4\xca\x00\x87\x42\x4d\x8f\xc3\xb6\x01\xe7\x43\xf3\xb0\x78\x50\x3c\x24\x1e\x10\x07\x07\x2c\x0c\x45\xab\xe5\xc5\x03\xe1\x65\x45\xc5\xde\x16\x9e\xed\x77\x5b\xa2\xe9\x9e\x1b\xb9\x64\x8f\xc9\x9c\x7b\x32\x8d\xe5\xe7\x9c\x97\x32\xc7\xe9\x77\x2b\x97\xfb\x6e\xab\x8a\x56\xee\xbb\xad\xaa\xc3\x4a\x56\x2b\x59\x1b\xab\x2b\x80\xa2\xf6\x6d\x2b\xc0\xe3\xd1\x53\xfa\x15\x40\x32\xe8\x45\x4f\xc9\xca\xd8\x09\x77\xc6\x58\xc9\xdd\xe8\xa9\xf9\x73\xa2\xc7\x04\xcb\x2b\xe6\xa7\x76\xe1\xce\xf9\x16\x60\xb9\x3c\xc0\x55\x75\x4c\xc0\xcf\xab\xb1\x6e\x42\xa5\x38\x4a\x42\xf5\xe1\xfa\x60\x1d\xa8\x2a\xa8\xbd\xca\x49\xbd\xba\xb9\x05\xc1\xa6\x50\x9f\x51\x9f\xcf\xc7\xf2\xd3\x23\xe1\x74\xec\x16\xd7\x6d\xe0\x2c\x93\x87\xbd\xfc\x27\xca\x3f\xe7\x74\x3b\x81\x39\xfd\x8a\x4c\x60\x55\x55\xbd\x3c\x81\xbd\x72\xf9\xdf\xc3\xa0\xdf\x60\xf9\xde\x6a\x1b\x1c\xbf\x5c\x1d\x90\x71\xdb\xf6\xe4\x6e\x79\x77\x0a\xad\x32\x28\xf6\x2b\xaf\xc9\x26\x5e\xbe\x71\x3d\xf8\xe9\x9a\xd6\xb6\x5f\x71\xf3\x41\xf3\xc9\x1b\xe7\x83\x76\x41\xf6\x3c\x03\xf4\x97\x86\xfa\x13\x55\xa7\x8d\x01\x56\x6e\x8e\x36\x75\x5b\x1b\xc0\x74\x02\x69\xf4\xd7\xee\xde\x26\xe8\xb6\x5e\x19\x8d\x7d\x80\x52\xf0\x18\x56\x1b\x96\x61\xc3\xa1\x66\x58\x73\x78\x70\x11\xde\xe9\x73\x76\x1a\x9b\xfd\x1b\x86\x22\xe3\xa8\xaa\xa8\x71\xd5\xec\x48\x92\x34\x73\x5c\xb7\x82\x25\x2b\xab\xca\x69\x9f\x76\xfa\x29\x58\xad\x7a\xc3\x86\xc7\xf4\xc9\x6e\x76\xbb\x92\x34\xca\x7d\x03\x76\x25\x6b\x8b\x31\x44\xbf\x9c\xc6\x0a\xb7\xab\xf4\xdb\x4a\x9d\x9c\x9f\x1b\xfa\xda\x5c\x1d\xfa\xae\x4c\x19\x6d\x50\x99\xaf\xe3\x35\x4a\xd3\x8c\xd1\x1a\xa7\xdb\xc8\xa2\x64\x7e\x73\x5d\x32\x3f\x97\x95\x5b\x7e\x50\x1e\xda\x2a\xb8\xdc\xe8\x66\xc6\xed\x6d\x2e\x2e\xdd\xde\x86\x8d\xce\xcf\xcf\xbc\x6a\xa1\x8b\x87\x1b\x59\xcf\x75\xdc\x6e\x8a\xf5\xc2\xaf\x04\xdd\x14\xab\x9b\x62\x75\x53\xac\x6e\x8a\xd5\x4d\xb1\xba\x29\xd6\x56\x2f\xb7\x4f\xee\xa6\x58\xdd\x14\xab\x9b\x62\x75\x53\xac\x36\x5c\x77\x53\xac\x6e\x8a\xd5\x4d\xb1\xba\x29\x56\x37\xc5\xd2\x1b\xdd\x14\xeb\x28\x53\xac\x7f\xcf\x6f\x3c\xfd\x80\xed\xbf\x03\x00\x00\xff\xff\x98\xa5\xd7\x37\x41\x2d\x00\x00")
+
+func fontsIsometric2FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsIsometric2Flf,
+ "fonts/isometric2.flf",
+ )
+}
+
+func fontsIsometric2Flf() (*asset, error) {
+ bytes, err := fontsIsometric2FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/isometric2.flf", size: 11585, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsIsometric3Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x5d\x6f\xdb\x36\x14\x7d\xd7\xaf\x38\x0f\x15\x64\x03\x36\x19\xa7\x29\xe0\xb0\xf0\xe0\x87\xa1\x5b\xb7\xac\x28\x90\x3d\x12\xa3\x6c\x87\xce\x8c\x24\x52\x21\x2b\xad\x03\x08\xfa\xed\x03\x3f\x24\x91\x8e\x93\x58\x89\xd3\x0e\x9b\x98\x04\xc9\xa5\xc9\xcb\xc3\xc3\xfb\x85\x8b\x2c\xaf\x97\xc7\xb3\x37\x18\x8d\xf4\xf7\x18\xc3\x11\x8e\xdf\x06\xab\x75\x7a\x23\xf3\x6c\xb5\x78\x4b\x96\xd7\xcb\x20\xf8\xb0\xba\xbc\x96\x39\x16\x69\xf2\x55\x66\xeb\x55\x9a\x60\x7e\x87\xdf\x65\x92\xe3\xd3\x6c\xbd\x96\x09\x7a\x57\x32\xc9\x93\xe9\xe2\x6e\x2e\xb3\xf5\x97\xd9\x42\x92\x34\xbb\xec\x0f\x30\x1e\x8e\x8e\x86\xa7\x27\x03\xcc\x67\x6b\x79\x11\xa4\x09\xf2\xbf\x25\xbe\xa4\xeb\x5c\x69\x38\x93\x49\x22\xb3\x1c\xe7\x79\xba\xb8\x62\x08\x82\x0f\x59\x7a\xc3\xb0\x56\xe2\x74\xf9\x6d\x45\x6e\xbf\xce\x48\x72\x8d\x9e\xb7\xb0\x1f\xfc\x3c\xcb\x25\xc3\xe8\x1d\x7e\xbb\xbd\xc6\xe8\xf4\xf4\x04\x47\x47\xec\xe8\x84\x1d\xbf\xc3\x2f\x7f\xfc\x19\x04\xbf\xca\x4c\x62\x96\x49\xa8\x6b\x60\x99\x26\xf9\x9a\xe0\x53\x9a\x0c\x97\xe6\x1e\x1f\xa3\x1b\xcc\x96\xd9\x6c\x75\x31\xc0\x6a\x89\xbb\xf4\x16\xdf\x66\x49\x32\xb3\x17\xcc\x15\xc8\x9b\x01\xe6\x32\xb8\xb9\xc3\xe5\xad\x5c\xe7\x04\x1f\x35\x6a\x79\xa1\x2f\x50\xf3\x63\x94\x63\x2e\x97\x69\x26\x49\x10\x0c\x0f\x3a\x82\x00\x6a\x90\x4d\xa8\xc7\x86\xa0\xcd\x68\xb6\x69\x35\x83\xb0\x1e\x6d\xf4\x10\x67\x5b\x60\xd5\x44\x40\x3f\x02\x78\xbf\x85\x1e\xd6\x03\x62\xf5\x63\x15\x0d\xc2\x4d\xd8\x17\x76\xf4\x51\xdf\x19\x67\x90\x48\x90\x40\x22\x43\x0e\xe0\x1c\x39\x52\x2c\x70\x65\x15\xf5\x20\x00\x08\x81\x5e\xb8\xd1\x9a\x7a\x61\x18\x96\x7f\x8d\xc7\x9f\xcb\xf1\xf8\x73\xd1\x02\x52\x51\x4e\x7e\x02\x99\x0c\x4b\x84\x61\xd8\x37\x9a\x18\x23\x20\x6c\xc0\x41\xa2\x16\x9a\x62\x02\x3a\xd0\x3b\x99\xd1\x14\xbf\x0f\x59\xcc\x09\xe2\x61\x84\x36\x90\x80\x42\xef\x21\x34\x62\x21\x8b\x14\xe1\x71\xbc\x89\x09\x86\x93\xc9\x64\x27\xa4\x7b\xce\x52\x13\x19\x93\xc9\x64\x32\x04\x89\x36\x91\x56\x04\x8a\x98\xc5\x44\x08\xf2\xbe\x15\x22\x80\xa9\x4d\x11\x8b\xc0\x03\x90\x8b\xf1\xdc\xd8\x0f\x21\x71\x4b\x83\x8c\x88\xdd\xa9\x74\x04\x6f\xec\xf4\x9b\xe9\xf7\xfd\x73\x1a\xec\xfc\xea\xa6\xbb\xe9\xff\xc8\xb4\xb1\x74\x21\x84\xfe\x6d\x65\x0a\x50\xde\xc8\x4a\x64\x8c\x57\xb2\x16\x29\x57\x13\x4a\x36\x62\xa9\x57\x4c\x03\x50\x21\x28\xa3\x76\xc5\x34\x00\x07\x38\xe3\x94\x51\x21\x38\x55\xeb\xf5\x04\xa3\xcd\x79\x66\x85\x73\x7e\x33\x61\xf1\x70\xb5\x57\xcb\x15\xe0\x6a\x58\x59\x67\x86\x03\x00\x2e\x5c\xc0\x25\x65\x1e\x60\xb5\xca\x01\xac\x44\x17\xb0\xbe\xd2\x83\x80\xf7\x60\x98\xc2\x07\x5c\xaf\xaf\x44\xa5\xa3\x01\x6c\x74\xd4\x80\xed\xaa\x1a\x30\xc7\x8b\x00\x3f\x83\x51\x73\x6a\x03\x50\xe9\x74\x18\x3d\x14\xc0\x6d\x0b\x68\xc3\xb0\xd8\x62\x98\xfa\x17\xd0\x2b\x3c\x93\x70\x19\xb6\x53\x07\x36\x09\x1f\xae\x0f\xd6\x87\xea\x03\xf5\x61\x7a\x20\xe1\xbb\x99\xef\x64\xbe\x8b\xf9\xe0\x0e\xc8\xa5\xf0\xdd\x4b\xe9\x77\xe3\x01\x68\x59\x1e\xd0\x5a\xef\x01\x16\x82\x7a\x01\xc4\xbf\xbd\xd1\x50\xdd\x5f\xed\xad\xec\xdb\x02\xe6\xf8\x3e\x01\xcc\x48\x1e\x78\x8f\x6b\x2f\x2e\x68\x26\x6b\xb5\xdc\x52\x2a\x84\x77\xa8\x31\x93\xea\x86\x86\x61\x4b\x48\xc5\x6f\xf3\xdc\xc1\x0e\x47\x72\xdd\xbe\xc2\xe2\x41\xf1\x90\x38\x40\xb6\x2e\xef\xc2\xe0\x8e\x1d\x55\x90\x3c\x44\xbb\x00\x3d\xf6\xb6\x45\x23\x17\x40\xc1\x1e\x94\x85\xf0\x64\xfd\xb6\xa2\x60\x85\x8a\x6e\xce\xdb\xaa\xe1\xbe\x6d\x59\x96\xe5\xc1\x92\xd3\xa3\x72\x75\x39\x27\xb6\x73\xbc\x56\x6c\xdf\x37\x74\xfa\xde\xa3\x19\x74\xbc\xc7\x30\xda\x78\x4f\x21\x14\xa3\x6e\xec\x67\x8c\x15\x70\xbd\xa7\x2c\xb9\xe7\x3d\xdc\x21\xe4\x39\x0c\xb7\x76\x77\x27\xdc\xe9\xcc\x66\xfd\xdf\x01\xac\x86\x07\xb8\x2c\x7d\xc0\x2f\x32\x89\x97\x17\x58\x3b\xb3\xeb\xab\xa5\xff\xa7\x92\x53\xe5\xe0\xd4\x09\x94\x4d\x61\xf5\xba\xc9\x69\xdb\x9d\x7e\x6c\xf1\x5a\x31\xf7\xb2\xca\xe4\x69\x80\x14\x3e\xc0\xd7\x0c\x60\x07\x29\xa5\x9e\x60\xf4\xe1\xea\x5a\xc3\x71\xac\xb5\x2e\x78\xf7\xcb\xa6\x4f\x17\x56\xdb\x55\x76\x0d\xbb\x7a\x05\x73\x60\xf5\x06\xf6\x38\x27\xa9\xd9\x5b\xd4\xa7\xd7\xc1\x6d\x8f\xc7\x6f\x19\xaa\xdc\x7c\x6a\xf7\xbe\xb2\xe7\xef\xf6\xae\x2d\xf8\x5b\xe8\xb7\xc0\x37\xd8\x2b\xa8\x66\x9f\xc9\x1c\x35\xf2\x5a\xb4\xb2\xce\x23\xb5\x0d\x68\x93\x6e\x9c\x4a\x5b\xf4\xbe\xb4\x0a\x2e\x5c\x5a\xcd\xa7\x0d\xad\xf6\x53\x8f\x56\x3b\xd1\xd0\x6a\x88\x73\x68\xe5\xec\xc0\x15\x6a\x9b\x2a\x46\x73\x03\xb7\xfc\x62\x8a\x30\x1d\x04\x14\x3b\x2a\x5d\xd5\x41\x40\x37\x2c\xcb\x82\x15\x55\x10\x70\x14\x3e\x24\x0b\x51\xec\xef\x53\x06\xbc\x0f\xf5\xbe\xd4\xc0\x76\x41\x57\x2b\x0d\xe4\x83\xf8\xd4\xae\x80\x5a\xf8\xf1\xa9\x96\x8d\xa8\x4b\x40\x27\x3e\x29\x94\xa6\xe0\x32\x0f\x57\xb0\x82\x36\x5c\x2a\xd9\x29\x9f\x4d\x41\x44\x7d\x2e\xe9\x63\x5c\xb6\xcf\x00\x0d\x53\x95\xc8\xbc\x7a\xe5\xec\xdc\xad\x57\xd8\xe8\xf4\xf4\xc4\xcb\x00\x8e\xf7\x54\x13\xfb\x59\x6b\xd7\x83\x7a\x66\x99\xdf\xf5\xa0\xba\x1e\x54\xd7\x83\xea\x7a\x50\xfb\x57\x7a\x5d\x0f\x6a\xdb\x95\xba\x1e\x54\xd7\x83\xda\xe9\x3d\x5d\x0f\xaa\xeb\x41\x75\x3d\xa8\xae\x07\xd5\xb2\x94\xea\x7a\x50\x3b\xb9\xec\x7a\x50\x5d\x0f\xaa\xeb\x41\xfd\x6f\x7a\x50\xff\x9e\xff\x36\xfa\x01\xd3\xff\x04\x00\x00\xff\xff\x92\x72\x45\x3e\xb6\x2c\x00\x00")
+
+func fontsIsometric3FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsIsometric3Flf,
+ "fonts/isometric3.flf",
+ )
+}
+
+func fontsIsometric3Flf() (*asset, error) {
+ bytes, err := fontsIsometric3FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/isometric3.flf", size: 11446, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsIsometric4Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\xdf\x6f\xdb\x36\x10\x7e\xd7\x5f\xf1\x3d\x44\x90\x0d\xd8\x54\x9c\xa5\x80\xc3\xc2\x83\x1f\x86\x6e\xdd\xb2\xa2\x40\xf6\x28\x8c\x92\x1d\x3a\x33\x92\x48\x85\xac\xb4\x0e\x20\xe8\x6f\x1f\xf8\x43\x24\x65\x3b\x35\x94\xc4\xce\x3a\x88\x6d\xd1\x1c\x4d\x1e\xbf\xfb\x78\xbc\x3b\x1f\xb2\xb8\x5b\x9c\x25\x27\x18\x8d\xe4\xdf\x31\x86\x23\x9c\xfd\xe4\x2d\x57\xd9\x3d\x2f\xf2\xe5\xfc\x9c\x2c\xee\x16\x9e\xf7\x61\x79\x73\xc7\x0b\xcc\xb3\xf4\x2b\xcf\x57\xcb\x2c\xc5\xec\x11\x7f\xf0\xb4\xc0\xa7\x64\xb5\xe2\x29\x7a\xb7\x3c\x2d\xd2\xe9\xfc\x71\xc6\xf3\xd5\x97\x64\xce\x49\x96\xdf\xf4\x07\x18\x0f\x47\xa7\xc3\x8b\xf3\x01\x66\xc9\x8a\x5f\x7b\x59\x8a\xe2\x1f\x8e\x45\x96\x16\x2b\x7c\xc9\x56\x05\xbf\x16\x9a\x2e\x79\x9a\xf2\xbc\xc0\x55\x91\xcd\x6f\xa9\xe7\x7d\xc8\xb3\x7b\x8a\x95\x90\xa6\x8b\x6f\x4b\xf2\xf0\x35\x21\xe9\x1d\x7a\x8d\x75\x7d\xef\x97\xa4\xe0\x14\xa3\x77\xf8\xfd\xe1\x0e\xa3\x8b\x8b\x73\x9c\x9e\xd2\xd3\x73\x7a\xf6\x0e\xbf\xfe\xf9\x97\xe7\xfd\xc6\x73\x8e\x24\xe7\x10\xd6\xa8\x43\x09\x3e\x65\xe9\x70\xa1\xcc\xf9\x18\xdc\x23\x59\xe4\xc9\xf2\x7a\x80\xe5\x02\x8f\xd9\x03\xbe\x25\x69\x9a\x68\x3b\x0b\x81\xf5\x7e\x80\x19\xf7\xee\x1f\x71\xf3\xc0\x57\x05\xc1\xc7\x1a\xb6\xb0\xc3\xd0\xa4\x2d\x9a\xf1\x45\x96\x73\xe2\x79\xc3\x57\x1d\x9e\x07\x31\xc8\xda\x97\x63\x4d\xd0\x66\xd8\x6d\x52\xcd\xc0\x37\xa3\x8d\x1e\xe2\x6c\xf3\xb4\x9a\x00\xe8\x07\x40\xd4\x6f\xa1\x87\xf6\x80\x58\xfc\xd3\x8a\x06\xfe\xda\xef\x33\x3d\xfa\x30\x36\xe3\x12\x1c\x29\x52\x70\xe4\x28\x00\x5c\xa1\x40\x86\x39\x6e\xb5\xa2\x1e\x18\x00\xc6\xd0\xf3\xd7\x52\x53\xcf\xf7\xfd\xea\xef\xf1\xf8\x73\x35\x1e\x7f\x2e\x5b\x40\x2a\xab\xc9\xcf\x20\x93\x61\x05\xdf\xf7\xfb\x4a\x13\xa5\x04\x84\x0e\x22\x90\xa0\x85\xa6\x98\x20\x1c\xc8\x9d\x54\x69\x8a\xdf\xfb\x34\x8e\x08\xe2\x61\x80\x36\x90\x80\x52\xee\x21\x61\x40\x7d\x1a\x08\xc2\xe3\x78\x1d\x13\x0c\x27\x93\xc9\x4e\x48\x5b\x8f\xc5\x10\x19\x93\xc9\x64\x32\x04\x09\xd6\x81\x54\x84\x10\x31\x8d\x09\x63\xe4\x7d\x2b\x44\x00\x15\x9b\x02\x1a\x20\xf2\x40\xae\xc7\x33\xe5\x3f\x84\xc4\x2d\x1d\x32\x20\x7a\xa7\xd0\xe1\x9d\xe8\xe9\x93\xe9\x71\x7f\x9c\x7a\x3b\xff\x74\xd3\xdd\xf4\xff\x64\x5a\x79\x3a\x63\x4c\xfe\xaf\xe5\x10\x08\x23\x2b\x0b\x91\xd2\xa8\x96\xa5\x18\x46\x62\x42\xc8\xf5\xa7\x62\x62\xea\x21\x64\x4c\x7d\xca\x22\x1a\x4d\x3d\x44\x8c\x45\x21\xc4\xa7\x21\x0d\xeb\xf3\xc4\x24\xa5\x61\x7d\x9e\x56\x69\xcf\x97\x3a\x2c\x1e\xad\x03\x38\x34\xe0\x52\x00\x96\x60\x1d\xc0\x6a\xc2\x01\x1c\xd5\xe6\xd4\xe7\xd5\xe6\x18\x3c\x00\xaa\xea\x75\x01\x2b\x0e\x2d\x60\x8d\xc2\x02\x56\x2c\x59\xc0\xb0\xe7\x39\x13\x1a\xb0\x99\x38\x1c\xc3\xdb\x80\x59\x93\x61\xb5\xca\x05\x1c\xbe\x29\xc3\x3b\x5c\xa2\xc9\xb0\xf4\x02\x17\xb0\xd9\x6f\x7c\x24\x6c\xc1\x70\x3d\x8e\x61\x80\x79\x84\xda\x00\x17\xa2\xc1\xa3\x57\x6d\xe1\x3b\x98\x4b\xb0\x88\x35\x18\x66\x2c\xdc\xc3\xb0\xeb\x12\x62\xe2\xc5\x51\x22\x44\x13\xb0\x59\x5f\x9b\x23\x74\x34\x18\x45\x78\xb8\xb0\xb6\xe1\x11\xda\x00\xa3\x4e\xf0\x63\x45\x79\x5a\xd4\x3c\x4c\x92\x29\xf6\x69\xfa\x25\x34\xb9\x2f\xa4\x61\x55\xc1\x50\xeb\x18\xbe\xe9\xaa\x16\x96\xb7\xdb\x0f\x9e\x8b\x52\xac\xb3\x28\xf5\xba\x1a\xa5\xb9\xdf\xa7\x50\xd6\xa8\xb6\x60\x3d\x81\xf2\x15\x2e\x9f\x6d\x5c\xbe\x18\xe6\xf2\xab\x92\x96\x55\x55\x55\x4a\x5f\x09\x94\xb4\xb4\xfa\xb7\x64\xc6\x1a\xb2\xd4\x51\x6e\x01\x76\xc1\xba\x40\x5d\x90\xee\x73\xb2\xd1\x55\xfe\x6c\xae\xd2\x8d\xaa\xee\x25\xbb\xc1\xc9\xf5\xc2\x56\x6f\xbc\x6c\xb0\x56\x1a\x59\x81\x2a\x69\xe9\xb2\xc6\xca\x06\x6b\x40\x58\x55\xce\x93\x71\x8d\xc2\xa1\x2a\x81\x56\x80\xe5\xbd\xb9\x6f\xbc\xa4\xa5\x05\x2c\xef\xd5\x01\x2c\xef\xf5\xb8\xa5\xcb\xee\xc4\x1a\x3d\x33\xb1\xee\x8f\xa2\x9b\x0f\xed\xe8\xc5\xa2\x86\x78\xa0\x3c\x65\x03\xbb\xfb\x50\x36\x1f\x8b\xfb\x60\x7e\x94\x6a\xd6\x0d\x55\x0e\x60\x15\x9a\x2c\x60\x25\x5b\x46\x55\xa8\xaa\xf6\x85\xaa\xe7\x32\xac\x93\xbe\x0b\x38\xc2\xde\x5a\x8b\xbd\xac\x12\xd8\xe7\xc3\x2a\x17\x59\x05\x6e\x1c\x85\xcd\x62\x9b\xc9\xd6\x25\x40\x9a\xe8\xc6\xec\xba\x1c\xb7\x0e\xb0\x95\xca\x5e\xe4\xc3\xdf\xcf\x5e\xf6\x00\xe7\xf8\xd0\xfd\xbe\xf0\xe6\x51\xe2\x69\x03\x34\xe2\x3a\x23\xea\x64\x6a\xb2\xa2\x92\x6d\x98\x53\x1e\xab\x36\x19\x86\x45\xda\x71\xa3\x84\xc8\xd5\x6d\x19\x66\x1b\x00\xc3\x66\x1c\x96\x2b\x2c\xc3\x6a\x85\x5b\xcb\x34\x18\xd6\x2b\x9e\xcd\xb0\xc6\x0b\x27\x13\x45\x1b\xb2\xcd\x74\x3b\x64\x4d\x92\x90\x45\x61\x23\x41\x3b\xa9\x59\xf2\xe5\x14\x34\x55\xf5\xd2\x82\x66\xdb\x25\x5e\xcd\x00\x73\x45\x94\x36\x1f\x9d\x31\xe0\x35\x1e\xdd\xde\xa8\xb0\xf5\x0d\xca\x56\x59\xaa\x5b\xdd\x4c\xcd\x7a\x38\x8f\xae\x92\x5e\xe9\x26\x1e\x7b\xde\x41\xbe\xa4\x53\xda\x4c\x1c\x6a\xa2\xf6\x61\x4a\x2f\xaf\x6a\x97\x90\x80\x47\x17\x17\xe7\x2e\x60\x85\xdf\x01\xec\x3e\xb2\xef\xfa\x70\xd7\xdb\x7a\xe3\x6a\xa0\xeb\x6d\x75\xbd\xad\xae\xb7\xf5\x82\x7a\xab\xeb\x6d\x75\xbd\xad\xae\xb7\xd5\xf5\xb6\xd0\xf5\xb6\x8e\x9c\x58\xbb\xde\x56\xd7\xdb\xea\x7a\x5b\xcf\xf5\xe1\xae\xb7\xd5\xf5\xb6\xba\xde\x56\xd7\xdb\xfa\x61\x7a\x5b\xff\x9d\xdf\x8e\x7a\x83\xe9\x7f\x03\x00\x00\xff\xff\x2b\xc1\x51\xba\x6d\x2d\x00\x00")
+
+func fontsIsometric4FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsIsometric4Flf,
+ "fonts/isometric4.flf",
+ )
+}
+
+func fontsIsometric4Flf() (*asset, error) {
+ bytes, err := fontsIsometric4FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/isometric4.flf", size: 11629, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsItalicFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x55\xcd\x6a\xdc\x30\x10\x3e\x47\x4f\xf1\x1d\x04\x91\x21\xf6\x6c\x93\x9e\x4a\x29\xa2\xf7\x5e\x7a\x28\x2d\x18\x06\x67\xe3\x6d\xdd\x6c\xd6\x90\x4d\x68\x03\x7a\xf8\xa2\x91\x6c\x4b\xb2\xd3\xc0\xae\x25\xcd\x9f\x66\xbe\xf9\xd1\xe1\x78\xb8\xee\x34\xde\xe3\x06\xef\x76\xd8\xe1\x46\x0d\x4f\xdd\x71\xd8\x37\x87\xe3\xe1\xe2\xe2\x5b\xff\x78\x1e\xc6\x13\xae\xd5\xed\xcb\x07\xe0\x73\x77\xc6\x97\x7e\xf8\xdd\x3f\x02\x78\x90\x8d\x1d\x4e\x87\xb1\xf9\x33\x9c\x9a\xa7\xe7\xbe\x39\x1d\x01\xdc\x76\x67\x7b\xd7\x3d\xf4\xf7\xcd\xfd\xd3\xaf\xe6\xdc\xab\xc3\xf0\xb7\xbf\x83\xb7\xf0\xf5\xa5\x3b\xe1\xc7\xf8\xbc\xbf\x07\x5e\xfc\x62\xf7\xe7\xe6\xf9\xb1\xff\x39\x9c\xba\x66\xdf\x29\x6d\xe3\x0f\xd6\x2a\xc0\x2a\x07\xab\x1a\xc8\xde\x2a\x22\x58\xa5\xb5\x1c\xe3\x47\xbe\x72\x62\xc7\x8e\x61\x55\xed\x6a\x57\x63\xa6\x5b\x05\x27\x74\xe3\x9c\x16\x31\x57\x41\x88\x93\xb6\x55\x3b\x6f\x97\x76\x99\x49\xab\x4c\xe5\xc9\xe6\x7b\xbc\x4a\x1c\xf0\xf7\xc7\xbf\x10\xb4\x88\x08\xa9\x9d\xd5\x5b\x39\xfb\x5b\x48\xcf\x44\x0d\xf8\xc8\x5a\xf2\x5f\x6a\x75\xa4\xc8\x22\x1c\x76\x2c\x44\x07\x3d\x11\xad\x92\xbd\xb6\xea\x4a\xcb\x7e\x36\xc3\xac\xe7\x7d\x94\x0c\x7b\xed\xe1\xd2\xe1\x18\xa3\x13\x1f\x13\x4f\x00\x66\x89\x89\x00\xef\xa4\x61\x26\x64\x80\xf9\x53\x2d\x5a\x09\xcc\x41\x87\x25\x2c\xe6\x05\x93\x94\xc1\xf2\x45\x86\x22\x53\xbc\x2b\xd1\x60\x31\x82\xb5\x46\x30\x1c\x58\x66\xe1\x79\x26\x07\x1e\x47\xbf\x32\x2d\x39\x19\xae\xd6\x5a\x31\xd6\x48\x4d\x23\x8d\x05\xd6\xa4\x05\x36\x11\xae\xe6\xfc\x0a\xaa\x92\xb3\x36\xe2\x5b\xe4\xa0\xae\xd3\x54\xce\x82\x94\x48\xb3\x54\x0c\x2a\xff\x6d\xc2\x5e\x2e\x5b\x7e\x4b\x10\xc4\xbe\xe2\x0d\xe0\x32\x3f\xe7\x8c\x05\xfc\x7d\xa8\x79\xc6\x26\x7e\x84\x00\xdb\xda\x88\xda\x45\xbe\x03\xb4\x86\x05\x55\x2a\xb4\x67\xa6\x0e\x65\xf4\x8a\xe9\x05\xe6\xa2\x94\x82\x42\xc5\x53\xe2\x36\x6a\x0d\x14\x62\xce\x5a\x5a\x16\x8a\x15\x94\xdd\x19\xb9\x34\x9b\x5c\xdf\x39\x55\x9c\xc9\x2a\x75\xd6\x74\xe4\x62\x15\xb9\x4d\x6f\xc9\x05\xa4\xe0\x4a\x6f\xdf\x6c\x9d\x49\x20\x14\x1c\x01\xfa\x2d\x0b\xed\x1b\x16\xcc\x86\x05\x5f\xee\x98\xfa\x27\x6f\x92\xd0\x41\x92\x2d\x03\x6c\x23\x37\x01\xbb\x6e\x7c\x04\x35\xcf\x76\xdb\xb8\x9b\x98\x16\x47\x2b\x70\x82\xf5\x36\xf4\x21\xda\x95\x76\xbc\xd2\x7b\xa0\x8b\x1a\x5b\x5a\xbb\x98\x2d\x56\xc9\xd8\x76\x9c\x56\x87\x55\xc1\xf8\x32\x73\x05\x33\xed\x64\xc0\xe7\x92\xd4\xa6\x8f\x46\xf2\x74\x28\x5e\x6c\xb6\xe5\x60\x0f\x52\x52\xf9\x54\xa8\x0a\x74\x55\x41\xe4\xe9\x1d\xc8\x6a\x50\x22\x32\xd9\xec\x0b\x74\x6d\x95\xa9\xd3\xd9\x2a\x1d\x56\x8c\xe9\xa0\x16\x92\xed\x0d\x49\x3e\x52\x2f\xa8\xf4\xe2\xb2\x98\xd9\x73\xfe\x2f\x65\x11\x16\x53\x19\x0c\x99\xad\x08\xb1\x0a\x46\xd0\xa4\xaa\x0c\x06\x5b\x9e\x60\x05\x12\x96\xce\xac\xa6\x11\xbe\xc2\x99\x0a\xe2\x1a\x0f\xed\xc9\x5c\xe9\xc2\x0b\x2e\x9f\xab\x20\xbc\x91\x3f\x29\x85\x96\x56\x76\x45\x76\x12\xce\xa5\xab\x12\x20\xbd\xe1\x6f\x80\x67\x29\x29\xaf\xf3\x11\x61\x15\x82\xc3\xf2\x17\x82\x87\xe1\x13\xc2\x9a\xb8\x42\x2d\x21\x43\xcc\x2a\x8c\x3c\xbe\xfe\x3a\x8c\x1c\xb9\xaf\x0e\xa5\x11\x18\xff\xdf\xf7\x56\xd5\x5c\xaf\xc1\xaa\xeb\x8d\x62\xaf\xb1\x92\x9c\xde\x8c\xf8\x40\x61\x7a\xa1\x68\xbe\xe3\x5f\x00\x00\x00\xff\xff\x4a\x0e\x3c\xe0\x68\x0a\x00\x00")
+
+func fontsItalicFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsItalicFlf,
+ "fonts/italic.flf",
+ )
+}
+
+func fontsItalicFlf() (*asset, error) {
+ bytes, err := fontsItalicFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/italic.flf", size: 2664, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsIvritFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x5a\x7b\x6f\xda\xc8\xfa\xfe\x9f\x4f\xf1\xfc\xaa\xea\xd7\xe4\xc8\xc1\x81\xb6\x69\xab\x2d\x51\x68\x43\x1a\x76\x73\x3b\x81\xa6\xda\x23\x4b\x53\x03\x43\xf0\xc6\xd8\xac\x6d\xd2\x66\xe5\x0f\x7f\x34\xf7\xf1\xd8\x24\xb4\x3d\x68\x1b\x5f\x98\x79\x9f\x77\xde\xe7\xbd\xcd\xb0\xf3\x78\xde\x0d\x9f\xe3\x00\xaf\xf1\xe6\x00\x9d\xd7\xe8\xbc\x42\x07\x9d\x83\xee\x9b\x4e\x6b\x78\x9f\x45\x05\x76\x4e\xe9\x24\xa3\xdf\x76\xf1\x39\x89\xa6\xe9\x8c\x62\x9e\x26\x05\xc2\x3c\xa7\xcb\x49\x4c\x67\x98\x3c\xe0\xf7\x74\x91\xe0\x63\xfa\x2d\x4c\xf0\x7e\xca\x2e\x47\xd3\x69\x14\xb7\xd3\xec\xf6\xb0\x75\x16\x16\x51\x82\xe9\x22\xcc\x72\xcc\xb3\x74\x09\x8c\x8a\x30\x99\x85\x19\x9f\xf9\xa9\x8d\x8f\x8b\x70\xb5\xa2\x71\x8c\xff\xc7\x30\x4c\xd8\x63\xd4\x12\x90\xf6\xac\xdf\x69\xb6\xce\xc3\x98\x2e\xf9\x2c\x3a\x0b\xe3\x28\x5c\xe0\x24\x8b\xe8\x8c\x26\x13\x9a\xdd\xe2\xfd\xed\x5c\x3c\x1d\x25\x0f\xdf\xdb\xd3\xbc\x3d\x5b\xb7\xe9\x6c\x7d\xd8\x82\xfc\x7c\xce\x29\x9e\x45\xf1\x82\xcb\x6e\xcf\xe3\xe9\x33\xcc\xd3\x0c\x12\xeb\x8e\x3e\x4c\x52\xa6\xd5\x32\x5c\xad\xa2\xe4\xb6\x3a\x6d\x9d\xbb\xd3\x3e\xb7\x47\xed\xbd\xbc\x78\x88\x69\x6d\x2a\x76\x9e\xcd\xf9\xe8\x67\xc8\xa7\x59\xb4\x2a\x76\xab\xc2\xde\xbe\x7d\xfd\x6e\xef\xad\x11\x35\x1c\x5d\x42\xbc\x43\x41\xbf\x17\x7a\xf0\x65\x86\x75\x4e\xf1\x79\x7c\xb2\xf7\xb6\xf5\xa5\x7f\x7d\x31\xbc\xf8\xf4\x7f\x38\x19\x7e\x62\x0c\xe4\x08\x33\x9a\xbc\x28\x30\x89\x66\x51\x46\xa7\x45\x94\x26\x61\xfc\x1b\x8a\x45\x94\x23\xca\x91\x17\x59\x34\x2d\xe2\x07\x64\xd1\xed\xa2\xd8\x2b\xd2\xbd\x98\xce\x0b\x68\xe1\x3b\x93\x07\xcc\xe8\x3c\x5c\xc7\xc5\x2e\xe8\x3d\x4d\xb8\x2a\xc5\x82\xc2\x30\x16\x4e\x0b\x9a\xe5\xed\xd6\x3c\xba\x8d\x69\x81\x8c\xc6\x34\xcc\x29\xba\xed\x2e\xf6\xf6\x70\x91\xde\xd3\xe5\x84\x66\xe8\xbc\x7b\x77\xd0\x6a\x9d\xa7\xb3\x68\x1e\x09\x87\xb8\x0a\xd7\x31\x3e\xac\xb3\x22\x4d\xf0\x3e\x4f\xe3\x35\xd3\xee\x88\x86\x59\xb1\x88\xa3\xe4\xae\x9d\xd0\xe2\x10\x9d\xae\xff\xee\x00\x45\x8a\x28\x99\xc6\xeb\x19\x45\x42\xbf\x61\x15\x66\xe1\x92\x16\x34\x6b\xe5\xeb\xd5\x2a\xcd\x0a\x21\xf0\x64\xf8\x89\x69\x10\x26\x33\x76\xfb\x25\x4a\xda\xc0\x79\xf8\x80\x30\xce\x53\x4c\x28\xf2\x98\xad\x32\x7e\xc0\x52\x69\xc1\x56\x33\xa1\x45\x41\xb9\x11\x5b\xe9\x9c\x8b\x9f\xaf\xe3\x78\xef\x5b\x34\x2b\x16\xfe\x1d\xcd\x12\x3f\x5f\xae\xf3\x05\xc2\xb8\xa0\x59\x12\x16\xd1\x3d\xcd\x3d\x4c\xd6\x85\xb2\x0c\xd2\x75\xb1\x5a\x17\xcc\x9e\x17\x97\x63\x66\x93\xe4\x96\xce\xda\x2d\x3c\x3f\x6a\xfa\x77\xd4\x02\x08\x8e\x5a\x28\x51\x9a\xbf\x84\xfd\xdd\x21\xbb\x47\xdc\xf6\x72\x10\x1f\xb6\x83\x12\xfc\xf5\x0d\x6e\xc0\xbf\x7e\x8e\xea\x55\x4d\x60\x53\xd8\x7f\xfc\x2d\x29\x51\x96\x28\x05\x12\x01\xda\x6d\xf6\x4e\x3e\xf0\xb1\x25\x9f\x53\x92\xb2\x24\xa5\x91\x64\x89\x23\xe2\x6d\x89\x92\x5d\x7d\x10\xae\x5e\x40\x08\x02\xae\x17\xe0\xf3\xef\x49\xa9\x14\x06\x21\x62\x19\xbe\xf8\x0a\x3e\x7c\x2e\xc3\x87\xcf\x35\xf1\x89\xaf\x17\x69\x70\x88\x52\x7a\x07\x04\xbb\x90\x33\x08\x02\x3f\xe0\x16\xda\x21\x87\xc0\x7b\xf6\x36\x20\x84\xf8\x81\x6f\x29\x6b\xec\xb9\xc3\xcd\x54\x0a\xc0\xe7\xd6\x5f\x83\x23\x55\x11\x66\x47\xed\x82\x80\x04\x6c\x28\x11\x2b\x0f\x10\x28\x03\xd4\x2e\x3e\xf1\x95\xd1\x85\xee\x4c\x2f\x0e\x10\x40\x1a\xc6\x67\xf6\x08\xf8\x98\xc0\xb7\x0c\x6c\xa6\x41\xb3\xa6\x29\xd3\x7c\x59\xfc\xd8\xe4\xc8\xc9\xee\x5f\xc7\x00\x2e\x82\x1e\xc6\x3e\x02\x81\x7d\x04\x02\xf3\xa3\x6d\x11\x2a\x0e\xaa\x4d\xaa\x8c\x5a\xe1\x1b\x92\x6f\xd4\x96\x4e\xa4\x7d\x05\xc7\xca\xfe\x3a\x1c\x88\x34\x34\xe7\xda\x55\x4c\x78\x91\x1d\x39\x56\xfc\xe8\x41\x0a\x81\x2d\x53\x92\xc8\xbc\x57\xc8\x65\x8e\xec\xd7\x8c\x50\x99\xac\x6d\x24\x97\xc3\x18\x09\x94\x05\x77\x25\x62\xb3\x7a\x8a\x4d\x11\x7e\xd6\xad\x92\x69\xa8\x75\xb9\x75\x95\x67\xb7\xa5\xb3\x8c\x27\xf0\xa1\x43\x89\x47\x9c\x10\xf3\x42\x5b\x79\x47\xd9\xa0\xd9\xb6\x95\x95\xa3\xd4\xd4\x42\x73\x2b\x44\x57\x49\x75\x59\x15\x41\xec\xf0\xfb\x38\x72\xa3\x4b\xd8\x53\x3c\xad\x4d\xc3\xe4\x9a\x7f\x36\xfa\x6a\xf3\xa0\x6a\xc8\xd8\x19\x42\xae\x5b\x25\x81\x40\x86\x72\x2d\x7e\x1b\x62\xea\x89\xe8\x72\xd2\x4b\xc0\xd3\xa9\x42\x35\xeb\x53\x9c\x28\xbf\x09\x14\x0b\x3a\xe9\x32\x63\x93\xdd\x5a\x11\xd0\xc6\xe4\xae\x2e\x51\xd8\x72\xc8\x57\x15\x32\xd8\xd1\x51\xc6\xcd\x2b\x95\x0d\xa4\x53\xa9\xe8\x36\x29\xc0\xe7\x79\x4d\x09\x65\x0f\x2a\x94\x24\x80\x70\x0a\x63\xa5\x0d\x0e\x2d\x3c\xa3\x84\x15\xf9\x4f\x39\xb4\xb0\x80\xc0\x52\xea\xeb\x18\x53\xdf\x06\x9b\x42\x19\x35\xbc\x5a\xa6\xd9\x10\xca\x9a\x57\x68\x5e\x79\x8e\xae\x22\x3f\x95\x44\x60\xa9\xad\x53\x83\x16\x43\x4a\x34\x87\x52\xd3\x9a\x55\xd7\x60\x27\xc8\x3a\x32\xcc\xc0\xfa\x4a\xf9\xf7\x32\x61\x9a\xa4\x59\xf7\x36\x99\xa2\x54\x5d\x54\x65\xd2\xc6\xd3\x61\x40\x94\xfe\x52\x2d\x82\xad\x73\xb9\x08\xb8\x92\x05\xa0\x28\xca\x2f\x44\xd0\x95\x68\x4b\xba\x48\x69\xbb\x94\x5e\xa1\x22\xa1\xe9\xee\x09\x62\xf8\x3f\x61\x0b\x56\x96\xa5\xa2\x81\xaf\x75\x86\xa9\x29\xa8\xda\xa8\x66\xe1\x40\xaf\x14\x81\x9e\x1f\x18\x0b\x07\x35\xfc\x5f\x2b\x7e\x8d\xfe\xac\xe2\x07\xa6\xae\x6d\xf2\xaa\x2d\x91\x2b\x51\xbc\x1d\x32\xde\x43\xaf\x79\xe3\x64\x5f\x57\xb4\x60\xeb\x8a\x66\xa5\x57\xab\x29\x82\x2a\x9c\xd6\x5d\x43\xa3\xd4\x1c\x0c\xdb\x59\x9b\x08\x3f\x93\x3d\x5d\x60\x52\x2f\x7b\xd0\x45\x31\xc0\x0d\x74\x73\x17\x38\x85\xb1\x22\xa8\x2a\xcb\x11\xe7\x48\x74\x84\xd6\xe5\x5a\xa2\x95\x50\x2d\x4e\xb7\x60\x3a\x31\xbb\x21\x24\x9a\x10\xa5\x8c\x9e\x78\xa3\xbb\x9d\xc7\x8d\xca\x3e\xaa\x97\xd9\xd4\xe6\x57\x42\x4f\x45\x9e\x48\xa6\xe5\xa6\xf6\xbb\x64\x73\xb4\xc1\xb4\xa9\x94\x91\x94\x79\x02\x6d\x18\x37\x31\x28\x3f\xa9\xb7\xeb\x3a\xa4\x05\x02\x33\x38\xaf\xfb\x81\x50\x52\xee\x13\xaa\x97\x86\x4e\xfd\xb1\xbb\x5a\x1f\xe0\x34\x19\x10\x58\x4d\x1b\x13\x23\x8d\xc8\x4d\x9f\x5d\xac\x77\x2c\x2f\xf5\x1a\xf3\xbd\xc9\x7c\xb5\x8e\xcf\x54\xd7\x76\x53\x75\xb5\x80\x4d\xc5\x51\xb0\xa6\xb2\x3a\x54\xc2\x64\x7d\xa2\x94\xdb\x5a\xe1\x46\x4c\x04\x3a\x83\x6d\xc2\x34\x83\x75\x35\x55\xb5\x54\xe5\xbc\x5a\x69\xda\xd6\xaa\xd2\x47\x4c\xf3\xf3\x94\x55\xad\x12\xd1\x50\x45\x4d\x97\xb9\x79\x8f\xa2\x2d\xa8\xfa\x54\xa9\x8e\xae\xa2\xbe\xf2\x58\x5b\x25\x89\xee\x96\x4d\xe8\xf4\xdb\x50\x2d\x5d\x35\x1a\x95\xa9\x78\x32\x37\x98\xbd\xec\xaf\x4e\xc5\xa8\x2e\xdf\x29\x92\x0d\x2d\x32\x7e\xd8\x86\x8e\x9b\xb8\x75\xeb\x89\xed\xc4\x13\xc8\xba\x6e\xb5\x9d\x8a\xf9\x73\x7e\x23\xf2\x64\xd5\xb9\x89\xce\x77\x2f\xec\xae\x55\x63\xd5\x03\xea\xc8\xf4\x5f\x2a\x08\xd5\x51\x0b\x77\xcc\x8a\x73\x9b\x4d\xa6\x6e\x51\xed\xa8\x60\x33\xeb\x8d\x9a\xd2\xec\x91\x06\xf1\x91\x90\xc5\x16\x85\x83\x17\xaa\xc6\xc9\xd6\xfc\x8a\x88\x8a\x94\x8a\x20\x47\x96\x9b\x3e\x1a\x4a\xdf\xa1\x0c\x83\x86\x8a\xf7\x43\xeb\xaf\x65\x03\x8b\x1e\x22\x3b\x11\x5f\x96\x3b\x55\xed\x5c\x6b\xcb\x83\x11\xb5\x5b\x13\x05\xee\x3d\xde\x57\x8e\xd4\xf4\x81\xd3\xc6\x28\xd5\xb1\xaa\x8c\xa7\xaa\x62\x45\xca\x21\x0e\xad\x67\xbe\x13\x93\x55\xce\x2f\x45\x99\xf3\x55\x65\x6b\xbe\xd6\xfa\xa5\x1d\xb2\x4b\x54\x62\xf2\x49\xe0\xc4\x1f\x43\x68\x68\xf3\x1a\x26\xdb\xad\xe6\x53\x7b\x01\x3d\xd9\xe4\xce\xed\x37\x12\x4d\xc8\xdb\x17\xd0\x47\xd4\x7e\xe2\xc8\x64\x7b\xb5\x1b\xc2\xaa\x5e\x00\x75\x46\x2f\x03\xf5\xa6\xe4\xa1\x2f\xb3\xc6\x51\xab\x73\xb0\x0f\x5c\x5c\xee\x7d\xb8\x1e\xf4\xff\xc0\xe8\xaa\xff\x71\xb0\xf9\xa4\xb9\xf3\xe6\x25\x30\xba\x3c\x19\xe3\xf4\xcf\xab\xd3\xc1\xc5\xb6\xad\x0b\xff\xb6\x76\x70\xd1\x79\x77\x00\x9c\xf5\xc7\xc3\x0b\x7c\xec\x5f\x0d\xc7\xfd\x33\x9c\x0d\xc6\xe3\xc1\x35\xfa\xf8\x32\x1c\x9f\xe2\x78\xd8\x1f\x5c\x0f\x46\xc3\xd1\xaf\xb9\x52\xb7\xf3\x6a\x03\xce\xe5\x76\x38\x5b\x7a\x5d\xb7\xbb\xbf\x01\xe7\xf3\xe3\x38\x3f\xe8\xa0\xdd\xee\x4b\x85\x33\x3a\xef\x9f\x69\x94\xd1\x69\xff\xfa\x0a\xa3\x9f\xf5\x84\x6e\xf7\x6d\xa3\xd8\x2d\xc9\xd8\x32\x40\xba\xaf\x0e\x1a\x51\x7e\x9c\x8a\xc7\x22\xa9\xfb\xba\xdb\x88\xf2\x6b\x44\xb8\x6b\xd9\xff\xbe\xff\xfa\x78\x1f\x38\x1d\x7c\xb8\x1e\x7c\xd1\xf6\x3a\x1b\x9c\x34\x97\xb6\x52\x57\x24\x41\x03\x36\x6c\x71\xb9\xdc\x8e\x2b\xf7\xc3\x60\x2c\xa9\xd5\x1d\x4c\x29\x6e\x4b\xb3\x78\x95\xc3\x45\xe0\xa1\x24\x6a\xf7\x44\xec\x9a\x5f\x01\xea\xba\x40\x9f\x86\xe7\x83\x33\x59\x75\xf4\xd1\x5f\x59\x05\xb2\x71\x74\x9d\xe0\x3f\xa6\xd4\x4e\xec\x38\xc8\x4b\x17\xe4\xb8\x7f\xc6\xd7\x23\x55\xd3\xd9\x02\xfa\xa0\xd8\x2a\x48\xee\x3d\x29\xd1\x04\xf2\xca\x05\x39\x1d\x34\x20\xe8\xa3\x68\x02\x7b\x3b\x67\xee\xeb\xe7\x34\x1a\xe1\xb5\x8b\x70\xd3\xbf\xa9\x9c\x73\x55\x9b\x6e\x73\xad\x14\x74\x2e\xea\xc0\x15\xf5\x9f\xfe\x9f\xc3\x8b\x96\x52\x97\x0b\x0c\xa4\x17\x49\x93\xea\x9e\xcf\xbd\xaf\xb6\x80\x16\xc8\x9b\xba\x45\x5c\xa3\xb7\xc5\x21\x56\xdd\x0c\x5b\x9a\xe4\xad\x0b\x31\x96\x10\x26\x0d\x95\x6d\x94\xfc\xe7\x03\x23\xd8\x42\x21\x7a\xcf\x57\x4a\xbd\xca\x46\x3f\x7d\xe7\x02\xfd\x79\x79\xdc\x68\x7b\x53\x70\xaa\x57\x23\xaa\xef\x8a\x3a\x19\x5e\xf4\xcf\xf0\x47\xff\xa4\xd1\x23\xdb\x4f\x7b\xa4\xeb\x9d\x12\xe8\x83\x0b\x64\x41\xc0\x20\x04\xb6\x20\x2b\xac\xb4\xcb\xda\xe9\x4d\x0b\xff\xe8\x0a\x3f\xeb\x9f\x0f\x8e\x5b\x28\x7b\xa5\xb3\x00\xa5\xbf\x3e\x14\x32\x3f\xbe\xd4\x7e\x7d\xd1\xe2\x8f\x9b\x8d\x74\x3e\x38\x37\x46\xb2\x5c\xe8\x57\xe9\x1d\xb8\x70\x15\xa0\x27\x5d\xd5\x80\x94\xa5\x8b\xa1\x20\x4e\x9a\x57\x74\xf1\xf9\x62\xab\x18\xb6\xfc\x4b\x08\x1c\xd4\x72\xbf\x10\xa5\xcb\xaf\x11\x66\x88\xb5\x68\xad\x1c\x49\x70\x81\xb5\xa4\x3f\xea\x9f\x0f\xfe\x38\xdd\xde\x0e\x44\xee\xf3\x9b\xfc\x46\xa3\xd4\x32\xbe\xc8\x3c\x32\x66\xc5\x86\x4f\x9f\x45\xf3\x7b\xad\x7d\x80\xaf\x96\x5b\xba\x87\xd9\x5c\x7a\x2d\xd5\x0b\x2b\x5f\x99\x5c\x0c\x75\x38\xa3\x8f\xcb\x89\x39\x50\x23\x65\x59\xa9\x00\x56\x58\x29\x84\x5a\x9e\xbf\x72\xf3\xbc\xed\x90\x01\x6b\x12\xad\xb8\xaa\x04\x56\xb3\xa7\x0c\x6a\x79\x5e\xac\x61\x3c\xea\x1f\x0f\x2b\x86\xe2\xa9\xcd\x72\x43\xdf\x57\x5b\x29\xdf\x37\xbb\x2a\xa8\x72\x5d\xda\x20\xb5\x0a\xa0\xc4\xab\xe4\xd9\x56\xe6\xb7\x02\xd7\x3a\x20\x26\x8c\x0e\xb9\x79\x53\x7c\xd4\xb7\xb8\x1c\xaa\x56\x07\xfe\x7d\x79\x52\xa5\xc3\x29\x8c\xd6\x92\x4a\x52\x3e\xbe\x8e\x5a\x05\xb8\x1e\x8c\x4e\x37\x4b\x77\x68\xad\x32\x5c\x77\xa7\x5a\xda\x1f\x9d\x0a\x67\x45\x7d\xef\x8d\xca\x99\xbc\x79\xf2\x79\x96\xb3\x7e\xa4\x27\xb5\xc3\x00\x8d\x57\xab\x0d\x63\x5e\xe2\xed\xe5\xc0\xf6\xde\x6a\x08\x92\xca\x0f\x3e\xa4\xa1\x6e\x0a\xa0\xee\x9b\x6e\x07\x18\x8d\xfb\xd7\xb8\x3c\xc1\x71\xff\x66\x78\x5c\x39\x8c\xf8\x81\xff\xf9\x63\x6f\xff\xfb\xfe\xfe\x7e\x17\x68\x85\x31\x5d\x2d\xd0\x43\xe1\x61\x42\x0b\xff\x9e\x16\xe8\x61\xea\xe1\x36\x5a\xd2\x18\x3d\xcc\x3c\xcc\xc2\x98\xbf\xcd\x3d\x2c\x28\x7a\xb8\xf7\x70\x1f\xde\xa3\x87\xb5\x87\x7f\xc2\x87\x28\x41\x0f\xff\x30\xf9\x0b\x3e\xec\x2f\x0f\x05\xbf\x79\xf0\xf0\x90\xce\xd0\xc3\xc2\xc3\x5d\x38\xf7\xa7\x8b\x70\x8e\x1e\xe6\x1e\xe6\x51\x12\xc6\xec\x1d\x7a\x88\x3d\xc4\xe1\x92\xb2\x71\x77\x1e\x96\x74\x89\x1e\x92\xa3\x96\x18\x22\x1e\x53\x0f\xc9\x9a\xa1\x4c\xd4\x54\xf1\x18\x79\xc8\xc3\x25\xbd\x63\xfa\x7f\xf7\x20\x55\xb9\xf5\xb0\xa2\xfe\x9c\x69\xba\xf2\xb8\x6d\xc4\x9c\x15\x7b\xf3\x9b\x87\x22\x0f\x67\x11\x7a\x58\x2a\x61\xea\x45\xdb\xc3\xdf\x29\x53\x89\x7a\xc8\x68\xce\xa4\x66\x1e\xf2\x45\x94\xf8\x39\x97\x1c\xe2\xa8\x55\xf0\x95\x7b\x98\xa6\xcb\x65\x88\x1e\x5e\x30\xb4\x2c\xe2\xeb\xf4\x3d\xe4\x74\x19\x4d\xd3\x38\x65\xc3\xbf\x7a\xc8\xe3\x90\xcb\xf9\xdb\x43\xb8\x4a\xf3\x22\x4b\x57\xdc\x84\xdf\xb8\x5e\xa3\x22\xcc\x90\xce\x71\x1c\xde\x47\x6c\xfe\xbf\xf0\xb3\x1f\x4d\xe9\x4b\x8b\xd2\xd0\xa6\x74\x62\x28\xbd\x35\x94\xce\x24\xa5\x0b\x45\xe9\x7d\x23\xa5\x53\x45\x69\xa1\x28\x7d\xa8\x50\x7a\x57\xa5\x74\x6e\x28\x8d\x15\xa5\xcb\x0d\x94\x26\x9b\x29\xa5\x9a\x52\xf2\x18\xa5\x6b\x43\xe9\x5f\x2e\xa5\xdf\x14\xa5\x7f\x6f\xa0\x34\xd7\x94\x7e\xff\x69\xe3\x5b\x34\xfc\x6f\x29\xfd\x6f\x00\x00\x00\xff\xff\x0a\x39\xf3\x83\xf4\x2a\x00\x00")
+
+func fontsIvritFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsIvritFlf,
+ "fonts/ivrit.flf",
+ )
+}
+
+func fontsIvritFlf() (*asset, error) {
+ bytes, err := fontsIvritFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/ivrit.flf", size: 10996, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsJazmineFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x59\x4f\x8f\xdb\xb8\x0e\x3f\x8f\x3f\x05\x51\x3c\x40\x78\x40\x1f\xf1\xda\x93\xd6\xa7\x7c\x04\x5f\x7d\x73\x5c\x39\x9d\x6c\x33\xc3\x6e\x26\xd3\xc5\xee\xa7\x5f\x88\x14\x65\xc9\x96\xed\x78\x66\x80\x4d\x1b\x8b\x56\x6c\x92\xa2\xf8\xe7\x47\xcd\xe9\x72\xfa\x7a\xfc\x0f\x7c\xf9\x3f\xff\xff\x0a\xff\xfb\x02\xbf\x55\xd5\xc3\xc3\xc3\x03\xc0\xef\xc7\xbf\x9f\xce\xcf\x03\x9e\x2e\xa7\xaa\x7a\x00\xfe\xfc\x39\x5c\x2e\x9f\xe1\xf6\x38\x00\xd0\xf5\xfc\xfd\xfc\x7c\xbc\xc0\x75\xf8\xe3\x75\x78\xb9\x0d\x57\x78\x3a\x7f\x7f\xbc\xc1\x33\xdd\xe0\xf1\xf8\x6b\x80\xcb\xf9\xc7\xe0\xf4\x4d\xff\xce\xcb\xf9\x3b\x9c\xc1\x9d\x9d\xbb\x0c\x0e\x4e\x74\x85\xc7\xe1\xfa\x19\xfa\xd7\x9b\x9f\x1e\xbe\x9d\xdd\xe0\xe0\x46\xf0\x74\xfc\x31\xc0\xd1\xab\x01\x27\x7a\xbe\x01\xbd\xde\x80\x4e\x70\xbe\x21\xbc\x90\xe7\x74\x1d\x10\xea\xff\xb2\xa2\xc2\x1d\x7e\x1d\x9f\x7e\xfe\x75\x3d\x1c\xbf\xbd\x60\xff\x8a\x83\x7b\xad\x2a\x80\xc3\xe2\xb7\xae\xe3\xd7\x4f\xc0\xa1\xb2\x76\x7e\xe9\x8c\x52\x88\xe8\x1f\xae\xe5\xc2\xaf\xf8\x9f\xc0\xff\x66\xc0\x80\xce\xcc\xaf\xb5\xbe\xa5\x57\xf9\x21\x3e\x91\x13\x68\x11\x2d\x7a\xd1\xb6\x33\xd6\x14\x67\x6a\x44\xff\x5f\xd8\x45\xbe\x29\xeb\x74\xb4\x81\x6f\x23\x4c\x5a\xab\xf3\xad\xdc\x13\x09\x4f\x0b\xc2\x12\x13\xd6\xa9\xae\xae\x07\x40\x12\x7b\x20\xc9\x8a\xfd\xe8\x09\x1e\xbd\x14\x32\x40\xfe\x19\x7f\x1f\xec\xc6\x1c\x57\x74\xcd\xcd\x60\x83\x19\xa8\x21\xf4\x44\x4b\x88\x62\x6a\x02\xe0\x99\xae\xb5\x0d\x4b\x15\x95\x83\xce\x73\xd6\x87\x8a\x37\x47\xf7\x66\x76\x89\x9b\x19\x77\x94\x57\x07\x8e\x99\x5b\x13\x36\x38\x1b\x44\x15\x68\x51\xe4\x77\x24\x7c\xe2\xfa\x0e\x87\x8a\xc2\x33\x5d\x2f\x92\x3a\x2b\x02\xb3\x01\x79\xc0\x06\xd8\x54\xbc\x88\x74\x09\x2b\xfb\x48\x68\x59\x4d\xb1\xc2\xa1\xc2\x46\xf6\xf1\x13\x58\xf8\xe4\xef\xf3\xfd\x9b\xee\xe3\x9c\x61\x64\x4c\x96\x77\x6e\x3a\x2f\xc6\x2d\x33\x5c\xb9\x48\xf8\x34\x6c\xa6\x2c\x68\x72\x1d\xf2\x91\xfc\xa7\x30\x3f\x91\xbd\x4b\x07\xb5\x46\xae\x43\x60\x8e\x41\xda\x9a\x3f\x8b\x66\x46\xe3\x13\x27\x6e\x5c\xf2\x67\xa4\xa6\x25\x14\xbf\x41\xe2\x6c\x02\xd8\x18\x26\xd0\x19\x76\x02\xcb\x21\x12\x22\xb0\x09\x61\x8d\x2b\x61\xed\xd9\x46\xa7\x2e\x5c\xea\x42\x86\xca\xb5\xf1\xb7\xea\x8e\x22\x12\xfd\x10\xdd\x5d\xc2\x2c\xec\x01\xca\xe7\xce\x85\x26\xac\x51\x58\xfb\x89\x5e\x7f\xaa\xf7\x2c\x34\x6e\x0f\x5a\x21\x9c\x11\x82\x2d\x07\x87\xaa\x49\xfd\xc4\x42\x4a\xd4\x1c\x8d\x1b\xac\x49\xdf\xb7\x3a\x63\x7f\x16\x4c\xe4\xe3\x73\xaf\xd6\xf8\x73\xdc\x79\x35\xa8\xce\x98\xc0\xda\x67\x91\x37\xb0\xa6\x64\xd5\x1f\xec\xaf\x80\x8d\xa4\x34\x6f\x44\x9b\x7b\xf0\x3b\xb5\x5e\x60\x14\xfd\xe1\x4d\xb6\x9e\x05\xf9\x76\xcc\x6f\xbd\xb2\x9c\xaa\x82\xad\x83\xa9\xd5\xd2\xde\xb7\x43\x9e\xc7\x90\xe8\xd9\xdb\xeb\xac\xdc\xad\xe6\xdf\x72\xce\x9b\xde\xaf\xe5\x3e\xd1\x24\x56\x1c\x52\x4d\x82\x2b\xa3\x04\x22\x4a\xb9\xc4\x10\xea\xe2\x11\x8b\x0c\xd3\x3d\xeb\xba\x31\x1a\x90\x1a\x09\xc6\x66\x56\xb2\xc7\x42\x81\x9b\x9e\x06\x4e\x58\x7b\x6d\x50\x32\xa3\x0b\x99\x11\x2c\xb1\x0c\xcf\x0e\x71\xa7\xa7\x45\x9d\x30\x5a\x0f\x1b\x2d\xba\xbe\xd0\x0a\x49\x3e\x77\xc4\xe2\x2b\xb3\x42\x81\x1d\xa3\x25\x49\x7b\x89\xb0\x4c\x1c\x7b\x84\x26\x0d\xab\x59\x83\xac\xaa\x2c\x73\xbd\x52\x21\x4d\x53\xb6\xa0\x64\x45\x29\xb5\x50\x48\x84\xc7\x98\x57\x32\x62\x7f\x7e\x25\x0a\x7e\x63\xbd\xee\x2a\xa3\xb3\x53\x61\x1c\x98\x5e\x71\x71\x22\xbc\x63\x93\x47\xad\x51\x7d\xb4\x27\x92\x9f\x9a\xa9\xfa\x3b\xab\x42\x0c\x0f\xab\xeb\xb0\x81\x75\x9c\x99\x13\x75\xee\xf3\xdb\x45\xbb\x60\xeb\xb1\x60\x64\xb9\x8b\xb5\xb6\x1a\xa7\x91\x40\xcc\x7d\xc5\xab\x08\x94\x79\x03\x71\xa9\xb5\x13\x0f\x99\x53\xa2\x7c\xea\x92\x13\x5f\x39\x54\xa2\xda\xfc\x2b\x2f\x8d\x4d\x8e\x84\x40\x00\x77\xa5\x6b\x40\x05\x71\x1b\x0a\x1d\x0b\x25\x0b\x61\xdf\x20\x4b\xbd\x51\x73\x8f\x1e\x6f\x53\xa2\x96\x36\x60\xb5\x63\xa1\xcc\x33\x56\xc6\x0c\xa0\x2c\xe7\xb1\xc8\x92\xad\xd3\x03\x80\x63\xbb\x74\x3d\x03\x0a\xcf\xb0\x23\x93\x6c\x74\x4e\x89\xcb\xac\x98\x3d\x95\x11\x45\xa8\x84\xc0\xac\xeb\x95\x6b\xd7\xdb\x34\xc4\xa6\x7b\xba\xc7\x23\xcb\xc4\xae\x64\x39\xcb\x5e\x50\xc8\x5e\x69\x0c\x65\x54\x3d\x05\x15\x45\xd3\x8c\x0b\x18\xd5\x9c\x52\x0e\x95\xea\x7a\x3b\xa6\xfc\x46\x97\x51\x6f\xa5\xc8\x37\xe6\xe1\xbb\x63\xab\xb8\x13\x9a\xb6\xe6\x88\x71\xef\x4e\xa4\xe5\xde\x16\xdb\xb2\x3d\xed\xd8\xd4\x21\x3f\xde\x6b\x92\x80\x2a\x84\x4c\xc7\x41\x66\x42\xf7\x2b\x7d\xb4\x37\x8e\x51\x20\x93\xb7\xe9\xe5\x0d\x8d\x52\x12\x31\x69\x36\x0e\xa4\xeb\x55\xa6\xc7\xae\x41\xa8\x47\xaf\x26\x5a\x29\x2b\x54\x4b\x75\x3c\x49\xce\x41\xef\x51\xf1\xde\x19\xc5\x80\x8c\x8f\x15\x36\x08\x56\x96\x52\xc6\xcd\xb7\xe6\x8a\x2d\x71\xb2\x34\x12\x53\xa9\xa1\xcc\x3b\xb7\x3b\x05\x8c\x2e\x74\x5e\xba\x04\x5d\x80\x0b\x6d\x81\xbb\xa7\xbb\x4b\x9b\xa3\xfb\x86\x84\xe7\xf4\x04\x83\x55\xc4\x18\x35\xa4\x88\x00\x02\xa9\x78\x35\xe0\xb7\x88\x61\x15\xc5\xd6\x33\xcb\x66\x5e\x33\xae\xbd\x74\xcc\x52\x18\x42\xc9\x9d\xe9\x8a\xaa\x03\x3a\x23\x88\xde\x3b\xd5\xd8\xc1\x42\x8a\x7a\x17\xa8\x82\x86\x33\x0f\xdf\x33\xd0\x92\x5d\x19\x59\xb1\x13\xcd\x7a\x1b\x55\x64\xf9\xcc\x23\x27\x62\x66\x43\x45\x23\x0b\x18\x67\x0b\x99\x15\x80\xe9\x72\xf9\xda\x7d\x14\xb0\xa4\x35\x73\x34\x4a\xec\x6d\x1a\x92\xa4\x1d\x09\x66\xfd\xfe\x64\xb9\xae\x75\xb4\x75\x04\xc8\x2d\xe9\x39\xec\x06\x6b\x8e\xe6\x58\xcf\x7c\xa9\x6b\x60\xbc\xcb\x87\x34\x79\xcc\x02\x73\xdb\xae\x2b\xde\x20\x40\xd7\x9b\x03\xc7\xce\xef\xad\xde\x10\x89\x0d\x54\xc4\xa9\x3a\x50\x74\xdf\x09\xd8\xe6\x2b\x82\x7a\xc3\x99\xc1\xfa\x02\xf8\xb8\x50\x56\xa2\x87\xc3\xa1\xf9\xb7\x9a\xad\xd6\x4f\xbb\xcb\x20\xbd\x08\xd4\xa7\xa9\x65\xa4\x88\x5a\x8a\x27\x2a\x36\x1a\x70\x46\x49\x01\xdc\x80\x36\x85\xe3\x08\x17\x99\xc7\x5e\x30\x1d\x73\x20\x5f\x2a\x48\xfb\xbd\xea\xc3\x12\x41\xee\x55\xca\xda\x42\x60\x6d\x21\xb0\x56\xfc\xfa\x91\xb1\xb0\xd0\xfd\x15\x2c\x3c\xb2\xed\x4c\xa1\xbf\xd9\x3e\x9f\x59\xd1\xb5\xed\x51\x6b\xa9\x69\xfb\x7d\xf9\x50\x9a\x43\x05\x1f\x3e\x72\x6c\x93\xdc\x65\x43\x5a\x93\xef\xca\x2c\x2b\xa8\xf4\xbd\x3e\x10\x59\xb7\xf1\x88\xb2\x47\x85\x84\x6d\x13\x01\xe1\xc6\xb9\x45\x16\x67\x53\x5a\x70\x5b\x14\x83\x0d\x46\x49\x1e\x2f\xa8\x30\xc3\xdf\x88\xdb\x26\x08\x34\xa7\x57\xd7\xd4\x11\x00\x05\x80\x18\xc0\x9c\x33\xf2\x27\x25\x32\x3e\xdb\xdc\xdb\x43\xee\xdf\x89\xbb\x73\x7c\xc9\x0d\x63\x53\x84\x4e\xca\x92\xe6\xca\xbb\x0a\x1c\x6a\xc0\x2a\xc6\x01\x39\x3b\x02\x85\xdb\x53\xe4\xd9\x89\xd7\xd7\x39\x42\x4a\x33\xeb\x34\xeb\x66\x99\xb6\x8b\x87\xfe\xf2\xa8\xfc\x59\x8e\x02\x8a\x6e\x71\x86\x1e\x31\x1e\x90\xe0\xdc\xed\x59\x49\xdf\x8f\x98\x1d\x98\x71\xa4\x0a\x69\x3a\x4d\xd8\x85\x7f\xff\xf6\xe4\x3f\x01\x00\x00\xff\xff\x6f\x29\x93\x28\x3c\x20\x00\x00")
+
+func fontsJazmineFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsJazmineFlf,
+ "fonts/jazmine.flf",
+ )
+}
+
+func fontsJazmineFlf() (*asset, error) {
+ bytes, err := fontsJazmineFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/jazmine.flf", size: 8252, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsJerusalemFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x59\x6d\x6f\xe3\xb8\x11\xfe\xce\x5f\xf1\x60\x11\x34\xf6\x35\x31\xcf\xb7\xbd\x3d\xdc\xde\x66\xa1\xa2\x7b\xd7\xf6\x80\x7e\x28\xae\xd8\x7e\x21\xc0\xa5\x2d\xca\xd2\x45\x96\x5c\x49\x4e\xe2\x05\xd1\xdf\x5e\xf0\x4d\x22\x65\x39\xf6\x6e\x13\x04\x12\x65\x91\x33\xc3\x99\x67\xde\xa8\xac\xcc\xbe\x13\x57\xf8\x01\x6f\xb0\xfc\xf6\x5b\x2c\xbf\xc7\xeb\x25\x96\xe4\x57\xd9\xec\x5b\x51\xca\x2d\x56\x07\xfc\x55\xa6\xa2\x2c\x44\x8e\x5f\x9a\x42\xa6\xb2\x5a\xc9\x66\x83\x5b\xac\x44\x2b\x53\xd4\x15\x7e\xeb\x44\x95\x8a\x26\x35\x73\x17\xf8\x4b\x2e\x76\x3b\x59\x96\xf8\x03\xfe\x2e\x2a\xfd\x58\x90\x7f\xee\x65\xdb\x15\x75\xd5\x42\x54\x29\xd6\xf5\x76\x2b\xab\xae\x45\x23\x37\xa2\x49\x8b\x6a\x83\xdf\x3d\xc3\x45\x56\x66\xe8\x6a\x6c\x32\xcb\x2c\xa9\x0e\x4f\x8b\x75\xbb\x48\xf7\x0b\x99\xee\xc9\x3f\xea\xb4\xc8\x0a\x99\x22\xab\x1b\x64\xc5\xa6\x94\x1d\xbe\x5b\x2c\x0d\xeb\x52\x56\xd5\xc0\x7d\xf9\x06\x1f\xe4\x1a\xcb\x1f\x7f\x7c\x4d\x3e\x88\x4e\xbe\xc5\xf2\x35\x7e\x91\x2b\xfd\xcb\x9f\x08\xf9\xf9\x69\x57\x8a\x4a\x68\xa1\x50\x67\xc8\x8a\xa6\xed\x50\x16\x95\x7c\x4b\xb4\x4e\x70\x8b\x57\x5b\xb1\x29\xd6\xa8\xf6\xdb\x95\x6c\x5e\x39\x86\xa5\x44\x91\xca\xaa\x2b\xb2\x62\x6d\x16\x13\x01\x00\xb7\x68\xf3\x7a\x5f\xa6\x10\xe5\xa3\x38\xb4\x58\x49\x7c\x12\xd7\x37\x66\x51\x55\x3f\x92\x2b\x3b\xa9\xcb\x25\x5e\xe5\xa2\x49\x57\xa5\xa8\xee\x5f\xe1\xf6\x16\xbb\xa6\xd0\x9a\x10\x2d\x04\xcc\xaf\x37\x58\xed\x3b\xac\x45\x75\xdd\x69\x32\xed\x76\xdf\xe6\x32\x25\x3f\x58\x0a\xb9\x2c\x36\x79\xa7\x25\x16\x58\xe7\xa2\x11\xeb\x4e\x36\xe4\xcd\x33\x2f\x6f\x50\xd5\x1d\x8a\x6a\x5d\xee\x8d\xa6\x53\xd9\xae\x65\x95\xca\xa6\x25\xda\xe2\xb8\x05\xb6\xe2\xc9\x6c\x1d\xa5\xac\x36\x5d\x8e\x99\x7c\xf2\xb3\x9d\xa9\xcc\xeb\x76\x8e\x3f\x42\x20\xdb\xa7\x1b\x89\x4c\xac\xbb\xba\x21\xcb\xef\x0d\xe7\x54\x66\x62\x5f\x76\x56\xda\x6d\x9d\x4a\xb3\xf3\x2e\x2f\x5a\x64\x75\xd5\x91\xd7\x4b\x33\xcd\xea\x52\x0b\x18\xd1\x25\x4b\x2b\xbf\xd1\x05\x1a\xbd\x89\xdb\xae\xbe\x2d\x65\xd6\x61\x16\x18\xb9\x6e\x50\x8a\x4e\x13\xa8\xca\xc3\x9c\x90\xbf\xc9\x55\x23\x1f\x71\x2f\x0f\xab\x5a\xe3\x6f\x2b\x76\xed\x5b\x42\xfe\x5c\x96\x58\x8b\x5d\xd1\x89\x12\xa5\xec\x3a\xd9\xb4\x8e\xb4\xd6\xbf\xac\x36\x65\xd1\xe6\x83\x82\x9c\xa8\xa2\xd3\x84\x16\x80\x5e\x6e\x05\x6d\x41\x34\x5c\xdb\xc3\x76\x55\x97\x2d\x44\x23\x0d\x85\x56\x6c\x25\x8a\x4a\xff\x5b\x09\xe8\xcf\x8e\xa6\x7c\x5a\xcb\x5d\xe7\x08\xd6\xad\xd4\xa8\x78\xac\x90\xcb\x46\x2e\xc8\xbf\x72\x89\x6f\x1c\xb1\xc8\xec\xbf\xca\x47\xbd\xb8\xed\x44\x83\xd9\x6f\xfa\x5a\x67\xf8\x20\x1e\x8a\x74\xbe\x20\xff\xce\x0d\xe6\x2a\x07\xf6\x1b\x74\x87\x9d\xc4\x7f\xb5\xdf\x09\x6b\xb4\xd5\x01\x45\xd7\x4a\xeb\x36\xad\x94\x56\xed\x65\xd1\x76\x6f\x09\x11\xa5\xdc\xe5\x00\xee\xd0\x41\xe1\xb3\x38\x14\x15\xcc\xe3\x67\x28\x94\x62\x2b\x53\xf3\x74\x0f\x85\xe1\xdd\x06\x0a\x6d\x5e\x54\xb4\xd5\xbf\xdc\x41\x90\x95\xec\xe8\x83\xec\x70\x87\x35\x14\xd6\xb9\xec\x60\xa7\xfe\x0e\x85\xad\xdc\xba\xa7\x0a\x0a\x3b\x79\xa0\x99\x3c\xe0\x0e\x3b\x28\x74\x22\xa3\xad\xc8\xcc\xdb\x1b\xb2\x29\xb6\x5b\x59\xea\x71\xaa\xdf\x39\x2a\xb8\xc3\x01\x0a\x59\x51\x89\x12\xaf\x70\x87\x3a\x7a\xfa\x09\x0a\x37\x33\x0d\x18\x31\xd7\x73\xaf\x49\x2a\x4a\x27\x77\x0b\x85\xc3\x3e\xf5\x64\x72\x28\x54\xfb\xca\x3d\xad\x34\x8f\xcf\x42\xa4\x85\x7e\xda\x42\x61\x31\xdb\xc9\xa6\xa8\xd3\x39\xee\x40\x49\x2e\x0e\x6e\xe6\x03\x14\xee\x45\x46\xd7\xb9\xc8\x70\x87\x2c\xe2\x5f\x44\x4f\x0b\x28\xfc\x04\xff\x77\x87\x4f\xe4\x41\x3c\xb8\xf1\x3e\x98\x89\x3b\x94\x5a\x8d\x62\x2b\xef\x73\xfd\xf4\xa4\x79\xec\x33\x37\x55\x42\x81\x06\x64\xfe\x63\xe0\x21\xda\x4e\x36\x45\x7b\x8f\xd9\x37\x73\x14\x1a\x1b\x11\x1c\xec\x64\x85\x46\xb6\xb9\x5d\xd6\x40\xe1\x7a\x26\x76\x75\xdb\x2d\xf4\xa6\x1e\x09\xb9\x4a\x8e\xff\x13\x02\x20\x21\xe0\x48\x88\x82\xf2\x17\xae\x12\x32\xe3\x73\xfb\xd6\x5c\xdd\x2c\x3d\x6f\x06\x05\xfd\xea\x23\x3e\xea\x1f\x71\x85\xf0\x16\xac\xf0\xcb\x00\x6e\xfe\x0d\x09\x05\xa5\xa0\x0c\x3f\x0e\x2c\x16\x00\x57\x76\xac\xff\xf4\x18\x50\x5c\x29\xae\x7a\x7a\x11\x51\x7d\xe3\xe6\xa6\xa0\x90\x10\x0a\xae\x05\x65\x9c\x83\x69\xd9\x00\xaa\xdf\x71\x35\x88\x61\x24\x07\xe7\x66\x4f\xd4\xbc\x07\x05\xd5\xbf\x53\x50\x2d\x0a\xe5\xd4\x6f\x37\x96\xdf\x70\xe3\x4e\xf6\x19\x38\xe6\xb0\xcb\x38\x18\x65\x5a\x5d\x33\xfe\x1e\x78\x97\x10\x30\xce\x39\x65\x34\x58\xeb\x95\x3b\xba\x58\x1d\xce\x13\xa2\xa8\x67\x65\xd9\x58\x79\x8c\x0d\x10\x5f\xc1\x38\xeb\xa7\x72\xb3\x7d\x06\xe6\x94\x10\x5f\x29\xa7\xd1\xce\xe1\x17\x51\xa6\x39\x30\x58\x0d\x51\xad\x11\xa6\xdf\x33\x1a\xcc\xeb\xa5\x8f\x07\x81\xf1\xbc\xe5\x06\x53\x85\x93\x8f\x2d\x6f\xfe\xcc\x58\xe9\x27\xc0\x2e\xd3\x4f\x56\x6a\x3e\x8c\x15\xe7\x9a\x9c\xb2\xa4\xc7\x96\x1f\x0b\xe5\x4d\xeb\x18\x28\x33\xb0\x2b\xaf\x30\x2d\x94\x99\x6e\xf6\x93\x10\xb5\x30\x52\x38\xc5\x81\x52\xa7\x4e\x4a\x7b\x74\xd9\x15\x66\x8b\x67\xcc\x39\xf2\x95\x00\x38\x1e\x2d\xce\x96\xde\xc9\xb8\xe5\x6c\x40\x33\x16\xd5\x11\xa5\x83\x3f\xf6\x4e\x39\xe6\xc1\x1d\x0f\xbd\x79\x0b\x08\xed\x0e\x86\xb4\x76\x0c\x3a\xd2\xcb\x91\x3a\x43\xe5\x59\x8f\xd0\x16\x66\xee\xd5\xdc\x1b\xe5\x58\xc6\xd0\xb1\xcc\xc8\xfa\xf5\x30\x72\x54\x7b\xa0\x8c\x90\x72\x62\x1b\x30\x08\x08\xf7\x73\x5e\x0c\xbb\x69\xa0\xf7\x67\x43\xe8\xda\xeb\x7c\xe6\xf4\x31\xa9\xea\x29\x35\x58\x84\xfa\x08\x61\xee\x86\x34\xa7\xd3\xa8\x0a\x4d\x6d\x43\x44\x64\xf3\x4b\xf8\x4f\x40\x25\x58\x76\xe3\x25\x9a\x84\xca\x08\x84\xd3\x70\xec\x37\x69\x03\xbd\x77\x44\x63\xa7\xc1\xf5\x14\x3c\x4c\x82\x11\x57\x93\x41\xca\xaa\xc7\x45\x21\x66\x43\xc9\x29\x5f\x3d\x72\xd1\x73\xbe\x3a\x0a\x72\x4c\x87\x76\xc7\xb6\xd7\x41\x98\x97\x3c\x75\x33\xcf\x4e\xb4\x29\x80\x18\x3d\x4e\xe4\xa5\x3e\x38\xc1\x19\xd9\xe3\x4d\xef\x8b\x7f\x72\xca\xc1\xcc\xfb\xa9\xb1\x83\x95\x98\x39\x24\x8e\xa9\x19\x47\x80\xc3\x0e\x43\x4f\x58\x8f\x9d\x3f\x5a\x1e\x16\x49\xbd\xce\x9e\x77\x07\x03\x27\x6d\x31\x1f\x42\x2e\x73\x07\x1b\x73\x0d\x4f\xb7\x15\xef\xa5\xee\x15\x3b\x13\x15\x30\x62\x3b\x8a\x5c\xcf\xf2\x1f\x80\xe6\xed\xad\xa3\x40\xc4\xff\xb2\xa8\x84\x41\x7e\x1f\x65\x3c\x21\xae\xf0\xac\x3b\x1e\xef\xdf\xd5\x38\x41\xe4\x3d\xc9\x1f\xfd\xec\xf1\xb6\x8d\x95\x6d\x34\x8e\xf2\xd4\x04\x1a\x6d\xe0\x73\x09\xdc\x65\xf3\x80\xe7\x91\xab\x70\x37\x70\x69\x11\x17\xe5\x8a\xa8\xbc\xd1\xd9\xcb\x16\x10\xd7\xc6\x3b\x15\x16\xd6\x7c\x5c\x05\x68\x3b\xda\xaa\x33\xcc\xf1\xe0\x9c\xa9\x7c\x3e\xf5\xc6\xd2\xa5\x84\x15\x99\x51\x2f\x7c\x9f\xda\xc7\x89\xfd\x84\xc6\x99\xdf\x36\x98\x27\xc1\x7a\x8d\xb3\x53\x16\xfb\xea\x5c\xfb\x0c\xe2\x9d\xa3\xa1\xcf\xa3\x67\x10\x77\x01\xff\xd0\xe7\xbf\x80\x3f\xde\xc1\xef\xff\xcc\x7a\xea\x13\x28\xfb\xb2\x04\x3a\x44\xe8\xa1\xb2\x83\xcb\xd7\xc3\xe0\x44\xad\x77\xc2\x63\x2e\xd6\xbf\x8f\xf7\xb0\x28\x66\x26\x78\xda\x20\xae\xc7\x3e\x11\x33\x7c\x84\xaf\x55\x59\x9c\x8c\x47\x95\x67\x40\x30\xa2\x19\x93\x8d\x29\xc7\xc4\x8f\xe8\xc7\x0e\xc7\x79\x4f\xd6\x13\xf4\xfd\x84\x8f\xf0\x27\x1c\xce\x56\x44\x4e\x22\xbf\xf6\xa3\x2f\xbd\xce\x68\xda\x1b\xca\x55\x56\x93\x8d\x4c\xe8\xaa\x43\xe2\xf6\xe1\x58\x4d\x75\x17\x8a\xf7\x39\x7e\xd0\x9c\xd7\x99\xd3\x96\xd3\x13\xf3\x1a\x1a\x6f\xae\xe7\xc1\xc7\x0d\x49\x5f\x5f\x04\x75\x04\x35\x10\xa7\xcc\x48\x7a\x85\xf1\xf5\x6c\xcd\x7f\x3c\x18\x97\x18\xcf\x55\x47\x71\xef\x35\x06\x71\x04\xe4\x08\xcc\xfd\x03\x35\xa5\xd8\x50\x5c\x6b\x5c\xc7\x60\x89\x3a\x30\x97\x8c\x54\x5f\x5a\xba\x08\x1f\x64\xd2\xb1\xc9\xa2\xc5\x3e\xb6\x28\x3b\x52\x3d\x2b\x97\x5b\xec\x96\xa1\xb8\xb3\xbf\x11\x28\xa2\x73\xba\xf0\x51\x11\xc5\x80\xa0\xeb\xae\x0d\xad\x53\xa5\x4a\x5c\x55\xf2\xa1\x78\xf6\xc9\xcb\xea\xac\xcf\x83\x38\xee\xa7\x62\xfb\xf5\x64\x18\xa2\x42\xd4\x09\xe4\xf5\x4d\x27\xfb\x08\x84\xdd\x9d\xc1\xaa\xab\x62\x99\x4b\x25\xe0\x9c\xe1\xd3\x40\x66\x2a\x1b\x85\xf9\x1b\xbe\xc3\x75\x75\x6a\x78\x7b\x76\xc5\xe4\x2d\xf0\xb1\x50\x73\xae\x15\xed\x5b\xe3\xa0\x33\x0e\x87\xc7\x7d\x71\xd2\x67\xef\x3e\x59\x8f\xcd\x30\x34\x31\x7d\x17\x33\x6e\x63\xc6\xd8\xe0\x63\x7b\x2e\x54\x8c\x8d\x67\x86\xe1\x99\x0b\xc2\xc6\x8c\xf3\x85\x0f\x1f\xbd\x40\x43\x34\xe7\xda\x2c\x36\xc4\x78\xbb\xc4\xde\xf4\x35\x7a\xe3\xbd\xde\x54\x6c\xe8\x23\x11\xf9\x98\x5e\x48\x70\xa0\xe8\x11\x08\xef\xf2\x27\xce\x28\xc6\x22\x06\x14\x99\xde\xe7\x00\xe8\x10\xd1\x27\x44\xb4\x77\xd3\x74\xf9\xd4\x15\x04\x7c\xf4\xbd\xc4\x44\xf4\x38\xe5\x9a\x71\x73\x17\xb5\x79\x17\x63\x02\x67\x30\xc1\xd5\x74\x6a\x9e\x4a\x7f\x0a\x2e\xfd\x99\x42\x8f\x3d\x53\xe8\x9c\x75\xb4\x89\xd2\x7a\x4a\xfe\x20\x48\x5d\xec\x68\x43\x1a\xf1\xc9\x83\xd8\x48\xe0\xc2\xc1\x57\x40\x54\x87\xb1\x01\x4f\xf4\x64\x31\xd3\x47\x35\xde\x9f\x5a\xd1\xff\x1f\xa2\x01\xea\x99\x23\xcf\x7c\x6e\xf2\x80\x0a\x87\x5c\x4d\xd7\x5b\x2e\x9d\x24\x43\xdb\x6d\x70\xf0\x0e\xef\x30\xb4\x3d\x18\xce\x2f\x8f\xcf\x9a\xa3\x03\xae\x9e\xaa\x3b\xd0\xf1\xa5\x87\xa7\xf3\x1e\xef\x87\x93\x5f\x93\x75\x93\x17\xfa\x92\x91\xbc\xd0\xa7\x8c\xe4\x85\xbe\x65\x24\x2f\xf4\x31\x23\x79\xa1\xaf\x19\xc9\x0b\x7d\xce\x48\x5e\xe8\x7b\xc6\x64\xfb\x31\xe3\x73\xee\x0e\xbf\x28\x67\x51\x43\xa6\xd1\x72\xba\x7d\x3a\x5a\x1f\xf4\x71\x97\xb4\x8f\xc3\x7a\x98\xf5\x5f\xda\x7e\x4e\xf1\x77\x87\x50\xb3\x61\xfd\xcd\xb9\x03\x8b\x29\xf9\x2f\x3a\xff\xbc\x4c\xfe\x49\xfe\x41\x85\x6b\x98\x86\xc7\x10\x8a\xb9\x67\xa5\x0b\x52\x17\x44\x12\xf2\xbf\x00\x00\x00\xff\xff\xa5\xc8\x5b\x7a\x5c\x20\x00\x00")
+
+func fontsJerusalemFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsJerusalemFlf,
+ "fonts/jerusalem.flf",
+ )
+}
+
+func fontsJerusalemFlf() (*asset, error) {
+ bytes, err := fontsJerusalemFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/jerusalem.flf", size: 8284, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsKatakanaFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\xdb\x8e\xdb\x36\x13\xbe\x8e\x9f\xe2\x03\x46\x97\xff\x2c\xfe\x0d\x8a\xb6\x29\x82\x60\x93\xa6\xc7\xf4\x98\xa6\x69\xd3\x3b\xee\x46\x5e\xab\x5e\x4b\xad\x65\x35\xf0\xdb\x17\xb6\x25\x72\x86\x1c\x4a\x32\x36\xcd\x06\x16\x49\x49\x9c\xc3\x37\x47\x2a\xcb\xbb\xe5\x43\x57\xe0\x53\x7c\x82\x87\xff\x07\x5f\xe2\xe3\xc5\x0b\xb7\x73\x6b\x57\xbb\x8b\xe5\xdd\x12\xd7\x7b\xbc\xae\xea\xba\xdc\xe3\xd5\xca\x55\x78\xdc\xb6\xcb\xaa\xda\x5d\x95\xdb\xaa\xbd\xb8\x69\x2f\xba\xcd\xf5\x45\xf9\xb6\x7b\x82\xe7\x6e\x57\x7e\x86\xa7\xdd\x6d\xd7\xee\x70\x79\xf9\x3f\x5c\x3e\x7a\xf4\xd1\xe2\xda\xb5\xe5\x5b\x34\x35\x9e\xb9\xba\x2e\xb7\x07\x6a\x2f\xf7\xae\xc6\x9b\xa6\xbb\x59\xe3\xf1\xfe\x30\x5c\x1d\xc8\x6c\xcb\xdb\xaa\x76\x17\x37\xee\xc9\xc2\xf1\x53\x54\xfc\xec\x41\xc7\x9f\xa3\xe4\xe7\x0f\x1a\xfe\x02\x6b\xc7\x5f\x62\x5d\xf1\x57\x58\x77\xfc\x35\xd6\x25\x7f\xf3\x60\xdd\xf0\xb7\x68\x1d\xbf\x40\xbb\xaa\xf8\x3b\xb4\x1d\x7f\x8f\xb6\xe4\x1f\xd0\x36\xfc\x23\x76\x8e\x7f\xc2\xe2\x66\x55\xf1\xcf\xd8\xb5\x1d\xbf\xc4\xae\xe4\x5f\xb0\x6b\xf8\x15\x6a\xc7\xbf\xa2\xae\xf8\x35\xea\x8e\x7f\x43\x5d\xf2\xef\xa8\x1b\x7e\x83\x95\xe3\x3f\xb0\xaa\xd8\x61\xd9\xf1\x35\x56\x25\xdf\x60\xd5\xf0\x5b\x6c\x1c\x97\x8b\x4d\xc5\x4b\x6c\x3a\xbe\xc5\xa6\xe4\x15\x36\x0d\x57\xd8\x3b\xfe\x13\xfb\x8e\xd7\x28\xf9\x0e\xfb\x86\x37\xd8\x3a\xae\xb1\xad\xb8\xc1\xb6\xe3\xbf\xb0\x2d\xf9\x6f\x6c\x1b\xde\xe2\x9d\xe3\x16\x15\xef\xf0\xae\xe1\x0e\x8b\x9a\xff\x59\x14\x45\x71\x35\xe3\x72\xb5\x20\xa2\x42\x5f\x41\x38\x5c\x81\xf8\xfe\xe1\xce\x71\x01\x7f\x1b\x7e\x0b\x4e\xdb\x0a\x1c\xff\xd4\x0c\x63\xb3\xc3\x94\x0e\xfb\x0b\x39\xa3\xd3\xdf\xe4\x3d\x39\x0b\x04\x8f\xef\x1d\xb7\x1c\x9e\x83\xfc\xec\xf8\xa2\x7f\x8a\xe8\x29\xc5\x4f\x21\x54\x1e\x5e\xa4\x5e\xd1\xa3\xf2\x08\x64\xbc\x34\x1e\x10\x1a\x48\xc3\xe3\x27\x54\xf6\xd2\x20\xa8\x22\x24\xec\xe1\x87\x24\xd3\x1b\xe6\xf8\x94\x12\x09\x23\xfb\x79\xd9\xac\xeb\x89\x5b\xcf\xbe\xa7\x9e\x0c\x42\xae\x9e\xd9\x89\x93\x57\xb5\xd7\xdd\x18\x7a\x84\xbc\x61\x4e\x1c\xbd\xed\xbd\xb7\x4c\x18\x57\xbc\x67\xfa\x4d\x40\x5d\x8e\x92\x90\x7e\x0e\x39\x66\xc1\xc9\x81\x99\x50\xf0\x63\xe0\x68\x3f\x3f\x8b\xa3\x0a\xb6\x93\xb6\x9e\xb6\x07\xc3\xf2\x3c\x01\xae\x37\xa3\x15\x6c\x14\xa3\x4b\x9e\x89\x35\x53\xd6\xa2\x34\xd8\xb4\xff\x9e\x36\x48\xf1\xec\x89\x82\x2c\x8d\x5a\xa9\x74\x14\x97\x41\x2d\x31\x23\x4d\xef\x2c\x82\x30\x95\xb6\xd2\x80\xe6\x4c\xd9\x99\x96\x26\x90\x31\xf2\x4a\xff\x62\x5e\xa9\xb3\x24\xb4\x54\xb6\x08\xda\x76\xb6\x33\x9f\x94\x70\x8e\xff\x99\xb3\x19\x12\x5a\x56\xbe\x97\xca\x61\x0b\x9d\x87\x21\xcc\x52\x98\xb9\x9f\xad\x94\xa3\x69\x44\xa4\x49\x9d\x82\x91\x49\xaf\x66\xfe\x89\xf3\xce\x44\x1e\x9a\x62\x62\x89\x33\x2f\x96\x4e\x99\x21\xf2\x08\xc1\x3d\xbe\x97\x33\xdb\xb1\xa8\xa6\xb3\x28\xee\xc7\x3c\x55\x19\x9b\x64\xe8\x05\x11\x28\x92\x4c\xb9\xab\xca\xa2\x4a\x6c\x9d\x92\x07\x36\x24\xb2\xdf\x50\x7f\xa0\x4a\xce\xe4\x54\x10\x26\x1d\xab\x3a\x3b\xa8\xaa\x2f\x75\x0b\xf0\x12\x09\x90\xc6\x35\x08\x6a\x47\x89\x46\x45\xed\xf4\xc2\x00\x3e\x62\x44\xb9\xf7\x44\x35\x11\xdd\x94\xc0\xef\xa4\x83\x2e\x3a\x94\xd3\x28\x2b\x10\x49\xe8\xe4\x42\xfa\x72\xdf\x6a\x09\xe3\x5b\x8c\x48\xd7\xd9\xde\x31\x33\x9d\xa0\xd9\xc4\x24\x9d\xa0\x76\x41\x21\x39\x09\xa3\xd3\xfb\x30\xfa\x28\x23\x52\x95\xed\xbc\x60\xc9\x7b\x97\xed\x1c\x67\x2c\xfc\x7e\x8b\x11\x21\xe7\x5d\x94\x18\x50\x2e\xc8\xf6\xe9\xa4\x61\xd2\x8c\xa0\x4e\x12\x50\xbe\xa2\xc9\x0b\xfa\xc2\x36\xca\x38\x7e\x1e\xf1\x53\xb9\x4c\x48\x2f\x64\xcf\x26\x9e\x21\x72\x84\xbf\x24\x29\x46\x99\x8d\xb2\x86\x92\x1a\x66\xf7\x60\x70\x23\x2b\x4e\x14\x60\xb1\x30\xa4\x6c\x21\xa1\x92\x40\x49\x98\x24\x07\xe5\xce\xd2\x9b\x65\xec\x0e\x87\x35\x11\x9a\xe7\x32\x40\x88\xb8\x5e\xcf\x39\xd9\x2f\x97\x31\xa5\x27\x68\xa8\x54\x05\xfc\x2f\xa0\x1a\xa4\x2f\x26\xa3\x33\x9b\xee\x0d\x37\x36\x8d\x2e\x4e\x91\x43\x23\xe1\x4f\xe2\xe9\x09\x73\x56\xfa\x9e\x25\x14\x54\x7b\x60\x20\x61\x55\x3e\xb5\xc8\x81\x34\x81\x58\x06\x8a\xb1\xbc\x17\xb7\xd2\x14\x19\x36\xc0\x4c\xca\xb4\xe7\x57\x3e\xc5\x48\x9c\xde\x84\xae\x43\xb5\xcd\xc0\x9d\x40\xa7\x48\xbf\xe7\x88\xb6\x1e\xf4\x80\x91\x4c\x3f\x3a\xf3\xca\x06\x29\xdd\x1b\xd9\x64\x78\x79\xce\x48\xaa\x9b\xd6\x1d\x68\xe0\x10\x15\x90\xe0\x9a\x01\xcf\x5c\xf1\x57\x4d\xca\x8c\x31\x91\x28\x1c\xa7\x43\xda\x9f\xf1\x21\x62\x11\x83\x5e\xdc\x6f\xe6\x9d\xce\xfe\x90\x18\x8e\x44\xc9\x35\x98\x2e\x7c\x2a\x1b\x28\x4a\x73\x8c\x4d\x91\xfa\xfc\x54\x11\x9d\xaa\xa7\xda\x55\x93\x22\x6a\x79\x58\x9a\x1b\x49\x92\x02\x92\x46\x16\x53\x49\xa4\x97\x6f\x3a\x2d\x52\xd2\x6e\x0a\x77\x50\x3e\x31\x1e\xdb\x73\x92\x88\x8a\xef\x5c\x27\x85\xf8\xc8\x27\x6c\x22\xb2\x43\x31\x7c\x5a\xf5\x05\xda\xef\x18\x7d\x34\xbf\x14\x18\x67\xba\xa8\x5f\x84\x91\xa0\x2d\x68\x2c\x34\x68\x1e\x1a\x14\x9e\x50\xda\x98\xe6\xaa\x34\x65\x0d\xa2\x1a\x89\xfc\x02\x63\xad\x99\xf8\x08\x28\xfb\xc7\x00\x1d\xc5\xfd\x70\x44\x7b\xda\xd8\x72\x65\xd6\xd7\xa9\xc5\xdc\x62\x3b\xc5\x28\xeb\xa4\xa3\x75\x73\xac\xaa\xdb\x35\x50\x1d\x58\x60\xd6\x46\xf5\x81\x90\x8c\x1a\x98\xeb\x42\x94\x88\x64\x30\x9f\x3c\x1a\x6a\x4d\x44\xe1\xb4\x46\xd5\xfc\x0f\xa9\x30\x2a\x1c\xa4\x4b\xdf\xf8\x82\x42\xa2\x12\xe5\xdb\x7f\x32\x89\xc4\x8e\x24\xc5\x74\x25\xf0\xb8\x84\xb6\x73\x6e\x1a\x2f\xb4\x61\x73\x47\x17\x32\x8c\x4c\x93\xfd\xc6\x98\xc9\x32\x59\x55\xf7\x11\xba\x21\x34\x8d\xe9\xf7\x48\xff\xa7\x71\xc3\x8c\x95\x93\x6c\x9d\xb0\xe3\x24\xd1\xc8\xbb\xf7\xb8\x12\x64\x76\x6d\x49\xb3\x29\x71\xd7\xe7\x52\xdc\xa3\xd9\x2c\x46\x7f\x1f\xe6\x05\xf9\x9f\xa7\x62\xa4\x68\x2d\xbe\x29\x45\xfd\x68\x11\x7e\x28\x92\x75\x5f\x41\x55\x34\x87\x91\x8c\xfb\x2a\xf3\xf4\x5f\x69\x21\xcb\x81\xf8\xe8\x19\x10\x9d\x3f\xbb\x5a\x44\xff\x3e\xd4\x8d\x7f\x03\x00\x00\xff\xff\x28\xc0\xd7\xf9\x8d\x20\x00\x00")
+
+func fontsKatakanaFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsKatakanaFlf,
+ "fonts/katakana.flf",
+ )
+}
+
+func fontsKatakanaFlf() (*asset, error) {
+ bytes, err := fontsKatakanaFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/katakana.flf", size: 8333, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsKbanFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x58\x5b\x6b\x1c\x47\x13\x7d\x9f\x5f\x71\xf8\x90\xa9\xd5\xb7\x3b\xd5\x91\x13\x1c\x0c\xb2\x32\xcf\xb9\xbc\x04\x42\x1e\x32\x61\x24\x13\x39\x16\x04\x3d\xc4\x26\x44\x6c\xeb\xbf\x87\xae\xaa\xbe\x4c\xcf\x4c\xef\x2a\x6f\x31\x78\xfa\x56\x7d\xba\xfa\xd4\xa5\x6b\xf5\xe1\x8f\x0f\xaf\xef\x2e\xf0\x35\xde\xe0\xf5\x17\xe8\xaf\xf0\x65\xf7\xdd\xfb\xbb\x47\xbc\x7f\xc2\x8f\x77\x8f\xbf\x3d\xe1\xdb\xbb\x7b\xfc\x7c\xff\xf0\xf8\xe9\xf3\xfd\xc3\x63\xf7\xc3\xdd\x13\xae\xde\x1c\x70\xf5\xf6\xed\x57\xe8\xf1\xfd\xfd\xc7\x87\xdf\x3f\xe2\xa7\xc7\x87\xbf\xee\xff\xfc\xf4\xf0\xf9\xa9\x43\x77\x71\x81\xa1\xfd\x19\x3a\xf6\x8c\xa1\xf3\xde\x63\xe8\xc8\x13\x86\x0e\x1e\xe1\xcb\xc8\x33\x40\x10\xfd\x9f\x74\x57\xff\xab\x8c\xfe\x0b\xfd\xe7\x23\x8e\xcf\xd2\xbf\xbe\xd9\xef\xdf\xed\xf7\xd7\x37\x71\xfe\xf9\xd8\x9c\x2f\x70\xd2\x60\xe8\x30\xed\xf7\xd3\x41\x15\xf5\x32\xe3\x7d\xdf\x8b\x8a\x78\xe5\x55\x7b\xc0\x3a\x87\x7e\x9a\xfa\x6a\x7f\xf8\x77\x90\x63\x01\x67\x33\xce\x96\x9c\xc9\x38\x13\x76\x40\x10\x4b\xfb\xc3\xd2\xa8\xed\xe8\xd2\x38\xa0\x39\x1a\x47\xd1\x0a\x18\x47\x0c\xdd\x38\xf6\x6e\x0c\x1b\xa9\x4d\x95\x0b\x7b\x9d\x5e\xa3\xfe\x8e\xa3\x0a\x0a\x4e\x3c\x76\x14\xbb\xf8\xfa\xeb\x9c\xaa\x3b\x33\xc0\xd0\x89\xfa\x30\x6a\x31\xda\x45\xaf\x6f\xfa\xfe\xff\x7d\x7f\x7d\x63\x97\x1f\x57\x64\x13\xf3\xfb\xd6\x05\x0e\xad\xc5\xe6\xd5\xb9\xb5\xe8\x4e\xfb\x97\x50\x3f\x1a\x59\xc2\xc1\x56\x8b\x31\xd8\x2a\x6e\x0c\xfb\x84\x5d\xa7\x24\x63\xad\x39\xb8\x9e\x66\x3b\xe4\xa0\x1d\x70\xa9\x6e\xe2\x8c\xf2\x00\xb3\x13\x91\xe3\x34\x4d\x61\xc7\x24\x6d\x77\x3b\x93\x41\xb4\xe4\xe5\x65\xb1\x91\xa2\xb5\x0e\xa5\x56\x1a\x73\xd3\xe4\x03\x4c\xdf\xf7\xbd\xfa\xb3\x88\x90\x6a\x25\x67\x98\x97\xdc\x4a\x3b\x69\x20\x88\x25\x45\xeb\xcb\xa4\xa8\x40\x13\xe6\xcc\xe1\x60\x0b\xea\x0f\xbb\x9d\x44\x49\x00\x94\x8d\xbb\x5d\x64\xce\x29\x73\xf1\xc4\x5b\xd8\x02\xe0\x0e\xe5\x09\x3b\x65\x01\x16\x92\xf0\xf1\xc4\xca\x46\xea\x82\x79\xde\x39\xf5\xe8\x75\x5b\x35\x8c\x8c\xd1\x45\x4d\x6c\x3c\xa5\x8d\x22\xb5\xe8\xa5\xcf\xba\x0c\x55\x32\xd7\x6d\x17\x1c\xba\x77\x98\xb7\x69\xf1\xa6\xb5\xf3\x9b\xd6\xe2\x70\xca\xed\x7d\x4e\x62\x9a\xfd\xa2\x73\x44\xde\x99\x88\xc8\x4b\x36\x0c\xe9\x1c\xec\x3d\xa3\x4e\xc9\x45\x70\x93\xf7\x2a\x9f\x8c\x97\xe2\x20\x01\xe9\xbc\xd2\x1c\xf0\x98\x3d\xa1\x05\x0a\x04\x11\x22\xd6\x1d\x24\xf3\x14\x3d\x36\xed\xd1\x73\x01\x88\x86\xe1\x34\x66\xae\x90\xab\x41\x53\xe1\xa4\xe4\x8b\x15\x16\x50\xa2\x0c\xc4\x40\x62\xc1\xa3\x38\x4c\xfb\x0a\xca\xec\xcf\x02\x2d\x30\x0b\xc8\x02\x51\x01\x6b\x8c\x79\x16\xce\x94\xae\x73\x1a\xd4\xc9\x9c\x1a\x27\xca\xa9\xdd\xab\xcd\x29\x20\xdf\x92\xbc\xe4\x06\x54\x53\x9c\x34\x5e\xb8\xd7\x3a\xf6\x46\x96\x2d\x77\xc7\x46\xda\xb8\x29\xeb\xb1\xd2\xf3\x1e\xd1\xae\x44\x34\x3f\x3b\x5d\xca\x04\x82\x2c\x65\x9b\x7a\x2e\x6c\x6a\xa1\xa3\x17\x3a\x23\x5c\xd2\x42\xe1\x10\x5b\xfd\x73\x1d\x45\x6f\x65\x44\x79\x0b\x6e\x49\xa3\x3e\xd8\xcf\x06\x08\x35\x58\xa4\x8e\xe1\xcf\xa2\x9f\x85\x4f\x32\x34\xc4\xa7\x24\x80\x71\xea\xa7\x13\xd9\xe4\xdb\xf1\x2d\xbe\x98\x78\xa3\x99\x4d\x80\x18\x7a\x31\xbe\x35\x26\xd5\x17\xeb\x40\xdc\x8e\xef\x22\xbc\xa5\xab\x9b\xff\x55\xd4\x9c\xa7\x29\x31\x34\x58\x61\x51\x73\x86\x67\x6f\xa6\x4e\x7d\xff\xe2\x3c\x67\x6d\x73\x19\xbd\x41\x6d\x8e\x72\xb9\xb4\x05\x39\x02\x7f\xde\x80\x44\x98\xf4\x39\x24\x3e\x9d\xde\x84\x02\xcb\x44\xe6\xef\x8d\xae\xb1\xba\xc9\x69\xcc\x16\x65\xb2\x40\xab\x2f\x7c\x52\xad\xd6\x5a\x60\x19\xa8\xb0\x1a\x5f\x02\x09\x87\x95\x47\x6f\xf6\x18\x6e\x82\x62\x01\xbc\x04\xaf\x0f\x58\x1c\xb2\x3c\x68\x75\x6c\xb7\x88\x16\x0e\x48\x4b\x76\x7d\xce\x37\x58\xa4\x9b\x15\xa2\xdb\x68\x2f\x30\x9b\x24\x72\xca\x49\x94\x3d\xcd\x41\xa0\xde\x17\xf7\x5a\xe6\x6a\xa7\xae\x5f\xd0\x28\x58\xc6\xd6\xe2\xaf\xad\x45\xe0\x6f\x2b\xfe\xb4\xa0\x75\xf2\xdb\x65\xe8\xe6\x3a\x2c\xda\xa1\x9b\x5a\xa8\xb7\xed\x23\x13\x98\x3c\xa5\xa1\x47\x14\x58\x8d\xa9\x43\x7b\x9a\x90\xcb\x18\xae\x5f\x9d\x34\x1b\x1e\x1d\x8e\x99\x8c\xaa\xda\xc4\xdc\xb1\x2e\x78\xaa\xf4\x55\xcc\xb2\x61\x89\xdf\x10\x15\x29\x2c\x23\x6d\x28\x25\x6d\x36\x3d\x73\xcc\x54\x4c\x79\x5e\xbc\x27\xd6\x0d\xfa\xea\x34\x9f\xc2\x75\xdd\x82\xc3\xf8\x97\xe9\x66\x99\x36\xfb\xaf\x9f\x57\x5c\xe5\x52\x05\xb0\x54\x43\x6b\x49\xfd\x91\xa0\x71\x43\x14\xd5\xf0\xde\x0e\xe2\x5a\xa1\x15\xbb\xa5\x5a\xa1\x2c\x59\x8a\xb2\xa5\x19\xb9\x51\x90\xf3\x3b\x76\xba\xe8\xb1\xdf\x23\x5a\xc7\xe5\xf1\xbc\x0d\xb6\xd3\x54\x46\xab\x8a\x23\x1f\xc9\x34\xaf\x77\xce\x51\x9c\x1a\xbf\x89\x37\x15\xcf\x50\x81\x7f\x2e\xc8\x2b\x0c\x51\x0e\x38\x0e\x4e\xbc\xb0\x35\x32\xa3\xb2\xc4\xcb\x8c\x52\x79\x4a\x0c\x26\xb2\x3f\x7b\xe5\x4a\xc5\xc7\x52\x63\xdd\x61\x0b\xa5\xf8\x44\x84\xfb\x1c\xe1\xd9\x4e\x64\xe5\x6a\xfd\xa7\x1a\xf3\xdf\x00\x4c\xb9\x4e\xc9\x61\x59\xd6\x82\x98\x15\xc4\x82\x38\xbb\x22\x9b\x1d\x4c\x33\x2a\x2b\xa7\x5c\x38\xb5\xaf\x98\x52\xa1\x3c\x06\x5a\x87\xc8\xfb\xc9\x56\x78\x94\x24\xcd\x63\xb2\xf0\x37\x94\x7f\x15\xf0\x29\x25\xd0\x5a\xfa\xde\xe4\x76\xc5\xe0\x96\xa4\xce\x30\xb8\xa2\x71\x8c\x2c\x89\x86\x5c\x99\xa4\x57\x95\x7c\x0d\xb1\x8e\x36\x53\xcf\x30\x8b\x3a\x42\x1f\xeb\x58\x45\x68\xe4\xc6\x1a\xa2\x46\x99\x8d\x96\xe6\xe3\x74\x4d\xf3\x0f\x9f\xbd\x76\xee\xea\x0d\x0f\x3d\xfb\xde\xcc\xb9\xd0\x21\x5a\x57\xca\x2c\x42\x48\x3f\xbd\xac\x62\x88\xf5\x82\xdf\x52\xea\xd8\x7a\x7c\xe3\x93\x21\x3b\x16\x43\x05\x78\x6e\x01\xbc\x6a\x2d\x6e\x2c\xfc\x17\x17\xff\x09\x00\x00\xff\xff\xce\xd1\xdd\x67\x19\x18\x00\x00")
+
+func fontsKbanFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsKbanFlf,
+ "fonts/kban.flf",
+ )
+}
+
+func fontsKbanFlf() (*asset, error) {
+ bytes, err := fontsKbanFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/kban.flf", size: 6169, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsLarry3dFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x5a\x5d\x6b\x5c\x39\x0f\xbe\x9f\x5f\xa1\x8b\xc0\x69\xe1\x10\xbd\x4d\xfb\x2e\x14\x86\x61\xa0\x17\x85\x65\xae\xf7\xca\xa0\x33\x6d\x27\xd9\xb2\xd3\xa4\x24\xcd\xee\x06\xf2\xe3\x17\xdb\x92\x25\xf9\xf8\xcc\x67\x92\x0d\x5b\x7b\x4e\xc6\x8f\x25\x4b\x8f\x3e\x7c\xae\xb7\xd7\x57\xeb\x0b\xf8\x08\xbf\xc1\xfb\xff\xc1\x3b\xf8\xff\x6c\xbb\xbe\xbf\x7f\x7a\xff\xed\xf2\x7a\x7b\x0d\x5f\x9e\x60\x15\xa7\xf0\x79\xb3\xfd\xb2\xb9\xbf\x81\x37\xe9\xe9\xcd\x72\xfd\xf7\xc3\xe5\xd7\xbb\x1f\x6f\x67\x6f\x1e\x7e\xdd\x6d\x37\xb7\xb0\xfd\xfe\x65\x73\xbf\xde\x6e\x9f\xe0\xfa\xfe\xee\x07\xfc\xfe\xb8\xbe\x85\x4f\xeb\xfb\xee\x01\x7e\x3e\x5e\x5f\x3f\xc5\xd5\xde\xce\x7e\xfd\xb3\x59\xff\xb5\xf9\x16\x97\xfd\xbc\xdd\xdc\xde\xc2\xa7\x3f\xd7\x3f\x7f\x6e\xb6\x5b\x98\xdf\xdc\x7c\x5d\x3e\x7e\x7f\xfc\x7a\xb9\xf9\xf6\xb8\x98\xfd\xb1\xb9\x7f\xf8\x7e\x77\x0b\xef\x2e\xaf\xe0\x0a\xaf\x3e\xe0\xc7\x0f\xb3\xd9\xc5\xc5\x05\xf0\xcf\x72\x06\x3a\x5b\xce\x40\x67\x71\x52\x66\x69\x22\xb3\x3c\xe1\x19\x4f\xf2\x4c\x26\x69\x56\x26\x71\xb6\x5c\xce\x80\x88\xd7\xc2\x00\x21\x8f\xe2\x20\xe4\x55\x78\x18\xbf\x15\x20\x50\xc8\xdf\x0f\x18\x28\xe4\x95\x02\x12\xea\x9a\x66\x94\x97\x76\xab\x5b\x00\x0a\x71\xb5\x8c\x81\x84\x48\xc8\x3b\x65\x41\x79\xa7\x32\xd3\x85\x1d\xca\x68\x12\x67\x0a\x1b\x1f\x52\x06\x4e\x9f\xc4\x6d\xc4\x41\xfc\x4d\x52\x05\xa4\x55\x7e\xbe\xa2\xb4\x12\x86\xf8\x77\xe9\x79\x92\x19\x09\xf3\x56\x45\x48\xde\xac\x87\x85\xd1\x54\x15\x2b\xc2\x8b\x22\x02\x76\x44\x43\xd0\xcf\x03\x6f\x25\xee\x91\x08\x42\x56\x49\xd6\x76\xde\x04\x0c\x81\x80\xd5\x3c\x04\x52\xe5\xb3\xfa\x15\x2c\xfe\x93\x84\x8c\xeb\x23\x20\xcb\x88\x3c\x91\x6d\xe6\x09\xcf\xd2\x84\xb2\xf8\x90\xff\x96\x01\xd2\xa4\x3a\xe1\xb1\xb0\xac\x73\x55\x39\x3e\x47\x0d\x06\x9e\x3d\x63\x1c\x3d\xcb\x17\x03\x22\x44\xf9\x31\xc9\x19\xff\x34\xac\x16\x00\x73\x5a\xce\xe0\x39\xab\x80\x30\x6b\x3b\x20\x4f\x6a\xc0\x11\x7c\xdb\x86\xf1\x42\x20\x93\x1d\x89\x71\x19\xcb\xba\x68\x5a\xae\xb3\xe1\x64\x0c\xf9\x53\xec\x64\x71\x0c\xd0\x63\xe7\x7c\x45\x9c\x65\x28\xde\x32\x04\xe2\x73\x1a\x42\x65\x31\x76\x58\x6d\x9f\x2d\x23\xc4\x7f\xf3\x52\x43\x1c\x67\xc7\x1b\x42\xdc\x43\x3e\xa8\x40\x7c\x2c\xd5\xe2\xd5\xf6\x2b\x4f\x80\xe2\x06\x03\x74\x20\x3e\xb0\x80\x78\x02\xe2\x00\x3d\xf4\xce\xfa\xad\xe9\x3b\xe5\xbb\x71\x05\x26\x27\x91\xf4\x42\xd9\xb8\xd9\xff\xa2\x77\x45\x80\x78\xbe\xc9\xce\x19\xc0\x10\xcc\x21\x60\xf2\x51\xf5\x7f\x86\x89\x6a\x8a\x36\x90\xcf\x9f\x9f\x4e\x1c\x81\x1b\x52\xfe\x91\xbd\x52\xd9\x6a\x32\xc6\xfd\x2b\xec\xdf\x1a\x2f\x88\xee\xa9\x2c\x41\xa4\x3e\xaa\xfe\x99\x8f\x3c\xfb\xb3\xf1\xe5\xec\xa0\x71\xd1\x3c\xd8\x65\xc5\xc6\x8c\x1d\xff\x20\x13\x7c\x00\xf9\x4f\x68\x5f\xf9\x27\xa8\xec\x49\x13\xfb\x4e\xa6\xe9\x32\xd4\x73\x50\x49\x66\x25\x51\x45\x31\xc5\x02\x8c\x01\xec\x52\x31\x79\x89\x54\x24\x0a\x50\x64\x8a\x64\x8d\x80\x85\xdd\xe2\x98\xa5\x92\xd3\x35\x54\x53\xd3\xfa\x38\xb4\x4c\xa9\x91\xc2\xca\x40\x52\xa0\xe2\x4d\x90\x9e\x9c\xa2\x46\x17\xc6\x4c\xf8\x94\xb3\xf2\xbc\x13\x72\x88\x29\x40\xd0\x0b\xfb\xb0\x17\xab\x36\x73\x40\xd8\xcf\xa9\xc2\xe9\x09\x3d\xce\x83\x82\x13\x61\xc1\x8e\xca\x1f\xf2\x11\x06\x2b\xb0\x97\xb8\x25\x72\x33\x78\x0b\x68\x3e\x56\x13\x28\x19\x32\xc9\x2d\x88\x69\x33\xa7\x6b\xb8\xf6\x75\x00\x71\x76\xc4\x0e\x3b\x76\xc0\x2e\xfe\xa6\xe3\x4c\x23\xe6\x37\x75\xb9\x18\xd3\xc6\x00\x63\xaf\xb0\xb6\x03\xc6\x05\x8d\xed\x2c\x80\xe0\x05\x6c\xc7\x53\xb1\xa0\x39\xb8\x92\x72\xf4\xec\x8a\x71\xd9\x1e\xd5\x19\xbd\x3b\x36\xf2\x80\x86\x7b\x98\x4f\x25\xae\x49\x3a\xc2\xae\x21\x41\xa6\x04\x98\xd1\xf7\x8e\x5b\xa8\xe8\x47\x74\x53\x2f\x44\xc5\xf9\x81\x89\x34\x0d\xe2\x72\x73\x80\x39\x2b\x62\x48\xbf\x29\xda\xc6\xc0\xfd\x2c\x71\x7b\x47\x64\xb5\x7a\xa0\xe2\x2d\x26\x6c\xf0\x56\x33\xb3\x14\xc1\x25\xa4\x14\xd2\xd9\xa9\xd5\x5a\xc5\xad\x54\xc1\x6d\x7e\x01\xb0\xa8\xc4\x0d\xe2\xee\xd9\x4e\xf7\x64\x3a\xd9\x60\x72\x1a\x93\xa2\x7f\x18\x38\x5e\x15\x8f\xc0\x63\x0b\x81\x4a\x20\x63\x9b\x19\x8b\x04\x37\xce\x20\x94\x4c\x2e\x9b\x6a\x76\xf9\x98\x4e\xe5\xbc\x24\x8f\x45\x8b\x83\x70\x77\x43\x57\x44\x56\x5f\x51\x3e\x5b\xe1\xac\x5c\x95\x03\x29\xf7\x16\x02\xe5\xb8\x58\x68\xcc\xb8\x42\xe2\xd3\x03\x72\x62\x97\x12\x27\xca\x1a\x83\x17\x6c\x98\x77\x0a\x7d\x0e\x81\xee\x46\x15\x0f\x62\x11\xc5\x2c\x5f\x1d\xd5\xc8\xaa\xf1\xde\x25\x19\x2f\x8f\xba\xb2\xb2\x02\x85\x15\xbc\xac\xac\x06\xd3\x20\x2a\x1e\xaa\x29\x59\x3b\x52\x23\xda\x59\x11\x1c\x2c\x59\x58\x91\x95\x0c\xfb\x73\x24\x03\x5f\x4a\x55\x2d\x01\xaa\x1c\x06\x9c\xc3\xc0\x4b\x38\x8c\x81\x27\xae\xd2\x4d\xca\xa8\x55\xab\x2d\xbb\xe2\x34\x57\x18\x3c\x43\x43\x0f\x9a\xdb\x1d\x04\xaf\xe0\xa4\xd9\xaa\x4d\x57\x49\xe5\xc4\x33\x72\xe4\x7d\xaa\x8e\x54\xa8\xaa\xee\x53\x9c\x52\x55\x87\xc1\x64\xcf\xa7\xa9\x5a\x9f\x95\x4a\x0d\x6c\x39\x6b\xfc\x55\x9a\x03\x67\x7b\x8e\x7f\x86\x5d\x20\x34\x79\x49\xfa\x71\x29\xa6\xa3\x0d\x42\xc3\x1b\x14\x54\xe8\xe4\x4a\x87\x0a\xbd\x43\xe7\x43\x70\xe6\xdd\xc3\xe0\xcc\x7b\x78\x11\xf3\x36\x4a\x07\x6a\xb1\xa4\xa7\x49\xcf\x93\x60\x15\x7f\x8a\x79\xc3\x04\x6d\x81\xd0\x56\x2f\xf5\xd0\xe9\xb4\x75\xba\x88\xa1\x0b\x4e\x44\xab\xe1\xd4\x74\x3b\x3c\xe2\x7a\xda\x6c\x07\xfc\x1e\x4a\x4b\x4c\xeb\xa9\xe9\x03\x86\x33\xe1\x7b\xa6\x6d\x4e\xb5\x43\x21\x18\xd0\x54\x5f\xe0\x73\x7e\x73\x0a\x7f\x51\x45\x9e\x96\x3a\x2d\x71\xf2\xd2\xa6\xf6\xf6\xd9\x7e\x6d\xd0\xc7\xf2\x17\xbc\xb6\x31\x0b\xbc\x43\x77\xe0\x13\xf9\x06\x16\xfe\x4a\x5a\x66\xa8\x94\x45\x1e\x12\x1f\x01\x3c\x72\x9c\x79\x74\x6c\xef\x60\xb4\x0b\x93\xf9\xa4\x9d\xfc\xab\xbb\xe9\xd8\xe2\xc7\x7d\xe6\x5a\x19\x76\x67\xbe\x0b\x6a\x0f\x64\x08\x83\x89\x28\x43\x40\x58\xe4\x88\x52\xdc\xba\x43\x8d\x29\x29\xbf\xaf\xec\xbf\x41\xb0\xf5\x4e\x54\x43\xa5\x05\x27\x05\x5a\xde\x41\x44\x91\x0a\x4b\x2a\x6a\x18\xce\xb1\xc1\x51\xc6\x90\x4b\x78\x28\x81\x9b\xeb\x78\xfd\xb2\x4c\x45\xd2\x54\x72\x10\x81\xcf\x1c\x6a\x7b\x1c\x59\xe4\xf8\x18\x1c\x01\xb0\xfb\x3b\xea\x03\x17\x52\xad\x33\x80\x23\x3d\x1b\x4f\xf7\x79\x60\xc1\x2a\x2c\x3b\x94\xb2\x70\x90\xb1\xb4\x90\x07\xe9\x21\xfb\xc6\xf4\xae\x2e\x5b\x9d\x8f\xf9\x6c\x0c\x9a\x94\xa2\xbe\x9d\xb5\x79\xb0\x40\xae\x65\x01\xa6\x63\x41\x28\xc4\x19\x10\x63\x0d\x9b\x9b\xf9\xee\xa2\xa8\x75\x4f\xb4\x13\x6c\xef\x1f\x4d\x8e\x0b\x6e\xda\x84\xb6\x90\x5c\x71\xaf\xb5\xfd\xe4\xf5\x44\x28\xd7\x13\x78\xce\xf5\xc4\xd4\x7e\x27\x1b\xbe\xab\x70\x19\x48\xba\x3f\x78\x19\xca\x7e\x47\x59\xcc\x94\xc9\xb5\xb3\x46\x12\x3f\x8a\xb3\x0c\xd9\xce\x1a\xfb\x93\xb2\x46\x3f\x92\x48\x27\x4d\x42\x6d\x11\x96\x9b\x34\x3d\x86\xe9\xbe\x84\x51\x92\xba\xa5\xa9\x73\x7c\x3f\x42\xbb\x11\x54\x7a\x11\x18\x47\xb0\xb3\x53\xdd\x3a\x40\xbb\xfd\x21\x94\x6c\xe9\xc8\xed\x83\xa8\xbc\xad\x05\xe9\x01\x73\xc8\x59\xd6\x97\xb8\xbb\xee\x8d\x0e\xb3\xab\x66\x17\xd3\x5f\x64\x12\x51\x39\x7d\xb4\x45\x12\xe5\xf8\xe6\xec\xca\x1b\x96\xb1\x2c\x50\xf6\x04\x32\x97\x6c\x2f\x51\x77\x96\xcf\x4d\xf9\x27\x7c\xe3\xe3\x78\xd1\x60\x51\xa0\xfd\x7a\xeb\xcc\x2d\x7f\x16\xf6\x0c\xe3\xdb\xf5\x52\x56\x6a\x51\x69\x0a\x2c\xf1\x93\x03\x74\x85\x9d\xbd\x15\x78\x85\xc2\xd1\x84\x1d\xbd\xe4\x8d\xc4\x5c\x85\xb5\x12\x1d\x12\x0c\x98\xf3\x2f\xda\xdb\x1b\x11\x26\xb7\x52\x38\x40\x8b\x9a\x2e\x16\x1b\x5c\x70\x68\x52\x88\xea\xb2\x56\x62\x11\xf7\xb0\xac\xa6\xf1\x48\x39\x88\xb1\xc1\xe3\x5a\x4c\x83\x77\x24\x4d\x28\xcb\x81\xd2\x04\x93\x69\xc3\x3c\xf6\xf8\xb2\x1f\xda\x6a\xa1\xd0\xf5\x69\xf5\xe0\x0e\xfe\x9e\x8d\xae\x22\xe8\xc0\xab\x08\xda\x77\x15\xd1\x70\xbd\x19\x50\x79\x05\x62\xe8\xf2\xcd\x6d\xd9\xb9\xee\xdb\x33\xdf\x84\xe7\xfa\x63\x10\x9a\xed\x85\x66\xe3\x66\x73\x63\xfc\xd0\x63\xf0\x97\x79\xac\xfb\xac\x64\xdb\x93\x75\x99\xa1\x26\x86\xb6\x14\xde\x6b\x45\xa3\xa3\xd6\x37\x43\xac\x79\x96\x1a\xc4\xf6\x72\xc6\x31\xf9\x5c\x0c\x84\xe7\x82\x81\x72\x00\xd5\x15\xe4\x04\x06\x34\x3d\x5f\xb0\x3c\x5e\x85\x29\x95\x5e\xc6\x4d\xc5\x55\x57\xb0\x47\xf8\x2d\xa0\x09\x73\xe0\x17\x88\x18\xb8\x4b\x98\xb8\x00\x98\x23\x27\x81\x28\x3e\x8f\x47\xdc\x89\x34\xc4\x83\x66\x71\xab\x5d\x31\x1c\x34\xce\xc2\x90\x8e\x6d\x01\xe2\x24\x68\x8a\x5b\xd6\xf7\x6e\x2e\x80\x42\xea\xfd\x50\x1a\x07\x00\xee\xe2\xca\x5c\x5b\xed\x31\x42\x21\xfc\x4e\xda\xa3\x7d\xd2\xfe\x9c\xdf\x39\x99\x83\xd4\x23\x5a\x8d\x78\xd3\x76\x5e\x59\xbd\x4a\x25\xe3\x52\x4b\x41\xb3\xb0\x02\x0d\x75\x07\xb7\x3c\x5c\x16\xc0\x9c\xce\xef\xe2\xc8\x0b\x3e\x8b\x78\xca\xe9\xc5\x86\xcc\x03\xa9\x92\xcd\xca\x9a\x24\x15\x72\xb7\x6b\x10\xf8\xbd\x08\xa9\x6e\x08\xf3\xdb\x6f\xd9\x64\x08\xb9\x0a\x28\xef\x03\x56\xef\xbf\xd5\x71\x79\x6f\xcc\x06\x9f\x87\xf8\x5c\x44\xae\xc5\xec\x6d\xba\x6a\x11\x8a\x85\x65\x6d\xe1\x49\xbd\xe6\x9d\xf0\xe4\xe0\xf1\xd5\x5a\x45\x4d\xf8\xd7\x6f\xbb\xee\x80\xcf\x0a\xa4\xf2\x45\x2d\x37\x26\x9a\x82\xbd\xc0\xc7\xca\xbd\x3f\xba\x51\x56\xd0\x15\xdc\x61\xd7\xd0\x06\xf9\xe8\x46\x99\x4b\xa6\x6b\x54\xee\x79\xa0\xbd\x67\xb5\x01\xe9\x44\xd4\xaa\xc7\x4d\xa3\xb6\x5c\x39\xe6\xb9\xbc\xa1\x53\x0e\x5d\xa9\xc2\xbf\x90\x56\x50\x1b\xaf\xcd\x2c\x97\xb3\xff\x02\x00\x00\xff\xff\x1d\x76\x41\x67\x61\x2c\x00\x00")
+
+func fontsLarry3dFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsLarry3dFlf,
+ "fonts/larry3d.flf",
+ )
+}
+
+func fontsLarry3dFlf() (*asset, error) {
+ bytes, err := fontsLarry3dFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/larry3d.flf", size: 11361, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsLcdFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x57\x4d\x8b\xdc\x30\x0c\xbd\xe7\x57\xbc\x43\x6e\xc1\xb8\xb3\xa5\x85\xde\xe6\xde\xfd\x09\x81\x30\xed\x76\x4f\xdb\x29\x2c\xb4\x50\xd0\x8f\x2f\xd3\xd8\xb1\x2d\x45\x96\x92\xb9\x98\x64\xf2\x2c\x3f\xe9\xe9\xc3\xaf\x6f\xaf\x4f\xb7\x11\x9f\xf1\x09\x97\x0f\x08\x17\x3c\x0d\xcf\xdf\x5f\xf0\xed\x2f\xbe\xde\xde\xdf\xf0\xe7\xd7\x1d\xcf\xb7\xdf\x2f\x3f\xde\x7f\xde\xee\x77\x5c\x2e\xf1\xcb\xc7\x61\x18\xff\xff\xae\xde\xf5\x3a\x8c\x00\xf0\x78\x01\x4a\xeb\x94\xd6\xfc\x3e\xd4\xcf\x2d\x80\x9a\x0f\x77\xd7\xeb\x30\x2e\xcb\xf2\x78\x41\x09\x40\x61\x0a\x54\x3d\x8f\x21\x04\x15\xf0\x58\x11\xa6\xd0\x58\x94\x80\xd5\x24\x81\x62\x03\x88\xdb\x11\x03\xe7\xb0\xd4\x3b\x66\x40\xb6\x28\x2d\x14\x52\xb1\x43\x76\xdf\x42\xeb\xd6\xfc\xcc\x8f\xb4\x68\x71\xc8\x47\x92\x16\xd6\x17\xf3\x4a\x7a\x2c\xa4\x67\xed\x48\x6c\xc7\xe2\x56\x03\xc0\xd6\xa8\x93\x6e\xff\xd8\x2c\x78\x01\x62\x55\xc5\x97\xe3\x30\x19\x47\xda\xb4\x84\xb8\x8a\x6e\x5a\x45\x18\xd1\xd7\x92\x1e\x07\x45\xad\x8f\x17\x54\x91\xa6\xcd\x09\x4e\x40\x79\x56\xc4\x47\xee\xc0\x15\xd2\x22\x0e\x46\xc6\x25\x4b\x15\x87\x2e\xe0\x4c\x1c\x58\xc6\x39\x8e\x94\xbd\x44\x1e\x2f\x49\xaf\x98\xf2\xa6\xc3\xf2\x8e\xac\x54\x5a\x19\xa7\xe4\x83\xca\x61\x06\x4e\xb9\x75\x04\x97\x06\x4f\x20\x21\xbe\x75\x75\x14\x63\xb0\xea\x8d\xbd\xf2\x5f\x5b\x20\x71\x24\x9f\xf8\xd8\xda\x11\xdf\x66\x21\xad\x5e\x0b\xde\x14\x55\x01\x56\xc6\x11\x2c\x79\x57\x24\x0f\xbb\xd5\x57\x97\xaa\x1d\xea\xc4\xf1\x1c\x29\x26\xd2\xf9\xb9\x2f\x6f\x7f\xe0\xf2\x07\x33\x2b\xc6\x2a\xe9\x02\x00\x03\xcc\x5d\x2f\x11\x23\xeb\x2e\x33\x87\x22\xcd\x2c\xcc\x47\x2d\x28\x6e\x3d\x5b\xbd\x3b\xb3\x86\x1e\x38\x9f\x97\xb8\x34\x92\x05\xb2\x4a\x65\xd9\x79\x6b\xbb\x4a\xe0\x4a\xe5\xe3\x0d\xc5\xa8\xad\x1c\x60\x35\x45\xb5\x65\x49\xd2\x96\x5b\xbd\xd5\xbb\x13\x69\x18\x39\xad\x77\x20\xdf\xec\x6d\x0d\x58\x76\x07\x3a\x6a\x21\xf0\x61\x45\xe1\x50\x6a\x2b\x07\xb8\x2d\xc0\x06\xe4\xf1\xbf\xe9\x0f\x3b\xd7\x81\x7d\x0b\x45\x1a\xc2\x42\x2b\x0d\xc7\x28\xcd\x5a\x16\xda\x69\x46\x3b\x92\xea\x25\x69\x61\x61\x7f\x98\x45\x60\x1f\xe0\x88\xc3\xa6\xd6\x4c\xda\x79\xe1\x90\x09\xd4\x8f\x34\x05\x6c\xd7\xb2\x7e\xd5\xf0\x7b\xc9\x52\xab\x48\xd1\xf6\x03\xe2\xe2\x3b\x11\x69\x2f\x07\x7f\x4e\x07\x56\x66\x8c\xc9\x58\xaa\xd5\xc8\x07\x38\x73\x5a\x00\xbc\x37\x45\x7f\x7f\x28\x81\x6b\x39\x04\x8d\x83\x6c\x28\xc7\xa4\x51\xfa\x43\x27\xd2\xc9\xad\x3c\xe3\xac\x1b\x8a\xd9\xb2\xd4\x8c\xeb\xa7\x28\xcd\xbb\x3b\xee\x5a\x58\x67\x8d\x39\x8b\xcf\x9a\xf9\x12\x00\xe9\x0f\xc7\x3d\x0e\x4b\x1b\x69\x73\x22\x6b\x01\x76\x43\x31\x01\x0a\x07\xbf\xbc\xe5\xcc\xd7\x92\xe6\x91\xfe\x17\x00\x00\xff\xff\xc6\xce\x60\x5b\xbb\x13\x00\x00")
+
+func fontsLcdFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsLcdFlf,
+ "fonts/lcd.flf",
+ )
+}
+
+func fontsLcdFlf() (*asset, error) {
+ bytes, err := fontsLcdFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/lcd.flf", size: 5051, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsLeanFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xdc\x5c\xdd\x6f\xda\xd8\xb7\x7d\xe7\xaf\x58\x0f\x96\x7e\x2f\xd3\x26\x38\x09\x49\xa4\xab\x2b\x28\x71\x13\xab\x04\x67\x0c\xb4\xd3\x27\x8b\x36\x4e\x83\x86\x40\x14\xc8\x8c\xfa\xdf\x5f\xf1\x65\xef\xaf\x63\x6c\x02\xd1\xd5\xaf\xf3\x30\x26\x80\xcf\x3a\xfb\xec\x8f\xb5\xd7\x39\xe6\x61\xfc\xe0\x0f\x3d\x5c\xa0\x01\xff\x1c\xc7\xa8\x1f\xe3\x18\x67\xe7\x8d\x5a\x27\x1d\x4e\xf0\xe3\x37\xae\xc7\xe9\x64\x82\xf6\xe3\xf0\xf9\x39\x1d\x8f\x71\x7a\x74\x79\x82\x0f\x1f\xf0\x63\x38\x4b\xef\x31\x9d\xe0\x9f\xe1\xcb\x68\xfa\x3a\xc3\xc7\xd9\xe8\xd7\x7f\x66\xb5\x70\xf2\x73\xfc\x7a\x9f\xce\x10\xf6\x22\x74\x86\xf3\xd1\xe4\x43\xbd\xf6\x30\xfa\x35\x4e\xe7\x78\x49\xc7\xe9\x70\x96\xc2\xff\x58\x5f\xdc\xa2\xee\xa3\xf5\xfa\x0b\xf5\xcb\xcb\xd3\xda\x5d\xfa\xf2\x34\x9a\xcd\x46\xd3\x09\x46\x33\x3c\xa6\x2f\xe9\x8f\xdf\xf8\x35\xfa\x27\x9d\x60\x3e\xc5\xd3\xf4\x7e\xf4\xf0\x1b\xf3\xc7\xd1\x0c\x0f\xd3\xc9\xfc\x0f\x0c\x67\x18\x4f\x27\xbf\x16\xff\x9f\x3f\xa6\xb5\xe5\x07\x46\xe9\xcb\x7f\x66\x98\x0c\x9f\xd2\xc5\x3d\x9e\xc7\xc3\x9f\x2b\x84\x43\xfc\x9c\x3e\x3d\xa5\x93\x39\xc6\xa3\x49\xfa\xb1\x56\xbb\x5d\x7d\xfa\x7e\x31\xbd\xbb\xe1\xeb\x18\x9f\x5e\x5f\xe6\xd3\x09\xfe\x67\x36\x1d\xbf\xce\x47\xd3\x49\x33\x1d\xbe\xcc\x1f\xc7\xa3\xc9\xdf\x1f\x27\xe9\xfc\x7f\x51\xf7\x8f\x2e\x1b\x0b\x20\xa3\xd5\xec\x30\x49\xff\xc5\xf3\xf0\x65\xf8\x94\xce\xd3\x97\xda\xec\xf5\xf9\x79\xfa\x32\x5f\xdd\xf0\x73\x78\xbd\x98\xeb\x70\x72\xbf\xb8\xfc\x36\x9a\x7c\x04\x6e\x87\xbf\x31\x1c\xcf\xa6\xf8\x91\x62\x36\x1e\xfd\x7a\x9c\x8f\x7f\xe3\x69\x83\xe2\x61\xfa\x82\x1f\xe9\x7c\x9e\xbe\xe0\x75\x96\xd6\xa6\x0f\xcb\xdb\x3f\xbc\x8e\xc7\x1f\xfe\x1d\xdd\xcf\x1f\x8f\xfe\x4e\x5f\x26\x47\xb3\xa7\xd7\xd9\x23\x86\xe3\x79\xfa\x32\x19\xce\x47\xff\xa4\xb3\x3f\xf0\xe3\x75\x8e\xfb\xf4\x61\xf8\x3a\x9e\x63\xfa\x3a\x7f\x7e\x9d\x2f\x66\xde\x8d\xfa\xf8\xf9\x38\x9c\xfc\x4a\xef\x3f\xd6\x6a\x58\xfd\xf3\x00\xaf\x59\xcb\xaf\xb1\x7e\xb1\xbc\x5e\xbf\x58\x5d\xaf\x5e\xac\xaf\x97\x2f\x36\xd7\x8b\x17\xd9\x35\x9a\xb5\xfc\x1a\xcd\x66\x36\xd0\x7a\x98\xe4\x68\x33\xc8\xf2\x6a\x79\xb9\xba\x5a\x0f\xb0\xbe\xfd\xfa\x6f\xab\x9b\x67\xb7\x06\xd8\x8d\x93\xa3\xd5\x97\xd7\x37\x21\x37\xc7\xfa\x56\x4b\x9c\x19\x9a\xfc\x56\x4b\x9c\x5e\x7e\xbb\xfc\xce\xf2\x05\x7b\xb5\xf8\xfe\xfa\x0f\xeb\xf1\xb0\x19\x7d\xf3\x1f\x99\xde\xfa\xfd\xd5\x74\xc8\xfb\xcb\x21\xe8\xfb\xf9\x98\x14\x2b\xff\x47\x81\xe4\x28\x08\x04\xb0\xf1\x97\x97\xf9\x22\x92\x91\x09\x8c\x0d\x8e\xdc\xd4\xd4\x40\x0a\x42\xbe\x86\xcb\x2f\xb1\xb5\xe4\xd3\x25\xd8\x88\xf3\xac\x3e\x93\x8f\xbd\xb9\x0b\x5d\x6b\x32\x45\xdb\x0e\x0c\x98\x47\x8d\x97\xcd\x84\xb8\x03\x98\x75\x32\xc8\x19\xfe\x0d\x5e\xf2\x2e\x1d\x93\xdd\xdf\x00\xb0\x71\xbe\xec\x5e\x9b\xf0\xf1\x94\x3d\xdf\xe6\x7c\xf6\x40\x64\x19\x41\x8d\x98\x5d\x6f\xa6\x6a\xbe\x43\xc1\x19\xee\xc4\x57\x98\x05\x2c\x84\xa9\x28\x0e\x0a\x84\x8c\xcd\xe7\x5f\xe8\x5c\x3a\x96\xd7\x2e\x8b\x3c\x61\xc8\x68\xe2\x9f\xd9\x8c\x4d\xd6\x74\x07\xe7\xca\x12\x88\x9a\x2f\xf1\x2c\x3b\xf0\x29\x54\xb0\x90\xa6\x3e\xe0\x1a\xb8\xdc\x95\xe7\xe5\xe6\xce\x4d\x9d\x9b\x59\x9a\xb8\xe8\xa5\x67\xce\x44\x5b\xa1\xc4\xad\xf2\x81\xdd\xff\x5b\x0d\xb7\x1a\x86\xdc\xde\xed\x14\x9b\x7f\x12\x9b\x99\x71\xc8\x72\x53\x07\x94\x0e\xb9\xf9\x94\xe7\xa1\x68\x36\x50\x19\x87\xa5\x1b\x59\x7a\x72\x97\xcb\x5c\xd0\x93\x89\x56\xe6\x05\x6b\x20\x59\x2f\x37\xce\xce\xeb\x25\xcb\xa5\xdb\xeb\xa5\x9e\x44\x56\x27\x88\xeb\xca\xa0\xa7\x55\x64\xf5\x75\xd0\x92\xc6\x0b\x58\xe6\x7d\xce\x9c\xc9\x00\xe4\x51\xcb\x57\x95\xbe\xcf\x97\x18\xb2\x90\xf1\x0a\xea\x2c\xa0\x3c\xb0\x1d\xcb\xc6\x42\x9a\x05\xb4\x0c\x67\x16\xcc\x45\x8c\x81\x55\x4d\x23\x4f\x88\xa4\x46\xeb\x25\x58\x6a\xe5\xd3\x55\xf3\x2d\x66\x0c\x34\x96\x04\x4f\x60\x28\x04\x08\xe2\x10\x20\x75\x92\x41\x70\x23\xb0\x2d\xe1\xca\x33\xac\xbc\xf0\x62\x0e\x5e\x48\x44\x14\xab\x18\x2e\xb6\x84\xc7\xca\x0a\x8d\x61\xcd\x68\xf2\x38\xe6\x51\x27\xdd\xce\xe5\x75\x3b\x86\x5d\x1e\x58\x7b\xf4\x7a\xbb\x6e\x80\x66\x78\xcf\x63\xb9\x84\xd4\x92\x9a\x3d\x23\x15\x53\x50\x49\x9a\x96\x0f\xcf\x93\x24\x41\xf2\x13\x9b\x7e\x5a\xf7\x16\xcb\x43\x19\x0e\x6c\x56\x54\x32\x5e\x95\x11\x8b\xdd\x76\x33\x43\x8b\x93\x90\x59\x1b\x4e\xe9\xf6\xd2\xdc\x66\x9c\x56\xf2\x4c\xb9\xdd\x16\x8e\xd0\x34\x5b\x09\x95\x87\x5d\xad\x04\x49\xf1\x84\xdc\x48\x7e\x57\xb3\x67\xc6\xed\x4a\x3e\x46\xcc\x97\x83\xc8\x92\x13\x87\x03\x52\x38\xb2\x30\xc9\x09\x3f\x2b\xbb\xf4\xd3\xcc\x35\xe8\xbd\x59\x46\xcb\x91\x10\xb2\xbc\x4b\x1c\xd3\x9b\x64\x03\x2a\x60\xfb\x2c\x9f\x26\x00\x92\xdb\xb1\x9f\xf2\x59\xbe\x98\x90\x3c\xbd\x99\x31\x5b\x02\xa3\xf7\x73\x71\xf3\x1d\x2d\x00\x08\x1f\xd9\x97\x05\xaa\xd6\x75\x9e\xa0\x40\x1b\x15\xd3\x0e\xee\x26\x65\xcf\x40\x68\x59\x2d\xa4\xc6\x7b\x22\x18\xe0\x62\x04\x34\xc1\xd8\xd1\x27\x78\x0f\xa9\xf2\x23\x28\x81\xd6\x5a\x8c\xaa\x49\x46\xe7\x58\x72\x49\xf8\x82\xc8\xf4\x4d\x52\xbb\xd9\xa9\x70\x85\x46\xba\x65\x21\xc1\xe0\xfd\x92\xa8\x54\x6e\x42\x61\x2c\xc1\x1b\x39\x9e\xbd\x04\xb2\x85\x97\x65\x5b\xb6\xef\x3b\x2e\x81\x27\x4d\x2c\x18\x07\xa4\x56\xb2\xfe\x9a\x66\xfe\xb0\xda\xdf\x62\xe9\x42\xce\x9a\xfa\x7b\x93\xe8\x52\xd2\xf9\xb4\xfb\x59\xb3\x2f\x2d\x5d\x94\x03\xc6\x63\xc2\x06\x96\x28\xc1\xee\x6d\xc0\xca\xd0\x6f\x8e\x6d\xef\xf4\x7b\x87\xaa\x09\x8b\xf2\xe8\x1c\x59\x18\x1d\x65\x67\x9e\xbb\x4b\x42\x65\x4a\xa1\x52\xe6\x77\xf6\xbc\x43\xce\x7c\x2f\x84\x85\x53\xf8\xa2\x22\xc5\x32\x83\x4c\x56\x6f\xef\x82\x6d\xa1\x2b\x29\x90\xec\x38\xc7\x65\xcb\x2f\x56\xbf\x54\x6a\xae\x48\x50\x70\x80\xf6\x9b\x98\x54\xa5\x1f\x15\xe3\xe6\x4e\x85\x20\x76\x0c\x45\x09\xc2\xa2\xc1\x58\x80\x34\x28\x9d\x08\xe0\x00\xa7\x01\x62\x1b\x48\x1b\xa8\x3b\x83\xea\x92\x06\x2e\x54\xa8\xb2\xb7\xb7\xd4\xbe\x96\x4f\x95\xd5\x78\x7d\x85\x29\xfb\xbf\xcd\x89\x0d\xb6\xb9\x93\x24\x0b\x4d\x7f\x77\xb5\xc8\xea\x9b\x9c\x61\x71\x82\xc5\xca\xbf\x88\x70\xb9\x01\xc6\x9a\x3e\xe6\xd8\x4d\xf2\x92\xf4\xd9\xe4\x06\xc4\xec\x84\xd2\x11\x2c\x24\x59\x91\x19\xd9\x33\x11\xf4\x8d\xe5\x7c\x26\x31\xb8\x66\xb9\x6d\x26\x14\x5f\xf2\x2e\x7b\xa7\xca\xb7\x76\x79\x69\x95\x1b\x9d\xd4\x4b\xd9\xdf\x53\x3a\x09\x99\x17\x5d\x20\x63\xad\x2c\x90\x16\xed\xdf\xce\x64\x64\x41\xb5\xeb\x69\x53\x24\x31\x96\x95\x08\xa7\x2b\xcb\xa8\x74\x91\x2d\xd7\x60\x94\x9d\x31\xc0\xab\xc9\x5b\x66\xcc\x86\x02\xf8\x6a\x56\x92\x58\xde\xd2\x5c\xf2\xb4\xc4\xa9\x4a\x76\xeb\x35\x30\xd5\xf3\x26\x52\x16\xb4\x34\x41\xbb\x89\xcc\xf8\xa0\x62\x2a\x44\xd4\x52\x4c\xf5\x6d\x49\xde\x61\x7a\xa3\xaf\x77\x99\x1e\xd6\x4a\xcb\xec\x94\x6b\x0f\x7b\xf6\x6e\xc8\x24\xe9\xb0\x78\xe1\xf9\x94\x3c\x51\x30\xc6\x21\xcd\x5b\x6e\xbf\x2d\x7f\x29\xeb\x65\xe1\x26\x33\xb7\x06\xaf\xa2\x54\xb7\xb1\x4f\xdc\x28\x4b\x52\x4a\x62\x68\xbb\x84\x43\x70\x2b\x5a\xf7\x2c\x63\x42\xd6\x5d\xbe\xcd\x84\xd9\x5f\xd5\x1f\x3d\xe1\x20\xa6\x9b\x58\xce\xb2\x95\x5f\x8a\x51\xca\xb2\x46\xfa\x52\x82\x3b\x90\xf7\xca\x71\xed\x0c\x45\x06\x55\xd1\x2b\xca\x81\x9d\x14\xb7\x6d\x95\x78\xc6\x89\x0d\xea\x81\xdb\x14\x39\xc1\xa9\x0a\xb4\xc9\x43\xd7\x61\x67\xb4\x95\x4a\x95\xa4\x8b\x27\x41\xe6\x96\xc5\x77\x55\x14\x9c\x00\x54\xae\xe6\x1d\x2e\x95\x75\x76\x96\xc1\xd9\x66\x1e\xc0\x05\x34\xb1\x88\x59\x49\xa4\x12\x8e\x16\x70\xca\xb3\x47\x6f\x27\xd5\x68\x27\xe6\x61\x9a\x58\xb4\x5f\xb2\x89\xe6\x7d\x5f\x53\xb4\xcc\xcd\x1a\x6f\x46\xb7\xae\xb1\xeb\x83\x36\x20\x07\x30\x1b\xa0\x0d\x14\x06\xe0\x7c\xb8\x2d\x78\xaa\x44\x89\xe2\x72\x87\x51\x9f\x4a\x01\x38\x0c\xa3\x29\x06\xa0\x3a\x68\xd6\x3e\xb3\xa0\x49\x76\x3c\x6f\x93\xb8\x8e\x0e\x6e\xdd\x3e\x77\x69\x08\x4d\xf3\xe8\x20\x68\xf7\x2a\x74\x92\xaa\x8a\xbc\x95\xf7\xc5\x19\x45\xd0\x71\xf9\xae\xb8\x7c\x57\xee\xa6\x83\x9b\x40\x73\x28\xc1\x96\x19\x6d\xca\x4f\x16\x1e\xec\xb8\x67\xee\x79\x45\xe5\x55\x88\x0e\x2a\xd5\x31\xa2\x65\x4a\x4e\xdb\xf6\x52\x1c\x38\x14\xb9\x28\x15\xaf\xbb\x48\x97\xc5\x00\x8a\xe3\xf5\x1d\x00\xe0\xf0\xdd\xe7\x7f\xdf\x12\xec\xda\x7f\x7b\x2c\xa6\xb7\x71\xcb\xe2\xf0\x30\x62\xdf\x19\xfd\x4b\x20\xf5\xc6\x31\xd0\x8d\x3e\x7c\x8a\x83\xd6\x17\xf4\xee\x5a\xed\x20\x0b\xa2\x83\x3f\x41\x51\x6f\xd4\x81\xb0\xfb\x35\x88\xfb\xc1\x15\x82\xbf\xda\x9d\xd6\x6d\xab\x1f\x46\x5d\xdc\xb6\xe2\x2f\xee\xee\xeb\xad\x0d\x6c\xbd\xe1\x03\xed\xa0\xdb\x47\x2f\xbc\xee\x1a\x4d\x0d\x44\xf2\x95\x84\x9b\xd7\x18\x4e\xef\x79\x25\x93\x7e\xc9\x8e\x81\xd5\x1b\x27\xc0\x5d\x34\xe8\x5e\x49\x20\x12\x8c\xf4\x0c\xcb\x37\x34\x17\xde\x30\x1e\x90\x5d\x36\xc9\x25\x69\x63\x69\x13\x9f\x25\xd0\x53\xa0\x3d\x88\xe3\xa0\xdb\xfe\x6e\x61\x05\x67\xe8\x39\x68\xf0\x13\x45\x89\x3c\x71\x65\x66\x70\xf1\x47\x70\x4a\xc1\xb6\x2c\xe9\x40\x72\xa5\x79\x2d\xaf\x37\xce\x80\xef\x41\xd7\x84\x5f\x65\x37\x24\x31\xcf\xc3\xd1\x58\x73\x69\xff\xb2\xf7\x03\x27\x9d\x6b\x98\x0d\xe0\x53\x1c\x7d\x09\xba\xf8\xd4\x8a\xab\x50\x10\xae\x62\x78\x15\x29\x48\xbd\x71\x0e\xf4\x82\xf6\x32\xfe\x98\x8d\xf4\x46\x04\x8a\x78\x1d\xb3\x8b\x6a\xbf\xdc\xc4\x52\xf6\x0e\x0b\x48\x17\xc0\x55\xd8\x0a\xe2\xa0\x17\xf6\xca\x51\x88\xf5\x0d\x68\x26\x02\x78\x36\x62\x6b\xc0\x5f\x1b\x8c\xc1\xa0\x10\xf5\xc6\x25\xd0\x8e\xee\xbe\xc7\xe1\xf5\x8d\x4c\x22\xcc\x4f\x79\xb4\x82\xa7\x95\xcd\x54\x92\x7c\xf3\xbb\xc9\x1f\xf0\x31\x1b\x2f\x6a\x46\x7e\x0c\x50\x94\x24\x3e\x24\x00\xee\xbf\x64\xd6\xcb\x49\x9d\x1f\x03\x9f\x83\xdb\xb0\x1b\x76\x03\x44\xf1\x55\xd8\x6d\x75\x10\x76\xaf\xc2\x76\xab\x1f\xc5\xdc\x0c\xc5\x9b\xde\x9c\x99\x2a\x89\x18\x74\xb7\xc9\xac\x9c\xc5\xd6\x3f\xaf\x03\x9d\xe0\x73\xff\xc3\x5d\x14\x76\xfb\x61\xf7\x1a\x57\xd1\xe0\x53\x27\x40\xab\x7b\xdd\x09\xf0\xe7\x20\xea\xeb\x2a\xa2\x71\xbb\x2b\x2b\xaf\xa3\x56\x65\x65\x9e\x5e\x92\x78\xd6\xcf\x7d\x2c\x9f\x55\xd4\x09\xa8\x59\xf0\xd2\xfd\x04\x8b\x90\x30\xed\xe3\x12\x35\x0d\xe3\x04\xe8\x45\x9f\xfb\xb8\xf9\x7e\x77\x13\x74\xdd\xa4\xbd\x66\x62\xd8\xb6\x99\xe6\xba\xdb\x62\xe4\x53\x20\x0e\xae\xc3\x5e\x3f\x88\x03\x59\xf3\xaa\xc5\x8d\x28\x65\x3c\x6e\x12\x7d\x7c\x96\x17\x3e\xba\xc6\x78\x73\xdc\x9c\x01\xb7\xad\x76\x1c\x75\x6b\xac\x36\x34\x0d\x62\xc1\x59\x29\xef\x9d\xf8\x3e\x46\x91\x56\x66\x2d\x6a\x03\xb8\x0a\xae\xe3\x20\x20\x66\xcd\x6d\xa6\xbd\x9d\x70\x38\xc5\x96\xaa\xf4\x75\xf5\xf3\x73\xe0\xae\x33\xe8\x7d\xb8\x0d\xbb\x83\x9e\x72\x6e\xbe\x27\x2c\x33\x41\x92\x09\x6c\x30\xf7\xdd\x13\x26\xb4\x59\x75\x17\x70\x4a\xd8\x4b\x74\x17\x40\x6f\x70\x17\xc4\xbd\x76\x1c\xde\xf5\xd1\xff\x16\xd5\xe4\xa2\x18\xd4\xca\xd0\x12\xe4\xc0\xc6\xa0\xda\x36\x97\x62\xf4\x9b\x38\x08\x98\x5b\x50\xee\xe6\x89\x9a\xc9\x2b\x26\xaf\x97\xdc\x9b\xf8\xd4\xc5\xab\x66\xad\x7e\x71\x0c\xb4\xda\x83\x7e\x80\x56\x7b\xc1\x7b\x35\xab\x38\x54\xdb\x5f\xbf\xa8\x03\xb7\x61\x3b\x8e\x6c\xda\x28\x17\x4d\x90\x48\x69\x15\x9a\xf3\x64\xf7\xa3\xd4\x81\x3c\x94\x09\x61\x54\x0d\xd0\x85\x0f\xdc\x85\x9d\x76\x1c\x7d\xd3\x10\x2d\x39\x8b\xd7\x5a\xeb\x11\x5b\x23\xa3\x54\x69\x0e\xeb\x17\x27\x0b\x9b\x5d\x5d\x75\x02\x5c\x45\xd9\x62\x35\xc5\x45\xa6\x14\x93\xdc\x92\x2d\x8c\xfc\xf0\xfa\xc6\x0b\x1a\x1f\x5c\x85\x9d\x4e\xab\xa6\x57\xa0\xdc\x95\x7c\x3a\x73\x6d\x86\xc5\xdd\xcf\xb8\xb7\x47\xdd\xa0\xf8\x3b\x35\x96\x8e\x37\xe6\xd2\x4f\xe6\xd4\x98\x71\x1a\x8b\x74\xdb\x6b\x0f\x3a\x5b\x79\x4a\xa5\xc7\x92\x58\xcc\x21\x2f\xa7\x0e\x75\x52\x61\x23\x08\xcf\x81\x25\x33\xac\x4c\x50\xf8\xe3\x31\x3c\x26\x93\x23\xde\x93\x56\xa5\x30\x28\x14\x45\x56\xc0\x2f\x80\xaf\x83\xce\x75\x2b\xc6\xe7\xb8\xb5\xea\x04\xa2\xee\x02\x70\x2b\xee\x07\xb1\x0a\x5e\x4f\xf7\x36\xf4\xca\xcb\x52\x16\x81\xa7\xf6\x34\xc4\xd4\x28\xcd\xe5\xf5\x80\x74\xb3\x3a\x49\x3a\x50\x59\xff\x96\x33\xbd\xb4\x67\x7a\xd3\xea\x7c\x76\xdc\xd0\x9e\xa5\x07\x3d\xc9\x6c\x95\xe8\x1c\x41\xfd\x5f\x13\x1b\x45\x3d\xac\x3a\xa7\xf1\x38\xa6\x77\x79\xac\xa7\xb7\xac\x3d\x9b\xa5\xec\x19\x5f\xe6\xab\xc9\x27\xb5\xfa\x00\x4d\xc4\x7a\x45\xe9\xdf\xe4\x9a\xba\x57\x15\xa5\xd7\x75\xfb\xca\xae\x27\x4f\x45\xa5\x3f\x07\x41\xcf\x0a\x35\xcf\x71\x1c\x8d\xc4\x60\x72\x24\x9a\x2c\x2e\x37\x5a\x62\xa3\xae\xbc\x97\x3e\xd0\x69\xf5\xc3\x2e\xda\xad\xbb\xb0\xdf\xea\xa0\x13\xf4\xfb\x41\x8c\x16\xbe\x85\xfd\x1b\x5c\xc7\xad\xaf\x01\x63\x43\x8e\x13\x15\x49\xc1\x2e\x3b\x15\x6b\x55\x55\x24\x96\x33\x78\xe3\xe5\x49\x31\xbe\x25\x6b\xa0\x24\xdd\xb5\x1f\x71\x28\x7c\xa7\xc5\xf8\xda\x61\xdc\x1e\xdc\x7e\xee\x04\x7f\xe5\x46\x4c\x0a\x24\x54\xb5\xca\x42\xfc\x92\xd9\x3e\xb1\xf4\xa9\x6d\x8d\xde\xe5\x59\x31\xe8\x7e\xd8\xb9\x62\x8b\xce\x79\x98\xe8\x81\x20\x0f\x0f\xed\x1f\x6f\xa3\x18\x6f\x45\x09\x46\xd6\x53\xb9\xe4\xfb\xc1\x7c\x5e\x8c\x39\x5e\x94\xdd\xd6\xa7\x88\x46\x57\xb1\x63\xbc\x07\xe8\x0b\x17\xe8\xc0\xca\x69\x52\x65\x71\x68\x2d\xeb\x0f\x73\x12\xcc\x73\x94\xfe\x2c\xf4\x23\xa4\x66\x76\x2d\x38\xa9\x9c\xcd\xea\xd2\x31\xab\xf6\x3a\x46\x05\xe3\x34\xe7\xe6\x7e\xb6\x8f\xab\x73\x72\x0e\x30\xf6\x5e\x12\x26\x2b\x92\x77\xd7\x88\xfd\xe3\x63\x07\xe2\xc0\x99\x95\x79\x13\xcb\x7f\x99\x88\x48\x10\xee\xfe\x63\x87\x7d\x6e\xff\xb8\x5e\x8c\xd3\xc8\xce\x60\xe9\xf9\xbd\x70\xba\xaa\x5c\xb0\x5b\x96\xe6\x25\x43\x2f\xb1\x76\x64\xdb\x85\x8b\x82\xd1\x3f\x76\x95\xbe\x60\xa7\xac\xf7\x3e\x98\x5d\xe5\x30\x54\x8e\x9b\x18\x4a\xda\x76\xb9\x81\xd4\x16\xc3\x09\x4c\x17\x58\xe2\x72\x55\xbc\xb0\x12\x8d\xe0\x16\x64\x68\x58\x58\x57\x7d\x92\xd4\x3f\x76\x55\xb8\xd0\xed\xa0\xdc\x3d\xd5\x4e\xdb\x01\x40\xba\x4a\x5a\xe8\x74\x48\x97\xce\x78\x38\x8c\xae\x0a\x16\xf4\x6f\xcc\xd6\x3b\xeb\x24\x8c\xd6\xdb\x50\x52\x20\x05\x2f\x21\x79\x15\x9f\xdf\xf3\x8f\x5d\xa5\xa8\x5b\x99\x79\x49\xbd\x49\xaa\x3c\x89\xe3\x37\xdf\x2a\xc5\x73\xdd\x55\x88\x22\x5d\x88\x44\x77\x60\xc8\x17\x7b\x3b\x0b\xeb\xd7\x5d\x85\x27\xb2\xe2\x59\x6e\x0f\x1e\x10\x97\xab\xd0\x44\x8e\x38\xae\xa0\xfb\x28\xe7\xa3\xeb\xb9\xc3\x21\x13\xbf\xee\x2a\x30\x91\x76\x46\xe6\x8b\xaa\x09\x38\x30\x4e\x57\x51\x89\xac\xbc\xe3\xa8\x83\xef\x73\x70\xc7\xaf\x9f\x01\xb7\x83\x4e\x3f\xbc\xeb\x84\xed\x96\xde\xab\x86\x90\xf0\x9a\x05\x9b\x1f\x89\xfa\x61\xc4\x12\x9a\xbe\x5f\x77\x95\x92\xb5\xb5\x7a\xfd\x38\xfa\xa2\xe8\xbc\xa6\xf2\x32\xcf\xd0\x4c\x43\x30\x53\x33\x81\x66\x9b\x44\x9e\x86\xc8\x17\xc2\x61\xbf\xcd\x04\x5c\x65\x66\x50\x25\xe7\x90\x69\xed\x2b\xb6\x5d\xa5\x65\x50\x25\xe7\x1c\x00\x97\xab\xa6\x0c\x76\xca\x39\xf9\x2a\x1d\x22\x3e\x7c\x57\x41\x19\x54\x8f\x65\x65\xb2\x7d\x63\x75\x15\x99\xef\xae\x05\x07\x5d\xf1\x4c\x2e\x06\x13\x9b\x38\xa1\xe5\x90\x68\x23\xd8\x54\x1b\xb0\x0a\x9f\xab\xd8\xf4\x6f\xa2\xb8\xcb\xe3\x8d\xf6\x31\xe5\x1e\xec\xa2\x79\x32\x21\xfa\x22\xb6\x3e\xd2\xe6\xfb\x59\x61\xe9\xdd\xb6\x3a\x19\xac\xde\x4d\x2b\xbe\x43\xcf\xec\x4e\x50\xa2\xe7\x32\x2c\xa7\xf8\x8e\x14\x0f\x68\x6b\xae\x0e\x17\xfa\xfe\xa9\x09\xd4\xd0\x3e\x4b\x25\x1a\xd6\xba\x18\x01\x2d\x54\x45\xc7\xa3\x88\xbe\x7f\x56\x84\x4a\xb4\x2a\x3c\x3a\xcc\x54\x03\xc9\xb9\xf7\x71\x42\xd4\xf7\x1b\x45\x28\x75\xc3\xc2\x4d\x98\xa8\x07\x9f\x0f\x09\xf5\xbc\x08\x6a\x79\x9a\x73\x60\x94\x17\x45\x28\xab\x93\x9c\x4a\x89\xb1\x1a\xd2\xcb\x22\xa4\x5a\xd9\xdc\xb2\xf4\xa2\xc1\xdf\xab\x51\x4f\x8e\x6d\xa8\xa6\x9e\x69\x31\x12\xd5\x28\x1a\x4d\x43\x72\x64\xc4\x7d\xc2\x85\x42\xfa\x75\xb9\xbb\x00\x3a\x0f\x03\xc3\x66\x2e\x75\x73\x2e\x45\x2a\xa6\xb8\x5b\xf9\x1f\x8f\x03\x21\x1f\x4a\x68\x61\x45\x8b\xcb\x97\x4b\x9c\xbe\x89\xd3\xd0\x2e\x13\xaa\x01\x02\x82\xee\x0a\xa6\x6e\x78\x06\xf0\x06\xcf\xb0\x8b\x94\xad\x5c\x16\x64\xd9\x03\xa3\xb4\x2b\x94\x4b\xb7\xac\xd4\x4e\xee\x1b\xaa\x5d\xb6\x4c\xb5\xb2\x62\x93\xb6\x6f\xa4\x76\xe9\x92\x1a\xa5\x60\x23\x7b\x3a\xdc\xef\x9f\xd8\xd5\xc8\x52\x22\x93\xad\xe7\x9f\x84\x82\x9b\x8d\x48\x62\xb2\xf0\xe7\x48\xfd\x13\xbb\xea\x38\x74\x47\x4e\x17\x79\x01\xf7\xe4\xaf\x38\xed\x0c\xc9\x2e\x2f\x96\xca\x98\x28\x8d\x31\x57\x18\xb1\x3f\x23\x9d\xda\x55\x64\xa3\x29\x0a\x14\x64\xad\x12\x7e\x28\xa6\x98\x1e\x96\xec\xf7\x4e\xed\x32\x50\x5d\x41\x84\xf2\xa5\x44\xec\xdd\x42\xf4\xf4\xa8\xae\x20\x9e\xda\xc5\xa0\x92\x7e\x08\xc9\xba\x80\xb7\xda\xd0\x4e\xfe\x95\xd4\xc3\x03\xa0\xb2\x93\xfd\x6e\xda\xa1\x0b\xe0\x7e\x7a\xe3\x53\x3b\xd9\x9b\xca\xe1\xca\xe7\xdd\x94\x9a\x9d\x5f\xda\x2f\x4a\x3b\xd1\xff\x3f\xd4\x0d\x4f\xcf\x81\xab\xf0\x6b\xd8\xd3\x8a\xa1\xe7\xfc\x9d\x92\xcd\xfb\xae\x03\xf8\x46\x4e\x5e\x7f\xd7\x09\x66\x89\xc5\x2e\x09\x45\xfa\x61\x59\x9a\xc9\xba\x92\x84\xff\x5c\x74\xd5\xbd\x94\x53\xbb\x4c\x28\x95\x90\xb5\x17\xa6\x09\x4b\xa9\x71\x25\x9b\xf7\x33\xbb\x54\x98\x1a\x61\xe9\xe6\x7d\xef\x1d\xdc\x99\x5d\x43\xde\x49\x31\xac\x06\xd5\x2e\x20\xef\xa3\x17\x56\x43\x6a\x17\x15\x53\x2d\x64\x20\x8d\x85\x2f\xf1\x3b\x1b\x56\x2f\xc9\x05\xf8\x3c\x03\x2d\xd0\xd9\xc5\x85\x69\x85\xd2\xad\xb9\x5e\x08\xb9\x59\x6a\x6a\x74\x06\x40\xc1\x28\x4c\x02\x96\xc1\xb4\x0b\xcb\xf7\x1d\xcf\x3c\x48\x3c\x50\x9a\xa1\xa4\x8a\x7a\xd1\x39\x65\x24\x66\x5d\x22\xfe\xbf\x00\x00\x00\xff\xff\x63\xd4\xf0\x9c\xb1\x6f\x00\x00")
+
+func fontsLeanFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsLeanFlf,
+ "fonts/lean.flf",
+ )
+}
+
+func fontsLeanFlf() (*asset, error) {
+ bytes, err := fontsLeanFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/lean.flf", size: 28593, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsLettersFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x97\x69\x5f\x22\x39\x10\xc6\xdf\xf7\xa7\x78\xc6\x89\x0a\xea\x88\xb2\x5e\x8c\x2c\xc6\xd1\x5d\x15\xc7\x5b\x01\x15\x45\x44\xf0\x42\x40\x10\xbc\xfd\xec\xfb\xab\x4a\x3a\x9d\x34\xed\xba\x2f\xb6\x6c\x52\xff\x3c\x55\x95\x4a\x1f\x1c\xd6\xea\xb5\x64\x59\x60\x06\xd3\x48\x4e\x60\x72\x1a\xb3\xde\xef\xea\xc3\x43\xb5\xdd\xc1\xf9\x33\xf6\xda\xd7\xed\xf2\x1d\xb2\xe3\x58\x69\xd6\xeb\xe5\x56\xb9\x5e\xbf\x1e\x03\xb2\xdd\xfa\x33\x26\x27\xc6\x30\x99\x4a\x4d\x79\x1e\xd0\x2c\x95\xe0\xdb\xe8\x8f\x48\x1b\x35\x09\x28\x95\x9a\x1e\x4a\xe3\x99\x44\xdc\xaf\x7a\x8b\xec\x84\x37\x53\x11\x2b\xa6\xc7\x4b\x5e\xac\x14\x47\x91\x86\xff\xd2\x28\x56\x8a\x27\xc0\xc9\x1e\x5c\x4b\x77\xb8\x99\xac\x94\x5b\xe5\x4a\xa5\xda\xe9\x8c\x37\xdb\x97\x19\xcf\x13\x32\x74\x48\xef\xdb\xb7\x6f\xc2\x1d\x01\xb8\x2c\xbd\x01\x32\x11\x78\x0c\x0c\x0c\x40\x85\x11\xe1\xa5\xd9\x0f\x6b\xdf\xbf\xd3\x41\xf8\x5d\x59\x08\xad\x04\x53\x26\x3d\x24\xde\x7e\x14\x85\xf4\x12\x74\x91\x84\xf4\x8a\x3f\xd4\x9c\xae\xe5\x9b\x9e\x27\xec\x9e\x83\x83\xc0\xe0\xa0\x60\x18\x1c\x54\xcb\x91\x46\xc0\x92\xb0\x72\xac\x3e\x18\x1a\x1a\xd2\x5b\x1d\x1a\xa2\x43\x23\x9b\x90\xde\x50\xa4\xea\x6c\x75\x98\x82\xc3\xc3\xc3\x3c\xc2\x5c\x43\x6b\x54\x05\x34\x8b\xc5\x62\x42\x7a\xb1\x58\x0c\x7d\x4e\xc5\x4c\x6a\x3c\x1e\x67\x35\x1e\x8f\xf7\x39\x15\x0b\xae\xfc\x08\x80\x11\x0a\x8f\x8c\x8c\xc0\xf2\x46\x0f\xdd\x19\x96\x46\x47\x47\x99\x46\x95\x39\x14\x44\xed\x13\x0d\x9f\x96\x87\x31\x1a\xc7\xc6\xc6\x78\xec\xeb\x60\xa8\x44\x16\xd2\xfa\x29\xaa\xc3\xf8\xf8\xb8\x19\xad\x73\x48\xe8\x7b\x9f\xd0\x90\x48\x24\xb8\x86\x3c\x01\x7b\xb8\x77\x7a\x82\x8c\xb4\x89\x09\x00\x13\x13\x9f\x50\x90\x67\x6f\x6c\x92\x84\xc9\xc9\x49\x92\xad\x51\x2b\x3a\x29\x99\x4c\x26\xb9\x6b\x92\xcd\x5f\x23\x99\x4c\x8a\xfe\x68\xd2\xed\xf0\x07\x9b\x2e\x21\x64\xb2\x34\x28\xcd\xc9\xb3\x6f\xeb\xd4\x94\x7f\xc2\x53\x3e\x92\x57\x38\xa5\x2d\x94\x60\x2d\x31\xcd\x46\xea\xf4\xb4\x7f\x67\x02\x0d\x00\x61\x58\x0b\xfa\xcf\xcc\xcc\xa8\x25\xc9\x33\xcd\xb0\x29\x02\x25\xa8\xa8\xd6\xac\xe2\x59\x65\x5a\x34\x34\x3b\x3b\xab\x12\x09\x98\x18\xc2\x9d\xe7\xc8\x48\x9c\x9b\x03\x30\x37\x27\xbe\xd2\x42\x97\x4d\xaf\x98\x22\x23\x4a\xa5\x00\xa4\x52\x46\x4b\xe9\x12\x15\x25\x9f\xea\x7f\x56\x7f\xfe\xfc\x19\xc5\x6e\xd2\xfc\xfc\x7c\x88\xe7\xe7\x9d\xcf\x86\x74\x3a\x2d\xa4\x97\x4e\xa7\x11\x38\x2d\x46\xbd\x7f\x7d\xfa\x53\x99\x43\x9f\xbd\xbb\x48\xc9\x64\x32\x1c\xc8\x64\x32\x81\xf3\x45\x3f\x75\x61\x61\x81\xe6\x0b\x0b\x58\x58\x50\xba\xf6\x4a\x0f\xbc\x59\x5b\x4a\x29\x59\x92\x90\x12\x52\x48\x4f\x42\x92\xcc\x04\x13\x35\x79\xf6\xc6\x16\x17\x17\xd5\x6e\x17\xc9\x88\x48\xc0\xe2\x22\x13\x9b\xa3\x59\xc5\xbf\xc8\xb8\x98\x1c\x7e\x29\x62\xd1\x68\xbf\x1c\xcd\xee\xbc\x44\x46\xe2\xd2\x12\x69\x4b\x86\x5c\x2d\xc8\xb3\x8a\x97\xc9\x38\x91\xdc\xf2\xb2\x4f\x58\x5e\x0e\x11\x27\xba\xc5\x7f\x29\x13\x44\x7e\x3f\x56\x34\x39\x1a\xe7\x59\xc5\x7f\x2b\x13\x44\x7e\x22\x09\x3e\x05\x5a\xe4\x63\xb0\xb2\xb2\xb2\xc2\xe2\xca\x0a\x4d\x84\xf4\x08\x54\x22\x13\x6b\x9c\xa6\x28\x28\x5e\x5d\x05\xb0\xba\x2a\x5c\x62\x13\xd1\x51\xab\x78\x8d\x8c\xa4\xb5\xb5\x35\x44\x78\x13\xb7\x9f\xd8\x6c\x36\x2b\xa2\x29\x9b\x35\x5a\x96\x2c\x74\x9e\xeb\xeb\xc0\xfa\xba\x60\x58\x5f\x07\x03\x69\xae\xa2\x73\x82\xb2\xdf\xbf\xfd\x4b\xf1\x15\xb1\xb9\x3d\x37\x36\x88\x36\x36\x04\xe1\x06\x91\x42\xf0\x21\x42\x09\x06\x61\x2d\xb1\xb9\x09\x60\x73\x53\x10\x6d\x1a\xc2\xa6\x21\x6c\x1a\x52\x9a\x7d\x6f\xb7\xc8\x68\x7b\x5b\x5b\x00\xb6\xb6\x3e\x21\xce\x0b\x7f\xc9\x6d\xb3\x91\xb8\xbd\x0d\x60\x7b\x5b\xf4\x69\x70\xc9\xee\xbc\x43\x46\xe2\xce\x0e\x80\x9d\x9d\x3e\x52\x51\xce\xc3\x8e\x5b\xbc\xcb\x46\xe1\xdd\x5d\x00\xbb\xbb\x22\xac\x85\xa3\x76\xe7\x3d\x32\x0a\xef\xed\x99\x8d\x19\x8d\x95\xbd\xbd\x7e\x4d\x15\xef\x2b\x63\x71\x7f\x7f\x5f\x9f\xd5\xbf\x93\x29\x3e\x38\x00\x70\x70\x20\xbe\x22\x1c\x90\x85\x8a\x73\x39\xc6\x5c\x4e\xb8\x0c\x9e\xe4\x72\x2a\x3d\x97\xe3\xb9\x2a\xcd\x71\xc8\x7a\x5e\x78\xa1\x7c\x5e\x71\x3e\x2f\xa2\x26\x79\x3d\x41\x3e\x8f\x3c\xbf\x78\x01\x15\xcb\x3b\xab\xf1\x72\x85\x02\x51\xa1\x40\x01\xe2\x42\x41\xe5\x14\x0a\x34\x73\x55\x3b\xd7\x5a\xe2\xf0\x10\xc0\xe1\xa1\xb0\x09\x87\x64\x6a\x29\x82\x30\x99\xe2\x23\x32\x25\x69\x7f\x74\xc4\x29\x47\x47\x9c\x6a\xc5\x55\xc1\xf1\xf1\xf1\xb1\x20\xc7\xe1\xb0\xe3\x98\x9f\x5a\x2c\xfa\xcf\x07\x13\x47\x88\x54\x4a\xb1\xe8\x6f\xa5\x58\x74\x3e\x12\x4e\x4e\x4e\x4e\x58\x88\x70\x26\xa6\x1f\xc6\xd3\x53\x5a\xe4\xf4\xf4\xf4\x94\x1c\x70\x2a\x82\x2f\x78\xdb\x7d\xf1\x5b\xd8\xa2\x92\xb2\xd0\x43\x7f\x46\xa1\xb3\xb3\x33\x92\xd5\x18\xfe\xed\xec\xae\x56\x2e\xa3\x5c\x26\x62\x20\x2a\x97\xa1\x89\x9c\x8e\x06\x1d\xce\xcf\xfd\x62\x9b\xc8\x8c\x76\x7e\xee\x68\xf6\xf6\x82\xc6\x95\x4a\xa5\x22\xa4\x57\xa9\x68\xc5\x00\x47\x2a\xce\x85\x66\xb8\xb8\x10\x0e\x5d\xb0\x09\xe9\x5d\x5c\xf4\x6b\xd1\x3d\xab\xd5\x2a\x41\xb5\x0a\xa0\xca\xa0\x15\x30\xb9\x3d\x6b\xb5\x9a\x90\x5e\xad\xc6\xb5\xb5\xd0\xec\xb3\x3b\x76\xc9\x26\xa4\x77\x79\x09\x40\x93\xaf\x71\x96\x22\x96\xb8\xf8\xea\xca\x2f\xb6\x89\xcc\x68\x57\x57\x0e\x59\xe7\x76\x7d\x7d\x6d\x6e\xae\x62\x7b\x34\xdb\xbb\xb9\xb9\x09\xde\x19\xd6\xdc\xf5\x37\x37\x37\x37\x5c\x70\x7b\xab\x33\x09\x6e\x6f\x19\x6e\x6f\x6f\xb5\x62\x40\x85\x82\xcd\xd4\xeb\x75\xf1\xf9\xe8\x5e\x2b\xdd\xe0\xee\x0e\x7c\xdc\xdd\xa9\xd9\x1d\xa0\x5e\x5f\xcc\xe0\x7e\x36\x05\x0b\x36\x1a\x68\x34\x1a\x8a\x1a\x40\xa3\xa1\xb4\x3e\x8a\x7c\x3e\x9a\xcd\x66\x93\xa0\xd9\x04\x9a\x4d\x1b\x4c\x28\xaa\x67\xab\x85\x56\x4b\x53\x0b\x68\xb5\x14\xd1\x44\x45\x83\xbc\xa8\xf7\xf8\x3d\x99\x90\xde\xfd\x3d\x68\x42\xda\xbd\xaf\x71\x96\x4b\xd6\x86\xdb\x6d\xb4\xdb\x0a\xda\x40\x5b\x29\x26\xd4\xf7\x8f\xae\xaf\x74\x3a\x1d\xf2\x9d\xd0\x9c\xa6\x9d\x60\x2e\xbd\x87\x07\x95\x10\xf8\x87\x07\x7b\x0e\x12\xc2\x3f\xcb\x54\xa8\xdb\x05\xd0\xed\x7e\x42\xe8\x76\xbb\x5d\x74\xa3\x6e\x03\x15\xf7\x7a\x00\x7a\x3d\x0a\xf7\x7a\x74\x70\x62\x8f\x64\x55\xd2\x8b\xfc\x17\xc6\xd4\x3f\x3e\x2a\x7c\x7c\x0c\x4f\xf0\xf8\xa8\x0f\x2e\xa7\x18\xbd\xfa\xbe\xeb\xcc\x52\x4f\x4f\xc0\xd3\x13\xc7\x09\x6d\xb0\x42\xfd\xa7\xf0\xfc\x0c\xe0\xf9\xd9\x21\x3c\xb3\xf9\x15\x96\xe6\xdc\x9e\x17\x32\x4e\x7a\x79\xe1\x86\x2f\x2f\x21\x3d\xe8\xf6\xfa\xca\xc2\xeb\x2b\x25\xbc\xbe\xbe\xc2\xf6\xbe\xae\xf3\x08\x84\xf4\xde\xde\xa2\x07\xe9\xbd\xbf\xeb\xcb\x4a\xc0\x75\xef\xef\xef\xb6\xd7\xba\xce\xb3\xdf\x38\x1f\x1f\xf8\xf8\x10\xd2\xfb\x00\x3e\x9c\xa7\xae\x1f\xa4\x67\xfd\xfd\xdf\x93\x7f\x02\x00\x00\xff\xff\xd9\x6e\xbb\x3d\xd6\x15\x00\x00")
+
+func fontsLettersFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsLettersFlf,
+ "fonts/letters.flf",
+ )
+}
+
+func fontsLettersFlf() (*asset, error) {
+ bytes, err := fontsLettersFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/letters.flf", size: 5590, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsLinuxFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x56\xcd\x6e\xe3\x36\x10\xbe\xf3\x29\x3e\x38\x06\x94\xb4\x1a\xaa\x4e\x36\x87\x14\xcd\x82\x3d\xb4\x97\x16\x58\xa0\xbd\x0a\xb5\x68\x8b\xb2\x84\x95\xa8\x85\x44\x75\x13\x94\x7d\xf7\x82\xa4\xa4\xc8\x8e\x9d\xed\x03\x04\x96\x61\x8a\xdf\xfc\x7e\x33\x43\xba\xa8\x8b\x5b\xb9\xc6\x07\xdc\xe1\x01\xb4\xc1\xe6\x8e\xd5\x95\x1e\x9e\xb0\x7b\xc6\xef\xb2\xeb\x9e\xf1\x67\x53\x99\x12\xf7\xc9\xe6\x36\x79\xb8\x07\x61\x27\x7b\x95\xa3\xd5\xe0\x7d\x75\x40\x5b\xe0\x8f\x76\xa7\x3a\x53\xe2\x37\xd9\x35\x52\x73\xf6\x6b\x75\xa8\x95\x41\xa7\x6a\x25\x7b\x85\x5b\xfe\x03\x88\xf0\xf3\x70\x18\x7a\x83\xfb\x18\x9b\x87\x87\x3b\xc6\x7e\x79\xfa\x52\x4b\x2d\x4d\xd5\x6a\x67\xa4\xa8\xba\xde\xa0\xae\xb4\xfa\x91\xb9\x98\x40\x58\x35\xf2\x50\xed\xa1\x87\x66\xa7\xba\x15\x8a\xb6\x43\x51\xd5\x0a\x55\xae\xb4\xa9\x8a\x6a\xef\x95\x99\x04\x00\x42\x5f\xb6\x43\x9d\x43\xd6\x5f\xe5\x73\x8f\x9d\x42\x26\xa3\xd8\x2b\xe9\xf6\x2b\x43\x10\x32\xa5\xc2\xaa\x94\x5d\xbe\xab\xa5\xfe\xbc\x72\x71\x7d\xe9\x2a\x6d\x7a\xc8\x1e\x12\x7e\x37\xc6\x6e\x30\xd8\x4b\x1d\x19\x67\xa6\x6f\x86\xbe\x54\x39\xfb\x10\x2c\x94\xaa\x3a\x94\xc6\x45\x2c\xb1\x2f\x65\x27\xf7\x46\x75\xec\xee\x0d\x30\x86\x6e\x0d\x2a\xbd\xaf\x87\xbc\xd2\x07\xe4\xaa\xdf\x2b\x9d\xab\xae\x67\x0f\x41\xad\x91\x4f\x3e\x73\xd4\x4a\x1f\x4c\x89\x6b\xf5\x34\x09\xef\xdb\xa6\x51\x3a\x10\xd3\xdf\xe0\x7b\x48\x14\x43\x7e\x50\x28\xe4\xde\xb4\x1d\xa3\x8d\xb7\x90\xab\x42\x0e\xb5\x09\xc1\x36\x6d\xae\x7c\xe2\xa6\xac\x7a\x14\xad\x36\xb8\xae\xab\xcf\x0a\x2b\x6a\xb0\xb9\x5f\xb9\xda\x39\xbb\x52\xe7\xde\xee\x0d\xdb\xdc\x79\x2b\x81\x69\x17\xfe\x91\x5b\xc6\xd6\x62\x7e\x04\xe3\xc4\x05\xcb\xfe\x8e\x04\x43\x0b\xe1\x98\x15\x82\x59\xeb\x56\xf3\x57\x30\x58\x0b\xc1\x1e\x81\xc7\x69\x8d\x20\xc9\xc9\x3a\x03\x48\x6d\x0a\xc1\x32\xb2\x14\x05\xcc\x81\x2d\x62\x8a\x05\x43\x82\xc4\x83\x11\xda\x17\x50\x7a\xe3\xda\x9b\xca\x67\xc7\x82\x61\x7c\x04\x0b\xda\xd7\xb8\x76\xef\x19\x65\x0b\xa7\xdc\x6d\xdd\xe0\x46\xb0\x88\xa2\x97\x68\x52\x9b\x08\x46\xdf\x91\x60\x89\x4d\x27\x9b\xb8\x82\x60\x57\x57\x57\xe3\x6a\xdc\xf4\x4f\x32\x3a\xc2\x2c\x81\x13\x89\x4f\x93\x84\xe7\x69\xcc\xc4\xf9\xc4\x4b\x26\x9c\x88\x1c\x6a\x1d\x33\xd6\x25\x4a\x34\xd3\xe0\xb5\x13\xee\x69\x13\x0c\x44\x93\x7d\xa7\xb5\x24\x87\x96\xcc\xf1\x60\x11\x20\x6b\x5f\x81\x88\x3d\x18\x91\xf7\x06\x64\x4b\x30\x26\xef\x22\x45\xea\xf5\xa2\x99\x9b\x98\xb8\x0b\xda\x22\xf1\x15\x3f\xeb\x2f\xa3\x04\x89\x27\x3b\x3a\xce\xcf\x61\x49\xc2\x4f\x4c\x4e\x80\xd3\xc9\x96\x75\xc0\x5a\xb0\x76\xfc\x62\xbd\xd8\x48\xa6\x8d\x35\xb6\x5b\xd7\x81\x09\xdc\xd6\x3a\xa3\xcc\xfd\x00\x01\xdc\x06\x90\x88\xe6\xdd\x39\x9a\xf5\x76\xeb\x5e\xd7\x29\x52\xf7\x13\x51\xb4\xd0\x8c\xa7\x50\xe1\xfb\xf9\x25\x22\xe5\x96\x72\xd1\xd1\x7c\xae\x59\x28\xd9\x5f\x27\x74\x38\x8c\x7e\xc2\xeb\x8c\x27\xad\xb3\x45\xe3\x9e\xe1\x91\xfc\xe8\x0c\xc3\x16\x96\x2e\x96\x7b\x06\x5f\xb5\x57\x00\xa3\x6d\x30\x9b\x2c\x41\x1e\x5a\xd3\xc2\x3e\x8e\xa9\x44\x8b\x8e\x98\x84\xbc\x80\x07\xe7\xfe\x1e\x5b\x3a\x9e\x7b\xf6\x28\x20\x1e\x07\x25\x8e\x40\x42\x94\x1d\xb5\xb4\xf3\x1b\xda\xc9\x6e\xb7\x38\xd3\xf3\x9c\xfc\x67\x64\x78\xf4\xbd\xa0\x64\x12\x1a\x65\x78\x36\x8a\x9c\xba\xf9\xc6\x68\x2d\x98\x8b\x2e\x33\xf7\x09\xb1\x07\xd3\xf4\x04\x0c\x19\xd0\x85\x14\xc3\x0c\xa6\x48\x2f\x56\x2c\x73\x55\x39\x33\x30\x53\x5a\x17\xa3\x0e\x02\x48\xe1\xa7\x1f\xc8\x5e\x02\xbf\xc4\xde\x91\x91\x23\x2b\x1f\xe1\x8b\x14\xb9\x0c\xb2\x73\x6e\x3e\x8e\x6e\x96\xfc\x7c\xf3\x0c\x8a\x63\x72\x37\x81\x03\xb2\xc5\xa9\xe5\x4f\x91\x91\x94\x93\xb3\x87\xf8\x74\xce\x51\x34\xf7\xd9\xf8\x39\xb7\x78\x9f\xc1\xf7\x19\x7c\x9f\xc1\xb7\x66\xd0\xdd\xac\xff\xf8\x79\x9b\xaf\xad\xa9\x8d\xe6\x5e\x12\xcc\x8f\xe2\xbf\x82\x25\xf3\xdf\x35\xaf\xee\xae\xfc\x6d\x3c\xbf\x4d\x36\xdf\x18\xc8\xff\xb3\xf8\x2f\x00\x00\xff\xff\xf6\x6c\xf8\xe3\x63\x0c\x00\x00")
+
+func fontsLinuxFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsLinuxFlf,
+ "fonts/linux.flf",
+ )
+}
+
+func fontsLinuxFlf() (*asset, error) {
+ bytes, err := fontsLinuxFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/linux.flf", size: 3171, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsLockergnomeFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x56\xdf\x6b\xe3\x38\x10\x7e\xf7\x5f\x31\x94\x82\x1b\x22\x59\xbd\xf6\xa0\x30\x38\x46\xdc\xc1\x1d\x2c\xfb\xb0\xb0\xaf\x82\x38\x49\xdd\x6d\x68\xda\x94\xb4\x7d\xe8\x22\xfc\xb7\x2f\x1a\x49\x96\x64\xcb\x61\xd9\x5d\x92\xa8\x1a\xcd\x37\xdf\x7c\x33\xfa\xf1\x70\x78\xb8\xd9\x5c\xc2\xdf\x70\x0b\x37\xd7\xc0\xff\x82\xdb\xe2\xeb\x71\xf7\xd4\x9d\xfe\x7f\x39\x3e\x77\xb0\xfd\x84\x7f\x1f\x4f\xfb\xb7\xf7\xe3\xeb\x63\x77\x82\x2f\xc7\xb7\xee\xf5\x11\xbe\xed\x4f\xfb\xc3\xe1\x08\xf5\x2b\x0d\x76\x37\x77\x77\xd7\x72\x77\xdc\x9e\x36\xd5\xc7\xcb\xbe\xea\xee\x3f\x9a\xe2\xbf\xfd\x8f\x43\xf7\xbe\xff\xd9\xdd\x1b\x90\xef\xfb\xe7\xe3\x0b\xfc\x73\xda\xdc\x1f\xba\x4f\xa8\xdf\x3e\xb7\xb7\x72\xb3\xed\x4e\xd5\x66\x57\x7d\x3c\x35\x45\x71\x79\x29\xe3\x8f\x2c\x10\x35\xc8\xa2\xc5\x12\x64\x01\x4b\x30\xdf\x00\xe0\x0c\xce\xd8\x02\x98\x8f\x35\x91\x39\x8c\x64\x01\xa8\x51\x9b\x39\xc4\xd5\x8a\x1c\x86\x99\xb0\xa8\x42\xd4\x88\xca\x44\x32\x83\x46\x16\xca\x0c\x84\x5d\xd4\xba\x90\x26\xa2\x28\xcd\x14\xa2\x30\x00\xcc\xfc\xa2\x8e\x91\x04\x22\x2a\xe2\xa0\x90\xa1\x58\x33\x13\x99\x31\xa6\xd6\x23\x5e\x96\xbc\xc5\x09\xa4\x0d\x61\x46\x71\xaf\xf0\x8a\x26\x5b\x54\xde\x51\x12\x28\xcd\x2e\x70\x01\x26\x58\x09\x89\xd1\x52\xe6\x1c\x39\x27\xb3\x0e\xce\x04\x4d\x92\x59\x31\xcc\x3f\x52\x63\x98\x8b\x45\x0b\x84\x62\xa2\x21\xd1\x22\xf2\x4f\x35\xcf\x7a\x07\x43\x4e\xc1\xd4\x9b\x19\x64\x26\x0b\x04\xce\x41\x53\x49\x10\xcb\x28\x0b\x74\xd5\xf3\x65\x0d\x34\xc8\xd8\xf7\xa6\x90\xe0\x64\x14\xc4\x33\xf2\x16\x58\xb6\x06\x1e\x40\x63\x6d\xcb\xc4\x52\x78\x0d\x36\xe3\xe0\x19\x25\x2a\x83\xa1\xa5\x52\x5b\xc2\x22\x5e\x40\x19\x28\xb3\x90\x73\xce\xb2\x19\x18\x17\x2f\x83\x49\x25\xf4\x41\xa2\x41\xc3\x39\xe7\x75\x06\xc1\x2f\x50\x66\x81\x76\x7f\x97\x49\xa9\xad\x38\x8b\xe1\x3b\x6b\x88\x4b\x6b\x05\xab\xb1\xce\xf4\xdd\xb4\xee\x93\x06\x30\x52\x56\xe4\xda\x60\x33\x6d\x4e\x81\x7d\xa8\x8c\xcb\x7e\xb9\x1c\x77\x8e\xdb\x3e\xb2\x68\xd5\x7a\xad\x61\x41\x23\x4c\xe4\x71\xbb\xda\x89\x8f\xa8\x19\x55\xc3\x1d\x08\x31\x9a\x6d\x72\x2a\x44\xc3\x11\x6b\x3f\x23\x92\x90\xa1\x5a\xda\x35\x6e\x39\x59\x14\x21\xb9\x28\x19\x24\xf4\x8d\x81\x88\x4d\xbc\xcb\xe6\x16\x99\x55\x71\xdc\x34\x3b\x47\x1c\x60\xb5\xf2\x33\xa3\x70\x09\x95\x73\x12\xe8\x61\x9b\x67\x39\x01\xed\x4b\x6d\xc3\x59\x1b\x26\x3d\x3d\x0d\x57\xc3\x4c\x38\x1d\xb6\xfd\xef\x48\x70\x31\x4f\x5c\x65\xb2\x53\x23\xe2\x51\x17\x9c\x21\x1e\x6a\xb7\xf6\x48\x7d\xdf\x4f\x15\x4f\xfa\x69\xa8\x41\x1e\x29\x6e\x3a\x35\xba\x4a\xc2\xf1\x40\x57\x09\x9b\xe3\x14\x97\x25\x1a\x64\x14\x77\xc4\xdb\x9c\x98\xd3\xcc\xd3\xed\x32\xaa\xdd\x45\xaa\x6a\x0e\xa9\x39\x5f\xe0\x69\xb8\x11\x71\xa8\x9d\x4e\xcc\x77\xed\xa0\x45\x8c\xb4\x02\x3a\x6c\xc1\x8f\x9d\xa1\xf5\x17\xa8\x41\x56\x0e\x19\x51\xb1\xd8\x7b\xb8\xc9\x61\x18\xfb\xed\x0c\x74\xf6\xa8\xc9\xb5\xea\x9d\xa3\x11\x8e\x0f\x31\x97\x22\x21\xd3\xa4\xfd\xf2\xa7\x98\x29\xae\x02\xfb\x4a\x88\xef\x1c\x7f\xa7\x96\x7a\x7a\x21\x05\x4f\x01\x2e\xb9\xd8\x68\xcf\xd2\x12\xe7\x3d\xb1\xef\x85\x35\xb2\xc8\xc8\xfc\x29\x6c\x05\x8c\x6e\xf0\xe0\x29\xec\x1a\x65\x7f\x58\x65\x18\x44\x6c\x2d\x80\x4e\x62\x2e\x97\x16\xcd\x7d\x79\x38\x9a\x66\xe0\xe1\x44\x26\x79\xbd\x26\x96\xba\x57\xa9\x31\x07\x67\x3d\x94\x38\x93\xb4\xdb\x8d\x3a\x67\x64\x43\x15\xc4\xbc\xa7\x35\x5a\x76\x33\x8a\x58\xf5\x63\x4f\x3d\xab\x65\x6d\xb7\x44\x83\x74\xb7\x85\x63\x23\x79\x83\x44\x1b\x21\xce\xd3\xbd\x61\xb3\x79\x2a\xe7\x29\x72\x9e\xfe\x7e\x56\x19\x4f\x65\x5d\xc4\xb0\x45\xe6\x63\x56\xcc\xbc\x9f\x07\xa3\xcb\xc1\x65\x14\x1a\x8a\xc4\x6c\x56\xe4\xa7\xd2\x97\xb6\x2c\x80\x4f\x5e\x73\x8a\x1a\x72\x55\x83\xbb\xec\x07\x03\xe3\xb8\x66\xe1\x39\x33\xfe\x95\x85\xfb\xff\xa7\x83\x5f\x01\x00\x00\xff\xff\x0f\xc2\xf4\x69\xae\x0c\x00\x00")
+
+func fontsLockergnomeFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsLockergnomeFlf,
+ "fonts/lockergnome.flf",
+ )
+}
+
+func fontsLockergnomeFlf() (*asset, error) {
+ bytes, err := fontsLockergnomeFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/lockergnome.flf", size: 3246, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsMadridFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x55\x4f\x6b\x1b\x3f\x10\xbd\xef\xa7\x78\x98\x85\xdf\x2f\x87\xf5\xc4\x49\xa1\x34\x78\x82\xa1\x3d\xf5\x90\x5b\x4f\x55\x31\x5b\x67\xdd\x38\x24\x76\xea\xb5\x53\x4a\xd5\x7e\xf6\xa2\x91\xb4\x92\x56\xda\x4b\x0d\x6b\xb4\x7a\xf3\x7f\xde\xcc\x6e\x9f\xb6\x57\x6d\x8d\x37\x58\x60\x71\x89\x66\x81\xb7\xd5\x73\x7b\x7f\xdc\xdd\xcf\xb7\x4f\x5b\x7c\xfd\x89\x8f\xe7\x76\x8f\xf7\xed\x11\xff\x3f\x6e\x56\x8f\xe7\x6f\xe7\xee\xd4\xcd\xbf\x9f\x77\xcf\xf3\xf3\xe6\x79\xde\xf5\x17\xd5\x6b\x77\xec\x77\x87\x3d\x16\xf3\x4b\x34\x0d\xae\xae\xe9\xee\xf0\x4a\xef\xae\xab\xea\x53\xdf\xf5\xe8\x5f\xda\xfd\xae\x7f\xc0\xe6\xa1\x3d\xb6\x9b\x53\x77\x44\xdf\x9d\xf0\x63\x77\x7a\x40\xf3\x01\x87\x97\xd3\xee\xb0\xbf\xa9\xf0\x2f\xbf\x75\x38\x55\x9f\xc1\x68\xff\x03\xa0\xc0\xe8\xcc\x01\x5f\xc0\xd8\xc9\xe9\x17\x18\x07\x39\x69\x30\xce\x72\xfa\x0d\xc6\x5e\x94\xff\x80\x71\x57\x55\x75\xbd\x8a\x9f\x55\xa5\x6b\xfb\x70\xbd\xaa\x20\x17\xe6\x0d\x88\xff\xdc\x25\x1b\x99\x01\x5e\x55\xa4\x95\x39\x2b\x23\xa6\x34\xc9\xbd\x00\x0c\x79\x21\x03\x10\x38\x00\xd0\x17\xe6\x8a\x0d\xac\x48\x05\x80\xac\x77\xff\x18\x65\xe3\x4b\x5e\xd5\xe0\x50\x3c\x41\x8b\xd5\x70\x29\x9e\x1b\x6e\xea\x21\x22\xef\x0c\x03\x60\xcf\x1e\x70\x8e\x68\x70\x86\x48\x12\x05\x49\x0e\x92\xa2\xc4\x36\xb3\x48\x92\xd8\x78\xd6\x64\x82\x53\x1c\xd5\x42\x6e\x6c\x0d\xa2\xca\x89\xb4\x2b\x50\x22\x6d\x01\x5e\x8e\xcd\x40\xec\x2c\xd9\xda\xd0\x01\xd0\xa2\x31\x6b\x54\xe6\xd8\x46\xc4\x05\x40\xd4\x69\x56\xce\xe1\x36\x77\x4e\xce\x48\xe6\xdc\xd7\x26\xd4\xc7\xbd\x50\xd2\xc7\x25\xa7\x7d\x5c\xaf\x3d\x9b\x22\x8a\x49\x73\xf9\x36\x6d\xae\xaf\x07\x8d\x7b\xe8\xb2\x9b\xd1\x54\xda\xd2\x08\x24\x80\xe1\x9e\x5e\x0a\x5b\xe5\x9c\x6a\x00\x63\x53\x2c\x21\x69\x49\x98\x29\x77\xce\x99\x46\x0c\xe8\x02\x3d\xb0\xce\x34\x30\x11\xae\x9f\x49\xed\x2b\x69\x4d\xac\x91\x31\x4c\xdb\x59\x71\x4e\xe3\xa1\x02\xca\x89\x91\x9d\x3d\xcd\xce\xad\xf7\x1b\x47\xa4\x0a\x05\x54\x43\x39\x8a\x59\xd3\x54\xd6\x56\x43\x4d\x69\x64\x80\x5b\x29\x85\xc1\xb0\x14\x48\x88\x80\xa9\xa8\x80\x28\x49\x28\xdf\x40\x0f\xc2\xe1\x60\xcd\xf0\x22\x41\x0a\x9e\x95\xf1\xc0\x47\x91\xc6\xc0\x88\x99\x54\x9e\x6d\xcd\x7e\xa5\x69\x8e\x58\x8f\x60\x26\xb6\x6f\xa3\x16\x16\x64\x7b\x23\xd4\x78\x18\xc4\xf1\x55\xc5\x66\xbe\x56\x95\xca\x16\x2b\x6c\x60\x3a\x9a\x68\x47\x23\x0c\xfb\x42\x27\xab\xc7\x69\xdc\x88\xc6\x4d\x0c\xe8\xb2\x29\xaf\x61\xb7\x46\x52\x9b\x3a\xae\x03\x26\x22\x92\xff\x51\x44\xa5\xb5\xa3\xd3\xa4\xe0\x3e\x35\x89\x09\x99\x5d\x21\x74\xf8\x98\xc1\x07\xa0\x38\x8e\xc2\x47\xed\x1d\x7a\x97\x79\x52\x69\x34\x49\xb6\x59\xe1\xf4\x78\x3a\xca\x3d\xd0\x16\xa8\x7d\x91\xf2\xfa\xc8\xa2\x4d\x08\xd5\x94\xf3\x28\xcf\x43\x02\xa8\x14\x70\x7b\x42\xdb\xcf\x72\xbc\x0d\x2c\xa6\xe6\xe6\x8e\x66\x6a\xc2\x5c\xdc\x35\x1f\x2e\x8d\xf9\x2f\x03\xe3\x86\x31\xf4\xa2\x0e\x4f\xf8\x0c\x08\x45\x92\xcf\x00\x4d\xf1\x9e\xa6\x28\x48\x65\x0a\xda\x28\x30\x2e\x31\x4d\xb5\x90\xc2\x7a\x8e\x81\xa6\x69\xca\x6c\x70\x57\xf9\xfa\xfc\x1b\x00\x00\xff\xff\x57\xd0\xd4\x0a\x85\x0a\x00\x00")
+
+func fontsMadridFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsMadridFlf,
+ "fonts/madrid.flf",
+ )
+}
+
+func fontsMadridFlf() (*asset, error) {
+ bytes, err := fontsMadridFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/madrid.flf", size: 2693, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsMarqueeFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\x4d\x8f\x1c\x35\x10\xbd\xcf\xaf\xa8\x43\xae\x98\x30\x42\x22\xf8\xd4\x1c\x92\x1b\x07\x56\xe2\xbe\x41\x9a\xa0\x95\x56\x20\xc1\x5e\xe0\xd7\xa3\xe9\xb6\xcb\xef\xbd\x2a\x77\xcf\x2c\xab\x6c\x36\xdd\x76\xb7\xbb\xbe\xeb\x55\xd9\xfb\xe5\xf9\xcb\xf9\xf3\x3b\xfb\x60\x3f\xd8\xf9\xbd\x7d\xf3\x9d\x9d\x4f\x3f\xff\xf4\xf0\xcb\xaf\x1f\x3f\xda\x6f\xff\xd8\xc3\x9f\x7f\xd8\xa7\xbf\x9e\x5e\xfe\xb5\x0f\xdf\xfe\xf8\xfd\xe9\xd3\xd3\xef\xcf\x97\x17\x7b\xb8\x3c\x5f\x3e\xff\x7d\xb1\x73\x79\x7f\x7a\xb7\x24\xbf\xb6\x2c\xa7\x52\x2b\x5f\xac\x5d\xcc\xac\x3d\xbb\x8e\xd6\x87\xa5\xfa\xcd\x6c\x7d\x7f\x7c\x6b\xf7\xfe\x73\x9d\x96\x5a\xad\x5d\x57\x0e\xeb\xcf\x7a\x0f\x6f\xef\x5c\x8c\x8c\xd6\x79\x7f\xb3\x4a\xbd\xa9\x56\x45\x8e\xed\xbb\xf1\x76\x1b\x45\xaa\xa0\xc9\x4a\x70\x5d\x89\x1f\x47\xa9\xdb\xba\x6e\xc9\xb1\x0e\x09\x96\xca\x04\x41\xc2\xab\x9a\xfe\x71\xce\x58\x24\xdc\xde\x34\x07\xcd\x2f\x4d\xc4\x46\xae\xd1\xd7\x9b\x8b\xeb\xec\x1a\x87\xec\x25\xdd\x88\x28\x1b\x4f\x34\xf1\x4b\x33\x5f\x77\x54\xf7\xb5\x75\x8f\xc7\xf7\xc9\xf7\x4c\x3f\x09\x07\x08\xc2\xe8\xfe\xce\xb4\x0c\x86\xe9\x1a\xa5\x83\x0c\x76\x2e\xee\x9a\xfe\x55\xbc\x23\xe7\xec\xfd\x5d\x9c\xd8\xe8\x6d\x38\x22\x70\x78\x67\xe8\xe5\xc1\x0a\x66\xec\x23\x54\x56\x92\x1a\xcd\x03\x84\x30\x9a\x28\xc3\x40\xa6\x36\xc5\x04\xca\xfc\xb7\x38\xa8\x48\xf8\x65\xb7\x02\x46\x0c\x49\x5b\x3b\xc0\xad\xcc\x38\x7d\x4b\xc8\x36\x8a\xbe\xa0\xfa\x48\x6a\xb1\x29\x07\x61\xad\xc5\xf5\xb9\x0a\xe0\x64\x8f\x6d\x2a\x01\x88\xb3\x9e\x08\x9c\x09\x90\x37\x31\x2b\x72\x9b\x92\x26\x95\x3d\x2e\xee\x20\x44\xec\x60\xa5\xb0\x26\x9a\x50\x70\x40\xbc\x51\xc4\x59\xf7\x89\xb8\x00\x3d\x13\x41\x5e\x72\x7a\xb3\xaa\xaa\x0d\x81\xbf\x93\xf7\xb9\x91\x72\x4d\xfa\x24\x0f\x72\x90\xd7\x24\xfc\xdb\x1b\x30\xc5\x0e\x23\x05\x3a\x37\xb8\x31\x39\xf6\x0a\x05\x48\x92\x49\x13\xec\x70\xc4\x10\xec\x38\x5c\x08\x70\x46\xd5\x90\xe1\x84\x30\x04\x43\x21\x89\xa8\xc4\x26\x30\x28\x92\x8f\xd9\x93\x30\xb8\x5f\x80\x03\x15\x88\xb0\x10\x1b\x8e\xa0\x67\x45\xbd\x9e\x3e\x93\xaa\xe5\x14\x30\x61\x8c\xdb\x1a\xa8\x80\x2d\x4b\x0a\x83\xeb\xe3\xe3\x63\xc0\xe8\xbc\x59\x1a\xd1\x0d\xf1\x64\x82\x00\x59\x2e\x53\x05\xe9\x49\x48\x48\x18\xe0\x3f\xb8\x9b\x7c\x35\x60\x00\x3f\x1d\x5f\x35\xd8\x81\x35\x9a\x1d\xd0\x3f\x64\x29\x2d\xfd\x19\x35\x5e\xe4\x6e\x19\xe3\x7a\xf3\x6c\x16\x06\x0d\x88\xe0\x63\x52\x1e\x99\x4d\xc6\x50\xc8\x02\x58\x2c\xa3\x2c\x55\x05\x6b\x18\x76\xc9\x76\x17\x68\xc2\xbd\x09\xe1\x10\x61\x0b\xda\xaa\x87\x6d\x12\x11\xe9\xa4\x57\x73\x37\x12\xc4\x59\x82\x6e\x04\xb7\xbb\x93\x51\x2c\x6e\xfc\x26\x30\x3a\xba\x40\x62\x51\x07\x76\x34\x2a\x15\xfb\xa3\x9a\xf4\xf8\xc6\x85\x07\xab\x26\x20\x96\x67\x73\xb2\x2c\x6b\xcf\x66\xb6\xbc\xc5\xd9\xf7\x86\x59\x9b\x74\x7d\x87\xaf\x87\x16\x05\x7c\xc0\x20\xe7\x38\x94\x90\xa2\xa9\x59\xd0\xa8\xe6\x7c\xc1\x78\xcc\x95\x99\x72\xbe\x1a\xb1\x0c\x1c\x07\xd6\xc4\x8e\x47\xac\x1f\xe5\xcf\xe7\x03\xc2\x0b\x76\xf2\x59\xa9\xe7\x8c\xb6\x7d\xfc\x89\x59\xbd\x07\x82\x53\x0d\x45\xc1\x23\xf7\x04\x6f\x15\xef\x5c\xa1\x60\x69\x9e\xaf\x9b\x5e\x94\x5a\x1a\xc6\x64\x66\x1a\x9e\x5a\xd7\xd5\x1d\xb9\x2f\xbb\x34\x6c\x3e\xa9\xaa\x52\xd5\x23\xf4\x23\x9d\xe0\x2b\xe3\x7e\x86\x89\xbd\xcd\x8c\x18\x46\x67\xbc\x7a\x72\x03\x2a\x27\x36\x73\x67\x63\x60\xe7\xcd\x85\x27\x24\xab\x26\xc1\x9f\x55\xa0\x4c\x90\x9d\x7c\x2b\xdc\x13\x04\x90\x40\x60\x18\xc5\x2c\xcf\xd7\x99\x00\x68\x06\x57\xb9\x40\xef\x63\xd2\xc3\xd3\xbb\x14\xc2\xd3\xa8\x4d\x19\x92\xd1\x67\x0c\xef\x99\x31\xc3\xb0\x11\x03\xa7\x26\x1e\x35\x49\x1d\xe9\x1c\xb1\x8e\xd4\x5c\x43\x37\xfd\xe1\x2d\x1c\x65\x09\x3b\xdd\x20\x04\x59\x21\xa5\xa6\xfb\x16\x3c\x9e\xdc\xbf\x25\x67\x15\x85\xa1\xb4\x1c\x94\xe9\xd7\x4c\xfa\xec\xfe\x7b\x3b\xa1\xf2\x2e\x27\xee\x10\xf9\x42\x08\xa7\xe3\xa1\xa9\xa7\x59\xd6\x30\x4b\xac\xd6\x88\x9a\x20\xdd\x64\x48\x56\xe4\x46\x9b\x16\x44\x1b\xc9\x86\xb2\x60\x37\xea\x6c\xe0\xc9\x58\xc3\x84\xe6\x7d\x1f\x82\x49\xda\x01\xb2\xd3\x6f\xb7\xa9\x6e\x24\x68\x8b\x64\xa3\x8f\x9e\x16\xf5\xa5\x6f\x38\xaf\x9f\xf9\xc1\x3f\xa1\xd5\x64\x10\x24\xd5\x21\x23\x99\x7a\x04\x9e\x76\x43\x51\x66\x82\x35\x4e\x23\x73\x71\x44\xc7\x2f\xc1\xba\xd5\x32\x9b\xe2\xc9\xf9\x41\x3f\xef\x4a\xa4\xf3\xf4\xbe\xf5\x9e\xcb\x4c\x60\xd9\xc4\x37\x93\x57\x8a\xe0\x99\xe8\x6e\xb3\xf9\x75\xc4\x64\x7e\xc8\x60\x64\x50\xaf\x70\xe0\x21\x71\x4d\x3e\xdd\x94\x2c\x2a\xe4\x7e\x38\x14\x3d\x30\x08\x31\x40\xe6\x09\xc4\x5f\x8d\x32\x42\x3d\xed\xdf\x42\xbc\xa1\xdc\x03\x57\x06\x61\x45\x95\xd4\xe1\x39\x41\x03\x5c\x41\x82\xc3\x11\x85\x3a\x63\x1f\xd5\xc9\x61\x99\xc2\x55\x1c\x14\xc9\xff\x1c\xf7\x36\x98\x40\xb8\xb3\x76\x58\x6c\xa2\x2e\x13\x52\x60\xb8\x0d\x45\xa8\xb8\xce\x8d\xaf\x5b\xb5\x7c\x64\xcd\x6c\x13\x00\xd5\x32\xc9\x75\x36\x2d\x40\x2e\x64\xd2\xc7\xe4\x75\x36\xe1\xc4\xac\x9c\x57\x65\xd8\x1f\xb3\xed\x17\x52\xc0\x42\x2d\x3c\xc8\x30\x44\x74\x08\x76\x1b\xd5\x42\x8a\xee\x24\xc3\xa6\x84\x8b\xfc\xf1\x34\xfc\x59\x44\x51\xff\x80\x30\x05\x94\xa4\xe7\x22\x67\xb3\xd9\x29\x83\xc9\xa6\x99\xe2\x90\xb7\xab\x52\xbb\x24\x8e\xb7\xd3\xc4\xed\xff\xf6\x35\xcd\x6f\x25\xb7\x23\xc4\xe0\x54\xbd\xe2\x5a\x8a\xa3\xff\x6b\xbc\x9c\xe4\xdf\xd7\x7a\xf0\x5f\x00\x00\x00\xff\xff\x20\x3b\xa8\x10\xbe\x20\x00\x00")
+
+func fontsMarqueeFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsMarqueeFlf,
+ "fonts/marquee.flf",
+ )
+}
+
+func fontsMarqueeFlf() (*asset, error) {
+ bytes, err := fontsMarqueeFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/marquee.flf", size: 8382, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsMaxfourFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x55\x4d\x6f\xe3\x36\x13\xbe\xf3\x57\x3c\xaf\x21\xc0\x0e\x36\x34\xe3\x4d\xde\x43\x8a\xa0\x60\x0f\xed\xad\x97\x9e\x52\x80\x00\xcb\x48\x94\x2d\x44\x96\x16\xfa\x68\xb2\x00\xa1\xdf\x5e\x70\x48\x4a\xb2\x77\xb3\xbd\x14\xd0\x07\x35\x9c\x8f\x67\x9e\x19\x8e\xca\xba\xfc\x6c\x32\x3c\xe0\x1e\x87\x03\xee\x70\xb8\x67\xbf\x9b\xf7\xb2\x1d\x3b\xbc\x7c\xc5\x1f\xa6\x29\x4c\x5d\xfb\x77\xdf\x9e\x71\x10\x8f\x0f\x78\xea\x47\x63\x72\x99\xf7\x7f\xef\xdf\x4c\xf7\x56\xe5\xaf\x7b\x93\xef\xc7\xd7\x9f\xd9\x6f\xd5\xb1\xb6\x03\x3a\x5b\x5b\xd3\x5b\x7c\xde\xdf\x81\x73\xfc\x32\x1e\xc7\x7e\xc0\xff\x6f\x71\x78\x7c\xbc\x67\xec\xd7\xf7\x2f\xb5\x69\xcc\x50\xb5\x0d\xda\x12\x65\xd5\xf5\x03\xea\xaa\xb1\x3f\x31\x0f\x06\x1c\x9b\xb3\x39\x56\x39\x9a\xf1\xfc\x62\xbb\x0d\xca\xb6\x43\x59\xd5\x16\x55\x61\x9b\xa1\x2a\xab\x9c\x8c\x99\x01\x00\x8e\xfe\xd4\x8e\x75\x01\x53\xbf\x99\xaf\x3d\x5e\x2c\xfe\x32\xdb\x5b\x32\x6a\xda\x37\x96\x05\xa5\xe1\x64\xb1\x39\x99\xae\x78\xa9\x4d\xf3\xba\xf1\xb8\xbe\x74\x55\x33\xf4\x30\x3d\x0c\x48\x7a\x8b\x97\x71\x40\x6e\x9a\xed\xe0\xdd\xf4\xe7\xb1\x3f\xd9\x82\x3d\x04\x0f\x27\x5b\x1d\x4f\x83\x47\x6c\x90\x9f\x4c\x67\xf2\xc1\x76\xec\xfe\x07\x9b\xb7\x68\xda\x01\x55\x93\xd7\x63\x51\x35\x47\x14\xb6\xcf\x6d\x53\xd8\xae\x67\x87\x03\x99\x9d\xcd\x3b\x65\x8e\xda\x36\xc7\xe1\x84\x9d\x7d\x4f\xca\x79\x7b\x3e\xdb\x26\x10\xd3\xdf\xe0\x13\x0c\xca\xb1\x38\x5a\x94\x26\x1f\xda\x8e\xdd\x85\xc0\x85\x2d\xcd\x58\x0f\x01\xec\xb9\x2d\x2c\x25\x3e\x9c\xaa\x1e\x65\xdb\x0c\xd8\xd5\xd5\xab\xc5\x86\x9f\x71\xb7\x41\xdb\x90\x5b\xd3\x14\xe4\xf6\x86\x1d\xee\xc9\x49\x20\xda\xa3\xbf\x88\xca\x58\x96\xc9\xf5\x2d\x99\xa3\x6b\x2f\x19\x7d\xb8\xab\x5d\xec\xb1\xcf\x24\xe3\x8e\x3b\x3e\xbf\xb0\xc5\x36\x69\xef\x26\xc9\xf4\x0d\xad\x25\x6b\x21\x24\xcb\x44\x26\x99\x40\x2b\x59\x06\xaf\x95\x45\xad\x9d\xa6\xb5\x64\x5e\x27\x5e\x92\x79\x0b\x87\x70\x43\x49\xc9\x94\x5f\xb8\x70\x0b\x90\x40\x48\xc6\x9f\xb9\xff\x54\xb3\x53\x42\xf5\x89\x4b\x96\x6d\xb3\x59\x48\x57\xeb\x23\x04\x11\xe3\x9c\xc7\xd5\x95\x06\x85\xf6\x8e\x21\xe0\x1d\xfb\xa0\x00\xe1\x99\x26\x45\x78\x00\x82\xa1\xb4\x16\x61\x37\x28\x08\x42\xea\x1f\xda\xe9\x64\x25\x26\xe5\xb9\x12\x92\x09\x7d\x25\xc4\x93\x64\x4a\x8b\xc5\xbf\x37\x15\xd1\xd6\x45\xcf\x9e\xcc\x69\x92\x6c\xeb\x4d\xf4\xa2\x2d\xbc\xf0\x4f\x2f\x5c\xb9\x98\xa6\xef\xe0\xde\x4d\x37\x31\xa2\x5a\x9b\x2b\xc9\xb6\x3c\xa9\x07\x61\x20\x20\x72\x30\x7f\x88\x58\x0b\xaf\xa7\x52\x2d\x16\x0e\x67\x22\xe7\xdd\xa4\x9d\xf2\xa4\xa8\xff\x5b\xa2\x78\x1e\x33\xcf\xe3\xce\x69\xdf\x55\x4a\xeb\x50\x07\x00\x91\x7d\x45\xf0\x85\xd6\x2a\xe4\x02\x72\x8b\x85\x10\x25\x99\xe3\xfc\x49\x32\x97\x38\x49\x25\x0a\x05\x0a\xe5\x59\x53\x98\x4a\xe7\x82\x4d\x2a\x5c\xe2\xd7\xf9\x34\xdc\x52\xa2\x95\xf0\xaa\x05\x48\x42\x8a\x6a\x8e\x4d\x16\xc1\x37\xe7\x2e\xad\xe3\xc6\xe4\xa6\x6f\xfb\x62\x0a\x52\x12\x2b\xbd\xae\x36\xf5\xfd\x8e\xd0\xaa\x19\x0d\x90\x1e\x2b\x88\x0a\x10\x14\x4c\x09\xb8\x55\x63\xce\x88\x54\x80\x04\x15\xb7\x95\x5b\xe0\xfe\x6b\x3b\x47\x96\x29\xc7\x48\xe9\xc7\x96\xcf\x3f\xb0\x54\xb3\x65\xa0\x6f\xcb\xf9\xde\x27\xbd\x2a\x9c\x67\x23\xd2\x81\xd5\x6b\x4e\x3e\xa5\x17\xa2\x89\xab\xcd\x20\x46\xec\x64\x25\x70\x01\x86\xbc\xb9\xd5\xc2\x6b\xa8\x25\xd5\x79\x92\xe0\x19\x71\x92\x24\x61\x98\x03\x2a\x3a\xbe\x00\xb5\x3a\x6a\xeb\xa6\x59\x46\x96\xd3\xc1\x05\x39\x20\x5c\x73\xe9\xdd\x32\xc7\x34\x8d\x3d\x75\x35\x5b\xd7\xa3\x58\x93\x9f\x8b\xc1\x48\xc5\x10\x93\xf7\xa3\xb4\x76\xab\xd6\xa1\x0e\x59\xb1\x9f\x2a\x16\x0d\x48\x7f\x6e\x66\x22\xe3\x3b\x6e\xa2\xb6\x90\x4c\x09\xbd\x6a\x7d\x45\x63\x3e\xcc\x38\xac\xb5\xaf\xd0\xd0\x33\x56\x46\x32\x27\xd6\x47\x2f\xd1\xb7\x4d\xbf\x97\xe8\x62\x9b\xf0\x84\xe7\xe2\xc2\x67\x22\x2e\xcf\xc2\x95\x69\x2c\x62\x08\xb4\x0a\xb6\x3e\x0c\x0b\xd4\x0f\x11\xc5\x34\x2e\xc7\x24\xbe\x61\xd4\x5d\xb8\xf2\x69\x23\xc0\x0d\x8c\x38\xb1\x58\x89\x38\x2b\xd6\x5c\x2d\xbf\xc5\x20\xf0\x66\xcb\x7c\xb8\x84\xb9\xf4\xfb\x25\x4c\x9a\xc3\xa1\x33\xc5\x65\x1d\xe2\x56\xda\x54\x17\xe7\x99\x36\x45\xe8\xb6\x0f\x5c\x69\x31\x6b\x4e\xf4\xc7\x9a\x61\x4e\xf1\x97\x12\x1a\x9a\x7a\xdb\x2d\x97\xcf\x61\xe9\x71\xe1\xdb\x7a\x09\xa0\xb9\xe6\x69\x9d\xa0\x2c\xd7\x7f\xfd\xc1\xfe\x09\x00\x00\xff\xff\x4a\xf6\xac\x28\xe4\x0a\x00\x00")
+
+func fontsMaxfourFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsMaxfourFlf,
+ "fonts/maxfour.flf",
+ )
+}
+
+func fontsMaxfourFlf() (*asset, error) {
+ bytes, err := fontsMaxfourFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/maxfour.flf", size: 2788, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsMikeFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x92\x5f\x6f\xd3\x30\x14\xc5\xdf\xfd\x29\x0e\x72\x85\xf8\xb7\xdc\xb5\x19\x8c\xc2\x18\x93\x90\xe0\xa9\x4f\x7b\x24\x60\x85\xd6\x49\xad\x19\xa7\xca\x9a\x01\x92\xb5\xcf\x8e\x12\x27\xd7\x6e\xe1\x91\x17\xa4\xa9\x8d\xf3\xbb\xf2\xcd\xb9\xd7\xe7\xba\xb2\xd5\xa2\x9c\x21\xc7\x02\xf9\x29\x4e\xe6\xc8\xc5\xca\xdc\x68\x7c\xfb\x85\x95\x59\x6f\x4b\x6d\x71\xdd\x59\x6b\xee\x4a\x87\xf9\x72\x79\x26\x3e\x9a\xda\xea\x3d\xee\x74\x7b\x6b\x1a\x87\xa6\xc2\x77\x73\xa3\x7f\xb4\x66\x6f\x5c\x8d\x5a\x3b\xdd\x96\x7b\xbd\xe9\x05\xb6\xa5\xdb\x64\x59\x26\x56\xc6\x35\x2d\x74\xdb\x36\xed\x2d\x2a\xf3\x33\xec\x7e\xb2\xda\x39\x7c\xd8\x96\xbb\x9d\xb6\x16\x17\x75\xbd\xbe\xea\x4c\xb7\xce\xf4\xa6\xbb\xc4\xe2\x1c\xd7\x7a\x17\x4a\xce\x66\x72\x7a\xa4\x78\x24\x05\xfa\xbf\x14\xde\x4b\x01\x0c\x4f\xbf\xd0\xfd\xbd\x22\x5e\x49\x0a\x10\x14\x81\x57\x82\x14\xd4\x23\x92\x75\x90\xe9\x35\x82\xd8\x10\x93\x14\xe4\x27\x59\x29\x1e\x87\x6a\xc4\x75\x21\xc5\x13\xa6\xa7\x4c\xcf\x98\x9e\x33\xbd\x60\x3a\x61\xca\x98\x88\xe9\x94\x69\xce\xb4\x60\xca\x99\xce\x98\x5e\x32\xbd\x62\x3a\x67\x7a\xcd\xb4\x64\x7a\xc3\xf4\x96\xe9\x82\xe9\x1d\xd3\x65\xa0\xf7\xe9\x79\xaf\x46\xc2\xe0\x37\x05\x7b\x82\x41\xc1\x3d\x9a\xdc\x0b\x19\x5e\xc5\xb8\xcf\x2d\x7c\x8c\xd5\x61\xbe\x2f\x26\x91\xe4\xfb\x50\xc0\x47\xfd\xe2\x70\x5f\xf9\xc3\x18\x31\x7f\xd4\x1e\x15\x63\x0b\x48\x3f\x09\x13\x2f\x92\x94\xbf\x55\xc1\x51\x95\xa9\x55\x96\x18\xab\x78\x8a\x07\x3b\x3e\x48\x62\x8c\x0a\x7b\x3e\xad\x1a\xcc\xf3\xc7\x8d\xd0\x1f\xbd\x52\x92\xd2\x1b\xca\xd7\x7e\x10\x0d\xb7\x9d\xbb\x40\xb4\x5f\x8a\xcf\x3c\xc5\x82\xe9\x0b\xd3\xd7\x69\xb2\x52\x28\x35\x8a\x16\x71\xf4\x0f\x03\xff\xcf\x06\x3e\xfc\xfe\xd5\xeb\x77\x00\x00\x00\xff\xff\x46\xb0\xae\x62\x1d\x06\x00\x00")
+
+func fontsMikeFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsMikeFlf,
+ "fonts/mike.flf",
+ )
+}
+
+func fontsMikeFlf() (*asset, error) {
+ bytes, err := fontsMikeFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/mike.flf", size: 1565, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsMiniFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x59\x5d\x6f\xa3\x3a\x13\xbe\xcf\xaf\x98\x0b\xa4\xed\x91\x96\x12\x9c\x34\x4d\xa4\xd5\x6a\x29\x71\x5b\xb4\x04\x72\x80\xec\xb6\x12\x12\x9b\xdd\xd2\x36\x3a\x29\x54\x09\x39\x47\x95\xf8\xf1\xaf\xc0\x06\x6c\x18\x47\x7a\x2f\x4a\x52\xec\x79\x3c\x1f\xcf\x8c\xc7\xce\xf3\xfe\x99\x6c\x35\x98\xc2\x04\xcc\x31\x8c\xf9\x63\x41\xc6\xa3\xd5\x2e\xdb\xc1\xef\x0f\xb8\xdb\xa7\x59\x06\xf6\xeb\xf6\xfd\x3d\xdd\xef\x61\x6a\x2c\x26\x23\x27\xfb\xb3\x3f\x3d\xa5\x47\x70\x42\x1f\xdc\x6d\xb1\xcb\x74\x73\xf4\xbc\x7b\xd9\xa7\x05\x1c\xd2\x7d\xba\x3d\xa6\x40\x2e\x4d\xd0\x75\x30\x09\x58\xa7\x17\x30\x17\x8b\xe9\x68\x9d\x1e\xde\x76\xc7\xe3\x2e\xcf\x60\x77\x84\xd7\xf4\x90\xfe\xfe\x80\x97\xdd\xbf\x69\x06\x45\x0e\x6f\xf9\xd3\xee\xf9\x03\x8a\xd7\xdd\x11\x9e\xf3\xac\xf8\x0c\xdb\x23\xec\xf3\xec\xa5\xfa\x2c\x5e\xd3\x51\x3d\x61\x97\x1e\x3e\x1d\x21\xdb\xbe\xa5\x15\xc6\xfb\x7e\xfb\x27\x7d\x82\x3c\x83\x2d\xfc\xc9\xdf\xde\xd2\xac\x80\xfd\x2e\x4b\x2f\x47\xa3\x15\x9b\xfd\x54\xd9\xb0\xde\x9e\xf6\x70\x73\x3a\x14\x79\x06\x5f\x8e\xf9\xfe\x54\xec\xf2\xec\x5b\xba\x3d\x14\xaf\xfb\x5d\xf6\xcf\x65\x96\x16\x5f\xc1\x24\xc6\x62\x56\x29\xb2\x63\xd6\x41\x96\xfe\x07\xef\xdb\xc3\xf6\x2d\x2d\xd2\xc3\xe8\x78\x7a\x7f\xcf\x0f\x05\x03\xbc\x75\xee\x2a\x5b\xb7\xd9\x53\xf5\xf5\xe7\x2e\xbb\x04\x58\x6d\x3f\x60\xbb\x3f\xe6\xf0\x3b\x85\xe3\x7e\xf7\xf2\x5a\xec\x3f\xe0\xad\xd1\xe2\x39\x3f\xc0\xef\xb4\x28\xd2\x03\x9c\x8e\xe9\x28\x7f\xae\xe1\x9f\x4f\xfb\xbd\xfe\xdf\xee\xa9\x78\x35\xfe\x49\x0f\x99\x71\x7c\x3b\x1d\x5f\x61\xbb\x2f\xd2\x43\xb6\x2d\x76\xff\xa6\xc7\xcf\xf0\xfb\x54\xc0\x53\xfa\xbc\x3d\xed\x0b\xc8\x4f\xc5\xfb\xa9\xa8\x2c\xf7\xfc\x08\xfe\xbc\x6e\xb3\x97\xf4\xe9\x72\x34\xd2\xb4\x6f\xe2\xdf\xb7\x11\x00\x7c\x1b\x41\xa9\x7d\x1b\x41\xae\xb1\x7f\xeb\x67\xfd\xb6\xd4\xda\xef\xdd\x00\xfb\x5f\x2f\xf5\x52\xd7\xc4\x2f\x7c\xa8\xfe\x96\x54\x2f\x2e\x4a\xad\x9a\x99\x94\x7f\x35\xc3\x1d\xb4\x6f\x54\xef\x0c\x5f\x93\xa1\x2b\xa9\xbf\x6a\xa9\x8b\xe4\x41\x96\xaa\xa6\x6b\xcd\x37\x11\x8a\xbd\x66\x6b\x41\xac\x75\x03\x31\x7b\x55\x1b\x61\x68\xe2\x1a\x71\xc9\x96\x2f\xe3\x9e\x66\x4c\xdf\x5a\xfb\x06\x51\x54\xa0\x7e\xe4\x0c\xaf\x5b\x27\x49\x10\x37\x49\xb3\x87\xea\x1a\x9a\x38\x3b\xa9\xff\x33\xa0\x56\x27\x4e\x8c\xa1\xbf\x8c\x52\x6b\x6d\xe1\x03\x4c\x08\x6a\xe7\x1a\xc9\x60\x20\xa9\x07\x92\xbf\x7a\x1e\xae\xe3\xda\x98\x28\xd8\x28\x2a\x52\x72\xe8\x44\x0e\x9c\x34\x58\xca\x83\xdc\x07\x4a\xdb\x2e\xd8\xf4\x0b\x14\xf2\x22\x29\x1b\x75\xfa\x1e\xcf\x07\xc4\x94\x5e\x1a\x9a\x4c\x8e\xb8\xef\x6d\x9d\x71\x54\xd7\x7a\xb1\x89\x35\x81\x4f\x3d\x67\xe6\x92\xfe\x95\x69\x2c\x6e\xc0\xa4\x4a\xb8\x60\xf4\x81\xb8\x1e\x12\x1c\x0b\x06\xe3\x9c\xa1\xeb\x2d\xb3\x64\xdf\xd5\x0b\x94\x03\x2f\xb4\x5e\x8b\xc5\x40\x36\x52\x7c\xdd\x1e\x2f\x12\xf6\xb2\x7b\x62\x03\x72\x28\xd8\x42\xec\x23\x4e\x4a\x84\xfc\x25\x7b\x5b\xca\xa1\x48\x12\x31\x25\x5a\xf6\x48\x92\x3c\x7a\x43\xd8\x0a\x8e\xa5\x68\x2c\x73\xb1\xd5\x4f\x56\xbf\x19\x8a\x0d\xae\x4a\xa7\x4b\x6f\x02\xf0\x09\x71\x89\x39\x5b\x91\x4e\x72\x24\x34\x80\xe1\x60\x2b\xf9\x70\x46\x12\xe4\xda\xc1\x3c\x74\xc1\x73\xaf\x9f\x1c\x52\x45\xe9\x17\x16\x66\x0d\x37\x66\x18\x95\x9a\x16\x3c\xb5\x20\x36\x7a\x19\x2b\x4e\xe9\x26\x89\xd3\x44\x7f\xc7\x2c\x41\xe3\x61\xd9\x6d\xdc\x24\x2b\x27\xa5\x35\x42\x32\x34\x7c\x5d\xe9\x8d\x87\xe5\xaa\x36\x2f\x11\xeb\x58\xa7\xcd\x70\xaf\xe9\x3d\x2b\x75\xa4\x0c\x96\x37\x03\x56\xb4\x2e\x35\xb1\xa4\xf4\xd8\x8d\xd5\xae\x46\x90\x07\x70\xe0\x1a\xae\x2e\x0e\xd9\x94\x30\xa3\x97\x13\x89\x76\x66\x2b\x91\x24\x39\x6c\xf5\x31\xd4\x54\x55\x12\xcb\xc1\xb6\x92\x6b\x92\x7b\xfb\x29\xf6\xa5\x5f\x01\xcb\x21\x0c\x1b\xb8\x4c\xda\xba\x23\x2c\x2f\xa9\x7e\xa9\xd0\x4e\xb6\xab\xef\x64\x51\x52\x48\x3f\x75\xec\x44\x33\x2e\x91\x7a\x26\xc4\x2d\xf9\x3a\x8c\x5b\xeb\x7d\xbc\x5c\x89\xf5\x0e\xa3\x5c\x6c\x20\x55\xa9\x4d\x17\xa3\x1d\x1e\x4a\x7e\xfd\x32\x48\x08\x29\xfd\x34\x61\x80\x57\x1c\x89\x76\x9f\x75\x1e\x45\xb1\x5c\xfc\xd2\x6b\x6f\x74\x61\x6b\x1e\xd5\xfe\x76\xc9\xa7\x8a\x74\xd3\x3f\x69\x3c\xbf\xba\x02\x28\x7f\x54\x64\x6a\x88\xa3\xda\xb9\xf2\x84\x6d\xb4\x68\x31\xcd\x39\x19\xd1\xda\xc5\x07\xf1\x84\x6c\x07\x31\xae\x34\x83\x78\x88\x1a\xee\xf1\x32\x2c\x12\xc9\x9c\x8d\x01\x3c\x5f\xbf\x09\xa8\xf5\x1d\xc2\xb5\x65\xd3\x11\x54\xad\xae\xfc\xa8\x26\x9a\x00\x8e\xf7\x83\x06\x11\x5d\x02\x7d\xb0\x5d\x6b\x65\x45\x8e\xef\xc1\xca\x0a\xbe\xe3\x89\x66\xce\x08\x80\x4d\xbd\x08\x42\xe7\xce\xeb\x3c\x59\xf2\xc2\xd1\xf9\xbe\x9a\x3b\x01\x58\xfb\x1b\x6f\xd9\x4d\x4e\xf8\x5e\x93\x18\xc9\x2f\x4e\xe3\x32\x69\x7b\x47\x68\x16\x99\x02\xd8\x9b\x20\xa0\x9e\xfd\x28\x2f\xf4\x2b\xff\x54\xcd\xfd\x04\xbf\x04\x77\x98\xb3\x2b\x80\x47\xea\x09\x53\x19\xad\xe2\x84\x71\x4a\xd7\x4b\x5d\x6e\xcf\xcd\xd9\x0c\xe0\x26\xf0\xbf\x53\x0f\x6e\xac\x00\xa7\x94\x39\xbb\x06\x08\xa9\x5d\xfb\x84\x63\x33\x3b\x59\xc0\xda\xe6\xb2\x9a\x3a\x07\x58\x3a\x16\x0d\x68\xe8\x84\xfd\xe8\xc9\x7c\x33\x67\x0b\x00\xdb\x5f\x3f\x06\xce\xdd\x7d\xd4\x01\xd7\x11\xb5\xeb\xe5\x7f\xe9\x9f\x44\xfb\xae\xc7\x00\xb7\x74\xe5\x78\x8e\x47\xc1\x0f\x96\x8e\x67\xb9\xe0\x78\x4b\xc7\xb6\x22\x3f\xe8\xd3\x4b\xef\x6c\xad\x85\x4d\x00\x97\xde\x46\xfa\xda\x77\xbc\xc8\xf1\xee\x60\xe9\x6f\x6e\x5c\x0a\x96\x77\xe7\x52\xf8\x7b\xe3\x47\x72\xd4\xeb\x14\x60\x9d\xa4\xb0\x77\x99\xd7\x04\xea\x73\x94\x14\x8f\xa6\x2f\x94\x8a\xa0\x79\x3d\x01\x08\xfd\xdb\x08\xee\x1f\xd7\xf7\xd4\x1b\x35\x59\x2e\x6d\x56\xe6\xf5\x14\x20\xa0\x77\x4e\x18\xd1\x80\x2e\x7b\x7e\x08\x50\x3f\x5c\x01\xac\x2c\x3b\xf0\xbd\xe1\x81\xa3\xd3\x73\x06\xb0\xa4\x77\x01\xa5\x1c\xd2\x17\xd7\x6d\x17\xbf\x06\x58\xbb\x9b\x50\x5f\x39\xde\x26\xec\x19\x55\x4a\x1b\x57\x23\x31\x07\x08\x37\x6b\x1a\x84\x76\xe0\xac\x23\x88\x7e\xfa\x23\x20\x28\xf6\xa2\x37\xf3\x3e\xa0\x74\x04\x13\x6c\xee\x7c\x0c\x60\xd9\x9b\x88\x82\x65\x57\x79\xd5\x3b\xe0\xb5\xd3\x4c\x80\x95\x63\x07\x7e\x2f\xef\xa4\xea\xd0\x14\x80\x39\x01\x58\x3b\xae\x1d\xf8\x3f\x5b\xaf\xf2\x1a\xd3\xec\x56\xa5\xdc\x4f\x9a\xf3\x49\x85\xbf\x5c\xba\x14\x96\x7e\x24\xe6\xbe\xa8\x44\x95\x96\x74\xe9\xb8\xae\xd5\xd3\x70\x04\x61\x9d\x05\xf3\x2b\xd9\x72\xdf\xa3\x23\x30\x51\x83\x66\x55\x28\x43\x7b\xe3\x2a\x39\x2d\x56\xc5\x1e\xa7\xe7\xd7\x00\x75\xf6\xfc\x5f\xa4\x66\x74\x36\x84\x2d\xcd\x9c\xcf\x01\x7e\x6c\xdc\x3b\x2b\x80\xdb\xc0\x62\x99\xee\x7b\x15\x80\x15\x44\x34\x68\x24\x4d\xb6\x67\x4d\x45\xc9\x05\x2e\x79\x6f\xb9\xb7\x3d\x31\x22\x88\x2d\xc6\x43\xb1\x9a\x1f\xcd\x92\x61\x23\x3c\x19\xae\xb9\x10\x0b\xf6\xdf\x1b\x1a\x0e\x4c\x64\x31\x13\x1b\x38\x73\x41\x00\x5c\x2b\x72\x3c\xb0\xad\xb5\x13\x59\x2e\xb8\x34\x8a\x68\x00\x16\xfc\x74\xa2\x7b\xb8\x0b\xac\x1f\xb4\x9a\xcd\xfb\x55\xc5\x26\x68\x2e\x26\xe7\x71\x6a\x16\xd7\x7d\xf2\xd9\x63\xa0\xb9\x98\x9e\xc7\xb1\x9d\xc0\xde\xac\x6e\x5d\xfa\xd0\x81\xa8\xc1\xae\xce\x83\x45\x8e\xbb\xac\x95\xe2\xfb\xbf\x12\x67\x76\x1e\x47\x2a\xed\xe7\xbb\x05\x73\x71\x7d\x1e\x2b\xa8\xe8\x6a\xdd\xf8\xcc\xeb\x7e\xe3\x2e\x68\xe1\x04\x3c\x06\x38\x57\x01\x52\xbe\xa9\xd6\x00\xac\x5c\x19\x7a\x57\xb6\x98\xf4\x42\x21\x6d\x73\x7f\xb7\x19\x3d\x3c\x82\xd7\x59\x4d\xc6\x63\x05\x02\x95\x18\x14\x2b\x0e\xe3\x64\x6c\x9e\x97\x6f\x98\xc3\xfa\xaa\x52\xbe\x7f\x69\x30\x54\x2c\xa6\x38\x6b\xd4\x40\x2a\x1a\xd3\x61\xa4\x59\xdb\xa7\xc0\x51\xd1\xd8\xe9\x39\x45\x7d\x6b\x40\xc6\x2a\xf6\x3a\x92\x63\x12\xe9\x58\xda\xc7\x50\x31\xd7\x51\x3a\x86\x37\x5c\x7d\x20\x15\x6d\x1d\x95\x63\x14\x0a\xa9\xd8\x4a\xa3\xfb\x11\x34\x75\x3d\x29\x93\x98\x1f\x4c\xa4\x33\x04\x19\xab\xe8\xea\xa1\x19\xad\xba\x00\x21\xa6\x8a\xb4\xbe\x5c\xf6\x62\xf5\x3d\x09\x31\x55\xc4\xf5\x07\x25\x4f\x8d\xa1\x22\xae\xaf\x8c\x8f\x02\x48\x45\x5c\x5f\x72\x0c\xf7\x8b\x02\x43\x45\x5a\x5f\x15\x63\x05\x4e\xd5\x88\x6d\xdc\xc8\x59\xbb\xd5\x7e\x2d\xf4\xc7\xed\x36\xff\xd0\x9e\x19\x88\xa9\xa2\x28\x5f\x35\x8c\xaa\x46\xbc\xeb\x52\x0c\xee\x87\xd8\xe8\x71\xc3\x54\x51\x74\x83\xc5\x14\x3d\x91\x11\x53\x45\xcf\x0d\x16\x53\x05\x86\x8a\xa3\x1b\x75\x31\x42\x81\x88\x8a\xa4\x1b\x64\xdb\x51\x1f\x33\x09\x51\x11\xf5\x11\x33\x0a\xbd\xe6\x22\x44\x45\xd4\xe8\xde\x0f\xbc\xfe\xbd\x91\x7c\x69\x48\x48\x4b\xce\x70\x65\xb9\xad\x68\x78\x6f\x05\x6b\x08\xcf\x1f\x58\x09\x99\xa2\xc2\x16\x16\x54\xf4\x24\x4d\xc8\xd5\x39\x04\xd9\x7a\x05\xc2\xec\x1c\x02\x12\x50\x05\xcc\xf5\x39\x18\x39\x45\x15\x08\xf3\x73\x08\xc8\x11\x13\x47\x59\x9c\x43\x91\x3a\x10\xff\x8c\x57\x26\x63\x1c\x86\x0a\xa7\xec\x7a\x3b\xe1\x97\x78\x46\x22\x75\x2e\x64\x62\xa2\xf2\x83\xce\x63\x78\xf9\xc8\x3a\x8f\x09\x41\xe5\x29\xce\x0c\xe4\x12\x92\x4c\x70\x62\x52\x9c\x19\x28\x02\xce\x4e\x75\xdf\xa1\x80\xc1\x29\x8a\x74\x1d\xf2\xad\x50\x0f\x05\xa7\x69\xaf\xe7\x68\x0f\x5c\xdd\xc5\x0d\x99\xe0\xcc\x94\x3b\x0d\x03\x95\xc4\x19\x89\xf4\x17\xe2\x2d\xb6\x78\x4b\x49\x26\x38\x1d\x91\xce\x42\xbe\x37\x91\x2b\xd4\x14\x67\x63\xdd\x57\x3c\xf0\x7a\x14\xcb\x3f\xa6\x71\x41\x9c\x86\x1e\x96\x95\xe8\xb5\x2e\x99\xe2\x44\x44\x7b\x09\xf4\x3e\x8f\x4c\x71\x22\xa2\x9d\x84\x02\x01\x27\xa2\xba\x8f\x50\xc0\xe0\x44\x44\xbb\x08\x05\x02\x4e\x42\xa4\x87\x38\x73\xc1\x49\xa6\xd7\x00\x4b\xe7\x87\x13\x0a\xdd\x03\xfb\xd5\xb1\x39\xec\xe7\x72\xf4\x71\x1a\xf6\x7b\x08\x90\x7f\x91\x90\x97\xc4\x69\x88\x76\x0f\x80\x5d\xbc\x92\x2b\x9c\x82\x68\xef\xa0\x40\xc0\xb9\xa8\xee\x1c\x14\x30\x38\x21\x95\x7d\x83\x02\x05\x27\xe5\xa0\x6b\x68\xb3\x5a\xbc\xbc\x27\x57\x38\x21\x79\xbf\xd0\xae\x88\xfc\xd8\x41\xae\x70\x12\x3e\x0e\xd5\xcf\xf1\xc5\xff\x17\x00\x00\xff\xff\x41\xfb\x7f\x3b\x8b\x23\x00\x00")
+
+func fontsMiniFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsMiniFlf,
+ "fonts/mini.flf",
+ )
+}
+
+func fontsMiniFlf() (*asset, error) {
+ bytes, err := fontsMiniFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/mini.flf", size: 9099, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsMirrorFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x1a\xeb\x8a\xe3\xbc\xf5\xbf\x9e\xe2\xb0\x0c\x9d\x84\xce\x46\xb1\x72\x2f\xcb\x90\xd2\x1b\x0b\x2d\x2d\x7c\x65\xfb\x47\xa0\xf5\x24\x4e\x62\xbe\xc4\x59\x62\xcf\x5e\xc0\x0f\x5f\x74\x74\x24\x4b\xb6\x92\x78\x66\x76\x49\x3c\x89\xce\xfd\x7e\x34\xbb\xe3\x4e\xa4\x0f\x30\x87\x19\x88\x31\x24\x33\x48\x96\x90\xb0\x7f\xe5\x97\xcb\xf9\x02\x2f\xbf\xe0\xaf\xe9\xf7\x7c\x0b\xff\x4b\x8f\xd5\xb9\x80\x4f\x3f\xf0\x7d\xbd\x29\x47\xaf\x9b\x6d\xfa\x3d\x2f\x47\xd9\xf6\xf5\x19\x40\x4c\xe1\xcf\xaf\x7b\x48\x56\xab\x29\xfb\xef\x21\x2f\x21\x2f\x21\x85\x93\xc1\x92\x9f\xd2\x7d\x06\xdf\xb3\x4b\x99\x9f\x0b\x38\xef\x46\xa3\x11\xfb\xad\x4a\x8b\x6d\x7a\xd9\x6a\x12\xff\x38\x66\x45\x01\x7f\x39\xa4\xdf\xbe\x65\xc7\x23\xfc\x01\x3e\xa7\xf8\x6b\x0e\x13\xbe\x9a\xc0\xc7\x8f\xf0\x92\x96\xd9\x16\xce\x05\xfc\xfd\x92\x16\xbf\x3f\x96\x30\x2a\xf3\x3d\xfb\x5c\x6c\x8e\xaf\xdb\xac\x84\xcf\xbf\xfd\x1b\xfe\x99\x56\x79\xf1\x31\x61\xbb\x7c\x7f\xcc\x2a\xb8\x64\xc7\x2c\x2d\x33\x10\xa3\x44\x23\x48\x44\xc3\xdf\x7f\xb2\xcb\x29\x2f\x91\x97\xbc\x84\x43\x76\xc9\x5e\x7e\xc1\x3e\xff\x9e\x15\x50\x9d\xe1\x74\xde\xe6\xbb\x5f\x50\x69\x21\x76\xe7\xa2\x7a\x82\xb4\x84\xe3\xb9\xd8\xeb\xf7\xea\x90\x31\x3c\x90\x67\x97\xc7\x12\x8a\xf4\x94\x69\x1c\xdf\x8e\xe9\xc6\xf0\x97\xc2\xe6\x7c\x3a\x65\x45\x05\xc7\xbc\xc8\x46\x8c\xfd\xed\xe7\xb7\x63\x5a\xa4\x95\x91\x1c\x76\xf9\xa5\x34\xdf\xfd\x89\x69\xcd\xc3\x47\xf8\x70\x4a\xf7\xf9\x06\x8a\xd7\xd3\x4b\x76\xf9\x00\xbb\xf3\x05\x76\xf9\x31\x83\x7c\x9b\x15\x55\xbe\xcb\x37\x08\xcc\x52\x00\x80\x8f\x50\x1e\xce\xaf\xc7\x2d\xa4\xc7\x1f\xe9\xaf\x12\x5e\x32\xf8\x9a\x3e\x3e\x21\x50\x71\xfe\xc1\x1e\xcc\xa1\xea\x90\xc1\x87\x43\x7a\xd9\xbe\x1c\xd3\xe2\xf7\x0f\x5a\x01\xdf\x2e\x79\x51\x95\x5a\x86\x14\xf0\xd3\x27\x78\x79\xad\x60\x93\x16\x8f\x95\x46\x53\x9e\x5e\xcb\x43\xb6\x65\x73\x83\xe1\x90\xe5\xfb\x43\xa5\x39\x4e\x61\x73\x48\x2f\xe9\xa6\xca\x2e\x6c\x76\xe3\xcb\x27\x28\xce\x15\xe4\x68\x92\xbc\xd8\xc3\x36\x2b\x37\x59\xb1\xcd\x2e\x25\x13\x63\x04\x3b\xa5\x3f\x51\x72\x38\x66\xc5\xbe\x3a\xc0\x20\xfb\x69\x0f\xfb\x4a\x2b\x87\xf0\x47\x48\x61\xf7\xba\xdd\x67\xb0\x4b\x37\xd5\xf9\xc2\x92\x19\x62\xd8\x66\xbb\xf4\xf5\x58\x19\x66\x4f\xe7\x6d\x86\x82\x3b\x53\xb1\x64\x89\xc7\x8c\x2a\x35\x7f\x01\x5e\xc6\x1e\xd6\xad\xff\x6b\x06\x0a\xd6\xac\x86\xda\xbe\xa8\x7a\xcd\x06\x6a\xb8\x66\x00\x60\xbe\xd6\x07\x06\x50\x83\xfe\xec\x0b\x7c\x01\xfd\xd5\x03\xf8\x6f\x74\x14\x40\xe1\x7f\xfd\x99\xaa\xa1\xae\xa1\x46\xe4\x0a\x60\x34\x02\x50\xb5\x79\xd6\x3f\xfa\x19\xa0\x56\x75\xad\x6a\x87\xa3\x41\xa4\xf0\xb3\x1a\x6a\x4d\x5a\x29\x90\x6b\xc6\x41\x29\xbe\x66\x12\x00\x19\xd1\x70\xeb\x35\x53\x48\x51\x7f\x2c\x0d\xd3\x12\xa4\xa1\xaf\x1f\x50\x12\xa9\xa4\xc5\x4f\x4c\x2a\x83\x1e\x06\xa0\x60\x08\x6b\xc6\x25\x07\x85\xc7\x9f\x01\x3e\xa9\xa1\xd6\x83\xe4\x52\x29\xc5\x3d\xd6\xac\xae\x06\x48\x5f\x6a\x01\x1e\xc0\xbe\x80\x65\x06\x59\x21\xe6\xc3\x57\xae\xb1\xa1\x70\x6a\xcd\x80\x03\x47\x8d\x43\xf8\x0a\x9a\x5b\xc7\x2e\x53\x4a\xb3\x61\xa4\xd6\x00\x5c\x8b\x8b\xe2\x48\xde\xa8\xcd\x01\x80\x35\x82\xb5\x80\x55\x7f\xa3\x6f\x4f\xd9\x06\x2c\x78\x09\xe4\x0b\xb1\xd2\x83\xd2\x3f\x88\x55\xff\x20\x56\xed\x05\xf7\xb1\x36\x2e\xa5\x94\xc1\x85\xa6\x02\xcf\x66\x40\xaa\x03\x68\xdb\xcc\x9a\xcc\xda\xa9\x46\xdf\x30\x3e\xab\x8c\x8e\x5b\xe6\x6a\x3c\x5b\x76\xdc\xdb\xc3\xaa\x08\x2b\x8a\x52\xc3\x80\xe8\x48\x45\x74\x3c\x29\x1d\x56\x0b\x26\x09\x4c\xc3\xa3\x5e\x11\x5e\x11\x7c\x1b\x8c\x82\x03\xcd\x80\xa1\xd1\x04\x89\xb5\x91\x67\xa4\x96\xdf\x39\x56\x35\x43\x50\xb7\x79\xbe\x41\x93\x5c\x9d\xc2\x41\x83\x7d\x05\x02\x1b\x5e\xd5\x9b\xb5\x31\x58\x09\x9d\xa9\x1a\x5b\x69\x1b\xb5\xac\x6e\xad\x64\xe3\xca\x33\xd7\x0d\x6a\x11\xe3\xd2\xe9\x1a\x46\x74\x5a\xd3\x8a\xf9\x58\xe3\x59\x2d\x1f\x8b\x7e\xdd\x38\x76\x10\xa9\x52\xbb\x88\x09\x48\xee\x98\x5b\xdf\x74\xfa\xdb\xde\xdf\x04\x38\x07\xee\xd1\xb1\x4e\x4d\x3a\x06\x93\xd4\x6a\x8a\x04\x9b\xd4\x18\x8a\xef\xa7\x55\xa4\x6e\x55\xa4\xcc\xd9\x1a\x1e\x15\xc5\x8b\x8e\x81\x21\x85\x83\x42\x8d\x71\xe7\x0f\xdc\x49\xa2\x5c\x24\x73\x67\x4c\xa3\x71\x17\x02\x88\x4d\xab\x20\x08\xc0\xb6\x0b\x0e\xa0\x71\x41\xb0\xbe\xd4\xc4\x60\x24\x5a\x80\x54\x67\xa3\x9b\xb2\xa2\x3e\x0b\x56\x99\x11\xa7\xb0\xb1\x49\x44\xa2\x11\x7f\x25\x36\x11\x25\x50\x38\x41\x97\xda\x0d\x30\x73\x1a\x80\x88\x38\x78\xc0\xc8\xbc\x23\x9b\x82\x16\x93\x31\xd9\x30\xd6\xa3\x49\xac\x06\x2b\x2d\x26\xef\x0e\x35\x93\xcd\x55\xed\x6a\x23\xbd\xd5\x9e\x44\x96\x02\x10\x85\xe6\x81\x68\x5e\xcd\x97\x5e\x2d\xa5\x23\xf0\x95\x0c\x3d\xa2\x02\xe6\xf1\x64\x03\x44\x05\x36\x8d\x1b\xb7\x23\x09\x26\x26\x94\x57\xd7\x31\xa3\x02\xc9\xad\x32\xac\x12\x75\x22\xf4\xb5\xd0\xd1\x1e\x27\x00\x8b\x03\x08\x85\xe2\x1d\xed\xbd\xb3\x84\x44\xfc\xd0\x73\xf6\xab\x9e\xd1\x83\x1a\x57\xfc\x2d\xd4\x9e\xe9\x13\x7e\x45\xb6\xa6\x3a\x48\x1b\xce\xfc\x4e\x75\x68\xbc\xbe\x69\x10\x80\x1a\x84\xe6\xa1\xd3\x32\xc4\xdc\xf7\xbe\x26\x4d\xd1\x07\xd3\xcc\x48\xcc\x42\x9c\x0a\x0b\xe5\x2b\x90\xf0\x05\xb8\x2b\x2e\x3c\x28\x82\x1e\x8a\x00\x4b\x88\x28\xc4\x15\xa2\xeb\x60\xf4\x9c\xde\xa0\xb3\x88\x0c\x0a\x0e\x36\x1d\x86\xcd\x88\x52\x1e\x03\x16\xe4\x0b\x91\xbd\xae\x36\xab\x6c\x69\xeb\x7c\xab\x51\xc5\x38\x09\x9a\x1e\x6b\x9b\x3a\xd6\x4c\xd6\x1a\x09\x25\x76\x45\x59\x9d\x9b\x94\x4e\xdc\xa3\xe8\x3c\x10\xba\xc1\x6a\x7a\xf1\x4e\xf7\x69\xb1\x72\xe4\x88\x53\x8f\x0b\xad\xd7\x6e\xc7\x79\xf5\xa1\x5d\x38\xfd\x4a\x5c\x73\xe8\xb6\xd0\x1e\x28\xf5\x2e\x54\xe8\x5c\x99\x73\x45\xae\xd5\x0d\xd8\x4c\x44\x79\x27\xe8\x74\x9c\x53\x3e\x75\x1a\x24\xc7\x27\x25\x72\xca\xe3\x96\x92\x4f\xa8\x95\x59\xdf\xca\x9e\x47\xc7\x66\x05\x9b\x42\x22\x74\x88\x1f\x62\xc7\x35\x89\xb6\x43\xf4\xdb\x83\x1e\x1a\xf3\x1a\x29\x65\x06\xa7\x9b\x1a\xab\x9b\x04\xdc\xa9\x42\xb6\xa5\x8a\xf7\xd4\xa6\x4f\xd1\x0d\x8c\xad\x3a\xde\x9b\xb4\x99\xc8\xb9\x2e\x8e\x38\x86\x98\xab\x3a\xcf\x00\xf1\x6a\xd3\x1a\x54\x3b\xed\x7c\x13\xd6\x94\x80\x95\x99\x5d\x31\x9b\x3e\x86\xc2\x05\x02\x86\x45\xa6\xe3\xde\x1e\x9a\xfb\xfa\x09\x39\xe8\xdf\x04\xdf\xa0\xe6\xfb\xaf\x5f\x70\xde\x68\x7b\x33\x57\xb4\xdc\x11\x28\x3a\xbf\x12\x62\x5b\xc5\x23\x85\xde\x6b\x41\x82\x81\xbc\xd5\x7b\x90\x57\xb9\xea\xef\x06\x1d\xfc\x8d\x43\xdc\x73\xaf\x76\x44\xd7\x82\x09\xee\x64\x62\x4c\xf7\x11\xb0\x06\xd2\x07\xf6\xe1\x7d\x14\x21\x96\x50\x7b\x9d\xca\xf1\x0c\xf0\x29\x56\x31\x7a\xc9\x79\x25\x42\x4d\xe1\xa0\xba\x61\xcb\x86\x49\x18\xb2\xd1\x24\x8d\x07\x6e\x8c\x30\xbd\x21\x3c\xc3\xb3\xfb\x8d\xdb\x51\x20\x16\x45\x36\x94\x8c\xf9\x14\xd5\x11\x07\xfb\x09\x3e\x05\x78\xcd\x8e\xa2\x96\xdc\x8c\x35\xa6\x4e\xb4\x56\x42\xe1\x66\xc8\x0a\x3e\x50\x43\x45\x53\x1a\x57\x32\x08\x0f\xcd\xa0\x3f\x75\xc4\xc1\xbc\x7e\xea\xd6\xdc\xef\xc0\xc0\xe6\xaa\x5e\xeb\x82\x16\xb5\x7e\xb9\xfd\x16\x93\xb7\x86\xec\xfb\x4c\x46\xa9\xb5\x2a\x08\x65\x4d\x4e\xad\xaf\x54\xb5\x1f\xc2\x6b\x96\xcc\xc7\xb1\xad\x5f\x32\x4f\xee\xe5\xf2\x64\x2e\x98\x5b\x26\x51\x0e\x1f\xb4\x0a\xe4\x00\xa8\x5b\x32\xfd\x8e\x06\x9a\xd8\xd4\x87\xc6\x55\x23\xb7\x2f\xc0\x64\xe9\x26\x03\xdb\x14\x8c\x68\x66\xb7\x02\x26\xf3\x29\x33\xab\x37\x69\x9c\x1e\x80\x7b\x9a\xa4\x39\x75\xcd\x24\x4e\xa9\xdc\xd7\x4d\x32\x9f\x99\x94\x46\xdb\x19\x13\xc7\x35\x7e\x52\x7b\x0f\x91\xee\x2c\x99\xcf\xfd\xc8\xc0\x53\xc1\xaf\xfa\xc8\xc2\x94\x65\x54\x03\xd5\x32\xdd\x66\x61\x2a\xe4\x18\x2f\x52\xb9\xfe\x53\xa9\x21\x02\x2d\x23\x96\xc6\x95\x01\x35\x3e\xed\x07\x8f\xa5\x95\x89\x46\xa7\x4c\x37\xa4\x1b\xca\xa6\x59\x31\x7e\x06\xc6\x20\x34\xb5\x99\x76\xc2\x31\xe2\xd6\x00\xc9\x62\x4c\x95\xc2\xfa\xb6\xf5\x31\x32\x86\x8d\x63\xbf\x15\x49\x16\x09\xb3\x83\xae\x84\x66\x65\x62\x97\x26\xb4\x36\x09\xfb\x97\x64\x21\x62\x5d\xa0\xdd\x27\xd9\x52\x14\x5b\x9f\x24\x8b\x49\x53\xa0\x7c\x0c\x70\x93\xc9\xe9\x6d\x65\xe9\x78\xa9\xad\xb2\x24\x16\x3a\x52\x16\x57\x9a\x9b\x98\xb2\x66\x77\xb6\x9d\xdd\x07\xc7\xcd\x9c\xb9\xd5\x1b\xcd\x11\x35\x0c\x5c\x2a\xe0\x10\x15\x61\xc1\x6e\x2d\x6f\x35\x9b\x6d\x56\x1c\xe8\xd2\xd6\xe6\x41\xbc\x4c\x04\xd9\x38\x59\xac\x9a\xaa\x82\xa8\x70\x81\xe9\x95\xf2\xf0\xf8\x72\xcc\xcc\x61\xc4\xf5\x10\xe9\xda\x93\x65\xd2\xbb\x9a\xb7\x5a\x98\x64\x29\xac\x9a\xc9\x93\xa1\x19\x98\x87\xb6\xdd\x72\x1d\x4c\x77\x37\x9a\x2c\xd1\x5f\x82\x6d\x5f\x87\xbd\x29\x83\xd6\x4e\xda\x83\x18\xe0\x91\x59\x67\x5f\xac\xea\x16\x96\xb9\xb7\xb6\xc3\x1c\xa4\x5c\xe8\xc4\xd4\xb6\xa0\xc9\xdc\x8b\x13\x68\x16\x82\x76\x25\x18\xb4\x0a\xc9\x72\x49\x33\x5d\xd3\x9d\xe3\x59\x64\x0b\xf5\x69\x33\xbe\xf6\x0c\x55\x4b\x90\x66\x1d\x84\x8a\x09\x56\xb2\x0e\x25\xe5\x11\xd7\x99\x29\x87\x70\x60\x16\xc3\x36\x6f\xe0\x3f\xbb\xde\x94\x1d\x6c\x1a\xd9\x6a\xec\xf8\xb3\x4b\x07\xe2\x90\x5c\xc9\xf2\x48\x2e\xd5\x70\xa9\x5a\x7c\xb6\x67\x71\x83\x3e\x71\x97\x3f\xb4\x04\xa5\x9e\x43\x49\x93\xac\x50\xe1\xcd\x71\xc1\xbc\x1d\x37\xb7\xcd\x5a\x8f\xd6\x22\x59\x4d\x28\x44\x6d\x47\xf3\x06\x50\xed\x4d\x5c\x52\xaf\xc5\x95\xac\xfb\x83\xce\x18\x60\xdf\x64\xa8\xf2\xb7\x80\xce\xdf\xdb\x46\x25\x2b\x3f\xb3\xc0\xe0\x3c\x7c\x83\xac\x4b\x8a\x4e\x5a\x1f\x9b\xc5\xaa\x5b\x20\xa3\x79\xed\x22\x43\xd7\xf5\xf0\xde\xa4\xb5\x46\x26\x94\xab\x37\x6e\x85\x07\x6a\x60\x40\xc5\x78\xec\xd9\x5b\xd7\x9c\x70\xd7\xab\xea\x66\x9c\x6e\xa5\x48\x31\x4e\x3c\x7b\xeb\xa8\x7b\x03\xa8\x88\xd8\xbb\x27\xe8\x24\xd6\x56\xf6\x03\x9d\x32\xda\x92\x02\xa7\xec\xe7\x6f\x7e\x5b\x2b\x5f\x31\x9e\xd9\xa5\x01\xc5\xed\x9d\xe3\x73\x86\x22\xad\x19\x0a\x74\xf7\xf8\x22\xe6\x7c\x08\x63\xfc\x80\xf6\x5e\xb5\x19\x5e\x02\x39\x96\xed\x1b\x0c\x70\x6b\x01\x57\xe5\xa0\x69\xce\xcc\xa2\xb2\xbd\xfb\x13\xe3\x15\x73\x81\x43\x71\x83\x8b\x5f\x2c\x10\x8f\x4f\xb4\xf6\x0d\xc7\x56\x91\x8c\x63\xf9\xa1\xcf\x0c\x21\x92\x24\x96\x1f\xfa\x81\xc6\xfc\xa5\x27\xe8\x24\x96\x1f\xfa\x81\x4e\xdf\x3b\x2f\x89\x64\xc6\xc0\xe5\x63\xbc\x0e\x97\xe6\x2a\x1c\xaf\xc1\x29\xe1\xe2\xc1\x79\x13\xba\x20\xa5\x45\x2d\xa5\x2d\xf3\x52\x5a\x1a\x52\xb6\x68\x2c\x62\xa1\xdb\x67\x2e\x13\xc9\x32\x16\xba\xfd\x40\x57\x81\x29\xc0\xfa\x4d\x0f\x50\x31\x7e\xef\x20\x29\x84\xe7\x3b\x0a\x19\xbe\xb6\x2e\x6e\xcf\x21\x42\x08\x6f\x33\x67\x53\x21\xde\xfa\x99\xe9\xee\xfa\x9d\x83\x10\x93\xb7\x4f\x87\x42\x4c\x5b\x66\xe9\xbd\xd3\x14\x62\xd6\x32\xcb\x1b\x40\xe7\xb1\x8c\xda\x0f\x74\xe1\x45\x88\x72\x99\xa0\x17\xe8\xf2\xbd\x33\xbe\x10\x2b\x4f\xd6\xc1\x60\x68\xd6\x9b\x5f\xa1\x07\xe8\x64\x1c\xac\x9e\x4c\xfc\x34\x66\xb2\xe4\xcd\x2a\xb8\x59\x3b\xab\xa7\xf0\xaf\x4f\x08\x59\x12\xcc\x44\x70\x6b\x67\x8d\x65\x13\x81\x84\x37\x8d\x18\x0b\xdf\x5d\x40\x8b\xc9\xc4\x4d\xbb\x36\xfb\xf5\x00\x9a\x32\x6b\x56\x6b\xd5\x1e\x40\xb3\x5b\x89\xab\xb9\x66\xab\xbb\x81\x36\xc1\x7c\x84\x9d\xcb\x95\x25\x86\x98\x2c\xbc\xe1\xe5\xca\x91\x65\xab\x16\x86\x97\xab\xf6\x56\xde\x11\x5d\x45\x1b\xb1\x1e\x57\x67\x62\x3a\xd6\x94\xc8\x79\x71\x5d\x88\xde\xc3\x25\xb7\x23\xb9\xb9\xbe\x33\x57\xf7\x21\x68\x72\xa5\x32\xdc\x5d\x49\x8b\x69\xb4\x4b\xee\xb3\xa4\x12\xd3\x68\x97\xdc\x0f\x34\xda\x25\xf7\x03\x8d\x76\xc9\xfd\x40\xa3\x5d\x72\x3f\xd0\x85\x37\xc3\x36\x83\xb8\xc6\x12\x8e\xdd\x74\xbb\xe1\x83\x2e\x99\x17\xe1\x4d\x89\xe4\x4d\x8d\x1c\x48\x39\x6c\x6a\x63\xeb\xef\xca\xc4\x74\xd5\xab\x3a\xc6\xf2\xcb\x6c\xdc\xab\x3a\x46\x41\x93\x5e\xd5\x31\x0a\x2a\xde\xbb\xc1\x14\xb3\x49\x3f\x86\xbb\x1b\x71\x31\x9b\x7a\xd5\xf1\xce\x4d\x5f\xb8\x66\x10\xb3\x59\x3f\x86\xbb\x54\xff\x1f\x00\x00\xff\xff\xbe\x22\xec\x0d\x20\x2c\x00\x00")
+
+func fontsMirrorFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsMirrorFlf,
+ "fonts/mirror.flf",
+ )
+}
+
+func fontsMirrorFlf() (*asset, error) {
+ bytes, err := fontsMirrorFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/mirror.flf", size: 11296, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsMnemonicFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\xbd\x69\x77\xdb\x38\xb6\x35\xfc\x1d\xbf\x82\xe9\xf5\x36\xa2\x54\x95\x13\x6b\xb0\x25\xa5\xaa\x52\xa4\x44\x48\x62\x4c\x91\x0a\x07\x3b\xf6\x17\x2f\x8d\xb1\x13\xc7\x4e\x7b\x48\x2a\xf9\xf5\xef\x02\xc1\x73\x08\x8a\x07\xa4\x9f\xbb\xee\xea\xdc\x6e\x63\xef\x43\x0c\x7b\x1f\x00\x14\x09\xee\x6e\x76\x9d\xe5\xff\x67\xb5\xe5\xff\x75\xac\x83\xb6\x75\x64\x1d\x5a\x87\x56\xbb\x3f\xec\xb3\xaf\xb7\xdb\xaf\x77\xb7\xd7\x6b\xeb\xc0\x5a\x5a\x13\x6f\xba\xbb\xbb\x7d\xb4\x56\x3f\xad\xf7\x77\x57\xb7\xd6\xf8\xee\xc7\xf2\xd6\xfa\x6b\x2d\xff\x9f\x6d\xaf\xd7\xd7\x37\xaf\xef\xee\x3f\xbd\x63\xc9\xd5\xf5\x83\x95\x21\x9f\x1e\xb6\x0f\xd6\xe3\xd5\xd6\x82\x38\x0f\xd6\xdd\xce\x8a\x26\xe3\x76\xb7\x77\xc4\x5a\x57\x8f\x8f\xdf\xde\xbe\x79\xb3\x79\x78\x7d\x7d\xfb\xb8\xbd\xbf\xbd\x5e\xbf\xbe\xdd\x3e\xbe\xb9\xdf\xad\xe5\x7f\x24\xe6\xf5\xe3\xbf\x8f\xaf\xac\xc7\x3b\xeb\xfa\xeb\xb7\x9b\xed\xd7\xed\xed\xa3\xb5\xb4\xee\xb7\xcb\x9b\x9b\x9f\xd6\xcd\xf2\xfe\xd3\xd6\x5a\x5f\x2d\xef\x97\xeb\xc7\xed\x3d\x7b\xd8\x3e\x5a\xf7\xcb\xc7\xab\xed\xbd\xb5\xbe\x7f\xda\x6c\x6f\x7e\xfe\x61\xad\x9e\x1e\xad\xfb\xed\xf7\xed\xfd\xc3\xf5\xea\xe6\xe7\x6b\xcb\x4a\x7e\xdc\x1d\xdc\x6c\x1f\x1f\xb7\xf7\x45\x9d\xd8\xf2\x7e\x6b\x7d\xbb\xdf\xee\xae\xff\xdd\x6e\x64\xeb\xf8\x9f\x2a\xb8\x86\xb1\x2a\x98\x4b\x6b\x79\xbb\xb1\x76\x77\x37\x37\x77\x3f\xd4\x9f\x2e\x5f\x33\x1e\x2f\x6c\x9b\xbd\xb0\x6d\xf6\x1f\xdb\x66\x3c\x58\xc9\x7f\xdd\xd0\xb6\xd9\x7f\xe5\x7f\xb3\x6d\xf6\xd2\xb6\x59\xcb\xb6\xd9\x2b\xdb\x66\xbf\xd9\x36\xfb\xdd\xb6\xd9\x1f\xb6\xcd\x0e\x6c\x9b\xbd\xb6\x6d\xf6\xc6\xb6\xd9\xa1\x6d\xb3\xb6\x6d\xb3\x8e\x6d\xb3\xae\x6d\xb3\x9e\x6d\xb3\x23\xdb\x66\xc7\xb6\xcd\xfa\xb6\xcd\x06\xb6\xcd\x86\xb6\xcd\xde\xda\x36\xfb\xd3\xb6\xd9\x5f\xb6\xcd\xfe\xb6\x6d\xf6\xce\xb6\xd9\x3f\xf2\x3a\xce\xa3\x6d\x33\xc7\xb6\xd9\xc8\xb6\xd9\xd8\xb6\x99\x6b\xdb\x4c\xd8\x36\x9b\xd8\x36\x9b\xda\x36\x9b\xd9\x36\xf3\x6c\x9b\xbd\xb7\x6d\x76\x62\xdb\xcc\xb7\x6d\x36\xb7\x6d\x16\xd8\x36\x93\xb5\x95\xad\xf8\x60\xdb\x2c\xb2\x6d\x16\xdb\x36\x4b\x6c\x9b\xa5\xb6\xcd\x4e\x6d\x9b\x9d\xd9\x36\xfb\x68\xdb\xec\xdc\xb6\xd9\x85\xbc\xda\x5f\xb2\x3d\xfc\x8d\xac\x39\x7f\x25\xeb\xc0\x5f\xca\x7f\x2f\xb3\xff\x26\xfb\x62\x69\xdb\x4c\xf6\xc4\xda\xb6\xd9\xc6\xb6\xd9\xd6\xb6\xd9\xce\xb6\xd9\x27\xdb\x66\x57\xb6\xcd\xae\x6d\x9b\x7d\xb6\x6d\xf6\xc5\xb6\xd9\x8d\x6d\xb3\xaf\xb6\xcd\x6e\x6d\x9b\xdd\xd9\x36\xfb\x66\xdb\xec\x7f\xb6\xcd\xee\x6d\x9b\x3d\xd8\x36\x93\x2d\x7b\xb2\x6d\xf6\xdd\xb6\xd9\x0f\xdb\x66\xff\xda\x36\xfb\x69\xdb\xec\x97\xbc\x5a\x4b\x5e\x8d\xbf\x50\xff\xbe\xca\xae\xaf\xfa\x43\xf6\x14\x0f\xb3\x7f\xd3\xec\xdf\x65\xf6\xef\x5d\xf6\xef\x53\xf6\xef\x83\x8c\x7e\xf8\xef\xe1\xe1\x61\xdb\xb2\x2c\x2b\x4e\x9c\x28\xb1\xc2\x89\x35\x13\x8e\xeb\x05\x53\xab\x15\x87\xb3\x57\x8c\xc7\x33\x80\x75\x4a\xb0\x44\x7c\x4c\xac\x56\x9c\x7c\x94\x98\x8f\x80\xe9\x4a\x8c\x08\xdc\x02\x21\x32\x84\x40\x44\x4f\x47\x44\x4e\x10\xcf\xbd\x38\xf6\xc2\xc0\x6a\x89\x30\x91\xc8\x04\x90\x47\x0a\xf9\x21\xf5\xa2\x73\xab\x25\x82\x0f\xb2\xf4\x03\x94\x1e\xcb\x52\x67\x7c\x12\x84\x67\xbe\x70\xa7\xc2\x6a\x39\xe3\x93\x57\x8c\x3b\x27\x80\xe8\x4b\xc4\x48\xf8\xbe\xd5\x1a\x09\xff\x15\xe3\x23\x1f\x8a\x06\x59\x91\x33\x3e\x89\x17\xce\x58\x58\xad\x51\x2c\x8b\x63\x28\x1e\xca\xe2\xf1\xcc\x89\x9c\x71\x22\x22\x2b\x71\x46\xa9\xef\x24\x59\x25\x67\xb2\x8e\x33\xac\xe3\x52\x22\x7d\x2f\x10\xd6\x44\x08\xd7\x6a\xf9\x93\x57\x8c\xfb\x13\x28\x5e\x61\xb1\x1e\xe3\x54\xc6\x38\xc5\x18\x6b\x09\x9a\x84\xd1\x3c\x8f\x31\x91\x31\x26\x18\x63\x93\x55\xc6\x89\x22\xcf\x99\x0a\x2b\x12\x49\x1a\x05\x56\x6b\x1c\xbd\x62\x7c\x1c\x01\x68\x9b\x8d\xcd\xcc\x9b\x24\x56\x98\xca\x71\x09\xe5\xb0\x84\x50\xbc\x2b\x8a\xbd\xc0\x6a\xc5\x9e\x2c\xf5\xf2\xd2\xf6\xa1\x2c\x75\x9d\xc4\xf1\xbd\xe0\xc4\x12\xf1\xd8\x59\x08\xab\xe5\xfa\xe2\x15\xe3\x2e\xf4\x59\x3b\x53\x89\x2b\x4e\xbd\xb1\xb0\xc6\x61\x90\x44\xa1\x6f\x85\x81\x04\x8e\xdb\x12\xd8\x06\x60\x87\x00\x26\x67\xa1\x04\x76\x24\xb0\x03\xc0\x2e\x05\x9c\x45\x22\x8b\xd9\x95\xd0\x2e\x40\x7b\x04\x74\x12\xa6\x91\x44\xf6\x24\xb2\x07\xc8\x4c\x35\x81\x98\x3a\x89\x77\x2a\xca\x02\x09\x1c\x29\x90\x00\x04\xd2\xce\x24\x14\x9f\x07\xe3\x28\x0c\xc2\x34\xb6\x3c\xd7\x17\x56\x2b\x3e\x0f\x64\xef\x9c\x03\xaa\x6f\x12\xec\xc8\x0f\xc7\x27\x52\xe0\x23\x29\xcc\x11\xe0\x07\x6a\xbc\x82\xb1\xf0\xad\xd6\xd8\x91\xc1\xc6\x01\x14\x0e\xb5\x60\x73\xe1\x7a\xe9\xdc\x6a\x89\xb9\xe4\xcf\x01\x92\x49\x2a\x4e\x47\x71\xe2\x25\x69\x22\x2b\x94\xca\x0b\xc4\x78\x81\x4c\x54\x30\x4a\x22\x1e\x4b\xf6\x18\x0a\x95\x98\x3c\x5f\x58\xb1\x58\x38\x91\x93\x84\x91\xd5\xf2\x62\xd9\x47\x13\xd0\x77\x3b\x93\xd4\x34\x0a\xd3\x45\x19\x25\xfb\x7c\x8a\xa8\x4c\x53\x91\x18\x87\x91\x5b\x86\xc9\x51\x8c\x10\x96\x69\x2b\x0d\xbc\xa4\x0c\x92\x9a\x48\x01\xd4\xdf\xa9\xf1\xf3\x85\x6c\x90\x9b\xb9\xd1\x05\x03\x0c\x32\xfd\x2d\x1c\x37\x4b\x3b\x85\xed\x5a\x0b\xc7\x7d\xc5\xf8\xc2\x01\x5c\xa6\xc0\x99\x37\x9d\x59\xe1\x38\x11\x89\xb5\x88\x44\x2c\x12\xab\x35\x0b\x17\xd2\x94\xa0\xf6\x41\x26\xc0\x51\x24\x9c\x13\x6b\x21\xa2\xb9\x97\x24\xc2\xb5\x66\x22\x92\x46\x5f\xc8\x9c\x36\x82\x9c\x36\xc8\x24\x18\x84\x39\x5a\x61\x82\x91\xc4\x04\x88\xc9\xb4\xe7\x05\xae\xf8\x68\xb5\xbc\x40\x56\xc9\x83\xf1\x1c\xe4\x6a\xfb\x98\x28\x97\xb7\x82\xac\x69\x01\x98\x66\x70\x5c\xca\x99\xb1\xf0\xc5\x58\x56\xc6\x89\x84\x63\xb5\xe2\xd8\x91\x03\x8b\xed\xd3\x95\xb6\x07\x15\x19\x54\x40\x7f\x0e\x06\xc6\x0c\xa5\x7a\x24\x91\x09\x6d\x86\x70\x73\x42\x3b\xf3\x92\x99\xf5\x3e\x8d\x13\x6f\xe2\x8d\x31\xc7\xbd\x97\xec\xf7\xc0\x5e\x52\x59\x2c\xbb\xce\x69\x76\x9d\x53\xbc\xce\x4a\x8d\x64\x94\x78\x8e\x9f\xa7\xc5\x30\x3a\x73\x22\xd7\x6a\x2d\xfc\x6c\x30\x5d\x80\xae\x2b\x50\x99\x8f\x01\x9b\x4a\x6c\x0a\xd8\x8d\x52\xe2\xa9\x88\x62\xa1\x67\xdb\x48\xe6\xb1\x08\xf2\xd8\x40\x25\x41\x2f\x98\xfa\xe2\x40\x25\xbb\x2c\xed\xc4\x99\x60\x63\x48\x3b\x83\x5d\x15\xa6\x92\x4e\x9c\x19\x20\x86\xa4\x33\x3c\x24\x92\x4e\x9c\x44\xd9\xe4\xe8\x8e\x65\xcb\x5d\xf0\xdd\x30\xd3\xe6\x22\xf2\x4e\x9d\x44\x58\x69\x2c\x54\x6a\x5c\xa4\xd2\x06\x0b\x48\x8d\xc3\xce\x3e\x2a\xab\xe0\x22\x95\x15\x5c\x40\x05\x87\x99\x28\x65\xff\xe6\xe9\x26\x91\x0a\xca\x32\x41\xd6\xdd\x09\x74\xf7\xb0\xa7\xa5\x1a\xcd\x37\xe3\xb1\x14\xf0\x18\xeb\x96\x89\x74\x2e\xe2\x58\x4e\x20\x67\x8e\x97\x64\x2d\x98\x9f\xbd\x62\x7c\x7e\x06\xa0\xb2\x52\xa7\xa9\x13\xb9\x85\x50\x17\x99\x50\xa7\x80\xd5\x85\x5a\x46\x8a\x0c\x29\x10\x39\x28\xeb\x3f\xef\xbc\x38\x94\xed\x88\xb1\x1d\xc3\x62\x44\xac\x69\xe4\x2c\x66\xde\x58\x6b\x8f\x27\x7b\xde\x4d\xc7\xb2\x69\xf1\x74\x2c\xc7\x7c\x8a\x6d\x5b\x6a\x54\x03\x25\x63\xc4\xc8\xc8\x34\x8a\xc3\x29\x3e\xa4\x22\x18\x8b\x12\x63\x9c\xcd\x8f\x63\xd0\xd5\x70\xad\x1a\x91\xd5\x3d\x91\x09\x25\x50\x49\x2e\x96\xf3\x78\x0c\x69\x6c\x98\xa9\x34\x5c\x88\xc8\xc9\x3a\x38\x3e\x8f\x13\x31\xb7\xc6\xe1\x7c\xee\x04\xae\xd5\x0a\xb3\x4c\x1d\x62\x3d\xb6\xa8\x85\xf1\x39\x8e\x4e\x6b\x21\x27\x83\x05\x4c\x06\xc3\x4c\xab\xce\x62\xe1\x83\x39\x17\x51\x38\x8d\x1c\x2d\xac\xb3\x90\x61\x1d\x08\xbb\x3c\x54\x19\xed\x40\x65\xb4\x6c\x7d\xc3\x78\x00\x5d\xbd\x6c\xab\x64\x76\x2a\x22\x99\x5c\xc4\xc7\xb1\xef\xcc\x55\xe4\xb9\x13\x9d\x30\xfe\x02\x5a\xbd\xcc\xb4\x3a\x16\x41\x62\xc5\xde\x34\x60\x7c\xfc\x08\x25\x99\x3e\x17\x61\x1a\xb8\x79\xd1\x62\x03\x45\x4a\x91\x69\x14\x89\x60\x7c\x0e\xc4\x27\x28\xcd\x84\x78\x2e\x82\xbc\xe0\x7c\x0b\x05\xc7\x2a\x63\x87\x27\x22\xb0\x46\x4e\xc4\xf8\x08\x66\xbb\x65\x5f\x99\x61\xac\x92\x4e\xc6\x8b\x05\x14\x66\xf2\x72\x3d\x47\x44\x22\xf6\x62\xc6\x5f\xbe\x85\x12\x95\xf1\xc2\xc5\x79\xe4\x4d\x67\xd8\x84\x3b\x28\xce\x64\x33\x11\x73\x2f\x90\xd9\x24\x8c\x5c\x2f\x70\x7c\x99\xe4\x65\x3f\x87\x11\xe3\x07\x4b\x80\xaa\x35\x9c\x98\x24\x07\x8b\xd0\x0b\xb2\xa1\x75\xc3\x74\xe4\x0b\xcb\xc9\x54\xf7\x21\x0d\x13\xbd\x07\xff\xfa\x0b\x98\x6b\x35\x14\x70\xf5\x00\x26\xa8\x65\xa6\x94\x38\x9c\x24\xd6\xec\x7c\x31\x13\x01\xe3\x07\x07\x50\x96\xcf\xba\x53\x2f\x4e\x44\x24\xa0\x87\xa3\x4f\x50\x9e\x29\x62\xee\xc8\x35\x0b\xe3\x2f\xbf\xe6\x7f\x5e\xe5\xb9\x6a\x2a\x13\x99\xa2\xb8\x60\xc2\x95\xca\x4d\x7e\x1a\x1f\xcc\xbd\x20\x8d\xf3\xf2\xdf\xe1\x92\x2b\xb5\xb0\x4f\x17\x22\x8a\xc7\x91\xb7\xc8\xd2\x26\xe3\x1d\xd0\xcc\xaa\x5b\x29\x97\xf9\x92\xf1\x2e\x22\x7a\x6a\x31\x2e\x97\x2b\xce\x58\x6a\x86\xf1\x97\x2f\xa1\x50\xa5\x1f\x6f\x1c\x85\xf9\x95\xe7\x3f\xa1\x28\x1b\xf7\x85\xe7\x8f\xa3\xf0\x0c\xb4\x04\x02\x5c\xf5\x15\xcf\x95\xab\x32\x37\x4c\x18\x7f\x0d\xb6\x58\xa9\xe9\x4f\xb8\x9e\xef\x3b\x8c\xbf\xfc\x03\xfe\x3e\xdc\xaf\x69\x18\x08\xc6\xdb\x58\xcf\xa5\xea\xbc\x78\x9c\xfa\xa6\x71\x07\x89\xac\xb2\x71\xcf\xd4\xf3\xcc\x81\x7f\xf7\x0e\xa8\xd9\xc0\x9f\xa6\xfe\xd4\x89\xac\x89\x4c\x49\x12\x24\x27\x84\x0f\xa9\x13\x25\x22\x62\xbc\x0d\xeb\xd5\xd5\xc6\x84\x9d\x39\xfe\x84\xf1\x36\xcc\x0a\xab\x2d\x05\x54\x33\x57\x1e\x36\x66\xbc\x8b\x71\x77\x25\xa3\x7f\x48\x45\xac\x55\xf5\x1f\xe8\xe4\x75\xa6\x1b\x39\xa5\x07\xd6\xd8\x59\x78\x89\x9c\x8c\x45\x22\x73\xa8\xa3\xd6\x06\xd3\xc8\x39\x15\x8c\x3b\x2f\x80\xd1\x6e\x62\x64\x3a\x60\xdc\x01\x01\xac\x3b\x4d\x8c\xb1\x17\x8d\xd3\xf9\xc4\x17\x1f\x19\x77\xa0\x17\xd7\xdd\x26\x5a\xe2\xf9\xae\xbc\xd0\x3f\xc0\xe8\x35\x31\xb4\x54\xe1\x40\xaa\x58\x1f\x35\xb1\xb2\xc4\xef\x8c\xc2\xac\x1f\x60\xb5\xb6\x3e\x36\xd3\x24\x0e\x72\xd4\xba\x6f\xc4\x8d\xf3\xd6\x83\x8e\xc7\xa0\xe3\xf5\xc0\xc8\x11\xa5\x51\x11\x38\x2a\xc3\x26\x46\x3e\x2a\x02\x47\x65\xd9\xc4\xd0\x47\x45\xe0\xa8\xac\x9a\x68\x5a\x1f\x0b\xec\xe3\xb5\x91\xe5\x95\x1a\xe4\x61\x83\x36\x4d\x8c\xbc\x41\x1e\x36\x68\xdb\xc4\xd0\x1b\xe4\x61\x83\x76\x4d\x34\xad\x41\x1e\x34\x68\x63\xf6\x8d\x48\x66\x56\xcb\x5b\x6f\x6f\x96\xb7\x9b\xeb\xb5\x5c\x24\x42\xa2\xdd\x98\xad\x13\x94\x14\x1d\x80\xa2\x37\x66\xeb\x84\xa5\x7e\x0b\xa1\xdf\x36\x66\xd7\x84\xa5\x7e\x0b\xa1\xdf\x36\x66\xd7\x84\xd5\x7e\x0b\xa1\xdf\x36\x66\xdb\x84\xa5\xc6\x84\xd8\x18\xb3\x63\xc2\x4a\x4f\x87\xd8\xd3\x6a\x1a\x48\xfd\xc4\x2b\x56\x41\x6a\xaa\xf8\x0d\x6e\x2a\x6d\xcc\x7e\xc9\x23\xc7\x89\x5c\x5c\x30\x1e\xbe\x01\x8a\xd9\x30\x69\xa9\x67\x53\xec\x59\xb3\x61\xd2\x52\xcf\xa6\xd8\xb3\x66\xaf\xa4\xd5\x9e\x4d\xb1\x67\xcd\x66\x49\x2b\xfd\x94\x62\x3f\x99\x0d\x73\x5e\xaa\xde\x39\x56\xcf\x6c\x98\x64\x16\x46\x41\x59\xc5\x09\xec\x87\x37\x9a\x61\xe2\xb9\xe3\x23\x29\x9e\x39\xd1\xc2\x8a\xad\xd6\x74\x7b\xff\x75\x79\xfb\x4a\xbb\xc5\xb8\x3d\x34\x70\xca\x93\xcc\x12\xfa\x7a\xdb\xae\xc7\xe7\x4d\x59\x42\x53\xb6\x9d\x7a\xbc\xde\xcf\x4b\xe8\xe7\x6d\xb7\x9e\x94\xeb\x77\x09\xfa\xdd\xf6\xea\xf1\xda\xa8\x2c\x61\x54\xb6\x47\xf5\x1c\x7d\x6a\x59\xc2\x92\x73\x7b\x6c\x22\x49\x14\x2c\x9a\xb7\x7d\x03\x6a\x7f\x5a\x59\xc3\xb4\xb2\x1d\x18\x18\xe5\x49\x65\x8b\xa3\x30\xac\xc7\xe7\xa3\xb0\xc5\x51\x58\xd6\xe3\xf5\x51\xd8\xe2\x28\xac\xea\x49\x5a\xaf\x6e\xb1\x57\xd7\x06\x4e\x79\x32\xb9\xc6\x86\x6c\xea\xf1\x79\x43\xae\xb1\x21\xdb\x7a\xbc\xde\x90\x6b\x6c\x88\xc9\x17\xd5\x69\xe4\x1a\x1a\xb2\x33\xf9\xa2\x32\x89\x6c\x60\x12\xd9\x99\xac\x51\x9e\x42\x6e\x41\xb5\x3b\x93\x35\xca\x13\xc8\x1d\xf4\xd5\xce\xe4\x8a\xf2\xf4\x71\x07\x7d\xb5\x33\xb9\x82\x98\x3c\xee\xa0\xaf\x76\x26\x5b\x94\xa7\x8e\x3b\x6c\x84\xc9\x11\xd5\x89\xe3\x0e\xfb\xb6\xaf\x36\x87\xa7\x5e\x5c\x4c\x19\x07\x58\x6a\xf2\xc2\xde\x84\x71\x07\x13\xc6\xce\x64\x86\xf2\x74\xf1\x84\xfd\x68\x32\x43\x79\xb2\x78\xc2\x7e\x34\xf9\x80\x98\x2a\x9e\xb0\x1f\x4d\x46\xa8\x4e\x14\x4f\xd8\x72\x93\x19\xca\xd3\xc4\x4f\xac\x98\xc9\x0c\xc4\x24\xf1\x78\x05\x24\x93\x19\xce\x2b\x15\xfb\x99\x57\xac\x7d\xd8\xb8\x17\x81\x6d\xaf\x73\x00\x94\x86\x79\x02\x08\x4b\x24\x34\xee\x45\x46\x91\xc8\xd6\xf9\x2d\x60\x34\xcc\x12\x39\x7e\x89\xf8\xc6\x4d\x48\x38\x0d\x03\x71\xc2\xb8\xf3\x27\x50\x1a\x26\x09\x20\x2c\x91\x60\x5e\x49\x8d\x4b\x83\x38\x7e\x09\x8c\x86\xc9\x22\xc7\xaf\x11\x6f\x5e\x51\x8d\xab\x7a\x1c\xbf\x03\x9a\xc9\x24\x04\x69\x8d\x24\xf3\xc2\x2a\xa7\xb9\x61\x02\x93\xe4\xf8\x35\xb0\x4c\x7e\xa9\x72\xd6\xc8\x31\xaf\xac\xa0\x82\x4e\xa6\x97\xf1\x5f\xc0\x30\x99\xa5\x8c\x5f\x23\xde\xbc\xa6\x72\x4b\x0c\x17\x19\x26\xa7\x94\xf1\x1b\xc0\xb7\xcd\x2e\x71\xcb\xa9\xcb\x7d\x03\x14\x93\x4b\xf6\x08\x1b\x24\x98\x5d\x22\xca\xc6\x12\x60\xac\xb6\xc9\x26\x7b\x84\x2d\x12\xcc\x3e\x11\x25\x67\x09\x70\x56\xdb\x64\x93\x32\x7e\x8b\x78\xb3\x4b\x44\x45\x23\x02\x34\xd2\x36\x39\xa5\xca\xd9\x22\xa7\x71\xbf\x0e\x16\x16\x60\xe1\x76\xc3\xda\x0a\x08\x5b\x24\x34\xef\xd7\x95\x52\x04\x2a\xa5\x61\x65\x95\xe3\xb7\x88\x37\xbb\x63\x5a\xb5\xef\x14\xec\xdb\x36\x59\x84\x20\x7d\x42\x92\xd9\x27\xd3\xd2\x68\x4e\x71\x34\x4d\x3e\x29\xe3\x3f\x01\xbe\x63\xf6\xc9\xb4\x32\x92\x53\x18\xc9\x8e\xc9\x2a\x55\xce\x27\xe4\x98\xdd\x32\xdd\x5b\x8a\x4f\xff\x00\x8e\xc9\x2e\xfb\x8c\x4f\xc8\x30\xfb\x65\x56\xed\xe8\x19\x74\x74\xc7\x64\x1a\x82\x74\x85\x24\xb3\x73\x66\xe5\x94\x31\x83\x94\xd1\x31\xd9\x66\x8f\x70\x85\x04\xb3\x67\xbc\xd2\x22\xd0\xfb\x07\x18\x26\xcb\x94\xf1\xd7\x88\x37\x3b\xc6\x2b\x27\x25\x0f\x92\x52\xc7\x64\x99\x3d\xc2\x35\x12\x1a\x6f\x6c\xe5\xba\xf4\x50\x97\x0d\x7b\x91\x1c\x7f\x8d\xf8\xc6\xdb\x5a\x90\x2a\x3c\x48\x15\x9d\x86\x9d\x08\x10\xae\x81\xd0\x35\x7b\xc5\xab\xe8\xde\x03\xdd\x77\x4d\x5e\xf1\x24\xdc\x17\xb1\xdc\xe9\x20\x98\x32\x89\x37\x75\x92\x34\x12\x96\xf7\x9e\x71\xef\x3d\x20\xab\xd6\xd0\x71\xd7\x9f\x01\x67\x36\xc4\xfb\xaa\xb6\xdf\x83\xb6\xbb\x26\x43\x10\xa4\xcf\x48\x32\x1b\xe2\x64\xcf\xb0\x27\x60\xd8\xae\xc9\x11\xfb\x8c\x2f\xc8\x30\xed\x49\x4e\x22\xc7\x6a\x4d\xef\xb7\xdb\x5b\x5c\x69\x7f\xf9\x02\x24\xf3\x8d\x2c\xbf\xb4\xb6\xf3\x61\x6d\xd7\x35\xed\x4c\xca\xf8\x1b\xc4\x9b\x6f\x63\xf9\x7b\x4d\xf1\xb1\x29\xa6\x8d\xc9\x3e\xe3\x06\x19\xe6\xfb\x57\x7e\x69\xbe\xf2\x61\xbe\xea\x9a\x36\x26\x65\xfc\x0d\xe2\xcd\x77\x7a\x73\x86\xfe\x63\x93\x0f\xca\xed\x99\xf6\xe8\x04\xe9\x06\x49\xe6\x5b\xbd\x7e\x39\x21\xfa\x90\x10\x7b\xa6\x8d\xfa\x1e\xe1\x06\x09\xe6\x5b\xbd\x41\x69\x24\x03\x18\xc9\x9e\x69\xaf\x5e\xc6\xdf\x22\xde\x7c\x8f\x37\xd8\x1b\xc7\x00\xc6\xb1\x67\xda\xaa\xef\x33\x6e\x91\x61\xfe\x85\x24\x28\x8d\x64\x00\x23\xd9\x33\x19\xa5\x8c\xbf\x45\xbc\x69\xe6\x08\xac\x45\x24\xc6\xc2\x15\xae\x35\x3a\xb7\x9c\x45\x28\x3b\x79\x31\x13\x8c\xbf\xbc\x05\x6e\xcd\xba\x2b\x98\x5a\x2d\x7f\xf9\xed\xdb\xf5\xc3\xd5\x2b\xc6\x83\x29\x50\x8c\x0b\xaf\x32\xe1\xf6\x13\x10\xcc\xb3\x48\x58\x9e\x78\x42\x98\x78\x7a\xa6\x69\x64\x8f\x70\x87\x04\xf3\x3c\x12\x96\x66\x9e\x10\x66\x9e\x9e\x69\x1a\x29\xe3\xef\x00\x7f\x64\x9e\x45\xe0\x36\x4d\xfe\xf3\x69\xfe\x0b\xc4\x7f\x80\x68\x9a\x48\x48\xda\x1d\xd2\xea\xa6\x94\x50\x5e\x40\x00\xd2\x3c\xa5\x48\xdc\xdd\x16\x70\xe6\x29\x25\x2a\x39\x24\x02\x87\x1c\x99\x66\x93\x32\xfe\x1e\xf1\xe6\x89\x24\xda\xf3\x47\x04\xfe\x38\x32\x4d\x24\xfb\x8c\x7b\x64\x98\xd7\x56\x51\xc9\x21\x11\x38\xe4\xc8\xe4\x90\x32\xfe\x1e\xf1\x66\x57\xc4\xa5\x96\xc7\xd8\x72\x93\x29\xca\xf8\x07\xc4\x9b\x3d\x11\x57\x67\xea\x18\x66\xea\x23\x93\x2f\x08\xd2\x03\x92\xcc\xde\x88\xf7\xfa\x38\xc6\x3e\x36\xfe\x0c\xb2\xc7\x78\x00\xc6\xb1\xd9\x1f\x71\xa9\x97\x63\xe8\xe5\x63\x93\x31\xca\xf8\x07\xc4\x9b\x77\x22\xc9\x5e\xad\x12\xac\x95\x69\x27\xb2\xcf\x78\x44\x86\xd9\x25\x49\xa9\x5e\x09\xd6\xcb\xe4\x92\x32\xfe\x11\xf1\x66\x97\x24\xe5\xc9\x30\x81\xc9\xf0\xd8\x64\x92\x3d\xc2\x23\x12\xcc\x1e\x49\x4b\xfb\x89\x14\xf6\x13\xc7\x0d\x77\x80\x73\xfc\x13\xe2\x1b\x7f\x30\x84\x24\x9d\x42\x92\x3e\x6e\xb8\x09\x0c\x84\x27\x24\x34\xfe\x56\x98\x67\xe9\x14\xb2\xf4\xb1\xc9\x20\x65\xfc\x13\xe2\xcd\xde\x48\xab\xbf\x61\xa5\x87\x40\x33\xd9\x83\x20\x3d\x01\xa9\x6f\x76\x48\x4a\x4d\x05\x29\x4c\x05\x7d\x93\x51\x48\xda\x13\xd2\xcc\x7e\x49\xcb\x5b\xa5\x14\xb6\x4a\x7d\x93\x5d\xf6\x08\x4f\x48\x30\xbb\xe5\xac\x9a\x92\xce\x20\x25\xf5\x4d\x96\x21\x48\x3f\x90\x64\xf6\xcd\x79\x95\x76\x8e\x34\x93\x77\x08\xd2\x4f\x24\x99\xfd\x53\xbd\xc7\x7f\x0e\xf7\xf8\xfb\xe6\xdd\xca\x45\x69\x1e\xb8\x80\x79\xa0\x6f\xda\xad\x94\xf1\xbf\x10\x6f\xde\xad\x5c\x54\xf6\xb2\x17\xb0\x5e\xef\x9b\xf6\x2b\x55\xce\x2f\xe4\x98\x77\x2c\x17\xa5\xbc\x76\x01\x79\xad\x6f\xda\xb1\x94\xf1\xbf\x00\xbf\x6c\x5c\x51\xcd\xc2\x48\xae\x0a\x87\x40\x68\x58\x49\x29\xf8\x1d\xc2\x6b\x1e\x2f\xf1\x18\x0f\x3d\xc0\x19\x7f\x13\xf4\x18\xbf\xbb\x06\x94\xa6\x3e\x50\x42\xc4\xf8\xcf\x7b\x28\x37\xef\xbf\x52\xbd\x7a\x29\x54\x6f\x65\xda\x79\x95\xe0\x4f\x08\x37\xef\x56\x2e\xca\x93\xc0\x05\x4c\x02\x2b\xd3\x66\x65\x8f\xf0\x0b\x09\xe6\xbd\x8a\xb8\x98\x31\x2e\xf2\xe7\xdb\xdb\x35\xcf\x2f\x39\xa5\xc1\x76\x60\xb0\xd7\x26\x71\x94\xf1\x4b\xc4\x37\x3e\xb8\x94\x33\x3c\x60\x6c\x4c\xfd\x59\xc6\x5f\x23\xde\xbc\x89\x0d\x4b\x8c\x10\x19\x0d\x3f\x36\xe7\xf8\x3b\xc4\x9b\xb7\xb0\x69\x89\x91\x22\xc3\xb4\x85\x2d\xe3\x9f\x10\x6f\x16\xc5\xfe\x6f\xa4\x96\x13\xb8\x38\xc3\x5e\xa6\x6f\x0f\x2e\x21\x86\x49\x25\xf5\x11\x9e\xb4\x08\x66\xd9\x90\x31\xf2\xa4\x76\x99\xbe\x7d\x89\x21\x4c\x7b\xde\xda\x00\x4f\x5a\x80\xc6\x27\x9e\xca\x21\xf2\x9e\xbc\x4c\xdf\xfe\x85\x21\x1a\x7e\xd3\xa6\x03\x3c\x69\x01\x1a\x9f\x88\x2a\x87\xc8\x7f\x54\xbf\x4c\xdf\xbe\xc0\x10\xcf\xfd\xc9\xbb\x14\xe0\x49\x0b\x60\x5e\xd0\xec\x3f\xc8\x53\x1a\x4f\xa7\x0d\x01\x4c\x4b\x9b\x5a\xfa\x12\xe8\xdb\xc6\x9f\xb9\x71\xb2\x29\x5f\xbf\x0f\x01\x1a\x7e\xf4\xa6\xe9\x4b\xa4\xd7\xfc\x04\xbe\xf7\x63\x9d\xd3\x05\x8e\xf1\x47\xf0\x3d\xc6\x12\x19\xe6\x65\xcf\xb4\x9c\x5b\xa7\x90\x5b\x8d\xcf\x4a\xed\x11\x3e\x21\xc1\xbc\xdc\x99\x96\xb2\xc1\x14\xb2\x81\xf1\x99\xa9\x32\xfe\x13\xe2\xcd\x8b\x9c\x93\x12\xe3\x04\x19\xa6\x4d\x42\x19\xff\x05\xf1\xe6\x4d\x42\x58\x5e\x51\x86\xb0\xa2\x34\x3e\x31\xb5\x47\xb8\x43\x42\xe3\xed\x25\x45\x29\xe9\x25\x44\xbd\x36\xdc\x69\x22\xb8\x77\xc8\x35\x7b\x4d\x5c\xcc\x4a\x3d\x22\x2e\x80\x63\xb2\xd7\x3e\x63\xfb\x2b\x67\x18\x9f\xa2\x7a\x5f\xc2\x7f\x86\x3e\xdf\x35\x6a\x33\x4f\x9f\x53\x58\x54\x1a\x9f\x57\x2a\xe3\x3f\x21\xde\x3c\xaa\x95\x07\xff\x4a\xf9\xda\x71\x30\x5f\x1b\x1f\x08\xaa\x8f\xb0\x5c\x16\x11\xcc\xe3\xee\x94\x1f\xe1\xbb\x74\x44\xc1\x32\x8d\xf7\x3e\x67\xb9\x2d\x38\x8d\x37\x17\x95\x79\x4b\x35\x0d\xdf\x14\xfc\x86\x5b\x8d\x04\xfb\x0e\xd9\x1d\xf5\xae\xc3\x3c\x74\xbd\x89\x27\x22\xbc\x6d\x2e\x26\x49\xf6\x12\x45\xd6\x53\x8c\xff\x99\xbf\x05\xd2\x51\x4f\xe4\xe7\xa2\x78\x99\x8b\xa2\xa3\xe6\xd7\x7c\xf7\xfb\xb2\x05\x7f\xcd\xec\xac\xad\xfe\x5f\xbe\x86\x92\x6c\x88\xf5\x6d\xec\xcb\x43\x28\xca\x46\x0e\x6c\xf8\xf2\x4f\xf8\xf3\x46\xc5\x2a\xb6\xa2\xc5\xcb\x32\xf9\x8e\xb4\xab\x5e\x18\x9d\x46\x42\x9c\x54\x86\xcc\x5f\xcc\xf6\xde\xb0\xf8\x2f\xb0\x06\x46\x96\x58\xc4\x9e\x1f\x96\xef\xef\x0b\xe4\x0d\xcd\xbc\xa4\x7c\xad\x73\xe4\x2c\x8d\x1c\x2f\xdc\x23\x79\x48\x5a\x1b\x49\x61\xf6\x66\x50\xb9\x82\x21\xf2\xb6\x46\x5e\x4a\x34\x2c\x45\xde\xae\xe6\x7a\x62\x5a\xae\xe5\x19\xb0\xd4\x0b\x9f\x8a\x55\x5e\x1f\x97\x1b\x96\xe9\x50\x7f\x9c\xb3\x0b\x01\xda\xf5\xa3\xc7\xb8\xf3\x1b\x40\x3b\x46\xe8\x48\x24\x0e\xe3\x23\x44\x76\x8d\xc8\xa9\x33\x9f\x3b\x8c\x4f\x11\xda\x33\x42\x5d\xe1\xcb\xa8\x2e\x42\x8f\x9a\x24\xc3\xb8\x40\xb0\x59\x95\x17\x59\x65\x2f\x10\xd9\xaf\x53\x14\xe3\xe7\x08\x34\x4b\x36\x99\x65\xd0\x19\x42\xcd\x2a\x95\x03\xc3\xb8\x87\x48\xb3\x36\x4f\x9c\xc5\xc2\x61\xfc\x04\xa1\x2b\x23\xd4\x77\xe6\xae\xc3\xb8\x8f\x50\xb3\x78\xe7\x29\xe3\x73\xc4\x6d\x8c\xb8\x20\x65\x3c\x40\x9c\x59\xd4\x1f\x3d\xc6\xc7\x88\xab\x13\xb1\x97\xcf\xd2\x00\x5e\x1e\x1a\xc1\x0b\x8f\xf1\x05\xe2\xcc\x12\x8d\x66\x21\xe3\x11\x02\xcd\xb2\x8b\xbd\xa9\x94\x5d\x8c\x50\xb3\xec\x12\x27\x65\x3c\x41\xa0\x59\x74\x29\x88\x2e\x45\xb0\x59\x74\x8b\x99\xc7\xf8\x04\x81\x66\xcd\x8d\x25\xf0\x23\x02\xcd\x9a\x5b\xc4\x1e\xe3\x1f\x10\x68\x56\x5c\x96\x3e\x18\x3f\x43\xe8\x73\xd2\xa1\x96\x2b\xde\x23\xd1\x2c\xc0\x52\x6a\xd3\xb8\xa7\xc8\x5d\x1b\x12\x55\x75\x8e\x58\x42\x72\x5b\x6e\x0c\x1c\x6a\x86\xd8\x22\x6b\x6b\x62\xed\xa5\xfa\x9f\xc8\xd8\x3d\x2f\x89\x32\x7e\x0d\x94\x95\x29\xef\x56\x73\xfc\x7e\xea\x7d\x82\xd4\xbb\x6a\xd7\x75\x09\xe3\x4b\xe8\xbb\x55\xc7\x00\x54\x69\x77\x85\xb8\xae\x01\x97\x27\xdd\x4f\x08\xec\x19\x80\x79\xca\xdd\x20\xf0\xa8\x7e\x04\x18\xdf\x22\xf4\xd8\x00\x55\xe9\xf6\x17\xe2\xfa\xe6\xe1\x61\xfc\x27\xc2\x06\x06\x58\x9e\x6a\xaf\x10\x38\xac\x19\x3c\xc6\xaf\x11\xb7\x34\xe0\xf2\x34\xfb\x05\x81\x2b\x03\x30\x4f\xb2\x37\x08\x34\x49\x5a\xa6\xd8\xaf\x88\x32\x89\x58\x26\xd8\x5b\x44\x99\x44\x2b\xd3\xeb\x1a\x51\x26\xa1\x62\x72\xbd\x03\xe8\xda\x24\x50\x99\x5a\xbf\x21\xca\x24\xc1\x2c\xb1\xde\x23\xcc\x24\xc0\x49\xf6\x2e\x72\x9e\x5c\x7f\x7b\x00\xb8\x49\x87\x39\xf0\x01\xe3\x9a\x74\x98\xe5\xe0\x47\x84\x99\x54\x88\x19\xf8\x09\xa1\x26\x15\x66\xf9\x77\x87\x30\x93\x08\xb3\xec\xfb\x2f\xc2\x4c\x22\xcc\x72\xef\xff\x10\x66\x92\x60\x9e\x79\x7f\x20\xd0\xa4\x41\x32\xef\x7e\x46\x9a\x49\x91\xa6\xac\xfb\x1d\x99\x26\x89\x52\x4b\xd8\x3b\x48\x6e\x6b\x93\x64\xa9\x05\xec\x13\xb2\x4c\x12\xae\x2e\x5f\x7f\x00\x67\xa3\x75\x70\x90\xce\x45\xa4\xd4\x24\x37\x39\x53\x80\x68\x9d\xeb\x87\x67\x99\x71\x74\xe0\x1f\x08\x34\x4f\x6b\x71\xa2\x84\x97\x40\xea\xdd\x98\x7a\x14\x90\x8f\x88\x34\xaf\xa4\x5c\x2f\xcf\xab\x73\x04\x9b\x3a\x0e\xa1\x5f\x11\x6a\x5e\x51\x9d\x84\x6a\xdd\x87\x50\x93\xeb\x73\xe0\x17\x00\x6e\xcd\x0b\xaa\xd8\x99\x67\x6b\x2a\x84\x9a\x8c\x9f\x03\xbf\x01\x70\x57\x39\x27\xa1\x3c\x9f\x59\xad\xe4\xee\xf6\xee\x21\x3b\x68\xcf\xbd\x5e\xde\xfc\x7c\xbc\xfe\xb2\x7c\xc5\xf8\x4b\x18\xe2\x9d\x66\xde\x4c\xe6\x23\xe1\x87\x67\x8c\x7f\xce\xaf\xd0\x53\x2f\xc4\x8c\xcf\x23\xcf\xf7\xbd\x71\x75\x45\xc2\xb8\x17\x02\xb4\x53\x07\x75\xdf\x0b\xab\x15\x6f\xef\x57\x77\xeb\xfb\xbb\xe5\xe3\x75\xf6\x3e\xa7\xfb\x5f\xe0\x76\xeb\xb8\x53\xc9\x9d\x2f\xd7\xdb\xcd\xdd\xad\x22\x4e\x91\xd8\xab\x23\xa6\x27\x91\xe3\x05\x9e\x13\x58\x9e\xdc\x3d\x0a\x20\x1d\xd5\xd6\xf4\x62\xff\x6a\x6e\x0c\xc4\xe3\x3a\xe2\xe8\x5c\xf8\x61\x94\xc6\xb1\xe7\x04\x07\xda\xa5\x19\xf7\x3c\x08\xd0\xaf\x0b\x70\xee\x59\xad\xf4\xcb\xfd\xf2\x3a\xbf\xee\x39\xd2\x06\x75\xb4\xf7\x82\xf1\xf7\xd8\x21\xc3\x3a\xa8\x2f\xb1\xfe\x7b\xc0\x2e\xeb\xb0\x81\xc4\x06\x88\x5d\xd5\x61\x93\x78\x46\x0c\x6f\xf2\x00\xe4\x75\x1d\xf9\xa4\x32\xbc\x27\x78\xd5\x6d\x1d\x31\x9e\x85\x51\x62\xa5\x56\x6b\xf4\x73\x7b\x73\x77\xff\xf4\xf0\xa0\xe8\xa7\xd8\x19\xbb\xfa\x81\x9e\x09\xc6\xdd\xfc\x3e\x61\x4f\xbd\x08\x63\x02\xcb\xbd\xf6\xdf\x80\xac\x35\xc5\x48\x30\x3e\x42\x68\xad\x29\x4e\x05\xe3\xa7\x08\xad\xf7\x80\xac\xeb\x14\xb1\xb5\xb2\x77\x65\xb3\x10\x5a\x2b\x76\xe9\x0b\x81\xd0\x5a\x79\x67\xbd\x75\x01\x5d\xdb\xae\x55\xf2\x85\x84\x62\xd8\x5a\xf5\x4a\x7b\x20\xb2\x56\xbc\x6a\xb8\x3d\xc6\xdf\x23\xbe\x56\xc0\x27\x32\x4f\x23\xb4\x56\xbf\xc2\x67\xdc\x47\x68\xad\x5a\xc5\x9c\xf1\x39\x42\x37\xb5\xd0\x80\xf1\x00\xa1\xb5\x52\x0e\x19\x0f\x11\x59\xab\xda\x85\x60\x7c\x01\xd0\x4e\xad\x66\x45\xc4\x78\x84\xd0\x5a\xd1\x8a\x98\xf1\x18\xa1\xb5\xa2\x95\x6b\x84\x04\xa1\xb5\xa2\x4d\x19\x4f\x11\x59\x2b\x59\x31\x61\x7c\x82\xd0\x5a\xc9\xca\xdd\xd7\x0c\xa1\xb5\x92\x4d\x62\xc1\xf8\x18\xb1\xb5\x92\x1d\x4b\x79\x8f\x41\xde\x9d\x5a\xcd\xc6\xb2\x0e\x31\x62\x1b\x54\x3b\xce\xd0\x6b\x40\xd7\x6a\x76\xe6\x44\x70\x44\xd3\xdf\xff\x01\x46\xad\x74\xcf\x45\x94\x32\x7e\x8e\x8d\xac\x15\x6f\x76\x46\x94\x0a\xff\x5f\x0c\x5f\xaf\x61\xc6\xdf\xc3\xbc\xd9\xa9\x95\xf0\x79\xca\xf8\xfb\x14\xa0\xb5\x1a\x3e\x77\x18\x7f\x9f\x1f\x7c\xd3\xeb\x96\x35\x5c\xde\x6c\x33\xbe\x84\x96\x75\xdb\x66\x9c\xcc\xb9\x2b\x04\x76\xcc\x40\x99\x71\xbf\x23\xb0\x6b\x06\x66\xf9\xf6\x13\x22\x7b\x66\xa4\xcc\xb6\x1b\x04\x1e\x99\x81\x32\xd7\x6e\x11\x78\x6c\x06\x66\x99\xf6\x17\xc8\xab\xdb\xaf\x41\x4a\x20\x86\x1c\xd4\x5c\x9b\xf1\x6b\xc4\x0d\xcd\x38\xcc\xb1\x9f\x11\xbd\x34\xa3\x65\x86\xfd\x82\xc0\x95\x19\x28\xf3\xeb\x0d\x02\xd7\x35\xc0\x39\xe3\x5f\x11\xb8\xa9\x01\x06\x8c\xdf\x22\x70\x6b\x06\x86\x8c\xdf\x21\x6e\x67\xc6\xc9\xbc\xfa\x0d\x80\xbd\x1a\x4d\xca\xac\x7a\x8f\xc0\x1a\x51\xca\x9c\xfa\x80\xc0\x1a\x51\xca\x8c\xfa\x88\xc0\x1a\x51\xa6\x8c\x3f\x21\xae\x46\x92\x32\x9b\xee\x10\x58\x23\x49\x99\x99\xae\x10\x58\x23\xc9\x2c\x93\xae\x11\x59\x23\xc9\x2c\x8f\xae\x41\xbc\xbd\x1a\x4d\x66\x59\xf4\x01\x91\xb5\xaa\xcc\x72\xe8\x03\xe4\xd0\x5e\x8d\x26\xf5\x0c\xfa\x12\xf0\x35\xd2\x54\xf9\xf3\x27\x36\xad\x46\x9c\x7a\xf6\xc4\xd0\x75\x1a\x65\xfc\xf3\x16\x70\x35\x12\x95\x99\xf3\xf3\x13\x00\x6b\x34\x2a\xf3\xe6\xe7\xfc\x54\x97\xde\x51\x8d\xf4\xe4\xc6\xec\xfa\x0e\x80\x35\xd2\x23\xb7\x65\x1b\x18\x93\xa3\xba\x04\x59\x59\xb5\x7f\x42\x5a\x8d\x34\xcb\x5b\xb2\x6b\xe8\x9e\xa3\x1a\x91\x56\x37\x64\x1b\xd8\x58\x1c\xd5\x48\xd6\xbc\x1d\xbb\xbe\x06\x7a\x8d\x8e\xf7\x37\x63\x3f\x91\x54\x23\x69\xb9\x65\xfa\x8c\xdd\x50\xa3\xe8\x6c\x23\x76\xf3\x19\x90\x35\x7a\xce\xb6\x61\xb7\x88\xac\x51\x32\xbd\x09\x7b\xc4\xbe\xaa\x51\x76\x75\x0b\xf6\x05\xaf\x58\x23\x5c\xd3\x06\xec\x3b\x76\x41\x8d\x98\xd5\xf6\x6b\x93\x3f\x74\xd1\x3b\xae\x5d\x74\x9e\x3b\x09\xe3\xe7\x70\x57\xe2\xb8\x46\x97\x19\xf2\x27\x22\x6b\x57\x5b\x23\x6f\x6a\x9d\xa7\x31\xe3\x21\xe2\x6b\xfa\x17\xd1\x77\x80\xee\xd7\xd6\x79\xe2\x25\x0e\xe3\x13\x04\xd7\x54\x5a\x41\x77\x08\xad\x5d\x2b\x7b\x17\x33\x2f\x89\x1d\xc6\x4f\x11\x5f\xb7\xea\x00\xf4\x77\x40\x0f\x6a\x37\x0d\xf9\x7d\xab\x31\xa2\x6b\xd2\x4c\x8e\x5d\x03\x76\x58\x1b\x79\x3a\xcb\x1f\xf8\x48\x17\x49\x1a\x05\x8c\x4f\x91\x57\x73\x8d\x0a\xeb\x53\xce\x3a\x52\x8f\x9f\xce\xc4\x28\x12\x67\xb8\x60\xf4\xe5\xdc\xe7\xfc\x0e\x90\x76\x15\x32\x12\x09\xe3\x23\x44\x74\xaa\x88\xa9\x37\x97\x0b\x96\x29\x62\xba\x55\x8c\xeb\xf8\x32\x8e\x8b\x98\x5e\x15\x23\xf5\x3d\x43\xc0\x51\x15\x70\xea\x9c\x32\x7e\x86\x88\xe3\x2a\xe2\xc2\x39\xf7\x02\xc6\x2f\x10\xd3\xa7\x2e\x93\x30\xfe\x11\x11\x83\x2a\x22\x91\x88\xe4\x33\x20\x86\x55\xc4\x79\xe8\x32\xfe\x1e\x63\x2c\xab\x08\xf5\x6b\xc2\x89\x33\x61\xfc\xe4\xbf\x80\x5b\x55\x71\x0a\x81\x91\xd6\x55\x84\xef\xcc\x85\xcb\xb8\x8f\x98\x8d\xe9\x6a\xf3\x6c\xb3\x8d\x57\xdb\x56\x71\x0a\x81\x91\x76\xa6\x48\x41\x2a\xf7\xe2\x10\x69\x4b\x28\x47\x21\x20\xd2\x96\x10\x4e\xec\xcc\xc5\xc9\x8c\xf1\x18\x41\x84\x76\xd4\x78\x09\x84\x10\xd2\x51\x35\xca\xf6\xf1\x58\x21\x42\x3d\x19\x00\xe3\x10\xea\x51\x71\x92\xd8\x71\x3d\xc6\x2f\x60\x74\xb7\x84\x8a\x00\xf3\x1e\x30\x84\x8a\x3e\x84\x13\xc6\x3f\xe0\xf5\x08\x15\x45\x22\x9e\x31\x1e\x21\x84\x90\x51\x3c\x93\xad\x8f\xaf\x00\x42\xe8\x28\x91\x9a\x4f\xf2\x20\xc7\xea\xce\xa0\x13\x39\x23\x99\x2f\xc2\xec\x36\xfc\x1f\x50\xa8\xee\xd9\xe4\x85\xb1\x98\x7b\xe3\x30\xfb\x41\xe9\x4f\x04\xec\x34\xc0\xfe\x91\xb4\x00\x52\x37\x3e\x72\x10\x2e\x12\xe7\x17\x0e\xe3\xb3\x97\x80\xe9\x54\x31\x32\x95\xc0\xc3\xa8\xae\xeb\xe0\xa9\x7a\x73\xe0\x74\xeb\x38\xd9\x15\x90\x33\x03\x4e\xaf\xca\x39\x73\xce\x08\xca\x0f\xa4\x1c\x35\x5f\x26\xbf\x6b\xbf\xbc\x02\xce\x71\x95\x73\x2e\x66\xc4\x65\x7e\xe2\x65\xfa\xf4\x65\x18\x5f\x62\x47\x0e\xaa\x90\x91\x98\x31\xbe\x42\xc4\xb0\x8a\x48\x84\xec\xc0\x68\x94\xca\x19\xee\xf1\x2b\x20\x97\x24\x92\xf1\x47\x8c\xb5\x22\x10\xb3\x0c\xf2\x05\x20\xeb\x2a\xe4\xbd\x90\x19\xe1\x13\x46\xd9\x50\x83\x3f\x63\xfc\x0a\x83\x6c\xab\x88\x93\x0c\xf2\x2f\x06\xd9\x55\x21\xae\xe3\x33\xbe\x01\x84\xba\x87\xb1\x5f\xd9\x0c\x02\xd7\xe9\x12\x32\x8c\x64\x73\xee\x31\x08\x21\xc2\x0b\x47\x1a\xea\x17\x42\x08\xcd\xc5\x42\xee\x85\x1f\x10\x42\x48\x2c\x9e\x29\xcc\x2d\x60\x08\x4d\xc5\x8e\xcb\xf8\x1a\xa3\x10\x0a\x72\x25\x62\xb3\x01\x04\x21\x98\x44\x76\xdb\xe3\x67\x40\x10\x7a\xb9\x90\x88\x5f\x20\xba\x2e\xa1\x97\xac\xc1\x5b\xac\x07\xa1\x93\xe9\x2c\xc3\x5c\x03\xa6\xa7\x77\x7e\xe2\x24\x67\x42\xce\xde\xbf\x63\x31\xd1\xf1\x13\xd9\xf1\x3b\x44\x10\x1d\xff\x41\x4e\x63\xff\x43\x04\xd1\xef\xd9\x44\xf7\x05\x11\x44\xb7\xfb\xce\x9c\xf1\x1b\x44\x10\x9d\x3e\xcf\xd4\xfa\x15\x21\x44\xaf\x07\x61\x76\xf4\x00\x42\x88\x6e\xcf\x5c\x71\x85\x08\xa2\xdb\xcf\x9c\x33\xc6\x7f\x20\x82\xea\x76\x99\x52\xe6\xce\x49\x9c\x46\x72\x93\x89\x50\xa2\xff\xcf\xe5\xe5\x7e\x22\x42\xf7\xe9\xc4\x49\x66\x4e\xe2\x04\x8c\xbf\xc5\x72\xdd\xa4\xae\x33\x9f\xab\xf2\xff\x60\xb9\xee\xd0\x13\x27\x8e\x54\xf9\xdf\x58\xbe\xdd\x8f\xcf\xf8\x1b\x2c\xdc\xed\x07\x67\xfc\x25\x14\x1e\x1d\xee\x47\x66\xbc\x8d\x85\xba\x2a\xe2\x99\xcc\xf0\x8c\x77\xb1\x54\x57\x44\x9c\x9e\xc8\xb5\xc1\x21\x14\xaa\xb7\x4a\xf5\x53\xe1\xc9\xb4\x19\x03\x9c\x48\x30\x0b\xd9\x85\xdf\x20\xe0\x92\xd0\xce\xa9\x44\x7c\x47\x04\x91\x81\xa6\x52\x7f\x9f\x76\x39\x42\x3d\xb3\x2e\x9c\x38\x11\x51\x90\x23\x0f\xb2\x73\xe8\x2d\xd7\x9b\x7a\x89\x75\x21\xa2\x90\xf1\xc3\x25\xe0\xdb\x0d\x78\x75\xd2\x3d\xc2\x3b\x0d\x70\x75\xc4\x3f\xc2\xbb\x4d\xf0\xfc\xc4\x7f\x24\xf4\x1a\x08\x93\x30\x8d\x18\xef\x21\xfe\xa8\x09\xef\xc9\xe9\xed\x08\xf1\xc7\x0d\xf8\xd8\xfb\xc8\xf8\x31\xc2\xfb\x4d\x70\x71\x2a\x33\x6a\x1f\x09\x83\x06\x82\xf0\xa6\xb3\x84\xf1\x01\x12\x86\x0d\x84\xc0\x93\x03\x30\x54\xf8\xf6\xb6\xf9\x30\xcb\xec\xd1\xf1\x7c\x25\x70\xe9\x1c\x1c\x5e\x02\xb3\xe1\xf5\x9e\x12\x6f\xa9\xf1\xcc\xef\xf5\x8c\x2a\x2f\xb1\x8e\x5e\x03\xcb\xf4\x66\x4f\x95\xb3\x42\x8e\xf9\xfd\x09\x8d\x05\x55\x1c\x1d\xbc\xc6\x2a\x9a\x5e\xa3\x20\x68\x2b\x8d\x66\x7e\xcf\x27\x27\xaa\xef\x07\x29\xe6\x08\x69\xa6\x97\x7d\x08\xd2\x0a\x49\xcd\x07\x5f\xaa\x03\x11\x4a\x2f\x23\x8c\xff\x78\x89\x01\x9a\x8e\xc0\x24\xe8\x6b\x8d\x6e\x7e\x73\xc4\xad\x8c\x88\x8b\x23\x62\x7a\x57\xa4\xca\xd9\x20\xc7\xfc\x76\x88\x5b\x1d\x0e\x57\x1b\x0e\xd3\x0b\x22\x04\x6d\xa3\xd1\x1a\x8f\xc6\xd4\x07\xc4\x45\x5a\xc3\xf9\x98\x3a\x69\x03\xa4\xe6\x43\x32\xf1\x58\x0b\xf7\x0f\xe0\x34\x9c\x92\x89\x8c\x0d\x32\xcc\x8e\x73\xf7\xdf\x9c\xd7\x3a\xf2\x1d\xd6\xd2\xe4\x3d\x33\x7b\xa3\xb1\x1b\x0f\xd0\x54\xaf\x63\x95\xde\x83\x14\x07\x2f\x90\xdf\x70\x9c\x26\xc1\xde\x6a\xec\xc6\xc3\x35\x35\x3e\xe8\x5c\x1c\xa0\xce\x9b\x8e\xd9\x24\xd8\x5b\x8d\xdd\x78\xe0\x26\xd1\x77\x42\xeb\xbb\x86\xd3\x37\x09\xf6\x56\x63\x37\x1e\xc5\x99\x1d\x05\xa2\x5d\xf8\x1f\xa4\x36\x9c\xc9\x59\x26\x6e\x35\xa2\xd9\xad\xa2\x9a\x58\xf2\xd7\x98\x2e\xc5\x1f\x2d\x0c\x60\x72\x6d\x0d\x7d\xab\xd1\xcd\xee\x9d\x54\x72\xcc\x04\x72\x8c\xf1\xd0\xce\x2a\x67\x07\x9c\xe6\x83\x3b\xe1\x35\xc3\xe9\x01\x50\x1a\x4e\xed\x04\xc2\x27\x24\x98\x9d\x3b\xab\xd4\x6c\x86\x35\x33\xf9\xb5\xca\xb9\x42\x4e\xe3\xb1\x9d\x7a\xba\x9c\x15\xe9\xb2\xe9\xe0\x4e\x9d\x76\xa5\xd1\x1a\x8f\xee\xd4\x1e\x6d\x9d\xbd\x05\x56\xc3\xe9\x9d\x1a\xe7\x0a\x39\x66\x0f\xce\xf6\x32\xe6\x0c\x32\xa6\xf1\x08\xcf\x7d\xc6\x15\x32\xcc\x5e\xcb\x39\x99\x58\xb5\x1e\x44\xc9\x1a\x0f\xf3\x24\x89\x57\x1a\xb1\xf1\x50\xcf\xb2\x4d\xbd\xc2\xa6\x4d\xa7\x7b\x96\x89\xd7\x1a\xb1\xf1\x98\x4f\xfa\x05\x7f\xef\x2d\x26\xc5\xa6\x63\x3f\xe9\x00\xd7\x45\x80\x9a\x63\x40\x4f\x4a\x8f\x1c\x9f\xbc\x04\x86\xc9\x78\x65\xfc\x17\xc4\x9b\x7d\x77\x52\x95\xf5\x49\x21\x6b\xe2\x50\x50\x23\xed\x8b\x46\x33\xbb\xef\xa4\xba\x7c\x38\x41\x9a\xc9\x7b\x04\xe9\x0b\x92\xcc\xce\xf3\xab\x95\xf4\xb5\x4a\x9a\xcc\x47\xd0\x6e\x34\x9a\xd9\x7f\xfb\xc4\xf2\xb9\x14\xfe\x81\x16\xc4\x64\xc8\xfa\x10\x37\x7a\x08\xb3\x43\xfd\x6a\x77\xf9\x48\x33\xb9\x93\x20\xdd\x20\xc9\xec\x4c\xdf\x38\x73\xfb\xc5\xcc\xdd\x35\xd9\xd3\xcc\xbe\xd1\xd8\x66\x8f\xce\x4b\x7a\x9f\xa3\xde\x4d\x96\x2c\xe3\xbf\x02\xbe\x67\x76\xe0\xbc\x32\xc7\xcc\x61\x8e\xe9\x99\x5c\x58\xe5\x7c\x45\x8e\xd9\x89\xf3\xaa\xec\xe6\xc5\x70\xf7\x4c\x4e\x24\x68\x5f\x35\x9a\xd9\x89\x41\xa5\x96\x01\xd6\xd2\x64\xc4\x2a\xe7\x16\x39\x66\x1f\x06\xd5\x2a\x06\x5a\x15\x4d\x3e\x24\x68\xb7\x1a\xcd\xec\xc3\xa0\x2a\xe5\x00\x69\xe6\x33\x49\x2b\xa4\x5b\x24\x99\xbd\x16\x18\x15\x1c\x14\x0a\x36\x9e\x4c\xfa\x3c\x76\xe3\x39\x12\x6a\x7a\x2b\xbd\xe4\xff\x0f\x4e\x2f\x4d\x47\x96\x56\xc9\x77\x1a\xb9\xf1\x84\x81\x82\xae\xad\x56\x2e\xc3\x7f\xde\x62\x88\x86\x43\x06\xe8\x00\x77\x45\x80\xe6\x03\x4e\x89\x3d\x53\x58\xec\x99\x9a\xce\x39\x25\xd8\x77\x1a\xbb\xf1\x5b\x70\xc4\x9e\x29\x2c\xf6\x4c\xc4\x21\xa8\x4d\xec\x3b\x8d\x6d\xf6\xef\xa2\x94\xcb\x16\x90\xcb\x8c\x47\xa3\x96\xf1\xdf\x10\x6f\xf6\xed\xa2\xe2\xf6\x05\xb8\xdd\x78\x38\x6a\x95\xf3\x0d\x39\x8d\xc7\xa3\x6a\xac\x08\x59\x0d\x47\xa4\x6a\x9c\x7b\xe4\x98\xfd\x1a\x55\x93\x4a\x54\x24\x15\xe3\x69\xa9\x04\xed\x5e\xa3\x99\x1d\xba\x4f\x2c\x4f\xe8\x91\x36\xa1\x1b\x8f\x50\xad\x0f\x71\xaf\x87\x30\xbb\x35\xaa\xa6\xb7\x08\x69\x26\x87\x12\xa4\x7b\x20\x35\x1f\xab\xaa\x8d\x4c\x0c\x23\xd3\x74\xb4\xaa\xc6\x79\x40\x8e\xd9\x81\x71\x75\x58\xe2\xa2\x3b\x8c\x67\xac\x12\xb4\x07\x8d\x66\xf6\x5c\x5c\x79\x27\xba\xa8\xef\x65\xfc\xb2\x08\x61\x32\x61\x6d\x80\x07\x2d\x80\xd9\x95\xfa\x21\xb4\xd5\x3a\xfc\x55\x84\x30\x59\xb4\x36\xc0\x83\x16\xc0\xec\xd7\xfd\x0e\xac\xd6\xe3\xb5\xd6\x9f\x26\x07\xff\xbf\x45\x31\x7b\x3a\xa9\x68\x27\x41\xed\x98\x0c\x5d\xe5\x3c\x22\xc7\xec\xe6\xa4\x2a\x9c\x44\xab\xa2\xc9\xc1\x04\xed\x51\xa3\xd5\x7c\x10\xb2\x6a\xc0\x04\x69\x26\xd7\x12\xa4\x47\x20\xd5\x1c\xf5\x9a\x18\xd7\x22\x49\xb1\x16\x31\x9e\xf8\x6a\x66\x3f\x6a\xec\xc6\x83\x5f\x8b\xcd\x32\xd0\xd3\x83\x03\x5c\x09\x34\x9d\x02\x5b\x65\x3f\xe9\x6c\xb3\xaf\x53\xea\x36\x41\x5a\xdc\x26\x30\x1e\x0b\x4b\x12\x9f\x34\xa2\xd9\xc7\x95\x0f\xcc\x69\x17\x2e\x7a\xcc\x64\x62\x33\xfb\x49\x63\x3f\xef\xb0\xe5\xf2\xd9\x87\xc5\xe2\xaf\xff\x9c\x93\x97\xcb\xe7\x1e\x6a\xe4\x67\x1e\xc3\x5c\x59\xf9\xa5\xda\x88\x3d\xeb\x5c\xe6\x4a\x84\x27\x2d\x82\xd9\xcb\xa7\x5a\x23\x18\x3f\xfd\x07\x18\x26\x13\x97\xf1\xdf\x11\x6f\x76\xef\x69\xd5\xf6\xa7\x85\xed\xfb\x26\xff\x12\xb4\xef\x05\x6d\x60\x76\x70\xfe\x80\x54\xbe\x88\x3d\x7b\x01\x0c\x93\x67\xcb\xf8\x1f\x88\x37\xbb\xf4\xac\xb4\x86\x3c\x83\x35\xe4\xc0\xe4\xcb\x32\xfe\x07\xe2\x1b\x0f\x67\xd6\x86\xf3\x0c\xee\x7c\x0e\x1a\xce\x66\xd6\x38\x3f\x90\x63\xf6\xdf\x59\x65\x06\x38\x83\x19\x60\x60\x72\x5d\x95\xf3\x03\x39\x66\xaf\x9d\x55\x07\xf4\x4c\x1b\x50\x93\xcb\x08\xda\x0f\x8d\x66\xf6\xd7\xc7\x4a\x2d\x3f\x62\x2d\x4d\x8e\xaa\x72\xfe\x45\x8e\xd9\x43\x1f\x2b\x3d\xff\x11\x7b\xde\xe4\xa3\x2a\xe7\x5f\xe4\x98\xbd\x74\x5e\xa9\xdf\x39\xd6\xaf\xe9\xa3\x97\x05\xe7\x27\x70\x86\x66\x17\x5d\xec\x67\x56\xc6\x2f\xde\x01\xcd\x64\x25\x82\xf4\x0b\x49\x66\x3f\x5d\x54\x87\xf8\xa2\x18\xe2\xa1\xc9\x56\x04\xed\x97\x46\x33\xbb\xeb\xa2\xba\x34\xb8\x40\x9a\xc9\x5e\x04\xe9\x17\x92\x4c\x67\xf4\xce\xaa\xa4\x2b\x24\x35\x7c\x34\x40\x93\xc6\x23\x48\x63\x68\x3a\x87\x37\x77\x89\x7e\x22\xe0\x8f\x43\x20\x99\xac\x75\x5e\x25\xfd\x04\x52\xcd\xe9\xdf\x4e\xb5\xdf\x9d\xa2\xdf\x8d\xa7\x80\x13\xb4\xa5\x46\x6b\xfc\x36\xea\x2c\x0c\x4f\xa0\x9a\x4e\x07\x68\x0d\x1f\x48\xd5\x49\x4b\x24\x35\x7e\x25\x55\x5b\x50\x94\x0e\xc8\x7c\x87\x13\xfb\xb2\xe1\xb3\xa9\x86\x08\x4b\x2d\x82\x39\x29\xd3\x31\xe0\xb6\x8c\xf3\x0e\x6f\xcb\x2c\x4d\x1a\xaa\x8f\xb0\xd4\x22\x98\x13\x36\x1d\x43\xef\xd1\x4b\xe7\x5d\x07\x03\x99\x54\xf6\x8c\x30\x4b\x2d\x4c\xe3\xe1\xa5\x7b\x81\xf2\x95\xc8\xa5\xf3\x0e\x97\x9b\xcb\x86\xc3\x4b\x0d\x11\x96\x5a\x84\x9a\xc3\x4b\xc9\x18\x25\x33\xbc\xd3\x64\x6d\x3c\xcf\xb4\x31\xcc\x52\x0f\xd3\x78\x6c\xb4\xfa\x3d\xb1\x24\xd6\x56\x21\xb5\x86\x43\xa3\xab\xe4\x65\x41\x5e\x35\x66\x82\x82\x8e\x12\x6d\xa1\xc0\x56\x0d\xf9\xa0\x4a\x5e\x6a\xe4\xe7\x7d\x31\x99\x10\x66\x0b\x15\xb5\x7a\xce\x37\x94\x09\x4d\x6a\x11\x1a\xf3\x45\x11\x03\xe5\xd8\x42\x31\xad\x1a\x52\x45\x95\xbc\xd4\xc8\x8d\x59\xa2\xa0\x97\x44\xd8\x2a\xd4\xb3\x6a\xc8\x12\x74\x84\xa5\x1e\xa1\xf1\x91\x17\x9d\x29\x34\x62\xc3\xb3\x2e\x3a\x6d\xab\xd1\x1a\x1f\x72\xd1\xc7\x4a\x40\x62\x5f\x35\x3c\xe0\xa2\x93\xb6\x48\x6a\x7c\xb8\x25\x1f\x16\x01\x9b\x9d\x55\xc3\xd3\x2c\x39\x7e\x8b\xf8\x9a\x83\xa8\x6b\x67\x0b\x51\xcc\x16\x2b\xe3\xc1\xd4\xb5\x11\xb6\x45\x84\xb5\xd9\xc7\x74\x0c\x7c\x6c\xab\x98\x2d\xd6\x26\x33\xd7\x47\xd8\x6a\x11\x1a\xbf\xee\x5c\x37\x51\x88\x62\xa2\x58\x37\x7c\xf3\xb9\x2e\xcc\x56\x0b\xd3\xf8\x20\x9b\x61\xb6\x10\xc5\x6c\xb1\x6e\x78\x98\xcd\x10\x61\xab\x45\x68\x7c\xa0\xad\x66\xa2\x10\xda\x44\xb1\x6e\x78\xb2\xad\x26\xcc\x56\x0f\xd3\xf8\x7d\x5c\xbd\x3f\x3d\xb0\xd2\xba\xe1\x23\xb9\x3a\xe9\x1a\x49\x8d\x5f\xca\xd5\x6b\xe9\x69\x95\x6c\xf8\x5e\xae\x4e\xbb\xd6\x68\x8d\x3f\x24\xea\xc4\x50\x23\x36\xfc\x84\xa8\xd3\xee\x34\x5a\xe3\x8f\x87\x7a\xb7\x84\xd8\x2d\x0d\x3f\x18\xea\xa4\x3b\x20\x6d\x1a\x7f\x24\x34\xe4\x89\xb0\xc8\x13\x9b\x86\x1f\x0a\x0d\x11\xee\xb4\x08\x8d\x3f\x16\x1a\xf2\x44\x58\xe4\x89\x4d\xc3\x0f\x86\x86\x08\x77\x5a\x04\xb3\xb3\xe9\x18\xa5\x14\x11\x16\x29\x62\x63\xb2\xf7\x33\xc2\xdc\x69\x61\xcc\x1e\xa7\x03\x41\x9e\x08\x8b\x3c\xb1\x31\xd9\xbb\x3e\xc2\x9d\x16\xc1\xec\x6c\x3a\x46\xc9\x0c\x5a\x8a\xd8\x98\xbc\xde\x1c\xe6\x4e\x0f\xd3\xf8\x09\x8a\x59\x18\xed\xfd\xac\x3c\x2c\x94\xd6\xf0\x35\x8a\x0a\xf7\x4e\xe3\x36\xe6\x01\x64\xa3\x3e\x87\x85\xba\x1a\x92\x41\x85\x7b\xa7\x71\x9f\x91\x11\x72\x76\x59\x93\xc3\x42\x4c\x8d\xd9\x81\x0a\x70\x57\x04\xa8\xf9\x10\xcc\x7e\x08\xd4\xe1\x10\x55\x64\xfc\x0a\x8c\x89\x7b\xa7\x71\x1b\xb3\x03\xb2\x4b\xda\x1b\x16\xa2\x31\x7e\x11\xa6\x2e\xc0\x9d\x1e\xa0\xf1\x47\x10\x9d\x99\x6a\xc4\x86\x9f\x40\x74\xda\x93\x46\x6b\xfc\x01\x44\x1f\xa7\x14\xd2\xb9\xf1\x8b\x31\x04\xe9\x09\x49\x8d\x3f\x77\x54\x5c\x91\x16\xae\x30\x7e\x42\xc6\xc4\x7d\xd2\xb8\x8d\x3f\x76\x54\x5c\x91\x16\xae\x30\x7e\x59\xc6\xc4\x7d\xd2\xb8\x8d\x5f\xa2\xa4\x0d\x91\x6a\x86\x68\xf8\x34\x25\x1d\xe0\x49\x0b\xd0\xf8\xad\xca\x8a\x2b\x52\xcd\x15\x0d\x9f\xac\xac\x70\x9f\x0a\xee\xae\xf1\xcb\x95\xa4\x21\x52\xcd\x10\xbb\x86\x6f\x58\x92\x01\x9e\xf4\x00\x66\x57\x9f\x97\x7e\x60\x39\x87\x1f\x58\x76\x26\x13\x97\xf1\x3f\x11\x6f\xf6\xec\x79\xd5\x7c\xe7\x5a\xd5\x4c\x9e\x25\x68\x3f\x35\x5a\xe3\xf7\x2c\x75\x25\x9c\x83\xfd\x76\x0d\xdf\xb3\xd4\x49\x3f\x91\xd4\xf8\x3d\xcb\x7c\xd8\xcf\x61\x4f\xb9\x6b\xb8\xa9\x9b\xe3\x7f\xe6\xf8\xdd\xa1\x76\xa2\xb0\xeb\xc4\x9e\xf6\x0e\x18\x7e\x08\xe6\xcf\x97\x00\xd6\xce\x14\x5e\xc4\x9e\xef\x11\xe0\x3f\x10\xdc\xa1\x22\x9f\x3a\x91\xe7\x30\xfe\xe7\x0b\x40\x75\xa9\x90\x39\xea\x0f\x44\xf5\xa8\x58\x0b\x11\x79\xf1\x22\x9c\x8b\xc0\x63\xfc\x9f\x3f\x01\x7b\x44\x45\x2c\x63\xff\x00\xac\x76\x98\x78\xf9\x49\xf4\xbc\x06\x2f\xde\x02\xb2\x6f\x42\x96\x23\x2b\x7c\xe7\x50\xb5\x5e\x04\x56\xbc\x70\xc6\x82\xf1\x76\x00\x05\xea\xad\xd6\x39\x16\xcc\xa1\x20\x6b\x63\xf6\x4e\xeb\xc1\x42\x44\x07\x05\xa4\x8b\x90\xac\x69\x93\x30\x8d\xf6\x10\x3d\x44\x64\x0d\x8a\xbd\x8f\x7b\x80\x63\x04\x0c\xd5\x55\xbc\xa2\x66\x09\x14\xa9\x83\x36\x1c\x2f\xc2\xa2\x59\x5e\xa4\x5e\x5d\x9b\x9d\x2f\x66\x22\x60\xfc\xa0\x0d\x7f\xee\xe6\x8d\x74\x9d\x78\xc6\xf8\x01\xb4\x51\xbd\x05\x26\xe6\xf0\x77\xb8\xb8\x7a\xbb\x6b\x16\x46\xde\x45\x18\x48\x2d\x8f\x9c\x88\xf1\x83\x2e\x14\x67\x95\xcf\xbf\x45\x74\x2a\xa2\xc4\x1b\x4b\xbd\x67\xef\xb0\xbe\xe8\x00\xa8\xaf\x81\xfc\xf0\x2c\x2f\xff\x1b\xcb\x95\x65\x44\x76\xca\x5a\x30\xf5\x85\xf5\x21\x0d\x13\x47\x3b\xd4\xe3\xe5\x31\x40\xb3\xbe\x88\xbc\xe9\xcc\x8c\x1d\x02\x76\xa9\x3a\x36\x43\xf9\xe1\xd9\xc1\xb0\x82\x7d\x8d\xd8\x95\x86\x9d\x79\xd3\xd9\x41\x24\x4e\x45\x14\x0b\x97\x60\x0d\x5f\x02\x6b\x8d\x15\xcf\x5b\xb7\x0f\xfd\x0f\x56\x7c\x53\x54\xdc\x84\xc5\xca\x6c\xcb\xfd\x45\x54\xe1\x2d\x62\x77\x1a\xb6\xb1\xe2\xff\xc9\x59\xea\xdd\x28\xd7\x99\x4e\x45\xc4\xf8\x9b\x03\xf8\x73\x5b\x0b\x86\xa5\x7f\x43\x69\x26\x85\xe4\x2c\xcc\xd2\xac\x2f\x1c\x57\x16\xbf\x7e\x9d\x17\xab\xb7\x3e\x16\x22\xb2\xe6\x9e\xef\x0b\x38\x30\xef\x10\x8a\x33\x77\x2d\x22\x6f\x2e\x55\x0a\x3d\xa8\xde\xc7\xc8\xaf\x98\x17\x76\xb0\x50\xd9\x2b\xf2\x16\x45\x61\x17\x0b\xb3\xda\x40\x63\x31\x30\xb4\x50\xbd\x45\x81\xc5\x7b\x57\x40\x54\xbf\x84\xda\xbb\x14\xa2\xd4\xc9\x6f\x4e\x24\x12\xc6\xc7\x4b\xf8\xeb\x50\x97\x97\x98\x24\x07\x8b\xd0\x0b\x92\xec\x17\x38\x52\x98\x7f\x81\x07\xbb\xba\x30\x33\x49\x34\x51\xdf\x21\x75\xa5\x2a\x3c\x11\x91\x08\xc6\x02\xd4\xf0\x11\x8a\xd7\x5a\x77\x8a\x8f\x63\xdf\x99\xeb\x61\x2e\x5f\xfc\x96\xaf\x71\x3a\x87\xea\x25\x84\xf0\x54\x44\xca\x8d\x2f\x41\x04\xea\x09\xfb\x49\xe4\x8c\x33\x66\xec\x67\x09\xe1\xcd\x2e\x2f\xae\x9e\x82\x50\x3a\x67\x20\x06\x58\x8f\x86\xe5\xef\xf3\x23\xec\xc8\x00\x53\xaf\xf1\x23\xec\x98\x86\xa9\xb7\xf7\x11\xd5\x37\xa0\xf2\x97\xf6\x11\x37\xa0\x71\xf0\xae\x3e\xe2\x86\x34\x2e\x7f\x45\x1f\x61\xcb\x7d\xd8\xc2\x4f\xe3\x5c\xff\xbf\x23\x6a\xb5\x8f\x9a\x7b\x41\x1a\x33\x7e\x80\x88\xf5\x3e\x42\x7c\x48\x1d\x1f\x22\xfd\x8d\xb8\xcd\x3e\x2e\xcb\x40\x0b\x27\x12\x41\x32\x53\x3f\x33\xb7\x10\xbc\xdd\x07\xab\x1c\x54\x42\xbf\x42\xf4\xae\x12\xba\xba\x2c\x09\x18\xbf\x05\xc2\x20\x57\xc3\x88\xd2\xc2\x03\x80\xda\x14\x48\x1d\x34\x81\x98\x0e\x85\x51\xa7\x4b\x20\xa6\x4b\x62\xf2\x23\x25\x10\xd5\xa3\x50\xb9\xee\x10\x74\x44\x82\x94\xea\x10\x74\x4c\x81\x94\xe6\x10\xd3\x27\x31\xb9\xe2\x10\x35\xa0\x50\xa0\x37\x44\x0d\x29\x54\xae\x36\x04\x2d\xcb\x20\x5d\x6b\x88\x59\x95\x31\xa0\x34\x2c\x5f\x97\xcb\xcb\x3a\x43\xd4\xa6\x8c\x22\x54\x86\xd0\x6d\x19\x4a\x69\x0c\xb0\xf9\x4f\xf6\x5e\xe4\xe4\x17\xf4\xaf\xa1\xa4\xaf\x66\x90\x58\x24\x50\xb6\x78\x84\xb2\xac\x6f\xce\x64\x42\xca\x0a\xce\xf2\x59\xa9\xad\x16\x67\xae\x90\xeb\x3c\x4b\xae\x67\xbd\x69\xe4\xc8\xf5\xf2\xdd\x18\x10\x47\x90\xbe\xad\x70\xc2\xf8\xfa\x0e\xfe\x3e\xd4\x98\x13\x67\x16\x89\x60\x26\xbc\x84\xf1\xbb\x49\x8e\x50\xab\x9b\xec\xd3\x26\x61\x7e\xdd\xe0\x10\xca\xd4\xc0\x87\x69\xe0\x5a\x91\x18\x87\x91\x2b\xd3\xf7\x38\x5c\x9c\x47\x6a\x58\x17\x21\x20\xb7\x6a\xe6\x13\xaa\x73\x64\x52\x4d\x9c\x13\xc1\x78\xf4\x6f\x8e\x50\xd3\x71\x2c\xa2\x53\x0f\x73\x7a\x3c\x87\xc2\x8e\x9a\x05\x1d\x57\x15\xe5\x15\x49\xb0\x3c\xab\x64\x38\x9b\xe7\x05\xe1\x57\x28\x50\x27\xf4\x04\xd3\x38\x89\x42\x01\xc5\x0e\x54\x4b\xbd\xc7\x71\x9a\xfa\x53\x27\x2a\xd2\x7d\x18\x08\xb9\xd4\x8c\x5c\xc6\xdb\x5d\x40\xf6\x28\xa4\x5c\x08\x64\xc8\x98\xf1\x0e\x42\x8f\x4c\x41\x27\xde\x24\x99\x31\xde\x3e\x02\xe4\xb1\x29\x68\x86\x94\x41\x11\xda\x27\xa1\xb3\x6c\xdc\x72\x70\x17\xc1\x03\x0a\x2c\xed\x8f\xd8\x1e\x62\x87\xa6\xda\xc6\xde\xc7\xac\xb6\xc7\x80\x5c\x92\x51\xbd\xd3\x1c\x1a\x33\x7e\x84\xd8\x95\x29\x6a\x66\x78\x19\x76\x00\xd0\xb5\xb9\x65\x0a\x2c\x9b\x86\xe8\x8d\xb1\x12\x08\x3e\x42\xf0\x96\x02\x67\x89\xa9\x40\xf7\x01\xad\x5e\x7e\x88\xc2\xb9\x13\xe0\xa7\x7c\x54\x82\x8e\x00\xd1\xae\x22\x54\x7a\x46\x44\x87\x40\xe4\xc9\x19\x31\xdd\x2a\x26\x4f\xcd\x08\xe9\x11\x10\x95\x98\x11\x72\x54\x85\xa8\xb4\x8c\x88\x63\x02\x91\x27\x65\xc4\xf4\xab\x18\x48\xc9\x88\x19\x54\x31\x79\x42\x46\xc8\x90\x68\xb6\xbc\xd0\x12\x11\x4b\xe2\x42\xbe\xaa\xcd\x0a\x41\x2b\xaa\x7f\x85\x2f\x1b\xbe\x46\xd0\x9a\xea\x9b\x49\x72\xce\xf8\xe5\xd1\x61\xfe\xfe\x4b\xa7\xad\x9e\xdb\xaf\x8c\xa6\x35\x4b\x03\x37\x12\x2e\xe3\x97\xed\x43\x0d\xbd\xa5\x3b\x5c\x83\x1f\xe9\xf0\x1d\x1d\x3c\x99\x85\x69\xec\x04\x79\xf4\x02\x9f\x2f\x18\xb3\x15\x04\x25\xb0\x7b\xc0\xb5\x4d\x38\x25\x33\xc4\x75\x8c\xb8\x5c\x6c\x88\xec\x9a\x90\xb9\xe4\x10\xd8\x33\x02\x95\xf0\x10\x78\x64\x02\x2a\xf9\x21\xee\xd8\x88\xcb\x45\x88\xc8\xbe\x09\x09\x52\x44\xe4\xc0\x84\xcc\x05\x89\xc0\xa1\xb1\x83\x32\x59\x22\x6e\x69\xbc\x34\x88\x13\xa1\x2b\xf3\xd8\xe4\x12\x45\xe8\xda\xdc\x97\x20\xd4\x7b\xd4\xc6\xa6\x46\x1b\x65\xb9\x16\x9c\x6d\xdd\x60\x95\x45\x5b\x90\x76\x75\x17\xda\x93\x2e\xb2\x06\x74\x56\x44\xbc\x35\xb6\x50\xee\x63\x17\x59\x44\xa6\xcc\xaa\xa6\x5d\xe6\x48\x77\xc8\x80\x4a\x9c\x22\xd8\xaf\x56\x41\xc8\x1f\xf6\x15\x93\xe4\xcc\x89\xdc\xd8\x72\xa2\x28\x3c\x63\xfc\xaf\x03\x28\xcf\x6a\x90\x2e\x4a\xa5\x07\x2f\xa0\xb4\x83\xb7\x22\xca\x80\x77\x00\xc8\x37\xe5\x67\x41\xb9\xfc\x3b\x94\xf7\xf0\xb6\x87\x5a\xe8\xc1\xf5\x31\xc0\x91\xba\x7e\x16\x03\x4a\x53\x17\x4a\xd5\xaa\x2a\x8c\x92\x99\x75\x26\x62\xa4\x5f\xfe\xf5\xe2\x05\xb6\xb0\x5f\x60\x84\xa3\x61\xde\xbc\x79\x87\x98\x41\xbe\x02\xdb\xc7\xbc\x78\x51\x60\x86\x05\xa6\x7c\xad\x37\x6f\x00\xb3\xd9\xeb\x4d\xf8\xb2\x76\xde\x28\x58\x68\x6e\xf6\xbb\xad\x8c\xfb\x1b\x1a\xbf\xd9\xef\x9d\x3d\x5c\x1e\xaf\xa3\x6e\xe3\x4e\xc2\xc8\x72\x7c\x9f\xf1\x89\x03\x7f\x57\x37\x4a\x9c\x28\xf1\x1c\xdf\x72\xbd\x49\xb6\xd7\x97\xff\x83\xf1\xcd\x02\x40\xd9\x10\x25\x33\x11\xc9\x7d\xbe\x17\x27\x31\xe3\x89\x80\x42\x75\x48\xde\x7c\x91\x9c\x5b\xb1\x48\x18\x7f\x73\x08\x25\x59\xd7\x7b\xc1\x38\x12\xf3\xec\xd6\xaf\x8b\x1c\xd5\xe1\xce\xc8\x77\x18\x0f\x46\xf0\x57\x75\xbc\x9d\x9f\xa1\xb3\xd5\x73\xeb\x00\x8a\xd4\x89\xe9\x61\x90\x38\x5e\x10\x5b\x4e\x6c\xcd\xc5\x7c\x24\x22\xc6\x0f\x5e\x01\x24\x33\x5d\x70\xe0\x44\xe7\xd6\x22\x0a\xdd\x74\x9c\x30\xfe\x1b\x34\x41\x9d\x93\xa5\x4a\xe3\x74\xae\x6e\x54\x30\xfe\xfb\x05\x94\x67\xfd\x90\x6d\x5d\xf2\xa5\xeb\x41\x07\x8a\xba\x58\x74\x10\x46\x07\xda\x16\xe8\xe0\x77\x80\xa8\xf3\x32\xe3\x44\x44\x5e\x7c\x62\x85\x0b\x11\x39\x49\x18\x31\xfe\x1b\x34\x40\xdd\x75\xcc\x9e\x98\x2e\x4a\xc3\x15\x94\x66\xc2\x19\xa5\xbe\x2f\x12\xad\x3c\xc6\x72\x95\x3c\x3f\xa4\x72\x5b\x11\x85\x61\xc2\x78\x94\x40\xd9\x46\x2d\xf8\xc3\x45\x18\xc9\x46\x49\x3b\xcb\xfd\x70\x0b\xca\xb7\x6a\x14\x26\x5e\xe0\xc9\x8c\x78\x08\xc3\xa3\x6e\xe6\xe5\x9e\x0a\xa6\xbe\x60\xfc\xc0\xcf\xcb\xd4\x1e\x01\xfe\x7a\x0a\x7f\x3d\xca\xc5\xe2\xf8\xbe\x50\x97\x59\x40\x07\xe7\x87\xf1\x84\xd3\xec\x9e\x6c\x96\x47\x9c\x00\xca\x06\x7a\x59\xd6\xf2\x08\x8a\x86\xaa\x76\x89\x88\x62\x31\x56\x83\xd2\x4a\xa1\x30\x6b\x76\x1a\x64\x7f\x7d\x85\x7f\x5d\x01\x65\x1a\x49\x99\x7a\xb7\x50\xa0\xdf\x8f\x2a\xca\x5d\x0f\xca\xb7\x20\x22\xb9\x3e\xd7\x02\xe4\x7b\xb4\x4e\x7e\x0b\x50\xea\x7c\x12\x46\x82\xf1\xd7\x6f\xa1\x24\x6b\xf9\x48\x8c\x9d\x34\x16\x8c\xbf\x7d\x0d\x7f\x57\x2b\x3f\xa9\x26\xc6\xdf\x42\xa3\xd4\x8d\xbe\x62\x48\x18\x7f\x8b\x81\xb2\x3a\xaa\x57\xbf\x8a\x81\xfe\xa7\x0d\xc5\xf9\x60\x9d\x8a\x28\x11\xae\xe5\x3b\x17\xe7\x56\xcc\xf8\x78\x9a\x97\xe7\x47\xc4\xc6\xe7\xf3\x45\x12\x66\xb7\xbf\xfd\x73\xb5\xa1\xce\x46\xe3\x1f\x90\x5b\x7e\x0c\xec\x62\x11\x85\x1f\xbd\xb9\x93\x88\x32\x0c\xb2\x42\x7e\x8a\xab\x3f\x0f\xe3\x44\x2f\x07\xe9\xe7\xc7\xaa\xfa\xbe\x56\xf8\xf7\x3f\x79\xa1\xda\xd2\x79\x73\x67\x2a\xb7\xba\x96\x4c\x2d\x86\xeb\xcd\x60\x04\xd4\xc2\x3f\x08\xf5\x8b\xbd\x80\xca\xa8\x35\xbf\xe7\xca\xf4\x33\x86\x8b\x75\xa1\x30\xcf\x73\x71\x7c\x90\xcc\x9c\x40\x5e\x4d\xab\xd2\x5f\x80\x82\x9f\x76\x9c\x44\x44\x04\xf0\x1d\x5e\x2b\x53\xd6\x3c\x1d\xcf\x8a\x98\x8c\xff\xf5\x1b\x14\xaf\xb0\x58\x0f\xc6\xf8\x6f\xef\x00\xb1\x85\x96\x68\xfc\x17\x58\x8f\x1d\x94\x96\xe9\x2f\x80\x5e\xdc\x80\x12\x79\xa6\x1b\x43\x49\x7e\xdb\x69\x21\x0d\xa1\xca\x5e\x61\xd9\x71\x89\x55\x6e\x5b\x7e\x10\x54\xa7\x33\xe8\xef\x45\x28\xe3\x5e\x01\x4e\xcd\x56\x63\x2f\x1a\xfb\x42\xfd\x3e\x5b\x08\xf2\x10\x04\xae\x3e\x4e\x0f\xa0\xbd\xfc\x75\x08\x3a\x59\xc2\x14\x9c\x38\xe3\x13\xc6\x0f\x20\x37\xa9\x07\x1c\xcb\xa1\x5f\x43\xc6\x50\xbf\x7b\xe3\xcf\x38\xc2\xf7\xbd\x45\x76\xf3\xe6\x2d\x0c\xba\xfa\x6d\x7b\xee\xb9\xd9\x7b\x30\xda\xcf\x42\x05\xf6\x75\x8e\xed\xaa\x89\x4c\xae\x61\x04\xe3\xe2\x0a\xfe\x5a\xfc\xd8\x33\x16\x9e\xef\x05\x53\xc6\xff\xea\x43\xa1\xf6\xf3\x0e\x96\xbe\xc3\xd2\x25\x52\x27\x7e\x28\x6b\xde\xff\x0b\x8a\x56\x05\x11\xca\xf2\x91\xed\xaa\x5f\xc2\xf0\x26\xbf\xd4\x40\x7e\x2f\xc7\x03\x44\x7e\xec\xef\x98\xf1\x96\x03\x7f\x53\xbf\x76\x08\x5f\x2c\x66\x72\xcd\xa7\xee\xf1\xc8\xf9\x2d\xc9\x93\x4a\x57\xa5\xe4\x24\x5c\x58\x33\xc7\x9f\xe8\xe9\xeb\x09\x10\x99\x81\x46\x61\x92\x84\xf3\x0a\xe8\x06\x40\x43\x68\xd6\xfe\xcf\x00\xa3\xc8\x19\x9f\xc8\x09\xfc\xaf\x37\x80\x5d\x62\x3b\x8d\xe0\x37\x79\xc3\xf3\x8f\xf4\x85\x0b\x11\x58\xa3\xf0\x23\xe3\xa7\xf9\x2d\xb8\xfc\x33\x57\xe1\x38\xca\x7e\xc2\x66\xbc\x7d\x05\x05\x6d\x28\x18\xcf\x1c\x2f\x62\xbc\x8b\x25\x1d\x28\x99\x84\xd1\x09\xe3\x1d\x2c\xe8\x42\x01\xe6\x48\x85\xe8\x21\xe2\x18\x10\xa3\xc8\x09\xc6\x33\x6b\xe4\x04\x27\x79\x56\x99\x78\xe3\x7c\xde\x6f\x7f\x06\x78\x1f\xe0\xce\x3c\x4c\xb3\x65\x87\x35\x9e\x09\xa9\xe2\x0e\x62\x06\x80\x51\x3f\x57\x76\xb1\x60\x88\x0d\x48\xe3\x24\x9c\x8b\xc8\x72\xc6\xe3\x2c\x4c\x90\xaa\xe5\x49\x0f\xb0\x2a\xf5\xa1\xdb\x8a\x9b\xd2\x97\xed\x83\xbb\x4b\x00\xb5\xab\xa0\x6c\x3f\x7a\xd9\xd1\x40\x1d\x02\xa4\x36\xa3\x97\x5d\x0d\xd6\xad\xc2\xd4\x4e\xf4\xb2\xa7\xa1\x7a\x04\x2a\xdb\x86\x5e\x1e\x69\xa8\xa3\x2a\x2a\xdb\x83\x5e\x1e\x6b\xa0\x63\x02\xa4\xb6\x76\x97\x7d\x0d\xd6\xaf\xc2\xf2\xdd\xe7\xe5\x40\x83\x0d\xaa\x30\xb5\xf5\xbc\x1c\x6a\xa8\x52\x0e\x53\x9d\xae\x36\x9e\x97\xed\x43\x0d\xb6\x24\x60\xb0\xef\xbc\x6c\xeb\x23\xb0\xa2\x02\xe6\xdb\xce\xcb\xb6\x3e\x0c\x6b\x0a\x39\xf3\xa2\x44\xa8\xa8\xfa\x58\x6c\x08\xac\x1c\x0c\xc0\xea\x23\xb2\xa5\xb0\xde\x04\xa0\xfa\xb0\xec\x08\x68\xec\x7d\x04\xa8\x36\x38\xfd\x43\x0a\x2a\x3b\x00\xc0\xda\x10\xf5\xdb\x54\x77\xc9\x31\xca\xb1\xda\x38\xf5\x3b\x04\x56\x0e\x14\x60\xb5\xd1\xea\x77\xe9\xce\x0d\xb2\x9d\x7a\x47\x1b\x30\x75\x8f\xa4\xb8\xa5\x7f\xb1\xe7\x99\x56\xfb\x15\x42\x8f\x4c\x50\xe5\x9c\x56\xa7\x80\x1e\x1b\xa1\xb9\x7f\x5a\xdd\x02\xdc\x37\x81\x73\x17\xb5\x7a\x05\x76\x60\xc4\x2a\x2f\xb5\x8e\x0a\xec\xd0\x84\x55\x8e\x6a\x1d\x17\xd0\xa5\x11\x9a\x4b\xb7\xd5\x2f\xc0\x2b\x13\x18\xdc\xd5\x1a\x14\xe0\xb5\x09\x9c\x7b\xac\x35\x2c\xb0\x9b\x2a\xb6\xe4\xb4\x56\xfb\xb0\x00\x6f\x8d\x60\xf4\x5b\xab\xad\x8d\xde\xce\x1c\x1c\x5c\xd7\x6a\x17\x43\xa8\x6e\x92\xd0\xf8\xc2\x7b\xad\x76\x31\x8e\xea\x06\x09\xc9\xd0\x1c\xd8\x6a\x17\xa3\x39\xe8\x98\x19\xe8\xc3\x56\xbb\x18\x52\xb5\x66\x23\x09\x85\x1b\x5b\xed\x62\x60\x07\x84\xbc\x09\x4f\xb6\xda\xc5\xf0\x0e\x08\x99\x57\x9d\xd9\x6a\x17\x63\x3c\x20\xd4\x5e\xf5\x67\xab\x5d\x8c\xf4\x80\x90\xfc\xbe\x4b\x5b\x9d\x62\xb0\xd5\x0f\x8d\xe8\x4b\x6b\x92\xfa\xbe\x15\x27\xe1\x82\xf1\xf6\x6b\xc0\x0c\x0b\x4c\xf6\x7b\x4b\x81\xe9\x20\x66\xa9\x61\xd4\x0f\x2d\x05\xaa\x8b\xa8\x55\x81\x52\xbf\xb0\x14\xa0\x1e\x82\xd6\x1a\xc8\x3b\x2d\x45\x3a\x42\xd0\xa6\x00\xc5\xde\x47\x1d\x73\x8c\x98\xad\x86\xc9\x7e\xc7\xd0\x50\x7d\x44\xed\x0a\x94\x50\xeb\xc1\x02\x35\x00\x94\xba\x83\x56\xf8\x4b\x07\x0d\x11\xa4\xee\x50\xa0\xb1\x74\xd0\x65\xfb\xf0\x35\x74\xba\xba\xa1\x56\xf2\x54\x19\xda\x2e\xa0\x5d\x3d\x64\x66\xa7\x32\xb4\x53\x40\x7b\x3a\x34\x77\x52\x19\xdc\x2d\xc0\x47\x1a\x18\x4c\x54\x06\xf7\x0a\xf0\xb1\x0e\x56\xfe\x29\x63\x8f\x0a\x6c\x5f\xc3\xe6\xd6\x29\x63\x8f\x0b\xec\x40\xc7\x82\x6b\xca\xe8\x7e\x81\x1e\xea\xbd\x96\x1b\xa6\x0c\x1e\x14\xe0\xa5\x06\x06\xaf\x94\xc1\xc3\x02\xbc\x2a\x77\x72\x90\x9c\x97\xa0\x1d\x6d\xe8\x88\xac\x4b\xbd\x5d\x29\x6d\xb6\x44\x97\x0d\x89\xfc\x4b\xb0\x46\x92\xb5\x2a\x58\x44\x22\x26\x58\x63\xc9\x5a\x17\x2c\x22\x1d\x13\x2c\x57\xb2\x36\xc8\x5a\x12\x49\x99\x7a\x95\x4c\xb2\xb6\x05\x8b\x48\xcc\x04\x6b\x22\x59\xbb\x82\x45\x24\x67\x82\x35\x95\xac\x4f\x05\x8b\xc8\xd0\xd4\xb1\x0b\x92\x75\x55\xb0\x88\x34\x4d\xbd\x36\x26\x59\xd7\x05\x8b\xc8\xd4\x04\xeb\xbd\x64\x7d\x2e\x58\x44\xb6\x26\x58\x27\x92\xf5\xa5\x60\x11\x19\x9b\x60\xf9\x92\x75\x53\xb0\x88\xe5\x0a\xc1\x9a\x4b\xd6\xd7\x82\x45\x2c\x5c\xe8\x07\x76\x2e\x5b\xb7\x05\x8b\x58\xc3\x50\x2f\x60\x48\xd6\x5d\xc1\x22\x16\x33\x04\x4b\xfa\xab\xf5\xad\x60\x3d\xcf\x5f\x1f\x24\xeb\x7f\x05\xeb\x79\xfe\xca\x96\x7c\xf7\x05\xeb\x79\xfe\x8a\x25\xeb\xa1\x60\x3d\xcf\x5f\xd9\x6a\xed\x11\x59\xab\xe7\xf9\x2b\x95\xac\xa7\x82\xf5\x3c\x7f\x9d\x4a\xd6\xf7\x82\xf5\x3c\x7f\x9d\x49\xd6\x8f\x82\xf5\x3c\x7f\x65\xeb\xdb\x7f\x0b\xd6\xf3\xfc\x95\x2d\x3b\x7e\x16\xac\xe7\xf9\xeb\x42\xb2\x7e\x15\xac\xd2\xee\x94\x7e\x2f\x3e\x3b\x90\x04\xf7\x20\xab\x7e\x23\x63\x94\x7d\x29\xa6\x60\x0c\x1a\x19\x32\xdf\x8e\x35\xc6\xb0\x91\xe1\x66\x9f\xdf\x28\x18\xcb\x46\x86\xfa\x68\x45\xc1\x58\x35\x32\x64\x8e\x9d\x68\x8c\x75\x23\x43\xe6\xd7\xa9\xc6\xd8\x34\x32\x66\xd9\x39\xf7\x05\x63\xdb\xc8\xf0\xb2\xd7\x76\x0b\xc6\xae\x91\x21\x73\xea\xfb\x82\xb1\x3e\x6c\x64\x9c\x64\x27\xb6\x17\x8c\x76\x23\xc3\xcf\x0e\xe7\x2e\x18\x9d\x46\xc6\x3c\x3b\x8b\xba\x60\x74\x1b\x19\x41\x76\x84\x71\xc1\xe8\x35\x32\xc2\xec\x95\xe3\x82\x71\xd4\xc8\x90\xb9\x73\xa1\x31\x9a\xfd\x21\xf3\xe6\x07\x8d\xd1\xec\x8f\x28\x3b\xa4\xb5\x60\x34\xfb\x23\xce\xce\x20\x2d\x18\xcd\xfe\x48\xb2\x23\x16\x0b\x46\xb3\x3f\xd2\xec\xd5\xbc\x82\xd1\xec\x8f\xd3\xec\xec\xb9\x82\xd1\xec\x0f\x75\x4a\x59\xc1\x68\xf6\x87\xcc\x8d\x1f\x35\x46\xb3\x3f\xce\xb3\xd7\x95\x0a\x46\xb3\x3f\x2e\xb2\x13\xb2\x90\xb1\x21\xfc\x51\x59\x89\x2e\x35\x3c\xe1\x8e\xca\x1a\x74\xa5\xe1\x09\x6f\x54\x56\x9f\x6b\x0d\x4f\x38\xa3\xb2\xee\xdc\x68\x78\xc2\x17\x95\x15\xe7\x56\xc3\x13\xae\xa8\xac\x35\x77\x1a\x9e\xf0\x44\x65\x95\xf9\x49\xc3\x13\x8e\xa8\xac\x2f\xaf\x34\x3c\xe1\x87\xca\xca\xf2\x5a\xc3\x13\x6e\xa8\xac\x29\x3f\x6b\x78\xc2\x0b\x95\xd5\xe4\x17\x0d\x4f\x38\xa1\xb2\x8e\xbc\xd1\xf0\x84\x0f\x2a\x2b\xc8\xaf\x1a\x9e\x70\x41\x65\xed\x78\xab\xe1\x09\x0f\x54\x56\x8d\x77\x1a\x9e\x70\x40\x65\xbd\xf8\xad\xc0\x6f\x9b\xf4\x2f\x33\xde\xff\x34\x7c\x93\xfe\xa3\xec\x44\xe9\x02\xdf\xa4\xff\x38\x3b\x3a\xb9\xc0\x37\xe9\x3f\xc9\x0e\x84\x2d\xf0\x4d\xfa\x4f\xb3\xb7\x89\x0b\x7c\x93\xfe\x4f\xb3\xc3\x32\x0b\x7c\x93\xfe\xd5\xa1\x8a\x05\xbe\x49\xff\x32\xc7\xfd\xab\xe1\x9b\xf4\x7f\x9e\xbd\x59\x59\xe0\x9b\xf4\x7f\x91\x1d\xe5\x57\xe0\x4b\xfa\xd7\xdf\x16\xb8\x2c\xee\x35\x1f\xa9\x47\x63\x46\xe1\x47\xcb\x8d\x9c\x33\x2f\x98\xc6\x96\x9f\xdd\xca\x29\x7e\x70\x64\xfc\xea\x0a\xd0\xed\x0a\x7a\x26\x9c\xd3\xf3\x12\x7a\x36\x03\x74\xc7\x10\x1b\x7e\xf6\x64\xfc\xfb\x77\xc0\x76\x0d\x91\x0b\xec\xe9\x29\x60\x7b\x86\xb8\xf9\x4b\x45\xae\x13\xcf\x4a\x35\xea\x1e\x00\xf3\xc8\x70\x15\x23\x13\xfb\xe9\xf8\x19\xd7\x2c\xea\xda\x7d\x01\xbc\xfe\x33\xae\xa8\xf1\xde\x00\x6f\x60\xb8\xde\x87\xd4\x71\xa3\x94\xac\x6c\x0f\x9b\x39\x34\x5c\xb4\x8e\x8c\x2d\x5d\x3e\xef\xca\x45\xa5\x7b\xd8\xd8\xd5\xf3\xae\xab\x51\xb1\xbd\x6b\xc3\x55\xd5\x73\x6d\x81\x6b\xe5\xcf\xfa\x6f\xee\x81\xb1\xa9\x30\x32\xac\x9f\x3f\xd3\x93\x33\x54\x0d\x18\xdf\x44\xc0\xdb\xd2\x3c\x55\xd3\x82\xe7\xab\xeb\xb9\x78\xbd\x9d\xa1\x71\xfb\x35\x74\xe1\x4a\x6d\x93\xb7\x90\xe1\x8b\x89\x6c\xd2\x0d\x10\xaa\xf6\xda\x6b\x52\xf6\x8b\x3c\xb4\xc8\x07\x5a\xd5\x67\x7b\x2d\xca\x68\xd0\x20\xbc\x9a\xc9\x72\x7b\xd5\xf3\x5d\x20\x98\x7c\x97\x2e\xf4\xf6\x3f\x41\x8f\xb5\xab\x6e\x4b\x17\xa6\xf1\x79\xc2\x5e\xab\x3a\x2d\x5d\x98\x46\x27\xc5\x6b\x99\x7c\x56\xae\x5b\x8a\x57\x31\xf9\x2b\xc7\xab\xa6\x3f\x61\x5f\x55\x1d\x55\x6a\x8a\x3e\x2e\x4f\x38\x2e\x55\x27\x95\x5a\xa2\x8f\x4a\x8a\x57\x32\x79\xa8\x54\xb1\x14\xaf\x61\xf2\x0d\x3e\x5a\xa2\xb5\xfe\x3b\xf6\x56\xd5\x3b\xda\x1b\xc5\xe4\xf8\x7c\xc7\x9e\xab\xfa\x87\x18\x9f\x42\xb7\x72\xbf\xb1\x81\xe7\x7c\x8f\xda\x55\x17\x91\xee\x83\xde\x95\x73\xb8\x8b\xec\x4e\xd5\x51\x58\x6f\x83\x42\x4e\xa1\xcd\x9d\x46\x73\xe1\x95\xf3\x26\x5f\xa6\x9b\x08\xaf\x5c\xf5\x18\xa1\xe5\xa2\x29\x59\xbd\x0b\x76\xd3\xec\xa6\x8f\xd2\x29\xf4\x74\xc7\xe4\xb7\x12\x4b\x09\xe2\x3b\xe8\xa7\x53\x35\x1d\x31\xb4\xba\x5e\xbf\x83\x96\x3a\x0d\xce\xcb\xdf\xbe\x2e\x0d\xec\x0d\x36\xb1\x6a\x40\x2a\x09\x95\xc6\xb5\x20\x57\xdd\x48\x8c\xab\xee\x97\x53\x6c\x6f\xd5\x99\x54\xce\x2c\x8d\xaa\x8f\xd7\x25\x1d\xba\x47\xdd\x1b\xd4\x82\x6c\x72\x2a\x31\x3c\xa7\xd8\xc7\x8d\xf3\x9c\x3e\x29\x6f\x60\xe1\xd5\xa9\x1a\xb6\x18\x42\x93\xed\x36\x7e\x61\x9c\xaa\x69\x35\x77\x1b\x46\x77\x73\x53\x08\xd8\x60\xdb\xa2\xab\xb4\x07\xd4\x60\x7e\x82\x75\x60\xb7\xea\xda\x3d\x69\x68\x64\x98\xa5\xa0\xe5\xdd\xaa\x6d\x35\x7f\x1b\x46\xc9\x2d\x5a\xde\x25\x16\xa1\xa8\x23\x93\x75\xdd\xa2\xe5\xdd\xc6\x59\x52\x1f\x30\x17\xdb\xdc\x30\x57\xea\xa4\x27\x6c\x6b\xd5\xbb\xe4\x28\xeb\x26\xd2\x5a\x5a\xb5\x2f\x39\xc6\x3a\x5b\x6b\x67\xd5\xbf\x25\x2b\x54\xc7\xf7\x09\xdb\x5a\x75\x6f\x29\x6f\x54\x47\x37\xc5\x16\x57\xdd\x4b\x8e\xae\x6e\x5f\xad\xc5\xc4\x52\x95\x1a\x5b\x9d\xad\xb5\xb8\x61\xa6\xd5\x87\x28\xc5\xb6\x3e\x6b\xbe\xd5\xa9\xdf\xb1\xad\xcf\xf4\x70\x39\x5d\xcb\x4d\xa9\xd6\xe2\x67\xfa\xb8\x1a\x43\x6b\x77\xd5\xcb\xc4\x0c\x51\x1d\xef\xef\xd0\x07\xbd\xaa\x9f\x4b\xe3\xad\xac\x54\x19\xf4\xcb\x74\x73\x05\x75\xe8\x19\x26\xe3\x22\x88\x8c\x58\x0d\xf1\xe4\x16\x21\xaa\xc6\x26\xe6\x8c\x6a\x8c\x53\x18\x8f\x5e\xd5\xd9\x25\xad\x99\x57\x33\xc5\x78\xf4\xaa\x36\x2f\x4b\xce\x3c\x71\xe2\x78\xf4\x0c\xae\x6f\x5e\x17\x69\xf5\x30\x79\xbf\x79\x0e\x2e\xea\x61\x98\xc1\x0b\x4d\x94\xc7\xa4\x98\x4f\x67\x18\x82\xcc\x04\x45\x80\x7d\x65\x14\xb3\x6a\x11\xe2\x99\x19\xa1\x3c\xd6\x8c\x5f\x9e\x6a\xbd\xf1\xcc\xbc\x50\x8d\xa1\xf5\xc6\xb3\x66\x77\xdd\xe8\xa7\xe0\x8f\x7e\x55\xdc\xf9\x1c\xef\x39\xd3\xec\x1d\x95\x74\xb1\x10\x51\x5e\x89\x24\xb4\xfc\xf0\x4c\x44\xf9\x4a\x61\x02\xbb\xad\xbe\xe9\xee\xc9\x5e\x94\xac\x65\x18\x24\x5f\x43\x8e\x20\x8a\x7a\x64\x4c\x21\xb3\xa7\xa2\x47\x7e\x38\x3e\x61\x3c\x19\x01\x40\xbd\x5b\x90\x91\x75\x80\x8f\x80\x6c\x4c\xb3\x87\x3a\xf2\xa2\x09\x16\x15\x87\xf2\xe8\xd4\x1b\x28\x57\x8f\xfe\xe4\x09\x4a\x03\x44\x08\x50\x07\xa8\xa9\x33\x86\x66\xd9\x59\x02\xaf\x63\x28\x53\x2f\x25\x09\xd7\x4b\xe7\x50\xf8\x16\x0b\xd5\x7b\x73\xd9\x3b\xfa\xaa\xe8\x1f\x28\x52\xcf\x63\x8c\x7c\x67\x7c\x92\xbf\x34\xc4\xf8\x0e\x0b\xb3\x0b\x9e\xcd\xbc\x44\x60\x61\x88\x85\x9d\xfd\xc2\xfc\x53\x0f\x61\x1a\xb8\xc2\xb5\xc6\x61\x14\x88\x28\x66\x3c\x0a\x81\xd1\xad\x30\xf2\xd7\xb4\xbc\x60\x0a\x75\xc8\xee\xd1\xc1\xc5\x22\xd8\x8e\xa8\xc7\x2b\xf4\xcb\x68\xbe\x98\x78\xbe\xcf\x78\x34\x01\xec\xd1\x3e\x16\x45\x98\x23\xcf\x01\x79\xbc\x8f\x0c\xa3\x64\x16\x2a\xbd\x8c\xa3\x30\x8e\x67\x4e\x32\x9e\x01\x0d\x14\xab\x9e\xa4\xd0\x69\x46\x6d\x01\xf5\x02\xa8\x03\x9a\x4a\x88\x1b\xa8\x27\x40\x1d\xee\x53\x51\xda\xd5\xaa\x7e\x04\xd2\x52\x1b\xde\x52\xd7\x3e\x80\xaa\xd4\x93\x10\x0a\x12\x89\x71\x92\xbf\xc9\x15\xc3\xbe\x4a\x3d\xf3\xa0\x46\x4d\x2b\x0f\x61\x68\xd4\x53\x00\x8a\x9f\x2e\x8a\x87\xff\x93\xc8\xcb\xa1\x69\x02\x50\x4d\x00\x34\xf4\x09\xa1\xc7\x5a\xad\xca\x6f\x15\x14\xe8\x05\xd4\x51\xfd\xfe\x9e\xd7\xd1\x84\x4e\xb0\xc6\x5a\x8b\x65\x8e\xa5\xc0\xee\x23\x80\xb5\xe6\x9b\xc0\x1b\xa8\xf5\x5a\x73\x53\xf9\xbd\x09\xad\xd2\xb0\xb9\x59\x6b\xee\x32\x81\x13\xd8\xb8\xad\xb5\xfe\x70\x3d\x67\x1e\x06\x2e\xe3\xee\x0a\x4a\xb5\xf6\x17\xa5\x3f\xa0\x54\xbd\x9e\x12\x5e\x88\x60\x2a\x18\xf7\x41\x8c\xea\xd7\x4c\xc5\x52\x77\xbe\x19\x3f\xfc\x0a\x85\x6a\xed\x94\xfa\x7e\x2c\xce\x65\xc1\x1d\x14\xec\x8a\x9a\x20\x2b\x3f\xf3\xe3\x48\xff\x99\x30\xff\x2e\x8d\x96\xef\xb2\x37\x7e\x0e\xa1\xfd\xfa\x4f\x84\xf0\x95\x18\x2d\xf7\x29\x30\x8c\xb0\xfa\xfd\x2b\x7b\x93\x23\x16\xf9\xeb\x8f\x8c\xc7\xb7\x50\x3c\xd4\x8b\xcb\x4d\xf2\xd6\x39\x68\xab\x29\x55\xf7\x68\xd1\xdd\x93\x0d\x40\xbb\xfb\x50\x65\x6e\x44\x8e\x72\xe4\x71\x7e\x93\x5c\x39\x2c\x71\x22\xc6\x7f\xeb\x40\xd1\xb1\x96\xef\x54\x51\x1b\x8a\xb6\x05\x0b\x5f\xe5\x61\xfc\x32\x11\xb0\x61\x3e\x56\x77\x50\x15\x5b\x87\x3c\x6e\xe1\x46\xc0\xb1\xba\x9d\x55\x28\xc8\x42\x05\x79\x81\x2b\x3e\x32\xfe\xd7\x0c\x90\xdb\x3d\x83\x54\xa0\xef\x00\xaa\xb6\x09\x79\xad\xe7\xd9\xab\x4e\xd6\x24\x3b\xc2\xef\xf0\x09\x20\x2b\x3d\xab\x94\x20\x29\x40\xb4\xaa\xc5\x69\xfe\xf5\xe5\xc8\x39\x8f\x19\x8f\x01\xa3\x56\xc6\x13\x31\x77\xf0\x54\xb6\xc9\x57\x28\x53\xf3\x59\x51\x32\xcf\x9d\x70\x7c\xac\xcf\x58\x0b\xc7\x95\xf1\xbd\x84\xf1\x75\x0c\x00\xcd\x57\x33\xe1\x44\x09\x00\xa0\x85\xc7\x9d\x8a\x5b\x00\xe2\x02\x44\x1b\xff\xb1\x9f\x8e\xa0\x7c\x0c\xe5\x3d\xad\x79\x5a\x25\x2e\xd7\xf1\x01\x8c\xce\xb1\xa6\x0c\xbd\x1e\x97\xeb\x59\x81\xa9\xda\x1a\x51\x6e\x81\xd2\xec\xad\xd5\xe6\x72\x3d\x2e\x20\x99\x01\x64\x6e\xcf\x7e\x1c\x0d\xb3\xaf\xb4\x83\x46\xd5\x3b\x2d\xea\x70\x15\x28\x1b\x40\x99\x1a\x4b\x27\x8a\x84\xab\x43\x62\xc6\xe7\x20\x64\xf5\xfe\x4a\x8e\xc9\x9f\xb5\x2d\x60\x97\xf3\xf6\x31\x56\x23\xcb\x96\xf3\x34\xf6\xc6\xd6\xc4\x77\xe0\x85\xb6\xf9\x0a\xca\xb7\x45\x79\xe0\x24\xa9\x3a\xa1\x22\x83\xfc\x0b\x90\x5d\x01\x89\x67\x4e\xb4\x00\x40\x3e\xa7\xf5\xd5\x9d\xf8\xec\xcd\xab\xfc\x48\xa2\xf0\x04\x8a\xd4\xa2\xdc\xf1\xfd\x30\xb1\x3e\x32\xfe\x11\x38\xea\x56\xe8\xdc\xf1\x13\x11\x0b\x35\x5f\x32\x7e\xa0\x4a\xbb\x87\xea\x67\x3d\xcf\x15\xe1\x34\x72\x16\x33\x79\x61\x75\x68\xa5\x17\x03\xa2\xbd\x8f\x18\x87\xf3\xb9\xc3\xf8\x1f\x97\x80\xe8\xec\x23\x16\x22\xf2\x42\x97\xf1\xd7\x08\x51\xcb\x30\x2f\x49\xc2\xbc\xe2\xbf\xff\x07\x8a\x7a\xfb\xec\x12\x0c\x23\x1c\xed\xc3\xbc\x44\x44\xfa\x49\x7a\xbf\x21\xf4\xb8\x52\x63\x3f\x8c\xa5\x53\x15\xf0\x4f\x04\xf6\xf7\x81\xf9\x03\xca\xf9\x61\x69\x88\x2b\x5e\x72\x84\x83\x03\xf6\xde\x05\xfc\x1d\x90\xda\x3b\x8f\x34\xf4\x1d\x42\x8b\x35\xb1\x5a\x2f\x6a\xe1\x5e\x02\x46\x3b\xa1\x72\x1f\xf4\x0e\x41\x5b\x0c\x94\xfb\x64\x3f\x1c\x76\xb5\xf6\x2e\x3b\x0d\x7d\x07\xd0\x36\x1e\xc0\x80\x73\x7a\x90\x78\xe3\xd4\x77\x34\x74\x0b\xd1\xed\x22\xb0\x19\xfe\x0a\xe1\xea\xe9\xc9\x30\x96\x4b\x58\x35\x26\x7f\x27\x50\xa6\x4e\xb2\x15\x89\x03\x25\x30\x0a\xed\xe2\x10\x87\x24\x8c\x92\xd0\x8b\x85\x15\xcf\x84\xdc\x6e\x60\x85\xa0\x4f\xd4\x2f\x4a\xb0\xb4\xa4\xc1\xaf\x10\x7c\xbc\xd7\x81\x64\x5b\x3d\x40\xf7\xf7\x3b\x91\x6c\x2b\xc2\xd5\x6c\xe0\x9c\x0a\x38\xc6\xf5\x9f\xbc\x44\x19\x53\xeb\x85\x7c\x22\xb9\xfc\x3b\x79\xfb\x0a\x1a\xad\xee\x7f\xcc\xbc\xc8\x99\x3a\x81\x83\x4f\x44\x64\xeb\x59\x87\x71\xe7\x08\x70\x1d\x0a\xe7\x30\xbe\x44\x44\xd7\x1c\xc9\x63\xdc\x43\x5c\x8f\xc2\x79\x8c\x5f\x23\xe2\xc8\x1c\x29\x65\x3c\x45\xdc\x31\x85\x4b\x19\x7f\x42\x44\xdf\x1c\x49\x30\x2e\x10\x37\xa0\x70\x82\xf1\x2d\x22\x86\xe6\x48\x21\xe3\x21\xe2\x96\x14\x2e\x64\xfc\x0e\x11\x2b\x0a\x71\xe2\x30\xfe\x65\x09\x90\x35\x05\x99\x3a\x8c\x7f\x42\xc8\x86\x8c\xe2\x31\xfe\xe5\x1a\x20\x5b\x32\x8a\xc7\xf8\x27\x84\xec\xc8\x28\x29\xe3\x5f\x9e\x72\xc8\xd1\x21\x19\x25\x65\xfc\x13\x42\x48\x0d\x9d\x08\xc6\xbf\x6c\x01\x42\xca\x47\x2e\x99\x3f\x21\x84\xd4\xcf\x49\xc8\xf8\x97\x3b\x80\x90\xd2\x99\x86\x8c\x7f\x42\x08\xad\x1d\x87\xf1\x07\xe8\xba\x23\x52\x36\x17\x0e\xe3\xbf\x10\x42\xeb\xc6\x63\xfc\x01\xba\xee\x88\x94\xcc\x85\xc7\xf8\x2f\x84\xd0\x9a\x49\x19\x7f\xc0\xae\x23\xe5\x72\x91\x32\xfe\x0b\x21\xa4\x5e\x62\xb9\xcf\xc4\xae\x23\xf5\x72\x21\x18\xff\x85\x10\x52\x2f\x71\xc8\xf8\x03\x76\x1d\xa9\x97\x8b\x90\xf1\x5f\x08\x21\xf5\x92\x38\x8c\x3f\x42\xd7\x1d\x93\x7a\x71\x1d\xc6\x37\x08\x21\xf5\x92\x78\x8c\x3f\x42\xd7\x1d\x93\x7a\x71\x3d\xc6\x37\x08\xa9\xc9\x37\x49\xca\xf8\x63\x0a\x40\x52\x35\x19\x04\xfa\xf8\x98\x54\x8d\x9b\x32\xbe\x41\x08\xa9\x1a\xb9\xde\x7b\x84\x3e\x3e\x26\x55\xe3\xca\x5d\x2c\x42\x48\xd5\x24\x21\xe3\x8f\xd0\xc7\xc7\xa4\x6a\xdc\x90\xf1\x0d\x42\x48\xd5\x04\x0e\xe3\xb7\xd8\xc7\xa4\x6a\x02\x8f\xf1\x5b\xec\x40\x52\x35\x41\xca\xf8\x2d\x36\x9a\x54\x8d\xdc\x2b\xdd\x62\x8b\x48\xd5\x04\x21\xe3\xb7\x58\x5d\x52\x35\x33\x87\xf1\x2b\xa8\x6e\x9f\x54\xcd\xc8\x61\x7c\x85\x10\x52\x35\x0b\x87\xf1\x6f\x08\x21\x55\x33\xf3\x18\xbf\x82\x46\xf7\x49\xd5\x8c\x3c\xc6\x57\x08\x21\xf5\xb2\xf0\x18\xff\x86\x10\x52\x2f\xb3\x94\xf1\x2b\xe8\xba\x3e\xa9\x97\x51\xca\xf8\x0a\x21\xa4\x5e\x16\x29\xe3\xdf\x10\x42\xea\x65\x26\x18\xbf\x82\x01\xe8\x93\x7a\x19\x09\xc6\x57\x08\x21\xf5\xb2\x10\x8c\x7f\x43\x08\xa9\x97\x59\xc8\xf8\x15\x0c\x63\x9f\xd4\xcb\x28\x64\x7c\x85\x10\x52\x2f\x8b\x90\xf1\x6f\x08\x21\xf5\x22\xd7\xfb\x5f\x71\x18\x49\xbd\xcc\x3d\xc6\xbf\xc2\x00\x0c\x48\xbd\xcc\x53\xc6\xbf\x42\xd7\x0d\x48\xbd\xcc\x05\xe3\x5f\xa1\xd1\x03\x52\x2f\xf3\x90\xf1\xaf\x50\xdd\x41\x4d\x96\x39\x77\x18\xff\xe9\x00\x90\x54\x4d\x06\x81\x76\x0d\x6a\xd6\x35\xe7\x29\xe3\x3f\x21\x63\x0d\x48\xed\x64\x10\x6c\x5d\xcd\xca\xe6\x3c\x64\xfc\x67\x08\x40\x52\x41\x19\x04\xdb\x48\x2a\x28\x72\x18\xbf\xc7\xaa\x93\x0a\x8a\x3c\xc6\xef\x71\x48\x48\x05\x45\x29\xe3\xf7\x58\x69\x52\x41\x91\x60\xfc\x1e\x87\x84\x54\x90\xdc\x2d\xdd\x63\x75\x49\x05\xa9\xa6\x9f\x39\x8c\xff\xc0\x21\x21\x75\x94\x41\xa0\x5d\x43\x52\x47\x67\x1e\xe3\x3f\xa0\x5d\x43\x52\x47\x67\x82\xf1\x1f\x50\xe9\x21\xa9\xa3\xb3\x90\xf1\x1f\x50\xe9\x21\xa9\xa3\x80\xf1\x5b\x58\x17\x0e\x49\x01\x9d\xa6\x8c\x7f\x87\xfe\x53\x2f\xb9\x9e\x38\x89\x73\xe2\x04\xce\x01\x62\x4f\x43\x6f\x2c\xdc\xfc\x60\xe2\xfc\xc3\x02\x18\x76\x4d\x73\x62\x31\xf7\x0e\x08\xe2\x21\x12\xcb\x23\x51\xd9\x0d\x23\xae\x3c\x1c\x79\xc8\x7d\xf8\xef\x00\x57\x3f\x7c\x40\x7d\x2a\x1b\x8e\xe5\x31\xe0\x3a\x14\x4e\x6e\x49\x10\xd1\x35\x47\x92\xdb\x09\xc4\xf5\x28\x9c\xdc\x92\x20\xe2\xc8\x1c\x49\x6e\x27\x10\x77\x4c\xe1\xe4\x96\x04\x11\x7d\x73\x24\xb9\x9d\x40\xdc\x80\xc2\xc9\x2d\x09\x22\x86\xe6\x48\x72\x3b\x81\xb8\x25\x85\x93\x5b\x12\x44\xac\x28\x84\xdc\x70\x9c\x80\x0d\x96\x6b\x0a\x22\x37\x1c\x53\x84\x6c\xc8\x28\x1e\xe3\x27\xe0\x14\xf5\x32\x66\x25\x8a\xc7\xf8\x14\x21\x3b\x32\x4a\xca\xf8\x09\x88\x5c\xbd\x66\x59\x89\x92\x32\x3e\x45\x08\xa9\x21\xb9\xe1\x38\x01\x4b\xae\x48\xf9\xc8\x0d\xc7\x14\x21\xa4\x7e\xe4\x86\xe3\x04\x5c\xbb\x22\xa5\x23\x37\x1c\x53\x84\xd0\xda\x71\x18\x8f\xa1\xeb\x56\xa4\x6c\xe4\x86\xe3\x02\x21\xb4\x6e\x3c\xc6\x63\xe8\xba\x15\x29\x19\xb9\xe1\xb8\x40\x08\xad\x99\x94\xf1\x18\xbb\x8e\x94\x8b\xdc\x70\x5c\x20\x84\xd4\x8b\xdc\x70\xc4\xd8\x75\xa4\x5e\xe4\x86\xe3\x02\x21\xa4\x5e\xe4\x86\x23\xc6\xae\x23\xf5\x22\x37\x1c\x17\x08\x21\xf5\x22\x37\x1c\x09\x74\xdd\x9a\xd4\x8b\xdc\x70\xb8\x08\x21\xf5\x22\x37\x1c\x09\x74\xdd\x9a\xd4\x8b\xdc\x70\xb8\x08\xa9\xc9\x37\x72\x37\x91\xc0\xf4\xbd\x26\x55\x93\x41\xa0\x8f\xd7\xa4\x6a\xe4\x86\xc3\x45\x08\xa9\x1a\xb9\xe1\x48\xa0\x8f\xd7\xa4\x6a\xe4\x86\xc3\x45\x08\xa9\x1a\xb9\xe1\x48\xa0\x8f\xd7\xa4\x6a\xe4\x86\xc3\x45\x08\xa9\x1a\xb9\xe1\x08\xb0\x8f\x49\xd5\xc8\x0d\x47\x80\x1d\x48\xaa\x46\x6e\x38\x02\x6c\x34\xa9\x1a\xb9\xe1\x08\xb0\x45\xa4\x6a\xe4\x86\x23\xc0\xea\x92\xaa\x91\x1b\x8e\x19\x54\x77\x43\xaa\x46\x6e\x38\x46\x08\x21\x55\x23\x37\x1c\x0b\x84\x90\xaa\x91\x1b\x8e\x19\x34\x7a\x43\xaa\x46\x6e\x38\x46\x08\x21\xf5\x22\x37\x1c\x0b\x84\x90\x7a\x91\x1b\x8e\x19\x74\xdd\x86\xd4\x8b\xdc\x70\x8c\x10\x42\xea\x45\x6e\x38\x16\x08\x21\xf5\x22\x37\x1c\x33\x18\x80\x0d\xa9\x17\xb9\xe1\x18\x21\x84\xd4\x8b\xdc\x70\x2c\x10\x42\xea\x45\x6e\x38\x66\x30\x8c\x1b\x52\x2f\x72\xc3\x31\x42\x08\xa9\x17\xb9\xe1\x58\x20\x84\xd4\x8b\xdc\x70\xcc\x71\x18\x49\xbd\xc8\x0d\xc7\x1c\x06\x60\x4b\xea\x45\x6e\x38\xe6\xd0\x75\x5b\x52\x2f\x72\xc3\x31\x87\x46\x6f\x49\xbd\xc8\x0d\xc7\x1c\xaa\xbb\xad\xc9\x32\x72\x37\x71\x0e\xab\xdb\x2d\xa9\x9a\x0c\x02\xed\xda\xd6\xac\x6b\xe4\x6e\xe2\x1c\x32\xd6\x96\xd4\x4e\x06\xc1\xd6\xd5\xac\x6c\xe4\x6e\xe2\x1c\x36\x1c\x5b\x52\x41\x19\x04\xdb\x48\x2a\x48\x6e\x38\x22\xac\x3a\xa9\x20\xb9\xe1\x88\x70\x48\x48\x05\xc9\x0d\x47\x84\x95\x26\x15\x94\x3d\xfe\x82\x43\x42\x2a\x48\x6e\x38\x22\xac\x2e\xa9\xa0\x62\xc3\x71\x86\x43\x42\xea\x28\x83\x40\xbb\x76\xa4\x8e\xe4\x86\xe3\x0c\xda\xb5\x23\x75\x24\x37\x1c\x67\x50\xe9\x1d\xa9\x23\xb9\xe1\x38\x83\x4a\xef\x48\x1d\x05\x8c\x07\xb0\x2e\xdc\x91\x02\x92\x1b\x8e\x53\xe8\xbf\x5d\x8d\x80\xb2\x05\x24\xb4\x7c\x47\x0a\x28\x07\xca\x75\x99\x00\x20\x29\xa3\x53\x87\xf1\x53\xec\x22\x52\x40\xa7\x1e\xe3\xa7\xd8\x45\xa4\x80\x4e\x05\xe3\xa7\xd8\x45\xa4\x80\x4e\x43\xc6\x4f\xb1\x8b\xca\x02\x9a\x7b\xae\xeb\x0b\xcb\x0d\x13\xc6\x5f\x63\x27\x19\xb6\x4f\x8b\x28\xf4\xc3\x60\xba\xb7\x79\x3a\x40\x5a\x59\x55\x95\xcd\x13\xe2\xca\xd2\x32\x6d\x9e\x72\x78\x1b\x5e\x1b\x5c\x84\xf3\x70\x12\x62\x46\x64\x7c\xd5\x03\xc4\x31\x85\x58\x30\xfe\x0d\x11\x7d\x0a\x31\x67\xfc\x2b\x22\x06\x14\x62\xc2\xf8\x0e\x11\x43\x0a\xe1\x32\xbe\x41\xc4\x92\x42\x24\x8c\x3f\x22\x62\x45\x21\xe4\x8e\x18\x11\x6b\x0a\xe1\x33\x7e\x83\x88\x0d\x85\x98\x32\xfe\x09\x11\x5b\x0a\x71\xc2\xf8\x17\x44\xec\x28\xc4\x8c\xf1\x2b\x40\xc0\xeb\x73\x65\xc4\x7b\xc6\x3f\x23\xa2\x4d\x21\x3e\x30\xfe\x3f\x44\x74\x28\xc4\x47\xc6\xff\x45\x44\x97\x42\x5c\xcc\x18\xff\x75\x05\x90\x1e\x05\x19\xcf\x18\x5f\x23\x84\x54\x48\x3c\x63\xfc\x01\x21\xa4\x44\x22\xc6\xef\xb1\x2a\xa4\x44\x2e\x18\xff\x85\x08\x52\x22\x63\xc6\xd7\x88\x20\x25\x12\x33\xfe\x80\x08\x52\x22\x0e\xe3\x4b\x44\x90\x12\x91\xbb\x5f\x44\x90\x12\x91\x3b\x6d\x44\x90\x12\x11\x33\xc6\x2f\xb7\x57\xf9\xbb\xa6\xdd\x76\x9b\x94\x89\xe3\x31\xbe\xbc\x06\x08\xa9\x13\xe1\x31\xbe\x05\x48\x87\x14\x8a\x93\x32\xbe\x7c\x02\x08\xa9\x94\x30\x65\xfc\x0e\x21\xa4\x54\x9c\x80\xf1\xe5\x2d\x40\x48\xad\x88\x80\xf1\x2d\x42\x48\xad\x38\xc1\x94\xf1\x65\x00\x18\x52\x2c\x42\x62\xb6\x88\x21\xd5\x22\x22\xc6\xb7\xf7\x00\x21\xe5\xe2\x31\x7e\x0d\x83\xd0\x21\xe5\x92\x32\xfe\x84\x08\x52\x2e\x5e\xca\xf8\x35\xf6\x0b\xa9\x97\x53\xc6\xbf\x63\x10\x3a\xa5\x4c\x19\xbf\x9d\x02\x84\x14\xcc\x34\x60\xfc\x53\xde\x73\x9d\x36\x71\x7e\xd5\xcc\x09\xa6\xa9\x6f\xbd\xcf\x0e\x77\x7a\x9f\xc2\xcf\xe7\xf9\x09\xfd\x65\x2c\x3e\xef\x91\x7f\xec\x66\x0d\x58\xe2\x24\xa8\x02\xab\x3e\x78\x83\x58\xe2\xfc\x27\x0d\x9b\x7f\xf4\x06\xd1\xc4\xb9\x4f\x05\x3a\xff\xf0\x0d\x82\x89\xe3\x9e\x34\xb0\xfa\xf8\x0d\x82\x89\x53\x9e\x0a\xb0\xfa\x00\x0e\x62\x89\xb3\xd3\x34\x6c\xfe\x11\x1c\x44\x13\x67\xa6\x15\x68\xf8\x10\x0e\xa2\x89\xb3\xd2\x0a\x74\xfe\x31\x1c\x04\x13\x47\xa4\x69\x9d\x97\x9f\x4b\xbc\x86\x31\x54\x3f\x37\x9c\x84\x91\x70\x02\x2b\x4e\x9c\xc0\x75\x22\xd7\x8a\xcf\xe7\xa3\xd0\x67\xfc\xf2\x24\x1e\x2b\xe4\x36\x7f\x54\xe9\x7d\xe8\x05\x56\x32\xf3\xe2\xec\x9b\xb6\xea\xf1\xbb\x40\x7c\x4c\xd4\xff\x6c\xcd\x6f\xb7\x5f\xef\x6e\xaf\xd7\xaf\x18\x7f\xb3\x06\x62\x36\x9c\xe9\xed\xf5\xa3\xf5\xf0\x6d\xb9\xde\x5a\x8e\xd5\xf2\xe2\xf0\xc0\x8b\x0e\x06\x07\x6d\xeb\xf0\xb8\xf7\x8a\xf1\xd4\x01\x74\x77\x0f\x3d\x2a\xa3\x87\xc7\x12\x3d\x02\xb4\x3a\x33\x32\x0c\x0e\xe2\x85\x33\xf6\x82\xa9\x95\xce\x7d\x27\x4d\x90\xd3\x1d\x58\x9d\xc3\xf6\x2b\xab\xb5\xbe\x5a\xde\x2f\xd7\x8f\xdb\x7b\xeb\xdb\xf2\xfe\xf1\x15\xe3\xff\xe9\x42\x8c\xa3\xfd\x18\xc5\xc7\x93\xb3\xf6\xa9\xcf\x46\x63\xc8\xfe\xa1\xd5\x1e\x76\xc8\x90\x6d\x08\x79\xbc\x1f\x32\xfb\x22\xf8\x7e\xa4\xf6\x61\xd7\x6a\x0f\xbb\x64\xa8\x17\x10\xaa\xbf\x1f\x4a\xff\x96\xf5\x5e\xa8\x1e\x19\xea\x25\x84\x1a\xec\x87\x1a\x7b\xd1\x38\x9d\x4f\x7c\xf1\x91\x8e\x77\x44\xc6\x7b\x07\xf1\x86\xfb\xf1\xd4\x47\x25\xca\x31\x8e\xc9\x18\xff\x40\x8c\xe5\x7e\x8c\xb9\x33\x8e\xc2\x60\x2f\x48\x9f\x0c\x72\x00\x41\x56\xfb\x41\x46\x91\x38\xdd\xaf\xc8\x80\x8c\xd1\x82\x18\xeb\x8a\x0a\xc2\x44\x7d\xec\x7c\x2f\xce\x90\x8c\xf3\x1a\xe2\x6c\xcc\x6a\xd2\xe3\x74\x0e\x0f\xc9\x38\x6f\x21\xce\x76\x3f\x4e\xf6\xe5\x83\x6a\x85\x3a\x87\xb4\x16\x0f\x21\xd0\xae\xda\x30\xf5\xec\xdc\x38\x13\x52\x39\x16\xad\xa0\xff\xe4\xb1\xda\x87\x15\x05\x39\xfb\x83\xd5\x39\xa4\x47\xfc\x2f\x88\xd1\xae\xc4\x10\xae\xe7\xfb\xce\x5e\x14\xda\x16\x7f\x40\x94\xce\x7e\x94\x70\x1a\x06\xe2\xe4\x59\x55\xf9\x13\x82\x74\xf7\x83\xc0\xc7\xba\x9f\xd5\x2b\x90\x19\xdb\x95\x24\xb4\xf7\xe9\xef\x52\x36\x6a\xd3\x5a\xfe\x1b\x82\x55\xb2\x91\xdc\x6a\x59\x71\xe8\x7b\x6e\xaa\x49\xa8\x63\x4e\x6c\x6f\x20\x94\xf6\xe5\x78\x3d\xa0\x17\x26\x8e\x35\x12\xb2\x76\x10\xee\xe8\xc8\xea\xd2\xba\xbe\x86\x60\x7d\x3a\x98\xfa\xd4\xfd\x22\x10\xe9\xdc\x49\x9c\x52\x40\xda\x70\x1b\x08\x38\xa0\x03\xaa\xef\xe1\x93\x01\xe9\x9e\xfb\x06\x01\x87\xd6\xde\x07\xf8\x2b\x41\xda\x03\x6b\xd8\x79\xc5\xf8\x9f\xa8\x80\xa5\xb5\xf7\x21\x7e\x8a\xd3\xee\xc8\x29\xea\x0f\xd4\xde\xaa\x20\x95\xcf\x9a\x52\x9b\xe8\x91\xd8\xbb\xe4\xf0\x15\xe3\x2b\x98\x6e\xda\xda\x89\x55\xc5\xd4\xd6\xb5\x0e\x3b\x43\x79\x95\x31\x76\x78\x96\x48\x26\x69\x90\x7f\xc8\xd2\x9b\x6a\x3e\xeb\x75\xad\x4e\xa7\xfd\x8a\xf1\x1d\xe4\x2f\xb5\x88\xa7\x0e\x20\xbb\x98\x15\xbc\xa3\x81\xd5\xee\xc9\x1e\xd8\xe2\x30\x64\xe9\xc1\x09\x12\x61\xcd\x45\xe4\xb9\x9e\x33\xdf\xbf\xd6\xd0\x3a\xec\x1c\xf7\x5f\x31\xbe\xfc\x9a\x93\x8a\xa7\x2b\xeb\x49\x83\x57\x8c\x7f\x43\x52\x66\xfc\x44\xf8\xd6\x38\x9c\x2f\x9c\xc4\x1b\x79\xbe\x97\x9c\x93\x44\xd9\x63\x97\x09\xbc\x91\xb0\x3d\xec\xe4\x1f\x2c\x71\x46\xde\x18\x97\xf3\xbe\x98\x58\x13\x2f\xc8\x3e\x6f\x18\xcd\xf7\xa2\xb6\xbc\xd1\x7c\x70\x2c\x9b\x2b\x7b\xf5\x72\xf9\xfb\x5b\x8c\xa5\x1e\x97\x4e\x93\xf1\xcc\x9a\xa6\x72\xc6\x8a\xa0\x0e\xa3\x79\xaf\xdb\xb7\xda\x47\xf2\xf2\x93\x1b\xc0\x67\xf6\x9e\x3a\xf3\xb9\x43\x0d\x47\xfb\xf0\xb8\x77\x7c\xd0\x76\xbd\xd8\x3a\xec\x76\xde\xa8\xff\xf4\xdf\xb4\x3b\xb2\x9b\xa7\x13\x08\x52\x3c\x33\xab\x3e\xa6\x76\x2a\xc6\x49\x18\xe9\xf9\x9c\x0c\x34\x78\x73\xd8\x93\x2b\x9e\x77\xa7\x10\x48\x33\xf5\xa9\x13\x79\x8e\x99\xdc\xeb\xbc\x69\x67\x8b\xab\x17\xbf\x01\x59\x33\xf1\x42\x44\x5e\xbc\x08\xe7\x22\xf0\x1a\x42\x1c\xbd\x62\xfc\x1f\x0c\x31\x28\x74\xb6\x7f\xf4\xa5\x5a\x2e\xe5\x53\xc2\xcd\xdd\x8f\xed\xfd\x7a\xf9\xb0\x7d\x6b\x1d\x1e\x1e\xbe\x51\xff\x69\xbf\xe9\xf4\x0e\x5f\x31\xfe\x5e\xcd\x06\xbb\x95\x7a\x44\xbe\x24\x5b\x6f\xea\x24\x69\x24\xac\xc9\x84\xf1\xdd\x0e\x70\x6d\x33\xce\x63\x7c\x77\x0d\xb8\x8e\x19\xe7\x33\xbe\xbb\x01\x5c\xb7\xe6\xba\x1e\xe3\x97\xbb\xdd\xf5\x25\x60\x7b\x35\x58\x3f\xc3\xde\x20\xf6\xc8\x8c\x4d\x18\xdf\x3d\x02\xee\xd8\x88\x8b\x13\xc6\x1f\x72\xdc\x56\x3d\x54\x94\x0b\x3f\x9e\x39\xae\xeb\x64\x6f\x63\xe6\xa2\x67\xfc\xb2\xfb\x7b\xfe\xc8\xfd\x6e\x3b\x30\xb9\x24\x1b\x97\x79\x46\x56\x82\x2b\x6c\x23\xbd\x31\x7f\x8d\x11\x7a\x75\x11\x66\xce\xfc\x82\x8e\x30\x2b\x22\x6c\x0c\x11\xbc\x38\xf4\x9d\xfc\x6b\x39\x19\xe7\xf7\x03\xe4\x6c\x1b\xdd\x9d\x11\x8a\x8b\xec\xaa\x84\x91\x98\x55\xae\xb1\x2a\xae\xa1\x1e\x76\x21\x28\x81\x97\x68\xbd\xb9\xfa\xfd\x0f\x64\xb4\x69\x46\xb9\xfb\x57\x45\xf7\x0f\x89\xee\x97\x84\x52\x2b\x56\x45\x2b\xd4\x63\x31\x65\x7c\x22\x2f\xe0\x44\xa3\x34\x71\x2a\xad\x79\xfc\x5a\xb4\x86\x18\x27\x9d\x5a\xba\xe4\xe3\xd7\xe2\x92\x47\x34\xaf\x72\x29\xad\xe3\x8e\x0d\x94\x72\xc7\x3d\x6a\x1d\xd7\x37\x54\xae\xd4\x71\x8f\x5a\xc7\x0d\x68\x42\xb9\x15\x5a\xc7\x0d\x09\xfc\x8c\x6a\xc6\x97\xa2\x19\x4b\x13\x67\xaf\x1d\x5f\x8a\x76\xac\x0c\x94\xbd\x86\x7c\x29\x1a\xb2\x36\x30\xca\x2d\xf9\x52\xb4\x84\x70\xcb\x7b\x21\xe6\x95\x96\x7c\xd2\x06\x84\x70\x8b\xe2\x94\x5b\xf2\x49\x1b\x11\xc2\x2f\x19\xa5\xdc\x92\x4f\xc5\x90\x2c\x09\xbb\x64\x8c\x52\x4b\x3e\x15\x63\xb2\x24\xdc\x32\x73\xaa\x43\x72\x55\x0c\xc9\x92\xf0\x4b\x46\x29\xb7\xe3\xaa\x18\x91\x25\xe1\x18\xc9\x28\x37\xe3\xaa\x18\x90\x25\xe1\x13\x49\x28\xb5\xe2\xaa\x18\x8f\x25\xe1\x8f\x13\xaa\x19\xff\x16\xe3\xb1\x24\x0c\x72\x42\xb4\xe3\xdf\x62\x3c\x96\x84\x43\x4e\xaa\x0d\xf9\x57\x1b\x0f\xc2\x22\x27\x95\x96\xfc\xab\x8d\x07\xe1\x11\xd7\xf1\x2b\x0d\xd9\x68\x0d\x21\x2c\xe2\x66\x6f\xb7\x6b\x97\xd8\x68\x97\x20\xfd\x41\x5d\x43\x1b\x73\xd2\x21\x95\x8b\x68\x23\x42\x38\x24\x22\xac\x7e\xaf\xb5\x83\x30\x48\xb4\x6f\xc2\x7b\xad\x1d\x84\x3b\x2e\x1c\x2f\xa8\x5c\xe3\x57\x71\x8d\x15\xe1\x8f\x8c\x53\xba\xc8\xaf\xe2\x22\x2b\xc2\x1f\xb1\x10\xd5\x8b\x3c\x68\x17\x21\x0c\xa2\x38\x65\x65\x3d\x14\xca\x5a\x11\x0e\xc9\x28\x65\x65\x3d\x14\xca\x5a\x11\x16\xc9\x18\xa5\x96\x3c\x68\x2d\x21\x3c\x12\xcf\xc8\xa6\xdc\x16\x4d\x21\x4c\x92\x93\xf6\xda\x72\x5b\xb4\x85\x70\x89\xe2\xec\x35\xe6\xb6\x68\x0c\x61\x13\x45\x29\xb7\xe6\xb6\x68\x0d\xe1\x93\xd8\x71\x2b\x6d\x59\x6b\xc3\x42\xf8\x24\xa3\x94\x5b\xb2\xd6\x46\x85\x70\x8a\x64\x94\xdb\xb1\xd6\x06\x85\xb0\x89\x24\x94\x5a\xb1\xd6\xc6\x84\x70\x89\x4b\xb4\x62\xb3\x29\x5a\x41\xb8\xc4\xad\xb6\x62\xb3\x29\x5a\x41\xf8\xc4\xad\xb4\x62\xb3\xc1\x56\xac\x09\x93\xb8\xfb\xad\xd8\x6c\xb0\x15\x6b\xc2\x23\x09\x91\x7c\x1f\x3f\x63\x2b\xd6\x84\x45\x92\x6a\xee\x7d\xfc\x8c\xad\x58\x53\xab\xae\x4a\xea\x7d\xfc\x5c\xb4\x82\x5a\x6b\xed\x67\xde\xc7\xcf\x45\x2b\x08\x7f\x5c\x10\xad\xf8\x35\x2b\x5a\x41\xb8\xe3\xa2\xda\x8a\x5f\xb3\xa2\x15\x84\x37\x2e\x2a\xad\xf8\x35\x2b\x5a\x41\x38\xe3\x62\xbf\x15\xbf\x8a\x75\xfc\x9a\xf0\x05\x95\x13\xb7\x85\x2f\xd6\x84\x2f\x32\x4a\xb9\x15\xdb\xc2\x17\x6b\xc2\x17\x92\x51\x6e\xc5\xb6\xf0\xc5\x9a\xf0\x45\x25\xeb\x6e\x0b\x5f\xac\x09\x5f\x4c\x67\x54\x3b\xae\xb5\x76\x10\xce\xc8\x49\xe5\x96\x5c\x6b\x2d\x21\xbc\xa1\x38\xe5\xb6\x5c\x17\x6d\xd9\x10\xee\x50\x94\x52\x6b\xae\x8b\xd6\x6c\x08\x7f\x4c\x88\xb9\x70\x57\xb4\x65\x43\xf8\x63\x52\x5d\xf5\xee\x8a\x96\x6c\x08\x7f\x4c\x2a\x8b\xde\x9d\xd6\x0e\xc2\x1f\x93\xfd\xe9\x76\xa7\xb5\x82\xf0\xc7\x07\xa7\xba\x41\xfc\x9f\xd6\x0a\xc2\x1f\x19\xa5\xdc\x8a\xff\x69\xad\x20\xfc\x21\x19\xe5\x56\xfc\x4f\x6b\x05\xe1\x0f\x49\x28\xb5\xe2\x7f\x5a\x2b\x08\x7f\x9c\x10\xad\xf8\xa2\xb5\x82\xf0\xc7\x49\xb5\x15\x5f\xb4\x56\x10\xfe\x38\xa9\xb4\xe2\x8b\xd6\x0a\xc2\x1f\x27\xfb\xad\xf8\xa2\xb5\x82\xf0\x87\xef\x54\xb7\x1f\x37\x5a\x2b\x08\x77\x64\x94\x72\x2b\x6e\xb4\x56\x10\xde\x90\x8c\x72\x2b\x6e\x8a\x56\x6c\x09\x67\x48\x42\xa9\x15\x37\x45\x2b\xb6\x84\x2f\xe6\xd4\x2e\xea\x6b\xd1\x8c\x2d\x61\x8c\x39\xb1\x8b\xfa\x5a\xb4\x63\x4b\x38\x63\x5e\xdd\x45\x7d\xd5\x1a\x42\x58\x63\x5e\xd9\x45\x7d\xd5\x5a\x42\x78\x23\x08\xc3\x6a\xba\xba\xd5\x5a\x42\x98\x43\x71\xca\x2d\xb9\xd5\x5a\x42\xb8\x23\xa3\x94\x5b\x72\xab\xb5\x84\xb0\x47\xc6\x28\xb5\xe4\x56\x6b\x09\xe1\x0f\x6a\x8b\x7e\xa5\x35\x84\xf0\x07\xb1\x43\xbf\xd2\xda\x41\xf8\xa3\xba\x41\xbf\xd2\x9a\x41\xf8\xa3\xb2\x3f\xbf\xd2\x5a\x41\xf8\xe3\xcc\x39\xab\xb4\xe2\x87\xd6\x0a\xc2\x1f\x92\x52\xba\xc4\x0f\xed\x12\x84\x3b\xb2\x9b\x5f\x73\xe7\x24\x4e\xa3\xea\x6d\xa0\xcf\xc5\xb5\x76\x84\x51\x4a\xdc\xd2\x45\x3f\x17\x17\xdd\x11\x8e\x39\x27\x46\xe7\xa7\x76\x2d\xc2\x30\xe7\xd5\xd1\xf9\x59\x8c\xce\x8e\xf0\xcb\x79\x65\x74\x7e\x16\xa3\xb3\x23\xec\x72\xbe\x3f\x3a\x3f\xb5\x56\x94\xdc\x02\xf7\x4f\x65\xa6\x50\xbf\xdb\x93\xb7\x3e\x2b\xa9\x6d\x5e\x34\xf1\xf8\xff\x10\xaf\x9c\x94\x8a\x5b\xa9\xbb\xfe\x33\x83\xe9\x77\x55\x2b\x95\x2b\xd6\x88\xbb\xc1\xff\x21\x5e\xb9\x72\xc5\xea\x6e\x37\xfc\x7f\x0a\xa6\x7e\x2c\xac\x54\xee\xaa\xa8\xdc\xf2\xff\x10\xaf\x5c\xb9\xab\xa2\x72\xab\xe6\x60\x95\xba\x2c\x8b\xba\xac\x9b\xe9\xe5\x4b\x2f\xb3\x4b\xff\xff\x01\x00\x00\xff\xff\x71\x9d\xca\x8f\xdf\x44\x01\x00")
+
+func fontsMnemonicFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsMnemonicFlf,
+ "fonts/mnemonic.flf",
+ )
+}
+
+func fontsMnemonicFlf() (*asset, error) {
+ bytes, err := fontsMnemonicFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/mnemonic.flf", size: 83167, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsMorseFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x54\x6d\x6f\xdb\x36\x10\xfe\xce\x5f\x71\x73\x03\x24\xd9\x4c\xc6\xb2\xd3\x36\x4e\x8b\xbe\x2c\x1b\x8a\x00\x1d\x56\xac\xed\xa7\x61\xc0\xce\xe2\xc9\x22\x4a\x91\x02\x49\x59\x4d\x87\xed\xb7\x0f\x7c\x91\xed\x24\xc0\xbe\xcf\x41\x40\xea\x78\xf7\xdc\x3d\xcf\x1d\xd9\xe8\x66\x89\x27\x50\x41\x05\xab\x05\xf0\x0a\x2e\x17\xec\x17\xeb\x3c\xc1\xe6\x0e\xde\x69\x32\x06\x6e\x5a\xec\x7b\xd2\x1a\x5e\x6e\xb7\xf5\x9b\x41\x0d\xb5\x20\x39\xbc\x82\x6a\x71\xb1\x7e\xca\x7e\x44\x4f\x12\xac\x01\x65\x1a\x0b\x8d\xb3\x1d\xcc\x32\xc0\x8d\x95\x04\x68\x24\x84\x96\xe0\x43\x6b\x0d\x05\x55\xc3\x5b\xdd\xb7\xb8\xa1\xe0\x67\xec\xf3\x6f\xef\xaf\xa1\x0d\xa1\xbf\xbe\xb8\x18\xc7\x51\x78\x1b\xac\x11\x58\x8b\xe1\xcb\xc5\x3f\xbe\xee\xd7\xab\xba\xbd\x70\xd4\x90\xbb\xc0\x12\x25\xda\xd0\x69\x76\x6b\x6a\x3d\x48\xf2\xe0\x6d\x47\x70\xfb\xf1\x57\x78\x8f\x41\x19\x5e\x41\xdd\xa2\xc3\x3a\x90\xf3\xec\x03\xb9\x4e\x79\xaf\x62\x69\x1e\x5a\x72\xb4\xb9\x83\xad\xda\x91\x81\x60\xa1\xb3\x52\x35\x77\x10\x5a\xe5\xa1\xb1\x26\xcc\x01\x3d\x68\x6b\xb6\x71\x0d\x2d\xb1\xe4\xa0\xc8\x9d\x7a\x30\xd8\x51\xc4\xe8\x35\xd6\x99\x2b\x42\x6d\xbb\x8e\x4c\x00\xad\x0c\x09\xc6\x3e\x7b\x02\xdb\x1c\xe0\x00\xb5\xb6\xa3\x87\x46\x6d\x35\x85\x98\xb0\xb6\x66\x47\x2e\xc0\xdb\x8f\x37\xb7\xb7\xd1\x70\x6b\x02\x39\x83\x41\x59\x83\x1a\x92\x64\x2c\x4a\x26\x18\xfb\xd4\x12\x34\x36\x22\x28\xb3\x05\x3f\x6c\x7c\x50\x61\x88\x9e\x1e\x5a\xdc\x11\x6c\x88\x0c\x74\x28\x69\x0e\x4a\x90\x98\x83\x6a\xa6\x54\x8e\x6a\x52\x3b\xf2\x80\x6c\x2f\x46\x2c\x39\x36\x41\x53\x13\x22\x3f\x65\xfa\x21\xcc\x41\x05\x18\x95\xd6\xd0\x3b\x65\x42\x72\x38\x6a\x5c\x63\x5d\xd2\xe1\x11\x88\x53\xdb\x36\x5c\xb3\xef\xe0\xfe\x8f\xbf\x02\xc1\x5e\x3c\x36\x5e\xb3\xdf\xff\xf8\xeb\xef\x07\xc6\xb3\x73\xf6\x8e\x5c\x87\x06\x3c\xff\xb6\xb7\x7a\xcf\xa6\x3e\xce\x7a\xa7\x3a\x9a\x45\xeb\x29\x7b\xf2\x18\xf5\xe5\x4f\xa4\x29\x10\x68\xf4\x01\x46\xeb\xe4\x2b\xf6\xfd\x63\xaf\x9b\x96\xb1\x9f\xbf\xd6\xd4\x27\xd6\xc6\x06\x92\x80\x1b\xbb\xa3\xf9\xd1\xa0\x44\x3b\xe0\x0e\x95\xc6\x8d\x26\x50\xe6\x58\x85\x83\x3e\x0c\x3d\xcc\x5e\xcf\x04\x63\xa9\x71\x3c\x26\x05\xdf\x63\x4d\xc7\x3d\x21\xa3\xd1\x6d\x49\xc6\x06\xab\xae\x77\x76\x47\xe0\x08\x25\x6e\x94\x56\xe1\x4e\xc0\xa7\x34\x09\x8d\x75\x1d\x0b\x36\xe9\xe9\x03\x1a\x89\x4e\xfa\x24\x39\x0e\xc1\x76\x18\x2f\x4a\x70\x68\xfc\x34\xc1\xb6\x39\xaa\x6a\x0e\x83\x27\xf0\xdd\xe0\xdb\xce\x4a\x62\xdf\xc8\x59\x38\x9b\x95\x01\xe0\x0d\x74\xc9\x95\x77\x8b\xd9\xf9\x0b\x18\x51\xe5\xe6\xca\xc1\xa5\x69\x8b\x60\x08\xd2\x86\x94\x90\xb0\x6e\x61\xa3\xd1\x7c\x61\x2a\x37\xd8\x0e\x21\x8d\x07\x7a\x18\xe3\xb5\x47\x0f\x1b\x0a\x63\xa4\x87\xe6\x0e\xc2\x68\x8b\xcb\xb1\x88\x67\xd2\x06\x3f\x67\x12\x7d\x4b\x1e\xac\xcb\x90\xfe\x5c\xc4\x0e\xf4\x1a\xcd\x3e\x75\xa3\x9c\xcf\xf7\xe6\x9a\xc5\xd7\x07\x38\xcc\x3a\xdc\xaa\x1a\xcc\xd0\x6d\xc8\xcd\x52\x59\x8d\x8a\xbd\x90\x64\x82\x6a\x54\x9d\x82\x19\xa6\xb6\x82\x6f\xed\xa0\x25\xa0\x1e\xf1\x2e\x96\x06\x7f\xe2\xe9\x3c\x05\x19\x3b\xb2\x93\xec\x14\x89\xcc\x5a\x74\x32\xd5\x31\x03\xce\x73\x1b\x7d\xa4\x83\xb9\xba\x39\x6c\x22\x09\x34\xa7\x21\xc2\x24\x41\x49\xb2\x2a\x23\xb4\x14\x07\x3d\x8b\xb5\x27\xfa\x9f\x87\xf3\x34\x4a\x2a\x3d\x4e\xf1\xe2\x4a\xf2\x35\x19\x19\x1f\xa3\xd5\x22\x85\x75\xf8\x35\x31\x07\x4d\x66\x1b\x5a\x38\xa3\xaf\x93\xf3\xf1\x83\xe2\xcf\xe1\x07\x40\x68\x06\xb9\x25\x68\xb0\x0e\xd6\x31\x5e\x25\x04\x49\x0d\x0e\x3a\x1c\xba\x5f\x2e\x6a\x79\x77\xd8\x65\x4e\x94\xa5\x8c\xf5\xdd\xc3\x65\x0c\xe0\xe4\x0d\x13\x3c\xfe\xe5\x8d\xe0\x22\x6e\xca\xef\xe4\x0d\x7b\x7d\xf2\x64\xff\x2f\x38\xe7\xe9\x9c\x0b\x9e\x23\x0e\x1b\xce\x79\xf1\xe6\x11\x25\x1f\x0a\x31\xe1\x4e\xee\x19\x9f\x17\x77\x31\xad\x62\x5a\xc5\xb4\x8a\x69\x15\x13\x52\x8a\x9b\x56\x3e\xad\x7c\xff\x7d\x6f\x73\xaf\x6c\x51\xdc\x33\x87\x82\x97\xab\x2f\xe8\x31\x57\xae\xa3\xa4\x29\xc9\xd3\x52\x0a\xcd\x01\x45\xa6\xe4\x95\x2c\x39\x6b\xf6\x29\xc1\xc5\x29\x63\x44\x53\x86\x2e\x04\xb3\x6b\x51\xa3\x68\x58\xb8\x1d\x2b\x9a\xa4\x3c\xfe\x38\x74\xe1\xff\xca\x40\xec\x67\xa5\x94\x3a\x0d\xc7\x63\xa3\x10\x27\x39\xf3\x22\x45\x56\xcf\x16\x79\x56\xab\xe7\xd5\x61\x4c\xab\xab\xc5\x61\x26\xab\xab\xe7\xc7\x27\x57\x65\xb8\xb2\x65\x1a\xa8\xea\x6a\xfd\xc0\x9e\x99\x57\xeb\x45\x19\xbe\x07\xfe\xeb\x15\x9b\x18\x54\xeb\x67\x53\xb1\xd5\xfa\xf9\xde\xbc\x5c\x54\x49\x75\x91\xf6\xeb\xa4\x5e\xb2\x57\x97\x13\xa9\xe5\x72\x31\x11\x5b\x2e\x57\x47\xe4\x96\xcb\xa7\x07\x9c\xe5\xd5\x04\xbf\x5c\xae\x0f\xe6\xd5\xea\x00\x7f\x59\x1d\xe0\x2f\x9f\xed\xe1\x9f\x2e\x27\xf8\x7f\x03\x00\x00\xff\xff\xa9\x58\xa7\xd0\xc0\x09\x00\x00")
+
+func fontsMorseFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsMorseFlf,
+ "fonts/morse.flf",
+ )
+}
+
+func fontsMorseFlf() (*asset, error) {
+ bytes, err := fontsMorseFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/morse.flf", size: 2496, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsMoscowFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x56\x4d\x8f\xd3\x30\x10\xbd\xe7\x57\x3c\x65\x38\xa4\x12\x94\x2d\x88\x95\x96\x03\x5a\x89\x13\x17\x2e\x20\x4e\x1c\x48\x53\xa7\x89\x36\x6d\x16\x27\xcb\xaa\x12\xe2\xb7\xa3\x6e\x63\x7b\x6c\x8f\xd3\xe5\x8a\x7a\x19\x7b\x9c\xf1\x9b\x0f\x3f\x8f\x53\x77\xf5\x9b\xf2\x05\xae\x71\x8d\x1b\xbc\x5a\x61\x75\x95\x7d\x3c\xe8\xb6\xeb\xda\x0a\x75\xbf\x1f\xb1\x3e\xe0\xab\x2e\xab\x03\xbe\x54\xcd\x43\xf3\xa8\xf4\x1d\x8a\xa7\x85\xa5\x5d\xb8\x1d\x36\xba\x5a\x56\xfd\x6e\xb1\xcc\x3e\xf7\xbf\xd4\x6e\xad\x34\x56\xef\xc6\xe6\x25\x56\x37\x37\x6f\x81\x6f\x4a\x0f\x6d\xbf\xc7\x6a\x79\x95\x7d\xc2\x50\x56\xba\xad\xdb\x4a\x6d\x30\x36\x0a\x75\xdf\x75\xfd\x63\xbb\xdf\x62\x38\xec\xd6\x7d\x37\xa0\xee\x35\x6c\x10\x9d\x1a\x47\xa5\x87\xf7\x19\x90\x7f\xcf\x51\x0c\x5d\x39\x34\x8b\xa3\xf6\x3a\x47\xb1\x2e\xab\x3b\xb8\xa5\xdf\x39\x8a\xfb\xf6\x5e\x2d\x70\xd4\xfe\xe4\x28\xc6\xb6\xdb\x4c\xea\x8f\xe3\xee\x76\xbf\xed\x14\x7e\x3e\xf4\xa3\x7a\xda\xf1\x21\x47\xb1\xd5\xaa\x1c\x95\xc6\xd8\x94\xfb\x45\x96\x01\xc0\xed\xbc\xb4\x0a\x45\xd2\xad\x1b\x85\x40\x56\x26\x91\x26\x23\x22\x69\xee\x60\x4f\x1f\x60\x3f\xb3\x15\x1f\x09\x27\x79\x32\x75\xeb\x7e\xe0\xc4\x51\x9d\x53\x17\x60\x88\x21\x95\x80\x19\xf9\x85\x20\x1e\x93\x5c\x2d\x8a\x8b\x69\xf2\x0a\xe6\x41\xe9\x22\xd3\x20\xa6\x48\x0a\xee\x98\x9c\x90\xa4\xec\x66\xf0\xfc\xec\x26\x49\xfc\x34\xb9\x11\xaf\x32\x52\x15\x27\x87\xe1\xd5\x89\x1b\x99\x60\x39\x49\x66\x8d\x10\x6e\x90\x98\xe9\x6d\x40\x84\x44\xb2\xeb\xb4\x91\x90\x5d\xe4\x62\xce\x9d\x78\x1d\xd2\x46\x42\x4c\xde\x15\x0d\xe7\xe7\x8c\x28\xc5\x71\x8f\xca\x88\xdc\x71\x26\xb1\xf9\x69\x30\x35\x9f\x6a\x65\x93\x30\x64\x31\x35\x3c\x73\x8e\x31\x01\x3d\x6e\x25\x5d\x1f\x51\xa6\xbd\x86\x55\xc4\x5c\xfa\xae\x8d\x81\x71\x36\x75\x0a\x7b\xe5\xc8\x01\xf0\xe4\x3c\x24\xb7\xc1\xe8\xbe\x07\x0b\x61\x31\xfd\x09\x91\x2d\x79\x1c\x98\xf1\xc3\x03\x25\xff\xbb\x94\xba\xbb\xa0\xc4\xf4\xe9\xbb\xec\xc1\xf3\xe4\x8f\x71\xea\xa6\xb8\x51\xb1\xa3\x1c\x1c\xf2\x79\x22\xcc\xc4\x1c\xe6\x24\x7b\x30\xa4\x00\xd7\x53\x65\x35\xe7\x1b\x8e\xe9\x1c\x28\xc8\x21\xc9\xa8\x80\x20\x67\x29\x08\x76\xb2\x82\xa1\xf9\x3e\x7f\x70\xff\x16\x52\x10\x9a\x48\x3e\x04\x86\xb3\xd4\x40\xc8\xd6\x60\x44\x74\x8d\xc8\x5d\x7b\xa4\xc7\x67\x91\x2f\xc1\xd6\x99\x1c\x98\x2e\x55\x89\xc4\x31\x38\x07\xbb\xc3\x9a\x88\x13\xc4\x17\x35\x38\xbe\xa8\xe5\x24\x7b\x94\x4f\x08\xab\x7b\x99\xd8\x1e\x1a\xff\xae\xf8\xcf\xcb\xb3\x1e\xf4\x18\x03\xa1\x11\xd8\x6e\xa4\x7f\xa1\x64\xe9\x95\xc6\x76\x8a\x09\xcf\xbe\x77\xf6\x18\x58\x37\xb9\x74\xfd\x4b\xd7\xbf\x74\xfd\x4b\xd7\xbf\x74\xfd\xb8\xeb\x93\xdc\xf5\x65\x9e\x06\xe9\x13\x10\x3d\x13\x0c\x29\x7e\x01\xa4\x58\x03\x8a\x45\xb1\xce\xc9\xff\xdd\xe8\x6f\x00\x00\x00\xff\xff\x2b\x5c\x68\xd7\x8f\x12\x00\x00")
+
+func fontsMoscowFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsMoscowFlf,
+ "fonts/moscow.flf",
+ )
+}
+
+func fontsMoscowFlf() (*asset, error) {
+ bytes, err := fontsMoscowFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/moscow.flf", size: 4751, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsNancyjFancyFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\x4d\x8f\x9c\x38\x13\xbe\xf3\x2b\x4a\x74\x24\x2e\x79\x4b\x9a\xf7\xb0\x5b\xca\xae\x56\x68\xef\x48\x5c\x7d\xc3\xc4\x74\xa6\x77\x9a\x26\x9a\x66\x12\xcd\xbf\x5f\xb9\x5c\x36\x86\xe6\xab\x67\x26\x4b\x32\x60\x1b\xbb\xbe\xeb\x71\xbb\x38\x9e\x8f\xff\xd7\x9f\x80\xe0\x37\x78\xf8\x1d\xfe\xf7\x00\x0f\x0f\x49\x02\xee\xba\xe8\xcb\xd7\xd7\x7f\xf0\x78\x3e\xf2\xd0\x45\xb7\x8d\x01\x7d\xec\x9b\x67\xe8\x1f\x1b\x38\x77\xdf\x4e\x17\xe8\x8e\xa0\xe1\x67\xd7\xea\x0b\xfc\x7c\xec\x00\xf4\xf5\xa9\x31\xd0\x36\xd0\x77\xd0\xea\xa7\x06\x1e\x9b\x67\xd0\x76\xfd\xf5\xf4\x0d\xa1\x7f\x3c\x5d\xe1\x74\x65\x02\xc7\xee\xd2\x43\xff\xa8\x7b\xf8\xaa\xdb\x06\xba\x97\xde\x52\x3b\xf5\x08\x61\x5a\xfb\x0a\xc7\xd3\xf3\xb5\x67\x91\x74\xdf\x37\xed\xf7\x1e\x74\x0f\x1a\x8e\xa7\x6f\xe7\xa6\x67\x1a\x9f\xe1\xda\xc1\xb9\xd1\x3f\x1a\xcb\x57\x9f\xbb\x4b\x83\x41\x09\x00\xf8\xa1\xdb\xef\xaf\xcf\xb9\xfe\x7a\xc5\xfa\x05\x1b\xf3\x92\x24\x45\x67\x4e\xc7\x53\x63\x82\x94\xbd\xae\xaf\x50\x9f\xf5\xe5\xe9\x0a\xf5\x2b\x94\xfa\xe5\x0c\x7f\xbf\x3c\xf7\xdd\x05\xfe\xbc\x76\xe7\x97\xfe\xd4\x5d\xf2\x46\x3f\xf7\x8f\xe7\xd3\xe5\x09\x2f\x4d\xff\x57\x92\x7c\xfa\x04\xf9\x8e\x5b\x9e\x98\x12\xf2\x84\xc8\xdf\xb8\x0b\x00\x79\xd2\x75\xbe\x65\x6f\xfc\x86\x5f\xfa\xa7\x53\x60\xf7\x33\x0f\x5a\xe7\x09\x38\x1a\xcc\x93\x2f\x3b\x46\x64\xff\x8f\xc7\xc2\xbc\x68\x2d\x44\x04\x0f\xfc\x1f\xf2\x04\x8d\x5d\x52\x66\x90\x27\x8a\x0e\x5d\x77\xe8\x10\xfc\x04\x26\x55\x51\x98\x10\x2d\x83\x5b\xba\xac\x2a\x95\x00\xcc\xd9\x8a\x03\x04\x60\x28\xe3\x8e\xa2\x52\xda\x6e\x89\x6d\xdb\xd9\xb6\xc3\xe3\x76\xb6\x53\x06\x00\x14\x95\x31\x65\x98\x74\x84\x02\xd5\xe1\x15\x55\x19\x45\xb4\xeb\x60\x2f\x2a\xab\x30\xcd\xf2\xa9\xa8\x76\x76\xa9\x58\xab\x4a\x6d\x30\x32\xc1\xc1\x58\xc6\x6e\x9d\xdc\xf2\x04\x34\xb1\xd0\x5e\x61\x12\x79\xfc\x53\x11\xba\xd9\xca\xca\x3d\xe3\x65\x45\xd4\xb9\x81\xca\x4f\x70\xbe\x0c\x4f\x14\x06\xa4\x16\xc3\x84\x4d\xcf\x6c\x6b\xb4\xcb\x90\xe5\xb7\x14\x89\x58\xb2\x3c\xb1\x64\x88\x58\x9c\x3c\xb1\x8e\x25\x82\x4a\x09\xa7\x81\xc0\xba\xf1\xa3\x17\x6e\x85\x97\x13\xa2\x40\xa4\xf1\xe8\x78\xee\x5c\xf8\xcc\x59\x77\x48\xb3\xe0\x80\x85\xf5\x71\x73\x2c\xc1\xfa\xdc\xfd\x12\xc4\xee\x06\x09\x62\x31\x9b\xd8\x76\x08\x78\x88\xc2\x5d\x5a\x21\x1a\x56\x25\xd0\x56\x6e\x0d\x12\x4a\x88\x1c\x0c\xd6\x95\x25\x78\xb4\x31\x99\x6b\x2a\xca\x32\x89\x0a\x1b\x56\x36\x00\xd7\x72\x93\x41\x02\x56\x1e\x86\x86\xbc\xf3\x0f\x1e\x25\x1b\x4e\x6e\xa4\x72\xbe\xd0\x5a\x1b\x06\x05\x8a\x74\x43\x69\x29\x87\x19\x4b\xf0\x33\x47\x10\x2c\xc1\x60\xce\x2a\x78\x0e\x1d\xb8\x6e\x10\x14\xd4\x11\xfb\x8a\x99\xb4\xd6\x43\x00\xcc\xb5\xcc\x22\x41\x0a\xfc\x62\xf5\x6a\xad\x35\xde\x48\x08\x7b\x24\x14\x98\x5d\x20\x48\x54\x09\x41\x6b\x16\x97\xb3\x95\x1a\x60\x77\xc9\x86\x81\x5f\xb0\x5c\x88\xc3\x10\x86\x21\x0a\x87\x20\x5c\x96\x90\x9d\xa2\x18\x26\x1d\xd4\xd4\xda\x48\xfc\x8d\x24\x94\xe8\xdb\x56\x39\x22\xe8\x36\x13\x4b\x90\x46\x36\x34\xe8\xbd\x5c\xdd\x84\xf0\xd4\xcb\xd3\x3c\x9c\xcf\xcd\xf5\x89\x63\x18\x71\xf8\xe8\x0d\xe8\xcd\x27\xe8\x08\xdc\xe0\x79\x8a\xd6\x76\xe6\x71\xd6\x69\xb9\xde\x0c\x49\xd6\xca\x3c\xc4\x7b\x97\xc3\x6f\x41\x6e\xab\x80\xb3\x11\x95\x51\x96\x26\xe3\x40\xab\xb5\x5b\x9d\x41\xb4\x9b\x80\x8d\xac\x10\x27\xa5\x87\x29\x48\xd3\x81\x46\xd7\x4d\x85\x19\xb7\x3d\x3e\x39\xc7\x1a\x61\xe0\x61\x89\x06\x88\x52\x9d\xdd\x72\xc2\xbe\x07\x61\xef\x9b\x46\xf5\x0d\x83\xa2\x28\x53\x77\x15\x05\xe4\x49\x91\x01\xb6\x6d\xdb\x02\xb8\x6e\x98\x5a\x49\xb7\xb0\xd7\xf0\x76\xad\x1b\x5d\xe3\x4d\xcd\x31\x3e\x08\xdf\xac\xb0\xbf\xf2\x0e\x07\x00\xcb\x18\x1d\xa7\x43\xe6\xa7\x22\xd3\x3a\x30\xed\x1a\x33\x15\x75\x8b\x0c\xc0\x77\xdd\xdc\x3f\x5c\xd7\x5f\x4c\xf9\x86\x71\x91\x31\x5b\x15\x2b\x8c\x63\x05\xbb\x2e\xee\x39\x05\x0a\x3b\xc7\xf2\x74\x12\x15\x28\x4e\x9e\xe8\x3a\xe1\x68\x19\x8a\x9e\xca\x5b\xa9\xbd\x65\x28\x8a\xcc\xf5\x3c\xc3\x60\x8f\x6d\x86\xc2\x31\x4d\x1d\x0f\x61\xd9\xb6\x2d\x77\x2b\x37\xd1\xab\x35\xd1\xf2\xb6\x1b\xfb\x61\xc3\xa7\xeb\x8c\xb3\x3b\x19\x8f\xba\x1b\x8c\x33\x61\xbb\xec\xd3\x22\x0a\xd2\x10\xd0\xf3\x3e\xdd\x61\x62\x9b\x2f\x45\x51\xf8\xb4\xb9\xc9\x84\x5f\x96\x36\x69\xea\x17\x6d\x3d\x22\x02\xf9\x40\x57\xd6\x7b\x0e\xb0\xd9\xfb\x00\x13\x6d\x05\xb3\x24\x37\xa8\x68\x66\x3d\x9b\x12\x7b\x18\x16\xc5\x92\xdb\x77\xf6\xe4\xda\x99\xd8\x95\x0d\xbd\x4a\x85\xdc\x46\xb9\xc5\xd1\x36\xc9\xe9\xfb\x06\x8a\xb5\x90\x88\x11\x26\x96\x62\x22\xc2\x2a\xc2\xcc\xf7\x56\x35\x97\x5d\x63\x0d\x43\x67\x89\x4e\x82\xc9\x9d\x1c\xcd\x1d\x90\x26\x2a\x7a\x64\x11\xb2\x93\xdd\xe2\xd7\x20\x8b\xa8\x63\x55\xfd\xbc\x92\xca\x56\xa4\xd0\xad\x1c\x80\x16\x51\xee\xa0\xb7\xd3\x16\xe3\x00\xa5\xb1\xc6\x9f\xd7\x34\xae\x11\xd2\x91\x8a\xde\x95\x4b\x9e\x9d\x65\x5c\x8e\xf8\x8a\xa1\x11\xc5\x7f\x0e\xd6\x54\x44\x08\x83\x6f\x31\xda\x93\xeb\x7b\xf7\x47\xc1\x09\x76\xaa\xdf\x31\x7c\x26\xdc\xd9\x99\xe3\xb4\x84\x48\xfb\x12\xa3\x8a\x35\x13\x8a\xbb\x34\xdb\x62\x58\x2e\xec\xf5\x45\x51\x66\x03\x3c\x3a\x43\xee\xc5\x5c\x7f\x5b\x84\x97\xd2\xdf\xfc\x40\xe6\x6e\x9e\x79\x95\x01\x42\x36\xe2\x8f\x66\x56\x84\x15\x44\x1a\x29\x5e\x0d\xe6\x93\x2c\x88\xd2\x69\x8c\x54\x73\x9d\x4d\x9f\x0a\x23\x74\x8c\xf0\x96\x11\x63\x8d\x79\x5f\xf0\xc4\x3f\x6d\x04\x7d\x86\x9f\x45\x25\xb3\x72\x3d\x69\x07\x70\x1c\x68\xde\xb1\xbb\x0c\x47\x58\x98\x2d\x71\x8d\xca\x3f\x73\xc7\x25\x55\xfb\xa1\x4a\x85\x12\x9d\x34\xed\x34\xd7\xe4\x05\xdc\xbc\x39\xb1\xcf\x9e\x82\x21\x4f\x6e\x6b\x65\xe3\xe7\xa2\x44\x36\x69\xa2\xf2\xa0\x9c\xb7\x2a\x3e\x11\xa5\xd9\x7d\xd5\xa3\x69\x21\x09\xe6\x5e\xbd\xbf\xdb\x45\xd7\x0c\x58\x0e\x07\x5d\x85\x30\x5f\xd0\x5a\x3b\xbb\xe2\x50\x9c\xe1\x4a\x85\x3f\xdc\x8d\x0f\xe9\x54\x2e\x1e\x63\xa5\x1a\x03\xd3\x72\x17\x91\x59\x27\x4c\xc4\xa7\xc3\x45\xa3\xef\x96\x38\x4d\x03\x61\xc4\x69\x05\x7b\x85\x70\x54\x0e\x72\x85\x02\x16\x58\x64\x7b\x9b\x29\x76\x48\x6c\xdd\x68\xe8\x5e\x89\x91\x29\x78\x0b\xa7\xbe\xde\x15\xd9\x3c\x6a\x4c\x6b\xba\x43\xe3\x7d\x51\x50\x0e\x39\x85\xf2\xd9\xc1\x57\x70\xee\x8d\x82\x60\x74\xb7\x6c\x54\x99\x9b\xa8\x3e\x7c\x5e\x59\xfc\x02\xb3\x31\x71\xbc\x64\x59\x54\xbb\xbf\x0c\x1f\x5b\xd2\x30\x5a\x49\xf5\xa3\x64\x9c\x5a\x11\x75\x95\xef\x6c\x2e\x4e\xf2\xdd\x19\xac\x46\x13\x4c\x56\xb9\x3f\x91\x44\xfe\x9c\x2c\xf2\xb7\x42\x6d\xc9\xdd\x1f\xe0\x95\xf7\xc4\xd1\x8e\xdc\xdc\x2b\xf1\x04\x4d\xa4\x42\x1d\x96\x0d\x9e\xfe\xb0\xc8\x8f\x77\x27\x17\x4e\xf7\xdb\x78\x22\xdb\x9b\x6d\xac\x18\x4d\x3a\x1c\xcb\xb6\xc7\xc6\xc6\x17\x13\x59\x20\xd9\x58\xcb\x78\x24\x6a\x98\xf2\x3e\x34\x89\xa2\x27\x8a\xa9\x0f\x88\x02\x26\x8c\x03\x61\x57\xde\x24\xb2\x64\x33\x9f\xb8\x43\xa1\x73\x95\xf0\x4d\xe6\x8d\x52\x6a\x94\x6c\x44\x68\x0d\x4e\xc2\xcd\x1a\x4a\x4d\x3e\xbd\xec\xcd\x3c\x53\xa2\xd7\xc0\xc2\x4a\xf8\x44\x67\xd8\xa3\x3c\xc1\xc6\xca\xfd\x99\xb7\xcf\xe6\xab\x08\xbe\x40\xd8\x55\xb1\xa5\xa6\x8c\x46\xdc\x86\x6c\x81\x68\xc2\xaa\xc4\x18\xbe\x34\xd1\x17\xf7\x1e\xbb\xf0\x81\x14\x4c\xf8\x60\xe8\xdf\x5a\x9c\x8d\x3f\x9b\x4e\x7f\x06\x06\x9c\xe5\xdf\x6c\x93\x6e\x84\xb3\x62\x56\xd7\xff\xe2\xe3\x19\x49\xf9\x9c\xa1\x7a\xf2\x56\xdd\x04\xd0\x88\x33\xa0\x4d\x37\x7b\x16\xb1\x6c\x53\x48\xcd\x34\x10\xde\xd5\xce\x93\xc9\xbf\xff\x6a\xe0\xdf\x00\x00\x00\xff\xff\x46\xd8\x61\x0e\x43\x22\x00\x00")
+
+func fontsNancyjFancyFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsNancyjFancyFlf,
+ "fonts/nancyj-fancy.flf",
+ )
+}
+
+func fontsNancyjFancyFlf() (*asset, error) {
+ bytes, err := fontsNancyjFancyFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/nancyj-fancy.flf", size: 8771, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsNancyjUnderlinedFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\xcd\x8e\xdc\xa8\x13\x3f\x8f\x9f\xa2\xd4\x89\xe4\xcb\xff\x8f\x94\x95\x76\x55\x9b\x53\x3f\x82\xaf\xdc\x8c\x83\x3b\xd3\x9b\xe9\x21\x9a\x76\x12\xe5\xd2\xcf\xbe\xa2\x28\xa0\x8c\x3f\x7b\x66\xb4\x4e\xc6\x06\x1b\xea\xf3\x57\x45\x41\x9f\x9e\x4e\x7f\x98\x8f\x80\xf0\x17\x7c\xfa\x13\xfe\xff\x09\xfe\xae\xaa\x87\x87\x87\x07\x00\x78\x36\xcf\x5f\x7e\xff\xa3\x4e\x4f\xa7\xaa\x7a\xf0\xdd\x4b\x6f\xc1\x9c\x86\xfe\x05\x86\xc7\x1e\x9e\xdc\xd7\xf3\x33\xb8\x13\x18\xf8\xe5\x2e\xe6\x19\x7e\x3d\x3a\x00\x73\xfd\xd6\x5b\xb8\xf4\x30\x38\xb8\x98\x6f\x3d\x3c\xf6\x2f\x60\xfc\xfc\xeb\xf9\xab\x82\xe1\xf1\x7c\x85\xf3\x95\x08\x9c\xdc\xf3\x00\xc3\xa3\x19\xe0\x8b\xb9\xf4\xe0\x7e\x0c\x9e\xda\x79\x50\x90\x86\x5d\x7e\xc3\xe9\xfc\x72\x1d\x2a\x2f\x90\x19\x86\xfe\xf2\x7d\x00\x33\x80\x81\xd3\xf9\xeb\x53\x3f\x10\x8d\xff\xc1\xd5\xc1\x53\x6f\x7e\xf6\x9e\xaf\x79\x72\xcf\xbd\x22\x25\x20\x5c\x3f\xcd\xe5\xfb\xef\x97\xa3\xf9\x72\x55\xdd\x0f\xd5\xdb\x1f\x55\xf5\xf1\x23\x1c\x97\x6f\xce\xb9\xd0\x3a\x56\xb6\x81\x63\x85\x18\x6f\xd4\x05\xa0\x31\x71\xa0\xef\xd2\x17\xfa\x18\x9f\x81\xf5\xf2\xd3\xd1\x95\xfa\xb1\x41\x43\x02\x0d\xe2\x49\x97\x7f\x87\xe8\xff\x8f\xdf\xa5\x71\xce\x8d\xc9\x31\xc1\x0f\xf4\x1f\x8e\x95\xb2\x7e\x4a\x53\xc3\xb1\xd2\xf8\xc1\xb9\x0f\x4e\x41\x1c\x40\xa4\x5a\x4c\x03\xc4\x34\x37\xa5\x4b\xaa\x62\x03\x40\x9c\xbd\x38\x80\x00\x16\x6b\xea\x68\x6c\xb8\x1d\x34\xf5\x6d\x3f\xda\x77\xe8\xbd\x1f\x1d\x94\x01\x00\x4d\x5f\x9c\x9b\x63\x13\x4d\x62\x11\xbb\x44\x0e\xdb\x1a\x05\xed\x2e\xd9\x0b\x9b\x36\x0d\xf3\x7c\x5a\xec\xc8\x2e\xd0\x92\x56\xad\xde\x60\x64\x93\x83\x55\x72\x70\xbe\x09\x2f\x83\x41\x12\x3a\x2a\x8c\x2c\x4f\x7c\x6a\x54\x61\x9e\xf6\x72\xcf\x78\x59\x23\xba\x40\xb8\xa5\x01\x5e\x2b\x1c\x3d\x15\x33\x40\xbd\x08\x13\x32\x3d\xb1\xed\x94\x9f\xa6\x48\x7e\x4f\x11\x91\x24\x3b\x56\x9e\x0c\x22\x89\x73\xac\xbc\x63\x11\xa1\xd5\xcc\x29\x13\x58\x37\xbe\xc0\x6c\x98\x11\xe5\x04\x01\x44\x1c\xbf\x15\x63\x17\xe0\x93\xe3\xa0\xb8\x87\xb8\x21\x82\x37\xd5\xdc\xf8\x7d\x29\xc9\x4c\x73\x2c\xc9\xcc\x80\x65\x49\x26\xb7\x1c\xf0\xd2\xed\xc0\x60\x66\xf3\xb1\x8d\x33\xf0\x41\xc0\x9e\x5b\x09\x15\xab\x12\x18\x2f\xb7\x01\x86\x94\x52\x04\x0a\xef\xd2\x06\x62\xd6\xb1\x75\x68\x6a\xac\x6b\x46\x87\x87\x97\x07\xe2\x5a\x8c\x52\xb2\x80\x95\x87\xc5\x1c\x7f\x3c\x39\x4c\x44\x0f\xab\xf0\xa6\x0d\x41\x61\x8c\xb1\x94\x1c\x50\xe8\xa6\x20\x62\x3e\x08\xb3\x90\x86\xe6\x08\x82\x27\x98\xcc\xd9\x26\xcf\xa9\x90\x64\x37\x08\x72\xf6\x61\xfb\xb2\x99\x8c\x31\x19\x00\x73\x2d\xbb\x48\x10\x13\x3f\xa9\x5e\x67\x8c\x51\x13\x09\x61\x8f\x84\x9c\x6e\x17\x08\x22\xb6\x4c\xd0\x9b\x25\xc4\x6e\xab\x63\xfa\x5d\xb6\x21\x36\x02\x7e\x19\x7d\x19\x7c\x19\x7b\x31\x41\x2d\xae\x0d\x24\x21\x39\x45\x53\xba\x0c\x29\xa7\x33\x96\xf1\x37\x92\x90\xd1\xb7\xad\xb2\x20\x18\x16\x15\x4f\x10\x47\x36\xb4\x2a\x7a\xb9\x9d\x40\xb8\xf4\x32\xc7\xe1\x56\x6c\x8a\xb4\x01\x3b\xd3\x49\xc8\x97\xd1\x90\xd1\x8c\x9c\x2d\x81\x1a\x34\x4e\xe3\xda\x4a\x3d\xce\x31\x86\xaf\x3d\xa9\x69\x21\x68\x69\x0d\x23\xbb\xf1\xe2\xd5\x71\x26\xf7\x31\x18\x6c\x85\x4d\x26\x90\x83\x36\x00\xae\x33\x61\x76\x0d\x62\x75\x01\x8f\xb0\x84\x97\x26\xa6\x2b\x38\x1c\xb2\x0a\xce\x95\x72\x8d\x56\x83\x94\xa7\x82\x83\x2d\x33\x88\xe9\x09\x73\xaa\xd2\xce\x2f\x41\x69\x1d\x84\xb4\x16\x96\xe8\x9e\x32\x08\x2a\xc4\xcc\x54\x73\xa8\xc5\xd0\xf6\xc1\x6d\x72\x46\x8d\x5f\x96\x3a\x6b\xcb\x5a\x60\x13\x6c\xc5\xab\x56\x30\x96\x09\x9c\xb8\x0a\xa2\x2f\x2d\x27\xae\x30\x4c\xc5\x4a\x0c\x27\xb1\x30\xc7\x68\xd9\x64\x02\x1d\xb9\x1d\x4c\xc6\x3c\xf6\x98\x4c\x2a\x22\xf5\xc8\x96\x98\x6b\x2b\xce\x4b\x38\x5d\x41\x26\x3e\x89\x9a\x76\xd9\x06\x8c\xf5\x60\x2a\xf6\xaf\xfc\x52\x76\xf6\x99\xea\xcd\x8c\xb8\xa0\xd9\xac\x69\x14\xb1\x51\xb0\xe5\x13\xdd\x08\x18\xb3\x4f\x42\x8d\x5c\xaf\x9a\x8c\xe5\x88\xd5\x3b\xdc\x0d\xe3\x11\x81\x15\x4d\x8a\x7d\x49\xb1\x43\x29\x4b\x17\x90\x7b\x12\x90\xd9\x68\xd2\x26\xeb\x28\x2e\xda\x69\x59\xda\xad\x32\xab\xc2\xf9\x26\x2c\xc9\x4d\x9d\x54\xe4\x60\x92\x90\x94\x73\xb7\x18\x4c\x02\x66\x5f\x7b\x0e\x80\x33\x81\xd4\x19\x25\x63\x89\x52\xb0\x08\x27\x59\x69\xac\x75\x6d\xda\x19\x15\x3a\x95\x2e\x7c\x43\x04\xdf\x61\xba\x39\xbc\xaf\x31\x88\x78\x6f\x12\xde\x9b\x75\xe7\xdf\x95\x4d\xd9\x27\x6f\x8c\xdc\x91\x2a\x73\xb1\x64\x3b\xee\x90\x36\x9a\xb3\x1c\xab\xa3\xc5\xb6\xec\xbd\xd7\x07\x48\xbb\xf2\x19\xcf\x4c\x18\xf1\x82\xd7\x89\x62\xfa\x50\xc7\x52\x50\x54\xcc\x91\x7d\x50\x5a\xd6\xff\x1b\xe9\xdb\xa2\xac\x1a\xc5\xfe\x6c\xb3\xb9\xb1\x81\x9b\x44\xfc\x06\x54\x25\xaa\xda\x3d\x2b\xdb\x3a\x83\xb8\x82\x41\x2a\x85\x7d\x9b\x52\x56\x8a\xf8\x7a\xbd\x9c\x29\xc2\x74\x26\xa6\xa9\xdc\xca\x9c\xc8\xf8\x91\x99\x67\x85\x92\x5f\xed\xfd\x51\xb2\x9c\x8d\xf8\xa0\x19\x31\x25\xab\x24\x77\x7a\x5c\x25\x68\xcb\x20\x15\xc1\x3e\x46\xd4\x9c\x4f\x56\x08\xbf\xda\xd9\x38\x82\x91\x2c\x27\x55\xda\x76\xa8\xbc\xdd\x88\xad\xbc\x33\xdc\x91\x7d\x9b\x99\xa3\x94\xe9\x13\x71\xb6\x1c\xd7\x5d\xe4\xd7\xea\x74\x24\xc4\x4d\x3a\x68\xd1\x5d\xd4\x95\x9a\x72\x23\x37\x95\x29\xaa\x3c\x7b\x36\x33\x7e\x2e\x4a\x04\x94\x84\xd2\x8e\x8c\x13\x55\x7b\x48\x31\x9e\xf5\xbf\xfb\xc0\x02\xe6\x26\xbc\x43\xf7\x67\xbe\x7c\xf7\x90\xaf\x71\xb9\xa1\xd5\xf4\xcc\x64\x5a\x6e\x14\xea\xa8\x7c\x08\x80\x01\xe0\xb9\xd4\x90\xe7\x8f\xb8\x99\x74\x60\x7c\xac\x82\x68\xd7\x09\x23\x72\x09\xb3\x6d\xd3\x75\x89\xbd\x1d\x98\xb0\x52\xe3\x13\xd3\x55\xc2\xa2\xf0\x0a\x67\x29\x24\x30\xcb\xf6\x3a\x53\xec\x90\xd8\x4f\xb2\x78\xaf\xc4\x2a\xd6\xe0\x64\xe1\x43\x2c\xe2\x84\xcd\x45\xa3\x3c\x43\x4c\xa4\xde\x88\x82\x50\x79\xbb\xdb\xed\x76\x53\x88\x37\x0a\x21\x5e\xeb\xee\x45\x01\xec\xcf\x9f\x74\x9c\x5f\x1c\x32\xcc\xd6\xd3\x8b\x03\xf9\x76\x0b\x1f\x96\x45\xf5\x79\x33\xaf\x54\x07\x10\x25\xa7\x8a\xa2\x16\x07\xd6\x93\x48\xb8\xab\xf4\x87\x32\xde\x83\xc1\x3a\x65\x93\xc9\xda\xf0\xc7\x92\xf0\x5f\x90\x85\xff\xee\x38\x2a\x7e\x47\xaf\xbc\x05\x47\x3b\x62\xb3\xb4\x0c\x55\x72\x49\x68\x10\xc4\x41\x50\x87\x90\x53\x88\xfc\x0d\xf1\x96\xe8\x67\x8f\xbf\x4b\x04\xf8\xeb\x16\x22\x00\xa2\xa1\x5e\x63\x6b\x19\xad\x7b\xd6\x96\x25\x89\x35\x65\x15\xa7\xc6\xf9\x6c\x8f\xad\xf9\xa7\x22\x2e\x3b\x78\x81\x6d\xe4\x1b\xd1\xb0\xcd\x7d\x59\x45\xa0\x48\x60\xeb\x75\x68\x98\x12\x56\x99\x70\xaa\x35\x15\x6f\x89\xe3\xfe\x68\xd7\x7a\x5d\x74\x46\xa1\x35\x0a\x3a\x44\xbf\x13\x55\xc8\xdc\xbc\xa1\x74\x59\xe9\xef\x8c\x40\xdb\xa8\xa8\x81\x4f\x2f\xe9\xa7\x21\x4b\x1e\xa5\x01\x1e\x2b\xf7\x47\xe0\x3e\x9b\xaf\x66\xf2\x05\xc2\xe2\x1c\x28\xd4\xf4\x54\x2e\x29\xb2\x80\x18\xb0\x2a\xb1\xb2\x09\x5d\x9f\x19\xc5\x2e\xfd\x30\x07\x36\x95\xbe\xf1\x2b\xd0\x39\x47\xb7\x7d\x12\x4d\xb5\x5b\xd1\x95\x3f\x01\x07\xb3\x06\xd9\x3f\x47\x3c\x2b\xd4\x31\x66\xb0\x2b\xbe\xea\x09\x80\x46\x9c\x41\xf9\x70\x03\x65\x89\xed\x01\x0e\x36\xd5\xf2\x33\xa8\x5a\x6e\xcf\xe3\xe6\x78\xac\x8a\x7f\xff\xd5\x8b\x7f\x03\x00\x00\xff\xff\x8d\x44\x2c\x65\x74\x20\x00\x00")
+
+func fontsNancyjUnderlinedFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsNancyjUnderlinedFlf,
+ "fonts/nancyj-underlined.flf",
+ )
+}
+
+func fontsNancyjUnderlinedFlf() (*asset, error) {
+ bytes, err := fontsNancyjUnderlinedFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/nancyj-underlined.flf", size: 8308, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsNancyjFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\xcd\x8e\xdb\xb8\x0f\x3f\x8f\x9f\x82\x48\x0b\xf8\xf2\xff\x0b\xe8\x02\xbb\xe0\xf6\x94\x47\xf0\x55\x37\xcb\x95\xd3\xc9\x36\x89\x8b\x89\xdb\xa2\x6f\xbf\x20\x45\xc9\xb4\xfc\x99\x99\xc1\xa6\x9d\x98\xb6\x25\x7e\xfe\x48\x51\xca\xe9\x72\xfa\xc3\x7d\x04\x84\xbf\xe0\xd3\x9f\xf0\xff\x4f\xf0\x77\x51\x3c\x3d\x3d\x3d\x01\xc0\xcd\xdd\xbe\xfc\xfe\xc7\x9c\x2e\xa7\xa2\x78\xa2\xdb\x6b\xeb\xc1\x9d\xfa\xf6\x05\xfa\xe7\x16\x2e\xdd\xd7\xf3\x0d\xba\x13\x38\xf8\xd5\x5d\xdd\x0d\x7e\x3d\x77\x00\xee\xfe\xad\xf5\x70\x6d\xa1\xef\xe0\xea\xbe\xb5\xf0\xdc\xbe\x80\xa3\xf9\xf7\xf3\x57\x03\xfd\xf3\xf9\x0e\xe7\x3b\x33\x38\x75\xb7\x1e\xfa\x67\xd7\xc3\x17\x77\x6d\xa1\xfb\xd1\x13\xb7\x73\x6f\x20\x0d\xbb\xfe\x86\xd3\xf9\xe5\xde\x17\xa4\x90\xeb\xfb\xf6\xfa\xbd\x07\xd7\x83\x83\xd3\xf9\xeb\xa5\xed\x99\xc7\xff\xe0\xde\xc1\xa5\x75\x3f\x5b\x92\xeb\x2e\xdd\xad\x35\x6c\x04\x84\xcf\x4f\x77\xfd\xfe\xfb\xe5\xe8\xbe\xdc\x4d\xf3\xc3\xb4\xfe\x47\x51\x7c\xfc\x08\xc7\x1d\x5f\xc7\xc2\x57\x70\x2c\x10\xe3\x17\xdf\x02\xc0\xb1\xe8\xba\x48\xd1\x17\xbf\xe1\x97\xf1\x1a\x44\xef\xbe\x46\x82\x1f\x05\x1e\x2c\x93\x3f\xf4\x0c\x91\xfe\x8f\x9f\xa5\x71\x6a\x2e\x28\x86\x1f\xf8\x3f\x1c\x0b\xe3\x69\x4a\x55\xc2\xb1\xb0\xf8\xa1\xeb\x3e\x74\x06\xe2\x00\x66\x55\x63\x1a\xa0\xa6\xc1\x94\x2f\x9b\x8a\x15\x00\x4b\x26\x75\x00\x01\x3c\x96\x7c\x63\xb1\x12\x3a\x4c\x21\x9a\x46\xd3\x0d\x3f\xa7\xd1\xc1\x18\x00\xb0\x58\x69\xce\x90\xdd\x08\x07\x6c\xd2\x2b\xac\x4b\x54\xbc\x9b\xe4\x2f\xac\xea\x34\x8c\xe4\xd4\xd8\x04\xbf\xd4\x6c\x55\x6d\x37\x04\xf9\x14\x60\x53\xe9\xb0\x66\x5f\xc7\x02\x1c\xb2\xd2\xd1\x60\x14\x7d\xe2\xd5\xa2\x09\xa3\x2d\xe9\x3d\x13\x65\x8b\xd8\x85\x07\x75\x1c\x10\x62\x99\xae\x46\x04\xa0\x5d\x84\x09\xbb\x9e\xc5\x36\x86\xa6\x19\xd6\x9f\x38\x22\xb2\x66\xc7\x82\xd8\x20\xb2\x3a\xc7\x82\x02\x8b\x08\xb5\x15\x49\x03\x83\x75\xe7\xab\x17\x61\x46\xd4\x13\x14\x10\x71\xfc\x74\x3c\x76\x0e\x3e\x73\xde\x1d\xd2\x2c\x05\x60\x61\xbe\x26\xc7\x1a\xac\x8f\xdd\xaf\x81\x0e\x37\x08\x88\xc5\x6d\xe2\xdb\x01\xf0\xa0\xe0\x2e\x54\x42\xc3\xaa\x06\x8e\xf4\x76\x20\x50\x32\x86\xc1\x40\xa1\xac\x20\x56\x1b\x5f\x06\xd2\x62\x59\x0a\x2a\x08\x56\x04\xc0\xb5\xdc\xe4\x22\x01\x2b\x17\x8f\x43\xde\xc5\x0b\x3f\x45\x82\x53\x78\x52\x87\x58\x38\xe7\x3c\x17\x05\x54\xb6\x19\xa1\x6c\xa8\x19\x4b\xe5\x67\x8e\x21\x10\xc3\xe4\xce\x3a\x45\xce\x84\xe2\xba\xc1\x50\xaa\x8e\xf8\x57\xdc\xe4\x9c\x1b\x00\x30\x47\xf9\x45\x86\x98\xe4\x69\xf3\x1a\xe7\x9c\x99\x68\x08\x7b\x34\x94\x32\xbb\xc0\x10\xb1\x16\x86\xe4\x96\x90\xb3\xb5\x1d\xca\xee\x92\x0f\x93\xbc\xe4\xb9\x84\xc3\x04\xc3\x84\xc2\x01\x84\xcb\x1a\x72\x50\x2c\x97\xc9\x50\x6a\x1a\xe7\x05\x7f\x23\x0d\x05\x7d\xdb\x26\x2b\x86\x61\x31\x21\x86\x38\xf2\xa1\x37\x31\xca\xf5\x04\xc2\x79\x94\xf3\x3c\x9c\xcf\xcd\xf5\x81\xe3\x32\x12\xea\x63\x74\x60\x74\x9f\x54\x47\x60\x82\xc7\x59\x5c\x5b\x99\xc7\x59\xe7\xe4\xf3\xea\x92\x44\x5e\xe6\x47\xbc\x76\x85\xfa\x2d\x95\x9b\x0c\x08\x3e\xc2\x4a\x65\x69\x31\x06\x5a\xe3\xc2\xec\x12\xd4\x6a\x02\x84\xac\x84\x93\x2a\x96\x29\x38\x1c\x06\x1e\x5d\x97\x2b\x33\xa6\x63\x7d\x0a\x81\xf5\x22\x20\x96\x25\x1c\x4a\x94\xed\x68\xc9\x49\xeb\x1e\xa4\xb5\x2f\x47\xf5\x54\x40\x30\x21\x56\x24\x06\x6d\xec\x6f\xd8\xad\x54\x1d\x53\x25\x8d\x6f\x96\x6e\x60\x5e\x0e\x0b\x0a\x62\x82\xaf\x64\x95\x0a\xce\x72\x41\x92\x28\xca\x6f\x6a\x29\x58\x61\x98\x89\x9d\x17\x4e\x72\x60\x4e\xd0\xb2\xcb\x14\x3a\x06\x3a\xb8\x4c\x64\xec\x71\x99\x36\x44\xdb\x31\x78\x62\x8e\x36\x52\x8f\x70\xba\x72\x4c\x62\x12\x2d\x6d\x06\x1f\x84\x61\xe2\x2a\x99\xa3\xdf\xe4\x37\xfb\x5c\xf5\x66\x41\xd2\xc0\x6c\xf6\x30\x86\xc5\x18\xd8\x8a\x89\xad\x14\x8c\x25\x26\xa1\x27\x2e\x57\x5d\x26\x7a\xc4\x6e\x3d\x3a\x7f\x3f\x8c\x47\x0c\x56\x2c\xc9\xf6\x21\x73\x3b\x92\x51\xb1\xd2\xab\x9e\xae\x46\x13\x9a\xbd\x63\xa4\x49\xe7\xe5\x68\xb7\xc9\x62\x8a\xd4\x9b\xb0\x14\x57\x65\x32\x51\x92\x49\x43\x52\xcf\xdd\x12\x30\x49\x98\x7d\xf4\x1c\x00\x67\x12\xa9\x71\x46\xe7\x12\x97\x60\x95\x4e\xba\xc3\x58\xbb\xf5\x69\x27\x94\xd9\x94\x87\xf0\x0d\x19\xfc\x80\xeb\xe6\xf0\xbe\x26\x20\xe2\xbd\x4a\x78\xaf\xd6\x83\xff\x50\x35\x8d\x0c\xde\x96\xb9\x23\x53\xe6\x72\xc9\x37\x72\xc3\xd6\xd8\x58\xe5\x82\x39\x56\x6d\xc3\xe6\x05\xbd\x7e\x7d\x80\xb4\x0b\x9f\x89\xcc\x44\x90\x2c\x78\x8d\x6a\xa2\x0f\x65\x6c\x01\x55\xa7\x1c\xc5\x07\xa3\x75\xdf\xbf\x51\xbe\xfd\x08\xfa\x6a\x3f\xb6\x49\x6e\x6c\xd8\x26\x19\xbf\x01\x55\x8d\xaa\x7a\xcf\xca\xb6\x2e\x20\xae\x60\x90\x5a\x60\xa2\xb9\x64\xa5\x8c\x2f\xd7\xdb\x99\x2c\x4d\x67\x72\x9a\xdb\xad\x41\x12\x3b\x3f\x0a\x23\x51\xa8\xe5\x95\x14\x8f\x5c\xe4\x6c\xc6\x07\xcb\x58\x28\x7b\x25\x85\x93\x70\x95\xa0\xad\x93\x54\x25\xfb\x18\x51\x73\x31\x59\x61\xfc\xea\x60\xe7\x15\x74\x68\x27\x4d\xda\x6e\x98\x61\x9b\x11\x29\x48\x7b\x85\x1d\xd5\xb7\x9a\x39\x3a\x99\x5e\x75\x1b\xad\xda\x71\xdb\xc4\x47\xb5\x4d\x47\x40\x42\xd2\xb0\x40\xf2\x04\x26\x27\x3b\xc2\xc9\x96\x63\x74\x8a\xb1\x7c\x5d\xd4\x08\xb8\x08\x49\x7d\xc3\x52\x0a\x55\xcd\x1d\xf7\xa1\xdc\xb1\x15\x58\x0a\x86\x46\xd3\x16\xd8\x1e\xbb\xed\xd4\x67\x1e\xb7\xd2\x5f\x58\xa3\xfb\x8b\xec\x6b\xc9\x06\x33\x6c\xfe\x31\x00\x7c\x68\x35\xf4\x79\xe3\xe2\x36\x49\x75\x01\xa3\xe3\x14\x44\xbf\xce\x18\x51\x5a\x98\x6d\x9f\xae\x6b\x7c\x38\x24\xc6\xc6\xe4\x27\xa4\x2b\x8c\x55\xd2\x86\x8d\x28\x2b\x2c\xba\xbd\xce\x15\x3b\x34\xa6\x30\x7a\x7c\x54\x63\x13\x7b\x70\xf6\xf0\x21\x36\x71\xca\xe7\x8a\xc8\xcf\x0c\x07\xe2\x6d\x28\xa8\x86\x9c\x92\xc6\xdb\xc7\xb5\xee\x51\x14\xc0\xfe\xfa\x39\x1c\xdf\x2f\x9e\xf0\x6f\x0c\x1c\x4f\x59\x56\x95\xea\xe6\xb0\x52\x1d\x40\xb5\x9c\x26\xaa\x9a\x1d\x50\x4f\x32\xe1\xa1\xd6\x1f\xa6\xbd\x15\x39\xac\x31\x3e\xb9\xac\x0e\x7f\xa2\x89\xfc\x05\x5d\xe4\x6f\xbd\x67\x9a\x0d\xf7\x3b\x44\xe5\x2d\x38\xda\x91\x9b\x7b\x35\xce\xaa\x49\x55\x8e\x63\x3a\x44\xfa\xdd\x90\xaf\x57\xa7\x00\xa7\xc7\x7d\x9c\xe9\xf6\x6a\x1f\x5b\xae\x26\x9d\x19\xeb\xb6\xc7\xc7\x3e\x1e\x56\xb1\x42\xb2\xb0\x56\xfa\x89\x22\x7c\xf5\x58\x35\x51\xe8\x51\x98\x7a\x07\x14\x30\x63\x33\x30\x4e\x3d\xa6\x91\xad\x70\xdc\x17\xed\x5a\xa7\xb3\x9b\x51\x4a\x8d\x92\x0d\x91\x76\xa0\x06\x45\x1a\x39\xca\xe6\x1d\xfe\xce\xcc\xf3\x95\x89\x16\x50\x59\x49\x3f\x01\x79\x8e\x28\x0f\x20\xac\x3c\x9e\x79\xfb\x7c\xbe\x5a\xc1\x17\x18\xab\xf3\x9f\xd0\xcb\x73\xd8\x0c\x7b\x40\x0d\x58\xd5\xd8\xa4\x5f\x32\xf0\x73\x78\x6f\xba\xf4\x03\x1c\xf8\xd4\xf2\xc6\xb7\xc0\xe7\x1b\xcd\x62\x1b\x98\xea\x2c\xf7\x6c\xd9\xad\xaa\xb3\xe2\xd6\x70\xff\x39\xe2\xd9\xa0\x8d\x39\x83\x4d\xf6\xd6\x4e\x00\x34\x92\x0c\x86\xd2\x0d\x8c\x67\xb1\x07\x38\xf8\xd5\xad\xde\xa3\xf4\xb1\xc8\xfe\xfd\x57\x0f\xfe\x0d\x00\x00\xff\xff\x77\xef\xd1\x81\x5c\x20\x00\x00")
+
+func fontsNancyjFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsNancyjFlf,
+ "fonts/nancyj.flf",
+ )
+}
+
+func fontsNancyjFlf() (*asset, error) {
+ bytes, err := fontsNancyjFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/nancyj.flf", size: 8284, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsNipplesFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\x4d\x8f\x1c\x35\x10\xbd\xf7\xaf\xa8\x43\xae\x40\x58\x21\x11\x6e\x7d\x21\x12\x12\x42\x51\xf8\x01\xde\x20\x6d\x50\xa4\x15\x48\x90\x0b\x58\xfc\x77\x34\xdd\xb6\xeb\xbd\xaa\xe7\xee\x99\x61\xc5\x66\xd3\xb6\xbb\xed\x2a\xd7\xd7\xab\xb2\xf7\xe3\xf3\xc7\x87\x0f\xaf\xec\x8d\x7d\x6b\x0f\xaf\xed\x8b\xaf\xed\x61\xf9\xe9\x87\x77\xef\x7e\xfc\xfe\x67\xfb\xe5\x2f\x7b\xff\xfb\x6f\xf6\xf6\x8f\x4f\x9f\xff\xb6\x37\x5f\x7d\xf7\xcd\xf2\xf6\xd3\xaf\xcf\x4f\x9f\xed\xfd\xd3\xf3\xd3\x87\x3f\x9f\xec\xe1\xcb\xd7\xcb\xab\x55\xfc\xda\xba\x2e\xb5\x14\x7e\x58\x7b\x98\x59\x7b\x77\xe9\x6d\x2f\x6b\x19\x8d\xd9\xf6\xfd\xbc\x69\x6d\xff\xb9\x0c\x6b\x29\xd6\x9e\x1b\x87\xcb\x8f\x6d\x6d\xfa\x7a\xe3\x64\x64\xb4\x8d\xfb\x97\x6d\xd7\xbb\x68\x25\xec\xa3\xad\xeb\x2a\x68\xf3\x32\x55\x94\xa4\xd1\x19\x53\x61\xae\x13\x6d\xac\x36\xee\x45\x2f\xa3\x9d\xfa\xdc\xb1\x17\x5f\x5f\x7c\x79\x98\x07\x6b\x9d\xe0\xfe\xa5\x19\x6a\xfe\x68\xdb\x6c\xe4\x1a\xfd\xd8\x8c\xfd\x76\x76\x9d\x83\xfa\x48\x0d\x11\x65\x25\x06\x49\xc6\xa3\xcb\xd3\x0c\xd6\x6d\x6e\xcd\xf2\xe2\xbb\x58\xcf\xf4\x85\x5b\xa0\x37\x5a\x76\x84\xae\xeb\xce\xf6\x68\x5a\xa6\x86\x8c\x0e\x1e\xc3\x44\x7d\x59\x6e\x89\xbb\xf8\x7e\x13\x27\x56\x3e\x48\x71\x87\x07\x07\x69\x43\x90\x03\x41\x24\x84\x5e\x35\x58\x0f\x72\xee\x31\xb8\xad\xe6\xf9\xd1\x8e\xeb\x00\x99\xe0\x86\xaa\xa9\xa0\x44\xda\xe9\x88\xa2\x46\x49\xe8\x06\x35\x82\x7a\x70\x2c\xe2\x58\x16\x28\x21\x14\xcb\xce\x49\x38\xd3\x43\xbf\x44\xf7\x92\x3a\x66\x37\xac\x38\xea\x01\xc2\x11\x02\xf1\x94\xa3\x45\xeb\x98\x24\x29\xec\x01\xc1\x3c\x5a\x12\x8d\x77\xd2\x59\x50\xdb\xe8\x81\x6e\x9f\xec\x44\x7d\x5a\x4e\x02\xc1\xd8\x75\xe4\x0e\x14\x3b\x19\x9b\x55\x3a\xe9\x1f\x49\xd2\x07\xda\xe9\xcd\xf7\x6b\x5a\x12\x50\xc5\x91\xf1\x93\x81\x5d\xe7\x2c\x5d\x2d\x12\xba\x58\xd9\xd2\xf8\x73\x24\x09\x98\x72\x3a\x11\x60\x6e\xe8\x3f\xa4\xf8\x88\x2d\xb8\x4b\xe1\x59\x42\x37\xd0\xa9\x85\xa0\x53\xbe\x49\x9d\xdb\x37\x70\x22\x02\x11\x0e\xc4\xd6\x25\x93\x72\x4b\xfa\x6a\xf9\x2e\x64\xb5\x41\x01\x03\xc7\xb8\xfc\x81\x0c\xd9\xa2\xa5\x32\xe8\x3e\x3e\x3e\x26\xec\xd6\x45\x95\x7b\x39\xb8\x94\x05\x24\x50\x6e\x46\x99\xa5\x07\x23\xe3\x6a\x4c\x0b\xc9\xdc\x64\x2b\xc7\x34\x5c\xea\xab\x1a\xfc\x24\x7c\xf7\x10\x81\xfa\x42\x85\x76\x88\x30\x2a\xcc\xc8\xdc\xa1\x8f\xf3\x6d\x44\x75\x60\x30\x60\x7e\x2c\x26\xe1\x91\xd9\xa4\x0f\x09\x2e\x81\xc6\x0a\x29\x2a\x82\x36\x74\xfb\xce\x0e\x27\xc4\x80\x7b\x11\xc2\xc9\xc3\x56\xd4\x55\x77\x5b\xe1\x11\x72\xd0\xb3\xfc\x50\x12\xf8\x99\x80\xd3\x80\x98\x07\x03\x4f\x1a\x57\xae\x49\x8c\xce\x1e\x10\x58\x54\x7d\x9c\xf5\x6a\xc1\xba\xa9\xc4\xd3\x0a\xc4\x1c\x1c\x3c\xa8\x2c\x69\x71\x51\xd9\x2c\x38\x6d\x96\x71\x95\x2e\xaf\x31\xf6\xad\x6e\xd6\x06\x5d\x5e\xb7\xb5\x4b\x51\xc1\x06\x0c\x72\x03\x87\x04\x29\x1a\x9a\x25\x89\x8a\xe6\x0b\xca\x63\xae\xcc\x94\xe3\xd5\x88\x65\xe2\xe8\x58\x93\x2b\x9f\xa0\xfd\xbc\x7f\x3d\x36\x2c\x09\x4c\xd1\x17\x12\x87\x88\x55\x98\x93\xa3\xfa\x08\x04\xa7\x12\x06\x01\xcf\xcc\x93\xac\x55\x47\x05\x0b\x09\x2b\xc6\xf9\xc5\xf6\x24\x19\xcb\xa6\x46\x16\xdd\x33\xe6\xf5\x68\x0e\x6d\xcb\xbe\x1b\x56\x5f\xc8\xaa\x21\xab\x67\xe8\x47\x3a\xc9\x56\xc6\xf5\x0c\x13\x7b\x99\x11\x31\xcc\xc6\xb8\x7b\x70\x05\x2a\x0b\x9d\x0d\x63\xa3\x63\xeb\xe2\x62\x04\x24\x8b\x16\x9c\x5f\x65\x20\xb5\x91\x83\x78\xab\x5c\x13\x24\x90\x40\x60\xf0\x64\xa6\xe3\x75\xb6\x01\x54\xc3\x10\xb9\x42\xed\x83\xb2\xa4\x6f\x12\xc2\xa5\xd7\x4a\x86\xa4\xf4\x19\xc3\x5b\x46\xcc\x30\x1d\xc8\xc0\xa8\xc2\xa2\x66\xe2\xd0\x52\x43\x29\x50\x44\x2a\x01\x86\x4d\xd0\xd3\x26\x5d\x75\x05\x76\xf1\x80\x90\xf6\x0a\x21\x35\x3d\xb7\xe0\x35\xe6\x71\x23\xee\x30\x2a\x43\x69\x3d\x49\xd3\xf7\x0c\xfa\xe8\xf6\xb6\xdd\x5c\x8d\x2a\x27\x9f\x10\xf9\x41\x08\x17\xfb\x2e\xe9\x08\x33\x55\x30\x07\x5f\x2d\x19\x35\x61\x77\x93\x2e\x69\x91\x0b\x6d\x9a\x90\x75\x14\x0e\x94\x15\xab\xd1\xc1\x06\xde\xf8\x1c\x26\x34\xaf\xfb\x10\x4c\x64\x05\xc8\x46\xbf\x5e\xa7\xf1\x20\x41\x47\x24\xf3\x3a\x7a\x9a\xd4\xd7\x7e\xe0\xbc\x2c\x1b\x7f\x20\x20\xb4\x9a\x74\xd2\x4e\x63\x97\x91\x2c\x5a\x04\xde\x76\x45\x51\x64\x82\x36\x16\x8f\x5c\xec\xd1\x35\x4c\xd2\x6e\x31\xa5\x53\xbc\x59\x3f\xa9\xe7\x87\x10\x72\x2c\xdb\xbd\xf6\x5c\x67\x1b\x0e\x87\xf8\xa6\xf2\x42\x1e\x3c\xdb\xfa\xd0\xd9\xfc\xe9\x3e\xa9\x2f\x19\x8c\x14\x3a\x32\x1c\x58\x28\x98\x46\x0f\x77\x21\x6b\xdc\xe4\xb1\x3b\xd4\x78\x61\x90\x7c\x80\xd4\x93\x88\xdf\x8d\x32\x81\xba\xac\xdf\x92\xbf\xe1\xbe\x1d\x57\x9c\x70\x44\x15\x69\x70\x4d\xd0\x00\x57\x90\xa0\x1b\xa2\x52\x65\x3c\x7a\x65\x72\x59\x16\xe1\x2a\x77\x6a\x88\x7f\x8d\x7b\xb5\xd0\x15\x71\x47\x0e\x03\xa4\x88\x38\xb5\x2a\x60\xb8\x0e\x45\x28\xb9\xce\x95\x1f\x8f\x6a\xba\x67\x4d\x6d\x13\x00\x8d\x69\x92\xf3\xac\x4c\x40\x63\x93\xa2\x8e\xd1\x79\x56\x70\x62\x56\x83\x57\x61\xd8\xf7\xd1\xfe\x0b\x21\x60\x29\x17\x9e\x44\x18\x22\x3a\x38\xbb\x79\xb6\x08\x49\x77\x12\x61\x53\xc2\x35\xfc\x91\xb5\xe4\xba\x29\xb8\xdf\x31\x61\x72\xa8\x10\x9e\x6b\xb8\x9b\x55\xb7\x0c\x16\x0e\xcd\xe4\x87\x7c\x5c\x0d\xb9\x2b\xf8\xf1\x7e\x9b\xb8\xff\xdf\x57\xd3\x78\x5d\x4a\xf9\xa7\x93\xdb\xba\xd4\xd9\xba\xea\x13\xac\x72\x4e\xc5\xe0\xaf\xbe\x02\x47\xff\x53\x7f\x5d\xc2\xbf\xff\xeb\xc5\xbf\x01\x00\x00\xff\xff\x2e\x0c\xdd\x8b\xe6\x20\x00\x00")
+
+func fontsNipplesFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsNipplesFlf,
+ "fonts/nipples.flf",
+ )
+}
+
+func fontsNipplesFlf() (*asset, error) {
+ bytes, err := fontsNipplesFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/nipples.flf", size: 8422, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsNtgreekFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x59\xfb\x8f\xdb\xb8\x11\xfe\x9d\x7f\xc5\x87\xc5\xa2\x91\x50\xed\x2a\x9b\x34\x38\x24\x58\x2f\x9c\x7b\xa5\x77\x6d\xef\x7a\xbd\x6b\xd0\x16\x42\x18\x5a\xa2\x6d\xdd\xca\x92\x2b\xc9\xd9\xdd\x83\xfe\xf8\x82\x4f\x51\x2f\xaf\xbc\xe9\x19\xb6\x44\x51\xe4\xcc\x70\xf8\xcd\xc7\x21\xbd\xce\xd6\x2f\xd8\x39\x5e\xe3\x0b\x5c\xbd\xc4\xd5\x2b\xbc\x7c\x4e\x7e\xf8\xe5\x5d\xc9\xf9\x2d\x56\x0f\xf8\xb2\x3c\xc4\x1c\xdf\xb3\x5b\x7e\xc7\x1e\x2e\x2e\x56\xac\xe2\x09\x8a\x1c\x3f\xd7\x2c\x4f\x58\x99\x88\x36\xef\x32\x9e\xe7\xf8\x6a\xcb\xf6\x7b\x9e\x65\xf8\x03\xbe\x63\xf2\x31\x25\x3f\x1d\x78\x55\xa7\x45\x5e\x81\xe5\x09\xe2\x62\xb7\xe3\x79\x5d\xa1\xe4\x1b\x56\x26\x69\xbe\x41\x5e\x6f\x84\xa6\xcb\x75\xb6\x46\x5d\x60\xbf\xfa\x55\x69\x5a\xe6\xfc\xb0\x63\x79\x7e\x79\xb8\x63\x35\x2f\xb3\xa2\xb8\x8c\x19\xf9\xb6\x28\xb1\x4e\x37\x19\xaf\x51\xf2\x8c\xb3\x8a\xe3\xc5\xe5\x73\xf2\x35\xab\xf9\x1b\xe0\xea\xf5\xeb\x3f\xe1\xed\xbe\xc4\x0b\x42\xbe\xb9\xdf\x67\x2c\x67\x42\x37\x8a\x35\xd6\x69\x59\xd5\xc8\xd2\x9c\xbf\x21\x62\xc0\xb8\xc0\xd9\x8e\x6d\xd2\x18\xf9\x61\xb7\xe2\xe5\x19\xd6\x52\x74\xc6\x91\x26\x3c\xaf\xd3\x75\x1a\xcb\xce\x84\x01\xc0\x05\xaa\x6d\x71\xc8\x12\xb0\xec\x8e\x3d\x54\x58\x71\x7c\x64\xcf\x02\xd9\x29\x2f\xee\xc8\xb9\x6a\x54\x6f\x39\xce\xb6\xac\x4c\x56\x19\xcb\x6f\xcf\x70\x71\x81\x7d\x99\x8a\x01\xb3\x0a\x0c\xb2\x36\xc0\xea\x50\x23\x66\xf9\xb3\x5a\x88\xa9\x76\x87\x6a\xcb\x13\xf2\x5a\x49\xd8\xf2\x74\xb3\xad\x85\xc5\x0c\xf1\x96\x95\x2c\xae\x79\x49\xbe\x38\xf2\x32\x40\x5e\xd4\x48\xf3\x38\x3b\x48\x87\x26\xbc\x8a\x79\x9e\xf0\xb2\x22\x57\x2f\x65\xb7\x1d\xbb\x97\x23\x47\xc6\xf3\x4d\xbd\x85\xc7\xef\x4d\x63\x3d\x21\xf2\x75\xe5\xe3\x8f\x60\x58\x1f\x92\x0d\xc7\x9a\xc5\x75\x51\x92\xab\x57\x52\x42\xc2\xd7\xec\x90\xd5\xca\xd8\x5d\x91\x70\x39\xf0\x7a\x9b\x56\x58\x17\x79\x0d\x2f\x4b\x6f\x39\xce\x2e\x76\xb8\x7a\x75\x26\xc0\x21\xe4\x8a\x09\x17\x72\x7d\xf2\xf2\xb9\x94\xa2\x3c\x2d\xcc\xef\xa8\x25\x44\x61\xed\x96\x3f\xac\x0a\x01\xa8\x1d\xdb\x57\x6f\x08\x79\x9b\x65\xa2\xae\x12\xcf\x02\x1a\xf5\xb6\xa8\x38\xd2\x1c\x95\x41\x1e\xbf\x8f\xf9\xbe\x7e\x43\x08\xcb\xf6\x5b\x31\x4f\x0b\xbc\x0d\xc4\x3d\x63\xbb\x55\xc2\xc4\xf3\x5f\x83\x0c\xc0\x7e\x9b\xc2\xf9\x2c\xf0\x6d\xb0\x06\x50\x16\x87\xcd\x16\xab\x92\xb3\x7a\x2b\xbc\x81\x05\x3c\xb2\xe2\x35\x53\x8d\xbe\x0c\x56\x00\x76\x07\xd3\xe9\x6f\xc1\x0e\x40\xdc\x97\xf5\x55\x10\x03\xa8\x76\x45\x51\xbb\xc2\x16\xf0\xc9\x86\xed\x76\xca\xae\x77\xc1\x06\x40\x6e\x65\xfd\x10\xe4\xc2\xae\xaa\x27\xeb\xdf\xc1\x03\x00\x16\x1f\x6a\x0e\x16\xc7\xc2\x47\xea\xc5\x33\x92\xf0\xac\x56\xb2\xbe\x0e\x12\x00\xf7\xa9\xe9\xf4\xaf\xe0\x1e\x40\xb1\xe3\x1b\xe6\xca\xba\x0b\xee\x00\x6c\x4a\xf6\xa9\x27\xeb\x23\xe1\xfb\x2a\xcd\x8a\x1c\x0b\x7c\x13\x70\xd9\x37\x8d\x4b\xf9\xfc\x63\x50\x88\xc1\xc4\x65\xba\xaf\x05\x9c\xb5\xca\xef\x65\xd7\x24\x65\x25\xaf\xd2\xca\x51\xf2\x81\xfc\x66\xfd\xf5\x9f\xe0\x37\x31\x26\x6b\xd7\xdf\x83\x7d\x2b\xcb\x4c\xc1\x02\xbf\x12\xdd\x03\x0b\xfc\x39\xd8\x8a\x79\xd8\x16\xfa\xf9\x1f\x41\x09\x60\x9d\xe6\x2c\x43\x95\x6e\x76\x5a\xf2\x7b\xd2\x9a\xf2\x53\xf0\x5f\x21\x55\xbf\x5c\xe0\xe7\xa0\xb2\xa3\x5f\xb1\xd2\x28\xff\x44\xd2\xc2\x18\xf6\x5d\x20\x74\xd7\xec\xa0\xdf\xfd\x12\x08\x57\x94\x2c\x15\x54\xb6\xe7\x65\x5a\x24\xa2\xfa\x0d\xb9\x65\xfb\xbd\x92\xfa\x97\xe0\x16\xc0\xc1\xfa\xe9\x9f\x81\xe8\x2c\x45\x56\x87\x95\x1e\xd3\x02\x94\x90\xf3\xe5\xd4\x77\x49\x00\x2c\x09\x28\x96\xa4\x41\x63\x2e\xb4\xd1\x75\x1e\xf5\x4d\x13\x40\xb5\x36\x1d\xd4\x7b\xf8\x1e\x44\x93\xf7\xc0\x7b\x38\xef\xdb\xfb\x39\x86\xf5\xa6\xd0\xd6\x52\xfd\x13\xa2\x1b\x34\xf2\x27\xf5\x9b\x77\xfe\xd1\x37\xba\xbe\x69\x75\x74\x14\xba\x5a\xa9\x79\xa1\x24\x89\x62\x28\xeb\x7d\x39\x1e\xcf\xd6\x46\xb2\x65\x64\xdb\xfa\x72\xa0\x4a\x6f\xa8\x44\x4b\x8d\xae\x96\x76\x64\xca\x47\xa0\x54\x3a\x11\x21\x42\xf9\x2a\x84\xea\x2a\xee\x4a\x75\x28\x1d\x19\xd2\x10\xc6\xd9\x1d\xcb\x1d\x5f\x49\x43\xa8\xf6\x52\x28\x6d\x93\x76\xe2\x47\x2b\x8c\x22\x0a\x23\x39\x0c\x7a\x03\x5c\xcb\x51\x50\x1a\x46\x61\x57\x8a\x2b\xda\x5c\xc2\x70\x49\xc2\x10\x9d\xba\xce\x45\x5c\xdb\x9f\xe7\x75\x9f\xf5\xaf\x5b\xe1\xfb\x93\x8d\xba\x38\x11\x36\x0a\x57\x45\xe2\x51\x18\x22\xf0\x15\x89\xf7\x51\x38\x82\x9f\x01\x8e\xba\x05\x17\x48\x16\x2a\x16\x26\x98\xe8\x35\x74\xc9\x79\xd7\x07\x1a\xf0\x4b\xd2\x84\xbd\x80\x18\x17\x49\xc5\x47\xea\x17\x9f\xde\xdc\x9e\x3f\x51\xff\x68\x40\x1a\x01\xc2\x85\x50\x28\x9b\x44\x1b\x34\xda\x8e\xe8\xef\x80\xcd\xe0\x4a\x31\x04\x0c\x4b\xd8\x02\x95\x05\x85\xb3\x63\x23\x92\x28\x17\x4d\x2f\x5a\x9e\x69\xc9\x66\x6c\x44\x54\xeb\x17\xfe\x33\x71\x48\x55\x14\x86\x50\xda\x84\x7e\xe9\xe3\x66\xcc\xc7\xc3\x88\x6c\x67\x04\x3d\xd7\x78\x46\x07\xd5\x3a\xe4\xac\x4d\x8f\xc8\xa9\xd3\x70\x13\x82\x1a\xed\xaf\x42\x21\x2f\xa4\x2d\xf4\xa4\xcb\x1c\xda\x98\x8e\xc8\xde\xf0\x1b\x35\x6c\x3d\x58\xe8\xc1\x9e\x6c\xac\x8a\x0c\x8a\x3e\x20\xb4\x8e\x67\x66\x8a\x3d\xed\xe2\xe3\x13\x3a\x02\x71\xc8\x6e\x82\x1b\x65\x37\x4f\x53\xea\xd3\x41\xa7\xc9\x57\xf1\x9b\x03\x43\xef\x34\x1b\x07\x30\x56\xfd\x35\x68\x03\x34\xdd\x50\xa1\xe1\xcc\xc0\xec\x85\xe3\x79\x9f\x2b\xa7\x82\x77\x92\x46\xf4\x0c\xe9\xf9\xd1\x9e\x5b\x92\x6b\x5c\x6b\x9e\x57\x31\x10\x29\x62\x6c\xad\x1b\xa7\xa1\x21\xfb\x1c\xe5\xa3\x51\xff\x09\x62\x96\xb7\xc8\xae\x35\xca\x86\x1b\xdc\x58\xfb\x5c\x8f\xf5\x2c\x52\x4a\x75\xc0\x45\xed\xc0\x44\x00\xc8\x99\xd1\xa1\xe7\x4f\xf4\x77\xdd\x42\x5b\xec\x5a\xf8\x2b\x68\x49\x1a\xf1\xe0\xc1\xf3\xa1\xc9\x48\x22\x83\x86\x54\xf9\x4b\x7e\xc2\x81\xcc\x59\x60\xb1\x0c\xd7\x48\x73\x3b\xe4\xa7\x72\x8e\x19\x21\x62\xc2\xd8\x4a\x94\xf0\x95\x35\x5e\xa7\x66\x4e\x18\x53\x93\x57\x88\xc9\x50\xfe\x8c\xf0\x49\xc3\xf7\x46\x83\x25\xc4\x07\xa9\x4c\x4c\x4e\x0b\x98\x71\x16\xeb\xb9\x43\xad\x20\x91\x2d\x87\x32\xd1\x30\xb4\x61\x90\x20\x98\x83\x46\x5a\x87\xfe\x44\xb3\x5c\x6c\x60\x28\x79\x8d\xfa\x6a\xf8\x30\x2e\xf2\x71\x22\xad\xbb\x2c\xac\x66\xb0\x9b\xd7\x99\x90\xb7\x19\x5c\x74\x3c\x83\x23\xf3\xad\x3e\xd7\x56\xb7\x05\xd5\x58\x09\x7d\x94\x3b\x01\x93\x77\xf7\x16\xd3\x27\x40\xad\x8d\x34\x28\x1e\x16\x1d\xfb\x37\xcf\xf1\xe5\x58\xa4\x19\x4f\x52\xea\x4c\x3e\xb5\xb3\x2f\x78\x53\xa7\x54\xb2\xd6\xac\x6d\x6a\xb6\xcc\xf2\xa6\xc2\x2d\xec\x21\xa0\xf7\x30\xf0\x03\x55\x83\x95\x70\x6e\xd0\x28\x66\x11\x5e\xbc\xd6\x9e\x55\x50\x13\x7e\xf8\xbd\xe0\x0c\x44\x36\x64\x80\x8e\x9a\x49\x38\x6b\xc7\xab\x95\x55\x1a\x1c\xc9\x34\x40\xd9\xfe\x09\x66\x16\x23\x1a\xda\xc4\x09\xed\x94\xa2\x33\xa9\x47\xc0\x67\xa1\x12\x19\xa8\x20\x32\x85\x56\x09\x8c\xdc\xe8\x51\x56\xfa\x3f\xe6\x76\x8e\x1f\xec\x0a\xa3\xe3\xd1\x00\xd1\x41\xe1\x48\x51\x6f\xdd\x1e\xf3\x83\x31\xdb\xda\xdd\xd2\x69\x1b\x36\x36\x6e\xa8\x63\xbb\x6b\xfc\x9c\x6c\x6b\x48\xd3\x26\xd9\xc4\xfc\xf8\xb6\xce\x88\x0c\x63\x48\x7c\xc1\xac\x9f\x2d\x8b\x5a\x0a\x9d\x9f\xbe\xb6\x1b\x1a\x93\x54\x8e\x14\x26\xf6\x3a\x53\xe0\xf5\xa8\x04\xaf\x92\xab\x56\x14\xcd\x91\xb0\x1c\xe9\x16\xe7\x32\xe7\x48\x41\x8f\x43\x2d\xe5\xbe\xca\xc8\xcc\xa6\xdb\xa4\xfa\xd0\x39\x9e\x78\x15\x4e\x64\x04\x68\x33\x02\x1d\xc7\xd2\x40\x07\x63\xa6\x2c\x96\x2a\x99\xec\x2a\x16\x6c\x9a\x8e\xbb\xe7\x2c\x57\x4e\xd6\x64\x30\x28\xf9\x74\xa2\xcd\x71\xa7\xc3\x1c\xa0\x34\x68\xd4\x57\x06\xb7\x64\xbe\x66\xb0\x46\x3d\xc1\xe9\x0a\x7d\x26\x31\x9f\xdc\x0d\x3e\x0e\xbe\x76\xd5\xf3\x75\x04\x4c\xdf\xcc\x8a\xed\x0f\x16\x17\x9d\xb5\xd8\x54\xd2\x26\x93\x4a\x9b\x61\x61\xd8\x04\x13\xd3\x34\xdf\xc6\x40\xa3\xf1\x3e\x75\x53\x14\x20\xe7\x7b\xc4\x22\xcb\xaa\x22\xff\x1c\x3f\x7b\x99\x53\x58\x8e\x9d\x70\x74\x7e\x4d\xd3\xd9\x0f\x44\x6a\x57\x13\xb9\x75\xdd\xcb\x28\x59\xf5\x68\x50\xef\x14\x42\x79\x42\x12\xca\x10\xf2\xc5\x6a\xa9\x62\x28\xec\xac\x5e\x13\x94\x37\x9a\xeb\xb6\x99\xe9\xf5\x3c\x12\x3c\xea\xa4\x27\xe5\xaa\x5d\x41\x4e\xda\xef\x77\xc0\x72\xfa\x76\x70\x70\x53\x50\x12\xf4\xe1\x2f\xc9\x8d\x52\x10\x1d\x4f\x92\x96\xdd\x64\xd3\x09\xce\xd3\xf2\xce\x41\x4c\x1f\x07\x9b\xc5\xaa\xf4\xa3\xdf\xf1\xe3\x14\xf5\x3f\x26\x91\xf6\xb7\xfe\x6e\xb2\xa9\xb7\xc5\x4e\x81\x6a\x18\xa3\x77\xa5\x86\x04\xcc\x15\x91\x71\xa0\xbe\x4e\xf0\x55\x9f\x12\xad\x41\x8d\x4a\xc6\x5a\x76\x3c\xc1\x7d\x23\x77\x6a\xf3\x4b\x9d\x5e\xaa\x38\x69\x68\xe3\x44\x89\xbd\xcf\xe5\xac\x1b\x0b\xc3\xd9\x3b\xad\xa3\x33\x3b\xb6\x0d\xb8\xa4\x01\x6d\x8e\xc4\xdc\x9c\xc1\xea\x54\x9a\xd2\xb1\x83\xd4\xc7\xd7\xe9\x27\x86\xda\x34\x77\xb9\x49\xa2\x39\x34\x52\xf3\x0c\x95\x0c\x76\x73\xc1\x53\xb8\x6b\xb0\x79\x9a\x9d\xbf\xce\x1b\xfe\xe7\xb2\xa1\x9b\xf8\xe0\x52\x27\x3e\x3e\x7c\x43\xda\x93\xeb\xcb\x34\x77\xf5\xb6\x7b\x6d\xe8\x0d\xb9\xeb\x44\xf4\xcd\xca\xfa\x3b\x51\x3c\x7c\x30\x07\x03\x76\xba\xcd\x31\xa1\xd0\x22\xc2\xa5\xd5\xf4\xa1\x97\xa6\x0f\xa4\xcd\xd7\x6a\x73\x5a\xd8\x3f\x58\x22\x3b\x7f\x27\x6b\x75\x49\x40\xcb\xbc\xd1\x07\xb2\x9e\xfa\x37\x48\xd5\xc8\x83\x8b\xd1\x44\x16\x3a\x91\x85\xd7\x4b\x64\x8f\x91\xe1\x67\xe5\x87\x1d\x0e\xd3\x28\x96\xc6\xfb\x7a\x29\xed\xfe\x1d\x60\x0f\x96\x1f\xb1\xda\x3d\x9b\xec\x1c\x2c\x98\x23\xca\xee\xa1\x83\x7b\x52\x39\xfc\x8f\x71\xec\x62\xfe\x0a\x18\x9c\x3b\xf6\x04\xab\xe3\xc7\x4e\x65\xe7\x14\xb2\x0d\x81\x30\x0a\x85\xe0\x30\x0a\x87\x11\x34\x7d\xeb\x26\x87\x54\x25\x87\x9f\x7b\x22\x78\x54\xe2\x93\xf6\xde\x83\x04\x76\x54\xd0\xe9\x71\x3d\x9a\x78\xb8\x56\x7f\xd4\x27\xae\xad\xc4\xe0\xf1\x13\x87\xa3\x12\x9f\x74\xb0\x3f\x22\x71\xe8\x87\x93\x6c\x1c\x3b\x15\xd1\x8c\xdf\x5c\x9b\x8c\xd8\xd6\x34\x6a\x0d\xe8\x9f\x06\x2c\xc9\xff\x02\x00\x00\xff\xff\x3f\xc5\x21\x35\xb0\x24\x00\x00")
+
+func fontsNtgreekFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsNtgreekFlf,
+ "fonts/ntgreek.flf",
+ )
+}
+
+func fontsNtgreekFlf() (*asset, error) {
+ bytes, err := fontsNtgreekFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/ntgreek.flf", size: 9392, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsO8Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x59\x4b\x8f\xdb\x36\x17\xdd\xfb\x57\x9c\x85\x16\xdf\xb7\xa8\xd1\xa4\x68\xc0\x00\x69\xe0\xa2\x8b\xa0\x40\x91\x6e\x82\xee\x35\x36\xfd\x40\x3c\xba\x03\x3f\xd0\x4e\x7f\x7d\x21\x3e\xee\x43\x22\x65\x79\x66\x84\x44\x22\x87\xd2\xe5\xe1\x7d\x1e\xd2\xdb\xe3\xf6\x7d\xdb\xe0\x03\x7e\xc6\xbb\x0f\xf8\x11\x1f\x17\x7f\x9e\x0e\xbb\x43\xd7\x1e\xb1\xa5\xee\x82\x87\x67\x7c\xa1\xd3\x86\x3a\xfc\xe1\x3d\x3e\x7d\xfc\x69\xfd\xb8\x3b\xae\x7c\xb7\x5b\xae\xdb\xc7\x65\xbb\x5e\x5e\xbf\x7f\x5e\xfc\x72\xf7\xa5\x66\x39\xec\x8e\xfe\x72\xf8\xb7\xbd\x1c\xa8\xeb\xa7\xfb\x46\xdd\x33\xbe\x5e\x77\xbe\xbb\xe0\x7f\xdf\x96\xb1\xb5\x3a\xaf\x2f\xcb\xdd\x75\xe9\x37\xd7\x65\x7b\xfd\xff\xe2\x2f\x7f\x3a\xf7\xef\xbf\x03\x7e\xc0\x57\xef\x37\x67\x9c\xfc\xf6\xd0\x1d\xba\x1d\xfe\x3e\x5c\xf6\xd8\xb7\xa7\xcd\xc3\xb1\xed\xbe\x9f\xd1\x76\x1b\xac\x8f\xbe\x0d\x83\xd7\x27\xd0\x16\x67\x7a\xf4\xa0\xed\xe2\xb2\xf7\x58\xef\xdb\x53\xbb\xbe\xf8\xd3\x79\x09\x7c\xdb\x7b\x1c\xdb\xf3\x05\x1f\xc2\xdf\xcf\xe8\xbc\xdf\xe0\x42\x78\xf0\xd8\x50\xe7\xf1\x74\xa2\x27\x7f\x3a\x3e\x2f\x5f\xb2\xe8\x8c\xfa\x7d\xbf\xce\xdf\xdb\x0e\xbf\xed\xdb\x03\x3e\x9d\x9f\xfc\xfa\x72\xf2\xab\xeb\xe1\xba\xee\x57\xf8\x19\xbf\x6e\x36\xfd\xb4\x7b\x2f\xeb\xc0\xf6\xf0\x4f\xbf\x94\x80\xf9\x8b\x3f\x3d\xb6\x9d\x86\xfe\x12\x38\x40\xb3\xaa\xde\x56\x0b\x10\x35\x58\x2d\x9c\x73\xae\xe1\x07\x9c\xeb\xff\x98\xc6\xd0\x5f\xab\x30\x08\x7e\x2d\xb5\x90\xae\x1b\xad\x20\x8b\x80\xfe\xde\x8b\x24\xe7\x1c\x51\xb8\xc7\xe9\x1c\x10\x24\xde\x18\x83\xba\x56\xa1\x4b\x14\x50\x22\xc2\x75\x2e\xfc\x8b\x2b\x4a\xbd\xbc\x86\x80\x19\x01\x35\x39\xfd\x66\x1e\x6b\x18\x69\x90\xdf\x43\x5d\x2d\x1c\xe0\x00\x0a\xa3\x01\x4d\xdf\x66\xc5\xf4\xed\x7e\x3c\x0a\x75\xe1\xbb\x32\x52\x0a\x57\x13\xf5\x12\xd6\xe4\xd2\x8c\xbd\xd0\xf0\x2d\xb1\x6e\x11\xa1\xc5\xb1\x30\x98\x94\x31\x10\xca\xd6\x4a\xf3\x8b\xb5\xec\x23\x41\xcd\xef\x46\x04\x0d\xd4\x53\x14\x1c\x66\x0a\xea\x1b\x0d\x44\x83\x3b\x23\x28\x69\x86\xd5\x96\x35\xd3\x2b\x3e\xc9\xee\x4d\x19\xae\xb8\x04\x4a\x46\x09\x16\x4b\x8b\x1d\x68\x2c\x9a\x16\xa2\x30\x80\xf5\xd5\x0b\x4c\xee\x11\x2d\x64\xc7\xc6\xbd\x81\xd0\xb1\x8a\x92\x18\xad\x45\xfd\xa5\x6d\x53\xbe\x9a\xfa\x3b\xa3\x39\xed\x3d\x39\x16\xc7\x8f\x9a\x8d\x74\x50\x69\x83\x12\x3b\x0b\xb7\xb3\x02\x1b\xc1\x26\x9d\x64\x73\xf6\xba\x68\x85\xf0\xad\x23\xf6\x32\x48\x3c\x53\x1a\x6c\xb2\xf1\xd8\xe5\x0b\x2a\xe4\x98\x22\x15\x97\xc5\x26\x87\xf1\x14\x2e\xe4\x6f\xf2\x7b\x64\x05\xf4\x8f\x26\xf9\x51\xb4\x7d\x21\x16\x4a\x42\xd5\xe4\xc9\x01\x63\x62\xe0\x39\xe6\x2c\x16\x7a\x30\x60\x48\x3d\x4a\x59\x10\x9c\xb4\xc2\xad\x11\x93\x8d\x1c\xbb\x17\x4a\xe2\x42\x1c\x80\xd9\x82\x4e\x42\x25\x3a\xca\x7c\xa4\x83\xe5\x57\x85\xde\xb1\x7c\x22\xed\xed\x8e\x75\x2a\x8b\x72\xfa\x43\xa7\x7c\x74\x2a\x06\xc7\x5e\x09\x95\xec\xe3\x95\x54\x43\x73\x97\xaf\x65\x32\xd0\x2c\x92\xc8\x69\xef\xb2\xce\xd5\x0c\x41\xae\x4a\x71\x5a\x8a\x59\x93\x37\x4a\x59\x64\xa1\xe5\x65\xaf\x55\x59\x91\x15\xc4\xc9\x56\x60\x0f\x9d\x30\xd9\x12\xe5\xfc\x33\x3d\x62\xd6\x16\xe7\xca\x03\x7a\x66\x99\x9a\xb5\x4c\x63\x2b\xae\x24\xa1\x1b\x75\xeb\x00\x26\xed\x17\xd6\x13\x6c\x4e\x9f\x16\x4a\xa4\xf9\x06\x34\xfb\x88\x35\xb3\xc9\x15\x32\x64\x85\x32\x41\xe8\x73\x87\x52\x84\x41\xe3\x00\x71\x80\x9c\x5a\x92\x71\xa8\x90\xbc\x4a\x01\x0c\x15\x17\x82\x46\xb0\xc9\x98\x10\x9b\x22\xd2\x2c\x34\xbf\x9a\x94\xda\x14\x72\x44\x26\x28\xe3\x09\x2b\x48\xb9\x94\xc3\x04\x86\xc5\x5d\x40\x7a\x3b\x2b\xc8\x87\xca\x18\x42\x6c\x1c\xb8\x5c\xc8\xf2\x0b\xe9\xfb\x3e\xa1\xa6\xe4\x65\x7f\x9e\xd0\x29\xf3\x4a\x11\xca\xd0\x72\x60\xd3\x78\xc2\xba\x4e\x31\x40\xea\x8a\x1f\x8e\x69\xed\xa4\x4b\x29\x56\x35\x7c\xda\xcf\x64\x69\x4d\x0a\x62\xe1\xb1\xd5\x96\xcb\x41\x19\x67\x93\xb5\x23\x13\x03\x76\x12\x15\x23\x8e\x09\xda\xbc\x25\xb0\x25\x8c\x95\xc6\xbd\xd8\x26\xf1\xb5\x72\x55\x4f\x48\x0d\xd6\x60\x29\xd1\x4f\x64\xc8\x62\x39\x64\xcc\x0d\xc7\x71\x5c\xde\x10\x73\x45\x15\xe1\x03\x2b\x5c\x44\xc3\x39\x2d\xb8\x46\xf6\x27\x4a\x9c\xcd\x96\x77\x94\xb8\xfb\xb2\xce\xbd\x11\x32\x13\xa9\x9b\x42\x1a\x36\x2d\x2f\xc8\x8f\xd6\xbd\x92\x98\x5a\x85\x27\x37\x66\x4d\x5c\x02\x0c\xdd\xe2\x54\x46\xd3\xb1\xac\x08\x8e\xf8\xce\xcd\x6d\x05\xab\xb5\x92\x20\x50\x4d\x65\xd5\x5e\xa6\x2a\x55\xeb\xd7\x84\x8a\xc7\x73\xc4\xcf\xa2\x62\x85\xe8\x8a\x7b\x61\x25\x18\x2e\xef\x8d\xb3\xe8\x01\xcf\xeb\xff\x17\xc4\x97\x50\x0f\x71\x0e\x8a\xb1\x61\xd3\x37\xca\xef\x5c\xa1\x77\x19\xcd\x78\x82\x25\xb7\xce\xb0\xb5\x5c\xd5\x24\x7b\x15\x8b\x5a\x4a\xa5\xec\xae\xb7\x1a\xe1\x65\xc5\xd0\xf8\x74\x40\xe5\x4e\xc0\x12\x38\xee\xeb\x30\xb4\x61\x90\xf6\xf3\x52\x78\x6f\x36\x04\x4b\x74\x0f\xcd\xdf\xd4\x6c\xe4\x84\x3e\xa6\x03\x95\x26\xb1\x46\xb5\xdf\xd7\x1a\x19\x78\xc8\xeb\xfb\x64\x0c\x57\x28\xa0\x86\x4f\x8f\x9e\x03\x93\x0d\xf2\x61\xea\x39\xc3\x18\x64\x82\x30\x84\x9a\x8b\xda\x7a\x57\x62\x61\x77\xf2\xae\x29\xa4\xa3\x5c\xad\x1d\x08\x93\xb4\x33\x5c\x1c\x4c\xf5\x05\x0f\xb7\x7f\xe6\x90\x6e\x12\x29\x49\xea\x8e\x75\xa4\x9a\xc7\x31\x11\x4c\x92\x0f\xd2\x36\x5b\x55\x3a\xdd\xd2\x4e\x79\x4b\x77\xe4\x1a\xb3\x5d\x84\xda\x2f\x52\x33\xde\xdb\x68\x7a\x37\xcb\xca\xf7\x33\x41\xb5\xf7\x22\x39\x4b\x73\xb6\x31\xf8\x56\x9f\xef\xe9\xb4\x58\x7a\x52\x15\x3c\x0c\xa9\x25\xa3\x5a\x37\x93\x03\x56\xe8\xeb\x04\x8d\xb5\x96\x89\xcc\x1a\x56\x8d\x5c\x73\xc6\x7d\x4a\x48\x4b\x78\x0a\x86\xcf\xc4\xfd\xb5\x36\x2a\x7b\x53\x39\x12\xb5\xff\xdc\x3e\x6b\x12\xa4\x34\x46\x5a\xcc\x19\x30\x39\x83\x34\xf7\xab\xfb\xfd\xf8\x3c\xa7\x16\xde\x8d\x2e\x2c\xb1\x94\xcc\xd0\xa9\xc2\x36\x9b\x89\x1a\xa4\x43\xb6\x47\x35\x7e\xc7\xe9\xa4\x42\xc4\xf5\xf1\x9c\x20\xd2\x0d\x14\x82\x69\x68\x0a\x60\x40\x67\x8b\x4e\x03\xe4\xd3\xfa\x9b\x4e\x43\x85\x2d\x98\x11\x53\x65\x1f\x55\xa1\x0a\xab\x15\xac\xe3\x07\xea\x84\x8d\x69\x97\x3e\x05\xb9\x07\xb5\xca\x13\x2b\x3e\x0f\x25\xc5\xe0\x4a\xdb\xae\xd7\xab\x22\x63\x25\x4e\x52\x13\xf1\x23\xc7\x61\xce\x58\x9c\x8f\xd0\x49\x79\x57\xa5\xe8\x68\x57\x96\x10\x8b\x7e\x39\x2c\x3f\x51\x78\xa6\x5c\xcd\x8d\x7b\xa4\x5a\xa4\xd8\xb5\x6c\xda\xe5\x2c\xce\x99\x6d\x3e\x1f\x41\xe7\x42\x90\x5f\x49\xaa\x2a\x15\xfa\xf9\xbd\xb4\x0b\x20\xbd\xb5\xb5\x34\xfd\x45\x67\x66\x90\x4d\xfe\x1b\x6e\x89\xfb\x31\x71\xb2\xb7\xd9\x69\x61\xf0\x33\xde\x9b\x10\xc2\x29\xa1\x2f\xaf\x18\xfc\xea\xdb\xa6\x29\x9d\x6b\x69\xee\xe1\x66\xe8\xb1\x6a\xf2\x8f\x3a\x49\xe8\x7f\x01\x00\x00\xff\xff\x89\xcf\x74\xf8\x80\x20\x00\x00")
+
+func fontsO8FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsO8Flf,
+ "fonts/o8.flf",
+ )
+}
+
+func fontsO8Flf() (*asset, error) {
+ bytes, err := fontsO8FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/o8.flf", size: 8320, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsOgreFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x58\xdf\x6b\xdb\x48\x10\x7e\xd7\x5f\xf1\x11\xca\xc5\xe6\x9c\x6c\x93\x90\x42\x8f\x10\x74\x1c\xd7\xe3\x9e\x0b\x79\x5a\x98\x2a\xb6\x6c\x8b\xca\x72\xb0\x65\xda\xc2\xfe\xf1\xc7\xec\xcc\x4a\xbb\x92\xe2\xa6\x67\x52\x5b\x95\x35\x33\xdf\xcc\x7c\xf3\x63\xbd\xae\xd7\xb7\xc5\x3b\x7c\xc0\x3d\x6e\xdf\xe3\xe6\x1e\x37\x77\xd9\xe7\xb6\x68\x56\xc5\x61\x85\xe7\x1f\xf8\xa7\x2e\x9b\x06\x7f\x6d\x8b\x97\x97\xb2\xae\xf1\x1b\xfe\x2d\xfc\x7f\x2b\xdc\x99\x8f\x77\xb8\xba\xc2\x73\x71\x2c\x57\xd8\x37\xb8\x3e\x56\x1b\xec\xd7\xf8\x74\x28\x9a\xaf\xf8\xbc\x2d\xcb\x43\xd1\x64\x9f\xaa\x4d\x5d\xb6\x38\x94\x75\x59\x1c\x4b\xdc\x5e\xbf\x67\xa1\x3f\x4f\x9b\xd3\xb1\xc5\xfd\x02\x37\x1f\x3f\xde\x65\xd9\xdf\xdf\x5f\xea\xa2\x29\xda\x6a\xdf\xb0\x8a\x75\x75\x38\xb6\xa8\xab\xa6\xfc\x23\x63\x84\xb8\xc2\xc5\xae\xd8\x54\x4b\x34\xa7\xdd\x73\x79\xb8\xc0\x7a\x7f\xc0\xba\xaa\x4b\x54\xab\xb2\x69\xab\x75\xb5\xf4\xc2\x59\x01\x00\x57\x38\x6e\xf7\xa7\x7a\x85\xa2\xfe\x56\xfc\x38\xe2\xb9\xc4\x97\xe2\x72\xe1\x85\x9a\xfd\xb7\xec\x9d\x3c\xd4\x6e\x4b\x5c\x6c\x8b\xc3\xea\xb9\x2e\x9a\xaf\x17\x8c\xeb\xe5\x50\x35\xed\x11\xc5\x11\x05\xfc\xdd\x05\x9e\x4f\x2d\x96\x45\x73\xd9\xb2\x9a\xe3\xee\x74\xdc\x96\xab\xec\x83\x68\xd8\x96\xd5\x66\xdb\x32\xe2\x02\xcb\x6d\x71\x28\x96\x6d\x79\xc8\xee\xcf\x7c\xb9\x40\xb3\x6f\x51\x35\xcb\xfa\xb4\xaa\x9a\x0d\x56\xe5\x71\x59\x36\xab\xf2\x70\xcc\x6e\xdf\x7b\xb1\x5d\xf1\xdd\x7b\x8e\xba\x6c\x36\xed\x16\xb3\xf2\x7b\x78\x78\xb9\xdf\xed\xca\x46\x02\x73\x9c\xe3\x77\x14\x58\x9f\x56\x9b\x12\xeb\x62\xd9\xee\x0f\xd9\xcd\xbd\xd7\xb0\x2a\xd7\xc5\xa9\x6e\x05\xec\x6e\xbf\x2a\xbd\xe3\xed\xb6\x3a\x62\xbd\x6f\x5a\xcc\xea\xea\x6b\x89\x8b\xab\x1d\x6e\xee\x2f\x38\x73\xac\xb7\x68\x56\x5e\xef\x3c\xbb\xb9\xf3\x5a\x24\xd2\x0c\x3f\x31\x9b\x65\xef\xf2\xc1\x5f\x9e\x01\x20\xf0\x87\x81\xcd\x33\x18\xc0\xe4\x99\xb1\x64\x90\x67\xd6\x00\xfe\x3b\xfe\xc8\x33\x90\x7f\x74\x06\x87\x79\x9e\xe1\x09\x4f\xdd\x97\xe9\x87\x6a\xe5\x3f\xbe\x47\x0e\xce\xc1\xb1\xac\x23\xe0\xfa\x1a\x20\x27\xd7\xfc\xe2\x6b\xc0\x91\x73\xe4\x3a\x1d\xbd\x22\xf2\xf7\x1c\x1c\xf2\xcc\x80\x68\x9e\x67\x96\x88\xc1\xce\xe0\xc1\xb2\xa8\xc2\x03\x51\x9e\xcd\x68\x6e\xfc\x7d\x18\xb0\x17\xfc\xc1\xb6\x0d\x99\x19\x4b\xc7\xba\x49\x21\xce\x40\x98\x43\x1e\x26\x58\x63\xf3\xcc\x61\x46\x8f\xc0\x43\x9e\xc1\x12\x91\xb1\xa6\x87\x26\xd6\x18\xc1\x3c\xcf\x9c\x11\xd0\xd1\x9b\xe8\x16\xd3\xac\x89\xb1\xc7\xef\xb0\x64\xf3\x3c\x23\xef\x9b\x85\x55\x0f\xd3\x77\xc3\x39\xe8\xe0\x66\x0c\x81\x75\x5a\x88\xdb\x86\xdd\xe5\x94\x81\xd3\x94\xb8\xd5\x27\x23\xca\x40\x08\x7f\x1f\xef\x28\xd8\xf9\xd0\x83\x81\x7f\xa9\x56\xbd\x20\x7e\x79\xad\xfc\x72\x13\xcf\xbc\xa2\x55\xb3\xa0\x5a\x7d\xa0\x80\x51\xce\x20\x39\xc3\xc0\x39\x92\xa8\x49\xa2\x34\xa2\x3e\x5e\xce\xfb\xe4\x42\xbe\x52\x18\x9e\x00\xfa\x54\x78\x53\xc8\xb9\xba\x02\x75\x45\xd2\xc1\x4c\xf3\xca\x98\x73\x66\xca\xcb\x41\x04\x04\x37\xc7\xd9\x6a\x70\xe6\x62\x65\x0a\x8c\x26\x46\x0a\xa3\xbf\x52\x5d\x5d\x92\x06\x59\x4a\xa1\xf2\x95\x4b\x30\x9f\xb3\x89\x40\x75\x5f\x0d\x5e\xfe\x32\x04\x70\xa6\xae\x4e\xc5\x2d\xf6\x10\x2e\x64\x0a\x21\x55\x5e\x63\x92\xa4\x34\x4b\x52\x58\x49\xba\xce\x58\x9b\x48\x6e\xf4\xf4\x22\xd8\x1f\x89\xa5\xcc\x1a\x73\x6c\xfc\x75\x4c\xec\xbe\x52\xc5\x33\x2d\x48\x2b\xd5\x35\xa8\xa9\x11\xe9\xcf\xb1\x3f\x29\x70\xab\x0d\xd6\x68\x69\x67\x51\x8c\xa5\xb7\xf1\x03\xd6\x68\x21\x58\x79\x64\x36\x1f\xb4\xd5\x10\x22\x4f\x4c\xd1\xcc\xb0\xe9\x8b\x12\x1b\xb3\x50\x05\x3e\x66\x82\xcc\x2a\x23\xe2\xa6\x00\x43\x56\x82\x6d\xc8\x5a\x8f\x80\xbf\x62\x0c\x64\x60\xc9\x0c\x62\x2c\x30\xc5\xae\xf7\x84\xc8\x1a\x1f\x34\x6e\x40\x5e\xcc\x5b\xf9\x99\x18\x84\x2d\xcc\x43\xff\x95\x9d\x62\x6b\x2f\xe7\x1f\xb7\xca\x37\xeb\x63\xc3\xa2\xc6\xf8\xf6\x40\xb4\xb8\x1c\x56\x88\xe7\xba\x38\xa8\x40\xbd\x9f\xc6\x68\x3a\xd8\xda\xa0\x61\x8e\x41\xaa\x8c\xb7\x1e\x46\xe1\xa8\xb5\x45\x62\x21\xb9\x64\x85\x47\x12\xd2\x57\x7c\x0b\xaa\x8c\xe5\x7f\xc1\x23\x61\x20\x83\xd4\xe1\x6b\x62\xa0\x7d\x85\xa8\x51\x4b\x21\x30\x3e\x32\x7e\x6c\x87\xe2\x56\xbb\x53\x81\x91\x7b\xca\x49\xb9\x62\x00\x56\xec\x4f\x56\x65\x8c\x37\xc0\x35\x14\xd0\x5a\x0d\x8f\x1d\x89\xf5\x4c\x35\xc0\x2f\xa4\xbe\x37\x67\x94\xa1\x02\xd4\x4b\xf2\x3d\x1b\x12\x32\x1c\xca\x88\x92\x6f\xbb\x8a\x63\x68\x92\x15\xab\xb1\x25\x9b\x4c\xcd\x51\x3e\x49\x69\xc0\xeb\x90\x50\x5c\x08\x67\x07\x61\x7d\x9d\x06\x73\x0d\x4f\xbf\x48\x4d\x89\xf5\xe6\xd0\xd9\x43\x30\x88\x60\x71\x41\xf6\xd5\x4c\x32\xc7\x25\x44\x56\x4a\xc2\xd7\xb0\xd8\xb4\xe3\x6e\x0e\x4d\x00\xd3\x5b\x5b\x93\x6c\x17\x72\x15\xaa\x63\x7a\x08\xf8\x02\xea\x6b\xd1\x44\x29\x85\x35\x13\x1e\xea\x2d\x4f\x1b\xad\x26\x49\x1e\x7e\x4a\xb7\x20\x08\x11\xf5\x84\x0d\x83\xc7\xe2\x09\x21\x0b\x36\x85\x1b\xfb\xa9\x6d\xd5\x74\x54\x90\xa4\x5b\xb5\x8c\x8e\x0e\x08\xf7\x87\xdb\x27\xe9\x4a\x69\x63\x21\x25\xa4\x95\xf5\xa4\x9b\x12\x3d\x78\xd9\x9f\x7d\x43\x04\x49\x90\x74\xa0\x98\x64\x9b\xe6\x97\x26\xcc\x68\xe3\xd7\x2a\x61\x61\x93\x34\x53\xf5\xca\x8f\x7d\x37\xb5\x52\x3a\x9e\x41\x82\xb8\x4f\xac\xc6\x4d\x83\x66\x43\xc4\xec\x58\x2b\x0d\xb7\x4f\xdd\xa9\x44\x6b\x9f\x0e\x9e\x9a\xd6\x75\x77\xfa\xf7\xc9\x0d\x71\x7c\x31\x1c\x9f\xf1\x3c\x86\x2a\xce\xd3\x45\xba\xd3\x41\x72\xfe\x88\x86\xdd\xac\x5f\xf8\x16\xc3\xd5\x4c\xc5\x78\xab\x1a\xee\x3b\x2e\xac\x49\xd7\xd3\xe4\x0b\x9b\x88\x6e\x7f\x6a\x8a\xa0\x7c\x75\xc3\x84\x93\x4a\xb8\xb0\x30\xfe\x1c\xde\x84\x1d\xf8\x43\x07\x24\xe9\x63\x3b\xdd\x73\xba\xea\x42\x9e\x96\x45\x76\x70\xf6\x7a\x5b\xc4\x24\xcd\xdd\x62\x70\x36\x62\x81\x0e\x7e\xc9\xce\x87\x9b\xb5\x5f\xac\xa6\x37\xeb\x10\x1d\x5d\xc8\xc4\xba\x7e\x90\x51\x8e\x45\x00\xc4\x1a\x17\x86\x83\xd3\xe3\x13\xf0\xe0\x29\xe3\x86\xd4\x45\x62\x75\x6c\x3a\x6a\x25\xe4\x83\x11\x39\xf6\x25\x3d\x3f\x24\x0e\x26\x4e\x8e\xc2\x4a\xf8\x95\xf8\xa4\xa9\x7e\xfb\x2a\x7c\xce\x9a\xf2\x17\xd7\xe1\x68\xe2\xfe\x57\xee\xe5\x80\x11\xd3\x91\x42\x93\xb9\xa4\xd0\x66\xd0\x19\x18\xf7\xb9\x7e\x75\xe5\xa7\xf5\x58\xee\xa2\xbe\x15\xd2\x1a\x51\x96\x22\x02\x33\x14\x37\xc5\x5c\x52\xde\x4c\x1f\xee\x26\x8b\x09\xda\xfc\xb4\x5f\x23\x34\xec\xa7\xd0\xe2\x27\x06\x77\x2a\x19\x0b\xc7\xf2\xb1\x8a\x54\x4b\x5a\xcc\xa3\x69\xf1\x28\xc4\x9d\x9e\x12\x6f\xf1\x73\x50\xa1\x7d\xd0\x49\xce\xf2\x61\x02\xcb\xb4\x48\x23\x29\xc7\x6a\x01\x22\x23\xe2\x01\x0f\xd1\x6f\x29\xd0\x1f\x21\x26\xab\x28\x94\x92\x46\x46\xe7\x49\x24\xfb\x88\xc7\xfe\x57\x19\x1f\x93\x1e\x9f\xb1\xc6\xf9\x39\xd1\x8f\xbb\xf4\x23\x72\x7c\x46\x73\x92\xd6\xd0\x57\x05\xe4\xa4\x39\xdd\x6c\x5e\x17\x3b\x7b\xfa\xef\xc4\x10\x7a\xd5\x9b\x7e\x34\x98\xb0\xf6\xb6\xd1\xf3\x1a\xc8\x73\x47\xed\xb7\x81\x1c\x59\xa3\xb0\x17\xe8\x04\x09\x5d\xd3\x59\xa9\x46\xe7\x92\x35\xe2\xbf\x00\x00\x00\xff\xff\x49\xee\xa5\xb3\x37\x16\x00\x00")
+
+func fontsOgreFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsOgreFlf,
+ "fonts/ogre.flf",
+ )
+}
+
+func fontsOgreFlf() (*asset, error) {
+ bytes, err := fontsOgreFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/ogre.flf", size: 5687, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsPawpFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\xcf\x6e\x23\x37\x0f\xbf\xcf\x53\xf0\xe0\x83\x74\xf8\x02\xe4\xc3\xb6\x40\x6e\x06\xf6\xd4\xbe\x40\x8f\x84\xb3\x6b\x17\x06\x12\x27\x88\xed\x2e\xf2\xf6\xc5\x48\x94\x48\x4a\x94\x46\x63\x07\x35\x60\x9b\x33\x23\x91\x14\xff\xfc\x48\x69\x0e\x2f\x87\xff\xef\x36\xf0\x04\xbf\xc3\xe3\x6f\xf0\x08\xdf\xa6\xf7\xdd\xaf\xf7\x87\xc3\xcb\x01\x9e\x3f\xe1\xfb\xf5\xe3\x72\x3c\xc3\x5f\xbb\xd3\x69\xff\x01\xee\xc7\xaf\x40\x6c\x77\x3f\xce\x0f\xcf\xd7\x87\xfd\xcf\xab\x9f\xdc\xeb\x27\x1c\x8e\x1f\xe7\x0b\x1c\x8e\x7f\xbf\xec\x2f\x70\x78\x3b\x5d\x1e\x00\xfe\xb8\xc0\xf1\x0c\xcf\xbb\xf3\xfe\x27\xbc\x9d\xe0\xfd\x7a\x38\x7c\x26\xb6\x7f\x5e\x77\x27\xf8\xbe\xfb\xf0\xd3\xcb\xee\x7c\xd9\x9f\x2f\xf0\xb1\xff\xe7\x78\x3e\xbe\x9d\xe0\x7f\x70\x7e\x7b\xdd\x5f\x8e\xaf\x7b\x38\x9e\xe0\xf1\xe9\xe9\xdb\x34\x6d\x36\x9b\xed\xe8\xcf\x76\x02\x84\xed\xe4\xd0\x57\x3f\xfc\x00\x00\xe2\xcf\x76\xda\x40\xfc\xcc\xd3\x01\x01\x00\x03\xe9\xd0\x83\x43\x5f\x90\x72\xec\x30\x19\x24\xf1\x27\x5e\x22\x7d\xe7\x4b\x44\x87\x3e\x7c\xa3\x82\xfc\xf1\x8b\x4f\x01\x48\xbd\xcc\xb9\x10\xc4\x97\x2c\x78\xa6\xd0\x81\x0f\x94\x43\x3f\x4f\x0f\x96\x41\x20\x43\xcd\x77\x82\xb8\x79\x90\x03\x2f\xc7\x91\x4c\xc1\x5f\x2f\x31\x18\x3a\x7e\xc8\xe0\x81\x4c\x86\x8f\x24\x4d\x47\x7a\x9a\x64\xea\x39\xc0\x73\x8c\x25\x29\xa9\xc1\x50\x88\x64\xd2\x68\x25\x4f\xb4\xcf\xcb\x81\xf0\xc0\xc7\x90\x80\xd9\xa4\xb4\x24\x71\xdf\x96\x16\x22\x65\x76\x2b\x6e\x82\x55\xb6\x93\x8b\x11\x61\xff\xd0\xd4\x60\xe8\x24\x38\x84\x61\xb2\x34\x69\xe9\xf9\x99\x14\x29\xe6\xcf\x4b\xaa\x87\x46\x4d\x15\x53\x6b\xbe\x5c\x09\xfb\x84\xbc\x8e\xc9\xfe\xcb\x41\x86\x14\x64\x79\x6e\xf2\xce\x58\xcc\x95\x8f\x38\x12\x59\xb6\x94\xcb\x81\x6d\x4c\xab\xc8\xb6\x17\x2c\x6f\x89\xa8\xb5\xa9\xa8\x02\x6b\xe3\x17\x67\x0c\x2b\x32\xf3\x2a\x43\xa4\x5a\x0f\xf2\xc5\x70\xce\x80\xc8\x99\x2a\x4d\x1a\x39\x13\x63\x13\x93\x4b\x51\x84\x66\x82\x4c\xa6\x10\x73\xc4\xa1\xf2\xba\x01\x02\xc4\x38\xb1\x8d\x0c\x1c\x3b\xd5\xfc\x17\xac\xaa\xa0\xc9\x5a\xa2\x52\x33\xc5\x6e\xb2\x02\x45\x75\x4e\x98\x52\xd5\x22\x68\x96\xed\x80\xa9\x6a\x70\xda\xae\xb1\x03\x08\x2c\x44\x76\x51\x4e\xfe\xc8\x4c\xe5\x5b\xb2\x85\xc4\xd7\x02\x6b\x2b\x58\x92\xa2\x50\xad\x3e\xeb\x5c\xdc\x0b\xe3\xc8\xb3\x63\xeb\x48\x36\x12\x46\x52\xdc\x99\x3d\xe6\xbb\xc2\x50\x23\x6e\xe0\xd4\xab\x91\xa0\xe1\x6a\x9a\x26\x72\x60\x40\x46\x67\x1d\xa5\xc6\x37\xaf\x63\x85\x0c\xed\xe1\x2e\xe4\xf5\x40\xc5\x82\x97\x85\xd1\x36\x2a\x26\xb8\x61\xa8\xc9\x30\x43\x1d\x42\x1c\x43\x91\x0b\x45\x91\x66\xa2\x89\xdb\xb6\x93\x9b\xae\x1f\xf2\x6c\x6e\x39\x1a\x3a\xd6\xeb\xd0\xca\x6a\xad\x29\xa2\x03\xdc\x78\x54\xa0\x08\xb2\xec\x89\xcc\x4c\x22\xab\xce\xa8\x09\x0b\x49\x4e\x0a\x6b\x59\x5c\x31\x37\x64\x11\x41\x19\xda\x30\x8b\x29\xa3\xb1\x05\x0b\x23\xf1\x28\x4c\x1e\x4d\xe3\x0a\xb2\x6f\xfd\x1e\xf4\x14\x30\x63\xdd\xeb\xdb\x2a\x55\x00\x76\x89\xf0\x89\x54\x14\x4a\xe8\x21\xdb\x0d\x55\x00\x5b\xfd\x4e\x25\x1c\x54\xdf\xee\x27\x62\xbf\x93\xc5\x71\x3d\x58\xee\x3b\x6e\x64\x4d\x33\x98\x5a\x36\x7a\x23\x66\x52\x6d\xcf\xc1\x79\x0f\xde\x03\xa8\x86\xdf\x15\xdc\xee\x8d\xcb\x5e\x4d\x11\x50\x9b\xc9\x56\x27\x3a\x26\xc3\x6a\x3b\x52\x7b\x9d\x49\x07\xe5\xa6\x63\xb0\x6e\xa5\x36\x42\x74\x11\xbc\xb7\x11\xee\xce\xae\xf1\xc5\xd8\x61\x7f\x14\x35\xb5\x49\xb6\xd6\xdc\x91\x91\x22\x8b\xc0\x8f\xb6\x30\x28\xb6\x45\xf4\x35\x2e\xa0\x48\xf7\xf1\xcd\x61\x3b\xd2\xf2\x8e\x37\x76\xa8\x32\xdb\x57\x46\x9a\x4c\x19\x99\x33\x52\x62\x4d\xa3\x8e\x85\xc1\x4e\x4f\x00\x96\xdc\xeb\x32\x3c\x55\x77\x0d\x07\xfe\x17\x0b\x72\x2a\x2a\xca\xdd\xf5\x4d\xf5\x03\x3c\xcc\xdf\xb2\x26\xc3\x3d\xad\x2b\x55\x0a\xcc\x63\xef\x6d\x5d\x01\xa1\x07\x33\x2d\x72\x51\x46\x20\xcc\xe2\x67\x90\x5f\x0b\xc9\x16\xf8\x26\xf4\x59\x53\x6b\x35\xd0\x64\x39\x08\x8d\xac\x97\x17\xe9\x8c\x82\x60\x03\x5c\xd9\x02\x8d\x42\x00\x84\x35\x40\x7b\x0d\x49\xf2\xea\x62\x63\x59\x4f\xc9\xf8\x82\x28\x68\x75\xca\xcd\xfd\xf0\x8a\x82\x16\xf9\xd3\xf8\xe4\x6e\xf9\x27\x9e\x49\x1e\xc5\x81\x93\x70\xb1\x6c\xca\xf3\x0c\xbe\xce\x2d\x35\x4a\x8d\xf2\x51\x13\xe4\x6b\xa8\x24\x18\xae\x2e\xd5\xcf\x9e\xe3\xfe\xbf\xa5\xfe\x26\x04\x61\xd8\x0e\xcd\xd2\xe2\xc1\x2f\x86\x63\xdf\x1c\x83\xf1\x4c\x77\x33\x44\x6c\x27\x20\x12\xbe\x84\xb4\xdc\x5e\x9d\x72\x6d\x9c\x5f\x3c\x93\x34\xf7\x3d\xe9\x0c\x24\x77\x25\xb1\x53\x49\x39\x82\xbe\xbf\xc7\xd3\xfb\x2f\xe5\x73\xb2\x37\x72\xb7\x92\x7b\x95\x05\x8e\x16\x41\x3a\xa2\xea\x3c\xa5\xd6\x8b\x1c\x8b\x5d\xab\x3e\xd0\x11\x3a\x8e\x73\x6c\x98\x4f\x2c\xd6\xaf\xd1\xd1\x62\x84\xa2\xc3\xd3\x26\x6e\xd8\xea\x16\x5f\x77\xec\xe0\x07\x7c\x5d\xeb\x28\x41\xbc\xa5\xa3\x7a\x2b\x63\xbc\xb8\x49\x33\xda\x2b\xaa\x8f\x21\xf4\x9d\x5c\x5a\x60\x70\x45\xa9\xc9\xe6\x46\xca\x17\x77\xba\x2b\x22\x14\x02\x75\x6a\x5f\xff\x2d\x82\x68\xff\x62\x7d\x0f\xdd\xe4\x66\x5a\x56\x1e\xa7\xdc\xe6\xd9\x6e\xf4\xe5\x66\xcc\x83\x11\x6b\x6b\x39\xaa\xde\xd1\x9b\x48\x53\xe5\xcc\xdd\x19\xa2\x62\xce\x05\x34\xd6\x7c\x92\x15\x93\x11\x93\x36\x49\x07\xfe\x2f\xe6\x59\x8c\xb0\x64\xc0\x40\xe8\xf9\xbe\xcd\x88\x14\x29\xeb\xb7\x2e\xea\x9d\xb7\x50\x2d\xab\x8b\x56\xc7\x99\x98\xb1\xda\x8f\x6d\x8e\xc5\xc1\x9a\xc1\x11\x96\x72\x06\xf3\x6b\x57\x92\x00\x5f\xd1\x5a\x36\x28\x14\xbb\x75\xd1\x60\xea\x0d\xba\x39\xf7\x2e\xa3\xd7\x45\xcd\xb7\x12\x5c\x75\x13\xfc\x96\x2f\x75\x8d\xfa\x51\xdf\x8d\x48\x88\x4b\x21\x24\x8e\x24\x3c\x37\x7c\xa0\xc6\x18\x1c\x2d\xf4\x6f\x54\x04\xbd\x10\x80\x5a\xda\xa2\x46\xed\x30\x62\x78\x0d\xc6\x00\xc6\x92\x3a\x2e\x56\x91\xda\x7d\x6a\x6b\xdb\xb8\x33\x00\xb4\x5d\x8e\xc5\xfc\x7a\xcc\x02\x47\x2e\xa1\x55\xd0\xad\xe1\xd8\x8e\xde\x4e\xdf\x34\xdf\x59\x2e\x2f\x36\xc7\x7b\xca\xcb\xd8\xf2\xef\x2f\x58\x2a\xc3\x64\x73\xe1\xaa\x3b\xc4\xf1\xdf\x00\x00\x00\xff\xff\x15\x86\x8b\x9b\xab\x23\x00\x00")
+
+func fontsPawpFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsPawpFlf,
+ "fonts/pawp.flf",
+ )
+}
+
+func fontsPawpFlf() (*asset, error) {
+ bytes, err := fontsPawpFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/pawp.flf", size: 9131, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsPeaksFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\x4d\x6f\x24\x35\x10\xbd\xcf\xaf\xa8\xc3\x5e\xc1\xcb\x08\x89\xe5\xd6\x1c\xc8\x85\x0b\x0a\x77\x2b\x41\x9a\xa0\x48\x11\x48\x90\x0b\xfc\x7a\x34\xd3\xb6\xeb\xbd\xaa\xe7\xee\x99\x21\x22\x9b\xed\xb6\xbb\xed\xfa\xae\x57\xe5\xce\xcb\xdb\xcb\xf1\xf9\x93\x7d\xb1\xef\xec\xf8\xd9\xbe\xfa\xc6\x8e\x87\x9f\x7f\xfc\xe1\xa7\x5f\xec\xd7\xbf\xed\xf1\x8f\xdf\xed\xe1\xcf\xd7\xf7\x7f\xec\x4b\xf9\xfe\xdb\xc3\xc3\xeb\x6f\x6f\xa7\x77\x7b\x3c\xbd\x9d\x9e\xff\x3a\xd9\xf1\xeb\xcf\x87\x4f\x8b\xf8\xb5\x65\x39\x94\x5a\xf9\x62\xed\x62\x66\xed\xd9\x79\x74\x79\x58\xea\xb8\x99\x5d\xde\xef\xdf\xda\xbd\xff\x9c\xa7\xa5\x56\x6b\xd7\x0b\x87\xf3\x8f\x5d\xee\xe9\xed\x8d\x8b\x91\xd1\x65\xde\xdf\x5c\xa4\x5e\x55\xab\x41\x8e\xb6\xaf\x9b\xa0\xad\xcb\x54\x51\x93\x46\x67\x2c\x85\xb5\x4e\xb4\xb1\xba\x70\xaf\x7a\x1b\x49\xea\x6b\x87\x2c\xbe\xbf\xfa\xf6\xb0\x0e\xf6\x3a\xc1\xf5\x4d\x73\xd4\xfc\xd2\xc4\x6c\xe4\x1a\xfd\x78\x1b\xf2\x76\x76\x9d\x83\x7a\x49\x37\x22\xca\x46\x0c\x9a\x8c\x4b\xd7\xa7\x39\xac\xfb\xdc\x9a\xe7\xc5\x7b\xb1\x9f\xe9\x8b\xb0\xc0\x68\xb4\x1c\x08\xdd\xd6\x9d\xed\xd6\xb2\x4c\x0d\x19\x6d\x5c\x86\x8b\xfa\xb6\x7c\x27\xee\xe2\xfd\x4d\x9c\xd8\xf8\xa0\xc5\x1d\x11\x1c\xb4\x0d\x49\x0e\x04\x91\x10\x46\xd5\x60\x3d\xc8\x79\xc4\xa0\x58\x2d\xf2\xa3\x1f\x97\x01\x32\x21\x0c\xd5\xad\x80\x11\x49\x52\xc7\x85\x95\x92\xb0\x0d\x5a\x04\xed\xe0\x58\xc4\xb9\x2c\x50\x42\x18\x96\x83\x93\x70\xa6\xa7\x7e\x8d\xe1\x25\x6d\xcc\x61\x58\x70\x06\x9a\x81\xf9\x21\x9f\x72\xb6\x68\x1b\x93\x26\x95\x23\x20\xb8\x47\x6b\xa2\xf1\x4e\x06\x0b\x5a\x1b\x23\xd0\xfd\x93\x83\xa8\x2f\xcb\x45\x20\x38\xbb\x8c\xda\x81\x6a\x27\x67\xb3\x49\x27\xe3\x2d\x4d\xfa\x44\x07\xbd\xb9\xbc\xa6\x35\x01\x53\x6c\x39\x3f\x39\xd8\x6d\xce\xda\x95\x2a\xa1\x8b\x8d\x2d\x9d\x3f\x47\x92\x80\x29\xbb\x0b\x01\xe6\x86\xfd\x43\x89\x8f\xd8\x82\x52\x8a\xc8\x12\xb6\x81\x41\xa9\x04\x9d\xf2\x49\x1a\xdc\x2e\xc0\x8e\x0a\x44\x38\x10\x5b\x0e\x99\x94\x7b\xd2\x77\xcb\x67\xa1\xaa\x0d\x0a\x98\x38\xc6\xed\x0f\x54\xc8\x96\x2d\x85\x41\xf7\xe9\xe9\x29\x61\xb7\x6e\xaa\x3c\xca\x21\xa4\x2c\x20\x81\x0a\x33\xaa\x2c\x3d\x19\x19\x57\x63\x59\x48\xee\x26\x5f\x31\x76\xf7\xad\xbe\xab\xc1\x4f\xc2\x77\x4f\x11\xe8\x2f\x54\x6a\x87\x0c\xa3\xc6\x8c\xdc\x1d\xc6\xb8\xde\x46\x56\x07\x06\x03\xe6\xc7\x66\x52\x1e\x99\x4d\xc6\x50\xe0\x12\x68\x2c\x50\xa2\x22\x68\xc3\xb0\x4b\xb6\xb9\x20\x26\xdc\x87\x10\x4e\x11\xb6\xa0\xad\x7a\xd8\x8a\x88\x90\x93\x5e\xe5\x87\x91\x20\xce\x04\x9c\x06\xc4\xdc\x98\x78\xd1\xb8\x72\x4f\x62\xb4\x77\x81\xc4\xa2\xee\x63\x6f\x54\x2a\xf6\x4d\x35\x9e\x56\x20\xe7\xe0\xe0\x41\x6d\x49\xcb\x8b\xc2\x6e\xc1\x65\xb3\x8a\xab\x6c\x79\x8d\xb3\x6f\x0d\xb3\x36\xe9\xfa\xba\xaf\x5d\x8b\x02\x3e\x60\x90\x1b\x38\x24\x48\xd1\xd4\x2c\x69\x54\x35\x5f\x30\x1e\x73\x65\xa6\x9c\xaf\x46\x2c\x13\x47\xc7\x9a\xdc\xf9\x04\xeb\x67\xf9\xf5\xdc\xb0\x25\x30\x45\x5f\x68\x1c\x32\x56\x61\x4e\xce\xea\x2d\x10\x9c\x6a\x18\x14\xdc\x73\x4f\xf2\x56\x19\x1d\x2c\x14\xac\x98\xe7\x67\xdf\x93\x66\xac\x9b\x9a\x59\x0c\xcf\x58\xd7\xa3\x3b\xb4\x2f\xbb\x34\x6c\xbe\x50\x55\x43\x55\xcf\xd0\x8f\x74\x92\xaf\x8c\xfb\x19\x26\xf6\x31\x33\x62\x98\x9d\x71\xf7\xe4\x0a\x54\x16\x36\x1b\xce\xc6\xc0\xd6\xcd\xc5\x48\x48\x56\x2d\x04\xbf\xaa\x40\x4a\x90\x8d\x7c\x2b\xdc\x13\x24\x90\x40\x60\xf0\x62\xa6\xf3\x75\x26\x00\x9a\x61\xa8\x5c\xa0\xf7\x41\x5d\xd2\x3b\x09\xe1\x32\x6a\x25\x43\x32\xfa\x8c\xe1\x2d\x33\x66\x98\x0e\x64\xe0\x54\xe1\x51\x33\x71\x68\x29\xa1\x15\xa8\xa2\x94\x00\xc3\xa6\xe8\xee\x2d\x7d\xea\x0a\xec\xe2\x01\x21\xc9\x0a\x29\x35\x3d\xb7\xe0\x67\xcc\xed\x9b\xf8\x86\x51\x18\x4a\xcb\x4e\x99\xbe\x67\xd2\x67\xb7\xdf\xdb\x97\xab\xd1\xe5\xe4\x13\x22\x5f\x08\xe1\xe2\xd8\x35\x1d\x69\xa6\x1a\xe6\x10\xab\x35\xa3\x26\x48\x37\x19\x92\x15\xb9\xd1\xa6\x05\xd9\x46\xe1\x40\x59\xb0\x1b\x1d\x6c\xe0\x89\xaf\x61\x42\xf3\xbe\x0f\xc1\x44\x76\x80\xec\xf4\xeb\x6d\x1a\x0f\x12\x74\x44\x32\xef\xa3\xa7\x45\x7d\xe9\x07\xce\xf3\xb6\xf1\x07\x02\x42\xab\xc9\x20\x49\x1a\x87\x8c\x64\xd1\x23\xf0\xb4\x1b\x8a\x32\x13\xac\x71\xf0\xcc\xc5\x11\x7d\x86\x49\xd6\xad\xa6\x6c\x8a\x5f\xd6\x77\xfa\xf9\xa1\x84\x9c\xcb\xfb\xda\x7b\x2e\x33\x81\xc3\x21\xbe\x99\xbc\x52\x04\xcf\x44\x1f\x36\x9b\x5f\x3d\x26\xf5\x47\x06\x23\x83\x8e\x0a\x07\x1e\x0a\xae\xd1\xd3\x55\xc9\x12\x85\xdc\x0e\x87\x12\x3f\x18\xa4\x18\x20\xf3\x24\xe2\x77\xa3\x4c\xa0\x2e\xfb\xb7\x14\x6f\x28\xb7\xe3\x8a\x13\x8e\xa8\x22\x1d\xae\x09\x1a\xe0\x0a\x12\x74\x47\x14\xea\x8c\xc7\xa8\x4e\x3e\x96\x45\xb8\xca\x83\x12\xf2\x5f\xe3\x5e\xa9\xf4\x89\xb8\x23\x87\x01\x52\x44\x9c\x5a\x14\x30\x5c\x87\x22\x54\x5c\xe7\xc6\x8f\x47\x35\x3d\xb2\x66\xb6\x09\x80\xc6\x32\xc9\x75\x56\x16\xa0\x21\xa4\xe8\x63\x74\x9d\x15\x9c\x98\xd5\xe0\x55\x19\xf6\x7d\xb6\xfe\x42\x0a\x58\xaa\x85\x3b\x19\x86\x88\x0e\xc1\x6e\x5e\x2d\x42\xd1\x9d\x64\xd8\x94\x70\x09\x7f\x64\xad\xb9\x6f\x0a\xe1\xb7\x4d\x98\x02\x2a\xa4\xe7\x12\xbe\xcd\xaa\xaf\x0c\x16\x0e\xcd\x14\x87\x7c\x5c\x0d\xb5\x2b\xc4\xf1\xfa\x35\x71\xfd\xbf\xee\xa6\xf9\xb5\xe4\x36\x84\x70\x4e\xd5\xe0\xaf\xbe\x02\x47\xff\xd3\x78\x39\x84\x7f\xff\xd7\x83\x7f\x03\x00\x00\xff\xff\x75\x29\x6c\x29\xe4\x20\x00\x00")
+
+func fontsPeaksFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsPeaksFlf,
+ "fonts/peaks.flf",
+ )
+}
+
+func fontsPeaksFlf() (*asset, error) {
+ bytes, err := fontsPeaksFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/peaks.flf", size: 8420, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsPebblesFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x59\xcd\x6f\xdc\xb6\x12\xbf\xef\x5f\x31\x07\x01\x4a\x00\x3f\xbe\x97\x87\x87\x97\xb4\x28\x0a\x5f\x1a\x34\x40\x81\x29\x7a\x29\x7a\x93\xbc\x4b\x7b\x05\xaf\x77\x8c\x95\x36\x4e\x7a\xe8\xdf\x5e\xf0\x63\xc8\x21\x45\x6a\xe5\xd8\x4d\xdd\x15\x49\xf1\x63\x3e\x7f\x33\x1c\xdd\x1e\x6e\xff\xdb\x37\xf0\xee\x3f\xf0\x01\xde\xfd\x1f\xfe\xf5\x0e\xde\x6f\x7e\xd5\x37\x37\x07\x3d\x5e\xc1\xed\x70\x77\xd0\xd3\xf0\xa7\xde\xc1\xcd\x57\xf8\xe9\xe1\xb1\x9f\xf6\xf0\xc3\xbe\xdf\xe9\xf1\xfa\xac\x9e\xfa\x71\x3f\x1c\xef\x26\x3a\x2a\xbd\x3b\xff\x08\xef\xff\xfd\xdd\xff\x36\x5b\x7a\x78\x3c\xe8\xc9\xad\xf8\xed\x6b\x7f\x84\x3f\xe8\xbc\xbd\x87\x37\x5f\xcd\xe3\x7a\x3b\xaa\xf3\x49\xdf\x0d\xc7\x5e\x6d\xfb\xb7\xf0\xc1\x2c\xf9\xeb\xe3\x89\x1e\xbe\x87\xdb\x83\xd6\xd7\xdb\x51\xab\xc7\xf1\x6c\x36\x84\x37\x1f\xf5\x61\xf8\x02\xbf\x68\xfd\x76\xf3\xb3\x3e\xe9\x76\x84\xfe\x08\xfd\xb8\x1d\x06\xb8\xa5\xe3\x04\x9f\xda\xcf\x1a\x6e\xb4\x3e\xc2\x13\x9d\xee\x87\xe3\x1d\xd0\x51\x01\x7c\x82\x71\xea\x4f\x86\x84\xa7\x61\xda\xc3\xb4\xd7\x30\xec\x74\x0f\x74\xbb\x39\x8f\x66\xd6\xcd\xd9\xf2\x07\x6f\x14\x10\xe0\x5b\x98\x08\x6e\xce\xc3\x61\x07\xbd\xdd\xf7\x0a\xdc\x34\xb3\xf0\x81\xa6\xe1\x16\x14\x21\x29\x98\x68\xa3\xbf\x3c\x9e\xf4\x38\x42\x0f\xdb\xf3\xe9\xb3\x56\x00\xbf\xef\xf5\xd1\x9c\x78\xaf\xa7\xed\x5e\xef\x80\xce\x93\x5d\x78\xa0\x27\x7d\xda\xf6\xa3\x86\x83\x9e\x26\x7d\x1a\xaf\x60\x98\x40\x1f\x77\x7a\xb7\x39\x3f\xc2\x81\xc8\x12\xfc\x40\x27\x0d\x87\xe1\x5e\xc3\xa3\x13\x3a\x4c\xfb\xfe\xc8\x14\x5e\xc1\x48\xf0\x09\x4e\xfa\xd8\x3f\xe8\x1d\x0c\x93\xda\x34\x00\x00\xcd\xf5\x6b\x3d\xaf\x37\x84\xcd\xf5\x06\xcd\x8f\x6b\x11\xb7\xec\xb4\xac\xeb\x96\x20\xd8\x51\x70\xc3\xf0\x9c\x5f\xfb\x00\x08\x23\xb1\x49\xf6\xcf\xec\x4b\x68\xff\xec\x28\xda\xbf\xea\x68\x6d\x33\x6e\xda\x36\xf9\x61\x45\x88\x46\x8f\x96\x76\xb3\x01\x59\x0e\x55\x98\x00\x1d\x22\xb9\x09\x60\x27\x74\x9e\x43\x33\x81\xdc\x5c\x04\x50\x76\xb4\x23\x22\x6c\xe3\x5c\x77\x9c\xb3\x14\xfb\x0f\xdd\x39\xee\x1d\xa0\x99\xd9\xa1\x59\x02\x40\x09\xf5\x28\xc9\x26\x94\x5c\x60\x22\x21\x73\x36\x79\x0e\xdc\x2b\x04\xe6\xc2\x4e\x73\xfb\x0b\x09\x04\x29\x30\xef\x71\xa9\x97\xb6\x13\x44\x1b\x8e\xc4\x78\x3e\xb5\x4e\x32\x61\x7f\x24\x77\x58\xe7\x86\xfd\x51\x1d\x1a\x49\x00\x52\x72\x6e\xd6\x49\x2c\xc9\x4a\xa6\x95\x36\x55\xfa\x71\x54\x1b\xbd\x61\x20\xc1\x8b\xb4\xd6\xeb\x88\xf5\xc8\xc4\xb8\x93\xbd\x4a\x49\x79\x75\x7a\x56\xeb\x3d\x6c\x2d\xb1\x41\x96\xc2\x70\x9b\xa4\x45\xac\x5a\xf3\x60\x4b\x35\x76\x4a\xc9\x98\x35\x26\xca\xd6\xce\x5b\x42\x66\xcd\xbc\x4d\xb9\x61\xb8\xc3\xec\x69\x94\x8d\xcf\xec\x6a\xb9\x7d\x41\x15\x25\xe5\xad\xda\x37\x69\x13\xff\x5b\x39\xff\x1b\x69\x8d\x30\x26\x4d\x29\xfe\xc3\xc4\x34\x51\xee\x9e\xfb\xa5\x01\xc9\xe8\x97\x16\x32\x83\x68\x6d\x0f\xd8\x2f\x5d\x0f\xbc\x73\xf9\x1e\x78\xc3\x84\xd0\x15\x64\x08\xb2\x3c\x36\x59\xf3\xb4\x4a\x23\x6f\xd9\x01\x43\x1c\xfa\x24\x23\xe8\xf0\x84\xb0\x6d\xc4\x3e\xd9\xd6\xd6\x44\x31\x3a\x3a\x23\xed\x42\xdf\x6c\x19\x44\x14\x9f\x25\x5a\x53\x71\x06\x13\x6c\x03\x26\x9a\x86\x62\x4f\x45\xf3\xdf\x02\xad\x17\xb7\x56\x14\x95\x45\x72\xce\x45\x31\x40\x80\x62\x2f\x46\xe2\x11\x0a\x2c\x47\x0f\x0a\xee\x96\x8f\xd4\xb6\x0e\xeb\x53\xb8\xf4\x61\xab\xc6\xd0\x2a\xaa\x53\xbb\x80\xe4\x8c\xe4\x15\x4a\xdb\x59\xb5\xb5\x8d\xa7\x33\xed\x05\x1a\x11\x12\x35\x82\x47\xda\x0c\x55\xd6\x50\x9d\x58\x73\x67\x5e\xb5\xe5\x57\xcf\x17\xc8\x7c\xfd\x8c\x8f\x15\x02\x49\x91\x03\x0b\xc8\x37\x43\x93\x02\x30\x96\x00\x28\x03\x4b\x8a\xc2\x8d\x21\x5d\x84\xe4\xa0\xe7\x74\xcc\x46\x5e\x09\xeb\x81\x47\x5a\x1f\x3d\xa2\x45\x96\x51\xf8\x05\xe8\x6c\xb8\x15\xb4\xc6\x09\x48\x82\xd6\xb8\x08\xf3\x31\x09\x51\x5e\x84\xd9\x31\x36\x53\x25\x0c\xa1\x1c\x62\x72\x26\x37\x54\x96\x7a\x33\xd1\x85\x6e\x24\xc6\x70\x92\x68\x5e\x1d\xe3\x4c\x89\x0f\x52\x9c\x80\x79\x93\x33\xe9\x97\xc9\xe0\x7c\xfe\xeb\x83\xb2\xf3\x3d\x9f\xeb\xb9\xd4\xc1\xa5\x62\x3e\x83\x40\x90\x82\xf3\xd9\x93\xc9\xb9\x9a\x90\x3e\xb5\x79\xca\xc4\xfa\x8c\x9a\x27\x10\xc9\x04\x43\x98\x73\xe2\x88\x3d\x11\x07\x84\x73\xf8\x51\x95\xca\x6a\x9e\x2b\x93\xc8\x90\x7d\xea\x47\xc2\x12\xd1\x87\x13\x23\x5e\x39\xc7\x29\x42\x1c\xea\xc7\x7d\x9e\x8c\x51\x1d\x35\xf3\xe1\xf4\xb4\x81\x20\x72\x32\x6d\xe2\x39\x0b\x6d\x14\x6d\x2f\x5a\x67\x05\x2c\xd8\xa5\x83\x49\xe5\x69\xb1\xcf\xd2\x84\xdc\x0a\x9c\x55\xc6\x95\x83\x18\xcf\xf0\xc5\x83\xf9\x3a\x23\x5c\x9e\x44\x93\x30\x05\x87\x7c\x42\x1c\xf5\x77\xa3\x05\xcd\x62\x98\x10\x37\x10\xeb\xcd\xdb\x7c\xac\xd0\xb2\x56\x9a\x7a\xe5\xa6\xa0\x45\xe1\x38\x24\x36\x80\xc4\x15\x7c\x5b\x71\xe4\x54\x52\xb0\xb6\xe3\xf9\x71\xd0\xbd\x2c\xcc\xb8\xb6\x62\xfa\x94\x85\xe8\xca\xdc\x6c\x42\x45\x98\x56\x94\x0c\xbd\x18\xde\x47\x88\x5e\x1e\x43\x91\x19\xa4\x00\x9e\x42\xb9\xb8\xef\x42\x8a\x9f\xe2\x22\xb1\x30\x2a\x34\x50\xf0\xc1\x8c\x27\xe7\x39\x18\x6c\x2c\x22\x0d\x86\x34\x32\xdc\x3f\x28\xcd\x06\x50\x98\x66\x82\x17\xf5\xe3\xb2\x8b\x65\xdd\xe2\x0a\x2d\xef\xe3\x36\x54\x5b\xbd\xd6\x44\x88\xac\x55\xa7\x6c\x8f\x9a\x5e\xc7\x0e\x4d\xd9\x0c\x90\x52\x9b\x48\x4c\x41\x24\xdd\x50\x9a\x06\x50\xe0\x92\xdd\x3c\x2e\xa1\xb0\xc0\xd3\xe2\x37\x22\x91\xde\x93\x4c\xf0\xc5\xb1\x48\xf1\x8e\x4f\x0b\x62\x2d\x78\xa0\x12\xe4\x4a\xa6\x70\x61\x3c\x5c\xf0\xd7\xe2\x28\xc6\xd8\xcc\x95\x88\x92\xaf\x29\x62\xb4\x71\xfb\x11\xe4\xfa\xb5\xa3\x6d\x81\xb9\x32\x9f\x09\xa3\x72\x47\x94\x7b\x52\xf9\xcd\x8b\xca\x19\x9d\x60\x99\xe3\xa0\x44\x73\xcc\xe3\x20\x0a\x1f\xf4\xae\x32\x8b\xad\x32\xa2\xd4\x44\x9d\x56\xb1\x20\x56\xb1\xc2\xec\xa4\x8a\x95\x26\x4a\x5c\xc5\x82\x62\x15\xab\x24\x6a\x87\x75\xf1\x7a\x24\x8b\x10\xa5\x82\xc4\xd2\x78\x32\x27\xcf\x78\x66\x26\x25\x28\xbe\x64\xb3\xb5\x39\xd2\x96\x65\x4e\x80\x2b\xa2\x49\xbb\xe4\x20\xf2\x60\x56\x78\x1b\x0e\xe3\x2a\x14\x09\xd8\xef\x9c\x55\xaf\x38\x38\xa8\x4c\xa4\x8d\x29\x1c\xe5\x20\x94\x10\x45\x19\x61\x98\x4a\xc2\xe7\xa9\xec\xd9\xd8\x96\x8b\x86\x85\x7e\x1a\x1a\x63\x0e\x2a\x33\x53\x71\xa3\xc9\x52\x57\x69\xed\xd2\x39\x17\xd0\xac\xa6\xf5\x04\x9d\x38\x09\x77\x6b\x3b\x99\x48\xaf\x31\xc3\xa2\x22\xac\x91\xc8\x7c\x2a\x86\x56\x4c\x76\x8f\x01\x3d\xf0\x39\x4b\xce\x5c\xea\xb5\x94\x9c\x79\xef\x5a\x51\xdf\x4c\x7b\x22\x7d\xf0\x0e\x13\x2a\x4d\xae\x10\x95\x74\xf9\x2e\x04\xa2\x88\xd5\xc8\x6e\x98\x10\xa8\x4b\x0a\x60\x3c\x41\xda\x05\x66\x66\x82\x99\xd5\x70\xb6\xe4\xe5\xe4\x2d\x64\x5d\x4f\x94\xa1\x38\x1f\x0a\x79\x46\x34\xa0\x68\x3e\xdf\xda\xa8\xda\xc1\xab\xb5\x2b\x37\x6b\x59\x28\x70\x5f\x07\x92\x2a\x43\xa5\x24\xbe\x82\x33\x77\x49\xcd\x2b\x5d\xf1\x03\x44\x51\x66\x3e\x2a\xb1\x5c\xc5\x93\xdd\xc8\x98\x1b\x27\x13\x0c\x47\xc8\x7b\xf2\x4e\xf1\x39\x1b\x98\x3d\x0d\x9d\xa5\x83\x96\x37\xac\xd7\xe9\x28\x30\x0f\xc5\x7a\xdf\x22\xf3\x2b\x68\x55\xbe\x68\xd6\x0a\x9a\xab\xb4\x2a\x2a\x39\x75\x24\x6d\xfe\x2e\xde\x18\x13\xb3\xbf\x4c\x17\x0a\x65\x60\x2c\x78\xc5\x8a\xa6\x05\x24\x4b\xe7\x5c\xcb\x94\x69\x9b\xb5\x4c\x99\x96\x51\x3a\x5b\xa2\x94\xc6\xcc\x32\x3f\x10\x7e\x30\x8c\xb9\x56\x3b\x33\x62\x07\xdd\x4d\x6c\xdb\x5f\xaf\x1d\x37\x9e\xb7\x3d\x03\x39\xc1\x34\x67\x84\x58\xd6\xc0\x9f\xfa\x16\x19\x08\x0e\xe8\xad\xb1\xd0\xaa\x7c\x4d\xa8\x61\xba\x6c\x76\x2e\x7f\x52\x3e\x2a\x50\x2c\x18\x60\x0c\xa5\xb4\x18\x08\xd7\x38\x7d\xcb\x8a\x0b\x15\x29\x40\x59\x9c\x58\xaa\xbc\xaf\xb1\xfb\xd7\x74\xfa\xd2\x86\x12\xb3\x80\x2f\x01\xaf\x84\x78\xf3\x4a\xbe\x81\xda\x75\x5b\x77\x89\x5c\xa1\x91\x15\x70\xaa\xad\x5a\x8f\x7d\x26\x21\x55\xc2\x4f\x9f\x21\x57\xbe\x76\x63\xcc\xc2\xe4\x78\xe8\x77\xb4\xfc\x39\x67\xa1\x31\x17\xe7\x7a\x30\xbd\x24\xd7\xa2\x99\x3a\x05\x75\xd4\x2e\xca\x75\xa5\xe7\xb5\x3e\x4f\xac\x7b\x5e\x87\xd4\xca\xef\x02\x65\xcf\x5b\x50\x23\x09\x78\xf5\x26\x11\x42\x5a\x5d\xea\x0b\x1b\xe6\x6e\x21\xf1\x9c\x37\xa4\x04\xcf\x61\x1e\x36\xf8\x11\x52\xa8\x50\x95\xf1\x11\xac\x14\x67\xdc\xb7\x76\x50\xa2\xc6\xdc\x88\x70\x91\xf5\xc3\xfb\x2e\x98\x19\x92\x64\xd4\x82\x6a\x33\x7f\xf2\xff\xe0\xfe\x77\x5f\xe7\xbd\xc1\xf2\x9d\x95\xfd\x35\x7e\x1e\xc8\xfa\xde\xd0\x5d\x0d\x41\x96\x5a\x1d\x9e\xab\x70\xff\x91\x17\x9b\x17\x37\x92\xeb\xcb\xcb\x4b\xf3\x97\xeb\xf1\x49\x6d\xe0\x05\xa5\x9d\x67\x97\x73\x92\x83\xc5\x24\x79\xaf\x2e\x5c\x81\xab\x07\xaf\xbe\x7b\xcf\x85\x4f\x69\x65\xf3\x05\xe9\x2d\xcc\x5d\x97\x5e\x1c\xe9\x2e\xd0\xfa\x8d\x00\xfa\x8f\x7c\x88\x41\x95\x15\xa0\x3c\xd1\x28\xe4\xff\x77\x00\x00\x00\xff\xff\x36\x15\xb6\xce\x0e\x28\x00\x00")
+
+func fontsPebblesFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsPebblesFlf,
+ "fonts/pebbles.flf",
+ )
+}
+
+func fontsPebblesFlf() (*asset, error) {
+ bytes, err := fontsPebblesFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/pebbles.flf", size: 10254, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsPepperFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x55\x51\x8b\xe3\x36\x10\x7e\xd7\xaf\xf8\x1e\x02\x4e\x20\xd6\x6c\xae\x0b\xed\xb6\x4d\x11\xec\xd1\xc2\x3d\x94\xbe\x14\x0a\x75\x51\x7c\x8e\x92\x38\x97\xd8\x6e\x6c\xf7\x28\x75\xf7\xb7\x17\x8d\x9c\xc4\x92\x1d\x28\xb7\xec\x7a\xe5\x19\xcd\x37\x9f\x3e\xcd\x8c\x77\xa7\xdd\xbb\x74\x86\x67\x7c\x85\xaf\xf1\x84\x17\x51\x99\xaa\x32\x17\xb9\x3b\xed\xf0\xf1\x6f\xbc\xbf\x48\xfc\xc2\x16\xcc\xcf\x59\x9d\xd5\xab\x63\xf6\xf9\xa8\xb6\x59\x23\xd3\x4c\xb6\x9f\x16\xe2\xb5\x3c\x57\x27\xd3\x98\x2d\xd2\x62\x8b\xaa\xbc\xd8\x65\x53\x62\x97\xef\x4f\xa6\xb1\x18\x1f\xda\xb4\xc0\x6b\x7a\xc1\xfc\x98\xa9\x63\xbb\x6f\x4d\x63\xe4\x9f\x6d\x7e\x96\x6d\x76\x96\xa6\x5e\x88\xbf\xcc\xa5\xce\xcb\x02\x2b\xf9\x84\x38\xc6\xbb\x27\xfa\x90\x16\xf4\xf2\x3c\x70\xac\xac\x63\xf5\x0d\xfd\x68\x3e\xd2\xcb\xb3\x7d\xa9\xcf\x6d\x7d\x38\x97\x5b\x83\xa7\x25\x9a\x43\x5a\x7c\xaa\x6d\xde\x9f\x4e\xa6\x28\xf0\x7a\x48\xab\xca\x9c\x4e\x98\xef\xf7\x99\x6a\xf3\x36\x93\x66\xdb\x2e\x84\xf8\xb5\x36\x35\xea\x2a\x2d\xf2\xfa\x80\xec\x90\x5e\xd2\xac\x31\x17\xd4\xa6\xc1\xe7\xbc\x39\x20\x7e\x8f\xb2\x6a\xf2\xb2\xf8\x56\xe0\x4b\x7e\xf4\x7d\x25\x7e\xc7\x1a\x69\x04\x20\xc1\x1a\xc6\x2e\xf0\x07\xd6\xc8\x79\xf5\x0f\xd6\x28\x79\xd5\x61\x8d\x96\x57\xff\x62\x8d\x82\x83\xdf\xb0\xc6\xcf\x42\xcc\xd4\xed\x57\x09\x40\x09\x90\x12\x12\xbc\xb6\x0f\xb6\x90\x12\x33\x5e\x5d\x8d\xfc\xa2\x49\x93\x12\x31\xc5\x84\xab\xd1\xfe\xd7\x4b\x1b\xa2\x37\x4a\x48\xcd\x9e\xa8\x77\x28\x21\x49\x09\x92\x37\x6c\xad\x04\xe6\xa4\xc4\x5c\xff\x76\xc3\x56\x82\xf8\x89\x01\x9d\xee\x4e\x47\x09\x74\x4a\x90\xc7\x4f\x76\x16\xb6\xdb\x0c\xf9\x29\xa1\x41\x5a\x09\x8a\x7a\xde\x3d\xf8\x15\xdf\x61\x69\xdd\x63\xde\xbd\xf2\xea\x65\x33\x31\xc2\x1d\x58\x33\x23\x36\x6b\x1a\x00\xc3\xea\xe0\xf1\xb2\xc8\x11\xef\x0b\xc3\x61\x55\x93\x7e\x38\x18\x90\xb1\x07\xbb\x35\x0b\x89\xd1\x6e\xc7\xc2\x2a\xec\xb3\x70\xc7\x99\xe6\xac\x47\x9c\xf5\x64\x52\x25\x20\xbd\x02\x70\x06\x1a\xa8\x44\x4a\x24\x43\x95\x6c\xda\x38\xc6\xe0\x0a\x93\xbb\xca\x36\x4b\xc4\xc9\x31\xe2\x24\x17\x96\xc1\xdb\xc4\xd1\x78\xff\xd4\x99\x39\x62\x31\x76\x80\xc5\x58\x4e\x38\x6c\xb9\x68\x19\x3d\x90\x6f\x22\x82\x1d\x98\x3d\xca\xf1\x9d\x77\x6f\x8f\xe8\xba\xc2\x1d\xd6\x83\xf3\x72\xb5\xd3\x03\x88\x4d\x12\xd4\x04\x63\x12\x37\x94\xd7\x79\xd4\x2d\x9d\xa2\x7e\xe7\xf5\x3e\x76\x75\x13\xfc\xc7\x65\x3b\x90\x7b\x86\x47\x11\xc9\xa3\x0b\x9a\x72\x6c\xc2\x6a\x75\x55\x8c\xa0\x00\xf0\x88\x11\x6c\xbb\x77\x4a\x74\x14\xce\x9b\x0e\xbd\xa3\x0b\x4e\xad\x44\xe2\x8a\x3e\x19\x44\xf4\xb5\x3d\x4c\xaa\x6f\x2d\xad\x65\xd8\x65\x2e\x00\xfe\x15\xf2\xf9\x92\x89\x2b\xd4\x61\xf3\x53\x37\x1c\x24\xf0\xa6\xcb\xb5\x23\xe0\xf5\x0c\xe7\xeb\x3c\xc2\x6e\x60\x71\x47\x22\xdc\x39\x0b\xa4\xc3\xb8\x9f\x07\xbb\x23\x0f\x42\x5b\x76\x34\xc3\x14\xae\x3d\x0c\x05\x0c\x40\xe1\x38\x18\xce\x5b\x07\xc3\x02\x5a\x73\x47\xe1\x01\x12\x7f\x9a\x50\x10\xee\x72\x73\x76\x5c\x53\x85\xb4\x30\xa9\x01\x8d\x34\xf0\xab\x77\xbc\x9b\x6e\x2c\x74\xf8\xd1\xe0\x09\xad\x13\x04\x4a\xe9\x09\xa5\x10\x66\x77\x7f\x1d\x85\xa2\xc0\x55\xa7\x3f\x06\xa0\xc4\x0f\xdf\xfb\x99\x43\xe5\xed\xc7\xca\x9a\xbc\x4a\xd3\xfd\xbc\xc1\xff\x1c\x2b\x52\xd3\xc6\x2f\x86\x2b\x95\x40\xcb\x68\xa2\xf2\x9c\x31\xf2\x8e\xb8\x1c\x49\xe6\x76\x05\x77\xc3\xfb\x46\x77\xa3\xe3\x78\x34\x13\xad\x69\x62\x3c\xfd\x17\x00\x00\xff\xff\xdd\xb3\x22\x4a\x20\x0a\x00\x00")
+
+func fontsPepperFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsPepperFlf,
+ "fonts/pepper.flf",
+ )
+}
+
+func fontsPepperFlf() (*asset, error) {
+ bytes, err := fontsPepperFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/pepper.flf", size: 2592, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsPoisonFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x4d\x8f\xdb\x36\x10\xbd\xfb\x57\xbc\x59\x18\x4d\x82\xee\x2e\xd6\xdb\xf4\x10\x22\x28\x78\x68\x0f\x3d\xf5\x52\xf4\x5c\xad\x25\xaf\x85\xd8\xd2\xc2\x92\x9b\xe4\xdf\x17\x22\x87\xc3\xa1\x3e\xfc\xb1\xbb\x49\x81\xc2\xdb\xd4\x22\x65\x8b\x7c\x7c\x1c\xce\x3c\x0e\xb5\xda\xac\xee\xb3\x39\x16\xf7\x58\xdc\xe1\xfe\x0e\x37\x0b\x2c\xde\xcf\x9e\xea\xb2\xa9\xab\xdb\xd5\x66\x85\x65\xbd\x7d\xaa\x9b\x22\x47\x59\xb5\x35\x56\xe5\xe3\xa6\x68\xf1\xf0\x15\x7f\x95\x55\x55\x7c\xc5\x9f\xeb\xac\xc4\xc7\xa6\x59\x95\x65\x6b\x8b\x5d\xd9\xdc\x2e\x97\xb7\xfb\xed\xc3\x6d\x91\xef\x7f\xe1\x76\xb0\xaa\xab\x16\x6f\xab\xfd\xf6\xa1\xd8\x35\xf8\x01\x4f\xfb\xaa\xdd\x67\x6d\x59\x57\xd8\x66\xbb\x4f\xcd\xbb\xd8\x4b\xda\x72\xda\xc0\xfe\xe9\xa9\xd8\x2d\xb3\xa6\xc0\x72\x9d\xed\xb2\x65\x5b\xec\xf4\xa3\xbf\x66\xff\x94\x39\x7e\x6f\x9a\x62\x83\x8f\x79\xd9\x5d\x6d\xb5\xaf\xca\xe5\x6d\xb5\xf7\x70\xf2\xac\x2d\x0c\xfe\x58\xb6\xb8\xff\xe9\x1a\x8b\x0f\x1f\xde\xcf\x7e\xfb\xf2\xb4\xc9\x2a\x8f\xa5\x5e\x61\x55\xee\x9a\x16\x9b\xb2\x2a\xcc\xac\xa3\x06\x37\xb8\xda\x66\x8f\xe5\x12\x1e\xfd\x15\x56\xf5\x0e\xab\x72\x53\xa0\xcc\x8b\xaa\x2d\x57\xe5\xd2\x3d\x3c\xcb\x00\xe0\x06\xcd\xba\xde\x6f\x72\x64\x9b\xcf\xd9\xd7\x06\x0f\x05\xfe\xce\xde\x5c\xbb\x87\xaa\xfa\xf3\x6c\xee\x7f\xd4\xae\x0b\x5c\xad\xb3\x5d\xfe\xb0\xc9\xaa\x4f\x57\xb8\xb9\xc1\xd3\xae\xac\xda\x06\x59\x83\x0c\xee\xee\x35\x1e\xf6\x2d\x96\x59\xf5\xa6\xed\x9a\x69\xb6\xfb\x66\x5d\xe4\xb3\xc5\xbd\x6b\x61\x5d\x94\x8f\xeb\xb6\x43\x9c\x45\x32\x66\x8b\xbb\xe9\x2f\xaf\x51\xd5\x2d\xca\x6a\xb9\xd9\xe7\x65\xf5\x88\xbc\x68\x96\x45\x95\x17\xbb\x66\x76\xef\x1f\xdb\x66\x5f\xdc\xc8\xb1\x29\xaa\xc7\x76\x8d\xb7\xc5\x97\xf0\xe3\x65\xbd\xdd\x16\x95\x27\xa6\x79\x87\x1f\x91\x61\xb5\xcf\x1f\x0b\xac\xb2\x65\x5b\xef\x66\x37\x0b\xd7\x42\x5e\xac\xb2\xfd\xa6\xf5\x60\xb7\x75\x5e\xb8\x81\xb7\xeb\xb2\xe1\x19\xdc\x94\x9f\x0a\x5c\xdd\x6c\x71\x77\x85\xba\x72\xcd\x66\x55\xee\x9a\x7d\x37\x5b\xfc\xec\x1a\xf1\x44\x77\xe8\x93\x5e\x67\xb3\x39\xe6\xf6\x99\x1f\x76\xd6\x11\x0f\x3b\xb3\xd6\x76\xf7\xe4\x42\xdd\x85\x2c\x5c\x8d\xdc\x4d\x22\x77\x93\x1f\x30\x64\x5c\xcd\xb8\x8b\xf1\x17\xff\x1d\x5f\x63\xc3\xaa\x71\xd5\x01\x77\x02\x4b\x00\x17\xd1\xd9\xc1\xbc\x7b\xec\xd9\xc5\xd0\xb1\x2a\x33\x12\xb8\xce\x3d\x82\xb1\xba\x25\x6b\xa9\xfb\x90\xd1\x93\x25\xbe\xe7\xd1\x75\x05\x50\xf7\xad\x7f\xbe\x63\xc4\x7d\xb8\x3a\x19\x22\xd3\x7d\x90\xa7\xa6\x2b\x1b\xbe\xe7\x9f\x37\x06\xdd\x87\x11\xac\xae\x0e\xd3\xc3\x3e\x36\x00\x5f\xf3\x50\x5d\xcd\x86\x3f\x0f\xd5\xf2\x3f\x06\x0e\x92\x5f\x92\x1b\x83\x47\x69\x67\x70\x55\xab\xe6\x92\x0c\x18\x20\x0f\x00\xbe\x66\x3a\xa4\xc6\xcd\x2f\xf7\xee\x81\xf7\xa1\x8e\x30\xed\x60\xf9\xef\xc2\xc4\x5b\xa9\xba\xef\x3b\x22\xbd\x01\xc4\xe6\x98\xd8\x50\xb7\x9e\xd7\x50\xa7\x50\xf5\x75\xc7\x71\xa4\xc6\x18\x72\x00\xd9\x28\x3d\xd3\x8e\x6a\x1e\x8a\xfb\xa5\x81\x32\xd3\xc9\x01\xb0\x65\x0c\xb9\x66\x74\x1d\x6c\x6d\x46\xdd\x58\x2c\x59\xc1\xce\x06\x13\x9a\xea\x08\x67\xf8\x8e\x7e\xe3\xff\x39\x22\x3a\xbc\x70\x9c\xbb\xa6\x3c\xdf\xc6\x04\xce\x99\x7f\x33\x82\x7a\xb0\x72\xc1\x54\xf3\x34\x33\x98\xd3\x2f\x3d\x26\x5c\x29\x34\x2d\x13\x17\xa7\x2c\x4e\x16\xc9\xd0\xc3\x14\x75\x25\x13\xda\x95\xc1\x05\x03\xe2\x3e\x92\x21\x25\x1d\x47\xa6\xd3\xb5\x4a\xe1\x61\x0a\xde\x02\x14\x56\x26\xa2\x41\x93\xd8\x00\x09\x8d\xdc\x9e\xd1\x16\x34\xbd\xca\x34\x14\xf2\x96\xe9\xbb\x21\xef\xaa\x02\x10\xef\x1b\xc4\x79\x38\x6f\x11\x60\xb8\x65\x14\xcc\x3b\x4c\xb3\x9f\xf3\x68\x9b\xf3\xc3\xbd\x4f\x1b\xe9\x91\x8a\xd5\x2b\x29\xce\x94\xc7\x18\xbd\xb9\x43\x9c\xd0\x16\x9e\x31\xba\x72\x42\xa7\x62\x8c\x67\x5f\xfa\x61\x24\x1a\xc8\x59\x23\x9e\xa8\x1c\x1c\xf1\x8b\x9a\x7e\xf1\x88\xcd\xe1\xc0\xd9\xef\x52\x96\xa2\xaa\xc6\xef\x5f\xd9\x93\xce\xa1\xeb\x52\x85\xf7\xa4\xf3\x71\x4a\x46\x57\x53\x0c\x52\x1c\x16\x62\xcc\x12\x37\x6a\x43\xcc\x82\x4c\x55\x77\x71\x41\x2c\xc4\x33\x09\xb4\xce\xb7\x50\x5c\xf0\x6e\x69\x21\x44\x30\xc3\xde\x93\x49\x35\xee\x3f\x18\x4d\x55\x0f\xa8\x78\x37\x06\xcb\xe1\x4a\x96\x71\x70\x35\xa2\x01\xe4\x4e\xea\x67\x3c\x55\x61\x2e\x93\xb5\x9d\xb0\x22\x9c\x24\x8c\x28\x13\x90\xb2\x0f\x22\xd1\xcd\x85\x68\x22\x2b\x93\x8c\x4c\xab\xa1\xe8\xda\x42\x0c\xe1\xf5\x34\x12\x3e\x06\x02\xad\x07\x47\x10\xf4\xc0\xf8\xf5\xc4\xb0\xfc\x62\x12\x66\x85\x0d\xe1\x83\x71\xa8\x89\x98\x4f\x0b\x34\x3d\x7c\xd1\x3a\xb1\x62\x55\x5f\xde\xcd\x72\x38\x22\x12\x7f\xec\x6d\x84\xbf\x09\x52\xcc\x78\x5d\xe3\x64\x98\xa2\xc1\x24\x91\xc8\x0c\x0c\x64\x8c\x21\x51\x32\x51\x73\x89\xc4\xb2\x14\xd5\x96\x0d\x80\x7c\x38\x50\x3a\xab\x5f\x54\xa6\x6a\x8e\x31\x24\xa2\x24\x9a\x6a\x1f\x87\x06\x12\x90\xd8\x04\x4a\x50\x79\x11\x81\x04\x26\x41\x23\xee\x78\x80\xa7\x0f\xc8\x0e\x79\xd1\x86\x1c\x47\x1b\xcd\xc4\x52\xa2\x9d\x83\x21\x93\x19\x33\xe4\xe8\x7a\xb4\xdf\x39\x00\x68\x6a\x65\x39\x4f\xd3\xf3\x33\x21\x9e\x0b\xb8\x30\x59\xac\x5e\x12\xff\xa2\xbd\x8b\xf6\x2d\xc7\x18\x3a\x17\x10\xa5\x12\x22\x0d\x56\x49\xf9\x5c\x40\x13\x97\xd0\xaf\x15\xcb\xe8\x5a\x9a\xcf\x4f\x8b\x53\x07\x1a\x85\x34\x1a\xbc\x63\xd2\xe8\xd1\x70\x9f\x6a\x34\x15\xfa\x94\x22\x8c\x3a\x07\xe2\x98\x11\x8d\x5f\x87\xad\x18\xf2\x90\xba\x51\xe9\xc8\x50\x6f\x73\x63\xfa\x0a\x68\x6c\x97\xf6\x4c\x8d\xc2\xd3\xec\x09\x4a\x34\x4a\x00\x35\x67\x15\x4d\x6e\x07\xe9\xb9\x52\x1e\xed\xb4\x7e\x06\x8c\xca\x9e\x06\x3a\xf2\xe9\x47\x13\x46\x81\x64\xb7\xcb\x37\x28\x11\x22\x89\x9c\x22\xa5\xf5\x53\x46\x95\x8a\x88\x32\x7c\x08\xf9\x59\x2b\x08\x07\x82\xa5\x1d\xc8\x58\x77\xdf\x28\x7d\xa4\x26\xda\x0c\x26\xfd\x59\x9a\x46\x2f\xed\x10\x31\xfd\xb2\x08\x2e\x99\xbf\xb3\x61\xb1\x13\x7b\x19\x92\x5d\xa1\x62\x4b\xfe\x62\x28\x1d\xfa\xe6\x17\xfb\x9e\x60\x86\xa2\x94\x49\x43\x1b\x73\x86\x6a\x13\x23\x79\x8c\xe3\xe1\xe2\x08\x20\xf4\x01\x85\xd8\x7e\x14\x10\x94\xe0\x60\xdd\x73\x92\x77\x1e\xc4\xaf\xc9\x80\x9a\x04\xd7\x58\x36\x49\x39\x89\x5f\x69\x40\x7d\x1d\x86\x92\x29\x83\xd2\xc8\x5a\x21\x4f\x31\x94\x0a\x8e\xe7\x46\x78\x3b\xc1\x4a\x37\x47\x26\x24\x08\x38\x0f\x06\x95\x0e\x18\x8b\xf0\x32\x65\x30\xc7\xa7\xec\x7b\x00\x8a\xe5\xd4\x35\x8e\x00\x4a\xbd\x81\x72\x06\xa9\x19\x25\xa0\x10\xfd\x82\x64\x55\x25\xe8\x77\xa6\x24\x5a\xda\x6f\x6d\x48\x0c\x48\xeb\xe9\x71\x1f\x30\x64\x4b\xa7\xe0\x80\xff\xcc\x05\x4c\xe6\x97\xb9\x7d\x9d\x5f\x56\xa3\x57\x4a\x41\x05\xa1\x81\x2e\xee\x69\x84\x09\x19\xaa\xd2\x46\x69\x14\x4b\x45\x96\x91\x11\x2b\x01\xa4\x45\x96\x19\x08\x81\x73\x68\xa7\x84\xf6\x20\x00\x44\xa8\x8b\x0a\x65\x23\xd5\x21\x41\x3b\xba\x94\xf6\x43\x1b\xbc\x00\xa8\xfb\x9b\xf7\xcb\x24\x65\x52\x65\x4b\xea\x7e\x52\x36\x52\x06\x6f\xbc\x07\x9e\x57\xb6\x0e\x07\x82\x68\x2f\x6e\x26\xd5\xe4\x78\x20\x49\x68\x4b\x3e\xc0\xfa\x25\x03\xa5\x5e\x81\x98\x2d\x60\x60\xc9\x2a\x4a\x66\x13\x2a\x15\xc9\x23\x3a\x2a\xee\x06\xd3\xaa\x8f\x32\xdc\xa1\x01\x43\x91\x15\xe4\xe2\xfd\x79\xde\x59\x32\x07\x9c\x22\x7c\xdd\xdd\xc5\xb9\xe1\xe2\xec\xed\xce\x33\xe2\xd7\xa4\xe1\xbf\xaa\x77\xe6\x14\x6d\x8a\x8f\x62\xba\x21\x82\x82\xa6\x09\x9a\x27\xd1\xe3\x2a\x75\xef\xd8\x9a\x43\xa8\xa2\x60\x53\x66\x2c\xbf\xfb\x72\xb6\x48\xb3\x65\x8f\xb8\x89\xb3\x05\xda\x88\x3d\x31\x07\x07\x12\x0c\x61\x77\xa0\xb6\xcf\x7e\xf5\xf5\xb2\x1d\x50\xe9\x0e\xa8\x7c\xc7\xe4\xf4\x4d\xa5\x5d\x92\x64\xa7\xda\x9d\x0c\x53\x0b\x6a\x9f\x67\xe5\x38\x40\x6b\x7e\x5f\xec\x2b\xfe\x97\x07\xd1\x6f\xbe\xca\x5e\x05\x90\x07\x21\x51\x96\xc2\x34\x81\x7d\x79\xc2\xcf\xa1\x2d\x51\x8a\x6a\x00\xad\x87\x8f\xa0\xbd\x3a\xe4\x23\xc4\x1d\x92\xe3\x34\x05\x37\xf1\xed\xa4\x80\x9b\x10\xa8\x11\xf5\x82\x3a\x34\x0b\x7b\x4f\x33\x79\xcc\xfa\xd2\xe0\x0d\xd2\xb9\xc9\xe8\xc3\x70\x7a\xf0\x3e\x30\xdd\x87\x8e\xcf\x49\x6f\x32\x03\x96\x01\x94\x57\x5b\x04\xa3\xba\x9b\x7f\xfb\x2a\xa9\xbe\x53\x15\x04\x23\x10\x28\x88\xfa\x5f\xfc\x13\x67\xb6\xd4\x4e\x4d\xa2\x8a\x74\x1c\x96\x5e\x58\x77\xc9\x71\xca\xd0\xc0\x91\x24\x4f\xfa\xd9\x13\x48\x9e\x3a\x39\x3c\xe9\x65\xa5\xfc\x25\x3d\x7e\xd1\x07\x32\xd2\x2d\x0d\xce\xdf\x8c\xe9\xe5\x61\x30\xd4\xa1\x03\xd2\x4e\x60\x4e\x4d\xdf\xc8\x59\x07\x4d\x9c\x75\x9c\xc1\x9c\x52\xe8\xea\x44\x9d\xd3\xfb\x31\x38\xbb\x0d\x11\xf3\x23\xf6\x24\xe4\x0a\x17\xdf\xf3\xce\x04\x8b\xbd\x71\xc9\xdf\x80\xf9\xef\x76\xc3\xe8\xbf\xd1\x1b\x13\x83\x51\xfb\xb1\x70\x9e\x82\xf0\x1a\xce\x79\x97\x4b\xfe\xe9\x92\x7f\xba\xe4\x9f\x2e\xf9\xa7\x4b\xfe\xe9\x92\x7f\xba\xe4\x9f\xf4\x54\x5e\xf2\x4f\x97\xfc\xd3\x25\xff\x74\xc9\x3f\x5d\xf2\x4f\x97\xfc\xd3\x25\xff\xf4\x3f\xc8\x3f\xe9\x04\x46\x00\x31\xf4\x0e\xda\x3d\xc4\x74\xd4\x60\xef\x96\xa6\x7a\x92\xd7\xae\x93\xcd\xfb\xf4\xcb\x78\x87\xa5\x2d\xbf\x76\x35\x2a\x6d\xa3\x04\x19\x7f\x09\x4b\xb2\x44\x83\x32\x12\x27\xd8\x7b\x47\xc8\x8e\x4a\x5b\xfd\x6a\x50\x3f\x01\x17\x02\xea\x89\x4b\x7d\xec\x06\xcb\xc7\xd0\xb7\xbc\x53\x15\xf7\xef\xe8\xbd\x17\x1d\x5f\xb4\xfa\x96\x37\x52\xa4\xce\x3e\xce\xf9\xff\xf2\xc0\x69\x0f\xfc\x1b\x00\x00\xff\xff\x36\x99\x57\x1a\xad\x39\x00\x00")
+
+func fontsPoisonFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsPoisonFlf,
+ "fonts/poison.flf",
+ )
+}
+
+func fontsPoisonFlf() (*asset, error) {
+ bytes, err := fontsPoisonFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/poison.flf", size: 14765, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsPuffyFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x59\x5f\x8b\xdc\xb6\x17\x7d\x9f\x4f\x71\x1e\x06\x6c\x81\x19\xb1\xbf\x5f\x5a\x1a\x58\x96\x81\xbe\x15\xfa\xda\x27\xc1\xf5\x36\xec\x96\x84\x24\x6d\x37\x5d\x68\xc0\x1f\xbe\xdc\x3f\x92\x25\x4b\x1e\x7b\x26\x19\xc2\x5a\xe3\xb1\x8f\xae\xee\x9f\xa3\x73\x95\xe7\x8f\xcf\xff\x7b\x3c\xe2\x27\xfc\x88\xbb\x37\xb8\xc3\xff\x0f\x7f\xbd\x3e\x3f\x7f\x3d\x3d\x7f\x7c\xc6\xef\x5f\xf1\xcb\xeb\xe3\x67\xfc\xfc\xf8\x82\xfe\xc3\xbb\xf3\x87\xd7\x3f\x5e\x9f\xfe\x79\x3a\xfd\xfd\xfa\xfe\xd3\xe9\xf5\xdd\xa7\xd3\xd3\x17\x77\xf8\xed\xe9\xe5\xcb\xfb\x3f\x3f\xe3\xee\x74\x87\x1f\xfc\xaf\x8f\x2f\xfe\xee\xed\xdb\x37\x87\xc3\xf1\x78\x3c\xef\xf8\x73\x3e\x80\x70\x3e\xf4\x70\xe7\xc3\x84\x29\xff\xd3\x93\xb3\x3f\x00\xce\xe7\xc3\x11\x04\x10\xf8\xc5\x1e\xae\x87\x93\x11\xb9\x9e\x64\x04\xf9\xec\x1f\x09\xac\x7d\x64\x2c\xe8\x32\x26\xc5\x17\xc3\x08\x38\x9d\x00\xb5\x45\x9f\x56\x93\x74\x66\x7b\x37\xc7\x89\x63\x79\x08\xfa\x84\xef\x08\x41\xd6\xd9\x93\x2e\x29\x50\xbc\xe3\xc8\xf1\xea\xc7\x40\x20\xdf\x19\x74\x86\xa5\x3e\xb2\xa9\xc5\x24\xc7\x43\xdf\xc1\xd9\x33\xbe\xe3\x7f\xf2\x45\x87\x36\xa7\x0e\xf5\x1d\x19\x22\xba\xb3\x65\xb0\x4e\xc4\x1f\xf9\xa1\x17\x77\x88\x21\x63\x00\x06\x06\xd0\x95\x8c\xc1\xb3\xe5\x13\x7a\x7a\xc0\x70\x3f\x8a\xed\x44\x3e\xa8\xf5\x35\x34\x07\x8f\x8e\x31\xca\x5e\xa2\xd0\xfe\x63\x81\x50\xeb\x25\x25\x06\x06\x9d\x30\x41\x66\x1c\x03\x74\xb6\xb8\x8c\x78\x31\x1f\xf1\x1c\xf6\x0c\x38\x87\x00\x49\x25\x46\x93\x8c\xa2\x64\x62\xf6\x62\x11\x77\xcd\xc6\x11\xea\xdd\x07\x00\xf7\xe2\xbf\x01\x43\x8a\x7b\x1e\x9c\x3c\x4a\x86\xa4\x37\x25\xf4\x82\x4a\x13\x26\xd2\x28\xf0\xcf\xd1\x78\x59\x94\x3d\x4b\x6e\xe1\xb1\xd2\x79\x2d\x6f\xd5\x0e\x9d\x5f\x2a\x46\xa4\x31\x95\xe9\xf9\xe3\x56\x9e\xab\x47\x97\x66\x66\x98\x32\x6c\x9a\xa0\x34\x03\x78\xec\xcc\x50\x64\x19\x5a\x25\xe5\x32\x43\x61\xf9\xe9\x3b\xd0\x68\x79\x08\x67\xac\x01\xa3\x0f\x76\xe8\x14\xf3\xb2\x5b\x8b\x56\x96\x68\x1c\xe0\x2c\x5f\xe2\xa5\x6f\x25\x5a\x32\x81\x8b\x41\x6d\x90\x00\x3a\x5b\x2e\x2f\x2b\x2e\xaf\x57\x70\x2a\xed\x28\x9d\x2c\x80\x14\x69\x42\x5f\x70\xba\x00\x50\x4f\x9a\x80\x70\xd9\x92\xb2\x18\x2e\x69\x22\x56\x81\x33\xea\x99\x30\xa5\xea\xe1\x51\xcc\xc3\x21\x82\x2c\x48\xac\xb4\x2c\xa5\x8e\x98\xe8\xd4\xb5\x24\x68\xfc\xc3\x18\x96\x96\xad\x39\xfb\x02\x10\xdb\xcc\x40\xfb\xa2\x46\x8b\x74\xce\x73\xcc\xde\xe1\x81\x85\x47\x73\x4a\xb2\xab\x4a\xa7\xb2\xc6\x66\x16\x10\x86\x33\xae\x76\xc6\x02\x84\xfb\x2e\xbb\xb3\x95\x57\x94\x48\x5f\x3d\x64\x0b\x63\xd2\xb7\x34\x4b\x19\x56\x72\x72\x0e\xd4\xac\xb8\x56\xed\xad\x3f\xd8\xa2\x07\x4a\x65\xe8\x52\x09\x9e\x0f\xf7\xcc\x73\x32\x7f\x80\x32\x28\x5f\x56\x13\xad\x4e\x96\x26\xcf\xec\x64\x9c\xb4\xc1\x19\x7d\xcb\x8f\x63\x88\x76\x30\x0b\x3f\x64\xb6\x1a\x55\xac\x57\x75\x19\x46\x0e\x99\xf9\x3a\xa6\xc8\x44\x93\xbe\x76\x99\xcc\x8b\xbb\x33\xb3\x2b\x72\x4c\x30\x1a\xe1\x34\x5b\xd0\x33\xd3\xab\x0f\xd9\x77\xb6\x61\x68\xc5\x96\x1b\xef\xb2\x24\x00\x97\x15\x80\x94\x44\xc1\x68\xfc\xc3\x5a\x9e\x20\xdf\xb1\x23\x23\x6a\x9e\x0a\xd0\x7d\x97\xdd\xe9\xe9\x72\x6d\x55\x40\x3a\xad\x50\x08\x19\x74\x7f\x0b\xd0\x94\x73\xb4\x22\xea\x62\xaf\xb6\x88\xcc\x22\x90\xfb\x26\x8b\x72\x20\xe3\x47\xcb\x41\x15\x58\x37\xf8\x48\x03\xca\xd0\xc3\xb6\x45\x51\x9a\xc1\x21\xca\x5f\x9a\x6e\x09\x3f\xac\xe6\x5b\xfa\x39\x3e\x5c\x24\x5c\x4e\x9b\x4a\x43\x64\x03\x26\xf3\x69\x9b\x83\x1b\xa6\x6b\x69\x4d\x18\x98\x47\xe4\x4e\x48\xe5\x77\xc1\xf4\x58\xf5\xe6\xf1\x14\x83\x2c\xe1\xa6\x1d\xe1\x8d\xb7\x7c\x17\xc8\xeb\x66\x22\x8b\x2b\x8a\x6a\x9f\x33\xab\xa5\x8d\xc1\x7c\x3a\x60\x34\xa0\x31\xec\x29\xca\xaa\xba\xd7\x64\x4a\x4f\x97\xf6\xf4\x46\x2d\xc5\xea\x1e\xd4\x23\xbb\x33\x77\x87\x45\x7d\x17\xcc\xa2\xb0\x65\xd1\xd4\xe0\x9b\x01\xa2\x7d\x38\xfc\xd8\x0e\xff\x6a\x51\x8e\x65\x7b\xb4\xa9\x7b\x52\x66\xa7\xf6\xcc\x44\x4f\x6b\x70\x81\xf4\x5b\x99\x1d\x5d\x73\x5d\xd4\xf6\x00\x05\xf2\xbb\x6a\x0d\x19\x18\xdf\x48\x80\x12\xbf\x0c\x74\xb6\xd0\x23\x64\x7e\xfb\x77\x21\x3f\x5b\xba\x9a\x8a\x59\x7a\x95\x39\x63\x88\x5b\xe6\x03\xb4\xb0\x79\xcf\x9b\x2b\xbb\x6c\x28\x5b\x5b\x7a\x42\x9c\x21\x29\x62\x8e\x01\xa6\xd4\xae\xe9\x86\xae\x96\x80\x85\x2a\x29\xf6\xe1\x1a\xd8\xb2\xd1\x65\x3d\x67\xbc\x44\x90\x95\xd6\x33\x22\x9a\x82\x41\xae\x62\xd2\xe3\xf1\xab\xbd\x9b\x69\x1c\xfd\xba\xa3\x3d\xb7\x34\x77\x55\xb3\x42\x53\xcc\xca\xda\xc2\x23\x6b\x52\xd6\x81\x1e\x08\xa2\x11\x7d\x50\x15\x99\x9d\x8a\xac\x5f\xcf\x07\xe8\x08\x37\x8d\x6a\x65\x98\x0b\xd4\x23\x13\xce\xc5\x03\x01\x54\x9c\x46\xb1\x77\x63\xf5\xa5\x0a\x3b\x6d\x5b\xc3\x35\xbb\x4d\x64\xb2\x6e\xc1\xad\x3d\x0d\xdb\xbb\x4d\x61\x51\xea\xe0\x54\xf9\xa2\xd7\x3b\x17\x79\x0b\xb3\x1e\xd7\xf2\xe0\xef\xf1\xc4\x82\x46\xdd\x91\xf7\x2c\xad\x6d\x51\xd6\xa3\xc6\xce\xcb\x6f\x5a\xb4\x58\x48\xd6\xa7\x71\xcb\xb8\x5b\x27\x5d\xb6\xa8\xec\x8b\x84\xed\xa3\xfc\x48\x9d\x12\xbb\x7f\x2d\x6a\xcb\xce\x71\xcf\xd6\xae\x4d\x4a\x2d\x96\x2a\x9d\x54\xbc\x9b\xc2\x43\x85\x60\xda\x56\x4e\x2b\xa6\xfb\x4e\x7d\x78\xb5\x4e\x92\xb2\xe7\x77\x61\x4d\x46\x71\x59\x21\xa6\xf9\x53\x7d\xe1\x38\x93\x3a\xd2\x77\xec\xc8\xb9\x0d\xd7\x3d\x2b\x73\xe8\xf6\xb9\x61\x23\xdc\x05\x78\xc8\xe4\xc6\x46\x94\x1a\x79\x03\x34\x1b\xf3\x8d\x36\x7c\x09\x44\xe9\x70\xa4\xab\x75\xcb\x8a\x92\xda\xcf\x3f\x29\x93\xdb\x1d\x7e\x7c\x3f\xbb\x12\x6c\xbf\xe9\x28\x6d\x38\x69\xea\xea\xf9\x06\x80\xd5\xaa\xef\xf4\x30\x47\xe6\x0e\x51\x29\xb7\x00\xd2\xe1\x10\x59\x41\xbb\xe5\x06\xb7\x72\xb6\xda\x72\x66\x25\x70\xf6\x1d\xba\xed\x00\xda\xa3\x8b\xd6\x72\x31\x02\x16\xa0\x39\x70\x0e\xbe\x47\x17\x55\x4e\xb7\x04\x61\x69\x64\x47\xc4\x7a\x42\xec\xb3\xdd\xbb\x8a\xda\x15\xbe\x1b\xd6\xe8\xa4\xca\x9f\x59\x0d\x0c\x7a\x96\xe3\xd3\x26\xbb\x66\x89\xd2\x99\x1d\xfe\xd8\xe9\xfa\x7d\x67\xca\xd8\xce\xd7\xcb\x83\x9f\x12\x60\xeb\xff\x6b\xf2\xad\x36\x6a\x21\x3b\x8d\x37\x11\x3e\xda\x51\x8e\xb1\x56\x3c\x16\xae\x66\xa2\xec\x80\x36\xc4\x43\x5a\x1f\x8a\x37\xd6\x65\xe2\x9a\xc6\xeb\xc9\x69\x87\xf1\xad\xa7\x2e\x4d\xa0\x5b\x1a\xbc\x34\xc9\xf7\xeb\x39\x32\xb3\x6f\x16\x4a\x35\xd0\x0d\x1c\x5c\x03\x7d\x3f\xda\xa8\xbb\xd9\xc9\xc3\x38\x3c\x44\x31\x37\x09\xe2\x4c\xe6\xff\x05\x00\x00\xff\xff\xc6\x63\x30\xa8\xef\x1c\x00\x00")
+
+func fontsPuffyFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsPuffyFlf,
+ "fonts/puffy.flf",
+ )
+}
+
+func fontsPuffyFlf() (*asset, error) {
+ bytes, err := fontsPuffyFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/puffy.flf", size: 7407, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsPyramidFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x97\x57\x74\xdc\xd4\x16\x86\xdf\xf5\x7c\xef\xfb\xbe\xbe\x01\x27\xc4\x93\x58\x1a\x7b\xec\x09\x21\x38\x84\x00\x01\x02\xa1\xb7\x10\xe7\xcc\xe8\x68\x46\x44\x23\x19\x49\x93\xd8\x74\xd3\x7b\xef\xbd\x2f\x7a\x67\xd1\x7b\xef\xbd\xf7\xde\x7b\xef\xac\x19\x2f\x98\xff\x0f\x7b\x78\x49\xd6\xfa\xbe\xa3\x23\xe9\x93\x6c\x6f\x05\x51\xe0\x99\x49\x29\x4a\x51\x86\xa4\xe0\x8a\x5b\x72\x96\x4c\xa4\xa6\x11\xfa\x52\x99\x90\x05\x91\x69\xfa\x56\x16\x9b\x34\x0f\xe3\x4c\xfa\xbd\xd9\xe5\x41\x67\x51\x5c\x8d\x9a\xbe\xcd\xa4\x5a\x37\xa9\xa9\xe6\x36\xcd\xc4\xf5\x86\x0b\xde\xe0\xa0\x13\x84\xb5\xc8\xe6\x92\xda\xc8\x9a\xcc\x8a\x37\xcb\x95\x42\x41\x5c\x4f\xe6\x37\x6b\xe2\x96\xcb\x03\xce\x12\x9b\x36\xc2\x2c\x0b\x93\x58\xc2\x4c\xea\x36\xb5\x95\x09\xa9\x85\x2b\x6d\x2c\x79\x22\x8d\xc4\x0f\x83\x09\xc9\xeb\x61\x26\x41\x12\xe7\x7d\x62\x32\x89\x92\xb8\xd6\xfa\x3f\xaf\x5b\xa7\xbd\x20\xb4\x69\x6f\x26\xb1\x69\xd8\xd6\x1e\x63\x91\xa9\x5a\x5f\x92\x58\x8c\x54\x93\x46\xc3\xc6\xb9\x44\x61\x6c\x67\x39\xce\xc2\xf1\xb1\xc8\xc4\x26\x6f\x9d\x2d\x09\x24\x08\xd3\x6c\xca\xcd\x71\x5a\x37\x2e\x05\xe9\x69\x98\x5a\x58\x95\xb8\xd9\xa8\xd8\xb4\x47\x82\x24\x95\x20\x8c\xac\x84\xbe\x8d\xf3\x30\x08\xab\xed\x83\x1d\x23\x22\x52\x90\xac\x9e\x34\x23\x5f\x4c\xb4\xca\x4c\x64\x52\xb1\xb2\xdc\xf4\xf6\xb5\x0f\x8a\x93\x55\xce\xb4\xa9\x45\x79\xdd\x4a\x4f\xdd\xa4\x7e\x25\x32\xf1\x8a\x9e\x56\x80\xb1\x34\x8c\xf3\xac\x75\x0f\x46\xda\xb4\x4f\x2a\xcd\x5c\xaa\x26\xee\xcd\x5b\xdb\x64\x8d\x66\x56\xb7\xbe\x53\x9c\xda\xa1\x6e\xc3\x5a\x3d\x6f\x5d\xb1\xe9\x44\xfe\x57\xd9\x27\x71\x92\x4b\xd8\x7e\x32\x61\x5c\x13\xdf\x66\x55\x1b\xfb\x36\xcd\x9c\xa1\xf6\x51\x0d\x33\xde\xbe\x71\x89\x6c\x5c\xcb\xeb\x32\xdd\x8e\xff\xb5\x16\x9b\x65\x33\x64\xa6\x18\x09\x9a\x7e\xcd\x4a\x60\xaa\x79\x92\x3a\x05\xb7\xbd\x83\x6f\x03\xd3\x8c\xf2\xa9\x6b\x6d\x24\xbe\x6d\xdf\xf7\xdf\x4f\xca\x71\x4b\xed\x65\x53\x25\x5b\x97\x47\xfb\x3a\xce\xe4\xe4\xe4\x48\xe7\x9f\x11\x47\x64\x99\xc8\x88\x23\xb3\xff\xb7\x54\x46\x9c\xb9\xa3\xa3\xa3\xf3\x90\xf6\xa8\xf4\xff\x2a\x9d\xa6\xd2\x35\x54\xba\xa6\x4a\x7b\x55\x3a\x5d\xa5\x33\x54\xba\x96\x4a\x67\xaa\xb4\x4f\xa5\x05\x95\xce\x52\xe9\x6c\x95\xf6\xab\xd4\x55\xa9\xa7\xd2\xa2\x4a\x07\x54\x3a\xa8\xd2\x92\x4a\x87\x54\x3a\xac\xd2\xb2\x4a\xe7\xa8\x74\x6d\x95\xce\x55\xe9\x3a\x2a\x9d\xa7\xd2\x75\x55\x3a\xa2\xd2\xf9\x2a\x5d\x4f\xa5\x0b\x54\xba\xbe\x4a\x17\xaa\x74\x03\x95\x6e\xa8\xd2\x8d\x54\xba\x48\xa5\x1b\xab\x74\x13\x95\x6e\xaa\xd2\xc5\x2a\xdd\x4c\xa5\x9b\xab\x74\x89\x4a\xb7\x50\xe9\x96\x2a\xdd\x4a\xa5\x5b\xab\x74\x1b\x95\x6e\xab\xd2\xed\x54\xba\xbd\x4a\x77\x50\xe9\x8e\x2a\xdd\x49\xa5\x4b\x55\xba\xb3\x4a\x97\xa9\x74\x54\xa5\xcb\x55\x6a\x54\x5a\x51\x69\x55\xa5\xbe\x4a\xad\x4a\x03\x95\xd6\x54\x5a\x57\x69\xa8\xd2\x5d\x54\xba\x42\xa5\x91\x4a\x1b\x2a\x8d\x55\x9a\xa8\x74\x4c\xa5\xbb\xaa\x34\x55\x69\xa6\xd2\x5c\xa5\x4d\x95\xae\x54\xe9\x2a\x95\x8e\xab\x74\x42\xa5\xbb\xa9\x74\x77\x95\xee\xa1\xd2\x3d\x55\xba\x97\x4a\x7f\x53\xe9\x4b\x2a\x3d\x4d\xa5\xfb\xab\xf4\x07\x95\x1e\xab\xd2\x33\x91\xba\xde\x70\xc7\x3c\xc0\xa6\xdc\x31\xbf\x92\x29\xf6\x77\xcc\x47\x6c\xdc\x8e\x79\x9b\x8d\xd7\x31\xef\xb2\x29\x76\xcc\x9b\x6c\x06\x3a\xe6\x3d\x36\x83\x1d\xf3\x01\x9b\x52\xc7\x7c\xcc\x66\xa8\x63\x3e\x61\x03\x0d\x3e\x64\x03\x0d\xbe\x20\x33\x00\x0d\x3e\x67\x03\x0d\x3e\x65\x03\x0d\xee\x65\x03\x0d\xee\x63\x03\x0d\x1e\x62\x03\x0d\xde\x67\x03\x0d\xee\x67\x03\x0d\xbe\x65\x03\x0d\xbe\x67\x03\x0d\xbe\x26\x33\x08\x0d\x7e\x61\x03\x0d\x7e\x62\x03\x0d\xfe\x60\x03\x0d\x9e\x67\x03\x0d\x5e\x65\x03\x0d\xce\x65\x03\x0d\xce\x63\x03\x0d\x2e\x60\x03\x0d\xce\x67\x03\x0d\x4e\x24\x53\x82\x06\x6f\xb1\x81\x06\x9f\xb1\x81\x06\xdf\xb0\x81\x06\x3f\xb3\x81\x06\x5f\xb1\x81\x06\x4f\xb1\x81\x06\x97\xb0\x81\x06\x37\xb3\x81\x06\x77\xb0\x81\x06\x17\x91\x19\x82\x06\x97\xa1\x71\xdc\x21\x88\x70\x1b\x1f\x04\x11\x6e\x65\x03\x11\xce\x61\x03\x11\x2e\x65\x03\x11\xae\x64\xd3\xfa\x7e\x93\x8e\x3d\x89\x2d\x84\x38\x99\x0d\x84\x38\x85\x0d\x84\xf8\x9d\xcc\x30\x84\xb8\x96\x0d\x74\xb8\x8e\x0d\x74\xb8\x9e\x0d\x74\xb8\x91\x0d\x74\xb8\x89\x0d\x74\x38\x9b\x0d\xbc\x0c\x17\xb2\x81\x06\x17\xb3\x81\x06\x97\xb3\x81\x06\xb7\x90\x29\x43\x83\xdb\xd9\x40\x83\x3b\xd9\x40\x83\xbb\xd8\x40\x83\xbb\xd9\x40\x83\x7b\xd8\x40\x83\x07\xd9\x94\xba\xfc\x29\x76\xcb\xd0\xe0\x61\x36\xd0\xe0\x11\x36\xd0\xe0\x51\x34\x5e\x3f\x34\xb8\x82\x0d\x34\x78\x92\x0d\x34\x78\x81\x0d\x34\x78\x8d\x0d\x34\x78\x9d\x0d\x34\x78\x8c\x0d\x34\xf8\x92\x0d\x34\x78\x9c\x0d\x34\x78\x82\x0d\x34\x78\x9a\x8c\xdb\xcf\x3f\x77\xcf\xb0\x85\x0e\xcf\xb2\x81\x0e\xcf\xb1\x81\x0e\x2f\xb2\x19\xe8\x32\x4c\x79\x2e\x74\x78\x99\x4d\xfb\xf7\x02\x5d\xe2\x2b\xbc\x00\x72\xbc\xc3\x06\x72\x7c\xc7\x06\x72\x9c\x4a\xc6\xeb\xef\x32\xd9\x79\x1e\xa4\x38\x9d\x0d\xa4\x38\x83\x4d\xb1\xcb\x3c\xe7\x79\x90\x62\x1f\x36\x90\xe2\x0d\x36\xf0\x4a\xec\xcb\x06\x1a\xec\xc7\x66\xb8\xcb\x4c\xea\xe1\xdc\x78\x00\x19\x9c\x1b\x0f\x64\x03\x0d\x0e\x5a\x2a\x23\x02\x0a\x22\x1c\xcc\x07\x41\x84\x43\xd8\x40\x84\x43\xd9\x0c\xfe\xe3\xa9\x1f\xc6\x0b\xa0\xc5\xe1\x6c\xa0\xc5\x11\x6c\xa0\xc5\x91\x6c\xca\xab\x9f\xed\x28\xf2\x38\x45\xfe\x87\x0d\x14\xb9\x9a\x0d\x04\xf9\x91\x4d\x71\xf5\xb3\xed\xcd\x1e\xb2\x9c\xc5\x06\xde\x8d\xff\xb2\x29\x75\xf9\xca\xf0\x70\x96\x3c\x81\x0d\xf4\xb8\x8a\x0d\xbc\x1b\x37\x90\xc1\x59\xf2\x78\x36\x50\xe2\x38\x36\x5e\x97\x6f\x1d\x0f\x67\xc9\x6b\xd8\x40\x83\x63\xd8\x40\x83\xa3\xd1\xfc\x19\x00\x00\xff\xff\xc2\x6e\xde\xca\x4c\x18\x00\x00")
+
+func fontsPyramidFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsPyramidFlf,
+ "fonts/pyramid.flf",
+ )
+}
+
+func fontsPyramidFlf() (*asset, error) {
+ bytes, err := fontsPyramidFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/pyramid.flf", size: 6220, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsRectanglesFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x58\xcd\x6a\xdb\x40\x10\xbe\xfb\x29\xbe\x83\x20\x97\xc8\xc2\xa1\x29\x14\x8c\xf1\xa1\xcf\xd0\x93\x60\x70\x5d\x39\x0d\xd8\x0e\x34\xa6\x50\xd0\xc3\x17\xcd\xee\xcc\xae\xf6\x4f\xeb\xa4\x50\x5b\x58\xf3\xcd\xef\xb7\x33\xb3\x39\x9d\x4f\x4f\x87\x06\x5f\xf1\x8c\xcd\x33\x36\xd8\xac\xfe\x0c\xc7\xdb\xe1\xfa\x72\x1e\xde\xd7\xa7\xf3\x09\x3f\xff\xe1\xfb\xe1\xef\xeb\x2f\xfc\x78\x3d\x9f\x87\x97\xc3\x3b\xb6\x97\xeb\x70\x19\xae\xb7\xdf\xfb\xeb\x70\x3b\xbe\x5d\xd6\xc7\xb7\xcb\x0e\x9b\xa7\xee\xdb\x97\x55\xd3\xec\x53\xff\xf7\x2b\x10\x61\xbf\x1a\x81\x51\x3f\x89\xf4\x13\x00\x58\x08\x46\x6a\x34\x02\x23\xbf\x6b\x9a\x06\xc1\x17\x23\x26\x61\x4c\x3f\x11\x03\x18\x39\xfd\x02\x18\xc5\xfa\x08\xb0\x2a\x96\x95\x7f\xa2\x42\x15\x58\xf7\x20\x5e\xc1\x3a\xe9\xeb\x10\x18\x2c\x8c\x6c\x54\x44\x1a\x98\xe2\x5d\x60\xcb\xd6\x1c\x2c\xb6\x66\x13\xc2\xe9\x98\xc2\x87\xf7\x61\xb5\xb2\x4e\xa3\x88\x83\x94\x2f\x62\x33\xac\xcb\x68\x9a\xff\x8a\xd1\x7d\x59\x7c\x22\x44\x22\x2d\x09\x7b\xd1\x02\x68\xa5\x3a\x51\x88\x16\x16\xc7\x1a\x46\xe6\xc3\x66\x31\x05\x11\x47\xf5\x27\x49\x79\xc4\x8d\x8c\x26\x49\x9b\x35\xe9\x72\x86\x8e\x43\xef\xd0\xb1\x58\xa7\x5e\x79\xa2\x12\xbd\x2d\xaf\x75\xcb\x95\x36\x4c\x96\x4d\x31\x4c\x05\xbc\xf0\x89\x62\x3e\xf8\x16\x48\x08\x44\x19\x0b\x91\xa8\x7c\x95\x44\xc5\x61\x40\x52\x5f\x08\x91\xaa\xb5\x1a\x51\xac\x97\x45\xd5\x72\x85\x03\x46\x5d\x8d\x56\x91\xc9\xf8\x3a\xab\xbc\x7b\xca\xbf\xf6\xc8\x36\x9d\x44\xc3\x8d\x4e\xb9\xb1\xc5\x96\x51\x3d\x7a\xa6\x48\x4f\xbd\xe5\xa5\xb2\x4f\xb9\x49\xb3\x72\xbb\xba\x5b\x99\xfd\xca\x72\x64\xd2\xe5\xeb\xdc\x61\xa7\xf6\x3a\xe6\x62\xa0\x4f\x13\x19\x1e\xa3\xf8\x3c\x25\x4e\xef\xd4\xa8\x0c\x83\x43\xc7\x16\x60\xda\xd7\xb4\x67\x57\xc0\x48\x60\x44\xb6\x57\xd4\x59\x83\x5a\x6b\xab\x60\x10\x58\x6f\x67\x8b\x12\x82\xba\xe5\x94\x44\xcd\xb7\xd2\xc9\x08\x36\xa2\xa2\x00\x0a\xf3\x9c\xac\xb0\x36\x7e\xa8\x00\x22\xed\x9a\x75\xc1\x1a\xfb\x66\xf0\x6e\x3e\x7f\xd4\xc9\x76\xd9\x49\xf3\x60\x60\xf6\x81\x4a\x4d\x32\xc7\x12\x7f\x4d\xa8\x81\x8d\x11\xec\x2e\x4e\xde\x97\x12\x8a\x17\x82\x2a\x96\x44\xd6\xe4\xbc\x83\x53\xba\x70\xde\xea\x0a\x10\x72\xd2\x2d\x3b\x35\xb1\x79\x93\x1c\x77\xb5\xa0\xcf\x92\xcb\x3c\xa0\x2f\x9d\x6e\x7f\x83\x0c\xca\x5d\xb4\x86\xc0\x5a\x5b\x49\xe5\x00\x56\xda\x72\x12\x99\x24\x44\x2c\x89\x9c\x0c\x66\xee\x6c\xc1\x73\xcb\xc5\xe8\x0f\x49\x7b\xac\xfa\x60\x68\xf9\x43\x32\x33\x9e\xed\x2e\xe8\xc6\x6a\x92\xd4\xbc\xd5\x8c\xc9\x09\xa8\x63\x2e\xff\xae\x30\x2f\x13\x8e\x15\x6f\x00\x6e\x63\xf3\x56\x83\x07\xe3\xfc\x63\x6a\x7d\x80\x9f\xb6\xe2\xa6\x81\xe4\x72\x94\x11\x25\xb8\xb4\xdd\xa3\xb5\x5d\x5e\xf6\xa4\xee\x70\xfb\xf9\x92\xd6\x78\x39\xca\x66\x00\xfe\x3d\x0b\xc9\x0d\xc9\xbb\x7b\xa4\xa2\x96\x95\x2e\x49\x9d\xb4\xd1\x07\x13\xca\x63\xc6\x28\x72\x46\xfd\xf3\x94\x6a\x9a\x99\x39\x90\x48\x69\x3a\xea\x42\x2e\x6b\x8a\xb9\x46\x58\xa8\xaa\x0a\xe9\xf5\xac\x48\xbc\x8a\xba\xbb\x55\x6b\x99\xf9\x35\x5a\xe7\x57\xf1\x62\x06\x7c\x51\xf4\xae\x3b\x67\x2a\x17\x35\xe9\xfc\xed\x68\x6e\x81\x32\xd4\x29\xf8\x9d\x3c\x05\xf3\xc4\xb5\x99\xc3\x6d\x5e\xbb\x95\x9b\xf4\x5e\x0d\x1d\x7c\xd0\x2b\xb6\xf4\xaf\x39\x85\x67\x64\x4e\x5e\x11\x3d\x1d\x91\x1d\xd2\x3f\x02\x44\x6b\x0c\x8d\xf3\x8b\x45\xb2\x07\xfb\x7f\xa0\x90\xf5\xb3\x62\xa3\x4f\xc1\x2a\xd6\xa0\x14\xac\x62\xe6\x4b\x6d\xed\x7d\xac\xd4\xc6\x33\xa2\x29\x86\x06\xa2\x4b\x64\x5e\xba\xc0\x30\x1b\xe4\xcc\x30\xec\x7f\x00\x00\x00\xff\xff\xbd\x5d\x2e\x99\x39\x13\x00\x00")
+
+func fontsRectanglesFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsRectanglesFlf,
+ "fonts/rectangles.flf",
+ )
+}
+
+func fontsRectanglesFlf() (*asset, error) {
+ bytes, err := fontsRectanglesFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/rectangles.flf", size: 4921, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsReliefFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x59\xb9\x6e\x1b\x31\x10\xed\xf5\x15\x0b\x28\x6d\x44\xc8\x08\x62\xb8\x4b\x1d\xc0\x2e\x52\x13\x20\x14\x47\x42\x04\x3b\x2e\x1c\xa8\x48\xc3\x6f\x0f\xac\x5d\x72\xe7\xcd\x0c\xaf\xb5\xe4\x8a\x2a\xc4\x6b\x39\x7c\x7c\x73\xae\x74\x78\x3e\xdc\xec\x3e\x0d\xb7\xc3\xed\xb0\xfd\x3a\x7c\xde\x0e\x37\xab\x1f\xfb\xe7\xe3\xfe\x30\xfc\xfc\x37\x3c\x1c\x1f\x9f\x86\xfb\xe3\xcb\xfe\xf5\xef\xf0\xb0\xb9\xdf\x8c\xdd\x6f\xbf\x4e\xaf\xbf\x77\x7f\x36\xbb\xc7\xcd\xe9\x69\xf5\xfd\xf4\xb2\x1f\xb6\x77\x77\x5f\x56\xee\xed\xb3\xae\x6f\xe2\xd0\x78\x6f\x45\x83\x6b\xb0\x63\x5a\xb0\xce\x4c\x1b\x42\x6f\x5e\xcd\xf6\xe6\x6e\x58\x08\x22\xa6\x13\xa7\x8f\x6d\x5a\x03\x99\x74\x78\xee\x1b\xba\xe9\xbc\x23\x8a\xb3\x11\x04\xce\x7b\xb8\x13\x0a\x0d\xb7\x0e\x8f\x8c\x7b\x89\x94\xf5\x0a\xe5\x71\x8a\x04\xc4\x88\x65\x7a\x1c\xe7\xbd\xb7\xe3\x7c\x3c\x88\x3c\x2f\x20\x8e\xe8\xd6\x2b\x13\x97\x95\xef\xb0\x2f\x20\x0d\xe7\xca\xd6\x51\x23\xa0\x1b\xc5\x03\xac\x35\x00\x50\x55\x4a\xd0\xab\x1d\x2f\x67\xe7\x1b\x5b\x3e\x4f\xb9\xd5\x69\x04\xa9\x7c\x60\xd0\x74\x52\x8f\x29\x56\x94\x6f\xe2\x5d\xad\x76\x45\xb5\x9f\xb0\xaf\x54\xbf\x05\x86\x20\x65\xec\x36\x59\x2a\x03\xa0\xfa\x2b\x71\x9c\xc9\xba\xc1\x76\xc1\x10\xe0\x48\x2f\x75\x28\x01\x03\x34\xee\xa0\xd0\x35\x0a\x93\xba\x6b\xcd\x16\xc9\xc9\xa0\x14\x54\x79\x7f\x51\x28\xe1\x82\x30\x51\x10\x8a\x0c\x4d\x98\x8c\x90\xa5\x98\x32\xd5\x6a\x82\x53\x0e\xd7\x61\x00\x04\x2b\xd1\x42\x4b\xc6\x79\xc1\x7b\x78\x18\xc3\xeb\xeb\xe1\x4a\x42\x7c\xbf\x9d\xd6\x41\x69\x83\x58\xbf\x59\xe7\x46\x08\x15\x8d\xf1\x53\xa4\x13\xa3\xa6\x1d\xe7\xe8\x1f\x0f\x8c\x28\x22\x83\x91\x3f\x32\xe3\x30\xca\xe7\x42\x59\x2a\x7c\x55\x84\x35\x0a\x4a\x39\x39\x0d\x53\x33\x98\x90\xd4\x33\x31\x8e\x62\x90\xb3\xdc\xfb\xa2\x05\xc6\xa3\x49\x22\x33\xc2\x7f\xc4\x1e\x97\xb0\x9b\x92\x6c\xee\x9b\x46\x19\x64\x64\xcf\xbc\xa7\x64\x17\x56\x96\xe2\xb6\x14\x82\x75\x32\xd6\xbd\x03\x77\x7a\xd0\x24\x5b\x85\x3a\x27\x21\x6d\xa5\x9a\xef\x46\xd9\xc4\x68\xae\xc3\x37\xc1\x3d\xae\x48\xdc\x05\x56\x97\xd8\xe0\xb4\x1b\xfc\x56\x76\x0c\xe3\x55\xc9\xf8\x9a\xfb\x2a\x5d\xe3\x65\x09\x51\xbe\x29\xa6\x4e\xac\xcb\x15\xb2\xf3\xda\x4f\xa8\x35\x3b\xa8\xb5\x2c\x54\x8a\x35\xfe\x82\x51\x82\x29\xdc\xa6\xb4\x6f\xd4\x83\x32\xb2\x4b\x56\xab\x42\xbd\x44\x94\xe0\x2b\x1a\xf9\x17\xc2\x4d\x4d\xba\x25\x4a\x34\x46\xe5\xa5\x7c\x6b\x2b\xe3\xe4\x42\xbe\xcb\xef\x49\xe9\x41\x46\x76\x65\x90\x5f\x64\x27\xb5\xe2\x2c\x94\x1e\x22\x9a\x88\x57\x9e\xd9\x2d\x2c\x16\x04\x75\x43\x47\x28\x75\x5c\x72\xee\x16\x19\xac\x86\xbf\x1b\xb4\x46\x80\x2c\x0f\x8b\x34\xcb\xbc\x42\x84\x6e\x07\xef\x59\x55\x51\x91\xe4\x0d\xe3\x31\xad\x62\x27\x93\x5b\xe2\x89\xf0\x02\x81\x3f\x26\x10\xac\x82\x47\x3d\xd3\xc9\x9a\x15\x43\x6b\xa2\x90\x0e\x67\xcc\x2f\x2f\x86\x17\x0c\x8a\x1e\xd3\x83\xda\xe7\x32\x83\x82\x16\xd6\xd3\x6f\x49\x6f\x98\xc3\x8c\xf8\xee\xc5\x6e\x2f\x76\x7b\xb1\xdb\x8b\xdd\x5e\xec\xf6\x62\xb7\x17\xbb\xa0\x97\x9a\x20\xdf\x8b\xdd\x5e\xec\x3a\x99\x1b\x8c\xc7\x02\x57\xd4\xad\x3c\xcf\x14\xff\xd4\xc5\x46\x39\xbf\xe2\x24\x1d\x55\xc2\x96\xe2\x66\x25\x81\x73\x85\x4a\xcb\xac\x19\x7f\x60\xe9\x79\xe5\xc0\x7f\xb5\x60\xd1\x39\x69\xc6\xad\x46\x1b\xcc\x8c\x20\xfb\x7f\x00\x00\x00\xff\xff\x8a\x69\x12\xdc\xc7\x21\x00\x00")
+
+func fontsReliefFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsReliefFlf,
+ "fonts/relief.flf",
+ )
+}
+
+func fontsReliefFlf() (*asset, error) {
+ bytes, err := fontsReliefFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/relief.flf", size: 8647, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsRelief2Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x58\x3b\x6f\xdb\x30\x10\xde\xf5\x2b\x0e\x70\xd7\x86\xb0\x51\x34\xc8\xd6\x4e\x9d\xba\x74\xe6\x92\x20\x72\x1b\x40\x69\x01\xa7\x46\xe1\x7f\x5f\xd4\x12\xa9\x7b\x7c\x7c\x48\xb6\x3b\x31\x83\xf9\xd2\x1d\x3f\x7e\xf7\xe0\x31\xfb\x61\xbf\x7b\x7c\x47\xf7\x74\x4f\xdb\x8f\xf4\x7e\x4b\xbb\xee\x5b\x3f\xbc\xf4\xfb\x1d\x3d\x9d\xe8\x6b\x7f\x18\x5e\x7e\xd2\x97\x43\x7f\xfa\xf3\x6b\xd8\xd3\xeb\x79\xfc\xe9\xe9\xf0\xf8\xe3\xf5\xed\xee\xf8\xdc\x0f\x77\xfd\xf3\xb1\xfb\x7c\xfc\x7e\x7c\xfb\x4d\xdb\x87\x87\x0f\x9d\xff\xf7\xb7\xa9\x6f\xe2\xd0\x39\x47\xa6\x91\x6b\x42\x62\x5a\x20\x1f\x04\x42\x6f\x5e\xcd\xf6\xe6\x6e\x58\x08\x2a\xa6\x1d\xa7\x3f\x5a\xb4\x26\x74\xf2\xe1\xb9\x2f\x84\xce\x12\x51\x1d\x45\x10\x72\x5e\x9e\x49\x2a\x0d\xa7\x0e\x9f\x8c\xb2\x4c\xcb\xa6\x93\xfa\x34\x45\x06\x62\xc4\x32\x7d\x2e\xe7\x9d\xa3\x71\x3e\x6e\xc4\xbe\x37\x10\x47\x74\x9b\x6e\x5e\x06\xbf\x41\x2e\x20\x0d\xfb\xda\xd6\x0b\x2a\x98\xa0\xf9\x40\xb5\x12\x20\x34\x4a\xb0\x2b\x8d\x87\xa3\xf9\xc4\xa4\xe7\x39\xb7\x98\x46\xa1\x55\x0f\x94\xeb\xa4\x3e\x03\x5e\x94\x6f\x66\xa8\xe8\x88\xb0\x9f\xf0\xaf\x54\x7f\x09\x0c\x43\xca\xd8\x5d\xe4\xa9\x0a\x00\x8c\x57\xa7\xa4\x95\xef\x0a\x47\x10\x5b\x02\x1b\x5a\xc0\x42\xb9\x0e\x50\xd1\x45\x4c\xe2\xd0\x9a\x3d\xd2\xf8\x00\xa3\xa0\x2a\xfa\x8b\x4a\x19\x17\x8c\x89\x82\x52\xc9\xd0\x84\xc9\xea\x02\xae\xcc\xad\x9a\xe0\x54\xc3\xf5\x32\x01\x0a\x2f\x41\xa9\x25\x13\xbc\x22\x7a\x74\x1a\x93\xc7\xc7\xe9\xca\x42\xbc\xdc\x4f\xeb\xa0\x2c\x83\x58\x2f\x8c\xb9\x31\x4a\x4d\xe3\x42\xa6\x33\xa3\x45\x12\x67\x4c\x71\xc3\x88\x22\x32\x18\xf9\x63\x33\x5e\x66\xf9\x5c\x2a\x4b\xa5\xaf\x8a\xb4\xc6\x41\x81\x9d\xd3\x30\x91\xc3\x78\xe8\xbd\x28\x1a\x12\xb3\x3a\xfa\x9c\xb9\x84\x59\xc8\xd8\xf8\x31\x32\x3e\xe1\x37\x25\xdd\x3a\x36\xd1\x20\xa3\xdb\x15\x75\x17\x56\xd6\xe2\x26\x0e\x81\xbc\xcd\x75\x17\xe0\x4e\x0f\x16\xe9\x86\x50\x1d\xbf\x3e\xcc\x4a\x35\xdf\x0b\x75\x33\xa7\xb9\x0d\xdf\x0c\xb7\x93\x29\x00\x08\x5d\xcd\x07\x27\x69\x11\xb7\xb6\xa3\x79\x05\x37\x3e\x0a\x5f\xd0\x65\x0c\xe7\x2c\xa4\x8e\x20\xa4\x55\x5d\x0e\xc8\xce\x5b\x3f\x61\xd6\xec\xa0\xd6\xb3\xa4\x51\x88\x1b\x65\xaa\x06\xd6\x67\x09\x65\x70\x4a\x59\x1f\xbb\x42\x46\x77\xc9\x6b\xa1\xba\x6b\x64\x09\xbd\x82\xc8\xbf\x12\x6e\xee\xd2\x91\xba\x6b\xe1\xbe\x9c\x6f\xb4\x32\x4e\xae\xe4\xbb\xfc\x4e\x4a\x0f\x32\xba\x2b\x93\xfc\x2a\x3f\xa9\x55\x37\xbf\xa2\x3d\xca\x26\xe6\xc9\x33\x87\x05\xc9\x28\xa9\x1b\x7a\xe7\x12\x67\x28\x9c\x22\x83\xd5\xe9\xb7\xc1\xd2\x0c\x90\xe5\x61\x95\x65\x55\x86\x33\xa9\xdb\x8b\x77\x56\x55\x56\x64\xf7\x46\x84\x07\x3b\x99\xbb\x25\xee\x28\x1e\x10\xf2\x9f\x09\xdc\x34\x1a\x0f\xbe\xe9\x6c\xcd\x2a\x53\x6b\xa2\x90\x0e\x7b\xcc\x8f\x17\x46\x7c\xd2\x8e\xe9\x41\xed\x77\x99\x41\xc1\x0a\x9b\x2e\xf8\x4b\x58\x07\xbf\xad\xd8\x6d\xc5\x6e\x2b\x76\x6f\x50\xec\x7a\x67\xaf\xa7\x56\xec\xae\xd0\xdd\x8a\xdd\x56\xec\xb6\x62\x17\x64\x93\x56\xec\xae\xb2\xac\xca\x70\x26\x75\xaf\x28\x76\xcd\xdd\x10\x41\x0a\xbc\xb2\xeb\x70\xb1\x3a\x9d\x3f\xdf\x80\xfd\x2b\x76\xc2\xa8\x12\xbe\x14\x85\xc1\x05\xae\x0d\x6a\x3d\xb3\x66\xfc\x1f\x4b\xcf\x1b\x27\xfe\x9b\x25\x8b\xc6\xc9\x62\xdc\xe5\x15\xa9\xfb\x6f\x00\x00\x00\xff\xff\xa9\x47\x91\x3a\xcd\x21\x00\x00")
+
+func fontsRelief2FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsRelief2Flf,
+ "fonts/relief2.flf",
+ )
+}
+
+func fontsRelief2Flf() (*asset, error) {
+ bytes, err := fontsRelief2FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/relief2.flf", size: 8653, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsRevFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x59\xbd\x72\x1b\x39\x0c\xee\xf5\x14\x28\xae\xb8\x14\xd1\x58\x4e\x8d\x19\x35\x29\xd3\xe5\x05\x9c\x58\x9a\x14\xb6\x33\x23\xcb\x99\xc9\xdb\x67\x2c\x89\x24\x3e\x00\x24\x41\xee\xda\x77\xd9\xc5\xae\x96\xe0\x87\x1f\x7e\x00\x77\x8f\x4f\xc7\xfb\x87\xff\x68\xb7\xa3\xdd\x1d\x7d\xb9\xa3\xcf\x3b\xba\xdf\x9c\x0e\x7f\x0e\xa7\xd7\xc3\xf6\xf8\x74\xa4\x1f\x7f\xe9\xdb\xc3\xf9\x4c\x5f\xb7\xf4\xfd\xd7\xdb\xe9\xf5\xfc\xfb\xe5\xff\xf3\x45\x78\x3e\xec\x7f\x3e\x3e\x6c\x9f\x4f\xaf\xdb\xb7\xe7\x97\xed\xe1\xf1\xed\xd3\x66\xc3\xef\x7f\xfb\x75\x4e\xd7\xf3\x7e\xc3\x44\xfd\xa3\x7d\xb2\xa8\x28\x3f\xa6\x9f\x88\xdf\xff\xc1\xaf\x6b\x48\x45\xbc\xde\xbe\xcd\xa8\x65\xba\xfd\x2d\x7d\x86\x2d\x04\x07\xc4\xf5\xf1\x34\xf8\xa2\xf3\xe6\x8d\xeb\xff\xe9\xbe\x7c\x9e\x8a\xd2\xea\xf3\x05\x84\x1c\x5b\x05\x21\xc2\x40\x9c\x02\x41\x0c\x16\xb3\x98\x58\x28\xbd\xfc\x20\x3c\xc1\x29\xca\x9c\xef\xc7\x3c\x71\xd5\x99\x32\x80\xdc\xfb\xc5\x13\xc9\xd3\x62\xb2\x12\x82\x9c\x64\x97\x01\x5d\x10\x25\x2b\xe5\x91\x63\xc7\xac\x2f\x7b\x26\xa3\xce\x70\x12\x46\x5f\x10\x8e\x85\xb0\x15\xcd\x72\x8e\xe0\x30\x23\x54\x01\xf5\x93\x02\x64\x48\x71\xa2\xa2\x4e\x2c\x09\x71\xbf\xbf\x24\x82\x99\xa9\x64\x5c\x12\xec\x81\xf0\x9f\x89\x82\x08\x1e\xfd\xc4\x89\xdb\xe1\xca\xca\x8e\x49\x3d\x43\x76\xf4\x28\x1a\x95\x13\x95\x0b\x09\x53\x06\x1a\x79\x8a\x55\x24\x60\x6d\x97\xc4\x64\x99\x9c\xda\x22\x8f\xc3\x05\x65\x52\x66\x9c\xeb\xf0\x59\xb9\xe8\x51\x54\x5a\x01\xa1\xe8\xb0\x92\x74\xf3\x72\x17\x04\xcb\xca\x90\x86\x30\x38\x06\xb8\x58\x6a\x23\x60\x75\x63\x47\xd6\x56\x22\xe3\xc1\x59\x0d\x0f\x41\x79\xab\x8c\x91\xda\xb4\xcb\x1b\x78\x74\x4a\x82\xe1\x04\xf5\x4c\x71\x17\xcb\x22\x23\xbd\x40\xae\x6a\xbc\xf0\xf1\x80\x06\x48\x77\x7d\x01\x1c\xcb\xa2\x22\xa7\xa9\xf4\x52\xcc\xd9\x5c\xb8\xb8\x8f\x87\x09\xdb\x0f\xad\x0e\x61\xf7\xf0\x20\x38\x0c\x78\x0c\x8f\xe7\x9f\x25\x4c\x13\xbd\xa8\xfa\x07\x70\xd7\x03\x01\xbd\xc8\xe2\x31\x83\x78\xac\xb3\x5a\x81\x48\x4d\x9d\x9f\x3f\x0c\x14\x58\x59\xef\x9d\xf2\xd1\xbe\x3f\xaf\xc2\xdf\x42\xb0\x6a\x7b\x44\x89\x29\xf5\xa5\xd8\x07\xf7\x20\x89\x80\x1e\x85\xdd\x33\x65\xbd\x56\xca\xe7\x4b\x3c\xd8\x3c\x65\x4b\xcc\x37\x15\x9b\x0d\x4d\xd8\x12\xca\x76\x62\xaf\xc2\x49\xdb\x3a\xad\x5a\xbc\xee\x4b\xce\xc8\xe9\xdd\x94\x25\x99\x2d\xaa\xfb\x4e\xc7\xdb\x68\x32\x14\xb9\xb5\xe5\x2a\x08\xa4\x63\x4d\x30\x44\xf6\xfe\xfc\xf3\x0d\x4f\x08\x77\x11\xd9\xca\x31\x21\x4b\x3d\xa0\xbf\xed\x89\x9e\xdb\x97\xc8\x71\x10\x03\xd6\xab\x70\x84\x9e\x0f\xe5\xc4\x47\x82\x90\xa1\xaf\x80\x88\xb7\xe6\x95\x09\xdc\xe7\x07\x97\xe8\x64\x8c\xa7\xf2\xc3\x82\xb8\x29\xcc\xd9\x3c\x71\x86\x58\x7b\xe5\xc7\xf4\xa0\x13\xb2\xe1\x81\x02\xa2\xbf\xf6\xeb\xc4\x51\x78\x3f\xb5\xd4\xd9\xc5\x62\x6c\x88\x8c\xfa\x2c\xf8\xd1\x72\x6f\xd9\xb1\x6d\xbc\x30\x89\x49\x16\x1d\x26\xb7\xd7\x9a\xb9\xa8\xe1\x41\x1b\x24\x26\xc8\x76\xa5\x56\x93\x37\x91\x89\x83\xc2\x80\x2b\x59\xb3\x8e\xc6\x58\xab\x1d\x23\x95\xb3\x2f\x4b\x3d\xac\xb7\x94\x1e\x88\xf1\xda\x61\xf6\x4a\x6b\x33\xe6\xbc\xf5\xaa\xc1\x91\x1c\xb4\x62\x15\x25\xe9\x89\x39\xb6\x5d\xe4\x89\xec\x53\xaf\x67\xec\x8f\x1d\x2b\xe5\x8d\x06\x75\x2d\xb9\x06\x62\x51\x1e\xd4\x92\xf7\xc3\xab\x28\xe3\x37\x01\xef\xeb\x08\xe1\x0b\x98\xa6\x27\x2c\x14\x3b\xf1\xe0\x9d\xb4\x30\x14\xb8\xf6\x9d\x7c\x69\xa0\x5b\x03\xaa\x59\xb5\xc0\x37\x3e\x55\xd6\x68\x33\x18\xd0\x45\xc1\x5a\x92\xda\xaa\xa6\x92\xbb\x61\xe4\x9a\x27\xd8\x93\x05\x29\xb4\x6b\xb6\xe8\xad\x80\xbe\x86\xce\xb5\xde\x0c\x39\x1f\x91\x21\x66\xb4\x0c\x6d\x46\x3a\x13\xce\x24\x2c\x67\x6a\xf9\x9a\x92\xeb\xf6\xa3\x3c\x77\xae\xda\x7c\x33\x43\xd8\x27\x12\x95\xb0\xb7\x34\xc3\xc6\xc5\x15\x54\xf4\xc5\x94\x41\x64\x67\xbe\x5a\xf3\x7e\x4c\x63\x06\x8e\x59\x5d\x47\x10\x25\x50\x96\xa1\x44\xdb\xf8\x13\xa6\xba\xff\xc5\xb0\x29\xe8\xc9\x3c\x01\x52\x6d\xde\x0e\x17\x47\xb1\xa3\x31\x87\xf6\x83\x15\x8c\x67\xac\xd0\xf2\xd5\xa0\x1d\x64\x0d\xea\xd8\x01\x84\x2a\x78\x56\x70\x84\x68\xcd\xf1\xee\x90\xb8\xd8\x3a\xc6\xee\x27\x1a\xa5\xf5\xb2\x8d\x9d\x28\xb9\xc7\xfc\x5c\x59\x96\xe6\x38\xe2\x0a\x64\x29\x37\xcf\x56\x70\x85\x5a\x54\x04\x75\x25\xe6\x8a\x9a\xb1\xed\xa3\x53\x8c\x23\xf2\x6d\x5f\x61\x8a\x6b\xf8\x45\xab\x2e\x4d\xd1\x78\xe0\xac\x53\x69\x33\x92\xfe\x31\x02\x99\x20\xc2\x66\xd6\x43\xff\x26\x85\x71\x3b\x02\xb4\x67\x85\x89\xaa\x8a\xdf\x74\xd5\x9b\x81\x90\x38\x9a\x09\x2e\x49\x15\x4a\x8d\x51\xb0\x77\x26\xf5\xba\x8d\xba\xaf\xe7\xbc\x36\xa8\x9f\xc6\xf1\xec\x9d\xab\x51\xad\x5c\x2d\xee\x28\x2e\xf3\x53\x4c\x45\xa7\x73\xa1\x5f\x6e\x11\xce\x0d\xf3\x23\x06\xc0\xa1\xdf\xd1\xac\x6a\xf3\x52\x7a\x88\xac\xa6\x40\xed\xef\x4a\xb8\x65\x91\x13\x94\x1c\x2f\x69\x6f\x47\x98\x3c\x6f\xe7\x33\xa8\xf3\xce\x6c\xf3\xbc\x53\x58\x62\x65\x67\x64\xee\x1e\x76\x93\xbb\x39\x04\x6e\x1d\x62\xfb\xbe\x63\x2d\xd9\x82\x30\xbb\x33\x11\xd0\x6c\x25\x39\x7b\x7a\xb5\x45\xef\x7e\x95\xf0\x41\x64\x3f\x92\x5d\x5d\x69\x6e\x62\x67\x79\xa6\xad\x5a\xf7\x02\x96\xb4\xf3\xa6\x35\xec\x94\x9a\x61\x31\x39\xfc\x46\xcb\x5d\xd4\x12\xdc\x3a\x5b\xae\xa1\x39\x96\x76\x1a\x76\x8e\x85\xa5\xc6\xfd\x6f\xbf\xf9\x17\x00\x00\xff\xff\xef\xe0\x0c\x2c\x8f\x2e\x00\x00")
+
+func fontsRevFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsRevFlf,
+ "fonts/rev.flf",
+ )
+}
+
+func fontsRevFlf() (*asset, error) {
+ bytes, err := fontsRevFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/rev.flf", size: 11919, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsRomanFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x5a\x5f\xab\xe4\xb6\x15\x7f\x9f\x4f\x71\xf0\x0c\x38\x7d\xa8\xc8\xa6\x85\x9e\x40\x28\xa5\xf4\xa9\x90\x60\xfa\x70\xc1\x2c\x0b\x5a\x47\x09\x0d\x69\x56\xb0\x65\x1f\xfa\xed\x8b\xce\x1f\xe9\x48\x96\x3d\xf6\xdc\xb9\xa5\xc3\xbd\x33\x92\x2c\x5b\xbf\xf3\xff\xe8\xc8\x3f\xff\xeb\xe7\x6f\x3e\xde\xe0\xdd\xd7\xe9\xef\x0f\x5f\xc3\xef\xdf\xc1\x37\x97\x7f\xc4\xdf\x3e\x7e\x82\xe5\x3f\xf0\xc3\x2f\x3f\xfe\x0a\xdf\xff\xf2\xe9\xa7\xcf\xff\x86\x1f\xdc\xf7\x8e\x9b\x7f\x09\x5f\x3e\xff\xf3\xe3\x6f\xee\xe3\x8f\xee\xcb\xaf\x97\xbf\x7f\xf9\xf4\x13\xbc\xfb\xf6\xdb\x3f\x5e\x6e\xb7\xdb\xf5\xd4\xd7\xf5\xe2\xa2\xbb\x5d\x2f\x88\x98\xbf\x67\x9c\x6e\xd7\x8b\xc7\xf1\xa6\x57\x79\x04\x00\xea\xef\xeb\x25\x62\x84\x88\x31\x4d\x7f\x19\xc1\xbf\x8c\x7c\x09\xf2\xa4\xd7\xb7\x72\xd3\x45\xf9\xca\x57\x1d\x8e\xf2\x45\x43\x0e\xcd\x47\x91\x94\x39\x34\xab\x9e\x93\x6f\x2c\x73\x78\xa8\x1e\x31\x78\xf2\xe7\xe8\x10\x8d\x45\x59\x3c\xd0\xb2\x89\xd1\xef\x01\x79\xcc\xcf\x88\xf8\x57\xc7\xf7\x22\x7c\x10\x31\x20\x4e\xa3\x8e\x1d\xe1\x51\x12\x04\x00\x22\x3d\x72\x10\xf0\x96\x05\xdc\x66\x92\x0a\xd1\x96\x5a\x92\x74\x7a\x04\x40\x96\xf7\x9a\xb0\xba\x4d\x0f\x8a\xd1\x15\xee\x8e\xe0\xd1\x51\x07\xd3\xaf\xae\xed\x11\x1d\x4e\xfa\x80\xc4\x87\xf7\x82\x90\x6f\x91\x7b\xfc\x12\xc3\x34\xa6\x6e\xc5\xcc\xbd\x0e\xd1\x4e\x8c\x24\xcc\x23\xf4\x34\x75\xeb\x9b\xf1\x0b\x0f\x88\x00\xc1\x04\xe6\x27\x11\x94\xa6\x78\x41\xe5\x07\x81\x90\x7f\xae\x97\xe8\xba\x53\x49\xd8\xfa\x53\x2d\x31\x8c\xe6\xfe\xcb\x5a\x57\x3c\x3a\xcc\x37\xa0\x3e\x0f\x86\xe7\xd9\xd3\x06\x5f\x49\x01\x56\x9d\x62\x34\xbb\xd3\x8e\x8a\x6c\x5f\x34\x95\xd3\x69\x05\x7a\x9c\xe4\x1a\xf0\x79\x26\x1d\x45\xd8\x53\x2a\xc8\xb2\x07\x91\x3b\x18\x9b\xcc\x16\x99\xed\xb1\x58\x23\xf3\xf2\x10\x42\x17\x63\x14\xc5\x83\x80\xd3\xe8\x67\x5c\x84\x70\x06\x80\xbb\x1d\x8f\xb8\x40\xb2\x45\x82\x97\x6e\x4e\x0f\x39\x27\x46\x17\xd3\x68\x44\xf6\x3c\x70\xe7\x37\xcd\x8b\xfa\x94\xf5\x6f\x43\x93\x0b\xd3\x30\xcc\xc8\x34\xf1\xa2\x1f\xb2\x5b\x04\x57\xc0\xba\x30\x65\xff\x1e\xc9\xc9\xb0\x51\xaf\x94\xf6\x28\x4d\x07\x21\x7c\x87\xb8\xb8\x7c\x25\xb1\x33\x69\x05\x79\x43\x87\x38\xb1\x19\x2f\x21\xf9\xf2\xb3\xd6\x51\x87\xba\x14\x38\xd4\x6d\x87\x11\xa5\xe3\xc2\x48\xa2\x14\xb5\x89\x91\xd8\x9b\xf9\x8b\xf9\x1e\x00\xba\x72\x0e\x42\x94\x0f\x29\xd7\x34\xf0\xe7\x76\xbd\x70\x0c\x5b\x5c\xbe\xc9\xb7\xfc\x61\x51\x3f\x85\x0b\x49\x14\x25\xba\xe7\x80\x15\xa4\x0d\x82\x67\x1a\xe6\x45\x2c\x12\xdf\x33\x06\x09\xad\xc4\x87\x89\x5d\x32\x2e\x31\xe0\x39\xfd\x8e\x86\x0b\x41\x78\x80\x25\xc9\x31\x41\xd6\x46\x59\x1b\x66\x6d\x9c\xcd\x19\xc5\x19\x08\xa4\x8d\xa2\x8e\x42\x37\x47\x83\x19\xd1\xb9\xec\x5d\xbc\x8a\x45\x9d\x89\x4f\x04\x4b\x48\x62\x49\xd0\xb4\x25\xc6\xd3\x5c\xb0\x10\x28\x6d\x4a\x9c\x75\xad\x3b\x01\xff\xb2\xa4\x67\x1b\x6b\xab\xf2\xb0\x62\xae\x71\x1a\xcf\x72\x61\xc3\x0f\x4b\xe8\x1f\xc6\xa6\xdd\x7a\xe3\xa3\x37\x7f\x68\x42\x8e\xe2\x10\x51\x06\xba\xec\xc2\xc4\xd2\xd0\x7c\x66\x5e\x74\x8e\x4f\x4d\x9e\xec\xe7\xe5\x56\xdf\x5e\x37\x1e\x89\x5e\xa7\x23\x9a\x59\x77\x1f\xe4\x16\x69\xbb\xf8\x59\x2f\xa2\xe3\x3b\x46\xf6\x05\x0b\x3b\x23\xf1\xd0\x92\x8e\x1a\x67\x9d\x34\xd5\x58\x47\xce\x1d\x39\xed\x3c\xad\x17\x16\x03\x04\x36\x2f\x4f\xee\x28\xa4\x65\x87\x25\x00\x50\xe4\x03\x40\x97\x92\x69\x17\x12\x33\x1c\xc0\x1c\xa7\x61\x61\x50\x64\x22\xa4\xa4\xb4\xc2\xcc\xcf\x9c\xea\xf5\xee\xf4\x8a\xdb\x76\xf5\x84\xb4\xe5\x70\x76\xc4\xe1\xa0\x43\xc5\x45\x78\x19\x52\x5f\xc7\xde\x5c\xd2\xe2\xec\x38\x78\x16\x47\xd2\x48\x23\x34\x2b\xd6\x60\xd6\xf0\xb6\x46\xae\x97\xec\xe1\x98\x85\x1e\xc5\xc5\xb0\x20\x41\x2c\x5c\x4d\x9c\x02\x0c\x21\x1b\xcd\x55\xf1\x34\xda\x15\x5f\x93\x66\x91\x43\x68\x73\x8a\x15\x94\x55\xb7\x12\x6c\x4e\x6f\x18\x95\x49\x70\xf4\xe6\xfd\x2e\xa7\x39\x14\xd0\x40\x13\x9d\x47\x61\x59\x6e\xb5\xec\x02\xcb\x2f\xc3\xb0\x43\x7d\xc9\xc2\x2c\xcf\x56\x02\xbb\xdf\xb7\x00\x29\x66\x29\xbe\x24\xa3\x6a\x79\x00\x2b\xce\xd2\x05\xb3\xc7\x28\x93\xa3\xe6\x6e\xf4\x09\xf8\x0a\xbe\x3d\x13\x16\x28\xac\x83\x38\x76\xb5\xac\x55\xb3\x56\x93\xf6\xfa\x86\x2e\x32\x6b\xca\x55\x1a\x5d\x7b\x5c\x9c\xf5\x02\x92\x01\xd4\x16\x68\x13\xed\x28\x16\x0a\x1b\xd7\x6d\x5f\xb9\x17\x7b\x4e\xe4\x30\x40\x05\x76\x7b\xca\x0e\x00\x34\xeb\x64\x32\xe5\xe2\x91\x56\x72\xbd\xec\x7b\xa8\xaa\x32\x6d\x06\x45\xe1\x2a\x18\xf0\x24\x35\x71\x09\xd4\x0d\x39\x4a\x51\xcc\x7d\x9f\x1f\x83\x88\x9e\x13\xe0\x32\xd9\x6b\xea\x25\x0c\xed\xf1\xf3\xa0\x95\x94\xcb\xc5\x4a\x7a\x8a\x7f\xb8\xfb\x0c\xe3\xd5\x6e\xab\xe8\x12\xde\x54\xf2\xe4\x67\x81\x77\x28\x34\x04\x29\x51\x04\x37\x19\x05\x14\xe5\x85\x6a\x08\x60\x06\xb0\x6a\x59\x56\xec\x87\xb7\x4e\x34\xeb\x0f\x55\x5c\x2d\xe2\x5e\x18\xbe\x17\xe8\xa0\x12\x85\x02\x49\x86\x0c\x46\x1e\xb2\x03\x4c\x4c\x03\xd9\xe3\x1a\xca\x91\x81\xc3\x51\xaf\xda\xcb\x6f\x74\x35\xea\xd9\xed\xfd\xab\xa3\x5e\x09\x7a\xb2\xef\x73\x45\xd5\x5c\x28\x7a\x40\x0e\xc8\x1a\x53\x79\xf4\x5b\x79\xef\xb5\xff\x86\x96\x67\xc7\x47\x0c\xf3\x96\x9c\x34\x2b\xff\xe6\x25\x8c\x4f\xc8\xb7\x1e\xe4\xe5\x1b\xb9\x9e\xcc\x4a\x2a\x9c\x30\x1b\x09\x16\x6f\x34\x17\xc3\x63\x3f\xcc\x94\x73\x9a\xca\x07\x95\x48\x12\x04\x96\xa5\x24\xfe\x38\x0c\x52\xc9\x3e\x99\x48\xc7\x26\x5d\xc8\xde\x42\xf3\x85\x22\xac\x72\xfb\xc9\x7e\xd6\xbc\xd7\x84\x65\xeb\x51\x34\x9f\x19\x6b\x2d\x47\x38\xd2\x2f\x89\x43\xde\x25\xcd\x54\x0a\x7f\x0d\xc0\x8c\x30\xca\x12\xe2\xb3\xf3\x22\x3a\x64\x4a\x17\x3c\x64\xeb\x17\x3c\x84\xd5\x8e\xbd\xd0\x9b\x17\xf7\xf6\xf8\x04\x76\x01\xee\x9b\x86\x46\x99\x0d\xf4\xbb\x64\xf4\xe9\xa1\x81\x3d\xc2\xf6\x28\xdc\x23\x75\x87\xe6\x1d\x52\x8f\x5d\xca\x56\x50\x82\x2e\xd7\x78\x00\x38\x37\xb9\xc9\x96\x19\xd1\xf1\xc9\x8a\xa1\xca\xd2\xe2\x70\x9a\xed\xde\x32\x28\xc5\x0b\x34\x5e\xa3\x17\x68\x8f\xc5\xad\x4a\x72\x56\x5c\x8d\x8c\x5a\x45\x6b\xa5\x51\x89\xe0\x99\x06\x0b\x8d\x47\x09\x23\xd7\xf2\x82\xa9\x50\xb1\x02\x4d\xe5\x01\x01\xab\x4a\x05\x5f\x2c\x6c\x14\xb8\x6e\xaa\x8f\x15\xdb\xaa\xc1\x71\x83\xe5\x2a\x05\xdc\xfb\xc9\xd9\x31\xb4\x3f\xf6\xf0\xc0\x97\x02\x83\x2f\xc2\xd7\xb3\x39\x2e\x22\x16\xd6\xbb\xc2\xf4\x7e\xce\xdc\x66\xcf\x3c\x82\x77\x7e\x52\xec\xda\xc4\x0a\x2e\x0e\x1c\x44\x06\xda\xd2\x0c\xf7\x56\x3e\xdf\x3a\x11\x75\x4e\xf4\x6a\x55\x3a\x7c\x9f\x16\x19\x67\x3e\x3f\xf0\x32\xe1\xd8\xb7\x79\xd6\xad\x69\x9b\xe3\x0a\x3f\x01\xfc\x4e\xab\xf1\x2e\x4e\x83\x24\xa7\x01\xbf\xca\xb9\x35\x6d\x8d\x86\xa1\xb6\xf5\xed\x36\x3d\x08\xf3\x95\x21\x47\xae\x92\x9e\x68\xf1\x4d\x4e\x72\x4d\x29\xa8\x2a\x72\x68\x95\x78\xa6\x3a\xfc\x54\xe7\x50\x7b\x9d\x7b\xb4\x4b\x01\x92\x96\x1f\xe6\x2a\x17\xce\x6d\x17\xe5\x44\x60\xbd\xf6\x2e\xed\xf4\x49\x0c\xd0\x2b\xca\x52\x5e\x3a\xf3\x57\x2a\x78\x65\xc1\x5e\x47\x96\xc7\x69\x78\x13\xda\x51\x6a\xaf\x52\x3b\x2c\x7c\x70\xf1\x21\xda\x5d\x4c\x59\x9e\x0a\x90\xec\x93\xf7\x91\x26\x85\xd9\x68\x89\xb3\x3e\x63\x9f\x2b\x2e\x38\x9b\x01\x2a\x81\x6b\x9e\xa2\x90\xc5\x9d\x68\x98\x32\xd0\xa3\xe6\xbf\x91\xde\xce\xdd\x54\xd4\x16\x03\xd4\x6f\xe6\xd4\x4c\x29\x72\x79\x3f\xc6\x47\x4d\x58\xd5\xfa\xea\xca\x4a\x55\x57\xe9\xa4\xe2\xf7\x5c\x04\x44\x39\xa7\xf3\xc3\xa8\xbe\x26\xc3\xba\x3d\x56\x4f\x91\x37\x74\x80\x9c\xac\x88\xff\x99\x35\x96\x03\x2c\x04\xa5\x83\x19\x9a\xeb\x61\x1c\x32\xed\x7e\xa6\xd9\xce\x3c\xc0\xc2\x7b\x2c\x7b\x88\x85\xd5\xa7\x0d\xe0\x90\xe3\x82\x13\x65\x71\x76\x7f\xc7\x2a\xd3\x55\x9c\x9e\xfa\xf4\x94\x68\xb3\x0c\xb2\x85\xa5\x33\x76\x37\xa8\xb9\x1e\xec\xb7\xd3\xf4\xde\xa5\x7d\xbf\xd6\xd4\x3a\x10\x5f\xe1\xd3\x57\xa0\x88\x07\x66\x6d\xc0\x63\xf1\x0c\xd1\xac\x6f\x03\x4f\xa9\x6d\x6c\xfb\xf4\x2d\xaf\x07\x9c\xa5\x1e\x0c\x2b\x2f\x1c\x56\x4c\xd9\x09\xed\x1b\x54\x95\xd7\x1b\x1a\x08\xb7\xaa\x49\x6b\x07\x39\x37\xa6\x34\x61\x32\x64\xd5\xcd\x80\xa5\x3a\xd2\x7d\x58\x8f\xe2\x66\x06\xe7\x2e\x42\xeb\x57\x29\xba\xd2\x81\xe1\x9c\x9d\x80\xe3\x84\x26\x57\x13\x2a\x31\xef\x2f\xa7\x99\x2e\xa5\x2f\xe4\xb9\xca\xeb\x11\x98\xdf\x8d\xa8\x5b\xcc\xb4\xb4\xd0\xdd\x6c\xf4\x7e\x8e\x58\xbc\x9e\xd7\x4a\x4d\xc7\x80\x9a\x9e\x7f\x41\x7c\x19\x5e\xda\xfc\xe8\xb8\x39\x6d\x82\xd1\x62\x85\x14\x1b\xec\xd6\xcc\x35\x1b\xb3\x6a\x5b\xb6\x3e\xab\x3f\x03\xa6\x33\xa3\x82\xd5\xc3\xd6\x03\xf8\xa1\x83\xb2\x07\xb5\x8b\x77\x07\xc4\x7a\xe8\x2c\x2f\x17\xe7\x8a\x85\xcd\x06\x92\x8b\x38\x8c\x66\x9f\x2d\x55\xac\x47\xfd\xe4\x93\x05\x6b\xde\x89\x8d\xce\x4d\xb9\xc6\xe1\x67\x29\xfe\xed\x83\x59\x39\xae\xfa\x85\xa1\x71\x18\xfe\x14\xf2\x5e\xd8\x95\x13\x30\x69\xd2\xae\x39\xf4\xb7\xcc\x7b\x9d\xeb\xa5\x94\xb4\x83\x9e\xb2\xa9\x0d\x7f\x57\x27\xa2\xa9\x31\xa3\x6e\x73\x67\xeb\x12\x7b\x8d\xeb\x85\x42\x8b\xfc\xc3\x6d\xdd\x97\x7f\xad\x0f\xab\xfc\x8b\xfb\xe0\xa7\x21\xfe\xb9\x1a\xd1\xb7\xa0\x5c\x55\x5d\xd8\xc0\x50\x12\x88\xdb\xf5\xc2\xc5\xec\x53\xef\x4d\xbd\xba\x23\x39\x28\xbf\xc7\x60\xb3\x51\x7e\x8f\x41\xf2\x52\xf8\xbf\x7b\x8f\xc1\x1e\x19\xc9\x7b\x3d\x5a\xd3\xd6\xac\xb7\x39\xdd\x85\xaa\xf0\xdf\x1d\xb0\xa7\x28\x62\x54\x3b\x27\xba\x87\x06\x94\xbf\x05\x29\xf1\x94\xd9\xc2\xef\x22\x9d\xad\x2e\x3f\xbd\x7a\x2c\x67\xc2\x51\x5f\x26\xd7\x7d\xc3\x5b\x97\x1a\xf6\x17\x7e\xcb\x9c\x30\xaf\x0c\x45\x20\x76\x0b\xf6\xbf\x0d\xe5\x36\x0d\x55\x7a\xcb\xf1\x90\x2b\xef\x8a\x34\x3e\x70\x6b\x5a\x84\xf9\xdc\x2b\x7f\xff\x0d\x00\x00\xff\xff\xb1\xed\x38\xfe\x94\x32\x00\x00")
+
+func fontsRomanFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsRomanFlf,
+ "fonts/roman.flf",
+ )
+}
+
+func fontsRomanFlf() (*asset, error) {
+ bytes, err := fontsRomanFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/roman.flf", size: 12948, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsRot13Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x1c\xd3\xd5\x77\x5d\x45\x18\x86\xf1\xfb\xe7\xaf\xd8\x50\xa4\x05\x92\xec\x99\xed\xe8\xdb\x16\x28\x45\x0b\x94\xe2\x72\x9a\x9c\xd3\x06\x4e\x93\x70\x92\x14\x8a\x15\x77\x77\x77\x77\x77\x77\x77\x77\x77\x77\x87\xf5\x76\xcd\xc5\x6f\xae\x66\xcd\x5a\xdf\xf3\x75\xba\x9d\xd8\x5a\x9a\x04\x9f\x34\xe9\x0b\x49\x0d\xbd\xd1\x89\x90\xf5\x77\xba\x9d\x64\xea\xcc\x69\x49\x68\x9a\x3c\x99\xbf\x24\x99\x37\x3c\x38\x31\xda\x4b\xe6\xb4\x7a\xad\xa1\x56\x32\x75\xf1\xd8\xb2\x8b\x86\x47\x3a\xfd\x93\x13\x9d\xf1\x45\xfd\x83\xdd\x69\x49\x93\x0f\x84\x38\x10\xeb\x7e\x98\xd1\x1a\x6f\x0f\x25\xa3\x23\xc9\xdc\x76\x6f\xd1\xf0\x48\xab\xeb\x47\x66\x75\xdb\x23\x23\xc9\xcc\x85\xad\xb1\xb1\x76\xb7\x9b\xe4\x03\x4d\x06\xb3\x47\x06\xbb\x93\x43\xed\xf1\x64\x70\x61\xab\xd7\x1a\x9c\x68\xf7\xc6\x93\x10\xeb\xbe\x58\x14\x74\x86\x17\x74\xdb\x13\x49\xaf\xdd\x6d\xb7\xc6\xdb\x49\xec\x0f\x49\x5f\x5f\x12\x62\x32\x7d\x72\xc1\xb2\xaf\xc1\x52\xb1\x9c\x58\x5e\x4c\x11\x2b\x88\x15\xc5\x4a\x62\x65\x31\x55\x4c\x13\xab\x88\x55\xc5\x6a\xa2\x4f\xf4\x8b\x01\x91\x8a\x20\xa2\xc8\x44\x2e\x0a\x51\x8a\x4a\xd4\xa2\x11\xab\x8b\x35\xc4\x9a\x62\x2d\xb1\xb6\x58\x47\x68\x0a\x9b\x8a\xcd\xc4\x1c\xb1\xb9\xd8\x42\x6c\x29\xe6\x8a\xad\xc4\x3c\xb1\xb5\xd8\x46\x6c\x2b\xb6\x13\xd3\xc5\x0c\x31\x53\xac\x2b\xd6\x13\xeb\x8b\x59\x62\x03\x31\x5b\x6c\x28\x36\x12\x1b\x8b\x4d\xc4\xf6\x62\x07\xb1\xa3\xd8\x49\xec\x2c\x76\x11\x23\x62\x54\x8c\x89\xdd\x45\x4f\x8c\x8b\x09\x31\x29\x16\x8b\x3d\xc4\x9e\x62\x89\xd8\x4b\xb4\xc4\x7c\x31\x28\x86\x44\x5b\x74\xc4\x02\xb1\x50\x0c\x8b\x5d\xc5\x6e\xa2\x2b\x16\x89\xbd\xc5\x3e\x62\x5f\xb1\x9f\x78\x58\xbc\x2a\xde\x16\x1f\x8b\x5f\xc5\xdf\xe2\x3d\x11\x62\xcd\xfe\xa6\xe1\x00\x11\xb2\x94\x03\x4d\xe0\x20\x13\x39\xd8\x64\x1c\x62\x72\x0e\x35\x05\x87\x99\x92\xc3\x4d\xc5\x11\xa6\xe6\x48\xd3\x70\x94\x08\x79\xca\xd1\x26\x70\x8c\x89\x1c\x6b\x32\x8e\x33\x39\xc7\x9b\x82\x13\x4c\xc9\x89\xa6\xe2\x24\x53\x73\xb2\x69\x38\x45\x84\x22\xe5\x54\x13\x38\xcd\x44\x4e\x37\x19\x67\x98\x9c\x33\x4d\xc1\x59\xa6\xe4\x6c\x53\x71\x8e\xa9\x39\xd7\x34\x9c\x27\x42\x99\x72\xbe\x09\x5c\x60\x22\x17\x9a\x8c\x8b\x4c\xce\xc5\xa6\xe0\x12\x53\x72\xa9\xa9\xb8\xcc\xd4\x5c\x6e\x1a\xae\x10\xa1\x4a\xb9\xd2\x04\xae\x32\x91\xab\x4d\xc6\x35\x26\xe7\x5a\x53\x70\x9d\x29\xb9\xde\x54\xdc\x60\x6a\x6e\x34\x0d\x37\x89\x50\xa7\xdc\x6c\x02\xb7\x98\xc8\xad\x26\xe3\x36\x93\x73\xbb\x29\xb8\xc3\x94\xdc\x69\x2a\xee\x32\x35\x77\x9b\x86\x7b\x44\x68\x52\xee\x35\x81\xfb\x4c\xe4\x7e\x93\xf1\x80\xc9\x79\xd0\x14\x3c\x64\x4a\x0f\x3d\x34\x15\x8f\x98\x9a\x47\x4d\xc3\x63\x22\xa6\x29\x8f\x9b\xc0\x13\x26\xf2\xa4\xc9\x78\xca\xe4\x3c\x6d\x0a\x9e\x31\x25\xcf\x9a\x8a\xe7\x4c\xcd\xf3\xa6\xe1\x05\x11\x43\xca\x8b\x26\xf0\x92\x89\xbc\x6c\x32\x5e\x31\xb9\x7b\x8b\xa1\xe0\x35\x53\xf2\xba\xa9\x78\xc3\xd4\xbc\x69\x1a\xde\x12\x31\xa6\xce\x32\xc6\xc0\x3b\x26\xf2\xae\xc9\xdc\x67\x8c\x39\xef\x9b\x82\x0f\x4c\xc9\x87\xa6\xe2\x23\x53\xbb\xe5\x18\x1b\x3e\x11\x31\x4b\xf9\xd4\x04\x3e\x33\x91\xcf\x4d\xc6\x17\x26\xe7\x4b\x53\xf0\x95\x29\xf9\xda\x54\x7c\x63\x6a\xbe\x35\x0d\xdf\x89\x98\xa7\x7c\x6f\x02\x3f\x98\xc8\x8f\x26\xe3\x27\x93\xf3\xb3\x29\xf8\xc5\x94\x5e\xa3\x98\x57\xfc\x66\x6a\x7e\x37\x0d\x7f\x88\x58\xa4\xfc\x69\x02\x7f\x99\xe8\x6d\x8b\x45\xc6\x3f\x26\xe7\x5f\x53\xf0\x9f\xf8\x3f\x00\x00\xff\xff\x89\x5e\x4d\x5c\x75\x05\x00\x00")
+
+func fontsRot13FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsRot13Flf,
+ "fonts/rot13.flf",
+ )
+}
+
+func fontsRot13Flf() (*asset, error) {
+ bytes, err := fontsRot13FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/rot13.flf", size: 1397, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsRoundedFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x58\xcb\x6a\x5e\x37\x10\xde\x9f\xa7\xf8\xc0\x59\xe8\x6c\xac\xc6\xf4\x42\x76\x7d\x01\xa7\x50\x68\xe9\xe2\xc0\xe0\xc6\x09\x0d\x69\x5d\x48\xf1\x22\xa0\x87\x2f\x9a\x9b\xa4\x23\x9d\x9b\xd3\x82\xfd\xff\x42\xbf\x34\xf7\xf9\x66\x34\x1f\xfe\xfc\x70\xf7\xf0\x0a\x3f\xe0\x7b\xdc\x7d\x83\xd7\xdf\xe1\x6e\xfa\xf9\xef\xe7\xa7\xc7\xf7\x8f\xf8\xfd\x0b\xde\x7e\x7c\xf7\x09\xf7\x1f\x9f\xde\x7f\xfe\x07\x6f\x6f\xef\x6f\x65\xf9\xe3\xe3\xf3\xe7\x3f\x1e\xfe\xba\x7d\x78\x77\xfb\xfc\x69\xba\x7f\xf8\x82\xd7\x6f\xde\x7c\x3b\xbd\x7a\x75\xb3\xf5\x7f\x33\x81\x70\x33\x25\x24\xfb\xa0\x64\x7b\xbc\x02\xe4\x0c\x6f\x05\xcc\x01\xf3\xcd\x94\x22\xb0\xc8\xaf\xf9\xc0\xd6\x37\x2f\x28\x5f\xce\x7b\x94\xf0\x0b\x12\x93\x21\xfe\x9d\x66\xd9\xfd\xa9\xdf\x45\xa2\x27\x4a\x85\x54\x45\xcd\x68\x25\x91\x1b\x44\xf9\x46\x22\x22\x64\xf9\x99\x8a\x48\x9e\x1a\x0a\xaa\x86\xe8\x41\x33\x58\x5b\x00\x11\x91\x0f\xe5\xef\xbc\xc8\xdf\xaa\x3e\x82\x08\x53\xf8\x33\x17\x39\x45\x58\xc0\x26\xc9\xc4\xe6\xbc\x37\x83\x10\x74\x2f\x1b\x28\xef\x2d\x44\x71\xa9\xa8\xc0\x2c\x6e\x76\x14\x13\xaf\x3e\x98\x95\xb0\x99\xd9\x2f\x68\x3f\xe1\x24\x55\xab\x4c\x8f\xf9\x89\x56\xd5\x67\x20\xe5\xa1\x06\x64\x1b\xb0\x09\xf3\xef\x2a\xca\x92\x90\x98\x15\x66\x16\x32\xb0\x8d\x62\x42\x32\x46\x6c\xcb\xde\x1d\xee\xee\x95\x5f\xc4\x0b\xf3\xc0\x0b\x8d\x39\x07\xda\x37\xb6\x19\x5c\x9b\xb2\x0f\x48\x78\x90\xf8\x7e\x70\xe6\x04\x0f\xbd\x69\x3c\x48\xaf\xed\x85\x05\x34\x2c\x3a\x1e\x22\x52\xde\x54\xa1\xa0\x39\x43\x96\x5d\x11\x51\x73\x0c\x88\x24\x4c\x16\x3e\x1b\x3b\xab\x7a\x90\x05\x26\x85\xe2\x37\x71\x05\xd4\xa0\x66\x6c\xac\x2d\x21\x51\xe1\x42\xc9\xcf\x12\x1f\x10\xf1\x66\x09\x61\x65\x9f\x94\x02\x24\x8f\x56\xc4\x76\xa8\x91\x53\xd3\xdd\x30\xda\xed\x55\x24\x37\x39\x2b\x23\x79\x96\xb5\x69\xa4\x00\x1c\x62\x52\xb5\xa4\x34\x94\xad\x84\x84\x48\x7f\x4e\xe2\x81\x6c\x07\xd4\x04\x72\x98\x9a\x48\xcc\xd4\xd2\x25\x6a\xaa\xbe\x1d\x8e\x82\x1f\x28\xd1\x96\x4d\x12\x07\x09\x37\x0c\xb4\x6a\x37\xba\x6c\x41\xa3\x67\xde\x0e\xb4\x3d\x4d\xcb\xee\x59\x2f\x8c\xd2\xab\x4f\xb4\x8d\x33\x6d\xc2\xb7\xf0\x17\x24\xaa\x0a\xe4\x4d\x1d\xfe\xf4\x90\x70\x0c\x12\x4e\xac\x86\x4f\x8d\x0c\x87\xcc\xa9\x4d\x4a\x07\xfe\x7c\x28\xc8\x69\xf5\x55\x8d\x82\x5c\x12\x36\x21\x22\xfb\x08\x16\x3f\x8c\x2a\x8a\xf1\x8b\x65\x63\xf2\xb3\x4b\xe5\xe5\x0b\x9e\xd3\x18\xd5\xa2\x6e\x9e\x13\xe8\xda\xca\x1f\xcf\x14\x94\x4c\x99\x55\x36\x96\x38\x98\x6c\xba\x7b\x2d\x7f\xdc\xfe\x22\x90\x2d\xed\xac\x6a\x7a\x88\x3b\x0e\xad\x0d\x7e\x58\xfb\x92\xc5\x89\x8e\x1f\xb1\xcb\x9f\x1d\xbb\xa1\xe4\xf6\xbc\x92\x6d\x1f\x13\xcf\x52\x73\xa5\x29\xad\x42\xf1\xc8\x6e\xe6\xd3\x0c\xd3\x70\x4d\x73\x0b\xb3\x93\xdb\x6e\x21\x8e\x45\xed\x64\x5e\x1c\x21\x6d\x8b\xb8\x6a\x16\x8f\x90\x8e\x3c\xcf\xb4\x74\x25\x6e\x0a\x92\x47\xf8\x00\xe9\xd6\xf2\x0b\xf4\x30\x59\xab\xa3\xd6\x62\x30\xa5\x45\x12\x8a\xe5\x5f\x7a\x4f\x79\xf4\x09\x35\x17\x68\x37\x26\x2f\xfa\x1d\xd6\x25\x27\xa4\x44\x29\x5d\xca\xbe\x71\xbe\xf4\x11\xfe\xdf\x52\x33\x6b\xee\x57\x88\xed\x1a\x2a\x51\x64\xa8\xf5\xf2\x08\x07\xb9\x17\xbc\xcd\x65\xd1\x2e\x20\xc3\x50\x36\xc0\x65\xab\x23\x64\x50\xbd\x5c\x36\xed\x8b\x68\xb6\x1a\x5a\x21\xf1\xd7\xf5\x10\x55\xf3\xad\xa9\xd0\x2f\x47\x6d\xf6\x46\x2e\xbf\xd4\xa7\xe7\xa9\xb1\xcd\xac\x11\x5e\xc6\x88\xea\x51\x1f\x68\x96\xbf\x2e\x17\xe0\xb9\x60\xcb\x6b\xb2\x55\x1d\xb1\xca\x66\x0d\xf9\xbe\x4f\x8f\x2c\x54\x77\x99\x05\x59\xcc\x63\xe7\x32\x4b\x82\x0c\xe5\xa9\x60\xb2\x6d\x60\x61\x45\x4d\x51\xd8\x10\xac\xfe\x32\xf4\xb1\x5b\x45\x1b\x4f\x34\xf5\x8e\x70\x5e\xe4\x2d\x0a\x8b\x72\xac\xec\x51\x38\x06\xeb\xe7\x52\xfd\x55\x34\x4f\x15\x47\xd1\x4d\x34\x13\xb2\xa1\x7d\xcc\x1e\x3e\xbd\x7a\x18\xd8\x5a\x6e\x57\x0f\xac\x1f\xcd\x36\x79\x58\x7f\x1c\x3f\x16\xb3\x92\xd2\x21\xa7\x9b\x69\x59\x79\x79\x68\x63\x8e\x16\xab\xe5\xde\xf3\x97\x8e\x3f\x8e\x34\x6e\x16\x0d\xaa\x38\xa6\x38\xa2\xcc\xdd\xfd\xd5\x43\xd4\xb2\x39\x42\xe7\x1b\x08\x75\x7e\xa7\x03\xfe\x5e\xcb\x4c\x6d\x5e\x90\x47\x7f\xc7\x5f\x85\x03\x0b\x3c\xdb\x93\xbe\xbc\xe9\xf5\x51\xef\x90\xb5\x46\xac\x63\x33\x0c\xd4\x28\x79\x97\xce\xbb\xa1\x14\xc2\x2e\xd4\x9b\xc7\xc5\xb8\x5d\x31\x43\x3b\xc4\x60\x3b\x2b\xe2\x66\x70\x38\xbc\x50\xb4\x9a\x23\x7d\x32\xa5\xa6\x0d\xf1\x31\x4d\x3f\xcb\x19\x4d\x74\xc6\x7e\x54\x03\xa0\x33\x00\xad\x0d\xb0\x7b\xff\x84\x01\xc7\x0e\x6c\xde\x3f\xda\xc3\x79\x07\xf7\x02\xfe\xa5\x93\x93\x0e\x42\x27\x2b\xe7\x02\xa8\xe1\xef\x6f\xd4\x24\x01\x74\x22\x0f\x8b\x17\x47\x03\x9d\x7a\xc7\xb4\xcf\x97\xab\x61\xa3\x86\x6c\xd1\xfc\xfc\x44\x4c\xc7\x36\x5c\x53\x7b\x00\x58\x19\xae\x2a\x61\xa9\x51\xfc\x1c\x00\x75\xf7\xb1\xe0\x57\x2f\xe9\x71\x08\xd9\xed\x7d\xea\xf8\xe3\x8a\xe3\xad\xa0\x73\x2b\x21\x23\xc6\xdf\x6c\xc0\xd8\xe5\xc8\x15\xfd\xdd\xf1\x41\x0d\x71\x58\x00\xe0\x73\xaf\x38\x1a\x0d\x58\xc9\x93\x8a\xc7\xbf\x68\x49\x0e\x08\x42\xcd\x5d\x57\x7b\xae\x7d\x21\x95\xf9\x79\xff\x42\xd2\x27\x88\x55\x6b\x4d\x7d\xe8\x20\x41\x1b\xde\xd0\xf4\x59\xda\x9c\xfa\x40\x04\x4b\xd4\x19\xc5\xd2\x36\x50\x07\xab\x55\x8d\x9d\x89\xe8\x2b\xdf\x84\x63\x6a\xfc\xfb\xff\xda\x95\x9e\xa4\x66\xb4\x42\x3f\x0f\x3a\xd5\x07\xb4\xf7\xaf\xe1\xdf\x80\xff\xb5\x34\xee\xb9\xe9\xb4\x29\x21\x05\x9b\xc4\xe8\x0e\xa5\xb0\xba\xff\x6f\x00\x00\x00\xff\xff\xed\x11\xce\x52\x3b\x1a\x00\x00")
+
+func fontsRoundedFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsRoundedFlf,
+ "fonts/rounded.flf",
+ )
+}
+
+func fontsRoundedFlf() (*asset, error) {
+ bytes, err := fontsRoundedFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/rounded.flf", size: 6715, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsRowancapFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x56\xef\x4f\xeb\x36\x14\xfd\xee\xbf\xe2\x2a\xe2\xc3\x26\x15\xbf\x86\x3d\x7e\x55\xe8\x2d\x08\xd6\x27\x44\x33\x45\x80\x2a\xed\xa3\xe3\x38\x6d\x46\x62\x47\xb6\x03\x63\x7f\xfd\xe4\xc4\x89\x93\xfe\x00\xca\xa6\x09\xe9\xb5\x08\x1a\x17\x7c\x7c\xce\xb9\xe7\x5e\x9c\xe6\xe9\x11\x39\x80\x13\x38\x06\xff\x0c\xbe\xc2\x91\x8f\xd0\x34\x5b\xe4\x4c\x03\x15\xfc\x89\x49\x95\x09\x0e\xf1\x0b\xdc\x32\xae\xe1\x77\xa2\x14\xe3\x23\x78\xe4\xf5\x43\x50\x15\x19\x5d\x62\x96\x54\x23\xf0\xbf\xf8\x5f\xce\x8f\x11\x92\xe2\x99\x70\x4a\x4a\x9c\xe6\x29\x42\x53\x29\x0a\x50\x25\xa3\x5a\xb2\xa0\xca\x2a\x6a\xfe\x18\x5d\x13\xcd\x26\x70\x4f\xf4\x08\x7c\x1f\xae\x19\x05\xff\xfc\xfc\x17\xf0\x8f\x26\xc7\xe7\x13\xff\x0c\x0e\xc7\x27\xe3\x71\xbd\x77\x02\x37\x84\xc3\xd5\x92\x64\x70\xb1\x0a\xf3\x0d\xdd\xb1\x32\x7f\x01\x2d\x26\xe0\x5d\x67\x8a\x56\xca\x90\x55\x40\x62\x51\x69\xd0\x4b\x06\x45\x95\xeb\xec\x30\x15\x5c\x43\x4e\xe4\x82\x1d\xe6\x4c\x6b\x26\xa1\x94\x62\x21\x49\x31\x82\xe9\xcd\xf7\xd9\x6f\x0f\xd8\x43\x60\x5e\x17\xcd\xf2\x70\x16\x3c\x15\x09\xa6\x4a\x60\x77\xd6\x83\x98\x40\x68\xe0\xca\x9c\x81\x64\x34\x2b\x33\xc6\xb5\x02\x91\x42\x9e\x29\x0d\xed\xd6\x57\x41\xee\xab\xf8\x4f\x46\xf5\x04\xee\x45\xc1\xf4\x32\xe3\x0b\x48\x85\x04\x25\x0a\x26\x38\xab\xdf\x9f\x97\x4c\x32\xc0\x80\x31\x42\xdf\x1a\x0b\x66\x82\x3e\x32\x59\x92\x5c\x88\xbf\x09\x5c\x44\x37\x77\x37\xb3\xd9\xd5\xd1\xe9\xe9\x38\xa0\x22\x96\x04\x57\x3c\x6b\xf0\xd1\x54\x54\x3c\xa9\xa5\x53\x52\xaa\x1a\x9c\x40\x29\x94\xca\xe2\x9c\x41\x6d\x84\xf9\xac\xa9\xf0\x08\xb2\x14\x08\x7f\x31\x47\x3f\x8b\x2a\x4f\x80\x12\xc9\x40\x0b\x60\x7f\x95\x84\x27\xbf\x22\x5b\x03\xe5\xfb\xa7\xbe\x7f\x36\x0e\x16\x19\x61\x31\xa6\x14\x17\x82\x13\x55\x57\x1e\x93\x0a\x7e\xba\x33\x45\x87\x2b\x49\x9e\x53\x21\x93\x9f\x3b\x9d\x97\x30\x15\x5c\x63\x5b\x70\x7f\xdc\xab\xf5\xc9\xe4\xf8\xab\xa9\xf5\xf7\xf0\x01\xa1\x03\x80\x83\xe0\xf5\x9f\x01\xea\x7d\x7d\xee\x45\x9d\x25\x58\x7f\x3f\x00\x52\x48\xa3\x27\x09\x23\xa3\xcb\x7e\xfe\x19\x28\xff\x9f\xd6\x60\x12\x86\x61\xdc\xe8\x4f\xc2\xc8\x4b\xc2\xa8\x5e\x24\xa1\x79\x45\xb5\x63\xc6\x21\xf3\x6d\x16\xee\xb9\xf3\xb2\x35\x0e\xc0\x6e\xdb\x06\x77\xeb\xb5\x70\x98\x84\x53\x0b\x67\x4e\xf1\xb6\xc0\xf5\xc8\x19\xb0\x79\x03\x66\x8f\xb7\x6c\x30\xb1\xcc\xe6\x1b\x91\x36\xf3\x82\x79\xc7\xcb\xca\xe9\x78\x45\xef\xe0\xd5\xba\xe3\xf0\xba\x70\x25\x8d\x6b\xd0\x19\x07\x8e\x6b\xd8\xff\xdd\x7f\x05\x1a\x39\x98\x0d\xa0\xb5\x83\x4e\xab\xd7\x07\x69\x04\x36\x26\x76\x25\x75\x2e\x6e\x11\x5e\xfb\xe5\x38\xb6\xe6\xb9\xc0\x0c\x13\x33\x8c\xcc\x36\xe1\x16\x90\x14\xb2\x05\x8b\x06\x62\x9d\x50\x07\x10\x58\x0e\x3d\xd3\x5a\xdf\xec\xa2\xcb\xec\x2d\x7c\x58\x20\x1e\x0a\x34\x11\xb6\xbc\xbc\xcb\x3a\xc3\x3b\x09\xec\x81\xad\x0b\x1c\x0a\x59\x89\xc5\x5a\x5b\xf5\x5a\x2b\x5a\x8d\xf1\xc6\x8e\xdd\xd4\xb5\xab\xc7\xc4\x83\xc2\x6e\xea\x90\x77\x0e\x82\x95\xce\x4d\x5c\xe7\x5a\xac\x8f\x76\x2e\x1e\x4c\x94\xc8\x5b\x69\x89\x41\x47\xec\xc2\x0b\xf7\x78\x85\x8e\x57\xe4\xb5\x85\xda\x89\x97\x9b\x74\x36\x25\x6f\xfa\x95\x0c\x78\xc1\xbc\x01\x33\xce\xc4\xcd\xf6\xa8\xcd\xf0\x6b\x7e\xd9\xac\x0c\x67\x88\xcb\xdb\xd0\xac\xbe\x57\xeb\x02\xdf\x99\x01\x5b\xc4\xb7\x1a\xab\x87\x36\x0c\x41\x87\xf5\x47\xf8\x74\xd9\x89\x9a\x5b\xa0\xed\xbc\xd6\xb8\xbd\x12\x7f\xbc\x3e\xe1\xe6\x9b\xb9\xc2\xd6\x41\x70\xeb\x06\x41\x5d\xab\x0f\x0d\x82\x15\xde\x0e\x72\xee\x66\x67\x72\xb9\xcb\xb0\x1a\xcc\x0c\x9c\xb4\x0d\xd1\x3d\xd7\xab\xee\xf9\xcd\x7f\x43\xfb\xfb\xc5\xfe\x7e\xb1\xbf\x5f\xf4\x37\xff\xd0\xf7\x0b\xd8\xdf\x2f\xf6\xf7\x8b\x3e\xd0\xfe\x7e\xb1\xbf\x5f\x7c\x9e\xfb\xc5\xbf\x5e\xfc\x13\x00\x00\xff\xff\xdf\x17\x66\x40\x70\x15\x00\x00")
+
+func fontsRowancapFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsRowancapFlf,
+ "fonts/rowancap.flf",
+ )
+}
+
+func fontsRowancapFlf() (*asset, error) {
+ bytes, err := fontsRowancapFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/rowancap.flf", size: 5488, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsRozzoFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\xdf\x6b\x1c\xb7\x13\x7f\xbf\xbf\x62\xd0\x2d\x1c\x04\x7d\x7d\xdf\x18\x42\xa7\x6f\xa5\x67\xf2\x12\x0a\xa2\xe4\x65\x29\x85\xdc\x56\x72\x9b\xc6\xf5\x85\x38\x6e\x49\xfe\xfa\x22\xcd\x8c\x34\xda\xd5\xfe\x48\xea\xf6\xc0\xbb\x92\x56\x3b\x33\x9a\x9f\x9f\x59\xdf\xde\xdd\x5e\x9f\x3b\xf8\x06\x5e\xc0\xf5\xff\xe1\x7f\xcf\xe1\x7a\xf7\xe1\xf2\xf9\xf3\xe5\xea\xf6\xee\x16\x6e\x2f\xf7\x1f\x61\xf8\x04\x3f\xbc\x7d\x17\xe0\xc7\xcb\xc3\xe3\x5d\x78\x07\x3f\x3d\xde\x9f\x3f\x5c\x7f\xf7\x70\x7b\xbe\xba\xbc\x0f\x57\xc1\x5f\xfd\x7a\xf9\xf3\x67\x78\x7e\x7c\x7e\x7d\xfc\xf6\xc5\xee\xf5\x6f\x6f\x1f\xe0\xaf\xf3\x03\x0c\xe7\x87\xe0\xe1\x72\x0f\x2f\x1f\x7f\x7f\xfb\xe9\xfc\xc7\xf9\xfb\xbb\xf3\x2f\xef\xe0\xf5\x87\xc7\xf0\xfa\xd3\xfb\x00\x2f\x2f\xf7\x1f\xaf\x76\x5d\xb7\x9f\xfb\xdb\xef\x10\xb1\x93\xab\x41\xd3\xed\x77\x10\xa0\x8c\x01\xe4\xba\xdf\x21\xa4\xad\xe9\xaa\x1e\x4c\xaf\xe9\x06\x1e\x1d\xf8\x44\x05\xcb\x2f\x6d\xa1\x27\x2e\xbd\x50\x3f\x0b\xf2\x44\x88\xc9\x6f\x3c\x4b\x53\xe4\x07\x1e\x01\x93\xd0\x27\x44\xd9\xdc\x23\xe0\x20\xaf\x21\xde\xc4\x91\x41\x40\xc7\x6b\xc8\x64\x2c\x5a\x38\x02\x9f\xf8\x28\x9c\x8e\x42\xe6\x18\x9f\xc7\xd1\x11\x0c\x1a\x2d\x87\x1e\xf1\xd0\xe3\x60\xd3\xb2\xf5\x03\xf4\xee\x40\xca\xec\x71\x00\x88\xeb\x1e\x87\x38\x31\xf1\xd5\x1e\x69\x52\x1d\xac\x1e\xa7\x17\xd2\x56\xd7\xed\x77\x36\x09\xee\xe6\x15\x1e\x48\xb9\x5e\x14\x99\x0d\xcb\xa6\x65\xe5\xf7\x62\x04\x13\xef\x71\x43\x10\x3b\x0c\x62\x8f\xa0\x5e\x8c\x37\xb6\xa1\xa3\xe7\x86\x38\xf6\x03\x20\xf8\x28\x1a\xbc\xb9\xc1\x57\x87\xf8\xd0\x3b\x40\xe8\x87\xb6\x92\x16\x14\x97\x96\xb0\xf8\x83\x9a\x57\xaf\x94\x7b\xcb\xf7\x66\xd4\x55\x6f\x12\xea\xf3\x8e\xbb\x40\xb5\xe5\xe3\xb4\xe0\xc5\xb1\xc4\xaf\xd9\x8d\x13\x01\xb7\xac\x80\x80\x08\x62\x86\x64\x3f\x10\x63\x9c\x90\x67\xe4\xbf\x3d\xcf\x98\x95\x49\x33\xb3\x25\x54\x7c\xe5\x1c\xde\x64\x1d\x8f\xee\x23\x1d\x5b\xb4\x06\x29\xb4\xc0\xa4\x5d\x37\x39\xa2\x24\x90\xec\x33\x96\x40\x47\xf8\x44\x92\x42\x8d\x42\xc4\x80\x45\xa4\x08\x01\x38\xe1\x2b\xda\x1c\xe0\x0d\x6f\x30\x68\xd4\x86\x16\x35\x00\x1f\x59\xe6\x04\x40\x43\x4f\x1a\x8a\x1e\x6c\x8c\x01\x76\x5e\x92\x18\x61\x9e\x5a\x11\x9e\x52\x08\x10\x81\x18\xa6\x24\x18\xe4\x14\x19\xe5\x5a\x34\xa6\x89\x39\x23\xdb\x12\x48\x3d\x62\xca\x00\xda\x92\x37\x95\x21\x2b\xcb\x8d\x26\x22\x22\x2f\xdb\x40\x89\x26\x24\x33\xd8\x90\xb3\xa9\xd3\xaf\xaa\xc1\x7e\x07\x36\xaa\x69\x20\xd1\x4c\xcc\x8f\x8e\x58\xaa\xf5\x93\x96\x4b\xef\x69\x49\x95\x88\x6a\xe7\x3d\x69\xdf\xe5\x53\xc9\x19\x49\x83\x8e\x9f\x44\x25\x8e\x1d\x77\x72\xe0\x69\xe4\xcd\xc6\xe2\xf2\xd6\x51\x32\xe0\xa0\xe5\x90\xcd\xce\x97\xb3\x71\x8f\xc3\x4c\xc2\x01\xd0\x35\xab\x5b\x5b\x6b\xba\x48\x2a\x07\x15\xbf\x1b\x52\x11\xcb\x93\x13\x48\x23\x18\x0f\x59\xb7\x73\xc1\x68\x0e\x20\xc9\xc1\x8c\xbd\xbc\x0e\x1f\x1b\x8c\x31\x26\x24\xb3\x07\x03\x71\x16\x4c\xca\xfc\x70\x4a\x44\x53\x9d\x37\x01\xcc\xb3\x10\xcc\xb3\x14\x46\x6f\x4c\x88\xbf\x35\x4f\x8d\x77\xae\x7b\xf2\x94\x6b\x9f\xcc\x3d\x4a\xfd\xcb\x81\x42\xbf\x81\x83\x98\x27\xca\x14\x4d\x6e\x25\x34\x80\x13\x07\x0d\x53\xe2\x48\xc3\x57\x62\x9d\xc6\x86\x39\xd5\x44\xa7\x3e\xf4\x25\x65\x02\x1c\xfa\x1c\xc2\x19\x5f\xc4\xb1\xf5\x12\xc0\xd6\x57\xa9\x6f\x12\x28\xa8\xe2\x44\x87\x89\x4e\xf0\x3a\xbd\x63\x2b\xb9\x37\x88\xb2\x9c\x71\xbb\x4d\x52\x22\xe2\x29\x97\x52\x30\x49\x42\x1c\xcb\x57\xbb\xe4\x06\x32\x79\xb4\x56\xc9\x22\x21\xd0\x8a\x2b\xc9\x2f\xba\x4e\x55\xc6\xbe\x2c\xf9\x41\x06\x24\xa0\xb0\xcd\x74\x0d\x66\xc3\xb0\x46\xbb\xd3\xeb\xa4\xbc\x17\x4a\x93\x51\xca\x67\x8e\x2b\x82\x3b\xcc\x2a\x85\xdd\x4d\x44\xcb\xb6\x55\x7e\xa9\xfc\x60\x06\x3a\x69\xd5\xcf\x8e\xb6\x58\x9a\x22\x93\xfe\x54\x64\xfa\x12\x99\x14\xb7\x2a\x32\x87\xbc\xc0\x91\x99\x17\xb6\x44\x26\xe3\x5c\x81\x9e\x71\xdc\xed\x77\x03\x8f\xa3\xc0\x3c\x4e\xb2\xd3\x78\x25\x32\xff\x5d\xac\xa4\xaa\xb4\xaa\x85\x58\x9c\x14\x0b\x40\x50\xc3\xff\x40\xe0\xa1\xa2\x1f\x0b\xf6\x76\x81\x69\xb3\x4e\x83\x73\x02\x7b\x67\x30\x09\x47\xe6\x11\xc3\x47\xcb\x24\xba\xc1\xbb\x66\x75\x8a\x29\xb5\xe4\x11\x77\x20\xc0\x45\x89\x93\xc3\x46\xbd\xb2\x34\x5b\x32\x0d\xe9\xab\xdb\x36\x4e\xa9\x68\x94\xea\x27\x29\x94\x7c\x19\x25\x1d\xc9\xd4\x65\x28\x00\x7d\x29\xc8\x69\x5a\x88\xf4\xdb\x3a\xd5\x3e\x87\x4c\xc5\x84\x28\x2b\x36\x89\xb6\x62\x54\x82\x92\x58\xf5\xed\x20\x6b\x05\x5d\xa2\x9d\x59\x15\x26\xd0\xe5\x96\xb4\x34\xa4\xf3\x48\x45\xd3\xd1\x84\x84\x12\x9b\x6e\x32\x6c\x7a\x16\xb5\xf6\x71\xd5\xd5\xed\x92\x17\xf4\xe3\x91\xf1\xcf\x72\xad\x12\x94\xbe\x7a\xa3\x0e\x17\x9e\xa6\x4f\x2b\x7d\xe9\xda\x2d\x33\xf6\xac\x66\xa7\x7a\xe2\xf5\x7b\x55\x87\x1a\x57\x55\xab\x92\x8d\xc8\x3c\x64\x99\xf9\xd7\xaa\x53\x59\x69\x6c\x22\x4a\x24\x7a\x36\x84\xdc\xe2\xac\x95\x50\x59\x9d\xa6\x9e\x41\xa1\x98\x3a\x0b\xcd\x79\x85\x5a\x8e\xe8\x81\x1b\x54\xca\x1d\x48\x1f\x4a\x22\x3f\x6a\x1a\x11\x6d\xc0\x45\xe4\xa6\x0a\x74\x3e\x86\x2f\xa0\xa0\x57\xf8\x60\x72\xce\x19\xd9\x92\xc2\x02\x10\x52\xf6\xb9\x4c\x6b\xb9\xfa\x10\x9c\x99\xad\xb9\xde\xd9\x90\xf6\xe1\x00\x92\x91\x99\x71\x8e\x99\x3a\x78\xd4\x60\xa2\xa2\xed\x87\xb2\x02\x51\x52\xc3\x95\x1a\xb9\x31\x68\x08\xa1\xc6\x1e\x9b\x81\x14\x9f\xc8\xc0\x3a\x90\x5a\xde\xca\x8e\xa2\x85\xcb\xb2\xf1\x20\x63\xa6\x02\x94\x86\xb6\xaa\xbe\x10\xde\x95\x93\xf1\x69\xa1\x72\xe6\x5a\x27\xb5\x5e\x46\x9e\xd3\xcc\xfb\x23\xf2\x5f\xab\x6a\x98\x3a\x40\x00\xe5\x01\x83\x72\x01\x57\x7c\x60\xa5\x6f\x1f\x9f\x7d\x5b\x14\x37\xc1\xcf\x3f\x70\xd1\x0a\x59\x83\x4a\xd8\xc2\xc2\xa2\xcd\x2d\x48\x37\x72\x90\xc5\x80\xe9\x08\xcb\x70\xdf\x46\x5d\x73\x4f\xd8\xc8\xdb\x19\x0c\x13\xab\x42\x06\x6a\x00\xb9\x13\xfd\xd2\x48\x85\x05\x50\xf2\xd5\x96\x82\xae\x80\x15\x85\x22\x14\x82\x30\x05\x3d\xb8\x09\xa1\x19\xa2\x15\xe1\x2d\x10\xa5\x30\x71\x2d\x46\x63\x66\x2d\x0f\x21\x52\x7d\x21\xab\x50\x89\x82\x25\x1b\xaa\xc6\xba\x4e\xfa\x0a\x9d\x2c\x8c\xb5\xdb\x09\x50\x29\x38\x45\x60\x4a\x46\x29\x4d\xeb\xdb\x02\x11\x24\x16\x08\x64\xa4\x6f\x4c\x40\x16\x17\xe8\x94\xdd\xc8\xa0\x7c\x89\xef\x56\x2e\x14\x11\xe3\xf7\xfb\xec\x8f\xfc\x21\x29\x7b\x31\x14\x24\xc4\x1f\xed\xad\xc7\xc1\xa6\x03\xa0\x33\x3d\xce\x15\xad\xe5\x11\x75\xbf\x6c\x2f\xf9\x67\x91\xfc\x73\x83\xbf\xb7\x3e\xf1\x07\x9e\xc4\x50\x3a\xa9\xc2\x92\xd3\x95\x30\x55\x1d\x55\x09\x05\xe9\xaa\x32\xe1\xdc\x59\x4d\x59\xb5\x57\xf2\xf7\x5f\xa2\x5d\x04\x50\x6b\x46\x7f\x67\x96\x7d\x99\x9c\x96\x22\xb3\x50\x72\x34\xd8\xce\xad\x91\x30\xf4\x13\x39\x08\xce\x89\x08\x2c\x98\x50\x60\x60\x07\xc5\xdb\x60\x94\x3c\x9b\xec\x26\x59\x82\x3d\x7a\x8b\x1d\x9e\x50\xeb\x30\x3e\x6b\x56\x6f\x66\xa6\x15\xfe\xa4\xec\xe1\x2b\xcb\xc8\xdf\x01\x00\x00\xff\xff\x09\x1d\x1a\x8f\xf0\x1d\x00\x00")
+
+func fontsRozzoFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsRozzoFlf,
+ "fonts/rozzo.flf",
+ )
+}
+
+func fontsRozzoFlf() (*asset, error) {
+ bytes, err := fontsRozzoFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/rozzo.flf", size: 7664, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsRunicFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x54\x5d\x6b\x2b\x37\x10\x7d\xd7\xaf\x38\x84\x40\x12\x1a\x5b\x38\xf4\x06\xd2\xc2\xc5\x29\xf4\xe1\x3e\xf4\xed\x3e\x2e\x6c\xe5\xdd\x59\xaf\xc8\xae\x64\x24\x6d\x1d\x83\xc8\x6f\x2f\xfa\xda\xd8\x89\x7b\x09\xa5\xf4\x03\xea\x10\xcf\xcc\x4a\x73\xe6\xcc\x99\xf1\x76\x43\x77\x27\x2e\x71\x8f\x7b\xac\x3e\x61\xb1\xc2\xea\x81\x7d\xed\x09\x34\xb4\x64\xd0\x4d\xae\x17\xe6\x09\x58\x2c\xb0\x39\xe0\x27\x73\x10\x0a\x8f\x03\x3d\x0b\xd5\x92\x61\xd7\x22\xbb\xeb\x51\xb8\xbe\xb1\x4b\xd3\xeb\x96\xec\x92\xda\xe9\x86\x75\x72\x3b\x90\x83\xa1\x81\x84\x25\xdc\x2d\x57\x01\x65\x75\x87\xc7\x69\x8b\xd5\xc3\xc3\xf7\xec\x6b\x2f\x2d\x3a\xad\x1c\x1a\xad\xac\xb4\xce\x42\x77\x70\x3d\xc1\x4c\x8a\x2c\xa4\x8a\xc1\x09\x95\x25\xf0\xc5\x41\x5a\x88\xa6\x99\x8c\x70\x04\x61\x59\x27\x0c\x84\xc5\x17\x3c\x29\xbd\x5f\x02\x8f\xea\x80\x46\x1b\x43\x8d\x93\x5a\xd9\x5b\x68\x03\xd9\x92\xb0\xd0\x0a\x72\xdc\x19\xfd\x9b\x54\xdb\x08\x1e\xca\x5f\x59\x88\xdd\x8e\x84\x11\xaa\x21\x26\x0c\x61\x4f\x43\xa3\x47\x5a\x02\xbf\xe8\x56\x76\x87\x74\xbb\xb0\x0d\x56\x2a\xc2\x5e\xba\x1e\x23\xfd\x88\x5d\x6a\x91\x16\xa3\x90\x03\x46\x0a\xc8\xcc\x90\x9d\x06\xb7\x64\x8c\xfd\xfc\xbc\x1b\x84\x12\x81\x4b\x68\xb0\x93\xc6\x3a\x0c\x52\xd1\x0f\x2c\xc8\x8f\x05\x2e\x46\xb1\x95\x0d\xd4\x34\x6e\xc8\x5c\xa0\xd3\x06\x9d\x1c\x28\x90\x56\x4e\x76\xb2\x89\xc9\x4c\x00\xc0\x02\xb6\xd7\xd3\xd0\x42\x0c\x7b\x71\xb0\xd8\x10\x7e\x15\x57\xb7\x31\x49\xe9\x3d\xbb\x4c\x97\x42\x73\x17\xbd\x30\xed\x66\x10\xea\xe9\x22\x68\xbf\x33\x52\x39\x1b\x94\x12\x88\x4f\x6f\xb1\x99\x1c\x1a\xa1\xae\x5c\x80\xb1\xe3\x64\x7b\x6a\xd9\x7d\x42\xe8\x49\x6e\x7b\x17\x18\x0b\x34\xbd\x30\xa2\x71\x64\xbe\x79\x78\x0b\xa5\x1d\xa4\x6a\x86\xa9\x0d\x92\xb5\x64\x1b\x0a\x9b\x62\xd9\xea\x53\x4c\x1b\xc5\x73\xec\x1c\x03\xa9\xad\xeb\x71\x4d\xcf\xe5\x72\xa3\xc7\x91\x54\x12\xc6\xde\xe0\x3b\x08\x74\x53\xbb\x25\x74\xa2\x71\xda\xb0\xc5\x2a\x22\xb4\xd4\x89\x69\x70\x89\xec\xa8\x5b\x8a\x8d\xcf\xc3\x61\xab\x87\x78\x2d\x49\x19\xf8\x9d\xe0\xb2\x28\xcf\xe5\xfa\xd5\xd4\xd1\xf8\xda\x1f\x3f\x0c\x66\xcd\x8e\xfe\xfe\xbe\x00\xf1\xb3\x66\x75\xcd\xab\xba\x5e\xb3\x2a\x84\x7c\xcd\x78\x0d\xd4\x55\x38\xaf\x78\x38\xcf\xf7\x3e\x8e\x5b\x63\xcd\x7c\xed\xcf\x7a\xff\x50\xaf\xdf\x54\x21\xd3\xbb\xae\x6f\x72\x38\x7b\x7f\x75\x31\x5f\x05\x78\x8f\x0a\x6f\x7c\xa0\x7c\xaf\x99\x7f\xc9\x27\xf8\x1c\x45\x8b\x43\x38\xf7\x30\x65\xe0\x9d\xa9\x50\x90\xd3\xc3\x0a\xb9\x34\xc0\x7d\x39\xe1\xf0\xf9\x94\xa3\xb8\xbc\x2a\x2e\x0f\x59\xd1\xe5\x21\xad\xf2\x1f\x85\x08\x9f\x3f\x74\x13\x32\x4f\xb0\xa9\xad\x60\xe6\x32\xe5\xee\x6c\xcb\x52\x86\x11\xc5\x82\x28\x6b\x19\x1d\x9e\x3a\x4d\x6c\xb1\x66\x89\xeb\x2c\x8c\x2f\x62\xcc\x8c\x0b\xdf\x99\x57\x35\x13\xcc\xf4\xce\xfe\xa7\x12\x98\x4b\x04\xa7\x42\x2e\x8a\xe4\xe5\xdf\x09\xcf\x4e\x9a\x4f\x8e\x79\xc9\x4c\x69\x29\x27\x76\x32\xcb\xfa\x66\x5e\x67\x27\x9b\xae\x16\xfd\x8b\xfa\xfc\x75\x50\x27\xdd\x1c\xb5\x15\x4c\x2a\xee\x73\xf9\x6c\xe1\x33\x11\x9f\x3b\xc8\x2b\x08\xfe\x32\x0b\x5a\x65\xd6\x79\x08\x3c\x2b\x7e\x7c\x9e\x89\x15\x5e\xef\xe7\x98\x68\x16\x96\xef\x7e\x57\xaf\xcb\x9d\x5b\xe7\x47\x8b\x7f\xba\xc6\xc8\x0b\x83\xbc\x30\xbc\xae\xeb\x7a\xd6\x3c\xda\xbc\x25\x1c\x65\x04\x7e\x5e\x13\x3f\xd3\xf6\xf3\xcc\xb2\xc4\x67\xbc\xb2\xf1\x99\x44\x61\x91\xdb\xf2\xef\xed\x9f\x4c\x08\xe1\xe7\x2c\xce\xc9\xbb\xa0\xbc\x11\xde\x88\xf5\xb2\xa8\xeb\x57\x71\x23\x5c\x50\xa1\xce\xc0\x7e\x2e\xf1\xd6\xfb\x37\xbc\x6f\xff\x0f\xfe\xab\xc1\xef\x01\x00\x00\xff\xff\x5b\x92\x7b\xc9\xc1\x0b\x00\x00")
+
+func fontsRunicFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsRunicFlf,
+ "fonts/runic.flf",
+ )
+}
+
+func fontsRunicFlf() (*asset, error) {
+ bytes, err := fontsRunicFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/runic.flf", size: 3009, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsRunycFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x56\xdf\x8b\x1b\x37\x10\x7e\xd7\x5f\xf1\x71\x04\x92\xd0\xb3\x15\xbb\x49\xca\xb5\x47\x70\x0a\x7d\x48\xa1\xd0\x87\x3c\xe4\x61\x61\xa3\xdb\x9d\xf5\x8a\xec\x6a\x8d\xa4\xcd\xdd\x81\xb8\xbf\xbd\xe8\xd7\xda\x3e\xaf\x8f\xd0\x1f\xe9\x05\x6b\x46\x3b\x9a\x99\x6f\xbe\x19\x89\x34\x5d\xb3\x16\xcf\xf0\x16\x6f\xb1\x7a\x83\xc5\x0a\xeb\x57\xec\x63\x4b\xa0\xae\x26\x8d\x66\xb4\xad\xd0\x5f\x80\xc5\x02\x37\xf7\xf8\x55\xdf\x0b\x85\xf7\x1d\xdd\x09\xe5\xcd\xd7\x22\xa9\x9b\x5e\xd8\xb6\x32\x4b\xdd\x0e\x35\x99\x25\xd5\xe3\x3b\xd6\xc8\x6d\x47\x16\x9a\x3a\x12\x86\xb0\x5e\xae\x7c\x94\xd5\x1a\xef\xc7\x2d\x56\x57\x57\xaf\xd9\xc7\x56\x1a\x34\x83\xb2\xa8\x06\x65\xa4\xb1\x06\x43\x03\xdb\x12\xf4\xa8\xc8\x40\xaa\xb0\x39\x82\xb2\x04\x3e\x58\x48\x03\x51\x55\xa3\x16\x96\x20\x0c\x6b\x84\x86\x30\xf8\x80\x2f\x6a\xb8\x5d\x02\xef\xd5\x3d\xaa\x41\x6b\xaa\xac\x1c\x94\xb9\xc4\xa0\x21\x6b\x12\x06\x83\x82\xec\x77\x7a\xf8\x2a\xd5\x36\x04\xf7\xe9\x9f\x1b\x88\xdd\x8e\x84\x16\xaa\x22\x26\x34\xe1\x96\xba\x6a\xe8\x69\x09\xfc\x31\xd4\xb2\xb9\x8f\xa7\x33\x5a\x2f\xa5\x22\xdc\x4a\xdb\xa2\xa7\x5f\xb0\x8b\x25\xd2\xa2\x17\xb2\x43\x4f\x3e\x32\xd3\x64\xc6\xce\x2e\x19\xfb\x11\xbb\x41\x2a\x8b\xaf\xa4\x8d\x1c\xd4\x71\x8d\xa3\xa1\xda\x63\x1f\x77\x3b\xd2\x95\x8f\x22\xea\x3a\x7e\xea\x86\xdb\xf4\xa9\x23\x6b\x49\x1b\x76\xc5\xd7\x6b\x7e\xf5\x13\x7e\x27\xad\x45\x8d\x3f\x25\xe9\x8a\x70\x7d\x43\xdd\xf6\x75\x2f\xed\xa6\x97\x36\x72\xcf\x7e\xbb\xdb\x75\x42\x09\x9b\xf2\x35\x52\x1b\x8b\x4e\x2a\xfa\x99\xf9\x8e\x63\x81\x8b\x5e\x6c\x65\x05\x35\xf6\x37\xa4\x2f\xd0\x0c\x1a\x8d\xec\xc8\xf3\xa4\xac\x6c\x64\x15\x9c\x99\x00\x80\x05\x4c\x3b\x8c\x5d\x0d\xd1\xdd\x8a\x7b\x83\x1b\xc2\x67\xf1\xfc\x32\x38\xa9\xe1\x96\x3d\x8b\x87\x7c\x55\x17\xad\xd0\xf5\x4d\x27\xd4\x97\x0b\xdf\xee\x9d\x96\xca\x1a\x5f\x8d\x40\xf8\x7a\x89\x9b\xd1\xa2\x12\xea\xb9\xf5\x61\x4c\x3f\x9a\x96\x6a\xf6\x36\x46\x68\x49\x6e\x5b\xeb\x11\x0b\x54\xad\xd0\xa2\xb2\xa4\x9f\x34\x5e\x42\x0d\x16\x52\x55\xdd\x58\xfb\x2e\xd5\x64\x2a\xf2\xc3\x69\xd8\xea\x4d\x70\xeb\xc5\x5d\xa8\x1c\x1d\xa9\xad\x6d\xf1\x82\xee\xf2\xe1\x6a\xe8\x7b\x52\x91\x18\xf3\x12\x3f\x40\xa0\x19\xeb\x2d\xa1\x11\x95\x1d\x34\x5b\xac\x42\x84\x9a\x1a\x31\x76\x36\x82\xed\x87\x9a\x42\xe1\xd3\x3c\xb0\xf5\xab\x70\x2c\x52\xe9\xf1\x1d\xc5\x65\x81\x9e\x67\x9b\xbd\x28\x83\x70\xa5\x3b\xfc\xe8\xc5\x86\x1d\xfc\xfb\x7e\x1b\x84\xbf\x0d\x2b\x4b\x5e\x94\xe5\x86\x15\x7e\xcb\x37\x8c\x97\x40\x59\x78\x7b\xc1\xbd\x3d\x9d\xfb\xf6\xb8\x25\x36\xcc\x95\x6e\x56\xfb\x9f\x6a\x7d\x92\x85\x04\xef\x45\xf9\x32\x6d\x27\xed\xdf\x4e\xe6\x0a\x1f\xde\xa1\xc0\x23\x1d\xc8\xeb\x86\xb9\x87\x64\xc1\xbb\x40\x5a\x68\xc2\xdc\xc7\xe8\x81\x13\x51\x20\x47\x8e\x1f\x0b\xa4\xd4\x00\x77\xd9\xc2\xe1\x92\x95\x23\xab\xbc\xc8\x2a\xf7\x5e\x41\xe5\xde\xad\x70\xdf\x1a\xc2\xff\x9d\x55\x63\x64\x1e\xc3\xc6\xb2\xbc\x98\xd2\xe4\xb3\x93\xcc\x43\xe9\x5b\x14\x12\x22\x8f\x65\x50\x78\xac\x34\xa2\xc5\x86\x45\xac\x13\x31\x2e\x93\x31\x21\xce\x78\x27\x5c\xc5\x04\x30\xc1\x9b\xfd\xc5\x14\x98\x52\x78\xa5\x40\x4a\x8a\xa8\xa5\x7b\xc2\x93\x12\xfb\x93\xf6\x3c\x7b\x46\xb7\xe8\x13\x2a\x99\x68\x7d\xd4\xaf\xd9\xce\xc6\xa3\x99\xff\xcc\x3e\xdf\x37\xea\xa8\x9a\x83\xb2\xbc\x88\xc9\x5d\x4a\x9f\x24\x5c\x02\xe2\x52\x05\x69\x04\xc1\x1f\x26\x42\x8b\x84\x3a\x35\x81\x27\xc6\x0f\xed\x09\x58\xc6\x75\xda\xc7\x08\x33\xa3\x3c\xb9\x57\xfb\xe1\x4e\xa5\xf3\x83\xc1\x3f\x1e\x63\xa4\x81\x41\x1a\x18\x5e\x96\x65\x39\x71\x1e\x64\x9a\x12\x8e\xdc\x02\x37\x8d\x89\x9b\x60\xbb\xa9\x67\x89\xe2\x19\x2d\x4f\x7c\x02\x91\x51\xa4\xb2\xdc\xa9\xfc\x9b\x0e\x7e\xfb\x2e\x91\x73\xf4\x16\xe4\x17\xe1\x11\x59\x0f\x8b\xb2\xdc\x93\x1b\xc2\x79\x16\xca\x14\xd8\x4d\x29\x1e\x6b\xdf\xe1\x21\x9d\x16\x57\x4c\x4b\xea\xc3\x8c\xf9\x3a\x56\x3d\x63\xde\x2f\xa9\xed\x53\x6f\x8e\xa4\x2b\xf2\x7d\xf8\x94\x6f\x41\xe1\x26\x87\xc7\xc2\x15\x7c\xe2\x23\x8b\x68\x3c\x5e\x1d\xe7\xc7\xed\x98\x3b\x54\xc4\x79\xfb\x14\x07\xaa\x38\x13\x29\x3d\x42\x2e\xeb\xde\xb0\xff\x1d\xbf\x31\x27\xde\xf9\xc9\x28\xd2\x40\x9f\xf2\x14\x30\x5c\xa7\x27\xe5\x1c\xcb\x38\x6c\xc2\x79\x56\x78\xf1\x34\x2b\x08\x81\x3e\xbb\xa8\x7f\x9e\x49\xc7\xc3\x5b\xc1\x93\x36\xcb\x47\xc1\xf7\xc3\xcd\x4f\x5f\x82\x59\xfc\xfc\x70\x0c\x8e\xf2\xf9\x65\xb1\x48\x3c\xcc\x32\x18\x22\xc0\x4d\xf8\xe7\x41\x1d\xb4\xea\xec\x4c\xcc\x1e\x3a\x03\xf6\xf4\xd6\xce\x04\x7c\x28\xe2\xff\x89\xfc\xea\xfe\xeb\xdb\xf9\x8f\x37\x7f\x05\x00\x00\xff\xff\x92\xe7\x29\xb9\x32\x0e\x00\x00")
+
+func fontsRunycFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsRunycFlf,
+ "fonts/runyc.flf",
+ )
+}
+
+func fontsRunycFlf() (*asset, error) {
+ bytes, err := fontsRunycFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/runyc.flf", size: 3634, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSbloodFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x58\x5b\x6f\xdb\x36\x1b\xbe\xd7\xaf\x78\x58\xfb\xa2\x05\x3e\x13\x39\x34\x69\xfb\xe2\xc3\xc0\x0e\x41\xb1\x62\x5d\x5a\x20\x1b\xb0\x5b\xda\xa6\x65\xb5\x36\x19\x48\x4c\x8c\xec\xd7\x0f\x3c\x49\x94\x25\xc7\x1e\xb0\xab\x21\x6e\x2b\xb3\x16\xf9\x1e\x9e\xe7\x3d\x49\xab\xcd\xea\x42\x4e\x71\x8d\x2b\x9c\xbf\xc7\xec\x1c\x17\xe7\x45\xf1\xa9\x2a\x37\xca\x62\x61\xf4\xa3\xaa\x9b\xca\x68\xcc\x9f\xf0\xab\xd2\x16\xb7\xb2\x69\x94\xc6\xeb\x1f\x4a\x5b\x2d\x16\x4f\x73\x55\x37\xf7\x72\xa1\xb8\xa9\xcb\x37\x98\xcb\x46\x2d\x61\x34\xec\x5a\x15\x2b\xa3\x2d\x96\xaa\xa9\x4a\xad\x96\x98\x3f\x51\x51\x7c\xac\x6d\xb5\xd8\x28\x5c\x5c\xbf\x7f\x07\xb3\x42\xad\x16\x5c\xd6\xb6\xe1\xb2\x59\x54\x15\x15\xdf\xa4\x5d\x13\xb4\xda\x35\xbc\xb2\x4b\xfe\xb0\xad\x16\x6b\xae\x96\x0f\x6c\x21\x95\x66\x5b\x69\xd7\xdc\xac\x2b\x33\x6b\xac\xb4\xca\xdf\x58\x9b\xdd\x46\xea\x25\xaf\x55\x63\x8d\xe6\x52\x37\x5c\x2b\xcb\xbc\x88\xe6\xbe\xae\xb4\xdd\x54\xfa\x87\xff\xad\x91\xcd\xba\xda\x56\x7c\xb7\x93\x7c\x61\xb6\x4c\x1b\x3b\x5b\x99\x7a\xb6\x95\xd5\xa6\xf8\x54\x9b\x2d\x61\x59\x35\x8d\xda\x08\xfd\xa0\xab\x05\xd7\x0f\x4e\x03\x5e\xdf\xc8\xc7\x6a\x89\x3b\x8e\xcf\xee\xe6\x9b\xe2\x56\xed\x9a\xb2\x36\x0f\xf7\x0d\xed\x39\xf0\x3f\xb9\xb1\x61\x35\x93\xb5\x2d\xee\x1e\xe6\xdf\xd5\xc2\x12\xbe\x54\x5a\x11\xee\xb6\x72\xb3\x51\x35\x7e\xfe\xf2\xf5\xeb\x0d\x3c\x3a\xaf\xaf\xb0\xa9\xb4\x7a\x53\xdc\x48\xab\x08\xd7\xb8\x35\x8f\x38\xff\xf0\xe1\x2d\xce\xaf\xe8\xec\x9a\x2e\xcf\x30\x3b\xbb\x3e\x3b\x2b\xbe\xd6\xa5\xd4\xd5\x5f\xd2\x56\x46\x13\x6e\xfd\xb7\xdc\xe0\x0f\x5d\x79\x82\xec\x53\xe1\x74\x34\x84\x77\x97\xc5\x9d\xd2\x4b\x55\x13\xe6\x66\x2e\x45\x74\xb6\xf8\x78\x7f\x5f\x9b\x47\xb5\xdc\xfb\xf9\x37\xd5\x34\xb2\x54\xb3\xcf\x37\x84\xff\x5f\x7e\xf8\x5e\x96\xdb\x69\xa5\x2f\x44\x29\xcb\xad\x4a\x48\xfd\x54\xdc\xde\xfe\xfe\x6d\xf6\xcd\x34\xb6\xd2\xe5\xec\x17\xd3\x58\x42\x6f\x47\xf1\x67\xad\x56\x63\xc4\xed\x33\xec\x89\xef\xa1\x44\xe7\x57\xef\x2e\xdf\x16\x45\xf1\xc9\xd4\xb0\x6b\xd3\x28\xec\xd6\xc6\xad\x1e\xca\xb5\x85\x5d\x4b\x1b\x11\xdb\xc9\x06\xd6\x18\xcc\xab\x92\x73\x8e\xcf\x30\xab\x95\xaa\x71\xe7\xef\x52\x31\xcb\x3e\xc5\x14\xc0\x74\x72\xc2\xd7\xa4\x98\x0a\x21\xda\x2b\x13\x2c\xdc\x99\x14\x53\xe2\x14\xd7\xfe\x36\x84\xf0\xa7\x04\x43\xda\xd4\xca\x19\x5f\xf8\xdd\xfe\xa0\x40\xd0\xc0\x84\x08\x7a\x20\x98\x00\x13\xcc\xfd\xce\x18\x23\xe6\x2e\xee\x77\x22\x80\x40\x48\x52\x10\xf5\xc3\x9f\xf4\xdb\x85\x60\xcc\x1b\x88\xb0\x0c\x5b\x9d\x10\x2f\x80\x13\xcf\x8f\xc7\xc3\x40\xd0\x0b\xb7\x08\xe6\x0b\x11\xc4\x30\x46\x48\x1e\xc3\x19\x30\x38\xec\x34\x23\xb8\xc0\xbc\x37\x51\xbb\x73\xa0\x15\xc1\x92\x55\x4e\x3f\x21\x81\xd7\x13\xe4\xcd\x0f\x08\x8d\x5d\xa3\xb6\x80\x55\xf0\x35\x21\x14\x24\x23\x09\x9d\x74\x7b\xe2\x09\x44\xea\x18\x73\x5f\x19\x84\x2d\x0d\x89\x07\xef\x39\x8b\x5e\x30\xb7\x62\x22\x9c\x02\x18\x11\xe5\x7e\x80\x53\x9f\x8b\x20\xae\x03\xa1\x5d\x79\x34\x22\xb2\x2d\x14\x9e\xca\x7d\x3c\x87\xae\x07\xe5\xe4\x9c\x73\xdc\x75\xfb\xa7\xfd\xa5\xc8\x95\x8c\x6d\x68\x97\x6e\x3d\x1d\x5e\xbc\x8a\x78\xdb\x47\x42\x8c\x89\x16\x19\xc6\x12\xb9\x2c\x52\xeb\x3d\x18\xf8\x20\xda\x70\xf4\x51\x14\x49\x73\x87\x83\x79\x3e\xa6\x22\xa8\x4e\x42\x1f\xc5\x8c\xe8\x51\xf6\x3a\xd0\xa6\x03\x6d\x99\xd9\x9c\xc5\xf8\x40\x1e\xc2\xe4\xb4\xd1\x9e\xb6\x4e\x42\x96\x01\x8e\xf5\xd6\xae\x90\x7f\x44\x34\xcc\x80\x14\x3c\x03\x6f\x7b\x64\xa4\x10\x02\xb2\x38\xed\xeb\x0f\xf1\x2f\x90\x92\x26\x4b\x5f\x84\xf4\x25\xda\xcb\xfe\x36\xdc\x5a\xb4\xd3\xf1\xa8\x1f\x27\xa1\x2d\x3a\x03\x90\xd7\x00\x20\x99\xc0\x03\x86\x1d\xe3\x63\x84\x0d\x39\xc7\x01\x2b\x3c\x0d\x27\x8a\x10\x21\x05\x3b\x20\x29\x3a\x42\x34\xb4\x22\x1c\x4e\xab\x88\x79\xb8\xb4\x95\xbb\xad\x75\xcf\x26\xd7\x5e\x12\x64\x89\xdc\xde\xed\x12\x19\x3e\xa8\xf6\xd2\x31\x16\xf4\xfe\xaf\xa9\x9c\x3f\x93\x99\xad\x7e\xd1\x06\x43\x5e\x52\x52\x12\x75\xfa\x3d\x12\xcf\x62\xe8\xb2\x41\xa4\x60\x7a\xf5\xaa\x75\x8f\xe8\x20\x93\xa9\x9b\x78\x7d\xb1\xf9\xc1\xb3\xe9\x34\xfa\xfc\x8f\x67\x43\x52\x1c\x6a\x4a\x23\x65\x20\x25\x46\x3f\x30\x9f\x49\x8c\x71\x11\x7b\x51\x45\x87\x2b\x49\x3f\xb9\x32\x1a\x91\xf9\x92\xb9\x72\xaa\x15\x23\xf5\xcc\x5b\x31\x8c\xed\x2c\xc3\x44\xa7\xda\x97\x98\x5e\x9b\x8d\x19\x76\xb8\x48\x9d\x26\x22\xe6\xe8\x71\x6a\x3b\x34\xfa\xd4\x76\xf3\xc6\x28\xb5\x47\x6b\xde\x49\xd4\x86\xd3\xa1\xd6\x85\x33\xde\xfb\xa8\x6d\xd0\x86\xb2\xb2\x14\x0e\x70\x5f\xe4\x43\x06\x70\x1a\xb4\xd2\x7d\x23\x59\x32\x52\xb4\x83\x03\x81\xda\xe1\x01\xe3\x98\x77\xc9\x98\x63\xde\x22\xd7\xa7\x8d\x1f\x0c\x9e\x2c\x7e\xe2\xbf\x28\xc8\xf5\x54\x91\xfc\x07\xf2\x0a\xe7\x3f\xfd\x22\x37\xea\x9a\xaf\x33\xc9\xb5\xb1\x88\xc4\x48\x44\xfe\xd3\x26\xcd\x0f\x06\xf5\x50\x44\x0e\xf0\x49\x11\x89\x5c\x06\x32\x3b\xa2\x14\xf7\x97\xd0\x59\x42\x83\xf1\xf1\x70\xa5\x38\x44\xf6\x80\x29\x8c\x74\x61\x8c\x76\x61\x3e\xec\xc2\x79\x07\x4d\xa3\x73\x68\x9f\xa9\x57\xb4\x44\xd2\x60\x60\x3a\x98\x4e\xa3\x5c\x8c\x36\xcf\xa3\x22\xc0\xdc\xd4\xcd\x9e\x29\xfc\xed\x14\xdc\x97\xc3\x90\x45\x6b\x18\x01\x43\xbc\x22\x18\xe5\x2f\x71\x9e\xf5\x43\xf1\x7e\x63\x3e\x92\x90\xe8\xe2\x05\x1d\x47\x5e\xc8\x78\x42\x76\x12\x58\x36\x64\xec\xc3\xcc\x47\x61\x1e\x1f\x73\xba\x47\xa6\xde\xa4\x78\x28\x9b\x93\x2b\xa1\x72\xa5\x07\x85\x54\x04\xba\x47\x9b\x49\xbf\x87\xb7\xcf\x49\xd9\x20\x1d\x9a\x78\x9a\x21\x72\x75\x6d\x44\xa6\xf6\x9f\x02\x2a\xb5\xfe\x60\x24\x7a\xda\xc2\x2c\x88\x2c\x83\xc4\x81\x41\xe3\xd8\xf8\x71\xc2\xe6\x62\xca\xc3\x67\xda\x36\x2d\x50\xf0\x39\x3e\x0a\x4f\x8e\x3c\xca\xbd\x4c\x07\x2f\xd3\xc1\xcb\x74\xf0\x32\x1d\xbc\x4c\x07\x2f\xd3\xc1\x7f\x61\x3a\xe8\xbf\xb5\x62\xa1\x09\x65\x59\x12\xb7\x8f\xbc\xe0\x8a\x7d\xbd\x23\xd1\x7d\xf1\xd0\x4e\x91\xbd\xca\x44\x3e\x05\x64\x2f\x3e\xd1\x9b\x02\x02\x0e\x93\xf8\x5e\x5a\x74\x5d\xfb\xd8\x6a\x52\x64\x7f\xfe\xed\xff\xfc\x1d\x00\x00\xff\xff\x06\x60\xe4\xa7\x4c\x1a\x00\x00")
+
+func fontsSbloodFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSbloodFlf,
+ "fonts/sblood.flf",
+ )
+}
+
+func fontsSbloodFlf() (*asset, error) {
+ bytes, err := fontsSbloodFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/sblood.flf", size: 6732, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsScriptFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x5b\x7d\x6f\xe2\xb8\xf3\xff\x9f\x57\x31\x7f\x44\x3a\xfa\xfb\xb5\x6b\x92\x3e\x50\xa4\xd3\xa9\x59\xc8\xb6\xd1\x52\xc2\x05\xd8\xbd\x95\x22\x59\xec\x36\xdd\xa2\xa3\xa4\xe2\xe1\x4e\x2b\xe5\xc5\x7f\xe5\xc7\xd8\x8e\x9d\x02\xed\xad\x0a\x71\x82\x3d\x33\x1e\xcf\x7c\x3c\x33\xce\x3e\x2e\x1f\x83\xb9\x07\x5d\xb8\x04\xff\x0a\x3a\xe0\x77\xa0\x03\xe7\xbd\xce\x45\x6b\xf2\x63\xbd\x78\xd9\xc2\xf7\x5f\x70\xbb\xcc\x57\x2b\xe8\x3f\xcd\x5f\x5e\xf2\xe5\x12\x2e\x50\xef\xbc\x15\xaf\x7e\x2c\x77\x0f\xf9\x06\xe2\x49\x02\xc3\xf9\x76\xb1\x3a\xf3\x5b\x8f\x8b\x9f\xcb\x7c\x0b\xeb\x7c\x99\xcf\x37\x39\x04\x1f\x7c\x38\x3b\x03\x3f\x80\x70\xf7\x13\xfc\x5e\xef\xa2\x35\xce\xd7\xcf\x8b\xcd\x66\x51\xac\x60\xb1\x81\xa7\x7c\x9d\x7f\xff\x05\x3f\x17\xff\xe4\x2b\xd8\x16\xf0\x5c\x3c\x2c\x1e\x7f\xc1\xf6\x69\xb1\x81\xc7\x62\xb5\x3d\x85\xf9\x06\x96\xc5\xea\x27\xb9\x6e\x9f\xf2\x16\xed\xb0\xc8\xd7\xbf\x6d\x60\x35\x7f\xce\x09\x8d\x97\xe5\xfc\x47\xfe\x00\xc5\x0a\xe6\xf0\xa3\x78\x7e\xce\x57\x5b\x58\x2e\x56\xf9\x87\x56\xeb\x9e\xf5\x7e\x20\x73\x18\xcf\x77\x4b\xf8\xb8\x5b\x6f\x8b\x15\xfc\xbe\x29\x96\xbb\xed\xa2\x58\xdd\xe4\xf3\xf5\xf6\x69\xb9\x58\xfd\xfd\x61\x95\x6f\xff\x00\x3f\x40\xbd\x2b\x22\xc8\x82\xcd\x0e\x56\xf9\xbf\xf0\x32\x5f\xcf\x9f\xf3\x6d\xbe\x6e\x6d\x76\x2f\x2f\xc5\x7a\xcb\x08\x7e\x8a\x6f\xc9\x5c\xe7\xab\x07\xd2\xfc\xba\x58\x7d\x00\xb8\x9f\xff\x82\xf9\x72\x53\xc0\xf7\x1c\x36\xcb\xc5\xcf\xa7\xed\xf2\x17\x3c\x0b\x29\x1e\x8b\x35\x7c\xcf\xb7\xdb\x7c\x0d\xbb\x4d\xde\x2a\x1e\x29\xf9\xc7\xdd\x72\x79\xf6\xef\xe2\x61\xfb\x84\xfe\xce\xd7\x2b\xb4\x79\xde\x6d\x9e\x60\xbe\xdc\xe6\xeb\xd5\x7c\xbb\xf8\x27\xdf\x9c\xc2\xf7\xdd\x16\x1e\xf2\xc7\xf9\x6e\xb9\x85\x62\xb7\x7d\xd9\x6d\xc9\xcc\x47\xc9\x14\x7e\x3c\xcd\x57\x3f\xf3\x87\x0f\xad\x96\xe7\xdd\xb8\x3e\x37\x2d\x80\x9b\x16\x94\xca\xa7\xe0\xcf\x80\xfc\x58\x90\xbb\x92\x3c\x26\x03\x94\x2f\xd6\x85\xf6\x11\xff\x68\xb3\xa4\x7f\x37\x2d\x38\x3b\xfb\x7f\xfa\xa7\x37\x95\x0e\xda\x30\xde\x14\x6d\x72\x2d\x71\x89\x6f\x5a\xd0\x2e\x71\x49\xee\x71\x89\xcb\x13\xfa\x1c\x4a\x50\xfb\xa9\x03\x49\xff\x13\x40\xf4\x0e\xd1\x5f\x11\x7d\x88\xa0\x7d\x52\x75\xa9\xb1\x6a\x9f\xb0\x2b\xca\x78\x6f\xc8\x08\x8d\x0c\x63\x94\xd9\x58\x11\xa5\x90\x0e\x9e\xf2\x91\x2a\xe3\xa4\x88\xde\x40\xfb\x82\x4c\x51\x19\x21\xcf\xa6\xa9\x7d\x21\x43\xad\xea\x35\x2b\x11\x53\xec\xff\x31\x55\xa2\x32\x73\x2a\x42\xff\x41\x59\x11\xe5\xbe\x3e\xd0\xf8\x88\x69\x3a\xa8\x02\xa7\x7a\xc6\xa9\x7a\xfb\x53\x05\x95\x2a\xbb\xd8\x16\xad\x5a\x2d\x75\xd1\x30\x06\xd1\x2b\x63\xca\x05\xa6\x3c\xd9\xa0\x2b\x57\x19\x56\xd5\x20\xad\x53\x42\xba\xac\xab\x5e\xb5\x68\x8c\xb9\x00\xd4\x6a\x3c\x4d\x2a\x8c\xb1\x45\x2a\x2c\x87\xb0\x65\xf6\x30\xa6\x33\xf2\xd8\x7d\x86\xf9\xbd\x6b\xb1\xa8\x5b\x90\x2b\x66\x66\x0f\x20\xcd\xdc\x61\xee\x98\x09\x52\x0a\x02\x5c\x82\x3d\x38\xf2\x8e\xc8\xe3\x9c\xd9\x7d\x89\xb8\xe8\x99\x63\x20\xe6\x1c\x09\x07\x3e\x37\xa6\x18\x0f\xc9\x05\x71\x89\x2a\xdc\x8a\x7b\x55\xed\xae\xae\x4e\x3e\xa2\xa4\x7d\xd8\x7a\x89\x75\x12\x17\x6d\x04\xb7\x2c\xe1\x8e\xba\x95\x59\x7e\x44\x75\x7f\x45\x95\x57\x66\x16\x88\xb3\x18\x7d\x65\xfc\xae\xa9\x1b\x24\x91\xe2\xe3\x75\x6b\xe3\x96\x43\x45\xe3\x3e\x5a\xd8\x7d\x40\xe1\x44\x56\x45\xe8\x1f\xe3\x53\xee\x12\x88\x02\x25\x6d\x12\xf5\x31\x9e\xc4\x26\x54\xc7\xa8\x0c\x02\x9f\x56\x4b\x58\x42\xe5\x55\x66\x93\x61\x62\x65\x1f\x16\xfc\x3e\x15\xf3\x91\x06\x45\x2c\x4c\xcc\x89\x3f\x69\x2b\x36\x66\xf8\x27\x91\xc6\x63\xb2\xb4\xf1\x09\x67\xef\x81\xda\xd0\x8d\xdb\x18\xef\x55\x0a\x69\x53\x86\x12\x03\x99\xe1\x78\x58\x36\xdb\x28\xab\x29\xc4\x98\x0d\x17\x46\xc8\x92\x61\xec\xf1\xc5\xa2\x57\xa7\x97\x51\x29\xa8\xbb\xb4\xf1\x09\x94\x1e\xff\x11\x97\x6c\x6e\x80\xf8\xf2\x40\x1b\x23\x8d\xad\xd2\xd2\x27\xd8\x3e\xe1\x76\x8f\x32\xe6\x0e\x88\xcf\x02\xb5\x9b\xd0\x4e\x3c\x43\xa5\x84\x12\x02\x15\xbc\x45\x9e\x65\xb2\x85\x1a\xc4\xc0\x42\x8d\xa5\x72\xc5\xc0\x2c\x2b\xc3\x28\x6b\x84\x37\xb1\xb5\x4a\x98\x13\xb2\x64\x98\x73\x45\x1c\xe6\xb2\xd2\x26\x38\x12\x82\x73\xa8\x29\x21\xf3\x44\x0b\x34\x7b\x34\x05\xf7\x30\xeb\x98\xe1\x12\x9f\x88\xfd\xd0\x63\x1d\x3d\x2c\x5a\xdc\x12\x9c\x64\x4e\x31\xa6\xfb\x8e\x10\xa8\x8a\x62\x5e\xbd\xd1\x9c\x45\x33\xb0\xca\x61\xe4\x54\x11\x64\x00\xd5\xd2\xd8\x9b\x8d\xee\x57\x6d\x8f\x19\xce\xd0\x11\xdb\x63\xdd\x7d\xb1\xe2\xbe\x9e\xd6\xb0\x8c\x67\x6a\xaa\x36\xe8\x6a\x8f\xe1\x60\x82\xe8\x1a\x1f\x02\x26\x95\x38\xd2\x7c\xd1\x81\x56\xa0\x38\x11\xf7\x21\x29\xa1\xf0\xa0\x3d\xbc\x98\xff\xe8\x89\x96\x27\x26\xf5\x8a\x17\x7b\x58\x79\xde\xc6\x2a\x9e\x82\xfb\xc6\xa2\x1e\x8b\xf9\x48\xda\x92\xb4\xb0\x8f\xd2\x20\xac\xd0\x45\x06\x25\xad\xad\x09\xac\x11\xae\x13\x37\x19\xe8\x4c\xea\x8c\x6a\x53\x30\x18\x52\x5e\x99\x88\xb5\x00\xbc\x4c\x52\xf0\x90\x70\x0d\x42\xb5\xd1\x6c\x34\x6a\x15\xee\x81\xbd\xc9\x36\x48\x41\x02\x55\xe1\x16\x87\x22\x8f\x9b\x60\x1b\x8b\xbd\x84\x07\x84\x42\x4a\x24\xac\xc7\xc4\x30\x5c\x4f\x02\x78\x90\x77\xa3\x46\x16\x34\x44\xe0\x1e\xc1\xe7\x22\x22\xfb\xec\xa6\xb6\xf9\x33\x20\xb6\x04\xb0\xb8\x94\x54\x59\xda\xe2\x59\xbe\xe0\xc6\x15\xd3\xd4\xaf\x9e\x76\x65\x9e\xc0\xa3\xa7\xcc\x9d\xfd\x68\xeb\x41\xb5\xc0\x83\x0b\x24\xac\x83\xe8\xdb\xb5\x7d\x0b\xb8\x2e\x65\xec\x21\x61\x23\xc3\x0c\x33\x50\x5d\x5a\x9b\xf8\x02\x38\x38\xc2\x37\x47\xe0\xfc\x49\x29\x86\x96\xfb\x4b\xac\x2e\x0f\x19\x2b\x51\x8e\x05\xe5\x96\xe8\xd6\xc3\x9e\x98\x9a\x72\xd1\x46\x94\x59\x45\xc6\x3e\xb9\x53\x29\x20\x97\xcf\x6a\x82\x54\x9d\x95\x22\xcd\x16\xaa\x00\xda\xd8\x57\x6a\x00\x4a\x16\x5e\x3c\x66\x03\xa8\xb4\x48\x3e\xd1\xba\x42\x51\x75\x15\x51\x07\x62\x7b\x27\x11\xb7\x7c\x65\xad\xf1\x09\x88\xd0\xd5\x0e\xcb\xaf\x2a\x10\xec\x11\x73\x0d\x7e\xf8\x92\xb1\x3f\xa6\xd2\x92\xfd\xb1\x08\xc1\xb1\x8b\x9b\x54\x1c\x58\xd4\xaa\x53\x56\xc8\x36\xef\xe3\x0e\x73\x06\xe6\x07\xda\x16\xee\x32\x67\xd9\xe0\x21\x81\x74\xa2\x92\x8f\x46\xc2\x12\xb2\xb2\x61\x7c\xa3\x03\xcb\x22\x04\x89\x04\xed\xe3\x4f\xa5\x02\xe4\xf4\x61\x5f\x77\x12\x9c\xa9\xdc\x64\x37\xb0\xaf\x6d\x75\xc1\x25\x07\x48\x3e\xe5\x06\x6b\x70\xb4\xaa\x6d\xcc\x33\xfc\xbe\xee\x15\x56\xe4\xa4\x6b\xcb\xc5\x6d\x58\xa3\x9a\xa9\x68\x22\xa8\x44\x54\x3a\x7b\x98\x0a\xbf\x22\x3e\xcc\x43\x0e\x37\xb2\x2c\x95\xae\x03\xa1\x02\x3e\x5a\x6e\x8d\x62\x7f\x33\x19\x4b\x1b\x45\x74\xeb\xf3\x90\xb0\x51\x73\x63\xe4\xc3\x90\x44\x87\xdf\x55\xa4\x10\xbb\xde\x8d\x51\x99\xd4\x3f\x92\x4e\xa6\x8d\xfd\x43\xb6\x91\x0a\x4b\x3c\x3f\x61\x79\x58\xfd\x5b\x43\xb0\x02\xaa\xbc\xfb\x95\xd4\x78\x8f\x10\xb6\x90\x60\xe8\x8c\xcc\x1b\x03\x72\x4e\x81\x2d\xe5\xbe\x81\xe4\x7e\xb1\x63\xa1\xd6\x17\xf6\xf0\x75\x53\xb6\x6a\x6a\x07\x82\x94\xaa\x61\x43\xb4\xc3\x1c\x90\x57\xb2\xa8\xc5\x94\xa2\xea\xca\xef\xb0\xd0\x71\xe5\xf9\xfe\x55\x07\x60\x94\x9c\x7d\x4c\xa3\xf0\x33\x4c\xc6\x61\x3f\xaa\x55\xb6\xeb\x5f\x64\x9c\x0f\x10\x8f\xbe\x44\xe9\x34\x1a\x40\xf4\x57\x7f\x18\xde\x87\xd3\x38\x19\xc1\x7d\x98\x7e\xae\x0a\x4c\xaa\x85\x52\xb6\x74\x6c\x00\xd0\x8f\x46\x53\x98\xc4\xb7\x23\x9b\xd7\x94\xbc\xfe\x23\x14\xae\xc4\xd8\x8a\xd2\xfc\xab\x73\x80\x71\x32\x1b\x0d\x14\x42\x58\x74\x41\x2c\x64\xc4\xb8\x14\x56\x86\x4b\x1e\xb8\xb5\x91\x56\xd2\x33\x94\xe8\x5f\x5d\x00\xf4\x67\x69\x1a\x8d\xfa\xdf\x0c\x11\x33\xc0\xcc\x47\x91\xa8\x61\xf1\x6d\x43\x89\x4c\x75\x11\x2f\x01\xbe\x45\xa3\x1a\x19\xb6\x32\x38\xc3\x08\x0b\x21\x6b\x33\x54\xc9\x5c\x01\x7c\x4c\x93\xcf\xd1\x08\x3e\x86\x69\x5d\xad\x2a\x08\xf8\x57\x5d\x80\x49\xd4\xa7\xab\xc1\xf9\xd2\x84\x0d\x44\x1c\x4c\x7d\x0d\xb3\xfa\x3f\xfb\x22\xa3\xae\x01\x06\x71\x18\xa5\xd1\x24\x9e\x30\x4b\x66\x1b\x93\xe7\xba\x80\x61\x49\x3d\x80\x7e\x32\xfe\x96\xc6\xb7\x77\xca\xd2\xb2\xe2\x13\x87\x37\xe2\x0f\x99\x40\x0f\x44\x92\x4f\x5e\x9d\x2b\xd9\x5c\x99\xef\x33\x37\xe1\x8e\xc2\x4b\x74\x35\x5f\xf5\xbb\x1d\x80\x4f\xd1\x7d\x3c\x8a\x47\x11\x24\xe9\x20\x1e\x85\x43\x88\x47\x83\xb8\x1f\x4e\x93\xd4\x1e\x12\x62\x5e\xa2\x64\xd4\xec\xf5\x79\xbf\xeb\x03\x0c\xa3\x4f\xd3\xb3\x71\x12\x8f\xa6\xf1\xe8\x16\x06\xc9\xec\xe3\x30\x82\x70\x74\x3b\x8c\xe0\xcf\x59\x32\xd5\x4c\x9d\xcf\x87\x46\x73\xac\xf8\xc3\x6d\x23\x33\x80\xd4\xef\x06\x40\x4f\xa2\x2a\x6b\x60\x69\x04\xef\x52\x72\xa9\xd4\x8b\xa6\xe2\xee\x39\xc0\x24\xf9\x34\x85\xbb\x6f\xe3\xbb\x68\x54\x8b\x0d\xd8\x45\x39\x7f\xb0\x90\xb8\x00\x48\xa3\xdb\x78\x32\x8d\xd2\x68\xe0\x58\xa6\x53\xa8\x96\x89\x95\x60\x32\xb9\x8d\x63\x24\x97\x89\x86\xa3\xaf\x2e\xd3\x25\xc0\x7d\xd8\x4f\x93\x91\x52\x30\x37\x32\xa9\xfa\xd5\x5c\x92\x2b\x80\x41\x74\x9b\x46\x91\xb4\x68\xb6\xb4\xac\x62\xae\xc4\xdc\xb5\xdd\xcb\xef\x76\x01\xc6\xc3\xd9\xe4\xec\x3e\x1e\xcd\x26\x2e\xcc\x31\x8e\x84\x2a\x8f\x34\x25\xb9\x06\x98\xcc\xc6\x51\x3a\xe9\xa7\xf1\x78\x0a\xd3\xaf\x89\xc8\x40\x4f\xe8\x61\x88\xf4\x2a\x3d\xbb\xf4\xbb\x3d\x63\xe0\x5d\x1a\x45\x54\x25\x14\x9b\xa8\x4b\x72\x9f\x74\x4c\xe4\xba\x03\x10\xf6\x67\xd3\x08\xc2\x3e\x81\xcf\xfa\x91\x9b\x9a\x78\xfa\xd7\x3e\xc0\x7d\xdc\x4f\x13\x75\xca\x7b\x6c\x31\xa5\xdc\x62\x4a\xed\x57\x21\x45\x00\x30\x8e\x87\xfd\x34\xf9\x2a\xd7\x42\x9e\xf5\x94\xe2\x7c\xa2\x04\x59\x16\x35\x1b\x60\x6c\x9a\xfe\xf5\x39\x11\x74\x30\x18\x46\x30\x48\xa6\xea\xa4\x5b\xe0\x25\x5e\x43\x64\xe2\x5f\x13\xa8\x8e\x06\xf1\x70\x18\x56\xca\x56\xbf\xe8\x10\x01\x75\x64\xc0\xa5\xbe\x0a\xc9\x28\xaa\x9f\x80\xd9\x96\xef\xfa\x8a\x98\xf1\xa4\x3f\x1b\xba\xe1\xc6\xba\xd5\xbf\x0a\x37\xd7\x5d\x00\x8a\x99\x07\xe1\x8d\x86\x31\x0a\xf6\xe8\xea\xb9\x06\xf8\x32\x1b\xde\x86\x29\x7c\x4a\x43\xb6\x23\x24\x23\x42\x32\x4c\xa7\x51\x2a\x8a\xca\x2c\xef\x11\x85\x64\x51\x5f\x42\xfc\xbc\x19\x69\x27\x6e\xc6\xd2\xf5\xec\x0c\xee\xc2\xe1\x27\x4e\x5d\x10\x67\xb4\x45\x78\xc2\x9c\x05\x84\xbf\x18\x2a\xe9\x75\xea\x64\xa9\xbf\x08\xc9\x27\x0c\x36\x45\xbc\x80\xb8\xf0\x18\x9f\xc8\xea\x98\x10\xdf\x94\xdf\xd8\xec\x7b\x6a\x1c\xf3\xe7\x2c\x9a\xe8\x9a\x66\xbd\x0b\x11\x3f\xf0\xf2\x89\xeb\x98\xce\xef\x05\x00\xc3\x70\x1a\x8f\xa0\x1f\x8e\xe3\x69\x38\x84\x61\x34\x9d\x46\x29\x84\xf0\x35\x9e\xde\xc1\x6d\x1a\x7e\x89\x58\x38\x2a\x47\xbe\x35\xa0\xf6\x7b\xe7\xcd\x4c\x29\x66\xf0\x98\xe8\xfd\x98\x5e\x34\x33\xed\xc7\x69\x7f\x76\xff\x69\x18\xfd\xc5\x38\x67\xef\xc7\xf9\xb2\x99\xf3\x34\x1e\x0e\xe8\x74\x51\x55\x2a\x7d\x3b\xd3\xab\x66\xa6\x4a\xe4\xf4\xae\xd9\x92\xdf\xeb\x36\x33\x4e\x09\x5e\x84\x1f\x13\x6e\x56\xd2\x27\xa0\x8d\x4f\xde\xc8\xf9\xda\xc5\x39\x12\x33\xab\x0e\x26\x09\xd9\xea\x70\x12\x44\xcc\x2d\x18\xaa\x2c\xf1\x2b\x49\x98\xdf\xeb\x39\x18\xf7\xb9\x69\x55\x80\x7f\xd0\xc9\xa8\x3c\xed\xe2\x8c\x82\x4e\xc7\xc1\x28\x32\xbc\x55\xd6\xd9\xe5\x61\x67\x9b\x15\xe4\xfe\x38\x3b\x93\x70\xe0\x3a\x80\x0d\x3a\x7e\x33\x1b\xe9\x9f\xe8\x6d\x6c\x5c\xd8\x13\x59\x3c\x12\xbd\x71\x4a\x2e\xc8\x89\x6a\xee\x50\x54\xf8\x79\x1c\x2b\x17\xd0\xc4\x16\x48\x65\xfb\x2c\xf6\x44\x48\xc7\x5e\x94\x12\x95\xd0\x4c\xb7\x78\x9d\x8d\x0b\x55\x62\x0b\x88\xbe\x81\x8d\x0b\x47\x62\x1b\x6c\xa2\xb7\x4d\xc9\x05\x1d\xb1\x15\xb3\x8a\xb7\xb0\x72\x61\x45\x34\xbd\x73\xbd\x81\xc0\x33\xf3\x43\xdf\x40\x08\x3a\x2e\x78\x18\x39\xf1\x7f\xbf\x03\xe5\x06\x30\x0c\x7c\x17\x54\x24\x0e\xa8\x38\xaa\xb6\x15\xf8\x2e\xa8\x48\x5c\x56\x78\x1c\x1b\x17\x54\x24\x8d\x56\x78\x1c\x2f\x17\x54\x24\x96\xe5\x7a\x03\x1b\x17\x4c\x24\x4d\xc6\x7e\x1c\x2b\x92\xd1\xce\x86\xd3\x78\x3c\x24\xc1\xbf\x52\x66\xd1\xd2\x70\x2f\x43\x1e\x2b\x36\x3b\x6b\x26\x81\xef\x82\x03\x2e\xf5\x64\x9a\x26\x9f\xf9\x76\xcb\x0b\x4f\x24\xe5\xe6\xb5\x3d\xfe\x12\x83\x48\xc8\x11\xae\x8a\x51\xa6\xc8\x2e\x28\x98\x99\x20\xca\x02\x53\x78\xf7\xd2\x6a\xe0\xbb\x20\x62\x66\x9a\x76\x15\xa7\xbe\xb7\x08\x2e\xe4\x98\x59\x63\x56\xb6\x49\xfe\x07\x72\x04\x2e\x30\x99\xd5\x6d\xf5\xbf\x2b\x76\x07\x81\x0b\x6c\xbe\xd5\x56\x04\xe9\x02\x34\xbc\x46\xf0\xca\xbb\x03\x41\xe0\x82\x9e\xe9\x5d\x92\x8e\x94\x8c\x54\xbe\x86\xd9\xf4\xde\x8d\x3e\x31\x4a\x5f\xc2\xcd\xe4\x3e\x1c\x4a\xea\x93\xbb\x30\x1d\x03\x55\xe8\x81\x15\xf2\x20\xb8\xb0\x52\x34\x33\xba\x4c\x93\xe4\xc0\x83\x83\x20\xb8\x6c\x62\x52\x8b\x10\x8f\x64\x72\xd5\xc4\xc4\x1e\x1f\x1e\xc9\xa9\xdb\xc4\x49\x40\x3e\xd2\x8e\xf1\x0e\x67\x72\xdd\xc4\xc4\xa8\x65\xbf\x89\x51\xaf\x89\x91\x91\x81\xf1\xc1\xed\x93\x63\x38\x9d\x77\xec\x9c\x24\x69\xc5\x8b\x39\x71\x59\x75\xaa\xc2\xb4\xd2\x7d\xb8\x11\x9c\xfb\x56\x0e\xf5\xd4\x4a\x2d\xc9\x68\xd5\x2d\x19\xb1\x53\x1e\x6a\x52\x45\xe9\x07\x56\xfa\x46\x46\x95\xa9\x1b\xe5\x1e\x6f\x88\x04\xe7\x76\xb7\x36\x32\x28\x74\x30\x59\xbb\x6f\x5b\x32\x26\x74\xb8\xc8\x76\x97\xb6\x65\x48\xc5\xa1\xa4\xed\x8e\xac\x67\x44\x52\x60\xf9\xed\x7a\x45\x25\x38\xb7\xbb\xab\x9e\xfa\xa0\x03\xe8\xd9\x3d\xd3\x92\xe3\xa0\x6c\x7f\xa2\x76\x2f\xac\x27\x33\x86\x3e\x25\x59\xb7\x3e\x2f\xec\x6e\xc7\x92\x17\xd1\x95\x9d\x97\xe3\xdf\x4a\xed\x3d\x7c\x93\x13\xa1\x66\x77\x31\x77\x7a\xa2\x3a\xf4\x51\x2f\xc7\x04\x17\x76\xaf\x4b\x6a\x5e\xe7\xf0\xe9\xc6\xc3\xe9\xe0\xc2\xee\x7c\x66\x4e\x82\x8e\xa4\x6e\xf7\x41\x5b\x2a\xa2\x38\xe1\x61\x2c\xec\xae\x98\xd4\xb7\xa3\xa3\xa8\xdb\xbd\xb1\x9e\x78\x1c\xfb\x76\x40\x70\xd1\x05\x18\xc4\x5f\xe2\x89\x9e\x6b\xe8\x7d\x13\x7a\xad\xfe\x03\x46\x02\x76\x5a\x76\xdf\xac\x25\x1c\x35\x5b\xe1\xb9\x05\x62\xa2\x22\x25\xd7\xd0\xc8\xdb\xbd\xd4\xcc\x33\x32\xa8\xed\x65\xa0\xba\xea\x3e\x6f\x3b\x04\x97\x76\xb7\x35\x13\x0a\xf4\x2e\xbc\xec\x4e\x6d\xcd\x1c\xf4\xe0\xe9\x58\x86\x76\x97\xae\xa7\x08\xef\xf3\xea\x48\x70\x69\x77\x72\x33\x17\xa8\x45\xa0\x3a\xa3\xe6\x17\xa4\x82\x4b\xbb\xaf\x8b\xd8\x5f\x60\x9f\x7c\xf1\x51\x69\xbc\xfe\xa6\x5e\x70\x69\x77\xf3\x6f\x0d\x35\xc9\xa3\xa6\xf1\xbf\x00\x00\x00\xff\xff\xc7\x1c\x89\xcb\x08\x3c\x00\x00")
+
+func fontsScriptFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsScriptFlf,
+ "fonts/script.flf",
+ )
+}
+
+func fontsScriptFlf() (*asset, error) {
+ bytes, err := fontsScriptFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/script.flf", size: 15368, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSerifcapFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x55\x4b\x6a\x1c\x41\x0c\xdd\xf7\x29\xde\x62\x16\x12\x34\x51\x32\xf8\x00\x8d\xf7\xb9\x41\x81\x70\x9c\x19\x30\x84\x10\x26\x64\x91\xdb\x07\x7d\xaa\xaa\xab\xc6\x33\x04\x42\x76\x93\xd8\xed\x6e\x95\x3e\x4f\x7a\x7a\xdd\xe7\x6f\xe7\xe3\xcb\x01\x4f\x78\xc2\xf1\x23\x3e\xe1\xb8\xfc\x3c\x5d\xde\xce\xaf\x2f\x3f\xf0\xe5\x37\x9e\x2f\xbf\x5e\x4f\xf8\xfc\x01\xcf\x6f\xdf\xbf\x9e\x2e\xcb\x72\x38\x6c\xfb\xdf\x6d\x81\x62\x5b\x04\x65\x5b\x8a\xca\xb6\x90\x72\x18\xcd\x4c\x6a\x8f\x0b\xec\x5f\xfd\xb3\x2d\xf9\x7f\x77\x03\x85\xfd\x78\xb4\x80\xdd\x57\x20\x96\x02\xa4\x52\x73\x6a\xf8\x40\x95\xbd\xa6\x32\xd8\xca\xaa\x0a\x1a\x92\x2c\x18\x17\xbb\x7a\x16\x31\x4f\x02\xd9\x7d\xa9\x10\x3d\x59\x31\x93\x27\xa2\x48\xd3\x51\x39\x28\x3b\x56\x02\x47\x3f\x66\xf3\x02\xa4\x9c\xf9\x51\x2f\xb5\x7c\x6f\xd8\x10\x5b\x94\xf6\x29\x5c\x45\x50\x8d\xd0\x6c\x9b\x1d\xae\x20\x00\x65\x0f\x0e\x16\x02\x87\x4b\x20\x07\x8c\xd2\x3a\xf7\x4c\x70\x23\x53\xd4\x6c\x33\xf3\x27\x23\x48\xa0\x46\x51\xd1\xab\x43\xf6\x41\x9b\x8f\x81\x95\xb1\xe6\xca\xd9\x7a\xef\xbc\x47\x5b\xce\x20\x61\x8a\xce\xe0\x60\x6a\x8d\xfd\xc8\xc3\xb1\xee\xd4\x6b\x1e\x62\xb5\xc3\xf7\x23\xab\x15\x80\xc4\x86\x34\xfa\x63\xdf\x76\x73\x1d\x8d\x95\x9e\x9b\x3b\x31\x10\xb6\x7f\xba\xb3\x30\x57\x73\x94\xd8\x5b\x9e\xb6\x29\x07\x6a\x34\x79\x79\xd5\x12\xe0\x68\x28\x0e\xac\x4e\x23\xd6\x99\x0e\xc7\xac\x01\x5a\x03\xf5\xa4\x0c\x34\x74\x81\x4f\x47\x84\x49\x21\x47\x92\x69\x0d\xa6\x43\xee\xab\xb7\xaf\x2b\x25\xf7\xae\xc9\xd6\xcc\x4c\xb1\x7a\xaa\x34\xb5\x74\x63\x2f\x6b\x5e\xe4\xa1\x6a\x3d\x6e\x64\x66\x4b\x1c\xd3\xe2\x5c\x7d\xe5\x46\x15\xb2\x67\xf6\xb1\x32\x35\xb6\xba\x43\xad\x5f\x24\x31\x98\x06\xa3\x90\x14\xe9\x2f\x82\x70\x2b\x54\x9d\x68\x28\xf5\x17\xf2\xab\xcc\x95\x98\xa0\x4c\x13\xbc\x11\xad\x65\x64\x6f\xbd\xd5\xea\x1d\xa5\x69\xdd\xbe\xaa\x4f\xa6\x58\x33\xad\x3a\x9d\x49\x22\xce\x95\x6f\xa3\x1e\x1d\x4a\x11\x99\x33\xb4\x11\x49\x89\x37\x94\x89\xcf\x85\x8b\xb0\x8d\x99\xd2\x89\xfb\xb0\xe7\x51\xb7\x2c\x21\xfe\x49\xfd\x8a\xe1\xd5\x10\x8c\x0e\x9f\x8b\x94\xa2\x37\x12\x4b\x9f\x1a\xbe\x16\x5c\x1d\x7c\xa0\x88\xf7\x30\xb6\xe9\xb3\xf4\x8e\xda\xed\xa1\xcc\x1f\x93\x87\x86\x1f\x1a\x7e\x68\xf8\xdf\x35\xfc\xff\x6e\xfe\x04\x00\x00\xff\xff\x48\xe3\x7f\x45\xd1\x0a\x00\x00")
+
+func fontsSerifcapFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSerifcapFlf,
+ "fonts/serifcap.flf",
+ )
+}
+
+func fontsSerifcapFlf() (*asset, error) {
+ bytes, err := fontsSerifcapFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/serifcap.flf", size: 2769, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsShadowFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x5a\x5f\x6f\x9b\xca\xd3\xbe\xf7\xa7\x78\x2e\xd0\xdb\x46\x4a\x82\x21\x89\x13\x4b\xd5\x91\xa9\x4d\x12\x54\x07\x7c\x30\x6e\x4f\x25\xa4\xad\xdb\x90\xc6\x3a\x8e\x1d\xf9\xcf\xa9\x2a\xf9\xc3\xbf\x5a\x96\x5d\x76\x61\x17\x93\xfe\x72\x81\x89\xcd\x3e\x33\x3b\x33\xcf\xcc\xec\x2e\x4f\xcb\x27\x77\x6e\xe1\x0a\x97\x70\x7a\xe8\xc2\xe9\xa2\x8b\xcb\x7e\xdf\xed\x4c\x9f\xe7\x8f\xeb\x5f\xf8\xfe\x1b\x77\xcb\x6c\xb5\xc2\xf0\x79\xfe\xfa\x9a\x2d\x97\xe8\xd9\xfd\x0b\x9c\x9d\xe1\xfb\x7c\x9b\x3d\x62\xbd\xc2\x74\x37\x5f\x3d\xce\x37\x8f\xf8\x3f\x4c\x5f\xd8\xb0\x4e\xb0\xfa\xb1\xdc\x3f\x66\x5b\x04\xd3\x08\xe3\xf9\x6e\xb1\x3a\x73\x3a\x4f\x8b\x9f\xcb\x6c\x87\x4d\xb6\xcc\xe6\xdb\x0c\xee\xb9\x43\x71\x1c\x17\xde\xfe\x27\x9c\x7e\xff\xb2\x33\xc9\x36\x2f\x8b\xed\x76\xb1\x5e\x61\xb1\xc5\x73\xb6\xc9\xbe\xff\xc6\xcf\xc5\x7f\xd9\x0a\xbb\x35\x5e\xd6\x8f\x8b\xa7\xdf\xd8\x3d\x2f\xb6\x78\x5a\xaf\x76\xa7\x98\x6f\xb1\x5c\xaf\x7e\xd2\xcf\xdd\x73\xd6\xc9\x1f\x58\x64\x9b\x77\x5b\xac\xe6\x2f\x19\xc5\x78\x5d\xce\x7f\x30\x35\xe7\xf8\xb1\x7e\x79\xc9\x56\x3b\x2c\x17\xab\xec\xbc\xd3\x79\x60\x4f\x3f\xd2\x39\x4e\xe6\xfb\x25\x3e\xee\x37\xbb\xf5\x0a\x1f\xb6\xeb\xe5\x7e\xb7\x58\xaf\x06\xd9\x7c\xb3\x7b\x5e\x2e\x56\xff\x9e\xaf\xb2\xdd\x5f\x70\x5c\xbb\xdf\xa3\x8a\x2c\xd8\xec\xb0\xca\x7e\xe1\x75\xbe\x99\xbf\x64\xbb\x6c\xd3\xd9\xee\x5f\x5f\xd7\x9b\x1d\x03\xbc\x0d\xee\xe8\x5c\xe7\xab\x47\x7a\xfb\x65\xb1\x3a\x07\x1e\xe6\xbf\x31\x5f\x6e\xd7\xf8\x9e\x61\xbb\x5c\xfc\x7c\xde\x2d\x7f\xe3\x85\x6b\xf1\xb4\xde\xe0\x7b\xb6\xdb\x65\x1b\xec\xb7\x59\x67\xfd\x94\xc3\x3f\xed\x97\xcb\xb3\x5f\x8b\xc7\xdd\xb3\xfd\x6f\xb6\x59\xd9\xdb\x97\xfd\xf6\x19\xf3\xe5\x2e\xdb\xac\xe6\xbb\xc5\x7f\xd9\xf6\x14\xdf\xf7\x3b\x3c\x66\x4f\xf3\xfd\x72\x87\xf5\x7e\xf7\xba\xdf\xd1\x99\x87\x51\x82\x1f\xcf\xf3\xd5\xcf\xec\xf1\xbc\xd3\x81\x65\x0d\x74\x17\x7a\x3d\x58\xe2\x4a\xd8\xf5\x84\x5e\x01\xb0\x9f\x91\xff\xfb\x19\x9f\x2d\xd0\xaf\x2d\x0b\xca\x27\x7f\x10\xf4\x51\x1c\xd8\xb7\x04\x38\x10\x1c\x0a\x3c\xf9\x1f\x80\x1c\xa8\x9c\x72\xb0\x82\x90\xcb\xb0\x40\x98\x0e\x29\x21\x48\xe9\xcd\x7b\x00\x36\x1f\x6e\xe5\x4f\x93\x13\xf1\x95\x65\x17\xaa\xd9\x85\x74\xbb\x9c\x03\x9f\x06\x08\x4e\xb8\xe6\x04\x29\x83\xb5\xde\xe3\x1b\xf0\xa1\x10\x45\xec\xd4\xb6\x24\xad\xf2\x71\x39\x0e\xc3\xb7\xa4\x2b\x57\xd9\xb2\x0b\xeb\xa1\xf6\x91\x92\x34\x37\x30\x95\x05\x3e\x3d\xdd\x27\xb1\x2d\x3e\xff\x94\xa9\x98\x82\xcf\xd7\x22\x00\x49\xd9\xe3\xa9\xad\x58\x6d\x20\xdd\x72\xe3\x15\xb6\x47\x69\x6b\xdd\x90\xca\xb5\x9c\x63\x05\x91\xdf\x11\xfa\xc7\x75\xb6\x70\x1c\x51\x89\x20\x70\x2b\xe9\x1c\xa5\xa0\x0d\xb8\x77\x0a\x33\x82\xc6\x93\x72\x97\x7b\xc9\xaa\xc8\x27\xec\x37\x6e\x4e\x6e\xd5\x03\xf7\xe5\x80\x4d\x41\xb8\x01\x27\x7c\x00\x07\x93\x27\xa8\x0c\xe1\xb2\xea\x83\x89\x4e\x13\x89\x01\x32\x19\x08\x41\x09\x5f\x8d\xfd\x7c\x5c\x2e\x1e\xec\xae\x9d\x28\x66\xc3\x82\x2d\xdc\x62\xef\x9b\xed\x44\x48\xf1\xb3\xe4\x0a\xe1\x8b\xaa\x33\x64\xda\xa8\x7e\x69\x96\x62\x78\x50\x48\xd6\x0d\x91\x82\x86\xd1\xab\x1a\x40\x95\x9f\x2b\x11\x5b\x84\x57\x31\x25\xc1\xb7\x94\x13\xa7\x46\x96\xd2\xdf\x75\xcf\x2b\x9a\x95\x58\x48\x2d\x59\x96\x3c\x09\x66\xdb\xea\x03\xcc\x9f\x54\xed\x6a\x9a\x2c\x5d\x6c\xd9\x20\xdf\x44\x8c\x97\xe6\xa2\x06\x3b\x2d\xd4\x4a\xb9\xfb\x0b\xbf\xa5\xc2\x4b\xcc\xd0\x85\x73\x04\x28\xb1\xf3\x28\x4b\xe5\x4c\xc6\x83\xac\xf0\x65\xa9\x41\xc9\x2c\x43\x90\x71\xeb\xe4\xc9\x05\x50\xee\x52\x1d\x6b\x74\xd8\x47\xa4\x58\x02\xc7\x22\x44\xd0\xc7\xd2\x24\x1f\xdd\x90\x52\x31\x31\x98\x88\xef\x8e\xce\x45\x0e\xe5\xba\x14\xcd\x0c\x72\x4b\x17\xc5\x52\x4e\x32\x22\x17\x11\x91\x85\x20\x7d\x2a\xe8\x3c\x18\x2d\xf1\x55\x51\x84\xd3\x46\x66\x51\x25\x58\x51\x78\xc7\x2b\xd2\x39\x77\xfa\x41\x0e\xf6\xe2\xe9\xba\xc7\x8e\x59\x95\x16\x9e\x62\xbe\xa9\x5d\xf3\x9d\x6e\xbe\xd2\x10\x4a\x12\x3e\xb8\x1c\x92\xd6\x86\xfc\x41\x86\x97\x52\x9c\xe2\x88\x22\x7b\x1b\xdc\xdd\x2c\x45\x31\x58\x93\x14\x7c\x28\xa4\xa0\x3e\x44\xca\xdc\xa9\x52\x62\xb8\x4b\x49\x2d\xe2\x79\xba\x28\x2b\xaa\x28\x08\xe5\x9d\xa6\x6e\x6b\x83\xb1\xd9\x6c\x29\x6b\x24\x8a\x36\x89\xfd\xc7\x1f\xa2\xff\x95\xfd\x44\x5a\x4d\xfe\x15\x04\x15\xa4\x8a\x53\x85\xd2\xa1\xc9\x80\x1c\x4a\x80\x58\xdc\x70\x74\x6c\xd5\xc6\x5c\xef\x62\x8c\x18\x24\x99\x4b\x5b\x54\x69\xcd\x31\xf5\x1d\x6a\xf0\xb3\x8c\x72\x30\x76\x72\xf9\xc3\xbc\x1a\x40\xd4\x03\x08\x0b\x58\x62\xee\x55\xe5\xf5\xbd\x09\x8f\x0d\x06\x6b\xa7\x6c\x94\x25\x1a\x6c\xe9\x43\xd3\xe8\xe9\xee\x78\x5b\xc6\x79\x2d\x8a\x64\x7a\xb0\x0c\xad\x6b\x39\xda\x12\x45\x48\xae\xd8\xa7\x9a\x7c\x28\xe5\xda\x7a\x05\x39\xd7\x97\x76\x21\xa4\xb0\xf0\x7b\xab\x2c\x1f\x15\x27\x94\xbc\x69\xad\x93\x2c\xa0\x68\xea\xf3\x16\xc3\x20\x40\x72\xb3\xa8\x19\x3c\x85\xe8\x7b\x05\x93\x26\xec\xee\x50\x16\x67\x83\x75\x0e\x22\x15\x1e\xea\xd5\xe2\xc4\xd2\xae\xc0\x4a\x25\x44\x23\x24\x6a\x45\xe5\xa6\x2a\x5f\xa9\x13\x10\xb9\x4b\x57\x1e\x8e\x88\x96\x6c\x40\x27\xf4\xad\xe2\x72\xb5\x2c\x54\x4a\x43\xdd\x8c\xda\x88\xd1\x55\x94\xaa\x47\xdb\xb4\x9c\x8d\x52\xac\xf3\x6a\xa1\x78\x83\x7f\x51\x2c\xa6\xe4\x48\xb3\xa0\x34\x12\x02\xb8\x16\xca\x6a\xe0\x8b\xc5\x2c\x2b\x09\xf5\x62\x2d\xc5\x23\xff\x3f\xd5\xb5\x0d\xd5\xde\x45\xa9\x02\x26\x86\x14\xeb\xca\x54\xc9\xe4\x22\x89\x13\xbb\x9e\x3f\xd5\x10\x90\x12\xbf\x54\x07\x24\x80\x1a\x46\x4d\x63\x29\xf7\x7f\xe3\x91\xa9\xcd\xf8\xc7\x27\xa9\x76\x93\xc2\x40\xf9\xe2\x57\x59\x0c\xe8\xfa\x2e\xb1\x1a\x65\xd9\xfd\x03\x55\x05\xf2\x37\x10\x6b\xf7\x3a\x4b\x4a\xae\x88\x82\xa0\x0e\xfd\x86\xbf\x14\x78\xb6\xae\xca\xf3\x3c\x0a\xb7\x57\xb7\x50\x6a\x5b\x29\xe4\x04\xa9\xa0\xfe\x1b\xdb\x7c\x72\x22\xb2\x86\xa6\x05\xd2\x2f\x0c\xc5\x90\xf6\x6b\x6e\x59\x4a\xbb\x4c\xad\x55\xec\xc8\x8a\xf5\x98\x62\x9a\x68\x17\x65\x40\x64\xc1\x03\xdf\xed\x39\x14\xbc\x2b\xe8\x3a\xe8\x38\xbd\x2e\x10\x46\x67\x1f\x63\xdf\xfb\x84\xe9\xc4\x1b\xfa\x94\xde\x2c\x77\xea\xae\x74\x88\x03\x04\xe1\x67\x3f\x4e\xfc\x11\xfc\x7f\x86\x63\xef\xc1\x4b\x82\x28\xc4\x83\x17\x7f\x3a\x96\xd2\x9d\x9e\x0b\x0c\xfd\x30\xc1\x34\xb8\x0b\xe5\x28\xb1\x8a\x2d\xaf\xb2\x3c\x02\x28\x22\xa0\xd8\xf2\x72\x7a\x17\xc0\x24\x9a\x85\x23\x31\x1a\xd6\x29\x29\xe2\x01\x38\x90\x72\x69\x58\xb6\xc4\xe4\xb4\xda\xea\x17\x9a\x5c\x02\xc3\x59\x1c\xfb\xe1\xf0\x6b\x81\x97\x42\xe2\x8f\xf0\x0c\x8f\x3a\xaa\x53\x1e\x74\xd5\x4d\x32\xa7\x77\x05\x7c\xf5\x43\x81\xc2\xf3\x42\xd9\xe5\xca\xfd\x6e\xbd\xb7\x75\x7a\x3d\xe0\x63\x1c\x7d\xf2\x43\x7c\xf4\xe2\xba\xe1\x54\xda\x39\xbd\x6b\x60\xea\x0f\x73\xab\x97\x96\xe0\xb1\xc5\xfb\xb1\x14\x29\x5f\xb5\xa7\x79\x86\x1b\x74\xf0\x9e\x70\x36\x3a\xbd\x1b\x60\x14\x78\x7e\xec\x4f\x83\xa9\x12\x6a\x39\x1a\x0c\x77\xb2\xd6\x7d\x60\x18\x4d\xbe\xc6\xc1\xdd\xbd\xe4\x50\xfa\xb3\x20\x2c\xe8\xbc\x79\xb0\x23\x5f\xe2\xcb\x8b\x7c\x72\xe0\x29\x34\xe5\x2b\x85\x1c\xfa\xba\x0b\xdc\xfa\x0f\x41\x18\x84\x3e\xa2\x78\x14\x84\xde\x18\x41\x38\x0a\x86\x5e\x12\xc5\x32\xe9\x4a\x12\x34\xef\xd2\x39\xd7\x0e\x30\xf6\x6f\x93\xb3\x49\x14\x84\x49\x10\xde\x61\x14\xcd\x3e\x8e\x7d\x78\xe1\xdd\xd8\xc7\xdf\xb3\x28\x91\xe3\x38\xdf\x9c\xe0\xa9\x14\x62\x67\x45\xda\x5b\xa9\xa6\x6d\xe7\xda\x45\xbe\xed\x2c\x5c\x22\x92\x32\x11\x8b\xe6\xfc\x4f\x38\xb6\xa2\x26\x43\xb9\x00\xa6\xd1\x6d\x82\xfb\xaf\x93\x7b\x3f\xd4\x37\xbc\xc7\xe6\x7a\x09\xc4\xfe\x5d\x30\x4d\xfc\xd8\x1f\x99\x5d\x23\xe6\x93\xff\x02\x5b\xb8\x06\xe4\x40\x52\x83\x6b\xae\x80\x07\x6f\x18\x47\xa1\x49\x0d\xdd\x5d\xa9\x5a\x0f\x18\xf9\x77\xb1\xef\x73\xb5\x2c\x29\x17\x72\x97\x8a\x85\x91\xa5\xb6\x15\xce\xf5\x35\x30\x19\xcf\xa6\x67\x0f\x41\x38\x9b\x2a\x59\x04\x86\xbd\x5f\xdd\x52\xdf\xb9\xbe\x01\xa6\xb3\x89\x1f\x4f\x87\x71\x30\x49\x90\x7c\x89\xf2\xd1\x27\xda\xe2\x59\x29\x50\xce\x75\xbf\x32\xfa\x3e\xf6\xfd\x9c\xe5\xc5\xe6\x97\x68\x74\x6c\xed\xf8\x9b\x2e\xe0\x0d\x67\x89\x0f\x6f\x48\xb3\x61\xa7\xa8\x8c\x96\x61\x9f\xdd\xb9\x71\x80\x87\x60\x18\x47\x6a\x70\x99\x96\xc5\xe7\x82\x13\xa2\xe3\x73\x6e\x5c\x60\x12\x8c\x87\x71\xf4\xa5\xb4\xbc\x18\x41\x6d\x5f\xee\x55\x1e\x44\xb0\x12\xb5\x69\x67\x48\x17\x54\x99\xd1\x68\xec\x63\x14\x25\x3c\x43\x29\xfb\x93\x8a\xee\x34\xd1\xfa\xa3\x60\x3c\xf6\x3a\x65\x20\x97\x99\x4d\x6c\x78\xd2\x67\xaf\x54\xc3\x46\xa1\x5f\x5b\x43\x96\x3e\x19\x74\x4a\x9d\x7a\x34\x2a\xa7\xc3\xd9\xd8\x9c\x31\x8a\x1c\xce\xbd\x52\x89\x5d\x25\xcc\x6e\xae\x81\x3c\xad\xb5\xcc\x16\xa9\xb2\x53\x5a\x6e\x85\xf2\x78\xb0\x6b\xb5\xdd\xb9\xb9\x01\x3e\xcf\xc6\x77\x5e\x8c\xdb\xd8\x63\xc9\x3c\x0a\x29\xb4\x17\x27\x7e\x9c\x4f\x9b\xad\xf6\x79\x1f\x4d\x0b\x7a\xee\x1a\x56\xd7\x0e\xb4\xa1\x22\x65\xb8\xdb\x40\xb9\xed\x2a\xfd\xe5\xc2\xfa\x7a\x61\xf7\xde\xf8\x56\x91\x24\x04\x09\x2e\xe4\x72\xca\x5d\x07\x2a\xa6\x56\x4f\x99\x90\x7e\xb7\x2e\x24\x67\x06\x9f\xd3\x94\x51\x44\x99\x15\xc9\x9b\x62\x31\x2d\xea\x1c\x75\x5e\xe6\x89\x31\xa1\x72\x3b\xf2\xf7\xcc\x9f\x2a\x39\x5c\xec\x3e\x8b\x36\xc3\xb6\x0c\x8b\x6f\xa7\xef\x02\x63\x2f\x09\x42\x0c\xbd\x49\x90\x78\x63\x8c\xfd\x24\xf1\x63\x78\xf8\x12\x24\xf7\xb8\x8b\xbd\xcf\x7e\xb1\xad\xce\xf3\x5b\x6a\x55\x56\x6a\xb9\x79\xaa\x85\xa1\x7f\xd1\x8c\x9c\xa7\x02\x66\xdc\xb7\x22\x5f\x36\x23\x0f\x83\x78\x38\x7b\xb8\x1d\xfb\xff\xd0\x61\x76\x2a\x4e\xe2\x5a\xc2\x5f\x35\xc3\x27\xc1\x78\x44\x15\xb7\xcb\xf3\x80\xb6\xc8\xbd\x66\x64\xa9\x33\xf9\x5f\x56\x03\x4e\xff\xba\x59\x4e\x4c\xa9\xed\x7d\x8c\x72\xcf\xd2\xfe\xe4\xc4\xfa\xa3\xd3\x05\xa7\x7f\x63\x12\xc4\x90\x2d\x25\xdf\xd8\x10\x9b\xf5\xf9\x9a\xbd\xdc\x97\x66\xf4\x32\x10\xac\x6f\x90\x31\x2c\xbc\x2d\xb2\x6c\xfb\x73\x8b\x9c\x21\x83\x8e\xdb\xed\x1a\xb0\x7d\x43\xf4\x4b\x47\x10\x8d\xa5\xd6\xed\x3a\xcd\xc8\xb5\xe8\x6f\x8f\x6c\x62\xac\xdf\x14\xfd\x2a\x3c\x31\x1e\x80\xba\x5d\x13\x6d\xfd\x5a\x8c\x4a\xdd\x73\x6b\xe5\x4d\xd4\x0d\x14\x83\xa7\x62\x7d\xc3\x10\xa4\x44\xa9\x2c\xec\xdd\xae\x89\xab\x81\x6a\x66\xbe\x17\x54\x39\xa8\xa9\xe3\x99\x18\x1a\xd4\x8d\xcb\x4d\x7b\x1c\xd4\x44\xc7\xa0\xc1\xa4\x0c\x56\x5a\xd8\xe5\xdf\x11\xb5\x22\xe4\xe8\x26\x0e\xfa\xc9\x3d\x0b\x76\xe9\x84\x42\x3a\x93\xcb\xd7\x28\xbc\x8c\xd6\xce\x2b\x18\xb4\x89\x7a\xa1\x26\x13\x16\xe7\x42\x45\x2f\x26\x36\xfb\xd2\x4a\xc5\x71\x1d\x13\xe7\x22\x53\xc5\x69\xb9\xa3\xe1\x3a\x26\xce\x45\xa6\x8a\xd3\x1a\xd9\xc4\xb9\xa8\xb1\xe2\xb4\x86\x37\x71\x2e\x32\x55\x9c\xd6\xc8\x26\xbe\x45\x4d\xa1\xd7\x1a\x9d\xae\x8a\x66\xe3\x24\x98\x8c\x69\xc7\xa9\xac\xcc\xcb\x13\x93\x41\x07\xa7\xc0\x3b\xb6\x95\x20\xbd\x6c\x93\x23\x98\xf8\x56\xe8\x37\x4d\xe2\xe8\x93\xcf\x54\xb2\xb9\x4a\xfc\x90\x52\x2c\xdd\x88\xad\x53\xce\xc4\xba\x99\x29\xb7\xb7\xdc\x06\x73\x1d\x13\xe3\x66\xa6\xdc\xde\x1a\xd9\x44\xb8\x59\x63\x6e\x6f\x0b\xef\x9a\xa8\x37\x6b\xca\xed\xad\xd1\x4d\xf4\xfb\x5a\x31\x0b\x8f\x62\xfd\xb1\x60\x7d\xa7\xc8\x75\x4d\xf4\x4b\xee\xa3\x38\x54\xea\xbd\x78\x27\xc3\x12\x0b\x51\xdd\x49\xb1\xeb\x0a\xca\x4d\x1f\xbc\xb1\x00\x9c\xde\x7b\xf1\x04\xd3\x37\xee\x28\xba\xee\xa5\x16\xcd\xd8\x43\xb7\xdc\x3d\x75\xdd\xab\x26\x5c\x29\xce\x88\xf5\x36\xdc\x5e\x13\xae\x31\x9b\xb5\x04\xbf\x6e\x02\xd7\xe5\xb2\x96\xb8\x37\x4d\xb8\xa6\x4c\xd6\x12\xbb\xdf\x84\xad\xf6\xcb\xef\xa5\x97\xa3\xde\xb5\x01\xbf\xe8\xea\xc1\x7d\xb9\xd7\xe5\xda\xf2\x6d\x94\x1c\x53\x3a\xd4\xd4\x6c\xe8\x32\x70\x47\x0b\x5e\x6b\x8e\x25\x21\xe6\x23\x59\xde\x17\x5f\xb8\x5a\x50\x5d\x57\x3c\x68\x77\x08\xeb\x5e\xe8\x09\xa7\x6b\x87\x5b\x43\xea\x59\xa7\xeb\x83\xd5\x92\x7c\x0c\x57\xcf\xba\xa6\x06\x58\x2a\x99\xe2\x5d\xb7\x54\xd7\xad\x5d\xe8\x99\x57\x6f\x7f\x07\xcd\xef\x36\xba\x17\x7a\x96\xa9\x7d\x2f\xe1\x2f\xaa\x6a\xcf\x25\xdc\x0b\x3d\xa3\x0c\xbd\x6e\xfd\x0d\x89\x83\xbc\x1b\xe5\x5e\xe8\x39\xd4\xd8\xe4\xb6\x7c\x0f\xc6\xbd\xd4\x53\xa8\x68\x71\xcb\x83\x45\xda\x61\x94\x07\x18\xdf\xa4\xd7\xbc\x6a\xaf\xe3\xb8\x97\x7a\xe6\xe8\x7a\xdb\x7c\xd2\xef\xda\x9d\x65\xbb\x97\x7a\xf2\xb4\x68\x6f\x1b\xcf\xc5\xdc\x4b\x3d\x83\x5a\x34\xb7\x47\x70\xf5\x34\x6a\xdb\xda\x1e\x01\xd7\x73\xa9\x45\x63\x7b\x04\x57\xcf\xa3\x96\x6d\xed\x11\xec\x6b\x60\x14\x7c\x0e\xa6\x95\x86\x96\x87\xe7\x49\x7d\x81\x4b\x4e\xea\x21\xab\x27\x57\xb5\xb1\x55\x32\x33\x6c\xa1\xa0\x38\x96\xa8\x35\xb7\x0c\x5d\x4f\xb6\x37\xf6\xb6\xf5\x5a\x75\xa5\x27\xda\x1b\x3b\x5b\x0d\xae\x9e\x6c\x7f\xd2\xd7\x6a\xc0\xf5\x8c\xfb\x83\xae\x56\x83\xad\x67\x5d\xb5\xa7\x3d\x66\x90\xea\xbb\x0b\xee\x95\x9e\x75\xf5\x8e\xb6\xe5\xcb\x2d\xee\x95\x9e\x69\x5f\xff\xc0\x08\x55\x65\xff\x3f\x00\x00\xff\xff\xf9\x5f\xcd\xb2\x32\x34\x00\x00")
+
+func fontsShadowFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsShadowFlf,
+ "fonts/shadow.flf",
+ )
+}
+
+func fontsShadowFlf() (*asset, error) {
+ bytes, err := fontsShadowFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/shadow.flf", size: 13362, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsShortFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x53\xc1\x8a\xdb\x40\x0c\xbd\xeb\x2b\x74\x08\xac\x0d\xc9\x0c\xdd\xf6\x50\x68\x58\x04\x7b\x6a\xc9\x6d\x2f\x4b\x33\x30\x71\x12\x27\xcd\x92\xd8\x69\x12\xb7\x2c\x08\x7f\x7b\xd1\x8c\x67\xac\xcd\xad\x90\xc0\xbc\x91\xe6\xe9\x49\x4f\xde\x1d\x77\x8f\xd5\x04\x3f\xe3\x23\x7e\xc5\xd9\x27\xfc\x02\x2f\xbf\xda\xcb\x0d\xab\x66\x8b\xd7\xbf\x75\x7d\xc3\xf5\x3b\xbe\x74\xeb\xd9\xcf\xfa\xd2\x62\xb1\x6e\xb7\xed\x89\xba\xfd\xf1\xdd\x74\x9b\xab\x39\x34\xdb\x43\xd5\x54\xa6\xde\x76\x25\x3c\xb7\xa7\xf3\xb1\xbe\xd5\xdb\xf0\xf8\xdc\x5e\xe4\x78\x6b\x71\x77\xd8\x1f\x23\xcf\x8f\xae\x6a\xf0\xb9\xba\x60\xf1\xb6\xa1\xb7\x6e\xdf\xd5\xb7\xda\xfc\xee\x0e\x27\xd3\x6d\x4e\xa6\xbe\x96\xf0\xfd\x74\xbe\xb4\x7f\x84\x62\x5f\x1d\x1a\x5d\x1b\x60\x42\xf1\x47\x80\x4c\x80\x86\x00\x91\x08\x1e\x1e\xc2\x21\x02\xe6\xf8\x0f\xa0\xe0\x15\x81\xe7\x52\xa0\xe0\xd6\x12\xd8\x36\x05\x4b\x82\xe2\x75\x00\x53\x02\x61\x20\x02\x4b\xe0\xe2\xc9\x05\x10\x4e\x2c\x0f\xd9\x25\x1e\xcf\x5e\x34\x60\xc2\x38\x10\x10\x78\xaf\xb4\x20\x81\x89\xd7\x28\xef\xd3\xb5\x75\x04\xce\x26\xf1\xc2\x12\xf9\x22\x2e\x09\xac\x4f\xc1\x92\xc0\x94\xe9\x99\x64\xf6\xdc\xa7\x4c\x39\xf9\x14\x44\x61\x2f\x7c\xee\xb4\xd7\x05\x8b\xbe\xfc\x10\x0c\x18\xed\x28\xdf\xa8\x69\x86\x43\x52\x37\x0e\xc3\x13\xcc\xee\xc7\x22\x34\x9c\x9b\xf5\xa2\xc0\x09\x73\xdf\x07\x45\x4c\x60\x67\x9c\xe5\x96\xf1\x1f\x79\x57\x04\x6e\x9a\x2c\x73\x04\x9c\x2a\x2e\x7b\x82\xa5\x57\x20\x17\xb0\x3d\x12\x38\x3f\x12\xca\x91\x71\xc4\xe1\x87\xc3\x76\xf8\xb4\x03\xc2\x1c\x9d\xa3\x48\xc6\x3e\xd7\xb5\x81\x61\xa0\x88\x57\x18\xae\xdc\x78\xf5\xc1\x2d\xd6\x1d\x87\xc8\xab\x8e\xa4\x32\xc5\x4a\x59\x13\x2d\x1b\x97\x25\x48\x66\xd5\x87\x4c\x9b\xad\x8e\x07\x45\x8e\x93\x8a\x30\x75\x1b\x0b\x46\x10\x0c\x1a\x29\x83\xdb\xb9\xad\x5e\xf5\xe8\x24\xc7\x65\x25\x6a\x2e\x03\xd9\x60\x1e\xe6\xd5\x1d\x1c\x87\x74\x5d\xb0\x9e\x5d\xde\x37\x2f\x1b\x95\x00\xab\xb4\xb8\x07\x36\x2f\xf4\x72\x45\xc0\x13\x55\xa7\x88\x2a\xa2\xc8\xfc\xa9\x9a\xd1\x3d\x93\x1d\x1c\x8a\xce\x93\x82\x9c\x33\x95\x22\xcc\x79\x86\x53\x4d\x15\x8a\x94\x0a\x0c\xae\xa9\x7e\x38\x45\x56\xaa\x1f\x9f\xb7\x64\xa6\x26\x28\x69\x0b\x4d\x9d\x97\x01\x43\x68\x91\x45\x08\x7c\x9a\xdf\x65\xda\xf0\xf1\xe0\x9d\x3f\xf3\xb8\x87\xba\x25\x31\x07\x9f\x86\xb6\x9b\x4e\x99\x63\x8c\x1a\x6f\x00\xa5\x02\x0b\xfe\xbf\x34\x19\xc6\xb7\x14\xf9\x17\x00\x00\xff\xff\x6e\x3d\x1c\xff\xfd\x05\x00\x00")
+
+func fontsShortFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsShortFlf,
+ "fonts/short.flf",
+ )
+}
+
+func fontsShortFlf() (*asset, error) {
+ bytes, err := fontsShortFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/short.flf", size: 1533, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSlantFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x5b\x6d\x4f\xdb\xc8\x16\xfe\x9e\x5f\xf1\x7c\x40\xba\x20\x51\x06\x1b\x08\x44\x62\x2b\xd2\xc4\x05\xab\x21\xce\x3a\x49\xbb\x95\x22\x4d\xd3\x62\x4a\xb4\x21\x41\x49\xd8\x55\x25\xff\xf8\xab\x79\x9f\xb1\xc7\x4e\xd2\xf6\xde\xee\xaa\x36\xac\xe7\x9c\x99\x73\xce\x73\x5e\x67\x1f\xe7\x8f\xe1\xf4\x00\x4d\x5c\x20\x68\x22\xb8\x40\x70\x8a\x53\x04\x57\x67\x41\xab\x31\x9c\x4f\x17\x1b\x7c\xfd\x81\xdb\x79\xb6\x58\xa0\xf3\x34\x7d\x79\xc9\xe6\x73\x9c\x91\xd6\x19\xde\xbc\xc1\xd7\xe9\x3a\x7b\xc0\x72\x81\xe1\x66\xba\x78\x98\xae\x1e\x1a\xf1\xe2\xdb\xfc\xf5\x21\x5b\x23\x1e\x26\xe8\x4d\x37\xb3\xc5\x9b\xa0\xf1\x38\xfb\x3e\xcf\x36\x58\x65\xf3\x6c\xba\xce\x10\x9e\x04\x6c\x71\x10\xa2\xfd\xfa\x1d\x41\xab\x75\xde\x18\x64\xab\xe7\xd9\x7a\x3d\x5b\x2e\x30\x5b\xe3\x29\x5b\x65\x5f\x7f\xe0\xfb\xec\x9f\x6c\x81\xcd\x12\xcf\xcb\x87\xd9\xe3\x0f\x6c\x9e\x66\x6b\x3c\x2e\x17\x9b\x63\x4c\xd7\x98\x2f\x17\xdf\xd9\x73\xf3\x94\x35\xf8\x07\xb3\x6c\xf5\x9f\x35\x16\xd3\xe7\x8c\xd1\x78\x99\x4f\xbf\x89\xbd\x4d\xf1\x6d\xf9\xfc\x9c\x2d\x36\x98\xcf\x16\xd9\x49\xa3\x71\x2f\xbe\x7e\x60\x07\x1b\x4c\x5f\xe7\x78\xf7\xba\xda\x2c\x17\xb8\x5e\x2f\xe7\xaf\x9b\xd9\x72\x71\x93\x4d\x57\x9b\xa7\xf9\x6c\xf1\xf7\xc9\x22\xdb\xbc\x45\x10\x92\x56\x93\x6d\x64\x26\x4e\x87\x45\xf6\x2f\x5e\xa6\xab\xe9\x73\xb6\xc9\x56\x8d\xf5\xeb\xcb\xcb\x72\xb5\x11\x04\xdf\xc7\xb7\xec\xac\xd3\xc5\x03\x7b\xfd\x34\x5b\x9c\x00\xf7\xd3\x1f\x98\xce\xd7\x4b\x7c\xcd\xb0\x9e\xcf\xbe\x3f\x6d\xe6\x3f\xf0\xac\x76\xf1\xb8\x5c\xe1\x6b\xb6\xd9\x64\x2b\xbc\xae\xb3\xc6\xf2\x91\x93\x7f\x7c\x9d\xcf\xdf\xfc\x3b\x7b\xd8\x3c\x91\xbf\xb3\xd5\x82\xac\x9f\x5f\xd7\x4f\x98\xce\x37\xd9\x6a\x31\xdd\xcc\xfe\xc9\xd6\xc7\xf8\xfa\xba\xc1\x43\xf6\x38\x7d\x9d\x6f\xb0\x7c\xdd\xbc\xbc\x6e\xd8\xc9\xfb\xc9\x08\xdf\x9e\xa6\x8b\xef\xd9\xc3\x49\xa3\x01\xf6\xe7\xe0\xe0\xa6\x21\x9e\xe0\x2f\x07\x07\xe0\x2f\xec\xc9\x5e\xf8\x13\x37\x0d\xf1\xc4\x8d\xf8\x9a\x52\xfe\x24\x20\xec\x49\x40\xd8\xa7\x84\x12\xf6\xe5\x21\x3d\x12\x4b\xf5\x02\x0a\xca\x7e\x8f\x1c\x47\x37\x8d\x9c\xe4\xfc\x6b\x41\x5f\x52\xb7\x69\x83\x52\xf6\x2f\xfb\x81\x52\x02\x42\x40\x28\xa7\x0e\x50\xfe\xab\x9b\x86\x79\x97\x7c\x39\x6b\xc3\xb4\x40\x8e\xbf\x50\xbd\x59\x4e\x02\x87\x14\x38\xc2\x4d\x83\xf0\xff\xc4\x5e\x24\x0d\xf1\xb5\x5e\x78\x48\x8f\x28\xe1\x2b\xd8\x87\xe2\x53\xfe\x42\xa1\x56\xf1\x13\x5b\xbc\x25\x09\x4a\xe5\x96\x0e\x41\x21\xbe\x60\xcc\x31\x21\x39\x63\xcb\x69\x5d\xe3\xa6\x31\xa1\x94\x52\x32\x21\x25\x12\x5c\x08\x87\x4c\x68\xd0\x32\x13\x22\x13\x5f\x96\x4e\x48\xb5\x3a\x04\x33\x22\xb6\x08\x29\x9c\x9c\xe6\xce\x32\x49\x26\x47\x2e\x5e\xa4\x84\x94\x3e\xd5\x69\x1d\xc1\x28\x31\x53\x4a\x72\xc6\x96\x53\x14\x2a\xa1\x34\x87\xd8\xaa\xad\x0a\x77\x19\xa4\x6a\xb9\x66\xa9\xd4\x24\xdf\xb6\xe0\x52\x58\xe6\xfc\x25\x8c\x88\x9b\x50\x89\xaa\xfc\x82\xff\x61\x54\xb9\x48\xb9\x1d\x7b\x36\x53\xa6\x4a\x8f\xc4\x8f\xfa\x43\x29\x52\x23\x54\x57\xf7\x80\x25\x18\xbf\xee\x85\x74\x85\xc2\xa5\x32\xb8\x7c\x85\xe2\x89\xd6\xbb\xbd\x5a\x2f\x66\xcf\x6b\xb8\xe8\x82\xa5\x0c\x1b\x5d\xc2\xd2\xd8\x4b\x2e\x79\x09\xe9\x4a\x73\x23\x90\xf2\x20\x45\x31\x48\x61\x89\x75\x4a\xf5\x94\x9b\x24\xf8\xf7\xd6\x52\xcf\x26\xa5\x8c\x04\x42\xc5\x06\x95\x4e\xb5\x52\x8b\x5a\x35\xfe\x43\xf1\xe6\x7b\xd4\x1f\xb3\x03\x68\x4d\xea\x13\xcb\x2d\x38\xf0\x2e\x1c\x81\x53\x21\x1a\x61\xd8\x2e\x67\x63\x2a\xfb\xc8\x99\x2a\x40\x53\x0e\x4b\xce\x0d\xf9\x8e\x5a\x2d\x9b\x84\xd4\xd3\x84\xd2\xe3\x5a\x69\xcb\xdf\x48\xee\xdc\x5a\x85\x73\xb1\x5d\xcf\xb6\x4f\x85\x0f\xe2\xf0\x14\xee\x85\x8a\x4d\x08\x0f\x71\xd3\x98\x70\xb9\x61\x42\x27\xae\x7b\x51\x80\x17\xa2\x26\x52\x5d\x96\x4d\x95\x30\xc6\x84\x62\xe8\xa9\xc3\x0a\xa1\x5a\xb4\xa5\x44\x88\x32\x5b\x02\xe3\x09\x7c\x71\x44\xd9\x8d\x16\xa3\x85\x2d\x4a\xf1\x45\x9e\x44\x6b\x82\xcb\x55\x8a\x73\xa2\x8d\x48\x5b\x20\xa4\xfd\x41\xf8\x3f\x02\x22\x3c\x21\xa7\xcc\x95\xca\x16\xe4\x34\xf7\x9a\x2f\xb4\xf5\x72\x4b\x30\xa6\x60\xed\x40\x9b\xae\xd7\x41\x58\x96\x2b\x4d\x97\x48\x69\x13\x01\x05\x58\xe6\x54\x26\x51\xdc\xc5\x44\x19\xb1\x86\xe3\xd6\x5d\x54\xe1\x10\x9a\xa5\xb5\x93\x3a\x1c\x56\x12\xe2\x51\x12\xda\x15\xb9\x6e\xb3\x0a\xd0\x1e\xb9\x08\x8b\x52\x67\xda\x26\x17\x3b\x41\xb1\x92\x14\xaa\x21\xce\x41\xaf\xf6\x52\xf4\x51\xce\xa1\x94\x8d\x50\x13\x1a\x45\x10\x50\xc1\xb5\xb4\x0d\x4f\x10\x91\x7b\x10\x5c\xc9\x3e\x07\x31\xe7\xd0\xc1\xfd\xf8\x5a\xab\x26\x67\xe1\x57\x1c\x82\xc7\x76\x2f\x09\x3b\xa4\xdb\xb9\x41\x31\x52\x96\x45\xa8\x0f\xcf\x7c\x86\x12\x62\x4e\x6d\x47\x69\x7b\xcb\xb2\x1c\x35\x39\x3b\x65\xcc\x8d\x46\x18\x61\xa2\xcf\x62\x48\xe5\x35\xee\xfe\xa7\xc3\x6a\x15\x5e\xac\x58\xa9\xa2\xe5\x2f\x87\xf5\x09\x9d\xfc\x04\xff\x63\x68\xfe\x7e\x75\x96\xc3\x1d\xf3\x6b\xc2\xcd\x6e\x8b\xd8\xd4\x38\x70\x13\x9d\x61\x60\xee\x62\xd3\x13\xee\x4d\xbc\x37\x1e\x66\x77\x73\xa6\x0a\x10\xdc\x66\x39\x81\x5c\x98\x02\xf8\x9b\x5c\x9e\x7b\xe1\x44\x2d\x40\xe5\x22\xe5\xb4\x48\x38\x54\x2c\x42\x24\x2f\xbb\x2b\x93\xde\xcb\xd4\x87\x2f\x10\x6f\x50\xb6\x08\x0d\xab\x82\x1a\x64\x68\x63\x4b\x27\x98\xc8\xd8\x8d\x2d\x79\x43\x4d\xa2\xa1\x11\x48\xdc\x30\x67\xc0\xa7\x62\xa2\x41\xae\x57\x69\x3a\x43\xa7\xd2\xdf\xb2\xd8\x0b\x19\x7d\xc5\x32\x19\x8d\x61\xe2\xbb\x97\x9b\xcc\x03\xb5\xc3\xf0\x7a\x3c\x53\x0f\x10\x56\xcb\x20\x27\x79\x2e\x13\x81\xda\xca\xce\xcd\xd6\xcb\x2f\xc5\xfc\xfd\xc6\x2d\x82\xf0\xb1\xa6\x08\xb2\xd2\x14\x50\xe5\xe4\xbf\x14\x91\x79\x5c\xe1\x19\xa0\x0f\x5b\x95\xa4\x11\x7a\xe2\x26\xd1\x55\xf9\x91\x84\x26\x57\xaf\x42\x04\xf1\x16\x44\x42\xea\x32\xd5\xb5\xe2\x52\x11\x50\xc7\x15\xf1\x41\x33\x96\x41\x8d\x6d\x98\x48\x70\x4f\x9c\xcd\x96\x03\x9a\x13\xa1\x4d\x7c\xae\xf6\x00\x96\xb6\xb4\x8c\x8d\x90\xed\xf0\x2a\xb3\x59\xcb\x15\xed\x26\x67\x93\x23\x12\x9f\x9c\xa5\xef\x94\xb5\xda\xf6\x6c\xdd\x5a\x63\x96\xd9\x96\x6d\x4c\xbb\x14\xcd\xbd\x1b\xd6\xe5\x8e\xcc\x4a\x64\x20\xf6\xba\x09\x54\x36\x49\xea\x37\x5c\x14\xb2\x1d\x6f\xbe\xb8\xa2\x72\xc5\xe5\x8a\xcc\x03\x8c\xda\xe0\x55\x25\x73\x1b\x54\xba\xb8\xd2\xe6\xa9\xbd\xbd\xc7\xb6\xd5\xe1\xb6\x05\xbd\x93\x52\xd0\xdd\x0f\xcf\xda\x2b\xda\x76\xe6\x9c\xb9\x58\x1f\x6e\x89\x74\x75\x8b\x0f\xa9\x6a\x1a\x55\x57\xc5\xea\x80\x0a\x53\x62\xc3\x12\xc9\xc4\xab\x73\x71\x4e\x53\x90\x79\x32\x0a\xbf\xdf\x92\x5e\xd3\x8a\x8c\x2a\x2a\xca\x88\x58\xe9\x7a\xcc\x4a\x7b\xb1\xbd\xde\x90\x90\x71\xf4\xa6\x9c\x20\x1b\x51\xd9\xf1\x94\x8b\x8a\xbe\xe5\x1d\x8c\x1a\x78\xd8\x82\xf6\x26\x17\xdb\xfd\x89\x8a\x19\xa2\x8f\xa4\x96\x49\x18\x17\x62\x8f\xdb\x24\x53\xdd\x9c\x6b\xb6\x49\xd8\x4d\x32\x96\xba\x95\x97\x15\x7b\x63\xe5\x26\x9b\xdb\x24\xab\xec\xad\xd1\xb7\xf4\x6d\x45\x6f\x8d\x4c\x08\x3f\x82\x6a\x05\xaa\x0e\x2c\x4c\x3c\x2d\x39\x74\xdb\x2d\x6a\xcf\x48\x45\xfe\x22\x20\xb3\xa5\x42\xa0\x76\xaf\x80\x0a\x12\xb2\x87\xb2\x6b\x9d\xe2\x90\x80\x22\xb1\x47\x6e\x58\xb3\x8b\x2f\x3b\x47\xc3\xff\xf3\x41\x2a\x63\xb2\x71\x78\x96\xc7\x2b\x16\xa2\x0c\x6d\xb2\x65\x56\x08\xbb\x9c\x50\xd0\x3c\x05\xfa\xc9\x9b\x77\x69\xd4\xfe\x80\xe1\xa0\xdd\x89\x04\xf1\xfd\xbb\xf5\x41\x33\x00\xe2\xfe\xc7\x28\x1d\x45\x5d\x44\x7f\x75\x7a\xed\xfb\xf6\x28\x4e\xfa\xb8\x6f\xa7\x1f\xf6\x0f\xac\x41\x33\x04\x3a\x51\x7f\x84\x61\x7c\xdb\xb7\x31\x62\x67\x31\x6e\x02\x54\xee\xb0\x07\xcd\x33\x60\x90\x8c\xfb\x5d\x87\x8c\x25\xb9\x63\xca\xd3\x54\xd1\x27\x86\xce\x40\xa9\x20\x79\x48\x8f\xcb\x3d\x0d\x41\xf8\x1c\xe8\x8c\xd3\x34\xea\x77\x3e\x1b\xda\x84\x7b\x42\x01\xc5\x5c\x67\x59\xa6\x29\x00\xd9\xd8\x12\x65\x80\x6c\x92\xe5\xde\x99\x42\xd0\xbc\x00\x3e\x47\x7d\x43\x5c\x85\x09\xaa\x2a\x5b\xe2\xcc\x29\xa8\x19\x8e\x14\xbc\x60\xd0\x6c\x02\xef\xd2\xe4\x43\xd4\xc7\xbb\x76\x5a\xe1\x70\x64\x7c\x55\xd3\x84\xb2\xc3\x09\x9a\x97\xc0\x30\xea\x70\xad\xda\xe2\x94\xde\x95\x40\x69\x56\x9a\x5d\x8e\xdc\xbc\xa9\x66\x9b\x45\xee\x0a\xe8\xc6\xed\x28\x8d\x86\xf1\xb0\x61\xc1\xc2\xa0\x82\x3b\xa5\x03\xe5\x9d\x74\x46\x7e\x50\x3e\x61\x0b\xe8\x24\x83\xcf\x69\x7c\x7b\x37\x72\x45\x66\xe5\x56\xfc\xa7\x89\xf6\xab\x5c\xb3\xb9\x02\x9f\xd2\x56\xce\x8b\x5d\xad\xae\x09\xa5\x56\x34\x08\x2e\x4f\x81\xf7\xd1\x7d\xdc\x8f\xfb\x11\x92\xb4\x1b\xf7\xdb\x3d\xc4\xfd\x6e\xdc\x69\x8f\x92\x54\x86\x73\x9d\xb4\x8a\x9c\x95\x4e\x38\x8c\x9d\x70\x7e\x00\x94\xf5\x74\x19\x00\xbd\xe8\xfd\xe8\xcd\x20\x89\xfb\xa3\xb8\x7f\x8b\x6e\x32\x7e\xd7\x8b\xd0\xee\xdf\xf6\x22\xfc\x39\x4e\x46\x0e\xa6\x74\x29\xa0\xbb\xab\xaa\xbf\xaa\x3a\xac\x4e\x0d\x16\x5c\x86\xe0\xb3\x39\xa3\xbc\x52\x39\x04\xd7\x1c\xdc\x68\x20\x88\x9c\x01\xc3\xe4\xfd\x08\x77\x9f\x07\x77\x51\xbf\xe1\x1e\xc4\x29\x44\xad\xd9\x88\xb3\x8d\x73\x20\x8d\x6e\xe3\xe1\x28\x4a\xa3\x6e\x9d\xb6\x00\x4b\x5b\xcc\xc3\x2a\x6d\x1d\x83\xaa\x62\x5c\x06\x7e\xbf\xb6\x2e\x80\xfb\x76\x27\x4d\xfa\xb5\x43\x1b\x75\xca\xa2\x52\x38\x89\x26\xd0\x8d\x6e\xd3\x28\x52\x1b\x2d\x16\x42\x44\xa7\xa8\xc4\x8a\xa3\x16\x85\x4b\x60\xd0\x1b\x0f\xdf\xdc\xc7\xfd\xf1\xd0\x16\xbe\x86\x8e\x9c\x52\xc1\x6a\x9a\x50\x39\xfb\xab\xec\xab\x06\x97\x57\xc0\x70\x3c\x88\xd2\x61\x27\x8d\x07\x23\x8c\x3e\x25\x0d\x67\x4a\x03\xdd\x66\x76\x87\x33\x3e\xa5\xb6\x0a\xb4\xee\xd2\x28\x6a\x58\x4e\x27\x97\x96\x41\xe5\xe4\xa6\x96\xda\xd5\x29\xd0\xee\x8c\x47\x11\xda\x1d\xe6\xc3\xf5\x10\x40\x89\xdd\x5b\x5e\x07\x57\x01\x70\x1f\x77\xd2\xc4\x31\x50\x2b\xc5\xdf\xda\x6f\x3d\x51\x09\xac\x1b\xe6\xae\x42\x60\x10\xf7\x3a\x69\xf2\xc9\x52\xa2\x29\xa4\x21\x67\x8b\x38\xd4\x18\xa2\x56\xea\x45\x4b\x1d\x47\x4e\xf4\x8c\xed\xb6\xdb\xed\x45\xe8\x26\xec\x88\x70\xa6\x7c\x07\xe2\x78\x7c\x11\xff\x9c\x05\x8c\xa8\x1b\xf7\x7a\xed\x86\x22\xe6\xfc\x45\xf9\xb6\x8f\xf8\xb7\x17\xae\x36\x92\x7e\xd4\x50\xdd\x93\x6b\x9d\x80\xaa\x63\x96\x7a\x20\xc1\x55\x93\x99\xfd\xb0\x33\xee\xd5\x7a\x29\xe5\xa4\x26\xc2\x47\x15\xc6\x2d\x3e\xbd\x5e\x02\xdc\xc3\xee\xe6\xa0\x14\x9a\x8d\x43\x32\x43\x1a\x59\x0e\xba\xbd\x83\xe0\xea\x0a\xf8\x38\xee\xdd\xb6\x53\xbc\x4f\xdb\x22\xd2\x24\x7d\x46\xb8\x9d\x8e\xa2\xb4\xa1\xa6\xdd\x62\xf3\xd7\xa2\x6d\x45\x75\x9b\x8b\xfd\x23\x20\xce\x8a\x67\x9d\xe2\xcb\xd8\x6e\xba\x5f\x42\x6c\x8c\x5f\xcb\xcf\xef\xae\xdd\x7b\x6f\x33\x83\xc3\x4e\xe1\x9f\x33\x94\x30\x93\x97\x03\x88\x13\x87\x8b\xf3\x50\x73\xd0\xd6\x69\x99\x31\xc7\x9c\x3a\xea\x50\x97\xd2\xc6\x4f\xe4\x54\x8e\x08\xa8\x9a\x9b\xe3\x1a\xd6\xa1\x19\x33\xeb\xdc\xf2\xa0\xee\xd1\xed\xd3\xb7\xec\x94\xed\xcf\x71\x34\xac\xc9\xd7\x54\xd3\x97\x73\xf5\xb4\x7d\x82\x56\x08\xf4\xda\xa3\xb8\x8f\x4e\x7b\x10\x8f\xda\x3d\xf4\xa2\xd1\x28\x4a\xd1\xc6\xa7\x78\x74\x87\xdb\xb4\xfd\x31\x6a\x38\x5e\x4f\x46\x27\x5e\x48\xe8\x32\x42\x17\x11\x8e\xe5\xb5\xce\xea\xa9\x73\x6f\xe3\x2b\xc0\x76\xa3\x7e\x5e\x4f\xbd\x13\xa7\x9d\xf1\xfd\xfb\x5e\xf4\x97\x58\x45\x64\x8a\x47\x55\x43\x52\xd4\x42\xa6\x14\x32\x95\x90\x1b\xe0\x5b\x17\xf5\x8c\x46\x71\xaf\x2b\x8f\x21\xab\x34\x76\x10\x55\xa8\xed\x51\x71\x05\xad\x66\x3d\x27\x3b\xf1\xfa\xe5\xfa\x2e\x68\x5d\xd6\x73\x4b\x99\xab\x68\xbf\x4b\xa4\x05\x1c\x1e\x1e\x1d\x49\x3f\xbe\xdf\x50\x34\x68\x5d\x55\x31\x8a\xac\x14\xc2\x1e\xa8\xc9\x5f\xea\xb1\x12\xec\xa1\x23\xcf\x77\xcc\xe0\x51\x24\xfe\x9e\x6e\xbe\xe2\xde\xaa\xe0\xde\x91\x76\x62\xfc\xfb\x4f\x0d\x5e\x09\x1f\x45\x73\x5e\xe1\xe9\x69\x05\xaf\x68\x07\x3c\xa9\x2b\x0a\xc4\x6a\x36\xda\x16\x1f\x9e\x06\xf5\xd4\x6b\xf1\xb4\x9d\x7a\x95\x2f\x88\x76\xc7\x93\xf2\xea\xb4\x66\xfe\x19\x9e\x56\xb9\x85\x68\x0f\x2b\xa7\xaa\xc3\x62\x06\xc7\xb4\x74\xcf\x8b\x73\xab\x72\x13\xf1\x76\x95\x40\xb6\x83\x50\x2d\xb4\x2a\xdf\x10\x6f\x57\xc9\x0e\xd4\xab\xfc\x41\xbc\xb3\x4a\xa0\xc2\x4e\xdd\x48\x3a\x3c\xad\x72\x05\xf1\xee\x2a\x01\x75\x66\x41\x75\x2a\xa9\xf2\x07\xd1\xe8\xae\xba\x4f\x42\xa9\x35\x6e\x91\xe9\xb7\x2a\xcd\x7d\xd5\x7e\x78\x5a\x05\xfc\xfe\x6e\x7e\xdb\xcc\x9f\x61\xc6\xcf\xa5\xe9\x33\xe3\x14\x54\xc1\x3e\xa9\xb0\x31\x2a\x6d\x6c\x97\x9e\x79\x18\x54\xc1\x3e\xa9\xb0\x31\x4a\x89\x75\xdd\x69\x1b\xf5\x2a\xd8\x27\x5e\x1b\x93\x26\xa6\x2c\x6c\x37\x16\x55\x80\x4f\x8a\x8a\x50\x7a\xd0\x6a\xd8\xf5\xc6\x56\x18\x54\xc1\x3c\xf1\x58\xf0\xaf\xb6\x03\xc3\x80\x95\xa8\xe3\xde\x28\x1e\xf4\x58\x76\xee\xf6\x56\x6e\xf4\x83\xe4\x5c\x5a\x6f\x79\xf1\xa5\xee\xb6\x6a\x1a\x55\xe0\x96\x3b\x1e\x8e\xd2\xe4\x83\x2e\xe7\x74\xe2\x4f\x88\xca\xc6\x09\x51\x1d\x04\xfe\xc6\xb7\xab\x5b\x86\xee\x76\xab\xe0\x3d\xf6\xd8\xa7\x31\xd0\xea\x89\x83\x4f\x01\x55\xa0\x1e\x7b\xac\x14\xda\x4c\xf7\xe3\x51\x85\xe8\x71\x95\xad\x42\x1b\xeb\x5e\x8c\xc2\x2a\x40\x8f\xb7\x59\xd3\x4f\xb4\xb8\xc3\xb0\x0a\xe0\x9f\x0b\xa2\xe3\x82\x53\x62\x2b\x5f\x32\x28\x4c\x90\xc2\xb0\x0a\xda\xa3\xbb\x24\xed\x3b\xfa\xf6\x0e\x5d\xa9\xaa\x2e\x3d\xc3\xb0\x30\xd4\xa0\x1e\xde\xb7\x7b\x9a\xf4\xf0\xae\x9d\x0e\x30\xac\x76\xe3\xfb\xb6\xbb\xc3\xf0\xdc\xcb\xc8\x57\xa1\x14\x4d\x77\xb7\x21\x7f\x18\x5e\xd4\x71\xa8\x35\xdc\x5d\x39\x34\xeb\x38\x6c\x37\xdb\x5d\xd9\x5c\xd6\xb1\xa9\x70\xb3\xfb\x71\xb8\xaa\xe3\xb0\x9b\x93\xdd\x71\x6c\x13\x86\xad\x3a\x5e\x85\xea\xc4\xe8\x46\xd6\x29\x3b\x1f\xe9\xec\xd4\xcf\x26\xb2\x6b\x89\x9b\x86\x3b\x74\x17\xd4\x61\xc5\x3e\x73\xb5\xe2\x98\x7a\x3a\x08\x9c\x53\xe0\xe5\x54\xae\x43\x6c\x8e\xf5\xd7\x46\x64\xf1\xc1\xa9\x87\x5e\xea\xc5\xca\x43\xc9\x49\x27\x20\xb5\x17\x43\xc2\x33\x3f\xcc\x4b\x15\x87\xcc\x3c\x74\xe2\xb1\x85\xaa\x1f\xd3\xfe\x4a\xa3\x9c\x72\xc8\x8c\x40\xd6\x1b\x9e\x3b\x34\xe1\x99\x1f\xd2\xbe\x0a\x83\x5a\x66\xaa\xad\x54\x65\x02\xaa\xd0\x98\x78\xd3\xe6\x33\x3f\xac\x8b\x95\x85\x72\x82\xba\xae\xa8\x1d\xa2\x85\x67\x7e\x14\x97\x2a\x0a\x55\x2e\xd3\x5d\xae\x90\x84\x67\x7e\xe4\xfa\x2b\x09\x55\x48\x98\x3a\xc2\x3f\xd0\x76\x44\xee\x87\xab\xa7\x82\xb0\x67\x46\xd4\x9a\x2c\x5a\x2c\xaa\xee\x60\x84\xe7\x7e\xb4\xea\xca\x21\x57\xdd\x9b\x3f\xf2\xfc\x0f\x31\xd7\x10\xbf\x63\x18\xfa\xc2\x43\x8d\x3f\xe4\x9f\xfb\xc1\xb9\x63\xad\xa0\x2e\x5a\x5a\x71\x5f\x5d\x1e\x2e\x78\xb5\x73\x3f\x4c\x7f\x4b\xa5\x70\xee\x07\xeb\x6f\xa9\x13\xce\xfd\x90\xfd\x7d\x55\xc2\xb9\x1f\xb2\xbf\xb1\x46\x38\xf7\xc3\xf5\x7f\x52\x21\x9c\x5f\x02\xdd\xf8\x63\x3c\x74\x6b\x03\x3d\x16\x91\x43\x37\x46\xdd\x9e\x6e\xb9\xff\x5f\x83\xa0\xe4\x07\x6e\xa9\x4a\x70\xa3\x86\x6a\x8e\x10\x35\xee\x52\x03\x2f\x91\x65\x15\x04\xe3\x87\xee\xcf\x56\x07\x9e\x20\x7b\xe1\x87\xed\xcf\xd6\x06\x3e\x0e\x7e\xfc\xfe\x52\x65\xe0\x63\xe3\x87\xef\xaf\xd6\x05\xde\x04\xe8\xc2\x0f\xe7\x62\x55\xe0\xce\x24\x29\xd9\xf7\xb2\x54\x78\xe1\x87\xb6\xa9\x12\x4c\x99\x60\xea\x84\x3d\xae\xec\x85\x17\x7e\x68\x7f\xae\x68\x2e\x59\xdd\x25\xfb\xe2\x89\x89\x70\xf6\x9c\xff\xd8\x6a\x6c\xe9\x6b\x0a\xff\x0d\x00\x00\xff\xff\x0d\x26\x17\x04\x9d\x3c\x00\x00")
+
+func fontsSlantFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSlantFlf,
+ "fonts/slant.flf",
+ )
+}
+
+func fontsSlantFlf() (*asset, error) {
+ bytes, err := fontsSlantFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/slant.flf", size: 15517, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSlideFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x58\x4d\x8f\xdc\x36\x0c\xbd\xfb\x57\x3c\x58\x0b\x6c\x02\x34\xcc\x4e\x91\x14\xd9\x5b\x3f\x80\xc2\x87\xa0\xed\xa1\xed\xdd\x99\xf1\x74\x8d\xcc\xda\x03\x7b\xb6\x40\x00\x23\xbf\x3d\x18\x5b\x94\x28\x89\xf2\x38\x7b\xb0\x65\x49\xa4\xc8\xc7\x47\x52\xb3\xc7\xd3\xf1\xc7\x9a\xf0\x13\xde\x63\xf7\x1e\x0f\xd8\x3d\x14\xc5\x78\x6a\x0f\x0d\x1d\x4f\x47\xbc\xfa\xed\x35\x76\x8f\x8f\xef\xf0\xe9\x0b\xfe\x6d\xf7\x97\x7e\xc0\x5f\xf5\x50\x1f\x6a\xbc\xfa\xff\x3c\x0f\x7e\x6e\xbb\x23\xbd\x5c\x8e\xe3\x33\xed\x4f\xaf\xf1\xf8\xee\xed\xc3\x87\xb7\xbb\x0f\x54\x14\x1f\xfb\xfe\xf3\x88\xae\xdd\x37\x68\x3b\x8c\xfd\x73\x83\xcf\x6d\x77\x40\x7f\xc4\xb8\x1f\x9a\xa6\x1b\x51\x77\x07\x9c\xeb\x73\x33\x50\xf1\x7b\xd3\x9c\x70\x1c\x9a\x06\x97\x1e\x43\x73\x3e\xd5\xfb\x06\xa5\x29\x7f\x40\x59\x95\xf3\xc6\x72\x2a\xaf\x6b\xb3\xa2\xfe\xf2\xd4\x0c\xd8\x3f\xd5\xc3\x48\x45\xf1\xf7\xf0\x05\xfd\xf9\xd2\xf6\x1d\xca\x37\xcf\x78\xb3\x9b\x37\x1e\xda\xb1\xfe\x74\x6a\x30\x3e\xbf\x8c\x4f\xb3\x86\xff\x9a\x0b\xf6\xa7\xa6\x1e\x70\xec\xbb\xcb\x55\xf2\x63\x7d\x69\xbb\xe5\x0b\xf5\x3d\x9a\x7b\xb4\xf7\xe8\xef\xf1\x72\x8f\xee\xeb\x2c\xf3\xc7\x57\xb6\x66\xc4\x2f\x25\xfe\x2c\xf1\x4f\x89\xba\x44\x5f\xe2\x65\xb1\xeb\x57\x2a\x0a\x02\xee\x0a\xa2\xf0\x01\xfb\xb8\x2b\xcc\x04\xf9\x98\x97\xe7\x11\xec\xb2\x5d\x5b\x5e\x30\xd7\x75\xd0\xac\x00\xd7\x3f\x7e\xdd\x15\x30\x15\xaa\xe9\x3a\x63\x4c\x55\x55\xd3\xac\x64\x75\x0e\xf6\xef\x2a\x0c\x33\x2d\xda\x8c\xdd\x66\x4c\x35\x2d\xc7\x90\x71\x33\x2c\xb7\x6c\xbe\x4e\x01\x76\x8d\x75\x92\xb1\x62\xa6\x72\x4b\xcb\x20\x3c\x8d\xe0\x54\xd9\xfd\x91\x40\x30\x27\x4c\x15\x88\x39\x2c\x19\x88\x19\x06\xab\xc4\xba\x4d\xf0\x5f\x76\xcd\x69\x0a\x67\xc9\xc2\x23\xe5\x3d\xb8\x86\x6d\x82\xa9\x16\xa8\x04\xa4\x6e\x4e\xee\x13\xee\x92\xf5\x96\xc1\x31\x8c\xb2\x87\xcb\xed\x11\x62\xce\x33\x42\xec\xb7\x0f\xff\x42\x06\xc3\xfa\x54\x6a\xe4\x34\xb9\x65\xaa\xec\xa7\x09\x22\x5c\x2c\xef\x59\x3f\x21\xb6\x8f\xf9\x10\xb2\xc0\x52\x05\x4c\xb6\x80\x6b\x4b\x80\x2c\xbe\x3c\x0e\x9e\x1c\x1a\x96\x23\x44\x9a\xae\xa7\x45\x20\x7a\x6e\xe4\xc5\xdc\x8c\x51\x4c\x9a\x83\xbe\xec\x9e\xf8\x10\x1e\x54\x93\x3d\x84\xa6\x48\xcc\xf8\x5c\x91\x26\xdd\x3c\x4d\x78\x42\x08\xc4\x7c\xae\xa4\x62\x82\x33\xf9\x28\x99\x0d\x51\x5a\x99\xb9\x29\x36\xe9\xd8\x2a\xc9\x49\x1a\xd3\xb2\xcb\x96\xd2\x96\x86\x41\xee\xb2\xb3\x8e\xa2\x8b\x7d\x1a\xed\xb5\x24\x48\xf5\x4c\xca\x19\x79\xfe\x2c\xa9\x1d\x24\x28\xa3\xae\x82\x55\xc5\x99\x00\xae\x6f\x2a\xed\x00\x35\x22\x01\xb5\x72\x24\x0f\x77\xeb\x33\x91\x91\x11\x5b\x1d\xff\xa4\x91\xb7\x4f\x4b\x07\x79\xb6\x1a\xc4\xb9\x71\x33\x81\xf5\x94\x92\xd6\x26\xa5\x52\xf3\x2d\x06\x50\x3b\x4d\xf5\x44\x77\x52\x88\x55\x92\xa6\xe1\x8b\xd7\x7c\xe9\x67\x69\x1e\x50\xa2\x58\x43\x2f\xee\xab\xc6\x77\x1d\xc4\x89\x89\x80\xe9\xd0\xde\x12\x4b\x96\xb0\xe7\xf0\x41\x1e\x30\x81\x81\x68\xc9\x69\x23\x16\xa0\xa5\xe8\x65\xe9\xab\xb6\x8d\x2d\x90\xac\xb1\x9e\xb6\x97\x3f\xe5\xce\x32\x37\xf2\xef\x38\x2d\x1b\x80\x94\x87\x9b\xfa\x8f\x76\x1d\x70\x45\x26\x1d\xac\xd1\xf7\x3b\xc9\x95\xdf\xad\x9e\x86\x84\x17\xde\x61\x19\xf2\x3c\x57\x94\x13\xd2\x4e\xb3\x62\xaa\x66\xa1\x62\xea\x4a\xab\xac\xd6\x8a\xcf\x24\xef\x8c\xe1\x2b\xc8\x6b\x7f\x1d\xe2\xd6\x2b\xcd\x70\x77\x47\x4a\x69\x35\x89\x5e\x16\xbc\xa2\x13\x5c\x83\xe2\x2a\x3a\xc5\xf7\x3a\x79\xbd\x0b\x69\x2f\x9b\x95\xbb\x7a\x12\x05\x7e\x07\xcd\x98\x3b\x74\x70\x91\xb6\xba\x0c\xfb\x45\xb2\x12\xa9\xc5\x24\xae\x3a\x32\x61\xfc\x37\x44\x71\x14\x39\x22\xcb\x14\x82\x79\x29\x60\x27\xf8\xa2\xe0\x04\x83\x6f\x84\xc8\x2c\xf7\x3a\x69\xf3\x92\x9e\x9a\x40\x44\x81\x89\x12\x26\x28\xba\x75\x23\x28\x70\x7b\x0b\x3e\x88\x00\x9d\x97\x89\xaf\x4a\xfe\xe9\xb6\x89\x3b\x13\x2d\x0e\xe9\xcc\x62\x03\x44\x6f\x0c\x23\x19\x18\x12\x19\x60\x41\xc8\x1a\x00\xcf\x14\xff\x6b\xd3\xc0\xa3\xe2\xdc\x83\xd4\x1f\x91\x4c\xc7\x22\x31\x29\x8d\x28\x62\xf4\x63\x92\xe5\x4e\xa8\x26\xa5\x57\x6e\x88\x6b\x48\x42\x79\xc2\xaa\x66\xd5\x87\x30\x31\x28\x97\x28\xf2\x67\x23\xfc\xb7\x28\x6a\x39\xa7\x33\x70\xe6\x12\x25\x0f\xa7\x20\x7f\x1c\x75\x8e\xab\x8c\xb5\x6b\xa9\xbe\xcb\x6a\x51\x8f\x4e\xc9\x11\x71\xc5\x3c\x3d\xd7\x44\xd4\x2b\x6e\xac\x80\x82\xa4\x48\xfc\x00\x5a\x17\x34\xff\xef\x8c\x24\x37\xf2\x0f\x19\x53\x6e\x06\x14\x18\xa2\xc4\xd8\x61\x57\x49\xe2\x71\x6e\x47\xf5\x5d\x20\xc3\xbf\xa7\x89\xb6\x54\x69\xcc\x16\x2c\x58\xd3\xb6\x92\x38\x6d\xa8\x42\x89\xd6\xdb\x69\x69\x34\x66\x66\x19\xea\x23\x49\xb4\xad\x7a\xfa\x4b\x00\xb9\x82\x9b\xfc\x9f\x22\xb9\x72\x7c\x0b\x00\x00\xff\xff\x77\x0b\x22\xaa\xf6\x14\x00\x00")
+
+func fontsSlideFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSlideFlf,
+ "fonts/slide.flf",
+ )
+}
+
+func fontsSlideFlf() (*asset, error) {
+ bytes, err := fontsSlideFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/slide.flf", size: 5366, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSlscriptFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x57\x5d\x6f\xa3\x56\x13\xbe\xe7\x57\xcc\x45\x24\x40\x32\x4c\x12\x65\x57\x1b\xc9\xb2\xc8\x7b\xf1\xaa\x5d\xa9\x52\x2f\x5a\xed\x5e\x20\x9d\x10\x38\x89\x69\x6d\xb0\x00\xaf\xeb\xca\x3f\xbe\x9a\x99\x73\xf8\x26\x71\xeb\xc4\x98\x8f\xf9\x3a\xcf\x3c\x33\x73\x78\xdd\xbd\xde\x27\x37\xf0\x19\x1e\xe0\xfe\x16\x6e\xe1\xee\xce\x71\xfe\x97\xd4\x3a\x83\xb2\x80\xf4\x58\xd5\xf9\x0f\xed\x7d\xf6\xe1\xe5\x0c\x5f\x93\x02\xbe\x95\xbb\x46\x57\x40\x9f\xf5\x1f\x49\x91\x46\x69\x95\xef\x43\xad\xd3\x3a\x3c\xee\xf3\x74\x1b\xea\xec\xb8\x21\xd5\xfb\x07\xf8\x7a\xdc\xc1\xdd\xe3\x97\x4f\xce\xff\xf3\xb7\x9d\x6e\x82\xfc\x6f\x9d\x41\x52\x64\xac\xfd\x72\x86\x6f\xba\xc8\xf4\x6e\x07\x3f\xe5\xe9\x9f\xba\x80\xf5\x69\xcb\x27\xd1\x21\xa9\x92\xba\x7c\x6d\xc2\xb4\xdc\x6f\x58\xb8\x2c\x00\x3e\xc1\x2f\x49\x05\x77\x8f\x8f\x0f\x0e\xdd\x7a\xca\x32\x9d\xc1\x3e\xaf\xeb\xbc\x78\x83\xc3\xb1\x48\x9b\x63\xd2\xe4\x65\xc1\x1e\x8a\xe3\xfe\x45\x57\xb5\xf3\xb4\xdf\x93\x13\x71\x69\x3e\xb4\x12\x5d\x55\x49\x06\xbf\xe6\xba\x4a\x35\xad\xe4\xc0\x67\x51\x7a\x48\x8a\xb0\xac\xde\x36\xad\x30\x79\xfe\x02\x4f\xc7\x37\xb8\xbf\xbd\xbd\x67\xcf\xbf\x17\x99\xae\xea\xb4\xac\x34\xbb\xca\x92\x7a\x0b\xdb\xe4\x87\x86\x17\xad\x0b\x38\x1e\xb2\xa4\xd1\x19\x34\x25\xec\x49\x24\xdd\x95\xb5\xde\x9d\x61\x9f\x34\xe9\xb6\x07\xa8\xe3\x18\x0f\xbf\x6d\x35\x80\xab\x5c\x48\xb7\x49\x95\xa4\x84\x6e\x5e\x43\x53\x69\x36\x93\x17\x90\x40\x7d\xd0\x69\x9e\xec\xe0\x94\x9c\x43\x80\x9f\x1b\xd8\x27\x67\x78\xd1\xd6\x42\x5e\xd4\xba\x32\xc2\xcd\x56\x43\xa3\xff\x6a\x20\x29\xce\xa7\xad\xae\x34\x9c\xcb\x23\x9c\xf2\x7a\x4b\x11\xed\x74\xf1\xd6\x6c\x35\xd9\x84\xb4\x2c\x02\x6b\xa1\xd0\x69\x43\x30\xee\xf2\x82\x96\xd1\x9c\x68\x25\xcd\x89\x14\x9a\x46\x57\x75\xe8\x38\x37\x37\xd1\xdc\x37\x62\x13\x7c\x44\x3a\x22\x9d\xbb\x74\xa7\xb4\xf7\x41\x84\xe8\x4e\x19\x39\x2e\xb8\xe6\xb2\x3d\x88\x36\xeb\x07\x18\x60\x10\x39\xfc\x03\x91\x83\x80\xad\x95\xde\x2f\x9d\xac\x58\x10\x3c\x85\xf2\x00\xc1\x07\x56\x74\x67\x15\x3c\xbf\x17\x1f\xab\x20\x78\x7e\x2f\x7a\xb6\xea\xf9\x7c\x85\x31\xfd\x78\x00\xdf\xe9\x2a\x46\x88\x8d\x25\xfb\x13\x39\xb4\x9c\xc8\x71\xf9\x84\xff\xe9\x91\xc2\xce\x78\x77\x84\x11\x10\xd8\x1e\x15\x2e\x0a\xf1\x55\xcc\xe1\x06\xc1\xf7\x20\x60\xc3\x31\x4c\xe3\xe8\xe0\x67\x51\x34\xa2\x30\x23\x6a\xff\x6d\xe0\x94\xc0\x1b\x73\x08\x48\xaf\xbb\x94\xcc\xf6\x14\xda\x35\x4e\x61\x9c\x0b\x5f\x29\x93\x14\xf0\x45\x90\x14\x3c\x65\x93\x35\xc9\xa6\x62\x69\x16\x65\x93\x63\x76\x18\x7b\x20\xf6\xc2\x20\x70\xc5\xde\x12\x3b\x46\x0a\x00\x01\x19\x56\xcb\x01\xc8\x35\x72\x10\x6e\xc0\xd2\x00\x38\x87\x22\x28\xa5\x5a\x88\xdd\x20\x08\xc5\xb0\x3f\x9f\x9b\x0e\x2c\x25\x11\x8f\x39\x27\xd6\xc8\x2d\x13\x7a\xba\x76\x59\x89\x67\x56\x8e\x66\xe1\x73\xee\x54\xdf\x45\x97\xa1\x71\x6e\xda\x43\xd9\xd6\x65\x1f\xea\xf9\xc7\xae\x3c\x46\x8a\x30\x72\x98\x88\x5c\x14\xfc\xed\xeb\x31\x91\xf8\xd0\x5b\x45\x2b\x6f\xf4\x7b\x7a\x26\x51\x12\x35\x5a\x87\xb3\xc0\x9b\x4b\x25\xa9\x2a\x63\x59\xad\xe0\x37\x16\x1d\x11\x50\x32\x8a\x00\x9e\x7a\x9f\x30\x9d\xc2\x9a\x14\x88\x31\xea\x2a\x05\x11\x78\x87\xe2\xf3\x35\x81\xe4\xe0\x43\x85\x67\x09\xc9\x78\x50\xab\x45\x85\x16\x0d\x04\xee\xb3\xd4\x25\x57\xa2\x86\x03\x85\xc1\x19\x9d\x52\xeb\x5b\xb1\xbb\xe7\xc0\xbd\x98\x15\x99\x08\x83\x75\x17\x62\xef\x84\x28\x47\x27\x2b\xa2\x87\x6f\x29\x47\x50\xb7\x58\x2f\xa8\xd1\xc7\x9a\xbc\x10\x1c\xab\x20\x08\x2e\xac\x1f\x2b\x84\x58\x2d\xa8\xa9\xb6\x18\x60\x23\xd7\x28\xb5\xc8\x2e\xd7\x0a\x47\x90\xa8\x2e\x3a\x13\xdc\xda\xf6\x2c\x7f\x09\x43\xee\xcb\x5d\x23\x6f\x11\xed\x4a\x48\xf1\x9f\x98\xf5\x4d\x32\xd1\x74\x2e\xb7\xcf\xb0\x31\x56\xca\x6a\x0d\x18\x70\x0d\x29\xdd\xab\xda\xe8\xc4\x83\xf4\xc9\x61\xe6\xaf\x20\xa5\xa7\x62\xeb\xe1\xf9\x5a\x0f\xf1\xc2\x1a\xcc\x48\x35\x33\x95\x1d\x59\xda\xcf\x17\x96\x1a\xb2\x98\x1e\x32\xa5\xae\x61\x31\xd3\x91\x94\x0d\x1f\x6d\x4f\xef\xd5\xe6\x47\xca\x7d\x2e\x7b\xed\x08\x88\x11\x96\xb8\xac\xa0\xaf\x67\xfb\xae\xa1\xa4\xa7\xbc\x01\x29\xe7\x7c\x32\x41\x65\xd4\x03\x6d\x39\x4c\x42\xe2\x59\x78\x66\x0a\x0e\xac\x2b\xea\x24\x7c\xc7\xa2\x85\x56\xad\x1b\x32\xb6\xa4\xa3\xf1\x80\x1d\xce\x0c\x54\x93\xc9\x11\xdb\x3d\x89\x00\x22\x0f\xe2\xe9\x78\x11\xd3\xed\x2e\x41\x4d\x67\x10\x76\x93\xa3\xff\xed\x6d\x38\x54\xb7\xe1\xe0\xdd\xc7\xf3\x70\x9f\x35\x18\x0f\x4a\x85\xc2\x8c\xcb\xec\x20\xe8\x4f\x60\x45\x0b\xf3\xdf\x19\x89\x2a\x64\x1c\xc7\xe0\x58\x61\xde\xb3\x29\xa9\x90\xae\x6b\x0f\xdc\xb5\x96\xa8\x1f\xe1\x8c\x25\x6b\x4a\xf6\x01\x68\x36\x1a\x62\x0d\x37\xfc\x7c\x8d\xa3\xf0\xc5\xe2\x8a\xfd\xfa\xdc\xf0\x2e\x10\x39\x17\x5c\xd8\x65\x20\xe0\xa4\x67\x59\x98\x4b\x6a\x93\xd1\x60\x70\x8f\x66\xad\x8c\x7d\x34\x84\xa0\x89\xee\x2e\x6d\x67\x10\xd6\x53\x47\x86\x4a\x28\x44\x64\x14\x66\x10\x9f\x96\xb1\xd4\xbd\xd9\xf4\x77\x96\xa7\x35\x33\xac\x09\x51\x34\x6a\xeb\x85\x59\xdd\x66\x45\x31\x84\x8b\x59\x31\xbf\x86\xfc\x68\xc0\x96\xfb\xee\x98\x54\xd3\xac\x6c\xa6\x59\x31\x6e\xe5\x7d\x63\x06\xac\x9e\x90\xd4\x9d\xbf\x20\x64\x27\x1d\xcf\xb9\x59\x44\xdb\x63\x08\xa1\x30\x74\x91\xe8\x2b\x4a\x52\x8c\xf0\x3e\x10\x2b\xfa\x33\x3d\x6c\x01\xd8\x41\x21\x86\x2b\x49\x43\x3c\x5f\x88\xa3\xa4\x71\x1b\x23\x50\x8c\x6d\xd3\x27\xdc\x79\xdb\x5c\xe4\x08\x20\x45\xee\x5d\x06\xb6\xe9\xbd\x4b\x5d\xf7\xde\xf5\xd1\x8b\x8b\xc1\x04\x65\x1b\x60\xe5\x66\x4a\x5d\x19\x4f\xb1\xc2\xb9\x2a\x1a\xc4\x57\x2a\x55\x46\xff\x66\x37\xda\x29\x5c\x39\xf8\x4b\xd6\xf9\x6f\x73\xcf\xdc\x29\xa1\xbc\xa2\x9d\x9a\xb7\xf8\xc5\x4a\x12\x43\xef\x93\xb0\x7d\x39\x33\x78\xd8\xdd\xb6\xb2\xdb\x6d\x1c\x85\x19\x45\xce\x3f\x01\x00\x00\xff\xff\xbf\xcb\xeb\x13\xa7\x12\x00\x00")
+
+func fontsSlscriptFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSlscriptFlf,
+ "fonts/slscript.flf",
+ )
+}
+
+func fontsSlscriptFlf() (*asset, error) {
+ bytes, err := fontsSlscriptFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/slscript.flf", size: 4775, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSmallFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x5a\x6d\x6f\xe2\x38\x17\xfd\xce\xaf\x38\x1f\x46\x9a\x22\x95\x9a\x04\x0a\xad\x54\x8d\x9a\x81\xb4\x8d\x96\x12\x9e\x10\x3a\x3b\x52\x24\x2f\x33\x4d\xa7\x68\x29\x54\xbc\xec\x6a\xa4\xfc\xf8\x47\x8e\xed\xc4\x71\xec\x94\x5d\x69\x27\x88\xda\xc7\xf7\x5e\xdf\x73\x7d\x7c\xc3\xcb\xfa\xc5\x5d\x7e\xc2\x25\xfa\x70\x7a\x70\x2e\xe1\x74\xd1\x85\xeb\xf6\x9d\xcb\xd6\xfc\x6d\xb9\x5e\xe3\xc7\x6f\xdc\xaf\xd3\xcd\x06\xa3\xd7\xe5\xfb\x7b\xba\x5e\xa3\x4f\xae\x7b\xe8\x74\xf0\x63\xb9\x4f\x9f\xb1\xdd\x60\x7e\x58\x6e\x9e\x97\xbb\xe7\x56\xb0\xf9\xb9\x3e\x3e\xa7\x7b\x04\xf3\x10\x93\xe5\x61\xb5\xe9\x38\xad\x97\xd5\xaf\x75\x7a\xc0\x2e\x5d\xa7\xcb\x7d\x0a\xf7\xc2\x61\x93\x1d\x17\xde\xf1\x17\x9c\xeb\xeb\x7e\x6b\x96\xee\xde\x56\xfb\xfd\x6a\xbb\xc1\x6a\x8f\xd7\x74\x97\xfe\xf8\x8d\x5f\xab\x7f\xd2\x0d\x0e\x5b\xbc\x6d\x9f\x57\x2f\xbf\x71\x78\x5d\xed\xf1\xb2\xdd\x1c\xce\xb1\xdc\x63\xbd\xdd\xfc\x62\xcf\xc3\x6b\xda\xca\x07\xac\xd2\xdd\xe7\x3d\x36\xcb\xb7\x94\x61\xbc\xaf\x97\x3f\xb9\x6d\x4b\xfc\xdc\xbe\xbd\xa5\x9b\x03\xd6\xab\x4d\x7a\xd1\x6a\x3d\xf2\xd1\xcf\xcc\xb1\xd9\xf2\xb8\xc6\xd7\xe3\xee\xb0\xdd\xe0\x66\xbf\x5d\x1f\x0f\xab\xed\xe6\x36\x5d\xee\x0e\xaf\xeb\xd5\xe6\xef\x8b\x4d\x7a\xf8\x02\xc7\x25\xd7\x03\x66\xc8\x8a\x7b\x87\x4d\xfa\x2f\xde\x97\xbb\xe5\x5b\x7a\x48\x77\xad\xfd\xf1\xfd\x7d\xbb\x3b\x70\xc0\xbb\xe0\x9e\xf9\xba\xdc\x3c\xb3\x8f\xdf\x56\x9b\x0b\xe0\x71\xf9\x1b\xcb\xf5\x7e\x8b\x1f\x29\xf6\xeb\xd5\xaf\xd7\xc3\xfa\x37\xde\xa4\x15\x2f\xdb\x1d\x7e\xa4\x87\x43\xba\xc3\x71\x9f\xb6\xb6\x2f\x39\xfc\xcb\x71\xbd\xee\xfc\xbb\x7a\x3e\xbc\x92\xbf\xd3\xdd\x86\xec\xdf\x8e\xfb\x57\x2c\xd7\x87\x74\xb7\x59\x1e\x56\xff\xa4\xfb\x73\xfc\x38\x1e\xf0\x9c\xbe\x2c\x8f\xeb\x03\xb6\xc7\xc3\xfb\xf1\xc0\x3c\x9f\x86\x31\x7e\xbe\x2e\x37\xbf\xd2\xe7\x8b\x56\x0b\x9f\x6e\xf5\xff\x6f\x5b\x00\xc5\x6d\x0b\x19\x32\xf6\x2f\x65\xff\x9e\xd1\x36\xfb\x1e\x10\x7f\xce\x07\x9c\x21\x43\xfe\xf5\x13\x9e\x90\xff\xf9\x13\xf8\x53\x0e\xe4\x43\xf9\x97\x34\x63\x88\x1c\x99\x02\x17\xec\x1b\xf1\x19\xe2\x33\xd8\x6a\x34\x2b\x26\xe7\xf3\xb2\x8c\xe6\x06\x74\x6e\x6e\x5b\x20\xa0\x84\x7f\x29\x2d\x01\xe5\xb6\xd0\x36\x01\xe1\xab\x13\x90\xfc\x3b\x10\x4a\x0a\xc3\x4b\xe3\xa9\x84\x26\xa0\x19\xe5\xd3\xbf\xb0\x8f\xdc\x88\x84\xb2\xff\x32\x94\xd3\x50\xc6\xe4\x2c\x77\x38\xe3\x0b\x7d\x82\x12\x13\x50\x9a\x2f\x09\xc2\x43\x87\xf2\x81\x84\x26\x6c\x0c\x5b\x99\x2d\x80\x84\x3b\x96\xc7\x57\x3c\x08\x25\xaa\xd7\x94\x24\x34\x37\x0b\x37\x39\x00\x91\xe6\x14\x61\x2d\x83\x5a\x84\x54\x09\x22\xa0\x79\x2d\xbf\x30\x78\x52\xec\x58\x1e\x1c\x81\x46\x05\x56\x7d\x47\x75\x9c\x4a\x66\xc8\x30\x88\x38\x40\xec\x09\xf3\x4e\xc3\x11\xc1\x00\x01\x0f\x47\x86\xb3\x36\x0f\x48\x42\x29\x29\xcd\x2f\x63\x4f\x78\x3e\x2a\x59\x59\x6e\x69\x11\x83\x76\x65\x55\xe9\x85\x32\x90\x72\xf7\xb8\x79\x19\x45\x22\xdc\x25\xd5\x81\xe0\xe6\x65\xc5\x56\xd2\x4a\x78\x35\xf3\xc4\xfa\xa0\x22\xa5\x6d\xb0\x22\x59\x0b\x03\xc1\x07\x26\xf5\xf5\xcb\x8d\x00\x8f\x8a\x9c\x53\x8d\x65\x65\xfd\x33\xd0\xdc\xff\x46\xd8\xea\xba\xe7\x62\x9b\x94\x88\xdf\xea\x5b\x6b\xd8\xe6\xfa\x9f\xab\xd9\xa4\x72\xe1\x06\x37\x05\x09\x2a\x39\x6c\xcc\xb8\x4c\xdf\x33\x8d\x34\x5f\xf0\x45\xb2\xa5\x55\xdf\x00\x11\xf8\xdc\x21\xf6\x3c\xa3\xed\x5a\xda\x95\x89\xc7\x46\xf3\x70\x10\xd0\xbf\xf2\x30\x27\x2c\x68\xe7\x54\xe6\x21\x2d\x59\x29\x19\x07\x42\x93\x02\x40\xcc\xa7\x44\xf1\xae\x9e\x14\x3c\x36\x68\x48\x0a\x5a\x58\xc4\x53\xfc\x4c\x7c\x93\xa8\xd1\x28\x61\x39\x6e\x41\x9c\xac\x0d\x19\xba\x1a\x71\xb4\xcc\x04\xcd\x60\x8a\xb2\x7d\x60\x56\x27\x6e\xdd\xda\x82\xb8\x35\x6b\xcb\xb3\x44\x10\x97\x45\x5d\x30\x38\x33\xf9\xc6\xb9\x46\x65\x69\x34\x5b\x0b\x01\x0b\x2a\xeb\x81\xc4\x37\x57\x0f\x9e\x90\x19\x4b\x50\x5e\x9e\x3f\xf3\xa4\xcc\x68\xa6\x6e\x9c\x1c\x5d\x50\x5f\x7e\x28\x73\xb4\x6e\xb2\x24\x75\x96\x97\x69\x69\x4d\x42\x8a\x42\x05\xa8\x8e\xd6\x02\x93\x48\x0f\x2e\xfe\x92\x33\x12\x7d\x15\xa8\x59\x5b\xd4\x4b\x5a\x16\x4c\xd5\xe7\x5a\xfa\x25\xdc\xba\x3c\xed\x2c\x1b\xda\x84\xdd\x98\xda\x02\x1b\x02\xbb\x1c\xaa\xd5\x1b\x79\xb4\xda\xea\x2d\x55\x6a\x78\x51\x68\x21\x6d\x35\x9d\x68\x14\x65\x6e\x95\x59\x40\x33\x7b\x4c\xf2\x93\x3f\xcf\x04\x56\x4d\xc4\x09\x95\xe0\x49\xea\x86\xa4\x52\x59\xcb\x29\xea\xac\xf2\x68\x4b\x90\x90\x84\x28\x73\xb5\xe9\x0a\x82\x9c\x2d\x66\xb2\x53\x5d\xd4\x0d\x3d\xfb\x3e\x32\xd1\x18\x08\x79\xa8\x41\x3b\x73\xeb\x1c\x17\xbb\x96\xd5\x24\x4a\xc6\xc6\xca\xf5\xa5\xab\xc2\x4b\xe9\xa0\xbe\xb5\x62\xbb\x14\x11\x53\x1c\xce\x1c\x0c\x84\x67\x13\x49\xa4\x96\x50\x1f\xda\x39\xa0\x3f\x2b\xe7\x82\x76\xce\x80\x03\x56\xf5\x57\x39\x51\xca\x05\x59\xd3\x8b\x8a\x6e\x24\xb9\x8c\xca\x67\x99\x9b\x17\x4a\x72\x56\x94\x68\x91\xcc\x02\x35\xd3\xfc\x10\x25\x49\xa4\x60\xe3\xfa\x9a\x97\x04\x9d\xfc\x30\x4d\xea\x95\xae\xac\xb6\x99\xa0\x71\x66\xa6\x71\xa3\xff\xea\x01\xa1\xfb\x2f\x3e\x7c\x16\xdc\x37\xd5\xe5\xf2\xb8\x37\xc9\x2f\xe9\x79\x21\x12\x44\x36\x50\x22\x97\x55\x56\x95\x41\xcf\x9f\xa2\x1c\xd3\x5a\x72\xa1\x5c\xca\xb8\x60\xe1\x2c\x68\x69\x7f\xe1\x00\xad\x14\x5c\x2d\x3c\x38\xc1\xe1\xda\xf6\xd8\x04\x55\xd5\x90\x4a\x1e\x41\xe4\x51\xbe\x55\x27\xef\x11\xe7\x78\xd5\x08\x14\xc8\xd6\xad\x17\xc6\x2a\x17\xa5\xd2\x52\x3d\xf4\x50\xf2\x48\x4d\xe3\x9a\x47\xda\xd1\xcd\xe4\xa2\x25\x50\xcc\x1f\x5e\xb4\x9e\x44\xc9\xd2\x05\x25\xaa\x63\xcb\xe1\xca\x8c\xa4\x52\xb1\x2d\x0b\x24\xf9\x70\x52\x4b\x99\x66\xbb\x45\x79\xa2\xd5\x5b\x16\x8a\xca\xc9\x31\x75\x46\x57\xee\x32\x54\xde\xe6\xe4\x53\x5e\xeb\x0c\xd9\x5a\xe4\xac\xa9\xa4\xb2\x3d\x50\x70\xb8\x9e\xe7\xe5\x92\x64\xbc\x5e\x12\x59\x29\xab\x4f\x5d\x3c\x9c\xd1\xb6\xa0\x1c\xe9\x74\x12\xcb\x91\x52\x1f\xcd\x95\xaf\xbc\xea\x92\x7a\x65\x94\xc3\x4b\xce\x37\x1d\xab\xc6\x05\x9a\x4b\xaf\x1c\x4e\xa5\xf9\x52\x79\x9c\xb8\x40\x73\x4e\x2a\x0a\x55\x50\x31\xbb\xc9\xef\xd1\x6c\x5a\x95\x93\xce\xa0\x0b\x4c\xc3\xce\xd7\xc8\xf7\xfe\xc0\x7c\xe6\x8d\x7c\x73\x4f\xc4\x19\x38\x40\x30\x7d\xf2\xa3\xd8\x1f\xc3\xff\x73\x34\xf1\x1e\xbd\x38\x08\xa7\x78\xf4\xa2\x3f\x3e\xaa\x91\xce\xc0\x05\x46\xfe\x34\xc6\x3c\xb8\x9f\x96\xf9\x97\x65\xa2\x0a\xe4\xc5\x9f\x3f\x44\x6f\xc3\x19\xf4\x80\x59\xb8\x98\x8e\xcb\x39\x52\xa8\x51\x02\x9a\x14\x4a\x59\xac\x7c\x5e\x11\xa7\x1c\xa2\x0f\x8c\x16\x51\xe4\x4f\x47\xdf\x05\x0a\x23\x59\xbe\xf5\xb8\xe0\x49\x2f\x4b\x1b\x41\xa2\x96\x36\x67\x70\x09\x7c\xf7\xa7\x72\x71\x2a\x0b\x5c\xa9\x46\xb2\xfc\xbb\xac\xf2\x49\x2a\x14\x06\x30\x00\xbe\x46\xe1\x1f\xfe\x14\x5f\xbd\xc8\xd4\x54\x52\x69\xe2\x0c\x86\xc0\xdc\x1f\xe5\x21\x55\x1d\x16\x0c\x14\x79\x22\xe5\x48\x22\x5a\x22\x67\x54\xb0\xc7\x19\x5c\x01\xe3\xc0\xf3\x23\x7f\x1e\xcc\x8d\x1c\xf9\x24\x15\xc3\x27\x45\x83\x88\xc9\xd7\xc0\x28\x9c\x7d\x8f\x82\xfb\x87\x72\x8f\xac\x77\xc5\x8c\x87\x2c\x2f\x9e\xb2\x7a\xc9\xb3\xd5\x19\x76\x81\x3b\xff\x31\x98\x06\x53\x1f\x61\x34\x0e\xa6\xde\x04\xc1\x74\x1c\x8c\xbc\x38\x8c\x1a\x05\x4a\xfd\x82\xe1\x0c\x1d\x60\xe2\xdf\xc5\x9d\x59\x18\x4c\xe3\x60\x7a\x8f\x71\xb8\xf8\x3a\xf1\xe1\x4d\xef\x27\x3e\xfe\xb7\x08\xe3\x4a\x1a\x4a\x35\x98\x1b\x2a\xaf\xdf\xc5\x05\xbc\x5a\x1a\x9c\xa1\x8b\xbc\x1f\x58\xec\x71\xad\xe9\x50\x64\xf1\x27\x54\x9b\x0e\xce\xb0\x07\xcc\xc3\xbb\x18\x0f\xdf\x67\x0f\xfe\x54\x57\x49\x59\xd9\x40\x2a\x6b\xaa\x33\xec\x03\x91\x7f\x1f\xcc\x63\x3f\xf2\xc7\x1f\x04\x3a\x43\xa7\x2d\x02\x9d\x65\x49\x52\x0f\xf4\x25\xf0\xe8\x8d\xa2\x70\xda\xd4\xb8\xaa\xd6\x4e\x67\x38\x00\xc6\xfe\x7d\xe4\xfb\x85\xd7\xf9\x6a\x17\xbc\x1e\x92\xdb\xaa\xae\x74\x86\x43\x60\x36\x59\xcc\x3b\x8f\xc1\x74\x31\x57\x32\xb3\xa1\x01\x97\x0b\x10\x69\x0d\x97\xaf\xce\xf0\x0a\x98\x2f\x66\x7e\x34\x1f\x45\xc1\x2c\x46\xfc\x2d\x54\x45\x74\x5b\x3d\x7f\xaa\x21\xbb\xd6\x26\x3e\x44\xbe\xaf\x1f\x5d\x19\x15\xca\xab\x32\xf5\xaa\x0b\x78\xa3\x45\xec\xc3\x1b\xb1\xe2\xd3\x12\x27\x1a\x51\xdd\x54\x9d\xbd\x72\x80\xc7\x60\x14\x85\x4a\x99\xb2\x1c\xaa\x19\x2e\xce\x4b\x39\xc2\x67\xbb\xc0\x2c\x98\x8c\xa2\xf0\x9b\x9e\x51\x24\x4f\xa5\x3c\xc2\xc5\x55\x81\x6a\xaa\xcb\xb9\xea\xb1\xd5\xc7\xe3\x89\x8f\x71\x18\xb7\x60\xe8\x32\x56\x8c\x65\xc5\xcd\x1f\x07\x93\x89\x57\x8c\xad\x75\x27\xdb\xb4\x9d\x8f\xbd\xac\x06\x31\x9c\xfa\x5a\x57\x91\xea\x37\x0a\xe7\x6a\xc0\xd2\x6b\x3e\x5a\x4c\xec\x44\x36\xaa\x43\xbd\x5d\xe1\x5c\x0d\x81\xbc\xb2\x9c\x48\xe2\x82\x0e\x89\xda\xf6\x92\x8d\x2f\xad\xbd\xe1\x5c\x5d\x01\x4f\x8b\xc9\xbd\x17\xe1\x2e\xf2\x78\x01\x0d\xa7\x0c\xd5\x8b\x62\x3f\x2a\x9a\xe4\xa2\xe5\x9d\x11\x96\x68\x3c\xed\xd8\xc7\xcf\x7c\x3b\x72\x15\x52\xed\x53\x70\xf4\x6b\x33\xfa\x83\x37\xb9\x2b\xa1\x4b\xe4\x12\x58\xb4\x62\x29\x21\x54\x6f\x7f\x38\xd7\xdd\x3a\x6a\x9e\xd8\xd2\xea\xb9\x08\xaf\xb4\x9b\xe5\xb9\x62\x38\x6d\x97\x96\x1b\x4d\xe7\xab\xa8\x47\xf6\xff\x16\xfe\xbc\x5a\x28\x79\x9a\x88\x16\xa1\xb4\x5d\xbf\x81\x39\xd7\x2e\x30\xf1\xe2\x60\x8a\x91\x37\x0b\x62\x6f\x82\x89\x1f\xc7\x7e\x04\x0f\xdf\x82\xf8\x01\xf7\x91\xf7\xe4\xb7\xca\x08\xb3\x32\x2b\x6a\x99\x55\x93\x39\xd7\xbd\x66\xd0\x9c\xb5\xd5\x13\x50\x6c\x7b\x13\x68\xbf\x19\x74\x14\x44\xa3\xc5\xe3\xdd\xc4\xff\x33\x07\x94\x6a\x94\x24\xd9\x87\xc8\x97\xcd\xc8\x71\x30\x19\xfb\x1c\x94\x64\x02\xf4\x63\x73\x07\xcd\xa0\xcd\x87\x79\x13\xf0\xb0\x19\x38\x62\x04\xf4\xbe\x86\xf9\xb6\x15\x9a\xea\xec\xac\xdd\xfe\xd0\xe4\x2b\x1b\xb2\xdc\xac\x62\xbb\xce\xa5\x20\x62\xd5\x81\x4a\xa1\x9f\x51\x03\x17\xae\x2d\xa0\x23\xb1\x6d\x65\x8d\x3b\xa5\x51\xdc\x66\xf9\x7c\xdb\x72\xbb\x5d\x0b\xac\x5f\xcb\xdb\xdb\xa2\x3b\x9f\x21\xbf\x3c\x66\x94\xde\x94\xe7\x88\xdb\x75\x9a\xa1\x8a\x6c\x15\xca\x83\x57\x41\x33\x94\x8d\x4d\xbe\x21\x47\x2b\xed\x23\x0b\x9e\x8d\x48\xfe\x29\x49\xc4\x30\x21\x2e\x86\x37\x95\xaa\xea\x76\x6d\x64\x0a\xea\xb4\x97\xac\x57\x5a\xd7\xfa\x19\xe0\x76\x6d\x14\x0a\x6a\x31\xc4\x6d\xf9\x46\xc6\x8e\x67\x63\x4f\x60\x0a\xa4\x8c\x24\xe5\xa1\xb4\x82\xda\x98\x13\x18\xa3\x59\xbb\xc6\x65\x32\xd5\x39\x74\xf5\x1a\xe7\x76\x6d\xec\xf1\xe3\x87\xaa\x0a\xcc\x0a\x15\x98\x23\xb6\x8b\xdb\x3b\xad\x75\x08\xdc\xae\x8d\x3e\xd3\x0f\x6a\x53\xd9\x79\xaf\x35\xdc\x5d\xc7\x46\x9e\xd0\x5e\xf4\x8b\x4e\xb7\xe5\x6a\xed\x3a\x36\x1a\x85\x96\xa2\x2f\xcf\xfa\x46\x50\x1b\xa1\xc2\x53\x8a\x7e\x23\xb2\x8d\x5a\xe1\x07\x81\x6d\x04\xb5\xd1\x2a\x3c\x81\xaf\x8d\xc0\xec\x32\xb0\x98\xc4\xc1\x6c\xc2\xf4\x59\xe5\x16\x99\x1b\x95\xe4\xd7\x5e\xf1\x42\x3d\x21\x89\xd2\x1d\x73\x1d\x1b\x99\x84\x55\xf3\x98\xdd\x63\x6b\x37\x15\x49\x2b\x9c\x11\x22\x5f\x97\x30\xb5\x53\xcb\x51\xc7\xc6\xab\x45\x35\x9d\xca\x7c\xa2\x32\xa1\x9a\x7b\x2f\xae\x63\xe3\xd4\xc2\x90\x53\x45\x52\x9d\x84\x6c\xe3\xd5\xc2\x98\x58\x65\x66\x21\xc9\x4e\x80\x77\x6d\x0c\x5b\x34\x97\x9a\x93\x5a\x52\xae\x6b\xa3\xda\x77\x63\xb5\xcd\x63\xa2\xb6\x2f\xd5\x57\xfc\x39\x9e\x8d\x65\xf1\x43\x18\x4d\x4d\xed\x55\xde\xcf\xd7\x7b\xb5\xae\x5b\x90\x6a\xfe\xe8\x4d\x0a\x98\xf9\x83\x17\xcd\x30\xff\x8f\xcd\x2b\xd7\xed\x1b\xd1\x1a\x94\xe9\x47\x6f\x46\x5c\xf7\xb2\x09\xb2\xa9\x44\xd9\x21\x07\x4d\x90\x1f\x16\x28\x3b\xee\xb0\x09\xb7\xa9\x3c\xd9\x21\xaf\x9a\x20\x3f\x2a\x4e\x76\xd8\xeb\x26\xd8\x66\x3d\xda\x84\xdb\xeb\x9a\x71\x7d\xa5\xfc\xc8\xde\x5d\xb9\xf3\xc5\xab\xa6\xf3\xba\x1a\x75\x7b\x8e\x11\xb2\xae\x45\x1b\x5e\x89\xf1\x4b\xb7\xdb\x73\x8d\x50\x75\xfd\xa9\x0a\x28\xdb\x9b\x30\xb7\x67\x66\x4e\x5d\x82\xaa\xf2\xc9\x8e\x66\x66\x8e\x51\x85\x56\xc5\x93\x1d\xd2\xcc\x1c\xb3\x10\x35\x74\xc0\x3b\xe2\xb7\x2a\x89\x41\x3a\xf5\xcc\x14\xaa\x6a\x51\x2a\x2e\xb0\x89\xb1\x05\xed\xf6\xcc\x74\xd1\xf4\xa7\xd2\x20\x32\x61\x98\xf9\x71\x82\xe6\x2c\xde\x9a\xe8\xa5\xb5\x67\xe6\xc6\x89\x8a\xb3\xf1\x37\x02\x6e\xdf\xcc\x0f\xae\x37\x93\x84\x88\x5e\x32\x49\x12\x9d\x69\x5a\x93\xc5\xed\x9b\x69\xa1\x69\x4c\x56\x6a\x20\xdf\xe0\xa0\xf9\x25\xa3\xdb\x37\xd3\xc3\xa0\x30\x2b\xf4\x30\xbf\x89\x74\xfb\x66\x7a\xe8\xd2\x52\xa7\x87\x0d\xcd\x4c\x0f\x93\xa6\xac\xd1\xc3\x06\x69\xa6\x47\x58\x8f\xa0\xf2\x0a\xcc\x8e\x66\x26\x84\x59\x45\xfe\xb7\xd7\x4d\x6e\x7f\x08\x8c\x83\xa7\x60\xae\x8a\xc8\x6a\xb7\xa8\xb8\x39\x69\x3f\x30\x73\xfb\x66\x82\xd4\x74\xa4\xfe\x7e\x99\xf0\x97\x32\x84\x68\x6e\x9a\xc9\xb1\xf8\xe0\x80\x6f\x78\x3d\xe6\x5e\x9a\x39\x61\xd2\x8b\xea\x01\xdf\x08\x69\x26\x87\x59\x28\x6a\x07\x7c\x23\xae\x99\x21\x66\x85\x78\xf2\x0b\x42\xf7\xd2\x4c\x15\x5d\x1a\x36\x46\xa0\xfa\x3e\xd9\xbd\x34\xf3\x45\x55\x87\x30\xff\xda\xa4\xf6\x2b\x01\xf7\xd2\x4c\x94\xef\xff\xd5\xeb\xaa\x89\xff\x0f\x00\x00\xff\xff\xde\x17\x3d\x84\xc8\x2f\x00\x00")
+
+func fontsSmallFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSmallFlf,
+ "fonts/small.flf",
+ )
+}
+
+func fontsSmallFlf() (*asset, error) {
+ bytes, err := fontsSmallFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/small.flf", size: 12232, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSmisome1Flf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x98\x5f\x4f\xdb\x3c\x14\xc6\xef\xfd\x29\x1e\x21\xa4\x17\xa4\x26\x6e\x51\x79\x01\xe7\x26\x17\x88\x8d\x2d\x70\xc3\x2e\x23\x59\x69\xeb\x74\x11\xad\x8d\x92\x14\xd6\xc9\x1f\x7e\x72\xfe\xba\x14\x41\x29\x99\x34\xa1\xa4\x17\xb5\x1b\xe7\xe7\xe7\x39\xc7\x76\x4f\x1b\x2f\xe2\x93\xe8\x10\x67\x38\xc3\xe8\x1c\xce\x08\xa3\x73\x92\x2d\x93\x4c\x2d\xc5\xc8\x8d\x17\x31\xb9\x54\x4f\x32\x4b\x7e\x8b\x19\x1e\x45\x9a\x25\x4a\x42\xc5\x28\xee\xe7\x69\x32\x2d\xc6\xc0\xc1\x8d\x8b\x20\x91\xb3\x4c\xac\x71\xb4\x9c\x2f\x8a\xa6\x2f\xd7\xbf\xdc\x69\xe6\xce\x56\xae\x98\xad\x8e\xc9\x95\x98\xa4\xab\x28\x5d\xe3\x64\x3c\xc0\xe8\xe2\xe2\x7f\xe2\x38\x0e\xd9\x44\x11\x72\x95\xcc\x17\x22\xc7\x54\xc9\x7a\xbe\xc9\x1a\xdf\x85\xcc\x71\x1b\x65\x99\x90\x38\xba\x17\x32\x97\xfe\x74\x3d\x11\x69\xf6\x10\x4d\x85\xab\xd2\xf9\xf1\x00\xe7\xce\x68\xe8\x5c\x8c\x07\x98\x44\x99\x98\x11\x25\x91\xff\x14\x88\x95\xcc\x33\x3c\xa8\x2c\x17\x33\x43\x0a\x84\x94\x22\xcd\x71\x97\xab\xe9\x3d\x23\xe4\x2a\x55\x4b\x86\xcc\xf4\xfc\xf8\x29\x71\x57\x8f\x91\x2b\x17\x38\xda\x18\x77\x4c\x2e\xa3\x5c\x30\x8c\x4e\xf1\x6d\xb5\x30\xda\xc7\x18\x0e\xd9\x70\xcc\x4e\x4e\xf1\xe5\xe6\x07\x21\x5f\x45\x2a\x10\xa5\x02\xc6\x4d\x39\xa9\x8b\x5b\x25\x9d\xb8\xb4\x73\xfd\xdf\x12\x51\x9c\x46\xc9\x6c\x80\x24\xc6\x5a\xad\xf0\x14\x49\x19\x55\x3e\x73\xa3\x75\x39\xc0\x44\x90\xe5\x1a\xf3\x95\xc8\x72\x17\xd7\xb5\x6c\xe3\xa3\x09\x53\xe5\x68\x22\x62\x95\x0a\x97\x98\x18\x76\x78\x11\x3c\xbf\x9a\x5b\x08\x20\x20\x21\x21\x90\x22\x07\x70\x87\x1c\x0a\x53\xdc\x6f\x3d\x03\x6c\x73\xb6\xae\xad\x98\x37\x13\x35\x90\x43\x00\x87\xfe\xee\x6f\x3e\xd9\x78\xf5\xdd\x4f\xd7\x35\xcb\x82\x73\x0e\xa0\x68\xd3\x10\x08\xcb\x36\x65\xac\xe8\xf8\xa4\x68\xb2\x90\xf3\xd0\x27\x08\x69\xc8\x18\x05\x68\x39\xbe\x68\x96\xcf\x86\x94\x73\x0a\xec\x05\x65\x16\xb4\x6a\xee\x09\xa5\x36\xb4\x7c\xbc\x84\x9a\x4f\xd1\x05\x94\x76\xa4\x74\xd3\x7e\xd8\x42\xc3\x6e\xa0\x46\x74\x6d\xbf\x26\xf9\xd6\x39\xb2\xa7\x7d\x66\xc5\x74\x37\xfb\x4d\xe0\x29\x33\x83\x78\xad\x94\x76\xb2\xa4\x78\xd8\x2a\x0d\x0d\xb6\x56\xca\xe8\xfe\xd9\xdf\x09\x5a\x72\xde\x8c\xa9\x6d\x1f\xad\x7d\xe7\xa0\x86\x7a\xcc\x73\x0e\x06\xce\x81\x19\xa3\x99\x06\x74\xad\x54\x73\xae\x77\x80\x82\xa2\x4a\x54\xa3\xa8\xd2\x5f\x8e\xd9\xd5\xbe\x05\x65\x01\x0f\x2a\xa5\x34\x68\x97\x14\xa7\xef\x4e\x94\x05\xd5\xe0\xba\xb6\xaf\xdb\xec\x6b\x2b\xfb\xba\xb3\xbd\xff\x17\xb6\xe9\xc6\x3a\xfd\xc0\x8e\x2a\xb7\x51\x09\x6d\xe4\x75\x7a\x9e\x7a\xac\x85\x6a\x66\x29\x7d\x65\x49\xbd\x08\x0d\x9f\x9f\x52\xef\xdc\xfb\x0d\x14\xed\x8e\x2a\x67\xa8\xec\xd3\xce\x76\x14\xe5\xf4\x23\xd9\x7f\x09\xaa\x19\x0b\x6a\xa8\x66\x56\x4c\x03\xcf\xdb\x29\xfb\x36\xb4\xe8\x94\x4a\x19\xb5\x0e\x94\xfd\x95\x1a\x79\x9c\x07\x55\xf6\x99\x9d\x7d\xaf\x8e\xa9\x66\xac\x48\xf9\x3e\xd0\xc2\x73\x9b\x28\xcf\x7b\x6f\xa2\x5e\x3c\x4f\x6d\xa5\xcc\x86\x7e\xe8\x2b\x3a\xb8\x6b\xa0\xe6\xe7\xc4\x1b\x31\xed\x2b\xa8\xbe\x82\xea\x2b\xa8\xbe\x82\xf2\xfb\x0a\xaa\xaf\xa0\xfa\x0a\xaa\xaf\xa0\x3e\x73\x05\xf5\x8f\xfc\xd5\xf4\x7a\xf7\x4f\x00\x00\x00\xff\xff\xf4\x63\xd4\xfe\x38\x17\x00\x00")
+
+func fontsSmisome1FlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSmisome1Flf,
+ "fonts/smisome1.flf",
+ )
+}
+
+func fontsSmisome1Flf() (*asset, error) {
+ bytes, err := fontsSmisome1FlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/smisome1.flf", size: 5944, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSmkeyboardFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\xd5\x7f\x7f\xdb\x34\x13\x00\xf0\xff\xf5\x2a\xae\xcf\x53\x20\xa6\xb1\x9d\x64\x59\xbb\x9a\xad\xa4\xa5\xeb\x16\xba\x66\xa3\xc9\x80\x81\xc1\x28\xf6\xc5\xf1\x62\x5b\xc6\x52\x1a\x32\x0c\xaf\x9d\x8f\x1d\x39\x4d\xba\x6e\x17\x86\xfa\xc9\xc9\x96\xbe\x27\x4b\xf2\x8f\x4e\xe2\x49\x87\xef\x43\x17\xba\xd0\x3e\x84\x36\x3c\x3c\x62\x4c\x26\x33\x5c\x8e\x05\xcf\x03\x6b\x12\x4f\x18\x3b\x0d\x78\xa6\x30\x80\x89\xc8\x61\x12\x85\x31\x2a\x18\x2f\xe1\x12\x53\x05\x03\x2e\x25\xa6\x4d\x98\x61\xaa\xd2\x9e\xbf\x1c\x63\x2e\x33\xee\xa3\x25\xf2\xb0\x09\xed\xb6\xdd\xe9\xd8\xc7\xdd\x26\x8c\xb9\xc4\x80\x89\x14\xd4\x14\x21\x0a\x90\x3b\x8c\x5d\xe4\x22\x71\xca\x9e\x5e\xc0\x13\x9c\x59\x33\x35\xb5\x24\x42\xe3\x8c\x4b\xb8\xc2\xe8\x2d\xe6\x06\x1b\xe0\x42\x86\xb9\x98\x67\xd2\x81\x1c\x7d\x8b\xe7\x4a\x5a\x5c\xfa\x51\xc4\x86\xf3\xf1\x5b\xf4\x95\x03\x23\x1e\xcf\xcc\x38\x4a\xd1\x81\xad\x79\x9f\x73\x85\x0e\x74\x3a\x30\x10\x37\xd0\x3e\x3e\xee\x42\xeb\xc8\xe9\x1c\x3a\xed\x16\x98\xad\xc3\x56\x8b\xbd\xcc\x43\x9e\x46\xef\xb8\x8a\x44\xea\xc0\xb5\x58\xf2\x18\xfa\xa9\x54\x91\x9a\x2b\x04\x31\x81\x11\xfa\xd3\x54\xc4\x22\x5c\xb2\x17\x51\x8a\xd2\x81\x6e\x9b\x0d\x31\x0d\x30\x77\x60\x2c\xc6\xbc\x17\xf2\x30\x41\x6b\xb1\xe0\x96\x2f\x12\x76\x9a\x65\xb9\xb8\xc1\x40\x77\xd6\xcd\x57\x28\x25\x0f\xd1\xec\x9f\x3b\xf0\xf8\x01\x97\xf9\x34\xda\xf7\x45\xba\x9d\x7c\xc2\xae\x71\x82\x39\xa6\x7e\x79\x9d\x92\xc5\x2a\xdb\xe7\x22\x7c\x9f\x65\xf1\xd2\x1c\x89\xf7\xb7\x8e\x0d\x06\xa3\x57\xe6\x2b\x21\x55\x94\x86\xe6\x73\x21\x95\x03\xdb\x13\x64\xac\x9f\x02\xcf\x55\xe4\xc7\x08\xef\x8d\xdd\x04\x29\x27\x51\xa4\x7a\xbe\xb4\xe6\xc9\xd8\xc2\x60\x0e\x8d\xe1\x3c\xc3\x7c\xa8\x72\x44\x75\x11\x85\x53\x85\x79\x67\x34\xcf\xc7\xc2\x80\x45\x1e\x29\x94\x0e\x3b\x01\x76\x02\x7d\x98\xf2\x1b\x04\x5f\x24\x99\x90\x18\x00\x87\x14\x17\xf5\xd3\x32\x11\xa9\xda\x83\x27\x06\x3b\x81\x48\x41\x24\xc1\xe7\x71\x8c\xc1\xd6\xed\xb2\xa0\xaf\x20\x47\x89\xc9\x38\xc6\xea\x31\xe1\xbe\x9a\xf3\x78\x8d\x9a\xb0\xc0\x38\x6e\xc2\x2c\x4a\x03\xae\x47\xe3\xe9\x72\xc1\x97\x7b\x30\xc5\x1c\xcb\x71\x39\x48\x9e\x64\x31\xea\x6e\xf0\x56\x65\xd7\x9a\x9d\x40\xe1\x42\x59\xec\x9d\xeb\x32\x07\x0e\x4c\xd3\x3c\xd8\xbd\xae\x72\x0a\x80\x2a\xee\x58\xaf\x72\xa4\x6e\xe3\xba\x4e\x74\x9d\xe9\x3a\xd6\x35\xde\xe6\x7c\xc2\xdc\xec\x6a\x37\xdc\x9d\x6b\xc6\x60\x73\x1b\xf5\xd1\x9d\x40\x74\xb0\xa2\x38\x85\xa2\x28\x60\x55\x8a\xa2\x38\x2b\x43\xbf\x0c\xa3\xed\x8e\xea\xf4\xe5\x3a\xac\x3b\x58\x51\x78\x5e\x51\x86\xaa\x14\xeb\xd3\x62\xe7\x0e\x56\xae\xa9\x5e\x98\x3e\xba\x13\xa8\x8e\xea\x41\xda\x9c\xfd\xb3\xed\xd9\x57\x6d\x17\xdb\x6d\x6f\xd6\x8b\x79\xfd\x81\x15\x7d\x7c\x09\xbb\x2f\xeb\xe3\xeb\xa0\xd6\x56\xdf\xa4\x61\x19\x2e\xb7\xd7\x70\x55\x86\xa7\x65\xd8\xdb\xee\x70\xca\x60\x94\xe1\x1a\xd5\x3c\x4f\x77\x5f\xd6\x07\x3a\x6e\x77\xe7\xdf\xdf\x9d\x8d\xb6\xb8\x1e\x06\xfe\x4b\x89\x8b\x7a\x8f\xcf\xb8\xb4\x3e\x79\x98\x8d\x77\x89\x61\xc2\xa3\xf8\x9e\xff\x8c\x65\xa9\xde\x15\x1d\xcb\x72\x39\x7a\xde\x84\x73\xcc\x94\x55\xfe\xc3\xba\xe2\xfe\xd4\x82\x73\x94\x51\x98\xb2\xf5\xd7\x0d\xd6\x39\x75\x96\x5d\x06\x77\x15\x6f\xdf\xc1\x7b\x0a\x6b\xe8\xf9\x55\x78\x95\x51\xe6\xd4\x63\xd4\xc5\xd5\xb5\xb1\xf1\x5b\x57\x2e\xd3\x1f\x31\xdd\x50\x62\xd7\xf3\x3c\xe3\xce\x20\x55\x8f\xeb\x79\xb6\x0b\x60\xbb\xb7\xa7\x75\xee\x6a\x18\x00\x68\xac\x1a\x5c\x4f\xe7\x34\xea\xd6\xfa\x8a\x06\x80\xe1\x95\x0d\x46\x79\x91\x92\x18\x5e\x9d\xbb\x39\x99\x6a\x00\xc3\xd5\x29\xab\x45\xe8\x2b\x56\x73\xb3\x57\x6b\xd6\xdf\x7a\xd0\x87\xd5\x8f\x35\xf4\x16\xd9\x9e\x5d\xe5\xac\x4e\x6e\x37\x43\x6f\x56\xfd\xe8\x19\xfa\x67\xaf\x4f\xed\x6a\x0f\x3e\xf6\xf4\xb9\xd5\x90\xab\xc8\x14\xc6\x96\x03\x07\xdd\x43\xb3\xd1\x32\x1e\x99\x47\xc7\x2d\x38\x7c\xd0\x7a\x74\x6f\xe2\xd0\x6c\xb7\x5a\xd0\xed\xc2\x50\x09\x7f\x36\x15\x71\xd2\x84\xe1\x02\x03\x4c\x19\xdb\xf8\xe6\xf6\xd8\xc6\x7b\xda\x63\x1b\x6f\x5b\x8f\x6d\xbc\x33\xbd\x9e\xfe\xbe\x97\x64\x6f\x4d\x6b\x75\x07\xfc\x8f\x02\xff\xa7\xc0\x3e\x05\x3e\xa3\xc0\xe7\x14\xf8\x82\x02\x0d\x0a\x18\x14\xf8\x92\x02\x07\x14\x68\x52\xc0\xa4\x80\x45\x01\x9b\x02\x2d\x0a\xb4\x29\xd0\xa1\xc0\x03\x0a\x74\x29\xf0\x90\x02\x87\x14\x38\xa2\xc0\x23\x0a\x1c\x53\xc0\xa1\xc0\x57\x14\x78\x4c\x81\x27\x14\x38\xa1\xc0\xd7\x14\xe8\x51\xe0\x94\x02\x67\x14\xf8\x86\x02\xe7\x14\x78\x4a\x81\x0b\x0a\x3c\xa3\xc0\x73\x0a\xf4\x29\xf0\x2d\x05\x2e\x29\xf0\x82\x02\x57\x14\x18\x50\xe0\x25\x05\x5e\x51\xe0\x3b\x0a\x5c\x53\x60\x48\x81\x11\x05\x5e\x53\xe0\x7b\x0a\xfc\x40\x81\x1f\x29\xf0\x86\x02\x3f\x51\xe0\x67\x0a\xb8\x14\xf8\x85\x02\xbf\x52\xc0\xa3\xc0\x6f\x14\xe0\x14\x18\x53\xc0\xa7\x40\x40\x01\xa4\xc0\x84\x02\x21\x05\xa6\x14\x88\x28\xf0\x96\x02\x33\x0a\xc4\x14\x48\x28\x90\x52\x40\x50\x20\xa3\xc0\xef\x14\xc8\x29\x20\x29\xa0\x28\x30\xa7\xc0\x0d\x05\x16\x14\xf8\x83\x02\x4b\x0a\xbc\xa3\xc0\x9f\x14\x28\x28\xf0\x17\x05\xfe\xbe\x1f\xe8\xbf\x4f\x3d\xf8\x27\x00\x00\xff\xff\xd7\x48\x84\xb7\x84\x16\x00\x00")
+
+func fontsSmkeyboardFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSmkeyboardFlf,
+ "fonts/smkeyboard.flf",
+ )
+}
+
+func fontsSmkeyboardFlf() (*asset, error) {
+ bytes, err := fontsSmkeyboardFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/smkeyboard.flf", size: 5764, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSmscriptFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x5a\xff\x6f\xe2\xb8\x12\xff\x9d\xbf\x62\x7e\x40\x3a\x78\x0f\xd6\x24\xa5\x5f\x90\x56\x2b\xb2\x90\xb6\xd1\xd1\x84\x0b\x61\xf7\x56\x8a\xe4\x47\xb7\x69\x8b\x8e\x42\xc5\x97\x3b\xad\xe4\x3f\xfe\x29\xf6\xd8\x8e\x13\x07\xe8\xdd\x89\x90\x92\x99\x8f\xc7\xe3\xcf\x8c\xc7\x93\x7d\x5e\x3d\xbb\x8b\x26\x5c\x42\x1f\x9c\x0b\xe8\x81\xd3\x83\x1e\x5c\x0c\x7a\xfd\xc6\xec\x6d\xf6\x73\xbb\x7c\xdf\xc3\xe3\x2f\xb8\x5b\x65\xeb\x35\x8c\x5e\x17\xef\xef\xd9\x6a\x05\x7d\x32\xb8\x80\x6e\x17\x1e\x17\xbb\xec\x09\x36\x6b\x10\x92\x8d\x60\xfd\x73\x75\x78\xca\x76\x10\xcc\x22\x98\x2c\xf6\xcb\x75\xd7\x69\x3c\x2f\x5f\x56\xd9\x1e\xb6\xd9\x2a\x5b\xec\x32\x70\x3f\x39\xb9\xaa\xe3\x82\x77\x78\x01\x67\x30\xe8\x37\xa6\xd9\xf6\x6d\xb9\xdb\x2d\x37\x6b\x58\xee\xe0\x35\xdb\x66\x8f\xbf\xe0\x65\xf9\x77\xb6\x86\xfd\x06\xde\x36\x4f\xcb\xe7\x5f\xb0\x7f\x5d\xee\xe0\x79\xb3\xde\x77\x60\xb1\x83\xd5\x66\xfd\x92\x7f\xef\x5f\xb3\x06\x17\x58\x66\xdb\xdf\x76\xb0\x5e\xbc\x65\x39\xc6\xfb\x6a\xf1\x53\x58\xb6\x80\x9f\x9b\xb7\xb7\x6c\xbd\x87\xd5\x72\x9d\x7d\x6a\x34\x1e\x84\xf4\x53\x3e\xad\xe9\xe2\xb0\x82\xaf\x87\xed\x7e\xb3\x86\xcf\xbb\xcd\xea\xb0\x5f\x6e\xd6\xc3\x6c\xb1\xdd\xbf\xae\x96\xeb\xbf\x3e\xad\xb3\xfd\x17\x70\x5c\x32\xb8\xca\x0d\x59\x8a\xd9\xc1\x3a\xfb\x07\xde\x17\xdb\xc5\x5b\xb6\xcf\xb6\x8d\xdd\xe1\xfd\x7d\xb3\xdd\x0b\xc0\xdb\xe0\x2e\x9f\xeb\x62\xfd\x94\xdf\x7e\x5f\xae\x3f\x01\x3c\x2c\x7e\xc1\x62\xb5\xdb\xc0\x63\x06\xbb\xd5\xf2\xe5\x75\xbf\xfa\x05\x6f\xd2\x8a\xe7\xcd\x16\x1e\xb3\xfd\x3e\xdb\xc2\x61\x97\x35\x36\xcf\x1c\xfe\xf9\xb0\x5a\x75\xff\x59\x3e\xed\x5f\xc9\x5f\xd9\x76\x4d\x76\x6f\x87\xdd\x2b\x2c\x56\xfb\x6c\xbb\x5e\xec\x97\x7f\x67\xbb\x0e\x3c\x1e\xf6\xf0\x94\x3d\x2f\x0e\xab\x3d\x6c\x0e\xfb\xf7\xc3\x3e\x9f\x79\x18\x25\xf0\xf3\x75\xb1\x7e\xc9\x9e\x3e\x35\x1a\x4d\x68\x0e\x6d\x97\x61\x03\x60\xd8\x00\x86\x9f\x0d\xff\x3b\xbf\xc9\xef\x58\xfe\x53\x2e\x89\x17\xfe\x84\xff\x37\x6c\x00\x65\x94\xd1\xc2\x37\x30\x60\xa0\x9e\x17\x04\x01\x05\x5a\x8c\x32\xa9\xd8\x56\x0a\x05\xc1\x56\x1b\x88\x40\x20\x42\x91\x40\xab\x5d\x42\x14\x62\xc3\x06\x90\x94\x0c\x1b\x90\x92\x14\x7f\x47\xe3\xf3\x1f\x9b\xf8\x41\x1d\x8e\x94\xcf\x06\xe4\x05\x52\xf5\x24\x15\x16\xca\x0b\x31\x2d\x4f\x19\x37\xa8\xdb\xfd\x4f\xb7\xcb\x61\x58\x6a\x9f\x22\x30\x10\x82\xff\x15\x82\xf8\xb7\x16\x2c\x7c\x84\x99\xf8\x54\x7f\x75\xbb\xa8\xda\x54\x3f\x5a\x14\x0b\x7e\x10\xb3\x12\x2e\x23\x12\x49\x3c\xa6\xd2\x7f\xa9\x98\x33\xce\x30\xa5\xc4\xb4\xaa\x93\xab\x32\xc3\x03\xf8\x84\x0a\xd4\xb6\x1e\x81\x52\x3d\x02\xa5\xe2\x2f\x4a\xb9\x09\x4d\xc8\x57\x21\xc5\xbf\x4a\xbe\x61\x80\x9e\xa7\xc8\x13\x28\xf3\x44\x80\x31\xca\xc7\xac\x03\x13\x0f\x09\xff\x62\x84\xcb\xe4\xf3\x29\xc8\x48\xa3\xa0\x49\x90\x44\xc2\x78\xc3\x9d\x62\x90\x16\xa5\x6d\xe1\x35\xdb\x58\x14\x27\xcf\xfd\x91\x52\xe1\x20\xe9\x1d\xbd\x2c\x1b\xa4\x99\x5e\x96\xd2\x8f\xc4\xe4\xdf\x67\xa4\x5e\x31\x90\xb4\xd9\xda\x7a\xc3\x5e\xcd\xd1\x2f\x82\x9e\x0d\x35\x5b\x71\x8f\x91\x94\x5f\x37\x26\x07\x28\x55\x34\xa0\xb4\x83\x4c\x20\x3c\xec\xf8\x6d\x3e\x33\x01\x98\xe6\xb2\x44\xe9\x75\xa4\x1a\xb2\x98\x69\x3e\xa7\x94\x68\xa7\x2b\x16\x21\x5b\x18\xa1\x68\x8d\x98\x25\x6b\x69\x51\x89\xdd\x54\x81\x8d\xc8\x4d\x50\x26\x68\xdc\x5c\xba\x29\xed\x6f\xe5\x78\x80\xc0\xdc\xf6\x56\x4a\x0b\x4c\x96\x8b\xd6\x14\xab\x26\x90\xbf\x74\x05\xb0\x81\x2b\x61\xb9\xa7\x5b\x6d\x60\x54\xa4\x35\x22\x5c\x02\x2d\xa2\x23\xb2\x14\xe0\xb9\x34\xb7\x3c\xe5\x74\x20\xad\x4a\x28\xa1\x24\x91\x7c\x07\xd6\xed\x32\x69\x36\x6b\xdb\x61\x41\x24\x14\x0a\x62\x25\x72\xf7\x92\x72\x82\x11\x89\x47\xb8\x8b\xc9\xb4\xc4\x6d\x62\x6a\xe8\x8e\x18\x9a\x22\xdb\x59\x2a\x53\x2f\xa4\x25\xb7\x72\x8f\x8b\xb1\x58\x5b\x27\x2f\x31\xc9\xb4\xbc\x08\xd0\xa1\x79\x32\xc1\x89\x31\x49\x83\xf2\x6d\x91\x12\x05\x77\x20\x2b\xb4\x31\x5a\xc9\xd4\x91\xec\xc0\xc9\xa6\x34\x25\xc8\x3b\x99\xb8\x2a\xeb\xad\x49\x87\x64\x43\xd3\x99\xdc\xab\x0c\x58\x04\xa6\x14\x6d\x61\x79\xe8\x2b\x4e\x97\x48\xad\x07\x50\x23\x80\x1c\xa2\xd6\xab\x8a\x26\x62\x06\x20\x48\xd2\x2e\xc4\xb2\xc1\x3c\xf4\x7c\x13\x6f\x6a\x98\x07\x2a\x00\x0a\x9e\x53\xca\xe5\x60\x2c\xea\xa1\x1a\x53\x4e\x51\x4a\xc6\x48\xc6\x50\x5a\xab\xa4\x58\xd0\x2d\xa9\x57\x07\x4d\x75\xca\xfd\xf2\x19\x33\x1c\x01\xa8\x66\x0d\x73\x40\x35\x18\x0e\xc4\x50\x5c\x72\x1c\xd7\x02\xda\x85\xa4\x4e\x70\xc9\x95\x8c\xb1\xc9\xe3\xa6\xa3\xf7\xcb\x14\x97\x1b\x87\xd0\xb9\x92\x9a\x35\x00\xbf\x50\x36\xe4\x45\xc6\xd0\x28\x80\x9a\xe5\xe4\x5d\xfe\x6a\xaa\x8c\x8e\x7b\x40\x5a\xad\x47\x50\x16\xd3\x2c\x41\xef\xa6\x84\x95\xb3\xa5\x60\x6a\x1b\x09\x9b\xf2\xed\x21\x25\xe6\xf6\x80\x58\x08\x25\x53\x9e\x6d\x1f\x06\xca\x4e\x0e\x38\x94\x3b\xbf\x48\x47\x4a\x40\x3f\x16\xf9\xaa\xf8\x98\xb5\x4d\x53\x3a\x72\x10\x31\x86\xb1\x42\x85\x39\xe1\xa4\x54\x89\x50\x32\x25\x77\x9f\x5e\x45\x52\xf4\xfb\x50\x6d\x75\x48\x1b\x22\x58\x64\x73\x1a\xee\x32\x69\xc9\x21\xd6\x89\x54\x03\xaf\x70\x4b\x58\xfe\x3f\xbf\x6d\xd6\xa4\x3c\x53\x0b\x75\x94\x46\x4d\xc2\x90\x2b\xc7\x57\xb7\x50\x9f\x99\xbb\x84\x4c\xa0\x48\x02\x26\xe4\x78\x5e\x38\x8f\x53\x85\x45\x02\x4c\xeb\xc8\x18\xee\xc3\x66\x75\x01\x50\xae\x68\x5e\xd3\x4a\x3e\xca\xa8\x8c\x5e\xb4\xad\x3c\x05\xc3\x29\x2a\x9d\x34\x0d\x02\x5a\x27\xcc\xf3\x10\x0e\x0c\x65\xf3\xaa\x6b\x24\x33\x17\x6a\x14\x95\xac\x51\x4b\xc4\x7c\x9a\xa4\x4c\x8f\x8a\x11\xd2\x5e\x21\x57\x62\xb3\xdc\xb7\x48\x5e\x68\x71\x3c\xb9\x8c\x5a\x90\x5f\x09\xf7\x56\x81\xb9\xe2\x1c\xc2\x2a\x9f\x72\xca\x92\xe7\x2b\x2c\xf4\xd5\xe9\x07\x6b\xc5\xe2\x15\x4f\x42\x79\x84\xa0\x6d\x1d\xbd\xd2\x80\x25\x46\xc9\xed\x1b\x19\x4f\x72\x22\xb8\xff\x1a\xbb\xae\x30\x8a\x94\xf3\x7f\x69\x7b\xb2\xef\x49\x1b\x65\xcd\x89\x9c\xb7\x91\x86\x1c\x89\x0a\x3d\xb7\xb3\x28\x45\x31\x03\xf0\xeb\x67\x9d\xb5\xf8\x63\xe7\xaa\x07\x10\x46\xdd\xaf\xb1\xef\xfd\x0e\xb3\xa9\x37\xf2\x75\xba\xd6\x9f\x5c\xd0\x01\x08\xc2\x6f\x7e\x9c\xf8\x63\xf0\xff\x1c\x4d\xbc\x07\x2f\x09\xa2\x10\x1e\xbc\xf8\x77\x5d\xfa\xcb\x35\x14\xe0\x2e\xc0\xc8\x0f\x13\x98\x05\x77\xa1\x91\x88\xa9\xe1\x05\xaa\xa2\x14\xf5\x2e\x00\xa6\xd1\x3c\x1c\x2b\x45\x2a\x23\xed\x7f\x32\xd4\x40\x96\xc1\x05\xf7\x39\x57\x7d\x80\xd1\x3c\x8e\xfd\x70\xf4\x03\x75\x53\xa0\xf2\x98\x28\x36\x3e\xf4\x26\xd1\x5b\x20\xea\x5e\x02\xfc\xf0\x43\xa5\x86\x74\x4d\x29\x11\xa7\x13\x86\xc7\x13\xf3\x60\xeb\x5c\x5d\x01\x7c\x8d\xa3\xdf\xfd\x10\xbe\x7a\x71\xd1\x01\x9a\xcc\xce\xd5\x35\xc0\xcc\x1f\x71\x7f\xe1\x94\x78\x1d\xc4\x27\x91\x97\x48\x58\x27\x71\xd9\x1b\x80\x71\xe0\xf9\xb1\x3f\x0b\x66\x9c\x11\x3c\x3f\x35\x4b\x57\x29\x3d\x00\x18\x45\xd3\x1f\x71\x70\x77\xaf\xfd\x6c\x1e\x7d\x40\x1d\x7d\xb0\x88\x67\x82\xd9\xb2\xb2\xc4\xa3\x8f\x73\xdd\x03\xb8\xf5\x1f\x82\x30\x08\x7d\x88\xe2\x71\x10\x7a\x13\x08\xc2\x71\x30\xf2\x92\x28\x56\x5b\x5b\x4b\x1c\x63\xbb\xdd\x2e\x86\x5d\x81\x9c\xce\xb5\x03\x30\xf1\x6f\x93\xee\x34\x0a\xc2\x24\x08\xef\x60\x1c\xcd\xbf\x4e\x7c\xf0\xc2\xbb\x89\x0f\x7f\xcc\xa3\xc4\xa0\x0d\x5a\xc9\x8f\x87\x78\x3e\xd4\x85\x89\x73\xed\x02\x6f\xe3\x28\xfe\x14\xce\x7d\xac\x14\xf3\xce\xf5\x05\xc0\x2c\xba\x4d\xe0\xfe\xc7\xf4\xde\x0f\x75\xda\x01\x61\x6d\x45\xbe\x0f\x10\xfb\x77\xc1\x2c\xf1\x63\x7f\x6c\xf5\x5d\x47\xfb\x8e\x51\xe9\x3b\x60\xa9\xc5\x77\x97\x00\x0f\xde\x28\x8e\xc2\xea\x49\xd6\xfc\xc2\xc1\xaf\x00\xc6\xfe\x5d\xec\xfb\x38\xb0\x68\xf4\x58\x2a\x2d\xe7\xfa\x1a\x60\x3a\x99\xcf\xba\x0f\x41\x38\x9f\x95\x63\xa9\xd4\x78\xd1\x3c\x95\xda\x37\x00\xb3\xf9\xd4\x8f\x67\xa3\x38\x98\x26\x90\x7c\x8f\x64\xc1\xc7\x3b\x00\xb4\x34\xd8\xa0\x24\x7e\x1f\xfb\x7e\x03\x64\xbb\x83\x87\x84\x20\x6b\xd1\x95\x37\x3d\x00\x6f\x34\x4f\x7c\xf0\x46\x79\xc0\x9b\x6d\x28\x59\xfa\x39\x37\x0e\xc0\x43\x30\x8a\xa3\xe2\x24\xec\x99\x8c\xc9\x4c\xc6\xd4\x4c\x6e\x5c\x80\x69\x30\x19\xc5\xd1\x77\x15\x44\x54\x25\x12\xd1\xaa\xc0\x73\x2c\x30\xd5\xac\x10\xaa\x17\xf9\xc0\xe3\xf1\xc4\x87\x71\x94\x98\xcc\x68\x46\xcd\xca\x74\xf2\x34\xe2\x8f\x83\xc9\xc4\x6b\x48\x51\x79\x11\x05\x6e\x9b\x8b\x5d\x9a\xbe\x8a\x42\xbf\xda\x52\xd2\xae\xbd\xb9\xca\x29\x32\x1b\xcd\x27\xb5\xf1\xc5\x93\x02\x77\xaf\x85\xaf\x37\xd7\x00\x3c\xcc\x3f\x14\x5b\x29\x36\x4f\x78\xf7\x84\x14\xe1\x6e\x00\xbe\xcd\x27\x77\x5e\x0c\xb7\xb1\x27\x72\x53\x14\xe6\x30\x5e\x9c\xf8\xb1\x79\x84\x95\xa5\x35\x30\x22\xbb\x9d\xc4\xe8\x63\x21\xe6\xc0\x8e\x79\xef\x4d\x6e\xcd\x16\x01\xc1\x9a\x89\x80\x6c\xb1\x21\x15\x15\xd6\xa0\x57\xc5\xe2\x6c\x94\x16\xce\x38\x2d\xf5\xa6\x42\xa4\x91\x94\xb6\x95\x95\x15\x33\x05\x76\x71\x33\xfb\x63\xee\xcf\xaa\x29\xa9\x50\x60\xb7\x0a\x9d\x3f\x67\xe0\x02\x4c\xbc\x24\x08\x61\xe4\x4d\x83\xc4\x9b\xc0\xc4\x4f\x12\x3f\x06\x0f\xbe\x07\xc9\x3d\xdc\xc5\xde\x37\x9f\x9f\xb2\xe0\xec\x02\xc4\x19\x5c\x1c\x07\xe5\xb1\x25\x67\x73\x36\x68\xff\x38\xe8\x28\x88\x47\xf3\x87\xdb\x89\xff\xa7\x38\xb0\x7f\x00\xf9\xf2\x38\x72\x12\x4c\xc6\x7e\x03\x8b\xa5\xb3\x41\xaf\x8e\x83\x1a\x7b\xe2\x07\xaa\x3b\x67\x70\x7d\x1c\x38\xce\x23\xc9\xfb\x1a\xf1\x65\x93\xcd\x9e\x3c\x0c\x4f\x23\xdf\xd4\x21\x0b\x28\xda\xd1\xfd\x3e\x60\xba\xe5\x07\xac\xab\xba\x7e\xc4\x6c\xfc\x49\xe4\x41\x0d\xf2\x08\xd7\x4e\x67\xa7\x73\x5a\x8a\x7c\x2e\xc3\x86\xdb\xeb\xd5\xc0\xfa\x55\xf2\x0e\x75\x4f\xf1\x33\x15\xd0\x9f\x4b\xbd\x44\xb7\xe7\x1c\xc7\x2b\xf2\xf6\x2c\xbc\xba\xe0\xf2\x6b\x28\x7b\x16\x68\x5d\x70\xf9\x76\x62\x9d\x85\x59\x17\x5b\x81\xe9\x48\x79\x80\x39\xd1\xe6\x74\x7b\x75\x11\x15\x94\x1c\x29\x3b\xe0\xa7\xf0\xea\x82\x29\xb0\x38\x12\xbb\x75\xa7\x41\xeb\x02\x29\xa8\x38\x52\x1d\x64\x4e\x62\xd6\x85\x90\x9f\xdc\xe3\x06\x0f\xc5\x16\x78\x97\x75\xeb\x5a\xe0\x6e\xaf\x2e\x68\x42\x33\x2d\x75\x64\x5e\x3a\xb7\x35\xeb\x3a\x75\x71\x13\xd5\xc5\xcd\xd1\x73\xa4\xeb\xd4\xc5\x4d\x54\x17\x37\x27\xf0\xea\xe2\x26\x3a\x1a\x37\x27\x40\xeb\xe2\x26\xaa\x66\xf9\xb3\xf0\xea\x62\x26\x3a\x16\x87\x27\x30\xf3\xb2\x7b\x3e\x49\x82\xe9\x24\xaf\xa2\x0a\xe7\x2b\x90\x07\xe2\xa6\xe8\x70\x88\x93\x93\x6a\x8d\x73\xe5\xba\x20\x41\x83\x66\x49\x7e\xae\x13\x39\x16\xdf\xa5\xa5\x04\x1b\xf3\xf8\x72\x8c\xb7\x60\xe5\x71\x12\x51\xeb\xa2\x64\x5e\x4a\x0d\xba\x44\xd0\xf5\xef\xc9\x56\x82\xeb\xd4\x05\xcc\xbc\x9a\x29\xfe\x0d\x7c\x5d\x0c\xcd\x6d\x89\x43\x97\x0d\x1f\x19\xc3\xad\x8b\xa6\x79\x35\x8f\xfc\xbb\x86\x8b\xeb\xd6\x05\xd8\x0f\x8b\x97\x8a\x07\x90\x56\x7d\x0f\xde\x75\xeb\xa2\x2c\xb9\x8f\xe2\x10\xeb\x5b\xf1\x1a\x0a\xab\x5b\xaa\xde\x07\x16\x5f\xc9\xb8\xae\x8a\xac\xd9\x83\x37\x51\x30\xb3\x7b\x2f\x9e\xc2\xec\x54\xcf\xc6\x75\xfb\x56\x75\x4b\x01\x3a\x3c\xdd\x72\x72\xdd\xcb\x63\x68\xd2\x51\xe4\x5c\xb4\xab\x63\x68\xf6\x3c\x74\x0a\xf2\xfa\x18\x24\x66\x21\x5d\x6a\x9e\x42\xbb\x39\x86\x66\x36\x5e\xce\x44\x1c\x1c\x43\x34\xaa\xcb\x56\xfb\x3c\xc8\x8b\x9e\x1d\xd2\x2f\x36\xd1\x3a\xf2\xec\x4b\xec\x18\x8e\x15\xa3\x5a\x40\x22\x9c\xac\x76\xa1\xf0\x06\x85\xb6\x05\x94\x6b\x85\xaa\x14\x8d\xc3\xfa\xb7\x27\xee\x85\x9d\xf3\x7e\x99\x66\x47\x31\xec\xc4\xb7\x14\x87\xe4\x84\x31\x76\xce\xdb\x0a\xc2\x62\x3f\x96\x09\x8e\x31\xe3\xfd\x92\x7b\x61\xa7\xbc\x59\x09\x62\x85\x55\x7d\xa1\xe3\x5e\xd8\xe9\x6d\x16\x7e\xa4\x5e\xdd\xce\x67\x4b\x9d\x87\xff\x52\xc8\x86\x61\x67\x70\xb5\xac\x53\x55\x9d\x6c\xd6\x58\xdc\xd1\xb7\x73\x97\xd7\x73\x29\x6f\x20\xfe\x96\x22\x71\x39\x6d\x41\x2f\x4b\xdf\x4e\xd9\xb0\xe6\x54\x29\xed\x38\xf2\x9a\xc9\xed\xdb\xa9\x5b\xad\xdb\x86\xc7\xbb\xee\x6e\xdf\xce\xdf\xa8\x92\x26\x4f\x02\xd9\x49\x5c\x53\xa9\x9d\x44\xb3\x33\x39\xaa\x24\xc7\x93\x40\x76\x16\xdb\x6a\xb3\x93\xaf\x28\xdc\xfe\x35\xc0\x38\xf8\x16\xcc\x8c\x82\x2c\x17\x88\x40\x37\xb7\xa2\xe2\xd2\xdb\x69\x5c\xa9\xc4\x54\x81\x8d\x55\x97\x78\x21\x98\x92\x42\x15\xc6\xe1\xec\x8c\x9e\xd7\xf4\x68\x0a\x8c\xae\x7b\x91\xe2\x5e\xda\x79\x5d\x2e\xbb\xc8\x47\x20\xed\x7c\xb7\x95\x5a\x66\xa1\x75\x0a\xd7\x4e\xfa\x6a\x79\xf5\xa1\x57\x49\xee\xa5\x3d\x04\xca\x25\x55\xf1\x55\x65\xfd\xdb\x43\xf7\xd2\x1e\x07\xb2\x96\x92\x4b\x23\xff\x8d\x4e\xcd\xab\x5f\xf7\xd2\x1e\x00\x3f\xea\xcf\x14\x27\x0c\xfb\x7f\x00\x00\x00\xff\xff\x9f\x52\x6a\x3c\x07\x2c\x00\x00")
+
+func fontsSmscriptFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSmscriptFlf,
+ "fonts/smscript.flf",
+ )
+}
+
+func fontsSmscriptFlf() (*asset, error) {
+ bytes, err := fontsSmscriptFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/smscript.flf", size: 11271, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSmshadowFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x5a\x6d\x6f\xe2\x38\x17\xfd\xce\xaf\x38\x1f\x90\x66\x90\x4a\x43\x52\xfa\x82\x54\x8d\x9a\x82\xdb\x46\x4b\x13\x9e\x24\x74\xb6\x52\x24\x2f\x9d\xa6\x2d\x5a\x0a\x15\x84\x1d\x8d\xc4\x8f\x7f\x94\xf8\x25\x4e\x62\xa7\x95\x56\x90\x2d\xbe\xc7\xf7\x5e\x9f\x7b\x7c\xed\xcc\xcb\xea\xc5\x59\x74\x31\xc4\x09\xec\x21\x06\xb0\x07\xf9\xc7\xc8\x19\x74\xa2\xf7\xe8\x6d\xf1\xbc\xf9\x8d\xa7\x3f\xb8\x5d\xa5\xeb\x35\xc6\x6f\x8b\x8f\x8f\x74\xb5\xc2\xd0\x1a\x9d\xa0\xdf\xc7\xd3\x62\x97\x3e\x63\xb3\x46\xf4\xbe\x58\xad\x3a\xde\xfa\xd7\x6a\xff\x9c\xee\xe0\x45\x01\xa6\x8b\x6c\xb9\xee\xdb\x9d\x97\xe5\xeb\x2a\xcd\xb0\x4d\x57\xe9\x62\x97\xc2\x39\xb6\x73\x4b\xdb\x81\xbb\x7f\x85\x3d\x1a\x0d\x3b\xb3\x74\xfb\xbe\xdc\xed\x96\x9b\x35\x96\x3b\xbc\xa5\xdb\xf4\xe9\x0f\x5e\x97\xff\xa5\x6b\x64\x1b\xbc\x6f\x9e\x97\x2f\x7f\x90\xbd\x2d\x77\x78\xd9\xac\xb3\x23\x2c\x76\x58\x6d\xd6\xaf\xf9\x77\xf6\x96\x76\x8a\x01\xcb\x74\xfb\x6d\x87\xf5\xe2\x3d\xcd\x31\x3e\x56\x8b\x5f\xcc\xb1\x05\x7e\x6d\xde\xdf\xd3\x75\x86\xd5\x72\x9d\x1e\x77\x3a\xf7\x6c\xf4\x73\x1e\xd5\x6c\xb1\x5f\xe1\x7a\xbf\xcd\x36\x6b\x5c\xee\x36\xab\x7d\xb6\xdc\xac\xaf\xd2\xc5\x36\x7b\x5b\x2d\xd7\xff\x1e\xaf\xd3\xec\x07\x6c\xc7\x1a\x9d\xe5\x8e\x2c\x59\x74\x58\xa7\xbf\xf1\xb1\xd8\x2e\xde\xd3\x2c\xdd\x76\x76\xfb\x8f\x8f\xcd\x36\x63\x80\x37\xde\x6d\x1e\xeb\x62\xfd\x9c\x3f\xfe\x5c\xae\x8f\x81\xfb\xc5\x1f\x2c\x56\xbb\x0d\x9e\x52\xec\x56\xcb\xd7\xb7\x6c\xf5\x07\xef\xc2\x8b\x97\xcd\x16\x4f\x69\x96\xa5\x5b\xec\x77\x69\x67\xf3\x52\xc0\xbf\xec\x57\xab\xfe\xef\xe5\x73\xf6\x66\xfd\x9b\x6e\xd7\xd6\xee\x7d\xbf\x7b\xc3\x62\x95\xa5\xdb\xf5\x22\x5b\xfe\x97\xee\x8e\xf0\xb4\xcf\xf0\x9c\xbe\x2c\xf6\xab\x0c\x9b\x7d\xf6\xb1\xcf\xf2\xc8\xfd\x20\xc6\xaf\xb7\xc5\xfa\x35\x7d\x3e\xee\x74\xd0\xed\x5e\xd5\x3e\xae\x3a\xc0\x21\x7f\xa6\xec\xb3\x97\x7f\x02\x60\x3f\xa0\xf8\xdf\x07\x3c\x74\xc1\xfe\x8c\xf2\xbb\x78\x38\xe4\xd6\xc5\x1f\x29\x0e\xf9\x7f\x0c\x45\x79\x06\x3d\xe4\xd8\xd2\xa0\x40\xfa\x4e\xfb\x97\x6c\x20\xb5\xf8\xa0\x6e\x31\x80\xf6\x60\xf1\xb9\x2c\x8e\x6b\x95\x4e\xc9\x69\x0b\x40\xf0\x47\xee\x7a\x42\x29\xa5\x87\xd2\x51\x31\xb8\x30\x16\xa0\x50\xa2\x03\x9b\x9a\x9b\xb0\xaf\x84\x26\x45\x4e\x12\x24\xc2\xe2\xd0\x55\xbf\xa9\xc5\x1c\x4d\x90\x70\x50\xca\xfc\xe1\xae\x26\xaa\x03\x57\xc2\x92\x45\x42\x41\x79\x4e\x78\x46\xea\x03\xcb\x4f\xe9\x74\x19\x78\x0e\x20\xed\xd5\x95\x68\x58\x57\x17\x51\xc4\x29\xdc\xb5\xba\xf5\x45\x14\xb1\x7e\xe7\x41\x26\x94\x5a\xdd\x2a\x3c\x15\x69\x10\x6b\x2a\xdc\x60\x3f\xa2\x57\x99\x42\x75\xf3\x8a\x45\xce\x97\x19\x49\x97\x0d\xb0\x2a\x03\x70\xe0\xf9\xcf\x73\xa4\xa4\xa8\x1a\x22\x87\xa5\x46\x14\xc8\xd8\xf8\x90\xa4\x32\x46\xf8\x22\x12\x22\x58\x51\x49\x89\x60\x98\x08\xc9\x8c\xa4\xfc\x26\x21\x9b\x89\x93\x6b\x51\x5b\x17\xf5\x87\xfa\x72\x17\x60\x97\xb8\x64\x58\x05\x27\xab\x0b\x56\xe3\x43\x9d\x18\x2a\x81\x7f\xe0\x47\x49\xdc\xea\x9a\x24\xd2\xe7\x62\x40\xaf\x5b\xe3\x45\x31\xa4\xf8\x9b\x05\xfa\x0f\x5f\xfa\x84\xd2\x23\xa5\xe0\x4a\xa7\x13\x35\xf7\xbc\x72\xa1\xb8\x2e\x16\x91\x27\xd6\xbc\x88\x22\x96\xef\xbc\xc6\x93\x66\x74\x72\x0e\x26\x40\x02\x47\xcf\x17\xc1\xa4\x06\x2d\x1b\x03\x0e\x8d\xd2\x90\xbe\x50\x59\x1a\x0d\x5f\x0e\xb2\x2a\xa8\x90\x52\xd4\x07\x95\xb4\x36\xf9\x22\x6b\x2b\x31\x57\x61\x3e\x15\xcb\xd6\x31\x27\x07\x3d\xa8\xec\xe0\x83\x84\x36\x8a\x07\x0d\x3d\xca\x69\x70\x48\x2c\xe9\x76\xc5\x6f\x39\xf0\xc0\xa7\x14\xc3\x92\x26\x1a\x55\x34\xa4\xcc\x94\xd5\x10\x43\x41\x3a\xbe\xea\xba\x8c\xeb\x90\x12\x1d\x8f\x92\xae\x52\x2d\xf4\xd0\xa8\x12\x2a\x69\x2a\xa9\xa6\x11\x83\x32\x35\xd2\x17\x9d\x38\xcb\x45\x3e\x98\x97\x27\xdf\x13\xc4\x02\x95\xfb\x43\x5e\x32\x15\x81\x51\x07\x57\xc6\x27\x50\x4d\x1a\x56\xaa\x21\x33\xfa\x01\xa1\x11\xf9\xf0\x7a\x8a\x94\x81\x0a\xb2\x26\xb8\xa6\x24\xea\x18\xc3\xff\x50\xd9\x2e\x8b\x51\x42\x6d\xc0\xe3\x90\x21\x24\xf5\x1a\xa8\xec\x21\xa2\x6e\x19\x02\x37\xb3\x92\x72\x67\xe9\x54\x8a\x43\x55\xe8\xa6\x06\x4a\x11\x95\xf6\x57\x9d\xaa\x35\x8f\xfe\x1f\xb9\x7a\x47\x4d\xae\x2b\x5d\x05\xa7\xcc\xb1\x46\xf5\xcb\xce\x83\x23\x35\x2b\x59\x84\xd8\x3e\x5d\x09\xd5\x67\xbb\x81\x4e\x5d\xd4\xfd\x50\x5f\x31\xfa\xe8\xa4\x2c\x4a\x89\x2e\xa3\x13\x02\xad\xd1\xa9\x1e\x5f\x64\xd9\x11\x96\x7e\xf4\x2a\x8d\x90\x5c\x3f\x15\x9e\x15\x08\x2b\xc8\xc6\xb6\x75\x30\x42\x97\x11\xfc\x23\x5d\xa3\x87\xb6\x84\x99\x23\x50\xd3\xd1\xb2\x75\xd7\x07\xe1\x58\x95\xa4\x2f\x64\x16\x7c\x49\x34\x94\xd0\xaf\x91\xda\xf6\x36\xfb\x9f\xee\x17\x48\x85\xaa\xfe\x1c\x19\x43\x67\xe2\x53\x54\x55\x73\x0f\x41\x75\x9c\x3a\xb4\x3a\xda\x8c\x4a\x9b\x9b\x8e\xce\xbf\xca\xce\xac\xa4\x41\xc8\x8d\x6e\x13\x64\x3f\x08\x95\x11\xdf\xa2\x2d\x57\x39\x54\x32\xa9\x22\x40\xc0\x81\x96\x82\x7e\x25\xdb\x3b\x26\x4e\x85\x8d\x95\x58\xfa\xf3\x0c\xed\x21\xa1\x4a\xdf\xc7\x7b\x9f\x66\x17\x43\x7b\x65\x3d\x50\x85\x66\x2a\xcf\xc4\x40\x51\x52\x2d\xcd\xb5\x8a\xd6\xa6\x18\x25\x5a\x5b\x83\xab\x99\x52\x43\x15\xc1\xfb\x43\xde\x67\x16\x0f\xf5\x02\xb0\xcf\x06\x80\x1f\xf4\xaf\x43\xe2\xfe\x85\x68\xe6\x8e\x89\xfe\x04\x69\x9f\xd9\x80\xe7\x3f\x90\x30\x26\x13\x90\xbf\xc7\x53\xf7\xde\x8d\xbd\xc0\xc7\xbd\x1b\xfe\x65\x16\x15\xfb\xcc\x01\xc6\xc4\x8f\x11\x79\xb7\xbe\xb2\xdc\xdc\x22\x91\xd1\xb2\xd3\xa1\x7d\x76\x02\xcc\x82\xb9\x3f\x91\x06\xe2\xc0\x45\x65\xd1\xd1\xa3\xaa\x88\x32\xc3\x21\x30\x9e\x87\x21\xf1\xc7\x8f\xdc\x36\xc1\xb1\x6c\xda\x79\x2e\xad\x72\x1b\x14\x76\xa7\xc0\x23\xf1\xa5\x89\x3c\xf3\x51\xe5\x30\x52\x3b\xd4\xe5\x66\x67\xc0\x75\x18\xfc\x45\x7c\x5c\xbb\x61\x2d\x74\x85\xb6\xf6\xd9\x39\x10\x91\x71\x91\xab\x32\xa4\x5e\x57\xdd\x49\x13\x24\x62\x52\x4b\xe0\x5f\x00\x13\xcf\x25\x21\x89\xbc\xa8\x42\x0b\xe8\xf7\xc9\xdc\x66\x04\x8c\x83\xd9\x63\xe8\xdd\xde\x95\x09\x47\x79\xfa\x63\x67\x69\x96\x89\x42\x80\xa4\x2e\xc8\x0a\xb6\xcf\x07\xc0\x0d\xb9\xf7\x7c\xcf\x27\x08\xc2\x89\xe7\xbb\x53\x78\xfe\xc4\x1b\xbb\x71\x10\xea\xf9\x4b\xa9\x66\x41\xce\x6d\x60\x4a\x6e\xe2\xfe\x2c\xf0\xfc\xd8\xf3\x6f\x31\x09\xe6\xd7\x53\x02\xd7\xbf\x9d\x12\xfc\x6f\x1e\xc4\x2a\x83\x72\x61\x90\xa7\x22\xe5\x5c\x54\x2f\x4c\xfb\xdc\x41\x71\xe7\xc1\xe2\xcb\x67\xae\xaa\x75\x55\xd5\x4b\xb3\x13\x20\x0a\x6e\x62\xdc\x3d\xce\xee\x88\xaf\x48\x55\x45\xa2\x3a\x8a\xc5\x10\x08\xc9\xad\x17\xc5\x24\x24\x13\x43\x3e\xfb\x3d\x91\x4f\x1c\x92\x44\x97\xcf\x53\xe0\xde\x1d\x87\x81\x6f\x9a\x4a\x9d\xf2\x0c\x98\x90\xdb\x90\x10\x31\xdd\x31\xd7\x00\xab\xd9\x33\xd9\xe7\xe7\xc0\x6c\x3a\x8f\xfa\xf7\x9e\x3f\x8f\x4a\x07\xe5\x75\x4d\xa5\xb3\x90\xbd\x14\x27\xe6\xf9\x05\x10\xcd\x67\x24\x8c\xc6\xa1\x37\x8b\x11\xff\x0c\x3a\xe2\xe8\xa6\xf8\xa9\xce\x37\xaa\x59\xdc\x85\x84\xe4\x36\x5c\xea\x7b\x1a\x9b\x8b\x01\xe0\x8e\xe7\x31\x81\x3b\xce\x75\xa0\x03\x19\xca\x55\xb5\x89\xb3\x2f\x6c\xe0\xde\x1b\x87\x41\x25\xd5\xaa\xca\xe1\xf8\x48\xd9\x7e\x99\x91\x03\xcc\xbc\xe9\x38\x0c\x7e\xaa\x66\x9c\xa0\xc5\xa5\x03\x4f\x40\x83\xa0\x17\x27\xf9\x7c\x93\xc9\x94\x60\x12\xc4\xc2\x99\xca\xa1\x9d\x0f\xcc\xa5\x85\x4c\xbc\xe9\xd4\x6d\x3a\xce\x2c\xf2\x51\xa7\xd5\xec\x04\x3e\x29\x1b\x62\x6d\x3e\x2f\xce\x72\x6a\x44\xe3\xf9\xd4\x5c\x6b\xb5\x3d\xa0\xd9\xb5\xdb\x17\xe7\x40\x51\xf1\x5f\x2c\xb4\xa4\x72\x71\x20\xaf\x0e\x1a\x27\x39\xfb\xe2\x02\x78\x98\x4f\x6f\xdd\x10\x37\xa1\xcb\x14\x2c\xf0\x73\x40\x37\x8c\x49\x58\x04\xc7\xee\x63\xd8\x1e\x7c\x80\x45\xbf\xc9\x7c\x5b\xf5\x72\x14\xa8\x23\x3d\xea\x9d\x3b\xbd\x51\x20\x25\xa2\xbc\xa4\xb1\x40\x6b\x78\x39\xdc\x68\xd0\x84\x2b\x78\x29\xdc\x8c\x0a\x82\x96\x7e\x52\xda\xfb\x92\x9f\x23\x75\xc3\xfb\xdf\x9c\x44\x15\xad\x92\x37\x29\xdc\xd7\x66\x5b\x6f\x8f\x1c\x60\xea\xc6\x9e\x8f\xb1\x3b\xf3\x62\x77\x8a\x29\x89\x63\x12\xc2\xc5\x4f\x2f\xbe\xc3\x6d\xe8\x3e\x10\x76\x1d\xc9\xc2\xed\xf7\xc5\xa5\x4a\xbd\xf7\xb2\x47\x27\xed\x58\x45\x85\x75\x94\xcb\xa9\x36\xac\x61\x3b\xd6\xd8\x0b\xc7\xf3\xfb\x9b\x29\xf9\x3b\xef\x8c\x92\xe4\x73\xc0\xd3\x76\xc0\xd8\x9b\x4e\x48\x07\xd6\x97\x9c\x3b\x6b\xc7\xaa\x6e\x89\x5f\xea\xe4\xec\xd1\x79\x3b\x66\x98\x97\x8c\x7b\x1d\x3c\x14\x19\xfc\x0e\xb1\xb4\x6d\x97\x5c\xf6\xe8\xc2\x04\x5a\xa0\x1c\x29\x2d\x83\xbc\x7b\xb2\x50\xdb\x26\x19\xd2\xc8\x80\x34\xe6\xeb\xa1\x28\x0f\x8c\xd7\x66\x05\x21\xaf\x3a\xce\x60\x60\x40\x23\x0d\xd6\x15\x4b\xc1\x0f\x2b\x97\xdd\x52\x97\x9c\x81\xdd\x8e\x21\xd8\xc6\x95\x5c\x8f\x61\x62\x3f\x69\xb2\x2c\x27\x99\x19\xc8\x44\x7d\xa2\x63\x84\x20\x44\x5f\x5c\x9a\xd0\xcb\x6a\x27\xee\x0c\x4c\xf4\xf7\x9a\x65\xa9\xdc\xea\xd5\x0f\x32\xce\xc0\xc4\x7a\xaf\x91\xa4\x76\x1c\x13\xe3\x3d\x7d\xa2\xda\xc1\x4c\x54\xf7\x74\xc9\x12\xd9\x92\x0c\x45\xfd\xf5\x4a\x81\x69\x62\x3a\x89\xef\x2a\x65\x92\xeb\xb5\xb8\x25\x6d\xec\x26\xce\xc0\x44\x73\xbf\xa2\x12\x4c\x26\x0a\xd3\xc4\x74\x19\xe9\xd8\x26\x92\x07\x95\x35\x54\xb4\xb5\xf5\x08\xe7\xd8\x26\xc2\x07\x35\x79\x2d\xaf\xd8\xdb\xf1\x4c\xe4\x0f\x34\x12\x5b\x6a\xec\x27\xa0\xa6\x42\x08\x34\x09\xfc\x0a\x9e\xa9\x10\x82\x36\xae\x7c\x82\x99\x37\xbb\xf3\x69\xec\xcd\xa6\x79\x0f\xa3\x9c\x79\x12\x66\x75\x04\x7c\x63\x07\xb1\xa4\x72\x3d\xe2\xd8\xa6\x32\xe0\xde\x44\x71\x7e\xd8\x62\x7c\xb3\xe4\xf5\xb1\x25\x3b\x3d\xab\x46\x39\x06\x6a\x2a\x87\xb9\x61\x0b\x36\x9f\xe0\x1d\xdb\x54\x06\x73\xc3\x16\xdc\x86\x65\xaa\x85\x79\xdb\x16\xdc\x02\xe8\x98\x0a\x62\xde\x22\x92\x6d\x78\xa6\x82\x78\xd4\x07\x5b\xde\x1b\x35\xde\xe9\x39\x8e\xa9\x18\xe2\xbb\x20\xf4\x95\x8b\x31\x7e\x43\x5a\xbf\x5a\x73\x1c\x49\xfc\xe8\xde\x9d\x4a\xf3\xe8\xce\x0d\x67\x88\xbe\x76\xd1\xe1\x38\x43\x2d\x88\x6b\x16\x8c\x96\x5b\x1a\xc7\x39\x6d\x43\xd3\xc9\x45\x2b\xda\x59\x1b\x9a\x51\x2c\x5a\x21\xcf\xdb\x20\x75\x52\xd1\x8a\x76\xd1\x86\x66\x12\x8a\x56\xc4\x51\x1b\xa2\xb1\x23\x6b\x83\x3c\x19\xe8\x21\x89\x7a\x62\xe0\x28\xe5\x65\x7c\xfd\x2a\x89\x63\xd9\x5a\x2c\x5d\x47\xa6\xbf\xd3\x65\x67\x42\xe7\xc4\xd1\xe2\x10\x0d\xeb\x58\xdb\x62\x7a\x49\xe0\x9c\xe8\x8b\x80\x18\xc4\xa7\x0d\x49\x5f\x09\x9a\xbe\x4c\x21\x5b\x0b\x9c\xbe\x14\xb4\xdd\x59\xd9\x9e\xf1\xf3\x53\xa2\x6b\x38\x4e\xf4\xe5\xd0\xec\xcf\x0a\xb3\xc6\xf9\x3a\x47\xd0\xb3\xbf\xda\x99\x51\xab\x7a\x57\xd7\x91\xd6\x7a\xb6\x1b\xfa\xb1\xab\xf2\x4d\x59\x19\x49\x01\xa3\xa7\x78\x6b\x27\xd6\xfa\x86\xd2\x19\xea\x19\xce\xfb\xb0\x23\x24\xdf\x1a\x95\xd7\xec\xc3\x86\x7a\x6a\xfb\x86\xb3\xda\x37\xe3\x6b\x18\x67\xa8\x27\xb7\xae\x07\xbb\xd2\xdd\x65\x28\x48\x7a\x72\xd7\xbb\xaf\x52\xac\xcc\x48\x7a\x72\xeb\xfa\x2e\x45\x49\xcd\x70\x7a\x72\xeb\x3a\xae\xcf\x90\xf4\xa4\xd6\xf6\x5a\x9f\xbe\x00\x70\x86\xe7\xc0\xc4\x7b\xf0\x22\xa5\xc3\xe2\x25\x25\x2b\xb4\xf6\x8f\x3d\x9c\xa1\x9e\xd6\x8d\xfe\x4a\x6a\x5a\xde\x67\xf1\xde\xaa\x3e\xbd\x9e\xda\x9f\x77\x55\xf5\x97\x14\xce\xa9\x9e\xd2\x9f\xf7\x54\x4d\x24\x3d\xaf\xbf\xd8\x51\x35\xe1\xf4\xe4\xfe\x5a\x3f\xd5\x44\xd3\x13\xdc\xd0\x4d\xb5\xbc\x60\x73\x4e\xf5\x04\x57\x7b\x29\x56\xb7\xc6\x97\x9e\xce\xa9\x9e\xd4\x8f\x5f\x0b\xad\xe6\xd0\xff\x03\x00\x00\xff\xff\x37\x7a\xd8\x72\x4d\x2a\x00\x00")
+
+func fontsSmshadowFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSmshadowFlf,
+ "fonts/smshadow.flf",
+ )
+}
+
+func fontsSmshadowFlf() (*asset, error) {
+ bytes, err := fontsSmshadowFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/smshadow.flf", size: 10829, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSmslantFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x5a\x6d\x4f\xdb\xc8\xf7\x7d\xef\x4f\x71\x5e\xa0\x7f\x89\x44\x98\xd8\x84\x40\x24\x84\xe2\x26\x06\xac\x0d\x71\xd6\x49\xda\xad\x64\x69\x9a\x16\x53\xa2\x0d\x09\xca\xc3\xae\x2a\xf9\xc3\xff\x35\x8f\x7e\x9a\x31\xec\x4f\xaa\x1a\x04\x33\x67\xee\xdc\xb9\xe7\xce\xb9\x77\xf2\xbc\x7e\xf6\x96\x27\xb8\x44\x17\x6e\x17\xee\x25\xdc\x0e\x3a\xf0\xbc\xae\x7b\xe9\xcc\x5e\x67\xeb\xe5\xe6\x80\x1f\xbf\x71\xbf\x4e\x37\x1b\x0c\x5f\x96\x6f\x6f\xe9\x7a\x8d\x1e\xe9\x5f\xa0\x8d\x1f\xcb\x7d\xfa\x84\xed\x06\xb3\xd7\xe5\x7a\x8d\xff\x03\x1f\xef\x84\x9b\x9f\xeb\xe3\x53\xba\x47\x38\x8b\x30\x5e\x1e\x56\x9b\xb6\xeb\x3c\xaf\x7e\xad\xd3\x03\x76\xe9\x3a\x5d\xee\x53\x78\xe7\x2e\xda\x6d\xb8\x1e\xfc\xe3\x2f\xb8\xfd\x7e\xd7\x99\xa6\xbb\xd7\xd5\x7e\xbf\xda\x6e\xb0\xda\xe3\x25\xdd\xa5\x3f\x7e\xe3\xd7\xea\x9f\x74\x83\xc3\x16\xaf\xdb\xa7\xd5\xf3\x6f\x1c\x5e\x56\x7b\x3c\x6f\x37\x87\x33\x2c\xf7\x58\x6f\x37\xbf\xd8\xe7\xe1\x25\x75\xf8\x80\x55\xba\xfb\xb4\xc7\x66\xf9\x9a\x32\x8c\xb7\xf5\xf2\xa7\x30\x70\x89\x9f\xdb\xd7\xd7\x74\x73\xc0\x7a\xb5\x49\xcf\x1d\xe7\x51\x8c\x7e\x62\x9b\x9b\x2e\x8f\x6b\x7c\x3e\xee\x0e\xdb\x0d\x6e\xf6\xdb\xf5\xf1\xb0\xda\x6e\x06\xe9\x72\x77\x78\x59\xaf\x36\x7f\x9f\x6f\xd2\xc3\x2d\x5c\x8f\xf4\x7b\xcc\x90\x95\xd8\x1d\x36\xe9\xbf\x78\x5b\xee\x96\xaf\xe9\x21\xdd\x39\xfb\xe3\xdb\xdb\x76\x77\x10\x80\x77\xe1\x3d\xdb\xeb\x72\xf3\xc4\x7e\xfc\xba\xda\x9c\x03\x8f\xcb\xdf\x58\xae\xf7\x5b\xfc\x48\xb1\x5f\xaf\x7e\xbd\x1c\xd6\xbf\xf1\xaa\xac\x78\xde\xee\xf0\x23\x3d\x1c\xd2\x1d\x8e\xfb\xd4\xd9\x3e\x73\xf8\xe7\xe3\x7a\xdd\xfe\x77\xf5\x74\x78\x21\x7f\xa7\xbb\x0d\xd9\xbf\x1e\xf7\x2f\x58\xae\x0f\xe9\x6e\xb3\x3c\xac\xfe\x49\xf7\x67\xf8\x71\x3c\xe0\x29\x7d\x5e\x1e\xd7\x07\x6c\x8f\x87\xb7\xe3\x81\xed\x7c\x12\xcd\xf1\xf3\x65\xb9\xf9\x95\x3e\x9d\x3b\x0e\x00\x9c\x0c\xd8\xc7\x09\xd8\xc7\x09\xd8\xc7\x09\xd8\x07\xfb\x1f\x03\xfe\x47\x4a\xd9\x07\x01\x19\x38\x20\x94\x60\xe0\x9c\xd2\x16\x1f\xaa\xc6\x50\x50\xf6\x5b\x64\x68\x0d\x9c\x8c\x64\x44\x03\xe4\x63\xc0\x91\x28\xe5\xbf\xa3\x94\x30\x40\xca\x11\x81\x73\xf6\x8b\x81\xc3\x7e\x14\x7f\x13\x2b\x51\x52\x9c\xcc\xe7\x11\x66\xc4\x29\x6d\xdf\x0c\x1c\x22\x27\x11\x6d\x84\x30\xf5\x94\xb6\xd8\x54\xf6\x1b\x86\x01\x86\x4b\x70\x4a\x5b\x12\x47\x22\x72\x5b\x38\x2a\x07\xa2\x7c\x97\xb7\x6c\x0e\xd8\xe4\x8c\xfd\x9d\x19\xa0\x67\xa9\x55\xd8\x46\xf9\x36\xc5\x26\xf9\xdf\xa5\x8d\xc2\x53\x72\x75\xb6\x43\xb6\x38\xb8\x81\x4e\x46\xb3\xc2\x40\x31\x2d\x43\xc6\x3f\x85\x6f\xa9\x70\xae\xd8\xb6\x1c\xc8\x7f\x9d\x0d\x9c\x5b\xd0\x1b\xbe\xa6\xb4\x47\x2f\xc8\x47\x50\xe1\x4b\xe6\x3f\x4a\xd5\x31\x15\x4c\x17\xa3\xd5\x7f\xa5\x2d\xe4\xce\xa5\xdc\x05\xcc\x11\x44\x47\x81\x6d\xb6\x74\x66\x7e\xae\x22\x50\x72\xb7\x43\x6f\x04\x35\xb7\x4b\x9f\x23\xe1\xce\xe1\x7b\x4f\xa8\x3c\xf5\xd2\xc0\x81\x83\x1b\x40\xf9\x52\x02\x96\x8c\x52\xf1\x94\x51\x70\x57\x12\x19\x3d\x84\x96\x00\xf3\xd1\x54\x8d\x96\x86\xe2\xc6\x36\x5a\x0e\x26\xe2\x70\xb8\x6b\xb5\x67\x4b\x86\x6a\x58\xa2\x9d\x4f\x91\xbc\x0b\x2b\x82\x17\x62\x68\x7d\xff\xea\x34\x1a\xf7\x2f\xb7\x7f\x0a\xca\x8e\x93\x81\x31\x2f\x98\x9d\x59\xf0\x3a\x12\x7a\x26\x36\x55\x1b\x28\x23\x53\x1c\xb0\xe0\x47\x95\xec\xc6\x31\xe0\x63\x32\x92\x2f\x28\xac\x1e\x38\x37\xdc\xc5\x48\x68\x52\x8a\x5c\xc9\x67\xe9\x0d\x2a\xf9\x5f\xb1\x87\x31\x74\xe0\x24\xdc\x45\xb8\xc5\xad\x70\x41\x8e\x23\xb6\xc5\xfd\x2d\x50\x88\xc1\x5c\x4a\xf3\xdd\x53\x15\x75\xa0\xf8\x4e\x38\x34\x3d\x13\x90\x89\xa4\x7b\x29\xae\xd8\x38\x15\x57\xec\x07\xb6\x7c\x46\xb3\x7a\x5c\xe9\xd1\x2d\xe9\x66\x31\xda\x12\x00\x2a\x02\x44\x08\x10\xb9\xcd\x4a\xbe\xa9\x63\x27\xc2\xa7\x44\x9d\x9d\x3d\xc2\x75\x28\x42\x51\xd1\x82\x6d\x19\x6d\x26\x6e\xc5\xee\x53\xca\xa3\xd2\x66\x77\x7e\x6f\xc8\xab\x83\x79\x45\x86\x31\x29\x67\xd6\xaa\x39\x90\x79\x04\x0d\xc6\xcb\x18\xa3\x54\x12\x94\x2f\xf3\x31\x73\xe4\x66\xcf\x6e\x20\x77\xcb\x73\x73\xdd\x1c\xe9\x78\x71\x1d\xb1\x63\x52\x6e\xaf\xf2\x5f\x65\x2b\x66\x2f\xe3\x80\xa4\x6c\x46\x0b\xbc\xad\x6c\x39\xe7\x92\x36\x2c\x53\x7e\x82\xf6\x53\x66\xf0\x53\x31\x9c\x65\x34\x53\x9d\x44\x8d\x21\x51\x09\x20\x45\x36\xcb\x21\x5b\xb1\x35\x85\x1b\xb0\xcf\x20\xb1\x99\x4b\xdf\x09\x37\xca\x88\x6d\x39\x5f\x4a\xf3\x04\x48\xf3\xeb\xd4\x1e\x9c\x79\xca\xd1\xf1\x40\xf3\x80\x30\xb9\x51\x45\x50\x86\x4c\x5e\xc0\x19\x3f\x02\x36\x30\xb3\x4e\x29\xcd\x2a\x4d\x2c\xcc\x25\x59\x55\x3a\xd4\x8e\x9b\x4d\x11\x5e\xb8\x05\xbb\xe5\x6c\x71\xa8\x77\x96\x20\x11\x8b\x31\xa7\x89\x53\x26\xf5\x40\xd7\x09\x55\x04\x61\x2e\xb2\x6a\x51\xab\x42\x96\xb3\x5e\x05\x3a\x4a\x8e\x56\x42\x44\x0a\x25\x79\x5c\x90\xf9\x38\x4f\xe9\x75\x44\xb1\xb8\xe2\x4e\x81\xc8\xea\x82\x20\x4c\xd4\x64\x24\xcb\x84\xd4\x10\x72\xb1\x7c\x41\xd4\x3e\x8a\x02\xa5\x28\x63\xf0\xa5\xae\xc4\xd4\x04\x50\x71\x2f\xf2\x64\xaf\x52\x7d\x03\xc9\x45\xd4\xd3\xf3\xba\xbb\x0a\x16\x88\x88\x4c\x0a\x64\xab\xa4\x24\x2a\x43\x50\x26\x3c\xb1\x70\x3d\x81\xe5\x37\x18\xda\xec\x32\xad\x23\xe6\x8c\xd1\xf9\x59\x0b\xc4\x8a\x79\xfa\x42\x85\xcc\xd2\x7c\xcf\xe2\xaa\x2f\x90\xac\x69\xd7\x32\x33\x96\xc2\x35\xbf\xe9\x6d\x1a\x2c\x97\xb3\xc8\x55\xb6\x3a\x79\x75\xf4\x92\x50\x85\x8c\xa9\xa2\x53\x58\x8b\x4f\x32\x6f\x24\x34\xa9\xe7\x8d\x41\x5e\x7f\xd8\x8d\x90\xfb\x87\x4c\x60\xf8\x24\x37\x45\x0b\xbb\xaa\xa9\x8f\x77\xf6\x5f\x3a\x23\x3e\x2a\x29\x30\xa9\xbc\xb4\x21\x1b\x9e\x97\x32\x6d\x63\x64\x42\x15\x3d\x16\x85\x84\x02\x94\xc1\x46\x19\x29\xb2\x32\xaa\xda\xa8\xf6\x49\x9a\xa3\x57\x58\x06\x11\xe3\x4a\x98\xd7\x39\xa3\xea\x00\x3e\x30\x93\xd7\x56\x66\xd0\x92\x85\xa1\xf9\x60\x3d\xfc\xac\x74\x59\x99\x8c\xe0\x99\x86\xef\xba\x18\x15\xf5\x03\xa7\x05\x5d\x64\x0e\x78\xe9\x73\x7e\x9f\x08\xf1\x44\x4a\xc9\xa6\x58\xb8\xd1\x4a\xe1\xc6\xd6\xae\x0c\x94\xc1\x58\xd0\x06\xa8\x14\x6e\x2a\xc2\x75\xb2\x54\x99\xb8\x5a\x1c\xb1\xe9\x09\xe1\x75\x6c\xc2\xc1\x8a\xe5\x77\x59\x74\xe7\x6c\x54\x84\x6c\x23\x6b\x50\x30\x54\x31\x93\x55\xc4\x7c\x8a\xb8\xd6\xf1\xce\xa5\x28\xa7\x40\x4e\x79\xff\x1e\x55\x33\xd4\x1a\xf8\x6e\xcd\x7a\xa6\xd1\x89\x55\xfd\xd6\x47\x6b\x91\x67\xcc\xa8\xba\xbf\x20\xc4\x66\x4b\x9e\x91\x2c\x41\xb8\xf4\x2b\x64\x50\x31\xcf\xed\x75\x80\x49\xd4\xfe\x1c\x07\xfe\x1f\x98\x4d\xfd\x61\xc0\xb1\xde\x6b\x8c\xb8\x3d\x17\x08\x27\x5f\x82\x78\x1e\x8c\x10\xfc\x35\x1c\xfb\x8f\xfe\x3c\x8c\x26\x78\xf4\xe3\x3f\x3e\x94\x3c\xdd\x9e\x07\x0c\x83\xc9\x1c\xb3\xf0\x7e\x52\xc8\x37\x84\xe4\x3c\x95\x39\x9f\xa8\x29\x17\xc0\x34\x5a\x4c\x46\x85\x39\x79\x53\x85\xf2\xda\x84\xb7\x30\x44\x9d\x7e\x46\x6b\x2c\x73\x7b\x5d\x60\xb8\x88\xe3\x60\x32\xfc\xa6\x51\x98\xd4\xcc\x84\x30\x39\x57\xb9\x08\x22\xbc\x84\xb6\x41\x15\xe5\x12\xf8\x16\x4c\x72\x33\x94\xbc\xa3\x99\xee\x15\x21\xef\xeb\xe4\x5d\x1d\x0d\xd0\x03\x3e\xc7\xd1\x1f\xc1\x04\x9f\xfd\xd8\xc4\x2e\x6a\x64\x97\xdb\xbb\x02\x66\xc1\x90\xfb\xba\xe6\x04\xe6\x2e\x2a\x0f\x9e\x69\x34\xa1\xce\x84\xdf\x4f\x69\x61\xf5\x6b\x60\x14\xfa\x41\x1c\xcc\xc2\x99\xa3\x03\x5f\xc7\x3d\x3f\xed\x13\x79\xde\x27\xe5\x50\x73\x7b\x7d\x60\x18\x4d\xbf\xc5\xe1\xfd\x43\x7e\x78\xa2\xa3\x24\x6f\x00\x2a\x32\x16\x11\x97\x76\xc6\x73\x1f\x95\x4c\x82\xa6\xd2\xc0\x71\xaf\x3a\xc0\x5d\xf0\x18\x4e\xc2\x49\x80\x28\x1e\x85\x13\x7f\x8c\x70\x32\x0a\x87\xfe\x3c\x8a\xd5\xbd\xa2\x64\x80\xb8\xd4\xa9\x4a\xcb\xc4\xc4\x49\xf7\xca\x05\xc6\xc1\xdd\xbc\x3d\x8d\xc2\xc9\x3c\x9c\xdc\x63\x14\x2d\x3e\x8f\x03\xf8\x93\xfb\x71\x80\x3f\x17\xd1\xbc\x14\xa9\xe5\x56\x07\x63\x8b\x2a\xd9\x73\xc5\xcf\x71\x3d\xf0\x0e\x62\x25\x5a\x4b\x8d\x8a\xd2\xad\xe2\x5e\x5d\x00\xb3\xe8\x6e\x8e\x87\x6f\xd3\x87\x60\x52\x49\xc5\xaa\xd1\xa4\x53\xb1\x7b\xd5\x05\xe2\xe0\x3e\x9c\xcd\x83\x38\x18\x59\x3c\x0b\xed\xd9\x76\x4b\x78\x96\x90\x24\x31\x78\xf6\x12\x78\xf4\x87\x71\x34\x31\x37\xb7\x2a\x39\xd6\xbd\xea\x01\xa3\xe0\x3e\x0e\x02\xb5\xb0\xbc\x37\xcf\xf9\x2a\x32\x82\x4f\x2a\x93\xae\x80\xe9\x78\x31\x6b\x3f\x86\x93\xc5\xac\xe0\x9a\x3c\x20\x65\x77\x0e\x39\x21\x38\x55\x09\x55\xc5\x4f\x6e\xf1\x35\x30\x5b\x4c\x83\x78\x36\x8c\xc3\xe9\x1c\xf3\xaf\x91\xb6\x22\x13\x3d\x1e\x2a\xea\xaa\xaa\x15\xfd\xca\xc4\x87\x38\x08\xb4\x2a\xc8\xd4\xa5\xd7\x32\x4c\xbd\xee\x00\xfe\x70\x31\x0f\xe0\x0f\x59\x2e\x72\xc4\xfd\x2f\xfd\x54\x12\xd6\xee\xb5\x0b\x3c\x86\xc3\x38\x2a\xee\x53\xab\x9f\x7a\xc1\x7f\x7e\x56\x4a\xb7\x1c\xc2\x03\xa6\xe1\x78\x18\x47\x5f\x73\x2f\xab\xf8\x03\x84\x36\xc8\xd3\x65\x35\xcb\xbb\xd7\x17\xcc\x84\xd1\x68\x1c\x60\x14\xcd\x1d\x94\x7b\x92\x25\x63\x59\x9a\x0b\x46\xe1\x78\xec\x3b\xc8\xfb\x97\x7a\x02\xa1\x2d\x3e\xec\xb2\xec\xba\x68\x12\xa8\xfe\xd5\x0d\x88\xea\x38\x95\xca\x13\xf7\xba\xc7\x22\x6b\x36\x5c\x8c\x1b\x49\x5b\x14\x83\x34\xc9\x7b\x5c\x95\x22\xdd\xbd\xbe\x02\x78\x2a\xf9\x18\x61\x15\x1b\x12\xe4\x9d\x31\xd9\x1b\x2b\x4b\x30\xf7\xfa\x1a\xf8\xb2\x18\xdf\xfb\x31\xee\x62\x5f\x64\xcc\x68\xc2\x00\xfd\x78\x1e\xc4\xba\x70\x16\x9b\xbb\x11\x3d\x77\xc9\x14\xc2\xff\x7d\x42\xde\x4e\x26\xa5\x9b\x44\x2d\xd1\x37\x2f\xf1\xe0\x8f\xef\x0a\xf8\x05\x78\xdd\x01\xca\x64\xb7\x8c\xf3\xa3\xd8\x2e\x90\xd0\xfd\x4e\x1d\x9a\x07\xb6\xb2\x7f\x26\x35\xbc\xde\x01\x8b\x9c\xc2\x16\x68\xab\xb0\x07\xdb\x26\xc4\x52\xc5\xbb\xfc\xcf\x45\x30\xab\x5f\xe4\x5a\x41\x31\x2e\x57\xaa\x00\xb7\xef\x01\x63\x7f\x1e\x4e\x30\xf4\xa7\xe1\xdc\x1f\x63\x1c\xcc\xe7\x41\x0c\x1f\x5f\xc3\xf9\x03\xee\x63\xff\x4b\x50\xa8\xbc\x64\x66\xe5\x0a\x4e\xe9\xb7\xe2\xc1\xf5\x2f\x9a\xf1\x38\x61\x6b\xca\xb5\x01\xaf\xdb\x8c\x37\x0c\xe3\xe1\xe2\xf1\x6e\x1c\xfc\x25\xaa\x37\x21\x05\xa8\x2c\xd0\x85\xd0\x34\xb6\x75\xdc\xfe\x65\x33\xf2\x3c\x1c\x8f\x84\xa5\x42\xe6\xf2\x37\x9c\x44\x5e\xec\x4d\xfa\xd5\xed\xf7\x9a\x91\x0b\xb7\xf7\x7f\x57\xc7\x6e\xff\xaa\x19\x3d\x66\x2c\xf4\x3f\x47\xe2\xd8\x4e\x4f\x5b\xad\xc1\xc7\xfa\xc1\x6e\xff\xda\x86\x1c\xa8\xbb\x2c\x2f\xeb\xf3\xee\x16\x7f\x60\x80\x22\x47\xad\x7f\xc4\x91\xfb\x16\xe4\xa1\x3c\x45\x9d\xed\xde\x6f\x32\x13\xda\x92\xb0\x5e\xa7\x63\x81\x0d\xca\xc1\x2b\x63\x57\x87\xae\xa8\x34\x6f\x0a\x97\x89\xd7\x71\x9b\xa1\xec\x71\x2b\xdf\x61\x6e\x4a\xd5\xad\xd7\xb1\xf1\x2a\x30\xc5\xad\x0c\xdb\x3c\x6a\x2d\xa0\x36\x72\x05\xf5\xc0\xaa\x56\x20\x02\x55\xc3\x96\xb8\xe0\x75\x6c\x2c\x0b\xeb\x59\x40\xa7\x01\x29\xb5\x6d\x97\x83\xd7\xb1\x11\x2c\xac\xba\x54\xf9\x54\x39\xb5\x09\xd4\xc6\xad\xf0\x43\xf9\xa0\x09\xd9\xc6\xab\xf0\x63\xac\xa5\xe5\x17\xbc\x32\x6b\xbd\x8e\x8d\x5b\xc1\xfc\xc1\x29\x14\x80\x54\x37\xb0\x59\x29\x94\x3f\x98\x54\x6b\x21\xaf\x63\xa3\xd4\xa4\x9a\xbe\xf2\xfc\x55\x48\x60\xaa\xe9\x4b\x0c\x2d\x5f\x06\xef\xda\xa8\x15\xd5\xa8\x05\x21\x12\x12\xa8\x32\x5d\x55\xdc\xc5\xd0\x75\x6d\xfc\x8a\x8c\xfc\x92\xa1\xd0\x80\x67\xe3\x57\x64\xe7\x97\x8c\x82\x06\x50\x1b\xbf\xa2\x8a\x4f\xa5\x47\x95\x3f\xb5\xb6\x37\x3c\x64\x78\xae\x8d\x5b\x91\x91\xb4\xff\xad\xf1\xe1\xb9\xac\x54\x58\x8c\xe7\xe1\x74\xcc\x24\x5c\xb9\xb2\x64\x27\x9d\xf1\xad\xdf\xf2\xc2\x48\x7e\xc1\x21\x9f\x6c\x23\x93\x34\x6d\x36\x67\x55\x6e\xe5\x25\x92\x10\xf5\xfe\xad\x1a\x6d\xaa\x39\x51\xb2\xcb\xc6\xa6\x85\x39\xa3\x50\x1d\x41\xf6\x37\x21\xcf\xb5\x91\x68\x61\xce\x28\x94\xab\xaa\xf7\x40\x6d\x44\x5a\x34\x64\x14\xaa\x63\xa9\x01\xd9\xb3\x71\x68\xd1\x7c\xf2\x1f\xea\x5f\x79\x9e\x8d\x51\xdf\x2a\xce\x60\xae\x90\x7c\x4a\xf0\xc5\x50\xec\x7a\x9e\x8d\x4c\xf3\x87\x28\x9e\x38\x86\xbe\x3b\xef\xfa\xd7\x7a\xba\x9e\xa7\x09\x34\x7b\xf4\xc7\x1a\x66\xf6\xe0\xc7\x53\xcc\xfe\xe7\x4e\x97\xe7\x75\x8d\xb8\xbe\x35\x17\x35\x3d\x9e\x78\xde\x65\x13\x9a\x35\x13\xd9\xd0\x7a\x4d\x68\xcd\x79\xc8\x06\x79\xd5\x04\xd9\x90\x85\xac\xfd\x4b\xcf\xbb\x6e\x82\x6c\x12\x0e\xcd\xb0\xfd\x26\xd8\xb2\x14\x95\x17\x9c\x50\xa4\xf6\xcd\x5f\x74\xcc\x90\x41\xe1\x82\x92\xef\x10\xfa\x79\xe3\xbb\x7a\x86\x3a\xab\x5e\x95\x02\xd2\x35\x42\xd6\xc4\x27\xac\x6f\x65\x5c\x74\x72\x28\xcf\x08\x65\x14\x9c\xa2\x56\x32\x3f\x91\x79\x17\x66\xaa\x54\xe5\x26\x55\xad\x77\x3b\x90\x99\x1b\x26\x9d\x29\xc2\x4f\x45\x9f\x19\xcd\xcc\x8d\xba\xc0\xa4\xba\xed\x28\xa3\xa4\xcd\x9b\x34\x09\xad\x7c\xcd\xc8\xbb\x30\xf3\x23\x6c\x94\xe8\x86\x9e\xb3\x77\x61\x66\x45\x55\x4d\xca\x0a\x85\x5a\x1f\xdd\xbc\x0b\x33\x17\x8c\x0a\xb2\xaa\xcc\x8b\x1d\xdd\xe2\x26\xcd\x3c\xa8\x4b\xc7\x42\xbb\x96\xe6\x0d\x76\xcb\xd7\x03\xbc\xae\x99\x0b\x4a\x33\x66\x99\xbc\xe5\xb2\x4c\x10\xe1\x3b\xaf\x76\x0d\x2f\x12\x5e\xd7\x4c\x81\x9a\x58\x34\xd4\xba\x54\x7d\xd9\xc1\xf0\xe5\x17\xaf\x6b\xe6\x43\x5d\x25\x16\xf8\x60\x7a\x8e\xf4\xba\x66\x3e\x54\xe5\x61\x89\x0f\x66\x20\x33\x1f\x3e\xa4\x0b\xcd\x5f\x69\xf3\xba\x66\x52\xbc\xaf\x0a\xad\x2f\x44\x5e\xd7\xcc\x0a\xb3\x26\xfc\xf0\xc3\x93\xd7\xbd\x02\x46\xe1\x97\x70\x56\x14\x82\xc5\x2e\x10\x35\x7d\xd5\xcc\xeb\x9a\x19\x51\x95\x81\x28\xbd\x2a\x13\xc2\xbc\x5f\x78\x7a\xe6\x48\x66\x22\x18\x54\x9f\x12\x7d\x0d\x4f\xb6\xde\xa5\x39\xfe\x6b\x72\xaf\x7c\x53\x5b\xd1\xcc\x1c\x30\xea\xbc\x4a\x64\x58\x21\xcd\xe1\x6f\x16\x78\x1f\x7e\x11\xf4\x2e\xcd\x64\xa8\x2a\xbb\x5a\xe1\x6c\x7f\x4a\xf6\x2e\xcd\xb4\xd0\x0a\x0f\xb9\x2c\x23\xa5\xfe\x6f\xfd\xcb\x00\xde\xa5\x99\x0f\xdf\x3e\xd8\xde\x22\xfa\x31\xe9\xac\xf4\x3d\x39\x86\xfd\xff\x01\x00\x00\xff\xff\xba\xc5\x6a\x59\xbf\x2f\x00\x00")
+
+func fontsSmslantFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSmslantFlf,
+ "fonts/smslant.flf",
+ )
+}
+
+func fontsSmslantFlf() (*asset, error) {
+ bytes, err := fontsSmslantFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/smslant.flf", size: 12223, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSmtengwarFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x55\x51\x6b\xdb\x30\x10\x7e\xd7\xaf\xb8\x07\x43\x1c\x70\xe4\xa6\x63\x63\x2d\xa5\x53\xc7\xd8\x5b\x1f\x06\x1d\xec\xc1\xa0\xc8\xb1\xd3\x78\x75\xed\x62\xa7\x0b\x85\xc3\xbf\x7d\xe8\xce\x92\xe5\xf4\x65\xdd\x5e\x07\x8d\x6a\xdd\x9d\xee\x3e\x7d\xdf\x97\x78\x57\xef\xce\x4d\x04\xef\xe0\x1c\xd6\x6b\x38\x83\xf7\xe2\xae\x6a\x5e\xe0\xae\x6c\xee\x8f\xa6\x83\xb5\x3c\x83\xfc\x05\x3e\x97\x75\xd5\x14\x06\x6e\xfa\xbc\xac\x6b\xb8\x7a\xcc\x8d\xda\x6e\x0b\xb9\x37\x5d\x57\xf5\x72\xdb\x3e\x5e\x8b\x9b\xc2\x3c\x1d\xca\x02\x76\x5d\xfb\x08\xb7\xd5\x43\x09\xdf\xbb\xdc\x34\x8b\x1e\xae\x9e\xed\x83\xea\xab\xa2\xec\xf7\xed\x51\xfe\x7c\xaa\x65\x63\x7a\x23\xef\xdb\x5f\xd7\x7e\xd4\xae\xed\x40\xdc\x96\x07\xb3\x6b\x9b\x03\xc4\xc7\x7d\xb5\xdd\x43\xd5\x27\x50\x35\x70\x78\xee\x9a\x04\x72\xd3\x97\x05\xb4\x0d\xdc\xb5\xf5\x43\x55\x36\x70\xb9\x14\x5f\xcc\xa1\xbc\x84\xf3\x8f\xf0\xb5\xcc\x61\x7d\x71\xf1\x41\x88\x48\xf1\x9f\x12\x69\xa4\x44\x16\xd1\x7f\x25\x52\xb0\x5b\x00\x70\xab\x12\x1a\x51\x47\x4a\xac\x10\x57\x1c\xa4\x68\x8c\x9b\x48\x09\x89\xcb\xa9\xb0\xb5\x47\xd3\x96\x02\x76\x0f\xdf\x6c\x97\x58\xff\x98\x4a\xa8\x39\x7f\x94\xa0\x51\x48\xdb\xcc\xee\x33\x7a\x44\xdb\x84\xf2\x19\x52\x43\xcc\x42\x2c\x9a\x6a\x02\x78\x63\x3b\x86\x4f\xb8\x57\x2b\x0f\x41\xca\x68\x5c\x60\x1a\x99\x82\xdf\x6f\x06\xdb\x3c\xd1\x69\x30\x42\x6b\x42\x0d\xb3\x10\xc7\x62\x1d\x30\xa0\x75\x10\xf7\x19\xce\x0d\x8c\x10\x99\x80\x84\x43\x9a\xb1\xc7\x7c\x26\x01\x17\xf5\x71\x9f\x19\xc1\x0e\x48\x4d\x91\xa2\x38\x86\xf4\xa8\x0d\xea\x25\x97\xe3\x54\xae\x21\xcc\x06\xf9\x89\x2a\xe9\xd8\x97\xe1\x26\x59\x44\x4a\x6c\x26\x9e\x08\x52\xc0\x23\x4b\x73\xed\xa5\x21\xd9\x79\x61\x5d\x89\x47\x54\x01\x8f\x72\x91\xbc\x92\xca\xe2\xb3\x75\x16\x1c\x9d\x75\x09\x00\x77\x47\xbe\x6f\x50\x0b\x4b\x98\xd5\x12\x54\x40\x0f\x0d\x5d\xcb\xb9\x5e\x4e\x18\x1c\x75\x41\x7f\x8d\x34\xf3\x67\x6d\x2b\xf4\x76\x04\x07\xe3\xe4\x94\x6b\x16\xa2\x1b\x8d\xb6\x9a\xf4\x3d\xbd\xdc\xc4\xfa\xc9\x4d\x7c\x62\x3b\x9b\xce\xca\x8d\xaa\xa2\xbf\x09\x06\xa3\xc1\x5b\x3c\xb3\x44\xc7\x6e\xae\x7d\xe6\xd6\x29\x4c\x21\x74\xbc\xd9\xd0\xa7\x70\x96\xf7\x89\x77\x09\x84\x68\xfd\xd9\x61\x18\x1c\x31\x78\x42\x4c\x50\xbb\x08\xa9\x9f\xa3\x59\xd2\xb4\xc1\x7d\xcd\xed\x97\xd7\x79\x69\x12\x81\x5d\x6e\x17\xf6\xb8\xd7\x47\x84\xe6\xe0\x95\xa4\x78\xdd\xe2\xbf\xd7\xde\xe6\x35\x16\x7f\xa0\xbb\xb2\xc6\x7f\x62\x34\x46\x3c\x84\x46\x0b\x1b\xbd\xd5\x68\xc1\xd9\xbf\x31\xda\x0c\x0d\x19\x2d\xb6\x46\xbb\x62\x5a\x69\x7a\xe4\x3f\x4a\x70\xa1\xfd\x05\xd3\x54\xbc\xd8\x2c\x4e\x5f\x74\xd3\x2b\xf1\x5f\x9e\x7e\x07\x00\x00\xff\xff\x7d\x58\x6d\xad\x2c\x08\x00\x00")
+
+func fontsSmtengwarFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSmtengwarFlf,
+ "fonts/smtengwar.flf",
+ )
+}
+
+func fontsSmtengwarFlf() (*asset, error) {
+ bytes, err := fontsSmtengwarFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/smtengwar.flf", size: 2092, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsSpeedFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x5a\xdd\x8b\xe3\xc8\x11\x7f\xef\xbf\xa2\x58\x0c\xe7\x21\xde\x6d\x4b\xfe\x0e\x73\x8b\x43\xc8\xc3\x41\x42\x02\x07\x79\x12\xf4\x68\xc6\xf2\x58\xc4\x23\x2f\xb6\x26\xb7\x0b\xfa\xe3\x43\x57\x77\x55\x77\x4b\x2d\x5b\xde\x5d\x72\x1c\x63\xed\x8c\xba\xba\x3e\x7f\xf5\xe5\xfd\x71\x9f\xe6\x23\x58\xc2\x02\x92\x25\x24\xfa\xa7\xf8\xfd\x4b\x51\xec\xe0\xf9\x1b\xfc\xf5\x98\xbf\xef\x0a\xf8\x47\x7e\xae\xcb\xea\x02\xa9\xdc\x2c\xe0\xe3\x47\x78\xce\x2f\xc5\x0e\x4e\x15\xfc\x7e\xcc\xab\x5a\xfc\x56\xbd\x1c\xdf\x77\xc5\x05\x7e\xfb\xfd\x9f\xf0\xf7\xbc\x2e\xab\x8f\x89\xd8\x97\xaf\xc7\xa2\x86\x73\x71\x2c\xf2\x4b\x01\xe9\xa7\x44\x9f\x4c\x52\xf8\xcb\xfb\x2b\x24\x9b\xcd\x5c\xfc\xab\x38\xbf\x95\x97\x4b\x79\xaa\xa0\xbc\xc0\xa1\x38\x17\xcf\xdf\xe0\xb5\xfc\x6f\x51\x41\x7d\x82\xb7\xd3\xae\xdc\x7f\x83\xfa\x50\x5e\x60\x7f\xaa\xea\x09\xe4\x17\x38\x9e\xaa\x57\xfd\x59\x1f\x0a\x81\x2f\x94\xc5\xf9\x97\x0b\x54\xf9\x5b\xa1\x69\x7c\x39\xe6\x2f\x86\xb1\x1c\x5e\x4e\x6f\x6f\x45\x55\xc3\xb1\xac\x8a\x4f\x42\xfc\xed\xeb\x97\x63\x5e\xe5\xb5\xbe\xed\xb4\x87\x7d\x79\xbe\x98\xbf\xfd\x59\x68\x0d\xc0\x47\xf8\xf0\x96\xbf\x96\x2f\x50\xbd\xbf\x3d\x17\xe7\x0f\xb0\x3f\x9d\x61\x5f\x1e\x0b\x28\x77\x45\x55\x97\xfb\xf2\x05\x0f\x8b\x1c\x00\xe0\x23\x5c\x0e\xa7\xf7\xe3\x0e\xf2\xe3\x1f\xf9\xb7\x0b\x3c\x17\xf0\x94\xff\x32\xc1\x43\xd5\xe9\x0f\x31\x32\x2f\xd5\x87\x02\x3e\x1c\xf2\xf3\xee\xf9\x98\x57\xff\xf9\xa0\x15\xf0\xe5\x5c\x56\xf5\x45\xcb\x90\x03\xfe\x76\x02\xcf\xef\x35\xbc\xe4\xd5\x2f\xb5\x26\x73\x79\x7b\xbf\x1c\x8a\x9d\x58\x1a\x0a\x87\xa2\x7c\x3d\xd4\x9a\xe3\x1c\x5e\x0e\xf9\x39\x7f\xa9\x8b\xb3\x58\x5c\xf9\xe3\x04\xaa\x53\x0d\x25\x9a\xa4\xac\x5e\x61\x57\x5c\x5e\x8a\x6a\x57\x9c\x2f\x22\x99\xe3\xb1\xb7\xfc\x2b\x4a\x0e\xc7\xa2\x7a\xad\x0f\x30\x2e\xbe\xd2\xcb\xbe\xd2\x2e\x0f\xf0\x27\xc8\x61\xff\xbe\x7b\x2d\x60\x9f\xbf\xd4\xa7\xb3\x48\x16\x48\x61\x57\xec\xf3\xf7\x63\x6d\x98\x7d\x3b\xed\x0a\x14\x9c\x4d\x25\x92\x25\xbe\x66\x54\xa9\xf9\x0b\xe8\x0a\xa1\xd9\x87\xd1\x68\x2b\xcc\x27\xe0\xc3\x68\x04\xf8\xa0\x3f\xf5\x03\x7e\xc2\x56\x98\x4f\xd8\x6e\x85\xc2\xff\xf0\x13\x40\xea\x4f\x00\xa9\x5f\x95\x4a\xea\x37\xc7\xea\xc1\x1c\xf5\x0e\x80\x82\xad\x50\x63\x68\xe0\x61\x2b\x54\x23\x1b\x69\x2e\xb1\x77\x40\xe7\x80\xc2\x43\x78\x4a\x29\x25\x41\x4a\x90\xfa\x4e\x50\x80\xff\x2b\xb9\x15\x92\x9f\xed\xed\xc8\x80\xa3\xd4\x22\xc7\xa4\x0c\xcb\x48\x42\x8d\x15\xc0\x03\x6c\x85\x04\x30\xdc\x13\x0d\xf3\x36\xe8\xf7\xf4\xe3\x58\x3d\x28\x89\x27\x34\x0d\xf3\x2a\x3e\x28\xa0\x53\x28\xb7\x77\x37\xdf\x0c\xe6\xe5\x31\x28\xc0\x37\xf0\x72\xc8\x64\xa3\xaf\x45\x5a\x8f\xb0\x15\x19\x52\xce\x64\x97\x84\x51\x9d\x51\x9c\x55\xd7\x56\x8c\x58\xd0\x8e\x84\x8a\x8d\x62\x2e\x93\x86\x45\xb0\xca\x69\x54\x13\xb2\x67\x1e\x1a\x68\x48\x66\x49\xc6\x25\x21\xbb\x8a\x51\x40\xa6\x69\xf4\xb5\x48\xd1\x98\x44\x53\xda\x0a\x68\x42\x53\x6c\xdd\x53\x70\xad\x31\xab\x24\x7b\x18\x75\x74\x8e\x85\x3f\x3b\x2a\x71\x1a\xf3\x9f\x94\xd3\x8a\xc4\x07\x69\x1c\xbc\xf5\xde\xb5\x1b\xd4\x43\x5b\xc5\xa4\x64\x15\xf7\x06\x00\x4f\x55\x71\x6f\x30\x82\x1b\x17\xb0\xe6\x41\x9f\x34\xae\x20\xd9\x13\x5a\x4c\xba\xcb\x1f\x83\xa8\x23\x3b\x87\x8a\x0b\x8d\xdb\xd8\xbb\xd8\xfd\x29\x68\xa4\xf9\x95\xaf\x6e\x5f\xcc\xc6\x39\x83\x54\xe8\xa4\x96\x84\x3b\x1a\x61\xd2\x46\x0c\x60\xcc\x1a\x06\xc9\xca\x6c\xe6\xb6\x9d\x03\x0d\x13\xb6\x58\x9b\x59\x41\x32\x7c\x9d\x18\x20\x0e\x5a\x64\x3a\x22\x20\x15\xc9\x31\x07\x83\xf5\x2c\x5b\xe8\x76\x43\xcf\x8a\x42\x5c\xa1\x57\xe2\x6d\xd0\x0c\xbc\xad\xeb\x12\xd6\x4e\x99\x52\x93\x7e\x6d\x07\x8e\x6e\x3e\xd1\x63\x19\x72\x02\x44\x1a\x74\xc0\x02\x14\x06\xaf\x65\xcf\x30\x64\xf0\x63\x2b\x32\xd4\x21\x64\x2a\xe3\xc8\x68\x07\x1c\xa2\xb4\xb2\x08\xcd\xfe\x35\x6a\xc3\x01\x63\x08\x52\x54\xe4\xa2\x46\xe9\xd2\x79\xe5\xd6\xe3\x97\x34\xa4\x24\x28\x7a\xad\x27\xe3\xb4\x14\xeb\x45\x9b\x52\xf0\x64\xe5\x61\xdb\x80\xd6\xb4\x55\x70\xc6\x6e\x15\xda\x47\xeb\xc8\x60\x24\x80\x34\x68\x89\x94\xd1\xcc\xfa\x40\xa3\x9a\xa8\x43\x03\xfb\x33\xfa\x86\x73\x0e\xb2\xb4\xef\xcc\x51\xc8\xf0\x7c\xd9\x3a\xb3\xb4\x3a\xd7\x32\x58\xeb\x65\x91\x70\x88\x73\x41\x8a\x06\x0e\xd0\x81\x5c\x74\x22\xd3\x00\x09\xe5\x19\xe2\xe4\x66\x64\xc6\x08\x61\x26\x05\x06\xa7\x10\x48\x7b\x09\x75\xf5\x62\xdc\x8a\x6c\x7b\x4b\x2f\x94\xdf\x3d\x75\x78\xfa\xb0\xa6\xe2\xc0\x6f\xa3\x56\x07\x6e\x90\xa0\x44\x9c\xa2\xfc\x6b\xd8\xb0\x5a\xe9\x07\x3d\xc7\x90\xa4\x8a\xc9\x98\x64\xa8\x20\x4e\x0e\x2e\x00\x26\x8f\x6c\x9a\x06\x1a\x12\x02\xf3\x7f\x94\x44\x90\xf6\xbd\xfa\x81\x00\x91\x73\x68\x47\x85\x74\x37\xa6\x7d\x52\x62\xe3\xb4\x28\x8d\x7a\xc9\xa4\x5d\x3d\x7a\x75\x85\x93\xa4\x71\x16\xd1\x84\x25\xcb\xe2\x48\x35\x57\x2c\xf2\x23\x89\x36\x1a\x2f\x5e\xf6\xa4\xfc\xf9\xc3\x89\x3e\x53\xd9\x77\xdc\x3f\x01\xbe\xbf\xd7\x9c\xad\x04\x68\x30\x70\x60\x0e\xf7\x23\xd4\x55\x93\xae\x9c\xf4\x64\x8f\x14\x00\xae\x02\x70\x08\x03\x72\xb8\x3b\x03\x3b\x01\xa0\xad\xa5\x7d\x94\xe4\x9a\x8d\xa4\xe0\xba\x46\x22\xa0\x02\x01\xa1\x90\x96\x4f\x4e\x36\x5d\xe4\xf2\xda\x01\x92\xac\x71\x9e\x49\x7e\x09\x1c\x62\x2d\x93\x6c\xc9\x0e\xfa\xb5\x4c\xde\x51\x55\x6c\x3b\x4d\x96\x09\x47\x32\x5d\x24\xe5\xf9\x28\xa4\x3c\x14\x8a\x19\xd0\xaf\xe8\x01\x38\x1b\x53\x05\x9c\x91\x4e\xd8\x6d\x14\xa5\xfd\xd8\x9d\x14\xf9\x0e\x42\xa2\x18\xc8\x77\x82\xd4\x1d\x90\x6e\x06\x1b\x5b\x20\xd8\x56\xd0\x34\x37\x5e\xfe\x67\x45\xde\x78\xf2\xf8\x21\xb4\xda\x86\xdd\x82\xfa\x77\xbc\x81\x6a\xd3\x00\x45\xe0\xff\xd4\x8e\xd8\x49\x4f\xc4\x00\x8b\xdc\x57\xce\x49\xf5\x29\x2c\xb7\xfb\xaa\x27\x1b\xb2\x98\xdb\x29\x52\x64\xa7\x7a\x8a\xe5\x0d\xca\x57\xed\x40\x9b\x44\xa2\x24\xb8\xd8\x26\x3b\xcd\xb0\xb4\x41\x9f\x05\xcc\x5e\x43\x06\xe5\xe7\xed\x1e\x64\x80\x8e\x99\x80\xf1\x09\x95\xec\xa7\x5d\x5b\xf7\x7a\x10\x35\x4c\xcf\x16\x60\x6d\xa6\x8e\x20\x93\x5f\xf3\x0e\xab\xeb\x15\x33\x4c\xa5\xb2\xe7\xdf\xce\xc1\x5d\x9b\xad\x54\xd8\x28\xfb\x0c\x73\x63\x64\xab\x15\x9b\xa0\x7b\x20\xa3\x1f\x01\xa2\x0c\x07\x78\xe5\x94\xec\xe7\xa1\xa7\x50\x55\xa1\xba\x42\x95\xf5\x04\xc6\x5d\x3a\x6f\x07\x15\xb7\x61\xec\x9e\x9c\x05\x22\x83\x02\x3f\xa2\xaf\x25\xc3\x4f\x9d\x64\x7c\x5f\x3c\x83\x0d\x2d\x49\x7e\x16\x05\x14\xbf\x93\xbc\x96\x01\x6f\x1c\x1e\x2b\x1a\x38\xf5\xe6\x5e\x82\x6b\x62\xd9\x32\x6c\x23\x59\x46\x6d\x1e\xa4\xa7\x78\xa5\xd1\xc5\xad\xe0\xb0\x9f\x2c\x39\x51\x4a\x76\xf4\xde\xc3\xde\xf9\x80\x44\x40\xc5\x23\x64\xf3\x6b\xbb\xf6\x8b\x0a\x82\x79\xd6\xa0\xcc\x67\x80\xc7\xde\x50\x69\x3b\x4c\xb4\x00\xb9\x8e\x2d\xa1\xd1\x5a\x51\x47\x20\x1b\xc9\xb7\x56\x28\xc3\xa4\x6d\x47\x1f\x35\xab\xe0\x8f\xdc\x74\x91\x17\x39\xd6\x9e\xb4\x75\x46\x76\xe1\x2c\xb2\x33\xa9\x93\x94\x70\x3f\xab\xcf\xdb\xf8\xa4\x4e\x66\x12\x1b\x65\x1a\x2c\x86\x13\xd7\x51\xe0\xbf\x5e\xfd\xc6\x40\xc9\x58\xa9\x4c\x75\x63\x82\xe8\x56\x2f\x01\x44\x62\xac\x1e\x2c\x6e\xda\xf9\xcb\xe0\x8e\xc6\x27\x01\x44\xe2\xae\x2a\xb2\x97\x8b\xa7\x61\xf9\xf1\xff\x2f\x48\x1f\x17\x7e\x1e\x72\x18\xd8\x6e\x59\x75\x8b\x67\xc7\x6d\xad\x44\x8c\x84\x92\xe5\xf4\x7b\x27\xfe\xc9\x32\xb9\x3f\x7f\x26\xcb\xb4\x15\x24\xae\x79\x0a\x8a\x9b\xee\xe4\x3d\x59\xce\x22\x72\x4f\xb0\xfa\xb4\x33\x63\xe0\xba\xd2\x66\xd8\xb1\x9a\x74\x60\xca\x12\x9b\xa3\xb2\x34\xf0\x28\x69\x22\xa7\x81\x20\xe8\xc8\x04\x26\x5b\x62\xb7\xb0\x15\x38\x03\x6b\xa2\x0b\x85\x64\xb9\x10\x36\xb7\x2a\x4b\xcf\x0a\x17\xac\x26\x94\xdb\x8a\xb4\x00\x2b\x59\x2e\xe3\x48\x60\xce\x28\x1e\xc8\x75\x91\x20\x59\xae\x44\xa8\x19\x09\x64\x0f\xeb\x01\x0d\x34\xee\x89\x26\x64\x1e\x81\xb5\xf0\xdc\x92\xbd\xd2\x60\xc3\x88\xd0\x81\x6b\xe4\x51\x97\xf9\x8d\xb3\x8e\xab\x6e\xf0\x5f\x19\xe3\x18\x32\xd6\x90\xb3\x93\xba\x1b\x80\xcc\x4d\x70\xcd\xa8\x8d\x31\x38\x59\x4d\xfd\x74\x8d\xa0\x83\x95\xa1\xca\x30\x34\x82\xa4\x39\x02\xe8\xaa\x75\x95\x38\x00\x07\xce\x81\x3c\xb8\xa4\xd1\xa5\xeb\x62\xf0\x50\xda\xdf\x42\xa0\x5d\xf4\x5f\xa4\x3f\xc6\x6c\xdf\x3a\x73\x95\x4e\x9b\x10\xb5\x22\x6e\xf7\xe0\x57\x3a\xc9\x6a\xde\xa3\x4a\x00\x4f\x95\x1a\x6e\x48\x95\xd8\xf9\x1b\x55\xda\x5c\x18\x57\xe5\x22\xd6\x0d\x05\xfb\x0f\x16\x25\xae\xca\x65\xa4\x31\x90\x5c\xb2\xc9\xd8\xde\x2e\x59\xad\x3a\x65\xb3\xe4\xf4\xc9\x1d\x83\x5d\x9b\xf5\x8e\x1b\x93\x95\xf6\x50\x70\xdb\x0b\xe0\x61\x6b\xb8\xb4\x68\x19\x03\x8f\x6e\x84\x17\x98\x0d\x05\x96\x5d\x5f\x5c\x3d\xba\x36\xde\x67\xc6\xca\x46\x41\xd1\x5e\x31\x59\x27\x3e\xc2\x70\x95\x7f\x63\x90\xf8\x89\x2a\xb0\x10\x95\xd7\x69\xd0\xcb\xe1\x46\xd3\xce\xdb\xc7\xec\xbb\x8a\xc7\x67\x9a\x62\x24\x4b\x24\xeb\x59\x74\x75\xe5\x44\xe0\x17\xe7\x10\xac\xba\xfc\x9f\xf6\xac\x54\x0f\xf8\xa6\x75\xa1\xad\xa0\x95\x93\xed\x2c\x8d\x18\xad\x1e\x3d\x59\x2f\xbd\x32\x9f\x5c\x46\x87\x6e\x6b\x13\x10\xd3\xfc\x4a\x78\x01\x60\x03\xd5\xcc\x1d\xdc\xa8\x9a\x3c\xa7\x75\x74\x4d\x47\xed\xb6\xf8\x11\x23\xc6\xbc\x67\x7a\x12\x45\xf3\x4b\xdd\x76\x59\xdb\xd8\x86\xc7\x0e\x6b\x81\x22\xdc\x90\xdc\xf8\x24\x21\x20\x6a\x15\x64\xc8\x5a\xc7\xb4\x8b\x67\x19\x00\x7e\x7b\xb3\xe6\x38\xde\x4c\xc9\x43\x81\x99\x36\x8e\x0a\xcc\xb7\xf1\x57\x8f\x75\x4d\xcc\xe3\xde\xb2\x1b\x0a\xe0\xcb\xb0\x49\x84\x57\x31\x06\x09\x1b\x05\x81\x48\x7b\x9f\x6c\x52\x11\xc4\x6e\xa6\x32\xae\xfd\xb8\xf2\xe3\xba\x2f\x30\xc3\x66\x16\x2d\x88\x07\x1d\x35\x10\x68\xa7\x41\x3a\x99\xe2\x40\x88\x6a\x4e\x57\x72\xba\x8a\x33\x44\xaa\x8d\xf5\x53\x5b\xea\xa2\xaa\x32\x09\x77\x96\xad\xc9\x66\xf9\x33\xaa\xdf\x64\x63\x7c\x79\x3c\x7e\xe0\xc5\xda\x5d\x4b\xa3\x64\xb3\xf6\x52\x82\xf2\x46\xeb\x10\xae\x4b\x9a\x60\xf7\xa2\xc2\xfd\x8b\xa9\x8b\x62\x93\x4c\x7b\xc9\x26\x9c\x20\xdd\xb1\x5a\x92\xb8\x6c\x43\x32\xe9\x74\xda\xe7\x31\xb4\x73\x95\xde\x4c\xc4\x37\x7b\x3a\x4d\xfa\x3c\xe6\xf6\xd1\xb4\xdf\x63\x14\xad\x6d\xae\xec\x5c\xd2\xe9\xec\x9a\xa9\x15\x35\x61\x6e\x0b\xa5\x3a\x5f\x2c\x41\x32\xf3\x1e\xe9\xed\xf0\xd5\xdb\x53\x77\x44\x58\xf4\x48\x3f\xe0\xe8\xb2\x57\x7a\x20\xf4\xb8\xb6\x71\x4a\xa7\xab\x2b\xd2\x83\x0a\x26\xb6\xd7\xa4\x5f\xdf\xe8\x4d\x68\xe8\x69\x54\x6a\xa1\xb1\x9b\xf0\x0d\xb1\xcd\x95\x18\x76\xab\x1f\x70\xcd\x46\x67\xf1\xa3\xc9\x24\x51\x7f\x1c\x32\x73\x4a\x93\xa8\x3f\x0e\x3b\x9a\x0a\xdf\x20\xd6\x1e\xc3\x8e\x1a\x4f\x64\xb1\x49\xea\xa1\xdf\x56\x48\x93\xf9\xcf\xe8\x53\xd3\x64\x61\x13\xb9\xa0\x94\x27\x1b\x2d\x0e\x7c\xc6\xba\x89\xbf\xb0\x45\xaf\x2f\xc3\x3a\x4f\xbb\x8d\xa4\x81\xa0\x94\x54\x78\xe3\x13\xde\xca\x2d\x69\x78\xeb\x8a\x8b\x27\xb6\x57\xff\x00\x2b\x26\xfd\xba\xdd\x0b\x29\x79\x1f\x81\x0d\x99\x0e\xd8\x76\x77\x11\x48\xa7\x3f\x63\x5a\x91\xa6\x49\xe0\xb8\x56\x0c\xb7\x2d\x6a\x7f\x19\xcb\x3f\x9a\x86\x4a\x8c\x0d\xc6\x15\x15\x61\x91\x81\x65\x9a\xc6\x9a\xed\xef\x1c\x32\xa4\xe9\xbc\xcf\xa4\xc3\x76\x29\x69\xba\xe8\x33\xe9\x50\x02\xcb\x3e\x93\x0e\x25\xb0\xea\xc6\xe4\x7d\x04\xd6\x3f\x63\xfc\x94\xa6\x9b\x96\x26\x6c\x4d\x31\x98\x8f\xd9\xb4\x33\xa5\xf5\x36\x02\x86\x0c\x78\x18\xe5\xf6\x3e\x13\xa5\xba\xe5\x2b\x92\x4c\xee\x5b\x58\xd9\x62\x01\x8f\xa6\xfe\x0c\x89\x91\xf9\xea\xc6\x29\x9d\xcd\x84\x07\xca\x8c\xc9\x37\x0e\xcd\x7b\xf0\xd8\x22\xaa\xad\x12\x22\x5b\xb5\x74\xb6\x10\x7e\x6a\xe4\xcc\x68\x0e\xbb\xd3\xee\x78\x5b\xe7\xcb\xae\x94\xb7\x26\x65\xe9\x6c\xd5\x95\xf2\xf6\xa1\x75\x4c\xca\xde\x19\x72\x20\xe5\xc6\x8c\xaa\x78\x02\x44\x1d\x82\x1c\xb6\xe5\x4f\xe7\x16\xf5\x1a\x1b\x63\xea\xd7\xa6\xf9\x75\xeb\xfd\x4e\x37\x43\x4f\x08\x15\x71\xd8\x9c\x27\xd7\x6a\x76\xbb\x70\xf6\x10\x94\xbe\x7b\xd3\x0a\x91\x79\xb4\x63\x19\x94\x79\xe7\xd1\x8e\x65\xd8\xd1\x3e\xff\x1a\x70\x74\xf1\x83\xf9\x7e\xbe\xfc\x29\xf9\x7e\xbe\x6a\xc5\x31\x70\x29\x18\x7c\xd5\x27\xfc\x66\x9d\x39\xba\x8e\x2f\x05\xb9\x06\x90\x5c\x02\x50\xde\x6f\x89\xb0\xb9\x27\xeb\x47\x70\x6d\x31\xbd\x27\xeb\xc7\x08\x24\xf7\x64\xfd\x18\x81\xf4\xde\xac\x1f\x45\xf8\xc5\x4c\xb4\x12\xaf\xcb\xfc\xc3\x57\x57\xe9\x82\x87\x88\xc0\xf9\x5b\xde\xbd\x32\x4d\x17\x0b\x37\xf7\x60\x6f\x00\x6f\x76\xe0\xbe\x81\xc5\x03\x73\xe2\xc8\x67\x49\x13\xfb\x5f\x00\x00\x00\xff\xff\x24\x85\xba\x3a\xcf\x32\x00\x00")
+
+func fontsSpeedFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsSpeedFlf,
+ "fonts/speed.flf",
+ )
+}
+
+func fontsSpeedFlf() (*asset, error) {
+ bytes, err := fontsSpeedFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/speed.flf", size: 13007, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsStampatelloFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x5a\x5b\x6f\xe3\xba\x11\x7e\xe7\xaf\x18\x04\x02\x64\x37\xbc\x58\xf4\xfd\x9c\x45\x60\xf4\xa1\x6f\xc5\x3e\x14\x05\x76\x51\xd5\x92\x36\xf1\x9e\x63\xc0\x8d\xb6\x89\x4f\xf6\x61\xb9\xfe\xed\x05\x67\x48\x4a\xd4\xc5\xce\xe9\x06\x91\x19\x73\x38\x1c\x0e\xe7\xf2\xcd\x68\xbf\x9e\xbe\xea\x2a\x81\x15\x2c\x20\x5b\xc2\x0c\x16\xec\x1f\x87\xc7\xfa\xf9\xa9\x82\xb7\xc3\xcb\xeb\xb1\x7e\x3e\xc0\xd3\xe1\x04\x5f\xeb\xe7\x33\xdc\xbd\x9e\xab\xff\x7c\xab\xce\x87\xd3\xa9\xbe\x83\x6f\x87\x17\xf8\x7a\xfc\xed\x74\x38\xb3\x97\xe3\xdb\xe1\xe9\x8f\x73\x05\x07\x78\xac\x5f\x5e\x0e\xe7\x73\x05\xc7\x13\xe8\x2d\xfc\xed\xf0\xe5\xcb\x4b\x75\xac\x21\xdb\x6e\x57\xf0\x54\xb1\xbf\x57\x2f\x8f\x35\xfc\xb5\x7e\x7a\xa9\xce\x35\x7c\xf8\x42\x83\xdd\x6f\x87\xe7\x63\x2d\x5f\x9f\x5f\xe5\xf1\xfc\x00\xbf\x9f\xcf\xdf\x7e\x51\xea\xfb\xf7\xef\xee\x2b\x75\x71\x84\x8a\xfd\xf3\xb5\x82\xc7\xea\xa5\x3a\x9f\x0f\x2f\x47\x78\x45\x61\x6b\x38\x55\x70\xae\xbe\x1c\x4e\xa7\x0a\x8e\xaf\xf5\x66\xb3\xdc\xc2\xe4\xfe\xbf\x7f\x54\xa7\xc7\xdf\x0f\xf0\x7a\xaa\x9e\x1f\x8f\x35\x3c\x1d\xe1\x6b\xf5\x7c\xae\x5e\x8f\xd5\x94\x41\x02\x3b\x06\x49\x12\x1e\xb0\x63\x09\xb8\xc7\x8e\xa9\x3c\xd9\xb1\xe9\x24\xd9\xb1\x5c\x25\x3b\xf6\xcb\xaf\x96\xc6\x4e\x03\x4e\xff\x0a\xf4\x05\x31\x71\xdf\xc7\xcf\x1d\x03\x09\xd2\x12\x08\x23\x8c\x48\x9a\x4f\x48\xa1\x4c\x1c\x19\x34\x9f\x7e\x35\x37\x32\xd9\xb1\xf2\x1e\x9f\x26\x4d\xba\x5c\xdd\x2a\x2e\x81\x83\x25\x49\x15\x97\x8e\xab\x27\xee\x71\x25\x7a\x4b\xfe\x20\x7e\xe1\x76\x95\x48\xcb\x24\xcc\x79\x52\xcb\x07\x79\xe0\x54\xf8\xdd\x31\xe0\x56\x70\x85\x27\x35\xf8\xcc\xe9\xd4\xa5\x48\x82\x64\x42\xd2\xa9\x72\xfc\xca\xe0\xd3\x2a\x4f\xa4\x49\x2c\xfe\x8e\x49\xb0\x42\x88\x4f\x76\xb5\xd5\xc6\xc0\x19\x51\x7f\xa4\x35\x3a\xdd\x00\x11\x5e\x81\xbb\x41\xbc\x22\xbf\xd3\xae\x75\x5b\x4c\x88\xf6\xe5\xb1\xf1\xd5\x10\xad\xc6\xb1\x15\x13\x94\xfd\x3e\xed\x5e\x73\xb8\x2f\x61\xd5\x66\x94\x21\xb5\x0e\x8b\x69\xf9\xa4\xa8\x92\x32\xe9\xca\x81\x3c\x2c\x41\xa2\xac\x3c\xa9\x18\xd1\x07\x6d\x94\x88\x0f\xa3\x1b\x59\xf3\x45\x63\xf8\x51\xd8\xbd\x12\x18\x21\x92\xa8\x92\x12\xf9\x8d\x72\x72\xe7\xba\x4e\x24\xda\x82\x43\x72\x4d\x43\x0f\xd7\x05\xe7\x6e\xa3\x51\x35\x36\x6e\x38\x78\x5f\xfd\x69\x9e\x36\xd3\xe8\xde\x56\xd4\x0f\x76\x3a\x29\x3b\xab\xed\xb0\x28\x12\xf7\x08\x33\x6d\x5b\x41\xe3\x4e\x1e\xda\x46\xe6\xa6\x9d\xe4\x30\xb5\x4b\x27\x38\x59\xf7\x35\xc1\xc9\x3d\x14\x17\xd2\x3a\x88\xe1\xc2\xd8\xa3\xe6\xa5\xd8\x2b\xb4\x8b\xc6\x4d\x82\x56\xb8\xf4\x46\xa7\xc0\x24\x34\xad\x2e\x17\xba\x13\x9e\x02\x40\xa3\xa9\xc8\xed\xbd\x60\x5c\x08\x41\xc1\xc1\x14\x45\x81\xfb\x70\x03\xe4\xa2\xa5\xd8\x0b\x11\x2d\x6f\x8d\x50\x60\x32\x00\xb7\x87\x5d\x46\x37\x24\x82\x2f\x46\x71\x46\x0a\x5c\x61\x5d\x05\xfc\x1e\x1c\x47\xca\xef\xd6\x3a\x61\x67\x37\xb7\xd8\xea\x21\x2f\x0a\x77\x52\x17\x5f\xd3\x32\x12\xb3\x19\xb8\x65\x38\x97\x1b\xbf\xcc\xc6\x27\x0c\x4d\x69\x12\x51\xb3\xb6\x62\x9c\xa4\x06\x80\x84\x32\x00\x1c\x19\x95\x42\x08\x83\x8c\xb8\x90\x34\x28\xc5\xbd\xa5\xb1\xcb\x0a\x8a\xb5\x29\x98\xc2\xa0\x36\x95\x01\x47\x14\x85\xdf\xce\x6e\xa8\xf9\x94\x62\xa2\xdc\x83\x71\x6a\xec\x07\xe0\x98\x14\xa2\x0f\x55\xb6\x16\xe2\xe5\x52\x74\x9a\x1a\xe5\x0e\x9e\x93\xdc\x4d\x40\x8d\xf3\x00\x27\x63\x9a\xe2\x87\x53\xee\x98\x18\xf6\x87\x8c\xaf\xe4\x06\xec\x8f\xdb\x03\x7e\x05\x83\x76\x00\x30\x60\x7f\x10\x8d\x89\x91\x63\x13\x31\x21\x0b\x46\x51\xc7\x2d\x90\x7b\x0b\x2c\x39\x9e\xdc\x38\x45\x94\x91\xd9\xf6\x2d\xd0\x99\x7b\xb0\x76\x7f\x3f\xc9\x98\x35\x84\x7d\xa4\xdf\x47\xfa\x7d\x72\xbf\x4f\x39\xb8\x4f\xe9\xf7\x99\x1a\xc8\xd1\x2b\xca\x14\x5a\xea\xef\x18\x2b\xad\xca\x0b\x6f\xaa\xde\x11\x47\xce\xc3\x05\x9a\xb7\xa5\x00\xca\xba\xc0\xfd\x00\xc3\xc5\x98\x75\x4b\xeb\xaa\xe0\x74\xed\x57\xe0\xd0\x5d\x5d\x29\xc4\xfe\x6a\xe4\x90\x14\x7d\x2c\x02\xb1\xfe\x8b\xf3\x06\x07\x8d\x6b\x8d\xf9\x32\x2d\x8e\x18\x44\x4c\x22\x46\xd0\x67\x36\xf0\x17\x31\x25\x7e\x90\x2b\x97\xd7\x54\x4e\x36\x4c\x4c\x86\x75\x4e\x41\xcb\x80\xbf\x59\x77\xb1\xe8\x89\xa2\xe3\x50\x74\x95\x94\xee\x9d\xbc\x8a\x12\x5c\xc7\x3f\xa4\x4d\x9f\xe8\xf7\xcd\xc3\x23\xa1\x26\xc9\xd2\x81\xc9\x29\xfb\x18\x87\x0c\xc8\x44\x0f\x7f\x25\x3e\xe7\x20\x0a\x6d\xa0\x69\x2b\xe7\x24\x98\xde\x09\xa9\xd9\xf1\xe5\xb2\x63\xee\xc0\x0d\xc8\x18\x86\x3d\x21\xd7\x72\x97\x6b\xf7\x5d\xd1\x48\x72\xe3\xc2\xbf\x25\xda\xdf\x00\x09\xb8\xd7\x60\xd6\x6e\x36\x32\x30\xb2\x5d\xc4\xc9\x05\xe1\xe1\xfc\xcf\xef\x90\xc4\x2b\x3f\xed\xe2\x35\xde\x12\x99\x90\x04\x70\x02\x5d\x78\xc3\xfd\x73\xa5\x43\x08\x89\x70\xb0\xf1\x58\x38\x60\x60\xc2\xa4\xfd\x5b\x73\xcc\x81\xf2\x88\x35\x17\xf3\x81\xd2\x60\xef\xd2\x65\xc7\x66\xd2\x3e\x18\x74\x70\xd0\x0b\xe9\xc5\x84\x51\x6c\x1f\x1f\x7b\xf0\x44\x7d\xdd\xbc\x83\x88\xae\x82\x82\x47\x9a\x5c\xd7\xb2\xcb\x53\x65\xd2\x23\x22\x45\x5c\x05\x86\xa3\x38\x94\xb4\x15\xae\x7b\x48\x5b\x56\xef\xf2\x96\x71\x21\x15\x5d\x0c\x39\x77\xd9\x8a\x9d\x8d\x57\x43\xa0\xa5\xcc\x6a\x14\x65\x56\xab\xfd\x2b\xf5\x1a\xd5\x32\xf0\x09\xae\xd5\x32\xb1\x94\x86\xa0\x83\x3f\x75\x50\x47\x41\xe5\x06\x72\xba\xeb\xab\x03\x23\x8c\x45\x99\x68\x5e\x38\x4a\x9b\xa8\x63\x92\xfe\x2f\x45\x1a\xcb\x75\x82\xd1\xe0\xc1\x8f\x7c\x8d\xd1\x36\xba\xb4\xe4\x54\xfc\xb9\x94\x09\x89\x3f\x76\xd2\x3d\x76\xcd\xa5\x87\xb8\x2a\xa4\xf5\x3f\x81\x4c\xa1\x2e\x6a\x40\x59\x00\x8f\x71\x3b\xb5\x43\x6d\x41\xb5\xbd\x8d\x3c\x64\xb4\x26\xa1\xf5\xf2\x59\x94\x90\xec\xd2\x9b\x41\xaf\x4d\x34\xea\x25\x44\x74\xd3\xe4\xb8\x2f\x85\x4d\x41\xc9\x84\x1b\x90\x94\xea\xc7\x61\x62\xa6\x37\x16\x74\x3a\x68\xa1\x00\x1c\x10\xce\x1b\x24\x5c\x76\xa0\x70\x7c\xcc\x4c\x6f\x87\x22\x88\x8b\xa8\xfb\x61\xc5\x66\xf3\x19\x93\x74\xac\xc1\x24\xc9\xa5\x83\xef\x16\xf4\x5b\xf2\x35\x93\xa5\xe4\xa9\xb5\x29\x59\xaa\x1c\x07\x62\xf2\xe3\xe7\x14\x6b\x79\x9e\x2b\x59\xe2\x20\x2d\x65\x1b\x07\xd9\xa5\x9b\xc6\xc5\xea\x7a\xf6\x11\xef\xff\x33\x95\x4d\xb9\x2b\x9c\x20\x2f\xa6\x49\x24\x1e\x9e\x29\x54\x04\x53\x72\x10\x24\xf6\xc6\x53\xd6\x75\x3d\x8b\x16\x2d\x66\x0c\x0a\xda\x69\x02\xae\x53\x31\xa5\x4c\xec\x17\xcd\xea\xba\xe6\xf1\xa2\x2c\x88\xf7\x71\x46\x93\x41\xbc\x29\xc5\x8d\x49\xa1\x62\x57\xc8\x16\x9a\xd5\xd6\x1f\xac\xde\xf2\x3d\xba\x34\xe4\x9f\x1d\x82\x28\x70\xc7\x42\x41\x5e\xc4\x3b\x2d\x18\x14\xf4\xcf\x09\x59\x60\x45\x52\x4c\xe9\x9a\x15\x4c\x3e\x4e\x21\x2f\x2f\x68\xdb\x39\x12\xaa\xcb\x25\x46\xda\x03\x18\x29\x5b\x2c\x1d\x63\x4a\x74\x75\x5d\xff\xab\xf8\x37\xde\x69\x5d\xd7\x06\x4c\x18\x16\x34\x2c\x8a\xc2\x11\xc4\x6c\x56\x41\x3e\xc7\x29\x77\xb3\x39\xe5\xb8\x9f\x82\xfe\xfd\xa4\xca\xcb\xfa\x26\xd4\x3e\x07\xb8\xb9\x9e\xb4\x96\xf1\x9a\x01\xe0\xa9\x93\x1d\xfb\x71\x91\x85\xbc\x20\x0b\xd4\x33\xc6\x83\xe9\xe5\x2f\x97\x89\x55\xf9\xa4\x98\x8a\x49\xcb\x16\x1c\x03\x34\x21\xe3\x50\x39\x7e\x4e\xca\x74\x9a\x04\x50\x3a\x10\xae\xb2\x55\xc6\x08\x39\x5a\x91\x3a\x8d\x3d\x4f\xa2\x19\xf5\xea\x38\xb6\xdd\x8c\x41\x3c\x73\x8f\x67\x68\x77\xaf\xb2\xd5\x1c\xdd\xdb\x1a\x47\x61\x0a\xba\xae\x29\x79\x67\x1a\xd5\xb7\x91\x00\x0b\x17\x20\x72\xa1\x42\xe0\x50\xa1\xb6\x68\x71\x5f\xba\x6c\x52\x7c\x2e\xae\xb5\xbe\xb2\xd5\xaa\x09\xf1\xad\x70\x9f\xa0\x8b\xae\xd6\xa1\xe3\x42\x89\x75\xa4\xef\x92\xad\x36\x2e\xa0\x41\x72\xb5\x91\x99\xad\xb6\xfd\xfe\x85\x0b\x13\x79\x29\xd2\xc1\xfe\x45\xb6\xb6\x4e\x88\x37\x84\xcd\xa8\xcb\xe5\x42\xa0\xb4\xc7\x7d\x9d\xf9\x2f\x38\x76\x68\x28\xbb\x95\xbd\x4c\x9a\xad\xb5\x4f\xd9\xd6\x86\xa2\x02\x79\x20\x9d\x67\xeb\x39\x0b\xd4\xcd\x21\x07\x8e\xb7\x5e\x0c\x1c\xaf\x40\x67\xce\x0d\xe4\x23\xc7\x5b\xfa\x66\x51\xaf\x63\xe4\xad\x6a\xbd\x6a\x19\xde\x08\xc9\xda\xcb\x68\x90\x19\x1a\x9e\x10\xa2\x7f\xf6\x0d\xf1\xc2\x68\x7c\x77\xd7\x63\x68\x49\xb6\x8e\xe4\x7e\x78\xcf\x1d\xcb\x36\x33\xc6\x9b\x89\x41\x89\x36\xd9\x00\x64\x31\x98\xe5\x0c\x7e\x9f\x7a\x42\x8d\xe9\x8a\xe2\x24\xc5\x16\x28\xa9\xa9\x05\xfe\x6f\x10\x7b\x11\x85\xbe\xcd\x3c\x34\x96\xeb\x06\x5c\x33\x37\xb9\xe8\x88\x43\x70\xbb\x6c\xaa\xa2\x6c\xb3\x6c\xf7\x52\xfb\xa7\xb0\x24\x6d\xad\x0f\x6b\x6a\xe3\xb5\x2e\x29\x4f\x3f\x60\x5b\x2f\xed\x9b\xe6\xc6\xa6\x64\x70\x3b\xba\xc2\xd0\x57\xb2\xca\x7d\x0f\x90\xde\xfb\x33\xa2\xff\x6d\xb6\xd7\x16\xb9\x06\x12\x75\xc5\x00\xc0\x4a\xb8\x63\xd9\x76\x46\x25\x2e\xde\x9f\x47\xa9\xca\xe7\x83\xfe\x4e\x28\xde\x36\x78\x4e\xed\x10\x21\x66\xb8\x0e\x9c\xb6\x84\xe8\x39\x79\xab\x9f\x58\xb6\x50\xdb\x04\xe3\x84\xb0\x42\x45\xe8\xa4\x8b\xda\xb2\x2d\x79\x14\x0f\x59\x50\xa5\x3d\xf0\x57\xde\x04\x7f\xd9\x16\xef\x59\xed\xf3\xc0\x26\x0c\x2d\x1b\x78\x1f\x86\xcc\xb6\x4b\x1b\x8b\x11\xb5\x7a\x28\x1a\xb1\xe1\x14\x3c\x6f\xb2\x59\xf5\x11\x6d\x97\x0d\x49\xd3\xea\x7b\x0e\xb0\x21\x9b\xfa\x18\x9a\x8e\x41\x1a\x8e\x6c\x7c\xa7\x02\xa8\xdc\x19\x65\x43\x20\xc9\xf7\xa4\x88\x0f\x01\x41\x45\xf2\xb4\x39\x5d\xef\xbe\x65\xdb\x6d\xab\x8d\x9b\x46\x6d\x5c\x28\x85\x72\x0d\xab\x38\x5d\xea\xd9\xcc\xa6\x8f\x22\xf7\x8d\x4e\xc2\x5e\x2a\x34\xd2\xf6\xa3\xdd\x58\x3d\xcb\x70\xa9\x0a\x3d\x38\xdf\xef\x7b\xc7\x52\x6b\xa1\xca\xed\x1a\x96\xf2\x77\x2d\x9d\x33\xe0\x75\x51\x13\x5a\xea\xed\xca\xaf\x2d\xb5\x48\x2c\x27\xe7\xba\xc3\x9e\x10\xbf\xd2\x9d\xd5\x33\x8b\xaf\x54\x8b\xbc\x29\x5b\x06\xc9\x57\x0c\x4d\x7b\xc7\xf8\x9e\xc8\xaf\x73\x5f\xb3\xba\xa8\xdf\x2f\xcc\x86\x5d\xa4\xeb\x63\x5b\x2c\x42\xef\xdd\x7c\xbf\x9d\x77\xda\xed\xf1\xb1\xad\x5d\x78\xc7\x91\xe9\xdb\x9d\x6c\x3a\xb3\xc4\xe6\x7a\x67\x56\x67\x98\xdb\x5d\xc7\x03\xca\x4e\x09\x37\x0c\x83\x74\x66\xad\x03\x14\xd5\xe1\x69\xd4\xd2\x8d\x4d\x39\x5a\xa4\x03\x90\xb6\x32\xc9\xf7\x2d\x9a\x87\x6a\xd6\xbf\x01\xb9\x59\x61\xea\x6c\xf1\xe7\xcb\x52\x9d\x2d\x11\x70\xda\x2a\x0d\xe3\xf9\x27\x72\xd4\x1e\xb4\xd3\xd9\xca\x8a\x42\xf0\x0f\x91\x85\x51\x0e\x06\x0e\x5e\x6e\xb6\x66\x92\xe7\xae\x8b\x5b\x62\xa1\x9b\x84\x92\xb7\xf0\x25\xef\xf8\xfb\x14\x9d\x6d\xac\xf9\x28\x62\x30\x35\x51\xcd\xec\x3a\xd5\x57\x6b\x66\x9d\x6d\x59\x88\xcb\x61\x79\x10\xc4\x2e\x96\x63\x5e\xa5\x67\x2c\x94\xeb\xf1\x52\xf7\x02\x69\x3f\xea\x90\x3a\x63\x12\xd4\x68\xcb\xb6\x53\x8d\x6a\xad\x19\x77\x78\xdf\x34\xaf\x74\xe8\xee\x44\x78\xb3\x83\xf3\x7b\x91\xf8\x3d\xe6\xff\x6f\x89\xae\xf5\xc2\x35\x74\x6f\x34\x13\xb4\x5e\xba\xd7\xc6\x37\x09\x57\x8c\xef\xe5\xed\xf6\x84\xd6\x6b\xf6\xb6\x7f\x7b\x0f\xe1\xe6\x7d\x0d\x0f\xad\xb7\xcc\xa6\xab\xdb\x84\xf3\x59\xb0\x7c\xdf\x57\xe0\xe2\x46\x5f\x41\xcf\x3d\x36\x69\x77\x02\xcb\xb7\xd4\x41\x84\x16\x77\x1d\xe9\x74\xb4\x03\xac\xe7\xf3\x48\xa7\x57\x08\x17\x91\x4e\xaf\x10\x2e\xe3\xb6\xcf\x38\xe1\x8a\x59\xdb\x18\xec\x0b\xeb\xf9\x9a\xa9\xf1\xc9\x0d\xdb\x8f\x4f\x6e\x7d\x01\x46\xc6\x48\xaf\x12\xfb\x38\x54\x2f\x66\xec\x01\xdf\x5c\x73\xac\x1a\x47\xfb\x53\x7a\x91\x45\x56\x32\xda\x13\xd6\x8b\x8e\xd6\xc7\x39\x76\xb4\x3e\x4e\xd8\xd1\xfa\x38\xe1\x72\x40\xc6\x41\xc2\xd5\xfb\xba\x72\x7a\xb1\x8e\x70\xb0\xab\x9f\xfa\x2f\xe1\x35\xf5\x0f\x90\xa3\x0a\xff\x69\x43\x0d\x71\xdc\x3a\xf5\xdc\xe8\xf5\xe9\xe5\xcc\xa9\xe7\x26\x61\xe6\xd4\x73\x93\x50\xbf\xaf\xcd\xa8\x97\xf3\xc1\xad\x7b\xcd\x65\xbd\xf4\xfd\x07\xd3\x32\xf3\x7d\xbf\x12\xd7\xcb\xe5\xe0\xd6\x3d\x8e\xff\x0b\x00\x00\xff\xff\x2e\xb2\xdc\xa2\x36\x26\x00\x00")
+
+func fontsStampatelloFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsStampatelloFlf,
+ "fonts/stampatello.flf",
+ )
+}
+
+func fontsStampatelloFlf() (*asset, error) {
+ bytes, err := fontsStampatelloFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/stampatello.flf", size: 9782, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsStandardFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x7c\x6d\x73\xda\xc8\xb2\xff\x7b\x3e\x45\xbf\xd8\xfa\x07\xea\x1f\x3c\x46\xb6\xb1\x5d\x95\x93\x32\x06\xd9\xd6\x06\x83\x8f\x80\xec\x49\x56\x5b\xb3\x24\x26\x31\xb5\x04\x52\x36\x3e\x7b\x53\x57\xf7\xbb\xdf\x9a\x47\x8d\x66\x7a\xa4\x91\x73\x6e\x6a\xd7\x60\x8c\xfa\x37\x3d\x33\xdd\xbf\x7e\x18\xe9\xcb\xe6\x4b\xb4\xfc\x05\xfa\x70\x02\xbd\x3e\xf4\x4e\xa0\xd7\x83\x43\x88\x8e\x8f\xfb\x47\xad\xd9\x7e\xb9\xbd\x5f\x3e\xde\xc3\xa7\x1f\x70\xbd\x59\x6d\xb7\x30\x7c\x58\x7e\xff\xbe\xda\x6c\xe0\xff\x41\xb2\xe4\xbf\xae\xe1\x88\x9c\x1f\x41\xb7\x0b\x9f\x96\x4f\xab\x7b\xd8\x6d\xe1\xea\x71\xb9\xfd\xeb\xd5\x13\x1c\x3c\xad\xbf\xb6\x92\xed\xe7\xcd\xf3\xfd\xea\x09\x92\xd9\x14\xc6\xcb\xfd\x7a\xdb\xed\xb5\xbe\xac\xbf\x6e\x56\x7b\x78\x5c\x6d\x56\xcb\xa7\x15\x44\x07\x3d\x26\xa0\x17\xc1\xe0\xf9\x2b\xf4\xce\xcf\x8f\x5b\xb7\xbb\xfb\xf5\x97\xf5\xea\x1e\xbe\xec\x1e\x41\x7e\x3d\x3a\x88\xd8\x48\x7e\xdd\x3d\x6c\x61\xb8\xfb\x7b\xb9\x85\x37\x9f\xd9\xcb\xc5\xe7\xcf\xeb\xcd\xc1\xee\xf1\xeb\xdb\x16\xc0\x7e\x07\xcb\xfb\x7b\x89\xf4\xdf\xd1\xeb\xa3\xd7\xc7\xaf\x4f\xfe\x07\x9e\x9e\xbf\x7f\xdf\x3d\xee\xa1\xbd\xd8\xae\x3f\xef\xee\x57\xb0\xf8\xff\x87\xbd\xc3\xc3\xee\x61\xef\xf4\xaa\x73\xd0\xba\x5b\x3d\x7e\x5b\x3f\x3d\xad\x77\x5b\x58\x3f\xc1\xc3\xea\x71\xf5\xe9\x07\x7c\x5d\xff\x7b\xb5\x65\x02\xbf\xb1\xc1\xfc\x80\xfd\xc3\xfa\x09\xbe\xec\xb6\xfb\xd7\xb0\x7c\x82\xcd\x6e\xfb\x95\xbd\xee\x1f\x56\xad\x6f\x62\xb4\x8f\xaf\x9e\x60\xbb\xfc\xb6\x62\x32\xbe\x6f\x96\x9f\xc5\x74\x2c\xe1\xf3\xee\xdb\xb7\xd5\x76\x0f\x9b\xf5\x76\x75\xd0\x2a\x74\xfb\xf4\x03\xee\x96\xcf\x1b\xb8\x7c\x7e\xdc\xef\xb6\xf0\xe6\x69\xb7\x79\xde\xaf\x77\xdb\x8b\xd5\xf2\x71\xff\xb0\x59\x6f\xff\x3a\xd8\xae\xf6\x6f\xa1\x17\x91\xf3\x3e\x1b\xc8\x5a\x4c\x26\x6c\x57\x7f\xc3\xf7\xe5\xe3\xf2\xdb\x6a\xbf\x7a\x6c\x49\xdd\x84\xc0\xab\xe4\x9a\xcd\xd5\x72\x7b\xcf\xde\xfe\xb6\xde\x1e\x00\xdc\x2e\x7f\xc0\x72\xf3\xb4\x83\x4f\x2b\x78\xda\xac\xbf\x3e\xec\x37\x3f\xe0\x9b\x39\xc3\x9f\x56\xfb\xfd\xea\x11\x9e\x9f\x56\xad\xdd\x17\x2e\xfe\xcb\xf3\x66\xd3\xfd\x7b\x7d\xbf\x7f\x20\x7f\xad\x1e\xb7\xe4\xe9\xdb\xf3\xd3\x03\x2c\x37\xfb\xd5\xe3\x76\xb9\x5f\xff\x7b\xf5\xf4\x1a\x3e\x3d\xef\xe1\x7e\xf5\x65\xf9\xbc\xd9\xc3\xee\x79\xff\xfd\x79\xcf\x34\x9f\x4c\xe7\xf0\xf9\x61\xb9\xfd\xba\xba\x3f\x68\xc1\x2f\x17\xd8\xff\x17\x2d\x00\x0a\x17\x2d\xc8\x21\x2f\x7e\x52\xf6\xb3\x4d\x3b\xec\xaf\x00\xf2\x4b\xfc\x6b\x6d\xc8\x81\x7f\xfc\x1e\xde\x03\xff\xf3\x2f\x50\x7e\x55\x17\xb0\x4b\xd8\x7f\xfc\x53\x9a\x43\x9e\x43\x2e\x90\x28\xc0\xc1\x01\xfb\x4c\xfe\xc2\xbf\x9b\xf3\x6b\x72\x9a\xe7\x34\x2f\x24\x19\xe2\xa8\xf8\x34\x87\x9c\xbd\x12\xa0\x7c\x78\x19\xa5\x90\xf1\x71\x01\x10\xfe\x77\x9a\xab\x01\x03\xa5\x42\x0d\x22\xfe\x04\x04\x08\x97\x41\x80\xf0\x91\x10\x4a\xb4\x92\x05\x0e\x55\x83\x6e\x03\x85\x0e\xc8\x2b\x28\x64\x24\xe3\x33\xd4\xa6\x6f\x01\xde\xb0\x4f\x33\x4a\x29\xc9\x88\x31\xd8\x62\x3e\xdb\x7c\x9a\x72\x01\xf8\x8b\xf1\xb3\xc0\x91\x43\x11\xd3\x0e\xce\x0b\x64\x34\x63\x5f\xa5\x42\xf3\x0c\x32\x35\x01\xce\x0b\xa1\x44\x4d\xba\x18\x3b\x1b\x17\x07\xc8\x40\x4e\x0c\x61\xf3\x91\xf1\xef\x64\xc4\x98\xe0\xe2\x32\xd0\xab\xa6\x97\x4c\xaf\x97\xb1\x3e\xe6\xe2\xc8\x8b\xed\x9f\xd6\x04\xd8\x08\xfa\x6b\xec\x9f\x40\x60\xff\x04\x02\xdb\x47\xa1\x08\xa5\x0d\xaa\xa7\x54\x4d\x6a\x69\xbd\x41\xae\x37\x38\xaa\x53\x39\xbf\x62\x8d\xd5\xfc\x6b\x73\xa0\x72\xa2\xf9\x5a\xdb\x03\x13\xbb\xc8\xb4\x1c\xc3\x7e\xf4\x97\x14\x02\x53\x53\x2e\x22\xdb\xbd\x42\x2e\xdb\xc8\xc4\x99\x84\xd2\xc5\x7a\x8e\xa4\x3a\x6c\x45\x32\x35\x83\x1d\x89\x88\x0f\x4f\xad\xa6\x30\x3f\xe3\xad\x92\x59\x2c\xad\xbd\xb6\xf6\xe0\xd9\xdb\xdc\x52\xa3\x06\x1f\xb4\x29\x71\x8b\x13\x62\x5e\xe9\x59\x6e\xab\x39\xc0\xe7\xb6\xa4\x39\xe4\x7a\x69\x41\xaf\xad\x10\x5d\x5e\x54\x7b\x55\x85\x11\x5b\xeb\x5b\x8d\x8c\x6e\x09\xf3\x92\xd7\x7a\x34\xc8\xc5\xce\xfe\x44\xf7\x2a\xfe\xa5\xb2\xc9\x98\x1e\x42\xea\xad\x9c\x40\x26\x4d\xd9\xb1\x5f\xc4\xa6\x6a\xac\xcb\x72\x2f\x19\x77\xa7\x0a\xb5\xd0\x4f\xad\x89\xda\x37\x99\x5a\x05\xed\x74\xd9\x64\xd3\x8e\x43\x02\x7a\x32\xf9\x56\x97\x28\x4c\x1d\xfa\xa7\x32\x19\x68\x6b\x2b\xe3\xd3\x2b\x07\x9b\xc9\x4d\xa5\xac\xbb\x70\x01\x84\xfb\x35\x25\x94\xfd\xa2\x4c\x49\x02\x88\x4d\x51\xcc\x92\x67\x43\x8b\x9d\x91\x83\x61\xf9\x75\x1b\x5a\xcc\x80\xc0\x52\xc3\xd7\x36\xa6\xfe\x9a\xf9\x4c\x19\x1c\x3c\xc7\xd3\x78\x4c\x59\xaf\x2b\xe8\x75\xe5\x3e\xba\x8c\x5c\xe7\x44\xc0\x18\xb6\x76\x0d\x5a\x0c\xcd\x01\x37\x25\x4c\x67\x15\x35\x98\x0e\xd2\x45\x86\xe2\x8b\xae\xa6\xfc\xef\xd2\x61\x16\x4e\xd3\xdd\x6d\xd2\x45\x29\x5e\x54\x34\x69\xe2\x69\x33\xa0\x6a\xfc\x72\x58\x14\x82\x7d\xb9\x30\xb8\x9c\x19\xa0\x20\xe5\x57\xc2\xe8\x72\x38\x90\xcb\x45\x73\x73\x4b\x69\x0d\xd5\x22\x60\xef\x6a\x16\x86\xff\x2f\xe6\x82\xd1\xb2\x1c\x68\x46\xf4\x98\xa1\xe0\x14\x28\xcf\x91\x33\xc3\x99\xd6\x14\x32\x7d\x7d\x56\xcc\x70\xe6\xe0\xff\x1c\xf9\xa1\xfb\x59\xd9\x0f\x14\xbc\xe6\xdb\x55\x81\xc8\x25\x2b\x0e\x43\x86\x37\xa0\x75\xf6\x5e\x4c\x34\xa3\x65\xc1\x8c\x66\xb8\x57\x23\x28\x02\x45\x9c\xc6\x3b\x24\x50\xc2\x8d\x21\x6c\xb6\xa9\xd8\x67\x32\xa6\xcb\x0a\xd7\xcb\x7e\xd1\xa4\x98\xc1\x7b\xd0\xc1\x5d\x66\x11\x63\x49\x50\x59\x96\x25\xce\x92\x68\x09\x75\xe5\x1a\xa2\x95\x50\x2d\x4e\x87\x60\xda\x31\xdb\x26\x24\x82\x10\x35\x18\x7d\xe1\x7b\x1d\xed\x54\x4f\x2a\xfb\xa7\x62\x19\x5f\x98\x5f\x32\x3d\x65\x79\xc2\x99\xe6\xbe\xf0\x3b\x67\xd7\xe8\x09\xd3\x53\xa5\x26\x49\x4d\x4f\xa6\x27\xc6\x76\x0c\x6a\x9f\xb8\xe1\xba\x36\x69\x81\xc0\x26\x9c\xf3\x7e\x26\x06\x29\xf3\x84\xf2\x0b\x12\xa9\x57\xbd\x73\xe2\x00\x2b\xc8\x00\x81\x85\x25\x26\x85\x34\x2a\x93\x3e\x93\xac\xdb\xc6\x2e\x7d\x8d\xfa\xfb\xc2\xf3\x39\x11\x5f\xc1\xae\x07\x18\xbb\x1a\xc0\x05\xe3\x28\xd8\x82\x59\xad\xa5\x84\xc2\xeb\x53\x35\xb8\xe0\x01\xa3\x98\x90\x69\x0f\xe6\xc3\x2c\xbe\xac\xd9\x54\x71\xa9\xf2\x79\x0e\x35\x85\xce\xaa\xdc\x23\x45\xf0\x53\x37\xab\x06\x45\x20\x2c\x5a\x44\x99\xfe\x1c\x45\xcf\xa0\x8a\x53\xe5\x70\x34\x8b\x12\xb5\x63\xcd\x21\x49\x74\x9b\x36\x41\xbb\x5f\x84\x2d\xed\x61\xa0\x83\x29\xed\x64\x3e\x61\xa6\xda\x7f\x5a\x8c\x51\x56\xdf\x22\x49\x24\x44\x86\xc6\x73\x68\x6d\x13\x9b\xb7\x6a\xd2\x89\x1a\x64\xcd\x5b\x07\x16\x63\xbe\x6c\xdf\x08\x3f\x59\xde\xdc\x54\xfb\xbb\x57\x66\xd4\xaa\xb1\x5c\x83\xba\x28\xe2\x2f\x65\x84\xaa\xd4\xc2\x37\x66\x69\x73\x17\x49\xa6\x0e\x51\x4d\xab\x60\x57\xba\x81\x9a\x1a\x59\x45\x80\x58\x61\xb2\x10\x40\x1c\x9c\xa8\xd0\x8b\x8d\xeb\x4b\x22\x4a\x52\x4a\x82\x2c\x59\xb6\xfb\x40\xa8\xef\xad\x34\x03\x84\xf1\x1a\xe9\xef\x78\x03\x63\x79\xa8\x8c\x44\x88\xa4\x3b\xc5\x76\xf6\x6c\xcb\xc2\x88\xca\xd6\x04\xc1\xbd\x81\x37\xa5\x92\x9a\x2e\x38\x79\xad\x54\xdb\xaa\x9a\x3c\xc5\x8a\x25\x29\x6f\xe1\xad\xf1\x3b\xcf\xc4\x24\xcb\x91\x5c\xd0\x1c\x51\xcc\x86\xbf\x3a\xf1\x52\x9b\x76\xa8\x72\x4c\x84\x66\x96\xfd\x31\x04\x24\xcc\x43\x2e\x36\x43\xcd\xba\x5c\x40\x5f\x5c\xf8\xce\xf0\x44\x02\x43\x0e\x27\xd0\x8a\x61\xd7\x94\x4c\xc2\x87\x8d\x98\x95\x4b\x80\xda\xa3\xe7\x99\xfa\x24\xe7\xa6\x2f\xbd\xc6\x45\xab\xd7\x3f\x04\x98\x4c\xbb\x97\x69\x3c\x78\x07\xb3\xbb\xc1\x30\xf6\x57\x9a\x7b\xfd\x1e\x40\x32\x79\x1f\xa7\xf3\x78\x04\xf1\xbf\x86\xe3\xc1\xed\x60\x9e\x4c\x27\x70\x3b\x48\xdf\x85\x51\x55\xaf\x1f\x01\x0c\xe3\xc9\x1c\x66\xc9\xf5\x44\x32\x57\x11\x27\xaa\xa0\xa1\x53\x0e\x1a\x00\x40\xd2\x9a\xa8\x0e\xf7\xfa\x47\x00\x77\xd3\xc5\x64\x64\x88\x31\xea\x14\xaf\x29\x9f\x6f\x5a\x64\xc9\x46\x2a\xd7\xa6\xaf\xad\x5c\x4e\x88\x3c\x06\x18\x2e\xd2\x34\x9e\x0c\x3f\x48\xa9\x44\x14\x88\x45\x19\x56\x9a\x69\xb1\x86\xb2\x5c\xc1\xfe\xca\x8b\x15\xa4\xb4\x20\xbd\xfe\x09\xc0\x87\x78\xa2\x06\x48\x95\x0f\x2f\x3c\x5c\xce\x3f\xcb\x4b\xef\xb0\x20\xb9\xd7\xef\x03\x5c\xa6\xd3\x77\xf1\x04\x2e\x07\xa9\x65\xe0\x34\xb7\x4d\x9e\x1b\x78\xaf\x7f\x0a\x30\x8b\x87\x7c\x7d\x8c\x49\x02\x19\x0e\xf0\x29\x26\x2a\x00\xce\x20\x93\x85\xa3\x8c\x79\x4b\x3e\x4b\xd2\xf0\x7b\xfd\x33\x80\x51\x32\x88\xd3\x78\x96\xcc\xf0\x5d\xca\xcb\x52\x2a\x16\x75\xdf\x19\x9a\x9c\x03\x0c\xa7\x77\x1f\xd2\xe4\xfa\x66\x5e\x5a\x3b\x5d\x6a\xd4\x65\x20\x50\x4e\x91\x45\x85\x9a\xe6\xdb\xfc\x8b\x45\xb1\x89\xe6\x85\x97\x17\x29\x1f\x07\x3a\x3d\x04\xb8\x8a\x6f\x93\x49\x32\x89\x61\x9a\x8e\x92\xc9\x60\x0c\xc9\x64\x94\x0c\x07\xf3\x69\xda\x2a\xd8\x58\x5b\xb6\x36\xaa\xbc\x5c\x6e\x33\x3d\x7f\xef\xb4\x07\x30\x8e\xaf\xe6\xdd\xbb\x69\x32\x99\x27\x93\x6b\x18\x4d\x17\x97\xe3\x18\x06\x93\xeb\x71\x0c\xff\x5c\x4c\xe7\x25\x8b\x50\x4e\x9e\xeb\xa1\xea\x80\xba\x12\xa8\x6b\x81\x65\x7e\xe9\x9d\x46\xc0\x9b\x3f\x7a\x7e\x00\xcb\x0a\xa0\x14\x2f\xa8\xe1\x5a\x13\x7e\x7a\x04\x30\x9b\x5e\xcd\xe1\xe6\xc3\xdd\x4d\x3c\x29\x45\xcc\xa6\x54\xa8\x53\xfc\x18\x20\x8d\xaf\x93\xd9\x3c\x4e\xe3\x51\xd8\xca\xe5\xdc\xef\xc9\x95\xe3\x01\x0b\xd1\x2b\x97\xd3\x9c\x66\xf8\xca\x9d\x00\xdc\x0e\x86\xe9\x74\x12\xd0\x62\xc0\xde\xe9\x21\xf7\x01\x46\xf1\x75\x1a\xc7\x7a\xb8\x45\xec\xa7\x1d\x72\xe1\x8f\x09\x78\x54\x3f\x05\xb8\x1b\x2f\x66\xdd\xdb\x64\xb2\x98\x95\xfc\x96\x98\x3e\xa4\xd1\x42\x99\x7e\xce\xb8\xb5\xc4\x33\x80\xd9\xe2\x2e\x4e\x67\xc3\x34\xb9\x9b\xc3\xfc\xb7\x69\xa9\x5c\x06\x1d\x34\x1e\x28\xf3\x6b\xef\xf4\xdc\x92\x72\x93\xc6\xb1\x19\x57\x50\x55\xdc\xb5\xc2\x3e\x4b\xce\xd9\x21\xc0\x60\xb8\x98\xc7\x30\x18\x32\xcf\xdc\x92\xf1\x06\x11\x5f\x37\x53\x4c\x23\xd1\xec\x9d\xf5\x00\x6e\x93\x61\x3a\x45\xb6\x69\x75\xd5\xf0\x40\x1b\x5a\xae\x85\x45\x00\x77\xc9\x78\x98\x4e\x7f\x33\x16\xab\x60\x34\x00\x55\x5b\x6b\x2b\x89\x3c\x9e\x55\x69\x0e\xdf\x4f\xb6\x47\x3f\x3b\x62\x23\x1c\x8d\xc6\x31\x8c\xa6\xf3\x56\x31\xba\xa2\x6c\x8f\xa8\xc5\x68\x20\x1e\x25\xe3\xf1\xa0\x55\x58\x8a\xfd\x93\xcb\xe8\xd0\x0e\xbf\xe2\xa4\xbc\x0e\xd3\x49\x8c\xb6\x96\x68\xee\x60\xf5\xd9\x56\x9f\x0d\x17\x63\xbf\x97\x52\x4e\x4a\x10\x8d\x5c\xc3\xdc\xb7\x27\xce\x4e\x01\xb8\x6f\x0d\x74\x50\xba\x98\x96\x99\x0d\x04\xdd\x42\x50\x4d\x04\x33\x54\xe1\x30\x67\x00\xef\x17\xe3\xeb\x41\x0a\x57\xe9\x40\x70\xcc\x74\xc2\xc4\x0f\xd2\x79\x9c\xaa\x2d\xa0\x92\x4c\xe6\x0a\xb8\x23\x57\x69\x06\xe1\x1f\xc9\x32\x0d\x01\xc2\xf6\xbc\x50\x48\x14\xfe\x55\x3f\x02\xca\xeb\x79\x8e\xa3\xde\x0c\xc6\x57\x26\x64\x81\xa8\xb2\xa6\x5c\xf4\xaf\x3a\x0a\xaf\x28\x31\x51\x52\x0e\xb8\x35\xd8\xf9\xa1\x0b\xc6\x2d\x4c\x29\x39\xd3\xb5\x48\xad\x27\x37\x39\x43\x53\x6e\x7a\x25\x5d\x69\x59\x5b\xbf\xbe\x72\x10\x66\xc0\xf5\xcf\x45\x3c\x2b\x73\x8b\xec\x90\xc9\xa6\x8d\xee\xac\x8b\xaa\x59\x66\xe5\x11\xbd\xf3\x08\x60\x3c\x98\x27\x13\x18\x0e\xee\x92\xf9\x60\x0c\xe3\x78\x3e\x8f\x53\x18\xc0\x6f\xc9\xfc\x06\xae\xd3\xc1\xfb\xb8\x65\x76\xfd\x18\x35\x29\xd7\x1e\x14\xb6\xf7\xce\x8f\xaa\x31\xb8\x9f\x51\x91\x88\x92\x4c\x1a\x62\x1c\x57\x63\x0c\x93\x74\xb8\xb8\xbd\x1a\xc7\xff\xe2\x42\x89\xca\x6f\x08\xcd\xf2\x66\x40\x27\xd5\x40\xf3\x64\x3c\xe2\xca\xb0\xcc\x48\x62\x64\x4d\x95\xe9\x57\x63\xf8\x02\xaf\x86\xf9\x54\xef\xfc\xb4\x1a\x27\x65\xae\x62\x70\x39\x7d\x1f\x97\xb8\x0d\xda\xbb\x4e\x43\x85\xce\x7c\x40\x42\xb2\x70\xeb\xaa\xcb\x43\x00\x0a\x7e\xe4\x66\xa3\xa2\x5f\xde\x6c\x54\x21\x3b\x43\x72\x98\x54\x23\x9e\x7b\x10\x87\x72\x3f\x14\xde\xfc\x05\xed\xbf\x0e\xb3\xae\x8b\x56\x74\x78\xe8\x41\x89\x7d\xd6\xc3\xc2\x3a\xac\xe5\xe7\x8d\x0b\xa2\xc3\x5e\x35\x86\x6b\x3d\xcc\x35\x37\xc4\xf0\x79\x81\x38\xcc\x7a\xc2\x81\x7c\xae\x20\x0e\xda\xd9\xe1\x38\x3e\x77\x90\x94\x17\x46\x4d\x59\x46\x65\x2f\xb0\xdc\x95\xb4\xbb\x91\xd1\xa1\xcf\xfa\x13\x6b\x31\xd4\x96\x52\xc5\xbf\x3a\xb9\x3e\x8b\x4f\x90\x05\x20\xaa\xb5\x40\xb3\x3c\x48\xb8\xcf\xcc\x93\x30\x77\xc2\x01\x84\x6d\xea\xb6\x4d\xae\xda\x6c\xe6\xa4\xfb\xac\x3c\x9e\xdf\xe8\xbc\x40\xe7\xf5\xa0\xbb\x73\xa5\x36\x79\x51\xee\x77\xbb\x75\x12\xc6\x67\xda\x13\xc4\x03\x6b\x07\xcc\xf7\x8c\xee\xa0\x1e\xfc\xa9\xc2\xaf\xac\xdc\x05\x88\x7a\x3e\x93\x9e\xd6\x13\x62\x60\x29\x2a\xea\xf9\x4c\x7a\x5a\x4f\x88\xc1\x18\x3e\x93\x9e\x06\x12\x62\x30\x90\xcf\xa4\xa7\xf5\x84\x18\x8c\xe1\x33\xe7\x69\xd8\x0e\x0e\xc6\x61\x69\xe6\x62\x3c\x4f\xee\xc6\x2c\xda\x2e\x55\x49\xd4\x57\x19\xf3\x88\x53\x83\xf2\xc4\x60\x56\x9c\x16\xe4\x32\x7c\xa6\x2c\xc7\x3a\x9b\xa7\xd3\x77\xb1\x4d\x3c\x84\xa8\xa0\x54\xa5\x07\x84\xa8\xb6\x17\x41\x06\xea\x33\xe9\x45\x00\xf1\x84\xd5\x3c\xa3\x9e\xcf\x9c\x17\x01\xc4\x13\x8a\xe1\xb3\xe5\x45\xcd\x2e\x85\x2c\x6f\x04\x14\xf9\xcc\x7a\x51\xbd\x83\x1a\x16\x8a\xa3\xc8\x67\xda\x1f\x3c\x93\x46\xf9\xa4\x55\x34\xca\x9d\xca\x5f\x14\xf9\x4c\x7b\x7e\x33\x4d\x27\x4e\x6b\xb1\x38\x24\x54\xb4\x40\x8d\x82\xaf\x2d\x5c\x9b\xf3\xec\x76\x30\xd6\xa2\x67\x37\x83\xf4\x0e\x66\xad\x17\x96\x94\xa3\xe8\x18\x15\x5b\x99\x65\x34\x6a\x53\x47\xd1\x49\x15\x02\xee\x52\x1b\x22\xf4\xab\x10\x42\x1c\x6a\x18\xcc\x69\x15\x0c\xee\x4e\x1b\x2a\x72\x56\x85\x10\xe0\x4c\xc3\x50\xce\xab\x50\xec\xdc\x42\xad\x4a\xbb\xdd\x29\x4e\x76\xbe\x0a\x80\x39\x3a\xc4\x61\xe2\x52\xf2\x2e\x37\x97\xe9\x72\xff\x04\xbd\x81\x19\x80\x71\x30\xc0\x69\x05\x48\xa4\x1e\x8a\xe4\x66\x14\x00\x0d\x8e\x3c\xa8\x5c\xe2\x28\x42\xa5\x63\x99\x84\x8e\x3a\x2e\xc2\x8e\x36\x44\x47\xb8\x51\x63\x19\x84\x8e\x36\x82\x65\xe3\x96\xed\xcd\x1c\xb4\x51\x04\x03\xe0\x86\x1d\x96\x31\x98\xd4\xaf\x0e\xaf\xc9\x0e\x81\xb5\x8d\x70\xe3\x2e\xe7\x0b\x54\x16\x51\xb2\x8a\x66\x56\x74\x84\xdb\xaf\x95\x21\x18\xd5\x54\xbf\x24\xdc\x4e\x03\x72\x02\xb0\x8e\x55\x96\x8a\x49\x5c\x34\x6e\x9c\x81\x19\x01\x84\x9d\x8e\x8b\x8e\x71\xdb\x94\xf9\x00\x0b\xa3\xc4\x05\xaa\xad\x0e\x94\x7d\xa4\xfa\x68\xba\x05\xe3\xd2\xec\x31\x6e\x8a\x58\x06\x50\x0e\x39\x43\x8f\x87\x44\xc7\xb8\x39\x36\xcb\x02\xaa\x3a\xbb\xd1\x31\x6e\x94\xcd\x72\x80\x6a\x04\xdc\x34\x5f\x90\x01\x54\xc3\xe0\x06\xda\x2c\xfe\xaf\x46\xc0\x8d\xb3\x79\xf4\x5f\x8d\x72\x0a\x30\x4a\xde\x27\xb3\x72\xdc\xaf\x43\x24\x1d\x4a\x33\xd9\x76\xe9\x81\x49\xb6\xe5\xe1\xe6\xeb\xe4\x01\x65\xc2\x28\x4e\x22\x29\x9b\x86\x36\x21\x6a\xd8\x76\x32\x20\x80\x70\x63\x7e\x79\x2e\xe0\x90\xec\x09\x6e\xc8\x2f\xcf\x04\x5c\x04\xdc\xa2\x7f\x32\x0f\x70\x61\x70\xb3\xfe\xb9\x2c\xc0\x45\xc1\x4d\xdb\x97\x03\x04\x4c\x97\x75\x60\x28\x3a\xc1\x4d\x1b\xcf\x00\x1a\x1d\x4f\x8b\x4e\x70\x73\xfe\xf0\x73\x53\x64\x29\x70\xf8\x5f\x87\x3d\x6f\xf5\x54\x86\x88\xba\xe1\x6b\x84\x6d\x85\xd9\x86\x95\x9e\x39\x0e\xbe\xb5\x1c\x14\x1d\xae\x01\xa1\x40\x49\x83\x58\x97\xa3\xd4\x74\x52\x2e\xd3\x58\x94\x1c\xf5\xb9\xcc\x2c\x93\x69\x7f\x23\x65\xf0\xad\x65\x81\x18\xc7\xe4\x4c\x8f\x12\xac\x4b\x4d\x37\x65\x7a\x3d\x9d\xc4\xef\x3c\xee\xb1\x56\x99\x36\x6d\x2b\x9c\xca\x9c\x0d\x43\x09\x3f\xbd\x6c\xa0\xf8\x2a\x32\x43\xdb\x1e\x75\x00\x4c\x8d\x08\xb8\x38\xf7\xe8\xbf\x11\x88\xc3\xe0\x71\x9f\x03\x52\x6c\x32\xbd\xc7\xea\xce\x43\x73\xf1\xbe\x72\xcc\x10\x73\x91\xea\xfc\x39\x70\x1a\xc9\x9a\xaa\x82\x13\x0a\x8e\xa4\x80\x48\x91\x90\x04\xe9\x33\xa8\xd6\x67\x34\x9d\x1b\xf9\xe1\xef\x7f\x98\x0c\xd9\x54\x9d\xcb\x2a\x75\x4a\x40\x26\x4e\x23\x6d\x86\x35\xab\x33\x90\x4e\x26\xcb\x94\xcd\x53\x23\x6d\x0f\xd6\x64\x54\xb9\x30\x26\x88\xc2\x68\xa4\x45\xec\xd1\x62\xe4\xd3\x82\x52\x1d\x58\xbb\x35\x56\xec\x76\x1b\x0e\x73\x85\x6a\x61\x81\x30\xc1\x2f\xbc\x05\x80\x81\x78\x0b\xf9\x23\xb4\x0e\xab\x7b\xf3\xfa\x6e\x43\x5e\xd7\x92\xb7\x62\xe7\x34\x27\x0a\x2f\xa7\x68\x5f\x82\x63\xe2\x4c\xe3\x20\x42\xb7\xdb\xcd\x5f\xae\x59\x4d\xb7\xae\x8a\x37\x43\x3b\x68\x1c\xa7\xb2\x6a\x50\xe6\x4d\xea\xf0\x66\x48\xd6\xcd\x51\x7c\x5c\x13\xd7\xf2\x66\x23\x65\x2a\xab\x08\x0a\x24\xcb\x58\x74\x79\x21\xd7\xc8\x49\x52\x6a\x75\xf1\x31\x4d\x5c\xe5\xd3\x7c\xb7\x81\x56\xeb\x83\xb3\x8d\x0f\xe8\xc2\xa4\x9e\x80\xaa\x0b\x87\xf0\xf6\xf3\xbc\xfc\x1c\xae\x4a\x9b\x6a\x7e\xee\xe1\x6c\x83\xa2\xd8\xbe\xd9\xaf\x47\xc1\xff\x3d\x1f\xd3\xc4\x55\x5e\xad\xf9\x8a\xe0\x2c\x83\x81\x88\x6b\xb3\xe0\x22\x1b\x17\xef\x63\x98\x6b\x8c\x95\x29\xc9\xb0\x43\x0d\x14\xdc\x16\x06\xa6\x0a\x4e\x33\x28\x92\x19\x69\x50\x75\x48\x2c\xe8\x1e\x28\x8e\xe4\x63\x9c\x6b\x2b\xa0\x45\xd9\x32\x5c\x21\x9c\x71\x2c\x10\xa3\x28\xd0\xf4\x7e\x2e\x06\xe2\xed\x31\x5d\x23\x46\x49\x7f\xff\xe3\x27\xf4\x89\x70\xa2\xc1\x80\x98\x97\xf9\x09\x9d\x7c\x5c\x73\x1d\x7a\x8e\xa6\x42\xa3\x0e\x15\xb5\x6f\x0e\x84\x93\x8d\x0b\x63\xba\x81\x40\x7d\x3a\x9d\x4e\x47\xc1\xf8\xd8\xe6\x06\xd9\xdb\x3c\x6b\x11\xc3\x27\x90\x39\x47\x56\xab\x6e\x74\xe7\x58\x38\xe5\xa0\x48\xfa\x7e\x51\xc8\x75\xd9\x27\xac\x52\xc9\x91\x7c\xbc\x73\x63\x45\x1e\xe6\x21\xdc\x7f\x34\xbb\x75\x9f\xe3\xe0\xa4\x83\xa1\x88\xa0\xf0\x1f\x4d\x6f\x6d\xe4\x28\x3e\xde\x49\xca\x15\x45\x22\x3c\x69\xe8\xa3\x04\xb8\xe8\xca\xb2\xb7\x2e\x55\x82\x68\xf2\x57\xd4\xe6\xb9\x30\x1f\xaf\x24\xe5\x08\x89\xe8\x7e\x6b\x83\x81\xe2\x64\x62\x49\x56\x91\x97\x42\xa8\x2b\xfb\x73\xc9\x3e\x1e\x49\x1c\x67\xd8\x78\xd0\x38\x6d\x58\x82\xc5\xd1\xe2\xca\xce\x07\x17\xe6\x63\x86\xc4\x8a\x0b\x42\x9f\x28\x61\x44\x1c\x11\x4e\x07\x8e\x64\x50\xc5\x2d\xb9\x6f\x8d\x17\x9a\x53\x21\x54\xc9\x3c\xf2\x79\xff\xc4\x75\xca\x54\x44\x64\x4d\xe6\xd6\xd3\x7c\x1c\x4d\xe7\xe3\x78\x36\x83\xa4\xa5\x43\x30\xa8\x99\xd8\x23\xd7\xa5\x27\xd7\x83\xf9\x22\x8d\x21\xf9\x55\xce\x27\x14\x53\x5a\xdc\xdd\x0e\xc5\xdb\x22\xc1\xcb\xdd\x7a\x34\x07\xb1\xdd\x79\x19\xa2\xa6\x70\x58\x8c\x5c\xde\xa3\x0c\xfa\x2e\x65\x2e\xdc\xe7\xc4\x7f\xc5\x03\x14\x1d\xa1\xf0\x22\x45\x7e\xa1\x9f\x20\x62\x50\x93\x0e\xeb\xcb\xb7\x84\x2a\x44\xdc\x95\xe3\x78\x24\x53\xf5\x10\x31\x72\xa5\x81\x78\xb5\xee\xba\xe6\xd2\x7d\xee\xfb\x9d\xcd\x7e\x14\xca\xe7\xe5\x85\x67\x05\x95\x82\x1f\xc8\xfb\x6c\xc4\x5d\xda\x52\x0f\xc6\xb2\x0a\x08\xf7\xdf\x18\x8c\x42\x09\xb9\x11\xbc\x53\x00\xe0\x2d\x8f\x77\x69\xa9\x2f\x5e\xdc\xb9\x9c\x13\x15\xfa\xfa\x6e\x2f\xe7\x52\x7d\xa7\x84\xc6\x56\x4f\x15\x64\xf6\x96\xf3\xf3\x53\x4a\x03\xe7\x2c\x8c\x27\x80\x3f\x1a\xa0\x83\xb7\x40\x88\xe3\xb8\x70\x2b\xbb\xac\x1e\xb3\x35\xd9\xce\x58\xab\x47\x6d\xae\xe9\xb0\x6a\xd4\x65\x18\x25\x1a\x7b\xd5\xdd\x5b\x63\x35\x47\x35\x3a\xc8\x9c\x86\xaa\xa4\x86\x09\xcb\x9a\xcf\x7b\x5c\xa9\x41\x20\x88\x7a\x87\x1c\x6a\xe2\x20\x57\xd5\xba\x94\xee\x09\xf2\x2c\x89\xf4\xda\xb5\x0a\x79\xda\xde\x5e\x24\x0d\xa4\x71\x4a\x9f\x38\x77\xf3\x73\x0c\xdf\x41\xb3\xb1\x1d\x8c\x15\x10\x44\x3e\xe3\x25\x27\x44\x8a\x24\xfc\x08\x7d\xa5\x2e\x78\xc3\xcc\x41\x31\x58\x87\xaf\x12\x21\x98\x55\x1c\xfb\x0e\x8b\x4e\x2c\x4b\x56\x37\xac\x34\x7f\x00\x12\x87\xc1\xbb\x63\x13\xb7\xde\xaf\x1c\x92\x3a\xa8\xdd\x20\x4c\x3d\xf6\x9d\x05\x9f\x60\xa6\xd7\x48\x9b\x0e\xed\x98\x40\x78\xf7\xdb\x81\xb1\x1c\x6c\xbd\x3e\x16\x8c\xef\x4c\xe9\xc4\x32\xc4\x8c\xbc\xf4\xe1\x54\x1c\x06\xa7\x08\x0b\x84\x97\x62\x84\x2e\x19\xf2\x94\xc1\xda\xb5\xc1\xe3\xfc\x09\xdc\xa5\xf1\x30\x1e\xc5\x23\xb8\xfc\x00\x83\xbb\x29\xdb\xbf\x77\x37\xe6\x51\xb1\x0b\xf5\xd4\x30\xf1\xbe\x0d\x1d\x86\x2b\x0f\xd7\x18\x41\x10\xf6\x54\x12\x05\xee\xad\x37\x4d\xae\x1b\xee\x06\x50\xf2\x0b\xa7\x7c\xec\x29\x33\x49\xd9\x75\x0b\xaf\x25\x1a\x77\x49\x52\x3d\x72\x5f\x6e\x30\xad\xa8\x2c\x83\x79\x58\x0c\x64\x16\xee\x3f\x66\xc1\x71\xf0\x44\xe1\x3f\x8d\xe2\xcb\x20\xa6\x56\xa6\x03\xea\x81\x56\x40\xbb\xc8\x03\xcc\x2a\xce\xfb\x72\x18\x3c\x99\xf8\xcf\x82\x9c\xd4\xdc\x96\xa0\x6e\xe8\x34\xba\x8c\xc5\x59\x3e\xa7\x26\x5f\x8b\x86\x27\x1b\xff\x37\x58\xfe\x74\x64\xaa\xda\x33\x56\xc9\xd7\x78\x16\x8d\xa0\xc9\x52\x20\x9f\x8b\x66\x04\x87\xcb\x75\x6b\xc2\x36\x52\xe7\x88\x46\x19\xb4\xec\x10\xe4\xf3\x83\x4b\x83\x30\xea\xb6\x7c\x23\x96\xaa\xb7\xc4\xaa\xe1\x96\xa1\x7d\xe9\x4b\x6a\x93\x20\xc5\x7a\x6b\x21\x4f\xc4\xe3\x30\x78\xce\x92\x22\x4d\x6f\xcd\x81\xd2\x73\x18\x77\xc1\x79\x03\x90\x13\x5f\xd2\x92\x3a\xf4\xd7\xf4\xc9\x7e\x65\x5e\x3a\xc1\x93\x16\x07\xa6\xcc\x7e\x75\x9a\x74\x8a\xd2\xe3\x89\xaf\xde\x94\xda\xc4\xf7\x73\xeb\x81\x73\x52\x8a\x10\x9f\xe6\xbd\x26\xeb\xe1\x63\x9d\x99\x67\x57\x35\x7f\x54\x22\x87\xc1\xe9\x67\xe6\x9e\x72\xb8\x90\x60\x01\x4f\x9b\xe2\x82\x7d\xdc\x33\x43\x2b\xb3\xd9\x4b\x9f\xf7\xc8\xb1\x70\xfe\xc1\x90\xd4\xa6\x22\x34\xa3\xa1\x9a\xf8\x78\x67\xe6\xb5\x8c\x06\x6a\x18\xa9\xdf\x09\xce\x3c\x0e\x0c\x14\xdd\x39\xa8\xd4\xa1\x88\x32\xfa\x3e\xbe\x99\x79\x6c\xe2\x65\x0b\xd1\xc7\x89\x66\xe6\xda\x84\x34\x89\xea\xf1\x1b\x82\xbd\xf7\xc8\x60\x6b\x60\x3f\xa9\x03\x6a\xce\x37\x1b\x6b\xd0\xc7\xfb\x16\x2e\x4c\x91\x0d\x8b\x57\xdf\xe3\xd4\x8c\x35\xf0\xf1\xc4\xdc\x5a\x83\x97\x3f\xbf\x94\xc3\xe0\x3c\x31\x77\x4f\x63\x04\x8d\xdf\x10\xec\x63\x88\xb9\x93\xa2\x56\x29\xd0\xcd\xbb\x79\xb7\x52\x01\x9c\x20\x1c\x14\xcf\x0a\x74\x2b\x34\xa8\xb9\x05\xae\x68\x18\x68\x13\x23\x59\xb3\x5b\xe0\x38\x4c\xe5\xf9\xdd\x17\x80\x60\xa7\x46\xfa\x3e\x7e\x58\x54\x9d\x1a\x01\x55\xa7\x0f\x57\x06\x27\x88\x0a\x94\xe2\x29\x5a\x0d\xb4\xf1\xb1\xc5\xc2\x6e\x36\xe8\x18\x2e\xab\xbb\x39\x11\x83\xc1\x89\xe2\xe5\x20\xa8\x2e\x3e\xbe\x58\xa0\xb7\x4a\x4d\xb5\x37\xaf\x79\xca\x20\xba\x3a\x38\x65\xd4\x22\xd1\xc6\x5a\x9d\xd6\xdd\x71\x69\x65\x11\xdd\x2e\x74\xbb\x62\xd7\x11\xd2\x78\xd7\x9d\x56\x1e\x1f\xc7\x32\x16\x1d\x9f\x54\x62\xa1\x9a\xf9\xb8\x65\xe1\xf6\x8f\x1a\x3f\x1b\xda\xe8\x52\x9d\xe2\xd4\x62\xa3\x18\x7e\x21\xfc\xb9\x9b\x45\xdf\xea\xd4\xc7\x32\xbf\xb9\xd1\x90\xa8\x25\x92\xcc\x78\xbc\x26\x10\x92\x65\x3f\xff\x9c\x69\x3e\x12\x9c\x88\x90\x71\x80\x1a\x06\xc8\x87\x56\xb2\x41\xbc\xf8\x89\x9f\x1c\xdb\xc7\x55\x1f\x7c\x67\x5e\x05\x34\x03\x86\x06\x37\xef\x72\x2c\x9c\xaf\x2a\x91\x84\x8a\x95\x6b\x8b\x9c\xde\x38\xf5\xf1\x17\x72\x98\xff\xf7\x3f\x40\x14\x9e\xc5\x22\x37\xb9\x23\x99\x43\xf9\x7a\x34\x1f\xed\xfb\xde\x88\x7a\x5a\x55\xf8\xa3\xbd\x39\x00\xde\x9d\xf9\xe8\x24\x1e\x60\x24\x1e\x75\xcf\x51\xe5\x82\x7d\x9d\x9a\x8f\x48\xe3\x96\xfe\xfe\x47\xe3\x07\x93\x73\x10\xbc\x4b\x83\x40\xa8\xd3\x7a\x81\x4f\x82\xe5\xc2\x7d\x7d\x9a\x8f\x6e\xb0\xfe\xb2\xd1\xe3\x1d\x9a\x8f\xde\x30\x3d\x78\xe4\x38\x1d\x8d\xa7\x93\x6b\x71\xb3\x79\x71\x5c\x5e\x3f\x96\xbb\xab\x5b\x56\xdd\x9a\xd0\x36\x1a\x9e\x82\x1a\x9d\x1a\x5c\xa6\x9f\xe8\x87\xbf\x88\x0b\x47\x67\xa0\xd8\x9d\x9f\x36\x15\x36\xa6\x79\xe7\x17\xef\xab\xbc\xfc\x1c\xcc\x35\xe5\x66\x25\xbe\xe4\xfc\x90\x17\x5c\x82\xe9\xd0\x3d\x63\xd3\x2f\x45\xf1\x22\x1a\x8d\xa0\x44\x6f\xc6\xf3\xfa\x40\x3d\x26\x49\x67\x47\x55\xe3\xfe\xdf\x00\x00\x00\xff\xff\xf2\x77\x6b\x98\xab\x6e\x00\x00")
+
+func fontsStandardFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsStandardFlf,
+ "fonts/standard.flf",
+ )
+}
+
+func fontsStandardFlf() (*asset, error) {
+ bytes, err := fontsStandardFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/standard.flf", size: 28331, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsStarwarsFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x59\x4d\x8b\xdb\x48\x13\xbe\xeb\x57\x3c\x07\x81\x2d\xb0\xd4\x64\x48\xde\x97\x80\x19\x44\x76\x61\xd9\xeb\x1e\x02\x0b\x4d\xca\xce\xac\x9d\x0c\xeb\xb5\xc3\x78\xc2\x12\xe8\x1f\xbf\x74\x7d\x74\xb7\x3e\x3c\x93\x64\xae\xce\xce\x5a\x6a\xa9\xab\xeb\xa9\xaa\xa7\xaa\x4b\xd2\xfe\xb0\xbf\xd9\xd6\xf8\x3f\xfe\x87\x9b\x1b\xbc\x7a\x83\xd7\xd5\xf9\x71\xfb\xf0\xef\xf6\xe1\xdc\xed\x0f\x7b\x7c\xfc\x86\x3f\xbe\x6d\x8f\xf8\xf3\xf4\xf5\xee\x6f\x2c\xbf\xc5\x43\x7f\x77\xee\xbe\x3e\xec\x3e\xdd\x1f\xb7\xdd\xdd\xb6\xc1\xaf\xbb\x3b\xdc\xbc\x71\xaf\xde\xbe\x7d\x5d\xfd\x8e\xed\x3f\x38\x9e\x1e\xf1\xb0\x3b\x7f\x39\x1d\xcf\xf7\x1f\x0f\x3b\xec\x4f\x0f\xf8\x7a\xde\xe1\xb4\xc7\xe3\xe7\xfb\x33\xf6\xa7\xe3\x23\x50\xbd\xdb\x9e\x77\x7f\xe1\x74\xc4\xbb\xfb\x4f\xa6\xec\xb7\xc3\xee\x78\xc4\x2f\x9f\xb7\x5f\xbe\xec\x0e\x87\xaa\xaa\x51\xf7\x4f\xff\xf4\x15\x88\xe2\x20\x00\x61\x7a\x20\x8a\x87\x25\x51\x53\xf7\x15\x00\x95\x00\xa1\xaf\x96\x08\x68\xfa\x0a\xef\xf1\x1e\xf1\x66\x8d\x99\x03\x80\x9e\x8f\xc4\x7f\xf1\x1a\x05\x84\x80\x40\xbc\x3e\xa2\x7a\x50\x28\xae\x63\x74\x1d\x81\x42\xa0\x00\x45\x80\x62\xd1\x38\x6b\xd5\xb6\x2b\xea\x64\xe8\xf4\x2e\x8b\x21\x00\x58\xb6\x6d\xdb\x6e\xe4\xae\xd7\xff\xeb\xbe\xea\xe2\xe5\x46\xe6\x28\x8e\xb8\x96\x93\xbb\xc0\xa2\x6d\x17\xb2\x14\x1b\xcc\xd0\xe3\x04\xaa\xa3\x05\x8e\x97\x71\x80\xab\xd9\x0f\x27\x34\x3c\x02\xdf\xf5\xe4\x64\x24\x93\x75\x26\x0b\xf1\x90\x47\x2c\x14\x87\x4e\xb4\x46\xa1\x3e\x1b\xc8\x3a\x49\x1d\xb6\x04\xa1\x61\x5c\x0e\x04\xef\x7c\x8c\xcf\x92\x6e\x81\x35\xab\x23\x72\xde\x25\x59\x8b\x69\x0c\x1b\xab\x08\x4e\x03\x32\xfe\x55\x2f\x12\x11\x2f\x0d\x77\x89\x05\x72\x88\x9a\x7c\xdf\x57\x8c\xab\xaf\x3c\xc4\xa0\x20\xee\x9e\x3b\xb0\x6d\x6a\x15\xa9\x59\xce\x07\x04\xc7\x92\x1e\x1b\x2c\xe0\x92\xff\x25\xdc\x0e\x2b\x74\xf0\xac\xd0\x05\x0a\xde\xa1\x08\x7c\xf6\x91\xb1\xca\x28\x65\x7c\xca\xa4\x51\xc6\xd4\x40\x5e\x41\xe5\xf3\x6f\xe1\x90\xb1\xd3\x86\xe1\x48\x67\xc4\xff\x98\xa5\xfc\x2f\x68\x66\xa4\x79\xf5\x50\x62\xac\x11\x13\x8d\xd4\x14\xe1\x80\x45\x44\xa9\x92\x39\xc3\x74\x51\xd2\xe9\x09\xc4\xc9\x33\x1a\x39\x4a\x89\x33\x92\xe1\xfc\xdf\xf8\x8c\x42\x8a\x2e\xb9\x22\xc9\x8a\xda\xe0\x48\xa6\x84\xd9\x03\x97\x88\x42\x82\x34\xa5\x54\x2d\x50\x37\x32\x93\x93\x40\x20\x39\xd2\x39\x94\xa4\xb3\x7c\x5a\x20\xad\x40\xd4\x98\x32\xc2\x9a\xaf\x91\x5d\xe3\x45\xa6\xc0\x85\x1b\x62\x62\xb0\x34\xd7\x02\xa3\xf0\x22\x55\x6a\xad\x14\x41\x13\x9f\xfd\x51\x96\x9a\x04\x4a\xab\xa4\x41\x0e\x8c\x65\x04\xf4\x19\x50\x52\xd4\x92\x2b\xb2\x2f\x64\xe9\x45\x0a\xd4\xd2\xec\xbd\x10\x94\x04\x47\xbc\xa5\x56\xd4\xe6\xdf\x62\x79\x39\x13\x4d\x5c\x68\x26\xb6\xcd\x32\x25\x01\xb8\x85\x3a\xfc\x39\x50\x4f\x2f\xe3\x89\x56\x06\x33\xa1\x64\x40\x13\x17\x71\xf0\x62\x56\xc4\xa4\xa8\x87\x43\x4b\x91\x0b\x73\x62\xe6\xa6\xc4\xd5\x24\xd2\x14\xe2\x74\xe9\xab\x35\xb0\x96\x22\x0d\x29\x31\x52\xd4\xaa\x71\x71\xb9\x94\xe7\x17\x72\x1f\xe3\xfc\xb3\xda\xcd\x6a\x4c\x1f\x4f\xb9\x05\x6e\x15\x4f\x4a\xde\x52\xbf\x6a\xd0\x2d\x19\xbc\x65\xd5\x7d\xb5\xd1\x0d\xcb\xb2\x45\xb6\x1b\x65\x6c\x41\x59\xa2\x14\xe2\x58\x57\x0a\xe2\x49\xd5\xe6\x7d\x89\x04\x4b\x0c\x04\x6d\x62\xa1\x8e\xfc\x5f\xc6\x42\xc0\x48\x63\xb0\xc4\x32\x2f\x34\x9e\xa9\xbf\x82\x31\x99\xed\x04\xa7\x8d\x1d\xf0\x81\x2d\x47\x2a\x5a\x24\xae\xd0\xd2\xa5\x46\xb2\x6f\x74\x07\x94\x50\x0c\x36\x79\x25\x45\x37\xf2\x09\xc1\xf8\x85\x40\x4d\xda\xa3\xe2\xf5\xf5\xe4\xba\xc8\xba\x41\xf7\x90\x08\x1b\x37\x74\x01\x04\xe9\x1a\x02\xb0\x8a\x9e\x5e\xc8\x2a\xb0\x12\x02\xf6\x7f\xa7\xe4\x1f\x06\xbe\xc8\x49\x2a\xc2\xc6\xfc\x0a\x40\xd7\xb6\x9d\xad\xad\x7f\x7c\x2e\x2d\x46\x48\x10\xc9\x4d\x20\x52\xa6\x9b\x86\x50\x97\x29\x9d\x21\xfb\x9c\x5c\x2d\xa9\x59\x42\xc4\x4f\xac\x06\xd9\xa3\x84\x5d\x03\x7e\xa3\x70\x1f\x95\x01\x4d\x46\xe6\x96\x32\x96\xdb\x90\xf0\x15\x5b\xcd\xa0\xf2\x17\xdb\x0d\x06\xd2\x28\x5a\x10\x06\x92\x62\x1d\x67\x86\xc9\x34\x99\x33\x5a\xfa\xf9\x36\x77\xd0\xed\x16\xb5\x28\xa3\x51\x86\xe4\x04\x4c\x03\x8d\x6f\x5a\x69\x23\x71\x2d\xec\x1c\x92\x2f\x5b\x2a\xec\x8b\x92\x5a\x9d\x22\x2b\x34\xaf\xd9\xe7\x6b\x8b\x4b\x67\x8c\x27\x0a\xa3\x2c\x29\xfc\x56\x44\xee\xc9\x53\xe3\xf2\x0c\x51\x2c\xdd\x18\x5c\xa7\x38\xbc\xcb\xbe\xf6\x9c\xcd\xe6\x34\xef\xc2\x8f\x45\xa1\x93\x6d\xd7\x96\xf6\x85\xdf\xe0\xf3\x79\x87\x4d\xa1\x04\xc5\xb2\x7e\x8e\x36\x65\xd1\x14\x32\x16\x15\x62\xc0\xa1\x1f\x0e\xd4\x77\xd7\x1e\x95\x16\x0d\x52\xf8\x02\x28\x0c\xbb\xc1\x7a\x98\x3c\xd0\x1c\xcb\x98\x35\xe7\x12\xd2\x8b\x63\x01\xbf\x88\xdc\x4b\xf8\xf5\x77\x58\x41\x6b\x94\x56\x24\x79\x8c\xd4\xb1\x2d\xf9\xae\x96\x74\xbb\x1b\x6b\xb7\x91\x26\x1a\xb5\xe9\x26\x15\xa6\x4c\x1a\xe5\xd5\x8b\x1f\xca\x2c\x2a\x40\x3d\xd5\xa4\x36\x99\xa6\x50\xdc\x0e\xb2\x5f\x46\xe4\x85\xa6\xa2\xa8\xcd\x0d\xa5\xce\xd5\x18\x68\xaa\xf1\x6c\x59\x7a\x19\xbf\x2c\x2c\xba\x15\xa9\x37\xa2\xc9\xbc\x1d\x78\x4b\x3f\xed\x12\xbc\xc6\xc6\x9e\xae\xbd\x8d\x14\xb6\xd7\x87\x81\xc2\x0a\x19\x96\x9a\x66\xf5\xcd\x6a\x9d\xd3\x3d\x8b\x60\x0e\xc7\x2c\x9a\x09\x26\x58\x1d\xe4\x0e\xc9\x65\x04\xef\x53\x87\x73\x9b\x4a\x61\xbc\x6f\xb5\x90\xdb\x86\x71\xcb\xf0\x33\x2e\x95\xc9\xc9\x20\x89\x60\x46\xcd\x75\x6c\xde\xa5\x46\xf4\xc1\xb6\xef\xac\x5d\xe3\x16\x2d\xf5\xe3\xa9\x0d\xe7\x73\xeb\x26\x1c\xcd\x6c\xd6\xc5\x83\x90\x2e\xab\x1b\x6b\x64\x32\x53\xac\x1e\x1e\x53\x31\x0f\xc9\xa7\xe9\x09\x5d\xcc\xca\xcd\x17\x52\x4b\x8a\xdc\x04\x0f\xdb\xe0\x6c\x5b\xa1\x7f\xd3\xea\xa3\x3d\x86\xc7\x4e\xaf\x27\xfd\xda\x1b\x6a\x5b\x15\x1b\x4d\xd7\xb6\x1f\xda\xd6\xe7\xc7\xbc\x27\x4e\x2e\x3c\x73\x0f\xce\x26\x4f\xda\xd3\xae\x3c\x3d\x5b\x83\x1f\x11\x7c\x78\xfa\x15\xc8\xb5\xa1\xbd\x36\xb4\xd7\x86\xf6\xda\xd0\x5e\x1b\xda\x6b\x43\x8b\x11\xb1\x71\x6d\x68\xaf\x0d\xed\xb5\xa1\x7d\x79\x43\x3b\x7e\x25\xab\xc4\xb2\x2f\x1a\xa9\x2f\x4d\x7b\x92\x7e\x6f\xfa\x9e\x8d\xae\xdc\xef\x66\xde\xbe\x32\x8d\xad\xf9\x1d\x41\xc8\x6f\x61\xa5\x8e\x01\xd6\x02\x78\x27\xdd\x8c\xf3\xc5\x4b\xd0\xfc\x5d\x73\xee\x2c\x95\x43\x29\x48\x7d\x85\x25\x35\xb4\xa4\xc6\xda\x48\x9f\x3a\x48\x8a\xe7\xf2\xba\x5c\x5f\xc8\x3a\xfd\x12\xe8\xc7\x7d\x0e\x60\xaf\xbb\x49\x5e\x79\x8b\x74\x6f\x1f\x72\x7a\xfb\x8e\x93\x5e\xce\xa7\x15\x46\xf2\x60\xf9\x52\xec\x67\xe4\xd9\x4d\xea\x25\x7b\x81\xbc\xcc\xf2\xab\x22\xf8\x17\xe5\xed\x11\xc1\x0c\xe1\x4f\x05\xdf\xab\xdf\xae\xcc\xe3\x1f\xeb\x9f\xd1\x16\xd0\xa8\xd8\x1a\xeb\xd1\x95\xc0\xfa\x83\x74\x89\x7d\x5f\xfd\x17\x00\x00\xff\xff\x42\x0d\x06\x12\xe5\x1f\x00\x00")
+
+func fontsStarwarsFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsStarwarsFlf,
+ "fonts/starwars.flf",
+ )
+}
+
+func fontsStarwarsFlf() (*asset, error) {
+ bytes, err := fontsStarwarsFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/starwars.flf", size: 8165, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsStellarFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\xcb\x8e\x1c\x45\x10\xbc\xcf\x57\xe4\xc1\x57\x0a\xb3\x42\xc2\xdc\x9a\x03\x3e\xf9\xb4\xf0\x01\x65\xa4\x35\xb2\xb4\x02\x09\x7c\x81\xaf\x47\x33\x53\x8f\x88\xc8\xa8\xee\x99\x65\xe5\xf5\xba\xbb\xaa\xbb\x2a\xdf\x19\x99\xd5\xfb\xe9\xf9\xd3\xc3\xc7\x37\xf1\x2e\x7e\x88\x87\xb7\xf1\xcd\x77\xf1\x70\xfa\xe5\xd7\x9f\x3f\x7c\xf8\xe9\x31\x7e\xfb\x27\x1e\xff\xfc\x23\xde\xff\xf5\xf9\xcb\xbf\xf1\xee\xdb\x1f\xbf\x3f\xbd\xff\xfc\xfb\xf3\xd3\x97\x78\x7c\x7a\x7e\xfa\xf8\xf7\x53\x3c\x94\xb7\xa7\x37\x9b\xf9\x8d\x6d\x3b\xd5\x52\xf8\x12\xed\x12\x11\xed\xd9\x79\x74\x79\x58\xcb\xb8\x45\x5c\xde\x1f\xdf\xda\xbd\xff\x9c\xa7\xb5\x94\x68\xd7\x0b\x87\xf3\x4f\x5c\xee\xe9\xed\x9d\x8b\x91\xd1\x65\xde\xdf\x5c\xa4\xbe\xaa\x56\x44\x8e\xb6\xaf\x9b\xa0\xad\xcb\x54\x51\x93\x46\x67\x2c\x85\xb5\x93\x68\x63\x75\xe1\x5e\xfc\x36\x92\x74\xae\x1d\xb2\xcc\xfd\x65\x6e\x97\x75\xb0\x77\x12\xbc\xbe\x69\x8e\x5a\x5f\x9a\x98\x8d\x5c\xa3\xaf\xb7\x21\x6f\x67\xd7\x39\xb8\x97\x74\x23\xa2\x6c\x44\xd1\x64\x5c\xba\x3e\xcd\x61\xdd\xe7\xd1\x3c\x6f\xde\x9b\xfd\x4c\xdf\x84\x05\x46\x63\xe4\x40\xe8\xb6\xee\x6c\xf7\x96\x65\x6a\xc8\x68\xe7\x32\x5c\xd4\xb7\xe5\x3b\x71\x37\xef\xef\xe2\xc4\xc6\x07\x2d\x5e\x10\xc1\xa2\xad\x24\x39\x10\x44\x42\x18\x55\x83\xf5\x20\x37\x23\x06\xc5\x6a\x91\xaf\x7e\xdc\x06\xc8\x48\x18\xba\x5b\x05\x23\x92\xa4\x33\x8b\xae\x94\x8c\x6d\xd0\x22\x68\x87\x89\x45\x9c\xcb\x06\x25\x8c\x61\x39\x38\x09\x67\x7a\xea\x17\x0d\x2f\x6b\x63\x0e\xc3\x8a\xb3\x9e\x20\x9c\x21\x90\x4f\x39\x5b\xbc\x8d\x49\x93\xc2\x11\x20\xee\xf1\x9a\x78\xbc\xb3\xc1\x82\xd6\xc6\x08\x9c\xfe\xc9\x41\xd4\x97\xe5\x22\x20\xce\xae\xa3\x76\xa0\xda\xc9\xd9\x6c\xd2\xc5\x78\x4f\x93\x3e\xf1\x41\x1f\x53\xde\xf0\x9a\x80\x29\xf6\x9c\x9f\x1c\x3c\x6d\xce\xda\xd5\x62\xa1\x8b\x8d\x6d\x9d\xbf\x46\x12\xc1\x94\xc3\x85\x00\x73\xc3\xfe\x52\xe2\x15\x5b\x50\x4a\x13\x59\xc6\x36\x30\xa8\x85\xa0\xd3\x3e\x49\x83\xfb\x05\x38\x50\x81\x08\x0b\xb1\xed\x94\x49\x4d\x4f\xce\xdd\xf6\x99\x54\xb5\x41\x01\x13\x27\xb8\xfd\x81\x0a\xd9\xb2\xa5\x32\xe8\xd6\x5a\x13\x76\xfb\xa6\x6a\x46\x39\x84\x54\x08\x12\xb8\x30\xa3\xca\xd2\x93\x91\x71\x55\xcb\x42\x72\x37\xf9\x6a\x62\x1a\x6e\x9d\xbb\x1a\xfc\x84\xe2\xfb\x4c\x11\xe8\x2f\x5c\x6a\x4b\x86\x51\x63\x46\xee\x96\x31\xae\x8f\x91\xd5\xc2\x60\xc0\xfc\xd8\x4c\xca\x23\xb3\xc5\x18\x0a\x5c\x02\x8d\x0d\x4a\x94\x82\x36\x0c\xbb\x64\xbb\x0b\x34\xe1\x5e\x85\x70\x8a\xb0\x0d\x6d\xd5\xc3\xd6\x44\x84\x9d\xf4\x2a\x3f\x8c\x04\x71\x66\xe0\x54\x10\x73\x67\x32\x8b\xc6\x8d\x7b\x12\xa3\xa3\x0b\x24\x16\x75\x1f\x47\xa3\x5a\xb0\x6f\x2a\x7a\x5a\x81\x9c\x83\x83\x07\xb5\x25\x2d\x2f\x2a\xbb\x05\x97\xad\x2a\xae\xb3\xe5\x2d\xce\xbe\x37\xcc\xda\xa4\xeb\x3b\x7d\x3d\xb5\xa8\xe0\x03\x06\xb9\x81\x43\x86\x14\x4d\x23\x92\x46\xc5\xf3\x05\xe3\x31\x57\x66\xca\xf9\x1a\xc4\x32\x71\x9c\x58\x93\x3b\x1f\xb1\x7e\x96\xdf\xcf\x03\x5b\x82\x70\xf4\x8d\xc6\x92\xb1\x0e\x73\x72\x56\xef\x81\xe0\x52\x43\x51\xf0\xc8\x3d\xc9\x5b\x75\x74\xb0\x50\xb0\x34\xcf\xcf\xbe\x27\xcd\x58\x37\x37\x0b\x0d\x4f\xad\xeb\xea\x0e\xef\xcb\x2e\x0d\x9b\x4f\xaa\xaa\x54\xf5\x0c\xfd\x48\x27\xf9\x2a\xb8\x9f\x61\x62\xaf\x33\x23\x86\xd9\x19\x2f\x9e\xdc\x80\xca\xc6\x66\xc3\xd9\x18\xd8\xbe\xb9\x18\x09\xc9\xaa\x49\xf0\xbb\x0a\xe4\x04\xd9\xc9\xb7\xca\x3d\x41\x02\x09\x04\x86\x59\xcc\x7c\xbe\xae\x04\xa0\x16\xad\x40\xbb\xa9\xfa\x46\x98\x77\x16\xc2\x6d\xd4\x5a\x86\x64\xf4\x15\xc3\x7b\x66\xcc\x30\x1d\xc8\xc0\xa9\xc6\xa3\x11\xe6\xd0\x52\xa5\x15\x28\xa6\x94\x00\xc3\xa6\xe8\xe1\x2d\x7d\xea\x12\x76\x7a\x40\x48\xb2\x42\x4a\x2d\xcf\x2d\xf8\x19\x73\xff\x66\xbe\x61\x54\x86\xd2\x7a\x50\xa6\x5f\x32\xe9\xb3\xfb\xef\xed\xcb\xd5\xe8\x72\xf2\x09\x91\x2f\x84\x70\x3a\x9e\x9a\x8e\x34\x73\x0d\xb3\xc4\x6a\xc9\xa8\x09\xd2\x2d\x86\x64\x45\x6e\xb4\x69\x41\xb6\x91\x1c\x28\x2b\x76\xa3\x83\x0d\x3c\x99\x6b\x98\xd0\xba\xef\x43\x30\xb1\x1d\x20\x3b\xfd\x76\x9b\xea\x41\x82\x8e\x48\x31\xfb\xe8\x65\x51\xdf\xfa\x81\xf3\xbc\x6d\xfc\x81\x80\xd0\x6a\x31\x48\x92\xea\x90\x91\x4c\x3d\x02\x4f\xbb\xa1\x28\x33\xc1\x1a\xa7\x99\xb9\x38\xa2\xcf\x30\xc9\xba\x25\x9c\x4d\xf1\xcb\xfa\x41\x3f\x3f\x94\xb0\x73\x7b\xbf\xf6\x9e\xdb\x4a\x60\x39\xc4\x37\x93\x17\x8a\xe0\x95\xe8\xc3\x66\xeb\xeb\x8c\x49\xff\x91\x21\xc8\xa0\xa3\xc2\x81\x87\xc4\x35\x7e\x7a\x55\xb2\xaa\x90\xfb\xe1\x50\xf5\x83\x41\x8a\x01\x32\x4f\x22\xfe\x62\x94\x11\xea\xb6\x7f\x4b\xf1\x86\x72\x4f\x5c\x99\x84\x15\x55\xac\xc3\x3d\xc1\x00\x5c\x41\x82\xd3\x11\x95\x3a\xe3\x31\x2a\x8b\x8f\x65\x0a\x57\x79\x50\x25\xff\x3d\xee\xd5\x42\x9f\x88\x3b\x72\x04\x20\x85\xe2\xd4\xe6\x80\xe1\x36\x14\xa1\xe2\xba\x36\xbe\x1e\xd5\xfc\x28\x9a\xd9\x16\x00\xaa\x65\x92\xeb\xac\x2d\x40\x43\x48\xd3\xc7\xf8\x3a\x6b\x38\x31\xab\xc1\xab\x30\xec\xcf\xd9\xf5\x17\x52\x20\x52\x2d\x3c\xc8\x30\x44\x74\x08\xf6\x98\xd5\x42\x8a\xee\x22\xc3\x96\x84\xab\xfc\x91\xb5\xe4\xbe\x49\xc2\x6f\x9f\x30\x05\x94\xa4\xe7\x26\xdf\x66\xdd\x57\x86\x90\x43\x33\xc5\x21\x53\x91\xda\x25\x71\x7c\xfd\x9a\x78\xfd\x7f\xdd\x4d\x73\x4d\x8b\x15\x39\x23\x44\x48\xea\x0d\x30\x9d\xde\x11\x1c\xfd\x5f\xe3\xed\x24\xff\xbe\xd6\x83\xff\x02\x00\x00\xff\xff\x45\xa0\xfc\xc0\xe6\x20\x00\x00")
+
+func fontsStellarFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsStellarFlf,
+ "fonts/stellar.flf",
+ )
+}
+
+func fontsStellarFlf() (*asset, error) {
+ bytes, err := fontsStellarFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/stellar.flf", size: 8422, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsStopFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x58\xc9\x6e\x1c\x37\x13\xbe\xcf\x53\x7c\xc0\xcc\xa1\xfb\x32\xfc\xed\x3f\x0b\x0c\x08\x82\x03\xf8\x6a\x1f\x12\x20\xc9\x81\x40\x61\xa2\x91\x12\xc1\xb6\x14\x48\x1a\x05\x01\xf8\xf0\x01\x6b\xe1\xd2\x4d\xf6\xf4\x58\x90\xd4\x6c\x36\x59\xac\xe5\xab\x85\x75\xf7\xe5\xee\xed\x61\x87\x1f\xf1\x03\xde\xfe\x0f\x6f\xbe\xc7\xff\x37\xbf\xbc\x3c\xfe\x8d\x3f\xfe\xc5\x87\xc3\xeb\xfd\x11\xbf\x1d\xbe\xbc\x3c\x3e\xe0\xea\x1f\x7e\xbe\xbf\x79\xde\x9f\x6e\x8e\x87\xd7\xfb\xe7\xfd\xed\xf1\x74\xbd\xf9\x70\xfb\x74\xff\x7a\x7b\xc4\xdd\xd3\xe3\x57\xfc\xfc\x78\x7a\x38\xde\x1e\xe3\xe6\x4f\xf7\x37\x9f\xf1\xf1\xfe\xe1\xf6\xe9\x19\x9f\xf6\x1f\xf7\x32\x7c\x7f\x3c\x3d\xfd\x75\xf8\xba\x3f\xdc\xec\x4f\x9f\x37\x6f\xdf\xe0\xa7\xd3\x9f\xa7\xe7\x17\xbc\x79\xf7\xee\xbb\xcd\x6e\xb7\xed\xfd\x6d\x37\x20\x6c\x37\x01\xc1\xfe\x51\xb0\x39\x1e\x01\xb2\x86\xa7\x06\x8c\x03\xc6\xed\x26\x38\x04\x07\xfe\x1a\x17\xf4\x9e\x3c\x20\xde\xcb\xb3\x14\x80\x10\x10\x98\x54\x9c\x0b\x01\xa0\x71\xf1\x0b\x02\x51\x08\xf1\xbb\x91\x2d\x69\x27\xba\x41\xa4\x00\x51\xdc\x15\x28\x9e\x1a\x94\x96\xc8\x51\xd3\x50\xa1\x44\x2a\x1a\xc1\xb2\x03\x70\x10\xb9\xe2\x33\x0e\xe2\x53\x95\x81\x41\x18\xca\xe7\xf3\x29\xb2\x8a\xe0\xc1\x0a\x8a\xc4\xc6\x38\x37\x82\x30\xe8\x9c\x03\x7c\x9c\xf3\x44\xce\x17\x54\x60\xfa\x37\xad\x8a\xc2\x27\xff\x4c\x8d\xc2\x17\x6f\x57\xf6\x86\x78\x02\x13\x86\x97\xef\x9e\x32\x79\x26\x2e\x1c\x0e\xca\x5f\xe4\xc3\x0b\xd9\x11\xac\x78\x11\x78\x20\x72\xb5\xe1\xc4\x6a\xc2\x9b\x0f\xd1\xdc\x23\x9f\x13\x67\x65\x07\x8b\xaa\xdc\xc4\x1f\xcf\xb3\x2e\x50\xa8\x44\x54\xfe\x13\x30\x26\x36\x13\x0b\x8d\x0d\x0b\x55\xaa\x6e\x68\xa6\xd2\x9b\xae\xce\x0f\x22\xa1\x9e\xf5\x31\x79\x2c\x51\xd5\x3d\x46\x95\x74\xd3\x12\x48\xa0\x20\x99\x71\x4e\xfc\xa3\x28\x61\x68\xb3\xa7\xc1\x39\x73\x3a\xe7\xa0\x43\x38\x22\x39\xc4\xf3\x2e\x87\xa9\x1e\x8d\x52\x5c\xe4\xc8\x09\x43\xa1\x7e\xa8\xdf\x1a\x00\xf8\x78\xd5\x05\x91\x9a\x3f\x0e\x05\x01\x2e\x9f\x44\x89\xd7\x41\x87\x53\x3b\xea\x34\xe5\x15\x4e\xd1\x29\x67\x00\x43\x3a\x83\xd2\x19\xba\x76\x2e\x8d\x28\x24\xeb\xd2\xb4\xa9\x5c\x88\x1b\xc3\xb8\x88\x5a\x33\x4b\x4c\x02\xc2\xb6\xcb\x7d\x5b\xfe\x35\xbc\xc1\x44\x4a\x76\x66\xd6\x90\x4c\xe9\xd5\xe1\x55\x91\x7e\x4a\xa7\xcf\x94\xa2\xca\xd6\x3a\x89\x18\xe5\x49\x18\xc8\x61\x26\x22\x92\x30\xcc\x41\x62\x21\xb9\xf3\x35\xae\x71\x85\x2b\x63\xac\xe4\xac\x09\x26\x5a\x14\x07\x8a\xf3\x42\x01\x13\xae\xb6\x1d\xdf\x99\x7b\x51\x67\xcd\xc4\x7f\x65\x9d\x06\x9e\xa8\x17\x0e\x3b\x03\x86\x28\x24\x33\x35\x96\xc1\x65\x12\x23\x1a\x8e\xdf\x0f\x03\x25\x11\x52\x6b\x0c\xf0\x83\x00\x64\xc4\xa8\xf0\x70\x43\xa9\xb9\x3a\x81\x14\xc8\xb2\xb0\xaa\x86\x10\x55\x95\x01\x8f\xc3\x65\xbd\x7f\xa7\xe3\x1d\xce\xbf\x50\x20\x79\x91\x18\xc2\x5f\x76\x1c\x6e\xe3\xef\xae\xde\x53\x18\x88\x59\xf1\xc9\xc9\x34\x0d\xb8\x38\xe7\x25\xf1\x6b\xc8\x09\x02\xcf\xd0\xc2\x6f\x72\x1f\x64\xf7\x19\xc1\xb6\x13\x37\x19\x8c\x94\xce\xf6\x9c\xaa\x0e\x86\x9a\xac\x35\x7f\x08\x89\x3c\xf4\x69\xad\x5f\x08\x46\xc8\xbc\x79\xb3\x25\x92\x6c\x16\xb4\x99\x37\x09\xdb\x41\x59\xbb\x20\x7c\x28\x43\x10\xa9\x95\x5a\x0e\x51\x0b\x81\x72\x25\xb5\x24\x34\x85\x09\xcc\xce\xe9\x4d\xb9\x40\xc0\x60\xb3\x12\x87\x16\x92\x08\xc7\x5c\x2b\xfb\x2a\x0d\xa5\x3c\x44\x34\xda\x6c\x5a\xc0\xbc\x85\x12\x20\x85\x15\x4c\xce\xb1\x82\xbc\x45\xec\x9c\xec\x6b\x5d\x6d\x53\xf2\xa0\x94\x3c\xf2\x77\x4a\x8a\x48\x74\x18\xab\xc9\xe2\x8d\x08\x49\x95\x68\x4e\x20\x1a\x34\x63\x07\x84\x18\x1c\xf5\xab\x82\x24\x8a\xd5\xa8\xc9\x9a\x90\xec\x0c\xd7\x81\x21\x9b\x3d\xa1\x33\x29\x3c\xc8\x6f\x3d\xe4\xba\xb7\xa3\xf0\x16\xb5\x6c\xc9\xd6\xb0\x63\xbe\x66\x4a\xe9\x52\xa3\x33\xf5\xc9\xb9\x6c\x2b\x1c\x93\xbb\x04\xf6\x67\x79\x63\x99\xbc\xb0\x64\x45\xf0\xa2\x15\x96\x2a\x01\xc9\x33\x40\x51\xee\xb5\xf5\x26\xf8\x94\xc5\xc2\x88\xcc\x7a\xab\xb4\x53\x1c\x5a\x51\x6d\x74\xc2\x45\x07\x85\x67\x03\x63\xc7\xc1\x57\xd9\x74\x8e\xb7\x8a\x58\x26\xa0\x9b\xe0\xad\x1c\xf6\x48\xd5\x8b\x9f\x97\x09\xf9\x42\xd1\x81\x3b\x18\xee\x97\x32\xe5\xe5\x58\x57\xb3\x32\x42\xee\x5e\x39\xd1\x71\xe5\xe2\xc9\xb7\xfc\xbc\x15\x0a\x5b\x38\x4f\xf7\x3d\xad\xad\xd6\x59\xf1\x5c\x95\xbb\x50\x6b\xab\x8f\x6b\x10\x43\xf9\xb0\x78\x33\x96\xb5\x7e\x8d\x16\x51\x09\xf2\xbd\x4f\x6d\x93\x4a\x95\x12\xd5\xdb\xa2\x58\x42\xe3\x5a\x21\xfa\x18\x0a\x53\x6c\x53\x6d\xc1\x92\x39\xcf\x64\x87\x49\x84\x5f\x18\x94\xf2\xae\x18\xf6\xb4\x5b\x5a\x53\x2b\x4a\xf8\xb0\xed\xde\xa4\x67\xdc\x14\xa9\x55\x9a\x06\x18\x0c\xdc\x75\xfc\x6d\xea\x58\xe2\xb8\xc1\xda\x6a\xaa\x31\x95\x41\xae\x25\x71\xef\x7c\x96\x49\x4a\xf7\xe4\xdf\xd3\x74\x39\xbb\x8f\x6a\x16\x81\x53\x4f\x8a\xfb\x0b\xf4\x86\x0b\xce\x87\x96\xdb\xea\x47\xad\xf3\x0b\x66\x47\x2b\x1b\xac\x66\x30\xb5\x58\x48\xb7\x9d\xdf\xa4\x78\xc3\x5b\x94\x60\xb5\xe2\x73\xb2\x9b\x1b\xae\xbc\x78\x4c\x1b\x5e\xb9\xa3\xa4\xa5\x7a\xf1\xd6\xf6\x03\xd7\x87\x43\x0a\x28\x56\x7f\x5c\x49\x81\x4c\xa1\xaa\x34\x1a\xcd\xb7\x0e\x57\x53\xcd\x15\x05\x00\x66\x92\xd3\x54\xf2\xc5\xfd\x74\x5e\x73\x6d\xcb\x59\x5a\x4e\x90\xcf\x90\x3b\x0b\xf9\x85\xf3\x63\x16\x70\x45\x2f\x65\x1d\x72\xd2\xfe\x84\x1c\x68\x7c\x5b\xe7\x72\xd9\x7c\xad\x16\x4e\x39\x53\xba\x40\xd1\x6c\x54\xac\xba\x39\xe4\x0d\x24\x1a\xb5\x2d\xa4\x23\xfb\x0e\xeb\x6c\x5c\xf6\x15\x2a\xd2\x54\x4a\x52\x17\x38\xf9\x6c\x3f\x3c\x7e\xb5\xbc\x5d\xdd\x86\x7a\xfb\x69\x76\x3e\xbe\xe1\xfc\x78\xbd\x96\x56\xe2\x88\xdf\xd9\x2b\xe2\xf5\x7a\xea\x15\x97\xca\x8f\x14\x2b\xa6\xad\x84\x12\x71\x96\x3a\x20\x7d\x2f\x88\xb9\x7a\x77\x12\xcd\xd7\xfc\xc5\x2e\x1d\xd6\x6e\xd5\xfc\xdb\x68\xb7\x62\xde\x46\x9f\xba\xf3\xac\x25\x1b\xa9\xf3\x57\x6d\xc9\xca\xfb\xbc\x25\xab\xad\x74\xe9\xff\x79\xa7\xed\x09\x3f\x69\x3a\x2d\x8f\xaa\x9a\x87\x1b\xb8\x29\xd8\x39\xe4\x36\x01\xe5\x3e\x01\xd9\x3d\x69\xa1\x10\x33\x6a\x44\x34\xd0\xb8\x50\xae\x9f\xbd\x3f\x54\xbc\x59\x20\x5e\x59\xa5\x35\x79\x33\x5a\x2a\xe5\xc5\xb9\x7e\xbe\x7f\x7d\xe0\x9b\xef\xbf\xd0\x8d\x1b\xa7\x61\xac\x73\x4a\x9a\xa1\x30\x4c\xce\xff\x2f\x00\x00\xff\xff\xc9\x25\x1d\xe0\x82\x1a\x00\x00")
+
+func fontsStopFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsStopFlf,
+ "fonts/stop.flf",
+ )
+}
+
+func fontsStopFlf() (*asset, error) {
+ bytes, err := fontsStopFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/stop.flf", size: 6786, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsStraightFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x55\x4d\x6f\xe3\x36\x10\x3d\x87\xbf\xe2\x1d\x78\x90\x81\x48\x74\xd3\x9c\x82\xa2\x10\x8a\x5e\x7b\xe9\xa1\x68\x01\x02\x84\xe2\xd0\x89\x1a\x5b\x5a\x58\xce\xee\x06\x98\x1f\xbf\xe0\x0c\x45\x49\x94\xbc\x80\x2d\x52\xf3\xf1\xe6\xcd\x07\xa9\xe3\xe9\xf8\xd0\x68\x3c\xe2\x57\xfc\xb2\xc7\x1e\x8f\x6a\xb8\x5e\x9a\xf6\xf5\xed\x5a\x1d\x4f\xc7\xbb\xbb\x7f\xfc\x65\x68\xfb\x0e\x0f\xea\xf9\xf3\x09\xf8\xa3\x19\xf0\x97\x6f\xff\xf7\x17\x00\x67\xde\xd4\x6d\x77\xec\xab\x6f\x6d\x57\x5d\x3f\x7c\xd5\x9d\x00\x3c\x37\x43\xfd\xd2\x9c\xfd\x7b\xf5\x7e\x7d\xab\x06\xaf\x8e\xed\x77\xff\x82\x80\xf0\xf7\x67\xd3\xe1\xbf\xfe\xe3\xf0\x0e\x7c\x86\xa5\x3e\x0c\xd5\xc7\xc5\xbf\xb6\x5d\x53\x1d\x1a\xf5\x67\x3b\x1c\x4e\x4d\x7b\xf6\x97\x27\x9c\xfb\xe1\x8a\x43\xf3\xa5\xbd\x36\xa7\x01\x6f\xcd\x57\x8f\x67\xef\x3b\xbc\xf8\xa1\x7d\xed\x18\x10\x43\x7f\xf6\x7d\xe7\xe1\x4f\x83\x57\x5a\xd7\xf3\x7f\xad\x80\x5a\x11\x6a\x55\x81\xf7\xb5\x32\x06\x41\xc5\xaf\xf1\xc1\x4f\x7e\x73\xe4\xc8\xa1\x56\x25\x95\x54\x22\xc9\x6b\x05\x62\x79\x41\xa4\xd9\x8c\x76\x60\xe1\xe8\x5d\xab\x7d\xc0\x35\xfb\x05\x64\xad\x8a\x5d\x10\x17\xff\xc6\x50\x4c\x20\xc4\x8f\x7f\x16\x68\x36\x61\x91\x4d\xee\x96\xdf\x43\x14\xa3\x93\x50\x03\x21\x2f\x6b\xc2\xd3\x58\x1d\x25\xbc\xb0\xc6\x91\x63\x21\x41\x8f\xc2\x5a\x21\xd6\xe3\x5e\xf3\x3e\xc1\x38\xa7\xd3\x3e\x5a\xca\x5e\x87\x72\x69\x79\x8d\xd9\x31\xc7\x05\x13\xe7\xa2\x1c\x96\x99\x3b\x27\x89\x21\x51\x65\x35\x41\xf8\x44\x09\x87\x65\x0d\xdc\x8e\x0d\x9c\x1b\xdd\xd6\x4a\x27\xcb\x0c\x92\xb5\xe4\xdc\x08\x48\xcb\x98\x02\x46\x02\x92\x7b\x8f\x8c\xe3\x6a\x67\xfa\x18\x3b\x52\x91\x44\x0c\xb6\xbc\x8b\xe8\x55\xe4\xde\x33\x03\x2b\x29\x2c\x0b\x82\x38\x84\x69\x10\x47\xc1\x7d\x9a\x03\xae\x3e\xf7\xd6\xc6\x3e\x64\xbd\x2a\xcb\x79\xcb\x93\xa1\x99\x59\xc7\x14\x76\xe1\x59\x4d\x55\xc7\xf4\x8b\x53\xcd\x13\x14\x16\x53\x96\x76\x1c\xf5\xa9\x05\x24\xf9\xc5\x65\xae\x0c\x13\x1c\x2c\x2c\xef\x33\x2f\x99\x06\x92\xdc\x97\x5e\x34\xe2\x2e\xbd\x92\x02\x58\xc1\x19\xb8\x18\x69\x41\x42\xe8\xc7\x29\x20\x19\x82\x49\x29\xe7\x9d\x52\x99\x35\xe3\xea\x20\x98\x70\xd2\x84\x12\x33\x25\xd8\x95\x02\x6b\xba\x31\xb0\x35\x9b\x81\xa3\x12\xa2\xb4\xb4\x2e\x6a\x3c\x2c\x76\x5d\x9e\x59\xc5\x23\xe1\x1b\x9e\xf6\x67\x9e\x36\xf7\xac\x55\xc1\x16\x8b\xc4\xe3\x9c\xf3\x4d\x06\xc2\x2a\xbf\x1b\x2c\x45\x69\xe5\x78\xc0\x1a\x6c\x24\x2f\x25\x21\x63\xf3\xca\x04\x38\xbe\x42\xd6\x85\x16\xc5\x82\x48\x64\x28\x1e\xf3\x0e\xf0\x78\x33\x71\x72\xf3\x9b\x96\x79\x05\x56\x49\x28\x87\x91\x9b\x4e\x4b\x4b\x63\xe7\x1f\x80\xd9\x67\x40\xb9\x09\xd3\xe6\x97\xb4\x24\x28\xf3\x58\x8c\x90\x93\x62\x1c\xee\xdd\x42\x11\x09\x17\x2e\xfb\x2a\x80\x01\x72\x98\xd1\xba\x9c\xac\x93\x37\xe9\x15\x84\x30\x09\x01\x9d\x59\x33\xc1\x82\x89\xdc\x34\x94\x5f\x3d\xc4\x1d\x19\xa3\x4b\x5d\x8b\x59\xa0\xfc\x28\xcd\x22\x13\xad\x6a\x80\xad\xc8\x39\xd7\x2d\x8f\x38\xbd\x37\xeb\x4c\xcb\x02\x51\xde\xbb\x20\x1c\xc1\x53\x32\x6e\x35\x24\xdc\x4e\x99\x9d\xbc\xf0\x3c\x0e\xe3\xd1\xca\xac\xed\xce\x6c\x59\xef\x8a\x65\xc0\x09\xc2\x4c\x42\x39\xbb\x13\x8b\xe0\xf3\x1b\x64\x65\x01\xe5\x35\x0e\x69\xfc\x0e\x59\x67\x54\x4c\x3a\xf7\x89\x4a\x0f\xf4\xe1\x6d\xf3\x16\xef\x9d\xeb\x6f\x1e\xe5\xe8\xb9\xad\x94\x18\xa5\x2b\xb7\x07\x7d\x54\xac\x7a\x59\xa2\x5c\x95\x76\xeb\x53\x42\x51\xf9\x23\x00\x00\xff\xff\xfc\x24\xb9\x78\x77\x0a\x00\x00")
+
+func fontsStraightFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsStraightFlf,
+ "fonts/straight.flf",
+ )
+}
+
+func fontsStraightFlf() (*asset, error) {
+ bytes, err := fontsStraightFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/straight.flf", size: 2679, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsTanjaFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x99\x7d\x57\xda\xca\x13\xc7\xff\xcf\xab\x18\x2f\xb5\x87\xf1\x54\xa8\x88\xc5\x9e\xc3\xd5\x20\xde\x62\x51\x14\x05\x45\xad\x1e\x2e\x02\x2a\x2a\x20\x20\x22\xb5\xfe\x5e\xfb\xef\xcc\xec\x43\x9e\x76\x11\xef\xf6\x98\x7c\xf6\x3b\xdf\x99\x24\x9b\x6c\x42\xd2\xeb\x87\xeb\x54\xe3\x13\xac\xc3\x37\x48\x7d\x85\xe5\x15\x48\x39\xd5\x46\xef\xae\x01\x93\xc6\x08\x26\xc3\xce\xd3\x53\xbb\x07\xd7\xfd\x21\x2c\xff\x2d\xf4\xbd\x69\xaf\xf7\x02\xc5\x46\xf3\x7e\xd4\xef\xfd\xbd\x0c\x57\x53\x27\x7f\x3b\xec\x8c\x9e\xfa\x8f\xb7\xed\x21\x14\x13\x50\xee\x0c\x3b\x0f\x0f\x7d\xf8\xab\x7a\xdb\x86\xbd\x7e\xf3\xbe\x3d\x84\x42\xaf\xdf\x6d\xff\x05\xd9\x47\x8e\xa5\xd3\x6e\x67\xd4\x1c\x8d\xc6\xbd\xc4\xb8\xd7\x49\xb4\x5b\xe3\x0d\xe7\xd3\xa7\x4f\xee\x1c\x0b\xd7\x81\x05\x04\x70\x9d\x05\x5c\x59\xf1\x56\x52\x04\x6a\x91\x1e\xaf\x5c\x67\x69\x69\x09\xe8\xcf\x75\x62\x31\x00\xfa\xf3\x13\xc8\x36\x37\x11\xc6\x10\x56\x57\x59\x8e\xe1\xaa\x68\x10\xd4\xe7\xf3\x44\xcb\xcb\x0d\x40\x05\xa5\x5e\xc1\x74\x3a\x9d\x26\xac\x20\x10\x84\x54\xe1\x4d\xa7\xd9\x90\x0e\xaa\xc1\xca\x54\x78\x91\xc4\xb5\xb5\x35\x70\x1d\x8d\xd2\xb3\x88\x6b\xd2\x2f\x88\x59\xa0\xf4\x4b\x9c\xb9\xe7\x9f\x31\x93\x11\xfa\x67\x04\x60\xb6\xa9\x84\xcc\xd2\x90\xc9\x64\x02\xbb\x1b\xd8\x73\x71\x02\xe9\x9c\x89\x93\x27\xa2\xd6\x25\xaf\xe2\x48\xdd\x38\xb2\x1c\x97\xc3\xa1\xd6\x4a\xd7\xbe\xc0\x46\x5d\xd7\x41\x3d\x7e\xa8\xae\x2a\xc4\xc0\x5a\xe8\x18\x18\x67\x5f\x01\x5a\x2d\xc9\x20\xad\xd7\x01\xd6\xd7\xd9\xb0\x84\xeb\xd4\x63\x7d\x5d\xb4\x88\xee\xf7\xcb\x32\x86\xcb\x24\xa0\xf2\xd5\x15\x13\x97\x1c\x37\xbf\x62\x32\xfb\x0b\x99\x96\x96\x41\x7f\x6f\xaa\xc4\x7c\x5b\x9f\xe5\x0b\x1e\x4a\x64\xa1\xa6\xac\x4f\x93\x39\x49\xdc\x94\xe9\x44\x02\x99\x18\x05\x11\x4a\x02\xd7\x51\x64\xbf\xc0\xe0\x2b\xa2\x38\xa1\x5f\x91\x4e\x2d\x0a\x42\x88\x10\xaa\x0b\x40\x67\x58\x0e\x69\x05\x17\x84\xb8\x82\x0b\x0b\x2a\xbc\x82\x56\x22\xdb\xc2\xc2\x82\xb5\x60\x0a\x73\xb9\x1c\x89\x29\xf2\xe7\x72\x32\x9c\x52\xfb\x90\x52\x05\x53\xf2\xaa\xe3\x04\xed\x8b\x16\x5c\xc5\x98\x38\xad\xab\x94\xa0\x86\x7a\x15\xbd\x1b\xe3\x2a\x06\xa3\x3a\xc3\x58\x30\x4d\xc6\x4a\x05\x82\x54\xa1\xa6\x8c\x69\x9c\x45\xe1\x82\x6b\xb8\xb8\xb8\xb8\x48\xe2\x1a\xaa\xb0\xa7\xb1\xb0\x86\x01\x0a\x45\x23\x87\xfc\x0d\xf7\xf7\xf7\x49\xfc\xa6\x0b\xb2\xe4\x69\xfb\xfb\x01\xf2\x32\x8c\x05\x33\xf8\x99\x9a\x14\x33\xea\x54\x64\xd4\xa9\xc8\xa8\xbb\x43\x46\x4d\xe1\x0c\xce\x9e\x09\xeb\x48\xd3\x0e\x5c\x67\x9d\x8c\x62\x06\x1a\x34\x53\xd4\x5c\xf0\x3b\xc6\xe3\x71\x12\xbf\x53\x4a\x3c\x0e\x4a\x8b\x2b\xe3\x77\x34\x44\xe7\x98\xab\xde\xe4\x0c\x4e\x53\xc7\x70\x5b\xd1\xf7\x83\xd9\xb7\x95\xac\x38\x9d\x59\x31\x90\x59\x31\x8c\x59\x35\x88\x59\x35\xac\x59\x35\xd0\x59\x0c\xdf\x72\xc3\x63\x6b\xba\x1b\xcd\x79\x87\x72\x9d\x0d\xb5\xe5\x0d\xb5\xe5\x0d\xb5\xe5\x0d\xf4\xf7\x65\x7c\x23\xf8\x30\x70\x1d\xd8\xc4\x64\x32\x99\x24\x6d\x93\x63\xc9\xa4\x0c\x6f\xea\xe9\xbf\x19\x79\x52\xdb\x55\xaf\x70\x0e\x53\xa9\x14\xa9\x39\x36\xa6\x04\xa5\x48\x14\xa4\x35\x10\x1a\xe4\xc2\x4f\x91\xd0\x69\xcd\x61\xa3\x21\x54\x72\x12\xab\xe2\x8d\x06\x63\x83\x5b\x58\xd5\x68\xd9\xd3\x2d\xbc\xba\xba\xba\x62\x79\x8b\xcc\xc4\x76\x15\x04\x2b\xc3\xd5\xac\x21\x80\x3c\x36\x9b\x4d\x96\xf3\x94\xd8\x6c\x82\xeb\xe4\x51\x9b\x7d\xe8\x33\xf8\xd3\xcc\x85\xb7\xb1\xd5\x6a\xb5\x58\xde\xa6\x34\x62\x89\xc4\x76\x6c\x89\x3c\x6b\xe1\x7f\xb0\xcd\x0d\x08\xb5\x43\xaa\x10\x56\xc3\x86\xb6\xbd\xf0\x0f\xbc\xe6\x06\x84\xda\x21\x55\x08\xab\x26\xb4\x8e\x71\x01\x6f\x6e\x6e\x6e\x48\x2e\xe8\x3b\x17\x11\x89\x12\xa9\xa3\x0d\x02\x45\xda\x8c\xc2\x3b\x9c\x77\x7b\x0b\x21\xbc\xe5\x16\x56\x4d\x68\x29\xfc\x13\x3b\x9d\x4e\x87\xc5\x9f\x6a\x8a\x59\xc1\x67\x0e\x96\x72\x5d\xa7\x88\x77\xdc\xa4\x58\xd4\xf3\x55\x21\xad\xee\xee\xc2\x08\x94\x37\x73\x4c\x77\x29\xfd\xfe\x9e\x64\x42\x22\xc6\x7b\xa6\xb0\x1a\xf0\x32\x5b\x0b\xef\x79\xa7\xf3\x63\xf8\xc0\x6d\xc6\x55\x50\xc2\x6e\x17\xba\xdd\x2e\x05\x4a\x08\x40\xd4\xed\xbe\xdb\xa1\x16\xed\x00\x98\x36\xc3\x1b\xda\xc7\x1e\x00\xf4\x7a\xc0\xd8\xd3\x48\x6b\x85\xd0\xeb\x69\x04\x1f\x0a\x83\xed\x08\x0e\xb0\xdf\xef\xf7\x49\x3e\x60\x73\xbf\x3f\x0f\xfa\xd2\x2c\x85\xcb\xf8\x48\x8d\xe4\x32\xe7\x3d\x3e\x82\x41\x05\x3b\xda\xf6\xf8\x10\x07\x83\xc1\x80\xe4\x43\x36\x0f\x06\x51\x1c\x0c\x40\xab\xc2\x2b\xd2\x58\xb5\x14\x3e\xc2\x21\x35\x92\x8f\xb8\xda\x70\x28\xd1\x53\x09\xb4\x21\xe2\xb5\xed\x71\x05\x47\xa3\xd1\x08\xc4\xbb\x2a\x00\x8c\x46\x20\x55\x9f\xb9\x82\x26\x83\x48\xb3\x14\xae\xe2\x13\x37\x21\x57\xbd\x07\xe3\x47\xd0\x54\xf8\x98\xc3\xe3\x31\x7c\x0c\xe1\x18\xc7\xe3\xf1\x78\x46\xe1\x13\x36\x3f\x3f\x83\x0d\x81\xf8\xf9\x59\xe4\x9d\x20\x91\x28\x71\x32\x7b\x8f\x6b\xf2\xba\x99\x4c\xc0\xd0\x99\x4c\xde\xed\x40\x0d\x27\x13\x98\x50\x7f\xe6\x4c\x3c\xe5\xda\x2f\x2f\x14\x20\x7e\x79\x11\x9e\x53\x24\x0a\xa1\x67\xf0\xa7\x99\x8f\xe0\x8c\x1d\xd3\x29\xc9\xc4\xd3\xa9\x70\x9c\x21\x91\x30\x9f\x79\x83\x60\x46\x53\xe1\x73\xfc\xcd\x4d\xcb\xe7\xea\xb7\xe1\xb9\xbe\x75\x9f\xab\x12\xe7\xfa\x59\x16\x49\x8b\x14\xfe\x85\xaf\xaf\x40\x2b\x8e\x58\x56\x6c\xf1\x27\xbb\xae\x73\x81\x7f\x74\x3d\xc5\x14\x95\xcc\x46\xc1\x22\x87\x59\xa6\x13\x5b\xf7\xe8\x12\xdf\xde\x58\xba\x44\xdb\x4a\x5b\x02\x7b\xc4\xaf\x0c\xe0\x7d\x00\x33\x3c\xf8\xe6\x81\x77\x7e\x37\xcf\xfd\x3b\xdc\x77\x48\xde\x17\xba\xe0\xcb\x82\x65\x69\xde\x46\x83\x5f\x78\x59\x6b\xa8\x97\xe5\x06\xbf\x2c\x7b\x9a\xf5\x75\xf8\x4a\x5f\x12\x7e\xda\xda\xda\xda\xd2\xda\xd6\x56\x88\x54\xd4\x58\xd0\x38\x1e\x4d\xcc\xe7\xf3\x79\x70\x9d\xa6\xde\x88\x47\x5e\xd4\x5e\xb0\xa5\xdf\x78\x04\xb5\x70\x7b\x7b\x7b\x1b\x5c\xa7\x45\x65\x42\xe4\x45\xe7\xde\xc3\x36\xfe\x43\x4d\x93\xd0\xb4\x4f\x8a\xb6\x82\xd7\xf8\xe3\xc7\x0f\x70\x9d\x6b\xf5\xae\x21\x84\xa0\x12\x86\x70\x25\xdb\xd8\xdd\x60\xa1\x50\x20\xba\xa1\xcc\x42\x21\x40\x22\x5a\x50\x19\x32\x5a\x10\x19\xae\x73\xab\x0f\xc1\x4f\x3b\x3b\x3b\x3b\x5a\xdb\xd9\xb1\x90\xf1\x50\xbd\x57\xde\x0e\x46\x17\xca\xad\x0e\xc5\x74\xe1\xdf\xe1\xbb\x74\x47\xfb\x50\x2c\x92\x76\x87\xc5\x62\x91\x0b\xde\xab\x71\x0b\xc0\xee\x2e\xc3\xee\xae\x52\x88\x7c\x21\xc3\x20\x3f\xe0\x1e\x0b\x0f\x68\x5d\x3d\xe0\xde\x9e\xe9\x36\x02\xd1\x31\x11\x9d\x2e\x96\x4a\x50\x2a\x95\xa8\xd3\x45\x00\xa2\x52\xc9\xd4\xa1\xc6\x1d\x6b\x35\xf3\x65\xd0\xd3\xdf\x6b\x7a\xa8\xbe\xd2\x98\xc8\x78\xd6\x8c\xd7\x55\x1f\x0f\x0e\x0e\x88\xfa\x94\x7c\x70\x10\x20\x2f\x3a\x77\xc1\x47\x2c\x97\xcb\x65\x41\x00\x50\x2e\x87\x28\x10\x85\x00\x59\xf6\x70\x80\x87\x87\x87\x44\x03\x32\x1e\x1e\x06\x48\x44\x0f\x55\xc6\x00\xfd\x64\x29\x38\xc4\xa3\xa3\x23\xa2\x21\x95\x39\x3a\x52\x04\x10\xa0\xf9\xc7\x70\x84\xf2\x33\x9f\x04\x15\x1d\x61\x54\x8b\x16\x7c\x12\x8f\xd1\x27\x7c\xaa\x56\xab\xe0\x53\xcc\x50\xfd\xc0\x5d\x63\x4c\x69\xc7\xc7\x16\x82\x31\x1e\x1f\x1f\xbf\x7b\xa8\xc1\x47\xf1\x33\x8f\xcf\xc9\x09\xa9\xc4\x27\x27\xc2\xf0\x8c\x44\xc2\xfb\x3c\xfb\xc7\x0a\x80\x29\x40\x9d\x89\x1c\xfc\x5a\x4d\x76\x6a\x35\x53\x07\x26\x58\xab\x41\x8d\xfa\x1f\x9e\x41\x2f\xb4\x89\xd3\x53\xd6\x5e\xf0\x54\x46\x15\xf9\xa3\x33\x86\xc4\x4f\x53\x4a\x39\x3b\xb3\x10\x4c\xf1\xec\x4c\x10\xb5\x29\x72\x94\x25\x5b\xc1\xdf\x78\x4e\x4d\x6a\xbf\xe5\x37\xb7\xdf\x68\x8a\x46\xf7\xf0\x15\x7f\xfd\xfa\xc5\xda\xab\xfc\x79\xf6\xaa\xcf\x86\x54\x40\x2b\x9e\x39\x58\xc9\x75\x9d\x3f\x78\x01\xef\x2d\xc1\xff\x9b\xe4\x0d\x2f\x2f\x2f\x45\xff\x4d\xff\xe6\x7c\xc3\xcb\x88\x42\xe0\x33\x47\xb6\xec\x1d\x57\x7d\xf9\xdf\xe5\xfa\xf2\xbf\xe6\x63\x9d\x97\x5c\x27\xf4\xef\x3f\x09\x5c\xeb\x82\x16\x49\x6f\x0b\x5f\x20\x01\x1b\xd9\x8d\x2c\x24\xe0\x8b\x94\x2e\x2e\x00\x92\x89\xc4\x05\x7f\xec\x24\xe9\x0b\x6b\x17\xf5\x7a\x92\x95\x2f\xe0\x3a\xe4\xb9\x10\xb5\x92\xea\xa3\xa8\xd0\xea\x75\xa9\xc8\x5a\xf5\x3a\x49\x42\x95\xc7\xf4\x3f\xd9\xac\x07\x07\xfc\x4b\x53\x2e\xe9\x51\x9d\x48\x24\xe4\x82\xba\xd5\x84\x6c\x79\x7e\x2a\xc7\x72\xa2\xb7\x23\xbf\x45\xc7\xf6\xa9\x77\xa4\xff\xdf\x2c\x56\x4c\x24\x7e\xc6\xbc\x21\x8d\xe5\x2a\x31\xff\x08\xc7\x62\x7a\x98\xff\x1f\x00\x00\xff\xff\xd0\x66\xcf\xd4\x57\x1f\x00\x00")
+
+func fontsTanjaFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsTanjaFlf,
+ "fonts/tanja.flf",
+ )
+}
+
+func fontsTanjaFlf() (*asset, error) {
+ bytes, err := fontsTanjaFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/tanja.flf", size: 8023, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsTengwarFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\x5f\xaf\xa3\xb8\x15\x7f\xe7\x53\x1c\x21\x24\x76\x55\xc6\x9a\x3b\x0f\x57\xde\xab\xd1\x28\x5b\x75\xfb\xb6\x2d\x52\xa7\x0f\xbc\x61\xc7\xe4\x86\x4e\x02\xb7\x81\x34\xb3\xfd\xf4\x95\x8f\x6d\xb0\x8d\x21\x21\x3b\x53\x69\xa5\x44\x11\x1c\xdb\x60\xff\xce\xff\x63\x27\xbb\xc3\xee\x03\x4b\xe0\xe9\x3d\x3c\xc3\x87\x27\x78\x0f\x4f\xcf\xd1\xe7\xaa\x79\xbd\xb0\x13\x3c\x91\xf7\xb0\xab\x5f\x0f\x55\x0f\xfc\x37\xf8\x73\x75\xa8\x1b\xc1\xe0\xe7\x8e\x57\x87\x03\x7c\x3c\x72\xb6\xd9\x6e\x05\xd9\xb3\xd3\xa9\xee\xc8\xb6\x3d\x7e\x8a\x7e\x16\xec\xad\xaf\x04\xec\x4e\xed\x11\x7e\xad\xbf\x54\xf0\xcf\x13\x67\x4d\xda\xc1\xc7\xb3\x24\x36\x5d\x2d\xaa\x6e\xdf\x5e\xc8\xbf\xde\x0e\xa4\x61\x1d\x23\xaf\xed\x7f\x3e\x81\x59\x71\xd7\x9e\x20\xfa\xb5\xea\xd9\xae\x6d\x7a\xf8\xe1\xb2\xaf\xb7\x7b\xa8\xbb\x0c\xea\x06\xfa\xf3\xa9\xc9\x80\xb3\xae\x12\xd0\x36\xf0\xb9\x3d\x7c\xa9\xab\x06\x5e\x7e\x8c\xfe\xc2\xfa\xea\x05\x3e\x50\xf8\x6b\xc5\xe1\xe9\xa7\x9f\x9e\xa3\xe8\x97\xaf\x6f\x07\xd6\xb0\xbe\x6e\x1b\x68\x77\xb0\xab\x4f\x5d\x0f\x87\xba\xa9\x5e\x00\x3e\x6e\xdb\xb7\xda\x80\x6c\xfb\x7d\x75\x92\x5c\x76\x9f\x22\x29\x0b\x78\x07\xf1\x91\xbd\xd6\x5b\x68\xce\x47\x5e\x9d\x62\xc4\xb4\xab\x0f\x15\xd4\xa2\x6a\xfa\x7a\x57\x6f\x71\xda\x88\x01\x00\xbc\x83\x6e\xdf\x9e\x0f\x02\xd8\xe1\xc2\x7e\xeb\x80\x57\x50\xb2\x34\xc3\x97\x9a\xf6\x12\x25\xea\xa1\x7e\x5f\x41\xbc\x67\x27\xc1\x0f\xac\xf9\x12\xc3\xbb\x77\xf0\x76\xaa\x9b\xbe\x03\xd6\x01\x03\xec\xcd\x80\x9f\x7b\xd8\xb2\x26\xed\xe5\x34\xdd\xf1\xdc\xed\x2b\x11\x3d\xbd\xc7\x19\xf6\x55\xfd\xba\xef\x25\x2f\x0c\xb6\x7b\x76\x62\xdb\xbe\x3a\x45\xcf\x30\x3f\x98\x41\xd3\xf6\x50\x37\xdb\xc3\x59\xd4\xcd\x2b\x88\xaa\xdb\x56\x8d\xa8\x4e\x5d\xf4\xe1\x09\x5f\x3b\xb2\xaf\x28\x13\x38\x54\xcd\x6b\xbf\x87\x1f\xaa\xaf\xe6\xe1\x6d\x7b\x3c\x56\x8d\x12\x59\xf7\x23\xfc\x09\x18\xec\xce\xe2\xb5\x82\x1d\xdb\xf6\xed\x29\x52\xa0\x44\xb5\x63\xe7\x43\xaf\xb0\x1e\x5b\x51\x21\xdf\xfd\xbe\xee\x40\x2a\x30\x7a\x7a\xc6\xc7\x94\x24\x25\x3c\x67\xda\xe8\x6f\x7f\xff\xfc\xcb\x0b\xfc\xe3\xcc\xbb\xbe\xee\xcf\x52\xa8\xdd\x0b\xa4\x5f\xf6\x29\x4e\xf3\xef\x0c\xd2\xff\x6a\xfa\x6b\x06\xe9\x56\xd3\x5b\x12\x45\x49\x92\x24\x9b\xfb\xae\x9b\x08\x80\x88\x3c\x4d\x24\x41\x29\xc0\x8d\x84\x7c\x47\xf7\xc8\x4f\x88\xd8\x44\x20\x28\x80\xa0\xc9\x26\x62\x79\x0a\x4c\xaf\xe2\x3e\xf7\x3b\xa9\x81\x1c\xfa\x45\x2a\xbf\xb2\x51\x5e\x2e\x14\xbf\x44\x8d\x50\xfc\x06\x46\x48\x2e\xbf\xf6\xc4\x6b\x1a\x66\x55\xd9\x2f\xf2\x94\xa6\x71\x91\x6c\xa2\x82\x13\x3a\x3c\x4b\xe3\x82\x27\x9b\x88\x33\x42\x89\xc8\xb1\x2f\xcb\x57\xf2\x99\x09\x49\x29\x55\x49\xd9\x83\xc8\x87\x47\xc4\x38\x19\x92\x8a\x46\x32\x13\x89\x7c\x17\x7b\x6d\x05\xb8\x6c\xcc\xd3\x36\x77\x99\x88\x69\xcc\xa5\xcc\x28\x8e\x4a\x4e\xca\x82\x11\xd0\x26\x11\xa7\x8a\x52\xa3\x1c\x47\xf9\x45\x5c\xd7\xbb\x32\x2c\x39\xc7\x68\x24\x77\xdc\x36\x91\xb1\x65\x41\x15\x62\x6a\x23\x92\x77\x8d\xb5\x90\x84\x7c\xaf\x2c\x38\x31\x48\xa6\x77\x64\x80\xa8\x8e\x92\x72\x35\x50\x52\xfd\x80\xbe\x13\x75\x27\x34\x57\x92\x4e\x03\x13\x45\x8e\xb9\x0a\x8d\xaa\x2c\x38\x50\x30\xf2\x29\x38\xd5\x2a\x2d\x2f\x68\x9c\xda\x3a\x45\x4e\x0b\xae\xe5\x9f\x03\x85\x01\x71\x96\xaf\x54\xa3\x33\x60\x40\x80\xf2\x0c\xa5\x42\xbd\x70\xea\xf5\xaf\x5c\xcc\x5f\x38\x09\x5f\xd0\x34\x35\xf3\xf6\xc5\x76\x2f\xcf\xdb\x82\xcd\x4c\x50\xca\xa5\x62\x21\x4b\x36\x91\x64\x0b\xca\x82\x52\x4b\x11\x37\x4f\xb5\xd4\x94\x16\x2e\x83\xa5\xf6\x3f\xcb\xaa\x83\xc4\x9a\x87\xc7\xa5\x88\xe3\x2d\x6e\x90\x15\x8e\x0a\x54\xcb\x89\x00\xa6\x99\x99\xd6\x18\xa9\xef\xe4\x58\xc9\x56\x0d\xe5\x28\xd7\xf1\x29\xba\x40\x72\xf4\x0b\xed\x61\xd4\xe1\x62\x9e\xbc\xfe\x44\x94\x16\x94\x4a\x65\xcb\x5e\xa2\xf8\x92\x24\xda\x29\x37\x0e\x7d\x71\x35\x7f\x7d\xb9\x9b\x44\xa3\x96\x76\x97\xf7\x20\xb8\x30\xc4\x14\xca\x8d\x42\xf7\x3e\xc9\xad\x5d\x23\xc4\x29\xcc\x00\xd4\x29\xdc\x19\xc8\x6b\x40\xa8\xa8\x66\x46\x4b\x2b\x07\x2e\x51\x43\xfa\x55\x30\x47\x9d\x8e\x2a\x75\xf3\x85\x5e\x04\xdc\x95\x2c\x58\x7e\xd3\x96\x89\x1c\xb5\xe4\x21\x57\xb7\x64\x21\x47\x2c\x39\xe8\x11\xf3\xb0\x1e\x99\x51\x9d\x0d\x2b\x00\x2d\x00\x6f\x02\x71\x0a\x33\x00\x75\x0a\x57\x84\x21\x07\x60\x2f\xa8\x4e\x3a\x38\x37\x83\x43\x9e\x83\x6b\x44\xa6\x09\x61\xb2\xa1\xa7\xb1\x71\x6a\x77\xf9\x41\x30\xc3\x6c\x7e\x5b\xc4\x32\xff\xba\xe3\xd4\x69\x13\x53\x06\x65\x83\x08\x51\x7a\x0a\xcb\x38\x9f\x23\x00\x9f\xfd\x09\xc0\x20\xca\x20\xd4\x00\xde\x19\xd0\x41\xe4\x01\xf8\x33\x3c\x04\x19\x99\x53\xe6\x95\xcc\x4b\x66\x33\xef\xdc\xc8\xc2\x2b\x80\x55\xa6\x1e\xca\x4c\xca\xca\xc4\x60\xb5\x58\x43\x0d\xce\x60\xcb\xc6\xae\xbe\x96\xc2\xbe\xcb\xd4\x2c\xe7\xd7\x8b\x81\xef\x55\x2a\xdc\xc8\xe4\xa2\x98\x56\x49\xa1\xe4\x84\x11\xe3\xec\x25\xd7\x44\x86\x7b\x0b\x9a\xd1\xe9\x10\xd1\x43\x8a\x55\xaf\x9a\x73\x3d\x95\x08\x65\x81\xa0\x36\x34\x9a\x07\xac\xa2\x89\xc8\x63\x4e\xd0\xd9\xa9\x09\x33\xaa\x81\x66\x59\x16\xb9\xda\xfa\x58\xa0\xa5\x7c\xa9\xed\x0f\x53\x09\x7a\x0d\x6c\x09\xae\x06\xf0\x0e\x82\xfb\xa2\x48\x0b\x6e\x45\xce\x00\x49\x68\x7e\x8f\x49\x05\xfd\x29\xd8\x23\xc3\x05\x56\x47\x63\x89\x44\x71\x4d\x5a\xc8\x0b\xd7\x3d\xf2\x69\xd5\x4d\x87\x1e\xac\xc9\x88\xd9\x2a\x4c\x93\x36\xf5\x9d\x5e\x31\xe3\xcb\x68\x0a\xce\xa3\x55\xed\xa7\x8c\x4e\x23\x41\x10\x05\xc5\xc8\x42\x15\x1b\xd2\xfe\xa9\x5d\xc2\xcd\xd0\x05\x25\x53\x69\x4d\x44\x13\xea\x90\x2e\x30\x8a\x4a\x71\x98\x8e\x92\x9a\x08\xca\x74\x60\x21\x2b\x2f\x13\xa1\x84\x3a\x5c\x21\x39\x67\x1b\x22\x4f\x7d\x7b\x4f\xf5\xa6\x2a\x70\xc8\x81\x13\x85\x9c\xc3\xf2\x12\xbf\x00\xb1\xc0\x04\x9b\xc4\x44\x1e\x6d\x27\x29\x0a\xd4\x79\xd8\xac\x8a\xcd\xcc\xec\xe9\xc9\xa4\x2a\x98\x13\xf5\xad\xa6\x1c\x17\x9c\x99\x8f\xa0\x18\x90\x06\x43\x71\xcc\x14\x6c\x9b\x41\xb4\x60\x5b\x8e\x0a\x9d\x53\xfb\x51\x9f\x5b\x7a\xb4\x45\x95\x63\xc4\x18\xe2\xa7\xcb\x80\x69\x9b\xf7\x0b\x6e\x37\x45\x6e\x95\x9c\x28\x38\x13\x1c\xc8\x18\xbf\xae\x0a\x2f\x24\x4b\xd9\x6b\x62\x0f\x16\xd8\xda\x56\x87\xab\xda\xf5\x0f\xef\x9b\xeb\x5d\x5e\x32\x46\x05\xdb\x65\x27\x7e\x3b\x71\xde\x19\x0d\x5c\xef\x08\x38\xf4\x54\x2a\xa5\xb1\x16\x6d\x2a\x1a\xe1\x30\x9b\x31\x5e\xdd\x44\x74\x83\x85\xa8\xe8\x3f\x01\xb7\xdc\x9c\xc2\x4a\x96\x5b\x65\xe1\x79\x08\xb1\xb2\xaa\xb3\x19\x36\x68\xad\xd3\x1f\x42\xc6\x83\xb4\x32\x8e\xe3\x34\xb0\xc2\xb7\x4f\x11\xf4\x86\x14\x31\x56\x87\x64\x9a\x22\xae\xaf\x7e\x6f\xa4\x06\x3f\x52\xe7\xcb\x91\x1a\xa3\x25\x17\xfa\x72\xd3\x2a\x21\xa8\xb2\xb4\x40\xf7\x52\xba\x13\xe9\xff\x29\xe3\x5f\xb5\x2d\x4c\x5d\xa3\xfa\xd0\xb0\x68\xe1\x05\x6e\x37\x6e\xdb\x59\xdd\xcf\xe8\x6e\xa2\x72\xc0\x18\x0f\xd3\x9f\xa0\x97\x0c\xee\x68\x46\xb5\xa9\x2f\xfb\x1f\xba\xd4\xfa\xf0\x17\x1a\xf4\x1b\x3a\x56\x8f\xa7\x98\xf6\xc9\x74\xc1\xad\xa3\x69\xcd\x36\xc6\x54\x09\xda\xa8\xb3\x20\xf6\x71\x78\xa9\x5c\xf0\xb6\xf3\x20\xa5\x1a\xac\x54\x51\x31\xaa\x4e\x55\xe9\x84\x9a\x4d\x2a\x31\x66\x39\xfc\x68\x41\x42\x55\xf7\x1a\x8e\xb5\x49\x38\x16\xe1\x18\x84\x63\x0f\x8e\x01\xf8\x8d\xd1\x18\x24\x04\x74\x02\x15\x9d\x4a\x29\x1f\x9d\x71\x1c\x24\x63\xe5\x62\xd5\x2e\x36\xe9\xd6\x2f\x4b\x7e\x10\xda\xf2\xba\xc5\xe7\x42\x97\x15\xd9\xa6\x91\x02\x02\xb1\xcd\x0e\x6e\xe9\xa8\x0d\xa7\x00\x0e\x86\xb7\x40\x7c\x5b\xef\xc6\xe0\xb8\x71\x0e\x6e\xbc\xf5\xdc\x78\x12\x79\x7d\x58\x8b\x29\xc2\x73\xe4\xd9\x5c\x6c\xc9\x41\x75\xac\xca\xf8\x53\xa7\xbe\x3d\xda\x4e\x06\x7d\xbf\xca\xe3\x78\x3c\x0a\x92\x8e\x3c\x90\x22\xd7\xa7\x10\x17\x37\xdc\x5f\x8f\xb6\xf3\x0f\x13\xc6\x98\xb2\x7a\xfc\x59\xa2\xe4\xca\x01\xc8\x70\x8a\x8c\x1a\xc1\xcd\xac\x29\x90\xac\x4c\xef\x78\xf4\x58\x0e\x58\xbf\x6a\x0e\x4b\xae\x6f\xa8\xdd\xf0\xc4\x00\x96\x1a\xbf\xbf\xa2\x35\xed\x71\x62\x2b\xf9\xe1\xe7\xae\x8a\xd6\x93\x0c\xb8\x01\x64\x6d\xe3\x2e\xc9\x48\x95\xe9\x00\x27\x75\xb6\xfe\x04\x68\x0d\x69\x2d\x9e\x7c\x7f\x5a\x4b\x97\x63\xf5\xaa\x65\x54\x16\xcc\xf0\x77\xc7\x0d\xef\x8f\x93\x10\x7b\xad\xc7\x49\xc8\xe3\x24\xe4\x71\x12\x32\x97\x37\x1e\x27\x21\x8f\x93\x90\xc7\x49\x88\xdf\x73\x6f\xa4\x7e\x9c\x84\x78\x02\x79\x9c\x84\x2c\x35\x1e\x27\x21\x8f\x93\x90\x50\xf5\x1b\x88\x6d\x76\x70\x7b\x9c\x84\x3c\x4e\x42\x46\xf2\x9b\x9e\x84\x38\x7f\x28\x1c\xbc\xc2\x38\x05\x19\xf6\x02\xba\xec\x54\x51\x87\x72\x3b\xa1\xe8\x72\xc0\xa9\x1a\x6d\x0a\xff\xe5\x9d\x6a\x6b\xb9\xe7\x46\xd0\xd8\x5c\x0c\x63\x26\x1b\xfe\xa8\x6b\x63\x18\x78\x32\x7f\xf3\x1d\xdf\x20\xde\xfe\xc6\xc3\x4a\x4c\x54\x51\x7f\x2d\x93\x0e\x2a\xe7\x65\x22\x4f\x57\x66\x85\x6f\xd8\xdc\x44\xc9\xd2\xf7\x8f\x3c\xfc\xbf\x00\x00\x00\xff\xff\xbe\xff\x80\x0f\x50\x33\x00\x00")
+
+func fontsTengwarFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsTengwarFlf,
+ "fonts/tengwar.flf",
+ )
+}
+
+func fontsTengwarFlf() (*asset, error) {
+ bytes, err := fontsTengwarFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/tengwar.flf", size: 13136, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsTermFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x99\xe9\x9f\x23\x55\xd5\xc7\xdf\x9f\xbf\xe2\x3c\x0f\xcf\x23\x2e\xd3\x4d\x52\xe9\x24\x1d\x45\x3c\xd5\xc9\xed\x74\x31\xe9\xaa\x50\xa9\xcc\x30\xe3\x9a\x49\x57\x4f\xc7\x49\x57\xb5\x49\x1a\x68\x37\xdc\xf7\x7d\xdf\x17\x10\x94\x45\x10\x10\x90\x1d\x15\x01\x11\x65\x13\x04\x59\x44\x59\x45\x94\x4d\x10\x64\xf3\x73\x92\x9b\x99\xba\xa9\x7b\xd3\xbe\x3a\x9d\x53\xdf\x7b\xeb\xde\x73\x7e\x75\xee\xa9\xea\xd5\xee\xaa\xd5\x3a\x11\xb3\x98\xc5\x1c\xce\x64\x31\x9b\xc3\x0c\x66\x20\x08\x7b\xeb\x9d\xa8\xd5\xc5\x7d\x5b\x58\xed\x86\x51\x84\xe5\xb5\xd6\xc6\x46\xd8\xed\xe2\xdc\x11\xa5\x1c\x38\x51\xbb\xbb\xb9\x12\xf6\xb1\xbd\xd6\xea\xb5\xda\x83\xb0\xd7\xc7\xac\x35\x3f\x63\xe5\xf3\x20\xa2\xb5\x56\xd4\x0e\x57\x70\x35\xee\x61\xad\x35\xe8\x44\x33\xd6\x8e\xdc\x8e\x39\x9e\xeb\xe8\x78\x2d\xc2\x72\x7c\x7c\x2b\xc2\x23\xdb\x6c\xa8\xdd\xee\x74\x67\xe3\xde\xfe\xa3\x60\x88\x1e\x9a\x10\xfb\xe1\xa0\x8f\xfd\xcd\x8d\x8d\xb8\x37\x08\x57\x30\x8e\xba\x5b\xd8\x59\xc5\xad\x78\xb3\x87\xfd\x76\x2f\x0c\x23\x5c\x8d\xa3\x01\xae\xc4\x61\x1f\x56\x3b\xfb\xbb\xe1\x00\x7b\x61\x37\x6c\xf5\x43\xb4\x66\x2d\x9c\x99\x41\x37\x3e\x2e\x5c\xdf\x17\xf6\x30\x5b\x2a\x15\xa0\xce\x9b\xea\xf7\x3b\x71\x84\x9d\x3e\xae\x85\xbd\x70\xdf\x16\xee\xef\x1c\x17\x46\x38\x88\x71\x3d\x5e\xe9\xac\x6e\xe1\x60\xad\xd3\x1f\xce\xbb\x03\x5b\x7d\xec\xc6\xd1\x7e\xb6\x83\xb5\x10\x86\x40\x27\xec\x1d\xde\xc7\xa8\xb5\x1e\xf2\x1c\x1b\xdd\x56\x7b\xb8\x34\x6c\x61\x3b\x5e\x5f\x0f\xa3\x01\x76\x3b\x51\x38\x0b\x50\x89\x37\xf7\x75\xc3\x99\xf6\x5a\xd8\x3e\x10\xae\xf0\xde\xeb\xad\xcd\x2e\x2e\x6c\xf6\x06\x71\x84\x47\xf6\xe3\xee\xe6\xa0\x13\x47\x14\xb6\x7a\x83\xb5\x6e\x27\x3a\x30\x1b\x85\x83\xa3\x30\x6b\x1d\x51\x2a\xcc\x22\xda\x2b\x2b\xe1\x0a\xdf\x16\xa3\xf0\x78\xd8\x68\xf5\x5a\xeb\xe1\x30\x28\x07\xe3\xb1\x6f\x0b\x17\x9d\x2a\x6f\xba\x15\xad\xf0\x9f\xbb\x3b\xd1\x2c\x62\x33\xea\x76\x0e\x84\xd8\xea\x76\x31\x1e\xac\x85\x3d\xbe\xc2\xdb\xe9\xef\x18\x6d\x2d\x8e\x42\xe8\xf4\xb1\x13\x0d\xc2\x68\x78\x8b\x18\x37\x7a\xf1\xca\x66\x3b\xc4\x78\x73\xb0\xb1\x39\xc0\xf0\x84\x56\x7b\xd0\xdd\x1a\xde\xbc\xcf\x1b\x1d\xed\x1f\x3b\x11\x5f\xdd\x8c\xba\x61\xbf\x3f\xdc\x6f\x34\xe8\xc5\x5d\x58\xed\x74\x87\xb1\xd8\xec\x87\x2b\xb3\x88\x01\xc7\x75\x35\xee\x85\xd8\x19\x8c\x67\x1e\x8d\x6f\xd8\xcb\x62\x7c\x0f\x96\x46\x7f\x7d\xb3\xbf\xb6\x03\x0f\x84\xbd\x08\xe3\x1e\xae\x76\x06\xb3\x80\x08\x27\x12\xfc\x0f\xc1\xff\x12\x1c\x46\xf0\x7f\x04\xff\x4f\xf0\x0a\x82\xc3\x09\x5e\x49\xf0\x2a\x82\x57\x13\xbc\x86\x60\x07\xc1\x0c\xc1\x2c\xc1\x11\x04\x19\x82\x2c\x81\x45\x90\x23\x98\x23\xc8\x13\x14\x08\x8a\x04\xf3\x04\x25\x82\xd7\x12\xbc\x8e\xe0\x48\x82\xd7\x13\x1c\x45\xf0\x06\x02\x3a\x0c\x6c\x82\x05\x82\x32\x41\x85\x40\x10\x2c\x12\x54\x09\x96\x08\x1c\x82\xa3\x09\x76\x12\xd4\x08\x96\x09\x5c\x02\x8f\xa0\x4e\x70\x0c\x81\x4f\xd0\x20\x08\x08\x9a\x04\xbb\x08\x76\x13\x1c\x4b\xb0\x87\x60\x2f\xc1\x1b\x09\xde\x44\xf0\x66\x82\xb7\x10\xbc\x95\xe0\x6d\x04\x2d\x82\x7d\x04\x6d\x82\x15\x82\x90\x60\x95\x60\x3f\xc1\x1a\x41\x87\xe0\xed\x04\x07\x08\xba\x04\xeb\x04\x11\x41\x4c\xb0\x41\xf0\x0e\x82\x1e\x41\x9f\x60\x40\xb0\x49\x70\x1c\xc1\xf1\x04\x27\x10\x6c\x11\xbc\x93\xe0\x5d\x04\xef\x26\x78\x0f\xc1\x7b\x09\xae\x22\xb8\x8d\xe0\x2e\x82\xfb\x09\x9e\x21\x78\x81\xe0\x4f\x04\x59\x6b\x1e\xde\xc7\xa6\x04\xef\x27\xc8\xe6\x32\xf0\x01\x36\x59\xf8\x20\x1b\x0b\x3e\xc4\x26\x07\x1f\x66\x33\x07\x1f\x61\x93\x87\x8f\xb2\x29\xc0\xc7\xd8\x14\xe1\xe3\x6c\xe6\xe1\x13\x6c\x4a\xf0\x49\x82\xec\x5c\x06\x3e\xc5\x26\x0b\x9f\x66\x63\xc1\x67\xd8\xe4\xe0\xb3\x6c\xe6\xe0\x73\x6c\xf2\xf0\x79\x36\x05\xf8\x02\x9b\x22\x7c\x91\xcd\x3c\x7c\x89\x4d\x09\xbe\x4c\x90\xcd\x67\xe0\x2b\x6c\xb2\xf0\x55\x36\x16\x7c\x8d\x4d\x0e\xbe\xce\x66\x0e\xbe\xc1\x26\x0f\xdf\x64\x53\x80\x6f\xb1\x29\xc2\xb7\xd9\xcc\xc3\x77\xd8\x94\xe0\xbb\x04\xd9\x42\x06\xd1\xf5\x66\x16\x7c\x61\xef\xc4\x46\xdd\x2e\x0b\xf8\x1e\xbb\xb3\x88\x8e\xbb\x4b\xf8\x81\xa8\xa0\x38\xb6\x5c\xb3\x97\xed\xc0\xf1\x5c\x5c\xb6\xfd\x9d\xf0\x7d\x26\x2c\xc4\xb2\x70\x03\x6c\x38\x55\x17\x4e\x62\x4f\x0e\xb1\xee\x35\xdd\xca\xc8\x75\x32\xbb\xe6\x10\xcb\x4d\xdf\x17\x6e\x79\xcf\xc8\xfb\x03\xf6\xe6\x11\xf7\x08\x77\xe4\x38\x85\x1d\x05\xc4\x05\xdf\xdb\x29\x5c\x5c\xb0\x7d\x38\x95\x5d\x45\xc4\x86\x28\x0f\xef\x39\xe4\x7e\xc8\xce\x79\xc4\x8a\x63\x0b\x5f\x34\x9c\x06\xfc\x88\x3d\x25\xc4\xb2\x57\xdf\xe3\x3b\xd5\x25\xb9\x94\xd3\x08\xb2\xc5\x0c\xe2\xa2\x58\x76\x5c\xc7\x15\xe8\xf9\x15\xc7\xb5\x6b\xe8\xb8\x15\xa7\x6c\x07\x9e\x0f\xa7\x33\x92\x45\xac\x89\xc5\x60\xa6\xee\x39\x6e\xe0\xb8\x55\xac\x78\xcd\x85\x9a\x40\xdb\xad\xd6\x04\x1e\xd3\xf4\x82\xc4\x8e\xcf\xe0\x11\x16\x87\x4a\xde\xe5\x4c\x76\xe4\x10\x1b\xde\x62\x80\x4b\x7b\xea\x4b\xc2\x85\x1f\xb3\x6f\x0e\xd1\x17\x55\xa7\x11\x08\x5f\xc8\x48\x9c\xc5\xfe\x3c\xe2\xb2\x5d\xf6\x3d\x17\xce\xe6\x9f\x05\xc4\x8a\xa8\xfa\x42\x8c\x90\x9f\xb0\xaf\x88\x58\xaf\x35\x1b\x33\xcb\x8e\xdb\x6c\x8c\xfc\xe7\xb0\x7f\x1e\xb1\xd1\xac\x0b\xbf\x51\xf6\x9d\x7a\x80\xc1\x6e\x0f\xce\x65\x7f\x69\xc2\xbf\xe4\x0b\x01\xe7\x11\x64\xe7\x33\x88\x76\xb9\x19\x08\xb4\xcb\x9c\x23\xf8\x29\x3b\xb3\x88\xcb\x4e\xd9\xf7\x46\x33\x9f\xcf\x2e\x0b\xb1\xee\xd4\xca\xbe\xb7\x7b\xe4\xbc\x80\x9d\x39\xe6\x2a\x95\x9a\xc0\x8a\x17\xc0\x85\xec\xe2\x34\x8a\x8a\x53\xab\xd9\xf0\x33\xfe\x9d\x57\xef\xec\xb9\x02\x2e\x62\x7f\x81\x37\xd9\x28\x37\x6b\xfa\xb8\x5f\xcc\x4c\x11\x71\x98\xad\xff\x2e\xf0\x97\xf0\x90\x79\xc4\x5d\xcd\x5a\xd5\xf6\x71\xd1\xb7\x47\x9a\xf0\x5c\x46\x6d\x3f\x10\x3e\x5c\xca\x4c\x49\xcf\x2c\xd9\xb5\x45\xb8\x8c\x20\x5b\xca\xa4\x81\x61\xc4\xc6\xd3\x34\xe0\x72\xc6\x92\xc2\x3f\xa6\x29\x1a\x87\x96\x72\x05\x5f\xb6\x10\x6b\x76\xe0\xb8\x58\xb6\xeb\x4e\x60\xd7\xb0\x26\x82\x40\xf8\x68\xe3\x6e\x27\x58\xc2\xaa\x6f\xef\x12\x70\x25\x93\xb9\xe9\xe4\x30\x3f\xf0\x73\x26\xe7\xa6\x93\x65\xc7\x2f\x37\x97\x17\x6b\xe2\x58\xf8\x05\xe3\xf9\xe9\x78\xe0\xd4\x2a\x02\x7e\xc9\x64\x61\x3a\x79\xe8\x51\xba\x8a\xe9\xe2\x74\xda\xe7\x54\xd9\x0b\xde\x2e\x01\xbf\x62\x7c\xde\x84\x0b\xb8\x9a\xaf\x97\x0c\xd7\xcb\x72\x57\x52\x4f\xd7\x10\x58\x99\x8c\x81\x15\xc9\xa8\x5e\xcb\x64\x76\x3a\x39\x8a\xea\xaf\x99\x34\x65\x4a\xa4\xa2\x7a\x1d\xe3\xa6\x74\x89\xc9\x58\xfd\x86\x69\x53\xca\x9c\xe4\x82\xaf\x67\xd2\x94\x2d\x27\xb9\xe0\xdf\x32\x69\xca\x96\x93\x5a\xf0\xef\x18\x37\xa5\xcb\x99\x5c\xf0\x0d\x4c\x9b\xb2\x25\x82\x25\xb8\x91\x01\x53\xba\xdc\xa4\xaa\x6e\x22\xb0\xb2\xa6\x64\x79\xc9\xbd\xdf\xcc\xa4\x29\x59\x5e\x72\xef\xb7\x30\x69\x4a\x96\x97\xda\xfb\xef\x19\x37\x25\xcb\x4b\x2e\xf6\x56\x26\x4d\x89\xf2\x26\xa3\x74\x1b\xd3\x5c\xa4\x9b\xb5\xc0\xa9\xd7\xb8\x62\x1d\x3c\x7b\xfe\xc0\xd7\x4c\xe9\x91\x33\x35\x02\x3e\xc0\xe0\x76\x46\x4d\xa9\x69\x26\x23\x74\x07\x93\xa6\xb4\x34\x93\x11\xfa\x23\x93\xa6\xfc\x34\x53\x11\xba\x93\xc0\xb2\x4c\x49\x6a\x4e\xee\xfb\x2e\xa6\x4d\x89\xda\x93\x5c\xc6\xdd\x4c\x9a\x12\x15\x2c\x79\xbe\x0b\xf7\x30\x72\x30\x39\x8d\x65\xbb\x76\x10\x68\x2c\xd9\x7e\x1d\x1b\xdc\x54\x59\xd6\x9c\x16\x51\x6a\xe8\xbd\xcc\xe5\xa7\x71\xa3\x55\xfd\x99\xb9\xc2\x34\x2e\x11\x9a\xbf\x30\x5c\x9c\x06\x8f\xa4\x73\x1f\x73\xf3\xd3\xb8\x43\x01\xbc\x9f\xd9\xd2\x34\x36\x51\x39\x1f\x20\xb0\x72\x19\x3d\x2c\xe0\x41\xbe\x9a\xd5\x5e\x9d\xa8\x9a\x0f\x31\x69\x69\x49\xa5\x66\x3e\xcc\x9c\x3e\x21\x4a\xc5\xfc\x2b\x73\xfa\xac\xa4\xeb\xe5\x23\x0c\xeb\x53\x93\xaa\x96\x7f\x63\x56\x9f\x1e\xa5\x56\x3e\xca\x9c\x3e\x33\x4a\xa5\xfc\x3b\x73\xfa\xcc\xa4\xeb\xe4\x3f\x18\xd6\xa7\x26\x55\x25\x1f\x23\xb0\xe6\xf4\x99\xe1\x1a\xf9\x38\x5f\xd6\xa7\x46\xa9\x90\x4f\x30\xa7\x4f\x8c\x52\x1f\x9f\x64\x4e\x9f\x18\xa5\x3a\x3e\xc5\x9c\x3e\x31\xe9\xda\xf8\x4f\x86\xf5\x89\x51\x2a\xe3\xd3\xcc\xe9\x93\x92\xaa\x8b\xcf\x30\x5b\xe4\xbe\x7b\x97\xd3\x38\x58\x11\xff\xc5\x5e\x7d\x1a\xd4\x7a\xf8\x2c\x83\xfa\x14\x28\xd5\xf0\x39\x02\x2b\xaf\x0f\xbf\x52\x0b\xff\xcd\x9c\x3e\x0f\xe9\x4a\xf8\x3c\xc3\xfa\x64\xa4\xea\xe0\x0b\xcc\xea\x13\xa2\x54\xc1\x17\x99\xd3\x27\x64\x54\x03\x5f\x62\x40\x9f\x84\x3d\x93\x37\x7d\x99\x20\x73\x42\x26\x6b\xec\x7f\x64\x01\x91\x2f\x0e\x57\x4a\x5a\xbf\x7d\x95\xbd\x57\xb2\xdb\xf4\xab\x0b\xbe\xd8\x35\x6c\x16\x87\xb0\x7e\xfb\x0a\x7a\x9f\x44\xb7\xe9\x59\xbd\xaa\xe7\x8a\xe1\x8b\xe2\x90\x9e\x5a\xc7\x25\x7b\x8e\x64\x4d\xe7\x6c\x39\x99\x85\xab\x25\xac\xaf\x18\x0a\xfa\xa0\x44\x4d\x47\x6d\x39\x25\x9b\xf1\xe4\x7a\xd9\xa6\xf9\xf1\x1d\xec\xe9\x77\xa8\x78\xc1\xa1\xfe\x79\x38\x60\x61\xda\x0d\x0e\xe1\x0f\x48\xbc\xbc\xcd\x0e\x6c\x4e\xfc\xb5\x12\xae\x4c\x5d\xfc\x10\x7d\x58\xa2\xc2\x30\x6f\x25\x09\xdf\x20\xe1\x45\xed\xbc\x0a\xfa\xd8\x08\x35\x36\x8a\x15\xa5\x42\xdc\x28\x69\xbd\xaa\x55\xf6\x71\xc9\x6e\xd3\xdb\xcb\x67\xe0\x74\x49\x4f\x3d\xff\x24\x7b\xb1\x64\x4d\xea\x13\x93\x49\xb9\x5e\x0e\xd0\x2b\x30\x85\x3f\x2a\x71\x63\x1f\xae\x3c\x0b\xd7\x49\x5a\xaf\x40\x95\x7d\x44\xb2\x26\xf5\x89\x64\x6a\xc6\xab\xd6\x2b\x4f\x41\xc7\x2b\x36\xa9\xae\x9a\x7a\x0e\x6e\x97\x23\xf4\xd2\x4b\xf3\xcf\x4a\xde\xa4\xbf\x6a\xb2\xf0\x9c\x21\x61\xbd\xfe\x14\xf4\x92\x11\x6a\xec\x81\xab\x93\xc9\xb9\x55\x0e\xd0\x4b\x30\x85\x3f\x2d\x71\x93\x0a\xab\x6a\xaf\x26\x57\x6e\xe8\x8b\x27\xe0\xf1\xda\x4d\xf5\x75\x29\x15\xc5\x53\xe5\x08\x7d\x8d\x4d\xf3\x17\x48\xde\xa4\xf4\x25\xe5\x89\x93\x15\xdc\xd0\x34\xab\xac\xac\xe0\x96\x49\xe3\x4e\xb2\x07\x39\x45\xc2\x53\xdb\xb3\x11\x7a\xbe\x44\x4d\x0a\x77\x94\x27\x59\x16\x2a\x4b\x2f\x71\x95\x95\x95\xca\x32\x29\xd0\x51\x9e\xb4\x6b\x24\xad\x97\xa0\xca\x3e\x34\x62\x73\x26\x0d\x3a\x93\xa2\x3a\x4d\x0e\x30\x94\x41\x2f\xa8\x89\x46\x03\x1d\xb8\x48\x72\x26\x81\x1c\x9d\x4a\xf8\x99\x72\x84\x5e\x20\x69\xfe\x52\xc9\x9b\x04\xb2\x53\x55\xec\x2d\x12\xd7\x2b\x64\x02\x7e\x4a\xc2\xfa\xd6\x71\xa7\x6f\xc3\x49\x92\x30\xbd\xef\xd6\x92\x67\xbb\x3c\x48\x73\xb6\x76\x3a\x05\x95\x87\x68\x6e\x61\xfa\xbc\xe3\x85\xca\xa7\x2a\x57\x9e\x36\xf3\x18\x96\x8f\x54\xae\xb2\xcd\xdc\xc3\xba\x2a\x85\x9f\x13\x53\x67\x1e\xa2\x52\xf8\x73\xa6\xd7\xf3\x9a\xf2\xf8\x9d\x2c\x69\x7d\xc3\xab\xb2\xe7\x49\xd6\xf4\x21\xc5\x4d\x86\xee\x26\x09\xeb\xbb\x5e\x05\x7d\x42\xa2\xa6\xaf\x5e\xae\x1a\xb8\xf1\xcc\xfa\x77\x91\x09\x78\x3c\xb7\xe9\xeb\x8a\x9b\x0c\xdd\xcd\x12\xd6\x0b\x4d\x41\x9f\x94\xa8\xf1\x00\x75\xab\x70\x99\x64\x0c\xe7\xa6\x5b\x85\x2b\x24\x61\x3a\x2e\x3d\xa5\xf0\x8c\x97\xa7\x3f\x2a\x55\x56\xae\x2f\xbf\xcd\x77\xb7\xf1\x57\xf4\x61\x1e\xe4\x89\x66\x78\x53\xd2\x8d\x90\x87\x5a\xde\x54\x57\xfc\x64\x9a\xe5\x9b\x88\xe1\x35\x47\x41\xe5\x8b\x48\xde\x54\x4d\x7c\x35\xc9\x52\xc4\x79\x7d\x35\x99\x80\xa5\x8a\xf3\xa6\x03\xc7\x4f\xa6\x59\x76\x27\x79\xfd\x81\xa3\xa0\xb2\x31\xc9\x9b\x14\xd1\x48\x6e\x50\x56\x8a\xbc\x5e\x1a\x0a\x2a\xeb\x44\xde\xa4\x91\x46\xaa\x16\xdf\x23\x47\xe8\x75\x92\xe6\x5f\x92\xbc\xe9\x40\x6b\xa8\x01\x94\x1d\x72\x5e\x7f\xa2\x4d\xc0\xb2\x45\x2e\x98\x74\xd8\x48\x86\x50\x1e\x67\x05\xbd\x00\x15\x54\x9e\x68\x05\xe3\xa7\x45\x75\x19\x32\x24\x05\x7d\x3b\x35\x01\xcb\x78\x14\x4c\xaa\x0e\x92\x0b\x91\x8d\x5a\x41\xaf\x6a\x05\x95\x6d\x5a\xc1\xa4\xea\x40\xa9\xb6\xf2\x04\x2e\xe8\x45\xad\xb2\xf2\xf4\x2d\x6c\xf3\x65\x78\xd4\x19\xdd\x2d\xe1\xa9\x1f\x58\x46\xe8\x8b\x12\x35\x69\xba\xa9\xd4\x9c\x71\x90\xf5\xa2\x56\xd9\x71\x8c\x4d\xaa\x6e\x26\x7b\xf3\xf1\x8a\xf5\x82\x56\xd0\xf1\x8a\x4d\x5a\x6e\xa6\xbe\xae\xde\x21\x47\xe8\xe5\x9c\xe6\x9f\x1b\xf1\xc5\xed\x3e\x96\x27\xeb\xe4\x9d\x72\xcc\xd4\x6f\x50\xca\x88\xe7\xe5\x08\x93\xbe\x9b\x4a\xe3\x28\xf7\x50\xd4\xcb\x5b\x65\xc7\xeb\x37\xf5\x4a\x7b\x93\xc5\x47\x8a\xb0\xa8\xef\x95\x14\x54\x6a\xb0\x68\xea\x95\xf6\x4e\x36\xaf\x67\xcb\x01\xfa\x6e\x29\x85\xcb\xb3\xb2\x68\xea\x97\xf6\x26\x1f\xb5\xb3\x24\xac\xef\x97\x14\xf4\xf2\x21\x6a\x95\x8b\x28\x1d\x17\x8e\x1c\x95\x79\x94\x9a\x3a\x49\x3a\x4a\x98\x58\xce\xcb\xd2\xb9\x80\xe3\xc0\x9e\x2b\x3d\x15\x54\x52\x39\xfe\x77\xfa\x65\x04\xff\x09\x00\x00\xff\xff\x17\x87\xd5\xd4\xdd\x25\x00\x00")
+
+func fontsTermFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsTermFlf,
+ "fonts/term.flf",
+ )
+}
+
+func fontsTermFlf() (*asset, error) {
+ bytes, err := fontsTermFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/term.flf", size: 9693, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsThickFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x57\x4d\x6f\xe3\x36\x10\xbd\xeb\x57\x3c\x08\x02\xbc\x8b\x26\x6a\x92\xda\xc0\x64\x4f\x2e\xd0\xf6\x52\x14\x10\x8a\x5e\x74\x33\x65\xd2\xb6\x10\x59\x5a\x58\x32\x98\xfd\xf7\x05\x39\xa4\x44\xca\x8a\x77\x7b\xe8\x62\xa3\x2f\xce\x3c\xbe\x99\x79\x1c\xd2\x87\xe6\xf0\x22\x32\x6c\xb0\xc6\xf3\x06\x4f\x78\x5e\x27\xff\x9c\xea\xfd\x1b\xaa\x6f\xf8\x5b\xb4\x52\x34\x8d\xb9\xf7\xdd\x19\x2f\x3f\xbf\xae\x93\x3f\xea\x63\xa3\x06\x5c\x54\xa3\x44\xaf\xf0\x92\x3f\xe1\xf1\x11\xbf\x5e\x8f\xd7\x7e\xc0\xe6\x01\xcf\xaf\xaf\xbf\x24\xbf\x89\x41\x7d\xc1\x06\x7f\x89\x8b\xf9\xb0\x4e\x92\xdf\xdf\xbf\x36\xa2\x15\x43\xdd\xb5\xe8\x0e\x38\xd4\x97\x7e\x40\x53\xb7\xea\x4b\x62\x18\xe0\x11\xe9\x59\x1c\xeb\x3d\xda\xeb\xb9\x52\x97\x14\x87\xee\x82\x43\xdd\x28\xd4\x52\xb5\x43\x7d\xa8\xf7\xd6\x39\x11\x00\xf0\x88\xfe\xd4\x5d\x1b\x09\xd1\x68\xf1\xad\x47\xa5\xb0\x13\xab\x07\xeb\xd4\x76\x3a\xc9\xd8\x68\x38\x29\xa4\x27\x71\x91\x55\x23\xda\xb7\xd4\x10\xfd\x7a\xa9\xdb\xa1\x87\xe8\x21\x60\xbf\x3e\xa0\xba\x0e\xd8\x8b\x76\x35\x18\x98\xfe\x7c\xed\x4f\x4a\x26\x1b\x46\x38\xa9\xfa\x78\x1a\x0c\x63\x81\xfd\x49\x5c\xc4\x7e\x50\x97\x64\x7d\x67\xf0\x01\x6d\x37\xa0\x6e\xf7\xcd\x55\xd6\xed\x11\x52\xf5\x7b\xd5\x4a\x75\xe9\x93\xe7\x8d\x75\x3b\x8b\x77\x1b\x39\x1a\xd5\x1e\x87\x13\x3e\xa9\x77\x6f\xbc\xef\xce\x67\xd5\x72\x62\xfa\xcf\xf8\x09\x02\x87\xab\x3c\x2a\x1c\xc4\x7e\xe8\x2e\xc9\x13\x4f\x2c\xd5\x41\x5c\x9b\x81\xc9\x9e\x3b\xa9\x6c\xe0\xc3\xa9\xee\x71\xe8\xda\x01\x9f\x9a\xfa\x4d\x21\x7d\x3c\xe3\x29\x45\xd7\x5a\x58\xd1\x4a\x0b\xfb\x39\x79\x5e\x5b\x10\x4e\xb4\x61\x1f\xcd\x9a\x24\x59\x96\x6d\x97\x2e\xdb\x84\x32\xfe\x4b\xb3\x6d\xa2\xed\xd7\xed\x36\xd1\x30\x8f\x29\xcc\xc7\x0c\x59\x7c\xdd\x26\x20\x80\x60\x1c\x48\x6b\xd2\xe1\xc3\x38\x04\xfb\xcf\x58\xe7\x9a\x74\x6e\xe0\x34\x59\x40\x80\x34\xf8\x5d\xf3\x7b\xca\x86\x1d\x20\x0b\xfb\x41\x16\x16\x42\x16\x66\x20\x31\xb7\xce\x43\x1a\x43\x59\x90\xb1\x2b\x2b\xad\xdd\xb0\x7d\xa3\xca\xa1\x59\x8e\x66\x28\x4f\x17\x22\xce\xed\x24\x64\xa7\x20\xeb\x4a\x95\xb9\xae\xca\xca\x0c\x97\x95\x21\x8b\x92\x98\xaa\xe5\x41\x76\x9a\x15\x0f\x3b\x96\xba\xac\x64\xa1\x99\x66\x59\x79\x9e\x65\x15\xc5\xee\x1e\x0c\x90\xbd\x9b\x2c\xe9\xe0\x7d\x34\x9c\xd7\xc6\xb3\x37\x39\x77\xa9\xb7\x37\xad\xad\x7f\xf4\xd1\x16\x6d\xfc\x1b\x8b\x88\x3b\xe9\x8c\xe6\xce\x25\x91\x0d\x9a\x4c\x00\xc4\x09\xe1\xa0\x77\x25\x91\x89\x3b\x08\xc9\x7e\xc7\xec\xe2\x46\x6c\x05\x52\x37\x2d\xcf\x2a\x89\xc8\xf9\x07\x36\xd0\x9a\xa9\x59\x77\x33\x49\x60\xe3\xe6\x86\x2c\x38\xef\x9a\x26\x53\x6f\x43\x0c\x4b\xda\x4a\x0b\xd8\x2d\xe1\x98\xc9\x6c\x7d\x0b\xcd\x76\xf7\xe2\x32\x88\x3f\x98\xae\x82\x35\x62\xf4\x67\x43\x95\x45\x9a\xda\xc2\xef\x8c\x26\x62\xd8\xdc\x45\x4c\x2e\x80\x1d\xe9\x31\x21\x14\x2b\x60\xac\x5d\x50\xc3\x2c\x73\x52\x9e\x9e\x58\x16\x88\xb3\x5c\x31\x47\x16\x22\xcb\x70\xae\x99\x65\xe9\x94\x33\x4f\x59\x05\xa8\x85\x5f\x6f\x1c\x5e\xea\x2b\xe3\x53\x04\x1d\xa7\x46\xa6\x69\x9a\x1a\xcb\x02\x45\x69\xc3\xab\x50\x49\xed\x17\xab\x5e\xcd\x17\x87\xe1\xed\xe6\x2d\x3c\x13\x59\x68\x3d\x2d\xa8\x68\x49\x8d\x95\x62\xb9\x6a\x56\x91\x49\xad\x4d\x71\x58\xd3\x28\xf7\xae\x84\xe4\x66\xdb\x05\x42\x89\x11\x5d\x51\xc6\xfb\x1c\x71\x92\x9d\x76\x66\xd9\xf8\xf1\xbe\xcd\x24\xa2\x91\x19\x4b\x13\xce\xee\x9e\x34\x3d\x1d\xad\x35\x2d\xd0\x0c\xe9\x71\x0f\x1e\xaf\x23\x35\xee\xdb\xe3\x2b\xb7\x6f\x77\xdf\x95\x3a\x8d\xea\x48\x4e\x5d\xa4\xb9\xd0\x44\x5c\x10\x0a\xab\xe1\x99\xdd\x04\x39\xcf\x87\xc9\xba\x0d\x8d\xca\xea\xcc\x8b\x9a\x6c\xd3\xf7\x31\x04\x51\x4c\x2e\xde\xc1\x9b\x2f\x06\xfc\xdf\x5a\x57\x50\xe6\xdc\xe5\xd3\x5a\x10\x7e\xa4\x23\xea\x09\x56\x7f\x0f\xf6\xcf\xd5\x52\xb6\x46\xd8\xd2\x37\x24\xe0\x7e\x43\xa2\x68\xaf\x98\xdf\x83\x22\x4c\xb9\x64\xb6\x79\xfe\x11\xac\x59\x66\xbe\x79\xf0\x66\xe6\x5b\x86\x6b\x78\x66\xc9\x85\x3d\x2f\xf2\x9b\xf9\xce\xfc\xe7\x18\x73\x9c\x10\xcb\xa3\x8c\xdd\xf6\xc3\x4d\x74\xc1\xda\x22\x73\x2e\x82\x64\xdc\xef\xe3\x81\x2c\x9d\xa1\x4d\x59\x7c\xa1\x31\x54\x1f\xa3\x0b\xce\x47\x55\xdd\x40\xcc\xf6\x42\x86\xb8\x8d\xc7\x9e\x5f\xb3\xa5\x87\xf9\x1e\xbf\xb4\xd5\x9b\xc5\x6a\x3a\x70\xbe\x70\xa0\x71\xea\x35\xea\x62\x11\xf8\xca\x87\x8b\xd0\x2f\x4d\xaf\x54\xa6\x3a\x6a\x23\xc6\xa9\xa6\xc5\xbc\x2b\x67\x7b\xb3\xf5\xbc\x3b\x17\x02\x42\x16\x29\xe7\x4d\xf1\xa6\xed\x82\x67\x02\xad\xfc\x61\xd2\x9d\x20\x17\x49\xdd\x4e\xc8\xdb\xef\xb4\x7e\x49\x8e\xab\xb6\x5c\x6c\x17\xda\xed\xad\xfe\xd0\xeb\x66\xe0\xe5\xac\xa7\x03\x9f\xbd\x06\xe0\x2e\x08\x4e\x20\x8b\x65\x14\x42\x78\x88\x9e\xe1\x8e\x8a\x67\x66\x21\xbb\x90\x61\xdc\xff\xe2\x1c\x7e\x37\xa4\x20\xd9\x6c\xb8\xe2\x26\x64\xea\xb6\x9a\x1b\x7e\xa4\x00\x5a\xa8\x9c\x6b\xe8\xe4\x37\x4c\x57\x14\x2a\x42\x30\x39\xee\xaf\xb7\x7b\x9c\xb3\x71\x22\xd8\xb9\x33\xd3\xec\x88\xc6\x07\x88\x59\xe9\x6f\x24\x37\xc2\xbb\x56\xec\x7b\x5b\x71\x9b\x0a\xfe\x29\x70\xa7\x61\xc4\xd6\xa1\x47\xe4\x15\x7b\x46\xde\x73\x62\x65\xe5\xfc\x76\x94\xbb\x25\x1f\xb7\x89\xbb\xc4\x7c\xc7\x74\xe7\xcc\xa0\x50\xf4\xf1\x31\x1a\xac\x46\xf0\xaf\x18\xbd\x62\x08\xd6\x26\xdc\x0f\x99\xb9\x28\x5d\x6b\xcb\x5d\x8a\x79\xf6\x1d\xff\x82\x21\xe6\xbd\xc2\xd4\xbb\xe0\x8e\xb6\x08\xb8\x4e\x09\xfb\xe0\x79\x9b\x64\xd1\xff\xff\xff\xfd\xdf\x00\x00\x00\xff\xff\xc0\xc7\x94\x97\xec\x10\x00\x00")
+
+func fontsThickFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsThickFlf,
+ "fonts/thick.flf",
+ )
+}
+
+func fontsThickFlf() (*asset, error) {
+ bytes, err := fontsThickFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/thick.flf", size: 4332, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsThinFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x57\xfd\x6e\xab\x36\x1c\xfd\xdf\x4f\x71\x14\x5d\x89\x76\xc5\xa0\x74\xea\xd5\x5d\x35\x4d\x68\xd2\xa6\xbd\xc1\xfe\x41\x0b\x0e\x98\x04\x95\xe0\x0a\x88\xda\x3b\xf1\xf0\x93\x3f\x30\x0e\x98\x24\xd3\x26\x05\x9b\x8f\xe3\xe3\xdf\x97\x8f\x9d\xb2\x2e\x9f\xd9\x17\x7c\xc5\x0b\xbe\x81\x6e\xb1\x7d\x26\xbf\xb2\x8e\x17\x10\x0d\x18\x6a\xf1\xc1\xdb\x9c\x75\x1c\xa5\x68\x7a\xbc\x8b\xae\xe7\x05\xf6\xdf\xd1\x8a\x3d\x6f\xfb\x24\xef\xa2\x9c\xd5\x3d\xcf\x8f\x11\x2f\xce\xe4\xf7\xea\x50\xf3\xbe\xfa\x5b\x63\xfe\xe4\x4d\xc1\xeb\x1a\x7f\x54\xf9\x1b\x6f\xb0\xdd\xc6\x3f\xfd\x88\x87\x8f\xa3\x7a\x4c\xde\x59\xcb\x3a\x51\xf6\x51\x2e\x4e\x8f\xe4\xb7\xcf\xf7\x9a\x35\xac\xaf\x44\x03\x51\xa2\xac\xda\xae\x47\x5d\x35\xfc\x95\x48\x0b\x41\xb1\x39\xb1\x43\x95\xa3\x39\x9f\xf6\xbc\xdd\xa0\x14\x2d\xca\xaa\xe6\xa8\x0a\xde\xf4\x55\x59\xe5\x6a\x30\x61\x00\x40\xd1\x1d\xc5\xb9\x2e\xc0\xea\x0f\xf6\xbd\xc3\x9e\x23\x63\x41\xa8\x06\x35\xe2\x83\x7c\xd1\xa0\xfe\xc8\xb1\x39\xb2\xb6\xd8\xd7\xac\x79\xdb\x80\x52\xbc\xb7\x55\xd3\x77\x60\x1d\x18\xd4\xdb\x10\xfb\x73\x8f\x9c\x35\x41\x2f\x69\xba\xd3\xb9\x3b\xf2\x82\x7c\xd5\x0c\x47\x5e\x1d\x8e\xbd\xb4\x98\x21\x3f\xb2\x96\xe5\x3d\x6f\xc9\xcb\x95\x8f\x21\x1a\xd1\xa3\x6a\xf2\xfa\x5c\x54\xcd\x01\x05\xef\x72\x19\xa7\xb6\x23\xdf\xf4\xb0\x13\xfb\x54\x9e\xa3\xe6\xcd\xa1\x3f\xe2\x81\x7f\x8e\xe0\x5c\x9c\x4e\xbc\xd1\x81\xe9\x1e\xf1\x04\x86\xf2\x5c\x1c\x38\x4a\x96\xf7\xa2\x25\x74\xab\x18\x0a\x5e\xb2\x73\xdd\x6b\x63\x4f\xa2\xe0\xca\xf1\xfe\x58\x75\x3a\x8d\x0f\x75\xf5\xc6\xb1\xa1\x27\x6c\x5f\x36\x32\xd1\x92\x97\x35\x85\xe2\x7d\x24\xdb\x67\xc5\xa2\x23\x2d\xcd\xbf\x98\x96\x10\x69\x66\x72\xbd\x4d\x08\x12\x32\xa8\x1f\x12\x22\x64\xab\xbe\x24\x64\xc0\x90\x90\x0c\x99\x79\xb4\x8d\x1e\x28\x1f\x22\x44\x48\x08\x7d\xa2\x4f\xd4\x76\xc8\x90\x61\x84\xc8\x3e\x94\xd0\x90\x0e\x34\x4a\x48\xa6\x3b\x40\x73\xd3\x81\x06\xf2\x29\xb3\xac\x09\x11\x40\x2c\xef\x63\x49\x12\xcb\x37\x31\x20\x26\x63\x27\xd3\x65\x17\x52\x69\x01\x86\xdd\xb0\x53\x2f\x87\x8b\xa9\xe5\x97\x84\x04\x30\xf7\xfa\x32\x37\xb1\x74\x70\xba\x90\x9a\x0f\xa9\x19\x35\x5e\xb1\x8d\x87\x6a\xa2\x21\x4a\x08\xfd\x81\x26\x24\x18\x32\x37\x1e\xb6\x1d\xa0\x63\x62\xef\xe1\x01\x2d\x06\x04\x16\xe4\x36\x94\xd2\xcb\xc0\x3b\xbf\x29\x55\xfa\xf3\x32\x6a\xf3\xb9\x43\x2a\x83\x3f\x40\xba\xa5\xdb\x8c\xea\x04\x38\x73\x07\x83\xca\x8f\x6d\x66\x4e\x6a\x8e\x50\x8d\x1b\xd4\x9b\x39\x87\x05\x01\x74\xd0\x49\xf1\x82\xac\x05\x16\x84\x71\xb6\x09\x44\xa9\x2e\x1b\xcd\xb7\xc2\x64\xfc\x72\xbc\xf3\x80\xe8\xc8\x11\xeb\xfa\x9b\x5a\x9f\x77\xd7\x98\xf4\xe7\x6c\xb7\x73\x0d\x0f\xdc\xe5\x34\x66\x67\xca\x91\xb9\xc4\x45\x55\x4e\x95\x18\x8f\x85\x97\xda\x12\xbd\x28\x81\x45\x1d\xb8\x78\x33\xde\x5d\x1e\xe1\xe8\x6d\xa8\xad\x37\x75\x28\x70\xb1\x3c\x5c\xe8\x00\xb1\x8b\x75\x4a\x75\x4e\x47\xb7\x3d\x50\xaa\x72\x36\x98\x7c\x4c\xce\xfb\xa1\xd1\x04\xbd\xca\x6a\xab\xe2\xaa\x01\x11\x2c\xdd\xc4\x1a\xac\xbb\x45\x29\xbd\x83\x55\x41\x77\xbb\xc8\x81\xba\x3a\xe3\xb1\x75\x77\xcb\xad\xd1\xc8\xab\xc1\x1a\x95\x57\x7e\x9a\x96\xb3\x99\x77\x98\x77\xeb\x13\xc5\xca\xfc\x58\x3f\xa5\xc6\xfc\xcc\x0b\x5d\x74\x6b\x41\x89\xb4\xa7\x83\x0e\xb5\xd9\x0c\x02\x5f\xae\x01\x48\x68\x6a\xb2\x92\x1a\x4f\xb3\xab\xb9\x1e\xee\x2c\x0b\x6a\xa5\xe6\x8e\xac\xcc\x58\xd3\xdb\xac\xeb\xc1\x0a\xad\xf6\x18\xe1\x58\xb7\x95\xd2\x48\x2f\x50\xb3\xce\x4c\x97\x79\x6c\x8d\x4c\xb0\x6e\x46\xc0\x60\x11\x1a\xe7\x65\x19\xa4\x46\xe0\x91\x05\x96\xfa\x82\x3b\xc2\x32\x67\x34\x98\x73\x2b\xe6\x30\x21\xf8\xe5\x67\xab\xc3\xc1\x5c\x7b\x9d\xc4\xce\x8c\x74\xbc\xbb\x08\x96\x64\x8c\xd4\x5a\x5c\xab\x2c\x89\xd3\xdb\xed\xab\xd9\x76\x33\x6a\x6d\x4a\x75\x6a\x53\xcd\x9e\x6a\xff\x52\xc7\xa6\x84\xa8\x44\xc8\x40\xbc\xea\x9e\x06\x56\x2a\x23\xb5\xe5\xa5\xf3\x1d\x74\xfe\x3c\x13\x56\x4d\xab\xb6\x81\x2c\x99\x1f\x12\xdc\x83\x86\x29\x86\x50\xaf\x66\xe9\xd8\x5f\xab\xab\xeb\x0e\xcd\xf3\x4a\xdf\x3a\x74\xb0\x33\xff\x1b\x56\x8d\xf9\xcf\x9a\xe7\x5d\x64\xd9\x14\x88\xe0\x56\x04\x16\x9a\x27\x12\x12\xad\x68\x9e\x39\xe8\x45\x7e\xe9\x5b\x4c\xf4\xff\x6a\x9e\x57\xfa\xfc\x9a\xe7\x0f\x8a\x77\x2b\x5c\x8d\xdf\x9d\xd0\x0b\x05\xbc\x2b\x2b\x3a\x66\x37\x8a\xed\x8e\x5c\x67\x53\xe7\xdf\x76\x70\xdf\x06\x6b\xe5\xc9\x2b\x27\x97\x9a\x07\x07\xac\x34\xea\x86\xe6\x59\xb8\x2b\x7d\x5e\xcd\xc3\x42\xf9\x7c\x9a\x37\x46\x60\x61\xeb\xb2\x08\x9d\x60\x4d\xd2\x17\x2c\xdc\x52\xff\x52\xd4\x31\x3f\x21\xf4\x15\xe6\x0e\x5a\xf9\x9c\x03\xc0\xe0\xfc\xf5\x32\xff\x6a\x64\xf3\x6a\xc7\x06\xae\x99\x3b\xd5\xc5\x48\x77\xf1\xdc\x20\x3b\xb7\x80\xb8\xf7\xd4\x76\x09\xbd\xba\x39\x69\xe8\xdd\xfb\xd8\x9c\xfc\xaa\x84\x7a\xed\xb8\xca\x7a\xbb\xa8\x56\x0e\xa3\xb3\x65\xf5\x4f\x00\x00\x00\xff\xff\xe8\x6e\xdc\x71\x5d\x11\x00\x00")
+
+func fontsThinFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsThinFlf,
+ "fonts/thin.flf",
+ )
+}
+
+func fontsThinFlf() (*asset, error) {
+ bytes, err := fontsThinFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/thin.flf", size: 4445, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsThreepointFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x54\xcf\x6b\xe3\x38\x14\xbe\xeb\xaf\xf8\x26\x18\x92\xd0\xc4\x6a\xda\xec\xa1\x43\x29\x1a\xd8\xdd\x53\x4f\x7b\x18\x72\x30\x28\x8a\x2d\xc7\x66\x1c\xb9\xd8\x32\xd3\x01\x91\xbf\x7d\x79\x92\xad\x38\x7b\x58\x18\x8a\x1b\xbf\x5f\xdf\xfb\xde\xfb\x24\x97\x4d\xf9\xa4\x12\x3c\xe3\x09\xbb\x1d\x1e\xb1\xdb\x33\x5b\x75\x5a\x7f\xb4\xb5\xb1\x38\xfd\xc2\x3f\xca\x14\xaa\x69\xe8\xb7\x6f\x2f\xd8\xf3\x97\x3d\x5e\x3b\x6f\x88\x73\xdd\x59\x75\x4a\x87\x3e\x4f\x75\x31\xbc\xb1\xbf\xeb\x73\xa3\x2d\x3a\xdd\x68\xd5\x6b\x3c\xa5\x8f\xd8\x6e\xf1\x6d\x38\x0f\xbd\xc5\x1f\x1b\xec\x5e\x5e\x9e\xd9\x9f\xca\xea\xaf\x78\xc1\xb7\x8f\x8e\x1c\x7b\xc6\xfe\xfa\xfc\x68\x94\x51\xb6\x6e\x0d\xda\x12\x65\xdd\xf5\x16\x4d\x6d\xf4\x57\x46\xf4\xb0\xc5\xe2\xa2\xce\x75\x0e\x33\x5c\x4e\xba\x5b\xa0\x6c\x3b\x94\x75\xa3\x51\x17\xda\xd8\xba\xac\x73\x5f\xcc\x14\x00\x6c\xd1\x57\xed\xd0\x14\x50\xcd\x4f\xf5\xab\xc7\x49\xe3\xa8\x96\x1b\x5f\x64\xda\x9f\x2c\x09\x49\xb6\xd2\x58\x54\xaa\x2b\x4e\x8d\x32\x3f\x16\x44\xf4\xa3\xab\x8d\xed\xa1\x7a\x28\x78\xef\x06\xa7\xc1\x22\x57\x66\x69\x09\xa6\xbf\x0c\x7d\xa5\x0b\xf6\x1c\x10\x2a\x5d\x9f\x2b\x4b\x8c\x15\xf2\x4a\x75\x2a\xb7\xba\x63\x4f\xff\x13\xdc\xc0\xb4\x16\xb5\xc9\x9b\xa1\xa8\xcd\x19\x85\xee\x73\x6d\x0a\xdd\xf5\x6c\xb7\xf3\x65\x17\xf5\xe9\x27\x47\xa3\xcd\xd9\x56\x58\xe9\xcf\x29\x39\x6f\x2f\x17\x6d\xc2\x62\xfa\x35\x1e\xa0\x50\x0e\xc5\x59\xa3\x54\xb9\x6d\x3b\xf6\x18\x1a\x17\xba\x54\x43\x63\x03\xd9\x4b\x5b\x68\x3f\xb8\xad\xea\x1e\x65\x6b\x2c\x56\x4d\xfd\x43\x63\xb1\xbd\xe0\x71\x81\xd6\x78\x58\x65\x0a\x0f\xbb\x66\xbb\xbd\x07\x09\x8b\x26\xf6\x77\x5d\x19\x4b\x12\x31\x3d\x82\x39\xc1\x52\xc1\xe8\x6d\xb9\x9c\xb9\x1f\x1e\xc2\xe3\x8d\x95\xbb\x0a\x26\xdd\x5a\xb0\x04\x3e\x93\x0b\xc6\x37\x53\x70\x0d\xc1\x56\xf2\x10\x83\x84\xe6\x01\xc1\x05\x73\x10\x0c\x99\x10\x2c\xa3\x17\x27\x18\x87\x10\x2c\xc5\x46\xb0\xed\x61\x2b\xd8\x12\x47\x41\xd8\x52\x30\x7c\xc1\x84\x91\x08\xb6\x09\x18\x52\xce\x48\x25\x91\x2b\x41\x73\x8c\x6e\x7e\x10\xec\xc0\x05\x03\x41\x2f\xa9\x63\xea\x52\x32\xbd\x7d\x5d\x53\xba\xbc\xb3\x53\xb9\x9e\x6c\x27\x1d\xbd\xba\xc9\x7e\xa7\x51\xd7\x23\x18\xb8\x9f\x2d\x26\x5f\xc7\xb6\xde\x58\x11\xd2\x2c\xb8\x0a\x9d\x30\xd9\x69\x64\x9b\xc6\x71\x88\xf7\x6a\x5a\xc9\x76\x1b\x1e\x9f\xed\xf7\xb3\x1e\xf7\x13\x48\x7f\x89\x50\x09\xbf\x5e\x33\x5a\xe6\xca\x71\xc1\x92\x4c\xca\xc0\x8e\x8a\x42\x08\xe3\x34\x54\xe8\x6e\x9c\xf8\xf5\x28\x58\x26\x37\x71\x5a\x0f\x23\xf9\x8d\x33\x8d\x30\x52\x20\x95\xe9\x19\x2b\x25\x55\xf2\xbb\x3d\xb9\xdb\x9e\xae\xe1\x4c\xc8\x3b\xfb\xdd\x45\xca\x44\xd4\x65\x13\x32\x08\x60\x32\x32\xee\xa1\x46\xac\xe0\x82\x77\x65\x37\x17\x27\xa6\xf3\xfe\x7e\xb2\x2b\x6e\x93\xf9\xf8\xe1\x3f\xf1\x6c\x3e\x59\xd4\xd1\x93\xc3\x8c\x9c\x6f\x27\xe3\x30\x19\x48\x18\x64\xa3\x78\xa3\x6b\x72\x46\x77\x08\xd0\x19\xc8\xa2\x6a\xfc\x0e\xd8\x1f\x90\xbb\x7d\x86\xc9\x47\x7d\xb3\xc8\x27\x5c\x06\xe9\x48\xec\xe3\xfc\x88\x27\xf1\xcc\x0b\x76\x8c\x57\x29\x91\x09\x09\xe5\x6e\x6a\x24\x77\x3a\x27\x72\xa6\x63\x42\x79\xb3\xe4\x50\x7c\xbb\x02\x70\xc7\x69\x25\xb3\xb8\xcf\xf7\x84\x02\xf8\x4d\xea\xd4\x7f\x25\x7c\x65\x1a\x78\xbf\xbb\x49\xd4\xd7\x69\xd6\x98\x93\x48\x8c\xf5\x93\xc0\xb1\xc7\x0c\x73\xec\xb9\xbe\xb3\xfd\x40\x6e\xb2\xfd\xd5\x0b\xab\x75\x7c\x9c\xd1\x21\xce\x28\x98\x9c\xd6\x19\x8e\xe1\x4d\x05\xfa\x3f\x97\x97\xcc\x6c\xfa\x40\x90\xf1\xfd\xfb\xcc\x78\x7b\x9d\x19\x19\x1f\xaf\x20\xf1\x89\x4a\x82\x96\xf5\x0a\xff\x09\x93\x71\x5a\xe7\x95\xf4\x5d\xdf\x88\x84\xbf\xb9\xc7\x65\xf8\x88\x8d\x5f\x32\xff\xf7\x3b\x3f\xff\x06\x00\x00\xff\xff\x14\xc8\xd7\xe6\xcc\x07\x00\x00")
+
+func fontsThreepointFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsThreepointFlf,
+ "fonts/threepoint.flf",
+ )
+}
+
+func fontsThreepointFlf() (*asset, error) {
+ bytes, err := fontsThreepointFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/threepoint.flf", size: 1996, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsTicksFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x57\xcd\x6e\xdb\x38\x10\xbe\xeb\x29\x06\xc2\x02\x4e\x0e\x2b\x39\xde\xec\x02\xbe\x79\xdb\x6b\xd1\xf6\xd0\xf6\x14\x60\xa0\xd8\x52\x2b\xd4\x91\x02\x4b\x6e\x91\x4b\x9e\xbd\xa8\x61\x5b\x1c\xce\x0f\x29\xcb\x0d\x10\x4b\x14\xc9\xf9\xfd\xbe\xe1\xb0\xda\x56\x8b\xe2\x2f\xf8\x0f\xfe\x85\xc5\x1c\xe6\xb0\x84\x79\x92\xf4\xf5\xfa\x7b\x97\x55\xdb\x0a\x6e\xde\xde\xc2\xdd\x72\x79\x0f\x8f\x2f\xf0\xa5\x5e\xf7\xed\x0e\x3e\x16\xbb\x62\x53\xc0\xcd\x8f\xe7\xc3\xcb\xaa\x6e\xaa\x6c\xdf\x57\xdd\x53\xb6\xde\xde\xc2\xf2\x3e\x9f\x2f\xf3\xc5\x3f\x59\x92\x54\xf5\xd7\x6d\xd9\xc3\x22\xbb\x83\xaa\x6d\x7a\x78\x2c\xba\x72\x03\x6d\x03\xdd\xb6\xde\x94\xbf\xc5\x67\x49\xf2\x69\xf7\x02\xed\x73\x5f\xb7\x0d\xa4\x7f\x3f\xc1\x5d\x0a\x7d\x0b\xdd\xd3\xbe\xfb\x06\x6d\x53\x42\x8a\x29\x3c\x96\xfd\xcf\xb2\x6c\x0e\x42\xba\x2c\x49\xde\x15\x7d\x7d\x1c\x41\x31\x83\x72\x06\xf5\x0c\xda\x19\xec\x67\xd0\xbc\x42\xd1\x6c\xe0\xfd\x2b\xec\xca\xe7\x6d\xb1\x2e\x3b\xf8\x3f\x85\x0f\x29\x7c\x4e\xa1\x48\xa1\x4d\x61\x9f\x1e\x56\xbc\xc9\x92\x04\x11\x71\x65\xff\xae\x12\xcc\x1f\xf2\x07\x14\x9e\x78\x5c\x46\xc7\xc7\x0f\xee\xe2\xe1\x1d\x0f\xff\xe7\xc5\x68\xbd\x1f\x06\x87\xad\xc7\x5f\x57\xdc\x20\xf4\xb2\x35\xde\xdf\xea\xf8\xe9\xb8\x00\x87\x4d\x82\x27\x8e\xa5\xd2\xbc\xab\x62\x58\x7f\x8a\xd3\xe9\xe3\x79\xac\x6d\xf0\xac\x16\xf6\xdb\x1e\x70\x91\xc4\x2b\x45\xac\xb2\x46\x08\x17\x47\x85\x13\x59\xf6\x74\xa5\x9e\x63\xe5\xc0\x07\xdd\xd4\x79\x56\xf8\xa8\xb0\x16\xd1\x8c\x73\x65\x01\x78\xa1\xe3\xbb\x0e\x26\x7f\x4d\x34\xbc\x86\x0f\x3c\xdb\x9a\x1a\x12\x47\x6f\x3f\x57\x20\x3c\xe5\x44\x19\x14\xf4\xad\x90\xd6\x5c\xa4\x99\xc5\x82\x6a\x09\x33\x81\x08\xb6\x63\x41\xb9\xa8\x53\x8f\x42\xc4\x87\x8f\x98\x4f\x07\x3a\xc3\x56\xf2\x4d\x7e\x3b\x6f\x96\x2a\x05\x0a\xe0\x65\x0c\x41\x1d\x2a\x38\x45\x81\x3f\xaf\xed\x27\x09\x94\x68\x48\x2d\xce\xc5\x92\xac\x25\x5c\xf1\x80\x16\x29\x1e\x82\x8b\x3d\x88\x8d\xb1\x8c\xa0\x20\x42\x62\x5c\xfe\xa3\x18\x1f\x3b\x3f\x41\x01\x85\xe1\xa8\x10\x59\x0d\x45\x2e\x35\x16\x31\x1b\x48\x89\xf3\xa8\xc8\xce\x1c\x31\x29\x62\x89\x43\xbb\x3e\x6a\xdf\xb9\xcf\x41\xcd\x9a\xa5\x22\xbe\x34\x8e\xfb\x14\x45\x66\x95\x28\xdc\x4e\xbf\x4f\x49\x9d\xa2\x11\xf8\xd2\x1a\x2e\xbd\x68\x4b\x35\x81\xc5\x5c\x0b\x91\x2e\x30\x6e\xde\x08\x91\x5e\xa5\xac\xb1\xc6\xa0\x51\x1e\x84\xc6\x41\x0a\x52\x0f\x28\x4a\x34\x03\xf8\x7c\xd0\x83\xb8\x42\x1e\x0e\xd9\x45\x39\xb0\x50\x13\xe1\x41\x5c\x8c\xe3\x72\xa2\x86\x88\x97\x04\xf9\x5d\xb4\x56\x6f\xab\xf4\xb1\x1e\x0a\xab\x60\x1b\x37\x18\x67\xbb\xda\x06\x04\x43\x21\xe6\x3e\x62\x24\xa6\x90\x0a\xa5\x29\xe3\x0d\x20\x4f\xa3\x74\x51\x0a\x5f\x8b\x14\x55\x3a\x5a\x2c\x78\xa2\x9f\x64\x99\x30\xf1\xf0\x8b\x48\x72\x48\xc1\x95\x18\x3b\xc6\x03\x9f\x0b\x01\xc6\x8e\xf7\x60\x04\x4c\x43\x35\x67\x72\x7f\xed\xa3\x04\x85\xc3\x7a\xec\x38\x08\xd3\xab\xa3\x68\xaa\xc0\x28\x0f\x38\x4e\x64\xb2\x59\xcc\xa7\x72\x30\xec\x4d\xd8\x5a\x1b\x81\xa3\xc3\x15\x13\x9e\x60\xb8\x38\x69\x42\x1e\x9c\x04\x8c\x38\xe8\xd1\x6b\x5a\xad\x77\x26\x6c\xa5\x92\xc9\x1d\x4b\xae\xea\x64\x33\x2d\xf5\x17\x4a\xef\xaa\xa5\xda\xa1\x7c\x4a\x1d\xaa\x17\x01\xed\x76\x21\x66\x6f\xfc\x98\x26\x4b\xbc\x38\xd1\x0b\x14\x7d\x7a\x47\xe8\xc0\x1a\x96\x00\x7a\xe6\xc7\x1f\xc4\xfa\x09\xce\x2a\x32\x9b\x43\x35\x76\x94\x27\x01\x85\x28\xe7\xd5\x15\x2a\x70\x45\x51\x21\xcf\x45\x59\x2a\xc5\x6d\x94\xa5\x3a\xed\xd8\x09\x6d\xdd\x27\xc3\x71\xb4\x9c\x94\x52\x35\x31\xe3\x22\x83\x1d\xa1\xc3\x04\xf9\xe6\xc7\xd4\x5d\x27\x90\xdc\x8d\x45\x5c\x21\x30\x5c\x93\x01\x6b\x39\xaa\xba\x16\x7e\x13\x5d\xa3\x59\xcc\xdd\xe6\x93\x55\x86\x49\x7d\xae\xa4\x28\x26\x97\xa6\xfb\x32\x06\x63\x00\x12\x5d\x20\xe2\xeb\x8c\x8e\xdd\xab\xb1\xc5\x1d\x89\x96\x8e\xb7\x6d\x74\x7d\xf4\xe3\x66\xcd\x39\x42\x79\xad\xa1\x0e\x53\x85\x72\x4a\x83\x89\x8a\x05\x11\x8f\xf0\x05\x42\xb9\x6d\x62\x3b\xa5\x33\x8d\xc7\x2f\xd4\x8d\x22\xfa\xfc\xf4\x25\x07\x3c\xf0\x6d\x8e\x2e\x34\xe3\xc3\x12\x51\xed\xb9\xd0\x5c\xba\xc1\x04\xf1\xe3\x59\xaa\x83\xcb\x07\xbe\x04\x35\xbd\xce\x46\x3f\x45\x36\x68\xbc\x41\xa3\x3b\x12\x5d\x93\x01\x82\xe2\xc5\x97\x46\xd8\x1e\x2b\xd9\x72\x17\x6b\x76\x06\x12\x82\x42\x37\x74\x95\x36\x66\xc2\x99\x6e\x59\x34\xe1\xd8\x88\xa9\x3f\x23\xaa\x91\x1e\xd8\x89\xfd\x90\x22\x96\x77\x01\x44\x98\x76\xd7\xa4\x0a\x7e\x05\x00\x00\xff\xff\x75\xa7\xe0\x03\x21\x23\x00\x00")
+
+func fontsTicksFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsTicksFlf,
+ "fonts/ticks.flf",
+ )
+}
+
+func fontsTicksFlf() (*asset, error) {
+ bytes, err := fontsTicksFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/ticks.flf", size: 8993, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsTicksslantFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x59\x4d\x6f\xe4\x44\x10\xbd\xfb\x57\x94\x2c\xa4\xd9\x95\x60\x3a\x09\xbb\x48\x73\x1b\xe0\x8a\x80\x03\x70\x8a\xd4\x72\x12\x3b\x58\x4c\xec\x28\xf6\x80\xf6\x92\xdf\x8e\xc6\xe3\xf1\xd4\x57\xbb\xdb\x6d\x1b\x11\x69\x57\x8e\xe3\xe9\xd7\xaf\xea\xd5\xab\x6a\x4f\x71\x28\xee\xb2\xaf\xe0\x3b\xf8\x0c\x77\x9f\xe1\x06\x76\x70\x93\x24\x6d\xf9\xf8\x57\xd3\x1c\xb2\xaa\xdd\x16\x87\x02\x3e\xfc\xf8\x11\x6e\x77\xbb\x4f\xf0\xf0\x05\xfe\x28\x1f\xdb\xfa\x0d\x7e\xcd\xde\xb2\xa7\x0c\x3e\xfc\xfd\xda\x5d\xec\xcb\xaa\xd8\x1e\xdb\xa2\x79\xd9\x3e\x1e\x3e\xc2\xee\x93\xb9\xd9\x99\xbb\x6f\xb7\x49\x52\x94\xcf\x87\xbc\x85\xbb\xed\x2d\x14\x75\xd5\xc2\x43\xd6\xe4\x4f\x50\x57\xd0\x61\x9c\x96\xff\x1a\x3a\xa4\xfc\x09\x8e\x4d\x59\x3d\x9f\x7f\x2b\xca\xe7\xd3\xe3\xdb\x24\xf9\xed\xed\x0b\xd4\xaf\x6d\x59\x57\x90\x7e\xf3\x02\xb7\x29\xb4\x35\x34\x2f\xc7\xe6\x4f\xa8\xab\x1c\x52\x9b\xc2\x43\xde\xfe\x93\xe7\x55\x07\xd0\x6c\x93\xe4\xa7\xac\x2d\xfb\xdf\x20\xdb\x40\xbe\x81\x72\x03\xf5\x06\x8e\x1b\xa8\xde\x21\xab\x9e\xe0\xe7\x77\x78\xcb\x5f\x0f\xd9\x63\xde\xc0\xf7\x29\xfc\x92\xc2\xef\x29\x64\x29\xd4\x29\x1c\xd3\xee\x89\x1f\xb6\x49\x02\xa7\x1f\x6b\xad\xdd\x27\x97\x2b\xe8\x2e\xbb\xab\xee\xf2\x7c\x75\xba\xec\xaf\x60\x9f\x5c\xae\x60\xbf\xef\x97\x30\xf7\xe6\xfe\xb2\x48\x77\xdd\x2f\x73\xbe\x1e\x16\x1a\x96\xea\xef\x5f\x16\xd3\x96\xe3\x4b\xd2\x65\x6d\xf7\x8f\x2c\x4d\x77\x7a\x5d\xf6\x02\x21\x61\xec\x79\x1f\xfd\xff\x1c\x8c\x42\xb2\x67\x7b\x60\xfe\xec\x05\x9e\x3d\x4b\x37\xa1\x6f\x65\x78\x1c\x65\x43\x6e\x63\xf8\x9d\x66\xc8\xf2\x2d\xa0\x4f\x92\x0d\xa0\xcf\x8a\xfc\x5d\xfe\x8c\xf3\x38\x70\x18\x64\x61\x25\x3c\x7a\x12\xe7\xd7\x5a\x99\xe7\x00\xf6\x58\x8d\xf8\x2e\x49\x04\x02\x1c\x12\x81\x9e\x27\x89\xc0\x9b\xf3\x26\xc2\xad\x64\x26\x37\x2c\x35\xb7\x92\x87\x1d\x10\x71\x5d\xd9\xf0\x60\xe2\x9c\x11\x06\xe3\x4a\x1e\x3e\xc6\xa4\x23\xf2\x46\x72\xc6\xe5\x12\x59\x30\x16\xc5\x99\x32\x23\xa5\xc1\xb4\x4a\x83\x18\x55\x30\xc3\x8f\x26\x18\x65\x1b\x7c\x13\x22\x8f\x18\xca\xaf\x58\x0c\x8b\x03\x4d\x34\xa9\x18\xde\xc0\x51\x61\x83\x97\x54\x58\xcc\x36\xbc\xf8\x5d\x8f\xe4\x00\x0b\xdc\xe2\xe8\x06\xb8\x06\x66\x81\xee\x84\xe5\x00\x79\x1c\x31\x2d\x2b\x9b\x90\xa5\x01\xe4\xbe\x80\x6b\xcd\xa9\x41\xb5\x18\x68\x61\xd3\x6e\x41\xb9\x52\xb1\x53\x00\xbd\xff\xf1\x2a\xe3\xcc\xd8\x8e\x89\x13\xf2\xc0\xe2\x0e\xe1\x61\x36\x07\x9e\x3e\x37\xde\x8c\x46\x54\xea\x32\x34\xe9\x9d\x92\xbd\x11\xed\xd8\xda\x51\x6f\x71\xb1\xe7\xbd\xd0\x92\xa2\x61\xac\x96\x63\xef\x56\xb5\x0f\xde\xb0\xb6\x1b\xa1\x6a\x8d\x3d\x0d\xe0\xff\xa2\xa6\xc7\x94\x3f\xbb\xa6\xa7\xc0\x4b\x4f\x9e\x19\x7c\x6d\xf8\xc0\x41\xe6\xd2\xf2\x8c\xd1\xb1\xcb\x39\x9a\x14\x95\x85\x56\x8f\x8a\x1c\x50\x1d\xaa\x0e\x34\xde\x0b\x8d\x98\xc4\xad\x60\x20\xcb\xdd\xdb\x0b\x8d\x3a\x6d\x2b\x02\x77\xb0\x31\x78\x92\xf6\x4d\x66\x21\x5e\x6a\xad\xcb\x4d\x2e\xcb\x92\x20\xce\xad\x27\x23\xce\x15\x5a\x8f\x94\xf0\x51\x56\x2e\x03\xad\x4b\x87\xc3\xf3\xdc\xf2\x12\x8f\x68\x64\x5a\x39\x87\x7a\x69\xb4\x95\xfb\x3b\x89\xa6\x6a\x77\xf0\x17\x67\xaf\x05\x7f\x26\x7b\xa3\xf6\x51\xfc\xb8\x3f\xf8\x98\x3d\xd7\xc3\x8a\x6d\xdc\x05\x4f\xa0\x96\xcc\xbd\x5e\x78\x46\xed\x24\xc1\xec\xad\x7a\xa0\x77\x29\xdf\x9f\x7b\x3b\xbd\xf0\xdc\xe6\xca\x9d\xce\x08\x73\x55\xa1\xf4\x56\x61\xc4\xb0\x22\xcd\x35\x44\xe1\x31\xed\x3a\xe0\xad\x09\x5a\x94\x49\x4c\xb2\x9e\x18\xe4\xfe\x0f\x52\x60\xd2\x5a\xa4\xb6\x65\x5d\x4b\x50\x17\x24\xe7\xac\xb7\x14\x97\xb8\xf8\xd1\x8b\xad\xab\x71\x0f\x0d\xfe\x75\x69\x9f\xc2\xcd\x9c\xd6\x32\xed\xf0\xb9\x8a\xf4\x42\xe1\x57\x75\xb7\x58\xf6\x54\xf9\x2b\x76\x36\x9d\xfd\xac\xc2\x0b\xf5\xf6\x95\xce\xc7\x46\xe9\x6c\x56\x79\xf5\x65\xd5\x23\x9a\xfe\xea\x0b\xdf\x5b\xb0\xb5\xac\xa4\xfc\x58\x78\x0e\x35\x83\xbd\xee\xfa\x6e\xeb\xd1\x5f\x3d\x2d\xee\x80\xda\x70\xad\xeb\x40\x46\x62\x62\x15\x84\x26\xc2\x55\x05\x0b\xc8\x50\xab\x82\x39\x2f\x2a\x22\x2c\x48\xd4\xbf\xe3\x30\xcc\xd9\x3a\xa1\x9c\x3d\x5e\x9e\x54\xad\xbf\xd6\xb5\x33\xf8\xc4\x1c\xab\x36\xe3\x3c\x24\xeb\xce\xe6\x9d\xe3\xa4\x97\xd3\x42\x3a\x2f\xbc\xc4\xeb\x6f\x11\x4c\x4c\x9e\x8e\x8b\x32\x98\x0e\x58\x04\x2d\x64\x14\xf2\x3a\x46\xff\x92\x54\x30\x72\xb2\x61\xe3\x8f\x2a\x0b\xfe\xb6\x64\xde\xf8\x37\x3e\x71\x4a\x48\x87\x2c\xb4\x42\xf7\xb1\xb4\x8a\x3c\xfc\x43\xae\x75\x6b\x51\x87\x74\xf8\x8a\x34\x35\x27\xcb\xc9\x90\x1a\x4b\xf5\xa0\xba\x0c\x4b\xbf\x81\xa9\x53\xe3\xb4\xf7\x5f\xe1\xf9\x33\x7a\xa3\x26\xb5\x86\x99\x31\x11\xad\xa3\x52\xa7\x53\xaa\x90\xd4\x53\xa8\x3a\x69\x18\x49\x21\xb0\xe5\x65\x00\xa5\x16\x95\x12\x77\x58\xb0\x1e\xb6\xe0\xa0\xf1\x3c\x85\xb8\x49\x54\xd0\xa4\xd8\x67\x06\x4d\x2a\xcf\xe0\xe3\xa1\xe7\x8b\x6a\x73\xbf\xd0\x39\xd5\xb5\x0d\xc9\x76\xdc\x4d\x26\x04\xd6\x5d\x73\xd3\x20\xad\x9d\x61\xd3\xa1\x2c\x35\xf9\x0c\x00\xbd\x5e\x27\xb2\x9c\xeb\x2c\xec\x8e\x8f\x65\x48\x91\x5c\x19\xe8\x2c\x23\x72\x39\x06\x49\x19\x4c\x6e\xb9\xc3\xfe\x58\x2e\x79\xff\xeb\x3f\xcc\x67\xea\xa5\xe4\xa3\x1d\xe8\xc2\x14\x1b\x55\x24\x21\x90\x94\xd3\xd5\x5f\xa7\xe6\x52\xc0\x5a\xf5\xf8\xea\x2a\x18\xae\x60\xea\x6b\xd1\xae\xa4\xcf\x38\xf2\xd4\x18\x65\xf7\xf3\x02\x1e\x35\x09\xe8\x90\x5c\xc9\x7c\x44\x96\x4a\x36\xe1\x23\x32\xda\xaf\x3c\xae\x39\xe7\x55\x77\xf1\x84\xf6\x51\xe5\x5c\x21\x4a\x05\xe7\x0c\xbb\xab\x5c\xce\x88\x79\x86\x5a\x39\xc9\xc1\x3e\xe1\x61\x8c\x75\x1c\xce\x64\xc4\xce\x27\x1f\xcc\xbc\xc5\x20\xc1\x71\xce\xa4\x4c\xcc\x9c\x93\x94\x84\xfc\x8f\x06\xfe\xd5\x66\xd4\x10\x36\x8b\x0f\x1c\x42\xfa\x6b\x76\x0c\x94\x0f\x3e\x8b\xaf\x79\xae\x18\x01\x15\x87\x35\x9d\x6b\xc4\x97\x1c\xff\x06\x00\x00\xff\xff\xdd\xdb\xf2\xef\x36\x2f\x00\x00")
+
+func fontsTicksslantFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsTicksslantFlf,
+ "fonts/ticksslant.flf",
+ )
+}
+
+func fontsTicksslantFlf() (*asset, error) {
+ bytes, err := fontsTicksslantFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/ticksslant.flf", size: 12086, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsTinkerToyFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x58\x4b\x6b\xec\x36\x14\xde\xfb\x57\x7c\x0c\x17\x6e\x42\xa3\xfa\x4e\x4a\xb8\xb4\xab\xd9\x14\xba\xd3\xa6\xd0\x8d\xa1\x55\xfc\xc8\x98\x78\xac\x60\x7b\x48\x02\xfe\xf1\xc5\x7a\x58\x47\xb2\x6c\x4f\x02\xf1\x4b\x3a\xaf\xef\x3c\x35\x55\x53\x3d\x8a\x6f\xf8\x89\x27\x1c\x1f\xc1\x8e\x38\x3e\x26\x7f\xd7\xed\x6b\xd9\xb1\x41\x7e\xe2\xf9\x13\xff\x94\x6d\x51\x36\x0d\xfe\xaa\xf3\xd7\xb2\xc5\xf1\x98\xfe\xfe\x1b\xee\xde\xcf\xea\xf5\xf4\x26\x3a\xd1\xcb\x6a\xf8\x35\x97\x97\xfb\x24\xf9\xf3\xe3\xad\x11\xad\x18\x6a\xd9\x42\x56\xa8\xea\xae\x1f\xd0\xd4\x6d\xf9\x47\x32\x49\x02\xc3\xe1\x22\x5e\xea\x1c\xed\xf5\xf2\x5c\x76\x07\x54\xb2\x43\x55\x37\x25\xea\xa2\x6c\x87\xba\xaa\x73\x45\x9c\x08\x00\x60\xe8\xcf\xf2\xda\x14\x10\xcd\xbb\xf8\xec\xf1\x5c\xe2\x3f\xf1\xfd\x41\x11\xb5\xf2\x3d\xf9\xa6\x37\x0d\xe7\x12\x87\xb3\xe8\x8a\xe7\x46\xb4\xaf\x07\x30\x86\xb7\xae\x6e\x87\x1e\xa2\x87\x80\xfa\xfa\x80\xe7\xeb\x80\x5c\xb4\xdf\x87\x89\x4d\x7f\xb9\xf6\xe7\xb2\x48\x7e\x6a\x0e\xe7\xb2\x7e\x39\x0f\x93\xc6\x02\xf9\x59\x74\x22\x1f\xca\x2e\x79\xda\x58\x7c\x40\x2b\x07\xd4\x6d\xde\x5c\x8b\xba\x7d\x41\x51\xf6\xf9\x04\x54\xd7\x5b\xb2\x8b\xf8\x50\x96\xa3\x29\xdb\x97\xe1\x8c\xbb\xf2\xc3\x6e\xce\xe5\xe5\x52\xb6\x1a\x98\xfe\x1e\xbf\x40\xa0\xba\x16\x2f\x25\x2a\x91\x0f\xb2\x4b\x8e\x4f\x8a\x43\x51\x56\xe2\xda\x0c\x5a\xd9\x8b\x2c\x4a\x65\xf8\x70\xae\x7b\x54\xb2\x1d\x70\xd7\xd4\xaf\x25\x0e\xec\x82\xe3\xd3\x01\xb2\x55\x7c\x45\x5b\x28\xbe\xf7\xc9\xf1\x51\x71\xd1\x48\x4f\xea\x7b\x62\x93\x04\xc0\xb7\xd3\x2d\xd7\x53\x22\x71\x4a\x46\xe8\x3b\x70\x4a\xb8\xb9\x03\x6a\x51\x2f\x8f\xea\x03\xd6\xaf\xa7\x04\xd3\x2e\x9c\x12\xc6\x19\x67\x58\x7f\x07\x1c\x99\x26\xd4\x2b\xd3\x27\xbd\x57\x29\xb3\xfc\xa6\xf7\xc9\xc8\x37\xa3\x2a\xa0\x75\x47\xaa\x97\x52\xcd\x20\xd5\xf2\x38\xa0\x89\x97\xf2\xf5\xab\x5a\x4c\x15\x14\x8c\x33\xcd\x3b\xb0\xd1\x62\x85\xe5\xbf\x12\xa4\xb4\x98\xb6\xd8\x27\x64\x9a\x58\x5f\x4e\x49\xa6\x1e\xa5\x86\xc3\x3c\xa5\xf0\xf7\x58\x05\xa5\xb5\x36\x1b\xd5\x16\xc6\x38\x63\x5a\xc7\xcc\x5b\x0f\x0c\xd1\xa8\x4b\x36\x3f\xc7\x9c\x15\x18\x40\x0c\xf3\xf7\x4b\x26\x37\x9d\x1e\xf0\xf1\x82\x67\xda\x23\x8d\x43\x34\xc0\xd6\x1d\xda\x5b\x56\x77\x7b\x9b\xf0\x60\xd2\xac\xa6\x5a\xa5\x54\xe1\x24\x53\xe3\x1e\xb3\x1e\xf1\xe1\x0f\xe3\xec\x71\xc6\xce\xc6\x87\x31\x83\xc5\x9d\xcf\x4c\xbc\x19\x28\x53\xaa\x23\x73\x34\x4e\x47\xa7\x82\xf6\x20\x7d\xa3\xea\x11\x0a\x98\x2c\x32\x7b\x18\x27\xf4\x24\x28\xa9\x0c\x66\x28\x80\x50\x62\x5c\x86\x42\x97\x46\x3b\x9b\x91\x34\x7a\xae\x20\x27\xd9\x6c\x65\x6a\xf3\x80\x22\xe7\xde\x43\xe4\x0c\xc7\x31\x90\x10\xbe\x6f\x12\x1a\xa7\x32\x1e\xd5\x60\xe1\x64\x17\x60\x7c\x91\x7d\xa4\x84\x05\x69\xea\x92\xdb\xd6\x01\x95\x98\x2e\xe9\xfd\x88\xa6\x81\x69\x1c\x11\x8b\x04\xea\x5e\xc2\x90\xcf\x82\x64\x24\x5d\x5c\x7c\x23\x0e\xba\xdd\xce\x43\xd3\x67\xf7\x9a\xdc\xe7\x5a\xa3\x6c\xae\x5e\x6c\x05\x33\x3e\xd3\x19\x67\x1b\x17\x19\x2d\xe2\xb1\x47\xfc\xc8\x83\x77\xbb\x1e\x11\x65\x72\x8c\x14\x5c\x04\x3a\x46\x73\x50\x81\xa2\x25\x64\x56\x12\xd7\xf7\x74\x8e\xff\x95\xd8\x25\x69\xc2\x9d\x9e\x1b\xc9\xbb\x41\xb1\x57\x92\xac\x92\x3a\x24\x76\x13\xcb\xcb\x7a\xae\x63\xdc\xd6\x80\x95\xac\x37\x4e\x0d\x8a\x97\x2b\x62\x7c\xa5\x88\x91\x2a\x32\x92\x7b\x86\x9d\xb2\x39\xeb\xa8\x33\x83\x1b\x0b\x33\xac\xeb\x38\xa3\xb0\xbc\x71\x1d\x5d\x11\x0a\x25\x24\x83\x6a\xae\x23\x38\x46\x1a\x4f\x6b\x7d\x99\x10\x1a\x82\xcc\x12\x66\x9b\x84\x61\x96\x2d\x24\x6d\xd4\xc2\xd5\xd0\xa7\x31\xf0\x25\x89\x5c\x4b\xe4\xd9\x6d\x12\xb9\xa4\xa9\xb0\x6b\xa3\x55\x8d\xda\xb4\x99\xa5\x7b\x41\xb6\x5a\x7d\x43\xdb\xc2\xfb\x56\x90\xc5\xdd\x90\xed\xd4\x7b\x0d\xb7\x23\x86\xc7\x80\x30\xf1\x18\x51\x66\x08\x9f\x63\xd2\x79\x50\x59\x77\xc2\x71\x41\xb8\x0b\x5c\xd8\x61\xed\xec\x6a\xea\x24\x59\xf7\x09\xf9\x5c\xab\xfc\x2b\x0f\x67\x32\x57\xbb\x32\xa7\x8a\x5a\xb3\x41\x17\x2b\xf3\xdc\x28\xef\x5f\xed\x77\xaf\x6b\x41\x8d\xa9\x99\xbf\x10\x9f\x07\x97\x35\x74\xd9\x52\x5d\x95\x38\x25\x3f\x36\x47\x6a\x2a\x41\xba\xa3\xc8\x34\xce\xc5\x11\x58\x54\xf6\xad\x91\xc9\xd3\x4e\xd2\xce\x40\x5b\x95\x47\x61\xbe\x9a\x80\x27\x25\x7d\x95\x62\x36\xc0\x08\x60\xdf\x63\x63\xb5\x66\x30\x4f\xef\x9c\x4c\xef\x72\x07\x65\xd7\xd3\x96\xe3\xa5\x5e\x5b\xa2\xe3\x51\x44\x0b\x3d\xc8\x3c\x35\x2e\xe7\x29\xb7\x39\x0c\x5d\xda\x88\x82\x8a\x4b\xf4\xf8\x42\xc3\x71\xf2\xe9\x31\x75\xa1\x07\xed\x90\x23\x4c\x9c\x40\xae\x9f\xf9\x28\x82\x5e\xb4\xac\xe0\xb1\xf0\xe4\x1c\x5b\x3b\xee\xa1\xcc\x63\x23\xc7\x7a\x28\x92\x30\xf3\xce\x0b\x71\x75\xb0\x32\x74\x2e\xb6\x1a\xbc\x63\x31\x08\x44\x4f\x90\xbb\x31\x18\x1e\x71\x56\x10\xf4\x9c\x75\x6b\x1f\x80\xfd\xf3\x1e\xe7\x2e\x40\x9a\x00\xe9\x01\x2b\x64\x3e\x1c\x86\x26\x5e\xdf\x76\x6d\x8c\xe4\x59\x04\xeb\x74\x0d\xeb\xb9\x62\xcc\xd3\x5d\xd8\x4f\x56\xc6\x65\x92\x09\x8b\x8c\x70\xb3\xb2\xe5\xc2\x03\x29\x9b\x20\x4f\x60\xfc\xab\x40\x49\x3d\x14\x57\xef\xea\x28\xa2\x7c\xf0\x85\x13\x86\xb2\x4c\x6a\xe0\xed\x8f\x21\x36\xd8\xe7\x0a\xe2\x8d\x13\xe4\xc1\x66\xb5\x9b\x0a\xc6\x79\x34\x9b\x8f\x44\xa9\x43\x90\xfa\x9f\x3c\xd9\xdf\xb6\x70\x5b\x73\x91\xb7\x26\xbf\x5f\x3d\x6e\xc9\x8b\x5b\x0f\x5c\xc1\x14\x7a\x4a\xfe\x0f\x00\x00\xff\xff\x68\xbd\xa6\xb5\xe0\x15\x00\x00")
+
+func fontsTinkerToyFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsTinkerToyFlf,
+ "fonts/tinker-toy.flf",
+ )
+}
+
+func fontsTinkerToyFlf() (*asset, error) {
+ bytes, err := fontsTinkerToyFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/tinker-toy.flf", size: 5600, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsTombstoneFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x56\x5f\x6f\xdb\xb6\x17\x7d\xe7\xa7\x38\x30\x84\x9f\x62\x80\x31\x1b\xff\xba\xa1\xc9\x93\xdc\x0e\x01\x8c\x0d\xdd\xd6\x64\x6f\x04\x68\xd9\xa6\x6c\xa1\xae\xe4\x49\x4a\x0b\x03\x04\x3f\xfb\xc0\x4b\xfd\xb5\x14\x60\xdb\xeb\x8a\x48\x0c\x75\xff\x1c\x1e\x9e\xcb\x2b\x39\x39\x25\xcb\x38\xc0\x0f\x78\x8b\x77\xb8\xbd\xc3\xdd\x92\xcd\xd2\x2c\xc9\xcf\xf9\xb7\x62\x91\x9c\x92\x19\x7b\x1f\x97\x7a\x8f\x3c\x43\x8c\xbb\x25\x4e\xba\xaa\x74\x81\x24\xcf\x2a\x3c\x16\xf9\x97\x07\xcc\x56\x59\xf9\x4d\x17\x25\xaa\x1c\x8f\x85\xfe\xf3\x45\x67\xd5\xe9\x82\x55\xf9\x59\xef\xf1\xfb\x8b\x2e\xab\x34\xcf\x4a\x06\xac\xb6\xf9\x4b\x85\xe7\x7c\x1f\x5f\xc2\x12\x1f\x8a\xcb\xb9\xca\x0f\x45\x7c\x3e\x5e\xf8\x0c\x5f\x97\x8b\x37\xd8\x17\x71\x52\x61\x99\x70\xdc\x8b\xe5\x1b\x71\xff\x7f\x8e\xed\x05\xbf\xc5\x2f\x27\x3c\xc6\xc7\x8c\x33\x60\x97\x9f\x2f\x45\x7a\x38\x56\xb8\xbb\x77\xfe\x4f\x4f\x2b\xfc\x12\x6f\xf3\x22\xae\xf2\x22\xd5\x25\x7b\x3a\xeb\x5d\x9a\xa4\xbb\xf8\x74\xba\x70\x54\x47\x8d\xd5\xd3\x87\xf5\xba\x26\x9e\x66\x07\x24\x45\xfe\x85\x1c\xb3\x9f\xd6\x4f\xcf\x9f\xd6\xef\xff\x78\x5e\xff\xfa\xf1\x61\x86\x52\xef\x1c\xd7\x07\x36\x53\x50\x1c\x0a\x4a\xf9\x89\xe2\xf0\x06\xff\xa4\x9a\x19\xc5\xe0\x3a\xc4\x47\x28\x8e\x19\x83\x81\x91\x6e\x50\x10\x90\x30\x6a\x0e\x18\x29\x0c\x3d\xc1\xb8\x8b\xec\x14\x83\x1b\x05\x0a\x21\x13\x7c\x1a\x0c\xe6\x04\x03\xe9\x06\x48\x08\x37\xaf\x93\x8d\x35\xf5\xac\xb6\xbb\x18\x8e\xb9\xb3\x79\x93\xf0\x69\x30\x56\x32\x58\x58\xf8\xc1\x4f\x3a\x83\xc5\xd5\xd5\x4e\x7b\x26\xeb\xcd\x8c\xad\xf6\xfb\xd4\x29\x15\x9f\xb0\x3b\xc6\x45\xbc\xab\x5c\xfd\xff\x87\x24\x3d\x9c\x74\x85\x5d\x9e\x7d\xd5\x45\x99\xe6\x19\xb6\x97\x07\x06\xe0\x67\x9d\x55\xf8\x18\x97\xa5\xce\x38\x3e\xeb\xac\xca\xa2\xdd\x65\xab\x8b\xf2\x1c\xef\xf4\x22\x2f\x0e\x1c\xef\xc4\xdd\x8f\xe2\xfe\x2d\x0b\x82\xe8\xfa\x8e\x18\x78\xc4\x60\xea\x7b\x11\x31\x78\xa3\xb3\x86\x61\xc4\x80\xa0\x37\x44\xac\xfd\xfb\x1b\x53\x82\x0e\x09\xb2\xb9\x23\x06\xd1\x5b\x4f\x36\x46\xd9\x33\x8a\xda\xf8\x0a\x68\x03\xd6\x81\x0f\x58\x5a\x3b\xe0\x1b\xd0\xc5\x23\x66\xdd\xa4\x75\xb9\x35\x04\x06\x91\x50\x41\xc4\x84\x63\x22\xc9\x6d\xd1\x7a\xfa\x12\xd9\x76\x49\xc5\x29\x6a\x4e\x78\xa0\xa5\x69\xed\x81\x5b\x91\x9b\x82\xac\x47\xac\xdd\x04\x2a\x3c\xa4\x35\x64\x19\x65\x1b\x85\x57\xb2\xc9\x2d\xc8\x2d\x3d\x83\xbe\x5b\x91\x5b\x11\x29\x51\x3b\x46\xd9\x37\x44\xed\x66\x9c\xdd\xb8\x45\xbb\x31\x84\x3d\x77\x50\x9f\x93\x45\xbf\xa8\x8d\x71\x58\x94\x56\x65\x49\xf9\xb2\x15\xb4\xab\xd4\x55\xb9\xfa\x91\xfd\x1a\x11\xad\xa0\xe3\xeb\xed\x8b\xa0\xa5\x15\x10\xeb\x40\xf0\x79\xc4\x02\xb9\x09\x9d\xc5\x61\x07\x43\xc5\xfc\x41\x23\xbd\x6d\x5f\x6f\x55\xeb\x3d\x6f\x47\x3b\x56\x4c\x60\x43\x0c\xf9\xb4\xde\xc6\x83\x2b\x71\x9d\xad\x7a\xc5\x34\x18\x9d\x94\x09\xf7\xd4\xda\x8a\xd6\x16\xa3\xb5\xb9\xa2\x6c\x3a\x9f\xb8\xde\x58\xa0\x22\x16\x98\xfa\xb6\x4d\xcb\x43\xb9\x1c\x4e\xd1\x37\x34\x62\x40\xa8\x86\x14\xed\xa6\x86\x5a\xf1\x8e\xa9\x21\x31\x86\xdb\xe1\x44\xd5\xbd\x8b\x7d\x98\xe7\x54\x23\x5c\xc5\xf8\xb6\x82\x9c\x88\xe9\x57\x6c\x6a\xdf\xfd\x8a\xbd\xae\x1a\x65\x4b\x9f\xbd\x79\x2d\x7b\xb4\xc5\xa6\x05\x40\x32\x4d\xf4\x97\x63\x0f\x83\x6e\x9c\x28\x09\xba\x92\x6c\x6c\x38\x76\x93\xbc\x62\xc4\xdc\x7d\xe7\x3a\xe1\xdc\x57\x66\x42\x3f\xff\xfa\x08\xa5\xef\x03\x21\x31\x8e\xe1\xf5\x89\xa1\xf2\x4a\xd3\xbe\x48\x60\xc3\x7a\x0f\x0e\x62\x53\xb7\x92\x68\xce\x25\x7a\x10\x8b\x5b\x22\xd2\x0c\x9b\xdb\xae\x19\x7d\xcb\xfa\x6e\xf5\xed\xda\xdf\xc3\xed\x82\x94\x69\x86\xdb\xb0\x4d\x14\xf2\xfa\x9b\xd2\x41\xfa\x87\xc1\x3f\xdb\x1c\xad\x3a\x86\x70\x37\x53\xd9\xf5\x1b\x51\x4e\xb6\xc1\x7f\xaf\xbf\xb9\x6f\x70\xf8\x0e\xf7\x47\x74\x50\xdb\xef\x4d\xfe\xbd\xc9\xaf\x7e\x65\x51\x77\x99\xde\xfd\x4f\x7f\xf0\xfd\xcb\xe9\x5f\x01\x00\x00\xff\xff\xd7\x8b\x21\xb8\x29\x0d\x00\x00")
+
+func fontsTombstoneFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsTombstoneFlf,
+ "fonts/tombstone.flf",
+ )
+}
+
+func fontsTombstoneFlf() (*asset, error) {
+ bytes, err := fontsTombstoneFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/tombstone.flf", size: 3369, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsTrekFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x59\xeb\x6b\x1b\x47\x10\xff\x7e\x7f\xc5\x34\x2c\xdc\x17\x67\x95\xf4\x91\xda\x02\x97\xf3\x06\x42\xc1\x0e\x5d\x70\x9b\x2f\x21\x48\x3a\xef\xc5\x32\xc8\x92\xb1\x24\x48\x20\x7f\x7c\xd9\x9d\x9d\xd9\xd9\xbb\xd3\xc3\x56\x9c\x26\x50\xd5\x54\x73\x8f\x79\xbf\x7e\xab\x7c\x9c\x7d\xfc\x79\xa2\xe0\x15\xfc\x06\x2f\x5f\xc1\x0b\xf8\xe5\x45\x31\x18\x3c\x7f\xfc\x67\x30\x28\x06\x03\x78\xfc\x87\xf9\xb5\x33\xc6\x18\x0b\xe1\x2b\x11\x35\x80\xa0\xb6\xf0\x1b\xdb\xf7\xd8\x98\x48\xb8\xfe\xe7\x89\x7f\x9c\xb4\xd9\xc4\x12\xf8\x83\xfe\xf3\x1d\xf6\x13\x67\xc6\x1e\xf8\x99\xd8\xc2\x8f\xce\x97\x19\x3b\x7e\x48\x6a\xb9\x5b\xff\x63\x3e\xbd\xfc\x1b\x72\x10\xbd\xcb\x42\xb9\x5b\xbf\x7c\xdd\x19\xab\xf3\x4c\x6c\xd0\x6f\x93\x1d\xe7\x48\x58\x10\x51\xda\xce\x9f\xd8\x65\x06\x44\x42\xb7\xf3\x67\xec\x3e\xf0\x5c\x99\xb6\x9b\x87\x27\x89\x3f\x3c\x3f\x7d\x0f\x7f\x4f\x1b\x78\x73\x73\x3d\x6b\x56\xf0\x66\x31\x5f\xc1\x87\xd3\xe7\x7b\xf3\x3f\x58\xff\x7b\x78\xd7\xdc\x2f\x6f\x16\x73\x78\xa9\x5f\xc0\x87\x43\xed\x7f\x30\xff\xcb\x93\x93\x5f\x8f\xa0\xfe\x0c\xb6\x59\x35\xf7\x70\xa1\xc1\xac\x97\x57\xd3\xdb\xc9\xfc\xdb\xe8\xb7\xb3\x66\xb2\x6c\x60\xd9\xcc\x1d\x4c\x66\x33\xb8\x5a\xdc\xde\x36\xf3\xd5\x12\x56\x0b\x58\x4d\x1b\x98\xac\x57\xd3\xc5\x3d\x4c\x56\xc3\xa7\xd1\xff\x34\xfc\x27\xbf\xd7\x31\x8a\x77\xd5\x64\x76\x3b\xd1\x8d\x5b\x3f\x84\xff\x6e\x86\xfc\xd5\xfc\xf3\x27\x7d\xb5\xd4\x6e\xdd\x91\xf0\x95\xec\xff\xeb\xec\x12\xce\xce\x2e\xe1\xe2\xe2\xf2\xa7\x87\xf3\x1f\xb6\xbf\xfe\x6c\x6e\xae\xa7\xab\x23\xf8\xe7\x6e\xe4\xbf\xde\x4e\x3e\xcd\x9a\xf9\xf5\x6a\x7a\x04\x97\xb7\xeb\xe5\xf4\xed\xc2\x35\x47\xf0\x1a\x0b\xe2\xf5\x62\x3d\x5f\x15\x45\x50\xad\x94\xaa\x8a\x48\x40\xa0\x3c\x11\xa8\x40\x78\x0a\x09\xa8\x8a\x48\x40\x55\x45\x66\x67\x6c\xe4\xf6\x73\x05\xd9\xc3\xc4\x09\xfc\x38\x83\xbc\x80\xe8\x67\x55\x28\x9a\x4b\x24\x02\x9f\x3b\x0b\xce\xfa\xa7\xfe\x1b\xe4\xa3\x36\x51\x15\x28\xcc\x1d\x1f\x07\x35\xca\x53\xf8\x09\x02\x8e\x4d\xa0\x83\x35\x8a\x5e\x93\x12\xe4\xd5\x08\x92\x2d\x4a\x9f\x9e\x9e\xea\x40\x0d\xe1\x4b\xf4\x60\xcc\xf7\x00\xbe\xc0\x90\xef\x95\xf1\xde\x33\x64\xf6\x76\x07\x07\x82\xa7\xe8\x81\x0a\x04\x52\xce\x26\x3f\xf1\x3d\x10\x9a\xb5\x31\x75\x89\x0a\x8d\xd6\x64\xde\x1f\x18\xa8\xaa\x00\x6d\xc8\x68\xad\xc7\x26\xcc\x6e\xe1\x4d\x8c\x08\x86\xb6\x2a\x14\xe5\x21\xff\x7f\xcc\x92\x57\xa5\x45\x9a\x64\x9e\xd0\x40\x4a\x4f\xca\x94\xa7\xc7\x84\x5c\x44\xe6\x8d\x8e\x42\xc3\x92\x41\xa1\xb8\x6f\x62\x70\xa8\x10\x88\x8c\x82\x70\xf9\x50\x22\xb5\xc6\x44\xe9\xe1\x30\x54\x00\xae\xc9\x61\xa0\x86\xce\x98\x1a\xef\xd9\xe1\xb0\xa4\xd4\x93\x15\x8a\xfc\x53\x5c\x47\xa4\x5f\xe1\xce\x0f\x02\x93\xa3\x39\x73\xe4\x8c\x49\x8b\xc2\x7d\x8d\x63\x1c\x43\x20\xa9\x21\xb0\x49\x14\x51\x8a\x28\xa1\x87\xef\xe5\x7a\x62\x53\xa0\x32\xd4\x45\xa9\xca\xdb\x40\x8d\x46\x14\xdb\x11\xc7\x73\xc4\x31\x1c\x71\x92\x64\x62\x00\x5a\xda\xd0\x20\x4b\x29\x2e\x35\xa5\xc3\x99\xa1\x26\x59\xf1\x3e\x70\xa0\x6c\xa7\x43\xb0\xaa\x03\x6c\x12\x1e\x15\xa2\xbd\xb9\x80\x44\xf9\xb4\x99\x7d\xf6\xa8\xf9\x23\x33\xda\xe3\x79\x46\x23\xa1\xbf\x15\xb6\xc4\x9d\xb1\x23\x80\xa3\x36\x13\x99\xb6\xed\x96\x88\x86\x3a\x7e\xbb\x55\x18\xf4\xbe\x28\x8e\x8e\x1b\xad\xa0\xa6\x1a\xcf\x1d\x62\x71\x4a\x0a\x4c\x4f\x3a\xb3\x87\x92\x43\x22\xc3\x54\x10\x83\x10\xc5\xc5\x59\x81\xc2\xde\xf5\x89\xaa\x48\xcb\x63\x73\x44\x66\xd4\xd1\x22\x1e\x4e\xca\x59\xc3\x99\xb2\x34\xc8\x14\x90\x19\xdd\x18\xc9\x84\x39\xcb\x13\x21\x18\x6e\x6c\x8a\x0e\xcd\xec\x8d\x82\x80\xb6\x50\x72\x85\x98\xc9\x0d\x62\xe2\x5d\x90\x7d\x63\xf7\xf2\x35\xa7\xdd\xa6\x66\x0b\xf7\x2d\xc5\xd8\x87\xb7\x8e\xfe\x71\x24\xab\x4e\x44\x53\xe1\xa5\xfc\x66\x65\xd7\x89\xad\x90\x3c\x0e\x39\xca\xb5\xb6\x72\x88\x2f\x53\xe7\x3b\x93\xad\x41\xd5\x1a\x62\x55\x56\x8a\xa2\x12\xb1\xe3\xfc\xdb\x23\x2f\x84\x38\x9f\x79\xcc\x1f\xeb\xc8\x84\x11\xdc\xdf\xed\x5c\x4b\x0a\x8f\x9d\x5c\x4d\x48\x2b\x3a\x8c\x70\x7d\xc7\x77\x36\x16\x03\x75\x2a\x9b\x78\x5e\xd2\x08\x02\x57\x8b\x09\x54\x6e\xee\xbc\xac\xef\xb6\x2e\xac\x2d\x55\xd5\x32\x09\xe3\xc1\x53\xa2\x64\x59\xe1\x6c\xc4\xee\x95\x7d\x73\x91\xed\x82\xde\x2c\x74\x4c\xdb\x31\x66\xdb\x53\xbb\x53\x76\xbd\xe2\x6c\xa7\xea\xb6\x38\x9b\xd5\x08\x8b\x2b\x21\x5e\x50\x2e\x37\x8b\xb3\x5c\x98\x00\xdd\xa2\x13\xc3\x26\x1b\x38\x3d\x13\x35\x13\xda\xda\xe2\xfb\x4f\x2d\x48\x45\x95\xd9\x03\x20\x50\x87\x33\xa5\xdb\x63\xcb\xe1\x5a\x11\x0e\x86\xe3\xfd\xb1\x15\x0e\xc6\xe2\x54\xe9\xe8\xcd\x0e\x96\x87\x3a\xd8\xb7\xfd\x20\x6f\x67\x94\x51\xa6\xa2\x8d\xbe\x95\xb1\x6e\xe5\x65\xf2\x1c\x2f\x5b\xb6\x6d\xeb\x07\x2b\xb7\x66\x9e\xd0\x2c\x9f\x3b\x0b\x38\x87\x1d\xe5\x43\x61\x07\x4f\x22\xde\xfe\xa9\x57\x43\x2e\x36\xe3\xd4\x03\xec\x92\x9d\x50\xf6\x77\x42\x8f\x5d\x69\xae\x99\xf3\xb2\x33\x20\xe3\x2f\x2f\x1d\xbb\x74\xb2\xca\xa4\xd3\xc9\x38\x5b\xe5\x98\x83\xbe\xd9\x58\xd1\x02\x65\xcf\x44\x07\xec\xc6\xf2\xbd\x85\x0a\x6e\x03\xba\xb1\xb2\x9f\xec\x68\x4f\x74\x13\xf8\xe4\x31\xc7\x33\x40\x0c\xbe\x31\x14\xf9\xce\xb8\x16\x16\xe1\x5f\x6e\x53\xb2\x0a\xff\xd8\x2e\xba\x94\x7b\xa9\xc7\x36\x8c\x9d\xdf\xc5\xde\x96\xb8\xcd\x45\x49\x98\xf3\x34\x1a\x49\x58\x99\xaf\x62\xda\xd8\x22\x62\x2e\x09\xd8\x67\x7e\x65\x60\xb2\x95\xb7\xfd\x67\x43\x0d\x4a\x64\x8f\x41\x53\xbc\x10\x22\x95\x2c\x86\x04\xa3\x8c\xb1\xf9\x51\xde\xdf\x1f\xe3\x21\xaf\x2a\x00\x29\xac\xca\x3a\x3a\x30\x36\xb5\x6a\x01\x90\xb8\xf0\xc8\x14\x1f\x13\x86\x6f\x81\x66\xd8\x6e\xc9\x0e\xa2\x23\xaa\x15\x56\x28\x87\x20\xc9\xd9\x31\x8d\x3d\x81\xf5\xda\xdf\xa4\x5f\xfc\x7c\x81\xd4\x3e\xa7\xb5\xaa\xe0\x40\xd4\xa1\x22\x02\x64\xa4\x4e\xad\x0a\x68\x61\x22\x76\xdb\x18\x81\x88\x44\xbf\x8b\xba\xab\x5a\xe7\x90\x1f\x04\x0d\xed\x9a\xfe\x7d\xd2\xfe\x47\x43\x5b\x0e\x83\x3f\x2a\x1a\x6a\x39\xe8\x8e\xf1\x1f\x3b\x04\x1a\x82\x8d\x68\xe8\x60\x07\xfb\x27\x5e\x0e\x86\x54\xe6\xb1\x18\xff\xad\x65\x80\x56\x89\xd5\x00\xfd\x76\x3d\x21\x0e\xb2\x62\xb9\x58\x81\x37\xec\x7f\x8c\x83\xb6\xd8\x75\x38\x0e\x82\x6f\x87\x83\xb8\x32\xbe\x53\x1c\xd4\x01\x42\x02\x09\x09\x28\x24\xb0\x50\xdb\xc1\xa7\x46\x43\x02\x0c\x09\x2c\xc4\x50\x88\x91\x50\x17\x08\xb5\x71\x50\x7a\xcc\x3f\xd2\x70\x9f\x7c\x75\x1c\x24\xfe\xfb\x1e\x2e\xfe\x0d\x00\x00\xff\xff\xe4\x59\x27\x82\x90\x20\x00\x00")
+
+func fontsTrekFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsTrekFlf,
+ "fonts/trek.flf",
+ )
+}
+
+func fontsTrekFlf() (*asset, error) {
+ bytes, err := fontsTrekFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/trek.flf", size: 8336, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsTsalagiFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x59\xdb\x72\xdb\x46\xd2\xbe\xe7\x53\x7c\x09\x9d\x40\x8a\x1b\x1c\x49\x8e\xe3\x43\xb9\xf4\xcb\x71\xe2\x24\xce\xc9\x89\x95\xa3\xe1\x0c\x21\x69\x28\x22\x22\x09\x9a\x04\xa8\xd0\x99\xf0\xe9\xfe\x67\xd8\xab\xad\xda\x9b\x7d\x86\xbd\xda\x8b\xad\xc6\xcc\xe0\x4c\x49\x74\x71\x97\xa5\xd2\xd7\x02\x07\xdf\x74\xf7\xf4\x69\xec\xc1\x68\x70\x10\xde\xc2\x5d\xdc\xc5\xfe\x1e\xfc\x7d\xdc\xbd\xd3\x39\x59\xe2\x99\x9a\xcd\xc2\x33\x3c\x8f\xd4\xec\x54\xe1\xe5\x30\x49\xa6\x0f\x85\xb8\xbc\xbc\xec\x4d\x93\xe1\xc9\x49\x2f\x9e\x9d\x8b\x79\x3c\x48\x2e\xc3\x99\x12\x83\xe8\x7c\xa4\x12\x91\xcc\xc3\x51\x78\x1e\xf5\x86\xc9\x78\xf4\xaa\x03\x60\x7f\x5f\x3c\xb8\x47\x38\x10\x7b\x07\x84\xfb\x62\xef\xa0\xf3\x5c\xcd\xc6\xd1\x7c\x1e\xc5\x13\x24\x31\xc6\xf1\x59\x34\x58\xe2\x7c\x16\x4e\x12\x75\x46\x38\x49\x13\x4c\x47\x2a\x9c\x2b\xcc\xd5\xe4\x0c\x63\x85\x10\xa7\xf1\x74\x89\x78\x86\x49\x9c\xf0\xe2\xb1\xea\x75\x1e\x8f\xe6\x31\xc2\x45\x18\x8d\xc2\x93\x91\x7a\x88\x13\x35\x4f\x30\x88\x12\x31\x0e\x93\xd3\x21\xe2\x01\x4e\x87\xe1\x2c\x3c\x4d\xd4\x6c\x4e\x08\x47\xa3\xf8\x12\xd3\x74\x72\x9a\xa4\x61\xc2\x5b\x8f\xa2\x0b\x85\x1e\xde\x85\x87\xff\x63\x3d\xed\x47\xbe\xdd\xa7\x60\xd8\xc1\xdb\x7d\x76\xaf\xa3\x90\x92\x7f\x41\x66\xbf\xa4\xfd\x7b\x23\x0a\x01\xe9\x49\x68\x68\xf0\x4f\xc0\x0f\x36\xa4\xd0\x0e\x0c\x05\x82\x26\xc3\x4d\x28\x8e\x78\x77\xbb\x7f\x0b\xc3\xb5\x86\x04\x52\x8a\x6c\xf7\x6c\xff\xa3\xb6\x25\xd7\xba\xf3\xfa\xcf\x15\x14\x2f\x96\xa3\x51\x78\x32\x5b\xe2\x49\x3c\x59\xa8\x59\x16\xcb\xc7\x1c\x87\xff\x0b\x2d\x42\x42\x08\x40\x11\xfa\xfc\x67\x44\x58\x31\xc6\x84\xd7\x8c\x29\xe1\x3b\xc6\x05\xe1\xf1\x1a\x0a\x3f\xfb\xdc\xf6\xab\x58\x7f\x60\xc1\x50\xe0\x78\xa8\x66\x0a\xd1\xbc\xce\x75\x1e\x12\xe6\x9b\x59\x84\xd9\x70\xc9\x69\x3d\x39\xab\x93\x5d\x84\x84\x09\x93\x2a\xc2\x3e\x63\x44\x78\x87\x31\x26\x5c\x32\xa6\x84\x9f\x18\x17\x84\x17\x8e\x4c\x85\xf3\x78\xb2\x05\x13\xeb\x14\xc3\x90\x70\xc6\xa8\x08\x07\x8c\x11\x65\xb1\x36\x8c\x09\x7c\xd0\xc3\x94\xf0\x29\xe3\x82\xf0\x89\x55\x26\x44\x1f\x2b\xbc\xc6\x77\x78\xbc\x0d\xa7\x37\xbc\x3d\x0a\x09\x03\x46\x45\xb8\xc3\x18\x11\xba\x8c\x31\x61\xc6\x98\x12\xbe\x67\x5c\x10\x9e\x5a\x92\x09\xf6\xf1\x0e\x2e\xf1\x13\x5e\x6c\x43\xa7\x33\x1c\xe0\x08\x0a\x9f\xe2\x93\x3a\xdd\x38\x24\x9c\x33\x2a\xc2\x87\x8c\x11\xe1\x16\x63\x4c\x48\x18\x53\xc2\x71\x2d\x16\x06\xb8\x83\x2e\x66\xf8\x1e\x4f\xb7\xa1\xdd\x39\x3e\xc4\x2d\x24\x38\xae\x93\x4d\x42\xc2\xf0\x06\xd1\x59\xd6\x6d\xd8\x08\x09\x66\x19\x6f\x46\x32\x6e\x6a\x32\x24\xfc\x0c\x4c\x14\xe1\x2e\xff\x1d\x11\xde\x63\x8c\x09\x4b\xc6\x94\xf0\x0b\xe3\x82\xf0\x99\x25\xf9\x19\x77\xf1\x1e\x96\xf8\x05\x9f\x6d\xc3\x4b\xbf\xe3\x23\xfc\x86\x14\x3f\xe0\xf3\x3a\xdd\xeb\x34\x24\xfc\xce\xa8\x08\x1f\x31\x46\x84\xdf\x18\x63\x42\xca\x98\x12\x7e\x60\x5c\x10\x3e\x37\x74\x17\xdb\xd0\xe9\x09\xee\xe1\x7d\x44\xf8\x02\xcf\xea\x74\xf3\x90\x70\xb1\x89\xd7\xb1\x8b\x11\xee\xe3\x03\xc4\xf8\x16\x5f\x36\xe8\x08\x4f\x32\x54\x84\x7b\x8c\x11\xe1\x7d\xc6\x98\x10\x31\xa6\x84\x2f\x18\x17\x84\x67\x96\x4e\xe0\x01\x76\xb6\x61\xe6\x8f\x75\x92\xb3\x90\x30\x62\x54\x84\xfb\x8c\x11\xe1\x03\xc6\x98\x10\x33\xa6\x84\x6f\x19\x17\x84\x2f\x2d\xc9\xaf\xd8\xc3\x2e\xa6\x78\x8e\xaf\xea\x74\x49\x48\x59\x4f\x4d\x14\xe1\x01\x63\x44\xd7\xf4\x9e\x5d\x7c\x8c\x47\x90\x78\x89\x3f\xf1\xcd\x36\x4c\x5c\xe0\x10\xb7\xf1\x0a\x7f\xe1\xeb\x86\xb1\x5c\xc0\x7e\xdc\xec\x24\x4f\x10\x40\xe3\x0d\xfe\xc0\x69\xc3\x58\xa6\xfb\x95\x51\x11\xf6\x18\x23\xc2\x2e\x63\x4c\x98\x32\xa6\x84\xe7\x8c\x0b\xc2\x57\xd8\x52\x2f\x6c\x68\xc1\xf1\xf9\x31\xa3\x22\x3c\x62\x8c\x88\xe7\xb4\x84\x03\xea\x25\x63\x4a\xf8\x93\x71\x41\xf8\xe6\xbf\xa5\xc5\x65\x48\x58\x30\x2a\xc2\x21\x63\x44\xb8\xcd\x18\x13\x5e\x31\xa6\x84\xbf\x18\x17\x84\xaf\xdb\x29\xb6\xa0\xc5\x32\x24\x9c\x30\x2a\xe2\x09\x0f\xcb\x88\xb2\x91\x6f\x19\x13\xde\x30\xa6\x84\x3f\x18\x17\x84\xd3\x76\x8a\xcd\x3f\x65\x8a\xb7\x1c\xe0\x77\x3b\x19\xc7\xf1\x30\x9a\x23\x9d\xab\x39\x92\xa1\xc2\x38\x9c\x4e\xa3\xc9\x39\x5f\x26\x9e\xc5\xe1\x04\xc7\x71\xfa\x46\x25\xde\x1c\x4f\x67\x4a\xf1\xad\x07\x4f\x86\x6a\x16\x5f\x28\x85\x41\x3c\x49\xb0\xd8\xef\xed\x1d\x74\x72\x65\xf8\xd9\x43\xee\x1a\xc5\xc5\x29\x4c\x96\xd3\xe8\x34\x1c\xf5\x26\x2a\x11\xc2\xbd\x9d\xdd\x96\xf2\xd7\x2e\xd4\x72\x1c\x4e\x1f\x5e\xfd\x1a\x4f\x9b\xe6\xb5\xce\xad\x5b\xd9\x6b\xdd\x9b\x08\xdd\x8e\xbd\x3a\x74\x3b\x76\x00\xef\x76\xec\x18\xcf\x82\x30\xab\xed\x48\xdd\xe5\x47\xd9\xac\xcf\x42\x1f\x9e\x11\x2c\x65\x43\x60\x29\xbb\x94\x74\x3b\xf6\x7e\x90\x09\x7d\xcf\x3d\xc9\xbe\x92\x5a\x3a\x4d\xf8\x26\xc3\x8f\xec\x65\xa2\xdb\xd1\x52\xea\xda\x13\x2b\xb0\xde\x12\xa8\x30\x41\xd7\x77\xe3\xb7\xb5\x5c\xbb\x3a\x7f\x12\x38\x4d\x44\xc3\x4a\x6e\x75\x37\xb0\x52\x5a\x26\xed\xbe\x73\x82\x30\xc2\x91\xc8\xf6\xb3\xab\x29\xfb\x4e\xc0\x78\x50\x3b\xca\x5c\xb0\x17\x9a\x0a\x37\x6e\xc6\x6d\x09\x84\xb5\x49\xaf\xac\x25\x1a\x5a\x6a\xcb\x9d\x5b\xb9\xce\xa6\xc2\x4b\xa2\x64\x65\x63\x91\x49\xfa\x35\x3e\x59\xcb\x2d\x02\x2b\xd8\xcb\x62\x79\xb5\xce\x5c\xa8\x2b\x42\x16\x97\xac\xb7\xe0\x9f\x35\x67\x59\x17\xa4\x09\x1d\xe6\xce\xd2\xb9\xee\x41\x91\x56\x9e\x48\x5e\x9f\xaf\xe6\x47\x7d\xc6\x00\x26\x16\xa0\x8d\xe0\xfb\x5e\xb6\x3a\x0b\x1d\xab\xb7\x30\x8b\x78\xb7\xa3\xcc\xf1\xb5\x88\x45\x20\x35\x5a\x4e\x47\xdb\x03\x0f\x9c\x20\xb4\x3b\x1d\x5d\xf3\xa0\x08\x72\xe3\x82\xdc\x4a\xde\xf6\x48\xf3\xc6\xb2\xe6\x6f\x17\x30\x02\xd6\x00\x18\x03\x76\x4c\x80\x57\x56\x67\x21\xc4\x87\x22\xb5\x8d\x4a\x68\x9b\xd7\x25\x2b\x5d\x5e\xb9\x88\x45\x20\xf3\xdd\x8c\x6e\x7d\x99\x47\x95\xf3\xa0\x49\x06\x4b\x29\x9d\xe0\x54\x62\x3b\xbb\x2d\xc1\x70\x65\x9c\x5c\xb1\xba\x2d\x62\xa5\x94\x79\x54\xb9\x23\x64\xb7\x18\xc1\xd6\x3a\x7d\x45\x36\x64\x01\x5e\x11\x2a\x11\x2b\x02\x7b\x3a\x7d\xcd\xfb\x16\xa1\x2b\xc0\x02\x02\x2d\x8d\x95\x10\xab\x55\x80\xf2\x59\x00\x58\xad\xaa\xa7\x6b\xab\xae\x39\xc2\xbc\xfe\xda\xd7\x5c\xf2\xba\xc2\x74\x24\x70\x24\x6a\x51\xf5\x48\x1e\xd6\x0d\x70\x27\xd0\x7a\x96\xd2\x93\xf5\xea\x73\x54\xaf\x3e\xcd\x60\xe2\xd7\xd9\xdc\x40\x1b\x81\xd3\xd2\x5a\x59\xf2\xa0\x08\x2a\xea\x9a\x74\x96\x19\x77\xe0\x49\x51\x8e\x13\x54\x4e\x67\xbd\xde\xf6\x51\xdf\x25\x98\x2f\x1b\x05\x51\x96\x6a\x6c\x1e\xb1\x41\x5e\x5a\xf5\xbb\x4e\xa8\x5a\xe9\xea\x89\x09\x6f\x0e\x2f\x59\x04\x93\xb4\x4f\x38\x3d\x0a\x2b\x4d\x41\xd9\xe1\x7b\x80\x97\x9d\x6f\x50\x38\x31\xcf\x7b\x81\xbc\x55\xe5\x0d\xc2\x65\xb0\xd9\xbc\xdc\x7c\x38\x27\xf2\x0d\xa4\x0d\x0d\x4b\x5f\xb0\x3b\xf2\x32\x77\xbd\x3a\x14\xdc\xe6\xb5\x9e\x6d\x8c\xd5\x12\xe4\x59\x4a\x97\x24\x9e\x7b\xbf\xd2\x7c\x72\x37\xae\x56\x8d\x56\xb5\x5a\xbf\x5a\xb7\x97\x09\x2d\xcb\xcd\xc7\xf8\x84\x8d\x0c\x8c\x07\x02\x78\xe5\xc6\x56\x4e\x89\x46\x63\x63\x47\xef\x16\x1e\x6f\x34\xb6\xcc\x83\x3a\xb0\x65\xd5\x04\xa0\xf5\x89\xce\x7c\xc2\x42\xb5\x74\x6a\xdf\x77\x1e\x6c\xf4\x15\xdf\x2f\x4a\xe7\x9a\x71\x49\xba\x71\xa9\xda\xd8\xac\x95\xe8\x67\x56\xea\xec\x81\xed\x70\x9e\x29\x13\x32\x4f\xa0\x52\x2d\x08\xa4\x75\xa5\x40\x60\x2a\x9f\xb6\xe9\xc6\x86\xba\xe4\xb4\x8d\x2d\x9f\x56\xac\xd0\xcb\x9f\x04\xa5\xd3\x59\x3f\x76\xf8\xb7\x7d\x7b\x96\xba\xe1\x6f\xd7\x22\x9d\xd0\xf7\x5b\xd2\x2d\xf7\x97\x77\x6d\x43\x66\xa5\x5d\x36\xd8\x39\x53\xd7\x3b\x1c\x33\xcb\x40\xae\x19\x21\xfd\x47\xd5\x27\x87\x5a\x4a\xaf\xd0\x44\xda\xc6\xd6\x67\xc7\x65\xe5\xdd\x0e\x12\xb0\x65\x59\xba\xb2\x5c\xa4\x79\xe0\x0a\x96\x08\xbc\xea\x6e\x79\x0c\x5e\x39\x76\x08\xed\xd9\x2c\xd6\xb5\xe6\x73\x45\xce\xbb\xaf\x6a\x56\x56\x7b\x7c\x26\x88\xd2\xfb\x95\xb2\xdc\xcf\x1b\xaa\x8b\xaa\x4c\x73\x33\x76\x48\xd1\xa8\x10\x87\x0d\x0f\x3a\x7f\x17\xc5\x50\x56\x8b\xf0\xce\xa1\x2e\x0a\x75\xbd\x69\x36\x56\x73\x52\xad\x1b\x24\xa4\x3b\x9d\xbc\x21\xe7\x82\xfd\xe7\xff\xac\xb2\x05\x2d\xa3\xaf\xf4\x65\xb7\xd3\x0f\x4a\x71\xa2\x1b\x15\xa2\x5e\xf2\xd9\x70\x8d\x75\x25\xbf\xae\x77\x4f\xef\xec\x66\xe6\xee\x6a\xaf\xde\x7c\xca\x83\x84\xae\x9b\x6b\x93\x48\xea\x52\x7c\xdb\xea\xe3\xf6\xd5\xbe\xef\x57\xaa\x4f\x29\x2f\xdb\x3c\x58\x12\x7a\xe6\x98\x39\xc0\xbb\xdd\x8e\xaf\xfd\xf5\x31\x98\x4f\x0d\xa5\x81\x53\xba\xa6\x89\xea\xfc\xa1\x77\x5d\xf5\xca\xab\xa6\xd1\x5b\x3a\x4a\x6d\x4a\x9c\x11\xf2\xd3\x31\x0e\x6f\xbd\x98\xec\x68\x53\x0f\x4a\xd7\xa0\xbe\xf4\xd0\x72\x96\x99\x73\xcc\xff\xd8\x64\xb9\x67\x07\x09\xae\x91\xb6\xb2\xd5\x07\x4e\x0d\x72\x27\xe0\xe5\xd5\x7e\xed\x90\x22\x65\x50\x54\xc6\x7a\x4f\x93\x05\x77\x90\x3b\xa7\x56\x3e\x5b\xae\x48\x04\xe8\x15\x99\x91\xdb\xdd\x64\xab\xf5\xbf\x5d\x6f\x5b\xff\x2b\x5d\x4a\xf7\xd7\x5e\x91\x84\xd5\x44\x98\x79\xcf\x38\x49\xd6\xb8\xbd\x55\xbd\x7e\x4b\x37\x72\x94\x2f\x3d\xf6\xbb\xfa\x5d\xde\x8d\xce\x42\x16\xd5\xbe\x34\x70\x9a\x9c\x15\x45\xad\xd3\xa8\x55\xb6\x96\x2b\xa9\x1b\xc5\x44\x31\xfc\xe4\x27\xdf\xd2\xa5\x84\x2d\x5a\x22\x1f\x21\x77\x3c\xb1\xb6\xcf\x3b\x4a\x2b\x1c\xe5\x73\x55\x7e\xb5\x2b\xaa\x5e\xcb\x2d\xb9\xe8\x52\x2d\xfe\xae\x09\xff\x8f\x72\xe7\xbe\x6e\xf5\xdf\x36\x5a\xfd\xf7\x8d\x56\xff\x73\xa3\xd5\xff\xda\x68\xf5\xbf\x37\x5a\xfd\x8f\x7c\xf5\x7f\x02\x00\x00\xff\xff\xeb\x2c\x6b\xe6\x17\x20\x00\x00")
+
+func fontsTsalagiFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsTsalagiFlf,
+ "fonts/tsalagi.flf",
+ )
+}
+
+func fontsTsalagiFlf() (*asset, error) {
+ bytes, err := fontsTsalagiFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/tsalagi.flf", size: 8215, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsTwopointFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x53\x51\x8b\xe3\x46\x0c\x7e\xd7\xaf\xf8\x08\x86\xc4\xdc\x26\xde\x84\x2d\xdc\x1d\x47\x99\x96\xb6\x0f\xfd\x05\x07\x6b\x98\x4e\xec\x71\xec\xae\x3d\x93\xda\x63\xb2\x0b\xae\x7f\x7b\x91\xc6\xde\x6c\x5f\xee\xc1\x41\xd2\x48\x9f\x3e\x7d\x52\xaa\xb6\x3a\x99\x04\x27\x9c\xf0\x19\x8f\x38\x3e\x51\xb8\xf9\xab\x6f\x5c\xc0\xf9\x0d\xbf\xf6\x63\x61\xf1\xa7\x79\xb1\x37\xf3\x86\xdd\xf5\xfc\x77\x34\x95\xb3\x63\x67\x9c\x3b\x8c\x37\x13\x6c\xdf\x7a\x7f\x28\x4c\x4a\x7f\xf8\x1e\x55\x73\x69\x6d\x40\x6f\x5b\x6b\x06\x8b\xd3\xe1\x91\x7e\x33\xc1\x7e\x05\x8e\x5f\xbe\x3c\xe1\x97\xf1\x82\xe3\x91\xe8\xf7\xd7\x6b\x6b\x9c\x09\x8d\x77\xf0\x15\xaa\xa6\x1f\x02\xda\xc6\xd9\xaf\xc4\x94\xb0\xc7\xa6\x33\x97\xa6\x80\x1b\xbb\xb3\xed\x37\xa8\x04\xbb\xb5\x68\x4a\xeb\x42\x53\x35\x85\x14\x93\x01\x80\x3d\x86\xda\x8f\x6d\x09\xd3\xde\xcc\xdb\x80\xb3\xc5\x5f\x66\xfb\x20\x45\xce\xdf\x28\x89\x49\xa1\xb6\xd8\xd4\xa6\x2f\xcf\xad\x71\x2f\x1b\xec\xf7\xb8\xf6\x8d\x0b\x03\xcc\x00\x03\x89\x3e\xe0\x3c\x06\x14\xc6\x6d\x03\xc3\x0c\xdd\x38\xd4\xb6\xa4\x53\x44\xa8\x6d\x73\xa9\x03\x33\x36\x28\x6a\xd3\x9b\x22\xd8\xfe\x87\x8f\x0f\x70\x3e\xa0\x71\x45\x3b\x96\x8d\xbb\xa0\xb4\x43\x61\x5d\x69\xfb\x81\x3e\xc7\xb2\xce\xbc\xca\xe4\x68\xad\xbb\x84\x1a\x3b\xfb\xba\x26\x17\xbe\xeb\xac\x8b\xc2\x0c\x29\x3d\xc6\x82\xd2\x56\x66\x6c\x43\xe4\xd6\xf9\xd2\xca\x9c\xa1\x6e\x06\x54\xde\x05\xec\xda\xe6\xc5\x62\xb3\xef\x70\xfc\x69\x03\xef\x04\xc6\xb8\x52\x60\x52\x3a\x3e\x09\x4a\x14\x96\xd9\xfe\xaf\x0b\x51\x92\x28\xfe\x14\x4d\x8a\xbc\x52\xb4\xdd\x2e\xfe\xa7\x4f\xf2\x29\xda\x4d\xb3\x22\x3d\xa5\x4a\x91\xcf\x14\x65\x9c\x05\x0f\x45\x3b\xfd\x5d\x29\x4a\x15\x71\x7a\x36\x2b\xca\xb5\x52\x34\xe7\x8a\x74\xa6\x14\xe5\x13\x67\x4f\xb9\x52\x94\x4c\x89\xa2\x79\x9a\xd9\xe4\x0a\x69\x41\xf3\xe2\x33\x60\xc2\xb9\x82\x93\x2b\xca\xb9\x7c\x3b\x71\x1d\x03\xa6\x8a\x32\x41\xce\x14\x69\x2e\xce\xee\x70\xc2\x8d\x63\xc8\x84\x51\xba\xe4\x09\xd6\x8e\x4b\x63\x6c\x37\x33\x9c\x44\x7d\xec\xe8\x23\x91\x4c\x11\x33\xdc\xef\xe5\x63\x87\xb2\xa5\xa9\xe7\x6c\x68\xc6\x35\xa9\xf4\x9a\xe2\x0f\xff\xa6\x8a\x26\x9d\x2e\x0c\x26\x2d\x46\xce\x16\x57\x3f\xcf\x8a\x9e\xf5\xfa\x18\x79\x6a\x7e\x94\x5a\xcd\x30\x98\xa2\xe6\x93\xc8\xc3\x02\xb3\x9f\x29\x12\xc1\x78\xc0\x08\x9a\x67\x92\x1d\xd3\x73\x88\x93\x4f\x22\x38\x2b\x25\xed\x22\x9b\x19\xf7\xe8\xf7\x7b\x34\x97\xe9\x17\x95\x58\x34\xd9\x46\x64\xb0\x30\xca\x81\x4c\x51\x92\x67\x31\x0e\xee\xc6\x6e\x0c\xe4\x99\x6c\x65\x31\x92\x55\x60\xfd\x71\xf6\x9c\xaf\x28\x97\x06\xcb\x28\xbc\x47\xb9\x23\xde\xb4\xe6\x9c\x9d\x22\x66\x98\xe8\x84\x97\x12\x95\x48\x56\x15\x13\xcd\x41\x31\xa6\xf5\x99\x63\xff\x4a\x8c\xfb\xc4\x7d\xc7\x3d\x7e\xa8\x16\x61\xfc\xa2\xa3\x5f\x75\xe4\x97\x6f\x77\x81\x0f\x1a\x4b\x32\xa2\xfb\x5e\xb9\xb0\x91\x45\xa6\x52\xc8\x07\xbf\x5c\xde\x41\x2f\x11\x66\xa2\x79\x3c\x3d\xe9\x55\xbf\x04\xc9\xaa\x1f\x8f\x28\x37\x9b\x00\x62\x46\x27\x51\xf4\xf3\xb7\x75\xe1\x91\x33\x77\xcb\x3e\x8c\xa4\xef\x1c\x67\x26\xad\x65\x48\xae\x17\x7c\x45\x7e\xf6\xeb\xcd\x89\x19\x17\xfe\x0f\xae\x6b\x6f\xaf\xfd\xaa\xd7\x62\xca\x1f\x15\xfe\xfd\xdc\xe4\x0c\xc0\xd1\xff\x02\x00\x00\xff\xff\xf1\x79\xae\x0d\xff\x05\x00\x00")
+
+func fontsTwopointFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsTwopointFlf,
+ "fonts/twopoint.flf",
+ )
+}
+
+func fontsTwopointFlf() (*asset, error) {
+ bytes, err := fontsTwopointFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/twopoint.flf", size: 1535, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsUniversFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x3b\x7b\x8b\xe3\x38\xf2\xff\xfb\x53\x14\x22\x90\x59\x7e\x9e\x66\x7b\x76\x7e\xa0\x59\x96\x25\xdc\x83\xa3\x0f\xfa\xf0\x3f\x77\x60\x96\x63\x2c\x47\x4e\x77\xb8\xb4\x33\xe4\xb1\x3b\x73\x9f\xfe\x90\x54\x25\x95\x6c\xd9\xb1\xd3\x0f\xc6\x0d\xb1\xaa\xac\x47\xa9\x54\x2f\x95\xd4\x9b\xdd\xe6\x83\x5a\xc0\xed\x2d\x7c\x82\x8f\x3f\xc2\x4f\x1f\xe0\xf6\x63\xf6\xcf\x76\xfb\x7b\x73\x38\x42\xfd\x0d\xfe\xb1\x3f\x3c\xa9\x56\xc3\xbf\x9a\xed\x6e\xd7\x9c\xbf\xc2\x2f\xed\xef\xae\xb8\x6a\x9e\x0e\x37\x6b\xf5\x6b\xb6\xd9\x3e\xec\x9a\xd3\xf6\xbf\x8d\x36\x0d\xfe\xb6\x6b\xda\x16\xfe\xfc\xa8\xbe\x7c\x69\x76\x3b\xf8\xe5\xe1\x61\xbd\x3a\x6f\xcf\xeb\x9b\x46\x9f\x7f\x85\xbf\xab\xf6\xac\x0e\xdf\xe0\xf6\x43\x0e\xb7\x9f\x3e\x7d\xcc\xfe\xa2\x4e\xcd\xcf\xf0\xff\x70\xaf\x0e\x0e\x91\xfd\xf5\xeb\x97\x9d\x6a\xd5\x69\xbb\x6f\x61\xbf\x81\xcd\xf6\x70\x3c\xc1\x6e\xdb\x36\x3f\x67\x86\x58\x78\x0f\xe2\x49\x3d\x6c\xd7\xd0\x9e\x9f\xea\xe6\x20\x60\xb3\x3f\xc0\x66\xbb\x6b\x60\xab\x9b\xf6\xb4\xdd\x6c\xd7\xb6\x71\xa6\x00\x00\xde\xc3\xf1\x71\x7f\xde\x69\x50\xbb\x3f\xd4\xb7\x23\xd4\x0d\x54\x6a\x99\xdb\x46\xed\xfe\x8f\x6c\xe1\x2a\x9d\x1e\x1b\x10\x8f\xea\xa0\xeb\x9d\x6a\xff\x23\xe0\xfd\x7b\xf8\x72\xd8\xb6\xa7\x23\xa8\x23\x28\xb0\xd8\x1c\xea\xf3\x09\xd6\xaa\x5d\x9e\x4c\x37\xc7\xa7\xf3\xf1\xb1\xd1\xd9\xed\xad\xed\xe1\xb1\xd9\x3e\x3c\x9e\x0c\xc5\x0a\xd6\x8f\xea\xa0\xd6\xa7\xe6\x90\x7d\x82\xe1\x8f\x39\xb4\xfb\x13\x6c\xdb\xf5\xee\xac\xb7\xed\x03\xe8\xe6\xb8\x6e\x5a\xdd\x1c\x8e\xd9\xc7\x1f\x6d\xb3\x27\xf5\xd5\xce\x1c\x76\x4d\xfb\x70\x7a\x84\x77\xcd\x57\xaa\xbc\xde\x3f\x3d\x35\xad\x63\xcc\xf1\x07\xf8\x3f\x50\xb0\x39\xeb\x87\x06\x36\x6a\x7d\xda\x1f\xb2\x9f\x3e\xd8\x1e\x74\xb3\x51\xe7\xdd\xc9\x11\xfb\xb4\xd7\x8d\x9d\xf8\xe9\x71\x7b\x84\xcd\xbe\x3d\x65\xb7\x1f\x6d\x35\xc7\x4a\x43\x5f\xd4\x6f\x66\xd8\xb3\x58\x3d\xe7\x77\x95\x19\x0e\xac\x32\x29\x0d\x6a\xe8\x57\x08\xf3\xab\x54\xc0\xb8\x56\xf6\xd7\xbd\xa8\x17\xdf\xcc\xb7\x74\x8d\xc1\x0c\x67\xdb\x5c\x53\xf0\x63\xd0\x48\x60\xfa\xb7\x3f\x8b\x04\xa8\x94\x94\xca\xfd\x38\x22\xa4\x14\xee\xc7\xcd\x63\xec\xeb\x78\xcf\x3d\x32\x38\xe8\x60\x09\xb6\xae\xfd\xac\xb4\x34\x4f\xad\x60\x01\xab\x4c\x4b\x61\xbf\x0a\x59\x9b\x91\x4a\x99\xf3\xca\x55\x29\x95\xf9\xcb\x69\xa4\x4a\x48\xf3\x57\xe7\xc4\x3f\x53\xb9\xa2\xb6\xca\x82\x4a\x16\xf6\xab\x28\xed\x40\x85\xb0\x03\x75\xc9\x48\x50\xd9\x99\x48\xae\x74\xad\x72\x07\xe5\xda\xad\xe1\x1d\xc0\x9d\x44\x84\xeb\x57\x6c\x6a\x5d\x2c\x3d\x22\xf4\xed\x11\x84\x62\x08\x87\xb2\x08\x00\x1c\x67\xb1\xca\x10\x01\x80\xe3\x98\x11\x05\x36\xc0\x71\x16\x49\x52\xfb\xa8\x2e\xce\xc2\x34\x12\xc1\x34\x0c\xc1\x42\xba\x31\x18\x7d\xb2\x06\x14\xdb\x1b\x3b\x4d\x28\xeb\x5c\xde\x59\xca\x0a\xd7\xb3\x94\xd2\x92\x65\x16\xc5\xb4\x29\xcc\x6a\xb8\xb5\x73\xdc\x87\xb2\xee\x93\xdd\x83\x99\xca\x00\x68\xd7\xa5\x7b\x83\x53\x36\x20\xe1\xbf\xbe\x60\xc7\x50\xa8\xac\xdd\x31\xdc\x1b\xf5\x1e\xa2\x82\x91\x4a\x27\x80\xae\x64\x9a\xdb\x12\x72\x8d\x4d\x6f\xb5\xca\xa4\xc2\x66\x56\x2e\x6d\xb3\x0a\x79\x02\x24\xab\x40\x5c\x65\x85\x1c\xe5\xd6\xbe\x8d\xfc\xd9\x37\x58\x19\xe0\x82\x35\xb0\xb8\x31\x7c\x27\xad\x2f\x51\x66\xad\xec\x77\x51\xd6\x79\xae\xad\x32\x58\x6b\x60\x94\xdd\xea\x3c\x2a\xbc\xd1\x76\xab\xf4\xa8\xf1\xb9\x2e\x96\x55\x59\xd3\xc4\xef\x9c\x20\x0a\xdf\xdf\x85\xf1\xc7\xa4\x31\x05\x29\xc5\x35\x53\x7a\x3d\x55\x68\x95\x38\x99\x81\x48\x5e\xd3\x92\x27\x52\xfa\x3d\x0a\x11\x38\xe3\x8d\xc4\x80\xc0\x95\x43\x49\x92\x82\xdb\xc3\x68\xce\xf3\xcb\x0a\x1f\x9a\x35\x9f\xf3\x8c\x7e\x10\x98\xf3\x92\xe4\xae\x82\x58\xd3\x6b\x6c\x9d\x35\xd7\x02\x23\xc3\xdc\x56\xe9\x88\x37\xee\xa3\x6f\x1f\xdb\x49\xff\xd1\xc1\xdc\x66\x1a\xe2\xc2\xc7\xf9\x72\x07\xc1\x0e\x5a\xd9\xf7\x96\x30\x97\x85\x58\x1a\xe7\x42\xea\x9d\x93\x71\xf3\x7a\x6e\x3d\x1e\x3e\xde\x9f\x77\x30\x46\xb7\xfd\x84\xdd\xf4\x2b\x69\x5d\x48\xae\xc8\xca\x18\x21\x2d\xbd\x5b\x4a\xd9\xee\x04\x26\xa0\x82\xd0\xa3\x81\xa6\xb5\x62\xcb\x35\xbf\x14\x0f\x9b\x88\x2c\xd0\x67\xa3\xdf\x25\x2f\x45\xf2\x8f\x0b\x42\x7e\x77\xe1\x7c\x1d\xf9\xdd\x85\xf9\x10\xf4\x52\x45\xeb\xdb\x5d\xde\xf0\xf4\x5c\xc6\x05\x9f\x7d\x0d\x95\x4a\x91\x17\xb7\xa0\xf0\xeb\x4f\x95\x59\x54\xe2\xda\x4a\x1e\x59\xc8\x84\x3f\xbe\x18\x59\x30\x1d\xd1\x51\x00\x65\x16\x93\x21\x6c\x2c\x10\x10\x18\x1a\x10\x22\x44\x0a\x92\x9c\xd6\x10\xef\x7a\x61\x5a\x32\x6e\x4b\x21\x7a\x53\xe3\x23\x80\xd7\x80\x85\xff\x0a\xf0\xf9\xf3\xe7\xcf\xde\x7b\x2a\x59\x14\x45\x81\xcb\x51\x14\x8e\x60\x72\x80\xb4\xea\xce\x6e\x94\xce\x5d\x8d\xc4\x6e\x53\x39\x6c\x40\x27\x08\x18\x54\x81\xb4\x71\x8b\xe9\xd2\x89\x05\xd5\x44\xbe\xe5\xda\xd4\xae\x6b\x54\x73\x57\x19\xa9\xf4\x3a\x8e\xe1\xdf\x8b\x51\xd9\x59\xb1\xef\xdf\x74\x26\x03\x77\xe0\x2a\xd2\x63\x8d\xf1\xdc\xc4\x1a\x23\xaf\xc2\xc5\xed\x93\xda\x5e\xbf\xf8\x43\x54\x4a\x1e\xb3\xa2\xed\x43\xbd\x26\x33\x0a\xa2\xb0\x0f\x59\x0c\x62\x97\x23\xcb\xc5\xb7\x8e\x48\x13\xdc\xa1\x19\x5f\x4e\xde\x04\x4d\x74\xb8\x8b\xc5\x44\x2f\x3c\xf2\xa6\x66\x14\x34\xcc\x8f\x58\x3c\x56\x49\x1f\x77\xa8\x50\x5f\x49\x6f\xd1\x55\x10\xb3\x55\x26\x30\xf8\xc5\x0e\x3c\x88\xe1\x99\x03\xa9\x6b\x0b\x26\x07\x4d\x2d\xee\x38\xd4\xd1\x25\x12\xf4\x45\xe2\xdb\xe4\x3e\x47\xa0\x0e\xd5\xd7\x4f\x7b\x1e\x7b\x27\xb2\xea\xa2\xb6\x0a\x41\xa3\x17\x9e\x94\x5c\x71\x8d\xd3\x52\xa4\x02\xeb\x4e\xb4\xde\x09\xd7\xe7\x1a\x41\xaa\x63\xc2\x23\xe3\x2b\xd0\x66\x93\xf1\x82\x1b\xf5\xa4\x6e\x14\x31\xcc\x08\xad\x0d\xd5\xa4\xf9\x16\x82\xb0\x1b\xa3\xd5\x56\xb3\x03\xce\x25\x28\x96\x41\x79\x0d\xee\x4f\xd6\xe5\x62\x2c\xe6\x16\x4d\x48\xdb\x9f\xa4\x7d\x11\x54\xd6\x6e\xd9\x47\xa3\xa6\xbb\xf9\xfb\x18\x3c\x19\xa2\x8d\x4c\xce\x3e\xba\x8e\x76\xfe\x8e\xc3\xb2\xee\xac\xac\x96\xcb\xca\x23\x69\x1d\x96\xe8\x8d\x3c\x4e\xcb\xd2\x90\x57\x22\x72\x65\xf7\xb2\x44\x9f\xdf\x72\xda\x86\xee\xa1\xdd\x27\x43\xf1\x8d\xe8\x10\xcd\x23\x93\x0b\x3a\x85\xf2\x45\x8e\x52\xc4\x7e\x33\x27\xee\x3b\x8e\xa2\x67\x93\x92\x68\x8d\x42\xeb\x8e\xcf\x55\xd4\x56\x5e\xed\x64\x83\x70\xc5\x92\xe5\x5c\x3c\xd2\xca\xb9\x42\xfb\xff\x0b\x08\x8a\x07\x3d\x02\x4a\xa9\x6e\x0c\x74\xe3\x35\x0a\xfd\x43\x29\x96\x89\x0d\xf3\xe5\x60\x2b\xe6\x71\x1e\x13\xe2\x48\x8f\x28\xeb\x06\x2c\x89\x5d\x4a\x1f\x51\x70\xc4\x0d\x79\x36\x1a\xd6\x91\xfe\xcc\x40\xd1\x67\x4c\xa3\xaf\x1d\x10\x77\xba\x04\x06\x45\x4b\x55\xee\x80\xcf\xd8\x30\xbc\x21\x95\xc3\x91\xd7\x1b\xcb\xb0\x9f\x2d\x93\x61\xe4\x1d\x93\x61\x19\xc9\x70\x52\xf7\xa6\xc8\x30\xa7\xa3\x2b\x7d\x43\x30\x59\x5f\x82\xbd\x61\x9b\xd8\xbe\x33\xa9\x51\x8a\x27\xa6\xfa\xfb\xbf\xa1\xb3\xc1\x20\x25\x1e\xff\x79\x90\x94\x79\x14\xa6\x96\x03\x8b\x32\x16\xa4\x44\xcb\x11\x54\x1d\xac\x95\x66\xa9\x4f\x03\x31\xb1\x36\x83\x2e\xd9\x16\x4f\x4a\x21\x5d\x36\xd4\xc1\x85\x4d\x91\xd4\x21\x63\x0a\x2e\xda\xce\x63\xfb\x54\xa6\xbc\xcd\xe5\x3d\xc7\x2c\xb5\x7a\x1e\x78\xb5\x1d\x09\x5d\xd4\x0c\x0e\x99\x99\x9a\xe3\x10\x19\x32\x45\x5a\x2e\xbd\x60\x11\xd6\x68\x73\x10\x67\x87\xb5\x1a\xce\x64\xdc\x60\x9d\xd6\x73\xc1\xaf\x6c\x32\xbe\xab\x0d\x15\x5a\x87\x94\x4a\xa4\x66\x38\x30\x4f\x3e\x9b\x90\x77\xaa\x23\x98\xe6\xd0\x25\xbf\x43\x79\x87\xe8\xba\x4b\xaf\x8c\xb5\xb9\x4a\x2d\xcb\xd4\x6c\x5f\x64\x3b\xfb\xc6\x33\x8e\x8b\xfa\x6e\x74\x30\xdb\xc7\x0c\x28\x65\xee\xe3\x28\x00\x7a\x61\xc0\xdc\x6c\x5f\x60\xfb\xb3\x63\xad\xf8\x6c\x23\xf4\xfc\x72\x7e\xea\x2d\x98\x6d\x0c\x4b\x97\xd9\xa5\xec\x33\xbb\xec\xed\x2c\xdf\x90\xd9\x91\x35\xf5\xc1\x3b\x93\xee\x38\x76\x4b\x05\xe2\xd7\xa7\x39\xa2\x7c\x25\x3b\x45\x35\x0f\x3b\x45\x65\xe1\x37\xd5\xab\x5e\x3a\x19\x33\x94\xe3\xea\xee\x16\x5f\x1b\x1e\xa2\xf7\x65\xe2\x95\x79\x70\x6f\x9f\x30\xba\x4d\x98\x60\xe1\x0c\xcd\xb1\xdf\x81\xf8\x24\x82\x1f\x45\x70\x8c\x13\x04\xe6\x71\xc8\x3c\x05\x7f\x13\xb6\xba\xe4\x6d\xf8\xe1\x9a\xf3\x35\x31\xa7\x2b\xb9\x4c\x26\x2b\x86\x51\x49\xd7\x43\xd5\xef\x58\x8c\x4a\x05\x3c\x7d\xe6\xb3\xa9\x3b\x33\x15\xd8\x2c\x97\xac\xe4\x8f\x6d\x5d\x77\x05\x2b\x91\x56\xf8\x89\x47\x2c\x40\xa6\x28\x50\xd6\x72\x51\x89\x33\x47\xa1\x4d\x73\xa5\x98\x49\x64\xed\xaa\x1e\xb3\x92\x53\x1e\xfe\x94\x10\x56\x76\xdc\x84\x26\xd1\xe5\x33\x83\x41\x34\x55\xf8\x3c\xc8\x5a\xb2\xfc\x02\xcf\x2d\xd8\x73\xaf\x70\xda\x8d\xb6\xda\x5b\x2c\x76\x28\x76\x85\x3b\x9e\x42\xb0\x45\xe4\x61\x4d\x40\x48\xa5\xa2\xf3\xef\x4a\x76\x58\xfc\xba\xe6\x60\x20\x2e\xcc\x23\x18\x43\x66\x84\x7d\x00\x6d\xe1\x10\x4e\x83\x3d\x69\x8c\xee\x80\x70\x68\x74\xbc\x21\x82\xbb\x9b\xd7\x17\x28\xc4\x43\xa7\x57\x71\xc1\xe1\xaa\xa4\x0d\x01\x11\x29\x64\x27\xdd\x55\x15\xbe\x0a\xf6\x27\xa2\x94\x96\xa9\x12\xc4\x0e\x1f\xe1\x2f\x4d\x80\xaf\x32\x8f\x29\xa9\x5b\x16\xd7\x14\x86\x98\x12\x65\x41\x73\x49\x1b\x23\x77\xde\x51\x88\x92\xce\x3b\xee\xbc\x7b\xbe\x8b\xb2\xd3\xe0\x2f\x74\xbd\x0a\xc8\xe1\xee\xf7\xef\x03\xee\xc8\x7b\x60\x70\xf2\xee\x0c\x84\x2b\x10\x5e\x50\x66\x17\x46\x77\xcc\xa3\x50\xae\x74\x51\x94\x25\x1e\x2b\x62\x0a\x1d\x65\xd2\x7e\xb3\x19\xec\xb0\x5f\x27\x23\x61\x42\xdf\x5a\x17\xa2\x2f\xbd\xe3\xfb\xf5\xd9\x5b\xd8\xdc\xd0\x47\x39\x22\x3a\xc9\xc4\xe4\x79\xef\x24\xd3\xdd\xd6\xc2\xe3\x07\x13\x32\xd7\xb5\x8d\xd5\x67\x46\x79\xb3\x20\xc7\x41\x64\xa0\x22\xa5\x70\x14\x90\x6b\xb0\x8b\x25\xa4\x72\xe4\x29\x0a\x92\x88\xba\x79\x0c\xf4\x45\xd9\x3f\x13\xef\x83\x48\x1e\x2e\x1b\xd2\x57\x95\xb8\xa6\x75\x54\x99\x28\xa4\x9c\xcc\xf0\x22\xbf\x22\x03\x8b\xcf\xe6\x41\xfa\x8a\x82\x5d\x13\x12\xb4\xbe\x57\x33\xd0\x16\x15\x4d\x8f\x1f\x43\x7b\x5f\x71\x7f\x2f\xe5\xfd\xfd\x3d\x2c\x22\xec\x84\x62\x7f\xf0\x91\xa5\x9b\x04\xd2\xd2\xe9\xab\x96\xae\xe4\x4b\xa7\x14\x57\x5e\x7b\x6f\xc0\x7e\x36\x9a\xf1\x26\x1a\xda\xd9\x39\x24\xc1\x51\x76\x38\x78\x15\x5d\x54\x0e\xdb\xff\x79\x59\xcd\xd8\x1d\xf6\x0d\xf0\x1c\x6f\x9a\x7b\x6f\x6a\xb8\xd9\x3d\x43\x65\xcc\xba\x00\xd0\xd5\x19\x0b\xe4\xfe\xd8\xd4\x38\x91\xdf\xc0\x67\x26\xcd\xb2\x2a\x96\x86\xac\xfa\x49\x81\x18\x88\xd9\x36\xfd\x37\xc5\xb6\xb1\xf5\xb9\x0a\x6b\x65\xc7\x4c\xc8\x48\x7a\x57\x84\xdc\x89\x68\x4f\x92\xd8\x7b\x26\x76\x06\x65\xcf\x53\x5c\x59\xa7\x54\xa2\x7a\x25\x95\xb8\x96\x4a\x6e\x77\x81\x79\x2e\xa4\x32\xec\x3f\xb9\x79\xa1\x93\x7d\x32\x2f\xb3\x5d\xeb\xcb\xf0\x72\x62\x00\x20\x2b\x4e\xe5\xa8\x1d\x7b\x5b\x53\x0d\x09\x53\xbd\x9c\xe0\xce\xaf\xf7\xb2\x9c\x8f\x41\xc5\x4a\xbe\xcd\x4a\xf0\xa5\x0b\x8d\x8c\x30\x62\x83\x46\x80\xc8\xf7\xdf\xc9\xdf\x20\xd8\xe3\xca\xf8\x28\x12\x4e\xcb\xb1\x7f\x63\x96\x24\xc8\xde\x45\xc3\xd7\xfd\x60\x2d\xb6\xee\xbb\xef\x49\x5e\xdf\x6f\xe5\x6c\x7a\x2b\x1a\xfd\xe5\xbc\xfe\x2c\xf3\x10\xd4\x32\x16\xa5\xd9\x01\xdb\x7c\xb5\xc4\x62\x9c\x9a\x8b\xd3\x72\x51\x4a\x2e\x8f\x32\x36\x42\x26\x2f\xb5\x5f\xa2\x32\x5d\xeb\x2a\x2c\xcd\x40\xd7\x89\x89\x68\x49\x6f\x36\x1f\xbc\xc8\x12\x4f\x8b\xae\xb2\xc4\xf9\x28\xcc\x29\x95\x45\x72\x92\xe3\x94\x3d\xdb\x5e\xda\x12\x5a\x22\x97\x81\xc0\x3b\x94\xb6\xf2\x0f\x52\xca\x77\x6c\x47\x2f\xc0\xdf\x60\x44\xdb\x9a\x4c\x49\x7c\x5f\xe2\x53\x4a\x19\xdf\x18\xe5\xd9\x33\x1d\x92\x92\xd7\x19\xa5\x7e\xb6\xca\xdd\x22\x73\xc6\xc3\xdf\x8e\x8c\xfe\x17\x6a\x28\xc3\xd5\x37\x4a\x4a\xfb\x5a\x32\xcc\x29\x69\x73\x30\x67\x68\xbb\x7f\xe7\x67\x28\xd8\x1d\xa9\xc9\xa6\xea\x52\x1c\x38\x1e\x4a\x23\xf1\x74\x36\x83\x8b\x22\xa3\x80\xb9\x5f\x0c\xff\x57\x64\xc5\x0e\x3b\xd2\x21\xad\x98\x6c\x96\xcb\x70\xfb\x1b\x6f\xb0\xf5\x34\xe5\x3a\x84\xd2\xb2\xc6\xff\x5c\x50\x21\xdb\x21\x44\xc9\xae\xf5\xd3\x83\xac\x7c\x3e\x62\x95\x25\xff\xbe\x27\xf4\xff\x02\x00\x00\xff\xff\xaa\x8c\x6e\xd1\x7c\x3c\x00\x00")
+
+func fontsUniversFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsUniversFlf,
+ "fonts/univers.flf",
+ )
+}
+
+func fontsUniversFlf() (*asset, error) {
+ bytes, err := fontsUniversFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/univers.flf", size: 15484, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsUsaflagFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x58\x4d\x6f\xe3\x36\x13\xbe\xf3\x57\x4c\x16\x3a\xec\x02\xaf\xb4\x51\x36\xc9\x26\xc4\xab\xc2\x01\x82\xd4\x8b\x6e\xdd\x00\xe9\x02\xbd\xd2\x32\x2d\x73\x23\x93\x86\x48\x27\x48\x7f\x7d\xa1\x6f\x0e\x45\xdb\x72\xd0\x4b\x01\x3b\x88\x38\xa6\x86\x0f\x67\x9e\xe1\x8c\x46\x5e\xe6\xcb\x0b\x16\xc0\x35\x5c\x41\x7c\x03\x61\x0c\xf1\x2d\xd9\x6a\xb6\xcc\x59\x16\x2d\xf3\x25\x84\x21\xc4\xf1\xe7\xeb\xcf\xb7\x97\x84\x3c\x88\x2c\xe7\x06\x52\x25\x5f\x78\xa1\x85\x92\x30\x7f\x83\xdf\xb8\x34\x30\x63\x5a\x73\x09\x1f\x9f\xb9\x34\x72\x92\xbe\xcd\x79\xa1\x37\x2c\xe5\x91\x2a\xb2\x4f\x30\x67\x9a\x2f\x40\x49\x30\x2b\x4e\x96\x4a\x1a\x58\x70\x2d\xb2\x72\x39\x25\xe4\xae\x30\x22\xcd\x39\x5c\x5c\xdf\xdc\x80\x5a\x42\xc1\xd3\x88\x15\x46\x47\x4c\xa7\x42\x50\xf2\xc8\xcc\x8a\x82\xe4\xaf\x3a\x12\x66\x11\x6d\xd7\x22\x5d\x45\x7c\xb1\x3d\x4b\x19\x97\x67\x7a\xa3\x54\x1e\xad\xb7\xd5\xcc\x4a\xbd\xe6\x4c\x2e\xa2\x82\x6b\xa3\x64\xc4\xa4\x8e\x24\x37\x67\xd5\x5a\xbd\x29\x84\x34\xb9\x90\xcf\xd5\x9c\x66\x7a\x25\xd6\x22\x7a\x7d\x65\x51\xaa\xd6\x67\x52\x99\x70\xa9\x8a\x70\xcd\x44\x4e\x1e\x0a\xb5\xa6\xb0\x10\x5a\xf3\x7c\x22\xb7\x52\xa4\x91\xac\x76\x80\x8f\xf7\xec\x45\x2c\xe0\x29\x82\x6f\xe5\xcd\x4f\x64\xc6\x5f\x75\x56\xa8\xed\x46\x53\xc7\xf2\xff\xb1\xdc\xd4\x52\xc8\x0a\x43\x9e\xb6\xf3\x9f\x3c\x35\x14\xbe\x0b\xc9\x29\xfc\x78\xba\x83\x87\xef\x77\xbf\x42\xc9\x07\xb9\x67\x86\x53\xb8\x86\x99\x7a\x81\xf8\xf6\xf6\x12\xe2\x2b\x7a\x79\x43\xcf\x63\x08\xcf\xaf\xcf\xcf\xc9\x1f\x45\xc6\xa4\xf8\x9b\x19\xa1\x24\x85\x59\x35\xb2\x1c\x7e\x48\x51\x45\xc2\xbc\x91\x12\x55\x53\xf8\x7a\x41\x9e\xb8\x5c\xf0\x82\xc2\x5c\xcd\xd9\xa4\x71\x8f\xdc\x6d\x36\x85\x7a\xe1\x0b\x67\xfa\x77\xae\x35\xcb\x78\xf8\xed\x9e\xc2\xff\xbf\xdc\xfe\x14\xdb\x55\xf0\x1c\x5f\x4c\x32\x96\xad\x79\xcb\xcd\x2f\x64\x36\xfb\xf3\x31\x7c\x54\xda\x08\x99\x85\x53\xa5\x0d\x05\xa4\x41\xfe\x2a\xf8\xd2\x17\x23\x37\x98\x55\x8c\x11\x2f\x34\xbe\xfa\xfa\xe5\x86\x84\xe8\x43\x02\x00\x08\x26\x23\x86\x09\x09\x92\x24\x71\xae\x00\x80\xe4\xea\x0b\x24\x49\x39\x0b\x95\x54\xdf\xe8\x70\xfc\x42\xad\x9d\x54\xff\x35\x5e\xfd\x19\x39\x0f\xed\xa7\x06\x9a\x26\xd3\x46\x7d\x0a\x53\x68\x4c\xe9\x54\xa7\x30\x6d\x00\x5a\x3d\xb4\x38\x81\xde\xe8\xd6\xaf\x72\x6d\xb3\x3f\xb4\x1e\x03\x24\xee\x62\x4a\x69\xa7\x40\x29\xad\xb0\xac\xdd\x5b\xda\x3a\x38\x7b\xde\x71\xa1\x56\xad\xf1\x03\xcf\xb5\x59\xdd\x00\x0e\x86\xce\xf2\x36\x24\x68\x16\x0d\x16\x85\x15\x6a\x69\x78\xcf\x6b\xe9\x51\xef\xbc\xc5\x7e\x6d\x7b\xef\x07\x0c\x62\x51\xc3\xf5\xce\x82\x03\xb4\xe3\x2e\x5a\x0c\xee\xb5\xb5\xbc\xa1\xa7\xd7\x0f\xb0\x88\x4c\xf5\x29\x74\x62\x29\x07\xc3\x4b\xbd\x34\x98\x38\x27\xa1\xf7\x12\x3b\x8f\x4f\x87\x7b\x26\xea\x35\x2d\xb3\xad\xea\x40\x6c\x39\xb5\x58\x6c\x20\xba\xab\x3f\x03\xdd\x7d\x1c\x83\x13\xcb\x4e\xf0\x92\x63\x41\x00\xf6\x18\x59\xd4\xed\x9b\xf8\xce\x7e\x7b\x1f\xfb\x89\x76\xf2\x8b\xd8\x85\x16\xc1\x32\x75\xdc\xfe\x88\x67\xe4\x29\x8c\xe5\x79\x87\xb1\x16\x85\x38\xd6\x3b\x20\x9c\x68\xc3\x3b\xac\xf0\x43\xb8\xb6\x59\x39\x68\xe7\x8d\x7d\x80\x6d\xa9\x3d\xcf\x41\x9f\x4a\xb6\xdc\xb0\x3b\x38\xf4\xc3\xf2\x87\xd3\x15\x85\x72\x32\x26\x11\x0f\xa4\xe7\x88\xbd\x7c\x36\xf5\xfb\xdb\x84\x7b\x93\x01\xe0\xc3\x87\x6e\x59\x57\xa7\x87\x10\x7d\xd0\xac\x74\x6d\x4d\x6f\x0f\x01\x38\xfa\x70\x38\x9e\x16\x01\x3b\x6a\xc1\x58\x08\x18\x40\x1c\x38\xdb\x38\x3d\x3c\xa2\x7b\xd6\xde\x51\xc9\x8e\xb5\xc2\x89\xe6\xc1\x22\x35\x1a\x62\x4f\x92\xa2\x5a\x01\xde\xd0\xe2\xdc\xf3\x85\x76\x7f\xcd\x1b\x15\xda\xc3\xb5\xbd\x54\xae\x55\xb0\xd4\xaa\x1e\x53\x98\x51\x27\x65\xbb\xed\x56\x27\x17\xa2\x6f\x6b\xf6\x1e\x9e\x03\x61\xeb\x59\x6f\xb6\xb5\x0c\xc0\x49\xe5\xfb\x06\x30\x48\xad\xde\x35\x8b\x74\x9b\xff\x61\x28\xde\x7b\xa8\x8f\x2a\xd8\x83\xf2\x31\xe6\xb1\x61\x63\xd8\x27\xd2\x26\xb6\x7f\x10\x25\xc3\xc6\x71\x94\x2d\x07\x83\x8d\x73\xe3\xc8\x2e\x20\x41\x01\xd9\xd9\xe4\x79\xda\xbd\x9d\xe9\x74\x54\x2c\xf6\x43\xe0\x75\xbe\xc2\xdf\xf1\xef\xe0\xb8\x60\x6e\x75\x48\xec\xce\xb0\x09\x1b\xee\x87\xf7\xda\x08\x4e\x74\x0f\x26\x24\x4a\x69\x27\x46\x87\x68\x46\x19\x8a\x5a\xdb\x71\x9d\x22\xaa\x6f\xfe\xb1\x5f\xe3\x3c\xcd\x93\x9e\x74\xcb\xb8\x61\xe3\x39\xdc\x0d\x3d\xfc\xad\x71\xb0\x5b\x13\x82\xc0\x4b\xe0\xae\xf7\x00\xe7\x95\x60\xb4\xb2\xbf\xaf\xe9\x5f\xdf\xec\x36\x6b\xf8\x12\x77\xea\x0e\x46\x58\x71\xea\x0e\x4e\xdd\xc1\xa9\x3b\x38\x75\x07\xa7\xee\xe0\x3f\xd1\x1d\x58\x5b\x36\x46\x0e\x26\xa1\x7f\xb4\xef\xb9\x02\xfa\xf5\x12\x03\x39\x93\x96\x6a\x7d\xbb\x54\xdb\xfb\x93\x73\x27\x4c\x88\xf5\xf7\x6f\x7f\xf9\x27\x00\x00\xff\xff\x82\x85\xbc\xdc\xf4\x19\x00\x00")
+
+func fontsUsaflagFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsUsaflagFlf,
+ "fonts/usaflag.flf",
+ )
+}
+
+func fontsUsaflagFlf() (*asset, error) {
+ bytes, err := fontsUsaflagFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/usaflag.flf", size: 6644, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsWavyFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x59\x5b\x6f\xdb\x3a\x12\x7e\xd7\xaf\x98\x07\x01\x95\x81\x75\x64\xd1\x97\xd8\x6f\x56\x64\x26\xd1\x56\x91\x7c\x24\xb9\x4d\x00\x01\x6c\x4e\xeb\xb4\x06\x12\x7b\x91\xe4\x14\x28\x90\x1f\xbf\xe0\x4d\x22\xa5\xa1\x77\x03\x38\xb6\xc5\x99\xe1\x5c\x3e\xce\x0c\xc7\x4f\xcf\x4f\xe4\xd1\x87\x19\x4c\x21\x9a\xc0\x04\x16\xe0\x7d\x7d\xfc\xfd\x07\xfe\xfe\x03\x57\xaf\x87\xc7\x23\x7c\x7e\x3d\xfd\x84\x68\x12\x4e\xe6\x5e\x7a\xfc\xfe\xfc\xcf\x8f\xfd\x1b\xa4\x55\x01\xd9\xe3\xfb\xe1\x38\x8e\xbc\xa7\xc3\xcf\xe7\xfd\x3b\xbc\xee\x9f\xf7\x8f\x6f\x7b\x20\x17\xe4\x82\xc0\x78\x0c\x93\x39\xfc\xfb\x9f\x67\x20\x93\xc9\xdc\xdb\xee\x5f\x5f\x0e\x6f\x6f\x87\xd3\x11\x0e\x6f\xf0\x6b\xff\xba\xff\xfb\x0f\xfc\x3c\xfc\xde\x1f\xe1\xfd\x04\x2f\xa7\x1f\x87\xa7\x3f\xf0\xfe\xeb\xf0\x06\x4f\xa7\xe3\xfb\xbf\xe0\xf1\x0d\x9e\x4f\xc7\x9f\xfc\xfd\xfd\xd7\xde\x13\x04\x87\xfd\xeb\xa7\x37\x38\x3e\xbe\xec\xb9\x8c\xff\x3c\x3f\x7e\xdf\xff\x80\xd3\x11\x1e\xe1\xfb\xe9\xe5\x65\x7f\x7c\x87\xe7\xc3\x71\x7f\xe1\x79\xbe\xbf\x36\x5f\x6b\xcf\x87\xb5\xf7\xe1\xaf\xbd\x93\x2f\x3e\xaf\x3d\x10\x4f\xf8\x23\xf1\x09\xe4\x43\xfe\x27\xbe\xb2\x90\x85\xcc\x5f\x7b\xe3\x70\x1c\x8e\xc5\x13\xb1\x22\x89\xf8\xf7\x20\xfd\xe6\xaf\xbd\x8b\x74\xe4\xab\x27\xe2\x6d\xed\x9d\x42\x7f\xed\x85\x27\x5f\x8b\x64\x9c\xb8\xe1\x54\xc1\xbd\x24\x35\xb4\xe1\xef\x92\x95\x73\x05\x62\x9f\xa6\xa5\x6a\xc4\x77\xce\x1a\x4a\x42\xa5\x22\xff\xc2\x1a\xa1\x1e\x84\x92\x08\xac\x45\x9f\x7d\x88\x45\xff\xc3\x5c\x54\x9b\x09\x17\x84\x7e\x6b\x88\xcf\x98\x36\x41\x1b\x62\x52\x76\x96\x09\x1d\x4d\x4d\x18\x7f\xf7\x82\x0b\xa9\x42\xc3\xa4\x2b\x5a\x5f\xf0\xc5\x30\x10\x6f\xc0\x46\x72\x13\x69\x18\xeb\x0c\x63\xad\xb5\xe2\xa1\x90\x21\x05\xf9\x86\x41\x21\x0b\x14\xbf\xb9\x07\x13\x2c\x23\x29\x8d\x99\x81\x50\x9a\x49\x82\x9e\x66\xea\xa1\x94\x14\x18\x56\x83\x58\x08\x04\x71\x80\x8a\x53\xbe\xb6\xc4\x69\x3f\xb5\xbe\x32\x1f\x84\x3a\xd8\xdc\x75\x8d\x05\x3d\xe1\xf5\xf1\xb8\xb5\x54\xc0\x44\xb2\x78\x1d\x70\x84\x96\x27\x13\xa0\x4c\xe9\x1f\x02\x13\x8b\x01\x04\x4c\x01\x87\x31\xa6\xe2\xaa\x48\x84\xa2\x21\x84\x16\x44\x14\xff\x48\x2e\xb2\x5e\xd4\xb4\xf0\x6f\xc2\x09\x17\x0a\xf9\xbe\xc5\xa9\x22\xd7\x17\x2b\x22\x34\x52\x4e\x64\x3d\x4e\x73\xd1\x07\x90\x06\x81\xbd\x27\x13\x7b\x72\x1b\x0c\x85\xc0\xd0\x36\xd0\xf1\xb2\xc5\xc2\x48\x38\x34\xb0\xf6\xd4\x7e\x92\x2c\x4d\xdf\x4e\x89\xe8\x91\xd8\x2c\xb4\x61\xa5\xb7\xd4\x86\x18\xe7\x5b\x2f\x35\xa1\x54\xa7\xd5\x67\x40\x00\x0e\x02\x6d\xab\x04\xd9\xb9\xc8\x48\x2f\xf1\xff\x18\xe7\xbd\x96\x8b\x70\x42\x2f\x27\xa8\xd5\x80\x89\xa8\x5e\x70\x57\x68\x47\x69\x4f\xb5\xf6\xfa\x3a\x34\x3a\x1b\x8a\x3d\x43\x44\x5b\xe9\xc2\x06\xc4\x22\x34\x83\xc5\x76\xfd\xbe\x25\x69\xa9\xa0\x0d\xbe\xd8\x54\x04\xc1\x3a\xf4\x22\x64\x23\x99\x74\x3a\x85\xa4\xa2\x61\x9b\x37\xf4\xe9\xe4\xc9\x94\x67\x54\x66\x9c\x26\xd0\xf9\xb3\xb1\x33\x0c\xf0\xbc\xcb\x3e\x3a\x76\x71\x3c\x9b\x5e\x1d\xd0\x1f\xbb\xb3\xda\x9d\xd0\x2e\x69\xab\x52\x21\x81\x12\x58\x85\x40\x24\x0c\x30\xc3\xd2\x62\x40\x31\x71\x9e\x7e\x9e\xd3\x67\x9a\x05\x48\x56\x07\x4b\x5c\xc0\xcc\x6a\xa4\xf3\xe3\x68\xa0\x44\x9b\xbc\x82\x2e\x79\x0d\x35\x04\x2c\xa5\x05\x5d\x4a\x03\x95\x85\x02\x9d\xa4\xdb\x32\x08\x12\x3c\x8d\xb1\x71\x9b\xb8\x02\xbb\xb2\x2a\x0b\x65\xd6\xee\xf6\x84\x81\x33\x47\x7d\x3b\xec\xe4\xdc\xcb\x0d\xb6\x5b\xce\x5b\x0f\x52\xf5\x36\x04\x23\xa3\x9c\x75\x71\xe9\x1b\x29\xab\x97\xca\x2f\xa6\xdb\x95\x0f\xac\xd8\xb7\xa8\x69\x6c\x44\x1b\x89\xc0\x1b\xb1\x16\x13\x28\x57\xd0\x18\x41\xd2\xb1\x42\x23\xc8\x98\xa2\x19\xa9\x33\xce\x74\x05\x10\x28\x17\x80\x37\x52\x98\x6e\x3c\xd4\x4b\x9c\x89\x96\x46\xd1\x9b\x06\x86\x4d\xd8\x6f\x0e\xe0\xc4\x44\x77\x83\x57\x17\xbd\x88\x26\x38\x38\x81\x5a\x0d\xa5\xdf\xc2\xce\x40\x4e\xa0\x96\x19\xf8\x9d\x53\xc5\xc9\xd5\x0b\x03\x0c\xa8\x05\x18\x70\xf4\x8a\x95\x9d\xe1\xa3\xc5\x04\x20\x2f\xc6\x57\x25\x8d\x3f\x43\xb5\x8d\x13\x3a\xec\x18\xa3\x45\x04\x90\xe6\x5f\x68\x59\xd3\x0d\xd0\xfb\x24\x8b\xef\xe2\x3a\x2d\x72\xb8\x8b\xcb\xcf\xed\x21\xf9\xd0\x87\x24\x5a\x10\x80\x84\xe6\x35\x54\xe9\x4d\xae\x7d\xf6\x21\x55\xe6\x89\x57\x7c\xe6\x74\x53\x80\x6d\xb1\xcb\x37\x9a\x90\xa9\x13\x2c\x88\x4e\xba\x53\x52\xc4\x33\x80\x64\x57\x96\x34\x4f\x1e\x4c\xc1\xdf\x4e\x9f\xfc\xb5\xf7\x49\x64\xf4\x96\x76\x0e\xf0\x40\x73\x4d\xa6\x00\xd2\x48\xf4\x8e\xc7\xa1\xec\x36\x3a\xd1\x0b\x80\xab\xb2\xf8\x4c\x73\xb8\x8a\xcb\x16\x1a\x9f\x34\x34\xa2\xc5\x25\x40\x45\x13\x61\xb3\x94\xd9\x9e\x8e\x40\xf7\x69\x9c\x6c\x09\xb0\x49\x63\x5a\xd2\x2a\xad\xda\x88\x74\xc7\xa3\xdd\x6f\x05\x90\x14\xdb\x87\x32\xbd\xb9\xad\x5b\x81\x5c\x58\x32\xea\x83\x2c\xba\x9c\x00\x5c\xd3\xbb\x34\x4f\x73\x0a\x45\xb9\x49\xf3\x38\x83\x34\xdf\xa4\x49\x5c\x17\xa5\x85\x91\xb1\xb2\x4b\x31\x46\x00\x19\xbd\xae\xc7\xdb\x22\xcd\xeb\x34\xbf\x81\x4d\xb1\xbb\xca\x28\xc4\xf9\x4d\x46\xe1\xaf\x5d\x51\x1b\x51\x14\xc0\x09\x45\x77\xd6\xd5\x89\xe8\x92\x70\x78\x58\x81\xd4\xdd\xc4\x87\xb9\xd5\x14\xa0\x2a\xae\x6b\xb8\x7d\xd8\xde\xd2\x5c\x78\x90\x99\x05\x22\xba\x9c\x01\x94\xf4\x26\xad\x6a\x5a\xd2\x8d\x65\x73\x89\xd8\x3c\x07\xb8\x8b\x93\xb2\xc8\x55\xa5\xb3\xaa\x10\x27\x58\x00\x6c\xe8\x4d\x49\xa9\x14\x55\x74\x9b\xe9\x0d\x2f\x01\xb6\xd9\xae\x1a\xdf\xa5\xf9\xae\xb2\x0c\x50\x47\x9c\x99\x06\x2c\x01\xaa\xdd\x96\x96\x55\x52\xa6\xdb\x1a\xea\xaf\x85\x47\xc4\x7a\xfb\xe2\x54\xab\x1e\xd5\x6d\x49\xa9\x37\x1d\xec\xbd\x9c\x00\xc4\xc9\xae\xa6\x10\x27\xfc\x1c\xe8\x56\xd6\x24\x89\x00\xee\xd2\xa4\x2c\x0c\x8c\xf6\x9b\xbc\x50\x25\x83\x68\x49\x00\xb6\x69\x96\x94\xc5\x57\xed\x39\x81\x3f\x79\x69\xfb\x30\x23\xb1\x9c\x72\xb9\x9b\x4d\x46\x61\x53\xd4\xe6\xdd\x45\x6f\xcc\x8f\x11\xdd\xa4\x59\x16\x9b\x2a\x79\x95\x88\xf7\x72\x6e\x5b\x58\xe4\xd4\x8b\x86\xca\x2f\x78\x78\xaa\x64\x97\xb9\x30\xd9\xa5\x27\x1b\x93\xcb\x4b\x00\x81\xfa\xff\x13\x94\xa2\x0e\x34\x1a\x99\x5a\xc8\x12\xe0\xcb\x2e\xbb\x89\x4b\xb8\x2e\x63\x79\x2a\x8b\x9c\x33\xc7\x65\x4d\x4b\x09\xe5\x48\x34\x47\x33\x83\x6b\x85\x73\xdd\xc6\xd9\xb5\xc9\x42\x3a\x96\xd5\x64\xc8\x22\x62\xae\xb7\xaa\x24\xe3\xb4\xbf\xd7\xca\x4c\x98\x7f\xed\x68\xd5\x33\x49\x64\x06\xa3\xe9\x89\x56\x04\x20\x8b\xeb\x34\x87\x24\xde\xa6\x75\x9c\x41\x46\xeb\x9a\x96\x10\xc3\xd7\xb4\xbe\x85\x9b\x32\xfe\x42\x3d\x50\xfd\x2c\x5a\x70\xa2\xd5\xf4\xbc\x0c\x81\x48\x9e\x64\x43\x67\xd1\x8a\x56\xb3\xf3\x32\x92\xb4\x4c\x76\x77\xd7\x19\xbd\xf7\x00\x64\xaf\xe8\x10\x34\x3f\x2f\xa8\x4e\xb3\x0d\xe5\x97\xf6\x73\xca\x2c\xce\xcb\xe8\x52\xed\xd9\x4a\x1c\xad\x2e\xcf\xcb\x29\x39\x0c\xe3\xab\x42\x78\xb8\x38\xe7\xe1\xa5\x4b\x10\x95\xf7\x51\xa6\x94\x10\xf8\x0f\x21\x6c\x2f\x7f\x1a\xff\xab\x95\x43\x42\xa2\xfc\xab\x4e\x26\x7e\xfd\xac\xa4\x1e\x64\x32\x71\x48\xa1\x16\x5a\x58\xe3\xbe\x88\x92\x49\x74\x5e\x86\x42\x8b\x9c\xfd\xb8\x64\xb8\x50\x4b\x87\x68\x61\x12\x2d\x0e\x41\x2e\xe8\x52\x57\xa4\x1d\x72\x5c\xf0\x4d\x31\xc7\xa0\xb7\x65\x32\x71\x21\x37\xc5\x1c\xe3\x90\xe1\x42\x6e\xea\x74\x8c\x43\x90\x0b\xba\xa9\xcb\x31\x7d\x39\x0a\x31\x2e\xe4\xd2\xfa\x56\x77\x88\x4c\x0f\x42\x2c\xd0\x93\x89\x0b\xb2\xb9\x75\x92\xf5\x51\x76\x5d\xf8\x49\xe4\x02\x6d\x81\xa6\x38\xac\x6d\x26\x91\x0b\xb4\x05\x9a\xe2\x70\x19\x2e\xd0\x16\xee\x14\x87\x0b\x72\x81\xb6\x40\x53\x1c\x2e\xc3\x05\xd8\xc2\x99\xe2\x70\x39\xbc\x61\xda\x65\x75\xba\xcd\x78\x0d\x6e\xfb\x54\x4e\x74\x6f\xd6\x7f\x12\xb9\xa0\xa9\x76\xac\x6a\xde\x08\x77\x09\x48\xce\x77\xc2\xde\x76\x2e\x58\xee\xf0\x58\x22\x53\x13\x12\xb9\x20\xb9\xb3\x63\x09\xa1\xef\x96\xe1\xc2\xe6\xee\x4c\x2c\x31\x41\xc4\x05\xce\xdd\x20\x0e\xff\xeb\xea\x46\x88\x0b\xa4\x0f\x96\x61\x82\x1b\x19\xed\x10\xe2\x02\x68\x7d\x5b\x94\x79\x6f\x96\xd2\x1b\x21\x12\xd2\x82\xb2\xba\x8b\xb3\x96\xb5\xba\x8d\xcb\x2d\x54\xdd\x08\x4c\x0f\x1d\xba\xfb\xa0\x3a\xa6\x64\x86\x0a\xb0\xfb\x90\x46\x0d\x30\xfa\x77\x4d\x42\xe6\xe7\xb8\x4d\xcb\x51\xee\xc5\x39\x6e\x33\x98\x32\x96\x98\x88\xcb\x73\x22\xe4\x91\x54\x27\x12\xe3\x5e\x9e\xe3\x1e\x5c\xed\x30\x09\xab\x73\x12\xcc\x4e\xa3\x70\x79\x61\x3a\xc1\x45\x50\xe3\x47\x19\x3d\x3c\x02\xd6\x0e\xc1\xf4\x18\x8c\x4c\x23\x94\xbf\xdf\x61\xf8\xf6\xf0\xad\x92\x7b\x13\x94\x97\xf6\xa3\xef\x1c\xc2\x91\x29\x0e\x40\xbb\xab\xd0\x7d\x15\x2e\x01\x47\x20\xd2\x53\xe8\x9f\x7c\x98\x1a\x61\xdb\x62\x70\x28\x22\x1d\x85\xba\xa7\xe3\x52\x70\x48\x5a\xfd\x84\xaf\xc6\xa1\x22\x88\xd2\x8d\x38\x0a\xad\x0e\xc2\x57\x3f\x86\x18\x5c\x38\xfa\x90\x9e\xc1\xd7\x93\x5a\x63\xae\x48\xa6\x38\xf4\x86\x9d\x82\xb8\x14\x9e\x7a\xdc\x33\x1c\x75\xa2\x3f\x80\x7b\x1f\x19\xc9\x6a\x46\x1c\x6e\x39\x76\xe2\xfc\xfe\x48\x93\xcc\x70\xc0\x15\x58\xba\x19\xcc\xbc\xc8\x0c\x07\x5b\x81\xa5\x1b\x84\x1b\x07\x1a\xd2\x07\xa8\x74\x63\x8a\x90\xf0\x98\xe1\x20\x2b\x5c\xc6\xf7\x14\xc0\xc1\x35\xa8\xfd\xce\xa1\x1f\x99\x5d\x02\x6c\xd2\x2f\x69\xd5\x4d\xa6\xc4\x74\x5a\xdd\xba\x4f\xc6\x50\x85\xcc\x70\x78\xf5\xeb\xbe\xe1\xad\xd0\xda\x0a\x87\xd7\x0e\x89\xd4\x70\x08\x49\xe6\x38\xbc\x76\xfd\xb4\xe0\xe0\xc6\x31\x86\x54\x79\xd5\x4c\x23\x22\x70\xa0\x0d\xea\xbb\x73\x8e\x4a\xe6\x38\xd8\x1e\xd0\xcc\xd6\x8e\xc3\x8d\x41\x35\x99\xe3\x80\x93\x75\xbd\x1d\x6e\xcb\xec\x6a\x96\x77\xce\x8a\x03\xed\x01\x53\xdf\xa9\x80\xfe\xfb\x6f\x00\x00\x00\xff\xff\xa7\x48\xc0\xee\xe6\x20\x00\x00")
+
+func fontsWavyFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsWavyFlf,
+ "fonts/wavy.flf",
+ )
+}
+
+func fontsWavyFlf() (*asset, error) {
+ bytes, err := fontsWavyFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/wavy.flf", size: 8422, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+var _fontsWeirdFlf = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x57\x4f\x8f\xa3\xb8\x17\xbc\xfb\x53\x94\xfa\xc7\x4f\x49\x66\x1a\x3c\x3d\xa3\x9e\x43\x9f\xd0\x4a\x7b\x5c\xad\xb4\xb7\x95\x90\x1c\x07\x4c\x60\x9b\x3f\x2d\x20\xdb\xdd\x92\x3f\xfc\x0a\x3f\x07\x42\x62\x02\x73\x08\x0e\x50\x2e\xbf\x57\xcf\x2e\x9b\xb4\x48\xbf\x4b\x0f\x3f\xf1\x8c\xa7\x6f\xf8\x86\xa7\x1f\xec\x5d\xe5\x4d\x12\xa4\x45\x8a\xed\xbf\xaa\x69\xf3\xba\xc2\xf7\x1d\x3b\x7c\xbe\x00\xbf\xc9\x16\x7f\xa8\xfc\x1f\xd5\x00\x28\xcd\x9f\x30\xaf\xd2\x3a\x78\xcf\xab\xa0\x3b\xa9\xa0\x2a\x00\x1c\x64\x1b\x26\xb2\x54\xaf\xc1\x6b\x97\x05\xad\x62\x69\xfe\xa1\x12\xf4\x0c\x7f\x7d\xca\x0a\x7f\xd7\xa7\xf8\x15\xc0\x67\xdf\x86\x71\x1b\x9c\x1a\x75\xcc\x2b\x19\xc4\x92\xb5\x75\xa9\xd0\xbe\xa9\x38\x97\x05\xe2\x4c\x36\x32\xee\x54\xd3\x62\xf3\xbf\xff\x7f\xd9\x40\x75\x71\x00\xd9\x28\x54\x75\x87\x52\x76\x71\x96\x57\xc7\x47\x74\x99\xfa\x34\x8f\xd3\xa6\x2e\x51\x77\x99\x6a\x90\xd6\x55\xd7\x06\xec\xf7\x8f\xb7\x42\x56\xb2\xeb\xb3\xa8\x53\xa4\x79\xd3\x76\x28\xf2\x4a\xbd\xb0\x3e\x75\xf8\x78\x28\xe5\x31\x8f\x51\x9d\xca\x83\x6a\x1e\x90\xd6\x0d\xd2\xbc\x50\xc8\x13\x55\x75\x79\x9a\xc7\xa6\x33\x93\x00\xe0\xa3\xcd\xea\x53\x91\x40\x16\xef\xf2\xb3\xc5\x41\x61\x2f\x37\x8f\xa6\x53\x55\xbf\x33\x8f\x40\x5d\xa6\xf0\x90\xc9\x26\x39\x14\xb2\x7a\x7d\x80\xef\xe3\xad\xc9\xab\xae\x85\x6c\x21\x61\x9e\x3e\xe2\x70\xea\x10\xcb\x6a\xd3\xf5\x34\x6d\x79\x6a\x33\x95\xb0\x9f\xc4\x90\xa9\xfc\x98\x75\x7d\xc4\x72\x54\x81\x3d\xdf\x79\xf9\x68\x34\xc9\xab\xb8\x38\x25\x79\x75\x44\xa2\xda\x58\x55\x89\x6a\x5a\xf6\xfd\x9b\xe9\x56\xca\x0f\x93\x39\x0a\x55\x1d\xbb\x0c\x5b\xf5\x71\x06\xc7\x75\x59\xaa\x8a\x84\x69\x77\xf8\x0a\x89\xf4\x94\x1c\x15\x52\x19\x77\x75\xc3\x9e\x9e\x0d\x43\xa2\x52\x79\x2a\x3a\x0a\xb6\xac\x13\x65\x12\xef\xb2\xbc\x35\x72\x63\x5b\xe4\xaf\x0a\x0f\x7e\x89\xa7\xe7\x07\xd4\x95\xe1\x95\x55\x62\x78\x77\xec\xe9\x87\x61\x21\xa5\xfb\xf0\x27\xc3\x1a\xf1\xbc\x70\x45\x13\xb2\x5e\x07\xf4\xb7\xdc\x3c\xdd\xd2\x4b\x4d\x8d\x30\x0d\x41\xa8\x0d\x99\xc7\x39\x75\xbf\xbc\xc2\xbe\x1d\xf8\x10\x20\x40\xc8\xfc\xaf\xfe\x57\x7f\x68\xb0\xc7\x1e\x23\x9f\x87\x47\xd1\x77\xe7\x1a\x3a\x64\x5b\xa1\x85\x19\x4c\x63\x17\x32\x2d\x34\x0d\xb3\x1f\xa2\x0c\x59\x0d\x70\x13\xaa\xe9\xd5\x0f\xcd\x81\xfa\x62\x68\x41\x01\x42\x7b\x3d\x9f\xb0\xb8\xc8\xf0\x09\x1e\x4d\x52\xe9\x5f\x99\x11\xc6\x0b\xc5\x66\x5e\x87\xac\x1f\x4a\x63\xfc\x21\xb2\x2f\xa2\xfe\x46\x8f\x3f\x3e\x10\x9a\x4b\xa0\x83\x90\xf9\x5f\xfc\x90\x6d\xf4\x7e\x24\x1c\x24\x62\xd0\x20\x65\x86\xff\x53\x7d\xa7\xca\x0e\x57\x7e\x55\x2f\x5b\x21\x21\x6e\x4a\x8b\x55\x7c\x3e\x2e\x94\x85\x51\x16\xe0\x26\xf1\xfe\x09\x9f\x16\x55\x08\x52\xd6\x54\x0a\xa6\xd1\x00\xac\xb2\x93\x41\x6d\x11\x74\x3f\xc8\x16\x9a\x46\x34\x45\xf5\xa8\xa8\xb8\x65\xdd\x19\x56\xaa\x07\x37\x50\x7e\xcd\x2a\x6c\xd6\x9a\xb2\xd6\x74\x67\x58\xaf\xa0\xb6\xb8\x14\xeb\x14\x4a\x63\x38\x02\xf0\x4c\x22\x67\x2d\x5d\xac\x97\xd0\x2d\x41\x67\x15\xb8\x15\x6b\x31\x80\x31\xd6\x55\xac\x4b\x0a\x0c\xb5\x16\x17\x75\xf7\xcf\xb3\xe3\x1e\x88\x4f\x40\xfd\x83\x90\xf5\xec\x51\xff\xd2\x2c\x21\xea\xed\x9d\xaf\xa4\x05\x5d\x2f\x9e\xdb\xc5\x62\x7b\x9d\x59\xdc\x0a\x51\x2e\xdc\xe9\x39\x53\xe8\x9f\x82\x93\x42\xde\x3a\x85\xce\x62\x3a\x75\xd7\x04\xd5\x2b\x75\xf7\xa8\x9a\x4b\x85\x3f\xb3\x2e\xac\x12\xf7\x74\xa2\xb4\xae\x15\x10\x73\xd0\xeb\x05\x3f\x8d\xf5\xee\x24\x75\xac\x92\x39\xb1\xa8\x7c\xdb\x9e\xcc\xfe\x26\xa6\xe6\xe9\x8b\xeb\x2e\x64\x18\x46\x9a\x1d\x28\xb2\xe1\x47\xd7\x7e\xb5\x5a\x6a\x0b\xd5\xdc\x4c\x0b\x8e\x3b\xe1\x9f\xa1\x34\x83\x34\x41\x69\x97\xc1\x9c\x21\xad\xb0\x39\xf7\x64\xbb\x5b\x95\x09\xab\x73\x5b\x72\xb1\xce\x88\xe5\x98\x41\xf3\xde\x65\x04\x20\x43\x26\x3f\x1e\xae\xee\x3a\xdd\xcf\xdd\x01\xf5\x22\x6b\x70\xd1\x22\x54\x93\xc5\x6b\xae\xdd\x50\x6e\x12\xe2\x74\x36\x30\xac\x7c\xa6\xa4\x6b\xbc\xf0\x2c\x93\x61\xb5\x1e\x63\x59\xaf\xa0\x62\xdc\xec\x5f\x6c\xbb\xf7\x87\x79\x1e\xd1\x6c\x8f\x68\xce\x47\xb4\x39\x46\x83\x7e\xe2\xf2\x54\xf0\x42\xad\xbf\x31\xb4\x66\x37\x8d\x2e\x8f\x1a\xb8\x3c\x6a\x0c\x1b\x2d\xe6\x8e\x6a\xbe\xef\x7b\xc3\xa1\x25\x9a\x3f\xb4\x4c\x98\x6e\xb6\x28\xed\x14\x10\x8b\xbb\xd9\x0c\xab\xcb\xa9\x06\xe8\xb8\x49\xff\x0a\xab\x10\x62\xe7\xf4\xbf\x5b\x57\x98\xc4\xb1\x18\xeb\x18\x80\x10\x7c\x59\x01\xb7\xff\x79\x2e\xff\x23\x03\x04\x79\x1f\xc5\xe2\xf5\x1c\x80\x77\x67\xb8\x31\x89\x9d\x63\x61\xdf\xb1\xdb\xcb\xec\x40\x21\xeb\x79\xcf\x73\x0b\xf1\x0b\xd0\x95\x53\x61\x84\xea\x95\x50\x7d\x9e\x26\x8b\xb1\x2e\xd7\xd7\x5a\xdf\xac\x47\x61\x71\x83\x75\xac\xc0\x55\x0a\xd8\xe5\x79\xcf\xf9\xdc\xac\x7c\x19\x3a\x1a\xe0\x22\x34\xb2\xce\x17\xd9\x58\xf9\xbc\x58\x56\x25\x7e\xb3\xc4\xcc\x37\x5f\xc8\x84\xf9\xd2\xe9\xdd\xcf\xdc\x82\xfc\xcf\xce\xc2\xc9\x8c\xf4\x8c\xe7\x19\xd3\xeb\x6f\xb5\xb0\xfd\xcc\xad\xbf\x21\x43\x05\x7d\x49\x44\x82\xbb\xbf\x51\x86\x08\x3c\x5f\x08\x7f\xdd\x71\xe4\x0a\x7a\x6f\xa3\xf2\x7c\x60\x25\x74\xaa\xa8\x2f\xcc\x18\xf7\xcd\x73\x0e\x3a\xcf\x0a\xf8\x6b\x0f\x8f\x2e\xf3\xd4\xf6\x5c\xfd\x5f\x00\x00\x00\xff\xff\xa0\x78\x63\x55\x69\x12\x00\x00")
+
+func fontsWeirdFlfBytes() ([]byte, error) {
+ return bindataRead(
+ _fontsWeirdFlf,
+ "fonts/weird.flf",
+ )
+}
+
+func fontsWeirdFlf() (*asset, error) {
+ bytes, err := fontsWeirdFlfBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "fonts/weird.flf", size: 4713, mode: os.FileMode(436), modTime: time.Unix(1529341546, 0)}
+ a := &asset{bytes: bytes, info: info}
+ return a, nil
+}
+
+// Asset loads and returns the asset for the given name.
+// It returns an error if the asset could not be found or
+// could not be loaded.
+func Asset(name string) ([]byte, error) {
+ cannonicalName := strings.Replace(name, "\\", "/", -1)
+ if f, ok := _bindata[cannonicalName]; ok {
+ a, err := f()
+ if err != nil {
+ return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
+ }
+ return a.bytes, nil
+ }
+ return nil, fmt.Errorf("Asset %s not found", name)
+}
+
+// MustAsset is like Asset but panics when Asset would return an error.
+// It simplifies safe initialization of global variables.
+func MustAsset(name string) []byte {
+ a, err := Asset(name)
+ if err != nil {
+ panic("asset: Asset(" + name + "): " + err.Error())
+ }
+
+ return a
+}
+
+// AssetInfo loads and returns the asset info for the given name.
+// It returns an error if the asset could not be found or
+// could not be loaded.
+func AssetInfo(name string) (os.FileInfo, error) {
+ cannonicalName := strings.Replace(name, "\\", "/", -1)
+ if f, ok := _bindata[cannonicalName]; ok {
+ a, err := f()
+ if err != nil {
+ return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
+ }
+ return a.info, nil
+ }
+ return nil, fmt.Errorf("AssetInfo %s not found", name)
+}
+
+// AssetNames returns the names of the assets.
+func AssetNames() []string {
+ names := make([]string, 0, len(_bindata))
+ for name := range _bindata {
+ names = append(names, name)
+ }
+ return names
+}
+
+// _bindata is a table, holding each asset generator, mapped to its name.
+var _bindata = map[string]func() (*asset, error){
+ "fonts/3-d.flf": fonts3DFlf,
+ "fonts/3x5.flf": fonts3x5Flf,
+ "fonts/5lineoblique.flf": fonts5lineobliqueFlf,
+ "fonts/acrobatic.flf": fontsAcrobaticFlf,
+ "fonts/alligator.flf": fontsAlligatorFlf,
+ "fonts/alligator2.flf": fontsAlligator2Flf,
+ "fonts/alphabet.flf": fontsAlphabetFlf,
+ "fonts/avatar.flf": fontsAvatarFlf,
+ "fonts/banner.flf": fontsBannerFlf,
+ "fonts/banner3-D.flf": fontsBanner3DFlf,
+ "fonts/banner3.flf": fontsBanner3Flf,
+ "fonts/banner4.flf": fontsBanner4Flf,
+ "fonts/barbwire.flf": fontsBarbwireFlf,
+ "fonts/basic.flf": fontsBasicFlf,
+ "fonts/bell.flf": fontsBellFlf,
+ "fonts/big.flf": fontsBigFlf,
+ "fonts/bigchief.flf": fontsBigchiefFlf,
+ "fonts/binary.flf": fontsBinaryFlf,
+ "fonts/block.flf": fontsBlockFlf,
+ "fonts/bubble.flf": fontsBubbleFlf,
+ "fonts/bulbhead.flf": fontsBulbheadFlf,
+ "fonts/calgphy2.flf": fontsCalgphy2Flf,
+ "fonts/caligraphy.flf": fontsCaligraphyFlf,
+ "fonts/catwalk.flf": fontsCatwalkFlf,
+ "fonts/chunky.flf": fontsChunkyFlf,
+ "fonts/coinstak.flf": fontsCoinstakFlf,
+ "fonts/colossal.flf": fontsColossalFlf,
+ "fonts/computer.flf": fontsComputerFlf,
+ "fonts/contessa.flf": fontsContessaFlf,
+ "fonts/contrast.flf": fontsContrastFlf,
+ "fonts/cosmic.flf": fontsCosmicFlf,
+ "fonts/cosmike.flf": fontsCosmikeFlf,
+ "fonts/cricket.flf": fontsCricketFlf,
+ "fonts/cursive.flf": fontsCursiveFlf,
+ "fonts/cyberlarge.flf": fontsCyberlargeFlf,
+ "fonts/cybermedium.flf": fontsCybermediumFlf,
+ "fonts/cybersmall.flf": fontsCybersmallFlf,
+ "fonts/diamond.flf": fontsDiamondFlf,
+ "fonts/digital.flf": fontsDigitalFlf,
+ "fonts/doh.flf": fontsDohFlf,
+ "fonts/doom.flf": fontsDoomFlf,
+ "fonts/dotmatrix.flf": fontsDotmatrixFlf,
+ "fonts/drpepper.flf": fontsDrpepperFlf,
+ "fonts/eftichess.flf": fontsEftichessFlf,
+ "fonts/eftifont.flf": fontsEftifontFlf,
+ "fonts/eftipiti.flf": fontsEftipitiFlf,
+ "fonts/eftirobot.flf": fontsEftirobotFlf,
+ "fonts/eftitalic.flf": fontsEftitalicFlf,
+ "fonts/eftiwall.flf": fontsEftiwallFlf,
+ "fonts/eftiwater.flf": fontsEftiwaterFlf,
+ "fonts/elite.flf": fontsEliteFlf,
+ "fonts/epic.flf": fontsEpicFlf,
+ "fonts/fender.flf": fontsFenderFlf,
+ "fonts/fourtops.flf": fontsFourtopsFlf,
+ "fonts/fuzzy.flf": fontsFuzzyFlf,
+ "fonts/goofy.flf": fontsGoofyFlf,
+ "fonts/gothic.flf": fontsGothicFlf,
+ "fonts/graffiti.flf": fontsGraffitiFlf,
+ "fonts/hollywood.flf": fontsHollywoodFlf,
+ "fonts/invita.flf": fontsInvitaFlf,
+ "fonts/isometric1.flf": fontsIsometric1Flf,
+ "fonts/isometric2.flf": fontsIsometric2Flf,
+ "fonts/isometric3.flf": fontsIsometric3Flf,
+ "fonts/isometric4.flf": fontsIsometric4Flf,
+ "fonts/italic.flf": fontsItalicFlf,
+ "fonts/ivrit.flf": fontsIvritFlf,
+ "fonts/jazmine.flf": fontsJazmineFlf,
+ "fonts/jerusalem.flf": fontsJerusalemFlf,
+ "fonts/katakana.flf": fontsKatakanaFlf,
+ "fonts/kban.flf": fontsKbanFlf,
+ "fonts/larry3d.flf": fontsLarry3dFlf,
+ "fonts/lcd.flf": fontsLcdFlf,
+ "fonts/lean.flf": fontsLeanFlf,
+ "fonts/letters.flf": fontsLettersFlf,
+ "fonts/linux.flf": fontsLinuxFlf,
+ "fonts/lockergnome.flf": fontsLockergnomeFlf,
+ "fonts/madrid.flf": fontsMadridFlf,
+ "fonts/marquee.flf": fontsMarqueeFlf,
+ "fonts/maxfour.flf": fontsMaxfourFlf,
+ "fonts/mike.flf": fontsMikeFlf,
+ "fonts/mini.flf": fontsMiniFlf,
+ "fonts/mirror.flf": fontsMirrorFlf,
+ "fonts/mnemonic.flf": fontsMnemonicFlf,
+ "fonts/morse.flf": fontsMorseFlf,
+ "fonts/moscow.flf": fontsMoscowFlf,
+ "fonts/nancyj-fancy.flf": fontsNancyjFancyFlf,
+ "fonts/nancyj-underlined.flf": fontsNancyjUnderlinedFlf,
+ "fonts/nancyj.flf": fontsNancyjFlf,
+ "fonts/nipples.flf": fontsNipplesFlf,
+ "fonts/ntgreek.flf": fontsNtgreekFlf,
+ "fonts/o8.flf": fontsO8Flf,
+ "fonts/ogre.flf": fontsOgreFlf,
+ "fonts/pawp.flf": fontsPawpFlf,
+ "fonts/peaks.flf": fontsPeaksFlf,
+ "fonts/pebbles.flf": fontsPebblesFlf,
+ "fonts/pepper.flf": fontsPepperFlf,
+ "fonts/poison.flf": fontsPoisonFlf,
+ "fonts/puffy.flf": fontsPuffyFlf,
+ "fonts/pyramid.flf": fontsPyramidFlf,
+ "fonts/rectangles.flf": fontsRectanglesFlf,
+ "fonts/relief.flf": fontsReliefFlf,
+ "fonts/relief2.flf": fontsRelief2Flf,
+ "fonts/rev.flf": fontsRevFlf,
+ "fonts/roman.flf": fontsRomanFlf,
+ "fonts/rot13.flf": fontsRot13Flf,
+ "fonts/rounded.flf": fontsRoundedFlf,
+ "fonts/rowancap.flf": fontsRowancapFlf,
+ "fonts/rozzo.flf": fontsRozzoFlf,
+ "fonts/runic.flf": fontsRunicFlf,
+ "fonts/runyc.flf": fontsRunycFlf,
+ "fonts/sblood.flf": fontsSbloodFlf,
+ "fonts/script.flf": fontsScriptFlf,
+ "fonts/serifcap.flf": fontsSerifcapFlf,
+ "fonts/shadow.flf": fontsShadowFlf,
+ "fonts/short.flf": fontsShortFlf,
+ "fonts/slant.flf": fontsSlantFlf,
+ "fonts/slide.flf": fontsSlideFlf,
+ "fonts/slscript.flf": fontsSlscriptFlf,
+ "fonts/small.flf": fontsSmallFlf,
+ "fonts/smisome1.flf": fontsSmisome1Flf,
+ "fonts/smkeyboard.flf": fontsSmkeyboardFlf,
+ "fonts/smscript.flf": fontsSmscriptFlf,
+ "fonts/smshadow.flf": fontsSmshadowFlf,
+ "fonts/smslant.flf": fontsSmslantFlf,
+ "fonts/smtengwar.flf": fontsSmtengwarFlf,
+ "fonts/speed.flf": fontsSpeedFlf,
+ "fonts/stampatello.flf": fontsStampatelloFlf,
+ "fonts/standard.flf": fontsStandardFlf,
+ "fonts/starwars.flf": fontsStarwarsFlf,
+ "fonts/stellar.flf": fontsStellarFlf,
+ "fonts/stop.flf": fontsStopFlf,
+ "fonts/straight.flf": fontsStraightFlf,
+ "fonts/tanja.flf": fontsTanjaFlf,
+ "fonts/tengwar.flf": fontsTengwarFlf,
+ "fonts/term.flf": fontsTermFlf,
+ "fonts/thick.flf": fontsThickFlf,
+ "fonts/thin.flf": fontsThinFlf,
+ "fonts/threepoint.flf": fontsThreepointFlf,
+ "fonts/ticks.flf": fontsTicksFlf,
+ "fonts/ticksslant.flf": fontsTicksslantFlf,
+ "fonts/tinker-toy.flf": fontsTinkerToyFlf,
+ "fonts/tombstone.flf": fontsTombstoneFlf,
+ "fonts/trek.flf": fontsTrekFlf,
+ "fonts/tsalagi.flf": fontsTsalagiFlf,
+ "fonts/twopoint.flf": fontsTwopointFlf,
+ "fonts/univers.flf": fontsUniversFlf,
+ "fonts/usaflag.flf": fontsUsaflagFlf,
+ "fonts/wavy.flf": fontsWavyFlf,
+ "fonts/weird.flf": fontsWeirdFlf,
+}
+
+// AssetDir returns the file names below a certain
+// directory embedded in the file by go-bindata.
+// For example if you run go-bindata on data/... and data contains the
+// following hierarchy:
+// data/
+// foo.txt
+// img/
+// a.png
+// b.png
+// then AssetDir("data") would return []string{"foo.txt", "img"}
+// AssetDir("data/img") would return []string{"a.png", "b.png"}
+// AssetDir("foo.txt") and AssetDir("notexist") would return an error
+// AssetDir("") will return []string{"data"}.
+func AssetDir(name string) ([]string, error) {
+ node := _bintree
+ if len(name) != 0 {
+ cannonicalName := strings.Replace(name, "\\", "/", -1)
+ pathList := strings.Split(cannonicalName, "/")
+ for _, p := range pathList {
+ node = node.Children[p]
+ if node == nil {
+ return nil, fmt.Errorf("Asset %s not found", name)
+ }
+ }
+ }
+ if node.Func != nil {
+ return nil, fmt.Errorf("Asset %s not found", name)
+ }
+ rv := make([]string, 0, len(node.Children))
+ for childName := range node.Children {
+ rv = append(rv, childName)
+ }
+ return rv, nil
+}
+
+type bintree struct {
+ Func func() (*asset, error)
+ Children map[string]*bintree
+}
+
+var _bintree = &bintree{nil, map[string]*bintree{
+ "fonts": &bintree{nil, map[string]*bintree{
+ "3-d.flf": &bintree{fonts3DFlf, map[string]*bintree{}},
+ "3x5.flf": &bintree{fonts3x5Flf, map[string]*bintree{}},
+ "5lineoblique.flf": &bintree{fonts5lineobliqueFlf, map[string]*bintree{}},
+ "acrobatic.flf": &bintree{fontsAcrobaticFlf, map[string]*bintree{}},
+ "alligator.flf": &bintree{fontsAlligatorFlf, map[string]*bintree{}},
+ "alligator2.flf": &bintree{fontsAlligator2Flf, map[string]*bintree{}},
+ "alphabet.flf": &bintree{fontsAlphabetFlf, map[string]*bintree{}},
+ "avatar.flf": &bintree{fontsAvatarFlf, map[string]*bintree{}},
+ "banner.flf": &bintree{fontsBannerFlf, map[string]*bintree{}},
+ "banner3-D.flf": &bintree{fontsBanner3DFlf, map[string]*bintree{}},
+ "banner3.flf": &bintree{fontsBanner3Flf, map[string]*bintree{}},
+ "banner4.flf": &bintree{fontsBanner4Flf, map[string]*bintree{}},
+ "barbwire.flf": &bintree{fontsBarbwireFlf, map[string]*bintree{}},
+ "basic.flf": &bintree{fontsBasicFlf, map[string]*bintree{}},
+ "bell.flf": &bintree{fontsBellFlf, map[string]*bintree{}},
+ "big.flf": &bintree{fontsBigFlf, map[string]*bintree{}},
+ "bigchief.flf": &bintree{fontsBigchiefFlf, map[string]*bintree{}},
+ "binary.flf": &bintree{fontsBinaryFlf, map[string]*bintree{}},
+ "block.flf": &bintree{fontsBlockFlf, map[string]*bintree{}},
+ "bubble.flf": &bintree{fontsBubbleFlf, map[string]*bintree{}},
+ "bulbhead.flf": &bintree{fontsBulbheadFlf, map[string]*bintree{}},
+ "calgphy2.flf": &bintree{fontsCalgphy2Flf, map[string]*bintree{}},
+ "caligraphy.flf": &bintree{fontsCaligraphyFlf, map[string]*bintree{}},
+ "catwalk.flf": &bintree{fontsCatwalkFlf, map[string]*bintree{}},
+ "chunky.flf": &bintree{fontsChunkyFlf, map[string]*bintree{}},
+ "coinstak.flf": &bintree{fontsCoinstakFlf, map[string]*bintree{}},
+ "colossal.flf": &bintree{fontsColossalFlf, map[string]*bintree{}},
+ "computer.flf": &bintree{fontsComputerFlf, map[string]*bintree{}},
+ "contessa.flf": &bintree{fontsContessaFlf, map[string]*bintree{}},
+ "contrast.flf": &bintree{fontsContrastFlf, map[string]*bintree{}},
+ "cosmic.flf": &bintree{fontsCosmicFlf, map[string]*bintree{}},
+ "cosmike.flf": &bintree{fontsCosmikeFlf, map[string]*bintree{}},
+ "cricket.flf": &bintree{fontsCricketFlf, map[string]*bintree{}},
+ "cursive.flf": &bintree{fontsCursiveFlf, map[string]*bintree{}},
+ "cyberlarge.flf": &bintree{fontsCyberlargeFlf, map[string]*bintree{}},
+ "cybermedium.flf": &bintree{fontsCybermediumFlf, map[string]*bintree{}},
+ "cybersmall.flf": &bintree{fontsCybersmallFlf, map[string]*bintree{}},
+ "diamond.flf": &bintree{fontsDiamondFlf, map[string]*bintree{}},
+ "digital.flf": &bintree{fontsDigitalFlf, map[string]*bintree{}},
+ "doh.flf": &bintree{fontsDohFlf, map[string]*bintree{}},
+ "doom.flf": &bintree{fontsDoomFlf, map[string]*bintree{}},
+ "dotmatrix.flf": &bintree{fontsDotmatrixFlf, map[string]*bintree{}},
+ "drpepper.flf": &bintree{fontsDrpepperFlf, map[string]*bintree{}},
+ "eftichess.flf": &bintree{fontsEftichessFlf, map[string]*bintree{}},
+ "eftifont.flf": &bintree{fontsEftifontFlf, map[string]*bintree{}},
+ "eftipiti.flf": &bintree{fontsEftipitiFlf, map[string]*bintree{}},
+ "eftirobot.flf": &bintree{fontsEftirobotFlf, map[string]*bintree{}},
+ "eftitalic.flf": &bintree{fontsEftitalicFlf, map[string]*bintree{}},
+ "eftiwall.flf": &bintree{fontsEftiwallFlf, map[string]*bintree{}},
+ "eftiwater.flf": &bintree{fontsEftiwaterFlf, map[string]*bintree{}},
+ "elite.flf": &bintree{fontsEliteFlf, map[string]*bintree{}},
+ "epic.flf": &bintree{fontsEpicFlf, map[string]*bintree{}},
+ "fender.flf": &bintree{fontsFenderFlf, map[string]*bintree{}},
+ "fourtops.flf": &bintree{fontsFourtopsFlf, map[string]*bintree{}},
+ "fuzzy.flf": &bintree{fontsFuzzyFlf, map[string]*bintree{}},
+ "goofy.flf": &bintree{fontsGoofyFlf, map[string]*bintree{}},
+ "gothic.flf": &bintree{fontsGothicFlf, map[string]*bintree{}},
+ "graffiti.flf": &bintree{fontsGraffitiFlf, map[string]*bintree{}},
+ "hollywood.flf": &bintree{fontsHollywoodFlf, map[string]*bintree{}},
+ "invita.flf": &bintree{fontsInvitaFlf, map[string]*bintree{}},
+ "isometric1.flf": &bintree{fontsIsometric1Flf, map[string]*bintree{}},
+ "isometric2.flf": &bintree{fontsIsometric2Flf, map[string]*bintree{}},
+ "isometric3.flf": &bintree{fontsIsometric3Flf, map[string]*bintree{}},
+ "isometric4.flf": &bintree{fontsIsometric4Flf, map[string]*bintree{}},
+ "italic.flf": &bintree{fontsItalicFlf, map[string]*bintree{}},
+ "ivrit.flf": &bintree{fontsIvritFlf, map[string]*bintree{}},
+ "jazmine.flf": &bintree{fontsJazmineFlf, map[string]*bintree{}},
+ "jerusalem.flf": &bintree{fontsJerusalemFlf, map[string]*bintree{}},
+ "katakana.flf": &bintree{fontsKatakanaFlf, map[string]*bintree{}},
+ "kban.flf": &bintree{fontsKbanFlf, map[string]*bintree{}},
+ "larry3d.flf": &bintree{fontsLarry3dFlf, map[string]*bintree{}},
+ "lcd.flf": &bintree{fontsLcdFlf, map[string]*bintree{}},
+ "lean.flf": &bintree{fontsLeanFlf, map[string]*bintree{}},
+ "letters.flf": &bintree{fontsLettersFlf, map[string]*bintree{}},
+ "linux.flf": &bintree{fontsLinuxFlf, map[string]*bintree{}},
+ "lockergnome.flf": &bintree{fontsLockergnomeFlf, map[string]*bintree{}},
+ "madrid.flf": &bintree{fontsMadridFlf, map[string]*bintree{}},
+ "marquee.flf": &bintree{fontsMarqueeFlf, map[string]*bintree{}},
+ "maxfour.flf": &bintree{fontsMaxfourFlf, map[string]*bintree{}},
+ "mike.flf": &bintree{fontsMikeFlf, map[string]*bintree{}},
+ "mini.flf": &bintree{fontsMiniFlf, map[string]*bintree{}},
+ "mirror.flf": &bintree{fontsMirrorFlf, map[string]*bintree{}},
+ "mnemonic.flf": &bintree{fontsMnemonicFlf, map[string]*bintree{}},
+ "morse.flf": &bintree{fontsMorseFlf, map[string]*bintree{}},
+ "moscow.flf": &bintree{fontsMoscowFlf, map[string]*bintree{}},
+ "nancyj-fancy.flf": &bintree{fontsNancyjFancyFlf, map[string]*bintree{}},
+ "nancyj-underlined.flf": &bintree{fontsNancyjUnderlinedFlf, map[string]*bintree{}},
+ "nancyj.flf": &bintree{fontsNancyjFlf, map[string]*bintree{}},
+ "nipples.flf": &bintree{fontsNipplesFlf, map[string]*bintree{}},
+ "ntgreek.flf": &bintree{fontsNtgreekFlf, map[string]*bintree{}},
+ "o8.flf": &bintree{fontsO8Flf, map[string]*bintree{}},
+ "ogre.flf": &bintree{fontsOgreFlf, map[string]*bintree{}},
+ "pawp.flf": &bintree{fontsPawpFlf, map[string]*bintree{}},
+ "peaks.flf": &bintree{fontsPeaksFlf, map[string]*bintree{}},
+ "pebbles.flf": &bintree{fontsPebblesFlf, map[string]*bintree{}},
+ "pepper.flf": &bintree{fontsPepperFlf, map[string]*bintree{}},
+ "poison.flf": &bintree{fontsPoisonFlf, map[string]*bintree{}},
+ "puffy.flf": &bintree{fontsPuffyFlf, map[string]*bintree{}},
+ "pyramid.flf": &bintree{fontsPyramidFlf, map[string]*bintree{}},
+ "rectangles.flf": &bintree{fontsRectanglesFlf, map[string]*bintree{}},
+ "relief.flf": &bintree{fontsReliefFlf, map[string]*bintree{}},
+ "relief2.flf": &bintree{fontsRelief2Flf, map[string]*bintree{}},
+ "rev.flf": &bintree{fontsRevFlf, map[string]*bintree{}},
+ "roman.flf": &bintree{fontsRomanFlf, map[string]*bintree{}},
+ "rot13.flf": &bintree{fontsRot13Flf, map[string]*bintree{}},
+ "rounded.flf": &bintree{fontsRoundedFlf, map[string]*bintree{}},
+ "rowancap.flf": &bintree{fontsRowancapFlf, map[string]*bintree{}},
+ "rozzo.flf": &bintree{fontsRozzoFlf, map[string]*bintree{}},
+ "runic.flf": &bintree{fontsRunicFlf, map[string]*bintree{}},
+ "runyc.flf": &bintree{fontsRunycFlf, map[string]*bintree{}},
+ "sblood.flf": &bintree{fontsSbloodFlf, map[string]*bintree{}},
+ "script.flf": &bintree{fontsScriptFlf, map[string]*bintree{}},
+ "serifcap.flf": &bintree{fontsSerifcapFlf, map[string]*bintree{}},
+ "shadow.flf": &bintree{fontsShadowFlf, map[string]*bintree{}},
+ "short.flf": &bintree{fontsShortFlf, map[string]*bintree{}},
+ "slant.flf": &bintree{fontsSlantFlf, map[string]*bintree{}},
+ "slide.flf": &bintree{fontsSlideFlf, map[string]*bintree{}},
+ "slscript.flf": &bintree{fontsSlscriptFlf, map[string]*bintree{}},
+ "small.flf": &bintree{fontsSmallFlf, map[string]*bintree{}},
+ "smisome1.flf": &bintree{fontsSmisome1Flf, map[string]*bintree{}},
+ "smkeyboard.flf": &bintree{fontsSmkeyboardFlf, map[string]*bintree{}},
+ "smscript.flf": &bintree{fontsSmscriptFlf, map[string]*bintree{}},
+ "smshadow.flf": &bintree{fontsSmshadowFlf, map[string]*bintree{}},
+ "smslant.flf": &bintree{fontsSmslantFlf, map[string]*bintree{}},
+ "smtengwar.flf": &bintree{fontsSmtengwarFlf, map[string]*bintree{}},
+ "speed.flf": &bintree{fontsSpeedFlf, map[string]*bintree{}},
+ "stampatello.flf": &bintree{fontsStampatelloFlf, map[string]*bintree{}},
+ "standard.flf": &bintree{fontsStandardFlf, map[string]*bintree{}},
+ "starwars.flf": &bintree{fontsStarwarsFlf, map[string]*bintree{}},
+ "stellar.flf": &bintree{fontsStellarFlf, map[string]*bintree{}},
+ "stop.flf": &bintree{fontsStopFlf, map[string]*bintree{}},
+ "straight.flf": &bintree{fontsStraightFlf, map[string]*bintree{}},
+ "tanja.flf": &bintree{fontsTanjaFlf, map[string]*bintree{}},
+ "tengwar.flf": &bintree{fontsTengwarFlf, map[string]*bintree{}},
+ "term.flf": &bintree{fontsTermFlf, map[string]*bintree{}},
+ "thick.flf": &bintree{fontsThickFlf, map[string]*bintree{}},
+ "thin.flf": &bintree{fontsThinFlf, map[string]*bintree{}},
+ "threepoint.flf": &bintree{fontsThreepointFlf, map[string]*bintree{}},
+ "ticks.flf": &bintree{fontsTicksFlf, map[string]*bintree{}},
+ "ticksslant.flf": &bintree{fontsTicksslantFlf, map[string]*bintree{}},
+ "tinker-toy.flf": &bintree{fontsTinkerToyFlf, map[string]*bintree{}},
+ "tombstone.flf": &bintree{fontsTombstoneFlf, map[string]*bintree{}},
+ "trek.flf": &bintree{fontsTrekFlf, map[string]*bintree{}},
+ "tsalagi.flf": &bintree{fontsTsalagiFlf, map[string]*bintree{}},
+ "twopoint.flf": &bintree{fontsTwopointFlf, map[string]*bintree{}},
+ "univers.flf": &bintree{fontsUniversFlf, map[string]*bintree{}},
+ "usaflag.flf": &bintree{fontsUsaflagFlf, map[string]*bintree{}},
+ "wavy.flf": &bintree{fontsWavyFlf, map[string]*bintree{}},
+ "weird.flf": &bintree{fontsWeirdFlf, map[string]*bintree{}},
+ }},
+}}
+
+// RestoreAsset restores an asset under the given directory
+func RestoreAsset(dir, name string) error {
+ data, err := Asset(name)
+ if err != nil {
+ return err
+ }
+ info, err := AssetInfo(name)
+ if err != nil {
+ return err
+ }
+ err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
+ if err != nil {
+ return err
+ }
+ err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
+ if err != nil {
+ return err
+ }
+ err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// RestoreAssets restores an asset under the given directory recursively
+func RestoreAssets(dir, name string) error {
+ children, err := AssetDir(name)
+ // File
+ if err != nil {
+ return RestoreAsset(dir, name)
+ }
+ // Dir
+ for _, child := range children {
+ err = RestoreAssets(dir, filepath.Join(name, child))
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func _filePath(dir, name string) string {
+ cannonicalName := strings.Replace(name, "\\", "/", -1)
+ return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
+}
diff --git a/vendor/github.com/common-nighthawk/go-figure/figlet-parser.go b/vendor/github.com/common-nighthawk/go-figure/figlet-parser.go
new file mode 100644
index 00000000000..4c595a5ee46
--- /dev/null
+++ b/vendor/github.com/common-nighthawk/go-figure/figlet-parser.go
@@ -0,0 +1,52 @@
+package figure
+
+import (
+ "strconv"
+ "strings"
+)
+
+const signature = "flf2"
+const reverseFlag = "1"
+
+var charDelimiters = [3]string{"@", "#", "$"}
+var hardblanksBlacklist = [2]byte{'a', '2'}
+
+func getHeight(metadata string) int {
+ datum := strings.Fields(metadata)[1]
+ height, _ := strconv.Atoi(datum)
+ return height
+}
+
+func getBaseline(metadata string) int {
+ datum := strings.Fields(metadata)[2]
+ baseline, _ := strconv.Atoi(datum)
+ return baseline
+}
+
+func getHardblank(metadata string) byte {
+ datum := strings.Fields(metadata)[0]
+ hardblank := datum[len(datum)-1]
+ if hardblank == hardblanksBlacklist[0] || hardblank == hardblanksBlacklist[1] {
+ return ' '
+ } else {
+ return hardblank
+ }
+}
+
+func getReverse(metadata string) bool {
+ data := strings.Fields(metadata)
+ return len(data) > 6 && data[6] == reverseFlag
+}
+
+func lastCharLine(text string, height int) bool {
+ endOfLine, length := " ", 2
+ if height == 1 && len(text) > 0 {
+ length = 1
+ }
+ if len(text) >= length {
+ endOfLine = text[len(text)-length:]
+ }
+ return endOfLine == strings.Repeat(charDelimiters[0], length) ||
+ endOfLine == strings.Repeat(charDelimiters[1], length) ||
+ endOfLine == strings.Repeat(charDelimiters[2], length)
+}
diff --git a/vendor/github.com/common-nighthawk/go-figure/figure.go b/vendor/github.com/common-nighthawk/go-figure/figure.go
new file mode 100644
index 00000000000..a2559fc4bca
--- /dev/null
+++ b/vendor/github.com/common-nighthawk/go-figure/figure.go
@@ -0,0 +1,80 @@
+package figure
+
+import (
+ "io"
+ "log"
+ "reflect"
+ "strings"
+)
+
+const ascii_offset = 32
+const first_ascii = ' '
+const last_ascii = '~'
+
+type figure struct {
+ phrase string
+ font
+ strict bool
+ color string
+}
+
+func NewFigure(phrase, fontName string, strict bool) figure {
+ font := newFont(fontName)
+ if font.reverse {
+ phrase = reverse(phrase)
+ }
+ return figure{phrase: phrase, font: font, strict: strict}
+}
+
+func NewColorFigure(phrase, fontName string, color string, strict bool) figure {
+ color = strings.ToLower(color)
+ if _, found := colors[color]; !found {
+ log.Fatalf("invalid color. must be one of: %s", reflect.ValueOf(colors).MapKeys())
+ }
+
+ fig := NewFigure(phrase, fontName, strict)
+ fig.color = color
+ return fig
+}
+
+func NewFigureWithFont(phrase string, reader io.Reader, strict bool) figure {
+ font := newFontFromReader(reader)
+ if font.reverse {
+ phrase = reverse(phrase)
+ }
+ return figure{phrase: phrase, font: font, strict: strict}
+}
+
+func (figure figure) Slicify() (rows []string) {
+ for r := 0; r < figure.font.height; r++ {
+ printRow := ""
+ for _, char := range figure.phrase {
+ if char < first_ascii || char > last_ascii {
+ if figure.strict {
+ log.Fatal("invalid input.")
+ } else {
+ char = '?'
+ }
+ }
+ fontIndex := char - ascii_offset
+ charRowText := scrub(figure.font.letters[fontIndex][r], figure.font.hardblank)
+ printRow += charRowText
+ }
+ if r < figure.font.baseline || len(strings.TrimSpace(printRow)) > 0 {
+ rows = append(rows, strings.TrimRight(printRow, " "))
+ }
+ }
+ return rows
+}
+
+func scrub(text string, char byte) string {
+ return strings.Replace(text, string(char), " ", -1)
+}
+
+func reverse(s string) string {
+ runes := []rune(s)
+ for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
+ runes[i], runes[j] = runes[j], runes[i]
+ }
+ return string(runes)
+}
diff --git a/vendor/github.com/common-nighthawk/go-figure/font.go b/vendor/github.com/common-nighthawk/go-figure/font.go
new file mode 100644
index 00000000000..fc6852e81ec
--- /dev/null
+++ b/vendor/github.com/common-nighthawk/go-figure/font.go
@@ -0,0 +1,112 @@
+package figure
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "path"
+ "strings"
+)
+
+const defaultFont = "standard"
+
+var colors = map[string]string{
+ "reset": "\033[0m",
+ "red": "\033[31m",
+ "green": "\033[32m",
+ "yellow": "\033[33m",
+ "blue": "\033[34m",
+ "purple": "\033[35m",
+ "cyan": "\033[36m",
+ "gray": "\033[37m",
+ "white": "\033[97m",
+}
+
+type font struct {
+ name string
+ height int
+ baseline int
+ hardblank byte
+ reverse bool
+ letters [][]string
+}
+
+func newFont(name string) (font font) {
+ font.setName(name)
+ fontBytes, err := Asset(path.Join("fonts", font.name+".flf"))
+ if err != nil {
+ panic(err)
+ }
+ fontBytesReader := bytes.NewReader(fontBytes)
+ scanner := bufio.NewScanner(fontBytesReader)
+ font.setAttributes(scanner)
+ font.setLetters(scanner)
+ return font
+}
+
+func newFontFromReader(reader io.Reader) (font font) {
+ scanner := bufio.NewScanner(reader)
+ font.setAttributes(scanner)
+ font.setLetters(scanner)
+ return font
+}
+
+func (font *font) setName(name string) {
+ font.name = name
+ if len(name) < 1 {
+ font.name = defaultFont
+ }
+}
+
+func (font *font) setAttributes(scanner *bufio.Scanner) {
+ for scanner.Scan() {
+ text := scanner.Text()
+ if strings.HasPrefix(text, signature) {
+ font.height = getHeight(text)
+ font.baseline = getBaseline(text)
+ font.hardblank = getHardblank(text)
+ font.reverse = getReverse(text)
+ break
+ }
+ }
+}
+
+func (font *font) setLetters(scanner *bufio.Scanner) {
+ font.letters = append(font.letters, make([]string, font.height, font.height)) //TODO: set spaces from flf
+ for i := range font.letters[0] {
+ font.letters[0][i] = " "
+ } //TODO: set spaces from flf
+ letterIndex := 0
+ for scanner.Scan() {
+ text, cutLength, letterIndexInc := scanner.Text(), 1, 0
+ if lastCharLine(text, font.height) {
+ font.letters = append(font.letters, []string{})
+ letterIndexInc = 1
+ if font.height > 1 {
+ cutLength = 2
+ }
+ }
+ if letterIndex > 0 {
+ appendText := ""
+ if len(text) > 1 {
+ appendText = text[:len(text)-cutLength]
+ }
+ font.letters[letterIndex] = append(font.letters[letterIndex], appendText)
+ }
+ letterIndex += letterIndexInc
+ }
+}
+
+func (font *font) evenLetters() {
+ var longest int
+ for _, letter := range font.letters {
+ if len(letter) > 0 && len(letter[0]) > longest {
+ longest = len(letter[0])
+ }
+ }
+ for _, letter := range font.letters {
+ for i, row := range letter {
+ letter[i] = row + strings.Repeat(" ", longest-len(row))
+ }
+ }
+}
diff --git a/vendor/github.com/common-nighthawk/go-figure/public_methods.go b/vendor/github.com/common-nighthawk/go-figure/public_methods.go
new file mode 100644
index 00000000000..5a154116214
--- /dev/null
+++ b/vendor/github.com/common-nighthawk/go-figure/public_methods.go
@@ -0,0 +1,108 @@
+package figure
+
+import (
+ "fmt"
+ "io"
+ "strings"
+ "time"
+)
+
+//stdout
+func (fig figure) Print() {
+ for _, printRow := range fig.Slicify() {
+ if fig.color != "" {
+ printRow = colors[fig.color] + printRow + colors["reset"]
+ }
+ fmt.Println(printRow)
+ }
+}
+
+// returns a colored string
+func (fig figure) ColorString() string {
+ s := ""
+ for _, printRow := range fig.Slicify() {
+ if fig.color != "" {
+ printRow = colors[fig.color] + printRow + colors["reset"]
+ }
+ s += fmt.Sprintf("%s\n", printRow)
+ }
+ return s
+}
+
+func (fig figure) String() string {
+ s := ""
+ for _, printRow := range fig.Slicify() {
+ s += fmt.Sprintf("%s\n", printRow)
+ }
+ return s
+}
+
+func (fig figure) Scroll(duration, stillness int, direction string) {
+ endTime := time.Now().Add(time.Duration(duration) * time.Millisecond)
+ fig.phrase = fig.phrase + " "
+ clearScreen()
+ for time.Now().Before(endTime) {
+ var shiftedPhrase string
+ chars := []byte(fig.phrase)
+ if strings.HasPrefix(strings.ToLower(direction), "r") {
+ shiftedPhrase = string(append(chars[len(chars)-1:], chars[0:len(chars)-1]...))
+ } else {
+ shiftedPhrase = string(append(chars[1:len(chars)], chars[0]))
+ }
+ fig.phrase = shiftedPhrase
+ fig.Print()
+ sleep(stillness)
+ clearScreen()
+ }
+}
+
+func (fig figure) Blink(duration, timeOn, timeOff int) {
+ if timeOff < 0 {
+ timeOff = timeOn
+ }
+ endTime := time.Now().Add(time.Duration(duration) * time.Millisecond)
+ clearScreen()
+ for time.Now().Before(endTime) {
+ fig.Print()
+ sleep(timeOn)
+ clearScreen()
+ sleep(timeOff)
+ }
+}
+
+func (fig figure) Dance(duration, freeze int) {
+ endTime := time.Now().Add(time.Duration(duration) * time.Millisecond)
+ font := fig.font //TODO: change to deep copy
+ font.evenLetters()
+ figures := []figure{figure{font: font}, figure{font: font}}
+ clearScreen()
+ for i, c := range fig.phrase {
+ appenders := []string{" ", " "}
+ appenders[i%2] = string(c)
+ for f, _ := range figures {
+ figures[f].phrase = figures[f].phrase + appenders[f]
+ }
+ }
+ for p := 0; time.Now().Before(endTime); p ^= 1 {
+ figures[p].Print()
+ figures[1-p].Print()
+ sleep(freeze)
+ clearScreen()
+ }
+}
+
+//writers
+func Write(w io.Writer, fig figure) {
+ for _, printRow := range fig.Slicify() {
+ fmt.Fprintf(w, "%v\n", printRow)
+ }
+}
+
+//helpers
+func clearScreen() {
+ fmt.Print("\033[H\033[2J")
+}
+
+func sleep(milliseconds int) {
+ time.Sleep(time.Duration(milliseconds) * time.Millisecond)
+}
diff --git a/vendor/github.com/containerd/containerd/archive/compression/compression_fuzzer.go b/vendor/github.com/containerd/containerd/archive/compression/compression_fuzzer.go
new file mode 100644
index 00000000000..3516494ac0b
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/archive/compression/compression_fuzzer.go
@@ -0,0 +1,28 @@
+//go:build gofuzz
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package compression
+
+import (
+ "bytes"
+)
+
+func FuzzDecompressStream(data []byte) int {
+ _, _ = DecompressStream(bytes.NewReader(data))
+ return 1
+}
diff --git a/vendor/github.com/containerd/containerd/content/content.go b/vendor/github.com/containerd/containerd/content/content.go
index ff17a8417b3..8eb1a16924c 100644
--- a/vendor/github.com/containerd/containerd/content/content.go
+++ b/vendor/github.com/containerd/containerd/content/content.go
@@ -25,6 +25,26 @@ import (
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
+// Store combines the methods of content-oriented interfaces into a set that
+// are commonly provided by complete implementations.
+//
+// Overall content lifecycle:
+// - Ingester is used to initiate a write operation (aka ingestion)
+// - IngestManager is used to manage (e.g. list, abort) active ingestions
+// - Once an ingestion is complete (see Writer.Commit), Provider is used to
+// query a single piece of content by its digest
+// - Manager is used to manage (e.g. list, delete) previously committed content
+//
+// Note that until ingestion is complete, its content is not visible through
+// Provider or Manager. Once ingestion is complete, it is no longer exposed
+// through IngestManager.
+type Store interface {
+ Manager
+ Provider
+ IngestManager
+ Ingester
+}
+
// ReaderAt extends the standard io.ReaderAt interface with reporting of Size and io.Closer
type ReaderAt interface {
io.ReaderAt
@@ -42,14 +62,31 @@ type Provider interface {
// Ingester writes content
type Ingester interface {
- // Some implementations require WithRef to be included in opts.
+ // Writer initiates a writing operation (aka ingestion). A single ingestion
+ // is uniquely identified by its ref, provided using a WithRef option.
+ // Writer can be called multiple times with the same ref to access the same
+ // ingestion.
+ // Once all the data is written, use Writer.Commit to complete the ingestion.
Writer(ctx context.Context, opts ...WriterOpt) (Writer, error)
}
+// IngestManager provides methods for managing ingestions. An ingestion is a
+// not-yet-complete writing operation initiated using Ingester and identified
+// by a ref string.
+type IngestManager interface {
+ // Status returns the status of the provided ref.
+ Status(ctx context.Context, ref string) (Status, error)
+
+ // ListStatuses returns the status of any active ingestions whose ref match
+ // the provided regular expression. If empty, all active ingestions will be
+ // returned.
+ ListStatuses(ctx context.Context, filters ...string) ([]Status, error)
+
+ // Abort completely cancels the ingest operation targeted by ref.
+ Abort(ctx context.Context, ref string) error
+}
+
// Info holds content specific information
-//
-// TODO(stevvooe): Consider a very different name for this struct. Info is way
-// to general. It also reads very weird in certain context, like pluralization.
type Info struct {
Digest digest.Digest
Size int64
@@ -58,7 +95,7 @@ type Info struct {
Labels map[string]string
}
-// Status of a content operation
+// Status of a content operation (i.e. an ingestion)
type Status struct {
Ref string
Offset int64
@@ -71,12 +108,17 @@ type Status struct {
// WalkFunc defines the callback for a blob walk.
type WalkFunc func(Info) error
-// Manager provides methods for inspecting, listing and removing content.
-type Manager interface {
+// InfoProvider provides info for content inspection.
+type InfoProvider interface {
// Info will return metadata about content available in the content store.
//
// If the content is not present, ErrNotFound will be returned.
Info(ctx context.Context, dgst digest.Digest) (Info, error)
+}
+
+// Manager provides methods for inspecting, listing and removing content.
+type Manager interface {
+ InfoProvider
// Update updates mutable information related to content.
// If one or more fieldpaths are provided, only those
@@ -94,21 +136,7 @@ type Manager interface {
Delete(ctx context.Context, dgst digest.Digest) error
}
-// IngestManager provides methods for managing ingests.
-type IngestManager interface {
- // Status returns the status of the provided ref.
- Status(ctx context.Context, ref string) (Status, error)
-
- // ListStatuses returns the status of any active ingestions whose ref match the
- // provided regular expression. If empty, all active ingestions will be
- // returned.
- ListStatuses(ctx context.Context, filters ...string) ([]Status, error)
-
- // Abort completely cancels the ingest operation targeted by ref.
- Abort(ctx context.Context, ref string) error
-}
-
-// Writer handles the write of content into a content store
+// Writer handles writing of content into a content store
type Writer interface {
// Close closes the writer, if the writer has not been
// committed this allows resuming or aborting.
@@ -131,15 +159,6 @@ type Writer interface {
Truncate(size int64) error
}
-// Store combines the methods of content-oriented interfaces into a set that
-// are commonly provided by complete implementations.
-type Store interface {
- Manager
- Provider
- IngestManager
- Ingester
-}
-
// Opt is used to alter the mutable properties of content
type Opt func(*Info) error
diff --git a/vendor/github.com/containerd/containerd/content/helpers.go b/vendor/github.com/containerd/containerd/content/helpers.go
index 723c3139171..5404109a6db 100644
--- a/vendor/github.com/containerd/containerd/content/helpers.go
+++ b/vendor/github.com/containerd/containerd/content/helpers.go
@@ -21,12 +21,12 @@ import (
"errors"
"fmt"
"io"
- "math/rand"
"sync"
"time"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/log"
+ "github.com/containerd/containerd/pkg/randutil"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
@@ -43,16 +43,26 @@ var bufPool = sync.Pool{
},
}
+type reader interface {
+ Reader() io.Reader
+}
+
// NewReader returns a io.Reader from a ReaderAt
func NewReader(ra ReaderAt) io.Reader {
- rd := io.NewSectionReader(ra, 0, ra.Size())
- return rd
+ if rd, ok := ra.(reader); ok {
+ return rd.Reader()
+ }
+ return io.NewSectionReader(ra, 0, ra.Size())
}
// ReadBlob retrieves the entire contents of the blob from the provider.
//
// Avoid using this for large blobs, such as layers.
func ReadBlob(ctx context.Context, provider Provider, desc ocispec.Descriptor) ([]byte, error) {
+ if int64(len(desc.Data)) == desc.Size && digest.FromBytes(desc.Data) == desc.Digest {
+ return desc.Data, nil
+ }
+
ra, err := provider.ReaderAt(ctx, desc)
if err != nil {
return nil, err
@@ -113,7 +123,7 @@ func OpenWriter(ctx context.Context, cs Ingester, opts ...WriterOpt) (Writer, er
// error or abort. Requires asserting for an ingest manager
select {
- case <-time.After(time.Millisecond * time.Duration(rand.Intn(retry))):
+ case <-time.After(time.Millisecond * time.Duration(randutil.Intn(retry))):
if retry < 2048 {
retry = retry << 1
}
diff --git a/vendor/github.com/containerd/containerd/content/local/content_local_fuzzer.go b/vendor/github.com/containerd/containerd/content/local/content_local_fuzzer.go
new file mode 100644
index 00000000000..a523f28d911
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/content/local/content_local_fuzzer.go
@@ -0,0 +1,76 @@
+//go:build gofuzz
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package local
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ _ "crypto/sha256"
+ "io"
+ "testing"
+
+ "github.com/opencontainers/go-digest"
+
+ "github.com/containerd/containerd/content"
+)
+
+func FuzzContentStoreWriter(data []byte) int {
+ t := &testing.T{}
+ ctx := context.Background()
+ ctx, _, cs, cleanup := contentStoreEnv(t)
+ defer cleanup()
+
+ cw, err := cs.Writer(ctx, content.WithRef("myref"))
+ if err != nil {
+ return 0
+ }
+ if err := cw.Close(); err != nil {
+ return 0
+ }
+
+ // reopen, so we can test things
+ cw, err = cs.Writer(ctx, content.WithRef("myref"))
+ if err != nil {
+ return 0
+ }
+
+ err = checkCopyFuzz(int64(len(data)), cw, bufio.NewReader(io.NopCloser(bytes.NewReader(data))))
+ if err != nil {
+ return 0
+ }
+ expected := digest.FromBytes(data)
+
+ if err = cw.Commit(ctx, int64(len(data)), expected); err != nil {
+ return 0
+ }
+ return 1
+}
+
+func checkCopyFuzz(size int64, dst io.Writer, src io.Reader) error {
+ nn, err := io.Copy(dst, src)
+ if err != nil {
+ return err
+ }
+
+ if nn != size {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/containerd/containerd/content/local/readerat.go b/vendor/github.com/containerd/containerd/content/local/readerat.go
index a83c171bbd2..899e85c0ba8 100644
--- a/vendor/github.com/containerd/containerd/content/local/readerat.go
+++ b/vendor/github.com/containerd/containerd/content/local/readerat.go
@@ -18,6 +18,7 @@ package local
import (
"fmt"
+ "io"
"os"
"github.com/containerd/containerd/content"
@@ -65,3 +66,7 @@ func (ra sizeReaderAt) Size() int64 {
func (ra sizeReaderAt) Close() error {
return ra.fp.Close()
}
+
+func (ra sizeReaderAt) Reader() io.Reader {
+ return io.LimitReader(ra.fp, ra.size)
+}
diff --git a/vendor/github.com/containerd/containerd/content/local/store.go b/vendor/github.com/containerd/containerd/content/local/store.go
index f41a92d04a5..baae3565bb4 100644
--- a/vendor/github.com/containerd/containerd/content/local/store.go
+++ b/vendor/github.com/containerd/containerd/content/local/store.go
@@ -20,7 +20,6 @@ import (
"context"
"fmt"
"io"
- "math/rand"
"os"
"path/filepath"
"strconv"
@@ -32,9 +31,10 @@ import (
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/filters"
"github.com/containerd/containerd/log"
+ "github.com/containerd/containerd/pkg/randutil"
"github.com/sirupsen/logrus"
- digest "github.com/opencontainers/go-digest"
+ "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
@@ -262,7 +262,7 @@ func (s *store) Walk(ctx context.Context, fn content.WalkFunc, fs ...string) err
return nil
}
- dgst := digest.NewDigestFromHex(alg.String(), filepath.Base(path))
+ dgst := digest.NewDigestFromEncoded(alg, filepath.Base(path))
if err := dgst.Validate(); err != nil {
// log error but don't report
log.L.WithError(err).WithField("path", path).Error("invalid digest for blob path")
@@ -473,7 +473,7 @@ func (s *store) Writer(ctx context.Context, opts ...content.WriterOpt) (content.
lockErr = nil
break
}
- time.Sleep(time.Millisecond * time.Duration(rand.Intn(1< maxSize
+ keyMaxLen = 64
)
// Validate a label's key and value are under 4096 bytes
func Validate(k, v string) error {
- if (len(k) + len(v)) > maxSize {
- if len(k) > 10 {
- k = k[:10]
+ total := len(k) + len(v)
+ if total > maxSize {
+ if len(k) > keyMaxLen {
+ k = k[:keyMaxLen]
}
- return fmt.Errorf("label key and value greater than maximum size (%d bytes), key: %s: %w", maxSize, k, errdefs.ErrInvalidArgument)
+ return fmt.Errorf("label key and value length (%d bytes) greater than maximum size (%d bytes), key: %s: %w", total, maxSize, k, errdefs.ErrInvalidArgument)
}
return nil
}
diff --git a/vendor/github.com/containerd/containerd/log/context.go b/vendor/github.com/containerd/containerd/log/context.go
index 0db9562b82b..20153066f3a 100644
--- a/vendor/github.com/containerd/containerd/log/context.go
+++ b/vendor/github.com/containerd/containerd/log/context.go
@@ -14,56 +14,169 @@
limitations under the License.
*/
+// Package log provides types and functions related to logging, passing
+// loggers through a context, and attaching context to the logger.
+//
+// # Transitional types
+//
+// This package contains various types that are aliases for types in [logrus].
+// These aliases are intended for transitioning away from hard-coding logrus
+// as logging implementation. Consumers of this package are encouraged to use
+// the type-aliases from this package instead of directly using their logrus
+// equivalent.
+//
+// The intent is to replace these aliases with locally defined types and
+// interfaces once all consumers are no longer directly importing logrus
+// types.
+//
+// IMPORTANT: due to the transitional purpose of this package, it is not
+// guaranteed for the full logrus API to be provided in the future. As
+// outlined, these aliases are provided as a step to transition away from
+// a specific implementation which, as a result, exposes the full logrus API.
+// While no decisions have been made on the ultimate design and interface
+// provided by this package, we do not expect carrying "less common" features.
package log
import (
"context"
+ "fmt"
"github.com/sirupsen/logrus"
)
-var (
- // G is an alias for GetLogger.
- //
- // We may want to define this locally to a package to get package tagged log
- // messages.
- G = GetLogger
+// G is a shorthand for [GetLogger].
+//
+// We may want to define this locally to a package to get package tagged log
+// messages.
+var G = GetLogger
+
+// L is an alias for the standard logger.
+var L = &Entry{
+ Logger: logrus.StandardLogger(),
+ // Default is three fields plus a little extra room.
+ Data: make(Fields, 6),
+}
- // L is an alias for the standard logger.
- L = logrus.NewEntry(logrus.StandardLogger())
-)
+type loggerKey struct{}
-type (
- loggerKey struct{}
-)
+// Fields type to pass to "WithFields".
+type Fields = map[string]any
+
+// Entry is a logging entry. It contains all the fields passed with
+// [Entry.WithFields]. It's finally logged when Trace, Debug, Info, Warn,
+// Error, Fatal or Panic is called on it. These objects can be reused and
+// passed around as much as you wish to avoid field duplication.
+//
+// Entry is a transitional type, and currently an alias for [logrus.Entry].
+type Entry = logrus.Entry
+// RFC3339NanoFixed is [time.RFC3339Nano] with nanoseconds padded using
+// zeros to ensure the formatted time is always the same number of
+// characters.
+const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
+
+// Level is a logging level.
+type Level = logrus.Level
+
+// Supported log levels.
const (
- // RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to
- // ensure the formatted time is always the same number of characters.
- RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
+ // TraceLevel level. Designates finer-grained informational events
+ // than [DebugLevel].
+ TraceLevel Level = logrus.TraceLevel
+
+ // DebugLevel level. Usually only enabled when debugging. Very verbose
+ // logging.
+ DebugLevel Level = logrus.DebugLevel
+
+ // InfoLevel level. General operational entries about what's going on
+ // inside the application.
+ InfoLevel Level = logrus.InfoLevel
+
+ // WarnLevel level. Non-critical entries that deserve eyes.
+ WarnLevel Level = logrus.WarnLevel
+
+ // ErrorLevel level. Logs errors that should definitely be noted.
+ // Commonly used for hooks to send errors to an error tracking service.
+ ErrorLevel Level = logrus.ErrorLevel
+
+ // FatalLevel level. Logs and then calls "logger.Exit(1)". It exits
+ // even if the logging level is set to Panic.
+ FatalLevel Level = logrus.FatalLevel
+
+ // PanicLevel level. This is the highest level of severity. Logs and
+ // then calls panic with the message passed to Debug, Info, ...
+ PanicLevel Level = logrus.PanicLevel
+)
- // TextFormat represents the text logging format
- TextFormat = "text"
+// SetLevel sets log level globally. It returns an error if the given
+// level is not supported.
+//
+// level can be one of:
+//
+// - "trace" ([TraceLevel])
+// - "debug" ([DebugLevel])
+// - "info" ([InfoLevel])
+// - "warn" ([WarnLevel])
+// - "error" ([ErrorLevel])
+// - "fatal" ([FatalLevel])
+// - "panic" ([PanicLevel])
+func SetLevel(level string) error {
+ lvl, err := logrus.ParseLevel(level)
+ if err != nil {
+ return err
+ }
+
+ L.Logger.SetLevel(lvl)
+ return nil
+}
- // JSONFormat represents the JSON logging format
- JSONFormat = "json"
+// GetLevel returns the current log level.
+func GetLevel() Level {
+ return L.Logger.GetLevel()
+}
+
+// OutputFormat specifies a log output format.
+type OutputFormat string
+
+// Supported log output formats.
+const (
+ // TextFormat represents the text logging format.
+ TextFormat OutputFormat = "text"
+
+ // JSONFormat represents the JSON logging format.
+ JSONFormat OutputFormat = "json"
)
+// SetFormat sets the log output format ([TextFormat] or [JSONFormat]).
+func SetFormat(format OutputFormat) error {
+ switch format {
+ case TextFormat:
+ L.Logger.SetFormatter(&logrus.TextFormatter{
+ TimestampFormat: RFC3339NanoFixed,
+ FullTimestamp: true,
+ })
+ return nil
+ case JSONFormat:
+ L.Logger.SetFormatter(&logrus.JSONFormatter{
+ TimestampFormat: RFC3339NanoFixed,
+ })
+ return nil
+ default:
+ return fmt.Errorf("unknown log format: %s", format)
+ }
+}
+
// WithLogger returns a new context with the provided logger. Use in
// combination with logger.WithField(s) for great effect.
-func WithLogger(ctx context.Context, logger *logrus.Entry) context.Context {
- e := logger.WithContext(ctx)
- return context.WithValue(ctx, loggerKey{}, e)
+func WithLogger(ctx context.Context, logger *Entry) context.Context {
+ return context.WithValue(ctx, loggerKey{}, logger.WithContext(ctx))
}
// GetLogger retrieves the current logger from the context. If no logger is
// available, the default logger is returned.
-func GetLogger(ctx context.Context) *logrus.Entry {
- logger := ctx.Value(loggerKey{})
-
- if logger == nil {
- return L.WithContext(ctx)
+func GetLogger(ctx context.Context) *Entry {
+ if logger := ctx.Value(loggerKey{}); logger != nil {
+ return logger.(*Entry)
}
-
- return logger.(*logrus.Entry)
+ return L.WithContext(ctx)
}
diff --git a/vendor/github.com/containerd/containerd/pkg/randutil/randutil.go b/vendor/github.com/containerd/containerd/pkg/randutil/randutil.go
new file mode 100644
index 00000000000..f4b657d7dd8
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/pkg/randutil/randutil.go
@@ -0,0 +1,48 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+// Package randutil provides utilities for [cyrpto/rand].
+package randutil
+
+import (
+ "crypto/rand"
+ "math"
+ "math/big"
+)
+
+// Int63n is similar to [math/rand.Int63n] but uses [crypto/rand.Reader] under the hood.
+func Int63n(n int64) int64 {
+ b, err := rand.Int(rand.Reader, big.NewInt(n))
+ if err != nil {
+ panic(err)
+ }
+ return b.Int64()
+}
+
+// Int63 is similar to [math/rand.Int63] but uses [crypto/rand.Reader] under the hood.
+func Int63() int64 {
+ return Int63n(math.MaxInt64)
+}
+
+// Intn is similar to [math/rand.Intn] but uses [crypto/rand.Reader] under the hood.
+func Intn(n int) int {
+ return int(Int63n(int64(n)))
+}
+
+// Int is similar to [math/rand.Int] but uses [crypto/rand.Reader] under the hood.
+func Int() int {
+ return int(Int63())
+}
diff --git a/vendor/github.com/containerd/containerd/platforms/cpuinfo.go b/vendor/github.com/containerd/containerd/platforms/cpuinfo.go
index 046e0356d19..8c600fc96b1 100644
--- a/vendor/github.com/containerd/containerd/platforms/cpuinfo.go
+++ b/vendor/github.com/containerd/containerd/platforms/cpuinfo.go
@@ -17,14 +17,9 @@
package platforms
import (
- "bufio"
- "fmt"
- "os"
"runtime"
- "strings"
"sync"
- "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/log"
)
@@ -37,95 +32,12 @@ var cpuVariantOnce sync.Once
func cpuVariant() string {
cpuVariantOnce.Do(func() {
if isArmArch(runtime.GOARCH) {
- cpuVariantValue = getCPUVariant()
+ var err error
+ cpuVariantValue, err = getCPUVariant()
+ if err != nil {
+ log.L.Errorf("Error getCPUVariant for OS %s: %v", runtime.GOOS, err)
+ }
}
})
return cpuVariantValue
}
-
-// For Linux, the kernel has already detected the ABI, ISA and Features.
-// So we don't need to access the ARM registers to detect platform information
-// by ourselves. We can just parse these information from /proc/cpuinfo
-func getCPUInfo(pattern string) (info string, err error) {
- if !isLinuxOS(runtime.GOOS) {
- return "", fmt.Errorf("getCPUInfo for OS %s: %w", runtime.GOOS, errdefs.ErrNotImplemented)
- }
-
- cpuinfo, err := os.Open("/proc/cpuinfo")
- if err != nil {
- return "", err
- }
- defer cpuinfo.Close()
-
- // Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
- // the first core is enough.
- scanner := bufio.NewScanner(cpuinfo)
- for scanner.Scan() {
- newline := scanner.Text()
- list := strings.Split(newline, ":")
-
- if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
- return strings.TrimSpace(list[1]), nil
- }
- }
-
- // Check whether the scanner encountered errors
- err = scanner.Err()
- if err != nil {
- return "", err
- }
-
- return "", fmt.Errorf("getCPUInfo for pattern: %s: %w", pattern, errdefs.ErrNotFound)
-}
-
-func getCPUVariant() string {
- if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
- // Windows/Darwin only supports v7 for ARM32 and v8 for ARM64 and so we can use
- // runtime.GOARCH to determine the variants
- var variant string
- switch runtime.GOARCH {
- case "arm64":
- variant = "v8"
- case "arm":
- variant = "v7"
- default:
- variant = "unknown"
- }
-
- return variant
- }
-
- variant, err := getCPUInfo("Cpu architecture")
- if err != nil {
- log.L.WithError(err).Error("failure getting variant")
- return ""
- }
-
- // handle edge case for Raspberry Pi ARMv6 devices (which due to a kernel quirk, report "CPU architecture: 7")
- // https://www.raspberrypi.org/forums/viewtopic.php?t=12614
- if runtime.GOARCH == "arm" && variant == "7" {
- model, err := getCPUInfo("model name")
- if err == nil && strings.HasPrefix(strings.ToLower(model), "armv6-compatible") {
- variant = "6"
- }
- }
-
- switch strings.ToLower(variant) {
- case "8", "aarch64":
- variant = "v8"
- case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
- variant = "v7"
- case "6", "6tej":
- variant = "v6"
- case "5", "5t", "5te", "5tej":
- variant = "v5"
- case "4", "4t":
- variant = "v4"
- case "3":
- variant = "v3"
- default:
- variant = "unknown"
- }
-
- return variant
-}
diff --git a/vendor/github.com/containerd/containerd/platforms/cpuinfo_linux.go b/vendor/github.com/containerd/containerd/platforms/cpuinfo_linux.go
new file mode 100644
index 00000000000..722d86c3578
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/platforms/cpuinfo_linux.go
@@ -0,0 +1,161 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package platforms
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "os"
+ "runtime"
+ "strings"
+
+ "github.com/containerd/containerd/errdefs"
+ "golang.org/x/sys/unix"
+)
+
+// getMachineArch retrieves the machine architecture through system call
+func getMachineArch() (string, error) {
+ var uname unix.Utsname
+ err := unix.Uname(&uname)
+ if err != nil {
+ return "", err
+ }
+
+ arch := string(uname.Machine[:bytes.IndexByte(uname.Machine[:], 0)])
+
+ return arch, nil
+}
+
+// For Linux, the kernel has already detected the ABI, ISA and Features.
+// So we don't need to access the ARM registers to detect platform information
+// by ourselves. We can just parse these information from /proc/cpuinfo
+func getCPUInfo(pattern string) (info string, err error) {
+
+ cpuinfo, err := os.Open("/proc/cpuinfo")
+ if err != nil {
+ return "", err
+ }
+ defer cpuinfo.Close()
+
+ // Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
+ // the first core is enough.
+ scanner := bufio.NewScanner(cpuinfo)
+ for scanner.Scan() {
+ newline := scanner.Text()
+ list := strings.Split(newline, ":")
+
+ if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
+ return strings.TrimSpace(list[1]), nil
+ }
+ }
+
+ // Check whether the scanner encountered errors
+ err = scanner.Err()
+ if err != nil {
+ return "", err
+ }
+
+ return "", fmt.Errorf("getCPUInfo for pattern %s: %w", pattern, errdefs.ErrNotFound)
+}
+
+// getCPUVariantFromArch get CPU variant from arch through a system call
+func getCPUVariantFromArch(arch string) (string, error) {
+
+ var variant string
+
+ arch = strings.ToLower(arch)
+
+ if arch == "aarch64" {
+ variant = "8"
+ } else if arch[0:4] == "armv" && len(arch) >= 5 {
+ //Valid arch format is in form of armvXx
+ switch arch[3:5] {
+ case "v8":
+ variant = "8"
+ case "v7":
+ variant = "7"
+ case "v6":
+ variant = "6"
+ case "v5":
+ variant = "5"
+ case "v4":
+ variant = "4"
+ case "v3":
+ variant = "3"
+ default:
+ variant = "unknown"
+ }
+ } else {
+ return "", fmt.Errorf("getCPUVariantFromArch invalid arch: %s, %w", arch, errdefs.ErrInvalidArgument)
+ }
+ return variant, nil
+}
+
+// getCPUVariant returns cpu variant for ARM
+// We first try reading "Cpu architecture" field from /proc/cpuinfo
+// If we can't find it, then fall back using a system call
+// This is to cover running ARM in emulated environment on x86 host as this field in /proc/cpuinfo
+// was not present.
+func getCPUVariant() (string, error) {
+
+ variant, err := getCPUInfo("Cpu architecture")
+ if err != nil {
+ if errdefs.IsNotFound(err) {
+ //Let's try getting CPU variant from machine architecture
+ arch, err := getMachineArch()
+ if err != nil {
+ return "", fmt.Errorf("failure getting machine architecture: %v", err)
+ }
+
+ variant, err = getCPUVariantFromArch(arch)
+ if err != nil {
+ return "", fmt.Errorf("failure getting CPU variant from machine architecture: %v", err)
+ }
+ } else {
+ return "", fmt.Errorf("failure getting CPU variant: %v", err)
+ }
+ }
+
+ // handle edge case for Raspberry Pi ARMv6 devices (which due to a kernel quirk, report "CPU architecture: 7")
+ // https://www.raspberrypi.org/forums/viewtopic.php?t=12614
+ if runtime.GOARCH == "arm" && variant == "7" {
+ model, err := getCPUInfo("model name")
+ if err == nil && strings.HasPrefix(strings.ToLower(model), "armv6-compatible") {
+ variant = "6"
+ }
+ }
+
+ switch strings.ToLower(variant) {
+ case "8", "aarch64":
+ variant = "v8"
+ case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
+ variant = "v7"
+ case "6", "6tej":
+ variant = "v6"
+ case "5", "5t", "5te", "5tej":
+ variant = "v5"
+ case "4", "4t":
+ variant = "v4"
+ case "3":
+ variant = "v3"
+ default:
+ variant = "unknown"
+ }
+
+ return variant, nil
+}
diff --git a/vendor/github.com/containerd/containerd/platforms/cpuinfo_other.go b/vendor/github.com/containerd/containerd/platforms/cpuinfo_other.go
new file mode 100644
index 00000000000..fa5f19c427a
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/platforms/cpuinfo_other.go
@@ -0,0 +1,59 @@
+//go:build !linux
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package platforms
+
+import (
+ "fmt"
+ "runtime"
+
+ "github.com/containerd/containerd/errdefs"
+)
+
+func getCPUVariant() (string, error) {
+
+ var variant string
+
+ if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
+ // Windows/Darwin only supports v7 for ARM32 and v8 for ARM64 and so we can use
+ // runtime.GOARCH to determine the variants
+ switch runtime.GOARCH {
+ case "arm64":
+ variant = "v8"
+ case "arm":
+ variant = "v7"
+ default:
+ variant = "unknown"
+ }
+ } else if runtime.GOOS == "freebsd" {
+ // FreeBSD supports ARMv6 and ARMv7 as well as ARMv4 and ARMv5 (though deprecated)
+ // detecting those variants is currently unimplemented
+ switch runtime.GOARCH {
+ case "arm64":
+ variant = "v8"
+ default:
+ variant = "unknown"
+ }
+
+ } else {
+ return "", fmt.Errorf("getCPUVariant for OS %s: %v", runtime.GOOS, errdefs.ErrNotImplemented)
+
+ }
+
+ return variant, nil
+}
diff --git a/vendor/github.com/containerd/containerd/platforms/database.go b/vendor/github.com/containerd/containerd/platforms/database.go
index dbe9957ca9d..2e26fd3b4fa 100644
--- a/vendor/github.com/containerd/containerd/platforms/database.go
+++ b/vendor/github.com/containerd/containerd/platforms/database.go
@@ -21,13 +21,6 @@ import (
"strings"
)
-// isLinuxOS returns true if the operating system is Linux.
-//
-// The OS value should be normalized before calling this function.
-func isLinuxOS(os string) bool {
- return os == "linux"
-}
-
// These function are generated from https://golang.org/src/go/build/syslist.go.
//
// We use switch statements because they are slightly faster than map lookups
diff --git a/vendor/github.com/containerd/containerd/platforms/defaults_darwin.go b/vendor/github.com/containerd/containerd/platforms/defaults_darwin.go
index e249fe48d38..72355ca85fd 100644
--- a/vendor/github.com/containerd/containerd/platforms/defaults_darwin.go
+++ b/vendor/github.com/containerd/containerd/platforms/defaults_darwin.go
@@ -1,5 +1,4 @@
//go:build darwin
-// +build darwin
/*
Copyright The containerd Authors.
diff --git a/vendor/github.com/containerd/containerd/platforms/defaults_freebsd.go b/vendor/github.com/containerd/containerd/platforms/defaults_freebsd.go
new file mode 100644
index 00000000000..d3fe89e0766
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/platforms/defaults_freebsd.go
@@ -0,0 +1,43 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package platforms
+
+import (
+ "runtime"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+ return specs.Platform{
+ OS: runtime.GOOS,
+ Architecture: runtime.GOARCH,
+ // The Variant field will be empty if arch != ARM.
+ Variant: cpuVariant(),
+ }
+}
+
+// Default returns the default matcher for the platform.
+func Default() MatchComparer {
+ return Ordered(DefaultSpec(), specs.Platform{
+ OS: "linux",
+ Architecture: runtime.GOARCH,
+ // The Variant field will be empty if arch != ARM.
+ Variant: cpuVariant(),
+ })
+}
diff --git a/vendor/github.com/containerd/containerd/platforms/defaults_unix.go b/vendor/github.com/containerd/containerd/platforms/defaults_unix.go
index 49690f1b3e7..44acc47eb32 100644
--- a/vendor/github.com/containerd/containerd/platforms/defaults_unix.go
+++ b/vendor/github.com/containerd/containerd/platforms/defaults_unix.go
@@ -1,5 +1,4 @@
-//go:build !windows && !darwin
-// +build !windows,!darwin
+//go:build !windows && !darwin && !freebsd
/*
Copyright The containerd Authors.
diff --git a/vendor/github.com/containerd/containerd/platforms/defaults_windows.go b/vendor/github.com/containerd/containerd/platforms/defaults_windows.go
index c1aaf72ca8e..d10fa9012bd 100644
--- a/vendor/github.com/containerd/containerd/platforms/defaults_windows.go
+++ b/vendor/github.com/containerd/containerd/platforms/defaults_windows.go
@@ -22,7 +22,7 @@ import (
"strconv"
"strings"
- imagespec "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/Microsoft/hcsshim/osversion"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/sys/windows"
)
@@ -39,25 +39,52 @@ func DefaultSpec() specs.Platform {
}
}
-type matchComparer struct {
- defaults Matcher
+type windowsmatcher struct {
+ specs.Platform
osVersionPrefix string
+ defaultMatcher Matcher
}
// Match matches platform with the same windows major, minor
// and build version.
-func (m matchComparer) Match(p imagespec.Platform) bool {
- if m.defaults.Match(p) {
- // TODO(windows): Figure out whether OSVersion is deprecated.
- return strings.HasPrefix(p.OSVersion, m.osVersionPrefix)
+func (m windowsmatcher) Match(p specs.Platform) bool {
+ match := m.defaultMatcher.Match(p)
+
+ if match && m.OS == "windows" {
+ // HPC containers do not have OS version filled
+ if p.OSVersion == "" {
+ return true
+ }
+
+ hostOsVersion := GetOsVersion(m.osVersionPrefix)
+ ctrOsVersion := GetOsVersion(p.OSVersion)
+ return osversion.CheckHostAndContainerCompat(hostOsVersion, ctrOsVersion)
+ }
+
+ return match
+}
+
+func GetOsVersion(osVersionPrefix string) osversion.OSVersion {
+ parts := strings.Split(osVersionPrefix, ".")
+ if len(parts) < 3 {
+ return osversion.OSVersion{}
+ }
+
+ majorVersion, _ := strconv.Atoi(parts[0])
+ minorVersion, _ := strconv.Atoi(parts[1])
+ buildNumber, _ := strconv.Atoi(parts[2])
+
+ return osversion.OSVersion{
+ MajorVersion: uint8(majorVersion),
+ MinorVersion: uint8(minorVersion),
+ Build: uint16(buildNumber),
}
- return false
}
// Less sorts matched platforms in front of other platforms.
// For matched platforms, it puts platforms with larger revision
// number in front.
-func (m matchComparer) Less(p1, p2 imagespec.Platform) bool {
+func (m windowsmatcher) Less(p1, p2 specs.Platform) bool {
m1, m2 := m.Match(p1), m.Match(p2)
if m1 && m2 {
r1, r2 := revision(p1.OSVersion), revision(p2.OSVersion)
@@ -78,14 +105,15 @@ func revision(v string) int {
return r
}
+func prefix(v string) string {
+ parts := strings.Split(v, ".")
+ if len(parts) < 4 {
+ return v
+ }
+ return strings.Join(parts[0:3], ".")
+}
+
// Default returns the current platform's default platform specification.
func Default() MatchComparer {
- major, minor, build := windows.RtlGetNtVersionNumbers()
- return matchComparer{
- defaults: Ordered(DefaultSpec(), specs.Platform{
- OS: "linux",
- Architecture: runtime.GOARCH,
- }),
- osVersionPrefix: fmt.Sprintf("%d.%d.%d", major, minor, build),
- }
+ return Only(DefaultSpec())
}
diff --git a/vendor/github.com/containerd/containerd/platforms/platforms.go b/vendor/github.com/containerd/containerd/platforms/platforms.go
index 23430994180..56613b07656 100644
--- a/vendor/github.com/containerd/containerd/platforms/platforms.go
+++ b/vendor/github.com/containerd/containerd/platforms/platforms.go
@@ -114,14 +114,18 @@ import (
"strconv"
"strings"
- "github.com/containerd/containerd/errdefs"
specs "github.com/opencontainers/image-spec/specs-go/v1"
+
+ "github.com/containerd/containerd/errdefs"
)
var (
specifierRe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
)
+// Platform is a type alias for convenience, so there is no need to import image-spec package everywhere.
+type Platform = specs.Platform
+
// Matcher matches platforms specifications, provided by an image or runtime.
type Matcher interface {
Match(platform specs.Platform) bool
@@ -136,9 +140,7 @@ type Matcher interface {
//
// Applications should opt to use `Match` over directly parsing specifiers.
func NewMatcher(platform specs.Platform) Matcher {
- return &matcher{
- Platform: Normalize(platform),
- }
+ return newDefaultMatcher(platform)
}
type matcher struct {
@@ -194,6 +196,10 @@ func Parse(specifier string) (specs.Platform, error) {
p.Variant = cpuVariant()
}
+ if p.OS == "windows" {
+ p.OSVersion = GetWindowsOsVersion()
+ }
+
return p, nil
}
@@ -216,6 +222,10 @@ func Parse(specifier string) (specs.Platform, error) {
p.Variant = ""
}
+ if p.OS == "windows" {
+ p.OSVersion = GetWindowsOsVersion()
+ }
+
return p, nil
case 3:
// we have a fully specified variant, this is rare
@@ -225,6 +235,10 @@ func Parse(specifier string) (specs.Platform, error) {
p.Variant = "v8"
}
+ if p.OS == "windows" {
+ p.OSVersion = GetWindowsOsVersion()
+ }
+
return p, nil
}
@@ -257,5 +271,6 @@ func Format(platform specs.Platform) string {
func Normalize(platform specs.Platform) specs.Platform {
platform.OS = normalizeOS(platform.OS)
platform.Architecture, platform.Variant = normalizeArch(platform.Architecture, platform.Variant)
+
return platform
}
diff --git a/vendor/github.com/containerd/containerd/platforms/platforms_other.go b/vendor/github.com/containerd/containerd/platforms/platforms_other.go
new file mode 100644
index 00000000000..59beeb3d1d9
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/platforms/platforms_other.go
@@ -0,0 +1,34 @@
+//go:build !windows
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package platforms
+
+import (
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// NewMatcher returns the default Matcher for containerd
+func newDefaultMatcher(platform specs.Platform) Matcher {
+ return &matcher{
+ Platform: Normalize(platform),
+ }
+}
+
+func GetWindowsOsVersion() string {
+ return ""
+}
diff --git a/vendor/github.com/containerd/containerd/platforms/platforms_windows.go b/vendor/github.com/containerd/containerd/platforms/platforms_windows.go
new file mode 100644
index 00000000000..733d18ddead
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/platforms/platforms_windows.go
@@ -0,0 +1,42 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package platforms
+
+import (
+ "fmt"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+ "golang.org/x/sys/windows"
+)
+
+// NewMatcher returns a Windows matcher that will match on osVersionPrefix if
+// the platform is Windows otherwise use the default matcher
+func newDefaultMatcher(platform specs.Platform) Matcher {
+ prefix := prefix(platform.OSVersion)
+ return windowsmatcher{
+ Platform: platform,
+ osVersionPrefix: prefix,
+ defaultMatcher: &matcher{
+ Platform: Normalize(platform),
+ },
+ }
+}
+
+func GetWindowsOsVersion() string {
+ major, minor, build := windows.RtlGetNtVersionNumbers()
+ return fmt.Sprintf("%d.%d.%d", major, minor, build)
+}
diff --git a/vendor/github.com/containerd/containerd/reference/docker/helpers.go b/vendor/github.com/containerd/containerd/reference/docker/helpers.go
new file mode 100644
index 00000000000..386025104ae
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/reference/docker/helpers.go
@@ -0,0 +1,58 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package docker
+
+import "path"
+
+// IsNameOnly returns true if reference only contains a repo name.
+func IsNameOnly(ref Named) bool {
+ if _, ok := ref.(NamedTagged); ok {
+ return false
+ }
+ if _, ok := ref.(Canonical); ok {
+ return false
+ }
+ return true
+}
+
+// FamiliarName returns the familiar name string
+// for the given named, familiarizing if needed.
+func FamiliarName(ref Named) string {
+ if nn, ok := ref.(normalizedNamed); ok {
+ return nn.Familiar().Name()
+ }
+ return ref.Name()
+}
+
+// FamiliarString returns the familiar string representation
+// for the given reference, familiarizing if needed.
+func FamiliarString(ref Reference) string {
+ if nn, ok := ref.(normalizedNamed); ok {
+ return nn.Familiar().String()
+ }
+ return ref.String()
+}
+
+// FamiliarMatch reports whether ref matches the specified pattern.
+// See https://godoc.org/path#Match for supported patterns.
+func FamiliarMatch(pattern string, ref Reference) (bool, error) {
+ matched, err := path.Match(pattern, FamiliarString(ref))
+ if namedRef, isNamed := ref.(Named); isNamed && !matched {
+ matched, _ = path.Match(pattern, FamiliarName(namedRef))
+ }
+ return matched, err
+}
diff --git a/vendor/github.com/containerd/containerd/reference/docker/normalize.go b/vendor/github.com/containerd/containerd/reference/docker/normalize.go
new file mode 100644
index 00000000000..b299bf6c068
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/reference/docker/normalize.go
@@ -0,0 +1,196 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package docker
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/opencontainers/go-digest"
+)
+
+var (
+ legacyDefaultDomain = "index.docker.io"
+ defaultDomain = "docker.io"
+ officialRepoName = "library"
+ defaultTag = "latest"
+)
+
+// normalizedNamed represents a name which has been
+// normalized and has a familiar form. A familiar name
+// is what is used in Docker UI. An example normalized
+// name is "docker.io/library/ubuntu" and corresponding
+// familiar name of "ubuntu".
+type normalizedNamed interface {
+ Named
+ Familiar() Named
+}
+
+// ParseNormalizedNamed parses a string into a named reference
+// transforming a familiar name from Docker UI to a fully
+// qualified reference. If the value may be an identifier
+// use ParseAnyReference.
+func ParseNormalizedNamed(s string) (Named, error) {
+ if ok := anchoredIdentifierRegexp.MatchString(s); ok {
+ return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s)
+ }
+ domain, remainder := splitDockerDomain(s)
+ var remoteName string
+ if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 {
+ remoteName = remainder[:tagSep]
+ } else {
+ remoteName = remainder
+ }
+ if strings.ToLower(remoteName) != remoteName {
+ return nil, fmt.Errorf("invalid reference format: repository name (%s) must be lowercase", remoteName)
+ }
+
+ ref, err := Parse(domain + "/" + remainder)
+ if err != nil {
+ return nil, err
+ }
+ named, isNamed := ref.(Named)
+ if !isNamed {
+ return nil, fmt.Errorf("reference %s has no name", ref.String())
+ }
+ return named, nil
+}
+
+// ParseDockerRef normalizes the image reference following the docker convention. This is added
+// mainly for backward compatibility.
+// The reference returned can only be either tagged or digested. For reference contains both tag
+// and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@
+// sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as
+// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa.
+func ParseDockerRef(ref string) (Named, error) {
+ named, err := ParseNormalizedNamed(ref)
+ if err != nil {
+ return nil, err
+ }
+ if _, ok := named.(NamedTagged); ok {
+ if canonical, ok := named.(Canonical); ok {
+ // The reference is both tagged and digested, only
+ // return digested.
+ newNamed, err := WithName(canonical.Name())
+ if err != nil {
+ return nil, err
+ }
+ newCanonical, err := WithDigest(newNamed, canonical.Digest())
+ if err != nil {
+ return nil, err
+ }
+ return newCanonical, nil
+ }
+ }
+ return TagNameOnly(named), nil
+}
+
+// splitDockerDomain splits a repository name to domain and remotename string.
+// If no valid domain is found, the default domain is used. Repository name
+// needs to be already validated before.
+func splitDockerDomain(name string) (domain, remainder string) {
+ i := strings.IndexRune(name, '/')
+ if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost" && strings.ToLower(name[:i]) == name[:i]) {
+ domain, remainder = defaultDomain, name
+ } else {
+ domain, remainder = name[:i], name[i+1:]
+ }
+ if domain == legacyDefaultDomain {
+ domain = defaultDomain
+ }
+ if domain == defaultDomain && !strings.ContainsRune(remainder, '/') {
+ remainder = officialRepoName + "/" + remainder
+ }
+ return
+}
+
+// familiarizeName returns a shortened version of the name familiar
+// to the Docker UI. Familiar names have the default domain
+// "docker.io" and "library/" repository prefix removed.
+// For example, "docker.io/library/redis" will have the familiar
+// name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp".
+// Returns a familiarized named only reference.
+func familiarizeName(named namedRepository) repository {
+ repo := repository{
+ domain: named.Domain(),
+ path: named.Path(),
+ }
+
+ if repo.domain == defaultDomain {
+ repo.domain = ""
+ // Handle official repositories which have the pattern "library/"
+ if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName {
+ repo.path = split[1]
+ }
+ }
+ return repo
+}
+
+func (r reference) Familiar() Named {
+ return reference{
+ namedRepository: familiarizeName(r.namedRepository),
+ tag: r.tag,
+ digest: r.digest,
+ }
+}
+
+func (r repository) Familiar() Named {
+ return familiarizeName(r)
+}
+
+func (t taggedReference) Familiar() Named {
+ return taggedReference{
+ namedRepository: familiarizeName(t.namedRepository),
+ tag: t.tag,
+ }
+}
+
+func (c canonicalReference) Familiar() Named {
+ return canonicalReference{
+ namedRepository: familiarizeName(c.namedRepository),
+ digest: c.digest,
+ }
+}
+
+// TagNameOnly adds the default tag "latest" to a reference if it only has
+// a repo name.
+func TagNameOnly(ref Named) Named {
+ if IsNameOnly(ref) {
+ namedTagged, err := WithTag(ref, defaultTag)
+ if err != nil {
+ // Default tag must be valid, to create a NamedTagged
+ // type with non-validated input the WithTag function
+ // should be used instead
+ panic(err)
+ }
+ return namedTagged
+ }
+ return ref
+}
+
+// ParseAnyReference parses a reference string as a possible identifier,
+// full digest, or familiar name.
+func ParseAnyReference(ref string) (Reference, error) {
+ if ok := anchoredIdentifierRegexp.MatchString(ref); ok {
+ return digestReference("sha256:" + ref), nil
+ }
+ if dgst, err := digest.Parse(ref); err == nil {
+ return digestReference(dgst), nil
+ }
+
+ return ParseNormalizedNamed(ref)
+}
diff --git a/vendor/github.com/containerd/containerd/reference/docker/reference.go b/vendor/github.com/containerd/containerd/reference/docker/reference.go
new file mode 100644
index 00000000000..4dc00474ee5
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/reference/docker/reference.go
@@ -0,0 +1,453 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+// Package docker provides a general type to represent any way of referencing images within the registry.
+// Its main purpose is to abstract tags and digests (content-addressable hash).
+//
+// Grammar
+//
+// reference := name [ ":" tag ] [ "@" digest ]
+// name := [domain '/'] path-component ['/' path-component]*
+// domain := host [':' port-number]
+// host := domain-name | IPv4address | \[ IPv6address \] ; rfc3986 appendix-A
+// domain-name := domain-component ['.' domain-component]*
+// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
+// port-number := /[0-9]+/
+// path-component := alpha-numeric [separator alpha-numeric]*
+// alpha-numeric := /[a-z0-9]+/
+// separator := /[_.]|__|[-]*/
+//
+// tag := /[\w][\w.-]{0,127}/
+//
+// digest := digest-algorithm ":" digest-hex
+// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]*
+// digest-algorithm-separator := /[+.-_]/
+// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/
+// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
+//
+// identifier := /[a-f0-9]{64}/
+// short-identifier := /[a-f0-9]{6,64}/
+package docker
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+
+ "github.com/opencontainers/go-digest"
+)
+
+const (
+ // NameTotalLengthMax is the maximum total number of characters in a repository name.
+ NameTotalLengthMax = 255
+)
+
+var (
+ // ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference.
+ ErrReferenceInvalidFormat = errors.New("invalid reference format")
+
+ // ErrTagInvalidFormat represents an error while trying to parse a string as a tag.
+ ErrTagInvalidFormat = errors.New("invalid tag format")
+
+ // ErrDigestInvalidFormat represents an error while trying to parse a string as a tag.
+ ErrDigestInvalidFormat = errors.New("invalid digest format")
+
+ // ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters.
+ ErrNameContainsUppercase = errors.New("repository name must be lowercase")
+
+ // ErrNameEmpty is returned for empty, invalid repository names.
+ ErrNameEmpty = errors.New("repository name must have at least one component")
+
+ // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax.
+ ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax)
+
+ // ErrNameNotCanonical is returned when a name is not canonical.
+ ErrNameNotCanonical = errors.New("repository name must be canonical")
+)
+
+// Reference is an opaque object reference identifier that may include
+// modifiers such as a hostname, name, tag, and digest.
+type Reference interface {
+ // String returns the full reference
+ String() string
+}
+
+// Field provides a wrapper type for resolving correct reference types when
+// working with encoding.
+type Field struct {
+ reference Reference
+}
+
+// AsField wraps a reference in a Field for encoding.
+func AsField(reference Reference) Field {
+ return Field{reference}
+}
+
+// Reference unwraps the reference type from the field to
+// return the Reference object. This object should be
+// of the appropriate type to further check for different
+// reference types.
+func (f Field) Reference() Reference {
+ return f.reference
+}
+
+// MarshalText serializes the field to byte text which
+// is the string of the reference.
+func (f Field) MarshalText() (p []byte, err error) {
+ return []byte(f.reference.String()), nil
+}
+
+// UnmarshalText parses text bytes by invoking the
+// reference parser to ensure the appropriately
+// typed reference object is wrapped by field.
+func (f *Field) UnmarshalText(p []byte) error {
+ r, err := Parse(string(p))
+ if err != nil {
+ return err
+ }
+
+ f.reference = r
+ return nil
+}
+
+// Named is an object with a full name
+type Named interface {
+ Reference
+ Name() string
+}
+
+// Tagged is an object which has a tag
+type Tagged interface {
+ Reference
+ Tag() string
+}
+
+// NamedTagged is an object including a name and tag.
+type NamedTagged interface {
+ Named
+ Tag() string
+}
+
+// Digested is an object which has a digest
+// in which it can be referenced by
+type Digested interface {
+ Reference
+ Digest() digest.Digest
+}
+
+// Canonical reference is an object with a fully unique
+// name including a name with domain and digest
+type Canonical interface {
+ Named
+ Digest() digest.Digest
+}
+
+// namedRepository is a reference to a repository with a name.
+// A namedRepository has both domain and path components.
+type namedRepository interface {
+ Named
+ Domain() string
+ Path() string
+}
+
+// Domain returns the domain part of the Named reference
+func Domain(named Named) string {
+ if r, ok := named.(namedRepository); ok {
+ return r.Domain()
+ }
+ domain, _ := splitDomain(named.Name())
+ return domain
+}
+
+// Path returns the name without the domain part of the Named reference
+func Path(named Named) (name string) {
+ if r, ok := named.(namedRepository); ok {
+ return r.Path()
+ }
+ _, path := splitDomain(named.Name())
+ return path
+}
+
+func splitDomain(name string) (string, string) {
+ match := anchoredNameRegexp.FindStringSubmatch(name)
+ if len(match) != 3 {
+ return "", name
+ }
+ return match[1], match[2]
+}
+
+// SplitHostname splits a named reference into a
+// hostname and name string. If no valid hostname is
+// found, the hostname is empty and the full value
+// is returned as name
+// DEPRECATED: Use Domain or Path
+func SplitHostname(named Named) (string, string) {
+ if r, ok := named.(namedRepository); ok {
+ return r.Domain(), r.Path()
+ }
+ return splitDomain(named.Name())
+}
+
+// Parse parses s and returns a syntactically valid Reference.
+// If an error was encountered it is returned, along with a nil Reference.
+// NOTE: Parse will not handle short digests.
+func Parse(s string) (Reference, error) {
+ matches := ReferenceRegexp.FindStringSubmatch(s)
+ if matches == nil {
+ if s == "" {
+ return nil, ErrNameEmpty
+ }
+ if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil {
+ return nil, ErrNameContainsUppercase
+ }
+ return nil, ErrReferenceInvalidFormat
+ }
+
+ if len(matches[1]) > NameTotalLengthMax {
+ return nil, ErrNameTooLong
+ }
+
+ var repo repository
+
+ nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1])
+ if len(nameMatch) == 3 {
+ repo.domain = nameMatch[1]
+ repo.path = nameMatch[2]
+ } else {
+ repo.domain = ""
+ repo.path = matches[1]
+ }
+
+ ref := reference{
+ namedRepository: repo,
+ tag: matches[2],
+ }
+ if matches[3] != "" {
+ var err error
+ ref.digest, err = digest.Parse(matches[3])
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ r := getBestReferenceType(ref)
+ if r == nil {
+ return nil, ErrNameEmpty
+ }
+
+ return r, nil
+}
+
+// ParseNamed parses s and returns a syntactically valid reference implementing
+// the Named interface. The reference must have a name and be in the canonical
+// form, otherwise an error is returned.
+// If an error was encountered it is returned, along with a nil Reference.
+// NOTE: ParseNamed will not handle short digests.
+func ParseNamed(s string) (Named, error) {
+ named, err := ParseNormalizedNamed(s)
+ if err != nil {
+ return nil, err
+ }
+ if named.String() != s {
+ return nil, ErrNameNotCanonical
+ }
+ return named, nil
+}
+
+// WithName returns a named object representing the given string. If the input
+// is invalid ErrReferenceInvalidFormat will be returned.
+func WithName(name string) (Named, error) {
+ if len(name) > NameTotalLengthMax {
+ return nil, ErrNameTooLong
+ }
+
+ match := anchoredNameRegexp.FindStringSubmatch(name)
+ if match == nil || len(match) != 3 {
+ return nil, ErrReferenceInvalidFormat
+ }
+ return repository{
+ domain: match[1],
+ path: match[2],
+ }, nil
+}
+
+// WithTag combines the name from "name" and the tag from "tag" to form a
+// reference incorporating both the name and the tag.
+func WithTag(name Named, tag string) (NamedTagged, error) {
+ if !anchoredTagRegexp.MatchString(tag) {
+ return nil, ErrTagInvalidFormat
+ }
+ var repo repository
+ if r, ok := name.(namedRepository); ok {
+ repo.domain = r.Domain()
+ repo.path = r.Path()
+ } else {
+ repo.path = name.Name()
+ }
+ if canonical, ok := name.(Canonical); ok {
+ return reference{
+ namedRepository: repo,
+ tag: tag,
+ digest: canonical.Digest(),
+ }, nil
+ }
+ return taggedReference{
+ namedRepository: repo,
+ tag: tag,
+ }, nil
+}
+
+// WithDigest combines the name from "name" and the digest from "digest" to form
+// a reference incorporating both the name and the digest.
+func WithDigest(name Named, digest digest.Digest) (Canonical, error) {
+ if !anchoredDigestRegexp.MatchString(digest.String()) {
+ return nil, ErrDigestInvalidFormat
+ }
+ var repo repository
+ if r, ok := name.(namedRepository); ok {
+ repo.domain = r.Domain()
+ repo.path = r.Path()
+ } else {
+ repo.path = name.Name()
+ }
+ if tagged, ok := name.(Tagged); ok {
+ return reference{
+ namedRepository: repo,
+ tag: tagged.Tag(),
+ digest: digest,
+ }, nil
+ }
+ return canonicalReference{
+ namedRepository: repo,
+ digest: digest,
+ }, nil
+}
+
+// TrimNamed removes any tag or digest from the named reference.
+func TrimNamed(ref Named) Named {
+ repo := repository{}
+ if r, ok := ref.(namedRepository); ok {
+ repo.domain, repo.path = r.Domain(), r.Path()
+ } else {
+ repo.domain, repo.path = splitDomain(ref.Name())
+ }
+ return repo
+}
+
+func getBestReferenceType(ref reference) Reference {
+ if ref.Name() == "" {
+ // Allow digest only references
+ if ref.digest != "" {
+ return digestReference(ref.digest)
+ }
+ return nil
+ }
+ if ref.tag == "" {
+ if ref.digest != "" {
+ return canonicalReference{
+ namedRepository: ref.namedRepository,
+ digest: ref.digest,
+ }
+ }
+ return ref.namedRepository
+ }
+ if ref.digest == "" {
+ return taggedReference{
+ namedRepository: ref.namedRepository,
+ tag: ref.tag,
+ }
+ }
+
+ return ref
+}
+
+type reference struct {
+ namedRepository
+ tag string
+ digest digest.Digest
+}
+
+func (r reference) String() string {
+ return r.Name() + ":" + r.tag + "@" + r.digest.String()
+}
+
+func (r reference) Tag() string {
+ return r.tag
+}
+
+func (r reference) Digest() digest.Digest {
+ return r.digest
+}
+
+type repository struct {
+ domain string
+ path string
+}
+
+func (r repository) String() string {
+ return r.Name()
+}
+
+func (r repository) Name() string {
+ if r.domain == "" {
+ return r.path
+ }
+ return r.domain + "/" + r.path
+}
+
+func (r repository) Domain() string {
+ return r.domain
+}
+
+func (r repository) Path() string {
+ return r.path
+}
+
+type digestReference digest.Digest
+
+func (d digestReference) String() string {
+ return digest.Digest(d).String()
+}
+
+func (d digestReference) Digest() digest.Digest {
+ return digest.Digest(d)
+}
+
+type taggedReference struct {
+ namedRepository
+ tag string
+}
+
+func (t taggedReference) String() string {
+ return t.Name() + ":" + t.tag
+}
+
+func (t taggedReference) Tag() string {
+ return t.tag
+}
+
+type canonicalReference struct {
+ namedRepository
+ digest digest.Digest
+}
+
+func (c canonicalReference) String() string {
+ return c.Name() + "@" + c.digest.String()
+}
+
+func (c canonicalReference) Digest() digest.Digest {
+ return c.digest
+}
diff --git a/vendor/github.com/containerd/containerd/reference/docker/regexp.go b/vendor/github.com/containerd/containerd/reference/docker/regexp.go
new file mode 100644
index 00000000000..4be3c575e04
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/reference/docker/regexp.go
@@ -0,0 +1,191 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package docker
+
+import "regexp"
+
+var (
+ // alphaNumeric defines the alpha numeric atom, typically a
+ // component of names. This only allows lower case characters and digits.
+ alphaNumeric = `[a-z0-9]+`
+
+ // separator defines the separators allowed to be embedded in name
+ // components. This allow one period, one or two underscore and multiple
+ // dashes. Repeated dashes and underscores are intentionally treated
+ // differently. In order to support valid hostnames as name components,
+ // supporting repeated dash was added. Additionally double underscore is
+ // now allowed as a separator to loosen the restriction for previously
+ // supported names.
+ separator = `(?:[._]|__|[-]*)`
+
+ // nameComponent restricts registry path component names to start
+ // with at least one letter or number, with following parts able to be
+ // separated by one period, one or two underscore and multiple dashes.
+ nameComponent = expression(
+ alphaNumeric,
+ optional(repeated(separator, alphaNumeric)))
+
+ // domainNameComponent restricts the registry domain component of a
+ // repository name to start with a component as defined by DomainRegexp.
+ domainNameComponent = `(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`
+
+ // ipv6address are enclosed between square brackets and may be represented
+ // in many ways, see rfc5952. Only IPv6 in compressed or uncompressed format
+ // are allowed, IPv6 zone identifiers (rfc6874) or Special addresses such as
+ // IPv4-Mapped are deliberately excluded.
+ ipv6address = expression(
+ literal(`[`), `(?:[a-fA-F0-9:]+)`, literal(`]`),
+ )
+
+ // domainName defines the structure of potential domain components
+ // that may be part of image names. This is purposely a subset of what is
+ // allowed by DNS to ensure backwards compatibility with Docker image
+ // names. This includes IPv4 addresses on decimal format.
+ domainName = expression(
+ domainNameComponent,
+ optional(repeated(literal(`.`), domainNameComponent)),
+ )
+
+ // host defines the structure of potential domains based on the URI
+ // Host subcomponent on rfc3986. It may be a subset of DNS domain name,
+ // or an IPv4 address in decimal format, or an IPv6 address between square
+ // brackets (excluding zone identifiers as defined by rfc6874 or special
+ // addresses such as IPv4-Mapped).
+ host = `(?:` + domainName + `|` + ipv6address + `)`
+
+ // allowed by the URI Host subcomponent on rfc3986 to ensure backwards
+ // compatibility with Docker image names.
+ domain = expression(
+ host,
+ optional(literal(`:`), `[0-9]+`))
+
+ // DomainRegexp defines the structure of potential domain components
+ // that may be part of image names. This is purposely a subset of what is
+ // allowed by DNS to ensure backwards compatibility with Docker image
+ // names.
+ DomainRegexp = regexp.MustCompile(domain)
+
+ tag = `[\w][\w.-]{0,127}`
+ // TagRegexp matches valid tag names. From docker/docker:graph/tags.go.
+ TagRegexp = regexp.MustCompile(tag)
+
+ anchoredTag = anchored(tag)
+ // anchoredTagRegexp matches valid tag names, anchored at the start and
+ // end of the matched string.
+ anchoredTagRegexp = regexp.MustCompile(anchoredTag)
+
+ digestPat = `[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`
+ // DigestRegexp matches valid digests.
+ DigestRegexp = regexp.MustCompile(digestPat)
+
+ anchoredDigest = anchored(digestPat)
+ // anchoredDigestRegexp matches valid digests, anchored at the start and
+ // end of the matched string.
+ anchoredDigestRegexp = regexp.MustCompile(anchoredDigest)
+
+ namePat = expression(
+ optional(domain, literal(`/`)),
+ nameComponent,
+ optional(repeated(literal(`/`), nameComponent)))
+ // NameRegexp is the format for the name component of references. The
+ // regexp has capturing groups for the domain and name part omitting
+ // the separating forward slash from either.
+ NameRegexp = regexp.MustCompile(namePat)
+
+ anchoredName = anchored(
+ optional(capture(domain), literal(`/`)),
+ capture(nameComponent,
+ optional(repeated(literal(`/`), nameComponent))))
+ // anchoredNameRegexp is used to parse a name value, capturing the
+ // domain and trailing components.
+ anchoredNameRegexp = regexp.MustCompile(anchoredName)
+
+ referencePat = anchored(capture(namePat),
+ optional(literal(":"), capture(tag)),
+ optional(literal("@"), capture(digestPat)))
+ // ReferenceRegexp is the full supported format of a reference. The regexp
+ // is anchored and has capturing groups for name, tag, and digest
+ // components.
+ ReferenceRegexp = regexp.MustCompile(referencePat)
+
+ identifier = `([a-f0-9]{64})`
+ // IdentifierRegexp is the format for string identifier used as a
+ // content addressable identifier using sha256. These identifiers
+ // are like digests without the algorithm, since sha256 is used.
+ IdentifierRegexp = regexp.MustCompile(identifier)
+
+ shortIdentifier = `([a-f0-9]{6,64})`
+ // ShortIdentifierRegexp is the format used to represent a prefix
+ // of an identifier. A prefix may be used to match a sha256 identifier
+ // within a list of trusted identifiers.
+ ShortIdentifierRegexp = regexp.MustCompile(shortIdentifier)
+
+ anchoredIdentifier = anchored(identifier)
+ // anchoredIdentifierRegexp is used to check or match an
+ // identifier value, anchored at start and end of string.
+ anchoredIdentifierRegexp = regexp.MustCompile(anchoredIdentifier)
+)
+
+// literal compiles s into a literal regular expression, escaping any regexp
+// reserved characters.
+func literal(s string) string {
+ re := regexp.MustCompile(regexp.QuoteMeta(s))
+
+ if _, complete := re.LiteralPrefix(); !complete {
+ panic("must be a literal")
+ }
+
+ return re.String()
+}
+
+// expression defines a full expression, where each regular expression must
+// follow the previous.
+func expression(res ...string) string {
+ var s string
+ for _, re := range res {
+ s += re
+ }
+
+ return s
+}
+
+// optional wraps the expression in a non-capturing group and makes the
+// production optional.
+func optional(res ...string) string {
+ return group(expression(res...)) + `?`
+}
+
+// repeated wraps the regexp in a non-capturing group to get one or more
+// matches.
+func repeated(res ...string) string {
+ return group(expression(res...)) + `+`
+}
+
+// group wraps the regexp in a non-capturing group.
+func group(res ...string) string {
+ return `(?:` + expression(res...) + `)`
+}
+
+// capture wraps the expression in a capturing group.
+func capture(res ...string) string {
+ return `(` + expression(res...) + `)`
+}
+
+// anchored anchors the regular expression by adding start and end delimiters.
+func anchored(res ...string) string {
+ return `^` + expression(res...) + `$`
+}
diff --git a/vendor/github.com/containerd/containerd/reference/docker/sort.go b/vendor/github.com/containerd/containerd/reference/docker/sort.go
new file mode 100644
index 00000000000..984e37528d2
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/reference/docker/sort.go
@@ -0,0 +1,73 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package docker
+
+import (
+ "sort"
+)
+
+// Sort sorts string references preferring higher information references
+// The precedence is as follows:
+// 1. Name + Tag + Digest
+// 2. Name + Tag
+// 3. Name + Digest
+// 4. Name
+// 5. Digest
+// 6. Parse error
+func Sort(references []string) []string {
+ var prefs []Reference
+ var bad []string
+
+ for _, ref := range references {
+ pref, err := ParseAnyReference(ref)
+ if err != nil {
+ bad = append(bad, ref)
+ } else {
+ prefs = append(prefs, pref)
+ }
+ }
+ sort.Slice(prefs, func(a, b int) bool {
+ ar := refRank(prefs[a])
+ br := refRank(prefs[b])
+ if ar == br {
+ return prefs[a].String() < prefs[b].String()
+ }
+ return ar < br
+ })
+ sort.Strings(bad)
+ var refs []string
+ for _, pref := range prefs {
+ refs = append(refs, pref.String())
+ }
+ return append(refs, bad...)
+}
+
+func refRank(ref Reference) uint8 {
+ if _, ok := ref.(Named); ok {
+ if _, ok = ref.(Tagged); ok {
+ if _, ok = ref.(Digested); ok {
+ return 1
+ }
+ return 2
+ }
+ if _, ok = ref.(Digested); ok {
+ return 3
+ }
+ return 4
+ }
+ return 5
+}
diff --git a/vendor/github.com/containerd/containerd/remotes/docker/auth/fetch.go b/vendor/github.com/containerd/containerd/remotes/docker/auth/fetch.go
index c259873d2a2..64c6a38f91a 100644
--- a/vendor/github.com/containerd/containerd/remotes/docker/auth/fetch.go
+++ b/vendor/github.com/containerd/containerd/remotes/docker/auth/fetch.go
@@ -29,7 +29,6 @@ import (
"github.com/containerd/containerd/log"
remoteserrors "github.com/containerd/containerd/remotes/errors"
"github.com/containerd/containerd/version"
- "golang.org/x/net/context/ctxhttp"
)
var (
@@ -115,7 +114,7 @@ func FetchTokenWithOAuth(ctx context.Context, client *http.Client, headers http.
form.Set("access_type", "offline")
}
- req, err := http.NewRequest("POST", to.Realm, strings.NewReader(form.Encode()))
+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, to.Realm, strings.NewReader(form.Encode()))
if err != nil {
return nil, err
}
@@ -127,7 +126,7 @@ func FetchTokenWithOAuth(ctx context.Context, client *http.Client, headers http.
req.Header.Set("User-Agent", "containerd/"+version.Version)
}
- resp, err := ctxhttp.Do(ctx, client, req)
+ resp, err := client.Do(req)
if err != nil {
return nil, err
}
@@ -162,7 +161,7 @@ type FetchTokenResponse struct {
// FetchToken fetches a token using a GET request
func FetchToken(ctx context.Context, client *http.Client, headers http.Header, to TokenOptions) (*FetchTokenResponse, error) {
- req, err := http.NewRequest("GET", to.Realm, nil)
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, to.Realm, nil)
if err != nil {
return nil, err
}
@@ -194,7 +193,7 @@ func FetchToken(ctx context.Context, client *http.Client, headers http.Header, t
req.URL.RawQuery = reqParams.Encode()
- resp, err := ctxhttp.Do(ctx, client, req)
+ resp, err := client.Do(req)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/containerd/containerd/remotes/docker/authorizer.go b/vendor/github.com/containerd/containerd/remotes/docker/authorizer.go
index eaa0e5dbdbc..8fc823144eb 100644
--- a/vendor/github.com/containerd/containerd/remotes/docker/authorizer.go
+++ b/vendor/github.com/containerd/containerd/remotes/docker/authorizer.go
@@ -29,7 +29,6 @@ import (
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/remotes/docker/auth"
remoteerrors "github.com/containerd/containerd/remotes/errors"
- "github.com/sirupsen/logrus"
)
type dockerAuthorizer struct {
@@ -45,13 +44,6 @@ type dockerAuthorizer struct {
onFetchRefreshToken OnFetchRefreshToken
}
-// NewAuthorizer creates a Docker authorizer using the provided function to
-// get credentials for the token server or basic auth.
-// Deprecated: Use NewDockerAuthorizer
-func NewAuthorizer(client *http.Client, f func(string) (string, string, error)) Authorizer {
- return NewDockerAuthorizer(WithAuthClient(client), WithAuthCreds(f))
-}
-
type authorizerConfig struct {
credentials func(string) (string, string, error)
client *http.Client
@@ -319,7 +311,7 @@ func (ah *authHandler) doBearerAuth(ctx context.Context) (token, refreshToken st
}
return resp.Token, resp.RefreshToken, nil
}
- log.G(ctx).WithFields(logrus.Fields{
+ log.G(ctx).WithFields(log.Fields{
"status": errStatus.Status,
"body": string(errStatus.Body),
}).Debugf("token request failed")
diff --git a/vendor/github.com/containerd/containerd/remotes/docker/converter_fuzz.go b/vendor/github.com/containerd/containerd/remotes/docker/converter_fuzz.go
new file mode 100644
index 00000000000..9082053924b
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/remotes/docker/converter_fuzz.go
@@ -0,0 +1,55 @@
+//go:build gofuzz
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package docker
+
+import (
+ "context"
+ "os"
+
+ fuzz "github.com/AdaLogics/go-fuzz-headers"
+ "github.com/containerd/containerd/content/local"
+ "github.com/containerd/containerd/log"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/sirupsen/logrus"
+)
+
+func FuzzConvertManifest(data []byte) int {
+ ctx := context.Background()
+
+ // Do not log the message below
+ // level=warning msg="do nothing for media type: ..."
+ log.G(ctx).Logger.SetLevel(logrus.PanicLevel)
+
+ f := fuzz.NewConsumer(data)
+ desc := ocispec.Descriptor{}
+ err := f.GenerateStruct(&desc)
+ if err != nil {
+ return 0
+ }
+ tmpdir, err := os.MkdirTemp("", "fuzzing-")
+ if err != nil {
+ return 0
+ }
+ cs, err := local.NewStore(tmpdir)
+ if err != nil {
+ return 0
+ }
+ _, _ = ConvertManifest(ctx, cs, desc)
+ return 1
+}
diff --git a/vendor/github.com/containerd/containerd/remotes/docker/fetcher.go b/vendor/github.com/containerd/containerd/remotes/docker/fetcher.go
index 11a75356e80..ecf245933f7 100644
--- a/vendor/github.com/containerd/containerd/remotes/docker/fetcher.go
+++ b/vendor/github.com/containerd/containerd/remotes/docker/fetcher.go
@@ -29,6 +29,7 @@ import (
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/log"
+ digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
@@ -52,18 +53,17 @@ func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.R
return newHTTPReadSeeker(desc.Size, func(offset int64) (io.ReadCloser, error) {
// firstly try fetch via external urls
for _, us := range desc.URLs {
- ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", us))
-
u, err := url.Parse(us)
if err != nil {
- log.G(ctx).WithError(err).Debug("failed to parse")
+ log.G(ctx).WithError(err).Debugf("failed to parse %q", us)
continue
}
if u.Scheme != "http" && u.Scheme != "https" {
log.G(ctx).Debug("non-http(s) alternative url is unsupported")
continue
}
- log.G(ctx).Debug("trying alternative url")
+ ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", u))
+ log.G(ctx).Info("request")
// Try this first, parse it
host := RegistryHost{
@@ -151,8 +151,106 @@ func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.R
})
}
+func (r dockerFetcher) createGetReq(ctx context.Context, host RegistryHost, ps ...string) (*request, int64, error) {
+ headReq := r.request(host, http.MethodHead, ps...)
+ if err := headReq.addNamespace(r.refspec.Hostname()); err != nil {
+ return nil, 0, err
+ }
+
+ headResp, err := headReq.doWithRetries(ctx, nil)
+ if err != nil {
+ return nil, 0, err
+ }
+ if headResp.Body != nil {
+ headResp.Body.Close()
+ }
+ if headResp.StatusCode > 299 {
+ return nil, 0, fmt.Errorf("unexpected HEAD status code %v: %s", headReq.String(), headResp.Status)
+ }
+
+ getReq := r.request(host, http.MethodGet, ps...)
+ if err := getReq.addNamespace(r.refspec.Hostname()); err != nil {
+ return nil, 0, err
+ }
+ return getReq, headResp.ContentLength, nil
+}
+
+func (r dockerFetcher) FetchByDigest(ctx context.Context, dgst digest.Digest) (io.ReadCloser, ocispec.Descriptor, error) {
+ var desc ocispec.Descriptor
+ ctx = log.WithLogger(ctx, log.G(ctx).WithField("digest", dgst))
+
+ hosts := r.filterHosts(HostCapabilityPull)
+ if len(hosts) == 0 {
+ return nil, desc, fmt.Errorf("no pull hosts: %w", errdefs.ErrNotFound)
+ }
+
+ ctx, err := ContextWithRepositoryScope(ctx, r.refspec, false)
+ if err != nil {
+ return nil, desc, err
+ }
+
+ var (
+ getReq *request
+ sz int64
+ firstErr error
+ )
+
+ for _, host := range r.hosts {
+ getReq, sz, err = r.createGetReq(ctx, host, "blobs", dgst.String())
+ if err == nil {
+ break
+ }
+ // Store the error for referencing later
+ if firstErr == nil {
+ firstErr = err
+ }
+ }
+
+ if getReq == nil {
+ // Fall back to the "manifests" endpoint
+ for _, host := range r.hosts {
+ getReq, sz, err = r.createGetReq(ctx, host, "manifests", dgst.String())
+ if err == nil {
+ break
+ }
+ // Store the error for referencing later
+ if firstErr == nil {
+ firstErr = err
+ }
+ }
+ }
+
+ if getReq == nil {
+ if errdefs.IsNotFound(firstErr) {
+ firstErr = fmt.Errorf("could not fetch content %v from remote: %w", dgst, errdefs.ErrNotFound)
+ }
+ if firstErr == nil {
+ firstErr = fmt.Errorf("could not fetch content %v from remote: (unknown)", dgst)
+ }
+ return nil, desc, firstErr
+ }
+
+ seeker, err := newHTTPReadSeeker(sz, func(offset int64) (io.ReadCloser, error) {
+ return r.open(ctx, getReq, "", offset)
+ })
+ if err != nil {
+ return nil, desc, err
+ }
+
+ desc = ocispec.Descriptor{
+ MediaType: "application/octet-stream",
+ Digest: dgst,
+ Size: sz,
+ }
+ return seeker, desc, nil
+}
+
func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64) (_ io.ReadCloser, retErr error) {
- req.header.Set("Accept", strings.Join([]string{mediatype, `*/*`}, ", "))
+ if mediatype == "" {
+ req.header.Set("Accept", "*/*")
+ } else {
+ req.header.Set("Accept", strings.Join([]string{mediatype, `*/*`}, ", "))
+ }
if offset > 0 {
// Note: "Accept-Ranges: bytes" cannot be trusted as some endpoints
diff --git a/vendor/github.com/containerd/containerd/remotes/docker/fetcher_fuzz.go b/vendor/github.com/containerd/containerd/remotes/docker/fetcher_fuzz.go
new file mode 100644
index 00000000000..b98886c5956
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/remotes/docker/fetcher_fuzz.go
@@ -0,0 +1,81 @@
+//go:build gofuzz
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package docker
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+
+ refDocker "github.com/containerd/containerd/reference/docker"
+)
+
+func FuzzFetcher(data []byte) int {
+ dataLen := len(data)
+ if dataLen == 0 {
+ return -1
+ }
+
+ s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+ rw.Header().Set("content-range", fmt.Sprintf("bytes %d-%d/%d", 0, dataLen-1, dataLen))
+ rw.Header().Set("content-length", fmt.Sprintf("%d", dataLen))
+ rw.Write(data)
+ }))
+ defer s.Close()
+
+ u, err := url.Parse(s.URL)
+ if err != nil {
+ return 0
+ }
+
+ f := dockerFetcher{&dockerBase{
+ repository: "nonempty",
+ }}
+ host := RegistryHost{
+ Client: s.Client(),
+ Host: u.Host,
+ Scheme: u.Scheme,
+ Path: u.Path,
+ }
+
+ ctx := context.Background()
+ req := f.request(host, http.MethodGet)
+ rc, err := f.open(ctx, req, "", 0)
+ if err != nil {
+ return 0
+ }
+ b, err := io.ReadAll(rc)
+ if err != nil {
+ return 0
+ }
+
+ expected := data
+ if len(b) != len(expected) {
+ panic("len of request is not equal to len of expected but should be")
+ }
+ return 1
+}
+
+func FuzzParseDockerRef(data []byte) int {
+ _, _ = refDocker.ParseDockerRef(string(data))
+ return 1
+}
diff --git a/vendor/github.com/containerd/containerd/remotes/docker/handler.go b/vendor/github.com/containerd/containerd/remotes/docker/handler.go
index 529cfbc274b..27638ccc02f 100644
--- a/vendor/github.com/containerd/containerd/remotes/docker/handler.go
+++ b/vendor/github.com/containerd/containerd/remotes/docker/handler.go
@@ -30,11 +30,6 @@ import (
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
-var (
- // labelDistributionSource describes the source blob comes from.
- labelDistributionSource = "containerd.io/distribution.source"
-)
-
// AppendDistributionSourceLabel updates the label of blob with distribution source.
func AppendDistributionSourceLabel(manager content.Manager, ref string) (images.HandlerFunc, error) {
refspec, err := reference.Parse(ref)
@@ -108,7 +103,7 @@ func appendDistributionSourceLabel(originLabel, repo string) string {
}
func distributionSourceLabelKey(source string) string {
- return fmt.Sprintf("%s.%s", labelDistributionSource, source)
+ return fmt.Sprintf("%s.%s", labels.LabelDistributionSource, source)
}
// selectRepositoryMountCandidate will select the repo which has longest
diff --git a/vendor/github.com/containerd/containerd/remotes/docker/pusher.go b/vendor/github.com/containerd/containerd/remotes/docker/pusher.go
index 56d60efe93b..ef6e8056a0d 100644
--- a/vendor/github.com/containerd/containerd/remotes/docker/pusher.go
+++ b/vendor/github.com/containerd/containerd/remotes/docker/pusher.go
@@ -191,6 +191,9 @@ func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref str
if resp == nil {
resp, err = req.doWithRetries(ctx, nil)
if err != nil {
+ if errors.Is(err, ErrInvalidAuthorization) {
+ return nil, fmt.Errorf("push access denied, repository does not exist or may require authorization: %w", err)
+ }
return nil, err
}
}
@@ -377,17 +380,24 @@ func (pw *pushWriter) Write(p []byte) (n int, err error) {
// If content has already been written, the bytes
// cannot be written and the caller must reset
- if status.Offset > 0 {
- status.Offset = 0
- status.UpdatedAt = time.Now()
- pw.tracker.SetStatus(pw.ref, status)
- return 0, content.ErrReset
- }
+ status.Offset = 0
+ status.UpdatedAt = time.Now()
+ pw.tracker.SetStatus(pw.ref, status)
+ return 0, content.ErrReset
default:
}
}
n, err = pw.pipe.Write(p)
+ if errors.Is(err, io.ErrClosedPipe) {
+ // if the pipe is closed, we might have the original error on the error
+ // channel - so we should try and get it
+ select {
+ case err2 := <-pw.errC:
+ err = err2
+ default:
+ }
+ }
status.Offset += int64(n)
status.UpdatedAt = time.Now()
pw.tracker.SetStatus(pw.ref, status)
@@ -428,7 +438,7 @@ func (pw *pushWriter) Digest() digest.Digest {
func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
// Check whether read has already thrown an error
- if _, err := pw.pipe.Write([]byte{}); err != nil && err != io.ErrClosedPipe {
+ if _, err := pw.pipe.Write([]byte{}); err != nil && !errors.Is(err, io.ErrClosedPipe) {
return fmt.Errorf("pipe error before commit: %w", err)
}
@@ -439,9 +449,7 @@ func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Di
var resp *http.Response
select {
case err := <-pw.errC:
- if err != nil {
- return err
- }
+ return err
case resp = <-pw.respC:
defer resp.Body.Close()
case p, ok := <-pw.pipeC:
@@ -453,18 +461,17 @@ func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Di
}
pw.pipe.CloseWithError(content.ErrReset)
pw.pipe = p
+
+ // If content has already been written, the bytes
+ // cannot be written again and the caller must reset
status, err := pw.tracker.GetStatus(pw.ref)
if err != nil {
return err
}
- // If content has already been written, the bytes
- // cannot be written again and the caller must reset
- if status.Offset > 0 {
- status.Offset = 0
- status.UpdatedAt = time.Now()
- pw.tracker.SetStatus(pw.ref, status)
- return content.ErrReset
- }
+ status.Offset = 0
+ status.UpdatedAt = time.Now()
+ pw.tracker.SetStatus(pw.ref, status)
+ return content.ErrReset
}
// 201 is specified return status, some registries return
diff --git a/vendor/github.com/containerd/containerd/remotes/docker/resolver.go b/vendor/github.com/containerd/containerd/remotes/docker/resolver.go
index 709fa028de2..3d6c0182f1b 100644
--- a/vendor/github.com/containerd/containerd/remotes/docker/resolver.go
+++ b/vendor/github.com/containerd/containerd/remotes/docker/resolver.go
@@ -32,12 +32,12 @@ import (
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/reference"
"github.com/containerd/containerd/remotes"
- "github.com/containerd/containerd/remotes/docker/schema1"
+ "github.com/containerd/containerd/remotes/docker/schema1" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
+ remoteerrors "github.com/containerd/containerd/remotes/errors"
+ "github.com/containerd/containerd/tracing"
"github.com/containerd/containerd/version"
- digest "github.com/opencontainers/go-digest"
+ "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
- "github.com/sirupsen/logrus"
- "golang.org/x/net/context/ctxhttp"
)
var (
@@ -70,6 +70,9 @@ type Authorizer interface {
// unmodified. It may also add an `Authorization` header as
// "bearer "
// "basic "
+ //
+ // It may return remotes/errors.ErrUnexpectedStatus, which for example,
+ // can be used by the caller to find out the status code returned by the registry.
Authorize(context.Context, *http.Request) error
// AddResponses adds a 401 response for the authorizer to consider when
@@ -95,25 +98,30 @@ type ResolverOptions struct {
Tracker StatusTracker
// Authorizer is used to authorize registry requests
- // Deprecated: use Hosts
+ //
+ // Deprecated: use Hosts.
Authorizer Authorizer
// Credentials provides username and secret given a host.
// If username is empty but a secret is given, that secret
// is interpreted as a long lived token.
- // Deprecated: use Hosts
+ //
+ // Deprecated: use Hosts.
Credentials func(string) (string, string, error)
// Host provides the hostname given a namespace.
- // Deprecated: use Hosts
+ //
+ // Deprecated: use Hosts.
Host func(string) (string, error)
// PlainHTTP specifies to use plain http and not https
- // Deprecated: use Hosts
+ //
+ // Deprecated: use Hosts.
PlainHTTP bool
// Client is the http client to used when making registry requests
- // Deprecated: use Hosts
+ //
+ // Deprecated: use Hosts.
Client *http.Client
}
@@ -140,6 +148,9 @@ func NewResolver(options ResolverOptions) remotes.Resolver {
if options.Headers == nil {
options.Headers = make(http.Header)
+ } else {
+ // make a copy of the headers to avoid race due to concurrent map write
+ options.Headers = options.Headers.Clone()
}
if _, ok := options.Headers["User-Agent"]; !ok {
options.Headers.Set("User-Agent", "containerd/"+version.Version)
@@ -152,7 +163,8 @@ func NewResolver(options ResolverOptions) remotes.Resolver {
images.MediaTypeDockerSchema2Manifest,
images.MediaTypeDockerSchema2ManifestList,
ocispec.MediaTypeImageManifest,
- ocispec.MediaTypeImageIndex, "*/*"}, ", "))
+ ocispec.MediaTypeImageIndex, "*/*",
+ }, ", "))
} else {
resolveHeader["Accept"] = options.Headers["Accept"]
delete(options.Headers, "Accept")
@@ -299,11 +311,11 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp
if resp.StatusCode > 399 {
// Set firstErr when encountering the first non-404 status code.
if firstErr == nil {
- firstErr = fmt.Errorf("pulling from host %s failed with status code %v: %v", host.Host, u, resp.Status)
+ firstErr = remoteerrors.NewUnexpectedStatusErr(resp)
}
continue // try another host
}
- return "", ocispec.Descriptor{}, fmt.Errorf("pulling from host %s failed with unexpected status code %v: %v", host.Host, u, resp.Status)
+ return "", ocispec.Descriptor{}, remoteerrors.NewUnexpectedStatusErr(resp)
}
size := resp.ContentLength
contentType := getManifestMediaType(resp)
@@ -340,26 +352,31 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp
if err != nil {
return "", ocispec.Descriptor{}, err
}
- defer resp.Body.Close()
bodyReader := countingReader{reader: resp.Body}
contentType = getManifestMediaType(resp)
- if dgst == "" {
+ err = func() error {
+ defer resp.Body.Close()
+ if dgst != "" {
+ _, err = io.Copy(io.Discard, &bodyReader)
+ return err
+ }
+
if contentType == images.MediaTypeDockerSchema1Manifest {
b, err := schema1.ReadStripSignature(&bodyReader)
if err != nil {
- return "", ocispec.Descriptor{}, err
+ return err
}
dgst = digest.FromBytes(b)
- } else {
- dgst, err = digest.FromReader(&bodyReader)
- if err != nil {
- return "", ocispec.Descriptor{}, err
- }
+ return nil
}
- } else if _, err := io.Copy(io.Discard, &bodyReader); err != nil {
+
+ dgst, err = digest.FromReader(&bodyReader)
+ return err
+ }()
+ if err != nil {
return "", ocispec.Descriptor{}, err
}
size = bodyReader.bytesRead
@@ -525,13 +542,14 @@ type request struct {
func (r *request) do(ctx context.Context) (*http.Response, error) {
u := r.host.Scheme + "://" + r.host.Host + r.path
- req, err := http.NewRequest(r.method, u, nil)
+ req, err := http.NewRequestWithContext(ctx, r.method, u, nil)
if err != nil {
return nil, err
}
- req.Header = http.Header{} // headers need to be copied to avoid concurrent map access
- for k, v := range r.header {
- req.Header[k] = v
+ if r.header == nil {
+ req.Header = http.Header{}
+ } else {
+ req.Header = r.header.Clone() // headers need to be copied to avoid concurrent map access
}
if r.body != nil {
body, err := r.body()
@@ -551,7 +569,7 @@ func (r *request) do(ctx context.Context) (*http.Response, error) {
return nil, fmt.Errorf("failed to authorize: %w", err)
}
- var client = &http.Client{}
+ client := &http.Client{}
if r.host.Client != nil {
*client = *r.host.Client
}
@@ -566,11 +584,18 @@ func (r *request) do(ctx context.Context) (*http.Response, error) {
return nil
}
}
-
- resp, err := ctxhttp.Do(ctx, client, req)
+ _, httpSpan := tracing.StartSpan(
+ ctx,
+ tracing.Name("remotes.docker.resolver", "HTTPRequest"),
+ tracing.WithHTTPRequest(req),
+ )
+ defer httpSpan.End()
+ resp, err := client.Do(req)
if err != nil {
+ httpSpan.SetStatus(err)
return nil, fmt.Errorf("failed to do request: %w", err)
}
+ httpSpan.SetAttributes(tracing.HTTPStatusCodeAttributes(resp.StatusCode)...)
log.G(ctx).WithFields(responseFields(resp)).Debug("fetch response received")
return resp, nil
}
@@ -630,7 +655,7 @@ func (r *request) String() string {
return r.host.Scheme + "://" + r.host.Host + r.path
}
-func requestFields(req *http.Request) logrus.Fields {
+func requestFields(req *http.Request) log.Fields {
fields := map[string]interface{}{
"request.method": req.Method,
}
@@ -648,10 +673,10 @@ func requestFields(req *http.Request) logrus.Fields {
}
}
- return logrus.Fields(fields)
+ return fields
}
-func responseFields(resp *http.Response) logrus.Fields {
+func responseFields(resp *http.Response) log.Fields {
fields := map[string]interface{}{
"response.status": resp.Status,
}
@@ -666,7 +691,7 @@ func responseFields(resp *http.Response) logrus.Fields {
}
}
- return logrus.Fields(fields)
+ return fields
}
// IsLocalhost checks if the registry host is local.
diff --git a/vendor/github.com/containerd/containerd/remotes/docker/schema1/converter.go b/vendor/github.com/containerd/containerd/remotes/docker/schema1/converter.go
index efa4e8d6eeb..8c9e520cd27 100644
--- a/vendor/github.com/containerd/containerd/remotes/docker/schema1/converter.go
+++ b/vendor/github.com/containerd/containerd/remotes/docker/schema1/converter.go
@@ -14,6 +14,9 @@
limitations under the License.
*/
+// Package schema1 provides a converter to fetch an image formatted in Docker Image Manifest v2, Schema 1.
+//
+// Deprecated: use images formatted in Docker Image Manifest v2, Schema 2, or OCI Image Spec v1.
package schema1
import (
@@ -33,6 +36,7 @@ import (
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images"
+ "github.com/containerd/containerd/labels"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/remotes"
digest "github.com/opencontainers/go-digest"
@@ -363,12 +367,12 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
cinfo := content.Info{
Digest: desc.Digest,
Labels: map[string]string{
- "containerd.io/uncompressed": state.diffID.String(),
+ labels.LabelUncompressed: state.diffID.String(),
labelDockerSchema1EmptyLayer: strconv.FormatBool(state.empty),
},
}
- if _, err := c.contentStore.Update(ctx, cinfo, "labels.containerd.io/uncompressed", fmt.Sprintf("labels.%s", labelDockerSchema1EmptyLayer)); err != nil {
+ if _, err := c.contentStore.Update(ctx, cinfo, "labels."+labels.LabelUncompressed, fmt.Sprintf("labels.%s", labelDockerSchema1EmptyLayer)); err != nil {
return fmt.Errorf("failed to update uncompressed label: %w", err)
}
@@ -387,7 +391,7 @@ func (c *Converter) reuseLabelBlobState(ctx context.Context, desc ocispec.Descri
}
desc.Size = cinfo.Size
- diffID, ok := cinfo.Labels["containerd.io/uncompressed"]
+ diffID, ok := cinfo.Labels[labels.LabelUncompressed]
if !ok {
return false, nil
}
@@ -406,7 +410,7 @@ func (c *Converter) reuseLabelBlobState(ctx context.Context, desc ocispec.Descri
bState := blobState{empty: isEmpty}
if bState.diffID, err = digest.Parse(diffID); err != nil {
- log.G(ctx).WithField("id", desc.Digest).Warnf("failed to parse digest from label containerd.io/uncompressed: %v", diffID)
+ log.G(ctx).WithField("id", desc.Digest).Warnf("failed to parse digest from label %s: %v", labels.LabelUncompressed, diffID)
return false, nil
}
diff --git a/vendor/github.com/containerd/containerd/remotes/errors/errors.go b/vendor/github.com/containerd/containerd/remotes/errors/errors.go
index 67ccb23df6e..f60ff0fc286 100644
--- a/vendor/github.com/containerd/containerd/remotes/errors/errors.go
+++ b/vendor/github.com/containerd/containerd/remotes/errors/errors.go
@@ -33,7 +33,7 @@ type ErrUnexpectedStatus struct {
}
func (e ErrUnexpectedStatus) Error() string {
- return fmt.Sprintf("unexpected status: %s", e.Status)
+ return fmt.Sprintf("unexpected status from %s request to %s: %s", e.RequestMethod, e.RequestURL, e.Status)
}
// NewUnexpectedStatusErr creates an ErrUnexpectedStatus from HTTP response
diff --git a/vendor/github.com/containerd/containerd/remotes/handlers.go b/vendor/github.com/containerd/containerd/remotes/handlers.go
index 4d91ed2e54d..0ff39179c2b 100644
--- a/vendor/github.com/containerd/containerd/remotes/handlers.go
+++ b/vendor/github.com/containerd/containerd/remotes/handlers.go
@@ -17,6 +17,7 @@
package remotes
import (
+ "bytes"
"context"
"errors"
"fmt"
@@ -27,10 +28,10 @@ import (
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images"
+ "github.com/containerd/containerd/labels"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/platforms"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
- "github.com/sirupsen/logrus"
"golang.org/x/sync/semaphore"
)
@@ -90,7 +91,7 @@ func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string {
// recursive fetch.
func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc {
return func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
- ctx = log.WithLogger(ctx, log.G(ctx).WithFields(logrus.Fields{
+ ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{
"digest": desc.Digest,
"mediatype": desc.MediaType,
"size": desc.Size,
@@ -100,20 +101,21 @@ func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc
case images.MediaTypeDockerSchema1Manifest:
return nil, fmt.Errorf("%v not supported", desc.MediaType)
default:
- err := fetch(ctx, ingester, fetcher, desc)
+ err := Fetch(ctx, ingester, fetcher, desc)
+ if errdefs.IsAlreadyExists(err) {
+ return nil, nil
+ }
return nil, err
}
}
}
-func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor) error {
+// Fetch fetches the given digest into the provided ingester
+func Fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor) error {
log.G(ctx).Debug("fetch")
cw, err := content.OpenWriter(ctx, ingester, content.WithRef(MakeRefKey(ctx, desc)), content.WithDescriptor(desc))
if err != nil {
- if errdefs.IsAlreadyExists(err) {
- return nil
- }
return err
}
defer cw.Close()
@@ -135,7 +137,11 @@ func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc
if err != nil && !errdefs.IsAlreadyExists(err) {
return fmt.Errorf("failed commit on ref %q: %w", ws.Ref, err)
}
- return nil
+ return err
+ }
+
+ if desc.Size == int64(len(desc.Data)) {
+ return content.Copy(ctx, cw, bytes.NewReader(desc.Data), desc.Size, desc.Digest)
}
rc, err := fetcher.Fetch(ctx, desc)
@@ -151,7 +157,7 @@ func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc
// using a writer from the pusher.
func PushHandler(pusher Pusher, provider content.Provider) images.HandlerFunc {
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
- ctx = log.WithLogger(ctx, log.G(ctx).WithFields(logrus.Fields{
+ ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{
"digest": desc.Digest,
"mediatype": desc.MediaType,
"size": desc.Size,
@@ -197,17 +203,26 @@ func push(ctx context.Context, provider content.Provider, pusher Pusher, desc oc
//
// Base handlers can be provided which will be called before any push specific
// handlers.
-func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, store content.Store, limiter *semaphore.Weighted, platform platforms.MatchComparer, wrapper func(h images.Handler) images.Handler) error {
+//
+// If the passed in content.Provider is also a content.InfoProvider (such as
+// content.Manager) then this will also annotate the distribution sources using
+// labels prefixed with "containerd.io/distribution.source".
+func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, store content.Provider, limiter *semaphore.Weighted, platform platforms.MatchComparer, wrapper func(h images.Handler) images.Handler) error {
var m sync.Mutex
- manifestStack := []ocispec.Descriptor{}
+ manifests := []ocispec.Descriptor{}
+ indexStack := []ocispec.Descriptor{}
filterHandler := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
switch desc.MediaType {
- case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest,
- images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+ case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
m.Lock()
- manifestStack = append(manifestStack, desc)
+ manifests = append(manifests, desc)
+ m.Unlock()
+ return nil, images.ErrStopHandler
+ case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+ m.Lock()
+ indexStack = append(indexStack, desc)
m.Unlock()
return nil, images.ErrStopHandler
default:
@@ -219,13 +234,14 @@ func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, st
platformFilterhandler := images.FilterPlatforms(images.ChildrenHandler(store), platform)
- annotateHandler := annotateDistributionSourceHandler(platformFilterhandler, store)
+ var handler images.Handler
+ if m, ok := store.(content.InfoProvider); ok {
+ annotateHandler := annotateDistributionSourceHandler(platformFilterhandler, m)
+ handler = images.Handlers(annotateHandler, filterHandler, pushHandler)
+ } else {
+ handler = images.Handlers(platformFilterhandler, filterHandler, pushHandler)
+ }
- var handler images.Handler = images.Handlers(
- annotateHandler,
- filterHandler,
- pushHandler,
- )
if wrapper != nil {
handler = wrapper(handler)
}
@@ -234,16 +250,18 @@ func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, st
return err
}
+ if err := images.Dispatch(ctx, pushHandler, limiter, manifests...); err != nil {
+ return err
+ }
+
// Iterate in reverse order as seen, parent always uploaded after child
- for i := len(manifestStack) - 1; i >= 0; i-- {
- _, err := pushHandler(ctx, manifestStack[i])
+ for i := len(indexStack) - 1; i >= 0; i-- {
+ err := images.Dispatch(ctx, pushHandler, limiter, indexStack[i])
if err != nil {
// TODO(estesp): until we have a more complete method for index push, we need to report
// missing dependencies in an index/manifest list by sensing the "400 Bad Request"
// as a marker for this problem
- if (manifestStack[i].MediaType == ocispec.MediaTypeImageIndex ||
- manifestStack[i].MediaType == images.MediaTypeDockerSchema2ManifestList) &&
- errors.Unwrap(err) != nil && strings.Contains(errors.Unwrap(err).Error(), "400 Bad Request") {
+ if errors.Unwrap(err) != nil && strings.Contains(errors.Unwrap(err).Error(), "400 Bad Request") {
return fmt.Errorf("manifest list/index references to blobs and/or manifests are missing in your target registry: %w", err)
}
return err
@@ -327,14 +345,15 @@ func FilterManifestByPlatformHandler(f images.HandlerFunc, m platforms.Matcher)
// annotateDistributionSourceHandler add distribution source label into
// annotation of config or blob descriptor.
-func annotateDistributionSourceHandler(f images.HandlerFunc, manager content.Manager) images.HandlerFunc {
+func annotateDistributionSourceHandler(f images.HandlerFunc, provider content.InfoProvider) images.HandlerFunc {
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
children, err := f(ctx, desc)
if err != nil {
return nil, err
}
- // only add distribution source for the config or blob data descriptor
+ // Distribution source is only used for config or blob but may be inherited from
+ // a manifest or manifest list
switch desc.MediaType {
case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest,
images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
@@ -342,16 +361,32 @@ func annotateDistributionSourceHandler(f images.HandlerFunc, manager content.Man
return children, nil
}
+ // parentInfo can be used to inherit info for non-existent blobs
+ var parentInfo *content.Info
+
for i := range children {
child := children[i]
- info, err := manager.Info(ctx, child.Digest)
+ info, err := provider.Info(ctx, child.Digest)
if err != nil {
- return nil, err
+ if !errdefs.IsNotFound(err) {
+ return nil, err
+ }
+ if parentInfo == nil {
+ pi, err := provider.Info(ctx, desc.Digest)
+ if err != nil {
+ return nil, err
+ }
+ parentInfo = &pi
+ }
+ // Blob may not exist locally, annotate with parent labels for cross repo
+ // mount or fetch. Parent sources may apply to all children since most
+ // registries enforce that children exist before the manifests.
+ info = *parentInfo
}
for k, v := range info.Labels {
- if !strings.HasPrefix(k, "containerd.io/distribution.source.") {
+ if !strings.HasPrefix(k, labels.LabelDistributionSource+".") {
continue
}
diff --git a/vendor/github.com/containerd/containerd/remotes/resolver.go b/vendor/github.com/containerd/containerd/remotes/resolver.go
index 624b14f05d6..f200c84bc7d 100644
--- a/vendor/github.com/containerd/containerd/remotes/resolver.go
+++ b/vendor/github.com/containerd/containerd/remotes/resolver.go
@@ -21,6 +21,7 @@ import (
"io"
"github.com/containerd/containerd/content"
+ "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
@@ -33,7 +34,7 @@ type Resolver interface {
// reference a specific host or be matched against a specific handler.
//
// The returned name should be used to identify the referenced entity.
- // Dependending on the remote namespace, this may be immutable or mutable.
+ // Depending on the remote namespace, this may be immutable or mutable.
// While the name may differ from ref, it should itself be a valid ref.
//
// If the resolution fails, an error will be returned.
@@ -50,12 +51,23 @@ type Resolver interface {
Pusher(ctx context.Context, ref string) (Pusher, error)
}
-// Fetcher fetches content
+// Fetcher fetches content.
+// A fetcher implementation may implement the FetcherByDigest interface too.
type Fetcher interface {
// Fetch the resource identified by the descriptor.
Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error)
}
+// FetcherByDigest fetches content by the digest.
+type FetcherByDigest interface {
+ // FetchByDigest fetches the resource identified by the digest.
+ //
+ // FetcherByDigest usually returns an incomplete descriptor.
+ // Typically, the media type is always set to "application/octet-stream",
+ // and the annotations are unset.
+ FetchByDigest(ctx context.Context, dgst digest.Digest) (io.ReadCloser, ocispec.Descriptor, error)
+}
+
// Pusher pushes content
type Pusher interface {
// Push returns a content writer for the given resource identified
diff --git a/vendor/github.com/containerd/containerd/tracing/helpers.go b/vendor/github.com/containerd/containerd/tracing/helpers.go
new file mode 100644
index 00000000000..981da6c7953
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/tracing/helpers.go
@@ -0,0 +1,94 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package tracing
+
+import (
+ "encoding/json"
+ "fmt"
+ "strings"
+
+ "go.opentelemetry.io/otel/attribute"
+)
+
+const (
+ spanDelimiter = "."
+)
+
+func makeSpanName(names ...string) string {
+ return strings.Join(names, spanDelimiter)
+}
+
+func any(k string, v interface{}) attribute.KeyValue {
+ if v == nil {
+ return attribute.String(k, "")
+ }
+
+ switch typed := v.(type) {
+ case bool:
+ return attribute.Bool(k, typed)
+ case []bool:
+ return attribute.BoolSlice(k, typed)
+ case int:
+ return attribute.Int(k, typed)
+ case []int:
+ return attribute.IntSlice(k, typed)
+ case int8:
+ return attribute.Int(k, int(typed))
+ case []int8:
+ ls := make([]int, 0, len(typed))
+ for _, i := range typed {
+ ls = append(ls, int(i))
+ }
+ return attribute.IntSlice(k, ls)
+ case int16:
+ return attribute.Int(k, int(typed))
+ case []int16:
+ ls := make([]int, 0, len(typed))
+ for _, i := range typed {
+ ls = append(ls, int(i))
+ }
+ return attribute.IntSlice(k, ls)
+ case int32:
+ return attribute.Int64(k, int64(typed))
+ case []int32:
+ ls := make([]int64, 0, len(typed))
+ for _, i := range typed {
+ ls = append(ls, int64(i))
+ }
+ return attribute.Int64Slice(k, ls)
+ case int64:
+ return attribute.Int64(k, typed)
+ case []int64:
+ return attribute.Int64Slice(k, typed)
+ case float64:
+ return attribute.Float64(k, typed)
+ case []float64:
+ return attribute.Float64Slice(k, typed)
+ case string:
+ return attribute.String(k, typed)
+ case []string:
+ return attribute.StringSlice(k, typed)
+ }
+
+ if stringer, ok := v.(fmt.Stringer); ok {
+ return attribute.String(k, stringer.String())
+ }
+ if b, err := json.Marshal(v); b != nil && err == nil {
+ return attribute.String(k, string(b))
+ }
+ return attribute.String(k, fmt.Sprintf("%v", v))
+}
diff --git a/vendor/github.com/containerd/containerd/tracing/log.go b/vendor/github.com/containerd/containerd/tracing/log.go
new file mode 100644
index 00000000000..98fa16f931e
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/tracing/log.go
@@ -0,0 +1,66 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package tracing
+
+import (
+ "github.com/sirupsen/logrus"
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/trace"
+)
+
+// NewLogrusHook creates a new logrus hook
+func NewLogrusHook() *LogrusHook {
+ return &LogrusHook{}
+}
+
+// LogrusHook is a logrus hook which adds logrus events to active spans.
+// If the span is not recording or the span context is invalid, the hook is a no-op.
+type LogrusHook struct{}
+
+// Levels returns the logrus levels that this hook is interested in.
+func (h *LogrusHook) Levels() []logrus.Level {
+ return logrus.AllLevels
+}
+
+// Fire is called when a log event occurs.
+func (h *LogrusHook) Fire(entry *logrus.Entry) error {
+ span := trace.SpanFromContext(entry.Context)
+ if span == nil {
+ return nil
+ }
+
+ if !span.SpanContext().IsValid() || !span.IsRecording() {
+ return nil
+ }
+
+ span.AddEvent(
+ entry.Message,
+ trace.WithAttributes(logrusDataToAttrs(entry.Data)...),
+ trace.WithAttributes(attribute.String("level", entry.Level.String())),
+ trace.WithTimestamp(entry.Time),
+ )
+
+ return nil
+}
+
+func logrusDataToAttrs(data logrus.Fields) []attribute.KeyValue {
+ attrs := make([]attribute.KeyValue, 0, len(data))
+ for k, v := range data {
+ attrs = append(attrs, any(k, v))
+ }
+ return attrs
+}
diff --git a/vendor/github.com/containerd/containerd/tracing/tracing.go b/vendor/github.com/containerd/containerd/tracing/tracing.go
new file mode 100644
index 00000000000..7fe7bfd5bf2
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/tracing/tracing.go
@@ -0,0 +1,117 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package tracing
+
+import (
+ "context"
+ "net/http"
+
+ "go.opentelemetry.io/otel"
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/codes"
+ semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
+ httpconv "go.opentelemetry.io/otel/semconv/v1.17.0/httpconv"
+ "go.opentelemetry.io/otel/trace"
+)
+
+// StartConfig defines configuration for a new span object.
+type StartConfig struct {
+ spanOpts []trace.SpanStartOption
+}
+
+type SpanOpt func(config *StartConfig)
+
+// WithHTTPRequest marks span as a HTTP request operation from client to server.
+// It'll append attributes from the HTTP request object and mark it with `SpanKindClient` type.
+func WithHTTPRequest(request *http.Request) SpanOpt {
+ return func(config *StartConfig) {
+ config.spanOpts = append(config.spanOpts,
+ trace.WithSpanKind(trace.SpanKindClient), // A client making a request to a server
+ trace.WithAttributes(httpconv.ClientRequest(request)...), // Add HTTP attributes
+ )
+ }
+}
+
+// StartSpan starts child span in a context.
+func StartSpan(ctx context.Context, opName string, opts ...SpanOpt) (context.Context, *Span) {
+ config := StartConfig{}
+ for _, fn := range opts {
+ fn(&config)
+ }
+ tracer := otel.Tracer("")
+ if parent := trace.SpanFromContext(ctx); parent != nil && parent.SpanContext().IsValid() {
+ tracer = parent.TracerProvider().Tracer("")
+ }
+ ctx, span := tracer.Start(ctx, opName, config.spanOpts...)
+ return ctx, &Span{otelSpan: span}
+}
+
+// SpanFromContext returns the current Span from the context.
+func SpanFromContext(ctx context.Context) *Span {
+ return &Span{
+ otelSpan: trace.SpanFromContext(ctx),
+ }
+}
+
+// Span is wrapper around otel trace.Span.
+// Span is the individual component of a trace. It represents a
+// single named and timed operation of a workflow that is traced.
+type Span struct {
+ otelSpan trace.Span
+}
+
+// End completes the span.
+func (s *Span) End() {
+ s.otelSpan.End()
+}
+
+// AddEvent adds an event with provided name and options.
+func (s *Span) AddEvent(name string, options ...trace.EventOption) {
+ s.otelSpan.AddEvent(name, options...)
+}
+
+// SetStatus sets the status of the current span.
+// If an error is encountered, it records the error and sets span status to Error.
+func (s *Span) SetStatus(err error) {
+ if err != nil {
+ s.otelSpan.RecordError(err)
+ s.otelSpan.SetStatus(codes.Error, err.Error())
+ } else {
+ s.otelSpan.SetStatus(codes.Ok, "")
+ }
+}
+
+// SetAttributes sets kv as attributes of the span.
+func (s *Span) SetAttributes(kv ...attribute.KeyValue) {
+ s.otelSpan.SetAttributes(kv...)
+}
+
+// Name sets the span name by joining a list of strings in dot separated format.
+func Name(names ...string) string {
+ return makeSpanName(names...)
+}
+
+// Attribute takes a key value pair and returns attribute.KeyValue type.
+func Attribute(k string, v interface{}) attribute.KeyValue {
+ return any(k, v)
+}
+
+// HTTPStatusCodeAttributes generates attributes of the HTTP namespace as specified by the OpenTelemetry
+// specification for a span.
+func HTTPStatusCodeAttributes(code int) []attribute.KeyValue {
+ return []attribute.KeyValue{semconv.HTTPStatusCodeKey.Int(code)}
+}
diff --git a/vendor/github.com/containerd/containerd/version/version.go b/vendor/github.com/containerd/containerd/version/version.go
index 6e76097d271..350f81eaced 100644
--- a/vendor/github.com/containerd/containerd/version/version.go
+++ b/vendor/github.com/containerd/containerd/version/version.go
@@ -23,7 +23,7 @@ var (
Package = "github.com/containerd/containerd"
// Version holds the complete version number. Filled in at linking time.
- Version = "1.6.12+unknown"
+ Version = "1.7.6+unknown"
// Revision is filled with the VCS (e.g. git) revision being used to build
// the program at linking time.
diff --git a/vendor/github.com/dapr/go-sdk/LICENSE b/vendor/github.com/dapr/go-sdk/LICENSE
new file mode 100644
index 00000000000..c2c85ba5774
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/LICENSE
@@ -0,0 +1,204 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2021 The Dapr Authors.
+
+ and others that have contributed code to the public domain.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/dapr/go-sdk/actor/actor.go b/vendor/github.com/dapr/go-sdk/actor/actor.go
new file mode 100644
index 00000000000..c14d65506e6
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/actor.go
@@ -0,0 +1,225 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package actor
+
+import (
+ "context"
+ "sync"
+ "time"
+)
+
+// Client is the interface that should be impl by user's actor client.
+type Client interface {
+ // Type defines the type of the actor server to be invoke
+ Type() string
+ // ID should be unique, the actor server with target ID would be created before server processing the invocation.
+ ID() string
+}
+
+// Deprecated: Server is deprecated in favour of ServerContext.
+type Server interface {
+ // ID is impl by ServerImplBase. It can be called by user defined actor function to get the actor ID of it's instance.
+ ID() string
+ // SetID is impl by ServerImplBase. It is called by actor container to inject actor ID of the instance, and should
+ // not called by user
+ SetID(string)
+ // Type is defined by user
+ Type() string
+ // SetStateManager is impl by ServerImplBase to inject StateManager to this actor instance
+ // Deprecated: SetStateManager is deprecated in favour of SetStateManagerContext.
+ SetStateManager(StateManager)
+ // SaveState is impl by ServerImplBase, It saves the state cache of this actor instance to state store component by calling api of daprd.
+ // Save state is called at two places: 1. On invocation of this actor instance. 2. When new actor starts.
+ SaveState() error
+
+ WithContext() ServerContext
+}
+
+// ServerContext is the interface that would be impl by user's actor server with ServerImplBaseCtx
+/*
+Actor user should only impls func Type() string, and his user-defined-method, Other function could be impl by
+combining ServerImplBaseCtx.
+*/
+type ServerContext interface {
+ // ID is impl by ServerImplBase. It can be called by user defined actor function to get the actor ID of it's instance.
+ ID() string
+ // SetID is impl by ServerImplBase. It is called by actor container to inject actor ID of the instance, and should
+ // not called by user
+ SetID(string)
+ // Type is defined by user
+ Type() string
+ // SetStateManager is impl by ServerImplBase to inject StateManager to this actor instance
+ SetStateManager(StateManagerContext)
+ // SaveState is impl by ServerImplBase, It saves the state cache of this actor instance to state store component by calling api of daprd.
+ // Save state is called at two places: 1. On invocation of this actor instance. 2. When new actor starts.
+ SaveState(context.Context) error
+}
+
+type ReminderCallee interface {
+ ReminderCall(string, []byte, string, string)
+}
+
+type (
+ Factory func() Server
+ FactoryContext func() ServerContext
+)
+
+// Deprecated: ServerImplBase is deprecated in favour of ServerImplBaseCtx.
+type ServerImplBase struct {
+ stateManager StateManager
+ ctx ServerImplBaseCtx
+ lock sync.RWMutex
+}
+
+type ServerImplBaseCtx struct {
+ stateManager StateManagerContext
+ once sync.Once
+ id string
+ lock sync.RWMutex
+}
+
+// Deprecated: Use ServerImplBaseCtx instead.
+func (b *ServerImplBase) SetStateManager(stateManager StateManager) {
+ b.lock.Lock()
+ b.ctx.lock.Lock()
+ defer b.lock.Unlock()
+ defer b.ctx.lock.Unlock()
+ b.stateManager = stateManager
+ b.ctx.stateManager = stateManager.WithContext()
+}
+
+// GetStateManager can be called by user-defined-method, to get state manager
+// of this actor instance.
+// Deprecated: Use ServerImplBaseCtx instead.
+func (b *ServerImplBase) GetStateManager() StateManager {
+ b.ctx.lock.RLock()
+ defer b.ctx.lock.RUnlock()
+ return b.stateManager
+}
+
+// Deprecated: Use ServerImplBaseCtx instead.
+func (b *ServerImplBase) ID() string {
+ b.ctx.lock.RLock()
+ defer b.ctx.lock.RUnlock()
+ return b.ctx.id
+}
+
+// Deprecated: Use ServerImplBaseCtx instead.
+func (b *ServerImplBase) SetID(id string) {
+ b.lock.RLock()
+ defer b.lock.RUnlock()
+ b.ctx.SetID(id)
+}
+
+// SaveState is to saves the state cache of this actor instance to state store
+// component by calling api of daprd.
+// Deprecated: Use ServerImplBaseCtx instead.
+func (b *ServerImplBase) SaveState() error {
+ b.lock.RLock()
+ defer b.lock.RUnlock()
+ return b.ctx.SaveState(context.Background())
+}
+
+// Deprecated: Use ServerImplBaseCtx instead.
+func (b *ServerImplBase) WithContext() *ServerImplBaseCtx {
+ b.ctx.lock.RLock()
+ defer b.ctx.lock.RUnlock()
+ return &b.ctx
+}
+
+func (b *ServerImplBaseCtx) SetStateManager(stateManager StateManagerContext) {
+ b.lock.Lock()
+ defer b.lock.Unlock()
+ b.stateManager = stateManager
+}
+
+// GetStateManager can be called by user-defined-method, to get state manager
+// of this actor instance.
+func (b *ServerImplBaseCtx) GetStateManager() StateManagerContext {
+ b.lock.RLock()
+ defer b.lock.RUnlock()
+ return b.stateManager
+}
+
+func (b *ServerImplBaseCtx) ID() string {
+ b.lock.RLock()
+ defer b.lock.RUnlock()
+ return b.id
+}
+
+func (b *ServerImplBaseCtx) SetID(id string) {
+ b.lock.RLock()
+ defer b.lock.RUnlock()
+ b.once.Do(func() {
+ b.id = id
+ })
+}
+
+// SaveState is to saves the state cache of this actor instance to state store
+// component by calling api of daprd.
+func (b *ServerImplBaseCtx) SaveState(ctx context.Context) error {
+ b.lock.RLock()
+ defer b.lock.RUnlock()
+
+ if b.stateManager != nil {
+ return b.stateManager.Save(ctx)
+ }
+
+ return nil
+}
+
+// Deprecated: StateManager is deprecated in favour of StateManagerContext.
+type StateManager interface {
+ // Add is to add new state store with @stateName and @value
+ Add(stateName string, value any) error
+ // Get is to get state store of @stateName with type @reply
+ Get(stateName string, reply any) error
+ // Set is to set new state store with @stateName and @value
+ Set(stateName string, value any) error
+ // Remove is to remove state store with @stateName
+ Remove(stateName string) error
+ // Contains is to check if state store contains @stateName
+ Contains(stateName string) (bool, error)
+ // Save is to saves the state cache of this actor instance to state store component by calling api of daprd.
+ Save() error
+ // Flush is called by StateManager after Save
+ Flush()
+
+ // Returns a new StateManagerContext with the same state as this StateManager
+ // but uses context.
+ WithContext() StateManagerContext
+}
+
+type StateManagerContext interface {
+ // Add is to add new state store with @stateName and @value
+ Add(ctx context.Context, stateName string, value any) error
+ // Get is to get state store of @stateName with type @reply
+ Get(ctx context.Context, stateName string, reply any) error
+ // Set sets a state store with @stateName and @value.
+ Set(ctx context.Context, stateName string, value any) error
+ // SetWithTTL sets a state store with @stateName and @value, for the given
+ // TTL. After the TTL has passed, the value will no longer be available with
+ // `Get`. Always preferred over `Set`.
+ // NOTE: SetWithTTL is in feature preview as of v1.11, and only available
+ // with the `ActorStateTTL` feature enabled in Dapr.
+ SetWithTTL(ctx context.Context, stateName string, value any, ttl time.Duration) error
+ // Remove is to remove state store with @stateName
+ Remove(ctx context.Context, stateName string) error
+ // Contains is to check if state store contains @stateName
+ Contains(ctx context.Context, stateName string) (bool, error)
+ // Save is to saves the state cache of this actor instance to state store component by calling api of daprd.
+ Save(ctx context.Context) error
+ // Flush is called by StateManager after Save
+ Flush(ctx context.Context)
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/api/reminder.go b/vendor/github.com/dapr/go-sdk/actor/api/reminder.go
new file mode 100644
index 00000000000..5fc2f78ee76
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/api/reminder.go
@@ -0,0 +1,21 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package api
+
+type ActorReminderParams struct {
+ Data []byte `json:"data"`
+ DueTime string `json:"dueTime"`
+ Period string `json:"period"`
+ TTL string `json:"ttl"`
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/api/runtime.go b/vendor/github.com/dapr/go-sdk/actor/api/runtime.go
new file mode 100644
index 00000000000..58c0eb6446d
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/api/runtime.go
@@ -0,0 +1,22 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package api
+
+type ActorRuntimeConfig struct {
+ RegisteredActorTypes []string `json:"entities"`
+ ActorIdleTimeout string `json:"actorIdleTimeout"`
+ ActorScanInterval string `json:"actorScanInterval"`
+ DrainOngingCallTimeout string `json:"drainOngoingCallTimeout"`
+ DrainBalancedActors bool `json:"drainRebalancedActors"`
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/api/timer.go b/vendor/github.com/dapr/go-sdk/actor/api/timer.go
new file mode 100644
index 00000000000..ad118283ac5
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/api/timer.go
@@ -0,0 +1,22 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package api
+
+type ActorTimerParam struct {
+ CallBack string `json:"callback"`
+ Data []byte `json:"data"`
+ DueTime string `json:"dueTime"`
+ Period string `json:"period"`
+ TTL string `json:"ttl"`
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/codec/codec.go b/vendor/github.com/dapr/go-sdk/actor/codec/codec.go
new file mode 100644
index 00000000000..ea96c47b50d
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/codec/codec.go
@@ -0,0 +1,44 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package codec
+
+import (
+ "fmt"
+)
+
+// Codec is serializer interface.
+type Codec interface {
+ Marshal(interface{}) ([]byte, error)
+ Unmarshal([]byte, interface{}) error
+}
+
+// Factory is factory of codec.
+type Factory func() Codec
+
+// codecFactoryMap stores.
+var codecFactoryMap = make(map[string]Factory)
+
+// SetActorCodec set Actor's Codec.
+func SetActorCodec(name string, f Factory) {
+ codecFactoryMap[name] = f
+}
+
+// GetActorCodec gets the target codec instance.
+func GetActorCodec(name string) (Codec, error) {
+ f, ok := codecFactoryMap[name]
+ if !ok {
+ return nil, fmt.Errorf("no actor codec implement named %s", name)
+ }
+ return f(), nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/codec/constant/constant.go b/vendor/github.com/dapr/go-sdk/actor/codec/constant/constant.go
new file mode 100644
index 00000000000..556d0589c5e
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/codec/constant/constant.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package constant
+
+// DefaultSerializerType is default actor invocation serialization type json.
+const DefaultSerializerType = "json"
+
+// YamlSerializerType is yaml actor invocation serialization type.
+const YamlSerializerType = "yaml"
diff --git a/vendor/github.com/dapr/go-sdk/actor/codec/impl/json.go b/vendor/github.com/dapr/go-sdk/actor/codec/impl/json.go
new file mode 100644
index 00000000000..adde1266662
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/codec/impl/json.go
@@ -0,0 +1,38 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package impl
+
+import (
+ "encoding/json"
+
+ "github.com/dapr/go-sdk/actor/codec"
+ "github.com/dapr/go-sdk/actor/codec/constant"
+)
+
+func init() {
+ codec.SetActorCodec(constant.DefaultSerializerType, func() codec.Codec {
+ return &JSONCodec{}
+ })
+}
+
+// JSONCodec is json impl of codec.Codec.
+type JSONCodec struct{}
+
+func (j *JSONCodec) Marshal(v interface{}) ([]byte, error) {
+ return json.Marshal(v)
+}
+
+func (j *JSONCodec) Unmarshal(data []byte, v interface{}) error {
+ return json.Unmarshal(data, v)
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/codec/impl/yaml.go b/vendor/github.com/dapr/go-sdk/actor/codec/impl/yaml.go
new file mode 100644
index 00000000000..bd8a385c0aa
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/codec/impl/yaml.go
@@ -0,0 +1,38 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package impl
+
+import (
+ "github.com/dapr/go-sdk/actor/codec"
+ "github.com/dapr/go-sdk/actor/codec/constant"
+
+ "gopkg.in/yaml.v3"
+)
+
+func init() {
+ codec.SetActorCodec(constant.YamlSerializerType, func() codec.Codec {
+ return &YamlCodec{}
+ })
+}
+
+// YamlCodec is json yaml of codec.Codec.
+type YamlCodec struct{}
+
+func (y *YamlCodec) Marshal(v interface{}) ([]byte, error) {
+ return yaml.Marshal(v)
+}
+
+func (y *YamlCodec) Unmarshal(data []byte, v interface{}) error {
+ return yaml.Unmarshal(data, v)
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/config/config.go b/vendor/github.com/dapr/go-sdk/actor/config/config.go
new file mode 100644
index 00000000000..656cc81ac3e
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/config/config.go
@@ -0,0 +1,42 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config
+
+import "github.com/dapr/go-sdk/actor/codec/constant"
+
+// ActorConfig is Actor's configuration struct.
+type ActorConfig struct {
+ SerializerType string
+}
+
+// Option is option function of ActorConfig.
+type Option func(config *ActorConfig)
+
+// WithSerializerName set serializer type of the actor as @serializerType.
+func WithSerializerName(serializerType string) Option {
+ return func(config *ActorConfig) {
+ config.SerializerType = serializerType
+ }
+}
+
+// GetConfigFromOptions get final ActorConfig set by @opts.
+func GetConfigFromOptions(opts ...Option) *ActorConfig {
+ conf := &ActorConfig{
+ SerializerType: constant.DefaultSerializerType,
+ }
+ for _, o := range opts {
+ o(conf)
+ }
+ return conf
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/error/error.go b/vendor/github.com/dapr/go-sdk/actor/error/error.go
new file mode 100644
index 00000000000..74702d6dac2
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/error/error.go
@@ -0,0 +1,33 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package error
+
+type ActorErr uint8
+
+// TODO(@laurence) the classification, handle and print log of error should be optimized.
+const (
+ Success = ActorErr(0)
+ ErrActorTypeNotFound = ActorErr(1)
+ ErrRemindersParamsInvalid = ActorErr(2)
+ ErrActorMethodNoFound = ActorErr(3)
+ ErrActorInvokeFailed = ActorErr(4)
+ ErrReminderFuncUndefined = ActorErr(5)
+ ErrActorMethodSerializeFailed = ActorErr(6)
+ ErrActorSerializeNoFound = ActorErr(7)
+ ErrActorIDNotFound = ActorErr(8)
+ ErrActorFactoryNotSet = ActorErr(9)
+ ErrTimerParamsInvalid = ActorErr(10)
+ ErrSaveStateFailed = ActorErr(11)
+ ErrActorServerInvalid = ActorErr(12)
+)
diff --git a/vendor/github.com/dapr/go-sdk/actor/manager/container.go b/vendor/github.com/dapr/go-sdk/actor/manager/container.go
new file mode 100644
index 00000000000..29619db4da9
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/manager/container.go
@@ -0,0 +1,123 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package manager
+
+import (
+ "context"
+ "log"
+ "reflect"
+
+ "github.com/dapr/go-sdk/actor"
+ "github.com/dapr/go-sdk/actor/codec"
+ actorErr "github.com/dapr/go-sdk/actor/error"
+ "github.com/dapr/go-sdk/actor/state"
+ dapr "github.com/dapr/go-sdk/client"
+)
+
+// Deprecated: use ActorContainerContext instead.
+type ActorContainer interface {
+ Invoke(methodName string, param []byte) ([]reflect.Value, actorErr.ActorErr)
+ //nolint:staticcheck // SA1019 Deprecated: use ActorContainerContext instead.
+ GetActor() actor.Server
+}
+
+type ActorContainerContext interface {
+ Invoke(ctx context.Context, methodName string, param []byte) ([]reflect.Value, actorErr.ActorErr)
+ GetActor() actor.ServerContext
+}
+
+// DefaultActorContainer contains actor instance and methods type info
+// generated from actor.
+// Deprecated: use DefaultActorContainerContext instead.
+type DefaultActorContainer struct {
+ //nolint:staticcheck
+ actor actor.Server
+ ctx *DefaultActorContainerContext
+}
+
+// DefaultActorContainerContext contains actor instance and methods type info
+// generated from actor.
+type DefaultActorContainerContext struct {
+ methodType map[string]*MethodType
+ actor actor.ServerContext
+ serializer codec.Codec
+}
+
+// NewDefaultActorContainer creates a new ActorContainer with provider impl actor and serializer.
+// Deprecated: use NewDefaultActorContainerContext instead.
+//
+//nolint:staticcheck
+func NewDefaultActorContainer(actorID string, impl actor.Server, serializer codec.Codec) (ActorContainer, actorErr.ActorErr) {
+ ctx, err := NewDefaultActorContainerContext(context.Background(), actorID, impl.WithContext(), serializer)
+ return &DefaultActorContainer{ctx: ctx.(*DefaultActorContainerContext), actor: impl}, err
+}
+
+// Deprecated: use NewDefaultActorContainerContext instead.
+func (d *DefaultActorContainer) GetActor() actor.Server {
+ return d.actor
+}
+
+// Invoke call actor method with given methodName and param.
+// Deprecated: use NewDefaultActorContainerContext instead.
+func (d *DefaultActorContainer) Invoke(methodName string, param []byte) ([]reflect.Value, actorErr.ActorErr) {
+ return d.ctx.Invoke(context.Background(), methodName, param)
+}
+
+// NewDefaultActorContainerContext is the same as NewDefaultActorContainer, but with initial context.
+func NewDefaultActorContainerContext(ctx context.Context, actorID string, impl actor.ServerContext, serializer codec.Codec) (ActorContainerContext, actorErr.ActorErr) {
+ impl.SetID(actorID)
+ daprClient, _ := dapr.NewClient()
+ // create state manager for this new actor
+ impl.SetStateManager(state.NewActorStateManagerContext(impl.Type(), actorID, state.NewDaprStateAsyncProvider(daprClient)))
+ // save state of this actor
+ err := impl.SaveState(ctx)
+ if err != nil {
+ return nil, actorErr.ErrSaveStateFailed
+ }
+ methodType, err := getAbsctractMethodMap(impl)
+ if err != nil {
+ log.Printf("failed to get absctract method map from registered provider, err = %s", err)
+ return nil, actorErr.ErrActorServerInvalid
+ }
+ return &DefaultActorContainerContext{
+ methodType: methodType,
+ actor: impl,
+ serializer: serializer,
+ }, actorErr.Success
+}
+
+// Invoke call actor method with given context, methodName and param.
+func (d *DefaultActorContainerContext) Invoke(ctx context.Context, methodName string, param []byte) ([]reflect.Value, actorErr.ActorErr) {
+ methodType, ok := d.methodType[methodName]
+ if !ok {
+ return nil, actorErr.ErrActorMethodNoFound
+ }
+ argsValues := make([]reflect.Value, 0)
+ argsValues = append(argsValues, reflect.ValueOf(d.actor), reflect.ValueOf(ctx))
+ if len(methodType.argsType) > 0 {
+ typ := methodType.argsType[0]
+ paramValue := reflect.New(typ)
+ paramInterface := paramValue.Interface()
+ if err := d.serializer.Unmarshal(param, paramInterface); err != nil {
+ return nil, actorErr.ErrActorMethodSerializeFailed
+ }
+ argsValues = append(argsValues, reflect.ValueOf(paramInterface).Elem())
+ }
+ returnValue := methodType.method.Func.Call(argsValues)
+ return returnValue, actorErr.Success
+}
+
+func (d *DefaultActorContainerContext) GetActor() actor.ServerContext {
+ return d.actor
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/manager/manager.go b/vendor/github.com/dapr/go-sdk/actor/manager/manager.go
new file mode 100644
index 00000000000..8070ca2cce0
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/manager/manager.go
@@ -0,0 +1,325 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package manager
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "log"
+ "reflect"
+ "sync"
+ "unicode"
+ "unicode/utf8"
+
+ "github.com/dapr/go-sdk/actor"
+ "github.com/dapr/go-sdk/actor/api"
+ "github.com/dapr/go-sdk/actor/codec"
+ actorErr "github.com/dapr/go-sdk/actor/error"
+)
+
+type ActorManager interface {
+ RegisterActorImplFactory(f actor.Factory)
+ InvokeMethod(actorID, methodName string, request []byte) ([]byte, actorErr.ActorErr)
+ DeactivateActor(actorID string) actorErr.ActorErr
+ InvokeReminder(actorID, reminderName string, params []byte) actorErr.ActorErr
+ InvokeTimer(actorID, timerName string, params []byte) actorErr.ActorErr
+}
+
+type ActorManagerContext interface {
+ RegisterActorImplFactory(f actor.FactoryContext)
+ InvokeMethod(ctx context.Context, actorID, methodName string, request []byte) ([]byte, actorErr.ActorErr)
+ DeactivateActor(ctx context.Context, actorID string) actorErr.ActorErr
+ InvokeReminder(ctx context.Context, actorID, reminderName string, params []byte) actorErr.ActorErr
+ InvokeTimer(ctx context.Context, actorID, timerName string, params []byte) actorErr.ActorErr
+}
+
+// DefaultActorManagerContext is to manage one type of actor.
+type DefaultActorManagerContext struct {
+ // factory is the actor factory of specific type of actor
+ factory actor.FactoryContext
+
+ // activeActors stores the map actorID -> ActorContainer
+ activeActors sync.Map
+
+ // serializer is the param and response serializer of the actor
+ serializer codec.Codec
+}
+
+// DefaultActorManager is to manage one type of actor.
+// Deprecated: use DefaultActorManagerContext instead.
+type DefaultActorManager struct {
+ ctx ActorManagerContext
+}
+
+// Deprecated: use DefaultActorManagerContext instead.
+func NewDefaultActorManager(serializerType string) (ActorManager, actorErr.ActorErr) {
+ ctx, err := NewDefaultActorManagerContext(serializerType)
+ return &DefaultActorManager{ctx: ctx}, err
+}
+
+// Deprecated: use DefaultActorManagerContext instead.
+func (m *DefaultActorManager) RegisterActorImplFactory(f actor.Factory) {
+ m.ctx.RegisterActorImplFactory(func() actor.ServerContext { return f().WithContext() })
+}
+
+// Deprecated: use DefaultActorManagerContext instead.
+func (m *DefaultActorManager) InvokeMethod(actorID, methodName string, request []byte) ([]byte, actorErr.ActorErr) {
+ return m.ctx.InvokeMethod(context.Background(), actorID, methodName, request)
+}
+
+// Deprecated: use DefaultActorManagerContext instead.
+func (m *DefaultActorManager) DeactivateActor(actorID string) actorErr.ActorErr {
+ return m.ctx.DeactivateActor(context.Background(), actorID)
+}
+
+// Deprecated: use DefaultActorManagerContext instead.
+func (m *DefaultActorManager) InvokeReminder(actorID, reminderName string, params []byte) actorErr.ActorErr {
+ return m.ctx.InvokeReminder(context.Background(), actorID, reminderName, params)
+}
+
+// Deprecated: use DefaultActorManagerContext instead.
+func (m *DefaultActorManager) InvokeTimer(actorID, timerName string, params []byte) actorErr.ActorErr {
+ return m.ctx.InvokeTimer(context.Background(), actorID, timerName, params)
+}
+
+func NewDefaultActorManagerContext(serializerType string) (ActorManagerContext, actorErr.ActorErr) {
+ serializer, err := codec.GetActorCodec(serializerType)
+ if err != nil {
+ return nil, actorErr.ErrActorSerializeNoFound
+ }
+ return &DefaultActorManagerContext{
+ serializer: serializer,
+ }, actorErr.Success
+}
+
+// RegisterActorImplFactory registers the action factory f.
+func (m *DefaultActorManagerContext) RegisterActorImplFactory(f actor.FactoryContext) {
+ m.factory = f
+}
+
+// getAndCreateActorContainerIfNotExist will.
+func (m *DefaultActorManagerContext) getAndCreateActorContainerIfNotExist(ctx context.Context, actorID string) (ActorContainerContext, actorErr.ActorErr) {
+ val, ok := m.activeActors.Load(actorID)
+ if !ok {
+ newContainer, aerr := NewDefaultActorContainerContext(ctx, actorID, m.factory(), m.serializer)
+ if aerr != actorErr.Success {
+ return nil, aerr
+ }
+ m.activeActors.Store(actorID, newContainer)
+ val, _ = m.activeActors.Load(actorID)
+ }
+ return val.(ActorContainerContext), actorErr.Success
+}
+
+// InvokeMethod to invoke local function by @actorID, @methodName and @request request param.
+func (m *DefaultActorManagerContext) InvokeMethod(ctx context.Context, actorID, methodName string, request []byte) ([]byte, actorErr.ActorErr) {
+ if m.factory == nil {
+ return nil, actorErr.ErrActorFactoryNotSet
+ }
+
+ actorContainer, aerr := m.getAndCreateActorContainerIfNotExist(ctx, actorID)
+ if aerr != actorErr.Success {
+ return nil, aerr
+ }
+ returnValue, aerr := actorContainer.Invoke(ctx, methodName, request)
+ if aerr != actorErr.Success {
+ return nil, aerr
+ }
+ if len(returnValue) == 1 {
+ return nil, actorErr.Success
+ }
+
+ var (
+ retErr interface{}
+ replyv reflect.Value
+ )
+
+ if len(returnValue) == 2 {
+ replyv = returnValue[0]
+ retErr = returnValue[1].Interface()
+ }
+
+ if retErr != nil {
+ return nil, actorErr.ErrActorInvokeFailed
+ }
+ rspData, err := m.serializer.Marshal(replyv.Interface())
+ if err != nil {
+ return nil, actorErr.ErrActorMethodSerializeFailed
+ }
+ if err := actorContainer.GetActor().SaveState(ctx); err != nil {
+ return nil, actorErr.ErrSaveStateFailed
+ }
+ return rspData, actorErr.Success
+}
+
+// DeactivateActor removes actor from actor manager.
+func (m *DefaultActorManagerContext) DeactivateActor(_ context.Context, actorID string) actorErr.ActorErr {
+ _, ok := m.activeActors.Load(actorID)
+ if !ok {
+ return actorErr.ErrActorIDNotFound
+ }
+ m.activeActors.Delete(actorID)
+ return actorErr.Success
+}
+
+// InvokeReminder invoke reminder function with given params.
+func (m *DefaultActorManagerContext) InvokeReminder(ctx context.Context, actorID, reminderName string, params []byte) actorErr.ActorErr {
+ if m.factory == nil {
+ return actorErr.ErrActorFactoryNotSet
+ }
+ reminderParams := &api.ActorReminderParams{}
+ if err := json.Unmarshal(params, reminderParams); err != nil {
+ log.Printf("failed to unmarshal reminder param, err: %v ", err)
+ return actorErr.ErrRemindersParamsInvalid
+ }
+ actorContainer, aerr := m.getAndCreateActorContainerIfNotExist(ctx, actorID)
+ if aerr != actorErr.Success {
+ return aerr
+ }
+
+ targetActor, ok := actorContainer.GetActor().(actor.ReminderCallee)
+ if !ok {
+ return actorErr.ErrReminderFuncUndefined
+ }
+ targetActor.ReminderCall(reminderName, reminderParams.Data, reminderParams.DueTime, reminderParams.Period)
+ return actorErr.Success
+}
+
+// InvokeTimer invoke timer callback function with given params.
+func (m *DefaultActorManagerContext) InvokeTimer(ctx context.Context, actorID, timerName string, params []byte) actorErr.ActorErr {
+ if m.factory == nil {
+ return actorErr.ErrActorFactoryNotSet
+ }
+ timerParams := &api.ActorTimerParam{}
+ if err := json.Unmarshal(params, timerParams); err != nil {
+ log.Printf("failed to unmarshal reminder param, err: %v ", err)
+ return actorErr.ErrTimerParamsInvalid
+ }
+ actorContainer, aerr := m.getAndCreateActorContainerIfNotExist(ctx, actorID)
+ if aerr != actorErr.Success {
+ return aerr
+ }
+ _, aerr = actorContainer.Invoke(ctx, timerParams.CallBack, timerParams.Data)
+ return aerr
+}
+
+func getAbsctractMethodMap(rcvr interface{}) (map[string]*MethodType, error) {
+ s := &Service{}
+ s.reflectType = reflect.TypeOf(rcvr)
+ s.reflctValue = reflect.ValueOf(rcvr)
+ sname := reflect.Indirect(s.reflctValue).Type().Name()
+ if !isExported(sname) {
+ return nil, fmt.Errorf("type %s is not exported", sname)
+ }
+ return suitableMethods(s.reflectType), nil
+}
+
+func isExported(name string) bool {
+ s, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(s)
+}
+
+// Service is description of service.
+type Service struct {
+ reflctValue reflect.Value
+ reflectType reflect.Type
+}
+
+// MethodType is description of service method.
+type MethodType struct {
+ method reflect.Method
+ ctxType reflect.Type // request context
+ argsType []reflect.Type // args except ctx, include replyType if existing
+ replyType reflect.Type // return value, otherwise it is nil
+}
+
+// suitableMethods returns suitable Rpc methods of typ.
+func suitableMethods(typ reflect.Type) map[string]*MethodType {
+ methods := make(map[string]*MethodType)
+ for m := 0; m < typ.NumMethod(); m++ {
+ method := typ.Method(m)
+ if mt, err := suiteMethod(method); err != nil {
+ log.Printf("method %s is illegal, err = %s, just skip it", method.Name, err)
+ } else {
+ methods[method.Name] = mt
+ }
+ }
+ return methods
+}
+
+// suiteMethod returns a suitable Rpc methodType.
+func suiteMethod(method reflect.Method) (*MethodType, error) {
+ mtype := method.Type
+ mname := method.Name
+ inNum := mtype.NumIn()
+ outNum := mtype.NumOut()
+
+ // Method must be exported.
+ if method.PkgPath != "" {
+ return nil, errors.New("method is not exported")
+ }
+
+ var (
+ replyType, ctxType reflect.Type
+ argsType []reflect.Type
+ )
+
+ if outNum > 2 || outNum == 0 {
+ return nil, errors.New("num out invalid")
+ }
+
+ // The latest return type of the method must be error.
+ if returnType := mtype.Out(outNum - 1); returnType != typeOfError {
+ return nil, fmt.Errorf("the latest return type %s of method %q is not error", returnType, mname)
+ }
+
+ // replyType
+ if outNum == 2 {
+ replyType = mtype.Out(0)
+ if !isExportedOrBuiltinType(replyType) {
+ return nil, fmt.Errorf("reply type of method %s not exported{%v}", mname, replyType)
+ }
+ }
+
+ index := 1
+
+ // ctxType
+ if inNum > 1 && mtype.In(1).String() == "context.Context" {
+ ctxType = mtype.In(1)
+ index = 2
+ }
+
+ for ; index < inNum; index++ {
+ argsType = append(argsType, mtype.In(index))
+ // need not be a pointer.
+ if !isExportedOrBuiltinType(mtype.In(index)) {
+ return nil, fmt.Errorf("argument type of method %q is not exported %v", mname, mtype.In(index))
+ }
+ }
+
+ return &MethodType{method: method, argsType: argsType, replyType: replyType, ctxType: ctxType}, nil
+}
+
+var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
+
+func isExportedOrBuiltinType(t reflect.Type) bool {
+ for t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+ // PkgPath will be non-empty even for an exported type,
+ // so we need to check the type name as well.
+ return isExported(t.Name()) || t.PkgPath() == ""
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/runtime/actor_runtime.go b/vendor/github.com/dapr/go-sdk/actor/runtime/actor_runtime.go
new file mode 100644
index 00000000000..5052b89c364
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/runtime/actor_runtime.go
@@ -0,0 +1,156 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package runtime
+
+import (
+ "context"
+ "encoding/json"
+ "sync"
+
+ "github.com/dapr/go-sdk/actor"
+ "github.com/dapr/go-sdk/actor/api"
+ "github.com/dapr/go-sdk/actor/config"
+ actorErr "github.com/dapr/go-sdk/actor/error"
+ "github.com/dapr/go-sdk/actor/manager"
+)
+
+// Deprecated: use ActorRunTimeContext instead.
+type ActorRunTime struct {
+ ctx *ActorRunTimeContext
+}
+
+type ActorRunTimeContext struct {
+ config api.ActorRuntimeConfig
+ actorManagers sync.Map
+}
+
+var (
+ actorRuntimeInstance *ActorRunTime
+ actorRuntimeInstanceCtx *ActorRunTimeContext
+)
+
+// NewActorRuntime creates an empty ActorRuntime.
+// Deprecated: use NewActorRuntimeContext instead.
+func NewActorRuntime() *ActorRunTime {
+ return &ActorRunTime{ctx: NewActorRuntimeContext()}
+}
+
+// NewActorRuntimeContext creates an empty ActorRuntimeContext.
+func NewActorRuntimeContext() *ActorRunTimeContext {
+ return &ActorRunTimeContext{}
+}
+
+// GetActorRuntimeInstance gets or create runtime instance.
+// Deprecated: use GetActorRuntimeInstanceContext instead.
+func GetActorRuntimeInstance() *ActorRunTime {
+ if actorRuntimeInstance == nil {
+ actorRuntimeInstance = NewActorRuntime()
+ }
+ return actorRuntimeInstance
+}
+
+// GetActorRuntimeInstanceContext gets or create runtime instance.
+func GetActorRuntimeInstanceContext() *ActorRunTimeContext {
+ if actorRuntimeInstanceCtx == nil {
+ actorRuntimeInstanceCtx = NewActorRuntimeContext()
+ }
+ return actorRuntimeInstanceCtx
+}
+
+// RegisterActorFactory registers the given actor factory from user, and create new actor manager if not exists.
+func (r *ActorRunTimeContext) RegisterActorFactory(f actor.FactoryContext, opt ...config.Option) {
+ conf := config.GetConfigFromOptions(opt...)
+ actType := f().Type()
+ r.config.RegisteredActorTypes = append(r.config.RegisteredActorTypes, actType)
+ mng, ok := r.actorManagers.Load(actType)
+ if !ok {
+ newMng, err := manager.NewDefaultActorManagerContext(conf.SerializerType)
+ if err != actorErr.Success {
+ return
+ }
+ newMng.RegisterActorImplFactory(f)
+ r.actorManagers.Store(actType, newMng)
+ return
+ }
+ mng.(manager.ActorManagerContext).RegisterActorImplFactory(f)
+}
+
+func (r *ActorRunTimeContext) GetJSONSerializedConfig() ([]byte, error) {
+ data, err := json.Marshal(&r.config)
+ return data, err
+}
+
+func (r *ActorRunTimeContext) InvokeActorMethod(ctx context.Context, actorTypeName, actorID, actorMethod string, payload []byte) ([]byte, actorErr.ActorErr) {
+ mng, ok := r.actorManagers.Load(actorTypeName)
+ if !ok {
+ return nil, actorErr.ErrActorTypeNotFound
+ }
+ return mng.(manager.ActorManagerContext).InvokeMethod(ctx, actorID, actorMethod, payload)
+}
+
+func (r *ActorRunTimeContext) Deactivate(ctx context.Context, actorTypeName, actorID string) actorErr.ActorErr {
+ targetManager, ok := r.actorManagers.Load(actorTypeName)
+ if !ok {
+ return actorErr.ErrActorTypeNotFound
+ }
+ return targetManager.(manager.ActorManagerContext).DeactivateActor(ctx, actorID)
+}
+
+func (r *ActorRunTimeContext) InvokeReminder(ctx context.Context, actorTypeName, actorID, reminderName string, params []byte) actorErr.ActorErr {
+ targetManager, ok := r.actorManagers.Load(actorTypeName)
+ if !ok {
+ return actorErr.ErrActorTypeNotFound
+ }
+ mng := targetManager.(manager.ActorManagerContext)
+ return mng.InvokeReminder(ctx, actorID, reminderName, params)
+}
+
+func (r *ActorRunTimeContext) InvokeTimer(ctx context.Context, actorTypeName, actorID, timerName string, params []byte) actorErr.ActorErr {
+ targetManager, ok := r.actorManagers.Load(actorTypeName)
+ if !ok {
+ return actorErr.ErrActorTypeNotFound
+ }
+ mng := targetManager.(manager.ActorManagerContext)
+ return mng.InvokeTimer(ctx, actorID, timerName, params)
+}
+
+// Deprecated: use ActorRunTimeContext instead.
+func (r *ActorRunTime) RegisterActorFactory(f actor.Factory, opt ...config.Option) {
+ r.ctx.RegisterActorFactory(func() actor.ServerContext { return f().WithContext() }, opt...)
+}
+
+// Deprecated: use ActorRunTimeContext instead.
+func (r *ActorRunTime) GetJSONSerializedConfig() ([]byte, error) {
+ return r.ctx.GetJSONSerializedConfig()
+}
+
+// Deprecated: use ActorRunTimeContext instead.
+func (r *ActorRunTime) InvokeActorMethod(actorTypeName, actorID, actorMethod string, payload []byte) ([]byte, actorErr.ActorErr) {
+ return r.ctx.InvokeActorMethod(context.Background(), actorTypeName, actorID, actorMethod, payload)
+}
+
+// Deprecated: use ActorRunTimeContext instead.
+func (r *ActorRunTime) Deactivate(actorTypeName, actorID string) actorErr.ActorErr {
+ return r.ctx.Deactivate(context.Background(), actorTypeName, actorID)
+}
+
+// Deprecated: use ActorRunTimeContext instead.
+func (r *ActorRunTime) InvokeReminder(actorTypeName, actorID, reminderName string, params []byte) actorErr.ActorErr {
+ return r.ctx.InvokeReminder(context.Background(), actorTypeName, actorID, reminderName, params)
+}
+
+// Deprecated: use ActorRunTimeContext instead.
+func (r *ActorRunTime) InvokeTimer(actorTypeName, actorID, timerName string, params []byte) actorErr.ActorErr {
+ return r.ctx.InvokeTimer(context.Background(), actorTypeName, actorID, timerName, params)
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/state/actor_state_change.go b/vendor/github.com/dapr/go-sdk/actor/state/actor_state_change.go
new file mode 100644
index 00000000000..ae8d3798857
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/state/actor_state_change.go
@@ -0,0 +1,34 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package state
+
+import (
+ "time"
+)
+
+type ActorStateChange struct {
+ stateName string
+ value interface{}
+ changeKind ChangeKind
+ ttlInSeconds *int64
+}
+
+func NewActorStateChange(stateName string, value any, changeKind ChangeKind, ttl *time.Duration) *ActorStateChange {
+ var ttlF *int64
+ if ttl != nil && *ttl > 0 {
+ ttlInSeconds := int64(ttl.Seconds())
+ ttlF = &ttlInSeconds
+ }
+ return &ActorStateChange{stateName: stateName, value: value, changeKind: changeKind, ttlInSeconds: ttlF}
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/state/state_async_provider.go b/vendor/github.com/dapr/go-sdk/actor/state/state_async_provider.go
new file mode 100644
index 00000000000..c1d5549a506
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/state/state_async_provider.go
@@ -0,0 +1,121 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package state
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/dapr/go-sdk/actor/codec"
+ "github.com/dapr/go-sdk/actor/codec/constant"
+ client "github.com/dapr/go-sdk/client"
+)
+
+type DaprStateAsyncProvider struct {
+ daprClient client.Client
+ stateSerializer codec.Codec
+}
+
+// Deprecated: use ContainsContext instead.
+func (d *DaprStateAsyncProvider) Contains(actorType string, actorID string, stateName string) (bool, error) {
+ return d.ContainsContext(context.Background(), actorType, actorID, stateName)
+}
+
+func (d *DaprStateAsyncProvider) ContainsContext(ctx context.Context, actorType string, actorID string, stateName string) (bool, error) {
+ result, err := d.daprClient.GetActorState(ctx, &client.GetActorStateRequest{
+ ActorType: actorType,
+ ActorID: actorID,
+ KeyName: stateName,
+ })
+ if err != nil || result == nil {
+ return false, err
+ }
+ return len(result.Data) > 0, err
+}
+
+// Deprecated: use LoadContext instead.
+func (d *DaprStateAsyncProvider) Load(actorType, actorID, stateName string, reply interface{}) error {
+ return d.LoadContext(context.Background(), actorType, actorID, stateName, reply)
+}
+
+func (d *DaprStateAsyncProvider) LoadContext(ctx context.Context, actorType, actorID, stateName string, reply interface{}) error {
+ result, err := d.daprClient.GetActorState(ctx, &client.GetActorStateRequest{
+ ActorType: actorType,
+ ActorID: actorID,
+ KeyName: stateName,
+ })
+ if err != nil {
+ return fmt.Errorf("get actor state error = %w", err)
+ }
+ if len(result.Data) == 0 {
+ return fmt.Errorf("get actor state result empty, with actorType: %s, actorID: %s, stateName %s", actorType, actorID, stateName)
+ }
+ if err := d.stateSerializer.Unmarshal(result.Data, reply); err != nil {
+ return fmt.Errorf("unmarshal state data error = %w", err)
+ }
+ return nil
+}
+
+// Deprecated: use ApplyContext instead.
+func (d *DaprStateAsyncProvider) Apply(actorType, actorID string, changes []*ActorStateChange) error {
+ return d.ApplyContext(context.Background(), actorType, actorID, changes)
+}
+
+func (d *DaprStateAsyncProvider) ApplyContext(ctx context.Context, actorType, actorID string, changes []*ActorStateChange) error {
+ if len(changes) == 0 {
+ return nil
+ }
+
+ operations := make([]*client.ActorStateOperation, 0)
+ var value []byte
+ for _, stateChange := range changes {
+ if stateChange == nil {
+ continue
+ }
+
+ daprOperationName := string(stateChange.changeKind)
+ if len(daprOperationName) == 0 {
+ continue
+ }
+
+ if stateChange.changeKind == Add {
+ data, err := d.stateSerializer.Marshal(stateChange.value)
+ if err != nil {
+ return err
+ }
+ value = data
+ }
+ operations = append(operations, &client.ActorStateOperation{
+ OperationType: daprOperationName,
+ Key: stateChange.stateName,
+ Value: value,
+ TTLInSeconds: stateChange.ttlInSeconds,
+ })
+ }
+
+ if len(operations) == 0 {
+ return nil
+ }
+
+ return d.daprClient.SaveStateTransactionally(ctx, actorType, actorID, operations)
+}
+
+// TODO(@laurence) the daprClient may be nil.
+func NewDaprStateAsyncProvider(daprClient client.Client) *DaprStateAsyncProvider {
+ stateSerializer, _ := codec.GetActorCodec(constant.DefaultSerializerType)
+ return &DaprStateAsyncProvider{
+ stateSerializer: stateSerializer,
+ daprClient: daprClient,
+ }
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/state/state_change_metadata.go b/vendor/github.com/dapr/go-sdk/actor/state/state_change_metadata.go
new file mode 100644
index 00000000000..626e3244a78
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/state/state_change_metadata.go
@@ -0,0 +1,43 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package state
+
+import "time"
+
+type ChangeKind string
+
+const (
+ None = ChangeKind("")
+ Add = ChangeKind("upsert")
+ Update = ChangeKind("upsert")
+ Remove = ChangeKind("delete")
+)
+
+type ChangeMetadata struct {
+ Kind ChangeKind
+ Value any
+ TTL *time.Duration
+}
+
+func NewChangeMetadata(kind ChangeKind, value any) *ChangeMetadata {
+ return &ChangeMetadata{
+ Kind: kind,
+ Value: value,
+ }
+}
+
+func (c *ChangeMetadata) WithTTL(ttl time.Duration) *ChangeMetadata {
+ c.TTL = &ttl
+ return c
+}
diff --git a/vendor/github.com/dapr/go-sdk/actor/state/state_manager.go b/vendor/github.com/dapr/go-sdk/actor/state/state_manager.go
new file mode 100644
index 00000000000..0bae7c9a852
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/actor/state/state_manager.go
@@ -0,0 +1,269 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package state
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "reflect"
+ "sync"
+ "time"
+
+ "github.com/dapr/go-sdk/actor"
+)
+
+type stateManager struct {
+ *stateManagerCtx
+}
+
+type stateManagerCtx struct {
+ actorTypeName string
+ actorID string
+ stateChangeTracker sync.Map // map[string]*ChangeMetadata
+ stateAsyncProvider *DaprStateAsyncProvider
+}
+
+// Deprecated: use NewActorStateManagerContext instead.
+func (s *stateManager) Add(stateName string, value any) error {
+ return s.stateManagerCtx.Add(context.Background(), stateName, value)
+}
+
+// Deprecated: use NewActorStateManagerContext instead.
+func (s *stateManager) Get(stateName string, reply any) error {
+ return s.stateManagerCtx.Get(context.Background(), stateName, reply)
+}
+
+// Deprecated: use NewActorStateManagerContext instead.
+func (s *stateManager) Set(stateName string, value any) error {
+ return s.stateManagerCtx.Set(context.Background(), stateName, value)
+}
+
+// Deprecated: use NewActorStateManagerContext instead.
+func (s *stateManager) Remove(stateName string) error {
+ return s.stateManagerCtx.Remove(context.Background(), stateName)
+}
+
+// Deprecated: use NewActorStateManagerContext instead.
+func (s *stateManager) Contains(stateName string) (bool, error) {
+ return s.stateManagerCtx.Contains(context.Background(), stateName)
+}
+
+// Deprecated: use NewActorStateManagerContext instead.
+func (s *stateManager) Save() error {
+ return s.stateManagerCtx.Save(context.Background())
+}
+
+// Deprecated: use NewActorStateManagerContext instead.
+func (s *stateManager) Flush() {
+ s.stateManagerCtx.Flush(context.Background())
+}
+
+// Deprecated: use NewActorStateManagerContext instead.
+func (s *stateManager) WithContext() actor.StateManagerContext {
+ return s.stateManagerCtx
+}
+
+func (s *stateManagerCtx) Add(ctx context.Context, stateName string, value any) error {
+ if stateName == "" {
+ return errors.New("state name can't be empty")
+ }
+ exists, err := s.stateAsyncProvider.ContainsContext(ctx, s.actorTypeName, s.actorID, stateName)
+ if err != nil {
+ return err
+ }
+
+ if val, ok := s.stateChangeTracker.Load(stateName); ok {
+ metadata := val.(*ChangeMetadata)
+ if metadata.Kind == Remove {
+ s.stateChangeTracker.Store(stateName, &ChangeMetadata{
+ Kind: Update,
+ Value: value,
+ })
+ return nil
+ }
+ return fmt.Errorf("duplicate cached state: %s", stateName)
+ }
+ if exists {
+ return fmt.Errorf("duplicate state: %s", stateName)
+ }
+ s.stateChangeTracker.Store(stateName, &ChangeMetadata{
+ Kind: Add,
+ Value: value,
+ })
+ return nil
+}
+
+func (s *stateManagerCtx) Get(ctx context.Context, stateName string, reply any) error {
+ if stateName == "" {
+ return errors.New("state name can't be empty")
+ }
+
+ if val, ok := s.stateChangeTracker.Load(stateName); ok {
+ metadata := val.(*ChangeMetadata)
+ if metadata.Kind == Remove {
+ return fmt.Errorf("state is marked for removal: %s", stateName)
+ }
+ replyVal := reflect.ValueOf(reply).Elem()
+ metadataValue := reflect.ValueOf(metadata.Value)
+ if metadataValue.Kind() == reflect.Ptr {
+ replyVal.Set(metadataValue.Elem())
+ } else {
+ replyVal.Set(metadataValue)
+ }
+
+ return nil
+ }
+
+ err := s.stateAsyncProvider.LoadContext(ctx, s.actorTypeName, s.actorID, stateName, reply)
+ s.stateChangeTracker.Store(stateName, &ChangeMetadata{
+ Kind: None,
+ Value: reply,
+ })
+ return err
+}
+
+func (s *stateManagerCtx) Set(_ context.Context, stateName string, value any) error {
+ if stateName == "" {
+ return errors.New("state name can't be empty")
+ }
+ if val, ok := s.stateChangeTracker.Load(stateName); ok {
+ metadata := val.(*ChangeMetadata)
+ if metadata.Kind == None || metadata.Kind == Remove {
+ metadata.Kind = Update
+ }
+ s.stateChangeTracker.Store(stateName, NewChangeMetadata(metadata.Kind, value))
+ return nil
+ }
+ s.stateChangeTracker.Store(stateName, &ChangeMetadata{
+ Kind: Add,
+ Value: value,
+ })
+ return nil
+}
+
+func (s *stateManagerCtx) SetWithTTL(_ context.Context, stateName string, value any, ttl time.Duration) error {
+ if stateName == "" {
+ return errors.New("state name can't be empty")
+ }
+
+ if ttl < 0 {
+ return errors.New("ttl can't be negative")
+ }
+
+ if val, ok := s.stateChangeTracker.Load(stateName); ok {
+ metadata := val.(*ChangeMetadata)
+ if metadata.Kind == None || metadata.Kind == Remove {
+ metadata.Kind = Update
+ }
+ s.stateChangeTracker.Store(stateName, NewChangeMetadata(metadata.Kind, value))
+ return nil
+ }
+ s.stateChangeTracker.Store(stateName, (&ChangeMetadata{
+ Kind: Add,
+ Value: value,
+ }).WithTTL(ttl))
+ return nil
+}
+
+func (s *stateManagerCtx) Remove(ctx context.Context, stateName string) error {
+ if stateName == "" {
+ return errors.New("state name can't be empty")
+ }
+ if val, ok := s.stateChangeTracker.Load(stateName); ok {
+ metadata := val.(*ChangeMetadata)
+ if metadata.Kind == Remove {
+ return nil
+ }
+ if metadata.Kind == Add {
+ s.stateChangeTracker.Delete(stateName)
+ return nil
+ }
+
+ s.stateChangeTracker.Store(stateName, &ChangeMetadata{
+ Kind: Remove,
+ Value: nil,
+ })
+ return nil
+ }
+ if exist, err := s.stateAsyncProvider.ContainsContext(ctx, s.actorTypeName, s.actorID, stateName); err != nil && exist {
+ s.stateChangeTracker.Store(stateName, &ChangeMetadata{
+ Kind: Remove,
+ Value: nil,
+ })
+ }
+ return nil
+}
+
+func (s *stateManagerCtx) Contains(ctx context.Context, stateName string) (bool, error) {
+ if stateName == "" {
+ return false, errors.New("state name can't be empty")
+ }
+ if val, ok := s.stateChangeTracker.Load(stateName); ok {
+ metadata := val.(*ChangeMetadata)
+ if metadata.Kind == Remove {
+ return false, nil
+ }
+ return true, nil
+ }
+ return s.stateAsyncProvider.ContainsContext(ctx, s.actorTypeName, s.actorID, stateName)
+}
+
+func (s *stateManagerCtx) Save(ctx context.Context) error {
+ changes := make([]*ActorStateChange, 0)
+ s.stateChangeTracker.Range(func(key, value any) bool {
+ stateName := key.(string)
+ metadata := value.(*ChangeMetadata)
+ changes = append(changes, NewActorStateChange(stateName, metadata.Value, metadata.Kind, metadata.TTL))
+ return true
+ })
+ if err := s.stateAsyncProvider.ApplyContext(ctx, s.actorTypeName, s.actorID, changes); err != nil {
+ return err
+ }
+ s.Flush(ctx)
+ return nil
+}
+
+func (s *stateManagerCtx) Flush(_ context.Context) {
+ s.stateChangeTracker.Range(func(key, value any) bool {
+ stateName := key.(string)
+ metadata := value.(*ChangeMetadata)
+ if metadata.Kind == Remove {
+ s.stateChangeTracker.Delete(stateName)
+ return true
+ }
+ metadata = NewChangeMetadata(None, metadata.Value)
+ s.stateChangeTracker.Store(stateName, metadata)
+ return true
+ })
+}
+
+// Deprecated: use NewActorStateManagerContext instead.
+func NewActorStateManager(actorTypeName string, actorID string, provider *DaprStateAsyncProvider) actor.StateManager {
+ return &stateManager{
+ stateManagerCtx: &stateManagerCtx{
+ stateAsyncProvider: provider,
+ actorTypeName: actorTypeName,
+ actorID: actorID,
+ },
+ }
+}
+
+func NewActorStateManagerContext(actorTypeName string, actorID string, provider *DaprStateAsyncProvider) actor.StateManagerContext {
+ return &stateManagerCtx{
+ stateAsyncProvider: provider,
+ actorTypeName: actorTypeName,
+ actorID: actorID,
+ }
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/actor.go b/vendor/github.com/dapr/go-sdk/client/actor.go
new file mode 100644
index 00000000000..5cfcf44efaf
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/actor.go
@@ -0,0 +1,506 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "reflect"
+ "strconv"
+
+ anypb "github.com/golang/protobuf/ptypes/any"
+
+ "github.com/dapr/go-sdk/actor"
+ "github.com/dapr/go-sdk/actor/codec"
+ "github.com/dapr/go-sdk/actor/config"
+ pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
+)
+
+const (
+ metadataKeyTTLInSeconds = "ttlInSeconds"
+)
+
+type InvokeActorRequest struct {
+ ActorType string
+ ActorID string
+ Method string
+ Data []byte
+}
+
+type InvokeActorResponse struct {
+ Data []byte
+}
+
+// InvokeActor invokes specific operation on the configured Dapr binding.
+// This method covers input, output, and bi-directional bindings.
+func (c *GRPCClient) InvokeActor(ctx context.Context, in *InvokeActorRequest) (out *InvokeActorResponse, err error) {
+ if in == nil {
+ return nil, errors.New("actor invocation required")
+ }
+ if in.Method == "" {
+ return nil, errors.New("actor invocation method required")
+ }
+ if in.ActorType == "" {
+ return nil, errors.New("actor invocation actorType required")
+ }
+ if in.ActorID == "" {
+ return nil, errors.New("actor invocation actorID required")
+ }
+
+ req := &pb.InvokeActorRequest{
+ ActorType: in.ActorType,
+ ActorId: in.ActorID,
+ Method: in.Method,
+ Data: in.Data,
+ }
+
+ resp, err := c.protoClient.InvokeActor(c.withAuthToken(ctx), req)
+ if err != nil {
+ return nil, fmt.Errorf("error invoking binding %s/%s: %w", in.ActorType, in.ActorID, err)
+ }
+
+ out = &InvokeActorResponse{}
+
+ if resp != nil {
+ out.Data = resp.Data
+ }
+
+ return out, nil
+}
+
+// ImplActorClientStub impls the given client stub @actorClientStub, an example of client stub is as followed
+/*
+type ClientStub struct {
+// User defined function
+ GetUser func(context.Context, *User) (*User, error)
+ Invoke func(context.Context, string) (string, error)
+ Get func(context.Context) (string, error)
+ Post func(context.Context, string) error
+ StartTimer func(context.Context, *TimerRequest) error
+ StopTimer func(context.Context, *TimerRequest) error
+ ...
+}
+
+// Type defined the target type, which should be compatible with server side actor
+func (a *ClientStub) Type() string {
+ return "testActorType"
+}
+
+// ID defined actor ID to be invoked
+func (a *ClientStub) ID() string {
+ return "ActorImplID123456"
+}.
+*/
+func (c *GRPCClient) ImplActorClientStub(actorClientStub actor.Client, opt ...config.Option) {
+ serializerType := config.GetConfigFromOptions(opt...).SerializerType
+ serializer, err := codec.GetActorCodec(serializerType)
+ if err != nil {
+ fmt.Printf("[Actor] ERROR: serializer type %s unsupported\n", serializerType)
+ return
+ }
+
+ c.implActor(actorClientStub, serializer)
+}
+
+type RegisterActorReminderRequest struct {
+ ActorType string
+ ActorID string
+ Name string
+ DueTime string
+ Period string
+ TTL string
+ Data []byte
+}
+
+// RegisterActorReminder registers a new reminder to target actor. Then, a reminder would be created and
+// invoke actor's ReminderCall function if implemented.
+// If server side actor impls this function, it's asserted to actor.ReminderCallee and can be invoked with call period
+// and state data as param @in defined.
+// Scheduling parameters 'DueTime', 'Period', and 'TTL' are optional.
+func (c *GRPCClient) RegisterActorReminder(ctx context.Context, in *RegisterActorReminderRequest) (err error) {
+ if in == nil {
+ return errors.New("actor register reminder invocation request param required")
+ }
+ if in.ActorType == "" {
+ return errors.New("actor register reminder invocation actorType required")
+ }
+ if in.ActorID == "" {
+ return errors.New("actor register reminder invocation actorID required")
+ }
+ if in.Name == "" {
+ return errors.New("actor register reminder invocation name required")
+ }
+
+ req := &pb.RegisterActorReminderRequest{
+ ActorType: in.ActorType,
+ ActorId: in.ActorID,
+ Name: in.Name,
+ DueTime: in.DueTime,
+ Period: in.Period,
+ Ttl: in.TTL,
+ Data: in.Data,
+ }
+
+ _, err = c.protoClient.RegisterActorReminder(c.withAuthToken(ctx), req)
+ if err != nil {
+ return fmt.Errorf("error invoking register actor reminder %s/%s: %w", in.ActorType, in.ActorID, err)
+ }
+ return nil
+}
+
+type UnregisterActorReminderRequest struct {
+ ActorType string
+ ActorID string
+ Name string
+}
+
+// UnregisterActorReminder would unregister the actor reminder.
+func (c *GRPCClient) UnregisterActorReminder(ctx context.Context, in *UnregisterActorReminderRequest) error {
+ if in == nil {
+ return errors.New("actor unregister reminder invocation request param required")
+ }
+ if in.ActorType == "" {
+ return errors.New("actor unregister reminder invocation actorType required")
+ }
+ if in.ActorID == "" {
+ return errors.New("actor unregister reminder invocation actorID required")
+ }
+ if in.Name == "" {
+ return errors.New("actor unregister reminder invocation name required")
+ }
+
+ req := &pb.UnregisterActorReminderRequest{
+ ActorType: in.ActorType,
+ ActorId: in.ActorID,
+ Name: in.Name,
+ }
+
+ _, err := c.protoClient.UnregisterActorReminder(c.withAuthToken(ctx), req)
+ if err != nil {
+ return fmt.Errorf("error invoking unregister actor reminder %s/%s: %w", in.ActorType, in.ActorID, err)
+ }
+ return nil
+}
+
+type RenameActorReminderRequest struct {
+ OldName string
+ ActorType string
+ ActorID string
+ NewName string
+}
+
+// RenameActorReminder would rename the actor reminder.
+func (c *GRPCClient) RenameActorReminder(ctx context.Context, in *RenameActorReminderRequest) error {
+ if in == nil {
+ return errors.New("actor rename reminder invocation request param required")
+ }
+ if in.ActorType == "" {
+ return errors.New("actor rename reminder invocation actorType required")
+ }
+ if in.ActorID == "" {
+ return errors.New("actor rename reminder invocation actorID required")
+ }
+ if in.OldName == "" {
+ return errors.New("actor rename reminder invocation oldName required")
+ }
+ if in.NewName == "" {
+ return errors.New("actor rename reminder invocation newName required")
+ }
+
+ req := &pb.RenameActorReminderRequest{
+ ActorType: in.ActorType,
+ ActorId: in.ActorID,
+ OldName: in.OldName,
+ NewName: in.NewName,
+ }
+
+ _, err := c.protoClient.RenameActorReminder(c.withAuthToken(ctx), req)
+ if err != nil {
+ return fmt.Errorf("error invoking rename actor reminder %s/%s: %w", in.ActorType, in.ActorID, err)
+ }
+ return nil
+}
+
+type RegisterActorTimerRequest struct {
+ ActorType string
+ ActorID string
+ Name string
+ DueTime string
+ Period string
+ TTL string
+ Data []byte
+ CallBack string
+}
+
+// RegisterActorTimer register actor timer as given param @in defined.
+// Scheduling parameters 'DueTime', 'Period', and 'TTL' are optional.
+func (c *GRPCClient) RegisterActorTimer(ctx context.Context, in *RegisterActorTimerRequest) (err error) {
+ if in == nil {
+ return errors.New("actor register timer invocation request param required")
+ }
+ if in.ActorType == "" {
+ return errors.New("actor register timer invocation actorType required")
+ }
+ if in.ActorID == "" {
+ return errors.New("actor register timer invocation actorID required")
+ }
+ if in.Name == "" {
+ return errors.New("actor register timer invocation name required")
+ }
+ if in.CallBack == "" {
+ return errors.New("actor register timer invocation callback function required")
+ }
+
+ req := &pb.RegisterActorTimerRequest{
+ ActorType: in.ActorType,
+ ActorId: in.ActorID,
+ Name: in.Name,
+ DueTime: in.DueTime,
+ Period: in.Period,
+ Ttl: in.TTL,
+ Data: in.Data,
+ Callback: in.CallBack,
+ }
+
+ _, err = c.protoClient.RegisterActorTimer(c.withAuthToken(ctx), req)
+ if err != nil {
+ return fmt.Errorf("error invoking actor register timer %s/%s: %w", in.ActorType, in.ActorID, err)
+ }
+
+ return nil
+}
+
+type UnregisterActorTimerRequest struct {
+ ActorType string
+ ActorID string
+ Name string
+}
+
+// UnregisterActorTimer unregisters actor timer.
+func (c *GRPCClient) UnregisterActorTimer(ctx context.Context, in *UnregisterActorTimerRequest) error {
+ if in == nil {
+ return errors.New("actor unregister timer invocation request param required")
+ }
+ if in.ActorType == "" {
+ return errors.New("actor unregister timer invocation actorType required")
+ }
+ if in.ActorID == "" {
+ return errors.New("actor unregister timer invocation actorID required")
+ }
+ if in.Name == "" {
+ return errors.New("actor unregister timer invocation name required")
+ }
+ req := &pb.UnregisterActorTimerRequest{
+ ActorType: in.ActorType,
+ ActorId: in.ActorID,
+ Name: in.Name,
+ }
+
+ _, err := c.protoClient.UnregisterActorTimer(c.withAuthToken(ctx), req)
+ if err != nil {
+ return fmt.Errorf("error invoking binding %s/%s: %w", in.ActorType, in.ActorID, err)
+ }
+
+ return nil
+}
+
+func (c *GRPCClient) implActor(actor actor.Client, serializer codec.Codec) {
+ actorValue := reflect.ValueOf(actor)
+ valueOfActor := actorValue.Elem()
+ typeOfActor := valueOfActor.Type()
+
+ // check incoming interface, the incoming interface's elem must be a struct.
+ if typeOfActor.Kind() != reflect.Struct {
+ fmt.Println("[Actor] ERROR: impl actor client stub failed, incoming interface is not struct")
+ return
+ }
+
+ numField := valueOfActor.NumField()
+ for i := 0; i < numField; i++ {
+ t := typeOfActor.Field(i)
+ methodName := t.Name
+ if methodName == "Type" {
+ continue
+ }
+ f := valueOfActor.Field(i)
+ if f.Kind() == reflect.Func && f.IsValid() && f.CanSet() {
+ outNum := t.Type.NumOut()
+
+ if outNum != 1 && outNum != 2 {
+ fmt.Printf("[Actor] ERROR: method %s of mtype %v has wrong number of in out parameters %d; needs exactly 1/2\n",
+ t.Name, t.Type.String(), outNum)
+ continue
+ }
+
+ // The latest return type of the method must be error.
+ if returnType := t.Type.Out(outNum - 1); returnType != reflect.Zero(reflect.TypeOf((*error)(nil)).Elem()).Type() {
+ fmt.Printf("[Actor] ERROR: the latest return type %s of method %q is not error\n", returnType, t.Name)
+ continue
+ }
+
+ funcOuts := make([]reflect.Type, outNum)
+ for i := 0; i < outNum; i++ {
+ funcOuts[i] = t.Type.Out(i)
+ }
+
+ f.Set(reflect.MakeFunc(f.Type(), c.makeCallProxyFunction(actor, methodName, funcOuts, serializer)))
+ }
+ }
+}
+
+func (c *GRPCClient) makeCallProxyFunction(actor actor.Client, methodName string, outs []reflect.Type, serializer codec.Codec) func(in []reflect.Value) []reflect.Value {
+ return func(in []reflect.Value) []reflect.Value {
+ var (
+ err error
+ inIArr []interface{}
+ reply reflect.Value
+ )
+
+ if len(outs) == 2 {
+ if outs[0].Kind() == reflect.Ptr {
+ reply = reflect.New(outs[0].Elem())
+ } else {
+ reply = reflect.New(outs[0])
+ }
+ }
+
+ start := 0
+ end := len(in)
+ invCtx := context.Background()
+ if end > 0 {
+ if in[0].Type().String() == "context.Context" {
+ if !in[0].IsNil() {
+ invCtx = in[0].Interface().(context.Context)
+ }
+ start++
+ }
+ }
+
+ if end-start <= 0 {
+ inIArr = []interface{}{}
+ } else if end-start == 1 {
+ inIArr = []interface{}{in[start].Interface()}
+ } else {
+ fmt.Println("[Actor] ERROR: param nums is zero or one is allowed by actor")
+ return nil
+ }
+
+ var data []byte
+ if len(inIArr) > 0 {
+ data, err = json.Marshal(inIArr[0])
+ }
+ if err != nil {
+ panic(err)
+ }
+
+ rsp, err := c.InvokeActor(invCtx, &InvokeActorRequest{
+ ActorType: actor.Type(),
+ ActorID: actor.ID(),
+ Method: methodName,
+ Data: data,
+ })
+
+ if len(outs) == 1 {
+ return []reflect.Value{reflect.ValueOf(&err).Elem()}
+ }
+
+ response := reply.Interface()
+ if rsp != nil {
+ if err = serializer.Unmarshal(rsp.Data, response); err != nil {
+ fmt.Printf("[Actor] ERROR: unmarshal response err = %v\n", err)
+ }
+ }
+ if len(outs) == 2 && outs[0].Kind() != reflect.Ptr {
+ return []reflect.Value{reply.Elem(), reflect.ValueOf(&err).Elem()}
+ }
+ return []reflect.Value{reply, reflect.ValueOf(&err).Elem()}
+ }
+}
+
+type GetActorStateRequest struct {
+ ActorType string
+ ActorID string
+ KeyName string
+}
+
+type GetActorStateResponse struct {
+ Data []byte
+}
+
+func (c *GRPCClient) GetActorState(ctx context.Context, in *GetActorStateRequest) (*GetActorStateResponse, error) {
+ if in == nil {
+ return nil, errors.New("actor get state invocation request param required")
+ }
+ if in.ActorType == "" {
+ return nil, errors.New("actor get state invocation actorType required")
+ }
+ if in.ActorID == "" {
+ return nil, errors.New("actor get state invocation actorID required")
+ }
+ if in.KeyName == "" {
+ return nil, errors.New("actor get state invocation keyName required")
+ }
+ rsp, err := c.protoClient.GetActorState(c.withAuthToken(ctx), &pb.GetActorStateRequest{
+ ActorId: in.ActorID,
+ ActorType: in.ActorType,
+ Key: in.KeyName,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("error invoking actor get state %s/%s: %w", in.ActorType, in.ActorID, err)
+ }
+ return &GetActorStateResponse{Data: rsp.Data}, nil
+}
+
+type ActorStateOperation struct {
+ OperationType string
+ Key string
+ Value []byte
+ TTLInSeconds *int64
+}
+
+func (c *GRPCClient) SaveStateTransactionally(ctx context.Context, actorType, actorID string, operations []*ActorStateOperation) error {
+ if len(operations) == 0 {
+ return errors.New("actor save state transactionally invocation request param operations is empty")
+ }
+ if actorType == "" {
+ return errors.New("actor save state transactionally invocation actorType required")
+ }
+ if actorID == "" {
+ return errors.New("actor save state transactionally invocation actorID required")
+ }
+ grpcOperations := make([]*pb.TransactionalActorStateOperation, 0)
+ for _, op := range operations {
+ var metadata map[string]string
+ if op.TTLInSeconds != nil {
+ metadata = make(map[string]string)
+ metadata[metadataKeyTTLInSeconds] = strconv.FormatInt(*op.TTLInSeconds, 10)
+ }
+ grpcOperations = append(grpcOperations, &pb.TransactionalActorStateOperation{
+ OperationType: op.OperationType,
+ Key: op.Key,
+ Value: &anypb.Any{
+ Value: op.Value,
+ },
+ Metadata: metadata,
+ })
+ }
+ _, err := c.protoClient.ExecuteActorStateTransaction(c.withAuthToken(ctx), &pb.ExecuteActorStateTransactionRequest{
+ ActorType: actorType,
+ ActorId: actorID,
+ Operations: grpcOperations,
+ })
+ return err
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/binding.go b/vendor/github.com/dapr/go-sdk/client/binding.go
new file mode 100644
index 00000000000..855fb102b03
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/binding.go
@@ -0,0 +1,86 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "errors"
+ "fmt"
+
+ pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
+)
+
+// InvokeBindingRequest represents binding invocation request.
+type InvokeBindingRequest struct {
+ // Name is name of binding to invoke.
+ Name string
+ // Operation is the name of the operation type for the binding to invoke
+ Operation string
+ // Data is the input bindings sent
+ Data []byte
+ // Metadata is the input binding metadata
+ Metadata map[string]string
+}
+
+// BindingEvent represents the binding event handler input.
+type BindingEvent struct {
+ // Data is the input bindings sent
+ Data []byte
+ // Metadata is the input binding metadata
+ Metadata map[string]string
+}
+
+// InvokeBinding invokes specific operation on the configured Dapr binding.
+// This method covers input, output, and bi-directional bindings.
+func (c *GRPCClient) InvokeBinding(ctx context.Context, in *InvokeBindingRequest) (*BindingEvent, error) {
+ if in == nil {
+ return nil, errors.New("binding invocation required")
+ }
+ if in.Name == "" {
+ return nil, errors.New("binding invocation name required")
+ }
+ if in.Operation == "" {
+ return nil, errors.New("binding invocation operation required")
+ }
+
+ req := &pb.InvokeBindingRequest{
+ Name: in.Name,
+ Operation: in.Operation,
+ Data: in.Data,
+ Metadata: in.Metadata,
+ }
+
+ resp, err := c.protoClient.InvokeBinding(c.withAuthToken(ctx), req)
+ if err != nil {
+ return nil, fmt.Errorf("error invoking binding %s/%s: %w", in.Name, in.Operation, err)
+ }
+
+ if resp != nil {
+ return &BindingEvent{
+ Data: resp.Data,
+ Metadata: resp.Metadata,
+ }, nil
+ }
+
+ return nil, nil
+}
+
+// InvokeOutputBinding invokes configured Dapr binding with data (allows nil).InvokeOutputBinding
+// This method differs from InvokeBinding in that it doesn't expect any content being returned from the invoked method.
+func (c *GRPCClient) InvokeOutputBinding(ctx context.Context, in *InvokeBindingRequest) error {
+ if _, err := c.InvokeBinding(ctx, in); err != nil {
+ return fmt.Errorf("error invoking output binding: %w", err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/bufpool.go b/vendor/github.com/dapr/go-sdk/client/bufpool.go
new file mode 100644
index 00000000000..757f3a654e8
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/bufpool.go
@@ -0,0 +1,31 @@
+/*
+Copyright 2023 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "sync"
+)
+
+// Maximum size, in bytes, for the buffer used by stream invocations: 2KB.
+const StreamBufferSize = 2 << 10
+
+// Pool of *[]byte used by stream invocations. Their size is fixed at StreamBufferSize.
+var bufPool = sync.Pool{
+ New: func() any {
+ // Return a pointer here
+ // See https://github.com/dominikh/go-tools/issues/1336 for explanation
+ b := make([]byte, StreamBufferSize)
+ return &b
+ },
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/client.go b/vendor/github.com/dapr/go-sdk/client/client.go
new file mode 100644
index 00000000000..2d5a4d37844
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/client.go
@@ -0,0 +1,383 @@
+/*
+Copyright 2023 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "os"
+ "strconv"
+ "sync"
+ "time"
+
+ "github.com/dapr/go-sdk/actor"
+ "github.com/dapr/go-sdk/actor/config"
+ "github.com/dapr/go-sdk/version"
+
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
+ "google.golang.org/grpc/metadata"
+ "google.golang.org/protobuf/types/known/emptypb"
+
+ pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
+
+ // used to import codec implements.
+ _ "github.com/dapr/go-sdk/actor/codec/impl"
+)
+
+const (
+ daprPortDefault = "50001"
+ daprPortEnvVarName = "DAPR_GRPC_PORT" /* #nosec */
+ traceparentKey = "traceparent"
+ apiTokenKey = "dapr-api-token" /* #nosec */
+ apiTokenEnvVarName = "DAPR_API_TOKEN" /* #nosec */
+ clientDefaultTimeoutSeconds = 5
+ clientTimeoutSecondsEnvVarName = "DAPR_CLIENT_TIMEOUT_SECONDS"
+)
+
+var (
+ logger = log.New(os.Stdout, "", 0)
+ lock = &sync.Mutex{}
+ _ Client = (*GRPCClient)(nil)
+ defaultClient Client
+)
+
+// Client is the interface for Dapr client implementation.
+//
+//nolint:interfacebloat
+type Client interface {
+ // InvokeBinding invokes specific operation on the configured Dapr binding.
+ // This method covers input, output, and bi-directional bindings.
+ InvokeBinding(ctx context.Context, in *InvokeBindingRequest) (out *BindingEvent, err error)
+
+ // InvokeOutputBinding invokes configured Dapr binding with data.InvokeOutputBinding
+ // This method differs from InvokeBinding in that it doesn't expect any content being returned from the invoked method.
+ InvokeOutputBinding(ctx context.Context, in *InvokeBindingRequest) error
+
+ // InvokeMethod invokes service without raw data
+ InvokeMethod(ctx context.Context, appID, methodName, verb string) (out []byte, err error)
+
+ // InvokeMethodWithContent invokes service with content
+ InvokeMethodWithContent(ctx context.Context, appID, methodName, verb string, content *DataContent) (out []byte, err error)
+
+ // InvokeMethodWithCustomContent invokes app with custom content (struct + content type).
+ InvokeMethodWithCustomContent(ctx context.Context, appID, methodName, verb string, contentType string, content interface{}) (out []byte, err error)
+
+ // PublishEvent publishes data onto topic in specific pubsub component.
+ PublishEvent(ctx context.Context, pubsubName, topicName string, data interface{}, opts ...PublishEventOption) error
+
+ // PublishEventfromCustomContent serializes an struct and publishes its contents as data (JSON) onto topic in specific pubsub component.
+ // Deprecated: This method is deprecated and will be removed in a future version of the SDK. Please use `PublishEvent` instead.
+ PublishEventfromCustomContent(ctx context.Context, pubsubName, topicName string, data interface{}) error
+
+ // PublishEvents publishes multiple events onto topic in specific pubsub component.
+ // If all events are successfully published, response Error will be nil.
+ // The FailedEvents field will contain all events that failed to publish.
+ PublishEvents(ctx context.Context, pubsubName, topicName string, events []interface{}, opts ...PublishEventsOption) PublishEventsResponse
+
+ // GetSecret retrieves preconfigured secret from specified store using key.
+ GetSecret(ctx context.Context, storeName, key string, meta map[string]string) (data map[string]string, err error)
+
+ // GetBulkSecret retrieves all preconfigured secrets for this application.
+ GetBulkSecret(ctx context.Context, storeName string, meta map[string]string) (data map[string]map[string]string, err error)
+
+ // SaveState saves the raw data into store using default state options.
+ SaveState(ctx context.Context, storeName, key string, data []byte, meta map[string]string, so ...StateOption) error
+
+ // SaveState saves the raw data into store using provided state options and etag.
+ SaveStateWithETag(ctx context.Context, storeName, key string, data []byte, etag string, meta map[string]string, so ...StateOption) error
+
+ // SaveBulkState saves multiple state item to store with specified options.
+ SaveBulkState(ctx context.Context, storeName string, items ...*SetStateItem) error
+
+ // GetState retrieves state from specific store using default consistency option.
+ GetState(ctx context.Context, storeName, key string, meta map[string]string) (item *StateItem, err error)
+
+ // GetStateWithConsistency retrieves state from specific store using provided state consistency.
+ GetStateWithConsistency(ctx context.Context, storeName, key string, meta map[string]string, sc StateConsistency) (item *StateItem, err error)
+
+ // GetBulkState retrieves state for multiple keys from specific store.
+ GetBulkState(ctx context.Context, storeName string, keys []string, meta map[string]string, parallelism int32) ([]*BulkStateItem, error)
+
+ // QueryStateAlpha1 runs a query against state store.
+ QueryStateAlpha1(ctx context.Context, storeName, query string, meta map[string]string) (*QueryResponse, error)
+
+ // DeleteState deletes content from store using default state options.
+ DeleteState(ctx context.Context, storeName, key string, meta map[string]string) error
+
+ // DeleteStateWithETag deletes content from store using provided state options and etag.
+ DeleteStateWithETag(ctx context.Context, storeName, key string, etag *ETag, meta map[string]string, opts *StateOptions) error
+
+ // ExecuteStateTransaction provides way to execute multiple operations on a specified store.
+ ExecuteStateTransaction(ctx context.Context, storeName string, meta map[string]string, ops []*StateOperation) error
+
+ // GetConfigurationItem can get target configuration item by storeName and key
+ GetConfigurationItem(ctx context.Context, storeName, key string, opts ...ConfigurationOpt) (*ConfigurationItem, error)
+
+ // GetConfigurationItems can get a list of configuration item by storeName and keys
+ GetConfigurationItems(ctx context.Context, storeName string, keys []string, opts ...ConfigurationOpt) (map[string]*ConfigurationItem, error)
+
+ // SubscribeConfigurationItems can subscribe the change of configuration items by storeName and keys, and return subscription id
+ SubscribeConfigurationItems(ctx context.Context, storeName string, keys []string, handler ConfigurationHandleFunction, opts ...ConfigurationOpt) (string, error)
+
+ // UnsubscribeConfigurationItems can stop the subscription with target store's and id
+ UnsubscribeConfigurationItems(ctx context.Context, storeName string, id string, opts ...ConfigurationOpt) error
+
+ // DeleteBulkState deletes content for multiple keys from store.
+ DeleteBulkState(ctx context.Context, storeName string, keys []string, meta map[string]string) error
+
+ // DeleteBulkStateItems deletes content for multiple items from store.
+ DeleteBulkStateItems(ctx context.Context, storeName string, items []*DeleteStateItem) error
+
+ // TryLockAlpha1 attempts to grab a lock from a lock store.
+ TryLockAlpha1(ctx context.Context, storeName string, request *LockRequest) (*LockResponse, error)
+
+ // UnlockAlpha1 deletes unlocks a lock from a lock store.
+ UnlockAlpha1(ctx context.Context, storeName string, request *UnlockRequest) (*UnlockResponse, error)
+
+ // Encrypt data read from a stream, returning a readable stream that receives the encrypted data.
+ // This method returns an error if the initial call fails. Errors performed during the encryption are received by the out stream.
+ Encrypt(ctx context.Context, in io.Reader, opts EncryptOptions) (io.Reader, error)
+
+ // Decrypt data read from a stream, returning a readable stream that receives the decrypted data.
+ // This method returns an error if the initial call fails. Errors performed during the encryption are received by the out stream.
+ Decrypt(ctx context.Context, in io.Reader, opts DecryptOptions) (io.Reader, error)
+
+ // Shutdown the sidecar.
+ Shutdown(ctx context.Context) error
+
+ // Wait for a sidecar to become available for at most `timeout` seconds. Returns errWaitTimedOut if timeout is reached.
+ Wait(ctx context.Context, timeout time.Duration) error
+
+ // WithTraceID adds existing trace ID to the outgoing context.
+ WithTraceID(ctx context.Context, id string) context.Context
+
+ // WithAuthToken sets Dapr API token on the instantiated client.
+ WithAuthToken(token string)
+
+ // Close cleans up all resources created by the client.
+ Close()
+
+ // RegisterActorTimer registers an actor timer.
+ RegisterActorTimer(ctx context.Context, req *RegisterActorTimerRequest) error
+
+ // UnregisterActorTimer unregisters an actor timer.
+ UnregisterActorTimer(ctx context.Context, req *UnregisterActorTimerRequest) error
+
+ // RegisterActorReminder registers an actor reminder.
+ RegisterActorReminder(ctx context.Context, req *RegisterActorReminderRequest) error
+
+ // UnregisterActorReminder unregisters an actor reminder.
+ UnregisterActorReminder(ctx context.Context, req *UnregisterActorReminderRequest) error
+
+ // RenameActorReminder rename an actor reminder.
+ RenameActorReminder(ctx context.Context, req *RenameActorReminderRequest) error
+
+ // InvokeActor calls a method on an actor.
+ InvokeActor(ctx context.Context, req *InvokeActorRequest) (*InvokeActorResponse, error)
+
+ // GetActorState get actor state
+ GetActorState(ctx context.Context, req *GetActorStateRequest) (data *GetActorStateResponse, err error)
+
+ // SaveStateTransactionally save actor state
+ SaveStateTransactionally(ctx context.Context, actorType, actorID string, operations []*ActorStateOperation) error
+
+ // ImplActorClientStub is to impl user defined actor client stub
+ ImplActorClientStub(actorClientStub actor.Client, opt ...config.Option)
+
+ // GrpcClient returns the base grpc client if grpc is used and nil otherwise
+ GrpcClient() pb.DaprClient
+}
+
+// NewClient instantiates Dapr client using DAPR_GRPC_PORT environment variable as port.
+// Note, this default factory function creates Dapr client only once. All subsequent invocations
+// will return the already created instance. To create multiple instances of the Dapr client,
+// use one of the parameterized factory functions:
+//
+// NewClientWithPort(port string) (client Client, err error)
+// NewClientWithAddress(address string) (client Client, err error)
+// NewClientWithConnection(conn *grpc.ClientConn) Client
+// NewClientWithSocket(socket string) (client Client, err error)
+func NewClient() (client Client, err error) {
+ port := os.Getenv(daprPortEnvVarName)
+ if port == "" {
+ port = daprPortDefault
+ }
+ if defaultClient != nil {
+ return defaultClient, nil
+ }
+ lock.Lock()
+ defer lock.Unlock()
+ if defaultClient != nil {
+ return defaultClient, nil
+ }
+ c, err := NewClientWithPort(port)
+ if err != nil {
+ return nil, fmt.Errorf("error creating default client: %w", err)
+ }
+ defaultClient = c
+
+ return defaultClient, nil
+}
+
+// NewClientWithPort instantiates Dapr using specific gRPC port.
+func NewClientWithPort(port string) (client Client, err error) {
+ if port == "" {
+ return nil, errors.New("nil port")
+ }
+ return NewClientWithAddress(net.JoinHostPort("127.0.0.1", port))
+}
+
+// NewClientWithAddress instantiates Dapr using specific address (including port).
+// Deprecated: use NewClientWithAddressContext instead.
+func NewClientWithAddress(address string) (client Client, err error) {
+ return NewClientWithAddressContext(context.Background(), address)
+}
+
+// NewClientWithAddress instantiates Dapr using specific address (including port).
+// Uses the provided context to create the connection.
+func NewClientWithAddressContext(ctx context.Context, address string) (client Client, err error) {
+ if address == "" {
+ return nil, errors.New("empty address")
+ }
+ logger.Printf("dapr client initializing for: %s", address)
+
+ timeoutSeconds, err := getClientTimeoutSeconds()
+ if err != nil {
+ return nil, err
+ }
+ ctx, cancel := context.WithTimeout(ctx, time.Duration(timeoutSeconds)*time.Second)
+ conn, err := grpc.DialContext(
+ ctx,
+ address,
+ grpc.WithTransportCredentials(insecure.NewCredentials()),
+ grpc.WithUserAgent("dapr-sdk-go/"+version.SDKVersion),
+ grpc.WithBlock(),
+ )
+ cancel()
+ if err != nil {
+ return nil, fmt.Errorf("error creating connection to '%s': %w", address, err)
+ }
+ if hasToken := os.Getenv(apiTokenEnvVarName); hasToken != "" {
+ logger.Println("client uses API token")
+ }
+
+ return NewClientWithConnection(conn), nil
+}
+
+func getClientTimeoutSeconds() (int, error) {
+ timeoutStr := os.Getenv(clientTimeoutSecondsEnvVarName)
+ if len(timeoutStr) == 0 {
+ return clientDefaultTimeoutSeconds, nil
+ }
+ timeoutVar, err := strconv.Atoi(timeoutStr)
+ if err != nil {
+ return 0, err
+ }
+ if timeoutVar <= 0 {
+ return 0, errors.New("incorrect value")
+ }
+ return timeoutVar, nil
+}
+
+// NewClientWithSocket instantiates Dapr using specific socket.
+func NewClientWithSocket(socket string) (client Client, err error) {
+ if socket == "" {
+ return nil, errors.New("nil socket")
+ }
+ logger.Printf("dapr client initializing for: %s", socket)
+ addr := "unix://" + socket
+ conn, err := grpc.Dial(
+ addr,
+ grpc.WithTransportCredentials(insecure.NewCredentials()),
+ grpc.WithUserAgent("dapr-sdk-go/"+version.SDKVersion),
+ )
+ if err != nil {
+ return nil, fmt.Errorf("error creating connection to '%s': %w", addr, err)
+ }
+ if hasToken := os.Getenv(apiTokenEnvVarName); hasToken != "" {
+ logger.Println("client uses API token")
+ }
+ return NewClientWithConnection(conn), nil
+}
+
+// NewClientWithConnection instantiates Dapr client using specific connection.
+func NewClientWithConnection(conn *grpc.ClientConn) Client {
+ return &GRPCClient{
+ connection: conn,
+ protoClient: pb.NewDaprClient(conn),
+ authToken: os.Getenv(apiTokenEnvVarName),
+ }
+}
+
+// GRPCClient is the gRPC implementation of Dapr client.
+type GRPCClient struct {
+ connection *grpc.ClientConn
+ protoClient pb.DaprClient
+ authToken string
+}
+
+// Close cleans up all resources created by the client.
+func (c *GRPCClient) Close() {
+ if c.connection != nil {
+ c.connection.Close()
+ c.connection = nil
+ }
+}
+
+// WithAuthToken sets Dapr API token on the instantiated client.
+// Allows empty string to reset token on existing client.
+func (c *GRPCClient) WithAuthToken(token string) {
+ c.authToken = token
+}
+
+// WithTraceID adds existing trace ID to the outgoing context.
+func (c *GRPCClient) WithTraceID(ctx context.Context, id string) context.Context {
+ if id == "" {
+ return ctx
+ }
+ logger.Printf("using trace parent ID: %s", id)
+ md := metadata.Pairs(traceparentKey, id)
+ return metadata.NewOutgoingContext(ctx, md)
+}
+
+func (c *GRPCClient) withAuthToken(ctx context.Context) context.Context {
+ if c.authToken == "" {
+ return ctx
+ }
+ return metadata.NewOutgoingContext(ctx, metadata.Pairs(apiTokenKey, c.authToken))
+}
+
+// Shutdown the sidecar.
+func (c *GRPCClient) Shutdown(ctx context.Context) error {
+ _, err := c.protoClient.Shutdown(c.withAuthToken(ctx), &emptypb.Empty{})
+ if err != nil {
+ return fmt.Errorf("error shutting down the sidecar: %w", err)
+ }
+ return nil
+}
+
+// GrpcClient returns the base grpc client.
+func (c *GRPCClient) GrpcClient() pb.DaprClient {
+ return c.protoClient
+}
+
+// GrpcClientConn returns the grpc.ClientConn object used by this client.
+func (c *GRPCClient) GrpcClientConn() *grpc.ClientConn {
+ return c.connection
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/configuration.go b/vendor/github.com/dapr/go-sdk/client/configuration.go
new file mode 100644
index 00000000000..9c245c4f590
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/configuration.go
@@ -0,0 +1,126 @@
+package client
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+
+ pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
+)
+
+type ConfigurationItem struct {
+ Value string
+ Version string
+ Metadata map[string]string
+}
+
+type ConfigurationOpt func(map[string]string)
+
+func WithConfigurationMetadata(key, value string) ConfigurationOpt {
+ return func(m map[string]string) {
+ m[key] = value
+ }
+}
+
+func (c *GRPCClient) GetConfigurationItem(ctx context.Context, storeName, key string, opts ...ConfigurationOpt) (*ConfigurationItem, error) {
+ items, err := c.GetConfigurationItems(ctx, storeName, []string{key}, opts...)
+ if err != nil {
+ return nil, err
+ }
+ if len(items) == 0 {
+ return nil, nil
+ }
+
+ return items[key], nil
+}
+
+func (c *GRPCClient) GetConfigurationItems(ctx context.Context, storeName string, keys []string, opts ...ConfigurationOpt) (map[string]*ConfigurationItem, error) {
+ metadata := make(map[string]string)
+ for _, opt := range opts {
+ opt(metadata)
+ }
+ rsp, err := c.protoClient.GetConfiguration(ctx, &pb.GetConfigurationRequest{
+ StoreName: storeName,
+ Keys: keys,
+ Metadata: metadata,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ configItems := make(map[string]*ConfigurationItem)
+ for k, v := range rsp.Items {
+ configItems[k] = &ConfigurationItem{
+ Value: v.Value,
+ Version: v.Version,
+ Metadata: v.Metadata,
+ }
+ }
+ return configItems, nil
+}
+
+type ConfigurationHandleFunction func(string, map[string]*ConfigurationItem)
+
+func (c *GRPCClient) SubscribeConfigurationItems(ctx context.Context, storeName string, keys []string, handler ConfigurationHandleFunction, opts ...ConfigurationOpt) (string, error) {
+ metadata := make(map[string]string)
+ for _, opt := range opts {
+ opt(metadata)
+ }
+
+ client, err := c.protoClient.SubscribeConfiguration(ctx, &pb.SubscribeConfigurationRequest{
+ StoreName: storeName,
+ Keys: keys,
+ Metadata: metadata,
+ })
+ if err != nil {
+ return "", fmt.Errorf("subscribe configuration failed with error = %w", err)
+ }
+ subscribeIDChan := make(chan string, 1)
+ go func() {
+ isFirst := true
+ for {
+ rsp, err := client.Recv()
+ if errors.Is(err, io.EOF) || rsp == nil {
+ // receive goroutine would close if unsubscribe is called.
+ fmt.Println("dapr configuration subscribe finished.")
+ break
+ }
+ configurationItems := make(map[string]*ConfigurationItem)
+
+ for k, v := range rsp.Items {
+ configurationItems[k] = &ConfigurationItem{
+ Value: v.Value,
+ Version: v.Version,
+ Metadata: v.Metadata,
+ }
+ }
+ // Get the subscription ID from the first response.
+ if isFirst {
+ subscribeIDChan <- rsp.Id
+ isFirst = false
+ }
+ // Do not invoke handler in case there are no items.
+ if len(configurationItems) > 0 {
+ handler(rsp.Id, configurationItems)
+ }
+ }
+ }()
+ subscribeID := <-subscribeIDChan
+ close(subscribeIDChan)
+ return subscribeID, nil
+}
+
+func (c *GRPCClient) UnsubscribeConfigurationItems(ctx context.Context, storeName string, id string, opts ...ConfigurationOpt) error {
+ resp, err := c.protoClient.UnsubscribeConfiguration(ctx, &pb.UnsubscribeConfigurationRequest{
+ StoreName: storeName,
+ Id: id,
+ })
+ if err != nil {
+ return fmt.Errorf("unsubscribe failed with error = %w", err)
+ }
+ if !resp.Ok {
+ return fmt.Errorf("unsubscribe error message = %s", resp.GetMessage())
+ }
+ return nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/crypto.go b/vendor/github.com/dapr/go-sdk/client/crypto.go
new file mode 100644
index 00000000000..e3d28c677ff
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/crypto.go
@@ -0,0 +1,272 @@
+/*
+Copyright 2023 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+
+ "google.golang.org/grpc"
+ "google.golang.org/protobuf/proto"
+
+ commonv1pb "github.com/dapr/go-sdk/dapr/proto/common/v1"
+ runtimev1pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
+)
+
+// Encrypt data read from a stream, returning a readable stream that receives the encrypted data.
+// This method returns an error if the initial call fails. Errors performed during the encryption are received by the out stream.
+func (c *GRPCClient) Encrypt(ctx context.Context, in io.Reader, opts EncryptOptions) (io.Reader, error) {
+ // Ensure required options are present
+ // This short-circuits and avoids a call to the runtime
+ if opts.ComponentName == "" {
+ return nil, errors.New("option 'ComponentName' is required")
+ }
+ if opts.KeyName == "" {
+ return nil, errors.New("option 'KeyName' is required")
+ }
+ if opts.KeyWrapAlgorithm == "" {
+ return nil, errors.New("option 'Algorithm' is required")
+ }
+
+ // Create the stream
+ stream, err := c.protoClient.EncryptAlpha1(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ // Use the context of the stream here.
+ return c.performCryptoOperation(
+ stream.Context(), stream,
+ in, opts,
+ &runtimev1pb.EncryptRequest{},
+ &runtimev1pb.EncryptResponse{},
+ )
+}
+
+// Decrypt data read from a stream, returning a readable stream that receives the decrypted data.
+// This method returns an error if the initial call fails. Errors performed during the encryption are received by the out stream.
+func (c *GRPCClient) Decrypt(ctx context.Context, in io.Reader, opts DecryptOptions) (io.Reader, error) {
+ // Ensure required options are present
+ // This short-circuits and avoids a call to the runtime
+ if opts.ComponentName == "" {
+ return nil, errors.New("option 'ComponentName' is required")
+ }
+
+ // Create the stream
+ stream, err := c.protoClient.DecryptAlpha1(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ // Use the context of the stream here.
+ return c.performCryptoOperation(
+ stream.Context(), stream,
+ in, opts,
+ &runtimev1pb.DecryptRequest{},
+ &runtimev1pb.DecryptResponse{},
+ )
+}
+
+func (c *GRPCClient) performCryptoOperation(ctx context.Context, stream grpc.ClientStream, in io.Reader, opts cryptoOperationOpts, reqProto runtimev1pb.CryptoRequests, resProto runtimev1pb.CryptoResponses) (io.Reader, error) {
+ var err error
+ // Pipe for writing the response
+ pr, pw := io.Pipe()
+
+ // Send the request in a background goroutine
+ go func() {
+ // Build the options object for the first message
+ optsProto := opts.getProto()
+
+ // Get a buffer from the pool
+ reqBuf := bufPool.Get().(*[]byte)
+ defer func() {
+ bufPool.Put(reqBuf)
+ }()
+
+ // Send the request in chunks
+ var (
+ n int
+ seq uint64
+ done bool
+ )
+ for {
+ if ctx.Err() != nil {
+ pw.CloseWithError(ctx.Err())
+ return
+ }
+
+ // First message only - add the options
+ if optsProto != nil {
+ reqProto.SetOptions(optsProto)
+ optsProto = nil
+ } else {
+ // Reset the object so we can re-use it
+ reqProto.Reset()
+ }
+
+ n, err = in.Read(*reqBuf)
+ if err == io.EOF {
+ done = true
+ } else if err != nil {
+ pw.CloseWithError(err)
+ return
+ }
+
+ // Send the chunk if there's anything to send
+ if n > 0 {
+ reqProto.SetPayload(&commonv1pb.StreamPayload{
+ Data: (*reqBuf)[:n],
+ Seq: seq,
+ })
+ seq++
+
+ err = stream.SendMsg(reqProto)
+ if errors.Is(err, io.EOF) {
+ // If SendMsg returns an io.EOF error, it usually means that there's a transport-level error
+ // The exact error can only be determined by RecvMsg, so if we encounter an EOF error here, just consider the stream done and let RecvMsg handle the error
+ done = true
+ } else if err != nil {
+ pw.CloseWithError(fmt.Errorf("error sending message: %w", err))
+ return
+ }
+ }
+
+ // Stop the loop with the last chunk
+ if done {
+ err = stream.CloseSend()
+ if err != nil {
+ pw.CloseWithError(fmt.Errorf("failed to close the send direction of the stream: %w", err))
+ return
+ }
+
+ break
+ }
+ }
+ }()
+
+ // Read the response in another goroutine
+ go func() {
+ var (
+ expectSeq uint64
+ readErr error
+ done bool
+ payload *commonv1pb.StreamPayload
+ )
+
+ // Read until the end of the stream
+ for {
+ if ctx.Err() != nil {
+ pw.CloseWithError(ctx.Err())
+ return
+ }
+
+ // Read the next chunk
+ readErr = stream.RecvMsg(resProto)
+ if errors.Is(readErr, io.EOF) {
+ // Receiving an io.EOF signifies that the client has stopped sending data over the pipe, so this is the end
+ done = true
+ } else if readErr != nil {
+ pw.CloseWithError(fmt.Errorf("error receiving message: %w", readErr))
+ return
+ }
+
+ // Write the data, if any, into the pipe
+ payload = resProto.GetPayload()
+ if payload != nil {
+ if payload.Seq != expectSeq {
+ pw.CloseWithError(fmt.Errorf("invalid sequence number in chunk: %d (expected: %d)", payload.Seq, expectSeq))
+ return
+ }
+ expectSeq++
+
+ _, readErr = pw.Write(payload.Data)
+ if readErr != nil {
+ pw.CloseWithError(fmt.Errorf("error writing data: %w", readErr))
+ return
+ }
+ }
+
+ // Stop when done
+ if done {
+ break
+ }
+
+ // Reset the proto
+ resProto.Reset()
+ }
+
+ // Close the writer of the pipe when done
+ pw.Close()
+ }()
+
+ // Return the readable stream
+ return pr, nil
+}
+
+// Interface for EncryptOptions and DecryptOptions
+type cryptoOperationOpts interface {
+ getProto() proto.Message
+}
+
+// EncryptOptions contains options passed to the Encrypt method.
+type EncryptOptions struct {
+ // Name of the component. Required.
+ ComponentName string
+ // Name (or name/version) of the key. Required.
+ KeyName string
+ // Key wrapping algorithm to use. Required.
+ // Supported options include: A256KW, A128CBC, A192CBC, A256CBC, RSA-OAEP-256.
+ KeyWrapAlgorithm string
+ // DataEncryptionCipher to use to encrypt data (optional): "aes-gcm" (default) or "chacha20-poly1305"
+ DataEncryptionCipher string
+ // If true, the encrypted document does not contain a key reference.
+ // In that case, calls to the Decrypt method must provide a key reference (name or name/version).
+ // Defaults to false.
+ OmitDecryptionKeyName bool
+ // Key reference to embed in the encrypted document (name or name/version).
+ // This is helpful if the reference of the key used to decrypt the document is different from the one used to encrypt it.
+ // If unset, uses the reference of the key used to encrypt the document (this is the default behavior).
+ // This option is ignored if omit_decryption_key_name is true.
+ DecryptionKeyName string
+}
+
+func (o EncryptOptions) getProto() proto.Message {
+ return &runtimev1pb.EncryptRequestOptions{
+ ComponentName: o.ComponentName,
+ KeyName: o.KeyName,
+ KeyWrapAlgorithm: o.KeyWrapAlgorithm,
+ DataEncryptionCipher: o.DataEncryptionCipher,
+ OmitDecryptionKeyName: o.OmitDecryptionKeyName,
+ DecryptionKeyName: o.DecryptionKeyName,
+ }
+}
+
+// DecryptOptions contains options passed to the Decrypt method.
+type DecryptOptions struct {
+ // Name of the component. Required.
+ ComponentName string
+ // Name (or name/version) of the key to decrypt the message.
+ // Overrides any key reference included in the message if present.
+ // This is required if the message doesn't include a key reference (i.e. was created with omit_decryption_key_name set to true).
+ KeyName string
+}
+
+func (o DecryptOptions) getProto() proto.Message {
+ return &runtimev1pb.DecryptRequestOptions{
+ ComponentName: o.ComponentName,
+ KeyName: o.KeyName,
+ }
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/invoke.go b/vendor/github.com/dapr/go-sdk/client/invoke.go
new file mode 100644
index 00000000000..46c2630f61c
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/invoke.go
@@ -0,0 +1,153 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "strings"
+
+ anypb "github.com/golang/protobuf/ptypes/any"
+
+ v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
+ pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
+)
+
+// DataContent the service invocation content.
+type DataContent struct {
+ // Data is the input data
+ Data []byte
+ // ContentType is the type of the data content
+ ContentType string
+}
+
+func (c *GRPCClient) invokeServiceWithRequest(ctx context.Context, req *pb.InvokeServiceRequest) (out []byte, err error) {
+ if req == nil {
+ return nil, errors.New("nil request")
+ }
+
+ resp, err := c.protoClient.InvokeService(c.withAuthToken(ctx), req)
+ if err != nil {
+ return nil, err
+ }
+
+ // allow for service to not return any value
+ if resp != nil && resp.GetData() != nil {
+ out = resp.GetData().Value
+ return
+ }
+
+ out = nil
+ return
+}
+
+func queryAndVerbToHTTPExtension(query string, verb string) *v1.HTTPExtension {
+ if v, ok := v1.HTTPExtension_Verb_value[strings.ToUpper(verb)]; ok {
+ return &v1.HTTPExtension{Verb: v1.HTTPExtension_Verb(v), Querystring: query}
+ }
+ return &v1.HTTPExtension{Verb: v1.HTTPExtension_NONE}
+}
+
+func hasRequiredInvokeArgs(appID, methodName, verb string) error {
+ if appID == "" {
+ return errors.New("appID")
+ }
+ if methodName == "" {
+ return errors.New("methodName")
+ }
+ if verb == "" {
+ return errors.New("verb")
+ }
+ return nil
+}
+
+// InvokeMethod invokes service without raw data ([]byte).
+func (c *GRPCClient) InvokeMethod(ctx context.Context, appID, methodName, verb string) (out []byte, err error) {
+ if err := hasRequiredInvokeArgs(appID, methodName, verb); err != nil {
+ return nil, fmt.Errorf("missing required parameter: %w", err)
+ }
+ method, query := extractMethodAndQuery(methodName)
+ req := &pb.InvokeServiceRequest{
+ Id: appID,
+ Message: &v1.InvokeRequest{
+ Method: method,
+ HttpExtension: queryAndVerbToHTTPExtension(query, verb),
+ },
+ }
+ return c.invokeServiceWithRequest(ctx, req)
+}
+
+// InvokeMethodWithContent invokes service with content (data + content type).
+func (c *GRPCClient) InvokeMethodWithContent(ctx context.Context, appID, methodName, verb string, content *DataContent) (out []byte, err error) {
+ if err := hasRequiredInvokeArgs(appID, methodName, verb); err != nil {
+ return nil, fmt.Errorf("missing required parameter: %w", err)
+ }
+ if content == nil {
+ return nil, errors.New("content required")
+ }
+ method, query := extractMethodAndQuery(methodName)
+ req := &pb.InvokeServiceRequest{
+ Id: appID,
+ Message: &v1.InvokeRequest{
+ Method: method,
+ Data: &anypb.Any{Value: content.Data},
+ ContentType: content.ContentType,
+ HttpExtension: queryAndVerbToHTTPExtension(query, verb),
+ },
+ }
+ return c.invokeServiceWithRequest(ctx, req)
+}
+
+// InvokeMethodWithCustomContent invokes service with custom content (struct + content type).
+func (c *GRPCClient) InvokeMethodWithCustomContent(ctx context.Context, appID, methodName, verb string, contentType string, content interface{}) ([]byte, error) {
+ if err := hasRequiredInvokeArgs(appID, methodName, verb); err != nil {
+ return nil, fmt.Errorf("missing required parameter: %w", err)
+ }
+ if contentType == "" {
+ return nil, errors.New("content type required")
+ }
+ if content == nil {
+ return nil, errors.New("content required")
+ }
+
+ contentData, err := json.Marshal(content)
+ if err != nil {
+ return nil, fmt.Errorf("error serializing input struct: %w", err)
+ }
+
+ method, query := extractMethodAndQuery(methodName)
+
+ req := &pb.InvokeServiceRequest{
+ Id: appID,
+ Message: &v1.InvokeRequest{
+ Method: method,
+ Data: &anypb.Any{Value: contentData},
+ ContentType: contentType,
+ HttpExtension: queryAndVerbToHTTPExtension(query, verb),
+ },
+ }
+
+ return c.invokeServiceWithRequest(ctx, req)
+}
+
+func extractMethodAndQuery(name string) (method, query string) {
+ splitStr := strings.SplitN(name, "?", 2)
+ method = splitStr[0]
+ if len(splitStr) == 2 {
+ query = splitStr[1]
+ }
+ return
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/lock.go b/vendor/github.com/dapr/go-sdk/client/lock.go
new file mode 100644
index 00000000000..c3e3c256f5e
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/lock.go
@@ -0,0 +1,100 @@
+/*
+Copyright 2022 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "errors"
+ "fmt"
+
+ pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
+)
+
+// LockRequest is the lock request object.
+type LockRequest struct {
+ ResourceID string
+ LockOwner string
+ ExpiryInSeconds int32
+}
+
+// UnlockRequest is the unlock request object.
+type UnlockRequest struct {
+ ResourceID string
+ LockOwner string
+}
+
+// LockResponse is the lock operation response object.
+type LockResponse struct {
+ Success bool
+}
+
+// UnlockResponse is the unlock operation response object.
+type UnlockResponse struct {
+ StatusCode int32
+ Status string
+}
+
+// TryLockAlpha1 attempts to grab a lock from a lock store.
+func (c *GRPCClient) TryLockAlpha1(ctx context.Context, storeName string, request *LockRequest) (*LockResponse, error) {
+ if storeName == "" {
+ return nil, errors.New("storeName is empty")
+ }
+
+ if request == nil {
+ return nil, errors.New("request is nil")
+ }
+
+ req := pb.TryLockRequest{
+ ResourceId: request.ResourceID,
+ LockOwner: request.LockOwner,
+ ExpiryInSeconds: request.ExpiryInSeconds,
+ StoreName: storeName,
+ }
+
+ resp, err := c.protoClient.TryLockAlpha1(ctx, &req)
+ if err != nil {
+ return nil, fmt.Errorf("error getting lock: %w", err)
+ }
+
+ return &LockResponse{
+ Success: resp.Success,
+ }, nil
+}
+
+// UnlockAlpha1 deletes unlocks a lock from a lock store.
+func (c *GRPCClient) UnlockAlpha1(ctx context.Context, storeName string, request *UnlockRequest) (*UnlockResponse, error) {
+ if storeName == "" {
+ return nil, errors.New("storeName is empty")
+ }
+
+ if request == nil {
+ return nil, errors.New("request is nil")
+ }
+
+ req := pb.UnlockRequest{
+ ResourceId: request.ResourceID,
+ LockOwner: request.LockOwner,
+ StoreName: storeName,
+ }
+
+ resp, err := c.protoClient.UnlockAlpha1(ctx, &req)
+ if err != nil {
+ return nil, fmt.Errorf("error getting lock: %w", err)
+ }
+
+ return &UnlockResponse{
+ StatusCode: int32(resp.Status),
+ Status: pb.UnlockResponse_Status_name[int32(resp.Status)],
+ }, nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/pubsub.go b/vendor/github.com/dapr/go-sdk/client/pubsub.go
new file mode 100644
index 00000000000..58cc52024dc
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/pubsub.go
@@ -0,0 +1,264 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "log"
+
+ "github.com/google/uuid"
+
+ pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
+)
+
+const (
+ rawPayload = "rawPayload"
+ trueValue = "true"
+)
+
+// PublishEventOption is the type for the functional option.
+type PublishEventOption func(*pb.PublishEventRequest)
+
+// PublishEvent publishes data onto specific pubsub topic.
+func (c *GRPCClient) PublishEvent(ctx context.Context, pubsubName, topicName string, data interface{}, opts ...PublishEventOption) error {
+ if pubsubName == "" {
+ return errors.New("pubsubName name required")
+ }
+ if topicName == "" {
+ return errors.New("topic name required")
+ }
+
+ request := &pb.PublishEventRequest{
+ PubsubName: pubsubName,
+ Topic: topicName,
+ }
+ for _, o := range opts {
+ o(request)
+ }
+
+ if data != nil {
+ switch d := data.(type) {
+ case []byte:
+ request.Data = d
+ case string:
+ request.Data = []byte(d)
+ default:
+ var err error
+ request.DataContentType = "application/json"
+ request.Data, err = json.Marshal(d)
+ if err != nil {
+ return fmt.Errorf("error serializing input struct: %w", err)
+ }
+ }
+ }
+
+ _, err := c.protoClient.PublishEvent(c.withAuthToken(ctx), request)
+ if err != nil {
+ return fmt.Errorf("error publishing event unto %s topic: %w", topicName, err)
+ }
+
+ return nil
+}
+
+// PublishEventWithContentType can be passed as option to PublishEvent to set an explicit Content-Type.
+func PublishEventWithContentType(contentType string) PublishEventOption {
+ return func(e *pb.PublishEventRequest) {
+ e.DataContentType = contentType
+ }
+}
+
+// PublishEventWithMetadata can be passed as option to PublishEvent to set metadata.
+func PublishEventWithMetadata(metadata map[string]string) PublishEventOption {
+ return func(e *pb.PublishEventRequest) {
+ e.Metadata = metadata
+ }
+}
+
+// PublishEventWithRawPayload can be passed as option to PublishEvent to set rawPayload metadata.
+func PublishEventWithRawPayload() PublishEventOption {
+ return func(e *pb.PublishEventRequest) {
+ if e.Metadata == nil {
+ e.Metadata = map[string]string{rawPayload: trueValue}
+ } else {
+ e.Metadata[rawPayload] = trueValue
+ }
+ }
+}
+
+// PublishEventfromCustomContent serializes an struct and publishes its contents as data (JSON) onto topic in specific pubsub component.
+// Deprecated: This method is deprecated and will be removed in a future version of the SDK. Please use `PublishEvent` instead.
+func (c *GRPCClient) PublishEventfromCustomContent(ctx context.Context, pubsubName, topicName string, data interface{}) error {
+ log.Println("DEPRECATED: client.PublishEventfromCustomContent is deprecated and will be removed in a future version of the SDK. Please use `PublishEvent` instead.")
+
+ // Perform the JSON marshaling here just in case someone passed a []byte or string as data
+ enc, err := json.Marshal(data)
+ if err != nil {
+ return fmt.Errorf("error serializing input struct: %w", err)
+ }
+
+ return c.PublishEvent(ctx, pubsubName, topicName, enc, PublishEventWithContentType("application/json"))
+}
+
+// PublishEventsEvent is a type of event that can be published using PublishEvents.
+type PublishEventsEvent struct {
+ EntryID string
+ Data []byte
+ ContentType string
+ Metadata map[string]string
+}
+
+// PublishEventsResponse is the response type for PublishEvents.
+type PublishEventsResponse struct {
+ Error error
+ FailedEvents []interface{}
+}
+
+// PublishEventsOption is the type for the functional option.
+type PublishEventsOption func(*pb.BulkPublishRequest)
+
+// PublishEvents publishes multiple events onto topic in specific pubsub component.
+// If all events are successfully published, response Error will be nil.
+// The FailedEvents field will contain all events that failed to publish.
+func (c *GRPCClient) PublishEvents(ctx context.Context, pubsubName, topicName string, events []interface{}, opts ...PublishEventsOption) PublishEventsResponse {
+ if pubsubName == "" {
+ return PublishEventsResponse{
+ Error: errors.New("pubsubName name required"),
+ FailedEvents: events,
+ }
+ }
+ if topicName == "" {
+ return PublishEventsResponse{
+ Error: errors.New("topic name required"),
+ FailedEvents: events,
+ }
+ }
+
+ failedEvents := make([]interface{}, 0, len(events))
+ eventMap := make(map[string]interface{}, len(events))
+ entries := make([]*pb.BulkPublishRequestEntry, 0, len(events))
+ for _, event := range events {
+ entry, err := createBulkPublishRequestEntry(event)
+ if err != nil {
+ failedEvents = append(failedEvents, event)
+ continue
+ }
+ eventMap[entry.EntryId] = event
+ entries = append(entries, entry)
+ }
+
+ request := &pb.BulkPublishRequest{
+ PubsubName: pubsubName,
+ Topic: topicName,
+ Entries: entries,
+ }
+ for _, o := range opts {
+ o(request)
+ }
+
+ res, err := c.protoClient.BulkPublishEventAlpha1(c.withAuthToken(ctx), request)
+ // If there is an error, all events failed to publish.
+ if err != nil {
+ return PublishEventsResponse{
+ Error: fmt.Errorf("error publishing events unto %s topic: %w", topicName, err),
+ FailedEvents: events,
+ }
+ }
+
+ for _, failedEntry := range res.FailedEntries {
+ event, ok := eventMap[failedEntry.EntryId]
+ if !ok {
+ // This should never happen.
+ failedEvents = append(failedEvents, failedEntry.EntryId)
+ }
+ failedEvents = append(failedEvents, event)
+ }
+
+ if len(failedEvents) != 0 {
+ return PublishEventsResponse{
+ Error: fmt.Errorf("error publishing events unto %s topic: %w", topicName, err),
+ FailedEvents: failedEvents,
+ }
+ }
+
+ return PublishEventsResponse{
+ Error: nil,
+ FailedEvents: make([]interface{}, 0),
+ }
+}
+
+// createBulkPublishRequestEntry creates a BulkPublishRequestEntry from an interface{}.
+func createBulkPublishRequestEntry(data interface{}) (*pb.BulkPublishRequestEntry, error) {
+ entry := &pb.BulkPublishRequestEntry{}
+
+ switch d := data.(type) {
+ case PublishEventsEvent:
+ entry.EntryId = d.EntryID
+ entry.Event = d.Data
+ entry.ContentType = d.ContentType
+ entry.Metadata = d.Metadata
+ case []byte:
+ entry.Event = d
+ entry.ContentType = "application/octet-stream"
+ case string:
+ entry.Event = []byte(d)
+ entry.ContentType = "text/plain"
+ default:
+ var err error
+ entry.ContentType = "application/json"
+ entry.Event, err = json.Marshal(d)
+ if err != nil {
+ return &pb.BulkPublishRequestEntry{}, fmt.Errorf("error serializing input struct: %w", err)
+ }
+
+ if isCloudEvent(entry.Event) {
+ entry.ContentType = "application/cloudevents+json"
+ }
+ }
+
+ if entry.EntryId == "" {
+ entry.EntryId = uuid.New().String()
+ }
+
+ return entry, nil
+}
+
+// PublishEventsWithContentType can be passed as option to PublishEvents to explicitly set the same Content-Type for all events.
+func PublishEventsWithContentType(contentType string) PublishEventsOption {
+ return func(r *pb.BulkPublishRequest) {
+ for _, entry := range r.Entries {
+ entry.ContentType = contentType
+ }
+ }
+}
+
+// PublishEventsWithMetadata can be passed as option to PublishEvents to set request metadata.
+func PublishEventsWithMetadata(metadata map[string]string) PublishEventsOption {
+ return func(r *pb.BulkPublishRequest) {
+ r.Metadata = metadata
+ }
+}
+
+// PublishEventsWithRawPayload can be passed as option to PublishEvents to set rawPayload request metadata.
+func PublishEventsWithRawPayload() PublishEventsOption {
+ return func(r *pb.BulkPublishRequest) {
+ if r.Metadata == nil {
+ r.Metadata = map[string]string{rawPayload: trueValue}
+ } else {
+ r.Metadata[rawPayload] = trueValue
+ }
+ }
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/secret.go b/vendor/github.com/dapr/go-sdk/client/secret.go
new file mode 100644
index 00000000000..604d198dd72
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/secret.go
@@ -0,0 +1,80 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "errors"
+ "fmt"
+
+ pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
+)
+
+// GetSecret retrieves preconfigured secret from specified store using key.
+func (c *GRPCClient) GetSecret(ctx context.Context, storeName, key string, meta map[string]string) (data map[string]string, err error) {
+ if storeName == "" {
+ return nil, errors.New("empty storeName")
+ }
+ if key == "" {
+ return nil, errors.New("empty key")
+ }
+
+ req := &pb.GetSecretRequest{
+ Key: key,
+ StoreName: storeName,
+ Metadata: meta,
+ }
+
+ resp, err := c.protoClient.GetSecret(c.withAuthToken(ctx), req)
+ if err != nil {
+ return nil, fmt.Errorf("error invoking service: %w", err)
+ }
+
+ if resp != nil {
+ data = resp.GetData()
+ }
+
+ return
+}
+
+// GetBulkSecret retrieves all preconfigured secrets for this application.
+func (c *GRPCClient) GetBulkSecret(ctx context.Context, storeName string, meta map[string]string) (data map[string]map[string]string, err error) {
+ if storeName == "" {
+ return nil, errors.New("empty storeName")
+ }
+
+ req := &pb.GetBulkSecretRequest{
+ StoreName: storeName,
+ Metadata: meta,
+ }
+
+ resp, err := c.protoClient.GetBulkSecret(c.withAuthToken(ctx), req)
+ if err != nil {
+ return nil, fmt.Errorf("error invoking service: %w", err)
+ }
+
+ if resp != nil {
+ data = map[string]map[string]string{}
+
+ for secretName, secretResponse := range resp.Data {
+ data[secretName] = map[string]string{}
+
+ for k, v := range secretResponse.Secrets {
+ data[secretName][k] = v
+ }
+ }
+ }
+
+ return
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/state.go b/vendor/github.com/dapr/go-sdk/client/state.go
new file mode 100644
index 00000000000..8265a777051
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/state.go
@@ -0,0 +1,527 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "time"
+
+ "github.com/golang/protobuf/ptypes/duration"
+
+ v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
+ pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
+)
+
+const (
+ // StateConsistencyUndefined is the undefined value for state consistency.
+ StateConsistencyUndefined StateConsistency = 0
+ // StateConsistencyEventual represents eventual state consistency value.
+ StateConsistencyEventual StateConsistency = 1
+ // StateConsistencyStrong represents strong state consistency value.
+ StateConsistencyStrong StateConsistency = 2
+
+ // StateConcurrencyUndefined is the undefined value for state concurrency.
+ StateConcurrencyUndefined StateConcurrency = 0
+ // StateConcurrencyFirstWrite represents first write concurrency value.
+ StateConcurrencyFirstWrite StateConcurrency = 1
+ // StateConcurrencyLastWrite represents last write concurrency value.
+ StateConcurrencyLastWrite StateConcurrency = 2
+
+ // StateOperationTypeUndefined is the undefined value for state operation type.
+ StateOperationTypeUndefined OperationType = 0
+ // StateOperationTypeUpsert represents upsert operation type value.
+ StateOperationTypeUpsert OperationType = 1
+ // StateOperationTypeDelete represents delete operation type value.
+ StateOperationTypeDelete OperationType = 2
+ // UndefinedType represents undefined type value.
+ UndefinedType = "undefined"
+)
+
+type (
+ // StateConsistency is the consistency enum type.
+ StateConsistency int
+ // StateConcurrency is the concurrency enum type.
+ StateConcurrency int
+ // OperationType is the operation enum type.
+ OperationType int
+)
+
+// GetPBConsistency get consistency pb value.
+func (s StateConsistency) GetPBConsistency() v1.StateOptions_StateConsistency {
+ return v1.StateOptions_StateConsistency(s)
+}
+
+// GetPBConcurrency get concurrency pb value.
+func (s StateConcurrency) GetPBConcurrency() v1.StateOptions_StateConcurrency {
+ return v1.StateOptions_StateConcurrency(s)
+}
+
+// String returns the string value of the OperationType.
+func (o OperationType) String() string {
+ names := [...]string{
+ UndefinedType,
+ "upsert",
+ "delete",
+ }
+ if o < StateOperationTypeUpsert || o > StateOperationTypeDelete {
+ return UndefinedType
+ }
+
+ return names[o]
+}
+
+// String returns the string value of the StateConsistency.
+func (s StateConsistency) String() string {
+ names := [...]string{
+ UndefinedType,
+ "strong",
+ "eventual",
+ }
+ if s < StateConsistencyStrong || s > StateConsistencyEventual {
+ return UndefinedType
+ }
+
+ return names[s]
+}
+
+// String returns the string value of the StateConcurrency.
+func (s StateConcurrency) String() string {
+ names := [...]string{
+ UndefinedType,
+ "first-write",
+ "last-write",
+ }
+ if s < StateConcurrencyFirstWrite || s > StateConcurrencyLastWrite {
+ return UndefinedType
+ }
+
+ return names[s]
+}
+
+var stateOptionDefault = &v1.StateOptions{
+ Concurrency: v1.StateOptions_CONCURRENCY_LAST_WRITE,
+ Consistency: v1.StateOptions_CONSISTENCY_STRONG,
+}
+
+// StateOperation is a collection of StateItems with a store name.
+type StateOperation struct {
+ Type OperationType
+ Item *SetStateItem
+}
+
+// StateItem represents a single state item.
+type StateItem struct {
+ Key string
+ Value []byte
+ Etag string
+ Metadata map[string]string
+}
+
+// BulkStateItem represents a single state item.
+type BulkStateItem struct {
+ Key string
+ Value []byte
+ Etag string
+ Metadata map[string]string
+ Error string
+}
+
+// SetStateItem represents a single state to be persisted.
+type SetStateItem struct {
+ Key string
+ Value []byte
+ Etag *ETag
+ Metadata map[string]string
+ Options *StateOptions
+}
+
+// QueryItem represents a single query result item.
+type QueryItem struct {
+ Key string
+ Value []byte
+ Etag string
+ Error string
+}
+
+// QueryResponse represents a query result.
+type QueryResponse struct {
+ Results []QueryItem
+ Token string
+ Metadata map[string]string
+}
+
+// DeleteStateItem represents a single state to be deleted.
+type DeleteStateItem SetStateItem
+
+// ETag represents an versioned record information.
+type ETag struct {
+ Value string
+}
+
+// StateOptions represents the state store persistence policy.
+type StateOptions struct {
+ Concurrency StateConcurrency
+ Consistency StateConsistency
+}
+
+// StateOption StateOptions's function type.
+type StateOption func(*StateOptions)
+
+// WithConcurrency set StateOptions's Concurrency.
+func WithConcurrency(concurrency StateConcurrency) StateOption {
+ return func(so *StateOptions) {
+ so.Concurrency = concurrency
+ }
+}
+
+// WithConsistency set StateOptions's consistency.
+func WithConsistency(consistency StateConsistency) StateOption {
+ return func(so *StateOptions) {
+ so.Consistency = consistency
+ }
+}
+
+func toProtoSaveStateItem(si *SetStateItem) (item *v1.StateItem) {
+ s := &v1.StateItem{
+ Key: si.Key,
+ Metadata: si.Metadata,
+ Value: si.Value,
+ Options: toProtoStateOptions(si.Options),
+ }
+
+ if si.Etag != nil {
+ s.Etag = &v1.Etag{
+ Value: si.Etag.Value,
+ }
+ }
+
+ return s
+}
+
+func toProtoStateOptions(so *StateOptions) (opts *v1.StateOptions) {
+ if so == nil {
+ return copyStateOptionDefaultPB()
+ }
+ return &v1.StateOptions{
+ Concurrency: v1.StateOptions_StateConcurrency(so.Concurrency),
+ Consistency: v1.StateOptions_StateConsistency(so.Consistency),
+ }
+}
+
+func copyStateOptionDefaultPB() *v1.StateOptions {
+ return &v1.StateOptions{
+ Concurrency: stateOptionDefault.GetConcurrency(),
+ Consistency: stateOptionDefault.GetConsistency(),
+ }
+}
+
+func copyStateOptionDefault() *StateOptions {
+ return &StateOptions{
+ Concurrency: StateConcurrency(stateOptionDefault.GetConcurrency()),
+ Consistency: StateConsistency(stateOptionDefault.GetConsistency()),
+ }
+}
+
+func toProtoDuration(d time.Duration) *duration.Duration {
+ nanos := d.Nanoseconds()
+ secs := nanos / 1e9
+ nanos -= secs * 1e9
+ return &duration.Duration{
+ Seconds: secs,
+ Nanos: int32(nanos),
+ }
+}
+
+// ExecuteStateTransaction provides way to execute multiple operations on a specified store.
+func (c *GRPCClient) ExecuteStateTransaction(ctx context.Context, storeName string, meta map[string]string, ops []*StateOperation) error {
+ if storeName == "" {
+ return errors.New("nil storeName")
+ }
+ if len(ops) == 0 {
+ return nil
+ }
+
+ items := make([]*pb.TransactionalStateOperation, 0)
+ for _, op := range ops {
+ item := &pb.TransactionalStateOperation{
+ OperationType: op.Type.String(),
+ Request: toProtoSaveStateItem(op.Item),
+ }
+ items = append(items, item)
+ }
+
+ req := &pb.ExecuteStateTransactionRequest{
+ Metadata: meta,
+ StoreName: storeName,
+ Operations: items,
+ }
+ _, err := c.protoClient.ExecuteStateTransaction(c.withAuthToken(ctx), req)
+ if err != nil {
+ return fmt.Errorf("error executing state transaction: %w", err)
+ }
+ return nil
+}
+
+// SaveState saves the raw data into store, default options: strong, last-write.
+func (c *GRPCClient) SaveState(ctx context.Context, storeName, key string, data []byte, meta map[string]string, so ...StateOption) error {
+ return c.SaveStateWithETag(ctx, storeName, key, data, "", meta, so...)
+}
+
+// SaveStateWithETag saves the raw data into store using provided state options and etag.
+func (c *GRPCClient) SaveStateWithETag(ctx context.Context, storeName, key string, data []byte, etag string, meta map[string]string, so ...StateOption) error {
+ stateOptions := new(StateOptions)
+ for _, o := range so {
+ o(stateOptions)
+ }
+ if len(so) == 0 {
+ stateOptions = copyStateOptionDefault()
+ }
+ item := &SetStateItem{
+ Key: key,
+ Value: data,
+ Metadata: meta,
+ Options: stateOptions,
+ }
+ if etag != "" {
+ item.Etag = &ETag{Value: etag}
+ }
+ return c.SaveBulkState(ctx, storeName, item)
+}
+
+// SaveBulkState saves the multiple state item to store.
+func (c *GRPCClient) SaveBulkState(ctx context.Context, storeName string, items ...*SetStateItem) error {
+ if storeName == "" {
+ return errors.New("nil store")
+ }
+ if items == nil {
+ return errors.New("nil item")
+ }
+
+ req := &pb.SaveStateRequest{
+ StoreName: storeName,
+ States: make([]*v1.StateItem, 0),
+ }
+
+ for _, si := range items {
+ item := toProtoSaveStateItem(si)
+ req.States = append(req.States, item)
+ }
+
+ _, err := c.protoClient.SaveState(c.withAuthToken(ctx), req)
+ if err != nil {
+ return fmt.Errorf("error saving state: %w", err)
+ }
+ return nil
+}
+
+// GetBulkState retrieves state for multiple keys from specific store.
+func (c *GRPCClient) GetBulkState(ctx context.Context, storeName string, keys []string, meta map[string]string, parallelism int32) ([]*BulkStateItem, error) {
+ if storeName == "" {
+ return nil, errors.New("nil store")
+ }
+ if len(keys) == 0 {
+ return nil, errors.New("keys required")
+ }
+ items := make([]*BulkStateItem, 0)
+
+ req := &pb.GetBulkStateRequest{
+ StoreName: storeName,
+ Keys: keys,
+ Metadata: meta,
+ Parallelism: parallelism,
+ }
+
+ results, err := c.protoClient.GetBulkState(c.withAuthToken(ctx), req)
+ if err != nil {
+ return nil, fmt.Errorf("error getting state: %w", err)
+ }
+
+ if results == nil || results.Items == nil {
+ return items, nil
+ }
+
+ for _, r := range results.Items {
+ item := &BulkStateItem{
+ Key: r.Key,
+ Etag: r.Etag,
+ Value: r.Data,
+ Metadata: r.Metadata,
+ Error: r.Error,
+ }
+ items = append(items, item)
+ }
+
+ return items, nil
+}
+
+// GetState retrieves state from specific store using default consistency option.
+func (c *GRPCClient) GetState(ctx context.Context, storeName, key string, meta map[string]string) (item *StateItem, err error) {
+ return c.GetStateWithConsistency(ctx, storeName, key, meta, StateConsistencyStrong)
+}
+
+// GetStateWithConsistency retrieves state from specific store using provided state consistency.
+func (c *GRPCClient) GetStateWithConsistency(ctx context.Context, storeName, key string, meta map[string]string, sc StateConsistency) (*StateItem, error) {
+ if err := hasRequiredStateArgs(storeName, key); err != nil {
+ return nil, fmt.Errorf("missing required arguments: %w", err)
+ }
+
+ req := &pb.GetStateRequest{
+ StoreName: storeName,
+ Key: key,
+ Consistency: v1.StateOptions_StateConsistency(sc),
+ Metadata: meta,
+ }
+
+ result, err := c.protoClient.GetState(c.withAuthToken(ctx), req)
+ if err != nil {
+ return nil, fmt.Errorf("error getting state: %w", err)
+ }
+
+ return &StateItem{
+ Etag: result.Etag,
+ Key: key,
+ Value: result.Data,
+ Metadata: result.Metadata,
+ }, nil
+}
+
+// QueryStateAlpha1 runs a query against state store.
+func (c *GRPCClient) QueryStateAlpha1(ctx context.Context, storeName, query string, meta map[string]string) (*QueryResponse, error) {
+ if storeName == "" {
+ return nil, errors.New("store name is not set")
+ }
+ if query == "" {
+ return nil, errors.New("query is not set")
+ }
+ req := &pb.QueryStateRequest{
+ StoreName: storeName,
+ Query: query,
+ Metadata: meta,
+ }
+ resp, err := c.protoClient.QueryStateAlpha1(c.withAuthToken(ctx), req)
+ if err != nil {
+ return nil, fmt.Errorf("error querying state: %w", err)
+ }
+
+ ret := &QueryResponse{
+ Results: make([]QueryItem, len(resp.Results)),
+ Token: resp.Token,
+ Metadata: resp.Metadata,
+ }
+ for i, item := range resp.Results {
+ ret.Results[i].Key = item.Key
+ ret.Results[i].Value = item.Data
+ ret.Results[i].Etag = item.Etag
+ ret.Results[i].Error = item.Error
+ }
+
+ return ret, nil
+}
+
+// DeleteState deletes content from store using default state options.
+func (c *GRPCClient) DeleteState(ctx context.Context, storeName, key string, meta map[string]string) error {
+ return c.DeleteStateWithETag(ctx, storeName, key, nil, meta, nil)
+}
+
+// DeleteStateWithETag deletes content from store using provided state options and etag.
+func (c *GRPCClient) DeleteStateWithETag(ctx context.Context, storeName, key string, etag *ETag, meta map[string]string, opts *StateOptions) error {
+ if err := hasRequiredStateArgs(storeName, key); err != nil {
+ return fmt.Errorf("missing required arguments: %w", err)
+ }
+
+ req := &pb.DeleteStateRequest{
+ StoreName: storeName,
+ Key: key,
+ Options: toProtoStateOptions(opts),
+ Metadata: meta,
+ }
+
+ if etag != nil {
+ req.Etag = &v1.Etag{
+ Value: etag.Value,
+ }
+ }
+
+ _, err := c.protoClient.DeleteState(c.withAuthToken(ctx), req)
+ if err != nil {
+ return fmt.Errorf("error deleting state: %w", err)
+ }
+
+ return nil
+}
+
+// DeleteBulkState deletes content for multiple keys from store.
+func (c *GRPCClient) DeleteBulkState(ctx context.Context, storeName string, keys []string, meta map[string]string) error {
+ if len(keys) == 0 {
+ return nil
+ }
+
+ items := make([]*DeleteStateItem, 0, len(keys))
+ for i := 0; i < len(keys); i++ {
+ item := &DeleteStateItem{
+ Key: keys[i],
+ Metadata: meta,
+ }
+ items = append(items, item)
+ }
+
+ return c.DeleteBulkStateItems(ctx, storeName, items)
+}
+
+// DeleteBulkStateItems deletes content for multiple items from store.
+func (c *GRPCClient) DeleteBulkStateItems(ctx context.Context, storeName string, items []*DeleteStateItem) error {
+ if len(items) == 0 {
+ return nil
+ }
+
+ states := make([]*v1.StateItem, 0, len(items))
+ for i := 0; i < len(items); i++ {
+ item := items[i]
+ if err := hasRequiredStateArgs(storeName, item.Key); err != nil {
+ return fmt.Errorf("missing required arguments: %w", err)
+ }
+
+ state := &v1.StateItem{
+ Key: item.Key,
+ Metadata: item.Metadata,
+ Options: toProtoStateOptions(item.Options),
+ }
+ if item.Etag != nil {
+ state.Etag = &v1.Etag{
+ Value: item.Etag.Value,
+ }
+ }
+ states = append(states, state)
+ }
+
+ req := &pb.DeleteBulkStateRequest{
+ StoreName: storeName,
+ States: states,
+ }
+ _, err := c.protoClient.DeleteBulkState(c.withAuthToken(ctx), req)
+
+ return err
+}
+
+func hasRequiredStateArgs(storeName, key string) error {
+ if storeName == "" {
+ return errors.New("store")
+ }
+ if key == "" {
+ return errors.New("key")
+ }
+ return nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/utils.go b/vendor/github.com/dapr/go-sdk/client/utils.go
new file mode 100644
index 00000000000..f49fb2a2243
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/utils.go
@@ -0,0 +1,32 @@
+/*
+Copyright 2023 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import "encoding/json"
+
+// isCloudEvent returns true if the event is a CloudEvent.
+// An event is a CloudEvent if it `id`, `source`, `specversion` and `type` fields.
+// See https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md for more details.
+func isCloudEvent(event []byte) bool {
+ var ce struct {
+ ID string `json:"id"`
+ Source string `json:"source"`
+ SpecVersion string `json:"specversion"`
+ Type string `json:"type"`
+ }
+ if err := json.Unmarshal(event, &ce); err != nil {
+ return false
+ }
+ return ce.ID != "" && ce.Source != "" && ce.SpecVersion != "" && ce.Type != ""
+}
diff --git a/vendor/github.com/dapr/go-sdk/client/wait.go b/vendor/github.com/dapr/go-sdk/client/wait.go
new file mode 100644
index 00000000000..6d7693f9d73
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/client/wait.go
@@ -0,0 +1,52 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "errors"
+ "time"
+
+ "google.golang.org/grpc/connectivity"
+)
+
+// The following errors are returned from Wait.
+var (
+ // A call to Wait timed out while waiting for a gRPC connection to reach a Ready state.
+ errWaitTimedOut = errors.New("timed out waiting for client connectivity")
+)
+
+func (c *GRPCClient) Wait(ctx context.Context, timeout time.Duration) error {
+ timeoutCtx, cancel := context.WithTimeout(ctx, timeout)
+ defer cancel()
+
+ // SDKs for other languages implement Wait by attempting to connect to a TCP endpoint
+ // with a timeout. Go's SDKs handles more endpoints than just TCP ones. To simplify
+ // the code here, we rely on GRPCs connectivity state management instead.
+ // See https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md
+ for {
+ curState := c.connection.GetState()
+ if curState == connectivity.Ready {
+ return nil
+ }
+
+ select {
+ case <-timeoutCtx.Done():
+ return errWaitTimedOut
+ default:
+ // Multiple state changes can happen: keep waiting for a successful one or time out
+ c.connection.WaitForStateChange(timeoutCtx, curState)
+ }
+ }
+}
diff --git a/vendor/github.com/dapr/go-sdk/dapr/proto/common/v1/common.pb.go b/vendor/github.com/dapr/go-sdk/dapr/proto/common/v1/common.pb.go
new file mode 100644
index 00000000000..577f5f7c458
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/dapr/proto/common/v1/common.pb.go
@@ -0,0 +1,1022 @@
+//
+//Copyright 2021 The Dapr Authors
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//http://www.apache.org/licenses/LICENSE-2.0
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.28.1
+// protoc v3.21.12
+// source: dapr/proto/common/v1/common.proto
+
+package common
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ anypb "google.golang.org/protobuf/types/known/anypb"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Type of HTTP 1.1 Methods
+// RFC 7231: https://tools.ietf.org/html/rfc7231#page-24
+// RFC 5789: https://datatracker.ietf.org/doc/html/rfc5789
+type HTTPExtension_Verb int32
+
+const (
+ HTTPExtension_NONE HTTPExtension_Verb = 0
+ HTTPExtension_GET HTTPExtension_Verb = 1
+ HTTPExtension_HEAD HTTPExtension_Verb = 2
+ HTTPExtension_POST HTTPExtension_Verb = 3
+ HTTPExtension_PUT HTTPExtension_Verb = 4
+ HTTPExtension_DELETE HTTPExtension_Verb = 5
+ HTTPExtension_CONNECT HTTPExtension_Verb = 6
+ HTTPExtension_OPTIONS HTTPExtension_Verb = 7
+ HTTPExtension_TRACE HTTPExtension_Verb = 8
+ HTTPExtension_PATCH HTTPExtension_Verb = 9
+)
+
+// Enum value maps for HTTPExtension_Verb.
+var (
+ HTTPExtension_Verb_name = map[int32]string{
+ 0: "NONE",
+ 1: "GET",
+ 2: "HEAD",
+ 3: "POST",
+ 4: "PUT",
+ 5: "DELETE",
+ 6: "CONNECT",
+ 7: "OPTIONS",
+ 8: "TRACE",
+ 9: "PATCH",
+ }
+ HTTPExtension_Verb_value = map[string]int32{
+ "NONE": 0,
+ "GET": 1,
+ "HEAD": 2,
+ "POST": 3,
+ "PUT": 4,
+ "DELETE": 5,
+ "CONNECT": 6,
+ "OPTIONS": 7,
+ "TRACE": 8,
+ "PATCH": 9,
+ }
+)
+
+func (x HTTPExtension_Verb) Enum() *HTTPExtension_Verb {
+ p := new(HTTPExtension_Verb)
+ *p = x
+ return p
+}
+
+func (x HTTPExtension_Verb) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (HTTPExtension_Verb) Descriptor() protoreflect.EnumDescriptor {
+ return file_dapr_proto_common_v1_common_proto_enumTypes[0].Descriptor()
+}
+
+func (HTTPExtension_Verb) Type() protoreflect.EnumType {
+ return &file_dapr_proto_common_v1_common_proto_enumTypes[0]
+}
+
+func (x HTTPExtension_Verb) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use HTTPExtension_Verb.Descriptor instead.
+func (HTTPExtension_Verb) EnumDescriptor() ([]byte, []int) {
+ return file_dapr_proto_common_v1_common_proto_rawDescGZIP(), []int{0, 0}
+}
+
+// Enum describing the supported concurrency for state.
+type StateOptions_StateConcurrency int32
+
+const (
+ StateOptions_CONCURRENCY_UNSPECIFIED StateOptions_StateConcurrency = 0
+ StateOptions_CONCURRENCY_FIRST_WRITE StateOptions_StateConcurrency = 1
+ StateOptions_CONCURRENCY_LAST_WRITE StateOptions_StateConcurrency = 2
+)
+
+// Enum value maps for StateOptions_StateConcurrency.
+var (
+ StateOptions_StateConcurrency_name = map[int32]string{
+ 0: "CONCURRENCY_UNSPECIFIED",
+ 1: "CONCURRENCY_FIRST_WRITE",
+ 2: "CONCURRENCY_LAST_WRITE",
+ }
+ StateOptions_StateConcurrency_value = map[string]int32{
+ "CONCURRENCY_UNSPECIFIED": 0,
+ "CONCURRENCY_FIRST_WRITE": 1,
+ "CONCURRENCY_LAST_WRITE": 2,
+ }
+)
+
+func (x StateOptions_StateConcurrency) Enum() *StateOptions_StateConcurrency {
+ p := new(StateOptions_StateConcurrency)
+ *p = x
+ return p
+}
+
+func (x StateOptions_StateConcurrency) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (StateOptions_StateConcurrency) Descriptor() protoreflect.EnumDescriptor {
+ return file_dapr_proto_common_v1_common_proto_enumTypes[1].Descriptor()
+}
+
+func (StateOptions_StateConcurrency) Type() protoreflect.EnumType {
+ return &file_dapr_proto_common_v1_common_proto_enumTypes[1]
+}
+
+func (x StateOptions_StateConcurrency) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use StateOptions_StateConcurrency.Descriptor instead.
+func (StateOptions_StateConcurrency) EnumDescriptor() ([]byte, []int) {
+ return file_dapr_proto_common_v1_common_proto_rawDescGZIP(), []int{6, 0}
+}
+
+// Enum describing the supported consistency for state.
+type StateOptions_StateConsistency int32
+
+const (
+ StateOptions_CONSISTENCY_UNSPECIFIED StateOptions_StateConsistency = 0
+ StateOptions_CONSISTENCY_EVENTUAL StateOptions_StateConsistency = 1
+ StateOptions_CONSISTENCY_STRONG StateOptions_StateConsistency = 2
+)
+
+// Enum value maps for StateOptions_StateConsistency.
+var (
+ StateOptions_StateConsistency_name = map[int32]string{
+ 0: "CONSISTENCY_UNSPECIFIED",
+ 1: "CONSISTENCY_EVENTUAL",
+ 2: "CONSISTENCY_STRONG",
+ }
+ StateOptions_StateConsistency_value = map[string]int32{
+ "CONSISTENCY_UNSPECIFIED": 0,
+ "CONSISTENCY_EVENTUAL": 1,
+ "CONSISTENCY_STRONG": 2,
+ }
+)
+
+func (x StateOptions_StateConsistency) Enum() *StateOptions_StateConsistency {
+ p := new(StateOptions_StateConsistency)
+ *p = x
+ return p
+}
+
+func (x StateOptions_StateConsistency) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (StateOptions_StateConsistency) Descriptor() protoreflect.EnumDescriptor {
+ return file_dapr_proto_common_v1_common_proto_enumTypes[2].Descriptor()
+}
+
+func (StateOptions_StateConsistency) Type() protoreflect.EnumType {
+ return &file_dapr_proto_common_v1_common_proto_enumTypes[2]
+}
+
+func (x StateOptions_StateConsistency) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use StateOptions_StateConsistency.Descriptor instead.
+func (StateOptions_StateConsistency) EnumDescriptor() ([]byte, []int) {
+ return file_dapr_proto_common_v1_common_proto_rawDescGZIP(), []int{6, 1}
+}
+
+// HTTPExtension includes HTTP verb and querystring
+// when Dapr runtime delivers HTTP content.
+//
+// For example, when callers calls http invoke api
+// POST http://localhost:3500/v1.0/invoke//method/?query1=value1&query2=value2
+//
+// Dapr runtime will parse POST as a verb and extract querystring to quersytring map.
+type HTTPExtension struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. HTTP verb.
+ Verb HTTPExtension_Verb `protobuf:"varint,1,opt,name=verb,proto3,enum=dapr.proto.common.v1.HTTPExtension_Verb" json:"verb,omitempty"`
+ // Optional. querystring represents an encoded HTTP url query string in the following format: name=value&name2=value2
+ Querystring string `protobuf:"bytes,2,opt,name=querystring,proto3" json:"querystring,omitempty"`
+}
+
+func (x *HTTPExtension) Reset() {
+ *x = HTTPExtension{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *HTTPExtension) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*HTTPExtension) ProtoMessage() {}
+
+func (x *HTTPExtension) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use HTTPExtension.ProtoReflect.Descriptor instead.
+func (*HTTPExtension) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_common_v1_common_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *HTTPExtension) GetVerb() HTTPExtension_Verb {
+ if x != nil {
+ return x.Verb
+ }
+ return HTTPExtension_NONE
+}
+
+func (x *HTTPExtension) GetQuerystring() string {
+ if x != nil {
+ return x.Querystring
+ }
+ return ""
+}
+
+// InvokeRequest is the message to invoke a method with the data.
+// This message is used in InvokeService of Dapr gRPC Service and OnInvoke
+// of AppCallback gRPC service.
+type InvokeRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. method is a method name which will be invoked by caller.
+ Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"`
+ // Required in unary RPCs. Bytes value or Protobuf message which caller sent.
+ // Dapr treats Any.value as bytes type if Any.type_url is unset.
+ Data *anypb.Any `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+ // The type of data content.
+ //
+ // This field is required if data delivers http request body
+ // Otherwise, this is optional.
+ ContentType string `protobuf:"bytes,3,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"`
+ // HTTP specific fields if request conveys http-compatible request.
+ //
+ // This field is required for http-compatible request. Otherwise,
+ // this field is optional.
+ HttpExtension *HTTPExtension `protobuf:"bytes,4,opt,name=http_extension,json=httpExtension,proto3" json:"http_extension,omitempty"`
+}
+
+func (x *InvokeRequest) Reset() {
+ *x = InvokeRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *InvokeRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InvokeRequest) ProtoMessage() {}
+
+func (x *InvokeRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use InvokeRequest.ProtoReflect.Descriptor instead.
+func (*InvokeRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_common_v1_common_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *InvokeRequest) GetMethod() string {
+ if x != nil {
+ return x.Method
+ }
+ return ""
+}
+
+func (x *InvokeRequest) GetData() *anypb.Any {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *InvokeRequest) GetContentType() string {
+ if x != nil {
+ return x.ContentType
+ }
+ return ""
+}
+
+func (x *InvokeRequest) GetHttpExtension() *HTTPExtension {
+ if x != nil {
+ return x.HttpExtension
+ }
+ return nil
+}
+
+// InvokeResponse is the response message including data and its content type
+// from app callback.
+// This message is used in InvokeService of Dapr gRPC Service and OnInvoke
+// of AppCallback gRPC service.
+type InvokeResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required in unary RPCs. The content body of InvokeService response.
+ Data *anypb.Any `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+ // Required. The type of data content.
+ ContentType string `protobuf:"bytes,2,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"`
+}
+
+func (x *InvokeResponse) Reset() {
+ *x = InvokeResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *InvokeResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InvokeResponse) ProtoMessage() {}
+
+func (x *InvokeResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use InvokeResponse.ProtoReflect.Descriptor instead.
+func (*InvokeResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_common_v1_common_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *InvokeResponse) GetData() *anypb.Any {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *InvokeResponse) GetContentType() string {
+ if x != nil {
+ return x.ContentType
+ }
+ return ""
+}
+
+// Chunk of data sent in a streaming request or response.
+// This is used in requests including InternalInvokeRequestStream.
+type StreamPayload struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Data sent in the chunk.
+ // The amount of data included in each chunk is up to the discretion of the sender, and can be empty.
+ // Additionally, the amount of data doesn't need to be fixed and subsequent messages can send more, or less, data.
+ // Receivers must not make assumptions about the number of bytes they'll receive in each chunk.
+ Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+ // Sequence number. This is a counter that starts from 0 and increments by 1 on each chunk sent.
+ Seq uint64 `protobuf:"varint,2,opt,name=seq,proto3" json:"seq,omitempty"`
+}
+
+func (x *StreamPayload) Reset() {
+ *x = StreamPayload{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *StreamPayload) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StreamPayload) ProtoMessage() {}
+
+func (x *StreamPayload) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StreamPayload.ProtoReflect.Descriptor instead.
+func (*StreamPayload) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_common_v1_common_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *StreamPayload) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *StreamPayload) GetSeq() uint64 {
+ if x != nil {
+ return x.Seq
+ }
+ return 0
+}
+
+// StateItem represents state key, value, and additional options to save state.
+type StateItem struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The state key
+ Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
+ // Required. The state data for key
+ Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
+ // The entity tag which represents the specific version of data.
+ // The exact ETag format is defined by the corresponding data store.
+ Etag *Etag `protobuf:"bytes,3,opt,name=etag,proto3" json:"etag,omitempty"`
+ // The metadata which will be passed to state store component.
+ Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // Options for concurrency and consistency to save the state.
+ Options *StateOptions `protobuf:"bytes,5,opt,name=options,proto3" json:"options,omitempty"`
+}
+
+func (x *StateItem) Reset() {
+ *x = StateItem{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *StateItem) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StateItem) ProtoMessage() {}
+
+func (x *StateItem) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StateItem.ProtoReflect.Descriptor instead.
+func (*StateItem) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_common_v1_common_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *StateItem) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+func (x *StateItem) GetValue() []byte {
+ if x != nil {
+ return x.Value
+ }
+ return nil
+}
+
+func (x *StateItem) GetEtag() *Etag {
+ if x != nil {
+ return x.Etag
+ }
+ return nil
+}
+
+func (x *StateItem) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+func (x *StateItem) GetOptions() *StateOptions {
+ if x != nil {
+ return x.Options
+ }
+ return nil
+}
+
+// Etag represents a state item version
+type Etag struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // value sets the etag value
+ Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
+}
+
+func (x *Etag) Reset() {
+ *x = Etag{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Etag) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Etag) ProtoMessage() {}
+
+func (x *Etag) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Etag.ProtoReflect.Descriptor instead.
+func (*Etag) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_common_v1_common_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *Etag) GetValue() string {
+ if x != nil {
+ return x.Value
+ }
+ return ""
+}
+
+// StateOptions configures concurrency and consistency for state operations
+type StateOptions struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Concurrency StateOptions_StateConcurrency `protobuf:"varint,1,opt,name=concurrency,proto3,enum=dapr.proto.common.v1.StateOptions_StateConcurrency" json:"concurrency,omitempty"`
+ Consistency StateOptions_StateConsistency `protobuf:"varint,2,opt,name=consistency,proto3,enum=dapr.proto.common.v1.StateOptions_StateConsistency" json:"consistency,omitempty"`
+}
+
+func (x *StateOptions) Reset() {
+ *x = StateOptions{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *StateOptions) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StateOptions) ProtoMessage() {}
+
+func (x *StateOptions) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StateOptions.ProtoReflect.Descriptor instead.
+func (*StateOptions) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_common_v1_common_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *StateOptions) GetConcurrency() StateOptions_StateConcurrency {
+ if x != nil {
+ return x.Concurrency
+ }
+ return StateOptions_CONCURRENCY_UNSPECIFIED
+}
+
+func (x *StateOptions) GetConsistency() StateOptions_StateConsistency {
+ if x != nil {
+ return x.Consistency
+ }
+ return StateOptions_CONSISTENCY_UNSPECIFIED
+}
+
+// ConfigurationItem represents all the configuration with its name(key).
+type ConfigurationItem struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The value of configuration item.
+ Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
+ // Version is response only and cannot be fetched. Store is not expected to keep all versions available
+ Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
+ // the metadata which will be passed to/from configuration store component.
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *ConfigurationItem) Reset() {
+ *x = ConfigurationItem{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ConfigurationItem) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ConfigurationItem) ProtoMessage() {}
+
+func (x *ConfigurationItem) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_common_v1_common_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ConfigurationItem.ProtoReflect.Descriptor instead.
+func (*ConfigurationItem) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_common_v1_common_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *ConfigurationItem) GetValue() string {
+ if x != nil {
+ return x.Value
+ }
+ return ""
+}
+
+func (x *ConfigurationItem) GetVersion() string {
+ if x != nil {
+ return x.Version
+ }
+ return ""
+}
+
+func (x *ConfigurationItem) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+var File_dapr_proto_common_v1_common_proto protoreflect.FileDescriptor
+
+var file_dapr_proto_common_v1_common_proto_rawDesc = []byte{
+ 0x0a, 0x21, 0x64, 0x61, 0x70, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d,
+ 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe3, 0x01, 0x0a, 0x0d, 0x48, 0x54, 0x54, 0x50, 0x45, 0x78, 0x74,
+ 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x04, 0x76, 0x65, 0x72, 0x62, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x54, 0x54, 0x50,
+ 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x65, 0x72, 0x62, 0x52, 0x04,
+ 0x76, 0x65, 0x72, 0x62, 0x12, 0x20, 0x0a, 0x0b, 0x71, 0x75, 0x65, 0x72, 0x79, 0x73, 0x74, 0x72,
+ 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x71, 0x75, 0x65, 0x72, 0x79,
+ 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x72, 0x0a, 0x04, 0x56, 0x65, 0x72, 0x62, 0x12, 0x08,
+ 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x45, 0x54, 0x10,
+ 0x01, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x45, 0x41, 0x44, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x50,
+ 0x4f, 0x53, 0x54, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x55, 0x54, 0x10, 0x04, 0x12, 0x0a,
+ 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f,
+ 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x4f, 0x50, 0x54, 0x49, 0x4f,
+ 0x4e, 0x53, 0x10, 0x07, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x08, 0x12,
+ 0x09, 0x0a, 0x05, 0x50, 0x41, 0x54, 0x43, 0x48, 0x10, 0x09, 0x22, 0xc0, 0x01, 0x0a, 0x0d, 0x49,
+ 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06,
+ 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65,
+ 0x74, 0x68, 0x6f, 0x64, 0x12, 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21,
+ 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
+ 0x65, 0x12, 0x4a, 0x0a, 0x0e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
+ 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31,
+ 0x2e, 0x48, 0x54, 0x54, 0x50, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0d,
+ 0x68, 0x74, 0x74, 0x70, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x0a,
+ 0x0e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+ 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+ 0x41, 0x6e, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e,
+ 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x35, 0x0a, 0x0d,
+ 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x12, 0x0a,
+ 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74,
+ 0x61, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x65, 0x71, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03,
+ 0x73, 0x65, 0x71, 0x22, 0xa9, 0x02, 0x0a, 0x09, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x74, 0x65,
+ 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+ 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x65, 0x74, 0x61,
+ 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45,
+ 0x74, 0x61, 0x67, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x49, 0x0a, 0x08, 0x6d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x64, 0x61,
+ 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
+ 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61,
+ 0x64, 0x61, 0x74, 0x61, 0x12, 0x3c, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
+ 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61,
+ 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22,
+ 0x1c, 0x0a, 0x04, 0x45, 0x74, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x89, 0x03,
+ 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x55,
+ 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e,
+ 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72,
+ 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x55, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74,
+ 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x64, 0x61, 0x70,
+ 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76,
+ 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53,
+ 0x74, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x52,
+ 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x68, 0x0a, 0x10,
+ 0x53, 0x74, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79,
+ 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4e, 0x43, 0x55, 0x52, 0x52, 0x45, 0x4e, 0x43, 0x59, 0x5f,
+ 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a,
+ 0x17, 0x43, 0x4f, 0x4e, 0x43, 0x55, 0x52, 0x52, 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x46, 0x49, 0x52,
+ 0x53, 0x54, 0x5f, 0x57, 0x52, 0x49, 0x54, 0x45, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f,
+ 0x4e, 0x43, 0x55, 0x52, 0x52, 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x4c, 0x41, 0x53, 0x54, 0x5f, 0x57,
+ 0x52, 0x49, 0x54, 0x45, 0x10, 0x02, 0x22, 0x61, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x74, 0x65, 0x43,
+ 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f,
+ 0x4e, 0x53, 0x49, 0x53, 0x54, 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
+ 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x4f, 0x4e, 0x53, 0x49,
+ 0x53, 0x54, 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x55, 0x41, 0x4c, 0x10,
+ 0x01, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x4f, 0x4e, 0x53, 0x49, 0x53, 0x54, 0x45, 0x4e, 0x43, 0x59,
+ 0x5f, 0x53, 0x54, 0x52, 0x4f, 0x4e, 0x47, 0x10, 0x02, 0x22, 0xd3, 0x01, 0x0a, 0x11, 0x43, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12,
+ 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
+ 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
+ 0x51, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28,
+ 0x0b, 0x32, 0x35, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64,
+ 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42,
+ 0x69, 0x0a, 0x0a, 0x69, 0x6f, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x43,
+ 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x5a, 0x2f, 0x67, 0x69, 0x74,
+ 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x61, 0x70, 0x72, 0x2f, 0x64, 0x61, 0x70,
+ 0x72, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
+ 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0xaa, 0x02, 0x1b, 0x44,
+ 0x61, 0x70, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x67,
+ 0x65, 0x6e, 0x2e, 0x47, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x33,
+}
+
+var (
+ file_dapr_proto_common_v1_common_proto_rawDescOnce sync.Once
+ file_dapr_proto_common_v1_common_proto_rawDescData = file_dapr_proto_common_v1_common_proto_rawDesc
+)
+
+func file_dapr_proto_common_v1_common_proto_rawDescGZIP() []byte {
+ file_dapr_proto_common_v1_common_proto_rawDescOnce.Do(func() {
+ file_dapr_proto_common_v1_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_dapr_proto_common_v1_common_proto_rawDescData)
+ })
+ return file_dapr_proto_common_v1_common_proto_rawDescData
+}
+
+var file_dapr_proto_common_v1_common_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
+var file_dapr_proto_common_v1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
+var file_dapr_proto_common_v1_common_proto_goTypes = []interface{}{
+ (HTTPExtension_Verb)(0), // 0: dapr.proto.common.v1.HTTPExtension.Verb
+ (StateOptions_StateConcurrency)(0), // 1: dapr.proto.common.v1.StateOptions.StateConcurrency
+ (StateOptions_StateConsistency)(0), // 2: dapr.proto.common.v1.StateOptions.StateConsistency
+ (*HTTPExtension)(nil), // 3: dapr.proto.common.v1.HTTPExtension
+ (*InvokeRequest)(nil), // 4: dapr.proto.common.v1.InvokeRequest
+ (*InvokeResponse)(nil), // 5: dapr.proto.common.v1.InvokeResponse
+ (*StreamPayload)(nil), // 6: dapr.proto.common.v1.StreamPayload
+ (*StateItem)(nil), // 7: dapr.proto.common.v1.StateItem
+ (*Etag)(nil), // 8: dapr.proto.common.v1.Etag
+ (*StateOptions)(nil), // 9: dapr.proto.common.v1.StateOptions
+ (*ConfigurationItem)(nil), // 10: dapr.proto.common.v1.ConfigurationItem
+ nil, // 11: dapr.proto.common.v1.StateItem.MetadataEntry
+ nil, // 12: dapr.proto.common.v1.ConfigurationItem.MetadataEntry
+ (*anypb.Any)(nil), // 13: google.protobuf.Any
+}
+var file_dapr_proto_common_v1_common_proto_depIdxs = []int32{
+ 0, // 0: dapr.proto.common.v1.HTTPExtension.verb:type_name -> dapr.proto.common.v1.HTTPExtension.Verb
+ 13, // 1: dapr.proto.common.v1.InvokeRequest.data:type_name -> google.protobuf.Any
+ 3, // 2: dapr.proto.common.v1.InvokeRequest.http_extension:type_name -> dapr.proto.common.v1.HTTPExtension
+ 13, // 3: dapr.proto.common.v1.InvokeResponse.data:type_name -> google.protobuf.Any
+ 8, // 4: dapr.proto.common.v1.StateItem.etag:type_name -> dapr.proto.common.v1.Etag
+ 11, // 5: dapr.proto.common.v1.StateItem.metadata:type_name -> dapr.proto.common.v1.StateItem.MetadataEntry
+ 9, // 6: dapr.proto.common.v1.StateItem.options:type_name -> dapr.proto.common.v1.StateOptions
+ 1, // 7: dapr.proto.common.v1.StateOptions.concurrency:type_name -> dapr.proto.common.v1.StateOptions.StateConcurrency
+ 2, // 8: dapr.proto.common.v1.StateOptions.consistency:type_name -> dapr.proto.common.v1.StateOptions.StateConsistency
+ 12, // 9: dapr.proto.common.v1.ConfigurationItem.metadata:type_name -> dapr.proto.common.v1.ConfigurationItem.MetadataEntry
+ 10, // [10:10] is the sub-list for method output_type
+ 10, // [10:10] is the sub-list for method input_type
+ 10, // [10:10] is the sub-list for extension type_name
+ 10, // [10:10] is the sub-list for extension extendee
+ 0, // [0:10] is the sub-list for field type_name
+}
+
+func init() { file_dapr_proto_common_v1_common_proto_init() }
+func file_dapr_proto_common_v1_common_proto_init() {
+ if File_dapr_proto_common_v1_common_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_dapr_proto_common_v1_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*HTTPExtension); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_common_v1_common_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*InvokeRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_common_v1_common_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*InvokeResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_common_v1_common_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*StreamPayload); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_common_v1_common_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*StateItem); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_common_v1_common_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Etag); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_common_v1_common_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*StateOptions); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_common_v1_common_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ConfigurationItem); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_dapr_proto_common_v1_common_proto_rawDesc,
+ NumEnums: 3,
+ NumMessages: 10,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_dapr_proto_common_v1_common_proto_goTypes,
+ DependencyIndexes: file_dapr_proto_common_v1_common_proto_depIdxs,
+ EnumInfos: file_dapr_proto_common_v1_common_proto_enumTypes,
+ MessageInfos: file_dapr_proto_common_v1_common_proto_msgTypes,
+ }.Build()
+ File_dapr_proto_common_v1_common_proto = out.File
+ file_dapr_proto_common_v1_common_proto_rawDesc = nil
+ file_dapr_proto_common_v1_common_proto_goTypes = nil
+ file_dapr_proto_common_v1_common_proto_depIdxs = nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/appcallback.pb.go b/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/appcallback.pb.go
new file mode 100644
index 00000000000..b61cf152ee7
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/appcallback.pb.go
@@ -0,0 +1,1897 @@
+//
+//Copyright 2021 The Dapr Authors
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//http://www.apache.org/licenses/LICENSE-2.0
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.28.1
+// protoc v3.21.12
+// source: dapr/proto/runtime/v1/appcallback.proto
+
+package runtime
+
+import (
+ v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ emptypb "google.golang.org/protobuf/types/known/emptypb"
+ structpb "google.golang.org/protobuf/types/known/structpb"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// TopicEventResponseStatus allows apps to have finer control over handling of the message.
+type TopicEventResponse_TopicEventResponseStatus int32
+
+const (
+ // SUCCESS is the default behavior: message is acknowledged and not retried or logged.
+ TopicEventResponse_SUCCESS TopicEventResponse_TopicEventResponseStatus = 0
+ // RETRY status signals Dapr to retry the message as part of an expected scenario (no warning is logged).
+ TopicEventResponse_RETRY TopicEventResponse_TopicEventResponseStatus = 1
+ // DROP status signals Dapr to drop the message as part of an unexpected scenario (warning is logged).
+ TopicEventResponse_DROP TopicEventResponse_TopicEventResponseStatus = 2
+)
+
+// Enum value maps for TopicEventResponse_TopicEventResponseStatus.
+var (
+ TopicEventResponse_TopicEventResponseStatus_name = map[int32]string{
+ 0: "SUCCESS",
+ 1: "RETRY",
+ 2: "DROP",
+ }
+ TopicEventResponse_TopicEventResponseStatus_value = map[string]int32{
+ "SUCCESS": 0,
+ "RETRY": 1,
+ "DROP": 2,
+ }
+)
+
+func (x TopicEventResponse_TopicEventResponseStatus) Enum() *TopicEventResponse_TopicEventResponseStatus {
+ p := new(TopicEventResponse_TopicEventResponseStatus)
+ *p = x
+ return p
+}
+
+func (x TopicEventResponse_TopicEventResponseStatus) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (TopicEventResponse_TopicEventResponseStatus) Descriptor() protoreflect.EnumDescriptor {
+ return file_dapr_proto_runtime_v1_appcallback_proto_enumTypes[0].Descriptor()
+}
+
+func (TopicEventResponse_TopicEventResponseStatus) Type() protoreflect.EnumType {
+ return &file_dapr_proto_runtime_v1_appcallback_proto_enumTypes[0]
+}
+
+func (x TopicEventResponse_TopicEventResponseStatus) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use TopicEventResponse_TopicEventResponseStatus.Descriptor instead.
+func (TopicEventResponse_TopicEventResponseStatus) EnumDescriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{1, 0}
+}
+
+// BindingEventConcurrency is the kind of concurrency
+type BindingEventResponse_BindingEventConcurrency int32
+
+const (
+ // SEQUENTIAL sends data to output bindings specified in "to" sequentially.
+ BindingEventResponse_SEQUENTIAL BindingEventResponse_BindingEventConcurrency = 0
+ // PARALLEL sends data to output bindings specified in "to" in parallel.
+ BindingEventResponse_PARALLEL BindingEventResponse_BindingEventConcurrency = 1
+)
+
+// Enum value maps for BindingEventResponse_BindingEventConcurrency.
+var (
+ BindingEventResponse_BindingEventConcurrency_name = map[int32]string{
+ 0: "SEQUENTIAL",
+ 1: "PARALLEL",
+ }
+ BindingEventResponse_BindingEventConcurrency_value = map[string]int32{
+ "SEQUENTIAL": 0,
+ "PARALLEL": 1,
+ }
+)
+
+func (x BindingEventResponse_BindingEventConcurrency) Enum() *BindingEventResponse_BindingEventConcurrency {
+ p := new(BindingEventResponse_BindingEventConcurrency)
+ *p = x
+ return p
+}
+
+func (x BindingEventResponse_BindingEventConcurrency) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BindingEventResponse_BindingEventConcurrency) Descriptor() protoreflect.EnumDescriptor {
+ return file_dapr_proto_runtime_v1_appcallback_proto_enumTypes[1].Descriptor()
+}
+
+func (BindingEventResponse_BindingEventConcurrency) Type() protoreflect.EnumType {
+ return &file_dapr_proto_runtime_v1_appcallback_proto_enumTypes[1]
+}
+
+func (x BindingEventResponse_BindingEventConcurrency) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use BindingEventResponse_BindingEventConcurrency.Descriptor instead.
+func (BindingEventResponse_BindingEventConcurrency) EnumDescriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{8, 0}
+}
+
+// TopicEventRequest message is compatible with CloudEvent spec v1.0
+// https://github.com/cloudevents/spec/blob/v1.0/spec.md
+type TopicEventRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // id identifies the event. Producers MUST ensure that source + id
+ // is unique for each distinct event. If a duplicate event is re-sent
+ // (e.g. due to a network error) it MAY have the same id.
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ // source identifies the context in which an event happened.
+ // Often this will include information such as the type of the
+ // event source, the organization publishing the event or the process
+ // that produced the event. The exact syntax and semantics behind
+ // the data encoded in the URI is defined by the event producer.
+ Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"`
+ // The type of event related to the originating occurrence.
+ Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
+ // The version of the CloudEvents specification.
+ SpecVersion string `protobuf:"bytes,4,opt,name=spec_version,json=specVersion,proto3" json:"spec_version,omitempty"`
+ // The content type of data value.
+ DataContentType string `protobuf:"bytes,5,opt,name=data_content_type,json=dataContentType,proto3" json:"data_content_type,omitempty"`
+ // The content of the event.
+ Data []byte `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"`
+ // The pubsub topic which publisher sent to.
+ Topic string `protobuf:"bytes,6,opt,name=topic,proto3" json:"topic,omitempty"`
+ // The name of the pubsub the publisher sent to.
+ PubsubName string `protobuf:"bytes,8,opt,name=pubsub_name,json=pubsubName,proto3" json:"pubsub_name,omitempty"`
+ // The matching path from TopicSubscription/routes (if specified) for this event.
+ // This value is used by OnTopicEvent to "switch" inside the handler.
+ Path string `protobuf:"bytes,9,opt,name=path,proto3" json:"path,omitempty"`
+ // The map of additional custom properties to be sent to the app. These are considered to be cloud event extensions.
+ Extensions *structpb.Struct `protobuf:"bytes,10,opt,name=extensions,proto3" json:"extensions,omitempty"`
+}
+
+func (x *TopicEventRequest) Reset() {
+ *x = TopicEventRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TopicEventRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopicEventRequest) ProtoMessage() {}
+
+func (x *TopicEventRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TopicEventRequest.ProtoReflect.Descriptor instead.
+func (*TopicEventRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *TopicEventRequest) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *TopicEventRequest) GetSource() string {
+ if x != nil {
+ return x.Source
+ }
+ return ""
+}
+
+func (x *TopicEventRequest) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *TopicEventRequest) GetSpecVersion() string {
+ if x != nil {
+ return x.SpecVersion
+ }
+ return ""
+}
+
+func (x *TopicEventRequest) GetDataContentType() string {
+ if x != nil {
+ return x.DataContentType
+ }
+ return ""
+}
+
+func (x *TopicEventRequest) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *TopicEventRequest) GetTopic() string {
+ if x != nil {
+ return x.Topic
+ }
+ return ""
+}
+
+func (x *TopicEventRequest) GetPubsubName() string {
+ if x != nil {
+ return x.PubsubName
+ }
+ return ""
+}
+
+func (x *TopicEventRequest) GetPath() string {
+ if x != nil {
+ return x.Path
+ }
+ return ""
+}
+
+func (x *TopicEventRequest) GetExtensions() *structpb.Struct {
+ if x != nil {
+ return x.Extensions
+ }
+ return nil
+}
+
+// TopicEventResponse is response from app on published message
+type TopicEventResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The list of output bindings.
+ Status TopicEventResponse_TopicEventResponseStatus `protobuf:"varint,1,opt,name=status,proto3,enum=dapr.proto.runtime.v1.TopicEventResponse_TopicEventResponseStatus" json:"status,omitempty"`
+}
+
+func (x *TopicEventResponse) Reset() {
+ *x = TopicEventResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TopicEventResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopicEventResponse) ProtoMessage() {}
+
+func (x *TopicEventResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TopicEventResponse.ProtoReflect.Descriptor instead.
+func (*TopicEventResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *TopicEventResponse) GetStatus() TopicEventResponse_TopicEventResponseStatus {
+ if x != nil {
+ return x.Status
+ }
+ return TopicEventResponse_SUCCESS
+}
+
+// TopicEventCERequest message is compatible with CloudEvent spec v1.0
+type TopicEventCERequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The unique identifier of this cloud event.
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ // source identifies the context in which an event happened.
+ Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"`
+ // The type of event related to the originating occurrence.
+ Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
+ // The version of the CloudEvents specification.
+ SpecVersion string `protobuf:"bytes,4,opt,name=spec_version,json=specVersion,proto3" json:"spec_version,omitempty"`
+ // The content type of data value.
+ DataContentType string `protobuf:"bytes,5,opt,name=data_content_type,json=dataContentType,proto3" json:"data_content_type,omitempty"`
+ // The content of the event.
+ Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"`
+ // Custom attributes which includes cloud event extensions.
+ Extensions *structpb.Struct `protobuf:"bytes,7,opt,name=extensions,proto3" json:"extensions,omitempty"`
+}
+
+func (x *TopicEventCERequest) Reset() {
+ *x = TopicEventCERequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TopicEventCERequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopicEventCERequest) ProtoMessage() {}
+
+func (x *TopicEventCERequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TopicEventCERequest.ProtoReflect.Descriptor instead.
+func (*TopicEventCERequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *TopicEventCERequest) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *TopicEventCERequest) GetSource() string {
+ if x != nil {
+ return x.Source
+ }
+ return ""
+}
+
+func (x *TopicEventCERequest) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *TopicEventCERequest) GetSpecVersion() string {
+ if x != nil {
+ return x.SpecVersion
+ }
+ return ""
+}
+
+func (x *TopicEventCERequest) GetDataContentType() string {
+ if x != nil {
+ return x.DataContentType
+ }
+ return ""
+}
+
+func (x *TopicEventCERequest) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *TopicEventCERequest) GetExtensions() *structpb.Struct {
+ if x != nil {
+ return x.Extensions
+ }
+ return nil
+}
+
+// TopicEventBulkRequestEntry represents a single message inside a bulk request
+type TopicEventBulkRequestEntry struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Unique identifier for the message.
+ EntryId string `protobuf:"bytes,1,opt,name=entry_id,json=entryId,proto3" json:"entry_id,omitempty"`
+ // The content of the event.
+ //
+ // Types that are assignable to Event:
+ //
+ // *TopicEventBulkRequestEntry_Bytes
+ // *TopicEventBulkRequestEntry_CloudEvent
+ Event isTopicEventBulkRequestEntry_Event `protobuf_oneof:"event"`
+ // content type of the event contained.
+ ContentType string `protobuf:"bytes,4,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"`
+ // The metadata associated with the event.
+ Metadata map[string]string `protobuf:"bytes,5,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *TopicEventBulkRequestEntry) Reset() {
+ *x = TopicEventBulkRequestEntry{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TopicEventBulkRequestEntry) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopicEventBulkRequestEntry) ProtoMessage() {}
+
+func (x *TopicEventBulkRequestEntry) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TopicEventBulkRequestEntry.ProtoReflect.Descriptor instead.
+func (*TopicEventBulkRequestEntry) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *TopicEventBulkRequestEntry) GetEntryId() string {
+ if x != nil {
+ return x.EntryId
+ }
+ return ""
+}
+
+func (m *TopicEventBulkRequestEntry) GetEvent() isTopicEventBulkRequestEntry_Event {
+ if m != nil {
+ return m.Event
+ }
+ return nil
+}
+
+func (x *TopicEventBulkRequestEntry) GetBytes() []byte {
+ if x, ok := x.GetEvent().(*TopicEventBulkRequestEntry_Bytes); ok {
+ return x.Bytes
+ }
+ return nil
+}
+
+func (x *TopicEventBulkRequestEntry) GetCloudEvent() *TopicEventCERequest {
+ if x, ok := x.GetEvent().(*TopicEventBulkRequestEntry_CloudEvent); ok {
+ return x.CloudEvent
+ }
+ return nil
+}
+
+func (x *TopicEventBulkRequestEntry) GetContentType() string {
+ if x != nil {
+ return x.ContentType
+ }
+ return ""
+}
+
+func (x *TopicEventBulkRequestEntry) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+type isTopicEventBulkRequestEntry_Event interface {
+ isTopicEventBulkRequestEntry_Event()
+}
+
+type TopicEventBulkRequestEntry_Bytes struct {
+ Bytes []byte `protobuf:"bytes,2,opt,name=bytes,proto3,oneof"`
+}
+
+type TopicEventBulkRequestEntry_CloudEvent struct {
+ CloudEvent *TopicEventCERequest `protobuf:"bytes,3,opt,name=cloud_event,json=cloudEvent,proto3,oneof"`
+}
+
+func (*TopicEventBulkRequestEntry_Bytes) isTopicEventBulkRequestEntry_Event() {}
+
+func (*TopicEventBulkRequestEntry_CloudEvent) isTopicEventBulkRequestEntry_Event() {}
+
+// TopicEventBulkRequest represents request for bulk message
+type TopicEventBulkRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Unique identifier for the bulk request.
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ // The list of items inside this bulk request.
+ Entries []*TopicEventBulkRequestEntry `protobuf:"bytes,2,rep,name=entries,proto3" json:"entries,omitempty"`
+ // The metadata associated with the this bulk request.
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // The pubsub topic which publisher sent to.
+ Topic string `protobuf:"bytes,4,opt,name=topic,proto3" json:"topic,omitempty"`
+ // The name of the pubsub the publisher sent to.
+ PubsubName string `protobuf:"bytes,5,opt,name=pubsub_name,json=pubsubName,proto3" json:"pubsub_name,omitempty"`
+ // The type of event related to the originating occurrence.
+ Type string `protobuf:"bytes,6,opt,name=type,proto3" json:"type,omitempty"`
+ // The matching path from TopicSubscription/routes (if specified) for this event.
+ // This value is used by OnTopicEvent to "switch" inside the handler.
+ Path string `protobuf:"bytes,7,opt,name=path,proto3" json:"path,omitempty"`
+}
+
+func (x *TopicEventBulkRequest) Reset() {
+ *x = TopicEventBulkRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TopicEventBulkRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopicEventBulkRequest) ProtoMessage() {}
+
+func (x *TopicEventBulkRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TopicEventBulkRequest.ProtoReflect.Descriptor instead.
+func (*TopicEventBulkRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *TopicEventBulkRequest) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *TopicEventBulkRequest) GetEntries() []*TopicEventBulkRequestEntry {
+ if x != nil {
+ return x.Entries
+ }
+ return nil
+}
+
+func (x *TopicEventBulkRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+func (x *TopicEventBulkRequest) GetTopic() string {
+ if x != nil {
+ return x.Topic
+ }
+ return ""
+}
+
+func (x *TopicEventBulkRequest) GetPubsubName() string {
+ if x != nil {
+ return x.PubsubName
+ }
+ return ""
+}
+
+func (x *TopicEventBulkRequest) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *TopicEventBulkRequest) GetPath() string {
+ if x != nil {
+ return x.Path
+ }
+ return ""
+}
+
+// TopicEventBulkResponseEntry Represents single response, as part of TopicEventBulkResponse, to be
+// sent by subscibed App for the corresponding single message during bulk subscribe
+type TopicEventBulkResponseEntry struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Unique identifier associated the message.
+ EntryId string `protobuf:"bytes,1,opt,name=entry_id,json=entryId,proto3" json:"entry_id,omitempty"`
+ // The status of the response.
+ Status TopicEventResponse_TopicEventResponseStatus `protobuf:"varint,2,opt,name=status,proto3,enum=dapr.proto.runtime.v1.TopicEventResponse_TopicEventResponseStatus" json:"status,omitempty"`
+}
+
+func (x *TopicEventBulkResponseEntry) Reset() {
+ *x = TopicEventBulkResponseEntry{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TopicEventBulkResponseEntry) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopicEventBulkResponseEntry) ProtoMessage() {}
+
+func (x *TopicEventBulkResponseEntry) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TopicEventBulkResponseEntry.ProtoReflect.Descriptor instead.
+func (*TopicEventBulkResponseEntry) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *TopicEventBulkResponseEntry) GetEntryId() string {
+ if x != nil {
+ return x.EntryId
+ }
+ return ""
+}
+
+func (x *TopicEventBulkResponseEntry) GetStatus() TopicEventResponse_TopicEventResponseStatus {
+ if x != nil {
+ return x.Status
+ }
+ return TopicEventResponse_SUCCESS
+}
+
+// AppBulkResponse is response from app on published message
+type TopicEventBulkResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The list of all responses for the bulk request.
+ Statuses []*TopicEventBulkResponseEntry `protobuf:"bytes,1,rep,name=statuses,proto3" json:"statuses,omitempty"`
+}
+
+func (x *TopicEventBulkResponse) Reset() {
+ *x = TopicEventBulkResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TopicEventBulkResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopicEventBulkResponse) ProtoMessage() {}
+
+func (x *TopicEventBulkResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TopicEventBulkResponse.ProtoReflect.Descriptor instead.
+func (*TopicEventBulkResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *TopicEventBulkResponse) GetStatuses() []*TopicEventBulkResponseEntry {
+ if x != nil {
+ return x.Statuses
+ }
+ return nil
+}
+
+// BindingEventRequest represents input bindings event.
+type BindingEventRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the input binding component.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Required. The payload that the input bindings sent
+ Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+ // The metadata set by the input binging components.
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *BindingEventRequest) Reset() {
+ *x = BindingEventRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BindingEventRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BindingEventRequest) ProtoMessage() {}
+
+func (x *BindingEventRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BindingEventRequest.ProtoReflect.Descriptor instead.
+func (*BindingEventRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *BindingEventRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *BindingEventRequest) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *BindingEventRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// BindingEventResponse includes operations to save state or
+// send data to output bindings optionally.
+type BindingEventResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of state store where states are saved.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // The state key values which will be stored in store_name.
+ States []*v1.StateItem `protobuf:"bytes,2,rep,name=states,proto3" json:"states,omitempty"`
+ // The list of output bindings.
+ To []string `protobuf:"bytes,3,rep,name=to,proto3" json:"to,omitempty"`
+ // The content which will be sent to "to" output bindings.
+ Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
+ // The concurrency of output bindings to send data to
+ // "to" output bindings list. The default is SEQUENTIAL.
+ Concurrency BindingEventResponse_BindingEventConcurrency `protobuf:"varint,5,opt,name=concurrency,proto3,enum=dapr.proto.runtime.v1.BindingEventResponse_BindingEventConcurrency" json:"concurrency,omitempty"`
+}
+
+func (x *BindingEventResponse) Reset() {
+ *x = BindingEventResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BindingEventResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BindingEventResponse) ProtoMessage() {}
+
+func (x *BindingEventResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[8]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BindingEventResponse.ProtoReflect.Descriptor instead.
+func (*BindingEventResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *BindingEventResponse) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *BindingEventResponse) GetStates() []*v1.StateItem {
+ if x != nil {
+ return x.States
+ }
+ return nil
+}
+
+func (x *BindingEventResponse) GetTo() []string {
+ if x != nil {
+ return x.To
+ }
+ return nil
+}
+
+func (x *BindingEventResponse) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *BindingEventResponse) GetConcurrency() BindingEventResponse_BindingEventConcurrency {
+ if x != nil {
+ return x.Concurrency
+ }
+ return BindingEventResponse_SEQUENTIAL
+}
+
+// ListTopicSubscriptionsResponse is the message including the list of the subscribing topics.
+type ListTopicSubscriptionsResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The list of topics.
+ Subscriptions []*TopicSubscription `protobuf:"bytes,1,rep,name=subscriptions,proto3" json:"subscriptions,omitempty"`
+}
+
+func (x *ListTopicSubscriptionsResponse) Reset() {
+ *x = ListTopicSubscriptionsResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListTopicSubscriptionsResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListTopicSubscriptionsResponse) ProtoMessage() {}
+
+func (x *ListTopicSubscriptionsResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListTopicSubscriptionsResponse.ProtoReflect.Descriptor instead.
+func (*ListTopicSubscriptionsResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *ListTopicSubscriptionsResponse) GetSubscriptions() []*TopicSubscription {
+ if x != nil {
+ return x.Subscriptions
+ }
+ return nil
+}
+
+// TopicSubscription represents topic and metadata.
+type TopicSubscription struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the pubsub containing the topic below to subscribe to.
+ PubsubName string `protobuf:"bytes,1,opt,name=pubsub_name,json=pubsubName,proto3" json:"pubsub_name,omitempty"`
+ // Required. The name of topic which will be subscribed
+ Topic string `protobuf:"bytes,2,opt,name=topic,proto3" json:"topic,omitempty"`
+ // The optional properties used for this topic's subscription e.g. session id
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // The optional routing rules to match against. In the gRPC interface, OnTopicEvent
+ // is still invoked but the matching path is sent in the TopicEventRequest.
+ Routes *TopicRoutes `protobuf:"bytes,5,opt,name=routes,proto3" json:"routes,omitempty"`
+ // The optional dead letter queue for this topic to send events to.
+ DeadLetterTopic string `protobuf:"bytes,6,opt,name=dead_letter_topic,json=deadLetterTopic,proto3" json:"dead_letter_topic,omitempty"`
+ // The optional bulk subscribe settings for this topic.
+ BulkSubscribe *BulkSubscribeConfig `protobuf:"bytes,7,opt,name=bulk_subscribe,json=bulkSubscribe,proto3" json:"bulk_subscribe,omitempty"`
+}
+
+func (x *TopicSubscription) Reset() {
+ *x = TopicSubscription{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TopicSubscription) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopicSubscription) ProtoMessage() {}
+
+func (x *TopicSubscription) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[10]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TopicSubscription.ProtoReflect.Descriptor instead.
+func (*TopicSubscription) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *TopicSubscription) GetPubsubName() string {
+ if x != nil {
+ return x.PubsubName
+ }
+ return ""
+}
+
+func (x *TopicSubscription) GetTopic() string {
+ if x != nil {
+ return x.Topic
+ }
+ return ""
+}
+
+func (x *TopicSubscription) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+func (x *TopicSubscription) GetRoutes() *TopicRoutes {
+ if x != nil {
+ return x.Routes
+ }
+ return nil
+}
+
+func (x *TopicSubscription) GetDeadLetterTopic() string {
+ if x != nil {
+ return x.DeadLetterTopic
+ }
+ return ""
+}
+
+func (x *TopicSubscription) GetBulkSubscribe() *BulkSubscribeConfig {
+ if x != nil {
+ return x.BulkSubscribe
+ }
+ return nil
+}
+
+type TopicRoutes struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The list of rules for this topic.
+ Rules []*TopicRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"`
+ // The default path for this topic.
+ Default string `protobuf:"bytes,2,opt,name=default,proto3" json:"default,omitempty"`
+}
+
+func (x *TopicRoutes) Reset() {
+ *x = TopicRoutes{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TopicRoutes) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopicRoutes) ProtoMessage() {}
+
+func (x *TopicRoutes) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[11]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TopicRoutes.ProtoReflect.Descriptor instead.
+func (*TopicRoutes) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *TopicRoutes) GetRules() []*TopicRule {
+ if x != nil {
+ return x.Rules
+ }
+ return nil
+}
+
+func (x *TopicRoutes) GetDefault() string {
+ if x != nil {
+ return x.Default
+ }
+ return ""
+}
+
+type TopicRule struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The optional CEL expression used to match the event.
+ // If the match is not specified, then the route is considered
+ // the default.
+ Match string `protobuf:"bytes,1,opt,name=match,proto3" json:"match,omitempty"`
+ // The path used to identify matches for this subscription.
+ // This value is passed in TopicEventRequest and used by OnTopicEvent to "switch"
+ // inside the handler.
+ Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
+}
+
+func (x *TopicRule) Reset() {
+ *x = TopicRule{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TopicRule) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopicRule) ProtoMessage() {}
+
+func (x *TopicRule) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[12]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TopicRule.ProtoReflect.Descriptor instead.
+func (*TopicRule) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *TopicRule) GetMatch() string {
+ if x != nil {
+ return x.Match
+ }
+ return ""
+}
+
+func (x *TopicRule) GetPath() string {
+ if x != nil {
+ return x.Path
+ }
+ return ""
+}
+
+// BulkSubscribeConfig is the message to pass settings for bulk subscribe
+type BulkSubscribeConfig struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. Flag to enable/disable bulk subscribe
+ Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
+ // Optional. Max number of messages to be sent in a single bulk request
+ MaxMessagesCount int32 `protobuf:"varint,2,opt,name=max_messages_count,json=maxMessagesCount,proto3" json:"max_messages_count,omitempty"`
+ // Optional. Max duration to wait for messages to be sent in a single bulk request
+ MaxAwaitDurationMs int32 `protobuf:"varint,3,opt,name=max_await_duration_ms,json=maxAwaitDurationMs,proto3" json:"max_await_duration_ms,omitempty"`
+}
+
+func (x *BulkSubscribeConfig) Reset() {
+ *x = BulkSubscribeConfig{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BulkSubscribeConfig) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BulkSubscribeConfig) ProtoMessage() {}
+
+func (x *BulkSubscribeConfig) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[13]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BulkSubscribeConfig.ProtoReflect.Descriptor instead.
+func (*BulkSubscribeConfig) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *BulkSubscribeConfig) GetEnabled() bool {
+ if x != nil {
+ return x.Enabled
+ }
+ return false
+}
+
+func (x *BulkSubscribeConfig) GetMaxMessagesCount() int32 {
+ if x != nil {
+ return x.MaxMessagesCount
+ }
+ return 0
+}
+
+func (x *BulkSubscribeConfig) GetMaxAwaitDurationMs() int32 {
+ if x != nil {
+ return x.MaxAwaitDurationMs
+ }
+ return 0
+}
+
+// ListInputBindingsResponse is the message including the list of input bindings.
+type ListInputBindingsResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The list of input bindings.
+ Bindings []string `protobuf:"bytes,1,rep,name=bindings,proto3" json:"bindings,omitempty"`
+}
+
+func (x *ListInputBindingsResponse) Reset() {
+ *x = ListInputBindingsResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListInputBindingsResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListInputBindingsResponse) ProtoMessage() {}
+
+func (x *ListInputBindingsResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[14]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListInputBindingsResponse.ProtoReflect.Descriptor instead.
+func (*ListInputBindingsResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *ListInputBindingsResponse) GetBindings() []string {
+ if x != nil {
+ return x.Bindings
+ }
+ return nil
+}
+
+// HealthCheckResponse is the message with the response to the health check.
+// This message is currently empty as used as placeholder.
+type HealthCheckResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+}
+
+func (x *HealthCheckResponse) Reset() {
+ *x = HealthCheckResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[15]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *HealthCheckResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*HealthCheckResponse) ProtoMessage() {}
+
+func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[15]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use HealthCheckResponse.ProtoReflect.Descriptor instead.
+func (*HealthCheckResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP(), []int{15}
+}
+
+var File_dapr_proto_runtime_v1_appcallback_proto protoreflect.FileDescriptor
+
+var file_dapr_proto_runtime_v1_appcallback_proto_rawDesc = []byte{
+ 0x0a, 0x27, 0x64, 0x61, 0x70, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x75, 0x6e,
+ 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x62,
+ 0x61, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x64, 0x61, 0x70, 0x72, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31,
+ 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
+ 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x64,
+ 0x61, 0x70, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
+ 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
+ 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb6,
+ 0x02, 0x0a, 0x11, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04,
+ 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
+ 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x70, 0x65, 0x63, 0x56, 0x65, 0x72, 0x73,
+ 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, 0x6f, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f,
+ 0x64, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12,
+ 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64,
+ 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x06, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x75, 0x62,
+ 0x73, 0x75, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
+ 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,
+ 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x37,
+ 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0a, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x74,
+ 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xae, 0x01, 0x0a, 0x12, 0x54, 0x6f, 0x70, 0x69,
+ 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a,
+ 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x42,
+ 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74,
+ 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e,
+ 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45,
+ 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74,
+ 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3c, 0x0a, 0x18, 0x54, 0x6f,
+ 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53,
+ 0x53, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x45, 0x54, 0x52, 0x59, 0x10, 0x01, 0x12, 0x08,
+ 0x0a, 0x04, 0x44, 0x52, 0x4f, 0x50, 0x10, 0x02, 0x22, 0xed, 0x01, 0x0a, 0x13, 0x54, 0x6f, 0x70,
+ 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x43, 0x45, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
+ 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c,
+ 0x73, 0x70, 0x65, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x0b, 0x73, 0x70, 0x65, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
+ 0x2a, 0x0a, 0x11, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f,
+ 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x61, 0x74, 0x61,
+ 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64,
+ 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12,
+ 0x37, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0a, 0x65, 0x78,
+ 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe4, 0x02, 0x0a, 0x1a, 0x54, 0x6f, 0x70,
+ 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x74, 0x72, 0x79,
+ 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x79,
+ 0x49, 0x64, 0x12, 0x16, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x0c, 0x48, 0x00, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x12, 0x4d, 0x0a, 0x0b, 0x63, 0x6c,
+ 0x6f, 0x75, 0x64, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x2a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e,
+ 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65,
+ 0x6e, 0x74, 0x43, 0x45, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x63,
+ 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e,
+ 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x5b, 0x0a, 0x08,
+ 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f,
+ 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74,
+ 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e,
+ 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
+ 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
+ 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
+ 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
+ 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22,
+ 0xe8, 0x02, 0x0a, 0x15, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x75,
+ 0x6c, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x4b, 0x0a, 0x07, 0x65, 0x6e, 0x74,
+ 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x64, 0x61, 0x70,
+ 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e,
+ 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x6c,
+ 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65,
+ 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x56, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45,
+ 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14,
+ 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74,
+ 0x6f, 0x70, 0x69, 0x63, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x5f, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x75, 0x62, 0x73, 0x75,
+ 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74,
+ 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x1a, 0x3b, 0x0a,
+ 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
+ 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
+ 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x94, 0x01, 0x0a, 0x1b, 0x54,
+ 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e,
+ 0x74, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x6e,
+ 0x74, 0x72, 0x79, 0x49, 0x64, 0x12, 0x5a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x42, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f,
+ 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
+ 0x73, 0x22, 0x68, 0x0a, 0x16, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42,
+ 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x08, 0x73,
+ 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74,
+ 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x52, 0x08, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x22, 0xd0, 0x01, 0x0a, 0x13,
+ 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x54, 0x0a, 0x08, 0x6d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65,
+ 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+ 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74,
+ 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xb2,
+ 0x02, 0x0a, 0x14, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65,
+ 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x6f,
+ 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73,
+ 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12,
+ 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12,
+ 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64,
+ 0x61, 0x74, 0x61, 0x12, 0x65, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
+ 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x43, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65,
+ 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63,
+ 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x37, 0x0a, 0x17, 0x42, 0x69,
+ 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72,
+ 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x45, 0x51, 0x55, 0x45, 0x4e, 0x54,
+ 0x49, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x41, 0x52, 0x41, 0x4c, 0x4c, 0x45,
+ 0x4c, 0x10, 0x01, 0x22, 0x70, 0x0a, 0x1e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63,
+ 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72,
+ 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x96, 0x03, 0x0a, 0x11, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x53,
+ 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x70,
+ 0x75, 0x62, 0x73, 0x75, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x0a, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05,
+ 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70,
+ 0x69, 0x63, 0x12, 0x52, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70,
+ 0x69, 0x63, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3a, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73,
+ 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54,
+ 0x6f, 0x70, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74,
+ 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x61, 0x64, 0x5f, 0x6c, 0x65, 0x74, 0x74, 0x65,
+ 0x72, 0x5f, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64,
+ 0x65, 0x61, 0x64, 0x4c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x51,
+ 0x0a, 0x0e, 0x62, 0x75, 0x6c, 0x6b, 0x5f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
+ 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42,
+ 0x75, 0x6c, 0x6b, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x52, 0x0d, 0x62, 0x75, 0x6c, 0x6b, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62,
+ 0x65, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74,
+ 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x5f,
+ 0x0a, 0x0b, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x36, 0x0a,
+ 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05,
+ 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22,
+ 0x35, 0x0a, 0x09, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05,
+ 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74,
+ 0x63, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x90, 0x01, 0x0a, 0x13, 0x42, 0x75, 0x6c, 0x6b, 0x53,
+ 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18,
+ 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
+ 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x5f,
+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+ 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x15, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x77,
+ 0x61, 0x69, 0x74, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x73, 0x18,
+ 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x6d, 0x61, 0x78, 0x41, 0x77, 0x61, 0x69, 0x74, 0x44,
+ 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x22, 0x37, 0x0a, 0x19, 0x4c, 0x69, 0x73,
+ 0x74, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e,
+ 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e,
+ 0x67, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63,
+ 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x86, 0x04, 0x0a, 0x0b, 0x41, 0x70,
+ 0x70, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x57, 0x0a, 0x08, 0x4f, 0x6e, 0x49,
+ 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x12, 0x23, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76,
+ 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x64, 0x61, 0x70,
+ 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76,
+ 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x22, 0x00, 0x12, 0x69, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x53,
+ 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45,
+ 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x35, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73,
+ 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x65, 0x0a,
+ 0x0c, 0x4f, 0x6e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x28, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x70, 0x75,
+ 0x74, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
+ 0x79, 0x1a, 0x30, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72,
+ 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e,
+ 0x70, 0x75, 0x74, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6b, 0x0a, 0x0e, 0x4f, 0x6e, 0x42, 0x69, 0x6e, 0x64, 0x69,
+ 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x6e, 0x64,
+ 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x22, 0x00, 0x32, 0x6d, 0x0a, 0x16, 0x41, 0x70, 0x70, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
+ 0x6b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x53, 0x0a, 0x0b,
+ 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x16, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
+ 0x70, 0x74, 0x79, 0x1a, 0x2a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c,
+ 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
+ 0x00, 0x32, 0x8b, 0x01, 0x0a, 0x10, 0x41, 0x70, 0x70, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
+ 0x6b, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x12, 0x77, 0x0a, 0x16, 0x4f, 0x6e, 0x42, 0x75, 0x6c, 0x6b,
+ 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31,
+ 0x12, 0x2c, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75,
+ 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76,
+ 0x65, 0x6e, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d,
+ 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74,
+ 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x76, 0x65, 0x6e,
+ 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42,
+ 0x79, 0x0a, 0x0a, 0x69, 0x6f, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x76, 0x31, 0x42, 0x15, 0x44,
+ 0x61, 0x70, 0x72, 0x41, 0x70, 0x70, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x50, 0x72,
+ 0x6f, 0x74, 0x6f, 0x73, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x64, 0x61, 0x70, 0x72, 0x2f, 0x64, 0x61, 0x70, 0x72, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x3b,
+ 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0xaa, 0x02, 0x20, 0x44, 0x61, 0x70, 0x72, 0x2e, 0x41,
+ 0x70, 0x70, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x67,
+ 0x65, 0x6e, 0x2e, 0x47, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x33,
+}
+
+var (
+ file_dapr_proto_runtime_v1_appcallback_proto_rawDescOnce sync.Once
+ file_dapr_proto_runtime_v1_appcallback_proto_rawDescData = file_dapr_proto_runtime_v1_appcallback_proto_rawDesc
+)
+
+func file_dapr_proto_runtime_v1_appcallback_proto_rawDescGZIP() []byte {
+ file_dapr_proto_runtime_v1_appcallback_proto_rawDescOnce.Do(func() {
+ file_dapr_proto_runtime_v1_appcallback_proto_rawDescData = protoimpl.X.CompressGZIP(file_dapr_proto_runtime_v1_appcallback_proto_rawDescData)
+ })
+ return file_dapr_proto_runtime_v1_appcallback_proto_rawDescData
+}
+
+var file_dapr_proto_runtime_v1_appcallback_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_dapr_proto_runtime_v1_appcallback_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
+var file_dapr_proto_runtime_v1_appcallback_proto_goTypes = []interface{}{
+ (TopicEventResponse_TopicEventResponseStatus)(0), // 0: dapr.proto.runtime.v1.TopicEventResponse.TopicEventResponseStatus
+ (BindingEventResponse_BindingEventConcurrency)(0), // 1: dapr.proto.runtime.v1.BindingEventResponse.BindingEventConcurrency
+ (*TopicEventRequest)(nil), // 2: dapr.proto.runtime.v1.TopicEventRequest
+ (*TopicEventResponse)(nil), // 3: dapr.proto.runtime.v1.TopicEventResponse
+ (*TopicEventCERequest)(nil), // 4: dapr.proto.runtime.v1.TopicEventCERequest
+ (*TopicEventBulkRequestEntry)(nil), // 5: dapr.proto.runtime.v1.TopicEventBulkRequestEntry
+ (*TopicEventBulkRequest)(nil), // 6: dapr.proto.runtime.v1.TopicEventBulkRequest
+ (*TopicEventBulkResponseEntry)(nil), // 7: dapr.proto.runtime.v1.TopicEventBulkResponseEntry
+ (*TopicEventBulkResponse)(nil), // 8: dapr.proto.runtime.v1.TopicEventBulkResponse
+ (*BindingEventRequest)(nil), // 9: dapr.proto.runtime.v1.BindingEventRequest
+ (*BindingEventResponse)(nil), // 10: dapr.proto.runtime.v1.BindingEventResponse
+ (*ListTopicSubscriptionsResponse)(nil), // 11: dapr.proto.runtime.v1.ListTopicSubscriptionsResponse
+ (*TopicSubscription)(nil), // 12: dapr.proto.runtime.v1.TopicSubscription
+ (*TopicRoutes)(nil), // 13: dapr.proto.runtime.v1.TopicRoutes
+ (*TopicRule)(nil), // 14: dapr.proto.runtime.v1.TopicRule
+ (*BulkSubscribeConfig)(nil), // 15: dapr.proto.runtime.v1.BulkSubscribeConfig
+ (*ListInputBindingsResponse)(nil), // 16: dapr.proto.runtime.v1.ListInputBindingsResponse
+ (*HealthCheckResponse)(nil), // 17: dapr.proto.runtime.v1.HealthCheckResponse
+ nil, // 18: dapr.proto.runtime.v1.TopicEventBulkRequestEntry.MetadataEntry
+ nil, // 19: dapr.proto.runtime.v1.TopicEventBulkRequest.MetadataEntry
+ nil, // 20: dapr.proto.runtime.v1.BindingEventRequest.MetadataEntry
+ nil, // 21: dapr.proto.runtime.v1.TopicSubscription.MetadataEntry
+ (*structpb.Struct)(nil), // 22: google.protobuf.Struct
+ (*v1.StateItem)(nil), // 23: dapr.proto.common.v1.StateItem
+ (*v1.InvokeRequest)(nil), // 24: dapr.proto.common.v1.InvokeRequest
+ (*emptypb.Empty)(nil), // 25: google.protobuf.Empty
+ (*v1.InvokeResponse)(nil), // 26: dapr.proto.common.v1.InvokeResponse
+}
+var file_dapr_proto_runtime_v1_appcallback_proto_depIdxs = []int32{
+ 22, // 0: dapr.proto.runtime.v1.TopicEventRequest.extensions:type_name -> google.protobuf.Struct
+ 0, // 1: dapr.proto.runtime.v1.TopicEventResponse.status:type_name -> dapr.proto.runtime.v1.TopicEventResponse.TopicEventResponseStatus
+ 22, // 2: dapr.proto.runtime.v1.TopicEventCERequest.extensions:type_name -> google.protobuf.Struct
+ 4, // 3: dapr.proto.runtime.v1.TopicEventBulkRequestEntry.cloud_event:type_name -> dapr.proto.runtime.v1.TopicEventCERequest
+ 18, // 4: dapr.proto.runtime.v1.TopicEventBulkRequestEntry.metadata:type_name -> dapr.proto.runtime.v1.TopicEventBulkRequestEntry.MetadataEntry
+ 5, // 5: dapr.proto.runtime.v1.TopicEventBulkRequest.entries:type_name -> dapr.proto.runtime.v1.TopicEventBulkRequestEntry
+ 19, // 6: dapr.proto.runtime.v1.TopicEventBulkRequest.metadata:type_name -> dapr.proto.runtime.v1.TopicEventBulkRequest.MetadataEntry
+ 0, // 7: dapr.proto.runtime.v1.TopicEventBulkResponseEntry.status:type_name -> dapr.proto.runtime.v1.TopicEventResponse.TopicEventResponseStatus
+ 7, // 8: dapr.proto.runtime.v1.TopicEventBulkResponse.statuses:type_name -> dapr.proto.runtime.v1.TopicEventBulkResponseEntry
+ 20, // 9: dapr.proto.runtime.v1.BindingEventRequest.metadata:type_name -> dapr.proto.runtime.v1.BindingEventRequest.MetadataEntry
+ 23, // 10: dapr.proto.runtime.v1.BindingEventResponse.states:type_name -> dapr.proto.common.v1.StateItem
+ 1, // 11: dapr.proto.runtime.v1.BindingEventResponse.concurrency:type_name -> dapr.proto.runtime.v1.BindingEventResponse.BindingEventConcurrency
+ 12, // 12: dapr.proto.runtime.v1.ListTopicSubscriptionsResponse.subscriptions:type_name -> dapr.proto.runtime.v1.TopicSubscription
+ 21, // 13: dapr.proto.runtime.v1.TopicSubscription.metadata:type_name -> dapr.proto.runtime.v1.TopicSubscription.MetadataEntry
+ 13, // 14: dapr.proto.runtime.v1.TopicSubscription.routes:type_name -> dapr.proto.runtime.v1.TopicRoutes
+ 15, // 15: dapr.proto.runtime.v1.TopicSubscription.bulk_subscribe:type_name -> dapr.proto.runtime.v1.BulkSubscribeConfig
+ 14, // 16: dapr.proto.runtime.v1.TopicRoutes.rules:type_name -> dapr.proto.runtime.v1.TopicRule
+ 24, // 17: dapr.proto.runtime.v1.AppCallback.OnInvoke:input_type -> dapr.proto.common.v1.InvokeRequest
+ 25, // 18: dapr.proto.runtime.v1.AppCallback.ListTopicSubscriptions:input_type -> google.protobuf.Empty
+ 2, // 19: dapr.proto.runtime.v1.AppCallback.OnTopicEvent:input_type -> dapr.proto.runtime.v1.TopicEventRequest
+ 25, // 20: dapr.proto.runtime.v1.AppCallback.ListInputBindings:input_type -> google.protobuf.Empty
+ 9, // 21: dapr.proto.runtime.v1.AppCallback.OnBindingEvent:input_type -> dapr.proto.runtime.v1.BindingEventRequest
+ 25, // 22: dapr.proto.runtime.v1.AppCallbackHealthCheck.HealthCheck:input_type -> google.protobuf.Empty
+ 6, // 23: dapr.proto.runtime.v1.AppCallbackAlpha.OnBulkTopicEventAlpha1:input_type -> dapr.proto.runtime.v1.TopicEventBulkRequest
+ 26, // 24: dapr.proto.runtime.v1.AppCallback.OnInvoke:output_type -> dapr.proto.common.v1.InvokeResponse
+ 11, // 25: dapr.proto.runtime.v1.AppCallback.ListTopicSubscriptions:output_type -> dapr.proto.runtime.v1.ListTopicSubscriptionsResponse
+ 3, // 26: dapr.proto.runtime.v1.AppCallback.OnTopicEvent:output_type -> dapr.proto.runtime.v1.TopicEventResponse
+ 16, // 27: dapr.proto.runtime.v1.AppCallback.ListInputBindings:output_type -> dapr.proto.runtime.v1.ListInputBindingsResponse
+ 10, // 28: dapr.proto.runtime.v1.AppCallback.OnBindingEvent:output_type -> dapr.proto.runtime.v1.BindingEventResponse
+ 17, // 29: dapr.proto.runtime.v1.AppCallbackHealthCheck.HealthCheck:output_type -> dapr.proto.runtime.v1.HealthCheckResponse
+ 8, // 30: dapr.proto.runtime.v1.AppCallbackAlpha.OnBulkTopicEventAlpha1:output_type -> dapr.proto.runtime.v1.TopicEventBulkResponse
+ 24, // [24:31] is the sub-list for method output_type
+ 17, // [17:24] is the sub-list for method input_type
+ 17, // [17:17] is the sub-list for extension type_name
+ 17, // [17:17] is the sub-list for extension extendee
+ 0, // [0:17] is the sub-list for field type_name
+}
+
+func init() { file_dapr_proto_runtime_v1_appcallback_proto_init() }
+func file_dapr_proto_runtime_v1_appcallback_proto_init() {
+ if File_dapr_proto_runtime_v1_appcallback_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TopicEventRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TopicEventResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TopicEventCERequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TopicEventBulkRequestEntry); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TopicEventBulkRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TopicEventBulkResponseEntry); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TopicEventBulkResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*BindingEventRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*BindingEventResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListTopicSubscriptionsResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TopicSubscription); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TopicRoutes); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TopicRule); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*BulkSubscribeConfig); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListInputBindingsResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*HealthCheckResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ file_dapr_proto_runtime_v1_appcallback_proto_msgTypes[3].OneofWrappers = []interface{}{
+ (*TopicEventBulkRequestEntry_Bytes)(nil),
+ (*TopicEventBulkRequestEntry_CloudEvent)(nil),
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_dapr_proto_runtime_v1_appcallback_proto_rawDesc,
+ NumEnums: 2,
+ NumMessages: 20,
+ NumExtensions: 0,
+ NumServices: 3,
+ },
+ GoTypes: file_dapr_proto_runtime_v1_appcallback_proto_goTypes,
+ DependencyIndexes: file_dapr_proto_runtime_v1_appcallback_proto_depIdxs,
+ EnumInfos: file_dapr_proto_runtime_v1_appcallback_proto_enumTypes,
+ MessageInfos: file_dapr_proto_runtime_v1_appcallback_proto_msgTypes,
+ }.Build()
+ File_dapr_proto_runtime_v1_appcallback_proto = out.File
+ file_dapr_proto_runtime_v1_appcallback_proto_rawDesc = nil
+ file_dapr_proto_runtime_v1_appcallback_proto_goTypes = nil
+ file_dapr_proto_runtime_v1_appcallback_proto_depIdxs = nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/appcallback_grpc.pb.go b/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/appcallback_grpc.pb.go
new file mode 100644
index 00000000000..5280e1ff11d
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/appcallback_grpc.pb.go
@@ -0,0 +1,437 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.2.0
+// - protoc v3.21.12
+// source: dapr/proto/runtime/v1/appcallback.proto
+
+package runtime
+
+import (
+ context "context"
+ v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+ emptypb "google.golang.org/protobuf/types/known/emptypb"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// AppCallbackClient is the client API for AppCallback service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type AppCallbackClient interface {
+ // Invokes service method with InvokeRequest.
+ OnInvoke(ctx context.Context, in *v1.InvokeRequest, opts ...grpc.CallOption) (*v1.InvokeResponse, error)
+ // Lists all topics subscribed by this app.
+ ListTopicSubscriptions(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ListTopicSubscriptionsResponse, error)
+ // Subscribes events from Pubsub
+ OnTopicEvent(ctx context.Context, in *TopicEventRequest, opts ...grpc.CallOption) (*TopicEventResponse, error)
+ // Lists all input bindings subscribed by this app.
+ ListInputBindings(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ListInputBindingsResponse, error)
+ // Listens events from the input bindings
+ //
+ // User application can save the states or send the events to the output
+ // bindings optionally by returning BindingEventResponse.
+ OnBindingEvent(ctx context.Context, in *BindingEventRequest, opts ...grpc.CallOption) (*BindingEventResponse, error)
+}
+
+type appCallbackClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewAppCallbackClient(cc grpc.ClientConnInterface) AppCallbackClient {
+ return &appCallbackClient{cc}
+}
+
+func (c *appCallbackClient) OnInvoke(ctx context.Context, in *v1.InvokeRequest, opts ...grpc.CallOption) (*v1.InvokeResponse, error) {
+ out := new(v1.InvokeResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.AppCallback/OnInvoke", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *appCallbackClient) ListTopicSubscriptions(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ListTopicSubscriptionsResponse, error) {
+ out := new(ListTopicSubscriptionsResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.AppCallback/ListTopicSubscriptions", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *appCallbackClient) OnTopicEvent(ctx context.Context, in *TopicEventRequest, opts ...grpc.CallOption) (*TopicEventResponse, error) {
+ out := new(TopicEventResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.AppCallback/OnTopicEvent", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *appCallbackClient) ListInputBindings(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ListInputBindingsResponse, error) {
+ out := new(ListInputBindingsResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.AppCallback/ListInputBindings", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *appCallbackClient) OnBindingEvent(ctx context.Context, in *BindingEventRequest, opts ...grpc.CallOption) (*BindingEventResponse, error) {
+ out := new(BindingEventResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.AppCallback/OnBindingEvent", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// AppCallbackServer is the server API for AppCallback service.
+// All implementations should embed UnimplementedAppCallbackServer
+// for forward compatibility
+type AppCallbackServer interface {
+ // Invokes service method with InvokeRequest.
+ OnInvoke(context.Context, *v1.InvokeRequest) (*v1.InvokeResponse, error)
+ // Lists all topics subscribed by this app.
+ ListTopicSubscriptions(context.Context, *emptypb.Empty) (*ListTopicSubscriptionsResponse, error)
+ // Subscribes events from Pubsub
+ OnTopicEvent(context.Context, *TopicEventRequest) (*TopicEventResponse, error)
+ // Lists all input bindings subscribed by this app.
+ ListInputBindings(context.Context, *emptypb.Empty) (*ListInputBindingsResponse, error)
+ // Listens events from the input bindings
+ //
+ // User application can save the states or send the events to the output
+ // bindings optionally by returning BindingEventResponse.
+ OnBindingEvent(context.Context, *BindingEventRequest) (*BindingEventResponse, error)
+}
+
+// UnimplementedAppCallbackServer should be embedded to have forward compatible implementations.
+type UnimplementedAppCallbackServer struct {
+}
+
+func (UnimplementedAppCallbackServer) OnInvoke(context.Context, *v1.InvokeRequest) (*v1.InvokeResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method OnInvoke not implemented")
+}
+func (UnimplementedAppCallbackServer) ListTopicSubscriptions(context.Context, *emptypb.Empty) (*ListTopicSubscriptionsResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method ListTopicSubscriptions not implemented")
+}
+func (UnimplementedAppCallbackServer) OnTopicEvent(context.Context, *TopicEventRequest) (*TopicEventResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method OnTopicEvent not implemented")
+}
+func (UnimplementedAppCallbackServer) ListInputBindings(context.Context, *emptypb.Empty) (*ListInputBindingsResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method ListInputBindings not implemented")
+}
+func (UnimplementedAppCallbackServer) OnBindingEvent(context.Context, *BindingEventRequest) (*BindingEventResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method OnBindingEvent not implemented")
+}
+
+// UnsafeAppCallbackServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to AppCallbackServer will
+// result in compilation errors.
+type UnsafeAppCallbackServer interface {
+ mustEmbedUnimplementedAppCallbackServer()
+}
+
+func RegisterAppCallbackServer(s grpc.ServiceRegistrar, srv AppCallbackServer) {
+ s.RegisterService(&AppCallback_ServiceDesc, srv)
+}
+
+func _AppCallback_OnInvoke_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(v1.InvokeRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AppCallbackServer).OnInvoke(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.AppCallback/OnInvoke",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AppCallbackServer).OnInvoke(ctx, req.(*v1.InvokeRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _AppCallback_ListTopicSubscriptions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(emptypb.Empty)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AppCallbackServer).ListTopicSubscriptions(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.AppCallback/ListTopicSubscriptions",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AppCallbackServer).ListTopicSubscriptions(ctx, req.(*emptypb.Empty))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _AppCallback_OnTopicEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(TopicEventRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AppCallbackServer).OnTopicEvent(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.AppCallback/OnTopicEvent",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AppCallbackServer).OnTopicEvent(ctx, req.(*TopicEventRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _AppCallback_ListInputBindings_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(emptypb.Empty)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AppCallbackServer).ListInputBindings(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.AppCallback/ListInputBindings",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AppCallbackServer).ListInputBindings(ctx, req.(*emptypb.Empty))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _AppCallback_OnBindingEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(BindingEventRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AppCallbackServer).OnBindingEvent(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.AppCallback/OnBindingEvent",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AppCallbackServer).OnBindingEvent(ctx, req.(*BindingEventRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// AppCallback_ServiceDesc is the grpc.ServiceDesc for AppCallback service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var AppCallback_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "dapr.proto.runtime.v1.AppCallback",
+ HandlerType: (*AppCallbackServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "OnInvoke",
+ Handler: _AppCallback_OnInvoke_Handler,
+ },
+ {
+ MethodName: "ListTopicSubscriptions",
+ Handler: _AppCallback_ListTopicSubscriptions_Handler,
+ },
+ {
+ MethodName: "OnTopicEvent",
+ Handler: _AppCallback_OnTopicEvent_Handler,
+ },
+ {
+ MethodName: "ListInputBindings",
+ Handler: _AppCallback_ListInputBindings_Handler,
+ },
+ {
+ MethodName: "OnBindingEvent",
+ Handler: _AppCallback_OnBindingEvent_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "dapr/proto/runtime/v1/appcallback.proto",
+}
+
+// AppCallbackHealthCheckClient is the client API for AppCallbackHealthCheck service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type AppCallbackHealthCheckClient interface {
+ // Health check.
+ HealthCheck(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*HealthCheckResponse, error)
+}
+
+type appCallbackHealthCheckClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewAppCallbackHealthCheckClient(cc grpc.ClientConnInterface) AppCallbackHealthCheckClient {
+ return &appCallbackHealthCheckClient{cc}
+}
+
+func (c *appCallbackHealthCheckClient) HealthCheck(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*HealthCheckResponse, error) {
+ out := new(HealthCheckResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.AppCallbackHealthCheck/HealthCheck", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// AppCallbackHealthCheckServer is the server API for AppCallbackHealthCheck service.
+// All implementations should embed UnimplementedAppCallbackHealthCheckServer
+// for forward compatibility
+type AppCallbackHealthCheckServer interface {
+ // Health check.
+ HealthCheck(context.Context, *emptypb.Empty) (*HealthCheckResponse, error)
+}
+
+// UnimplementedAppCallbackHealthCheckServer should be embedded to have forward compatible implementations.
+type UnimplementedAppCallbackHealthCheckServer struct {
+}
+
+func (UnimplementedAppCallbackHealthCheckServer) HealthCheck(context.Context, *emptypb.Empty) (*HealthCheckResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method HealthCheck not implemented")
+}
+
+// UnsafeAppCallbackHealthCheckServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to AppCallbackHealthCheckServer will
+// result in compilation errors.
+type UnsafeAppCallbackHealthCheckServer interface {
+ mustEmbedUnimplementedAppCallbackHealthCheckServer()
+}
+
+func RegisterAppCallbackHealthCheckServer(s grpc.ServiceRegistrar, srv AppCallbackHealthCheckServer) {
+ s.RegisterService(&AppCallbackHealthCheck_ServiceDesc, srv)
+}
+
+func _AppCallbackHealthCheck_HealthCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(emptypb.Empty)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AppCallbackHealthCheckServer).HealthCheck(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.AppCallbackHealthCheck/HealthCheck",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AppCallbackHealthCheckServer).HealthCheck(ctx, req.(*emptypb.Empty))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// AppCallbackHealthCheck_ServiceDesc is the grpc.ServiceDesc for AppCallbackHealthCheck service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var AppCallbackHealthCheck_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "dapr.proto.runtime.v1.AppCallbackHealthCheck",
+ HandlerType: (*AppCallbackHealthCheckServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "HealthCheck",
+ Handler: _AppCallbackHealthCheck_HealthCheck_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "dapr/proto/runtime/v1/appcallback.proto",
+}
+
+// AppCallbackAlphaClient is the client API for AppCallbackAlpha service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type AppCallbackAlphaClient interface {
+ // Subscribes bulk events from Pubsub
+ OnBulkTopicEventAlpha1(ctx context.Context, in *TopicEventBulkRequest, opts ...grpc.CallOption) (*TopicEventBulkResponse, error)
+}
+
+type appCallbackAlphaClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewAppCallbackAlphaClient(cc grpc.ClientConnInterface) AppCallbackAlphaClient {
+ return &appCallbackAlphaClient{cc}
+}
+
+func (c *appCallbackAlphaClient) OnBulkTopicEventAlpha1(ctx context.Context, in *TopicEventBulkRequest, opts ...grpc.CallOption) (*TopicEventBulkResponse, error) {
+ out := new(TopicEventBulkResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.AppCallbackAlpha/OnBulkTopicEventAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// AppCallbackAlphaServer is the server API for AppCallbackAlpha service.
+// All implementations should embed UnimplementedAppCallbackAlphaServer
+// for forward compatibility
+type AppCallbackAlphaServer interface {
+ // Subscribes bulk events from Pubsub
+ OnBulkTopicEventAlpha1(context.Context, *TopicEventBulkRequest) (*TopicEventBulkResponse, error)
+}
+
+// UnimplementedAppCallbackAlphaServer should be embedded to have forward compatible implementations.
+type UnimplementedAppCallbackAlphaServer struct {
+}
+
+func (UnimplementedAppCallbackAlphaServer) OnBulkTopicEventAlpha1(context.Context, *TopicEventBulkRequest) (*TopicEventBulkResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method OnBulkTopicEventAlpha1 not implemented")
+}
+
+// UnsafeAppCallbackAlphaServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to AppCallbackAlphaServer will
+// result in compilation errors.
+type UnsafeAppCallbackAlphaServer interface {
+ mustEmbedUnimplementedAppCallbackAlphaServer()
+}
+
+func RegisterAppCallbackAlphaServer(s grpc.ServiceRegistrar, srv AppCallbackAlphaServer) {
+ s.RegisterService(&AppCallbackAlpha_ServiceDesc, srv)
+}
+
+func _AppCallbackAlpha_OnBulkTopicEventAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(TopicEventBulkRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AppCallbackAlphaServer).OnBulkTopicEventAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.AppCallbackAlpha/OnBulkTopicEventAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AppCallbackAlphaServer).OnBulkTopicEventAlpha1(ctx, req.(*TopicEventBulkRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// AppCallbackAlpha_ServiceDesc is the grpc.ServiceDesc for AppCallbackAlpha service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var AppCallbackAlpha_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "dapr.proto.runtime.v1.AppCallbackAlpha",
+ HandlerType: (*AppCallbackAlphaServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "OnBulkTopicEventAlpha1",
+ Handler: _AppCallbackAlpha_OnBulkTopicEventAlpha1_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "dapr/proto/runtime/v1/appcallback.proto",
+}
diff --git a/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/dapr.pb.go b/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/dapr.pb.go
new file mode 100644
index 00000000000..368d28ab0d1
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/dapr.pb.go
@@ -0,0 +1,8260 @@
+//
+//Copyright 2021 The Dapr Authors
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//http://www.apache.org/licenses/LICENSE-2.0
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.28.1
+// protoc v3.21.12
+// source: dapr/proto/runtime/v1/dapr.proto
+
+package runtime
+
+import (
+ v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ anypb "google.golang.org/protobuf/types/known/anypb"
+ emptypb "google.golang.org/protobuf/types/known/emptypb"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type UnlockResponse_Status int32
+
+const (
+ UnlockResponse_SUCCESS UnlockResponse_Status = 0
+ UnlockResponse_LOCK_DOES_NOT_EXIST UnlockResponse_Status = 1
+ UnlockResponse_LOCK_BELONGS_TO_OTHERS UnlockResponse_Status = 2
+ UnlockResponse_INTERNAL_ERROR UnlockResponse_Status = 3
+)
+
+// Enum value maps for UnlockResponse_Status.
+var (
+ UnlockResponse_Status_name = map[int32]string{
+ 0: "SUCCESS",
+ 1: "LOCK_DOES_NOT_EXIST",
+ 2: "LOCK_BELONGS_TO_OTHERS",
+ 3: "INTERNAL_ERROR",
+ }
+ UnlockResponse_Status_value = map[string]int32{
+ "SUCCESS": 0,
+ "LOCK_DOES_NOT_EXIST": 1,
+ "LOCK_BELONGS_TO_OTHERS": 2,
+ "INTERNAL_ERROR": 3,
+ }
+)
+
+func (x UnlockResponse_Status) Enum() *UnlockResponse_Status {
+ p := new(UnlockResponse_Status)
+ *p = x
+ return p
+}
+
+func (x UnlockResponse_Status) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (UnlockResponse_Status) Descriptor() protoreflect.EnumDescriptor {
+ return file_dapr_proto_runtime_v1_dapr_proto_enumTypes[0].Descriptor()
+}
+
+func (UnlockResponse_Status) Type() protoreflect.EnumType {
+ return &file_dapr_proto_runtime_v1_dapr_proto_enumTypes[0]
+}
+
+func (x UnlockResponse_Status) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use UnlockResponse_Status.Descriptor instead.
+func (UnlockResponse_Status) EnumDescriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{54, 0}
+}
+
+type SubtleGetKeyRequest_KeyFormat int32
+
+const (
+ // PEM (PKIX) (default)
+ SubtleGetKeyRequest_PEM SubtleGetKeyRequest_KeyFormat = 0
+ // JSON (JSON Web Key) as string
+ SubtleGetKeyRequest_JSON SubtleGetKeyRequest_KeyFormat = 1
+)
+
+// Enum value maps for SubtleGetKeyRequest_KeyFormat.
+var (
+ SubtleGetKeyRequest_KeyFormat_name = map[int32]string{
+ 0: "PEM",
+ 1: "JSON",
+ }
+ SubtleGetKeyRequest_KeyFormat_value = map[string]int32{
+ "PEM": 0,
+ "JSON": 1,
+ }
+)
+
+func (x SubtleGetKeyRequest_KeyFormat) Enum() *SubtleGetKeyRequest_KeyFormat {
+ p := new(SubtleGetKeyRequest_KeyFormat)
+ *p = x
+ return p
+}
+
+func (x SubtleGetKeyRequest_KeyFormat) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SubtleGetKeyRequest_KeyFormat) Descriptor() protoreflect.EnumDescriptor {
+ return file_dapr_proto_runtime_v1_dapr_proto_enumTypes[1].Descriptor()
+}
+
+func (SubtleGetKeyRequest_KeyFormat) Type() protoreflect.EnumType {
+ return &file_dapr_proto_runtime_v1_dapr_proto_enumTypes[1]
+}
+
+func (x SubtleGetKeyRequest_KeyFormat) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use SubtleGetKeyRequest_KeyFormat.Descriptor instead.
+func (SubtleGetKeyRequest_KeyFormat) EnumDescriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{55, 0}
+}
+
+// InvokeServiceRequest represents the request message for Service invocation.
+type InvokeServiceRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. Callee's app id.
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ // Required. message which will be delivered to callee.
+ Message *v1.InvokeRequest `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
+}
+
+func (x *InvokeServiceRequest) Reset() {
+ *x = InvokeServiceRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *InvokeServiceRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InvokeServiceRequest) ProtoMessage() {}
+
+func (x *InvokeServiceRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use InvokeServiceRequest.ProtoReflect.Descriptor instead.
+func (*InvokeServiceRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *InvokeServiceRequest) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *InvokeServiceRequest) GetMessage() *v1.InvokeRequest {
+ if x != nil {
+ return x.Message
+ }
+ return nil
+}
+
+// GetStateRequest is the message to get key-value states from specific state store.
+type GetStateRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of state store.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // The key of the desired state
+ Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
+ // The read consistency of the state store.
+ Consistency v1.StateOptions_StateConsistency `protobuf:"varint,3,opt,name=consistency,proto3,enum=dapr.proto.common.v1.StateOptions_StateConsistency" json:"consistency,omitempty"`
+ // The metadata which will be sent to state store components.
+ Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *GetStateRequest) Reset() {
+ *x = GetStateRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetStateRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetStateRequest) ProtoMessage() {}
+
+func (x *GetStateRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetStateRequest.ProtoReflect.Descriptor instead.
+func (*GetStateRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *GetStateRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *GetStateRequest) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+func (x *GetStateRequest) GetConsistency() v1.StateOptions_StateConsistency {
+ if x != nil {
+ return x.Consistency
+ }
+ return v1.StateOptions_StateConsistency(0)
+}
+
+func (x *GetStateRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// GetBulkStateRequest is the message to get a list of key-value states from specific state store.
+type GetBulkStateRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of state store.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // The keys to get.
+ Keys []string `protobuf:"bytes,2,rep,name=keys,proto3" json:"keys,omitempty"`
+ // The number of parallel operations executed on the state store for a get operation.
+ Parallelism int32 `protobuf:"varint,3,opt,name=parallelism,proto3" json:"parallelism,omitempty"`
+ // The metadata which will be sent to state store components.
+ Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *GetBulkStateRequest) Reset() {
+ *x = GetBulkStateRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetBulkStateRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetBulkStateRequest) ProtoMessage() {}
+
+func (x *GetBulkStateRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetBulkStateRequest.ProtoReflect.Descriptor instead.
+func (*GetBulkStateRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *GetBulkStateRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *GetBulkStateRequest) GetKeys() []string {
+ if x != nil {
+ return x.Keys
+ }
+ return nil
+}
+
+func (x *GetBulkStateRequest) GetParallelism() int32 {
+ if x != nil {
+ return x.Parallelism
+ }
+ return 0
+}
+
+func (x *GetBulkStateRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// GetBulkStateResponse is the response conveying the list of state values.
+type GetBulkStateResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The list of items containing the keys to get values for.
+ Items []*BulkStateItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"`
+}
+
+func (x *GetBulkStateResponse) Reset() {
+ *x = GetBulkStateResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetBulkStateResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetBulkStateResponse) ProtoMessage() {}
+
+func (x *GetBulkStateResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetBulkStateResponse.ProtoReflect.Descriptor instead.
+func (*GetBulkStateResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *GetBulkStateResponse) GetItems() []*BulkStateItem {
+ if x != nil {
+ return x.Items
+ }
+ return nil
+}
+
+// BulkStateItem is the response item for a bulk get operation.
+// Return values include the item key, data and etag.
+type BulkStateItem struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // state item key
+ Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
+ // The byte array data
+ Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+ // The entity tag which represents the specific version of data.
+ // ETag format is defined by the corresponding data store.
+ Etag string `protobuf:"bytes,3,opt,name=etag,proto3" json:"etag,omitempty"`
+ // The error that was returned from the state store in case of a failed get operation.
+ Error string `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"`
+ // The metadata which will be sent to app.
+ Metadata map[string]string `protobuf:"bytes,5,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *BulkStateItem) Reset() {
+ *x = BulkStateItem{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BulkStateItem) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BulkStateItem) ProtoMessage() {}
+
+func (x *BulkStateItem) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BulkStateItem.ProtoReflect.Descriptor instead.
+func (*BulkStateItem) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *BulkStateItem) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+func (x *BulkStateItem) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *BulkStateItem) GetEtag() string {
+ if x != nil {
+ return x.Etag
+ }
+ return ""
+}
+
+func (x *BulkStateItem) GetError() string {
+ if x != nil {
+ return x.Error
+ }
+ return ""
+}
+
+func (x *BulkStateItem) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// GetStateResponse is the response conveying the state value and etag.
+type GetStateResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The byte array data
+ Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+ // The entity tag which represents the specific version of data.
+ // ETag format is defined by the corresponding data store.
+ Etag string `protobuf:"bytes,2,opt,name=etag,proto3" json:"etag,omitempty"`
+ // The metadata which will be sent to app.
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *GetStateResponse) Reset() {
+ *x = GetStateResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetStateResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetStateResponse) ProtoMessage() {}
+
+func (x *GetStateResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetStateResponse.ProtoReflect.Descriptor instead.
+func (*GetStateResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *GetStateResponse) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *GetStateResponse) GetEtag() string {
+ if x != nil {
+ return x.Etag
+ }
+ return ""
+}
+
+func (x *GetStateResponse) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// DeleteStateRequest is the message to delete key-value states in the specific state store.
+type DeleteStateRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of state store.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // The key of the desired state
+ Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
+ // The entity tag which represents the specific version of data.
+ // The exact ETag format is defined by the corresponding data store.
+ Etag *v1.Etag `protobuf:"bytes,3,opt,name=etag,proto3" json:"etag,omitempty"`
+ // State operation options which includes concurrency/
+ // consistency/retry_policy.
+ Options *v1.StateOptions `protobuf:"bytes,4,opt,name=options,proto3" json:"options,omitempty"`
+ // The metadata which will be sent to state store components.
+ Metadata map[string]string `protobuf:"bytes,5,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *DeleteStateRequest) Reset() {
+ *x = DeleteStateRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DeleteStateRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteStateRequest) ProtoMessage() {}
+
+func (x *DeleteStateRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DeleteStateRequest.ProtoReflect.Descriptor instead.
+func (*DeleteStateRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *DeleteStateRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *DeleteStateRequest) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+func (x *DeleteStateRequest) GetEtag() *v1.Etag {
+ if x != nil {
+ return x.Etag
+ }
+ return nil
+}
+
+func (x *DeleteStateRequest) GetOptions() *v1.StateOptions {
+ if x != nil {
+ return x.Options
+ }
+ return nil
+}
+
+func (x *DeleteStateRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// DeleteBulkStateRequest is the message to delete a list of key-value states from specific state store.
+type DeleteBulkStateRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of state store.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // The array of the state key values.
+ States []*v1.StateItem `protobuf:"bytes,2,rep,name=states,proto3" json:"states,omitempty"`
+}
+
+func (x *DeleteBulkStateRequest) Reset() {
+ *x = DeleteBulkStateRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DeleteBulkStateRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteBulkStateRequest) ProtoMessage() {}
+
+func (x *DeleteBulkStateRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DeleteBulkStateRequest.ProtoReflect.Descriptor instead.
+func (*DeleteBulkStateRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *DeleteBulkStateRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *DeleteBulkStateRequest) GetStates() []*v1.StateItem {
+ if x != nil {
+ return x.States
+ }
+ return nil
+}
+
+// SaveStateRequest is the message to save multiple states into state store.
+type SaveStateRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of state store.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // The array of the state key values.
+ States []*v1.StateItem `protobuf:"bytes,2,rep,name=states,proto3" json:"states,omitempty"`
+}
+
+func (x *SaveStateRequest) Reset() {
+ *x = SaveStateRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SaveStateRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SaveStateRequest) ProtoMessage() {}
+
+func (x *SaveStateRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[8]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SaveStateRequest.ProtoReflect.Descriptor instead.
+func (*SaveStateRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *SaveStateRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *SaveStateRequest) GetStates() []*v1.StateItem {
+ if x != nil {
+ return x.States
+ }
+ return nil
+}
+
+// QueryStateRequest is the message to query state store.
+type QueryStateRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of state store.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // The query in JSON format.
+ Query string `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"`
+ // The metadata which will be sent to state store components.
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *QueryStateRequest) Reset() {
+ *x = QueryStateRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *QueryStateRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*QueryStateRequest) ProtoMessage() {}
+
+func (x *QueryStateRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use QueryStateRequest.ProtoReflect.Descriptor instead.
+func (*QueryStateRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *QueryStateRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *QueryStateRequest) GetQuery() string {
+ if x != nil {
+ return x.Query
+ }
+ return ""
+}
+
+func (x *QueryStateRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+type QueryStateItem struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The object key.
+ Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
+ // The object value.
+ Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+ // The entity tag which represents the specific version of data.
+ // ETag format is defined by the corresponding data store.
+ Etag string `protobuf:"bytes,3,opt,name=etag,proto3" json:"etag,omitempty"`
+ // The error message indicating an error in processing of the query result.
+ Error string `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"`
+}
+
+func (x *QueryStateItem) Reset() {
+ *x = QueryStateItem{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *QueryStateItem) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*QueryStateItem) ProtoMessage() {}
+
+func (x *QueryStateItem) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[10]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use QueryStateItem.ProtoReflect.Descriptor instead.
+func (*QueryStateItem) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *QueryStateItem) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+func (x *QueryStateItem) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *QueryStateItem) GetEtag() string {
+ if x != nil {
+ return x.Etag
+ }
+ return ""
+}
+
+func (x *QueryStateItem) GetError() string {
+ if x != nil {
+ return x.Error
+ }
+ return ""
+}
+
+// QueryStateResponse is the response conveying the query results.
+type QueryStateResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // An array of query results.
+ Results []*QueryStateItem `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"`
+ // Pagination token.
+ Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"`
+ // The metadata which will be sent to app.
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *QueryStateResponse) Reset() {
+ *x = QueryStateResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *QueryStateResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*QueryStateResponse) ProtoMessage() {}
+
+func (x *QueryStateResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[11]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use QueryStateResponse.ProtoReflect.Descriptor instead.
+func (*QueryStateResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *QueryStateResponse) GetResults() []*QueryStateItem {
+ if x != nil {
+ return x.Results
+ }
+ return nil
+}
+
+func (x *QueryStateResponse) GetToken() string {
+ if x != nil {
+ return x.Token
+ }
+ return ""
+}
+
+func (x *QueryStateResponse) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// PublishEventRequest is the message to publish event data to pubsub topic
+type PublishEventRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of the pubsub component
+ PubsubName string `protobuf:"bytes,1,opt,name=pubsub_name,json=pubsubName,proto3" json:"pubsub_name,omitempty"`
+ // The pubsub topic
+ Topic string `protobuf:"bytes,2,opt,name=topic,proto3" json:"topic,omitempty"`
+ // The data which will be published to topic.
+ Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
+ // The content type for the data (optional).
+ DataContentType string `protobuf:"bytes,4,opt,name=data_content_type,json=dataContentType,proto3" json:"data_content_type,omitempty"`
+ // The metadata passing to pub components
+ //
+ // metadata property:
+ // - key : the key of the message.
+ Metadata map[string]string `protobuf:"bytes,5,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *PublishEventRequest) Reset() {
+ *x = PublishEventRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PublishEventRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PublishEventRequest) ProtoMessage() {}
+
+func (x *PublishEventRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[12]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PublishEventRequest.ProtoReflect.Descriptor instead.
+func (*PublishEventRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *PublishEventRequest) GetPubsubName() string {
+ if x != nil {
+ return x.PubsubName
+ }
+ return ""
+}
+
+func (x *PublishEventRequest) GetTopic() string {
+ if x != nil {
+ return x.Topic
+ }
+ return ""
+}
+
+func (x *PublishEventRequest) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *PublishEventRequest) GetDataContentType() string {
+ if x != nil {
+ return x.DataContentType
+ }
+ return ""
+}
+
+func (x *PublishEventRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// BulkPublishRequest is the message to bulk publish events to pubsub topic
+type BulkPublishRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of the pubsub component
+ PubsubName string `protobuf:"bytes,1,opt,name=pubsub_name,json=pubsubName,proto3" json:"pubsub_name,omitempty"`
+ // The pubsub topic
+ Topic string `protobuf:"bytes,2,opt,name=topic,proto3" json:"topic,omitempty"`
+ // The entries which contain the individual events and associated details to be published
+ Entries []*BulkPublishRequestEntry `protobuf:"bytes,3,rep,name=entries,proto3" json:"entries,omitempty"`
+ // The request level metadata passing to to the pubsub components
+ Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *BulkPublishRequest) Reset() {
+ *x = BulkPublishRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BulkPublishRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BulkPublishRequest) ProtoMessage() {}
+
+func (x *BulkPublishRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[13]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BulkPublishRequest.ProtoReflect.Descriptor instead.
+func (*BulkPublishRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *BulkPublishRequest) GetPubsubName() string {
+ if x != nil {
+ return x.PubsubName
+ }
+ return ""
+}
+
+func (x *BulkPublishRequest) GetTopic() string {
+ if x != nil {
+ return x.Topic
+ }
+ return ""
+}
+
+func (x *BulkPublishRequest) GetEntries() []*BulkPublishRequestEntry {
+ if x != nil {
+ return x.Entries
+ }
+ return nil
+}
+
+func (x *BulkPublishRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// BulkPublishRequestEntry is the message containing the event to be bulk published
+type BulkPublishRequestEntry struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The request scoped unique ID referring to this message. Used to map status in response
+ EntryId string `protobuf:"bytes,1,opt,name=entry_id,json=entryId,proto3" json:"entry_id,omitempty"`
+ // The event which will be pulished to the topic
+ Event []byte `protobuf:"bytes,2,opt,name=event,proto3" json:"event,omitempty"`
+ // The content type for the event
+ ContentType string `protobuf:"bytes,3,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"`
+ // The event level metadata passing to the pubsub component
+ Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *BulkPublishRequestEntry) Reset() {
+ *x = BulkPublishRequestEntry{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BulkPublishRequestEntry) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BulkPublishRequestEntry) ProtoMessage() {}
+
+func (x *BulkPublishRequestEntry) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[14]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BulkPublishRequestEntry.ProtoReflect.Descriptor instead.
+func (*BulkPublishRequestEntry) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *BulkPublishRequestEntry) GetEntryId() string {
+ if x != nil {
+ return x.EntryId
+ }
+ return ""
+}
+
+func (x *BulkPublishRequestEntry) GetEvent() []byte {
+ if x != nil {
+ return x.Event
+ }
+ return nil
+}
+
+func (x *BulkPublishRequestEntry) GetContentType() string {
+ if x != nil {
+ return x.ContentType
+ }
+ return ""
+}
+
+func (x *BulkPublishRequestEntry) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// BulkPublishResponse is the message returned from a BulkPublishEvent call
+type BulkPublishResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The entries for different events that failed publish in the BulkPublishEvent call
+ FailedEntries []*BulkPublishResponseFailedEntry `protobuf:"bytes,1,rep,name=failedEntries,proto3" json:"failedEntries,omitempty"`
+}
+
+func (x *BulkPublishResponse) Reset() {
+ *x = BulkPublishResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[15]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BulkPublishResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BulkPublishResponse) ProtoMessage() {}
+
+func (x *BulkPublishResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[15]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BulkPublishResponse.ProtoReflect.Descriptor instead.
+func (*BulkPublishResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{15}
+}
+
+func (x *BulkPublishResponse) GetFailedEntries() []*BulkPublishResponseFailedEntry {
+ if x != nil {
+ return x.FailedEntries
+ }
+ return nil
+}
+
+// BulkPublishResponseFailedEntry is the message containing the entryID and error of a failed event in BulkPublishEvent call
+type BulkPublishResponseFailedEntry struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The response scoped unique ID referring to this message
+ EntryId string `protobuf:"bytes,1,opt,name=entry_id,json=entryId,proto3" json:"entry_id,omitempty"`
+ // The error message if any on failure
+ Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
+}
+
+func (x *BulkPublishResponseFailedEntry) Reset() {
+ *x = BulkPublishResponseFailedEntry{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[16]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BulkPublishResponseFailedEntry) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BulkPublishResponseFailedEntry) ProtoMessage() {}
+
+func (x *BulkPublishResponseFailedEntry) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[16]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BulkPublishResponseFailedEntry.ProtoReflect.Descriptor instead.
+func (*BulkPublishResponseFailedEntry) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{16}
+}
+
+func (x *BulkPublishResponseFailedEntry) GetEntryId() string {
+ if x != nil {
+ return x.EntryId
+ }
+ return ""
+}
+
+func (x *BulkPublishResponseFailedEntry) GetError() string {
+ if x != nil {
+ return x.Error
+ }
+ return ""
+}
+
+// InvokeBindingRequest is the message to send data to output bindings
+type InvokeBindingRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of the output binding to invoke.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // The data which will be sent to output binding.
+ Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+ // The metadata passing to output binding components
+ //
+ // Common metadata property:
+ // - ttlInSeconds : the time to live in seconds for the message.
+ // If set in the binding definition will cause all messages to
+ // have a default time to live. The message ttl overrides any value
+ // in the binding definition.
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // The name of the operation type for the binding to invoke
+ Operation string `protobuf:"bytes,4,opt,name=operation,proto3" json:"operation,omitempty"`
+}
+
+func (x *InvokeBindingRequest) Reset() {
+ *x = InvokeBindingRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[17]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *InvokeBindingRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InvokeBindingRequest) ProtoMessage() {}
+
+func (x *InvokeBindingRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[17]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use InvokeBindingRequest.ProtoReflect.Descriptor instead.
+func (*InvokeBindingRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{17}
+}
+
+func (x *InvokeBindingRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *InvokeBindingRequest) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *InvokeBindingRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+func (x *InvokeBindingRequest) GetOperation() string {
+ if x != nil {
+ return x.Operation
+ }
+ return ""
+}
+
+// InvokeBindingResponse is the message returned from an output binding invocation
+type InvokeBindingResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The data which will be sent to output binding.
+ Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+ // The metadata returned from an external system
+ Metadata map[string]string `protobuf:"bytes,2,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *InvokeBindingResponse) Reset() {
+ *x = InvokeBindingResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[18]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *InvokeBindingResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InvokeBindingResponse) ProtoMessage() {}
+
+func (x *InvokeBindingResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[18]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use InvokeBindingResponse.ProtoReflect.Descriptor instead.
+func (*InvokeBindingResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{18}
+}
+
+func (x *InvokeBindingResponse) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *InvokeBindingResponse) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// GetSecretRequest is the message to get secret from secret store.
+type GetSecretRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of secret store.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // The name of secret key.
+ Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
+ // The metadata which will be sent to secret store components.
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *GetSecretRequest) Reset() {
+ *x = GetSecretRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[19]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetSecretRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetSecretRequest) ProtoMessage() {}
+
+func (x *GetSecretRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[19]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetSecretRequest.ProtoReflect.Descriptor instead.
+func (*GetSecretRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{19}
+}
+
+func (x *GetSecretRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *GetSecretRequest) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+func (x *GetSecretRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// GetSecretResponse is the response message to convey the requested secret.
+type GetSecretResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // data is the secret value. Some secret store, such as kubernetes secret
+ // store, can save multiple secrets for single secret key.
+ Data map[string]string `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *GetSecretResponse) Reset() {
+ *x = GetSecretResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[20]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetSecretResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetSecretResponse) ProtoMessage() {}
+
+func (x *GetSecretResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[20]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetSecretResponse.ProtoReflect.Descriptor instead.
+func (*GetSecretResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *GetSecretResponse) GetData() map[string]string {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+// GetBulkSecretRequest is the message to get the secrets from secret store.
+type GetBulkSecretRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of secret store.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // The metadata which will be sent to secret store components.
+ Metadata map[string]string `protobuf:"bytes,2,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *GetBulkSecretRequest) Reset() {
+ *x = GetBulkSecretRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[21]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetBulkSecretRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetBulkSecretRequest) ProtoMessage() {}
+
+func (x *GetBulkSecretRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[21]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetBulkSecretRequest.ProtoReflect.Descriptor instead.
+func (*GetBulkSecretRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *GetBulkSecretRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *GetBulkSecretRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// SecretResponse is a map of decrypted string/string values
+type SecretResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Secrets map[string]string `protobuf:"bytes,1,rep,name=secrets,proto3" json:"secrets,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *SecretResponse) Reset() {
+ *x = SecretResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[22]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SecretResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SecretResponse) ProtoMessage() {}
+
+func (x *SecretResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[22]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SecretResponse.ProtoReflect.Descriptor instead.
+func (*SecretResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *SecretResponse) GetSecrets() map[string]string {
+ if x != nil {
+ return x.Secrets
+ }
+ return nil
+}
+
+// GetBulkSecretResponse is the response message to convey the requested secrets.
+type GetBulkSecretResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // data hold the secret values. Some secret store, such as kubernetes secret
+ // store, can save multiple secrets for single secret key.
+ Data map[string]*SecretResponse `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *GetBulkSecretResponse) Reset() {
+ *x = GetBulkSecretResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[23]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetBulkSecretResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetBulkSecretResponse) ProtoMessage() {}
+
+func (x *GetBulkSecretResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[23]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetBulkSecretResponse.ProtoReflect.Descriptor instead.
+func (*GetBulkSecretResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{23}
+}
+
+func (x *GetBulkSecretResponse) GetData() map[string]*SecretResponse {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+// TransactionalStateOperation is the message to execute a specified operation with a key-value pair.
+type TransactionalStateOperation struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The type of operation to be executed
+ OperationType string `protobuf:"bytes,1,opt,name=operationType,proto3" json:"operationType,omitempty"`
+ // State values to be operated on
+ Request *v1.StateItem `protobuf:"bytes,2,opt,name=request,proto3" json:"request,omitempty"`
+}
+
+func (x *TransactionalStateOperation) Reset() {
+ *x = TransactionalStateOperation{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[24]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TransactionalStateOperation) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TransactionalStateOperation) ProtoMessage() {}
+
+func (x *TransactionalStateOperation) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[24]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TransactionalStateOperation.ProtoReflect.Descriptor instead.
+func (*TransactionalStateOperation) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{24}
+}
+
+func (x *TransactionalStateOperation) GetOperationType() string {
+ if x != nil {
+ return x.OperationType
+ }
+ return ""
+}
+
+func (x *TransactionalStateOperation) GetRequest() *v1.StateItem {
+ if x != nil {
+ return x.Request
+ }
+ return nil
+}
+
+// ExecuteStateTransactionRequest is the message to execute multiple operations on a specified store.
+type ExecuteStateTransactionRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. name of state store.
+ StoreName string `protobuf:"bytes,1,opt,name=storeName,proto3" json:"storeName,omitempty"`
+ // Required. transactional operation list.
+ Operations []*TransactionalStateOperation `protobuf:"bytes,2,rep,name=operations,proto3" json:"operations,omitempty"`
+ // The metadata used for transactional operations.
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *ExecuteStateTransactionRequest) Reset() {
+ *x = ExecuteStateTransactionRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[25]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ExecuteStateTransactionRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExecuteStateTransactionRequest) ProtoMessage() {}
+
+func (x *ExecuteStateTransactionRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[25]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ExecuteStateTransactionRequest.ProtoReflect.Descriptor instead.
+func (*ExecuteStateTransactionRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{25}
+}
+
+func (x *ExecuteStateTransactionRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *ExecuteStateTransactionRequest) GetOperations() []*TransactionalStateOperation {
+ if x != nil {
+ return x.Operations
+ }
+ return nil
+}
+
+func (x *ExecuteStateTransactionRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// RegisterActorTimerRequest is the message to register a timer for an actor of a given type and id.
+type RegisterActorTimerRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ ActorType string `protobuf:"bytes,1,opt,name=actor_type,json=actorType,proto3" json:"actor_type,omitempty"`
+ ActorId string `protobuf:"bytes,2,opt,name=actor_id,json=actorId,proto3" json:"actor_id,omitempty"`
+ Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
+ DueTime string `protobuf:"bytes,4,opt,name=due_time,json=dueTime,proto3" json:"due_time,omitempty"`
+ Period string `protobuf:"bytes,5,opt,name=period,proto3" json:"period,omitempty"`
+ Callback string `protobuf:"bytes,6,opt,name=callback,proto3" json:"callback,omitempty"`
+ Data []byte `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"`
+ Ttl string `protobuf:"bytes,8,opt,name=ttl,proto3" json:"ttl,omitempty"`
+}
+
+func (x *RegisterActorTimerRequest) Reset() {
+ *x = RegisterActorTimerRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[26]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *RegisterActorTimerRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RegisterActorTimerRequest) ProtoMessage() {}
+
+func (x *RegisterActorTimerRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[26]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RegisterActorTimerRequest.ProtoReflect.Descriptor instead.
+func (*RegisterActorTimerRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{26}
+}
+
+func (x *RegisterActorTimerRequest) GetActorType() string {
+ if x != nil {
+ return x.ActorType
+ }
+ return ""
+}
+
+func (x *RegisterActorTimerRequest) GetActorId() string {
+ if x != nil {
+ return x.ActorId
+ }
+ return ""
+}
+
+func (x *RegisterActorTimerRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *RegisterActorTimerRequest) GetDueTime() string {
+ if x != nil {
+ return x.DueTime
+ }
+ return ""
+}
+
+func (x *RegisterActorTimerRequest) GetPeriod() string {
+ if x != nil {
+ return x.Period
+ }
+ return ""
+}
+
+func (x *RegisterActorTimerRequest) GetCallback() string {
+ if x != nil {
+ return x.Callback
+ }
+ return ""
+}
+
+func (x *RegisterActorTimerRequest) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *RegisterActorTimerRequest) GetTtl() string {
+ if x != nil {
+ return x.Ttl
+ }
+ return ""
+}
+
+// UnregisterActorTimerRequest is the message to unregister an actor timer
+type UnregisterActorTimerRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ ActorType string `protobuf:"bytes,1,opt,name=actor_type,json=actorType,proto3" json:"actor_type,omitempty"`
+ ActorId string `protobuf:"bytes,2,opt,name=actor_id,json=actorId,proto3" json:"actor_id,omitempty"`
+ Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *UnregisterActorTimerRequest) Reset() {
+ *x = UnregisterActorTimerRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[27]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UnregisterActorTimerRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnregisterActorTimerRequest) ProtoMessage() {}
+
+func (x *UnregisterActorTimerRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[27]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnregisterActorTimerRequest.ProtoReflect.Descriptor instead.
+func (*UnregisterActorTimerRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{27}
+}
+
+func (x *UnregisterActorTimerRequest) GetActorType() string {
+ if x != nil {
+ return x.ActorType
+ }
+ return ""
+}
+
+func (x *UnregisterActorTimerRequest) GetActorId() string {
+ if x != nil {
+ return x.ActorId
+ }
+ return ""
+}
+
+func (x *UnregisterActorTimerRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+// RegisterActorReminderRequest is the message to register a reminder for an actor of a given type and id.
+type RegisterActorReminderRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ ActorType string `protobuf:"bytes,1,opt,name=actor_type,json=actorType,proto3" json:"actor_type,omitempty"`
+ ActorId string `protobuf:"bytes,2,opt,name=actor_id,json=actorId,proto3" json:"actor_id,omitempty"`
+ Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
+ DueTime string `protobuf:"bytes,4,opt,name=due_time,json=dueTime,proto3" json:"due_time,omitempty"`
+ Period string `protobuf:"bytes,5,opt,name=period,proto3" json:"period,omitempty"`
+ Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"`
+ Ttl string `protobuf:"bytes,7,opt,name=ttl,proto3" json:"ttl,omitempty"`
+}
+
+func (x *RegisterActorReminderRequest) Reset() {
+ *x = RegisterActorReminderRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[28]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *RegisterActorReminderRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RegisterActorReminderRequest) ProtoMessage() {}
+
+func (x *RegisterActorReminderRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[28]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RegisterActorReminderRequest.ProtoReflect.Descriptor instead.
+func (*RegisterActorReminderRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{28}
+}
+
+func (x *RegisterActorReminderRequest) GetActorType() string {
+ if x != nil {
+ return x.ActorType
+ }
+ return ""
+}
+
+func (x *RegisterActorReminderRequest) GetActorId() string {
+ if x != nil {
+ return x.ActorId
+ }
+ return ""
+}
+
+func (x *RegisterActorReminderRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *RegisterActorReminderRequest) GetDueTime() string {
+ if x != nil {
+ return x.DueTime
+ }
+ return ""
+}
+
+func (x *RegisterActorReminderRequest) GetPeriod() string {
+ if x != nil {
+ return x.Period
+ }
+ return ""
+}
+
+func (x *RegisterActorReminderRequest) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *RegisterActorReminderRequest) GetTtl() string {
+ if x != nil {
+ return x.Ttl
+ }
+ return ""
+}
+
+// UnregisterActorReminderRequest is the message to unregister an actor reminder.
+type UnregisterActorReminderRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ ActorType string `protobuf:"bytes,1,opt,name=actor_type,json=actorType,proto3" json:"actor_type,omitempty"`
+ ActorId string `protobuf:"bytes,2,opt,name=actor_id,json=actorId,proto3" json:"actor_id,omitempty"`
+ Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *UnregisterActorReminderRequest) Reset() {
+ *x = UnregisterActorReminderRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[29]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UnregisterActorReminderRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnregisterActorReminderRequest) ProtoMessage() {}
+
+func (x *UnregisterActorReminderRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[29]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnregisterActorReminderRequest.ProtoReflect.Descriptor instead.
+func (*UnregisterActorReminderRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{29}
+}
+
+func (x *UnregisterActorReminderRequest) GetActorType() string {
+ if x != nil {
+ return x.ActorType
+ }
+ return ""
+}
+
+func (x *UnregisterActorReminderRequest) GetActorId() string {
+ if x != nil {
+ return x.ActorId
+ }
+ return ""
+}
+
+func (x *UnregisterActorReminderRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+// RenameActorReminderRequest is the message to rename an actor reminder.
+type RenameActorReminderRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ ActorType string `protobuf:"bytes,1,opt,name=actor_type,json=actorType,proto3" json:"actor_type,omitempty"`
+ ActorId string `protobuf:"bytes,2,opt,name=actor_id,json=actorId,proto3" json:"actor_id,omitempty"`
+ OldName string `protobuf:"bytes,3,opt,name=old_name,json=oldName,proto3" json:"old_name,omitempty"`
+ NewName string `protobuf:"bytes,4,opt,name=new_name,json=newName,proto3" json:"new_name,omitempty"`
+}
+
+func (x *RenameActorReminderRequest) Reset() {
+ *x = RenameActorReminderRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[30]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *RenameActorReminderRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RenameActorReminderRequest) ProtoMessage() {}
+
+func (x *RenameActorReminderRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[30]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RenameActorReminderRequest.ProtoReflect.Descriptor instead.
+func (*RenameActorReminderRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{30}
+}
+
+func (x *RenameActorReminderRequest) GetActorType() string {
+ if x != nil {
+ return x.ActorType
+ }
+ return ""
+}
+
+func (x *RenameActorReminderRequest) GetActorId() string {
+ if x != nil {
+ return x.ActorId
+ }
+ return ""
+}
+
+func (x *RenameActorReminderRequest) GetOldName() string {
+ if x != nil {
+ return x.OldName
+ }
+ return ""
+}
+
+func (x *RenameActorReminderRequest) GetNewName() string {
+ if x != nil {
+ return x.NewName
+ }
+ return ""
+}
+
+// GetActorStateRequest is the message to get key-value states from specific actor.
+type GetActorStateRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ ActorType string `protobuf:"bytes,1,opt,name=actor_type,json=actorType,proto3" json:"actor_type,omitempty"`
+ ActorId string `protobuf:"bytes,2,opt,name=actor_id,json=actorId,proto3" json:"actor_id,omitempty"`
+ Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
+}
+
+func (x *GetActorStateRequest) Reset() {
+ *x = GetActorStateRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[31]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetActorStateRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetActorStateRequest) ProtoMessage() {}
+
+func (x *GetActorStateRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[31]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetActorStateRequest.ProtoReflect.Descriptor instead.
+func (*GetActorStateRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{31}
+}
+
+func (x *GetActorStateRequest) GetActorType() string {
+ if x != nil {
+ return x.ActorType
+ }
+ return ""
+}
+
+func (x *GetActorStateRequest) GetActorId() string {
+ if x != nil {
+ return x.ActorId
+ }
+ return ""
+}
+
+func (x *GetActorStateRequest) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+// GetActorStateResponse is the response conveying the actor's state value.
+type GetActorStateResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+}
+
+func (x *GetActorStateResponse) Reset() {
+ *x = GetActorStateResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[32]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetActorStateResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetActorStateResponse) ProtoMessage() {}
+
+func (x *GetActorStateResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[32]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetActorStateResponse.ProtoReflect.Descriptor instead.
+func (*GetActorStateResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{32}
+}
+
+func (x *GetActorStateResponse) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+// ExecuteActorStateTransactionRequest is the message to execute multiple operations on a specified actor.
+type ExecuteActorStateTransactionRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ ActorType string `protobuf:"bytes,1,opt,name=actor_type,json=actorType,proto3" json:"actor_type,omitempty"`
+ ActorId string `protobuf:"bytes,2,opt,name=actor_id,json=actorId,proto3" json:"actor_id,omitempty"`
+ Operations []*TransactionalActorStateOperation `protobuf:"bytes,3,rep,name=operations,proto3" json:"operations,omitempty"`
+}
+
+func (x *ExecuteActorStateTransactionRequest) Reset() {
+ *x = ExecuteActorStateTransactionRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[33]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ExecuteActorStateTransactionRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExecuteActorStateTransactionRequest) ProtoMessage() {}
+
+func (x *ExecuteActorStateTransactionRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[33]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ExecuteActorStateTransactionRequest.ProtoReflect.Descriptor instead.
+func (*ExecuteActorStateTransactionRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{33}
+}
+
+func (x *ExecuteActorStateTransactionRequest) GetActorType() string {
+ if x != nil {
+ return x.ActorType
+ }
+ return ""
+}
+
+func (x *ExecuteActorStateTransactionRequest) GetActorId() string {
+ if x != nil {
+ return x.ActorId
+ }
+ return ""
+}
+
+func (x *ExecuteActorStateTransactionRequest) GetOperations() []*TransactionalActorStateOperation {
+ if x != nil {
+ return x.Operations
+ }
+ return nil
+}
+
+// TransactionalActorStateOperation is the message to execute a specified operation with a key-value pair.
+type TransactionalActorStateOperation struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ OperationType string `protobuf:"bytes,1,opt,name=operationType,proto3" json:"operationType,omitempty"`
+ Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
+ Value *anypb.Any `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"`
+ // The metadata used for transactional operations.
+ //
+ // Common metadata property:
+ // - ttlInSeconds : the time to live in seconds for the stored value.
+ Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *TransactionalActorStateOperation) Reset() {
+ *x = TransactionalActorStateOperation{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[34]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TransactionalActorStateOperation) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TransactionalActorStateOperation) ProtoMessage() {}
+
+func (x *TransactionalActorStateOperation) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[34]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TransactionalActorStateOperation.ProtoReflect.Descriptor instead.
+func (*TransactionalActorStateOperation) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{34}
+}
+
+func (x *TransactionalActorStateOperation) GetOperationType() string {
+ if x != nil {
+ return x.OperationType
+ }
+ return ""
+}
+
+func (x *TransactionalActorStateOperation) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+func (x *TransactionalActorStateOperation) GetValue() *anypb.Any {
+ if x != nil {
+ return x.Value
+ }
+ return nil
+}
+
+func (x *TransactionalActorStateOperation) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// InvokeActorRequest is the message to call an actor.
+type InvokeActorRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ ActorType string `protobuf:"bytes,1,opt,name=actor_type,json=actorType,proto3" json:"actor_type,omitempty"`
+ ActorId string `protobuf:"bytes,2,opt,name=actor_id,json=actorId,proto3" json:"actor_id,omitempty"`
+ Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"`
+ Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
+ Metadata map[string]string `protobuf:"bytes,5,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *InvokeActorRequest) Reset() {
+ *x = InvokeActorRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[35]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *InvokeActorRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InvokeActorRequest) ProtoMessage() {}
+
+func (x *InvokeActorRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[35]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use InvokeActorRequest.ProtoReflect.Descriptor instead.
+func (*InvokeActorRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{35}
+}
+
+func (x *InvokeActorRequest) GetActorType() string {
+ if x != nil {
+ return x.ActorType
+ }
+ return ""
+}
+
+func (x *InvokeActorRequest) GetActorId() string {
+ if x != nil {
+ return x.ActorId
+ }
+ return ""
+}
+
+func (x *InvokeActorRequest) GetMethod() string {
+ if x != nil {
+ return x.Method
+ }
+ return ""
+}
+
+func (x *InvokeActorRequest) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *InvokeActorRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// InvokeActorResponse is the method that returns an actor invocation response.
+type InvokeActorResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+}
+
+func (x *InvokeActorResponse) Reset() {
+ *x = InvokeActorResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[36]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *InvokeActorResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InvokeActorResponse) ProtoMessage() {}
+
+func (x *InvokeActorResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[36]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use InvokeActorResponse.ProtoReflect.Descriptor instead.
+func (*InvokeActorResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{36}
+}
+
+func (x *InvokeActorResponse) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+// GetMetadataResponse is a message that is returned on GetMetadata rpc call
+type GetMetadataResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ ActiveActorsCount []*ActiveActorsCount `protobuf:"bytes,2,rep,name=active_actors_count,json=actors,proto3" json:"active_actors_count,omitempty"`
+ RegisteredComponents []*RegisteredComponents `protobuf:"bytes,3,rep,name=registered_components,json=components,proto3" json:"registered_components,omitempty"`
+ ExtendedMetadata map[string]string `protobuf:"bytes,4,rep,name=extended_metadata,json=extended,proto3" json:"extended_metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ Subscriptions []*PubsubSubscription `protobuf:"bytes,5,rep,name=subscriptions,proto3" json:"subscriptions,omitempty"`
+ HttpEndpoints []*MetadataHTTPEndpoint `protobuf:"bytes,6,rep,name=http_endpoints,json=httpEndpoints,proto3" json:"http_endpoints,omitempty"`
+}
+
+func (x *GetMetadataResponse) Reset() {
+ *x = GetMetadataResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[37]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetMetadataResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetMetadataResponse) ProtoMessage() {}
+
+func (x *GetMetadataResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[37]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetMetadataResponse.ProtoReflect.Descriptor instead.
+func (*GetMetadataResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{37}
+}
+
+func (x *GetMetadataResponse) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *GetMetadataResponse) GetActiveActorsCount() []*ActiveActorsCount {
+ if x != nil {
+ return x.ActiveActorsCount
+ }
+ return nil
+}
+
+func (x *GetMetadataResponse) GetRegisteredComponents() []*RegisteredComponents {
+ if x != nil {
+ return x.RegisteredComponents
+ }
+ return nil
+}
+
+func (x *GetMetadataResponse) GetExtendedMetadata() map[string]string {
+ if x != nil {
+ return x.ExtendedMetadata
+ }
+ return nil
+}
+
+func (x *GetMetadataResponse) GetSubscriptions() []*PubsubSubscription {
+ if x != nil {
+ return x.Subscriptions
+ }
+ return nil
+}
+
+func (x *GetMetadataResponse) GetHttpEndpoints() []*MetadataHTTPEndpoint {
+ if x != nil {
+ return x.HttpEndpoints
+ }
+ return nil
+}
+
+type ActiveActorsCount struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
+ Count int32 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"`
+}
+
+func (x *ActiveActorsCount) Reset() {
+ *x = ActiveActorsCount{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[38]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ActiveActorsCount) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ActiveActorsCount) ProtoMessage() {}
+
+func (x *ActiveActorsCount) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[38]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ActiveActorsCount.ProtoReflect.Descriptor instead.
+func (*ActiveActorsCount) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{38}
+}
+
+func (x *ActiveActorsCount) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *ActiveActorsCount) GetCount() int32 {
+ if x != nil {
+ return x.Count
+ }
+ return 0
+}
+
+type RegisteredComponents struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+ Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"`
+ Capabilities []string `protobuf:"bytes,4,rep,name=capabilities,proto3" json:"capabilities,omitempty"`
+}
+
+func (x *RegisteredComponents) Reset() {
+ *x = RegisteredComponents{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[39]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *RegisteredComponents) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RegisteredComponents) ProtoMessage() {}
+
+func (x *RegisteredComponents) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[39]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RegisteredComponents.ProtoReflect.Descriptor instead.
+func (*RegisteredComponents) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{39}
+}
+
+func (x *RegisteredComponents) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *RegisteredComponents) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *RegisteredComponents) GetVersion() string {
+ if x != nil {
+ return x.Version
+ }
+ return ""
+}
+
+func (x *RegisteredComponents) GetCapabilities() []string {
+ if x != nil {
+ return x.Capabilities
+ }
+ return nil
+}
+
+type MetadataHTTPEndpoint struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *MetadataHTTPEndpoint) Reset() {
+ *x = MetadataHTTPEndpoint{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[40]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *MetadataHTTPEndpoint) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MetadataHTTPEndpoint) ProtoMessage() {}
+
+func (x *MetadataHTTPEndpoint) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[40]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use MetadataHTTPEndpoint.ProtoReflect.Descriptor instead.
+func (*MetadataHTTPEndpoint) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{40}
+}
+
+func (x *MetadataHTTPEndpoint) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+type PubsubSubscription struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ PubsubName string `protobuf:"bytes,1,opt,name=pubsub_name,json=pubsubname,proto3" json:"pubsub_name,omitempty"`
+ Topic string `protobuf:"bytes,2,opt,name=topic,proto3" json:"topic,omitempty"`
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ Rules *PubsubSubscriptionRules `protobuf:"bytes,4,opt,name=rules,proto3" json:"rules,omitempty"`
+ DeadLetterTopic string `protobuf:"bytes,5,opt,name=dead_letter_topic,json=deadLetterTopic,proto3" json:"dead_letter_topic,omitempty"`
+}
+
+func (x *PubsubSubscription) Reset() {
+ *x = PubsubSubscription{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[41]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PubsubSubscription) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PubsubSubscription) ProtoMessage() {}
+
+func (x *PubsubSubscription) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[41]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PubsubSubscription.ProtoReflect.Descriptor instead.
+func (*PubsubSubscription) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{41}
+}
+
+func (x *PubsubSubscription) GetPubsubName() string {
+ if x != nil {
+ return x.PubsubName
+ }
+ return ""
+}
+
+func (x *PubsubSubscription) GetTopic() string {
+ if x != nil {
+ return x.Topic
+ }
+ return ""
+}
+
+func (x *PubsubSubscription) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+func (x *PubsubSubscription) GetRules() *PubsubSubscriptionRules {
+ if x != nil {
+ return x.Rules
+ }
+ return nil
+}
+
+func (x *PubsubSubscription) GetDeadLetterTopic() string {
+ if x != nil {
+ return x.DeadLetterTopic
+ }
+ return ""
+}
+
+type PubsubSubscriptionRules struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Rules []*PubsubSubscriptionRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"`
+}
+
+func (x *PubsubSubscriptionRules) Reset() {
+ *x = PubsubSubscriptionRules{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[42]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PubsubSubscriptionRules) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PubsubSubscriptionRules) ProtoMessage() {}
+
+func (x *PubsubSubscriptionRules) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[42]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PubsubSubscriptionRules.ProtoReflect.Descriptor instead.
+func (*PubsubSubscriptionRules) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{42}
+}
+
+func (x *PubsubSubscriptionRules) GetRules() []*PubsubSubscriptionRule {
+ if x != nil {
+ return x.Rules
+ }
+ return nil
+}
+
+type PubsubSubscriptionRule struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Match string `protobuf:"bytes,1,opt,name=match,proto3" json:"match,omitempty"`
+ Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
+}
+
+func (x *PubsubSubscriptionRule) Reset() {
+ *x = PubsubSubscriptionRule{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[43]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PubsubSubscriptionRule) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PubsubSubscriptionRule) ProtoMessage() {}
+
+func (x *PubsubSubscriptionRule) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[43]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PubsubSubscriptionRule.ProtoReflect.Descriptor instead.
+func (*PubsubSubscriptionRule) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{43}
+}
+
+func (x *PubsubSubscriptionRule) GetMatch() string {
+ if x != nil {
+ return x.Match
+ }
+ return ""
+}
+
+func (x *PubsubSubscriptionRule) GetPath() string {
+ if x != nil {
+ return x.Path
+ }
+ return ""
+}
+
+type SetMetadataRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
+ Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
+}
+
+func (x *SetMetadataRequest) Reset() {
+ *x = SetMetadataRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[44]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SetMetadataRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SetMetadataRequest) ProtoMessage() {}
+
+func (x *SetMetadataRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[44]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SetMetadataRequest.ProtoReflect.Descriptor instead.
+func (*SetMetadataRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{44}
+}
+
+func (x *SetMetadataRequest) GetKey() string {
+ if x != nil {
+ return x.Key
+ }
+ return ""
+}
+
+func (x *SetMetadataRequest) GetValue() string {
+ if x != nil {
+ return x.Value
+ }
+ return ""
+}
+
+// GetConfigurationRequest is the message to get a list of key-value configuration from specified configuration store.
+type GetConfigurationRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of configuration store.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // Optional. The key of the configuration item to fetch.
+ // If set, only query for the specified configuration items.
+ // Empty list means fetch all.
+ Keys []string `protobuf:"bytes,2,rep,name=keys,proto3" json:"keys,omitempty"`
+ // Optional. The metadata which will be sent to configuration store components.
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *GetConfigurationRequest) Reset() {
+ *x = GetConfigurationRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[45]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetConfigurationRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetConfigurationRequest) ProtoMessage() {}
+
+func (x *GetConfigurationRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[45]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetConfigurationRequest.ProtoReflect.Descriptor instead.
+func (*GetConfigurationRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{45}
+}
+
+func (x *GetConfigurationRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *GetConfigurationRequest) GetKeys() []string {
+ if x != nil {
+ return x.Keys
+ }
+ return nil
+}
+
+func (x *GetConfigurationRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// GetConfigurationResponse is the response conveying the list of configuration values.
+// It should be the FULL configuration of specified application which contains all of its configuration items.
+type GetConfigurationResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Items map[string]*v1.ConfigurationItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *GetConfigurationResponse) Reset() {
+ *x = GetConfigurationResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[46]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetConfigurationResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetConfigurationResponse) ProtoMessage() {}
+
+func (x *GetConfigurationResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[46]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetConfigurationResponse.ProtoReflect.Descriptor instead.
+func (*GetConfigurationResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{46}
+}
+
+func (x *GetConfigurationResponse) GetItems() map[string]*v1.ConfigurationItem {
+ if x != nil {
+ return x.Items
+ }
+ return nil
+}
+
+// SubscribeConfigurationRequest is the message to get a list of key-value configuration from specified configuration store.
+type SubscribeConfigurationRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of configuration store.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // Optional. The key of the configuration item to fetch.
+ // If set, only query for the specified configuration items.
+ // Empty list means fetch all.
+ Keys []string `protobuf:"bytes,2,rep,name=keys,proto3" json:"keys,omitempty"`
+ // The metadata which will be sent to configuration store components.
+ Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *SubscribeConfigurationRequest) Reset() {
+ *x = SubscribeConfigurationRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[47]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubscribeConfigurationRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubscribeConfigurationRequest) ProtoMessage() {}
+
+func (x *SubscribeConfigurationRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[47]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubscribeConfigurationRequest.ProtoReflect.Descriptor instead.
+func (*SubscribeConfigurationRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{47}
+}
+
+func (x *SubscribeConfigurationRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *SubscribeConfigurationRequest) GetKeys() []string {
+ if x != nil {
+ return x.Keys
+ }
+ return nil
+}
+
+func (x *SubscribeConfigurationRequest) GetMetadata() map[string]string {
+ if x != nil {
+ return x.Metadata
+ }
+ return nil
+}
+
+// UnSubscribeConfigurationRequest is the message to stop watching the key-value configuration.
+type UnsubscribeConfigurationRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of configuration store.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // The id to unsubscribe.
+ Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
+}
+
+func (x *UnsubscribeConfigurationRequest) Reset() {
+ *x = UnsubscribeConfigurationRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[48]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UnsubscribeConfigurationRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnsubscribeConfigurationRequest) ProtoMessage() {}
+
+func (x *UnsubscribeConfigurationRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[48]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnsubscribeConfigurationRequest.ProtoReflect.Descriptor instead.
+func (*UnsubscribeConfigurationRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{48}
+}
+
+func (x *UnsubscribeConfigurationRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *UnsubscribeConfigurationRequest) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+type SubscribeConfigurationResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Subscribe id, used to stop subscription.
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ // The list of items containing configuration values
+ Items map[string]*v1.ConfigurationItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *SubscribeConfigurationResponse) Reset() {
+ *x = SubscribeConfigurationResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[49]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubscribeConfigurationResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubscribeConfigurationResponse) ProtoMessage() {}
+
+func (x *SubscribeConfigurationResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[49]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubscribeConfigurationResponse.ProtoReflect.Descriptor instead.
+func (*SubscribeConfigurationResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{49}
+}
+
+func (x *SubscribeConfigurationResponse) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *SubscribeConfigurationResponse) GetItems() map[string]*v1.ConfigurationItem {
+ if x != nil {
+ return x.Items
+ }
+ return nil
+}
+
+type UnsubscribeConfigurationResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
+ Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
+}
+
+func (x *UnsubscribeConfigurationResponse) Reset() {
+ *x = UnsubscribeConfigurationResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[50]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UnsubscribeConfigurationResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnsubscribeConfigurationResponse) ProtoMessage() {}
+
+func (x *UnsubscribeConfigurationResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[50]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnsubscribeConfigurationResponse.ProtoReflect.Descriptor instead.
+func (*UnsubscribeConfigurationResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{50}
+}
+
+func (x *UnsubscribeConfigurationResponse) GetOk() bool {
+ if x != nil {
+ return x.Ok
+ }
+ return false
+}
+
+func (x *UnsubscribeConfigurationResponse) GetMessage() string {
+ if x != nil {
+ return x.Message
+ }
+ return ""
+}
+
+type TryLockRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The lock store name,e.g. `redis`.
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // Required. resource_id is the lock key. e.g. `order_id_111`
+ // It stands for "which resource I want to protect"
+ ResourceId string `protobuf:"bytes,2,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"`
+ // Required. lock_owner indicate the identifier of lock owner.
+ // You can generate a uuid as lock_owner.For example,in golang:
+ //
+ // req.LockOwner = uuid.New().String()
+ //
+ // This field is per request,not per process,so it is different for each request,
+ // which aims to prevent multi-thread in the same process trying the same lock concurrently.
+ //
+ // The reason why we don't make it automatically generated is:
+ // 1. If it is automatically generated,there must be a 'my_lock_owner_id' field in the response.
+ // This name is so weird that we think it is inappropriate to put it into the api spec
+ // 2. If we change the field 'my_lock_owner_id' in the response to 'lock_owner',which means the current lock owner of this lock,
+ // we find that in some lock services users can't get the current lock owner.Actually users don't need it at all.
+ // 3. When reentrant lock is needed,the existing lock_owner is required to identify client and check "whether this client can reenter this lock".
+ // So this field in the request shouldn't be removed.
+ LockOwner string `protobuf:"bytes,3,opt,name=lock_owner,json=lockOwner,proto3" json:"lock_owner,omitempty"`
+ // Required. The time before expiry.The time unit is second.
+ ExpiryInSeconds int32 `protobuf:"varint,4,opt,name=expiry_in_seconds,json=expiryInSeconds,proto3" json:"expiry_in_seconds,omitempty"`
+}
+
+func (x *TryLockRequest) Reset() {
+ *x = TryLockRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[51]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TryLockRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TryLockRequest) ProtoMessage() {}
+
+func (x *TryLockRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[51]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TryLockRequest.ProtoReflect.Descriptor instead.
+func (*TryLockRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{51}
+}
+
+func (x *TryLockRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *TryLockRequest) GetResourceId() string {
+ if x != nil {
+ return x.ResourceId
+ }
+ return ""
+}
+
+func (x *TryLockRequest) GetLockOwner() string {
+ if x != nil {
+ return x.LockOwner
+ }
+ return ""
+}
+
+func (x *TryLockRequest) GetExpiryInSeconds() int32 {
+ if x != nil {
+ return x.ExpiryInSeconds
+ }
+ return 0
+}
+
+type TryLockResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
+}
+
+func (x *TryLockResponse) Reset() {
+ *x = TryLockResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[52]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TryLockResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TryLockResponse) ProtoMessage() {}
+
+func (x *TryLockResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[52]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TryLockResponse.ProtoReflect.Descriptor instead.
+func (*TryLockResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{52}
+}
+
+func (x *TryLockResponse) GetSuccess() bool {
+ if x != nil {
+ return x.Success
+ }
+ return false
+}
+
+type UnlockRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ StoreName string `protobuf:"bytes,1,opt,name=store_name,json=storeName,proto3" json:"store_name,omitempty"`
+ // resource_id is the lock key.
+ ResourceId string `protobuf:"bytes,2,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"`
+ LockOwner string `protobuf:"bytes,3,opt,name=lock_owner,json=lockOwner,proto3" json:"lock_owner,omitempty"`
+}
+
+func (x *UnlockRequest) Reset() {
+ *x = UnlockRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[53]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UnlockRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnlockRequest) ProtoMessage() {}
+
+func (x *UnlockRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[53]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnlockRequest.ProtoReflect.Descriptor instead.
+func (*UnlockRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{53}
+}
+
+func (x *UnlockRequest) GetStoreName() string {
+ if x != nil {
+ return x.StoreName
+ }
+ return ""
+}
+
+func (x *UnlockRequest) GetResourceId() string {
+ if x != nil {
+ return x.ResourceId
+ }
+ return ""
+}
+
+func (x *UnlockRequest) GetLockOwner() string {
+ if x != nil {
+ return x.LockOwner
+ }
+ return ""
+}
+
+type UnlockResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Status UnlockResponse_Status `protobuf:"varint,1,opt,name=status,proto3,enum=dapr.proto.runtime.v1.UnlockResponse_Status" json:"status,omitempty"`
+}
+
+func (x *UnlockResponse) Reset() {
+ *x = UnlockResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[54]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UnlockResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnlockResponse) ProtoMessage() {}
+
+func (x *UnlockResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[54]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnlockResponse.ProtoReflect.Descriptor instead.
+func (*UnlockResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{54}
+}
+
+func (x *UnlockResponse) GetStatus() UnlockResponse_Status {
+ if x != nil {
+ return x.Status
+ }
+ return UnlockResponse_SUCCESS
+}
+
+// SubtleGetKeyRequest is the request object for SubtleGetKeyAlpha1.
+type SubtleGetKeyRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name of the component
+ ComponentName string `protobuf:"bytes,1,opt,name=component_name,json=componentName,proto3" json:"component_name,omitempty"`
+ // Name (or name/version) of the key to use in the key vault
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ // Response format
+ Format SubtleGetKeyRequest_KeyFormat `protobuf:"varint,3,opt,name=format,proto3,enum=dapr.proto.runtime.v1.SubtleGetKeyRequest_KeyFormat" json:"format,omitempty"`
+}
+
+func (x *SubtleGetKeyRequest) Reset() {
+ *x = SubtleGetKeyRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[55]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleGetKeyRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleGetKeyRequest) ProtoMessage() {}
+
+func (x *SubtleGetKeyRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[55]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleGetKeyRequest.ProtoReflect.Descriptor instead.
+func (*SubtleGetKeyRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{55}
+}
+
+func (x *SubtleGetKeyRequest) GetComponentName() string {
+ if x != nil {
+ return x.ComponentName
+ }
+ return ""
+}
+
+func (x *SubtleGetKeyRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *SubtleGetKeyRequest) GetFormat() SubtleGetKeyRequest_KeyFormat {
+ if x != nil {
+ return x.Format
+ }
+ return SubtleGetKeyRequest_PEM
+}
+
+// SubtleGetKeyResponse is the response for SubtleGetKeyAlpha1.
+type SubtleGetKeyResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name (or name/version) of the key.
+ // This is returned as response too in case there is a version.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Public key, encoded in the requested format
+ PublicKey string `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
+}
+
+func (x *SubtleGetKeyResponse) Reset() {
+ *x = SubtleGetKeyResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[56]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleGetKeyResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleGetKeyResponse) ProtoMessage() {}
+
+func (x *SubtleGetKeyResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[56]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleGetKeyResponse.ProtoReflect.Descriptor instead.
+func (*SubtleGetKeyResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{56}
+}
+
+func (x *SubtleGetKeyResponse) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *SubtleGetKeyResponse) GetPublicKey() string {
+ if x != nil {
+ return x.PublicKey
+ }
+ return ""
+}
+
+// SubtleEncryptRequest is the request for SubtleEncryptAlpha1.
+type SubtleEncryptRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name of the component
+ ComponentName string `protobuf:"bytes,1,opt,name=component_name,json=componentName,proto3" json:"component_name,omitempty"`
+ // Message to encrypt.
+ Plaintext []byte `protobuf:"bytes,2,opt,name=plaintext,proto3" json:"plaintext,omitempty"`
+ // Algorithm to use, as in the JWA standard.
+ Algorithm string `protobuf:"bytes,3,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
+ // Name (or name/version) of the key.
+ KeyName string `protobuf:"bytes,4,opt,name=key_name,json=keyName,proto3" json:"key_name,omitempty"`
+ // Nonce / initialization vector.
+ // Ignored with asymmetric ciphers.
+ Nonce []byte `protobuf:"bytes,5,opt,name=nonce,proto3" json:"nonce,omitempty"`
+ // Associated Data when using AEAD ciphers (optional).
+ AssociatedData []byte `protobuf:"bytes,6,opt,name=associated_data,json=associatedData,proto3" json:"associated_data,omitempty"`
+}
+
+func (x *SubtleEncryptRequest) Reset() {
+ *x = SubtleEncryptRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[57]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleEncryptRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleEncryptRequest) ProtoMessage() {}
+
+func (x *SubtleEncryptRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[57]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleEncryptRequest.ProtoReflect.Descriptor instead.
+func (*SubtleEncryptRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{57}
+}
+
+func (x *SubtleEncryptRequest) GetComponentName() string {
+ if x != nil {
+ return x.ComponentName
+ }
+ return ""
+}
+
+func (x *SubtleEncryptRequest) GetPlaintext() []byte {
+ if x != nil {
+ return x.Plaintext
+ }
+ return nil
+}
+
+func (x *SubtleEncryptRequest) GetAlgorithm() string {
+ if x != nil {
+ return x.Algorithm
+ }
+ return ""
+}
+
+func (x *SubtleEncryptRequest) GetKeyName() string {
+ if x != nil {
+ return x.KeyName
+ }
+ return ""
+}
+
+func (x *SubtleEncryptRequest) GetNonce() []byte {
+ if x != nil {
+ return x.Nonce
+ }
+ return nil
+}
+
+func (x *SubtleEncryptRequest) GetAssociatedData() []byte {
+ if x != nil {
+ return x.AssociatedData
+ }
+ return nil
+}
+
+// SubtleEncryptResponse is the response for SubtleEncryptAlpha1.
+type SubtleEncryptResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Encrypted ciphertext.
+ Ciphertext []byte `protobuf:"bytes,1,opt,name=ciphertext,proto3" json:"ciphertext,omitempty"`
+ // Authentication tag.
+ // This is nil when not using an authenticated cipher.
+ Tag []byte `protobuf:"bytes,2,opt,name=tag,proto3" json:"tag,omitempty"`
+}
+
+func (x *SubtleEncryptResponse) Reset() {
+ *x = SubtleEncryptResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[58]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleEncryptResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleEncryptResponse) ProtoMessage() {}
+
+func (x *SubtleEncryptResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[58]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleEncryptResponse.ProtoReflect.Descriptor instead.
+func (*SubtleEncryptResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{58}
+}
+
+func (x *SubtleEncryptResponse) GetCiphertext() []byte {
+ if x != nil {
+ return x.Ciphertext
+ }
+ return nil
+}
+
+func (x *SubtleEncryptResponse) GetTag() []byte {
+ if x != nil {
+ return x.Tag
+ }
+ return nil
+}
+
+// SubtleDecryptRequest is the request for SubtleDecryptAlpha1.
+type SubtleDecryptRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name of the component
+ ComponentName string `protobuf:"bytes,1,opt,name=component_name,json=componentName,proto3" json:"component_name,omitempty"`
+ // Message to decrypt.
+ Ciphertext []byte `protobuf:"bytes,2,opt,name=ciphertext,proto3" json:"ciphertext,omitempty"`
+ // Algorithm to use, as in the JWA standard.
+ Algorithm string `protobuf:"bytes,3,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
+ // Name (or name/version) of the key.
+ KeyName string `protobuf:"bytes,4,opt,name=key_name,json=keyName,proto3" json:"key_name,omitempty"`
+ // Nonce / initialization vector.
+ // Ignored with asymmetric ciphers.
+ Nonce []byte `protobuf:"bytes,5,opt,name=nonce,proto3" json:"nonce,omitempty"`
+ // Authentication tag.
+ // This is nil when not using an authenticated cipher.
+ Tag []byte `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
+ // Associated Data when using AEAD ciphers (optional).
+ AssociatedData []byte `protobuf:"bytes,7,opt,name=associated_data,json=associatedData,proto3" json:"associated_data,omitempty"`
+}
+
+func (x *SubtleDecryptRequest) Reset() {
+ *x = SubtleDecryptRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[59]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleDecryptRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleDecryptRequest) ProtoMessage() {}
+
+func (x *SubtleDecryptRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[59]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleDecryptRequest.ProtoReflect.Descriptor instead.
+func (*SubtleDecryptRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{59}
+}
+
+func (x *SubtleDecryptRequest) GetComponentName() string {
+ if x != nil {
+ return x.ComponentName
+ }
+ return ""
+}
+
+func (x *SubtleDecryptRequest) GetCiphertext() []byte {
+ if x != nil {
+ return x.Ciphertext
+ }
+ return nil
+}
+
+func (x *SubtleDecryptRequest) GetAlgorithm() string {
+ if x != nil {
+ return x.Algorithm
+ }
+ return ""
+}
+
+func (x *SubtleDecryptRequest) GetKeyName() string {
+ if x != nil {
+ return x.KeyName
+ }
+ return ""
+}
+
+func (x *SubtleDecryptRequest) GetNonce() []byte {
+ if x != nil {
+ return x.Nonce
+ }
+ return nil
+}
+
+func (x *SubtleDecryptRequest) GetTag() []byte {
+ if x != nil {
+ return x.Tag
+ }
+ return nil
+}
+
+func (x *SubtleDecryptRequest) GetAssociatedData() []byte {
+ if x != nil {
+ return x.AssociatedData
+ }
+ return nil
+}
+
+// SubtleDecryptResponse is the response for SubtleDecryptAlpha1.
+type SubtleDecryptResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Decrypted plaintext.
+ Plaintext []byte `protobuf:"bytes,1,opt,name=plaintext,proto3" json:"plaintext,omitempty"`
+}
+
+func (x *SubtleDecryptResponse) Reset() {
+ *x = SubtleDecryptResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[60]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleDecryptResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleDecryptResponse) ProtoMessage() {}
+
+func (x *SubtleDecryptResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[60]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleDecryptResponse.ProtoReflect.Descriptor instead.
+func (*SubtleDecryptResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{60}
+}
+
+func (x *SubtleDecryptResponse) GetPlaintext() []byte {
+ if x != nil {
+ return x.Plaintext
+ }
+ return nil
+}
+
+// SubtleWrapKeyRequest is the request for SubtleWrapKeyAlpha1.
+type SubtleWrapKeyRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name of the component
+ ComponentName string `protobuf:"bytes,1,opt,name=component_name,json=componentName,proto3" json:"component_name,omitempty"`
+ // Key to wrap
+ PlaintextKey []byte `protobuf:"bytes,2,opt,name=plaintext_key,json=plaintextKey,proto3" json:"plaintext_key,omitempty"`
+ // Algorithm to use, as in the JWA standard.
+ Algorithm string `protobuf:"bytes,3,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
+ // Name (or name/version) of the key.
+ KeyName string `protobuf:"bytes,4,opt,name=key_name,json=keyName,proto3" json:"key_name,omitempty"`
+ // Nonce / initialization vector.
+ // Ignored with asymmetric ciphers.
+ Nonce []byte `protobuf:"bytes,5,opt,name=nonce,proto3" json:"nonce,omitempty"`
+ // Associated Data when using AEAD ciphers (optional).
+ AssociatedData []byte `protobuf:"bytes,6,opt,name=associated_data,json=associatedData,proto3" json:"associated_data,omitempty"`
+}
+
+func (x *SubtleWrapKeyRequest) Reset() {
+ *x = SubtleWrapKeyRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[61]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleWrapKeyRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleWrapKeyRequest) ProtoMessage() {}
+
+func (x *SubtleWrapKeyRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[61]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleWrapKeyRequest.ProtoReflect.Descriptor instead.
+func (*SubtleWrapKeyRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{61}
+}
+
+func (x *SubtleWrapKeyRequest) GetComponentName() string {
+ if x != nil {
+ return x.ComponentName
+ }
+ return ""
+}
+
+func (x *SubtleWrapKeyRequest) GetPlaintextKey() []byte {
+ if x != nil {
+ return x.PlaintextKey
+ }
+ return nil
+}
+
+func (x *SubtleWrapKeyRequest) GetAlgorithm() string {
+ if x != nil {
+ return x.Algorithm
+ }
+ return ""
+}
+
+func (x *SubtleWrapKeyRequest) GetKeyName() string {
+ if x != nil {
+ return x.KeyName
+ }
+ return ""
+}
+
+func (x *SubtleWrapKeyRequest) GetNonce() []byte {
+ if x != nil {
+ return x.Nonce
+ }
+ return nil
+}
+
+func (x *SubtleWrapKeyRequest) GetAssociatedData() []byte {
+ if x != nil {
+ return x.AssociatedData
+ }
+ return nil
+}
+
+// SubtleWrapKeyResponse is the response for SubtleWrapKeyAlpha1.
+type SubtleWrapKeyResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Wrapped key.
+ WrappedKey []byte `protobuf:"bytes,1,opt,name=wrapped_key,json=wrappedKey,proto3" json:"wrapped_key,omitempty"`
+ // Authentication tag.
+ // This is nil when not using an authenticated cipher.
+ Tag []byte `protobuf:"bytes,2,opt,name=tag,proto3" json:"tag,omitempty"`
+}
+
+func (x *SubtleWrapKeyResponse) Reset() {
+ *x = SubtleWrapKeyResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[62]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleWrapKeyResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleWrapKeyResponse) ProtoMessage() {}
+
+func (x *SubtleWrapKeyResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[62]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleWrapKeyResponse.ProtoReflect.Descriptor instead.
+func (*SubtleWrapKeyResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{62}
+}
+
+func (x *SubtleWrapKeyResponse) GetWrappedKey() []byte {
+ if x != nil {
+ return x.WrappedKey
+ }
+ return nil
+}
+
+func (x *SubtleWrapKeyResponse) GetTag() []byte {
+ if x != nil {
+ return x.Tag
+ }
+ return nil
+}
+
+// SubtleUnwrapKeyRequest is the request for SubtleUnwrapKeyAlpha1.
+type SubtleUnwrapKeyRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name of the component
+ ComponentName string `protobuf:"bytes,1,opt,name=component_name,json=componentName,proto3" json:"component_name,omitempty"`
+ // Wrapped key.
+ WrappedKey []byte `protobuf:"bytes,2,opt,name=wrapped_key,json=wrappedKey,proto3" json:"wrapped_key,omitempty"`
+ // Algorithm to use, as in the JWA standard.
+ Algorithm string `protobuf:"bytes,3,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
+ // Name (or name/version) of the key.
+ KeyName string `protobuf:"bytes,4,opt,name=key_name,json=keyName,proto3" json:"key_name,omitempty"`
+ // Nonce / initialization vector.
+ // Ignored with asymmetric ciphers.
+ Nonce []byte `protobuf:"bytes,5,opt,name=nonce,proto3" json:"nonce,omitempty"`
+ // Authentication tag.
+ // This is nil when not using an authenticated cipher.
+ Tag []byte `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
+ // Associated Data when using AEAD ciphers (optional).
+ AssociatedData []byte `protobuf:"bytes,7,opt,name=associated_data,json=associatedData,proto3" json:"associated_data,omitempty"`
+}
+
+func (x *SubtleUnwrapKeyRequest) Reset() {
+ *x = SubtleUnwrapKeyRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[63]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleUnwrapKeyRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleUnwrapKeyRequest) ProtoMessage() {}
+
+func (x *SubtleUnwrapKeyRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[63]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleUnwrapKeyRequest.ProtoReflect.Descriptor instead.
+func (*SubtleUnwrapKeyRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{63}
+}
+
+func (x *SubtleUnwrapKeyRequest) GetComponentName() string {
+ if x != nil {
+ return x.ComponentName
+ }
+ return ""
+}
+
+func (x *SubtleUnwrapKeyRequest) GetWrappedKey() []byte {
+ if x != nil {
+ return x.WrappedKey
+ }
+ return nil
+}
+
+func (x *SubtleUnwrapKeyRequest) GetAlgorithm() string {
+ if x != nil {
+ return x.Algorithm
+ }
+ return ""
+}
+
+func (x *SubtleUnwrapKeyRequest) GetKeyName() string {
+ if x != nil {
+ return x.KeyName
+ }
+ return ""
+}
+
+func (x *SubtleUnwrapKeyRequest) GetNonce() []byte {
+ if x != nil {
+ return x.Nonce
+ }
+ return nil
+}
+
+func (x *SubtleUnwrapKeyRequest) GetTag() []byte {
+ if x != nil {
+ return x.Tag
+ }
+ return nil
+}
+
+func (x *SubtleUnwrapKeyRequest) GetAssociatedData() []byte {
+ if x != nil {
+ return x.AssociatedData
+ }
+ return nil
+}
+
+// SubtleUnwrapKeyResponse is the response for SubtleUnwrapKeyAlpha1.
+type SubtleUnwrapKeyResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Key in plaintext
+ PlaintextKey []byte `protobuf:"bytes,1,opt,name=plaintext_key,json=plaintextKey,proto3" json:"plaintext_key,omitempty"`
+}
+
+func (x *SubtleUnwrapKeyResponse) Reset() {
+ *x = SubtleUnwrapKeyResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[64]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleUnwrapKeyResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleUnwrapKeyResponse) ProtoMessage() {}
+
+func (x *SubtleUnwrapKeyResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[64]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleUnwrapKeyResponse.ProtoReflect.Descriptor instead.
+func (*SubtleUnwrapKeyResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{64}
+}
+
+func (x *SubtleUnwrapKeyResponse) GetPlaintextKey() []byte {
+ if x != nil {
+ return x.PlaintextKey
+ }
+ return nil
+}
+
+// SubtleSignRequest is the request for SubtleSignAlpha1.
+type SubtleSignRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name of the component
+ ComponentName string `protobuf:"bytes,1,opt,name=component_name,json=componentName,proto3" json:"component_name,omitempty"`
+ // Digest to sign.
+ Digest []byte `protobuf:"bytes,2,opt,name=digest,proto3" json:"digest,omitempty"`
+ // Algorithm to use, as in the JWA standard.
+ Algorithm string `protobuf:"bytes,3,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
+ // Name (or name/version) of the key.
+ KeyName string `protobuf:"bytes,4,opt,name=key_name,json=keyName,proto3" json:"key_name,omitempty"`
+}
+
+func (x *SubtleSignRequest) Reset() {
+ *x = SubtleSignRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[65]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleSignRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleSignRequest) ProtoMessage() {}
+
+func (x *SubtleSignRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[65]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleSignRequest.ProtoReflect.Descriptor instead.
+func (*SubtleSignRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{65}
+}
+
+func (x *SubtleSignRequest) GetComponentName() string {
+ if x != nil {
+ return x.ComponentName
+ }
+ return ""
+}
+
+func (x *SubtleSignRequest) GetDigest() []byte {
+ if x != nil {
+ return x.Digest
+ }
+ return nil
+}
+
+func (x *SubtleSignRequest) GetAlgorithm() string {
+ if x != nil {
+ return x.Algorithm
+ }
+ return ""
+}
+
+func (x *SubtleSignRequest) GetKeyName() string {
+ if x != nil {
+ return x.KeyName
+ }
+ return ""
+}
+
+// SubtleSignResponse is the response for SubtleSignAlpha1.
+type SubtleSignResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The signature that was computed
+ Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"`
+}
+
+func (x *SubtleSignResponse) Reset() {
+ *x = SubtleSignResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[66]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleSignResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleSignResponse) ProtoMessage() {}
+
+func (x *SubtleSignResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[66]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleSignResponse.ProtoReflect.Descriptor instead.
+func (*SubtleSignResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{66}
+}
+
+func (x *SubtleSignResponse) GetSignature() []byte {
+ if x != nil {
+ return x.Signature
+ }
+ return nil
+}
+
+// SubtleVerifyRequest is the request for SubtleVerifyAlpha1.
+type SubtleVerifyRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name of the component
+ ComponentName string `protobuf:"bytes,1,opt,name=component_name,json=componentName,proto3" json:"component_name,omitempty"`
+ // Digest of the message.
+ Digest []byte `protobuf:"bytes,2,opt,name=digest,proto3" json:"digest,omitempty"`
+ // Algorithm to use, as in the JWA standard.
+ Algorithm string `protobuf:"bytes,3,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
+ // Name (or name/version) of the key.
+ KeyName string `protobuf:"bytes,4,opt,name=key_name,json=keyName,proto3" json:"key_name,omitempty"`
+ // Signature to verify.
+ Signature []byte `protobuf:"bytes,5,opt,name=signature,proto3" json:"signature,omitempty"`
+}
+
+func (x *SubtleVerifyRequest) Reset() {
+ *x = SubtleVerifyRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[67]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleVerifyRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleVerifyRequest) ProtoMessage() {}
+
+func (x *SubtleVerifyRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[67]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleVerifyRequest.ProtoReflect.Descriptor instead.
+func (*SubtleVerifyRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{67}
+}
+
+func (x *SubtleVerifyRequest) GetComponentName() string {
+ if x != nil {
+ return x.ComponentName
+ }
+ return ""
+}
+
+func (x *SubtleVerifyRequest) GetDigest() []byte {
+ if x != nil {
+ return x.Digest
+ }
+ return nil
+}
+
+func (x *SubtleVerifyRequest) GetAlgorithm() string {
+ if x != nil {
+ return x.Algorithm
+ }
+ return ""
+}
+
+func (x *SubtleVerifyRequest) GetKeyName() string {
+ if x != nil {
+ return x.KeyName
+ }
+ return ""
+}
+
+func (x *SubtleVerifyRequest) GetSignature() []byte {
+ if x != nil {
+ return x.Signature
+ }
+ return nil
+}
+
+// SubtleVerifyResponse is the response for SubtleVerifyAlpha1.
+type SubtleVerifyResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // True if the signature is valid.
+ Valid bool `protobuf:"varint,1,opt,name=valid,proto3" json:"valid,omitempty"`
+}
+
+func (x *SubtleVerifyResponse) Reset() {
+ *x = SubtleVerifyResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[68]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SubtleVerifyResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubtleVerifyResponse) ProtoMessage() {}
+
+func (x *SubtleVerifyResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[68]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubtleVerifyResponse.ProtoReflect.Descriptor instead.
+func (*SubtleVerifyResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{68}
+}
+
+func (x *SubtleVerifyResponse) GetValid() bool {
+ if x != nil {
+ return x.Valid
+ }
+ return false
+}
+
+// EncryptRequest is the request for EncryptAlpha1.
+type EncryptRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Request details. Must be present in the first message only.
+ Options *EncryptRequestOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"`
+ // Chunk of data of arbitrary size.
+ Payload *v1.StreamPayload `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
+}
+
+func (x *EncryptRequest) Reset() {
+ *x = EncryptRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[69]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *EncryptRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EncryptRequest) ProtoMessage() {}
+
+func (x *EncryptRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[69]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EncryptRequest.ProtoReflect.Descriptor instead.
+func (*EncryptRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{69}
+}
+
+func (x *EncryptRequest) GetOptions() *EncryptRequestOptions {
+ if x != nil {
+ return x.Options
+ }
+ return nil
+}
+
+func (x *EncryptRequest) GetPayload() *v1.StreamPayload {
+ if x != nil {
+ return x.Payload
+ }
+ return nil
+}
+
+// EncryptRequestOptions contains options for the first message in the EncryptAlpha1 request.
+type EncryptRequestOptions struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name of the component. Required.
+ ComponentName string `protobuf:"bytes,1,opt,name=component_name,json=componentName,proto3" json:"component_name,omitempty"`
+ // Name (or name/version) of the key. Required.
+ KeyName string `protobuf:"bytes,2,opt,name=key_name,json=keyName,proto3" json:"key_name,omitempty"`
+ // Key wrapping algorithm to use. Required.
+ // Supported options include: A256KW (alias: AES), A128CBC, A192CBC, A256CBC, RSA-OAEP-256 (alias: RSA).
+ KeyWrapAlgorithm string `protobuf:"bytes,3,opt,name=key_wrap_algorithm,json=keyWrapAlgorithm,proto3" json:"key_wrap_algorithm,omitempty"`
+ // Cipher used to encrypt data (optional): "aes-gcm" (default) or "chacha20-poly1305"
+ DataEncryptionCipher string `protobuf:"bytes,10,opt,name=data_encryption_cipher,json=dataEncryptionCipher,proto3" json:"data_encryption_cipher,omitempty"`
+ // If true, the encrypted document does not contain a key reference.
+ // In that case, calls to the Decrypt method must provide a key reference (name or name/version).
+ // Defaults to false.
+ OmitDecryptionKeyName bool `protobuf:"varint,11,opt,name=omit_decryption_key_name,json=omitDecryptionKeyName,proto3" json:"omit_decryption_key_name,omitempty"`
+ // Key reference to embed in the encrypted document (name or name/version).
+ // This is helpful if the reference of the key used to decrypt the document is different from the one used to encrypt it.
+ // If unset, uses the reference of the key used to encrypt the document (this is the default behavior).
+ // This option is ignored if omit_decryption_key_name is true.
+ DecryptionKeyName string `protobuf:"bytes,12,opt,name=decryption_key_name,json=decryptionKeyName,proto3" json:"decryption_key_name,omitempty"`
+}
+
+func (x *EncryptRequestOptions) Reset() {
+ *x = EncryptRequestOptions{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[70]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *EncryptRequestOptions) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EncryptRequestOptions) ProtoMessage() {}
+
+func (x *EncryptRequestOptions) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[70]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EncryptRequestOptions.ProtoReflect.Descriptor instead.
+func (*EncryptRequestOptions) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{70}
+}
+
+func (x *EncryptRequestOptions) GetComponentName() string {
+ if x != nil {
+ return x.ComponentName
+ }
+ return ""
+}
+
+func (x *EncryptRequestOptions) GetKeyName() string {
+ if x != nil {
+ return x.KeyName
+ }
+ return ""
+}
+
+func (x *EncryptRequestOptions) GetKeyWrapAlgorithm() string {
+ if x != nil {
+ return x.KeyWrapAlgorithm
+ }
+ return ""
+}
+
+func (x *EncryptRequestOptions) GetDataEncryptionCipher() string {
+ if x != nil {
+ return x.DataEncryptionCipher
+ }
+ return ""
+}
+
+func (x *EncryptRequestOptions) GetOmitDecryptionKeyName() bool {
+ if x != nil {
+ return x.OmitDecryptionKeyName
+ }
+ return false
+}
+
+func (x *EncryptRequestOptions) GetDecryptionKeyName() string {
+ if x != nil {
+ return x.DecryptionKeyName
+ }
+ return ""
+}
+
+// EncryptResponse is the response for EncryptAlpha1.
+type EncryptResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Chunk of data.
+ Payload *v1.StreamPayload `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
+}
+
+func (x *EncryptResponse) Reset() {
+ *x = EncryptResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[71]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *EncryptResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EncryptResponse) ProtoMessage() {}
+
+func (x *EncryptResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[71]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EncryptResponse.ProtoReflect.Descriptor instead.
+func (*EncryptResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{71}
+}
+
+func (x *EncryptResponse) GetPayload() *v1.StreamPayload {
+ if x != nil {
+ return x.Payload
+ }
+ return nil
+}
+
+// DecryptRequest is the request for DecryptAlpha1.
+type DecryptRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Request details. Must be present in the first message only.
+ Options *DecryptRequestOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"`
+ // Chunk of data of arbitrary size.
+ Payload *v1.StreamPayload `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
+}
+
+func (x *DecryptRequest) Reset() {
+ *x = DecryptRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[72]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DecryptRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DecryptRequest) ProtoMessage() {}
+
+func (x *DecryptRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[72]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DecryptRequest.ProtoReflect.Descriptor instead.
+func (*DecryptRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{72}
+}
+
+func (x *DecryptRequest) GetOptions() *DecryptRequestOptions {
+ if x != nil {
+ return x.Options
+ }
+ return nil
+}
+
+func (x *DecryptRequest) GetPayload() *v1.StreamPayload {
+ if x != nil {
+ return x.Payload
+ }
+ return nil
+}
+
+// DecryptRequestOptions contains options for the first message in the DecryptAlpha1 request.
+type DecryptRequestOptions struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name of the component
+ ComponentName string `protobuf:"bytes,1,opt,name=component_name,json=componentName,proto3" json:"component_name,omitempty"`
+ // Name (or name/version) of the key to decrypt the message.
+ // Overrides any key reference included in the message if present.
+ // This is required if the message doesn't include a key reference (i.e. was created with omit_decryption_key_name set to true).
+ KeyName string `protobuf:"bytes,12,opt,name=key_name,json=keyName,proto3" json:"key_name,omitempty"`
+}
+
+func (x *DecryptRequestOptions) Reset() {
+ *x = DecryptRequestOptions{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[73]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DecryptRequestOptions) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DecryptRequestOptions) ProtoMessage() {}
+
+func (x *DecryptRequestOptions) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[73]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DecryptRequestOptions.ProtoReflect.Descriptor instead.
+func (*DecryptRequestOptions) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{73}
+}
+
+func (x *DecryptRequestOptions) GetComponentName() string {
+ if x != nil {
+ return x.ComponentName
+ }
+ return ""
+}
+
+func (x *DecryptRequestOptions) GetKeyName() string {
+ if x != nil {
+ return x.KeyName
+ }
+ return ""
+}
+
+// DecryptResponse is the response for DecryptAlpha1.
+type DecryptResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Chunk of data.
+ Payload *v1.StreamPayload `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
+}
+
+func (x *DecryptResponse) Reset() {
+ *x = DecryptResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[74]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DecryptResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DecryptResponse) ProtoMessage() {}
+
+func (x *DecryptResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[74]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DecryptResponse.ProtoReflect.Descriptor instead.
+func (*DecryptResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{74}
+}
+
+func (x *DecryptResponse) GetPayload() *v1.StreamPayload {
+ if x != nil {
+ return x.Payload
+ }
+ return nil
+}
+
+// GetWorkflowRequest is the request for GetWorkflowAlpha1.
+type GetWorkflowRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // ID of the workflow instance to query.
+ InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceID,proto3" json:"instance_id,omitempty"`
+ // Name of the workflow component.
+ WorkflowComponent string `protobuf:"bytes,2,opt,name=workflow_component,json=workflowComponent,proto3" json:"workflow_component,omitempty"`
+}
+
+func (x *GetWorkflowRequest) Reset() {
+ *x = GetWorkflowRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[75]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetWorkflowRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetWorkflowRequest) ProtoMessage() {}
+
+func (x *GetWorkflowRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[75]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetWorkflowRequest.ProtoReflect.Descriptor instead.
+func (*GetWorkflowRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{75}
+}
+
+func (x *GetWorkflowRequest) GetInstanceId() string {
+ if x != nil {
+ return x.InstanceId
+ }
+ return ""
+}
+
+func (x *GetWorkflowRequest) GetWorkflowComponent() string {
+ if x != nil {
+ return x.WorkflowComponent
+ }
+ return ""
+}
+
+// GetWorkflowResponse is the response for GetWorkflowAlpha1.
+type GetWorkflowResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // ID of the workflow instance.
+ InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceID,proto3" json:"instance_id,omitempty"`
+ // Name of the workflow.
+ WorkflowName string `protobuf:"bytes,2,opt,name=workflow_name,json=workflowName,proto3" json:"workflow_name,omitempty"`
+ // The time at which the workflow instance was created.
+ CreatedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
+ // The last time at which the workflow instance had its state changed.
+ LastUpdatedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=last_updated_at,json=lastUpdatedAt,proto3" json:"last_updated_at,omitempty"`
+ // The current status of the workflow instance, for example, "PENDING", "RUNNING", "SUSPENDED", "COMPLETED", "FAILED", and "TERMINATED".
+ RuntimeStatus string `protobuf:"bytes,5,opt,name=runtime_status,json=runtimeStatus,proto3" json:"runtime_status,omitempty"`
+ // Additional component-specific properties of the workflow instance.
+ Properties map[string]string `protobuf:"bytes,6,rep,name=properties,proto3" json:"properties,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *GetWorkflowResponse) Reset() {
+ *x = GetWorkflowResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[76]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetWorkflowResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetWorkflowResponse) ProtoMessage() {}
+
+func (x *GetWorkflowResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[76]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetWorkflowResponse.ProtoReflect.Descriptor instead.
+func (*GetWorkflowResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{76}
+}
+
+func (x *GetWorkflowResponse) GetInstanceId() string {
+ if x != nil {
+ return x.InstanceId
+ }
+ return ""
+}
+
+func (x *GetWorkflowResponse) GetWorkflowName() string {
+ if x != nil {
+ return x.WorkflowName
+ }
+ return ""
+}
+
+func (x *GetWorkflowResponse) GetCreatedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CreatedAt
+ }
+ return nil
+}
+
+func (x *GetWorkflowResponse) GetLastUpdatedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.LastUpdatedAt
+ }
+ return nil
+}
+
+func (x *GetWorkflowResponse) GetRuntimeStatus() string {
+ if x != nil {
+ return x.RuntimeStatus
+ }
+ return ""
+}
+
+func (x *GetWorkflowResponse) GetProperties() map[string]string {
+ if x != nil {
+ return x.Properties
+ }
+ return nil
+}
+
+// StartWorkflowRequest is the request for StartWorkflowAlpha1.
+type StartWorkflowRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The ID to assign to the started workflow instance. If empty, a random ID is generated.
+ InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceID,proto3" json:"instance_id,omitempty"`
+ // Name of the workflow component.
+ WorkflowComponent string `protobuf:"bytes,2,opt,name=workflow_component,json=workflowComponent,proto3" json:"workflow_component,omitempty"`
+ // Name of the workflow.
+ WorkflowName string `protobuf:"bytes,3,opt,name=workflow_name,json=workflowName,proto3" json:"workflow_name,omitempty"`
+ // Additional component-specific options for starting the workflow instance.
+ Options map[string]string `protobuf:"bytes,4,rep,name=options,proto3" json:"options,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // Input data for the workflow instance.
+ Input []byte `protobuf:"bytes,5,opt,name=input,proto3" json:"input,omitempty"`
+}
+
+func (x *StartWorkflowRequest) Reset() {
+ *x = StartWorkflowRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[77]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *StartWorkflowRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StartWorkflowRequest) ProtoMessage() {}
+
+func (x *StartWorkflowRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[77]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StartWorkflowRequest.ProtoReflect.Descriptor instead.
+func (*StartWorkflowRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{77}
+}
+
+func (x *StartWorkflowRequest) GetInstanceId() string {
+ if x != nil {
+ return x.InstanceId
+ }
+ return ""
+}
+
+func (x *StartWorkflowRequest) GetWorkflowComponent() string {
+ if x != nil {
+ return x.WorkflowComponent
+ }
+ return ""
+}
+
+func (x *StartWorkflowRequest) GetWorkflowName() string {
+ if x != nil {
+ return x.WorkflowName
+ }
+ return ""
+}
+
+func (x *StartWorkflowRequest) GetOptions() map[string]string {
+ if x != nil {
+ return x.Options
+ }
+ return nil
+}
+
+func (x *StartWorkflowRequest) GetInput() []byte {
+ if x != nil {
+ return x.Input
+ }
+ return nil
+}
+
+// StartWorkflowResponse is the response for StartWorkflowAlpha1.
+type StartWorkflowResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // ID of the started workflow instance.
+ InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceID,proto3" json:"instance_id,omitempty"`
+}
+
+func (x *StartWorkflowResponse) Reset() {
+ *x = StartWorkflowResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[78]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *StartWorkflowResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StartWorkflowResponse) ProtoMessage() {}
+
+func (x *StartWorkflowResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[78]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use StartWorkflowResponse.ProtoReflect.Descriptor instead.
+func (*StartWorkflowResponse) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{78}
+}
+
+func (x *StartWorkflowResponse) GetInstanceId() string {
+ if x != nil {
+ return x.InstanceId
+ }
+ return ""
+}
+
+// TerminateWorkflowRequest is the request for TerminateWorkflowAlpha1.
+type TerminateWorkflowRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // ID of the workflow instance to terminate.
+ InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceID,proto3" json:"instance_id,omitempty"`
+ // Name of the workflow component.
+ WorkflowComponent string `protobuf:"bytes,2,opt,name=workflow_component,json=workflowComponent,proto3" json:"workflow_component,omitempty"`
+}
+
+func (x *TerminateWorkflowRequest) Reset() {
+ *x = TerminateWorkflowRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[79]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *TerminateWorkflowRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TerminateWorkflowRequest) ProtoMessage() {}
+
+func (x *TerminateWorkflowRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[79]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TerminateWorkflowRequest.ProtoReflect.Descriptor instead.
+func (*TerminateWorkflowRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{79}
+}
+
+func (x *TerminateWorkflowRequest) GetInstanceId() string {
+ if x != nil {
+ return x.InstanceId
+ }
+ return ""
+}
+
+func (x *TerminateWorkflowRequest) GetWorkflowComponent() string {
+ if x != nil {
+ return x.WorkflowComponent
+ }
+ return ""
+}
+
+// PauseWorkflowRequest is the request for PauseWorkflowAlpha1.
+type PauseWorkflowRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // ID of the workflow instance to pause.
+ InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceID,proto3" json:"instance_id,omitempty"`
+ // Name of the workflow component.
+ WorkflowComponent string `protobuf:"bytes,2,opt,name=workflow_component,json=workflowComponent,proto3" json:"workflow_component,omitempty"`
+}
+
+func (x *PauseWorkflowRequest) Reset() {
+ *x = PauseWorkflowRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[80]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PauseWorkflowRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PauseWorkflowRequest) ProtoMessage() {}
+
+func (x *PauseWorkflowRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[80]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PauseWorkflowRequest.ProtoReflect.Descriptor instead.
+func (*PauseWorkflowRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{80}
+}
+
+func (x *PauseWorkflowRequest) GetInstanceId() string {
+ if x != nil {
+ return x.InstanceId
+ }
+ return ""
+}
+
+func (x *PauseWorkflowRequest) GetWorkflowComponent() string {
+ if x != nil {
+ return x.WorkflowComponent
+ }
+ return ""
+}
+
+// ResumeWorkflowRequest is the request for ResumeWorkflowAlpha1.
+type ResumeWorkflowRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // ID of the workflow instance to resume.
+ InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceID,proto3" json:"instance_id,omitempty"`
+ // Name of the workflow component.
+ WorkflowComponent string `protobuf:"bytes,2,opt,name=workflow_component,json=workflowComponent,proto3" json:"workflow_component,omitempty"`
+}
+
+func (x *ResumeWorkflowRequest) Reset() {
+ *x = ResumeWorkflowRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[81]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ResumeWorkflowRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ResumeWorkflowRequest) ProtoMessage() {}
+
+func (x *ResumeWorkflowRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[81]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ResumeWorkflowRequest.ProtoReflect.Descriptor instead.
+func (*ResumeWorkflowRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{81}
+}
+
+func (x *ResumeWorkflowRequest) GetInstanceId() string {
+ if x != nil {
+ return x.InstanceId
+ }
+ return ""
+}
+
+func (x *ResumeWorkflowRequest) GetWorkflowComponent() string {
+ if x != nil {
+ return x.WorkflowComponent
+ }
+ return ""
+}
+
+// RaiseEventWorkflowRequest is the request for RaiseEventWorkflowAlpha1.
+type RaiseEventWorkflowRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // ID of the workflow instance to raise an event for.
+ InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceID,proto3" json:"instance_id,omitempty"`
+ // Name of the workflow component.
+ WorkflowComponent string `protobuf:"bytes,2,opt,name=workflow_component,json=workflowComponent,proto3" json:"workflow_component,omitempty"`
+ // Name of the event.
+ EventName string `protobuf:"bytes,3,opt,name=event_name,json=eventName,proto3" json:"event_name,omitempty"`
+ // Data associated with the event.
+ EventData []byte `protobuf:"bytes,4,opt,name=event_data,json=eventData,proto3" json:"event_data,omitempty"`
+}
+
+func (x *RaiseEventWorkflowRequest) Reset() {
+ *x = RaiseEventWorkflowRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[82]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *RaiseEventWorkflowRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RaiseEventWorkflowRequest) ProtoMessage() {}
+
+func (x *RaiseEventWorkflowRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[82]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RaiseEventWorkflowRequest.ProtoReflect.Descriptor instead.
+func (*RaiseEventWorkflowRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{82}
+}
+
+func (x *RaiseEventWorkflowRequest) GetInstanceId() string {
+ if x != nil {
+ return x.InstanceId
+ }
+ return ""
+}
+
+func (x *RaiseEventWorkflowRequest) GetWorkflowComponent() string {
+ if x != nil {
+ return x.WorkflowComponent
+ }
+ return ""
+}
+
+func (x *RaiseEventWorkflowRequest) GetEventName() string {
+ if x != nil {
+ return x.EventName
+ }
+ return ""
+}
+
+func (x *RaiseEventWorkflowRequest) GetEventData() []byte {
+ if x != nil {
+ return x.EventData
+ }
+ return nil
+}
+
+// PurgeWorkflowRequest is the request for PurgeWorkflowAlpha1.
+type PurgeWorkflowRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // ID of the workflow instance to purge.
+ InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceID,proto3" json:"instance_id,omitempty"`
+ // Name of the workflow component.
+ WorkflowComponent string `protobuf:"bytes,2,opt,name=workflow_component,json=workflowComponent,proto3" json:"workflow_component,omitempty"`
+}
+
+func (x *PurgeWorkflowRequest) Reset() {
+ *x = PurgeWorkflowRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[83]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PurgeWorkflowRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PurgeWorkflowRequest) ProtoMessage() {}
+
+func (x *PurgeWorkflowRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_dapr_proto_runtime_v1_dapr_proto_msgTypes[83]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PurgeWorkflowRequest.ProtoReflect.Descriptor instead.
+func (*PurgeWorkflowRequest) Descriptor() ([]byte, []int) {
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP(), []int{83}
+}
+
+func (x *PurgeWorkflowRequest) GetInstanceId() string {
+ if x != nil {
+ return x.InstanceId
+ }
+ return ""
+}
+
+func (x *PurgeWorkflowRequest) GetWorkflowComponent() string {
+ if x != nil {
+ return x.WorkflowComponent
+ }
+ return ""
+}
+
+var File_dapr_proto_runtime_v1_dapr_proto protoreflect.FileDescriptor
+
+var file_dapr_proto_runtime_v1_dapr_proto_rawDesc = []byte{
+ 0x0a, 0x20, 0x64, 0x61, 0x70, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x75, 0x6e,
+ 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x12, 0x15, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72,
+ 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+ 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x1a, 0x21, 0x64, 0x61, 0x70, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63,
+ 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x65, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53,
+ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a,
+ 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3d, 0x0a,
+ 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23,
+ 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
+ 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa8, 0x02, 0x0a,
+ 0x0f, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12,
+ 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+ 0x79, 0x12, 0x55, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e,
+ 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x50, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61,
+ 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x64, 0x61, 0x70,
+ 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e,
+ 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79,
+ 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
+ 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xfd, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x42,
+ 0x75, 0x6c, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12,
+ 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x65,
+ 0x79, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x69, 0x73,
+ 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65,
+ 0x6c, 0x69, 0x73, 0x6d, 0x12, 0x54, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47,
+ 0x65, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79,
+ 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
+ 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x52, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x42, 0x75,
+ 0x6c, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+ 0x3a, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24,
+ 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74,
+ 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0xec, 0x01, 0x0a, 0x0d,
+ 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x10, 0x0a,
+ 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+ 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64,
+ 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x4e, 0x0a,
+ 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x32, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e,
+ 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a,
+ 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
+ 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
+ 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xca, 0x01, 0x0a, 0x10, 0x47,
+ 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+ 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64,
+ 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x51, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64,
+ 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79,
+ 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
+ 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc5, 0x02, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65,
+ 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d,
+ 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a,
+ 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+ 0x2e, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
+ 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x74, 0x61, 0x67, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12,
+ 0x3c, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x22, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x53, 0x0a,
+ 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x37, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e,
+ 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64,
+ 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22,
+ 0x70, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x74, 0x61,
+ 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f,
+ 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73,
+ 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
+ 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e,
+ 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65,
+ 0x73, 0x22, 0x6a, 0x0a, 0x10, 0x53, 0x61, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x65,
+ 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x22, 0xd9, 0x01,
+ 0x0a, 0x11, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61,
+ 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x52, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61,
+ 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x64, 0x61, 0x70,
+ 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e,
+ 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74,
+ 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d,
+ 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+ 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+ 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
+ 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x60, 0x0a, 0x0e, 0x51, 0x75, 0x65,
+ 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x6b,
+ 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a,
+ 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74,
+ 0x61, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xfd, 0x01, 0x0a, 0x12,
+ 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72,
+ 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75,
+ 0x6c, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x53, 0x0a, 0x08, 0x6d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x64, 0x61,
+ 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,
+ 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45,
+ 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b,
+ 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+ 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+ 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x9f, 0x02, 0x0a, 0x13,
+ 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x5f, 0x6e, 0x61,
+ 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62,
+ 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61,
+ 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2a,
+ 0x0a, 0x11, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74,
+ 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x43,
+ 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x54, 0x0a, 0x08, 0x6d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e,
+ 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+ 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+ 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa7, 0x02,
+ 0x0a, 0x12, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x5f, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x75, 0x62, 0x73, 0x75,
+ 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x48, 0x0a, 0x07, 0x65,
+ 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e,
+ 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x53, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+ 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79,
+ 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
+ 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x84, 0x02, 0x0a, 0x17, 0x42, 0x75, 0x6c, 0x6b,
+ 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x49, 0x64, 0x12, 0x14,
+ 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x65,
+ 0x76, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f,
+ 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x58, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64,
+ 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+ 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74,
+ 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x72,
+ 0x0a, 0x13, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x45,
+ 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x52, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x69,
+ 0x65, 0x73, 0x22, 0x51, 0x0a, 0x1e, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73,
+ 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x45,
+ 0x6e, 0x74, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x69, 0x64,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x49, 0x64, 0x12,
+ 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
+ 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xf0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65,
+ 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12,
+ 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c,
+ 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x55, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a,
+ 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
+ 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
+ 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc0, 0x01, 0x0a, 0x15, 0x49, 0x6e, 0x76,
+ 0x6f, 0x6b, 0x65, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
+ 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x56, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45,
+ 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b,
+ 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+ 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+ 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd3, 0x01, 0x0a, 0x10,
+ 0x47, 0x65, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12,
+ 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+ 0x79, 0x12, 0x51, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53,
+ 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61,
+ 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+ 0x01, 0x22, 0x94, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18,
+ 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
+ 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e,
+ 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x1a,
+ 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
+ 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
+ 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc9, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74,
+ 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65,
+ 0x12, 0x55, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+ 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x75,
+ 0x6c, 0x6b, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e,
+ 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64,
+ 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+ 0x3a, 0x02, 0x38, 0x01, 0x22, 0x9a, 0x01, 0x0a, 0x0e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x72, 0x65,
+ 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e,
+ 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x73, 0x65,
+ 0x63, 0x72, 0x65, 0x74, 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73,
+ 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+ 0x01, 0x22, 0xc3, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x65, 0x63,
+ 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x04, 0x64,
+ 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x5e, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45,
+ 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65,
+ 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x7e, 0x0a, 0x1b, 0x54, 0x72, 0x61, 0x6e, 0x73,
+ 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6f,
+ 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x39, 0x0a, 0x07,
+ 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
+ 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x07,
+ 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xb0, 0x02, 0x0a, 0x1e, 0x45, 0x78, 0x65, 0x63,
+ 0x75, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
+ 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74,
+ 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73,
+ 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x52, 0x0a, 0x0a, 0x6f, 0x70, 0x65, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x52, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x5f, 0x0a, 0x08,
+ 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43,
+ 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74,
+ 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a,
+ 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
+ 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
+ 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xde, 0x01, 0x0a, 0x19, 0x52,
+ 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x69, 0x6d, 0x65,
+ 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x6f,
+ 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63,
+ 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x63, 0x74, 0x6f, 0x72,
+ 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, 0x6f, 0x72,
+ 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x75, 0x65, 0x5f, 0x74, 0x69,
+ 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x75, 0x65, 0x54, 0x69, 0x6d,
+ 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x6c,
+ 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x6c,
+ 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20,
+ 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74, 0x6c,
+ 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x22, 0x6b, 0x0a, 0x1b, 0x55,
+ 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x69,
+ 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63,
+ 0x74, 0x6f, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
+ 0x61, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x63, 0x74,
+ 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74,
+ 0x6f, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xc5, 0x01, 0x0a, 0x1c, 0x52, 0x65, 0x67,
+ 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x6d, 0x69, 0x6e, 0x64,
+ 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x74,
+ 0x6f, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61,
+ 0x63, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x63, 0x74, 0x6f,
+ 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, 0x6f,
+ 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x75, 0x65, 0x5f, 0x74,
+ 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x75, 0x65, 0x54, 0x69,
+ 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x05, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61,
+ 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x10,
+ 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x74, 0x6c,
+ 0x22, 0x6e, 0x0a, 0x1e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x63,
+ 0x74, 0x6f, 0x72, 0x52, 0x65, 0x6d, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70,
+ 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+ 0x22, 0x8c, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x41, 0x63, 0x74, 0x6f, 0x72,
+ 0x52, 0x65, 0x6d, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19,
+ 0x0a, 0x08, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x07, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x6c, 0x64,
+ 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x6c, 0x64,
+ 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x22,
+ 0x62, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x6f, 0x72,
+ 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x74,
+ 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f,
+ 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x49,
+ 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+ 0x6b, 0x65, 0x79, 0x22, 0x2b, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x53,
+ 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04,
+ 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
+ 0x22, 0xb8, 0x01, 0x0a, 0x23, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x41, 0x63, 0x74, 0x6f,
+ 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
+ 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x6f,
+ 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63,
+ 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x63, 0x74, 0x6f, 0x72,
+ 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, 0x6f, 0x72,
+ 0x49, 0x64, 0x12, 0x57, 0x0a, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54,
+ 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x74, 0x6f,
+ 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+ 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xa6, 0x02, 0x0a, 0x20,
+ 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x74,
+ 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x12, 0x24, 0x0a, 0x0d, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70,
+ 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x12, 0x61, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54,
+ 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x74, 0x6f,
+ 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
+ 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64,
+ 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+ 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8c, 0x02, 0x0a, 0x12, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x41,
+ 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61,
+ 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x09, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x63,
+ 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63,
+ 0x74, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18,
+ 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x12, 0x0a,
+ 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74,
+ 0x61, 0x12, 0x53, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x6f,
+ 0x6b, 0x65, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
+ 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
+ 0x02, 0x38, 0x01, 0x22, 0x29, 0x0a, 0x13, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x63, 0x74,
+ 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61,
+ 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x9d,
+ 0x04, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x4d, 0x0a, 0x13, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65,
+ 0x5f, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x74, 0x69,
+ 0x76, 0x65, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x61,
+ 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x56, 0x0a, 0x15, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
+ 0x72, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67,
+ 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74,
+ 0x73, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x65, 0x0a,
+ 0x11, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65,
+ 0x6e, 0x64, 0x65, 0x64, 0x12, 0x4f, 0x0a, 0x0d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x64, 0x61,
+ 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,
+ 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, 0x73, 0x75, 0x62, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72,
+ 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x52, 0x0a, 0x0e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x65, 0x6e,
+ 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x54,
+ 0x54, 0x50, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0d, 0x68, 0x74, 0x74, 0x70,
+ 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x1a, 0x43, 0x0a, 0x15, 0x45, 0x78, 0x74,
+ 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74,
+ 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x3d,
+ 0x0a, 0x11, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x43, 0x6f,
+ 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x7c, 0x0a,
+ 0x14, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x6f,
+ 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70,
+ 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a,
+ 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
+ 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62,
+ 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63,
+ 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0x2a, 0x0a, 0x14, 0x4d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x54, 0x54, 0x50, 0x45, 0x6e, 0x64, 0x70, 0x6f,
+ 0x69, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xcf, 0x02, 0x0a, 0x12, 0x50, 0x75, 0x62, 0x73,
+ 0x75, 0x62, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f,
+ 0x0a, 0x0b, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x6e, 0x61, 0x6d, 0x65, 0x12,
+ 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
+ 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x53, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+ 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x50, 0x75, 0x62, 0x73, 0x75, 0x62, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
+ 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79,
+ 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x44, 0x0a, 0x05, 0x72, 0x75,
+ 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x50, 0x75, 0x62, 0x73, 0x75, 0x62, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73,
+ 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x61, 0x64, 0x5f, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x5f,
+ 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x61,
+ 0x64, 0x4c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x1a, 0x3b, 0x0a, 0x0d,
+ 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+ 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+ 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
+ 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x5e, 0x0a, 0x17, 0x50, 0x75, 0x62,
+ 0x73, 0x75, 0x62, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+ 0x75, 0x6c, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, 0x73,
+ 0x75, 0x62, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75,
+ 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x42, 0x0a, 0x16, 0x50, 0x75, 0x62,
+ 0x73, 0x75, 0x62, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+ 0x75, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74,
+ 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3c, 0x0a,
+ 0x12, 0x53, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xe3, 0x01, 0x0a, 0x17,
+ 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65,
+ 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x6f,
+ 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02,
+ 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x58, 0x0a, 0x08, 0x6d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61,
+ 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+ 0x01, 0x22, 0xcf, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50,
+ 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x49,
+ 0x74, 0x65, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73,
+ 0x1a, 0x61, 0x0a, 0x0a, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
+ 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
+ 0x12, 0x3d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x27, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
+ 0x02, 0x38, 0x01, 0x22, 0xef, 0x01, 0x0a, 0x1d, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62,
+ 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x65,
+ 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03,
+ 0x28, 0x09, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x5e, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61,
+ 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x64, 0x61, 0x70,
+ 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e,
+ 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08,
+ 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61,
+ 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x50, 0x0a, 0x1f, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63,
+ 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72,
+ 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74,
+ 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0xeb, 0x01, 0x0a, 0x1e, 0x53, 0x75, 0x62, 0x73,
+ 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x56, 0x0a, 0x05, 0x69, 0x74,
+ 0x65, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x69, 0x74, 0x65,
+ 0x6d, 0x73, 0x1a, 0x61, 0x0a, 0x0a, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+ 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
+ 0x65, 0x79, 0x12, 0x3d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x27, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4c, 0x0a, 0x20, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63,
+ 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73,
+ 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73,
+ 0x61, 0x67, 0x65, 0x22, 0x9b, 0x01, 0x0a, 0x0e, 0x54, 0x72, 0x79, 0x4c, 0x6f, 0x63, 0x6b, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72,
+ 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f,
+ 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6f,
+ 0x77, 0x6e, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x6b,
+ 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f,
+ 0x69, 0x6e, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05,
+ 0x52, 0x0f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x49, 0x6e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64,
+ 0x73, 0x22, 0x2b, 0x0a, 0x0f, 0x54, 0x72, 0x79, 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x6e,
+ 0x0a, 0x0d, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f,
+ 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12,
+ 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x22, 0xb6,
+ 0x01, 0x0a, 0x0e, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x44, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x0e, 0x32, 0x2c, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72,
+ 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
+ 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x5e, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75,
+ 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x17,
+ 0x0a, 0x13, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x44, 0x4f, 0x45, 0x53, 0x5f, 0x4e, 0x4f, 0x54, 0x5f,
+ 0x45, 0x58, 0x49, 0x53, 0x54, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x4c, 0x4f, 0x43, 0x4b, 0x5f,
+ 0x42, 0x45, 0x4c, 0x4f, 0x4e, 0x47, 0x53, 0x5f, 0x54, 0x4f, 0x5f, 0x4f, 0x54, 0x48, 0x45, 0x52,
+ 0x53, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f,
+ 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x22, 0xbe, 0x01, 0x0a, 0x13, 0x53, 0x75, 0x62, 0x74,
+ 0x6c, 0x65, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65,
+ 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4c, 0x0a, 0x06, 0x66, 0x6f,
+ 0x72, 0x6d, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x34, 0x2e, 0x64, 0x61, 0x70,
+ 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e,
+ 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4b, 0x65, 0x79, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74,
+ 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x1e, 0x0a, 0x09, 0x4b, 0x65, 0x79, 0x46,
+ 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x45, 0x4d, 0x10, 0x00, 0x12, 0x08,
+ 0x0a, 0x04, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x01, 0x22, 0x49, 0x0a, 0x14, 0x53, 0x75, 0x62, 0x74,
+ 0x6c, 0x65, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b,
+ 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
+ 0x4b, 0x65, 0x79, 0x22, 0xd3, 0x01, 0x0a, 0x14, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x45, 0x6e,
+ 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e,
+ 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x4e,
+ 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78,
+ 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12,
+ 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f,
+ 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65,
+ 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x64,
+ 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x61, 0x73, 0x73, 0x6f, 0x63,
+ 0x69, 0x61, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x22, 0x49, 0x0a, 0x15, 0x53, 0x75, 0x62,
+ 0x74, 0x6c, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65,
+ 0x78, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
+ 0x03, 0x74, 0x61, 0x67, 0x22, 0xe7, 0x01, 0x0a, 0x14, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x44,
+ 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a,
+ 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74,
+ 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65,
+ 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72,
+ 0x74, 0x65, 0x78, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68,
+ 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74,
+ 0x68, 0x6d, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a,
+ 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f,
+ 0x6e, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c,
+ 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61,
+ 0x74, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e,
+ 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x22, 0x35,
+ 0x0a, 0x15, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x69, 0x6e,
+ 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x6c, 0x61, 0x69,
+ 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xda, 0x01, 0x0a, 0x14, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65,
+ 0x57, 0x72, 0x61, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25,
+ 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e,
+ 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65,
+ 0x78, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x6c,
+ 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x6c,
+ 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61,
+ 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4e,
+ 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01,
+ 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x73, 0x73,
+ 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01,
+ 0x28, 0x0c, 0x52, 0x0e, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x44, 0x61,
+ 0x74, 0x61, 0x22, 0x4a, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x57, 0x72, 0x61, 0x70,
+ 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x77,
+ 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
+ 0x52, 0x0a, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03,
+ 0x74, 0x61, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0xea,
+ 0x01, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x55, 0x6e, 0x77, 0x72, 0x61, 0x70, 0x4b,
+ 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6d,
+ 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65,
+ 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x4b, 0x65,
+ 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12,
+ 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f,
+ 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65,
+ 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x74,
+ 0x61, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64,
+ 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x61, 0x73, 0x73,
+ 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x22, 0x3e, 0x0a, 0x17, 0x53,
+ 0x75, 0x62, 0x74, 0x6c, 0x65, 0x55, 0x6e, 0x77, 0x72, 0x61, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74,
+ 0x65, 0x78, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70,
+ 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x8b, 0x01, 0x0a, 0x11,
+ 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6f,
+ 0x6e, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65,
+ 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74,
+ 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x19,
+ 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x32, 0x0a, 0x12, 0x53, 0x75, 0x62,
+ 0x74, 0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+ 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xab, 0x01,
+ 0x0a, 0x13, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65,
+ 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63,
+ 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06,
+ 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x64, 0x69,
+ 0x67, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68,
+ 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74,
+ 0x68, 0x6d, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a,
+ 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c,
+ 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x2c, 0x0a, 0x14, 0x53,
+ 0x75, 0x62, 0x74, 0x6c, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x22, 0x97, 0x01, 0x0a, 0x0e, 0x45, 0x6e,
+ 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x46, 0x0a, 0x07,
+ 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3d, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72,
+ 0x65, 0x61, 0x6d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c,
+ 0x6f, 0x61, 0x64, 0x22, 0xa6, 0x02, 0x0a, 0x15, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x25, 0x0a,
+ 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74,
+ 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12,
+ 0x2c, 0x0a, 0x12, 0x6b, 0x65, 0x79, 0x5f, 0x77, 0x72, 0x61, 0x70, 0x5f, 0x61, 0x6c, 0x67, 0x6f,
+ 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6b, 0x65, 0x79,
+ 0x57, 0x72, 0x61, 0x70, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x34, 0x0a,
+ 0x16, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+ 0x5f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64,
+ 0x61, 0x74, 0x61, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x69, 0x70,
+ 0x68, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x18, 0x6f, 0x6d, 0x69, 0x74, 0x5f, 0x64, 0x65, 0x63, 0x72,
+ 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+ 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x6f, 0x6d, 0x69, 0x74, 0x44, 0x65, 0x63, 0x72, 0x79,
+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x13,
+ 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x64, 0x65, 0x63, 0x72, 0x79,
+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x50, 0x0a, 0x0f,
+ 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+ 0x3d, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x23, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61,
+ 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x97,
+ 0x01, 0x0a, 0x0e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x46, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+ 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79,
+ 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3d, 0x0a, 0x07, 0x70, 0x61, 0x79,
+ 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x64, 0x61, 0x70,
+ 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76,
+ 0x31, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52,
+ 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x59, 0x0a, 0x15, 0x44, 0x65, 0x63, 0x72,
+ 0x79, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6f,
+ 0x6e, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4e,
+ 0x61, 0x6d, 0x65, 0x22, 0x50, 0x0a, 0x0f, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61,
+ 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53,
+ 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61,
+ 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x64, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b,
+ 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69,
+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x12, 0x2d, 0x0a, 0x12,
+ 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65,
+ 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
+ 0x6f, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x9c, 0x03, 0x0a, 0x13,
+ 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f,
+ 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e,
+ 0x63, 0x65, 0x49, 0x44, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
+ 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72,
+ 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65,
+ 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+ 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74,
+ 0x65, 0x64, 0x41, 0x74, 0x12, 0x42, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64,
+ 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+ 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x55,
+ 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x75, 0x6e, 0x74,
+ 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x0d, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
+ 0x5a, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x57,
+ 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e,
+ 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
+ 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x50,
+ 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
+ 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
+ 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xb1, 0x02, 0x0a, 0x14, 0x53,
+ 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f,
+ 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e,
+ 0x63, 0x65, 0x49, 0x44, 0x12, 0x2d, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
+ 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e,
+ 0x65, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b,
+ 0x66, 0x6c, 0x6f, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x52, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05,
+ 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x69, 0x6e, 0x70,
+ 0x75, 0x74, 0x1a, 0x3a, 0x0a, 0x0c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74,
+ 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x38,
+ 0x0a, 0x15, 0x53, 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61,
+ 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e,
+ 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x22, 0x6a, 0x0a, 0x18, 0x54, 0x65, 0x72, 0x6d,
+ 0x69, 0x6e, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
+ 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61,
+ 0x6e, 0x63, 0x65, 0x49, 0x44, 0x12, 0x2d, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
+ 0x77, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6f,
+ 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x66, 0x0a, 0x14, 0x50, 0x61, 0x75, 0x73, 0x65, 0x57, 0x6f, 0x72,
+ 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b,
+ 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x12, 0x2d, 0x0a,
+ 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e,
+ 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66,
+ 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x67, 0x0a, 0x15,
+ 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
+ 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74,
+ 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x12, 0x2d, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
+ 0x6f, 0x77, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6d, 0x70,
+ 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0xa9, 0x01, 0x0a, 0x19, 0x52, 0x61, 0x69, 0x73, 0x65, 0x45,
+ 0x76, 0x65, 0x6e, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f,
+ 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e,
+ 0x63, 0x65, 0x49, 0x44, 0x12, 0x2d, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
+ 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e,
+ 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x61,
+ 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x44, 0x61, 0x74,
+ 0x61, 0x22, 0x66, 0x0a, 0x14, 0x50, 0x75, 0x72, 0x67, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
+ 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73,
+ 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
+ 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x12, 0x2d, 0x0a, 0x12, 0x77, 0x6f,
+ 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
+ 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x32, 0xe9, 0x27, 0x0a, 0x04, 0x44, 0x61,
+ 0x70, 0x72, 0x12, 0x64, 0x0a, 0x0d, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x72, 0x76,
+ 0x69, 0x63, 0x65, 0x12, 0x2b, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x6f,
+ 0x6b, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x1a, 0x24, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53,
+ 0x74, 0x61, 0x74, 0x65, 0x12, 0x26, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
+ 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x69, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x42, 0x75,
+ 0x6c, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x47, 0x65, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42,
+ 0x75, 0x6c, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x09, 0x53, 0x61, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12,
+ 0x27, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e,
+ 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
+ 0x22, 0x00, 0x12, 0x69, 0x0a, 0x10, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x28, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51,
+ 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x1a, 0x29, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75,
+ 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a,
+ 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x29, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
+ 0x00, 0x12, 0x5a, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x75, 0x6c, 0x6b, 0x53,
+ 0x74, 0x61, 0x74, 0x65, 0x12, 0x2d, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c,
+ 0x65, 0x74, 0x65, 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x6a, 0x0a,
+ 0x17, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61,
+ 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61,
+ 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+ 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
+ 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x0c, 0x50, 0x75, 0x62,
+ 0x6c, 0x69, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12,
+ 0x71, 0x0a, 0x16, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x76,
+ 0x65, 0x6e, 0x74, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x29, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x6c,
+ 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x0d, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x42, 0x69, 0x6e, 0x64,
+ 0x69, 0x6e, 0x67, 0x12, 0x2b, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x6f,
+ 0x6b, 0x65, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x1a, 0x2c, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75,
+ 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x42,
+ 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
+ 0x12, 0x60, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x27, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47,
+ 0x65, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x53, 0x65, 0x63,
+ 0x72, 0x65, 0x74, 0x12, 0x2b, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42,
+ 0x75, 0x6c, 0x6b, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x1a, 0x2c, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75,
+ 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6c, 0x6b,
+ 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
+ 0x12, 0x60, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x63, 0x74, 0x6f,
+ 0x72, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x30, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52,
+ 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x69, 0x6d, 0x65,
+ 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
+ 0x22, 0x00, 0x12, 0x64, 0x0a, 0x14, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
+ 0x41, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x32, 0x2e, 0x64, 0x61, 0x70,
+ 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e,
+ 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x63, 0x74,
+ 0x6f, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+ 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x66, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69,
+ 0x73, 0x74, 0x65, 0x72, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x6d, 0x69, 0x6e, 0x64, 0x65,
+ 0x72, 0x12, 0x33, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72,
+ 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
+ 0x65, 0x72, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x6d, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00,
+ 0x12, 0x6a, 0x0a, 0x17, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x63,
+ 0x74, 0x6f, 0x72, 0x52, 0x65, 0x6d, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x35, 0x2e, 0x64, 0x61,
+ 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,
+ 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x63,
+ 0x74, 0x6f, 0x72, 0x52, 0x65, 0x6d, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x62, 0x0a, 0x13,
+ 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x6d, 0x69, 0x6e,
+ 0x64, 0x65, 0x72, 0x12, 0x31, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61,
+ 0x6d, 0x65, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x6d, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00,
+ 0x12, 0x6c, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x12, 0x2b, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72,
+ 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74,
+ 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c,
+ 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74,
+ 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x53,
+ 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x74,
+ 0x0a, 0x1c, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a,
+ 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74,
+ 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x41, 0x63,
+ 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
+ 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70,
+ 0x74, 0x79, 0x22, 0x00, 0x12, 0x66, 0x0a, 0x0b, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x63,
+ 0x74, 0x6f, 0x72, 0x12, 0x29, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x6f,
+ 0x6b, 0x65, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a,
+ 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74,
+ 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x63, 0x74,
+ 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7b, 0x0a, 0x16,
+ 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x2e, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47,
+ 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47,
+ 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x75, 0x0a, 0x10, 0x47, 0x65, 0x74,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
+ 0x12, 0x8f, 0x01, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6c, 0x70, 0x68, 0x61,
+ 0x31, 0x12, 0x34, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72,
+ 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72,
+ 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
+ 0x30, 0x01, 0x12, 0x89, 0x01, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x73,
+ 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x93,
+ 0x01, 0x0a, 0x1e, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6c, 0x70, 0x68, 0x61,
+ 0x31, 0x12, 0x36, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72,
+ 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73,
+ 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x22, 0x00, 0x12, 0x8d, 0x01, 0x0a, 0x18, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63,
+ 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x12, 0x36, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72,
+ 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73,
+ 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x22, 0x00, 0x12, 0x60, 0x0a, 0x0d, 0x54, 0x72, 0x79, 0x4c, 0x6f, 0x63, 0x6b, 0x41,
+ 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x25, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72,
+ 0x79, 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x79, 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0c, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b,
+ 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x24, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55,
+ 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x62, 0x0a, 0x0d, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
+ 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x25, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45,
+ 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x62, 0x0a, 0x0d, 0x44, 0x65, 0x63,
+ 0x72, 0x79, 0x70, 0x74, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x25, 0x2e, 0x64, 0x61, 0x70,
+ 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e,
+ 0x76, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x1a, 0x26, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72,
+ 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70,
+ 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x53, 0x0a,
+ 0x0b, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45,
+ 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
+ 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+ 0x61, 0x12, 0x29, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72,
+ 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45,
+ 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x6d, 0x0a, 0x12, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65,
+ 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x2a, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x47, 0x65, 0x74, 0x4b, 0x65,
+ 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a, 0x13, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x45,
+ 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x2b, 0x2e, 0x64,
+ 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79,
+ 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a, 0x13, 0x53, 0x75, 0x62, 0x74, 0x6c,
+ 0x65, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x2b,
+ 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74,
+ 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x44, 0x65, 0x63,
+ 0x72, 0x79, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x64, 0x61,
+ 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,
+ 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70,
+ 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a, 0x13, 0x53, 0x75, 0x62,
+ 0x74, 0x6c, 0x65, 0x57, 0x72, 0x61, 0x70, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31,
+ 0x12, 0x2b, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75,
+ 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x57,
+ 0x72, 0x61, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e,
+ 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x57, 0x72, 0x61, 0x70,
+ 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x76, 0x0a, 0x15, 0x53,
+ 0x75, 0x62, 0x74, 0x6c, 0x65, 0x55, 0x6e, 0x77, 0x72, 0x61, 0x70, 0x4b, 0x65, 0x79, 0x41, 0x6c,
+ 0x70, 0x68, 0x61, 0x31, 0x12, 0x2d, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62,
+ 0x74, 0x6c, 0x65, 0x55, 0x6e, 0x77, 0x72, 0x61, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x74,
+ 0x6c, 0x65, 0x55, 0x6e, 0x77, 0x72, 0x61, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x53, 0x69, 0x67,
+ 0x6e, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x28, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x1a, 0x29, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72,
+ 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65,
+ 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x12,
+ 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x41, 0x6c, 0x70, 0x68,
+ 0x61, 0x31, 0x12, 0x2a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+ 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x6c,
+ 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b,
+ 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74,
+ 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x74, 0x6c, 0x65, 0x56, 0x65, 0x72,
+ 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x13, 0x53,
+ 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x6c, 0x70, 0x68,
+ 0x61, 0x31, 0x12, 0x2b, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+ 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74,
+ 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+ 0x2c, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e,
+ 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72,
+ 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
+ 0x6c, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x6c,
+ 0x70, 0x68, 0x61, 0x31, 0x12, 0x29, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
+ 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+ 0x2a, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e,
+ 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66,
+ 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5c, 0x0a,
+ 0x13, 0x50, 0x75, 0x72, 0x67, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x6c,
+ 0x70, 0x68, 0x61, 0x31, 0x12, 0x2b, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x72,
+ 0x67, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x64, 0x0a, 0x17, 0x54,
+ 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
+ 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x2f, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54,
+ 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
+ 0x00, 0x12, 0x5c, 0x0a, 0x13, 0x50, 0x61, 0x75, 0x73, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
+ 0x6f, 0x77, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x2b, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x50, 0x61, 0x75, 0x73, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12,
+ 0x5e, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
+ 0x77, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x2c, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12,
+ 0x66, 0x0a, 0x18, 0x52, 0x61, 0x69, 0x73, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x57, 0x6f, 0x72,
+ 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x12, 0x30, 0x2e, 0x64, 0x61,
+ 0x70, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,
+ 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x61, 0x69, 0x73, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x57, 0x6f,
+ 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+ 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, 0x64,
+ 0x6f, 0x77, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
+ 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x69, 0x0a, 0x0a, 0x69, 0x6f, 0x2e, 0x64, 0x61, 0x70, 0x72,
+ 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x44, 0x61, 0x70, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x5a,
+ 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x61, 0x70, 0x72,
+ 0x2f, 0x64, 0x61, 0x70, 0x72, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
+ 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x75, 0x6e, 0x74, 0x69,
+ 0x6d, 0x65, 0xaa, 0x02, 0x1b, 0x44, 0x61, 0x70, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
+ 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x67, 0x65, 0x6e, 0x2e, 0x47, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31,
+ 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_dapr_proto_runtime_v1_dapr_proto_rawDescOnce sync.Once
+ file_dapr_proto_runtime_v1_dapr_proto_rawDescData = file_dapr_proto_runtime_v1_dapr_proto_rawDesc
+)
+
+func file_dapr_proto_runtime_v1_dapr_proto_rawDescGZIP() []byte {
+ file_dapr_proto_runtime_v1_dapr_proto_rawDescOnce.Do(func() {
+ file_dapr_proto_runtime_v1_dapr_proto_rawDescData = protoimpl.X.CompressGZIP(file_dapr_proto_runtime_v1_dapr_proto_rawDescData)
+ })
+ return file_dapr_proto_runtime_v1_dapr_proto_rawDescData
+}
+
+var file_dapr_proto_runtime_v1_dapr_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_dapr_proto_runtime_v1_dapr_proto_msgTypes = make([]protoimpl.MessageInfo, 112)
+var file_dapr_proto_runtime_v1_dapr_proto_goTypes = []interface{}{
+ (UnlockResponse_Status)(0), // 0: dapr.proto.runtime.v1.UnlockResponse.Status
+ (SubtleGetKeyRequest_KeyFormat)(0), // 1: dapr.proto.runtime.v1.SubtleGetKeyRequest.KeyFormat
+ (*InvokeServiceRequest)(nil), // 2: dapr.proto.runtime.v1.InvokeServiceRequest
+ (*GetStateRequest)(nil), // 3: dapr.proto.runtime.v1.GetStateRequest
+ (*GetBulkStateRequest)(nil), // 4: dapr.proto.runtime.v1.GetBulkStateRequest
+ (*GetBulkStateResponse)(nil), // 5: dapr.proto.runtime.v1.GetBulkStateResponse
+ (*BulkStateItem)(nil), // 6: dapr.proto.runtime.v1.BulkStateItem
+ (*GetStateResponse)(nil), // 7: dapr.proto.runtime.v1.GetStateResponse
+ (*DeleteStateRequest)(nil), // 8: dapr.proto.runtime.v1.DeleteStateRequest
+ (*DeleteBulkStateRequest)(nil), // 9: dapr.proto.runtime.v1.DeleteBulkStateRequest
+ (*SaveStateRequest)(nil), // 10: dapr.proto.runtime.v1.SaveStateRequest
+ (*QueryStateRequest)(nil), // 11: dapr.proto.runtime.v1.QueryStateRequest
+ (*QueryStateItem)(nil), // 12: dapr.proto.runtime.v1.QueryStateItem
+ (*QueryStateResponse)(nil), // 13: dapr.proto.runtime.v1.QueryStateResponse
+ (*PublishEventRequest)(nil), // 14: dapr.proto.runtime.v1.PublishEventRequest
+ (*BulkPublishRequest)(nil), // 15: dapr.proto.runtime.v1.BulkPublishRequest
+ (*BulkPublishRequestEntry)(nil), // 16: dapr.proto.runtime.v1.BulkPublishRequestEntry
+ (*BulkPublishResponse)(nil), // 17: dapr.proto.runtime.v1.BulkPublishResponse
+ (*BulkPublishResponseFailedEntry)(nil), // 18: dapr.proto.runtime.v1.BulkPublishResponseFailedEntry
+ (*InvokeBindingRequest)(nil), // 19: dapr.proto.runtime.v1.InvokeBindingRequest
+ (*InvokeBindingResponse)(nil), // 20: dapr.proto.runtime.v1.InvokeBindingResponse
+ (*GetSecretRequest)(nil), // 21: dapr.proto.runtime.v1.GetSecretRequest
+ (*GetSecretResponse)(nil), // 22: dapr.proto.runtime.v1.GetSecretResponse
+ (*GetBulkSecretRequest)(nil), // 23: dapr.proto.runtime.v1.GetBulkSecretRequest
+ (*SecretResponse)(nil), // 24: dapr.proto.runtime.v1.SecretResponse
+ (*GetBulkSecretResponse)(nil), // 25: dapr.proto.runtime.v1.GetBulkSecretResponse
+ (*TransactionalStateOperation)(nil), // 26: dapr.proto.runtime.v1.TransactionalStateOperation
+ (*ExecuteStateTransactionRequest)(nil), // 27: dapr.proto.runtime.v1.ExecuteStateTransactionRequest
+ (*RegisterActorTimerRequest)(nil), // 28: dapr.proto.runtime.v1.RegisterActorTimerRequest
+ (*UnregisterActorTimerRequest)(nil), // 29: dapr.proto.runtime.v1.UnregisterActorTimerRequest
+ (*RegisterActorReminderRequest)(nil), // 30: dapr.proto.runtime.v1.RegisterActorReminderRequest
+ (*UnregisterActorReminderRequest)(nil), // 31: dapr.proto.runtime.v1.UnregisterActorReminderRequest
+ (*RenameActorReminderRequest)(nil), // 32: dapr.proto.runtime.v1.RenameActorReminderRequest
+ (*GetActorStateRequest)(nil), // 33: dapr.proto.runtime.v1.GetActorStateRequest
+ (*GetActorStateResponse)(nil), // 34: dapr.proto.runtime.v1.GetActorStateResponse
+ (*ExecuteActorStateTransactionRequest)(nil), // 35: dapr.proto.runtime.v1.ExecuteActorStateTransactionRequest
+ (*TransactionalActorStateOperation)(nil), // 36: dapr.proto.runtime.v1.TransactionalActorStateOperation
+ (*InvokeActorRequest)(nil), // 37: dapr.proto.runtime.v1.InvokeActorRequest
+ (*InvokeActorResponse)(nil), // 38: dapr.proto.runtime.v1.InvokeActorResponse
+ (*GetMetadataResponse)(nil), // 39: dapr.proto.runtime.v1.GetMetadataResponse
+ (*ActiveActorsCount)(nil), // 40: dapr.proto.runtime.v1.ActiveActorsCount
+ (*RegisteredComponents)(nil), // 41: dapr.proto.runtime.v1.RegisteredComponents
+ (*MetadataHTTPEndpoint)(nil), // 42: dapr.proto.runtime.v1.MetadataHTTPEndpoint
+ (*PubsubSubscription)(nil), // 43: dapr.proto.runtime.v1.PubsubSubscription
+ (*PubsubSubscriptionRules)(nil), // 44: dapr.proto.runtime.v1.PubsubSubscriptionRules
+ (*PubsubSubscriptionRule)(nil), // 45: dapr.proto.runtime.v1.PubsubSubscriptionRule
+ (*SetMetadataRequest)(nil), // 46: dapr.proto.runtime.v1.SetMetadataRequest
+ (*GetConfigurationRequest)(nil), // 47: dapr.proto.runtime.v1.GetConfigurationRequest
+ (*GetConfigurationResponse)(nil), // 48: dapr.proto.runtime.v1.GetConfigurationResponse
+ (*SubscribeConfigurationRequest)(nil), // 49: dapr.proto.runtime.v1.SubscribeConfigurationRequest
+ (*UnsubscribeConfigurationRequest)(nil), // 50: dapr.proto.runtime.v1.UnsubscribeConfigurationRequest
+ (*SubscribeConfigurationResponse)(nil), // 51: dapr.proto.runtime.v1.SubscribeConfigurationResponse
+ (*UnsubscribeConfigurationResponse)(nil), // 52: dapr.proto.runtime.v1.UnsubscribeConfigurationResponse
+ (*TryLockRequest)(nil), // 53: dapr.proto.runtime.v1.TryLockRequest
+ (*TryLockResponse)(nil), // 54: dapr.proto.runtime.v1.TryLockResponse
+ (*UnlockRequest)(nil), // 55: dapr.proto.runtime.v1.UnlockRequest
+ (*UnlockResponse)(nil), // 56: dapr.proto.runtime.v1.UnlockResponse
+ (*SubtleGetKeyRequest)(nil), // 57: dapr.proto.runtime.v1.SubtleGetKeyRequest
+ (*SubtleGetKeyResponse)(nil), // 58: dapr.proto.runtime.v1.SubtleGetKeyResponse
+ (*SubtleEncryptRequest)(nil), // 59: dapr.proto.runtime.v1.SubtleEncryptRequest
+ (*SubtleEncryptResponse)(nil), // 60: dapr.proto.runtime.v1.SubtleEncryptResponse
+ (*SubtleDecryptRequest)(nil), // 61: dapr.proto.runtime.v1.SubtleDecryptRequest
+ (*SubtleDecryptResponse)(nil), // 62: dapr.proto.runtime.v1.SubtleDecryptResponse
+ (*SubtleWrapKeyRequest)(nil), // 63: dapr.proto.runtime.v1.SubtleWrapKeyRequest
+ (*SubtleWrapKeyResponse)(nil), // 64: dapr.proto.runtime.v1.SubtleWrapKeyResponse
+ (*SubtleUnwrapKeyRequest)(nil), // 65: dapr.proto.runtime.v1.SubtleUnwrapKeyRequest
+ (*SubtleUnwrapKeyResponse)(nil), // 66: dapr.proto.runtime.v1.SubtleUnwrapKeyResponse
+ (*SubtleSignRequest)(nil), // 67: dapr.proto.runtime.v1.SubtleSignRequest
+ (*SubtleSignResponse)(nil), // 68: dapr.proto.runtime.v1.SubtleSignResponse
+ (*SubtleVerifyRequest)(nil), // 69: dapr.proto.runtime.v1.SubtleVerifyRequest
+ (*SubtleVerifyResponse)(nil), // 70: dapr.proto.runtime.v1.SubtleVerifyResponse
+ (*EncryptRequest)(nil), // 71: dapr.proto.runtime.v1.EncryptRequest
+ (*EncryptRequestOptions)(nil), // 72: dapr.proto.runtime.v1.EncryptRequestOptions
+ (*EncryptResponse)(nil), // 73: dapr.proto.runtime.v1.EncryptResponse
+ (*DecryptRequest)(nil), // 74: dapr.proto.runtime.v1.DecryptRequest
+ (*DecryptRequestOptions)(nil), // 75: dapr.proto.runtime.v1.DecryptRequestOptions
+ (*DecryptResponse)(nil), // 76: dapr.proto.runtime.v1.DecryptResponse
+ (*GetWorkflowRequest)(nil), // 77: dapr.proto.runtime.v1.GetWorkflowRequest
+ (*GetWorkflowResponse)(nil), // 78: dapr.proto.runtime.v1.GetWorkflowResponse
+ (*StartWorkflowRequest)(nil), // 79: dapr.proto.runtime.v1.StartWorkflowRequest
+ (*StartWorkflowResponse)(nil), // 80: dapr.proto.runtime.v1.StartWorkflowResponse
+ (*TerminateWorkflowRequest)(nil), // 81: dapr.proto.runtime.v1.TerminateWorkflowRequest
+ (*PauseWorkflowRequest)(nil), // 82: dapr.proto.runtime.v1.PauseWorkflowRequest
+ (*ResumeWorkflowRequest)(nil), // 83: dapr.proto.runtime.v1.ResumeWorkflowRequest
+ (*RaiseEventWorkflowRequest)(nil), // 84: dapr.proto.runtime.v1.RaiseEventWorkflowRequest
+ (*PurgeWorkflowRequest)(nil), // 85: dapr.proto.runtime.v1.PurgeWorkflowRequest
+ nil, // 86: dapr.proto.runtime.v1.GetStateRequest.MetadataEntry
+ nil, // 87: dapr.proto.runtime.v1.GetBulkStateRequest.MetadataEntry
+ nil, // 88: dapr.proto.runtime.v1.BulkStateItem.MetadataEntry
+ nil, // 89: dapr.proto.runtime.v1.GetStateResponse.MetadataEntry
+ nil, // 90: dapr.proto.runtime.v1.DeleteStateRequest.MetadataEntry
+ nil, // 91: dapr.proto.runtime.v1.QueryStateRequest.MetadataEntry
+ nil, // 92: dapr.proto.runtime.v1.QueryStateResponse.MetadataEntry
+ nil, // 93: dapr.proto.runtime.v1.PublishEventRequest.MetadataEntry
+ nil, // 94: dapr.proto.runtime.v1.BulkPublishRequest.MetadataEntry
+ nil, // 95: dapr.proto.runtime.v1.BulkPublishRequestEntry.MetadataEntry
+ nil, // 96: dapr.proto.runtime.v1.InvokeBindingRequest.MetadataEntry
+ nil, // 97: dapr.proto.runtime.v1.InvokeBindingResponse.MetadataEntry
+ nil, // 98: dapr.proto.runtime.v1.GetSecretRequest.MetadataEntry
+ nil, // 99: dapr.proto.runtime.v1.GetSecretResponse.DataEntry
+ nil, // 100: dapr.proto.runtime.v1.GetBulkSecretRequest.MetadataEntry
+ nil, // 101: dapr.proto.runtime.v1.SecretResponse.SecretsEntry
+ nil, // 102: dapr.proto.runtime.v1.GetBulkSecretResponse.DataEntry
+ nil, // 103: dapr.proto.runtime.v1.ExecuteStateTransactionRequest.MetadataEntry
+ nil, // 104: dapr.proto.runtime.v1.TransactionalActorStateOperation.MetadataEntry
+ nil, // 105: dapr.proto.runtime.v1.InvokeActorRequest.MetadataEntry
+ nil, // 106: dapr.proto.runtime.v1.GetMetadataResponse.ExtendedMetadataEntry
+ nil, // 107: dapr.proto.runtime.v1.PubsubSubscription.MetadataEntry
+ nil, // 108: dapr.proto.runtime.v1.GetConfigurationRequest.MetadataEntry
+ nil, // 109: dapr.proto.runtime.v1.GetConfigurationResponse.ItemsEntry
+ nil, // 110: dapr.proto.runtime.v1.SubscribeConfigurationRequest.MetadataEntry
+ nil, // 111: dapr.proto.runtime.v1.SubscribeConfigurationResponse.ItemsEntry
+ nil, // 112: dapr.proto.runtime.v1.GetWorkflowResponse.PropertiesEntry
+ nil, // 113: dapr.proto.runtime.v1.StartWorkflowRequest.OptionsEntry
+ (*v1.InvokeRequest)(nil), // 114: dapr.proto.common.v1.InvokeRequest
+ (v1.StateOptions_StateConsistency)(0), // 115: dapr.proto.common.v1.StateOptions.StateConsistency
+ (*v1.Etag)(nil), // 116: dapr.proto.common.v1.Etag
+ (*v1.StateOptions)(nil), // 117: dapr.proto.common.v1.StateOptions
+ (*v1.StateItem)(nil), // 118: dapr.proto.common.v1.StateItem
+ (*anypb.Any)(nil), // 119: google.protobuf.Any
+ (*v1.StreamPayload)(nil), // 120: dapr.proto.common.v1.StreamPayload
+ (*timestamppb.Timestamp)(nil), // 121: google.protobuf.Timestamp
+ (*v1.ConfigurationItem)(nil), // 122: dapr.proto.common.v1.ConfigurationItem
+ (*emptypb.Empty)(nil), // 123: google.protobuf.Empty
+ (*v1.InvokeResponse)(nil), // 124: dapr.proto.common.v1.InvokeResponse
+}
+var file_dapr_proto_runtime_v1_dapr_proto_depIdxs = []int32{
+ 114, // 0: dapr.proto.runtime.v1.InvokeServiceRequest.message:type_name -> dapr.proto.common.v1.InvokeRequest
+ 115, // 1: dapr.proto.runtime.v1.GetStateRequest.consistency:type_name -> dapr.proto.common.v1.StateOptions.StateConsistency
+ 86, // 2: dapr.proto.runtime.v1.GetStateRequest.metadata:type_name -> dapr.proto.runtime.v1.GetStateRequest.MetadataEntry
+ 87, // 3: dapr.proto.runtime.v1.GetBulkStateRequest.metadata:type_name -> dapr.proto.runtime.v1.GetBulkStateRequest.MetadataEntry
+ 6, // 4: dapr.proto.runtime.v1.GetBulkStateResponse.items:type_name -> dapr.proto.runtime.v1.BulkStateItem
+ 88, // 5: dapr.proto.runtime.v1.BulkStateItem.metadata:type_name -> dapr.proto.runtime.v1.BulkStateItem.MetadataEntry
+ 89, // 6: dapr.proto.runtime.v1.GetStateResponse.metadata:type_name -> dapr.proto.runtime.v1.GetStateResponse.MetadataEntry
+ 116, // 7: dapr.proto.runtime.v1.DeleteStateRequest.etag:type_name -> dapr.proto.common.v1.Etag
+ 117, // 8: dapr.proto.runtime.v1.DeleteStateRequest.options:type_name -> dapr.proto.common.v1.StateOptions
+ 90, // 9: dapr.proto.runtime.v1.DeleteStateRequest.metadata:type_name -> dapr.proto.runtime.v1.DeleteStateRequest.MetadataEntry
+ 118, // 10: dapr.proto.runtime.v1.DeleteBulkStateRequest.states:type_name -> dapr.proto.common.v1.StateItem
+ 118, // 11: dapr.proto.runtime.v1.SaveStateRequest.states:type_name -> dapr.proto.common.v1.StateItem
+ 91, // 12: dapr.proto.runtime.v1.QueryStateRequest.metadata:type_name -> dapr.proto.runtime.v1.QueryStateRequest.MetadataEntry
+ 12, // 13: dapr.proto.runtime.v1.QueryStateResponse.results:type_name -> dapr.proto.runtime.v1.QueryStateItem
+ 92, // 14: dapr.proto.runtime.v1.QueryStateResponse.metadata:type_name -> dapr.proto.runtime.v1.QueryStateResponse.MetadataEntry
+ 93, // 15: dapr.proto.runtime.v1.PublishEventRequest.metadata:type_name -> dapr.proto.runtime.v1.PublishEventRequest.MetadataEntry
+ 16, // 16: dapr.proto.runtime.v1.BulkPublishRequest.entries:type_name -> dapr.proto.runtime.v1.BulkPublishRequestEntry
+ 94, // 17: dapr.proto.runtime.v1.BulkPublishRequest.metadata:type_name -> dapr.proto.runtime.v1.BulkPublishRequest.MetadataEntry
+ 95, // 18: dapr.proto.runtime.v1.BulkPublishRequestEntry.metadata:type_name -> dapr.proto.runtime.v1.BulkPublishRequestEntry.MetadataEntry
+ 18, // 19: dapr.proto.runtime.v1.BulkPublishResponse.failedEntries:type_name -> dapr.proto.runtime.v1.BulkPublishResponseFailedEntry
+ 96, // 20: dapr.proto.runtime.v1.InvokeBindingRequest.metadata:type_name -> dapr.proto.runtime.v1.InvokeBindingRequest.MetadataEntry
+ 97, // 21: dapr.proto.runtime.v1.InvokeBindingResponse.metadata:type_name -> dapr.proto.runtime.v1.InvokeBindingResponse.MetadataEntry
+ 98, // 22: dapr.proto.runtime.v1.GetSecretRequest.metadata:type_name -> dapr.proto.runtime.v1.GetSecretRequest.MetadataEntry
+ 99, // 23: dapr.proto.runtime.v1.GetSecretResponse.data:type_name -> dapr.proto.runtime.v1.GetSecretResponse.DataEntry
+ 100, // 24: dapr.proto.runtime.v1.GetBulkSecretRequest.metadata:type_name -> dapr.proto.runtime.v1.GetBulkSecretRequest.MetadataEntry
+ 101, // 25: dapr.proto.runtime.v1.SecretResponse.secrets:type_name -> dapr.proto.runtime.v1.SecretResponse.SecretsEntry
+ 102, // 26: dapr.proto.runtime.v1.GetBulkSecretResponse.data:type_name -> dapr.proto.runtime.v1.GetBulkSecretResponse.DataEntry
+ 118, // 27: dapr.proto.runtime.v1.TransactionalStateOperation.request:type_name -> dapr.proto.common.v1.StateItem
+ 26, // 28: dapr.proto.runtime.v1.ExecuteStateTransactionRequest.operations:type_name -> dapr.proto.runtime.v1.TransactionalStateOperation
+ 103, // 29: dapr.proto.runtime.v1.ExecuteStateTransactionRequest.metadata:type_name -> dapr.proto.runtime.v1.ExecuteStateTransactionRequest.MetadataEntry
+ 36, // 30: dapr.proto.runtime.v1.ExecuteActorStateTransactionRequest.operations:type_name -> dapr.proto.runtime.v1.TransactionalActorStateOperation
+ 119, // 31: dapr.proto.runtime.v1.TransactionalActorStateOperation.value:type_name -> google.protobuf.Any
+ 104, // 32: dapr.proto.runtime.v1.TransactionalActorStateOperation.metadata:type_name -> dapr.proto.runtime.v1.TransactionalActorStateOperation.MetadataEntry
+ 105, // 33: dapr.proto.runtime.v1.InvokeActorRequest.metadata:type_name -> dapr.proto.runtime.v1.InvokeActorRequest.MetadataEntry
+ 40, // 34: dapr.proto.runtime.v1.GetMetadataResponse.active_actors_count:type_name -> dapr.proto.runtime.v1.ActiveActorsCount
+ 41, // 35: dapr.proto.runtime.v1.GetMetadataResponse.registered_components:type_name -> dapr.proto.runtime.v1.RegisteredComponents
+ 106, // 36: dapr.proto.runtime.v1.GetMetadataResponse.extended_metadata:type_name -> dapr.proto.runtime.v1.GetMetadataResponse.ExtendedMetadataEntry
+ 43, // 37: dapr.proto.runtime.v1.GetMetadataResponse.subscriptions:type_name -> dapr.proto.runtime.v1.PubsubSubscription
+ 42, // 38: dapr.proto.runtime.v1.GetMetadataResponse.http_endpoints:type_name -> dapr.proto.runtime.v1.MetadataHTTPEndpoint
+ 107, // 39: dapr.proto.runtime.v1.PubsubSubscription.metadata:type_name -> dapr.proto.runtime.v1.PubsubSubscription.MetadataEntry
+ 44, // 40: dapr.proto.runtime.v1.PubsubSubscription.rules:type_name -> dapr.proto.runtime.v1.PubsubSubscriptionRules
+ 45, // 41: dapr.proto.runtime.v1.PubsubSubscriptionRules.rules:type_name -> dapr.proto.runtime.v1.PubsubSubscriptionRule
+ 108, // 42: dapr.proto.runtime.v1.GetConfigurationRequest.metadata:type_name -> dapr.proto.runtime.v1.GetConfigurationRequest.MetadataEntry
+ 109, // 43: dapr.proto.runtime.v1.GetConfigurationResponse.items:type_name -> dapr.proto.runtime.v1.GetConfigurationResponse.ItemsEntry
+ 110, // 44: dapr.proto.runtime.v1.SubscribeConfigurationRequest.metadata:type_name -> dapr.proto.runtime.v1.SubscribeConfigurationRequest.MetadataEntry
+ 111, // 45: dapr.proto.runtime.v1.SubscribeConfigurationResponse.items:type_name -> dapr.proto.runtime.v1.SubscribeConfigurationResponse.ItemsEntry
+ 0, // 46: dapr.proto.runtime.v1.UnlockResponse.status:type_name -> dapr.proto.runtime.v1.UnlockResponse.Status
+ 1, // 47: dapr.proto.runtime.v1.SubtleGetKeyRequest.format:type_name -> dapr.proto.runtime.v1.SubtleGetKeyRequest.KeyFormat
+ 72, // 48: dapr.proto.runtime.v1.EncryptRequest.options:type_name -> dapr.proto.runtime.v1.EncryptRequestOptions
+ 120, // 49: dapr.proto.runtime.v1.EncryptRequest.payload:type_name -> dapr.proto.common.v1.StreamPayload
+ 120, // 50: dapr.proto.runtime.v1.EncryptResponse.payload:type_name -> dapr.proto.common.v1.StreamPayload
+ 75, // 51: dapr.proto.runtime.v1.DecryptRequest.options:type_name -> dapr.proto.runtime.v1.DecryptRequestOptions
+ 120, // 52: dapr.proto.runtime.v1.DecryptRequest.payload:type_name -> dapr.proto.common.v1.StreamPayload
+ 120, // 53: dapr.proto.runtime.v1.DecryptResponse.payload:type_name -> dapr.proto.common.v1.StreamPayload
+ 121, // 54: dapr.proto.runtime.v1.GetWorkflowResponse.created_at:type_name -> google.protobuf.Timestamp
+ 121, // 55: dapr.proto.runtime.v1.GetWorkflowResponse.last_updated_at:type_name -> google.protobuf.Timestamp
+ 112, // 56: dapr.proto.runtime.v1.GetWorkflowResponse.properties:type_name -> dapr.proto.runtime.v1.GetWorkflowResponse.PropertiesEntry
+ 113, // 57: dapr.proto.runtime.v1.StartWorkflowRequest.options:type_name -> dapr.proto.runtime.v1.StartWorkflowRequest.OptionsEntry
+ 24, // 58: dapr.proto.runtime.v1.GetBulkSecretResponse.DataEntry.value:type_name -> dapr.proto.runtime.v1.SecretResponse
+ 122, // 59: dapr.proto.runtime.v1.GetConfigurationResponse.ItemsEntry.value:type_name -> dapr.proto.common.v1.ConfigurationItem
+ 122, // 60: dapr.proto.runtime.v1.SubscribeConfigurationResponse.ItemsEntry.value:type_name -> dapr.proto.common.v1.ConfigurationItem
+ 2, // 61: dapr.proto.runtime.v1.Dapr.InvokeService:input_type -> dapr.proto.runtime.v1.InvokeServiceRequest
+ 3, // 62: dapr.proto.runtime.v1.Dapr.GetState:input_type -> dapr.proto.runtime.v1.GetStateRequest
+ 4, // 63: dapr.proto.runtime.v1.Dapr.GetBulkState:input_type -> dapr.proto.runtime.v1.GetBulkStateRequest
+ 10, // 64: dapr.proto.runtime.v1.Dapr.SaveState:input_type -> dapr.proto.runtime.v1.SaveStateRequest
+ 11, // 65: dapr.proto.runtime.v1.Dapr.QueryStateAlpha1:input_type -> dapr.proto.runtime.v1.QueryStateRequest
+ 8, // 66: dapr.proto.runtime.v1.Dapr.DeleteState:input_type -> dapr.proto.runtime.v1.DeleteStateRequest
+ 9, // 67: dapr.proto.runtime.v1.Dapr.DeleteBulkState:input_type -> dapr.proto.runtime.v1.DeleteBulkStateRequest
+ 27, // 68: dapr.proto.runtime.v1.Dapr.ExecuteStateTransaction:input_type -> dapr.proto.runtime.v1.ExecuteStateTransactionRequest
+ 14, // 69: dapr.proto.runtime.v1.Dapr.PublishEvent:input_type -> dapr.proto.runtime.v1.PublishEventRequest
+ 15, // 70: dapr.proto.runtime.v1.Dapr.BulkPublishEventAlpha1:input_type -> dapr.proto.runtime.v1.BulkPublishRequest
+ 19, // 71: dapr.proto.runtime.v1.Dapr.InvokeBinding:input_type -> dapr.proto.runtime.v1.InvokeBindingRequest
+ 21, // 72: dapr.proto.runtime.v1.Dapr.GetSecret:input_type -> dapr.proto.runtime.v1.GetSecretRequest
+ 23, // 73: dapr.proto.runtime.v1.Dapr.GetBulkSecret:input_type -> dapr.proto.runtime.v1.GetBulkSecretRequest
+ 28, // 74: dapr.proto.runtime.v1.Dapr.RegisterActorTimer:input_type -> dapr.proto.runtime.v1.RegisterActorTimerRequest
+ 29, // 75: dapr.proto.runtime.v1.Dapr.UnregisterActorTimer:input_type -> dapr.proto.runtime.v1.UnregisterActorTimerRequest
+ 30, // 76: dapr.proto.runtime.v1.Dapr.RegisterActorReminder:input_type -> dapr.proto.runtime.v1.RegisterActorReminderRequest
+ 31, // 77: dapr.proto.runtime.v1.Dapr.UnregisterActorReminder:input_type -> dapr.proto.runtime.v1.UnregisterActorReminderRequest
+ 32, // 78: dapr.proto.runtime.v1.Dapr.RenameActorReminder:input_type -> dapr.proto.runtime.v1.RenameActorReminderRequest
+ 33, // 79: dapr.proto.runtime.v1.Dapr.GetActorState:input_type -> dapr.proto.runtime.v1.GetActorStateRequest
+ 35, // 80: dapr.proto.runtime.v1.Dapr.ExecuteActorStateTransaction:input_type -> dapr.proto.runtime.v1.ExecuteActorStateTransactionRequest
+ 37, // 81: dapr.proto.runtime.v1.Dapr.InvokeActor:input_type -> dapr.proto.runtime.v1.InvokeActorRequest
+ 47, // 82: dapr.proto.runtime.v1.Dapr.GetConfigurationAlpha1:input_type -> dapr.proto.runtime.v1.GetConfigurationRequest
+ 47, // 83: dapr.proto.runtime.v1.Dapr.GetConfiguration:input_type -> dapr.proto.runtime.v1.GetConfigurationRequest
+ 49, // 84: dapr.proto.runtime.v1.Dapr.SubscribeConfigurationAlpha1:input_type -> dapr.proto.runtime.v1.SubscribeConfigurationRequest
+ 49, // 85: dapr.proto.runtime.v1.Dapr.SubscribeConfiguration:input_type -> dapr.proto.runtime.v1.SubscribeConfigurationRequest
+ 50, // 86: dapr.proto.runtime.v1.Dapr.UnsubscribeConfigurationAlpha1:input_type -> dapr.proto.runtime.v1.UnsubscribeConfigurationRequest
+ 50, // 87: dapr.proto.runtime.v1.Dapr.UnsubscribeConfiguration:input_type -> dapr.proto.runtime.v1.UnsubscribeConfigurationRequest
+ 53, // 88: dapr.proto.runtime.v1.Dapr.TryLockAlpha1:input_type -> dapr.proto.runtime.v1.TryLockRequest
+ 55, // 89: dapr.proto.runtime.v1.Dapr.UnlockAlpha1:input_type -> dapr.proto.runtime.v1.UnlockRequest
+ 71, // 90: dapr.proto.runtime.v1.Dapr.EncryptAlpha1:input_type -> dapr.proto.runtime.v1.EncryptRequest
+ 74, // 91: dapr.proto.runtime.v1.Dapr.DecryptAlpha1:input_type -> dapr.proto.runtime.v1.DecryptRequest
+ 123, // 92: dapr.proto.runtime.v1.Dapr.GetMetadata:input_type -> google.protobuf.Empty
+ 46, // 93: dapr.proto.runtime.v1.Dapr.SetMetadata:input_type -> dapr.proto.runtime.v1.SetMetadataRequest
+ 57, // 94: dapr.proto.runtime.v1.Dapr.SubtleGetKeyAlpha1:input_type -> dapr.proto.runtime.v1.SubtleGetKeyRequest
+ 59, // 95: dapr.proto.runtime.v1.Dapr.SubtleEncryptAlpha1:input_type -> dapr.proto.runtime.v1.SubtleEncryptRequest
+ 61, // 96: dapr.proto.runtime.v1.Dapr.SubtleDecryptAlpha1:input_type -> dapr.proto.runtime.v1.SubtleDecryptRequest
+ 63, // 97: dapr.proto.runtime.v1.Dapr.SubtleWrapKeyAlpha1:input_type -> dapr.proto.runtime.v1.SubtleWrapKeyRequest
+ 65, // 98: dapr.proto.runtime.v1.Dapr.SubtleUnwrapKeyAlpha1:input_type -> dapr.proto.runtime.v1.SubtleUnwrapKeyRequest
+ 67, // 99: dapr.proto.runtime.v1.Dapr.SubtleSignAlpha1:input_type -> dapr.proto.runtime.v1.SubtleSignRequest
+ 69, // 100: dapr.proto.runtime.v1.Dapr.SubtleVerifyAlpha1:input_type -> dapr.proto.runtime.v1.SubtleVerifyRequest
+ 79, // 101: dapr.proto.runtime.v1.Dapr.StartWorkflowAlpha1:input_type -> dapr.proto.runtime.v1.StartWorkflowRequest
+ 77, // 102: dapr.proto.runtime.v1.Dapr.GetWorkflowAlpha1:input_type -> dapr.proto.runtime.v1.GetWorkflowRequest
+ 85, // 103: dapr.proto.runtime.v1.Dapr.PurgeWorkflowAlpha1:input_type -> dapr.proto.runtime.v1.PurgeWorkflowRequest
+ 81, // 104: dapr.proto.runtime.v1.Dapr.TerminateWorkflowAlpha1:input_type -> dapr.proto.runtime.v1.TerminateWorkflowRequest
+ 82, // 105: dapr.proto.runtime.v1.Dapr.PauseWorkflowAlpha1:input_type -> dapr.proto.runtime.v1.PauseWorkflowRequest
+ 83, // 106: dapr.proto.runtime.v1.Dapr.ResumeWorkflowAlpha1:input_type -> dapr.proto.runtime.v1.ResumeWorkflowRequest
+ 84, // 107: dapr.proto.runtime.v1.Dapr.RaiseEventWorkflowAlpha1:input_type -> dapr.proto.runtime.v1.RaiseEventWorkflowRequest
+ 123, // 108: dapr.proto.runtime.v1.Dapr.Shutdown:input_type -> google.protobuf.Empty
+ 124, // 109: dapr.proto.runtime.v1.Dapr.InvokeService:output_type -> dapr.proto.common.v1.InvokeResponse
+ 7, // 110: dapr.proto.runtime.v1.Dapr.GetState:output_type -> dapr.proto.runtime.v1.GetStateResponse
+ 5, // 111: dapr.proto.runtime.v1.Dapr.GetBulkState:output_type -> dapr.proto.runtime.v1.GetBulkStateResponse
+ 123, // 112: dapr.proto.runtime.v1.Dapr.SaveState:output_type -> google.protobuf.Empty
+ 13, // 113: dapr.proto.runtime.v1.Dapr.QueryStateAlpha1:output_type -> dapr.proto.runtime.v1.QueryStateResponse
+ 123, // 114: dapr.proto.runtime.v1.Dapr.DeleteState:output_type -> google.protobuf.Empty
+ 123, // 115: dapr.proto.runtime.v1.Dapr.DeleteBulkState:output_type -> google.protobuf.Empty
+ 123, // 116: dapr.proto.runtime.v1.Dapr.ExecuteStateTransaction:output_type -> google.protobuf.Empty
+ 123, // 117: dapr.proto.runtime.v1.Dapr.PublishEvent:output_type -> google.protobuf.Empty
+ 17, // 118: dapr.proto.runtime.v1.Dapr.BulkPublishEventAlpha1:output_type -> dapr.proto.runtime.v1.BulkPublishResponse
+ 20, // 119: dapr.proto.runtime.v1.Dapr.InvokeBinding:output_type -> dapr.proto.runtime.v1.InvokeBindingResponse
+ 22, // 120: dapr.proto.runtime.v1.Dapr.GetSecret:output_type -> dapr.proto.runtime.v1.GetSecretResponse
+ 25, // 121: dapr.proto.runtime.v1.Dapr.GetBulkSecret:output_type -> dapr.proto.runtime.v1.GetBulkSecretResponse
+ 123, // 122: dapr.proto.runtime.v1.Dapr.RegisterActorTimer:output_type -> google.protobuf.Empty
+ 123, // 123: dapr.proto.runtime.v1.Dapr.UnregisterActorTimer:output_type -> google.protobuf.Empty
+ 123, // 124: dapr.proto.runtime.v1.Dapr.RegisterActorReminder:output_type -> google.protobuf.Empty
+ 123, // 125: dapr.proto.runtime.v1.Dapr.UnregisterActorReminder:output_type -> google.protobuf.Empty
+ 123, // 126: dapr.proto.runtime.v1.Dapr.RenameActorReminder:output_type -> google.protobuf.Empty
+ 34, // 127: dapr.proto.runtime.v1.Dapr.GetActorState:output_type -> dapr.proto.runtime.v1.GetActorStateResponse
+ 123, // 128: dapr.proto.runtime.v1.Dapr.ExecuteActorStateTransaction:output_type -> google.protobuf.Empty
+ 38, // 129: dapr.proto.runtime.v1.Dapr.InvokeActor:output_type -> dapr.proto.runtime.v1.InvokeActorResponse
+ 48, // 130: dapr.proto.runtime.v1.Dapr.GetConfigurationAlpha1:output_type -> dapr.proto.runtime.v1.GetConfigurationResponse
+ 48, // 131: dapr.proto.runtime.v1.Dapr.GetConfiguration:output_type -> dapr.proto.runtime.v1.GetConfigurationResponse
+ 51, // 132: dapr.proto.runtime.v1.Dapr.SubscribeConfigurationAlpha1:output_type -> dapr.proto.runtime.v1.SubscribeConfigurationResponse
+ 51, // 133: dapr.proto.runtime.v1.Dapr.SubscribeConfiguration:output_type -> dapr.proto.runtime.v1.SubscribeConfigurationResponse
+ 52, // 134: dapr.proto.runtime.v1.Dapr.UnsubscribeConfigurationAlpha1:output_type -> dapr.proto.runtime.v1.UnsubscribeConfigurationResponse
+ 52, // 135: dapr.proto.runtime.v1.Dapr.UnsubscribeConfiguration:output_type -> dapr.proto.runtime.v1.UnsubscribeConfigurationResponse
+ 54, // 136: dapr.proto.runtime.v1.Dapr.TryLockAlpha1:output_type -> dapr.proto.runtime.v1.TryLockResponse
+ 56, // 137: dapr.proto.runtime.v1.Dapr.UnlockAlpha1:output_type -> dapr.proto.runtime.v1.UnlockResponse
+ 73, // 138: dapr.proto.runtime.v1.Dapr.EncryptAlpha1:output_type -> dapr.proto.runtime.v1.EncryptResponse
+ 76, // 139: dapr.proto.runtime.v1.Dapr.DecryptAlpha1:output_type -> dapr.proto.runtime.v1.DecryptResponse
+ 39, // 140: dapr.proto.runtime.v1.Dapr.GetMetadata:output_type -> dapr.proto.runtime.v1.GetMetadataResponse
+ 123, // 141: dapr.proto.runtime.v1.Dapr.SetMetadata:output_type -> google.protobuf.Empty
+ 58, // 142: dapr.proto.runtime.v1.Dapr.SubtleGetKeyAlpha1:output_type -> dapr.proto.runtime.v1.SubtleGetKeyResponse
+ 60, // 143: dapr.proto.runtime.v1.Dapr.SubtleEncryptAlpha1:output_type -> dapr.proto.runtime.v1.SubtleEncryptResponse
+ 62, // 144: dapr.proto.runtime.v1.Dapr.SubtleDecryptAlpha1:output_type -> dapr.proto.runtime.v1.SubtleDecryptResponse
+ 64, // 145: dapr.proto.runtime.v1.Dapr.SubtleWrapKeyAlpha1:output_type -> dapr.proto.runtime.v1.SubtleWrapKeyResponse
+ 66, // 146: dapr.proto.runtime.v1.Dapr.SubtleUnwrapKeyAlpha1:output_type -> dapr.proto.runtime.v1.SubtleUnwrapKeyResponse
+ 68, // 147: dapr.proto.runtime.v1.Dapr.SubtleSignAlpha1:output_type -> dapr.proto.runtime.v1.SubtleSignResponse
+ 70, // 148: dapr.proto.runtime.v1.Dapr.SubtleVerifyAlpha1:output_type -> dapr.proto.runtime.v1.SubtleVerifyResponse
+ 80, // 149: dapr.proto.runtime.v1.Dapr.StartWorkflowAlpha1:output_type -> dapr.proto.runtime.v1.StartWorkflowResponse
+ 78, // 150: dapr.proto.runtime.v1.Dapr.GetWorkflowAlpha1:output_type -> dapr.proto.runtime.v1.GetWorkflowResponse
+ 123, // 151: dapr.proto.runtime.v1.Dapr.PurgeWorkflowAlpha1:output_type -> google.protobuf.Empty
+ 123, // 152: dapr.proto.runtime.v1.Dapr.TerminateWorkflowAlpha1:output_type -> google.protobuf.Empty
+ 123, // 153: dapr.proto.runtime.v1.Dapr.PauseWorkflowAlpha1:output_type -> google.protobuf.Empty
+ 123, // 154: dapr.proto.runtime.v1.Dapr.ResumeWorkflowAlpha1:output_type -> google.protobuf.Empty
+ 123, // 155: dapr.proto.runtime.v1.Dapr.RaiseEventWorkflowAlpha1:output_type -> google.protobuf.Empty
+ 123, // 156: dapr.proto.runtime.v1.Dapr.Shutdown:output_type -> google.protobuf.Empty
+ 109, // [109:157] is the sub-list for method output_type
+ 61, // [61:109] is the sub-list for method input_type
+ 61, // [61:61] is the sub-list for extension type_name
+ 61, // [61:61] is the sub-list for extension extendee
+ 0, // [0:61] is the sub-list for field type_name
+}
+
+func init() { file_dapr_proto_runtime_v1_dapr_proto_init() }
+func file_dapr_proto_runtime_v1_dapr_proto_init() {
+ if File_dapr_proto_runtime_v1_dapr_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*InvokeServiceRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetStateRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetBulkStateRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetBulkStateResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*BulkStateItem); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetStateResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*DeleteStateRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*DeleteBulkStateRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SaveStateRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*QueryStateRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*QueryStateItem); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*QueryStateResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PublishEventRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*BulkPublishRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*BulkPublishRequestEntry); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*BulkPublishResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*BulkPublishResponseFailedEntry); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*InvokeBindingRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*InvokeBindingResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetSecretRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetSecretResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetBulkSecretRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SecretResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetBulkSecretResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TransactionalStateOperation); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ExecuteStateTransactionRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*RegisterActorTimerRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UnregisterActorTimerRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*RegisterActorReminderRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UnregisterActorReminderRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*RenameActorReminderRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetActorStateRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetActorStateResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ExecuteActorStateTransactionRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TransactionalActorStateOperation); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*InvokeActorRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*InvokeActorResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetMetadataResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ActiveActorsCount); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*RegisteredComponents); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*MetadataHTTPEndpoint); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PubsubSubscription); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PubsubSubscriptionRules); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PubsubSubscriptionRule); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SetMetadataRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetConfigurationRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetConfigurationResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubscribeConfigurationRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UnsubscribeConfigurationRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubscribeConfigurationResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UnsubscribeConfigurationResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TryLockRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TryLockResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UnlockRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UnlockResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleGetKeyRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleGetKeyResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleEncryptRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleEncryptResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleDecryptRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleDecryptResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleWrapKeyRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleWrapKeyResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleUnwrapKeyRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleUnwrapKeyResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleSignRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleSignResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleVerifyRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*SubtleVerifyResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*EncryptRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*EncryptRequestOptions); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*EncryptResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*DecryptRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*DecryptRequestOptions); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*DecryptResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetWorkflowRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetWorkflowResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*StartWorkflowRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*StartWorkflowResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*TerminateWorkflowRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PauseWorkflowRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ResumeWorkflowRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*RaiseEventWorkflowRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_dapr_proto_runtime_v1_dapr_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PurgeWorkflowRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_dapr_proto_runtime_v1_dapr_proto_rawDesc,
+ NumEnums: 2,
+ NumMessages: 112,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_dapr_proto_runtime_v1_dapr_proto_goTypes,
+ DependencyIndexes: file_dapr_proto_runtime_v1_dapr_proto_depIdxs,
+ EnumInfos: file_dapr_proto_runtime_v1_dapr_proto_enumTypes,
+ MessageInfos: file_dapr_proto_runtime_v1_dapr_proto_msgTypes,
+ }.Build()
+ File_dapr_proto_runtime_v1_dapr_proto = out.File
+ file_dapr_proto_runtime_v1_dapr_proto_rawDesc = nil
+ file_dapr_proto_runtime_v1_dapr_proto_goTypes = nil
+ file_dapr_proto_runtime_v1_dapr_proto_depIdxs = nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/dapr_additional.go b/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/dapr_additional.go
new file mode 100644
index 00000000000..f122a1c15a9
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/dapr_additional.go
@@ -0,0 +1,154 @@
+/*
+Copyright 2023 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package runtime
+
+import (
+ "google.golang.org/protobuf/proto"
+
+ commonv1pb "github.com/dapr/go-sdk/dapr/proto/common/v1"
+)
+
+// This file contains additional, hand-written methods added to the generated objects.
+
+// SubtleCryptoRequests is an interface for all Subtle*Request structs.
+type SubtleCryptoRequests interface {
+ // SetComponentName sets the value of the ComponentName property.
+ SetComponentName(name string)
+}
+
+func (x *SubtleGetKeyRequest) SetComponentName(name string) {
+ if x != nil {
+ x.ComponentName = name
+ }
+}
+
+func (x *SubtleEncryptRequest) SetComponentName(name string) {
+ if x != nil {
+ x.ComponentName = name
+ }
+}
+
+func (x *SubtleDecryptRequest) SetComponentName(name string) {
+ if x != nil {
+ x.ComponentName = name
+ }
+}
+
+func (x *SubtleWrapKeyRequest) SetComponentName(name string) {
+ if x != nil {
+ x.ComponentName = name
+ }
+}
+
+func (x *SubtleUnwrapKeyRequest) SetComponentName(name string) {
+ if x != nil {
+ x.ComponentName = name
+ }
+}
+
+func (x *SubtleSignRequest) SetComponentName(name string) {
+ if x != nil {
+ x.ComponentName = name
+ }
+}
+
+func (x *SubtleVerifyRequest) SetComponentName(name string) {
+ if x != nil {
+ x.ComponentName = name
+ }
+}
+
+// CryptoRequests is an interface for EncryptRequest and DecryptRequest.
+type CryptoRequests interface {
+ proto.Message
+
+ // SetPayload sets the payload.
+ SetPayload(payload *commonv1pb.StreamPayload)
+ // GetPayload returns the payload.
+ GetPayload() *commonv1pb.StreamPayload
+ // Reset the object.
+ Reset()
+ // SetOptions sets the Options property.
+ SetOptions(opts proto.Message)
+ // HasOptions returns true if the Options property is not empty.
+ HasOptions() bool
+}
+
+func (x *EncryptRequest) SetPayload(payload *commonv1pb.StreamPayload) {
+ if x == nil {
+ return
+ }
+
+ x.Payload = payload
+}
+
+func (x *EncryptRequest) SetOptions(opts proto.Message) {
+ if x == nil {
+ return
+ }
+
+ x.Options = opts.(*EncryptRequestOptions)
+}
+
+func (x *EncryptRequest) HasOptions() bool {
+ return x != nil && x.Options != nil
+}
+
+func (x *DecryptRequest) SetPayload(payload *commonv1pb.StreamPayload) {
+ if x == nil {
+ return
+ }
+
+ x.Payload = payload
+}
+
+func (x *DecryptRequest) SetOptions(opts proto.Message) {
+ if x == nil {
+ return
+ }
+
+ x.Options = opts.(*DecryptRequestOptions)
+}
+
+func (x *DecryptRequest) HasOptions() bool {
+ return x != nil && x.Options != nil
+}
+
+// CryptoResponses is an interface for EncryptResponse and DecryptResponse.
+type CryptoResponses interface {
+ proto.Message
+
+ // SetPayload sets the payload.
+ SetPayload(payload *commonv1pb.StreamPayload)
+ // GetPayload returns the payload.
+ GetPayload() *commonv1pb.StreamPayload
+ // Reset the object.
+ Reset()
+}
+
+func (x *EncryptResponse) SetPayload(payload *commonv1pb.StreamPayload) {
+ if x == nil {
+ return
+ }
+
+ x.Payload = payload
+}
+
+func (x *DecryptResponse) SetPayload(payload *commonv1pb.StreamPayload) {
+ if x == nil {
+ return
+ }
+
+ x.Payload = payload
+}
diff --git a/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/dapr_grpc.pb.go b/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/dapr_grpc.pb.go
new file mode 100644
index 00000000000..f3e9484feab
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/dapr/proto/runtime/v1/dapr_grpc.pb.go
@@ -0,0 +1,2014 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.2.0
+// - protoc v3.21.12
+// source: dapr/proto/runtime/v1/dapr.proto
+
+package runtime
+
+import (
+ context "context"
+ v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+ emptypb "google.golang.org/protobuf/types/known/emptypb"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// DaprClient is the client API for Dapr service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type DaprClient interface {
+ // Invokes a method on a remote Dapr app.
+ // Deprecated: Use proxy mode service invocation instead.
+ InvokeService(ctx context.Context, in *InvokeServiceRequest, opts ...grpc.CallOption) (*v1.InvokeResponse, error)
+ // Gets the state for a specific key.
+ GetState(ctx context.Context, in *GetStateRequest, opts ...grpc.CallOption) (*GetStateResponse, error)
+ // Gets a bulk of state items for a list of keys
+ GetBulkState(ctx context.Context, in *GetBulkStateRequest, opts ...grpc.CallOption) (*GetBulkStateResponse, error)
+ // Saves the state for a specific key.
+ SaveState(ctx context.Context, in *SaveStateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Queries the state.
+ QueryStateAlpha1(ctx context.Context, in *QueryStateRequest, opts ...grpc.CallOption) (*QueryStateResponse, error)
+ // Deletes the state for a specific key.
+ DeleteState(ctx context.Context, in *DeleteStateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Deletes a bulk of state items for a list of keys
+ DeleteBulkState(ctx context.Context, in *DeleteBulkStateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Executes transactions for a specified store
+ ExecuteStateTransaction(ctx context.Context, in *ExecuteStateTransactionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Publishes events to the specific topic.
+ PublishEvent(ctx context.Context, in *PublishEventRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Bulk Publishes multiple events to the specified topic.
+ BulkPublishEventAlpha1(ctx context.Context, in *BulkPublishRequest, opts ...grpc.CallOption) (*BulkPublishResponse, error)
+ // Invokes binding data to specific output bindings
+ InvokeBinding(ctx context.Context, in *InvokeBindingRequest, opts ...grpc.CallOption) (*InvokeBindingResponse, error)
+ // Gets secrets from secret stores.
+ GetSecret(ctx context.Context, in *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error)
+ // Gets a bulk of secrets
+ GetBulkSecret(ctx context.Context, in *GetBulkSecretRequest, opts ...grpc.CallOption) (*GetBulkSecretResponse, error)
+ // Register an actor timer.
+ RegisterActorTimer(ctx context.Context, in *RegisterActorTimerRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Unregister an actor timer.
+ UnregisterActorTimer(ctx context.Context, in *UnregisterActorTimerRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Register an actor reminder.
+ RegisterActorReminder(ctx context.Context, in *RegisterActorReminderRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Unregister an actor reminder.
+ UnregisterActorReminder(ctx context.Context, in *UnregisterActorReminderRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Rename an actor reminder.
+ RenameActorReminder(ctx context.Context, in *RenameActorReminderRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Gets the state for a specific actor.
+ GetActorState(ctx context.Context, in *GetActorStateRequest, opts ...grpc.CallOption) (*GetActorStateResponse, error)
+ // Executes state transactions for a specified actor
+ ExecuteActorStateTransaction(ctx context.Context, in *ExecuteActorStateTransactionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // InvokeActor calls a method on an actor.
+ InvokeActor(ctx context.Context, in *InvokeActorRequest, opts ...grpc.CallOption) (*InvokeActorResponse, error)
+ // GetConfiguration gets configuration from configuration store.
+ GetConfigurationAlpha1(ctx context.Context, in *GetConfigurationRequest, opts ...grpc.CallOption) (*GetConfigurationResponse, error)
+ // GetConfiguration gets configuration from configuration store.
+ GetConfiguration(ctx context.Context, in *GetConfigurationRequest, opts ...grpc.CallOption) (*GetConfigurationResponse, error)
+ // SubscribeConfiguration gets configuration from configuration store and subscribe the updates event by grpc stream
+ SubscribeConfigurationAlpha1(ctx context.Context, in *SubscribeConfigurationRequest, opts ...grpc.CallOption) (Dapr_SubscribeConfigurationAlpha1Client, error)
+ // SubscribeConfiguration gets configuration from configuration store and subscribe the updates event by grpc stream
+ SubscribeConfiguration(ctx context.Context, in *SubscribeConfigurationRequest, opts ...grpc.CallOption) (Dapr_SubscribeConfigurationClient, error)
+ // UnSubscribeConfiguration unsubscribe the subscription of configuration
+ UnsubscribeConfigurationAlpha1(ctx context.Context, in *UnsubscribeConfigurationRequest, opts ...grpc.CallOption) (*UnsubscribeConfigurationResponse, error)
+ // UnSubscribeConfiguration unsubscribe the subscription of configuration
+ UnsubscribeConfiguration(ctx context.Context, in *UnsubscribeConfigurationRequest, opts ...grpc.CallOption) (*UnsubscribeConfigurationResponse, error)
+ // TryLockAlpha1 tries to get a lock with an expiry.
+ TryLockAlpha1(ctx context.Context, in *TryLockRequest, opts ...grpc.CallOption) (*TryLockResponse, error)
+ // UnlockAlpha1 unlocks a lock.
+ UnlockAlpha1(ctx context.Context, in *UnlockRequest, opts ...grpc.CallOption) (*UnlockResponse, error)
+ // EncryptAlpha1 encrypts a message using the Dapr encryption scheme and a key stored in the vault.
+ EncryptAlpha1(ctx context.Context, opts ...grpc.CallOption) (Dapr_EncryptAlpha1Client, error)
+ // DecryptAlpha1 decrypts a message using the Dapr encryption scheme and a key stored in the vault.
+ DecryptAlpha1(ctx context.Context, opts ...grpc.CallOption) (Dapr_DecryptAlpha1Client, error)
+ // Gets metadata of the sidecar
+ GetMetadata(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetMetadataResponse, error)
+ // Sets value in extended metadata of the sidecar
+ SetMetadata(ctx context.Context, in *SetMetadataRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // SubtleGetKeyAlpha1 returns the public part of an asymmetric key stored in the vault.
+ SubtleGetKeyAlpha1(ctx context.Context, in *SubtleGetKeyRequest, opts ...grpc.CallOption) (*SubtleGetKeyResponse, error)
+ // SubtleEncryptAlpha1 encrypts a small message using a key stored in the vault.
+ SubtleEncryptAlpha1(ctx context.Context, in *SubtleEncryptRequest, opts ...grpc.CallOption) (*SubtleEncryptResponse, error)
+ // SubtleDecryptAlpha1 decrypts a small message using a key stored in the vault.
+ SubtleDecryptAlpha1(ctx context.Context, in *SubtleDecryptRequest, opts ...grpc.CallOption) (*SubtleDecryptResponse, error)
+ // SubtleWrapKeyAlpha1 wraps a key using a key stored in the vault.
+ SubtleWrapKeyAlpha1(ctx context.Context, in *SubtleWrapKeyRequest, opts ...grpc.CallOption) (*SubtleWrapKeyResponse, error)
+ // SubtleUnwrapKeyAlpha1 unwraps a key using a key stored in the vault.
+ SubtleUnwrapKeyAlpha1(ctx context.Context, in *SubtleUnwrapKeyRequest, opts ...grpc.CallOption) (*SubtleUnwrapKeyResponse, error)
+ // SubtleSignAlpha1 signs a message using a key stored in the vault.
+ SubtleSignAlpha1(ctx context.Context, in *SubtleSignRequest, opts ...grpc.CallOption) (*SubtleSignResponse, error)
+ // SubtleVerifyAlpha1 verifies the signature of a message using a key stored in the vault.
+ SubtleVerifyAlpha1(ctx context.Context, in *SubtleVerifyRequest, opts ...grpc.CallOption) (*SubtleVerifyResponse, error)
+ // Starts a new instance of a workflow
+ StartWorkflowAlpha1(ctx context.Context, in *StartWorkflowRequest, opts ...grpc.CallOption) (*StartWorkflowResponse, error)
+ // Gets details about a started workflow instance
+ GetWorkflowAlpha1(ctx context.Context, in *GetWorkflowRequest, opts ...grpc.CallOption) (*GetWorkflowResponse, error)
+ // Purge Workflow
+ PurgeWorkflowAlpha1(ctx context.Context, in *PurgeWorkflowRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Terminates a running workflow instance
+ TerminateWorkflowAlpha1(ctx context.Context, in *TerminateWorkflowRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Pauses a running workflow instance
+ PauseWorkflowAlpha1(ctx context.Context, in *PauseWorkflowRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Resumes a paused workflow instance
+ ResumeWorkflowAlpha1(ctx context.Context, in *ResumeWorkflowRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Raise an event to a running workflow instance
+ RaiseEventWorkflowAlpha1(ctx context.Context, in *RaiseEventWorkflowRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Shutdown the sidecar
+ Shutdown(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error)
+}
+
+type daprClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewDaprClient(cc grpc.ClientConnInterface) DaprClient {
+ return &daprClient{cc}
+}
+
+func (c *daprClient) InvokeService(ctx context.Context, in *InvokeServiceRequest, opts ...grpc.CallOption) (*v1.InvokeResponse, error) {
+ out := new(v1.InvokeResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/InvokeService", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) GetState(ctx context.Context, in *GetStateRequest, opts ...grpc.CallOption) (*GetStateResponse, error) {
+ out := new(GetStateResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/GetState", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) GetBulkState(ctx context.Context, in *GetBulkStateRequest, opts ...grpc.CallOption) (*GetBulkStateResponse, error) {
+ out := new(GetBulkStateResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/GetBulkState", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) SaveState(ctx context.Context, in *SaveStateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/SaveState", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) QueryStateAlpha1(ctx context.Context, in *QueryStateRequest, opts ...grpc.CallOption) (*QueryStateResponse, error) {
+ out := new(QueryStateResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/QueryStateAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) DeleteState(ctx context.Context, in *DeleteStateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/DeleteState", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) DeleteBulkState(ctx context.Context, in *DeleteBulkStateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/DeleteBulkState", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) ExecuteStateTransaction(ctx context.Context, in *ExecuteStateTransactionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/ExecuteStateTransaction", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) PublishEvent(ctx context.Context, in *PublishEventRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/PublishEvent", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) BulkPublishEventAlpha1(ctx context.Context, in *BulkPublishRequest, opts ...grpc.CallOption) (*BulkPublishResponse, error) {
+ out := new(BulkPublishResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/BulkPublishEventAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) InvokeBinding(ctx context.Context, in *InvokeBindingRequest, opts ...grpc.CallOption) (*InvokeBindingResponse, error) {
+ out := new(InvokeBindingResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/InvokeBinding", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) GetSecret(ctx context.Context, in *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error) {
+ out := new(GetSecretResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/GetSecret", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) GetBulkSecret(ctx context.Context, in *GetBulkSecretRequest, opts ...grpc.CallOption) (*GetBulkSecretResponse, error) {
+ out := new(GetBulkSecretResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/GetBulkSecret", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) RegisterActorTimer(ctx context.Context, in *RegisterActorTimerRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/RegisterActorTimer", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) UnregisterActorTimer(ctx context.Context, in *UnregisterActorTimerRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/UnregisterActorTimer", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) RegisterActorReminder(ctx context.Context, in *RegisterActorReminderRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/RegisterActorReminder", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) UnregisterActorReminder(ctx context.Context, in *UnregisterActorReminderRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/UnregisterActorReminder", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) RenameActorReminder(ctx context.Context, in *RenameActorReminderRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/RenameActorReminder", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) GetActorState(ctx context.Context, in *GetActorStateRequest, opts ...grpc.CallOption) (*GetActorStateResponse, error) {
+ out := new(GetActorStateResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/GetActorState", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) ExecuteActorStateTransaction(ctx context.Context, in *ExecuteActorStateTransactionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/ExecuteActorStateTransaction", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) InvokeActor(ctx context.Context, in *InvokeActorRequest, opts ...grpc.CallOption) (*InvokeActorResponse, error) {
+ out := new(InvokeActorResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/InvokeActor", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) GetConfigurationAlpha1(ctx context.Context, in *GetConfigurationRequest, opts ...grpc.CallOption) (*GetConfigurationResponse, error) {
+ out := new(GetConfigurationResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/GetConfigurationAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) GetConfiguration(ctx context.Context, in *GetConfigurationRequest, opts ...grpc.CallOption) (*GetConfigurationResponse, error) {
+ out := new(GetConfigurationResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/GetConfiguration", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) SubscribeConfigurationAlpha1(ctx context.Context, in *SubscribeConfigurationRequest, opts ...grpc.CallOption) (Dapr_SubscribeConfigurationAlpha1Client, error) {
+ stream, err := c.cc.NewStream(ctx, &Dapr_ServiceDesc.Streams[0], "/dapr.proto.runtime.v1.Dapr/SubscribeConfigurationAlpha1", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &daprSubscribeConfigurationAlpha1Client{stream}
+ if err := x.ClientStream.SendMsg(in); err != nil {
+ return nil, err
+ }
+ if err := x.ClientStream.CloseSend(); err != nil {
+ return nil, err
+ }
+ return x, nil
+}
+
+type Dapr_SubscribeConfigurationAlpha1Client interface {
+ Recv() (*SubscribeConfigurationResponse, error)
+ grpc.ClientStream
+}
+
+type daprSubscribeConfigurationAlpha1Client struct {
+ grpc.ClientStream
+}
+
+func (x *daprSubscribeConfigurationAlpha1Client) Recv() (*SubscribeConfigurationResponse, error) {
+ m := new(SubscribeConfigurationResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (c *daprClient) SubscribeConfiguration(ctx context.Context, in *SubscribeConfigurationRequest, opts ...grpc.CallOption) (Dapr_SubscribeConfigurationClient, error) {
+ stream, err := c.cc.NewStream(ctx, &Dapr_ServiceDesc.Streams[1], "/dapr.proto.runtime.v1.Dapr/SubscribeConfiguration", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &daprSubscribeConfigurationClient{stream}
+ if err := x.ClientStream.SendMsg(in); err != nil {
+ return nil, err
+ }
+ if err := x.ClientStream.CloseSend(); err != nil {
+ return nil, err
+ }
+ return x, nil
+}
+
+type Dapr_SubscribeConfigurationClient interface {
+ Recv() (*SubscribeConfigurationResponse, error)
+ grpc.ClientStream
+}
+
+type daprSubscribeConfigurationClient struct {
+ grpc.ClientStream
+}
+
+func (x *daprSubscribeConfigurationClient) Recv() (*SubscribeConfigurationResponse, error) {
+ m := new(SubscribeConfigurationResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (c *daprClient) UnsubscribeConfigurationAlpha1(ctx context.Context, in *UnsubscribeConfigurationRequest, opts ...grpc.CallOption) (*UnsubscribeConfigurationResponse, error) {
+ out := new(UnsubscribeConfigurationResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/UnsubscribeConfigurationAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) UnsubscribeConfiguration(ctx context.Context, in *UnsubscribeConfigurationRequest, opts ...grpc.CallOption) (*UnsubscribeConfigurationResponse, error) {
+ out := new(UnsubscribeConfigurationResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/UnsubscribeConfiguration", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) TryLockAlpha1(ctx context.Context, in *TryLockRequest, opts ...grpc.CallOption) (*TryLockResponse, error) {
+ out := new(TryLockResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/TryLockAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) UnlockAlpha1(ctx context.Context, in *UnlockRequest, opts ...grpc.CallOption) (*UnlockResponse, error) {
+ out := new(UnlockResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/UnlockAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) EncryptAlpha1(ctx context.Context, opts ...grpc.CallOption) (Dapr_EncryptAlpha1Client, error) {
+ stream, err := c.cc.NewStream(ctx, &Dapr_ServiceDesc.Streams[2], "/dapr.proto.runtime.v1.Dapr/EncryptAlpha1", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &daprEncryptAlpha1Client{stream}
+ return x, nil
+}
+
+type Dapr_EncryptAlpha1Client interface {
+ Send(*EncryptRequest) error
+ Recv() (*EncryptResponse, error)
+ grpc.ClientStream
+}
+
+type daprEncryptAlpha1Client struct {
+ grpc.ClientStream
+}
+
+func (x *daprEncryptAlpha1Client) Send(m *EncryptRequest) error {
+ return x.ClientStream.SendMsg(m)
+}
+
+func (x *daprEncryptAlpha1Client) Recv() (*EncryptResponse, error) {
+ m := new(EncryptResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (c *daprClient) DecryptAlpha1(ctx context.Context, opts ...grpc.CallOption) (Dapr_DecryptAlpha1Client, error) {
+ stream, err := c.cc.NewStream(ctx, &Dapr_ServiceDesc.Streams[3], "/dapr.proto.runtime.v1.Dapr/DecryptAlpha1", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &daprDecryptAlpha1Client{stream}
+ return x, nil
+}
+
+type Dapr_DecryptAlpha1Client interface {
+ Send(*DecryptRequest) error
+ Recv() (*DecryptResponse, error)
+ grpc.ClientStream
+}
+
+type daprDecryptAlpha1Client struct {
+ grpc.ClientStream
+}
+
+func (x *daprDecryptAlpha1Client) Send(m *DecryptRequest) error {
+ return x.ClientStream.SendMsg(m)
+}
+
+func (x *daprDecryptAlpha1Client) Recv() (*DecryptResponse, error) {
+ m := new(DecryptResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (c *daprClient) GetMetadata(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetMetadataResponse, error) {
+ out := new(GetMetadataResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/GetMetadata", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) SetMetadata(ctx context.Context, in *SetMetadataRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/SetMetadata", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) SubtleGetKeyAlpha1(ctx context.Context, in *SubtleGetKeyRequest, opts ...grpc.CallOption) (*SubtleGetKeyResponse, error) {
+ out := new(SubtleGetKeyResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/SubtleGetKeyAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) SubtleEncryptAlpha1(ctx context.Context, in *SubtleEncryptRequest, opts ...grpc.CallOption) (*SubtleEncryptResponse, error) {
+ out := new(SubtleEncryptResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/SubtleEncryptAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) SubtleDecryptAlpha1(ctx context.Context, in *SubtleDecryptRequest, opts ...grpc.CallOption) (*SubtleDecryptResponse, error) {
+ out := new(SubtleDecryptResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/SubtleDecryptAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) SubtleWrapKeyAlpha1(ctx context.Context, in *SubtleWrapKeyRequest, opts ...grpc.CallOption) (*SubtleWrapKeyResponse, error) {
+ out := new(SubtleWrapKeyResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/SubtleWrapKeyAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) SubtleUnwrapKeyAlpha1(ctx context.Context, in *SubtleUnwrapKeyRequest, opts ...grpc.CallOption) (*SubtleUnwrapKeyResponse, error) {
+ out := new(SubtleUnwrapKeyResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/SubtleUnwrapKeyAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) SubtleSignAlpha1(ctx context.Context, in *SubtleSignRequest, opts ...grpc.CallOption) (*SubtleSignResponse, error) {
+ out := new(SubtleSignResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/SubtleSignAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) SubtleVerifyAlpha1(ctx context.Context, in *SubtleVerifyRequest, opts ...grpc.CallOption) (*SubtleVerifyResponse, error) {
+ out := new(SubtleVerifyResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/SubtleVerifyAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) StartWorkflowAlpha1(ctx context.Context, in *StartWorkflowRequest, opts ...grpc.CallOption) (*StartWorkflowResponse, error) {
+ out := new(StartWorkflowResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/StartWorkflowAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) GetWorkflowAlpha1(ctx context.Context, in *GetWorkflowRequest, opts ...grpc.CallOption) (*GetWorkflowResponse, error) {
+ out := new(GetWorkflowResponse)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/GetWorkflowAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) PurgeWorkflowAlpha1(ctx context.Context, in *PurgeWorkflowRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/PurgeWorkflowAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) TerminateWorkflowAlpha1(ctx context.Context, in *TerminateWorkflowRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/TerminateWorkflowAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) PauseWorkflowAlpha1(ctx context.Context, in *PauseWorkflowRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/PauseWorkflowAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) ResumeWorkflowAlpha1(ctx context.Context, in *ResumeWorkflowRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/ResumeWorkflowAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) RaiseEventWorkflowAlpha1(ctx context.Context, in *RaiseEventWorkflowRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/RaiseEventWorkflowAlpha1", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *daprClient) Shutdown(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/dapr.proto.runtime.v1.Dapr/Shutdown", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// DaprServer is the server API for Dapr service.
+// All implementations should embed UnimplementedDaprServer
+// for forward compatibility
+type DaprServer interface {
+ // Invokes a method on a remote Dapr app.
+ // Deprecated: Use proxy mode service invocation instead.
+ InvokeService(context.Context, *InvokeServiceRequest) (*v1.InvokeResponse, error)
+ // Gets the state for a specific key.
+ GetState(context.Context, *GetStateRequest) (*GetStateResponse, error)
+ // Gets a bulk of state items for a list of keys
+ GetBulkState(context.Context, *GetBulkStateRequest) (*GetBulkStateResponse, error)
+ // Saves the state for a specific key.
+ SaveState(context.Context, *SaveStateRequest) (*emptypb.Empty, error)
+ // Queries the state.
+ QueryStateAlpha1(context.Context, *QueryStateRequest) (*QueryStateResponse, error)
+ // Deletes the state for a specific key.
+ DeleteState(context.Context, *DeleteStateRequest) (*emptypb.Empty, error)
+ // Deletes a bulk of state items for a list of keys
+ DeleteBulkState(context.Context, *DeleteBulkStateRequest) (*emptypb.Empty, error)
+ // Executes transactions for a specified store
+ ExecuteStateTransaction(context.Context, *ExecuteStateTransactionRequest) (*emptypb.Empty, error)
+ // Publishes events to the specific topic.
+ PublishEvent(context.Context, *PublishEventRequest) (*emptypb.Empty, error)
+ // Bulk Publishes multiple events to the specified topic.
+ BulkPublishEventAlpha1(context.Context, *BulkPublishRequest) (*BulkPublishResponse, error)
+ // Invokes binding data to specific output bindings
+ InvokeBinding(context.Context, *InvokeBindingRequest) (*InvokeBindingResponse, error)
+ // Gets secrets from secret stores.
+ GetSecret(context.Context, *GetSecretRequest) (*GetSecretResponse, error)
+ // Gets a bulk of secrets
+ GetBulkSecret(context.Context, *GetBulkSecretRequest) (*GetBulkSecretResponse, error)
+ // Register an actor timer.
+ RegisterActorTimer(context.Context, *RegisterActorTimerRequest) (*emptypb.Empty, error)
+ // Unregister an actor timer.
+ UnregisterActorTimer(context.Context, *UnregisterActorTimerRequest) (*emptypb.Empty, error)
+ // Register an actor reminder.
+ RegisterActorReminder(context.Context, *RegisterActorReminderRequest) (*emptypb.Empty, error)
+ // Unregister an actor reminder.
+ UnregisterActorReminder(context.Context, *UnregisterActorReminderRequest) (*emptypb.Empty, error)
+ // Rename an actor reminder.
+ RenameActorReminder(context.Context, *RenameActorReminderRequest) (*emptypb.Empty, error)
+ // Gets the state for a specific actor.
+ GetActorState(context.Context, *GetActorStateRequest) (*GetActorStateResponse, error)
+ // Executes state transactions for a specified actor
+ ExecuteActorStateTransaction(context.Context, *ExecuteActorStateTransactionRequest) (*emptypb.Empty, error)
+ // InvokeActor calls a method on an actor.
+ InvokeActor(context.Context, *InvokeActorRequest) (*InvokeActorResponse, error)
+ // GetConfiguration gets configuration from configuration store.
+ GetConfigurationAlpha1(context.Context, *GetConfigurationRequest) (*GetConfigurationResponse, error)
+ // GetConfiguration gets configuration from configuration store.
+ GetConfiguration(context.Context, *GetConfigurationRequest) (*GetConfigurationResponse, error)
+ // SubscribeConfiguration gets configuration from configuration store and subscribe the updates event by grpc stream
+ SubscribeConfigurationAlpha1(*SubscribeConfigurationRequest, Dapr_SubscribeConfigurationAlpha1Server) error
+ // SubscribeConfiguration gets configuration from configuration store and subscribe the updates event by grpc stream
+ SubscribeConfiguration(*SubscribeConfigurationRequest, Dapr_SubscribeConfigurationServer) error
+ // UnSubscribeConfiguration unsubscribe the subscription of configuration
+ UnsubscribeConfigurationAlpha1(context.Context, *UnsubscribeConfigurationRequest) (*UnsubscribeConfigurationResponse, error)
+ // UnSubscribeConfiguration unsubscribe the subscription of configuration
+ UnsubscribeConfiguration(context.Context, *UnsubscribeConfigurationRequest) (*UnsubscribeConfigurationResponse, error)
+ // TryLockAlpha1 tries to get a lock with an expiry.
+ TryLockAlpha1(context.Context, *TryLockRequest) (*TryLockResponse, error)
+ // UnlockAlpha1 unlocks a lock.
+ UnlockAlpha1(context.Context, *UnlockRequest) (*UnlockResponse, error)
+ // EncryptAlpha1 encrypts a message using the Dapr encryption scheme and a key stored in the vault.
+ EncryptAlpha1(Dapr_EncryptAlpha1Server) error
+ // DecryptAlpha1 decrypts a message using the Dapr encryption scheme and a key stored in the vault.
+ DecryptAlpha1(Dapr_DecryptAlpha1Server) error
+ // Gets metadata of the sidecar
+ GetMetadata(context.Context, *emptypb.Empty) (*GetMetadataResponse, error)
+ // Sets value in extended metadata of the sidecar
+ SetMetadata(context.Context, *SetMetadataRequest) (*emptypb.Empty, error)
+ // SubtleGetKeyAlpha1 returns the public part of an asymmetric key stored in the vault.
+ SubtleGetKeyAlpha1(context.Context, *SubtleGetKeyRequest) (*SubtleGetKeyResponse, error)
+ // SubtleEncryptAlpha1 encrypts a small message using a key stored in the vault.
+ SubtleEncryptAlpha1(context.Context, *SubtleEncryptRequest) (*SubtleEncryptResponse, error)
+ // SubtleDecryptAlpha1 decrypts a small message using a key stored in the vault.
+ SubtleDecryptAlpha1(context.Context, *SubtleDecryptRequest) (*SubtleDecryptResponse, error)
+ // SubtleWrapKeyAlpha1 wraps a key using a key stored in the vault.
+ SubtleWrapKeyAlpha1(context.Context, *SubtleWrapKeyRequest) (*SubtleWrapKeyResponse, error)
+ // SubtleUnwrapKeyAlpha1 unwraps a key using a key stored in the vault.
+ SubtleUnwrapKeyAlpha1(context.Context, *SubtleUnwrapKeyRequest) (*SubtleUnwrapKeyResponse, error)
+ // SubtleSignAlpha1 signs a message using a key stored in the vault.
+ SubtleSignAlpha1(context.Context, *SubtleSignRequest) (*SubtleSignResponse, error)
+ // SubtleVerifyAlpha1 verifies the signature of a message using a key stored in the vault.
+ SubtleVerifyAlpha1(context.Context, *SubtleVerifyRequest) (*SubtleVerifyResponse, error)
+ // Starts a new instance of a workflow
+ StartWorkflowAlpha1(context.Context, *StartWorkflowRequest) (*StartWorkflowResponse, error)
+ // Gets details about a started workflow instance
+ GetWorkflowAlpha1(context.Context, *GetWorkflowRequest) (*GetWorkflowResponse, error)
+ // Purge Workflow
+ PurgeWorkflowAlpha1(context.Context, *PurgeWorkflowRequest) (*emptypb.Empty, error)
+ // Terminates a running workflow instance
+ TerminateWorkflowAlpha1(context.Context, *TerminateWorkflowRequest) (*emptypb.Empty, error)
+ // Pauses a running workflow instance
+ PauseWorkflowAlpha1(context.Context, *PauseWorkflowRequest) (*emptypb.Empty, error)
+ // Resumes a paused workflow instance
+ ResumeWorkflowAlpha1(context.Context, *ResumeWorkflowRequest) (*emptypb.Empty, error)
+ // Raise an event to a running workflow instance
+ RaiseEventWorkflowAlpha1(context.Context, *RaiseEventWorkflowRequest) (*emptypb.Empty, error)
+ // Shutdown the sidecar
+ Shutdown(context.Context, *emptypb.Empty) (*emptypb.Empty, error)
+}
+
+// UnimplementedDaprServer should be embedded to have forward compatible implementations.
+type UnimplementedDaprServer struct {
+}
+
+func (UnimplementedDaprServer) InvokeService(context.Context, *InvokeServiceRequest) (*v1.InvokeResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method InvokeService not implemented")
+}
+func (UnimplementedDaprServer) GetState(context.Context, *GetStateRequest) (*GetStateResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetState not implemented")
+}
+func (UnimplementedDaprServer) GetBulkState(context.Context, *GetBulkStateRequest) (*GetBulkStateResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetBulkState not implemented")
+}
+func (UnimplementedDaprServer) SaveState(context.Context, *SaveStateRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SaveState not implemented")
+}
+func (UnimplementedDaprServer) QueryStateAlpha1(context.Context, *QueryStateRequest) (*QueryStateResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method QueryStateAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) DeleteState(context.Context, *DeleteStateRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method DeleteState not implemented")
+}
+func (UnimplementedDaprServer) DeleteBulkState(context.Context, *DeleteBulkStateRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method DeleteBulkState not implemented")
+}
+func (UnimplementedDaprServer) ExecuteStateTransaction(context.Context, *ExecuteStateTransactionRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method ExecuteStateTransaction not implemented")
+}
+func (UnimplementedDaprServer) PublishEvent(context.Context, *PublishEventRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method PublishEvent not implemented")
+}
+func (UnimplementedDaprServer) BulkPublishEventAlpha1(context.Context, *BulkPublishRequest) (*BulkPublishResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method BulkPublishEventAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) InvokeBinding(context.Context, *InvokeBindingRequest) (*InvokeBindingResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method InvokeBinding not implemented")
+}
+func (UnimplementedDaprServer) GetSecret(context.Context, *GetSecretRequest) (*GetSecretResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetSecret not implemented")
+}
+func (UnimplementedDaprServer) GetBulkSecret(context.Context, *GetBulkSecretRequest) (*GetBulkSecretResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetBulkSecret not implemented")
+}
+func (UnimplementedDaprServer) RegisterActorTimer(context.Context, *RegisterActorTimerRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method RegisterActorTimer not implemented")
+}
+func (UnimplementedDaprServer) UnregisterActorTimer(context.Context, *UnregisterActorTimerRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method UnregisterActorTimer not implemented")
+}
+func (UnimplementedDaprServer) RegisterActorReminder(context.Context, *RegisterActorReminderRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method RegisterActorReminder not implemented")
+}
+func (UnimplementedDaprServer) UnregisterActorReminder(context.Context, *UnregisterActorReminderRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method UnregisterActorReminder not implemented")
+}
+func (UnimplementedDaprServer) RenameActorReminder(context.Context, *RenameActorReminderRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method RenameActorReminder not implemented")
+}
+func (UnimplementedDaprServer) GetActorState(context.Context, *GetActorStateRequest) (*GetActorStateResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetActorState not implemented")
+}
+func (UnimplementedDaprServer) ExecuteActorStateTransaction(context.Context, *ExecuteActorStateTransactionRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method ExecuteActorStateTransaction not implemented")
+}
+func (UnimplementedDaprServer) InvokeActor(context.Context, *InvokeActorRequest) (*InvokeActorResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method InvokeActor not implemented")
+}
+func (UnimplementedDaprServer) GetConfigurationAlpha1(context.Context, *GetConfigurationRequest) (*GetConfigurationResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetConfigurationAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) GetConfiguration(context.Context, *GetConfigurationRequest) (*GetConfigurationResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetConfiguration not implemented")
+}
+func (UnimplementedDaprServer) SubscribeConfigurationAlpha1(*SubscribeConfigurationRequest, Dapr_SubscribeConfigurationAlpha1Server) error {
+ return status.Errorf(codes.Unimplemented, "method SubscribeConfigurationAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) SubscribeConfiguration(*SubscribeConfigurationRequest, Dapr_SubscribeConfigurationServer) error {
+ return status.Errorf(codes.Unimplemented, "method SubscribeConfiguration not implemented")
+}
+func (UnimplementedDaprServer) UnsubscribeConfigurationAlpha1(context.Context, *UnsubscribeConfigurationRequest) (*UnsubscribeConfigurationResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method UnsubscribeConfigurationAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) UnsubscribeConfiguration(context.Context, *UnsubscribeConfigurationRequest) (*UnsubscribeConfigurationResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method UnsubscribeConfiguration not implemented")
+}
+func (UnimplementedDaprServer) TryLockAlpha1(context.Context, *TryLockRequest) (*TryLockResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method TryLockAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) UnlockAlpha1(context.Context, *UnlockRequest) (*UnlockResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method UnlockAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) EncryptAlpha1(Dapr_EncryptAlpha1Server) error {
+ return status.Errorf(codes.Unimplemented, "method EncryptAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) DecryptAlpha1(Dapr_DecryptAlpha1Server) error {
+ return status.Errorf(codes.Unimplemented, "method DecryptAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) GetMetadata(context.Context, *emptypb.Empty) (*GetMetadataResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetMetadata not implemented")
+}
+func (UnimplementedDaprServer) SetMetadata(context.Context, *SetMetadataRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SetMetadata not implemented")
+}
+func (UnimplementedDaprServer) SubtleGetKeyAlpha1(context.Context, *SubtleGetKeyRequest) (*SubtleGetKeyResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SubtleGetKeyAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) SubtleEncryptAlpha1(context.Context, *SubtleEncryptRequest) (*SubtleEncryptResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SubtleEncryptAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) SubtleDecryptAlpha1(context.Context, *SubtleDecryptRequest) (*SubtleDecryptResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SubtleDecryptAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) SubtleWrapKeyAlpha1(context.Context, *SubtleWrapKeyRequest) (*SubtleWrapKeyResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SubtleWrapKeyAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) SubtleUnwrapKeyAlpha1(context.Context, *SubtleUnwrapKeyRequest) (*SubtleUnwrapKeyResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SubtleUnwrapKeyAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) SubtleSignAlpha1(context.Context, *SubtleSignRequest) (*SubtleSignResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SubtleSignAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) SubtleVerifyAlpha1(context.Context, *SubtleVerifyRequest) (*SubtleVerifyResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SubtleVerifyAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) StartWorkflowAlpha1(context.Context, *StartWorkflowRequest) (*StartWorkflowResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method StartWorkflowAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) GetWorkflowAlpha1(context.Context, *GetWorkflowRequest) (*GetWorkflowResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetWorkflowAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) PurgeWorkflowAlpha1(context.Context, *PurgeWorkflowRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method PurgeWorkflowAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) TerminateWorkflowAlpha1(context.Context, *TerminateWorkflowRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method TerminateWorkflowAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) PauseWorkflowAlpha1(context.Context, *PauseWorkflowRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method PauseWorkflowAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) ResumeWorkflowAlpha1(context.Context, *ResumeWorkflowRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method ResumeWorkflowAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) RaiseEventWorkflowAlpha1(context.Context, *RaiseEventWorkflowRequest) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method RaiseEventWorkflowAlpha1 not implemented")
+}
+func (UnimplementedDaprServer) Shutdown(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Shutdown not implemented")
+}
+
+// UnsafeDaprServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to DaprServer will
+// result in compilation errors.
+type UnsafeDaprServer interface {
+ mustEmbedUnimplementedDaprServer()
+}
+
+func RegisterDaprServer(s grpc.ServiceRegistrar, srv DaprServer) {
+ s.RegisterService(&Dapr_ServiceDesc, srv)
+}
+
+func _Dapr_InvokeService_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(InvokeServiceRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).InvokeService(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/InvokeService",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).InvokeService(ctx, req.(*InvokeServiceRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_GetState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetStateRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).GetState(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/GetState",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).GetState(ctx, req.(*GetStateRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_GetBulkState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetBulkStateRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).GetBulkState(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/GetBulkState",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).GetBulkState(ctx, req.(*GetBulkStateRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_SaveState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SaveStateRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).SaveState(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/SaveState",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).SaveState(ctx, req.(*SaveStateRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_QueryStateAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(QueryStateRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).QueryStateAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/QueryStateAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).QueryStateAlpha1(ctx, req.(*QueryStateRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_DeleteState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(DeleteStateRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).DeleteState(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/DeleteState",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).DeleteState(ctx, req.(*DeleteStateRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_DeleteBulkState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(DeleteBulkStateRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).DeleteBulkState(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/DeleteBulkState",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).DeleteBulkState(ctx, req.(*DeleteBulkStateRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_ExecuteStateTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ExecuteStateTransactionRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).ExecuteStateTransaction(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/ExecuteStateTransaction",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).ExecuteStateTransaction(ctx, req.(*ExecuteStateTransactionRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_PublishEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(PublishEventRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).PublishEvent(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/PublishEvent",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).PublishEvent(ctx, req.(*PublishEventRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_BulkPublishEventAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(BulkPublishRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).BulkPublishEventAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/BulkPublishEventAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).BulkPublishEventAlpha1(ctx, req.(*BulkPublishRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_InvokeBinding_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(InvokeBindingRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).InvokeBinding(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/InvokeBinding",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).InvokeBinding(ctx, req.(*InvokeBindingRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_GetSecret_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetSecretRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).GetSecret(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/GetSecret",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).GetSecret(ctx, req.(*GetSecretRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_GetBulkSecret_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetBulkSecretRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).GetBulkSecret(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/GetBulkSecret",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).GetBulkSecret(ctx, req.(*GetBulkSecretRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_RegisterActorTimer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RegisterActorTimerRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).RegisterActorTimer(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/RegisterActorTimer",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).RegisterActorTimer(ctx, req.(*RegisterActorTimerRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_UnregisterActorTimer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UnregisterActorTimerRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).UnregisterActorTimer(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/UnregisterActorTimer",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).UnregisterActorTimer(ctx, req.(*UnregisterActorTimerRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_RegisterActorReminder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RegisterActorReminderRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).RegisterActorReminder(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/RegisterActorReminder",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).RegisterActorReminder(ctx, req.(*RegisterActorReminderRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_UnregisterActorReminder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UnregisterActorReminderRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).UnregisterActorReminder(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/UnregisterActorReminder",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).UnregisterActorReminder(ctx, req.(*UnregisterActorReminderRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_RenameActorReminder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RenameActorReminderRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).RenameActorReminder(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/RenameActorReminder",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).RenameActorReminder(ctx, req.(*RenameActorReminderRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_GetActorState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetActorStateRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).GetActorState(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/GetActorState",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).GetActorState(ctx, req.(*GetActorStateRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_ExecuteActorStateTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ExecuteActorStateTransactionRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).ExecuteActorStateTransaction(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/ExecuteActorStateTransaction",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).ExecuteActorStateTransaction(ctx, req.(*ExecuteActorStateTransactionRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_InvokeActor_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(InvokeActorRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).InvokeActor(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/InvokeActor",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).InvokeActor(ctx, req.(*InvokeActorRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_GetConfigurationAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetConfigurationRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).GetConfigurationAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/GetConfigurationAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).GetConfigurationAlpha1(ctx, req.(*GetConfigurationRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_GetConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetConfigurationRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).GetConfiguration(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/GetConfiguration",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).GetConfiguration(ctx, req.(*GetConfigurationRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_SubscribeConfigurationAlpha1_Handler(srv interface{}, stream grpc.ServerStream) error {
+ m := new(SubscribeConfigurationRequest)
+ if err := stream.RecvMsg(m); err != nil {
+ return err
+ }
+ return srv.(DaprServer).SubscribeConfigurationAlpha1(m, &daprSubscribeConfigurationAlpha1Server{stream})
+}
+
+type Dapr_SubscribeConfigurationAlpha1Server interface {
+ Send(*SubscribeConfigurationResponse) error
+ grpc.ServerStream
+}
+
+type daprSubscribeConfigurationAlpha1Server struct {
+ grpc.ServerStream
+}
+
+func (x *daprSubscribeConfigurationAlpha1Server) Send(m *SubscribeConfigurationResponse) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func _Dapr_SubscribeConfiguration_Handler(srv interface{}, stream grpc.ServerStream) error {
+ m := new(SubscribeConfigurationRequest)
+ if err := stream.RecvMsg(m); err != nil {
+ return err
+ }
+ return srv.(DaprServer).SubscribeConfiguration(m, &daprSubscribeConfigurationServer{stream})
+}
+
+type Dapr_SubscribeConfigurationServer interface {
+ Send(*SubscribeConfigurationResponse) error
+ grpc.ServerStream
+}
+
+type daprSubscribeConfigurationServer struct {
+ grpc.ServerStream
+}
+
+func (x *daprSubscribeConfigurationServer) Send(m *SubscribeConfigurationResponse) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func _Dapr_UnsubscribeConfigurationAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UnsubscribeConfigurationRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).UnsubscribeConfigurationAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/UnsubscribeConfigurationAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).UnsubscribeConfigurationAlpha1(ctx, req.(*UnsubscribeConfigurationRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_UnsubscribeConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UnsubscribeConfigurationRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).UnsubscribeConfiguration(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/UnsubscribeConfiguration",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).UnsubscribeConfiguration(ctx, req.(*UnsubscribeConfigurationRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_TryLockAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(TryLockRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).TryLockAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/TryLockAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).TryLockAlpha1(ctx, req.(*TryLockRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_UnlockAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UnlockRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).UnlockAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/UnlockAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).UnlockAlpha1(ctx, req.(*UnlockRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_EncryptAlpha1_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(DaprServer).EncryptAlpha1(&daprEncryptAlpha1Server{stream})
+}
+
+type Dapr_EncryptAlpha1Server interface {
+ Send(*EncryptResponse) error
+ Recv() (*EncryptRequest, error)
+ grpc.ServerStream
+}
+
+type daprEncryptAlpha1Server struct {
+ grpc.ServerStream
+}
+
+func (x *daprEncryptAlpha1Server) Send(m *EncryptResponse) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func (x *daprEncryptAlpha1Server) Recv() (*EncryptRequest, error) {
+ m := new(EncryptRequest)
+ if err := x.ServerStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func _Dapr_DecryptAlpha1_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(DaprServer).DecryptAlpha1(&daprDecryptAlpha1Server{stream})
+}
+
+type Dapr_DecryptAlpha1Server interface {
+ Send(*DecryptResponse) error
+ Recv() (*DecryptRequest, error)
+ grpc.ServerStream
+}
+
+type daprDecryptAlpha1Server struct {
+ grpc.ServerStream
+}
+
+func (x *daprDecryptAlpha1Server) Send(m *DecryptResponse) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func (x *daprDecryptAlpha1Server) Recv() (*DecryptRequest, error) {
+ m := new(DecryptRequest)
+ if err := x.ServerStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func _Dapr_GetMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(emptypb.Empty)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).GetMetadata(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/GetMetadata",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).GetMetadata(ctx, req.(*emptypb.Empty))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_SetMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SetMetadataRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).SetMetadata(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/SetMetadata",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).SetMetadata(ctx, req.(*SetMetadataRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_SubtleGetKeyAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SubtleGetKeyRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).SubtleGetKeyAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/SubtleGetKeyAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).SubtleGetKeyAlpha1(ctx, req.(*SubtleGetKeyRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_SubtleEncryptAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SubtleEncryptRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).SubtleEncryptAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/SubtleEncryptAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).SubtleEncryptAlpha1(ctx, req.(*SubtleEncryptRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_SubtleDecryptAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SubtleDecryptRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).SubtleDecryptAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/SubtleDecryptAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).SubtleDecryptAlpha1(ctx, req.(*SubtleDecryptRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_SubtleWrapKeyAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SubtleWrapKeyRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).SubtleWrapKeyAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/SubtleWrapKeyAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).SubtleWrapKeyAlpha1(ctx, req.(*SubtleWrapKeyRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_SubtleUnwrapKeyAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SubtleUnwrapKeyRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).SubtleUnwrapKeyAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/SubtleUnwrapKeyAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).SubtleUnwrapKeyAlpha1(ctx, req.(*SubtleUnwrapKeyRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_SubtleSignAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SubtleSignRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).SubtleSignAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/SubtleSignAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).SubtleSignAlpha1(ctx, req.(*SubtleSignRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_SubtleVerifyAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SubtleVerifyRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).SubtleVerifyAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/SubtleVerifyAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).SubtleVerifyAlpha1(ctx, req.(*SubtleVerifyRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_StartWorkflowAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(StartWorkflowRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).StartWorkflowAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/StartWorkflowAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).StartWorkflowAlpha1(ctx, req.(*StartWorkflowRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_GetWorkflowAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetWorkflowRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).GetWorkflowAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/GetWorkflowAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).GetWorkflowAlpha1(ctx, req.(*GetWorkflowRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_PurgeWorkflowAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(PurgeWorkflowRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).PurgeWorkflowAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/PurgeWorkflowAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).PurgeWorkflowAlpha1(ctx, req.(*PurgeWorkflowRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_TerminateWorkflowAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(TerminateWorkflowRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).TerminateWorkflowAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/TerminateWorkflowAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).TerminateWorkflowAlpha1(ctx, req.(*TerminateWorkflowRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_PauseWorkflowAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(PauseWorkflowRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).PauseWorkflowAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/PauseWorkflowAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).PauseWorkflowAlpha1(ctx, req.(*PauseWorkflowRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_ResumeWorkflowAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ResumeWorkflowRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).ResumeWorkflowAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/ResumeWorkflowAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).ResumeWorkflowAlpha1(ctx, req.(*ResumeWorkflowRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_RaiseEventWorkflowAlpha1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RaiseEventWorkflowRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).RaiseEventWorkflowAlpha1(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/RaiseEventWorkflowAlpha1",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).RaiseEventWorkflowAlpha1(ctx, req.(*RaiseEventWorkflowRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _Dapr_Shutdown_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(emptypb.Empty)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(DaprServer).Shutdown(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/dapr.proto.runtime.v1.Dapr/Shutdown",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(DaprServer).Shutdown(ctx, req.(*emptypb.Empty))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// Dapr_ServiceDesc is the grpc.ServiceDesc for Dapr service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Dapr_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "dapr.proto.runtime.v1.Dapr",
+ HandlerType: (*DaprServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "InvokeService",
+ Handler: _Dapr_InvokeService_Handler,
+ },
+ {
+ MethodName: "GetState",
+ Handler: _Dapr_GetState_Handler,
+ },
+ {
+ MethodName: "GetBulkState",
+ Handler: _Dapr_GetBulkState_Handler,
+ },
+ {
+ MethodName: "SaveState",
+ Handler: _Dapr_SaveState_Handler,
+ },
+ {
+ MethodName: "QueryStateAlpha1",
+ Handler: _Dapr_QueryStateAlpha1_Handler,
+ },
+ {
+ MethodName: "DeleteState",
+ Handler: _Dapr_DeleteState_Handler,
+ },
+ {
+ MethodName: "DeleteBulkState",
+ Handler: _Dapr_DeleteBulkState_Handler,
+ },
+ {
+ MethodName: "ExecuteStateTransaction",
+ Handler: _Dapr_ExecuteStateTransaction_Handler,
+ },
+ {
+ MethodName: "PublishEvent",
+ Handler: _Dapr_PublishEvent_Handler,
+ },
+ {
+ MethodName: "BulkPublishEventAlpha1",
+ Handler: _Dapr_BulkPublishEventAlpha1_Handler,
+ },
+ {
+ MethodName: "InvokeBinding",
+ Handler: _Dapr_InvokeBinding_Handler,
+ },
+ {
+ MethodName: "GetSecret",
+ Handler: _Dapr_GetSecret_Handler,
+ },
+ {
+ MethodName: "GetBulkSecret",
+ Handler: _Dapr_GetBulkSecret_Handler,
+ },
+ {
+ MethodName: "RegisterActorTimer",
+ Handler: _Dapr_RegisterActorTimer_Handler,
+ },
+ {
+ MethodName: "UnregisterActorTimer",
+ Handler: _Dapr_UnregisterActorTimer_Handler,
+ },
+ {
+ MethodName: "RegisterActorReminder",
+ Handler: _Dapr_RegisterActorReminder_Handler,
+ },
+ {
+ MethodName: "UnregisterActorReminder",
+ Handler: _Dapr_UnregisterActorReminder_Handler,
+ },
+ {
+ MethodName: "RenameActorReminder",
+ Handler: _Dapr_RenameActorReminder_Handler,
+ },
+ {
+ MethodName: "GetActorState",
+ Handler: _Dapr_GetActorState_Handler,
+ },
+ {
+ MethodName: "ExecuteActorStateTransaction",
+ Handler: _Dapr_ExecuteActorStateTransaction_Handler,
+ },
+ {
+ MethodName: "InvokeActor",
+ Handler: _Dapr_InvokeActor_Handler,
+ },
+ {
+ MethodName: "GetConfigurationAlpha1",
+ Handler: _Dapr_GetConfigurationAlpha1_Handler,
+ },
+ {
+ MethodName: "GetConfiguration",
+ Handler: _Dapr_GetConfiguration_Handler,
+ },
+ {
+ MethodName: "UnsubscribeConfigurationAlpha1",
+ Handler: _Dapr_UnsubscribeConfigurationAlpha1_Handler,
+ },
+ {
+ MethodName: "UnsubscribeConfiguration",
+ Handler: _Dapr_UnsubscribeConfiguration_Handler,
+ },
+ {
+ MethodName: "TryLockAlpha1",
+ Handler: _Dapr_TryLockAlpha1_Handler,
+ },
+ {
+ MethodName: "UnlockAlpha1",
+ Handler: _Dapr_UnlockAlpha1_Handler,
+ },
+ {
+ MethodName: "GetMetadata",
+ Handler: _Dapr_GetMetadata_Handler,
+ },
+ {
+ MethodName: "SetMetadata",
+ Handler: _Dapr_SetMetadata_Handler,
+ },
+ {
+ MethodName: "SubtleGetKeyAlpha1",
+ Handler: _Dapr_SubtleGetKeyAlpha1_Handler,
+ },
+ {
+ MethodName: "SubtleEncryptAlpha1",
+ Handler: _Dapr_SubtleEncryptAlpha1_Handler,
+ },
+ {
+ MethodName: "SubtleDecryptAlpha1",
+ Handler: _Dapr_SubtleDecryptAlpha1_Handler,
+ },
+ {
+ MethodName: "SubtleWrapKeyAlpha1",
+ Handler: _Dapr_SubtleWrapKeyAlpha1_Handler,
+ },
+ {
+ MethodName: "SubtleUnwrapKeyAlpha1",
+ Handler: _Dapr_SubtleUnwrapKeyAlpha1_Handler,
+ },
+ {
+ MethodName: "SubtleSignAlpha1",
+ Handler: _Dapr_SubtleSignAlpha1_Handler,
+ },
+ {
+ MethodName: "SubtleVerifyAlpha1",
+ Handler: _Dapr_SubtleVerifyAlpha1_Handler,
+ },
+ {
+ MethodName: "StartWorkflowAlpha1",
+ Handler: _Dapr_StartWorkflowAlpha1_Handler,
+ },
+ {
+ MethodName: "GetWorkflowAlpha1",
+ Handler: _Dapr_GetWorkflowAlpha1_Handler,
+ },
+ {
+ MethodName: "PurgeWorkflowAlpha1",
+ Handler: _Dapr_PurgeWorkflowAlpha1_Handler,
+ },
+ {
+ MethodName: "TerminateWorkflowAlpha1",
+ Handler: _Dapr_TerminateWorkflowAlpha1_Handler,
+ },
+ {
+ MethodName: "PauseWorkflowAlpha1",
+ Handler: _Dapr_PauseWorkflowAlpha1_Handler,
+ },
+ {
+ MethodName: "ResumeWorkflowAlpha1",
+ Handler: _Dapr_ResumeWorkflowAlpha1_Handler,
+ },
+ {
+ MethodName: "RaiseEventWorkflowAlpha1",
+ Handler: _Dapr_RaiseEventWorkflowAlpha1_Handler,
+ },
+ {
+ MethodName: "Shutdown",
+ Handler: _Dapr_Shutdown_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{
+ {
+ StreamName: "SubscribeConfigurationAlpha1",
+ Handler: _Dapr_SubscribeConfigurationAlpha1_Handler,
+ ServerStreams: true,
+ },
+ {
+ StreamName: "SubscribeConfiguration",
+ Handler: _Dapr_SubscribeConfiguration_Handler,
+ ServerStreams: true,
+ },
+ {
+ StreamName: "EncryptAlpha1",
+ Handler: _Dapr_EncryptAlpha1_Handler,
+ ServerStreams: true,
+ ClientStreams: true,
+ },
+ {
+ StreamName: "DecryptAlpha1",
+ Handler: _Dapr_DecryptAlpha1_Handler,
+ ServerStreams: true,
+ ClientStreams: true,
+ },
+ },
+ Metadata: "dapr/proto/runtime/v1/dapr.proto",
+}
diff --git a/vendor/github.com/dapr/go-sdk/service/common/service.go b/vendor/github.com/dapr/go-sdk/service/common/service.go
new file mode 100644
index 00000000000..7f306e4d036
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/service/common/service.go
@@ -0,0 +1,58 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package common
+
+import (
+ "context"
+
+ "github.com/dapr/go-sdk/actor"
+ "github.com/dapr/go-sdk/actor/config"
+)
+
+const (
+ // AppAPITokenEnvVar is the environment variable for app api token.
+ AppAPITokenEnvVar = "APP_API_TOKEN" /* #nosec */
+ APITokenKey = "dapr-api-token" /* #nosec */
+)
+
+// Service represents Dapr callback service.
+type Service interface {
+ // AddHealthCheckHandler sets a health check handler, name: http (router) and grpc (invalid).
+ AddHealthCheckHandler(name string, fn HealthCheckHandler) error
+ // AddServiceInvocationHandler appends provided service invocation handler with its name to the service.
+ AddServiceInvocationHandler(name string, fn ServiceInvocationHandler) error
+ // AddTopicEventHandler appends provided event handler with its topic and optional metadata to the service.
+ // Note, retries are only considered when there is an error. Lack of error is considered as a success
+ AddTopicEventHandler(sub *Subscription, fn TopicEventHandler) error
+ // AddBindingInvocationHandler appends provided binding invocation handler with its name to the service.
+ AddBindingInvocationHandler(name string, fn BindingInvocationHandler) error
+ // RegisterActorImplFactory Register a new actor to actor runtime of go sdk
+ // Deprecated: use RegisterActorImplFactoryContext instead
+ RegisterActorImplFactory(f actor.Factory, opts ...config.Option)
+ // RegisterActorImplFactoryContext Register a new actor to actor runtime of go sdk
+ RegisterActorImplFactoryContext(f actor.FactoryContext, opts ...config.Option)
+ // Start starts service.
+ Start() error
+ // Stop stops the previously started service.
+ Stop() error
+ // Gracefully stops the previous started service
+ GracefulStop() error
+}
+
+type (
+ ServiceInvocationHandler func(ctx context.Context, in *InvocationEvent) (out *Content, err error)
+ TopicEventHandler func(ctx context.Context, e *TopicEvent) (retry bool, err error)
+ BindingInvocationHandler func(ctx context.Context, in *BindingEvent) (out []byte, err error)
+ HealthCheckHandler func(context.Context) error
+)
diff --git a/vendor/github.com/dapr/go-sdk/service/common/type.go b/vendor/github.com/dapr/go-sdk/service/common/type.go
new file mode 100644
index 00000000000..1883b3c3d79
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/service/common/type.go
@@ -0,0 +1,118 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package common
+
+import (
+ "encoding/json"
+)
+
+// TopicEvent is the content of the inbound topic message.
+type TopicEvent struct {
+ // ID identifies the event.
+ ID string `json:"id"`
+ // The version of the CloudEvents specification.
+ SpecVersion string `json:"specversion"`
+ // The type of event related to the originating occurrence.
+ Type string `json:"type"`
+ // Source identifies the context in which an event happened.
+ Source string `json:"source"`
+ // The content type of data value.
+ DataContentType string `json:"datacontenttype"`
+ // The content of the event.
+ // Note, this is why the gRPC and HTTP implementations need separate structs for cloud events.
+ Data interface{} `json:"data"`
+ // The content of the event represented as raw bytes.
+ // This can be deserialized into a Go struct using `Struct`.
+ RawData []byte `json:"-"`
+ // The base64 encoding content of the event.
+ // Note, this is processing rawPayload and binary content types.
+ // This field is deprecated and will be removed in the future.
+ DataBase64 string `json:"data_base64,omitempty"`
+ // Cloud event subject
+ Subject string `json:"subject"`
+ // The pubsub topic which publisher sent to.
+ Topic string `json:"topic"`
+ // PubsubName is name of the pub/sub this message came from
+ PubsubName string `json:"pubsubname"`
+}
+
+func (e *TopicEvent) Struct(target interface{}) error {
+ // TODO: Enhance to inspect DataContentType for the best
+ // deserialization method.
+ return json.Unmarshal(e.RawData, target)
+}
+
+// InvocationEvent represents the input and output of binding invocation.
+type InvocationEvent struct {
+ // Data is the payload that the input bindings sent.
+ Data []byte `json:"data"`
+ // ContentType of the Data
+ ContentType string `json:"contentType"`
+ // DataTypeURL is the resource URL that uniquely identifies the type of the serialized
+ DataTypeURL string `json:"typeUrl,omitempty"`
+ // Verb is the HTTP verb that was used to invoke this service.
+ Verb string `json:"-"`
+ // QueryString represents an encoded HTTP url query string in the following format: name=value&name2=value2
+ QueryString string `json:"-"`
+}
+
+// Content is a generic data content.
+type Content struct {
+ // Data is the payload that the input bindings sent.
+ Data []byte `json:"data"`
+ // ContentType of the Data
+ ContentType string `json:"contentType"`
+ // DataTypeURL is the resource URL that uniquely identifies the type of the serialized
+ DataTypeURL string `json:"typeUrl,omitempty"`
+}
+
+// BindingEvent represents the binding event handler input.
+type BindingEvent struct {
+ // Data is the input bindings sent
+ Data []byte `json:"data"`
+ // Metadata is the input binding metadata
+ Metadata map[string]string `json:"metadata,omitempty"`
+}
+
+// Subscription represents single topic subscription.
+type Subscription struct {
+ // PubsubName is name of the pub/sub this message came from
+ PubsubName string `json:"pubsubname"`
+ // Topic is the name of the topic
+ Topic string `json:"topic"`
+ // Metadata is the subscription metadata
+ Metadata map[string]string `json:"metadata,omitempty"`
+ // Route is the route of the handler where HTTP topic events should be published (passed as Path in gRPC)
+ Route string `json:"route"`
+ // Match is the CEL expression to match on the CloudEvent envelope.
+ Match string `json:"match"`
+ // Priority is the priority in which to evaluate the match (lower to higher).
+ Priority int `json:"priority"`
+ // DisableTopicValidation allows to receive events from publisher topics that differ from the subscribed topic.
+ DisableTopicValidation bool `json:"disableTopicValidation"`
+}
+
+const (
+ // SubscriptionResponseStatusSuccess means message is processed successfully.
+ SubscriptionResponseStatusSuccess = "SUCCESS"
+ // SubscriptionResponseStatusRetry means message to be retried by Dapr.
+ SubscriptionResponseStatusRetry = "RETRY"
+ // SubscriptionResponseStatusDrop means warning is logged and message is dropped.
+ SubscriptionResponseStatusDrop = "DROP"
+)
+
+// SubscriptionResponse represents the response handling hint from subscriber to Dapr.
+type SubscriptionResponse struct {
+ Status string `json:"status"`
+}
diff --git a/vendor/github.com/dapr/go-sdk/service/http/Readme.md b/vendor/github.com/dapr/go-sdk/service/http/Readme.md
new file mode 100644
index 00000000000..6f28a344516
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/service/http/Readme.md
@@ -0,0 +1,114 @@
+# Dapr HTTP Service SDK for Go
+
+Start by importing Dapr Go `service/http` package:
+
+```go
+daprd "github.com/dapr/go-sdk/service/http"
+```
+
+## Creating and Starting Service
+
+To create an HTTP Dapr service, first, create a Dapr callback instance with a specific address:
+
+```go
+s := daprd.NewService(":8080")
+```
+
+Or with address and an existing `http.ServeMux` in case you want to combine existing server implementations:
+
+```go
+mux := http.NewServeMux()
+mux.HandleFunc("/", myOtherHandler)
+s := daprd.NewServiceWithMux(":8080", mux)
+```
+
+Once you create a service instance, you can "attach" to that service any number of event, binding, and service invocation logic handlers as shown below. Onces the logic is defined, you are ready to start the service:
+
+```go
+if err := s.Start(); err != nil && err != http.ErrServerClosed {
+ log.Fatalf("error: %v", err)
+}
+```
+
+## Event Handling
+
+To handle events from specific topic you need to add at least one topic event handler before starting the service:
+
+```go
+sub := &common.Subscription{
+ PubsubName: "messages",
+ Topic: "topic1",
+ Route: "/events",
+}
+err := s.AddTopicEventHandler(sub, eventHandler)
+if err != nil {
+ log.Fatalf("error adding topic subscription: %v", err)
+}
+```
+
+The handler method itself can be any method with the expected signature:
+
+```go
+func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool, err error) {
+ log.Printf("event - PubsubName:%s, Topic:%s, ID:%s, Data: %v", e.PubsubName, e.Topic, e.ID, e.Data)
+ // do something with the event
+ return true, nil
+}
+```
+
+## Service Invocation Handler
+
+To handle service invocations you will need to add at least one service invocation handler before starting the service:
+
+```go
+if err := s.AddServiceInvocationHandler("/echo", echoHandler); err != nil {
+ log.Fatalf("error adding invocation handler: %v", err)
+}
+```
+
+The handler method itself can be any method with the expected signature:
+
+```go
+func echoHandler(ctx context.Context, in *common.InvocationEvent) (out *common.Content, err error) {
+ log.Printf("echo - ContentType:%s, Verb:%s, QueryString:%s, %+v", in.ContentType, in.Verb, in.QueryString, string(in.Data))
+ // do something with the invocation here
+ out = &common.Content{
+ Data: in.Data,
+ ContentType: in.ContentType,
+ DataTypeURL: in.DataTypeURL,
+ }
+ return
+}
+```
+
+## Binding Invocation Handler
+
+To handle binding invocations you will need to add at least one binding invocation handler before starting the service:
+
+```go
+if err := s.AddBindingInvocationHandler("/run", runHandler); err != nil {
+ log.Fatalf("error adding binding handler: %v", err)
+}
+```
+
+The handler method itself can be any method with the expected signature:
+
+```go
+func runHandler(ctx context.Context, in *common.BindingEvent) (out []byte, err error) {
+ log.Printf("binding - Data:%v, Meta:%v", in.Data, in.Metadata)
+ // do something with the invocation here
+ return nil, nil
+}
+```
+
+## Templates
+
+To accelerate your HTTP Dapr app development in Go even further you can use one of the GitHub templates integrating the HTTP Dapr callback package:
+
+* [Dapr HTTP Event Subscriber in Go](https://github.com/mchmarny/dapr-http-event-subscriber-template) - Template project to jump start your Dapr event subscriber service with HTTP development
+* [Dapr HTTP cron Handler in Go](https://github.com/mchmarny/dapr-http-cron-handler-template) - Template project to jump start your Dapr service development for scheduled workloads
+
+
+## Contributing to Dapr Go client
+
+See the [Contribution Guide](../../CONTRIBUTING.md) to get started with building and developing.
diff --git a/vendor/github.com/dapr/go-sdk/service/http/binding.go b/vendor/github.com/dapr/go-sdk/service/http/binding.go
new file mode 100644
index 00000000000..f8d888cd085
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/service/http/binding.go
@@ -0,0 +1,84 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package http
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+
+ "github.com/dapr/go-sdk/service/common"
+)
+
+// AddBindingInvocationHandler appends provided binding invocation handler with its route to the service.
+func (s *Server) AddBindingInvocationHandler(route string, fn common.BindingInvocationHandler) error {
+ if route == "" {
+ return fmt.Errorf("binding route required")
+ }
+ if fn == nil {
+ return fmt.Errorf("binding handler required")
+ }
+
+ if !strings.HasPrefix(route, "/") {
+ route = fmt.Sprintf("/%s", route)
+ }
+
+ s.mux.Handle(route, optionsHandler(http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ var content []byte
+ if r.ContentLength > 0 {
+ body, err := io.ReadAll(r.Body)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
+ content = body
+ }
+
+ // assuming Dapr doesn't pass multiple values for key
+ meta := map[string]string{}
+ for k, values := range r.Header {
+ // TODO: Need to figure out how to parse out only the headers set in the binding + Traceparent
+ // if k == "raceparent" || strings.HasPrefix(k, "dapr") {
+ for _, v := range values {
+ meta[k] = v
+ }
+ // }
+ }
+
+ // execute handler
+ in := &common.BindingEvent{
+ Data: content,
+ Metadata: meta,
+ }
+ out, err := fn(r.Context(), in)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ if out == nil {
+ out = []byte("{}")
+ }
+
+ w.Header().Add("Content-Type", "application/json")
+ if _, err := w.Write(out); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })))
+
+ return nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/service/http/health_check.go b/vendor/github.com/dapr/go-sdk/service/http/health_check.go
new file mode 100644
index 00000000000..3f4ca7c15b4
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/service/http/health_check.go
@@ -0,0 +1,45 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package http
+
+import (
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/dapr/go-sdk/service/common"
+)
+
+// AddHealthCheckHandler appends provided app health check handler.
+func (s *Server) AddHealthCheckHandler(route string, fn common.HealthCheckHandler) error {
+ if fn == nil {
+ return fmt.Errorf("health check handler required")
+ }
+
+ if !strings.HasPrefix(route, "/") {
+ route = fmt.Sprintf("/%s", route)
+ }
+
+ s.mux.Handle(route, optionsHandler(http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ if err := fn(r.Context()); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.WriteHeader(http.StatusNoContent)
+ })))
+
+ return nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/service/http/invoke.go b/vendor/github.com/dapr/go-sdk/service/http/invoke.go
new file mode 100644
index 00000000000..f9500069cf7
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/service/http/invoke.go
@@ -0,0 +1,97 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package http
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+
+ "google.golang.org/grpc/metadata"
+
+ "github.com/dapr/go-sdk/service/common"
+)
+
+// AddServiceInvocationHandler appends provided service invocation handler with its route to the service.
+func (s *Server) AddServiceInvocationHandler(route string, fn common.ServiceInvocationHandler) error {
+ if route == "" || route == "/" {
+ return fmt.Errorf("service route required")
+ }
+
+ if fn == nil {
+ return fmt.Errorf("invocation handler required")
+ }
+
+ if !strings.HasPrefix(route, "/") {
+ route = "/" + route
+ }
+
+ s.mux.Handle(route, optionsHandler(http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ if s.authToken != "" {
+ token := r.Header.Get(common.APITokenKey)
+ if token == "" || token != s.authToken {
+ http.Error(w, "authentication failed.", http.StatusNonAuthoritativeInfo)
+ return
+ }
+ }
+ // capture http args
+ e := &common.InvocationEvent{
+ Verb: r.Method,
+ QueryString: r.URL.RawQuery,
+ ContentType: r.Header.Get("Content-type"),
+ }
+
+ // check for post with no data
+ if r.ContentLength > 0 {
+ content, err := io.ReadAll(r.Body)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
+ e.Data = content
+ }
+
+ ctx := r.Context()
+ md, ok := metadata.FromIncomingContext(ctx)
+ if !ok {
+ md = metadata.MD{}
+ }
+ for k, v := range r.Header {
+ md.Set(k, v...)
+ }
+ ctx = metadata.NewIncomingContext(ctx, md)
+
+ // execute handler
+ o, err := fn(ctx, e)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ // write to response if handler returned data
+ if o != nil && o.Data != nil {
+ if o.ContentType != "" {
+ w.Header().Set("Content-type", o.ContentType)
+ }
+ if _, err := w.Write(o.Data); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ }
+ })))
+
+ return nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/service/http/service.go b/vendor/github.com/dapr/go-sdk/service/http/service.go
new file mode 100644
index 00000000000..df70f32f33b
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/service/http/service.go
@@ -0,0 +1,108 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package http
+
+import (
+ "context"
+ "net/http"
+ "os"
+ "time"
+
+ "github.com/go-chi/chi/v5"
+
+ "github.com/dapr/go-sdk/actor"
+ "github.com/dapr/go-sdk/actor/config"
+ "github.com/dapr/go-sdk/actor/runtime"
+ "github.com/dapr/go-sdk/service/common"
+ "github.com/dapr/go-sdk/service/internal"
+)
+
+// NewService creates new Service.
+func NewService(address string) common.Service {
+ return newServer(address, nil)
+}
+
+// NewServiceWithMux creates new Service with existing http mux.
+func NewServiceWithMux(address string, mux *chi.Mux) common.Service {
+ return newServer(address, mux)
+}
+
+func newServer(address string, router *chi.Mux) *Server {
+ if router == nil {
+ router = chi.NewRouter()
+ }
+ return &Server{
+ address: address,
+ httpServer: &http.Server{ //nolint:gosec
+ Addr: address,
+ Handler: router,
+ },
+ mux: router,
+ topicRegistrar: make(internal.TopicRegistrar),
+ authToken: os.Getenv(common.AppAPITokenEnvVar),
+ }
+}
+
+// Server is the HTTP server wrapping mux many Dapr helpers.
+type Server struct {
+ address string
+ mux *chi.Mux
+ httpServer *http.Server
+ topicRegistrar internal.TopicRegistrar
+ authToken string
+}
+
+// Deprecated: Use RegisterActorImplFactoryContext instead.
+func (s *Server) RegisterActorImplFactory(f actor.Factory, opts ...config.Option) {
+ runtime.GetActorRuntimeInstance().RegisterActorFactory(f, opts...)
+}
+
+func (s *Server) RegisterActorImplFactoryContext(f actor.FactoryContext, opts ...config.Option) {
+ runtime.GetActorRuntimeInstanceContext().RegisterActorFactory(f, opts...)
+}
+
+// Start starts the HTTP handler. Blocks while serving.
+func (s *Server) Start() error {
+ s.registerBaseHandler()
+ return s.httpServer.ListenAndServe()
+}
+
+// Stop stops previously started HTTP service with a five second timeout.
+func (s *Server) Stop() error {
+ ctxShutDown, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+
+ return s.httpServer.Shutdown(ctxShutDown)
+}
+
+func (s *Server) GracefulStop() error {
+ return s.Stop()
+}
+
+func setOptions(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Access-Control-Allow-Origin", "*")
+ w.Header().Set("Access-Control-Allow-Methods", "POST,OPTIONS")
+ w.Header().Set("Access-Control-Allow-Headers", "authorization, origin, content-type, accept")
+ w.Header().Set("Allow", "POST,OPTIONS")
+}
+
+func optionsHandler(h http.Handler) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodOptions {
+ setOptions(w, r)
+ } else {
+ h.ServeHTTP(w, r)
+ }
+ }
+}
diff --git a/vendor/github.com/dapr/go-sdk/service/http/topic.go b/vendor/github.com/dapr/go-sdk/service/http/topic.go
new file mode 100644
index 00000000000..461c2a99213
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/service/http/topic.go
@@ -0,0 +1,291 @@
+/*
+Copyright 2021 The Dapr Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package http
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "io"
+ "net/http"
+
+ "github.com/go-chi/chi/v5"
+
+ actorErr "github.com/dapr/go-sdk/actor/error"
+ "github.com/dapr/go-sdk/actor/runtime"
+ "github.com/dapr/go-sdk/service/common"
+ "github.com/dapr/go-sdk/service/internal"
+)
+
+const (
+ // PubSubHandlerSuccessStatusCode is the successful ack code for pubsub event appcallback response.
+ PubSubHandlerSuccessStatusCode int = http.StatusOK
+
+ // PubSubHandlerRetryStatusCode is the error response code (nack) pubsub event appcallback response.
+ PubSubHandlerRetryStatusCode int = http.StatusInternalServerError
+
+ // PubSubHandlerDropStatusCode is the pubsub event appcallback response code indicating that Dapr should drop that message.
+ PubSubHandlerDropStatusCode int = http.StatusSeeOther
+)
+
+// topicEventJSON is identical to `common.TopicEvent`
+// except for it treats `data` as a json.RawMessage so it can
+// be used as bytes or interface{}.
+type topicEventJSON struct {
+ // ID identifies the event.
+ ID string `json:"id"`
+ // The version of the CloudEvents specification.
+ SpecVersion string `json:"specversion"`
+ // The type of event related to the originating occurrence.
+ Type string `json:"type"`
+ // Source identifies the context in which an event happened.
+ Source string `json:"source"`
+ // The content type of data value.
+ DataContentType string `json:"datacontenttype"`
+ // The content of the event.
+ // Note, this is why the gRPC and HTTP implementations need separate structs for cloud events.
+ Data json.RawMessage `json:"data"`
+ // The base64 encoding content of the event.
+ // Note, this is processing rawPayload and binary content types.
+ DataBase64 string `json:"data_base64,omitempty"`
+ // Cloud event subject
+ Subject string `json:"subject"`
+ // The pubsub topic which publisher sent to.
+ Topic string `json:"topic"`
+ // PubsubName is name of the pub/sub this message came from
+ PubsubName string `json:"pubsubname"`
+}
+
+func (s *Server) registerBaseHandler() {
+ // register subscribe handler
+ f := func(w http.ResponseWriter, r *http.Request) {
+ subs := make([]*internal.TopicSubscription, 0, len(s.topicRegistrar))
+ for _, s := range s.topicRegistrar {
+ subs = append(subs, s.Subscription)
+ }
+ w.Header().Set("Content-Type", "application/json")
+ if err := json.NewEncoder(w).Encode(subs); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ }
+ s.mux.HandleFunc("/dapr/subscribe", f)
+
+ // register health check handler
+ fHealth := func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ }
+ s.mux.Get("/healthz", fHealth)
+
+ // register actor config handler
+ fRegister := func(w http.ResponseWriter, r *http.Request) {
+ data, err := runtime.GetActorRuntimeInstanceContext().GetJSONSerializedConfig()
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ w.WriteHeader(http.StatusOK)
+ if _, err = w.Write(data); err != nil {
+ return
+ }
+ }
+ s.mux.Get("/dapr/config", fRegister)
+
+ // register actor method invoke handler
+ fInvoke := func(w http.ResponseWriter, r *http.Request) {
+ actorType := chi.URLParam(r, "actorType")
+ actorID := chi.URLParam(r, "actorId")
+ methodName := chi.URLParam(r, "methodName")
+ reqData, _ := io.ReadAll(r.Body)
+ rspData, err := runtime.GetActorRuntimeInstanceContext().InvokeActorMethod(r.Context(), actorType, actorID, methodName, reqData)
+ if err == actorErr.ErrActorTypeNotFound {
+ w.WriteHeader(http.StatusNotFound)
+ return
+ }
+ if err != actorErr.Success {
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ w.WriteHeader(http.StatusOK)
+ _, _ = w.Write(rspData)
+ }
+ s.mux.Put("/actors/{actorType}/{actorId}/method/{methodName}", fInvoke)
+
+ // register deactivate actor handler
+ fDelete := func(w http.ResponseWriter, r *http.Request) {
+ actorType := chi.URLParam(r, "actorType")
+ actorID := chi.URLParam(r, "actorId")
+ err := runtime.GetActorRuntimeInstanceContext().Deactivate(r.Context(), actorType, actorID)
+ if err == actorErr.ErrActorTypeNotFound || err == actorErr.ErrActorIDNotFound {
+ w.WriteHeader(http.StatusNotFound)
+ }
+ if err != actorErr.Success {
+ w.WriteHeader(http.StatusInternalServerError)
+ }
+ w.WriteHeader(http.StatusOK)
+ }
+ s.mux.Delete("/actors/{actorType}/{actorId}", fDelete)
+
+ // register actor reminder invoke handler
+ fReminder := func(w http.ResponseWriter, r *http.Request) {
+ actorType := chi.URLParam(r, "actorType")
+ actorID := chi.URLParam(r, "actorId")
+ reminderName := chi.URLParam(r, "reminderName")
+ reqData, _ := io.ReadAll(r.Body)
+ err := runtime.GetActorRuntimeInstanceContext().InvokeReminder(r.Context(), actorType, actorID, reminderName, reqData)
+ if err == actorErr.ErrActorTypeNotFound {
+ w.WriteHeader(http.StatusNotFound)
+ }
+ if err != actorErr.Success {
+ w.WriteHeader(http.StatusInternalServerError)
+ }
+ w.WriteHeader(http.StatusOK)
+ }
+ s.mux.Put("/actors/{actorType}/{actorId}/method/remind/{reminderName}", fReminder)
+
+ // register actor timer invoke handler
+ fTimer := func(w http.ResponseWriter, r *http.Request) {
+ actorType := chi.URLParam(r, "actorType")
+ actorID := chi.URLParam(r, "actorId")
+ timerName := chi.URLParam(r, "timerName")
+ reqData, _ := io.ReadAll(r.Body)
+ err := runtime.GetActorRuntimeInstanceContext().InvokeTimer(r.Context(), actorType, actorID, timerName, reqData)
+ if err == actorErr.ErrActorTypeNotFound {
+ w.WriteHeader(http.StatusNotFound)
+ }
+ if err != actorErr.Success {
+ w.WriteHeader(http.StatusInternalServerError)
+ }
+ w.WriteHeader(http.StatusOK)
+ }
+ s.mux.Put("/actors/{actorType}/{actorId}/method/timer/{timerName}", fTimer)
+}
+
+// AddTopicEventHandler appends provided event handler with it's name to the service.
+func (s *Server) AddTopicEventHandler(sub *common.Subscription, fn common.TopicEventHandler) error {
+ if sub == nil {
+ return errors.New("subscription required")
+ }
+ // Route is only required for HTTP but should be specified for the
+ // app protocol to be interchangeable.
+ if sub.Route == "" {
+ return errors.New("handler route name")
+ }
+ if err := s.topicRegistrar.AddSubscription(sub, fn); err != nil {
+ return err
+ }
+
+ s.mux.Handle(sub.Route, optionsHandler(http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ // check for post with no data
+ if r.ContentLength == 0 {
+ http.Error(w, "nil content", PubSubHandlerDropStatusCode)
+ return
+ }
+
+ // deserialize the event
+ var in topicEventJSON
+ if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
+ http.Error(w, err.Error(), PubSubHandlerDropStatusCode)
+ return
+ }
+
+ if in.PubsubName == "" {
+ in.Topic = sub.PubsubName
+ }
+ if in.Topic == "" {
+ in.Topic = sub.Topic
+ }
+
+ var data interface{}
+ var rawData []byte
+ if len(in.Data) > 0 {
+ rawData = []byte(in.Data)
+ data = rawData
+ var v interface{}
+ // We can assume that rawData is valid JSON
+ // without checking in.DataContentType == "application/json".
+ if err := json.Unmarshal(rawData, &v); err == nil {
+ data = v
+ // Handling of JSON base64 encoded or escaped in a string.
+ if str, ok := v.(string); ok {
+ // This is the path that will most likely succeed.
+ var vString interface{}
+ if err := json.Unmarshal([]byte(str), &vString); err == nil {
+ data = vString
+ } else if decoded, err := base64.StdEncoding.DecodeString(str); err == nil {
+ // Decoded Base64 encoded JSON does not seem to be in the spec
+ // but it is in existing unit tests so this handles that case.
+ var vBase64 interface{}
+ if err := json.Unmarshal(decoded, &vBase64); err == nil {
+ data = vBase64
+ }
+ }
+ }
+ }
+ } else if in.DataBase64 != "" {
+ var err error
+ rawData, err = base64.StdEncoding.DecodeString(in.DataBase64)
+ if err == nil {
+ data = rawData
+ if in.DataContentType == "application/json" {
+ var v interface{}
+ if err := json.Unmarshal(rawData, &v); err == nil {
+ data = v
+ }
+ }
+ }
+ }
+
+ te := common.TopicEvent{
+ ID: in.ID,
+ SpecVersion: in.SpecVersion,
+ Type: in.Type,
+ Source: in.Source,
+ DataContentType: in.DataContentType,
+ Data: data,
+ RawData: rawData,
+ DataBase64: in.DataBase64,
+ Subject: in.Subject,
+ PubsubName: in.PubsubName,
+ Topic: in.Topic,
+ }
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ // execute user handler
+ retry, err := fn(r.Context(), &te)
+ if err == nil {
+ writeStatus(w, common.SubscriptionResponseStatusSuccess)
+ return
+ }
+
+ if retry {
+ writeStatus(w, common.SubscriptionResponseStatusRetry)
+ return
+ }
+
+ writeStatus(w, common.SubscriptionResponseStatusDrop)
+ })))
+
+ return nil
+}
+
+func writeStatus(w http.ResponseWriter, s string) {
+ status := &common.SubscriptionResponse{Status: s}
+ if err := json.NewEncoder(w).Encode(status); err != nil {
+ http.Error(w, err.Error(), PubSubHandlerRetryStatusCode)
+ }
+}
diff --git a/vendor/github.com/dapr/go-sdk/service/internal/topicregistrar.go b/vendor/github.com/dapr/go-sdk/service/internal/topicregistrar.go
new file mode 100644
index 00000000000..ec4efb9e080
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/service/internal/topicregistrar.go
@@ -0,0 +1,64 @@
+package internal
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/dapr/go-sdk/service/common"
+)
+
+// TopicRegistrar is a map of - to `TopicRegistration`
+// and acts as a lookup as the application is building up subscriptions with
+// potentially multiple routes per topic.
+type TopicRegistrar map[string]*TopicRegistration
+
+// TopicRegistration encapsulates the subscription and handlers.
+type TopicRegistration struct {
+ Subscription *TopicSubscription
+ DefaultHandler common.TopicEventHandler
+ RouteHandlers map[string]common.TopicEventHandler
+}
+
+func (m TopicRegistrar) AddSubscription(sub *common.Subscription, fn common.TopicEventHandler) error {
+ if sub.Topic == "" {
+ return errors.New("topic name required")
+ }
+ if sub.PubsubName == "" {
+ return errors.New("pub/sub name required")
+ }
+ if fn == nil {
+ return fmt.Errorf("topic handler required")
+ }
+
+ var key string
+ if !sub.DisableTopicValidation {
+ key = sub.PubsubName + "-" + sub.Topic
+ } else {
+ key = sub.PubsubName
+ }
+
+ ts, ok := m[key]
+ if !ok {
+ ts = &TopicRegistration{
+ Subscription: NewTopicSubscription(sub.PubsubName, sub.Topic),
+ RouteHandlers: make(map[string]common.TopicEventHandler),
+ DefaultHandler: nil,
+ }
+ ts.Subscription.SetMetadata(sub.Metadata)
+ m[key] = ts
+ }
+
+ if sub.Match != "" {
+ if err := ts.Subscription.AddRoutingRule(sub.Route, sub.Match, sub.Priority); err != nil {
+ return err
+ }
+ } else {
+ if err := ts.Subscription.SetDefaultRoute(sub.Route); err != nil {
+ return err
+ }
+ ts.DefaultHandler = fn
+ }
+ ts.RouteHandlers[sub.Route] = fn
+
+ return nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/service/internal/topicsubscription.go b/vendor/github.com/dapr/go-sdk/service/internal/topicsubscription.go
new file mode 100644
index 00000000000..ca628993767
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/service/internal/topicsubscription.go
@@ -0,0 +1,112 @@
+package internal
+
+import (
+ "errors"
+ "fmt"
+ "sort"
+)
+
+// TopicSubscription internally represents single topic subscription.
+type TopicSubscription struct {
+ // PubsubName is name of the pub/sub this message came from.
+ PubsubName string `json:"pubsubname"`
+ // Topic is the name of the topic.
+ Topic string `json:"topic"`
+ // Route is the route of the handler where HTTP topic events should be published (passed as Path in gRPC).
+ Route string `json:"route,omitempty"`
+ // Routes specify multiple routes where topic events should be sent.
+ Routes *TopicRoutes `json:"routes,omitempty"`
+ // Metadata is the subscription metadata.
+ Metadata map[string]string `json:"metadata,omitempty"`
+}
+
+// TopicRoutes encapsulates the default route and multiple routing rules.
+type TopicRoutes struct {
+ Rules []TopicRule `json:"rules,omitempty"`
+ Default string `json:"default,omitempty"`
+
+ // priority is used to track duplicate priorities where priority > 0.
+ // when priority is not specified (0), then the order in which they
+ // were added is used.
+ priorities map[int]struct{}
+}
+
+// TopicRule represents a single routing rule.
+type TopicRule struct {
+ // Match is the CEL expression to match on the CloudEvent envelope.
+ Match string `json:"match"`
+ // Path is the HTTP path to post the event to (passed as Path in gRPC).
+ Path string `json:"path"`
+ // priority is the optional priority order (low to high) for this rule.
+ priority int `json:"-"`
+}
+
+// NewTopicSubscription creates a new `TopicSubscription`.
+func NewTopicSubscription(pubsubName, topic string) *TopicSubscription {
+ return &TopicSubscription{ //nolint:exhaustivestruct
+ PubsubName: pubsubName,
+ Topic: topic,
+ }
+}
+
+// SetMetadata sets the metadata for the subscription if not already set.
+// An error is returned if it is already set.
+func (s *TopicSubscription) SetMetadata(metadata map[string]string) error {
+ if s.Metadata != nil {
+ return fmt.Errorf("subscription for topic %s on pubsub %s already has metadata set", s.Topic, s.PubsubName)
+ }
+ s.Metadata = metadata
+
+ return nil
+}
+
+// SetDefaultRoute sets the default route if not already set.
+// An error is returned if it is already set.
+func (s *TopicSubscription) SetDefaultRoute(path string) error {
+ if s.Routes == nil {
+ if s.Route != "" {
+ return fmt.Errorf("subscription for topic %s on pubsub %s already has route %s", s.Topic, s.PubsubName, s.Route)
+ }
+ s.Route = path
+ } else {
+ if s.Routes.Default != "" {
+ return fmt.Errorf("subscription for topic %s on pubsub %s already has route %s", s.Topic, s.PubsubName, s.Routes.Default)
+ }
+ s.Routes.Default = path
+ }
+
+ return nil
+}
+
+// AddRoutingRule adds a routing rule.
+// An error is returned if a there id a duplicate priority > 1.
+func (s *TopicSubscription) AddRoutingRule(path, match string, priority int) error {
+ if path == "" {
+ return errors.New("path is required for routing rules")
+ }
+ if s.Routes == nil {
+ s.Routes = &TopicRoutes{ //nolint:exhaustivestruct
+ Default: s.Route,
+ priorities: map[int]struct{}{},
+ }
+ s.Route = ""
+ }
+ if priority > 0 {
+ if _, exists := s.Routes.priorities[priority]; exists {
+ return fmt.Errorf("subscription for topic %s on pubsub %s already has a routing rule with priority %d", s.Topic, s.PubsubName, priority)
+ }
+ }
+ s.Routes.Rules = append(s.Routes.Rules, TopicRule{
+ Match: match,
+ Path: path,
+ priority: priority,
+ })
+ sort.SliceStable(s.Routes.Rules, func(i, j int) bool {
+ return s.Routes.Rules[i].priority < s.Routes.Rules[j].priority
+ })
+ if priority > 0 {
+ s.Routes.priorities[priority] = struct{}{}
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/dapr/go-sdk/version/sdk-version b/vendor/github.com/dapr/go-sdk/version/sdk-version
new file mode 100644
index 00000000000..b7c8e167db9
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/version/sdk-version
@@ -0,0 +1 @@
+v1.7.0
\ No newline at end of file
diff --git a/vendor/github.com/dapr/go-sdk/version/version.go b/vendor/github.com/dapr/go-sdk/version/version.go
new file mode 100644
index 00000000000..e5c4a1128c9
--- /dev/null
+++ b/vendor/github.com/dapr/go-sdk/version/version.go
@@ -0,0 +1,11 @@
+package version
+
+import (
+ // Required for go:embed.
+ _ "embed"
+)
+
+// SDKVersion contains the version of the SDK.
+//
+//go:embed sdk-version
+var SDKVersion string
diff --git a/vendor/github.com/docker/cli/AUTHORS b/vendor/github.com/docker/cli/AUTHORS
index 8990f85b56e..483743c9921 100644
--- a/vendor/github.com/docker/cli/AUTHORS
+++ b/vendor/github.com/docker/cli/AUTHORS
@@ -1,9 +1,10 @@
-# This file lists all individuals having contributed content to the repository.
-# For how it is generated, see `scripts/docs/generate-authors.sh`.
+# File @generated by scripts/docs/generate-authors.sh. DO NOT EDIT.
+# This file lists all contributors to the repository.
+# See scripts/docs/generate-authors.sh to make modifications.
Aanand Prasad
Aaron L. Xu
-Aaron Lehmann
+Aaron Lehmann
Aaron.L.Xu
Abdur Rehman
Abhinandan Prativadi
@@ -24,22 +25,27 @@ Akihiro Suda
Akim Demaille
Alan Thompson
Albert Callarisa
+Alberto Roura
Albin Kerouanton
Aleksa Sarai
Aleksander Piotrowski
Alessandro Boch
+Alex Couture-Beil
Alex Mavrogiannis
Alex Mayer
Alexander Boyd
Alexander Larsson
-Alexander Morozov
+Alexander Morozov
Alexander Ryabov
Alexandre González
+Alexey Igrychev
+Alexis Couvreur
Alfred Landrum
Alicia Lauerman
Allen Sun
Alvin Deng
Amen Belayneh
+Amey Shrivastava <72866602+AmeyShrivastava@users.noreply.github.com>
Amir Goldstein
Amit Krishnan
Amit Shukla
@@ -48,6 +54,8 @@ Anca Iordache
Anda Xu
Andrea Luzzardi
Andreas Köhler
+Andres G. Aragoneses
+Andres Leon Rangel
Andrew France
Andrew Hsu
Andrew Macpherson
@@ -67,8 +75,9 @@ Antonis Kalipetis
Anusha Ragunathan
Ao Li
Arash Deshmeh
-Arko Dasgupta
-Arnaud Porterie
+Arko Dasgupta
+Arnaud Porterie
+Arnaud Rebillout
Arthur Peka
Ashwini Oruganti
Azat Khuyiyakhmetov
@@ -76,18 +85,23 @@ Bardia Keyoumarsi
Barnaby Gray
Bastiaan Bakker
BastianHofmann
+Ben Bodenmiller
Ben Bonnefoy
Ben Creasy
Ben Firshman
Benjamin Boudreau
+Benjamin Böhmke
+Benjamin Nater
Benoit Sigoure
Bhumika Bayani
Bill Wang
Bin Liu
Bingshen Wang
+Bishal Das
Boaz Shuster
Bogdan Anton
Boris Pruessmann
+Brad Baker
Bradley Cicenas
Brandon Mitchell
Brandon Philips
@@ -96,6 +110,7 @@ Bret Fisher
Brian (bex) Exelbierd
Brian Goff
Brian Wieder
+Bruno Sousa
Bryan Bess
Bryan Boreham
Bryan Murphy
@@ -114,15 +129,19 @@ Charles Chan
Charles Law
Charles Smith
Charlie Drage
+Charlotte Mach
ChaYoung You
+Chee Hau Lim
Chen Chuanliang
Chen Hanxiao
Chen Mingjie
Chen Qiu
+Chris Couzens
Chris Gavin
Chris Gibson
Chris McKinnel
Chris Snow
+Chris Vermilion
Chris Weyl
Christian Persson
Christian Stefanescu
@@ -131,6 +150,7 @@ Christophe Vidal
Christopher Biscardi
Christopher Crone
Christopher Jones
+Christopher Svensson
Christy Norman
Chun Chen
Clinton Kitson
@@ -139,8 +159,10 @@ Colin Hebert
Collin Guarino
Colm Hally
Comical Derskeal <27731088+derskeal@users.noreply.github.com>
+Conner Crosby
Corey Farrell
Corey Quon
+Cory Bennet
Craig Wilhite
Cristian Staretu
Daehyeok Mun
@@ -170,11 +192,13 @@ Dattatraya Kumbhar
Dave Goodchild
Dave Henderson
Dave Tucker
+David Alvarez
David Beitey
David Calavera
David Cramer
David Dooling
David Gageot
+David Karlsson
David Lechner
David Scott
David Sheets
@@ -186,7 +210,8 @@ Denis Defreyne
Denis Gladkikh
Denis Ollier
Dennis Docter
-Derek McGowan
+Derek McGowan
+Des Preston
Deshi Xiao
Dharmit Shah
Dhawal Yogesh Bhanushali
@@ -196,12 +221,14 @@ Dimitry Andric
Ding Fei
Diogo Monica
Djordje Lukic
+Dmitriy Fishman
Dmitry Gusev
Dmitry Smirnov
Dmitry V. Krivenok
Dominik Braun
Don Kjer
Dong Chen
+DongGeon Lee
Doug Davis
Drew Erny
Ed Costello
@@ -211,12 +238,14 @@ Eli Uriegas
Elias Faxö
Elliot Luo <956941328@qq.com>
Eric Curtin
+Eric Engestrom
Eric G. Noriega
Eric Rosenberg
Eric Sage
Eric-Olivier Lamey
Erica Windisch
Erik Hollensbe
+Erik Humphrey
Erik St. Martin
Essam A. Hassan
Ethan Haynes