diff --git a/.github/workflows/build-and-push-all-docker-images.yml b/.github/workflows/build-and-push-all-docker-images.yml index a9ca73094d..2ae56dc5de 100644 --- a/.github/workflows/build-and-push-all-docker-images.yml +++ b/.github/workflows/build-and-push-all-docker-images.yml @@ -14,6 +14,7 @@ jobs: fail-fast: false matrix: component: + - cacheservice - datacatalog - flyteadmin - flytecopilot diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 9f692f0f4a..457eb30650 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -30,6 +30,7 @@ jobs: fail-fast: false matrix: component: + - cacheservice - datacatalog - flyteadmin # TODO(monorepo): Enable lint flytecopilot @@ -50,6 +51,7 @@ jobs: fail-fast: false matrix: component: + - cacheservice - datacatalog - flyteadmin - flytecopilot @@ -65,6 +67,7 @@ jobs: fail-fast: false matrix: component: + - cacheservice - datacatalog - flyteadmin - flytecopilot @@ -108,6 +111,7 @@ jobs: fail-fast: false matrix: component: + - cacheservice - datacatalog - flyteadmin - flytecopilot diff --git a/.github/workflows/end2end.yml b/.github/workflows/end2end.yml index aff4665fee..cf98656a2f 100644 --- a/.github/workflows/end2end.yml +++ b/.github/workflows/end2end.yml @@ -30,6 +30,11 @@ jobs: - uses: actions/setup-python@v3 with: python-version: 3.11 + - id: load-docker-cache-cacheservice + uses: actions/cache@v3 + with: + path: /tmp/tmp/docker-images-cacheservice + key: ${{ inputs.cache_key }}-cacheservice - id: load-docker-cache-datacatalog uses: actions/cache@v3 with: @@ -52,6 +57,7 @@ jobs: key: ${{ inputs.cache_key }}-flytepropeller - name: Create Sandbox Cluster run: | + cp /tmp/tmp/docker-images-cacheservice/snapshot-cacheservice.tar snapshot-cacheservice.tar cp /tmp/tmp/docker-images-datacatalog/snapshot-datacatalog.tar snapshot-datacatalog.tar cp /tmp/tmp/docker-images-flyteadmin/snapshot-flyteadmin.tar snapshot-flyteadmin.tar cp /tmp/tmp/docker-images-flytecopilot/snapshot-flytecopilot.tar snapshot-flytecopilot.tar @@ -60,6 +66,7 @@ jobs: flytectl sandbox start --source=$(pwd) - name: Prime docker cache run: | + flytectl sandbox exec -- docker load -i /root/snapshot-cacheservice.tar flytectl sandbox exec -- docker load -i /root/snapshot-datacatalog.tar flytectl sandbox exec -- docker load -i /root/snapshot-flyteadmin.tar flytectl sandbox exec -- docker load -i /root/snapshot-flytecopilot.tar @@ -107,10 +114,11 @@ jobs: run: | flytectl sandbox exec -- helm repo add flyteorg https://flyteorg.github.io/flyte flytectl sandbox exec -- helm repo update - flytectl sandbox exec -- helm upgrade flyte -n flyte-core --kubeconfig=/etc/rancher/k3s/k3s.yaml flyteorg/flyte-core -f /flyteorg/share/flyte/values-sandbox.yaml --wait --set datacatalog.image.repository=${{ github.repository_owner }}/datacalog,datacatalog.image.tag=latest + flytectl sandbox exec -- helm upgrade flyte -n flyte-core --kubeconfig=/etc/rancher/k3s/k3s.yaml flyteorg/flyte-core -f /flyteorg/share/flyte/values-sandbox.yaml --wait --set datacatalog.image.repository=${{ github.repository_owner }}/datacalog,datacatalog.image.tag=latest,cacheservice.image.repository=${{ github.repository_owner }}/cacheservice,cacheservice.image.tag=latest # TODO(monorepo): the following commands are not correct. # we have to separate the calls to replace the images into different commands. # flytectl sandbox exec -- helm upgrade flyte -n flyte-core --kubeconfig=/etc/rancher/k3s/k3s.yaml flyteorg/flyte-core -f /flyteorg/share/flyte/values-sandbox.yaml --wait \ + # --set cacheservice.image.repository=${{ github.repository_owner }}/cacheservice,cacheservice.image.tag=latest # --set datacatalog.image.repository=${{ github.repository_owner }}/datacalog,datacatalog.image.tag=latest # --set flyteadmin.image.repository=${{ github.repository_owner }}/datacalog,flyteadmin.image.tag=latest # --set flytecopilot.image.repository=${{ github.repository_owner }}/datacalog,flytecopilot.image.tag=latest diff --git a/Dockerfile b/Dockerfile index 6ce448399b..e25463157f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,6 +10,7 @@ ENV GOOS linux WORKDIR /flyteorg/build +COPY cacheservice cacheservice COPY datacatalog datacatalog COPY flyteadmin flyteadmin COPY flytecopilot flytecopilot diff --git a/Dockerfile.cacheservice b/Dockerfile.cacheservice new file mode 100644 index 0000000000..4453f91248 --- /dev/null +++ b/Dockerfile.cacheservice @@ -0,0 +1,53 @@ +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +FROM --platform=${BUILDPLATFORM} golang:1.21.5-alpine3.18 as builder + +ARG TARGETARCH +ENV GOARCH "${TARGETARCH}" +ENV GOOS linux + +RUN apk add git openssh-client make curl + +# Create the artifacts directory +RUN mkdir /artifacts + +# Pull GRPC health probe binary for liveness and readiness checks +RUN GRPC_HEALTH_PROBE_VERSION=v0.4.11 && \ + wget -qO/artifacts/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ + chmod +x /artifacts/grpc_health_probe && \ + echo 'ded15e598d887ccc47bf2321371950bbf930f5e4856b9f75712ce4b2b5120480 /artifacts/grpc_health_probe' > .grpc_checksum && \ + sha256sum -c .grpc_checksum + +WORKDIR /go/src/github.com/flyteorg/cacheservice + +COPY cacheservice . +COPY flyteadmin ../flyteadmin +COPY flytecopilot ../flytecopilot +COPY flyteidl ../flyteidl +COPY flyteplugins ../flyteplugins +COPY flytepropeller ../flytepropeller +COPY flytestdlib ../flytestdlib + +# This 'linux_compile' target should compile binaries to the /artifacts directory +# The main entrypoint should be compiled to /artifacts/cacheservice +RUN make linux_compile + +# update the PATH to include the /artifacts directory +ENV PATH="/artifacts:${PATH}" + +# This will eventually move to centurylink/ca-certs:latest for minimum possible image size +FROM alpine:3.18 +LABEL org.opencontainers.image.source=https://github.com/flyteorg/cacheservice + +COPY --from=builder /artifacts /bin + +# Ensure the latest CA certs are present to authenticate SSL connections. +RUN apk --update add ca-certificates + +RUN addgroup -S flyte && adduser -S flyte -G flyte +USER flyte + +CMD ["cacheservice"] diff --git a/Dockerfile.flyteadmin b/Dockerfile.flyteadmin index 993949b221..883000d1c7 100644 --- a/Dockerfile.flyteadmin +++ b/Dockerfile.flyteadmin @@ -23,6 +23,7 @@ RUN GRPC_HEALTH_PROBE_VERSION=v0.4.11 && \ WORKDIR /go/src/github.com/flyteorg/flyteadmin +COPY cacheservice ../cacheservice COPY datacatalog ../datacatalog COPY flyteadmin . COPY flytecopilot ../flytecopilot diff --git a/Dockerfile.flytecopilot b/Dockerfile.flytecopilot index 247a04e969..6101764f8f 100644 --- a/Dockerfile.flytecopilot +++ b/Dockerfile.flytecopilot @@ -13,6 +13,7 @@ RUN apk add git openssh-client make curl WORKDIR /go/src/github.com/flyteorg/flytecopilot +COPY cacheservice ../cacheservice COPY datacatalog ../datacatalog COPY flyteadmin ../flyteadmin COPY flytecopilot . diff --git a/Dockerfile.flytepropeller b/Dockerfile.flytepropeller index 8da39815be..d524fbcf4a 100644 --- a/Dockerfile.flytepropeller +++ b/Dockerfile.flytepropeller @@ -13,6 +13,7 @@ RUN apk add git openssh-client make curl WORKDIR /go/src/github.com/flyteorg/flytepropeller +COPY cacheservice ../cacheservice COPY datacatalog ../datacatalog COPY flyteadmin ../flyteadmin COPY flytecopilot ../flytecopilot diff --git a/Dockerfile.flytescheduler b/Dockerfile.flytescheduler index 2956d93959..28a1dc145b 100644 --- a/Dockerfile.flytescheduler +++ b/Dockerfile.flytescheduler @@ -16,6 +16,7 @@ RUN mkdir /artifacts WORKDIR /go/src/github.com/flyteorg/flyteadmin +COPY cacheservice ../cacheservice COPY datacatalog ../datacatalog COPY flyteadmin . COPY flytecopilot ../flytecopilot diff --git a/Dockerfile.sandbox-lite b/Dockerfile.sandbox-lite index 46fd6acb72..92414120e2 100644 --- a/Dockerfile.sandbox-lite +++ b/Dockerfile.sandbox-lite @@ -15,6 +15,7 @@ RUN apk add --no-cache build-base COPY go.mod go.sum /app/flyte/ WORKDIR /app/flyte +COPY cacheservice cacheservice COPY datacatalog datacatalog COPY flyteadmin flyteadmin COPY flytecopilot flytecopilot diff --git a/Makefile b/Makefile index 7bcc6e8cf8..f8d9d1e68e 100644 --- a/Makefile +++ b/Makefile @@ -108,6 +108,7 @@ build_native_flyte: .PHONY: go-tidy go-tidy: go mod tidy + make -C cacheservice go-tidy make -C datacatalog go-tidy make -C flyteadmin go-tidy make -C flyteidl go-tidy diff --git a/cacheservice/.gitignore b/cacheservice/.gitignore new file mode 100644 index 0000000000..72ff26ecff --- /dev/null +++ b/cacheservice/.gitignore @@ -0,0 +1,5 @@ +.idea/ +vendor/ +vendor-new/ +.DS_Store +bin/ diff --git a/cacheservice/.golangci.yml b/cacheservice/.golangci.yml new file mode 100644 index 0000000000..7f4dbc80e8 --- /dev/null +++ b/cacheservice/.golangci.yml @@ -0,0 +1,40 @@ +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +run: + skip-dirs: + - pkg/client + +linters: + disable-all: true + enable: + - deadcode + - errcheck + - gas + - gci + - goconst + - goimports + - golint + - gosimple + - govet + - ineffassign + - misspell + - nakedret + - staticcheck + - structcheck + - typecheck + - unconvert + - unparam + - unused + - varcheck + +linters-settings: + gci: + custom-order: true + sections: + - standard + - default + - prefix(github.com/flyteorg) + skip-generated: true diff --git a/cacheservice/Makefile b/cacheservice/Makefile new file mode 100644 index 0000000000..f931c88d17 --- /dev/null +++ b/cacheservice/Makefile @@ -0,0 +1,28 @@ +export REPOSITORY=cacheservice +include boilerplate/flyte/docker_build/Makefile +include boilerplate/flyte/golang_test_targets/Makefile + +.PHONY: update_boilerplate +update_boilerplate: + @curl https://raw.githubusercontent.com/flyteorg/boilerplate/master/boilerplate/update.sh -o boilerplate/update.sh + @boilerplate/update.sh + +.PHONY: compile +compile: + mkdir -p ./bin + go build -o bin/cacheservice ./cmd/main.go + +.PHONY: linux_compile +linux_compile: export CGO_ENABLED ?= 0 +linux_compile: export GOOS ?= linux +linux_compile: + go build -o /artifacts/cacheservice ./cmd/ + +.PHONY: generate +generate: + @go generate ./... + + +.PHONY: go-tidy +go-tidy: + go mod tidy diff --git a/cacheservice/boilerplate/flyte/code_of_conduct/CODE_OF_CONDUCT.md b/cacheservice/boilerplate/flyte/code_of_conduct/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..e12139d691 --- /dev/null +++ b/cacheservice/boilerplate/flyte/code_of_conduct/CODE_OF_CONDUCT.md @@ -0,0 +1,2 @@ +This project is governed by LF AI Foundation's [code of conduct](https://lfprojects.org/policies/code-of-conduct/). +All contributors and participants agree to abide by its terms. diff --git a/cacheservice/boilerplate/flyte/code_of_conduct/README.rst b/cacheservice/boilerplate/flyte/code_of_conduct/README.rst new file mode 100644 index 0000000000..0c9f2f1ec5 --- /dev/null +++ b/cacheservice/boilerplate/flyte/code_of_conduct/README.rst @@ -0,0 +1,2 @@ +CODE OF CONDUCT +~~~~~~~~~~~~~~~ diff --git a/cacheservice/boilerplate/flyte/code_of_conduct/update.sh b/cacheservice/boilerplate/flyte/code_of_conduct/update.sh new file mode 100755 index 0000000000..42f6158460 --- /dev/null +++ b/cacheservice/boilerplate/flyte/code_of_conduct/update.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +cp ${DIR}/CODE_OF_CONDUCT.md ${DIR}/../../../CODE_OF_CONDUCT.md diff --git a/cacheservice/boilerplate/flyte/docker_build/Makefile b/cacheservice/boilerplate/flyte/docker_build/Makefile new file mode 100644 index 0000000000..e2b2b8a18d --- /dev/null +++ b/cacheservice/boilerplate/flyte/docker_build/Makefile @@ -0,0 +1,12 @@ +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +.PHONY: docker_build +docker_build: + IMAGE_NAME=$$REPOSITORY ./boilerplate/flyte/docker_build/docker_build.sh + +.PHONY: dockerhub_push +dockerhub_push: + IMAGE_NAME=flyteorg/$$REPOSITORY REGISTRY=docker.io ./boilerplate/flyte/docker_build/docker_build.sh diff --git a/cacheservice/boilerplate/flyte/docker_build/Readme.rst b/cacheservice/boilerplate/flyte/docker_build/Readme.rst new file mode 100644 index 0000000000..7790b8fbfd --- /dev/null +++ b/cacheservice/boilerplate/flyte/docker_build/Readme.rst @@ -0,0 +1,23 @@ +Docker Build and Push +~~~~~~~~~~~~~~~~~~~~~ + +Provides a ``make docker_build`` target that builds your image locally. + +Provides a ``make dockerhub_push`` target that pushes your final image to Dockerhub. + +The Dockerhub image will tagged ``:`` + +If git head has a git tag, the Dockerhub image will also be tagged ``:``. + +**To Enable:** + +Add ``flyteorg/docker_build`` to your ``boilerplate/update.cfg`` file. + +Add ``include boilerplate/flyte/docker_build/Makefile`` in your main ``Makefile`` _after_ your REPOSITORY environment variable + +:: + + REPOSITORY= + include boilerplate/flyte/docker_build/Makefile + +(this ensures the extra Make targets get included in your main Makefile) diff --git a/cacheservice/boilerplate/flyte/docker_build/docker_build.sh b/cacheservice/boilerplate/flyte/docker_build/docker_build.sh new file mode 100755 index 0000000000..817189aee1 --- /dev/null +++ b/cacheservice/boilerplate/flyte/docker_build/docker_build.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +set -e + +echo "" +echo "------------------------------------" +echo " DOCKER BUILD" +echo "------------------------------------" +echo "" + +if [ -n "$REGISTRY" ]; then + # Do not push if there are unstaged git changes + CHANGED=$(git status --porcelain) + if [ -n "$CHANGED" ]; then + echo "Please commit git changes before pushing to a registry" + exit 1 + fi +fi + + +GIT_SHA=$(git rev-parse HEAD) + +IMAGE_TAG_SUFFIX="" +# for intermediate build phases, append -$BUILD_PHASE to all image tags +if [ -n "$BUILD_PHASE" ]; then + IMAGE_TAG_SUFFIX="-${BUILD_PHASE}" +fi + +IMAGE_TAG_WITH_SHA="${IMAGE_NAME}:${GIT_SHA}${IMAGE_TAG_SUFFIX}" + +RELEASE_SEMVER=$(git describe --tags --exact-match "$GIT_SHA" 2>/dev/null) || true +if [ -n "$RELEASE_SEMVER" ]; then + IMAGE_TAG_WITH_SEMVER="${IMAGE_NAME}:${RELEASE_SEMVER}${IMAGE_TAG_SUFFIX}" +fi + +# build the image +# passing no build phase will build the final image +docker build -t "$IMAGE_TAG_WITH_SHA" --target=${BUILD_PHASE} . +echo "${IMAGE_TAG_WITH_SHA} built locally." + +# if REGISTRY specified, push the images to the remote registry +if [ -n "$REGISTRY" ]; then + + if [ -n "${DOCKER_REGISTRY_PASSWORD}" ]; then + docker login --username="$DOCKER_REGISTRY_USERNAME" --password="$DOCKER_REGISTRY_PASSWORD" + fi + + docker tag "$IMAGE_TAG_WITH_SHA" "${REGISTRY}/${IMAGE_TAG_WITH_SHA}" + + docker push "${REGISTRY}/${IMAGE_TAG_WITH_SHA}" + echo "${REGISTRY}/${IMAGE_TAG_WITH_SHA} pushed to remote." + + # If the current commit has a semver tag, also push the images with the semver tag + if [ -n "$RELEASE_SEMVER" ]; then + + docker tag "$IMAGE_TAG_WITH_SHA" "${REGISTRY}/${IMAGE_TAG_WITH_SEMVER}" + + docker push "${REGISTRY}/${IMAGE_TAG_WITH_SEMVER}" + echo "${REGISTRY}/${IMAGE_TAG_WITH_SEMVER} pushed to remote." + + fi +fi diff --git a/cacheservice/boilerplate/flyte/end2end/Makefile b/cacheservice/boilerplate/flyte/end2end/Makefile new file mode 100644 index 0000000000..98ee63ae7a --- /dev/null +++ b/cacheservice/boilerplate/flyte/end2end/Makefile @@ -0,0 +1,14 @@ +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +.PHONY: end2end_execute +end2end_execute: export FLYTESNACKS_PRIORITIES ?= P0 +end2end_execute: export FLYTESNACKS_VERSION ?= $(shell curl --silent "https://api.github.com/repos/flyteorg/flytesnacks/releases/latest" | jq -r .tag_name) +end2end_execute: + ./boilerplate/flyte/end2end/end2end.sh ./boilerplate/flyte/end2end/functional-test-config.yaml --return_non_zero_on_failure + +.PHONY: k8s_integration_execute +k8s_integration_execute: + echo "pass" diff --git a/cacheservice/boilerplate/flyte/end2end/end2end.sh b/cacheservice/boilerplate/flyte/end2end/end2end.sh new file mode 100755 index 0000000000..5dd825c1a0 --- /dev/null +++ b/cacheservice/boilerplate/flyte/end2end/end2end.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst +set -eu + +CONFIG_FILE=$1; shift +EXTRA_FLAGS=( "$@" ) + +python ./boilerplate/flyte/end2end/run-tests.py $FLYTESNACKS_VERSION $FLYTESNACKS_PRIORITIES $CONFIG_FILE ${EXTRA_FLAGS[@]} diff --git a/cacheservice/boilerplate/flyte/end2end/functional-test-config.yaml b/cacheservice/boilerplate/flyte/end2end/functional-test-config.yaml new file mode 100644 index 0000000000..13fc445675 --- /dev/null +++ b/cacheservice/boilerplate/flyte/end2end/functional-test-config.yaml @@ -0,0 +1,5 @@ +admin: + # For GRPC endpoints you might want to use dns:///flyte.myexample.com + endpoint: dns:///localhost:30080 + authType: Pkce + insecure: true diff --git a/cacheservice/boilerplate/flyte/end2end/run-tests.py b/cacheservice/boilerplate/flyte/end2end/run-tests.py new file mode 100644 index 0000000000..905f29079c --- /dev/null +++ b/cacheservice/boilerplate/flyte/end2end/run-tests.py @@ -0,0 +1,282 @@ +#!/usr/bin/env python3 +import json +import sys +import time +import traceback +from typing import Dict, List, Optional + +import click +import requests +from flytekit.configuration import Config +from flytekit.models.core.execution import WorkflowExecutionPhase +from flytekit.remote import FlyteRemote +from flytekit.remote.executions import FlyteWorkflowExecution + +WAIT_TIME = 10 +MAX_ATTEMPTS = 200 + + +def execute_workflow( + remote: FlyteRemote, + version, + workflow_name, + inputs, + cluster_pool_name: Optional[str] = None, +): + print(f"Fetching workflow={workflow_name} and version={version}") + wf = remote.fetch_workflow(name=workflow_name, version=version) + return remote.execute(wf, inputs=inputs, wait=False, cluster_pool=cluster_pool_name) + + +def executions_finished( + executions_by_wfgroup: Dict[str, List[FlyteWorkflowExecution]] +) -> bool: + for executions in executions_by_wfgroup.values(): + if not all([execution.is_done for execution in executions]): + return False + return True + + +def sync_executions( + remote: FlyteRemote, executions_by_wfgroup: Dict[str, List[FlyteWorkflowExecution]] +): + try: + for executions in executions_by_wfgroup.values(): + for execution in executions: + print(f"About to sync execution_id={execution.id.name}") + remote.sync(execution) + except Exception: + print(traceback.format_exc()) + print("GOT TO THE EXCEPT") + print("COUNT THIS!") + + +def report_executions(executions_by_wfgroup: Dict[str, List[FlyteWorkflowExecution]]): + for executions in executions_by_wfgroup.values(): + for execution in executions: + print(execution) + + +def schedule_workflow_groups( + tag: str, + workflow_groups: List[str], + remote: FlyteRemote, + terminate_workflow_on_failure: bool, + parsed_manifest: List[dict], + cluster_pool_name: Optional[str] = None, +) -> Dict[str, bool]: + """ + Schedule workflows executions for all workflow groups and return True if all executions succeed, otherwise + return False. + """ + executions_by_wfgroup = {} + # Schedule executions for each workflow group, + for wf_group in workflow_groups: + workflow_group_item = list( + filter(lambda item: item["name"] == wf_group, parsed_manifest) + ) + workflows = [] + if workflow_group_item: + workflows = workflow_group_item[0]["examples"] + executions_by_wfgroup[wf_group] = [ + execute_workflow(remote, tag, workflow[0], workflow[1], cluster_pool_name) + for workflow in workflows + ] + + # Wait for all executions to finish + attempt = 0 + while attempt == 0 or ( + not executions_finished(executions_by_wfgroup) and attempt < MAX_ATTEMPTS + ): + attempt += 1 + print( + f"Not all executions finished yet. Sleeping for some time, will check again in {WAIT_TIME}s" + ) + time.sleep(WAIT_TIME) + sync_executions(remote, executions_by_wfgroup) + + report_executions(executions_by_wfgroup) + + results = {} + for wf_group, executions in executions_by_wfgroup.items(): + non_succeeded_executions = [] + for execution in executions: + if execution.closure.phase != WorkflowExecutionPhase.SUCCEEDED: + non_succeeded_executions.append(execution) + # Report failing cases + if len(non_succeeded_executions) != 0: + print(f"Failed executions for {wf_group}:") + for execution in non_succeeded_executions: + print( + f" workflow={execution.spec.launch_plan.name}, execution_id={execution.id.name}" + ) + if terminate_workflow_on_failure: + remote.terminate( + execution, "aborting execution scheduled in functional test" + ) + # A workflow group succeeds iff all of its executions succeed + results[wf_group] = len(non_succeeded_executions) == 0 + return results + + +def valid(workflow_group, parsed_manifest): + """ + Return True if a workflow group is contained in parsed_manifest, + False otherwise. + """ + return workflow_group in set(wf_group["name"] for wf_group in parsed_manifest) + + +def run( + flytesnacks_release_tag: str, + priorities: List[str], + config_file_path, + terminate_workflow_on_failure: bool, + test_project_name: str, + test_project_domain: str, + cluster_pool_name: Optional[str] = None, +) -> List[Dict[str, str]]: + remote = FlyteRemote( + Config.auto(config_file=config_file_path), + test_project_name, + test_project_domain, + ) + + # For a given release tag and priority, this function filters the workflow groups from the flytesnacks + # manifest file. For example, for the release tag "v0.2.224" and the priority "P0" it returns [ "core" ]. + manifest_url = ( + "https://raw.githubusercontent.com/flyteorg/flytesnacks/" + f"{flytesnacks_release_tag}/flyte_tests_manifest.json" + ) + r = requests.get(manifest_url) + parsed_manifest = r.json() + workflow_groups = [] + workflow_groups = ( + ["lite"] + if "lite" in priorities + else [ + group["name"] + for group in parsed_manifest + if group["priority"] in priorities + ] + ) + + results = [] + valid_workgroups = [] + for workflow_group in workflow_groups: + if not valid(workflow_group, parsed_manifest): + results.append( + { + "label": workflow_group, + "status": "coming soon", + "color": "grey", + } + ) + continue + valid_workgroups.append(workflow_group) + + results_by_wfgroup = schedule_workflow_groups( + flytesnacks_release_tag, + valid_workgroups, + remote, + terminate_workflow_on_failure, + parsed_manifest, + cluster_pool_name, + ) + + for workflow_group, succeeded in results_by_wfgroup.items(): + if succeeded: + background_color = "green" + status = "passing" + else: + background_color = "red" + status = "failing" + + # Workflow groups can be only in one of three states: + # 1. passing: this indicates all the workflow executions for that workflow group + # executed successfully + # 2. failing: this state indicates that at least one execution failed in that + # workflow group + # 3. coming soon: this state is used to indicate that the workflow group was not + # implemented yet. + # + # Each state has a corresponding status and color to be used in the badge for that + # workflow group. + result = { + "label": workflow_group, + "status": status, + "color": background_color, + } + results.append(result) + return results + + +@click.command() +@click.argument("flytesnacks_release_tag") +@click.argument("priorities") +@click.argument("config_file") +@click.option( + "--return_non_zero_on_failure", + default=False, + is_flag=True, + help="Return a non-zero exit status if any workflow fails", +) +@click.option( + "--terminate_workflow_on_failure", + default=False, + is_flag=True, + help="Abort failing workflows upon exit", +) +@click.option( + "--test_project_name", + default="flytesnacks", + type=str, + is_flag=False, + help="Name of project to run functional tests on", +) +@click.option( + "--test_project_domain", + default="development", + type=str, + is_flag=False, + help="Name of domain in project to run functional tests on", +) +@click.argument( + "cluster_pool_name", + required=False, + type=str, + default=None, +) +def cli( + flytesnacks_release_tag, + priorities, + config_file, + return_non_zero_on_failure, + terminate_workflow_on_failure, + test_project_name, + test_project_domain, + cluster_pool_name, +): + print(f"return_non_zero_on_failure={return_non_zero_on_failure}") + results = run( + flytesnacks_release_tag, + priorities, + config_file, + terminate_workflow_on_failure, + test_project_name, + test_project_domain, + cluster_pool_name, + ) + + # Write a json object in its own line describing the result of this run to stdout + print(f"Result of run:\n{json.dumps(results)}") + + # Return a non-zero exit code if core fails + if return_non_zero_on_failure: + for result in results: + if result["status"] not in ("passing", "coming soon"): + sys.exit(1) + + +if __name__ == "__main__": + cli() diff --git a/cacheservice/boilerplate/flyte/flyte_golang_compile/Readme.rst b/cacheservice/boilerplate/flyte/flyte_golang_compile/Readme.rst new file mode 100644 index 0000000000..e6b56dd16e --- /dev/null +++ b/cacheservice/boilerplate/flyte/flyte_golang_compile/Readme.rst @@ -0,0 +1,16 @@ +Flyte Golang Compile +~~~~~~~~~~~~~~~~~~~~ + +Common compile script for Flyte golang services. + +**To Enable:** + +Add ``flyteorg/flyte_golang_compile`` to your ``boilerplate/update.cfg`` file. + +Add the following to your Makefile + +:: + + .PHONY: compile_linux + compile_linux: + PACKAGES={{ *your packages }} OUTPUT={{ /path/to/output }} ./boilerplate/flyte/flyte_golang_compile.sh diff --git a/cacheservice/boilerplate/flyte/flyte_golang_compile/flyte_golang_compile.Template b/cacheservice/boilerplate/flyte/flyte_golang_compile/flyte_golang_compile.Template new file mode 100644 index 0000000000..f587e971be --- /dev/null +++ b/cacheservice/boilerplate/flyte/flyte_golang_compile/flyte_golang_compile.Template @@ -0,0 +1,26 @@ +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +if [ -z "$PACKAGES" ]; then + echo "PACKAGES environment VAR not set" + exit 1 +fi + +if [ -z "$OUTPUT" ]; then + echo "OUTPUT environment VAR not set" + exit 1 +fi + +# get the GIT_SHA and RELEASE_SEMVER + +GIT_SHA=$(git rev-parse HEAD) +RELEASE_SEMVER=$(git describe --tags --exact-match $GIT_SHA 2>/dev/null) + +CURRENT_PKG=github.com/flyteorg/{{ REPOSITORY }} +VERSION_PKG="${CURRENT_PKG}/vendor/github.com/flyteorg/flytestdlib" + +LDFLAGS="-X ${VERSION_PKG}/version.Build=${GIT_SHA} -X ${VERSION_PKG}/version.Version=${RELEASE_SEMVER}" + +GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "$LDFLAGS" -o "$OUTPUT" "$PACKAGES" diff --git a/cacheservice/boilerplate/flyte/flyte_golang_compile/update.sh b/cacheservice/boilerplate/flyte/flyte_golang_compile/update.sh new file mode 100755 index 0000000000..b1e6101c2b --- /dev/null +++ b/cacheservice/boilerplate/flyte/flyte_golang_compile/update.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +echo " - generating ${DIR}/flyte_golang_compile.sh" +sed -e "s/{{REPOSITORY}}/${REPOSITORY}/g" ${DIR}/flyte_golang_compile.Template > ${DIR}/flyte_golang_compile.sh diff --git a/cacheservice/boilerplate/flyte/github_workflows/Readme.rst b/cacheservice/boilerplate/flyte/github_workflows/Readme.rst new file mode 100644 index 0000000000..f236923514 --- /dev/null +++ b/cacheservice/boilerplate/flyte/github_workflows/Readme.rst @@ -0,0 +1,22 @@ +Golang Github Actions +~~~~~~~~~~~~~~~~~ + +Provides a two github actions workflows. + +**To Enable:** + +Add ``flyteorg/github_workflows`` to your ``boilerplate/update.cfg`` file. + +Add a github secret ``package_name`` with the name to use for publishing (e.g. ``flytepropeller``). Typically, this will be the same name as the repository. + +*Note*: If you are working on a fork, include that prefix in your package name (``myfork/flytepropeller``). + +The actions will push to 2 repos: + + 1. ``docker.pkg.github.com/flyteorg//`` + 2. ``docker.pkg.github.com/flyteorg//-stages`` : this repo is used to cache build stages to speed up iterative builds after. + +There are two workflows that get deployed: + + 1. A workflow that runs on Pull Requests to build and push images to github registry tagged with the commit sha. + 2. A workflow that runs on master merges that bump the patch version of release tag, builds and pushes images to github registry tagged with the version, commit sha as well as "latest" diff --git a/cacheservice/boilerplate/flyte/github_workflows/boilerplate_automation.yml b/cacheservice/boilerplate/flyte/github_workflows/boilerplate_automation.yml new file mode 100644 index 0000000000..9bda305d4f --- /dev/null +++ b/cacheservice/boilerplate/flyte/github_workflows/boilerplate_automation.yml @@ -0,0 +1,36 @@ +name: Update Boilerplate Automation +on: + workflow_dispatch: +jobs: + update-boilerplate: + name: Update Boilerplate + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: "0" + - name: Update Boilerplate + run: | + make update_boilerplate + - name: Create Pull Request + id: cpr + uses: peter-evans/create-pull-request@v3 + with: + token: ${{ secrets.FLYTE_BOT_PAT }} + commit-message: Update Boilerplate + committer: Flyte-Bot + author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> + signoff: true + branch: flyte-bot-update-boilerplate + delete-branch: true + title: 'Update Boilerplate' + body: | + Update Boilerplate + - Auto-generated by [flyte-bot] + labels: | + boilerplate + team-reviewers: | + owners + maintainers + draft: false + diff --git a/cacheservice/boilerplate/flyte/github_workflows/master.yml b/cacheservice/boilerplate/flyte/github_workflows/master.yml new file mode 100644 index 0000000000..a8eab5af0e --- /dev/null +++ b/cacheservice/boilerplate/flyte/github_workflows/master.yml @@ -0,0 +1,31 @@ +name: Master + +on: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + with: + fetch-depth: '0' + - name: Bump version and push tag + id: bump-version + uses: anothrNick/github-tag-action@1.17.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + WITH_V: true + DEFAULT_BUMP: patch + - name: Push Docker Image to Github Registry + uses: whoan/docker-build-with-cache-action@v5 + with: + username: "${{ github.actor }}" + password: "${{ secrets.GITHUB_TOKEN }}" + image_name: ${{ secrets.package_name }} + image_tag: latest,${{ github.sha }},${{ steps.bump-version.outputs.tag }} + push_git_tag: true + registry: docker.pkg.github.com + build_extra_args: "--compress=true" diff --git a/cacheservice/boilerplate/flyte/github_workflows/pull_request.yml b/cacheservice/boilerplate/flyte/github_workflows/pull_request.yml new file mode 100644 index 0000000000..932400bc4f --- /dev/null +++ b/cacheservice/boilerplate/flyte/github_workflows/pull_request.yml @@ -0,0 +1,19 @@ +name: Pull Request + +on: + pull_request + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Push Docker Image to Github Registry + uses: whoan/docker-build-with-cache-action@v5 + with: + username: "${{ github.actor }}" + password: "${{ secrets.GITHUB_TOKEN }}" + image_name: ${{ secrets.package_name }} + image_tag: ${{ github.sha }} + push_git_tag: true + registry: docker.pkg.github.com diff --git a/cacheservice/boilerplate/flyte/github_workflows/stale.yml b/cacheservice/boilerplate/flyte/github_workflows/stale.yml new file mode 100644 index 0000000000..385321acb9 --- /dev/null +++ b/cacheservice/boilerplate/flyte/github_workflows/stale.yml @@ -0,0 +1,61 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 120 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 7 + +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: [] + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - pinned + - security + - "[Status] Maybe Later" + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: false + +# Label to use when marking as stale +staleLabel: wontfix + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue/pullrequest has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Comment to post when closing a stale Issue or Pull Request. +# closeComment: > +# Your comment here. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +only: pulls + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +# pulls: +# daysUntilStale: 30 +# markComment: > +# This pull request has been automatically marked as stale because it has not had +# recent activity. It will be closed if no further activity occurs. Thank you +# for your contributions. + +# issues: +# exemptLabels: +# - confirmed \ No newline at end of file diff --git a/cacheservice/boilerplate/flyte/github_workflows/update.sh b/cacheservice/boilerplate/flyte/github_workflows/update.sh new file mode 100755 index 0000000000..15c3cb18e2 --- /dev/null +++ b/cacheservice/boilerplate/flyte/github_workflows/update.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +mkdir -p ${DIR}/../../../.github/workflows + +echo " - generating github action workflows in root directory." +sed -e "s/{{REPOSITORY}}/${REPOSITORY}/g" ${DIR}/master.yml > ${DIR}/../../../.github/workflows/master.yml +sed -e "s/{{REPOSITORY}}/${REPOSITORY}/g" ${DIR}/pull_request.yml > ${DIR}/../../../.github/workflows/pull_request.yml +cp ${DIR}/stale.yml ${DIR}/../../../.github/stale.yml diff --git a/cacheservice/boilerplate/flyte/golang_dockerfile/Dockerfile.GoTemplate b/cacheservice/boilerplate/flyte/golang_dockerfile/Dockerfile.GoTemplate new file mode 100644 index 0000000000..a51f8e1b14 --- /dev/null +++ b/cacheservice/boilerplate/flyte/golang_dockerfile/Dockerfile.GoTemplate @@ -0,0 +1,38 @@ +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +FROM golang:1.17.1-alpine3.14 as builder +RUN apk add git openssh-client make curl + +# COPY only the go mod files for efficient caching +COPY go.mod go.sum /go/src/github.com/flyteorg/{{REPOSITORY}}/ +WORKDIR /go/src/github.com/flyteorg/{{REPOSITORY}} + +# Pull dependencies +RUN go mod download + +# COPY the rest of the source code +COPY . /go/src/github.com/flyteorg/{{REPOSITORY}}/ + +# This 'linux_compile' target should compile binaries to the /artifacts directory +# The main entrypoint should be compiled to /artifacts/{{REPOSITORY}} +RUN make linux_compile + +# install grpc-health-probe +RUN curl --silent --fail --show-error --location --output /artifacts/grpc_health_probe "https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/v0.4.5/grpc_health_probe-linux-amd64" && \ + chmod +x /artifacts/grpc_health_probe && \ + echo '8699c46352d752d8f533cae72728b0e65663f399fc28fb9cd854b14ad5f85f44 /artifacts/grpc_health_probe' > .grpc_checksum && \ + sha256sum -c .grpc_checksum + +# update the PATH to include the /artifacts directory +ENV PATH="/artifacts:${PATH}" + +# This will eventually move to centurylink/ca-certs:latest for minimum possible image size +FROM alpine:3.14 +COPY --from=builder /artifacts /bin + +RUN apk --update add ca-certificates + +CMD ["{{REPOSITORY}}"] diff --git a/cacheservice/boilerplate/flyte/golang_dockerfile/Readme.rst b/cacheservice/boilerplate/flyte/golang_dockerfile/Readme.rst new file mode 100644 index 0000000000..dba3b34f60 --- /dev/null +++ b/cacheservice/boilerplate/flyte/golang_dockerfile/Readme.rst @@ -0,0 +1,16 @@ +Golang Dockerfile +~~~~~~~~~~~~~~~~~ + +Provides a Dockerfile that produces a small image. + +**To Enable:** + +Add ``flyteorg/golang_dockerfile`` to your ``boilerplate/update.cfg`` file. + +Create and configure a ``make linux_compile`` target that compiles your go binaries to the ``/artifacts`` directory :: + + .PHONY: linux_compile + linux_compile: + RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o /artifacts {{ packages }} + +All binaries compiled to ``/artifacts`` will be available at ``/bin`` in your final image. diff --git a/cacheservice/boilerplate/flyte/golang_dockerfile/update.sh b/cacheservice/boilerplate/flyte/golang_dockerfile/update.sh new file mode 100755 index 0000000000..5439bada4f --- /dev/null +++ b/cacheservice/boilerplate/flyte/golang_dockerfile/update.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +echo " - generating Dockerfile in root directory." +sed -e "s/{{REPOSITORY}}/${REPOSITORY}/g" ${DIR}/Dockerfile.GoTemplate > ${DIR}/../../../Dockerfile diff --git a/cacheservice/boilerplate/flyte/golang_support_tools/go.mod b/cacheservice/boilerplate/flyte/golang_support_tools/go.mod new file mode 100644 index 0000000000..2cfeb8aa3a --- /dev/null +++ b/cacheservice/boilerplate/flyte/golang_support_tools/go.mod @@ -0,0 +1,247 @@ +module github.com/flyteorg/boilerplate + +go 1.19 + +require ( + github.com/EngHabu/mockery v0.0.0-20220405200825-3f76291311cf + github.com/alvaroloes/enumer v1.1.2 + github.com/flyteorg/flytestdlib v0.4.16 + github.com/golangci/golangci-lint v1.53.3 + github.com/pseudomuto/protoc-gen-doc v1.4.1 +) + +require ( + 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect + 4d63.com/gochecknoglobals v0.2.1 // indirect + cloud.google.com/go v0.110.2 // indirect + cloud.google.com/go/compute v1.19.3 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v1.1.2 // indirect + cloud.google.com/go/storage v1.29.0 // indirect + github.com/4meepo/tagalign v1.2.2 // indirect + github.com/Abirdcfly/dupword v0.0.11 // indirect + github.com/Antonboom/errname v0.1.10 // indirect + github.com/Antonboom/nilnil v0.1.5 // indirect + github.com/Azure/azure-sdk-for-go v62.3.0+incompatible // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.17 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.10 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.0 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/BurntSushi/toml v1.3.2 // indirect + github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect + github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0 // indirect + github.com/Masterminds/semver v1.5.0 // indirect + github.com/Masterminds/sprig v2.15.0+incompatible // indirect + github.com/OpenPeeDeeP/depguard/v2 v2.1.0 // indirect + github.com/alexkohler/nakedret/v2 v2.0.2 // indirect + github.com/alexkohler/prealloc v1.0.0 // indirect + github.com/alingse/asasalint v0.0.11 // indirect + github.com/aokoli/goutils v1.0.1 // indirect + github.com/ashanbrown/forbidigo v1.5.3 // indirect + github.com/ashanbrown/makezero v1.1.1 // indirect + github.com/aws/aws-sdk-go v1.37.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bkielbasa/cyclop v1.2.1 // indirect + github.com/blizzy78/varnamelen v0.8.0 // indirect + github.com/bombsimon/wsl/v3 v3.4.0 // indirect + github.com/breml/bidichk v0.2.4 // indirect + github.com/breml/errchkjson v0.3.1 // indirect + github.com/butuzov/ireturn v0.2.0 // indirect + github.com/butuzov/mirror v1.1.0 // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/charithe/durationcheck v0.0.10 // indirect + github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8 // indirect + github.com/coocood/freecache v1.1.1 // indirect + github.com/curioswitch/go-reassign v0.2.0 // indirect + github.com/daixiang0/gci v0.10.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/denis-tingaikin/go-header v0.4.3 // indirect + github.com/envoyproxy/protoc-gen-validate v0.10.0 // indirect + github.com/ernesto-jimenez/gogen v0.0.0-20180125220232-d7d4131e6607 // indirect + github.com/esimonov/ifshort v1.0.4 // indirect + github.com/ettle/strcase v0.1.1 // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/fatih/structtag v1.2.0 // indirect + github.com/firefart/nonamedreturns v1.0.4 // indirect + github.com/flyteorg/stow v0.3.1 // indirect + github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/fzipp/gocyclo v0.6.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-critic/go-critic v0.8.1 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-toolsmith/astcast v1.1.0 // indirect + github.com/go-toolsmith/astcopy v1.1.0 // indirect + github.com/go-toolsmith/astequal v1.1.0 // indirect + github.com/go-toolsmith/astfmt v1.1.0 // indirect + github.com/go-toolsmith/astp v1.1.0 // indirect + github.com/go-toolsmith/strparse v1.1.0 // indirect + github.com/go-toolsmith/typep v1.1.0 // indirect + github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/gofrs/flock v0.8.1 // indirect + github.com/gofrs/uuid v4.2.0+incompatible // 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/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect + github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect + github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe // indirect + github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 // indirect + github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect + github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect + github.com/golangci/misspell v0.4.0 // indirect + github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 // indirect + github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/s2a-go v0.1.4 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/googleapis/gax-go/v2 v2.11.0 // indirect + github.com/gordonklaus/ineffassign v0.0.0-20230610083614-0e73809eb601 // indirect + github.com/gostaticanalysis/analysisutil v0.7.1 // indirect + github.com/gostaticanalysis/comment v1.4.2 // indirect + github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect + github.com/gostaticanalysis/nilerr v0.1.1 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hexops/gotextdiff v1.0.3 // indirect + github.com/huandu/xstrings v1.0.0 // indirect + github.com/imdario/mergo v0.3.5 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jgautheron/goconst v1.5.1 // indirect + github.com/jingyugao/rowserrcheck v1.1.1 // indirect + github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/julz/importas v0.1.0 // indirect + github.com/kisielk/errcheck v1.6.3 // indirect + github.com/kisielk/gotool v1.0.0 // indirect + github.com/kkHAIKE/contextcheck v1.1.4 // indirect + github.com/kulti/thelper v0.6.3 // indirect + github.com/kunwardeep/paralleltest v1.0.7 // indirect + github.com/kyoh86/exportloopref v0.1.11 // indirect + github.com/ldez/gomoddirectives v0.2.3 // indirect + github.com/ldez/tagliatelle v0.5.0 // indirect + github.com/leonklingele/grouper v1.1.1 // indirect + github.com/lufeee/execinquery v1.2.1 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/maratori/testableexamples v1.0.0 // indirect + github.com/maratori/testpackage v1.1.1 // indirect + github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mbilski/exhaustivestruct v1.2.0 // indirect + github.com/mgechev/revive v1.3.2 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moricho/tparallel v0.3.1 // indirect + github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007 // indirect + github.com/nakabonne/nestif v0.3.1 // indirect + github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect + github.com/ncw/swift v1.0.53 // indirect + github.com/nishanths/exhaustive v0.11.0 // indirect + github.com/nishanths/predeclared v0.2.2 // indirect + github.com/nunnatsa/ginkgolinter v0.12.1 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/pascaldekloe/name v0.0.0-20180628100202-0fd16699aae1 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/polyfloyd/go-errorlint v1.4.2 // indirect + github.com/prometheus/client_golang v1.12.1 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/pseudomuto/protokit v0.2.0 // indirect + github.com/quasilyte/go-ruleguard v0.3.19 // indirect + github.com/quasilyte/gogrep v0.5.0 // indirect + github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect + github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect + github.com/ryancurrah/gomodguard v1.3.0 // indirect + github.com/ryanrolds/sqlclosecheck v0.4.0 // indirect + github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect + github.com/sashamelentyev/interfacebloat v1.1.0 // indirect + github.com/sashamelentyev/usestdlibvars v1.23.0 // indirect + github.com/securego/gosec/v2 v2.16.0 // indirect + github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sivchari/containedctx v1.0.3 // indirect + github.com/sivchari/nosnakecase v1.7.0 // indirect + github.com/sivchari/tenv v1.7.1 // indirect + github.com/sonatard/noctx v0.0.2 // indirect + github.com/sourcegraph/go-diff v0.7.0 // indirect + github.com/spf13/afero v1.8.2 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/cobra v1.7.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.12.0 // indirect + github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect + github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect + github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect + github.com/subosito/gotenv v1.4.1 // indirect + github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect + github.com/tdakkota/asciicheck v0.2.0 // indirect + github.com/tetafro/godot v1.4.11 // indirect + github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect + github.com/timonwong/loggercheck v0.9.4 // indirect + github.com/tomarrell/wrapcheck/v2 v2.8.1 // indirect + github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect + github.com/ultraware/funlen v0.0.3 // indirect + github.com/ultraware/whitespace v0.0.5 // indirect + github.com/uudashr/gocognit v1.0.6 // indirect + github.com/xen0n/gosmopolitan v1.2.1 // indirect + github.com/yagipy/maintidx v1.0.0 // indirect + github.com/yeya24/promlinter v0.2.0 // indirect + github.com/ykadowak/zerologlint v0.1.2 // indirect + gitlab.com/bosi/decorder v0.2.3 // indirect + go.opencensus.io v0.24.0 // indirect + go.tmz.dev/musttag v0.7.0 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.24.0 // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect + golang.org/x/exp/typeparams v0.0.0-20230224173230-c95f2b4c22f2 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect + golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect + golang.org/x/tools v0.11.1 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/api v0.126.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/grpc v1.55.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + honnef.co/go/tools v0.4.3 // indirect + k8s.io/apimachinery v0.20.2 // indirect + k8s.io/client-go v0.0.0-20210217172142-7279fc64d847 // indirect + k8s.io/klog/v2 v2.5.0 // indirect + mvdan.cc/gofumpt v0.5.0 // indirect + mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect + mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect + mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d // indirect +) + +replace github.com/pseudomuto/protoc-gen-doc => github.com/flyteorg/protoc-gen-doc v1.4.2 diff --git a/cacheservice/boilerplate/flyte/golang_support_tools/go.sum b/cacheservice/boilerplate/flyte/golang_support_tools/go.sum new file mode 100644 index 0000000000..4cc434803e --- /dev/null +++ b/cacheservice/boilerplate/flyte/golang_support_tools/go.sum @@ -0,0 +1,1225 @@ +4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA= +4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= +4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc= +4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= +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.44.3/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 v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA= +cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v1.19.3 h1:DcTwsFgGev/wV5+q8o2fzgcHOaac+DKGC91ZlvpsQds= +cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= +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/iam v1.1.2 h1:gacbrBdWcoVmGLozRuStX45YKvJtzIjJdAolzUs1sm4= +cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI= +cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/4meepo/tagalign v1.2.2 h1:kQeUTkFTaBRtd/7jm8OKJl9iHk0gAO+TDFPHGSna0aw= +github.com/4meepo/tagalign v1.2.2/go.mod h1:Q9c1rYMZJc9dPRkbQPpcBNCLEmY2njbAsXhQOZFE2dE= +github.com/Abirdcfly/dupword v0.0.11 h1:z6v8rMETchZXUIuHxYNmlUAuKuB21PeaSymTed16wgU= +github.com/Abirdcfly/dupword v0.0.11/go.mod h1:wH8mVGuf3CP5fsBTkfWwwwKTjDnVVCxtU8d8rgeVYXA= +github.com/Antonboom/errname v0.1.10 h1:RZ7cYo/GuZqjr1nuJLNe8ZH+a+Jd9DaZzttWzak9Bls= +github.com/Antonboom/errname v0.1.10/go.mod h1:xLeiCIrvVNpUtsN0wxAh05bNIZpqE22/qDMnTBTttiA= +github.com/Antonboom/nilnil v0.1.5 h1:X2JAdEVcbPaOom2TUa1FxZ3uyuUlex0XMLGYMemu6l0= +github.com/Antonboom/nilnil v0.1.5/go.mod h1:I24toVuBKhfP5teihGWctrRiPbRKHwZIFOvc6v3HZXk= +github.com/Azure/azure-sdk-for-go v62.3.0+incompatible h1:Ctfsn9UoA/BB4HMYQlbPPgNXdX0tZ4tmb85+KFb2+RE= +github.com/Azure/azure-sdk-for-go v62.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 h1:qoVeMsc9/fh/yhxVaA0obYjVH/oI/ihrOoMwsLS9KSA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 h1:E+m3SkZCN0Bf5q7YdTs5lSm2CYY3CK4spn5OmUIiQtk= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +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 v0.11.17 h1:2zCdHwNgRH+St1J+ZMf66xI8aLr/5KMy+wWLH97zwYM= +github.com/Azure/go-autorest/autorest v0.11.17/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/adal v0.9.10 h1:r6fZHMaHD8B6LDCn0o5vyBFHIHrM6Ywwx7mb49lPItI= +github.com/Azure/go-autorest/autorest/adal v0.9.10/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +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 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= +github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= +github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= +github.com/EngHabu/mockery v0.0.0-20220405200825-3f76291311cf h1:M7A2Tn3R8rVgsoJHHKkmkpiNOItys4GxJj6JytRjdDg= +github.com/EngHabu/mockery v0.0.0-20220405200825-3f76291311cf/go.mod h1:Kya4Y46gyq/3TEyAzeNe5UkCk+W9apy5KbuX+5KnZ6M= +github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0 h1:+r1rSv4gvYn0wmRjC8X7IAzX8QezqtFV9m0MUHFJgts= +github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0/go.mod h1:b3g59n2Y+T5xmcxJL+UEG2f8cQploZm1mR/v6BW0mU0= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/sprig v2.15.0+incompatible h1:0gSxPGWS9PAr7U2NsQ2YQg6juRDINkUyuvbb4b2Xm8w= +github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OpenPeeDeeP/depguard/v2 v2.1.0 h1:aQl70G173h/GZYhWf36aE5H0KaujXfVMnn/f1kSDVYY= +github.com/OpenPeeDeeP/depguard/v2 v2.1.0/go.mod h1:PUBgk35fX4i7JDmwzlJwJ+GMe6NfO1723wmJMgPThNQ= +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/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/alexkohler/nakedret/v2 v2.0.2 h1:qnXuZNvv3/AxkAb22q/sEsEpcA99YxLFACDtEw9TPxE= +github.com/alexkohler/nakedret/v2 v2.0.2/go.mod h1:2b8Gkk0GsOrqQv/gPWjNLDSKwG8I5moSXG1K4VIBcTQ= +github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= +github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= +github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= +github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= +github.com/alvaroloes/enumer v1.1.2 h1:5khqHB33TZy1GWCO/lZwcroBFh7u+0j40T83VUbfAMY= +github.com/alvaroloes/enumer v1.1.2/go.mod h1:FxrjvuXoDAx9isTJrv4c+T410zFi0DtXIT0m65DJ+Wo= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/aokoli/goutils v1.0.1 h1:7fpzNGoJ3VA8qcrm++XEE1QUe0mIwNeLa02Nwq7RDkg= +github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/ashanbrown/forbidigo v1.5.3 h1:jfg+fkm/snMx+V9FBwsl1d340BV/99kZGv5jN9hBoXk= +github.com/ashanbrown/forbidigo v1.5.3/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= +github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= +github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= +github.com/aws/aws-sdk-go v1.37.1 h1:BTHmuN+gzhxkvU9sac2tZvaY0gV9ihbHw+KxZOecYvY= +github.com/aws/aws-sdk-go v1.37.1/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +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/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJY= +github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM= +github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= +github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= +github.com/bombsimon/wsl/v3 v3.4.0 h1:RkSxjT3tmlptwfgEgTgU+KYKLI35p/tviNXNXiL2aNU= +github.com/bombsimon/wsl/v3 v3.4.0/go.mod h1:KkIB+TXkqy6MvK9BDZVbZxKNYsE1/oLRJbIFtf14qqo= +github.com/breml/bidichk v0.2.4 h1:i3yedFWWQ7YzjdZJHnPo9d/xURinSq3OM+gyM43K4/8= +github.com/breml/bidichk v0.2.4/go.mod h1:7Zk0kRFt1LIZxtQdl9W9JwGAcLTTkOs+tN7wuEYGJ3s= +github.com/breml/errchkjson v0.3.1 h1:hlIeXuspTyt8Y/UmP5qy1JocGNR00KQHgfaNtRAjoxQ= +github.com/breml/errchkjson v0.3.1/go.mod h1:XroxrzKjdiutFyW3nWhw34VGg7kiMsDQox73yWCGI2U= +github.com/butuzov/ireturn v0.2.0 h1:kCHi+YzC150GE98WFuZQu9yrTn6GEydO2AuPLbTgnO4= +github.com/butuzov/ireturn v0.2.0/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= +github.com/butuzov/mirror v1.1.0 h1:ZqX54gBVMXu78QLoiqdwpl2mgmoOJTk7s4p4o+0avZI= +github.com/butuzov/mirror v1.1.0/go.mod h1:8Q0BdQU6rC6WILDiBM60DBfvV78OLJmMmixe7GF45AE= +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/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +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/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= +github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= +github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8 h1:W9o46d2kbNL06lq7UNDPV0zYLzkrde/bjIqO02eoll0= +github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8/go.mod h1:gakxgyXaaPkxvLw1XQxNGK4I37ys9iBRzNUx/B7pUCo= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/coocood/freecache v1.1.1 h1:uukNF7QKCZEdZ9gAV7WQzvh0SbjwdMF6m3x3rxEkaPc= +github.com/coocood/freecache v1.1.1/go.mod h1:OKrEjkGVoxZhyWAJoeFi5BMLUJm2Tit0kpGkIr7NGYY= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= +github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= +github.com/daixiang0/gci v0.10.1 h1:eheNA3ljF6SxnPD/vE4lCBusVHmV3Rs3dkKvFrJ7MR0= +github.com/daixiang0/gci v0.10.1/go.mod h1:xtHP9N7AHdNvtRNfcx9gwTDfw7FRJx4bZUsiEfiNNAI= +github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/denis-tingaikin/go-header v0.4.3 h1:tEaZKAlqql6SKCY++utLmkPLd6K8IBM20Ha7UVm+mtU= +github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +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/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/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= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.10.0 h1:oIfnZFdC0YhpNNEX+SuIqko4cqqVZeN9IGTrhZje83Y= +github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/ernesto-jimenez/gogen v0.0.0-20180125220232-d7d4131e6607 h1:cTavhURetDkezJCvxFggiyLeP40Mrk/TtVg2+ycw1Es= +github.com/ernesto-jimenez/gogen v0.0.0-20180125220232-d7d4131e6607/go.mod h1:Cg4fM0vhYWOZdgM7RIOSTRNIc8/VT7CXClC3Ni86lu4= +github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStBA= +github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= +github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= +github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y= +github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI= +github.com/flyteorg/flytestdlib v0.4.16 h1:r4dCPUOqoE9xCAhOw9KDB7O6cBoCxyEtepIWYcj93H0= +github.com/flyteorg/flytestdlib v0.4.16/go.mod h1:WA5Y4hrcgD0ybGOKJVOQ4sP8q7NLRV+S5SWOlH0axgM= +github.com/flyteorg/protoc-gen-doc v1.4.2 h1:Otw0F+RHaPQ8XlpzhLLgjsCMcrAIcMO01Zh+ALe3rrE= +github.com/flyteorg/protoc-gen-doc v1.4.2/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg= +github.com/flyteorg/stow v0.3.1 h1:cBMbWl03Gsy5KoA5mutUYTuYpqtT7Pb8+ANGCLnmFEs= +github.com/flyteorg/stow v0.3.1/go.mod h1:HBld7ud0i4khMHwJjkO8v+NSP7ddKa/ruhf4I8fliaA= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= +github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= +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-critic/go-critic v0.8.1 h1:16omCF1gN3gTzt4j4J6fKI/HnRojhEp+Eks6EuKw3vw= +github.com/go-critic/go-critic v0.8.1/go.mod h1:kpzXl09SIJX1cr9TB/g/sAG+eFEl7ZS9f9cqvZtyNl0= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-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/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +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-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/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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= +github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= +github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= +github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= +github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= +github.com/go-toolsmith/astequal v1.1.0 h1:kHKm1AWqClYn15R0K1KKE4RG614D46n+nqUQ06E1dTw= +github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= +github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco= +github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= +github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= +github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= +github.com/go-toolsmith/pkgload v1.2.2 h1:0CtmHq/02QhxcF7E9N5LIFcYFsMR5rdovfqTtRKkgIk= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw= +github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= +github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= +github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= +github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= +github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +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/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/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0= +github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= +github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe h1:6RGUuS7EGotKx6J5HIP8ZtyMdiDscjMLfRBSPuzVVeo= +github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= +github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 h1:amWTbTGqOZ71ruzrdA+Nx5WA3tV1N0goTspwmKCQvBY= +github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2/go.mod h1:9wOXstvyDRshQ9LggQuzBCGysxs3b6Uo/1MvYCR2NMs= +github.com/golangci/golangci-lint v1.53.3 h1:CUcRafczT4t1F+mvdkUm6KuOpxUZTl0yWN/rSU6sSMo= +github.com/golangci/golangci-lint v1.53.3/go.mod h1:W4Gg3ONq6p3Jl+0s/h9Gr0j7yEgHJWWZO2bHl2tBUXM= +github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= +github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= +github.com/golangci/misspell v0.4.0 h1:KtVB/hTK4bbL/S6bs64rYyk8adjmh1BygbBiaAiX+a0= +github.com/golangci/misspell v0.4.0/go.mod h1:W6O/bwV6lGDxUCChm2ykw9NQdd5bYd1Xkjo88UcWyJc= +github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 h1:DIPQnGy2Gv2FSA4B/hh8Q7xx3B7AIDk3DAMeHclH1vQ= +github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6/go.mod h1:0AKcRCkMoKvUvlf89F6O7H2LYdhr1zBh736mBItOdRs= +github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys= +github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= +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.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= +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 v0.0.0-20161128191214-064e2069ce9c/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.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/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.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/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gordonklaus/ineffassign v0.0.0-20230610083614-0e73809eb601 h1:mrEEilTAUmaAORhssPPkxj84TsHrPMLBGW2Z4SoTxm8= +github.com/gordonklaus/ineffassign v0.0.0-20230610083614-0e73809eb601/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= +github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= +github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= +github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q= +github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= +github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCpZ2CiZ1Q7jl6ZxNV70= +github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= +github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk= +github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= +github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= +github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +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/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.0.0 h1:pO2K/gKgKaat5LdpAhxhluX2GPQMaI3W5FUz/I/UnWk= +github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM= +github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= +github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +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.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= +github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/errcheck v1.6.3 h1:dEKh+GLHcWm2oN34nMvDzn1sqI0i0WxPvrgiJA5JuM8= +github.com/kisielk/errcheck v1.6.3/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkHAIKE/contextcheck v1.1.4 h1:B6zAaLhOEEcjvUgIYEqystmnFk1Oemn8bvJhbt0GMb8= +github.com/kkHAIKE/contextcheck v1.1.4/go.mod h1:1+i/gWqokIa+dm31mqGLZhZJ7Uh44DJGZVmr6QRBNJg= +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/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/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= +github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= +github.com/kunwardeep/paralleltest v1.0.7 h1:2uCk94js0+nVNQoHZNLBkAR1DQJrVzw6T0RMzJn55dQ= +github.com/kunwardeep/paralleltest v1.0.7/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= +github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ= +github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= +github.com/ldez/gomoddirectives v0.2.3 h1:y7MBaisZVDYmKvt9/l1mjNCiSA1BVn34U0ObUcJwlhA= +github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= +github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo= +github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= +github.com/leonklingele/grouper v1.1.1 h1:suWXRU57D4/Enn6pXR0QVqqWWrnJ9Osrz+5rjt8ivzU= +github.com/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= +github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= +github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +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/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= +github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= +github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= +github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= +github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE= +github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo= +github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= +github.com/mgechev/revive v1.3.2 h1:Wb8NQKBaALBJ3xrrj4zpwJwqwNA6nDpyJSEQWcCka6U= +github.com/mgechev/revive v1.3.2/go.mod h1:UCLtc7o5vg5aXCwdUTU1kEBQ1v+YXPAkYDIDXbrs5I0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/moricho/tparallel v0.3.1 h1:fQKD4U1wRMAYNngDonW5XupoB/ZGJHdpzrWqgyg9krA= +github.com/moricho/tparallel v0.3.1/go.mod h1:leENX2cUv7Sv2qDgdi0D0fCftN8fRC67Bcn8pqzeYNI= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/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/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007 h1:28i1IjGcx8AofiB4N3q5Yls55VEaitzuEPkFJEVgGkA= +github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= +github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= +github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA= +github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= +github.com/ncw/swift v1.0.53 h1:luHjjTNtekIEvHg5KdAFIBaH7bWfNkefwFnpDffSIks= +github.com/ncw/swift v1.0.53/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/nishanths/exhaustive v0.11.0 h1:T3I8nUGhl/Cwu5Z2hfc92l0e04D2GEW6e0l8pzda2l0= +github.com/nishanths/exhaustive v0.11.0/go.mod h1:RqwDsZ1xY0dNdqHho2z6X+bgzizwbLYOWnZbbl2wLB4= +github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= +github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= +github.com/nunnatsa/ginkgolinter v0.12.1 h1:vwOqb5Nu05OikTXqhvLdHCGcx5uthIYIl0t79UVrERQ= +github.com/nunnatsa/ginkgolinter v0.12.1/go.mod h1:AK8Ab1PypVrcGUusuKD8RDcl2KgsIwvNaaxAlyHSzso= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= +github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pascaldekloe/name v0.0.0-20180628100202-0fd16699aae1 h1:/I3lTljEEDNYLho3/FUB7iD/oc2cEFgVmbHzV+O0PtU= +github.com/pascaldekloe/name v0.0.0-20180628100202-0fd16699aae1/go.mod h1:eD5JxqMiuNYyFNmyY9rkJ/slN8y59oEu4Ei7F8OoKWQ= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/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.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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/polyfloyd/go-errorlint v1.4.2 h1:CU+O4181IxFDdPH6t/HT7IiDj1I7zxNi1RIUxYwn8d0= +github.com/polyfloyd/go-errorlint v1.4.2/go.mod h1:k6fU/+fQe38ednoZS51T7gSIGQW1y94d6TkSr35OzH8= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +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 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/pseudomuto/protokit v0.2.0 h1:hlnBDcy3YEDXH7kc9gV+NLaN0cDzhDvD1s7Y6FZ8RpM= +github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= +github.com/quasilyte/go-ruleguard v0.3.19 h1:tfMnabXle/HzOb5Xe9CUZYWXKfkS1KwRmZyPmD9nVcc= +github.com/quasilyte/go-ruleguard v0.3.19/go.mod h1:lHSn69Scl48I7Gt9cX3VrbsZYvYiBYszZOZW4A+oTEw= +github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= +github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= +github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= +github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryancurrah/gomodguard v1.3.0 h1:q15RT/pd6UggBXVBuLps8BXRvl5GPBcwVA7BJHMLuTw= +github.com/ryancurrah/gomodguard v1.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50= +github.com/ryanrolds/sqlclosecheck v0.4.0 h1:i8SX60Rppc1wRuyQjMciLqIzV3xnoHB7/tXbr6RGYNI= +github.com/ryanrolds/sqlclosecheck v0.4.0/go.mod h1:TBRRjzL31JONc9i4XMinicuo+s+E8yKZ5FN8X3G6CKQ= +github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= +github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= +github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= +github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= +github.com/sashamelentyev/usestdlibvars v1.23.0 h1:01h+/2Kd+NblNItNeux0veSL5cBF1jbEOPrEhDzGYq0= +github.com/sashamelentyev/usestdlibvars v1.23.0/go.mod h1:YPwr/Y1LATzHI93CqoPUN/2BzGQ/6N/cl/KwgR0B/aU= +github.com/securego/gosec/v2 v2.16.0 h1:Pi0JKoasQQ3NnoRao/ww/N/XdynIB9NRYYZT5CyOs5U= +github.com/securego/gosec/v2 v2.16.0/go.mod h1:xvLcVZqUfo4aAQu56TNv7/Ltz6emAOQAEsrZrt7uGlI= +github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= +github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +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.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= +github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= +github.com/sivchari/nosnakecase v1.7.0 h1:7QkpWIRMe8x25gckkFd2A5Pi6Ymo0qgr4JrhGt95do8= +github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY= +github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak= +github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= +github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00= +github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo= +github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= +github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +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.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/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.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= +github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= +github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= +github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc= +github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= +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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +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/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/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/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/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8= +github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk= +github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM= +github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= +github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= +github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= +github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= +github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= +github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw= +github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= +github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M= +github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= +github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4= +github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg= +github.com/tomarrell/wrapcheck/v2 v2.8.1 h1:HxSqDSN0sAt0yJYsrcYVoEeyM4aI9yAm3KQpIXDJRhQ= +github.com/tomarrell/wrapcheck/v2 v2.8.1/go.mod h1:/n2Q3NZ4XFT50ho6Hbxg+RV1uyo2Uow/Vdm9NQcl5SE= +github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= +github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= +github.com/ultraware/funlen v0.0.3 h1:5ylVWm8wsNwH5aWo9438pwvsK0QiqVuUrt9bn7S/iLA= +github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= +github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqzi/CzI= +github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= +github.com/uudashr/gocognit v1.0.6 h1:2Cgi6MweCsdB6kpcVQp7EW4U23iBFQWfTXiWlyp842Y= +github.com/uudashr/gocognit v1.0.6/go.mod h1:nAIUuVBnYU7pcninia3BHOvQkpQCeO76Uscky5BOwcY= +github.com/xen0n/gosmopolitan v1.2.1 h1:3pttnTuFumELBRSh+KQs1zcz4fN6Zy7aB0xlnQSn1Iw= +github.com/xen0n/gosmopolitan v1.2.1/go.mod h1:JsHq/Brs1o050OOdmzHeOr0N7OtlnKRAGAsElF8xBQA= +github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= +github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= +github.com/yeya24/promlinter v0.2.0 h1:xFKDQ82orCU5jQujdaD8stOHiv8UN68BSdn2a8u8Y3o= +github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA= +github.com/ykadowak/zerologlint v0.1.2 h1:Um4P5RMmelfjQqQJKtE8ZW+dLZrXrENeIzWWKw800U4= +github.com/ykadowak/zerologlint v0.1.2/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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= +gitlab.com/bosi/decorder v0.2.3 h1:gX4/RgK16ijY8V+BRQHAySfQAb354T7/xQpDB2n10P0= +gitlab.com/bosi/decorder v0.2.3/go.mod h1:9K1RB5+VPNQYtXtTDAzd2OEftsZb1oV0IrJrzChSdGE= +go-simpler.org/assert v0.5.0 h1:+5L/lajuQtzmbtEfh69sr5cRf2/xZzyJhFjoOz/PPqs= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.tmz.dev/musttag v0.7.0 h1:QfytzjTWGXZmChoX0L++7uQN+yRCPfyFm+whsM+lfGc= +go.tmz.dev/musttag v0.7.0/go.mod h1:oTFPvgOkJmp5kYL02S8+jrH0eLrBIl57rzWeA26zDEM= +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 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +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-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +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/exp v0.0.0-20230510235704-dd950f8aeaea h1:vLCWI/yYrdEHyN2JzIzPO3aaQJHQdp89IZBA/+azVC4= +golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20230224173230-c95f2b4c22f2 h1:J74nGeMgeFnYQJN59eFwh06jX/V8g0lB7LWpjSLxtgU= +golang.org/x/exp/typeparams v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +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/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/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.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.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= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-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-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-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-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +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-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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.1.0/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-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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-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-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-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/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-20210330210617-4fbd30eecc44/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-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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-20220702020025-31831981b65f/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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +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/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/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-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-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-20190321232350-e250d351ecad/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-20190524210228-3d17549cdc6b/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-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-20190910044552-dd2b5c81c578/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-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/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-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.11.1 h1:ojD5zOW8+7dOGzdnNgersm8aPfcDjhMp12UfG93NIMc= +golang.org/x/tools v0.11.1/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +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-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +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= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/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-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +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/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/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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +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/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +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.3/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-20210107192922-496545a6307b/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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.4.3 h1:o/n5/K5gXqk8Gozvs2cnL0F2S1/g1vcGCAx2vETjITw= +honnef.co/go/tools v0.4.3/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA= +k8s.io/api v0.0.0-20210217171935-8e2decd92398/go.mod h1:60tmSUpHxGPFerNHbo/ayI2lKxvtrhbxFyXuEIWJd78= +k8s.io/apimachinery v0.0.0-20210217011835-527a61b4dffe/go.mod h1:Z7ps/g0rjlTeMstYrMOUttJfT2Gg34DEaG/f2PYLCWY= +k8s.io/apimachinery v0.20.2 h1:hFx6Sbt1oG0n6DZ+g4bFt5f6BoMkOjKWsQFu077M3Vg= +k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/client-go v0.0.0-20210217172142-7279fc64d847 h1:d+LBRNY3c/KGp7lDblRlUJkayx4Vla7WUTIazoGMdYo= +k8s.io/client-go v0.0.0-20210217172142-7279fc64d847/go.mod h1:q0EaghmVye2uui19vxSZ2NG6ssgUWgjudO6vrwXneSI= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.5.0 h1:8mOnjf1RmUPW6KRqQCfYSZq/K20Unmp3IhuZUhxl8KI= +k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +mvdan.cc/gofumpt v0.5.0 h1:0EQ+Z56k8tXjj/6TQD25BFNKQXpCvT0rnansIc7Ug5E= +mvdan.cc/gofumpt v0.5.0/go.mod h1:HBeVDtMKRZpXyxFciAirzdKklDlGu8aAy1wEbH5Y9js= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= +mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d h1:3rvTIIM22r9pvXk+q3swxUQAQOxksVMGK7sml4nG57w= +mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d/go.mod h1:IeHQjmn6TOD+e4Z3RFiZMMsLVL+A96Nvptar8Fj71is= +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/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/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/cacheservice/boilerplate/flyte/golang_support_tools/tools.go b/cacheservice/boilerplate/flyte/golang_support_tools/tools.go new file mode 100644 index 0000000000..6c3da04107 --- /dev/null +++ b/cacheservice/boilerplate/flyte/golang_support_tools/tools.go @@ -0,0 +1,13 @@ +//go:build tools +// +build tools + +package tools + +import ( + _ "github.com/EngHabu/mockery/cmd/mockery" + _ "github.com/alvaroloes/enumer" + _ "github.com/golangci/golangci-lint/cmd/golangci-lint" + _ "github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc" + + _ "github.com/flyteorg/flyte/flytestdlib/cli/pflags" +) diff --git a/cacheservice/boilerplate/flyte/golang_test_targets/Makefile b/cacheservice/boilerplate/flyte/golang_test_targets/Makefile new file mode 100644 index 0000000000..280e1e55e4 --- /dev/null +++ b/cacheservice/boilerplate/flyte/golang_test_targets/Makefile @@ -0,0 +1,57 @@ +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + + +.PHONY: download_tooling +download_tooling: #download dependencies (including test deps) for the package + @boilerplate/flyte/golang_test_targets/download_tooling.sh + +.PHONY: generate +generate: download_tooling #generate go code + @boilerplate/flyte/golang_test_targets/go-gen.sh + +.PHONY: lint +lint: download_tooling #lints the package for common code smells + GL_DEBUG=linters_output,env golangci-lint run --deadline=5m --exclude deprecated -v + +# If code is failing goimports linter, this will fix. +# skips 'vendor' +.PHONY: goimports +goimports: + @boilerplate/flyte/golang_test_targets/goimports + +.PHONY: mod_download +mod_download: #download dependencies (including test deps) for the package + go mod download + +.PHONY: install +install: download_tooling mod_download + +.PHONY: show +show: + go list -m all + +.PHONY: test_unit +test_unit: + go test -cover ./... -race + +.PHONY: test_benchmark +test_benchmark: + go test -bench . ./... + +.PHONY: test_unit_cover +test_unit_cover: + go test ./... -coverprofile /tmp/cover.out -covermode=count + go tool cover -func /tmp/cover.out + +.PHONY: test_unit_visual +test_unit_visual: + go test ./... -coverprofile /tmp/cover.out -covermode=count + go tool cover -html=/tmp/cover.out + +.PHONY: test_unit_codecov +test_unit_codecov: + go test ./... -race -coverprofile=coverage.txt -covermode=atomic + curl -s https://codecov.io/bash > codecov_bash.sh && bash codecov_bash.sh diff --git a/cacheservice/boilerplate/flyte/golang_test_targets/Readme.rst b/cacheservice/boilerplate/flyte/golang_test_targets/Readme.rst new file mode 100644 index 0000000000..f9d890fdd7 --- /dev/null +++ b/cacheservice/boilerplate/flyte/golang_test_targets/Readme.rst @@ -0,0 +1,31 @@ +Golang Test Targets +~~~~~~~~~~~~~~~~~~~ + +Provides an ``install`` make target that uses ``go mod`` to install golang dependencies. + +Provides a ``lint`` make target that uses golangci to lint your code. + +Provides a ``test_unit`` target for unit tests. + +Provides a ``test_unit_cover`` target for analysing coverage of unit tests, which will output the coverage of each function and total statement coverage. + +Provides a ``test_unit_visual`` target for visualizing coverage of unit tests through an interactive html code heat map. + +Provides a ``test_benchmark`` target for benchmark tests. + +**To Enable:** + +Add ``flyteorg/golang_test_targets`` to your ``boilerplate/update.cfg`` file. + +Make sure you're using ``go mod`` for dependency management. + +Provide a ``.golangci`` configuration (the lint target requires it). + +Add ``include boilerplate/flyte/golang_test_targets/Makefile`` in your main ``Makefile`` _after_ your REPOSITORY environment variable + +:: + + REPOSITORY= + include boilerplate/flyte/golang_test_targets/Makefile + +(this ensures the extra make targets get included in your main Makefile) diff --git a/cacheservice/boilerplate/flyte/golang_test_targets/download_tooling.sh b/cacheservice/boilerplate/flyte/golang_test_targets/download_tooling.sh new file mode 100755 index 0000000000..9cd49959f4 --- /dev/null +++ b/cacheservice/boilerplate/flyte/golang_test_targets/download_tooling.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# Everything in this file needs to be installed outside of current module +# The reason we cannot turn off module entirely and install is that we need the replace statement in go.mod +# because we are installing a mockery fork. Turning it off would result installing the original not the fork. +# We also want to version all the other tools. We also want to be able to run go mod tidy without removing the version +# pins. To facilitate this, we're maintaining two sets of go.mod/sum files - the second one only for tooling. This is +# the same approach that go 1.14 will take as well. +# See: +# https://github.com/flyteorg/flyte/issues/129 +# https://github.com/golang/go/issues/30515 for some background context +# https://github.com/go-modules-by-example/index/blob/5ec250b4b78114a55001bd7c9cb88f6e07270ea5/010_tools/README.md + +set -e + +# List of tools to go get +# In the format of ":" or ":" if no cli +tools=( + "github.com/EngHabu/mockery/cmd/mockery" + "github.com/flyteorg/flytestdlib/cli/pflags@latest" + "github.com/golangci/golangci-lint/cmd/golangci-lint" + "github.com/daixiang0/gci" + "github.com/alvaroloes/enumer" + "github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc" +) + +tmp_dir=$(mktemp -d -t gotooling-XXX) +echo "Using temp directory ${tmp_dir}" +cp -R boilerplate/flyte/golang_support_tools/* $tmp_dir +pushd "$tmp_dir" + +for tool in "${tools[@]}" +do + echo "Installing ${tool}" + GO111MODULE=on go install $tool +done + +popd diff --git a/cacheservice/boilerplate/flyte/golang_test_targets/go-gen.sh b/cacheservice/boilerplate/flyte/golang_test_targets/go-gen.sh new file mode 100755 index 0000000000..5ac17fa40a --- /dev/null +++ b/cacheservice/boilerplate/flyte/golang_test_targets/go-gen.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +set -ex + +echo "Running go generate" +go generate ./... + +# This section is used by GitHub workflow to ensure that the generation step was run +if [ -n "$DELTA_CHECK" ]; then + DIRTY=$(git status --porcelain) + if [ -n "$DIRTY" ]; then + echo "FAILED: Go code updated without committing generated code." + echo "Ensure make generate has run and all changes are committed." + DIFF=$(git diff) + echo "diff detected: $DIFF" + DIFF=$(git diff --name-only) + echo "files different: $DIFF" + exit 1 + else + echo "SUCCESS: Generated code is up to date." + fi +fi diff --git a/cacheservice/boilerplate/flyte/golang_test_targets/goimports b/cacheservice/boilerplate/flyte/golang_test_targets/goimports new file mode 100755 index 0000000000..40f50d106e --- /dev/null +++ b/cacheservice/boilerplate/flyte/golang_test_targets/goimports @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +goimports -w $(find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./pkg/client/*" -not -path "./boilerplate/*") +gci write -s standard -s default -s "prefix(github.com/flyteorg)" --custom-order --skip-generated . diff --git a/cacheservice/boilerplate/flyte/golangci_file/.golangci.yml b/cacheservice/boilerplate/flyte/golangci_file/.golangci.yml new file mode 100644 index 0000000000..7f4dbc80e8 --- /dev/null +++ b/cacheservice/boilerplate/flyte/golangci_file/.golangci.yml @@ -0,0 +1,40 @@ +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +run: + skip-dirs: + - pkg/client + +linters: + disable-all: true + enable: + - deadcode + - errcheck + - gas + - gci + - goconst + - goimports + - golint + - gosimple + - govet + - ineffassign + - misspell + - nakedret + - staticcheck + - structcheck + - typecheck + - unconvert + - unparam + - unused + - varcheck + +linters-settings: + gci: + custom-order: true + sections: + - standard + - default + - prefix(github.com/flyteorg) + skip-generated: true diff --git a/cacheservice/boilerplate/flyte/golangci_file/Readme.rst b/cacheservice/boilerplate/flyte/golangci_file/Readme.rst new file mode 100644 index 0000000000..e4cbd18b96 --- /dev/null +++ b/cacheservice/boilerplate/flyte/golangci_file/Readme.rst @@ -0,0 +1,8 @@ +GolangCI File +~~~~~~~~~~~~~ + +Provides a ``.golangci`` file with the linters we've agreed upon. + +**To Enable:** + +Add ``flyteorg/golangci_file`` to your ``boilerplate/update.cfg`` file. diff --git a/cacheservice/boilerplate/flyte/golangci_file/update.sh b/cacheservice/boilerplate/flyte/golangci_file/update.sh new file mode 100755 index 0000000000..ab2f85c680 --- /dev/null +++ b/cacheservice/boilerplate/flyte/golangci_file/update.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Clone the .golangci file +echo " - copying ${DIR}/.golangci to the root directory." +cp ${DIR}/.golangci.yml ${DIR}/../../../.golangci.yml diff --git a/cacheservice/boilerplate/flyte/precommit/Makefile b/cacheservice/boilerplate/flyte/precommit/Makefile new file mode 100644 index 0000000000..3c6f17d6b2 --- /dev/null +++ b/cacheservice/boilerplate/flyte/precommit/Makefile @@ -0,0 +1,9 @@ +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + + +.PHONY: setup-precommit +setup-precommit: #setup the precommit + @boilerplate/flyte/precommit/update.sh diff --git a/cacheservice/boilerplate/flyte/precommit/hooks/pre-push b/cacheservice/boilerplate/flyte/precommit/hooks/pre-push new file mode 100755 index 0000000000..f161cfe856 --- /dev/null +++ b/cacheservice/boilerplate/flyte/precommit/hooks/pre-push @@ -0,0 +1,41 @@ +DUMMY_SHA=0000000000000000000000000000000000000000 + +echo "Running pre-push check; to skip this step use 'push --no-verify'" + +while read LOCAL_REF LOCAL_SHA REMOTE_REF REMOTE_SHA +do + if [ "$LOCAL_SHA" = $DUMMY_SHA ] + then + # Branch deleted. Do nothing. + exit 0 + else + if [ "$REMOTE_SHA" = $DUMMY_SHA ] + then + # New branch. Verify the last commit, since this is very likely where the new code is + # (though there is no way to know for sure). In the extremely uncommon case in which someone + # pushes more than 1 new commit to a branch, CI will enforce full checking. + RANGE="$LOCAL_SHA~1..$LOCAL_SHA" + else + # Updating branch. Verify new commits. + RANGE="$REMOTE_SHA..$LOCAL_SHA" + fi + + # Verify DCO signoff. We do this before the format checker, since it has + # some probability of failing spuriously, while this check never should. + # + # In general, we can't assume that the commits are signed off by author + # pushing, so we settle for just checking that there is a signoff at all. + SIGNED_OFF=$(git rev-list --no-merges --grep "^Signed-off-by: " "$RANGE") + NOT_SIGNED_OFF=$(git rev-list --no-merges "$RANGE" | grep -Fxv "$SIGNED_OFF") + if [ -n "$NOT_SIGNED_OFF" ] + then + echo >&2 "ERROR: The following commits do not have DCO signoff:" + while read -r commit; do + echo " $(git log --pretty=oneline --abbrev-commit -n 1 $commit)" + done <<< "$NOT_SIGNED_OFF" + exit 1 + fi + fi +done + +exit 0 diff --git a/cacheservice/boilerplate/flyte/precommit/hooks/prepare-commit-msg b/cacheservice/boilerplate/flyte/precommit/hooks/prepare-commit-msg new file mode 100755 index 0000000000..8148d104b8 --- /dev/null +++ b/cacheservice/boilerplate/flyte/precommit/hooks/prepare-commit-msg @@ -0,0 +1,16 @@ +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst +# $ ln -s ../../support/hooks/prepare-commit-msg .git/hooks/prepare-commit-msg + +COMMIT_MESSAGE_FILE="$1" +AUTHOR=$(git var GIT_AUTHOR_IDENT) +SIGNOFF=$(echo $AUTHOR | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') + +# Check for DCO signoff message. If one doesn't exist, append one and then warn +# the user that you did so. +if ! $(grep -qs "^$SIGNOFF" "$COMMIT_MESSAGE_FILE") ; then + echo "\n$SIGNOFF" >> "$COMMIT_MESSAGE_FILE" + echo "Appended the following signoff to the end of the commit message:\n $SIGNOFF\n" +fi diff --git a/cacheservice/boilerplate/flyte/precommit/update.sh b/cacheservice/boilerplate/flyte/precommit/update.sh new file mode 100755 index 0000000000..971c8386c1 --- /dev/null +++ b/cacheservice/boilerplate/flyte/precommit/update.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash + +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +set -e + +# Helper script for Automatically add DCO signoff with commit hooks +# Taken from Envoy https://gitlab.cncf.ci/envoyproxy/envoy +if [ ! "$PWD" == "$(git rev-parse --show-toplevel)" ]; then + cat >&2 <<__EOF__ +ERROR: this script must be run at the root of the envoy source tree +__EOF__ + exit 1 +fi + +# Helper functions that calculate `abspath` and `relpath`. Taken from Mesos +# commit 82b040a60561cf94dec3197ea88ae15e57bcaa97, which also carries the Apache +# V2 license, and has deployed this code successfully for some time. +abspath() { + cd "$(dirname "${1}")" + echo "${PWD}"/"$(basename "${1}")" + cd "${OLDPWD}" +} +relpath() { + local FROM TO UP + FROM="$(abspath "${1%/}")" TO="$(abspath "${2%/}"/)" + while test "${TO}" = "${TO#"${FROM}"/}" \ + -a "${TO}" != "${FROM}"; do + FROM="${FROM%/*}" UP="../${UP}" + done + TO="${UP%/}${TO#${FROM}}" + echo "${TO:-.}" +} + +# Try to find the `.git` directory, even if it's not in Flyte project root (as +# it wouldn't be if, say, this were in a submodule). The "blessed" but fairly +# new way to do this is to use `--git-common-dir`. +DOT_GIT_DIR=$(git rev-parse --git-common-dir) +if test ! -d "${DOT_GIT_DIR}"; then + # If `--git-common-dir` is not available, fall back to older way of doing it. + DOT_GIT_DIR=$(git rev-parse --git-dir) +fi + +mkdir -p ${DOT_GIT_DIR}/hooks + +HOOKS_DIR="${DOT_GIT_DIR}/hooks" +HOOKS_DIR_RELPATH=$(relpath "${HOOKS_DIR}" "${PWD}") + +if [ ! -e "${HOOKS_DIR}/prepare-commit-msg" ]; then + echo "Installing hook 'prepare-commit-msg'" + ln -s "${HOOKS_DIR_RELPATH}/boilerplate/flyte/precommit/hooks/prepare-commit-msg" "${HOOKS_DIR}/prepare-commit-msg" +fi + +if [ ! -e "${HOOKS_DIR}/pre-push" ]; then + echo "Installing hook 'pre-push'" + ln -s "${HOOKS_DIR_RELPATH}/boilerplate/flyte/precommit/hooks/pre-push" "${HOOKS_DIR}/pre-push" +fi diff --git a/cacheservice/boilerplate/flyte/pull_request_template/Readme.rst b/cacheservice/boilerplate/flyte/pull_request_template/Readme.rst new file mode 100644 index 0000000000..ee54437252 --- /dev/null +++ b/cacheservice/boilerplate/flyte/pull_request_template/Readme.rst @@ -0,0 +1,8 @@ +Pull Request Template +~~~~~~~~~~~~~~~~~~~~~ + +Provides a Pull Request template. + +**To Enable:** + +Add ``flyteorg/golang_test_targets`` to your ``boilerplate/update.cfg`` file. diff --git a/cacheservice/boilerplate/flyte/pull_request_template/pull_request_template.md b/cacheservice/boilerplate/flyte/pull_request_template/pull_request_template.md new file mode 100644 index 0000000000..9cdab99b46 --- /dev/null +++ b/cacheservice/boilerplate/flyte/pull_request_template/pull_request_template.md @@ -0,0 +1,35 @@ +## _Read then delete this section_ + +_- Make sure to use a concise title for the pull-request._ + +_- Use #patch, #minor or #major in the pull-request title to bump the corresponding version. Otherwise, the patch version +will be bumped. [More details](https://github.com/marketplace/actions/github-tag-bump)_ + +# TL;DR +_Please replace this text with a description of what this PR accomplishes._ + +## Type + - [ ] Bug Fix + - [ ] Feature + - [ ] Plugin + +## Are all requirements met? + + - [ ] Code completed + - [ ] Smoke tested + - [ ] Unit tests added + - [ ] Code documentation added + - [ ] Any pending items have an associated Issue + +## Complete description + _How did you fix the bug, make the feature etc. Link to any design docs etc_ + +## Tracking Issue +_Remove the '*fixes*' keyword if there will be multiple PRs to fix the linked issue_ + +fixes https://github.com/flyteorg/flyte/issues/ + +## Follow-up issue +_NA_ +OR +_https://github.com/flyteorg/flyte/issues/_ diff --git a/cacheservice/boilerplate/flyte/pull_request_template/update.sh b/cacheservice/boilerplate/flyte/pull_request_template/update.sh new file mode 100755 index 0000000000..051e9dbce0 --- /dev/null +++ b/cacheservice/boilerplate/flyte/pull_request_template/update.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +cp ${DIR}/pull_request_template.md ${DIR}/../../../pull_request_template.md diff --git a/cacheservice/boilerplate/update.cfg b/cacheservice/boilerplate/update.cfg new file mode 100644 index 0000000000..9d3bd30565 --- /dev/null +++ b/cacheservice/boilerplate/update.cfg @@ -0,0 +1,6 @@ +flyte/docker_build +flyte/golang_test_targets +flyte/golangci_file +flyte/golang_support_tools +flyte/pull_request_template +flyte/ diff --git a/cacheservice/boilerplate/update.sh b/cacheservice/boilerplate/update.sh new file mode 100755 index 0000000000..73de4dc91c --- /dev/null +++ b/cacheservice/boilerplate/update.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + +# WARNING: THIS FILE IS MANAGED IN THE 'BOILERPLATE' REPO AND COPIED TO OTHER REPOSITORIES. +# ONLY EDIT THIS FILE FROM WITHIN THE 'FLYTEORG/BOILERPLATE' REPOSITORY: +# +# TO OPT OUT OF UPDATES, SEE https://github.com/flyteorg/boilerplate/blob/master/Readme.rst + +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +OUT="$(mktemp -d)" +trap 'rm -fr $OUT' EXIT + +git clone https://github.com/flyteorg/boilerplate.git "${OUT}" + +echo "Updating the update.sh script." +cp "${OUT}/boilerplate/update.sh" "${DIR}/update.sh" + +CONFIG_FILE="${DIR}/update.cfg" +README="https://github.com/flyteorg/boilerplate/blob/master/Readme.rst" + +if [ ! -f "$CONFIG_FILE" ]; then + echo "$CONFIG_FILE not found." + echo "This file is required in order to select which features to include." + echo "See $README for more details." + exit 1 +fi + +if [ -z "$REPOSITORY" ]; then + echo "$REPOSITORY is required to run this script" + echo "See $README for more details." + exit 1 +fi + +while read -r directory junk; do + # Skip comment lines (which can have leading whitespace) + if [[ "$directory" == '#'* ]]; then + continue + fi + # Skip blank or whitespace-only lines + if [[ "$directory" == "" ]]; then + continue + fi + # Lines like + # valid/path other_junk + # are not acceptable, unless `other_junk` is a comment + if [[ "$junk" != "" ]] && [[ "$junk" != '#'* ]]; then + echo "Invalid config! Only one directory is allowed per line. Found '$junk'" + exit 1 + fi + + dir_path="${OUT}/boilerplate/${directory}" + # Make sure the directory exists + if ! [[ -d "$dir_path" ]]; then + echo "Invalid boilerplate directory: '$directory'" + exit 1 + fi + + echo "***********************************************************************************" + echo "$directory is configured in update.cfg." + echo "-----------------------------------------------------------------------------------" + echo "syncing files from source." + rm -rf "${DIR:?}/${directory}" + mkdir -p "$(dirname "${DIR}"/"${directory}")" + cp -r "$dir_path" "${DIR}/${directory}" + if [ -f "${DIR}/${directory}/update.sh" ]; then + echo "executing ${DIR}/${directory}/update.sh" + "${DIR}/${directory}/update.sh" + fi + echo "***********************************************************************************" + echo "" +done < "$CONFIG_FILE" diff --git a/cacheservice/cmd/entrypoints/root.go b/cacheservice/cmd/entrypoints/root.go new file mode 100644 index 0000000000..803224f007 --- /dev/null +++ b/cacheservice/cmd/entrypoints/root.go @@ -0,0 +1,54 @@ +package entrypoints + +import ( + "context" + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/flyteorg/flyte/flytestdlib/config" + "github.com/flyteorg/flyte/flytestdlib/config/viper" + "github.com/flyteorg/flyte/flytestdlib/logger" +) + +var ( + cfgFile string + configAccessor = viper.NewAccessor(config.Options{}) +) + +func Execute() error { + if err := RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } + return nil +} + +// RootCmd represents the base command when called without any subcommands +var RootCmd = &cobra.Command{ + Use: "cacheservice", + Short: "Launches cacheservice", + Long: ` +To get started run the serve subcommand which will start a server on localhost:8091: + + cacheservice serve +`, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + return initConfig(cmd.Flags()) + }, +} + +func initConfig(flags *pflag.FlagSet) error { + configAccessor = viper.NewAccessor(config.Options{ + SearchPaths: []string{cfgFile, ".", "/etc/flyte/config", "$GOPATH/src/github.com/flyteorg/flyte/cacheservice"}, + StrictMode: false, + }) + + logger.Infof(context.TODO(), "Using config file: %v", configAccessor.ConfigFilesUsed()) + + configAccessor.InitializePflags(flags) + + return configAccessor.UpdateConfig(context.TODO()) +} diff --git a/cacheservice/cmd/entrypoints/serve.go b/cacheservice/cmd/entrypoints/serve.go new file mode 100644 index 0000000000..4e3c205567 --- /dev/null +++ b/cacheservice/cmd/entrypoints/serve.go @@ -0,0 +1,60 @@ +package entrypoints + +import ( + "context" + + "github.com/spf13/cobra" + + "github.com/flyteorg/flyte/cacheservice/pkg/config" + "github.com/flyteorg/flyte/cacheservice/pkg/rpc/cacheservice" + "github.com/flyteorg/flyte/cacheservice/pkg/runtime" + "github.com/flyteorg/flyte/flytestdlib/contextutils" + "github.com/flyteorg/flyte/flytestdlib/logger" + "github.com/flyteorg/flyte/flytestdlib/otelutils" + "github.com/flyteorg/flyte/flytestdlib/profutils" + "github.com/flyteorg/flyte/flytestdlib/promutils/labeled" +) + +var serveCmd = &cobra.Command{ + Use: "serve", + Short: "Launches the Cache Service server", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + cfg := config.GetConfig() + + // serve a http healthcheck endpoint + go func() { + err := cacheservice.ServeHTTPHealthCheck(ctx, cfg) + if err != nil { + logger.Errorf(ctx, "Unable to serve http", config.GetConfig().GetHTTPHostAddress(), err) + } + }() + + // Serve profiling endpoint. + cacheServiceConfig := runtime.NewConfigurationProvider().ApplicationConfiguration().GetCacheServiceConfig() + go func() { + err := profutils.StartProfilingServerWithDefaultHandlers( + context.Background(), cacheServiceConfig.ProfilerPort, nil) + if err != nil { + logger.Panicf(context.Background(), "Failed to Start profiling and Metrics server. Error, %v", err) + } + }() + + // Set Keys + labeled.SetMetricKeys(contextutils.AppNameKey, contextutils.ProjectKey, contextutils.DomainKey) + + // register otel tracer providers + for _, serviceName := range []string{otelutils.CacheServiceGormTracer, otelutils.CacheServiceServerTracer} { + if err := otelutils.RegisterTracerProvider(serviceName, otelutils.GetConfig()); err != nil { + logger.Errorf(ctx, "Failed to create otel tracer provider. %v", err) + return err + } + } + + return cacheservice.ServeInsecure(ctx, cfg) + }, +} + +func init() { + RootCmd.AddCommand(serveCmd) +} diff --git a/cacheservice/cmd/entrypoints/serve_dummy.go b/cacheservice/cmd/entrypoints/serve_dummy.go new file mode 100644 index 0000000000..6faf28457e --- /dev/null +++ b/cacheservice/cmd/entrypoints/serve_dummy.go @@ -0,0 +1,34 @@ +package entrypoints + +import ( + "context" + + "github.com/spf13/cobra" + + "github.com/flyteorg/flyte/cacheservice/pkg/config" + "github.com/flyteorg/flyte/cacheservice/pkg/rpc/cacheservice" + "github.com/flyteorg/flyte/flytestdlib/logger" +) + +var serveDummyCmd = &cobra.Command{ + Use: "serve-dummy", + Short: "Launches the CacheService server without any connections", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + cfg := config.GetConfig() + + // serve a http healthcheck endpoint + go func() { + err := cacheservice.ServeHTTPHealthCheck(ctx, cfg) + if err != nil { + logger.Errorf(ctx, "Unable to serve http", cfg.GetGrpcHostAddress(), err) + } + }() + + return cacheservice.Serve(ctx, cfg) + }, +} + +func init() { + RootCmd.AddCommand(serveDummyCmd) +} diff --git a/cacheservice/cmd/main.go b/cacheservice/cmd/main.go new file mode 100644 index 0000000000..952482eeb5 --- /dev/null +++ b/cacheservice/cmd/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "github.com/golang/glog" + + "github.com/flyteorg/flyte/cacheservice/cmd/entrypoints" +) + +func main() { + glog.V(2).Info("Beginning Cache Service") + err := entrypoints.Execute() + if err != nil { + panic(err) + } +} diff --git a/cacheservice/go.mod b/cacheservice/go.mod new file mode 100644 index 0000000000..34bc9af6c2 --- /dev/null +++ b/cacheservice/go.mod @@ -0,0 +1,160 @@ +module github.com/flyteorg/flyte/cacheservice + +go 1.21 + +require ( + github.com/aws/aws-sdk-go-v2/config v1.26.6 + github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.12.17 + github.com/flyteorg/flyte/flyteidl v0.0.0-00010101000000-000000000000 + github.com/flyteorg/flyte/flytestdlib v0.0.0-00010101000000-000000000000 + github.com/go-redis/redis/v8 v8.11.5 + github.com/golang/glog v1.1.2 + github.com/golang/protobuf v1.5.3 + github.com/mitchellh/mapstructure v1.5.0 + github.com/spf13/cobra v1.7.0 + github.com/spf13/pflag v1.0.5 + github.com/stretchr/testify v1.8.4 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 + go.opentelemetry.io/otel v1.22.0 + google.golang.org/grpc v1.60.1 +) + +require ( + github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect + github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.18.7 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.8.11 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect + github.com/aws/smithy-go v1.19.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/google/s2a-go v0.1.4 // indirect + golang.org/x/sync v0.4.0 // indirect +) + +require ( + cloud.google.com/go v0.110.8 // indirect + cloud.google.com/go/compute v1.23.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v1.1.2 // indirect + cloud.google.com/go/storage v1.30.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect + github.com/aws/aws-sdk-go v1.44.2 // indirect + github.com/aws/aws-sdk-go-v2 v1.24.1 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.27.1 + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/coocood/freecache v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/flyteorg/stow v0.3.8 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-logr/logr v1.4.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.2 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v5 v5.0.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.3.1 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.4 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/hashicorp/hcl v1.0.0 // 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/kylelemons/godebug v1.1.0 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // 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/ncw/swift v1.0.53 // indirect + github.com/pelletier/go-toml v1.9.4 // indirect + github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.16.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/sirupsen/logrus v1.9.2 // indirect + github.com/spf13/afero v1.9.2 // indirect + github.com/spf13/cast v1.4.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/viper v1.11.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.22.0 // indirect + go.opentelemetry.io/otel/metric v1.22.0 // indirect + go.opentelemetry.io/otel/sdk v1.22.0 // indirect + go.opentelemetry.io/otel/trace v1.22.0 // indirect + golang.org/x/crypto v0.18.0 // indirect + golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/oauth2 v0.13.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/term v0.16.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/api v0.128.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect + google.golang.org/protobuf v1.32.0 + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.66.4 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.28.2 // indirect + k8s.io/apimachinery v0.28.2 // indirect + k8s.io/client-go v0.28.1 // indirect + k8s.io/klog/v2 v2.100.1 // indirect + k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + sigs.k8s.io/controller-runtime v0.0.0-00010101000000-000000000000 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) + +replace ( + github.com/flyteorg/flyte/cacheservice => ../cacheservice + github.com/flyteorg/flyte/flyteadmin => ../flyteadmin + github.com/flyteorg/flyte/flyteidl => ../flyteidl + github.com/flyteorg/flyte/flyteplugins => ../flyteplugins + github.com/flyteorg/flyte/flytepropeller => ../flytepropeller + github.com/flyteorg/flyte/flytestdlib => ../flytestdlib + k8s.io/api => k8s.io/api v0.28.2 + k8s.io/apimachinery => k8s.io/apimachinery v0.28.2 + k8s.io/client-go => k8s.io/client-go v0.28.2 + k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20230905202853-d090da108d2f + sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.16.2 +) diff --git a/cacheservice/go.sum b/cacheservice/go.sum new file mode 100644 index 0000000000..bf6e90320b --- /dev/null +++ b/cacheservice/go.sum @@ -0,0 +1,818 @@ +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.44.3/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 v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME= +cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.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/iam v1.1.2 h1:gacbrBdWcoVmGLozRuStX45YKvJtzIjJdAolzUs1sm4= +cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= +cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.2 h1:t5+QXLCK9SVi0PPdaY0PrFvYUo24KwA0QwxnaHRSVd4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.2/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 h1:LNHhpdK7hzUcx/k1LIcuh5k7k1LGIWLQfCjaneSj7Fc= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 h1:Ma67P/GGprNwsslzEH6+Kb8nybI8jpDTm4Wmzu2ReK8= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0/go.mod h1:c+Lifp3EDEamAkPVzMooRNOK6CZjNSdEnf1A7jsI9u4= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 h1:nVocQV40OQne5613EeLayJiRAJuKlBGy+m22qWG+WRg= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0/go.mod h1:7QJP7dr2wznCMeqIrhMgWGf7XpAQnVrJqDm9nvV3Cu4= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 h1:hVeq+yCyUi+MsoO/CU95yqCIcdzra5ovzk8Q2BBpV2M= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +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/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/aws/aws-sdk-go v1.44.2 h1:5VBk5r06bgxgRKVaUtm1/4NT/rtrnH2E4cnAYv5zgQc= +github.com/aws/aws-sdk-go v1.44.2/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU= +github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= +github.com/aws/aws-sdk-go-v2/config v1.26.6 h1:Z/7w9bUqlRI0FFQpetVuFYEsjzE3h7fpU6HuGmfPL/o= +github.com/aws/aws-sdk-go-v2/config v1.26.6/go.mod h1:uKU6cnDmYCvJ+pxO9S4cWDb2yWWIH5hra+32hVh1MI4= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.12.17 h1:jPuObStSZU1cGheSslAbF2nA4c/IgeIQA1X9frB60Oc= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.12.17/go.mod h1:df3uvEupLM3MkLim3BDkCaRpgAROW7wk41dwNQjw0kA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 h1:n3GDfwqF2tzEkXlv5cuy4iy7LpKDtqDMcNLfZDu9rls= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.27.1 h1:plNo3WtooT2fYnhdyuzzsIJ4QWzcF5AT9oFbnrYC5Dw= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.27.1/go.mod h1:N5tqZcYMM0N1PN7UQYJNWuGyO886OfnMhf/3MAbqMcI= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.18.7 h1:srShyROqxzC7p18Ws8mqM2sqxJO/8L3Kpiqf+NboJLg= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.18.7/go.mod h1:9efZgg4nJCGRp91MuHhkwd2kvyp7PWLRYYk5WjEQ5ts= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.8.11 h1:e9AVb17H4x5FTE5KWIP5M1Du+9M86pS+Hw0lBUdN8EY= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.8.11/go.mod h1:B90ZQJa36xo0ph9HsoteI1+r8owgQH/U1QNfqZQkj1Q= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U= +github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= +github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= +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 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.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/coocood/freecache v1.1.1 h1:uukNF7QKCZEdZ9gAV7WQzvh0SbjwdMF6m3x3rxEkaPc= +github.com/coocood/freecache v1.1.1/go.mod h1:OKrEjkGVoxZhyWAJoeFi5BMLUJm2Tit0kpGkIr7NGYY= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +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.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/flyteorg/stow v0.3.8 h1:4a6BtfgDR86fUwa48DkkZTcp6WK4oQXSfewPd/kN0Z4= +github.com/flyteorg/stow v0.3.8/go.mod h1:fArjMpsYJNWkp/hyDKKdbcv07gxbuLmKFcb7YT1aSOM= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +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-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +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.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.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +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/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= +github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +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/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +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/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.1.2/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.4 h1:uGy6JWR/uMIILU8wbf+OkstIrNiMjGpEIyhx8f6W7s4= +github.com/googleapis/enterprise-certificate-proxy v0.2.4/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.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +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/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +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/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/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/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +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/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +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/ncw/swift v1.0.53 h1:luHjjTNtekIEvHg5KdAFIBaH7bWfNkefwFnpDffSIks= +github.com/ncw/swift v1.0.53/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +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.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= +github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.0-beta.8 h1:dy81yyLYJDwMTifq24Oi/IslOslRrDSb3jwDggjz3Z0= +github.com/pelletier/go-toml/v2 v2.0.0-beta.8/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +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.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +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.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-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.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +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/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +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/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= +github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +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.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +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.11.0 h1:7OX/1FS6n7jHD1zGrZTM7WtY13ZELRyosK4k93oPr44= +github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUsX7Zk= +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 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +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.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/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/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +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/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= +go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= +go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.22.0 h1:zr8ymM5OWWjjiWRzwTfZ67c905+2TMHYp2lMJ52QTyM= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.22.0/go.mod h1:sQs7FT2iLVJ+67vYngGJkPe1qr39IzaBzaj9IDNNY8k= +go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= +go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= +go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= +go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +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-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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +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/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +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/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/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.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-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-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +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-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-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-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-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/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.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +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/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.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.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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/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-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= +golang.org/x/tools v0.9.3/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= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.128.0 h1:RjPESny5CnQRn9V6siglged+DZCgfu9l6mO9dkX9VOg= +google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/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-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= +google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= +google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU= +google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= +google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +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/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +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.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= +gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +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.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/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.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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= +k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= +k8s.io/apiextensions-apiserver v0.28.0 h1:CszgmBL8CizEnj4sj7/PtLGey6Na3YgWyGCPONv7E9E= +k8s.io/apiextensions-apiserver v0.28.0/go.mod h1:uRdYiwIuu0SyqJKriKmqEN2jThIJPhVmOWETm8ud1VE= +k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= +k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= +k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= +k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= +k8s.io/component-base v0.28.1 h1:LA4AujMlK2mr0tZbQDZkjWbdhTV5bRyEyAFe0TJxlWg= +k8s.io/component-base v0.28.1/go.mod h1:jI11OyhbX21Qtbav7JkhehyBsIRfnO8oEgoAR12ArIU= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20230905202853-d090da108d2f h1:eeEUOoGYWhOz7EyXqhlR2zHKNw2mNJ9vzJmub6YN6kk= +k8s.io/kube-openapi v0.0.0-20230905202853-d090da108d2f/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/controller-runtime v0.16.2 h1:mwXAVuEk3EQf478PQwQ48zGOXvW27UJc8NHktQVuIPU= +sigs.k8s.io/controller-runtime v0.16.2/go.mod h1:vpMu3LpI5sYWtujJOa2uPK61nB5rbwlN7BAB8aSLvGU= +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/cacheservice/pkg/config/config.go b/cacheservice/pkg/config/config.go new file mode 100644 index 0000000000..5c00738a29 --- /dev/null +++ b/cacheservice/pkg/config/config.go @@ -0,0 +1,52 @@ +package config + +import ( + "fmt" + + "github.com/flyteorg/flyte/flytestdlib/config" +) + +const SectionKey = "cache" + +//go:generate pflags Config + +type Config struct { + GrpcPort int `json:"grpcPort" pflag:",On which grpc port to serve Cache Service"` + GrpcServerReflection bool `json:"grpcServerReflection" pflag:",Enable GRPC Server Reflection"` + HTTPPort int `json:"httpPort" pflag:",On which http port to serve CacheService"` + Secure bool `json:"secure" pflag:",Whether to run CacheService in secure mode or not"` + ReadHeaderTimeoutSeconds int `json:"readHeaderTimeoutSeconds" pflag:",The amount of time allowed to read request headers."` +} + +var defaultConfig = &Config{ + GrpcPort: 8091, + HTTPPort: 8090, + GrpcServerReflection: true, + // Set the HTTP timeout to avoid security vulnerabilities with expired, inactive connections: + // https://deepsource.io/directory/analyzers/go/issues/GO-S2114 + // just shy of requestTimeoutUpperBound + ReadHeaderTimeoutSeconds: 32, +} +var applicationConfig = config.MustRegisterSection(SectionKey, defaultConfig) + +func GetConfig() *Config { + return applicationConfig.GetConfig().(*Config) +} + +func SetConfig(c *Config) { + if err := applicationConfig.SetConfig(c); err != nil { + panic(err) + } +} + +func (c Config) GetGrpcHostAddress() string { + return fmt.Sprintf(":%d", c.GrpcPort) +} + +func (c Config) GetHTTPHostAddress() string { + return fmt.Sprintf(":%d", c.HTTPPort) +} + +func init() { + SetConfig(&Config{}) +} diff --git a/cacheservice/pkg/config/config_flags.go b/cacheservice/pkg/config/config_flags.go new file mode 100755 index 0000000000..f433bddd32 --- /dev/null +++ b/cacheservice/pkg/config/config_flags.go @@ -0,0 +1,59 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots. + +package config + +import ( + "encoding/json" + "reflect" + + "fmt" + + "github.com/spf13/pflag" +) + +// If v is a pointer, it will get its element value or the zero value of the element type. +// If v is not a pointer, it will return it as is. +func (Config) elemValueOrNil(v interface{}) interface{} { + if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr { + if reflect.ValueOf(v).IsNil() { + return reflect.Zero(t.Elem()).Interface() + } else { + return reflect.ValueOf(v).Interface() + } + } else if v == nil { + return reflect.Zero(t).Interface() + } + + return v +} + +func (Config) mustJsonMarshal(v interface{}) string { + raw, err := json.Marshal(v) + if err != nil { + panic(err) + } + + return string(raw) +} + +func (Config) mustMarshalJSON(v json.Marshaler) string { + raw, err := v.MarshalJSON() + if err != nil { + panic(err) + } + + return string(raw) +} + +// GetPFlagSet will return strongly types pflags for all fields in Config and its nested types. The format of the +// flags is json-name.json-sub-name... etc. +func (cfg Config) GetPFlagSet(prefix string) *pflag.FlagSet { + cmdFlags := pflag.NewFlagSet("Config", pflag.ExitOnError) + cmdFlags.Int(fmt.Sprintf("%v%v", prefix, "grpcPort"), defaultConfig.GrpcPort, "On which grpc port to serve Cache Service") + cmdFlags.Bool(fmt.Sprintf("%v%v", prefix, "grpcServerReflection"), defaultConfig.GrpcServerReflection, "Enable GRPC Server Reflection") + cmdFlags.Int(fmt.Sprintf("%v%v", prefix, "httpPort"), defaultConfig.HTTPPort, "On which http port to serve CacheService") + cmdFlags.Bool(fmt.Sprintf("%v%v", prefix, "secure"), defaultConfig.Secure, "Whether to run CacheService in secure mode or not") + cmdFlags.Int(fmt.Sprintf("%v%v", prefix, "readHeaderTimeoutSeconds"), defaultConfig.ReadHeaderTimeoutSeconds, "The amount of time allowed to read request headers.") + return cmdFlags +} diff --git a/cacheservice/pkg/config/config_flags_test.go b/cacheservice/pkg/config/config_flags_test.go new file mode 100755 index 0000000000..d94f73d45c --- /dev/null +++ b/cacheservice/pkg/config/config_flags_test.go @@ -0,0 +1,172 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots. + +package config + +import ( + "encoding/json" + "fmt" + "reflect" + "strings" + "testing" + + "github.com/mitchellh/mapstructure" + "github.com/stretchr/testify/assert" +) + +var dereferencableKindsConfig = map[reflect.Kind]struct{}{ + reflect.Array: {}, reflect.Chan: {}, reflect.Map: {}, reflect.Ptr: {}, reflect.Slice: {}, +} + +// Checks if t is a kind that can be dereferenced to get its underlying type. +func canGetElementConfig(t reflect.Kind) bool { + _, exists := dereferencableKindsConfig[t] + return exists +} + +// This decoder hook tests types for json unmarshaling capability. If implemented, it uses json unmarshal to build the +// object. Otherwise, it'll just pass on the original data. +func jsonUnmarshalerHookConfig(_, to reflect.Type, data interface{}) (interface{}, error) { + unmarshalerType := reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() + if to.Implements(unmarshalerType) || reflect.PtrTo(to).Implements(unmarshalerType) || + (canGetElementConfig(to.Kind()) && to.Elem().Implements(unmarshalerType)) { + + raw, err := json.Marshal(data) + if err != nil { + fmt.Printf("Failed to marshal Data: %v. Error: %v. Skipping jsonUnmarshalHook", data, err) + return data, nil + } + + res := reflect.New(to).Interface() + err = json.Unmarshal(raw, &res) + if err != nil { + fmt.Printf("Failed to umarshal Data: %v. Error: %v. Skipping jsonUnmarshalHook", data, err) + return data, nil + } + + return res, nil + } + + return data, nil +} + +func decode_Config(input, result interface{}) error { + config := &mapstructure.DecoderConfig{ + TagName: "json", + WeaklyTypedInput: true, + Result: result, + DecodeHook: mapstructure.ComposeDecodeHookFunc( + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToSliceHookFunc(","), + jsonUnmarshalerHookConfig, + ), + } + + decoder, err := mapstructure.NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +func join_Config(arr interface{}, sep string) string { + listValue := reflect.ValueOf(arr) + strs := make([]string, 0, listValue.Len()) + for i := 0; i < listValue.Len(); i++ { + strs = append(strs, fmt.Sprintf("%v", listValue.Index(i))) + } + + return strings.Join(strs, sep) +} + +func testDecodeJson_Config(t *testing.T, val, result interface{}) { + assert.NoError(t, decode_Config(val, result)) +} + +func testDecodeRaw_Config(t *testing.T, vStringSlice, result interface{}) { + assert.NoError(t, decode_Config(vStringSlice, result)) +} + +func TestConfig_GetPFlagSet(t *testing.T) { + val := Config{} + cmdFlags := val.GetPFlagSet("") + assert.True(t, cmdFlags.HasFlags()) +} + +func TestConfig_SetFlags(t *testing.T) { + actual := Config{} + cmdFlags := actual.GetPFlagSet("") + assert.True(t, cmdFlags.HasFlags()) + + t.Run("Test_grpcPort", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("grpcPort", testValue) + if vInt, err := cmdFlags.GetInt("grpcPort"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vInt), &actual.GrpcPort) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_grpcServerReflection", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("grpcServerReflection", testValue) + if vBool, err := cmdFlags.GetBool("grpcServerReflection"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vBool), &actual.GrpcServerReflection) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_httpPort", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("httpPort", testValue) + if vInt, err := cmdFlags.GetInt("httpPort"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vInt), &actual.HTTPPort) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_secure", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("secure", testValue) + if vBool, err := cmdFlags.GetBool("secure"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vBool), &actual.Secure) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_readHeaderTimeoutSeconds", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("readHeaderTimeoutSeconds", testValue) + if vInt, err := cmdFlags.GetInt("readHeaderTimeoutSeconds"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vInt), &actual.ReadHeaderTimeoutSeconds) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) +} diff --git a/cacheservice/pkg/errors/errors.go b/cacheservice/pkg/errors/errors.go new file mode 100644 index 0000000000..372f816247 --- /dev/null +++ b/cacheservice/pkg/errors/errors.go @@ -0,0 +1,65 @@ +package errors + +import ( + "fmt" + + "github.com/golang/protobuf/proto" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const ( + invalidArgFormat = "invalid value for %s, value:[%s]" + missingFieldFormat = "missing %s" + notFound = "missing entity of type %s with identifier %v" +) + +type CacheServiceError interface { + Error() string + Code() codes.Code + GRPCStatus() *status.Status + WithDetails(details proto.Message) (CacheServiceError, error) + String() string +} + +type cacheServiceErrorImpl struct { + status *status.Status +} + +func (e *cacheServiceErrorImpl) Error() string { + return e.status.Message() +} + +func (e *cacheServiceErrorImpl) Code() codes.Code { + return e.status.Code() +} + +func (e *cacheServiceErrorImpl) GRPCStatus() *status.Status { + return e.status +} + +func (e *cacheServiceErrorImpl) String() string { + return fmt.Sprintf("status: %v", e.status) +} + +func NewCacheServiceError(code codes.Code, message string) error { + return &cacheServiceErrorImpl{ + status: status.New(code, message), + } +} + +func NewCacheServiceErrorf(code codes.Code, format string, a ...interface{}) error { + return NewCacheServiceError(code, fmt.Sprintf(format, a...)) +} + +func NewNotFoundError(entityType string, key string) error { + return NewCacheServiceErrorf(codes.NotFound, notFound, entityType, key) +} + +func NewMissingArgumentError(field string) error { + return NewCacheServiceErrorf(codes.InvalidArgument, fmt.Sprintf(missingFieldFormat, field)) +} + +func NewInvalidArgumentError(field string, value string) error { + return NewCacheServiceErrorf(codes.InvalidArgument, fmt.Sprintf(invalidArgFormat, field, value)) +} diff --git a/cacheservice/pkg/errors/errors_test.go b/cacheservice/pkg/errors/errors_test.go new file mode 100644 index 0000000000..04b32187ba --- /dev/null +++ b/cacheservice/pkg/errors/errors_test.go @@ -0,0 +1 @@ +package errors diff --git a/cacheservice/pkg/manager/impl/cache_data_store.go b/cacheservice/pkg/manager/impl/cache_data_store.go new file mode 100644 index 0000000000..c296807e57 --- /dev/null +++ b/cacheservice/pkg/manager/impl/cache_data_store.go @@ -0,0 +1,226 @@ +package impl + +import ( + "context" + "encoding/json" + + "github.com/aws/aws-sdk-go-v2/aws" + awsConfig "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/go-redis/redis/v8" + "google.golang.org/grpc/codes" + + "github.com/flyteorg/flyte/cacheservice/pkg/errors" + "github.com/flyteorg/flyte/cacheservice/pkg/manager/interfaces" + "github.com/flyteorg/flyte/cacheservice/pkg/runtime/configs" + "github.com/flyteorg/flyte/cacheservice/repositories/models" + "github.com/flyteorg/flyte/flytestdlib/logger" +) + +var ( + _ interfaces.CacheDataStoreClient = &memClient{} +) + +type memClient struct { + cacheMap *map[string]*models.CachedOutput +} + +// Get returns the cached output for the given key. It returns an error if the key does not exist. +func (c *memClient) Get(ctx context.Context, key string) (*models.CachedOutput, error) { + cache := *c.cacheMap + if value, exists := cache[key]; exists { + return value, nil + } + + return nil, errors.NewNotFoundError("output", key) +} + +// Put will always set the value for the given key. It will overwrite the existing value if it exists. +func (c *memClient) Put(ctx context.Context, key string, cachedOutput *models.CachedOutput) error { + cache := *c.cacheMap + cache[key] = cachedOutput + return nil +} + +// Delete is an idempotent operation. It will not return an error if the key does not exist. +func (c *memClient) Delete(ctx context.Context, key string) error { + cache := *c.cacheMap + if _, exists := cache[key]; exists { + delete(cache, key) + return nil + } + + return errors.NewNotFoundError("output", key) +} + +var ( + _ interfaces.CacheDataStoreClient = &dynamoClient{} +) + +type dynamoClient struct { + DynamoDbClient *dynamodb.Client + TableName string +} + +// Get returns the cached output for the given key. It returns an error if the key does not exist. +func (c *dynamoClient) Get(ctx context.Context, key string) (*models.CachedOutput, error) { + dynamoKey, err := attributevalue.Marshal(key) + if err != nil { + logger.Debugf(ctx, "Failed to marshal key to dynamo key with error %v", err) + return nil, err + } + + response, err := c.DynamoDbClient.GetItem(context.TODO(), &dynamodb.GetItemInput{ + Key: map[string]types.AttributeValue{"id": dynamoKey}, TableName: aws.String(c.TableName), + }) + if err != nil { + logger.Debugf(ctx, "Failed to get item from dynamo with error %v", err) + return nil, errors.NewCacheServiceErrorf(codes.Internal, "Failed to get item from dynamo with error %v", err) + } + if response.Item == nil { + logger.Debugf(ctx, "Item with key %s not found in dynamo", key) + return nil, errors.NewNotFoundError("output", key) + } + + cachedOutput := models.CachedOutput{} + err = attributevalue.UnmarshalMap(response.Item, &cachedOutput) + if err != nil { + logger.Debugf(ctx, "Failed to unmarshal dynamo item with error %v", err) + return nil, errors.NewCacheServiceErrorf(codes.Internal, "Failed to unmarshal dynamo item with error %v", err) + } + + return &cachedOutput, nil +} + +// Put will always set the value for the given key. It will overwrite the existing value if it exists. +func (c *dynamoClient) Put(ctx context.Context, key string, cachedOutput *models.CachedOutput) error { + item, err := attributevalue.MarshalMap(cachedOutput) + if err != nil { + logger.Debugf(ctx, "Failed to marshal output to dynamo object with error %v", err) + return errors.NewCacheServiceErrorf(codes.Internal, "Failed to marshal output to dynamo object with error %v", err) + } + + _, err = c.DynamoDbClient.PutItem(context.TODO(), &dynamodb.PutItemInput{ + TableName: aws.String(c.TableName), Item: item, + }) + if err != nil { + logger.Debugf(ctx, "Failed updating dynamo table with error %v", err) + return errors.NewCacheServiceErrorf(codes.Internal, "Failed updating dynamo table with error %v", err) + } + return nil +} + +// Delete is an idempotent operation. It will not return an error if the key does not exist. +func (c *dynamoClient) Delete(ctx context.Context, key string) error { + dynamoKey, err := attributevalue.Marshal(key) + if err != nil { + logger.Debugf(ctx, "Failed to marshal key to dynamo key with error %v", err) + return errors.NewCacheServiceErrorf(codes.Internal, "Failed to marshal key to dynamo key with error %v", err) + } + _, err = c.DynamoDbClient.DeleteItem(context.TODO(), &dynamodb.DeleteItemInput{ + TableName: aws.String(c.TableName), Key: map[string]types.AttributeValue{"id": dynamoKey}, + }) + if err != nil { + logger.Debugf(ctx, "Failed to delete item with key %v from dynamo with error %v", key, err) + return errors.NewCacheServiceErrorf(codes.Internal, "Failed to delete item with key %v from dynamo with error %v", key, err) + } + return nil +} + +var ( + _ interfaces.CacheDataStoreClient = &redisClient{} +) + +type redisClient struct { + RedisClient *redis.Client +} + +// Get returns the cached output for the given key. It returns an error if the key does not exist. +func (r *redisClient) Get(ctx context.Context, key string) (*models.CachedOutput, error) { + val, err := r.RedisClient.Get(ctx, key).Result() + if err == redis.Nil { + logger.Debugf(ctx, "Item with key %s not found in redis", key) + return nil, errors.NewNotFoundError("output", key) + } else if err != nil { + logger.Errorf(ctx, "Failed to get item from redis with error %v", err) + return nil, errors.NewCacheServiceErrorf(codes.Internal, "Failed to get item from redis with error %v", err) + } + + var cachedOutput models.CachedOutput + err = json.Unmarshal([]byte(val), &cachedOutput) + if err != nil { + logger.Errorf(ctx, "Failed to unmarshal output with error %v", err) + return nil, errors.NewCacheServiceErrorf(codes.Internal, "Failed to unmarshal output with error %v", err) + } + + return &cachedOutput, nil +} + +// Put will always set the value for the given key. It will overwrite the existing value if it exists. +func (r *redisClient) Put(ctx context.Context, key string, cachedOutput *models.CachedOutput) error { + val, err := json.Marshal(cachedOutput) + if err != nil { + logger.Errorf(ctx, "Failed to marshal output with error %v", err) + return errors.NewCacheServiceErrorf(codes.Internal, "Failed to marshal output with error %v", err) + } + + err = r.RedisClient.Set(ctx, key, val, 0).Err() + if err != nil { + logger.Errorf(ctx, "Failed updating redis for key %v with error %v", key, err) + return errors.NewCacheServiceErrorf(codes.Internal, "Failed updating redis for key %v with error %v", key, err) + } + + return nil +} + +// Delete is an idempotent operation. It will not return an error if the key does not exist. +func (r *redisClient) Delete(ctx context.Context, key string) error { + _, err := r.RedisClient.Del(ctx, key).Result() + if err != nil { + logger.Errorf(ctx, "Failed deleting redis key %v with error %v", key, err) + return errors.NewCacheServiceErrorf(codes.Internal, "Failed deleting redis key %v with error %v", key, err) + } + + return nil +} + +func NewCacheDataStore(ctx context.Context, serviceConfig configs.CacheServiceConfig) interfaces.CacheDataStoreClient { + clientType := serviceConfig.DataStoreType + + switch clientType { + case configs.Mem: + cacheMap := make(map[string]*models.CachedOutput) + return &memClient{cacheMap: &cacheMap} + case configs.DynamoDB: + cfg, err := awsConfig.LoadDefaultConfig(context.TODO(), + awsConfig.WithRegion(serviceConfig.AwsRegion), + ) + if err != nil { + panic("unable to load AWS config to connect to Dynamo" + err.Error()) + } + return &dynamoClient{ + DynamoDbClient: dynamodb.NewFromConfig(cfg), + TableName: "cache", + } + case configs.Redis: + rdb := redis.NewClient( + &redis.Options{ + Addr: serviceConfig.RedisAddress, + Username: serviceConfig.RedisUsername, + Password: serviceConfig.RedisPassword, + }) + + _, err := rdb.Ping(ctx).Result() + if err != nil { + panic("failed to connect to redis " + err.Error()) + } + + return &redisClient{ + RedisClient: rdb, + } + } + + panic("unsupported cache data store type") +} diff --git a/cacheservice/pkg/manager/impl/cache_data_store_test.go b/cacheservice/pkg/manager/impl/cache_data_store_test.go new file mode 100644 index 0000000000..4f9d22e382 --- /dev/null +++ b/cacheservice/pkg/manager/impl/cache_data_store_test.go @@ -0,0 +1 @@ +package impl diff --git a/cacheservice/pkg/manager/impl/cache_manager.go b/cacheservice/pkg/manager/impl/cache_manager.go new file mode 100644 index 0000000000..eb30bc795b --- /dev/null +++ b/cacheservice/pkg/manager/impl/cache_manager.go @@ -0,0 +1,319 @@ +package impl + +import ( + "context" + "fmt" + "time" + + "github.com/golang/protobuf/proto" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/flyteorg/flyte/cacheservice/pkg/errors" + "github.com/flyteorg/flyte/cacheservice/pkg/manager/impl/validators" + "github.com/flyteorg/flyte/cacheservice/pkg/manager/interfaces" + "github.com/flyteorg/flyte/cacheservice/repositories/models" + "github.com/flyteorg/flyte/cacheservice/repositories/transformers" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" + "github.com/flyteorg/flyte/flytestdlib/logger" + "github.com/flyteorg/flyte/flytestdlib/promutils" + "github.com/flyteorg/flyte/flytestdlib/promutils/labeled" +) + +type cacheMetrics struct { + scope promutils.Scope + putResponseTime labeled.StopWatch + updateResponseTime labeled.StopWatch + getResponseTime labeled.StopWatch + deleteResponseTime labeled.StopWatch + getReservationResponseTime labeled.StopWatch + releaseReservationResponseTime labeled.StopWatch + validationErrorCounter labeled.Counter + getFailureCounter labeled.Counter + getSuccessCounter labeled.Counter + putFailureCounter labeled.Counter + putSuccessCounter labeled.Counter + updateFailureCounter labeled.Counter + updateSuccessCounter labeled.Counter + deleteFailureCounter labeled.Counter + deleteSuccessCounter labeled.Counter + createDataFailureCounter labeled.Counter + createDataSuccessCounter labeled.Counter + getReservationFailureCounter labeled.Counter + getReservationSuccessCounter labeled.Counter + releaseReservationFailureCounter labeled.Counter + releaseReservationSuccessCounter labeled.Counter + notFoundCounter labeled.Counter + alreadyExistsCount labeled.Counter +} + +type cacheManager struct { + outputStore interfaces.CacheOutputBlobStore + dataStore interfaces.CacheDataStoreClient + reservationStore interfaces.ReservationDataStoreClient + systemMetrics cacheMetrics + maxInlineSizeBytes int64 + heartbeatGracePeriodMultiplier time.Duration + maxHeartbeatInterval time.Duration +} + +// Get retrieves the cached output for the given key. If the key is not found, a NotFound error is returned. +func (m *cacheManager) Get(ctx context.Context, request *cacheservice.GetCacheRequest) (*cacheservice.GetCacheResponse, error) { + timer := m.systemMetrics.getResponseTime.Start(ctx) + defer timer.Stop() + + err := validators.ValidateGetCacheRequest(request) + if err != nil { + logger.Warningf(ctx, "Invalid get cache request %v, err: %v", request, err) + m.systemMetrics.validationErrorCounter.Inc(ctx) + return nil, err + } + + outputModel, err := m.dataStore.Get(ctx, request.Key) + if err != nil { + if status.Code(err) == codes.NotFound { + logger.Debugf(ctx, "Key %v not found in data store", request.Key) + m.systemMetrics.notFoundCounter.Inc(ctx) + } else { + logger.Errorf(ctx, "Failed to get output in data store, err: %v", err) + m.systemMetrics.getFailureCounter.Inc(ctx) + } + return nil, err + } + + output, err := transformers.FromCachedOutputModel(ctx, outputModel) + if err != nil { + logger.Errorf(ctx, "Failed to transform output model to cached output, err: %v", err) + m.systemMetrics.getFailureCounter.Inc(ctx) + return nil, errors.NewCacheServiceErrorf(codes.Internal, "Failed to transform output model to cached output, err: %v", err) + } + + m.systemMetrics.getSuccessCounter.Inc(ctx) + return &cacheservice.GetCacheResponse{Output: output}, nil +} + +// Put stores the given output in the cache with the given key. If the key already exists and overwrite is false, an AlreadyExists error is returned. +func (m *cacheManager) Put(ctx context.Context, request *cacheservice.PutCacheRequest) (*cacheservice.PutCacheResponse, error) { + timer := m.systemMetrics.putResponseTime.Start(ctx) + defer timer.Stop() + + err := validators.ValidatePutCacheRequest(request) + if err != nil { + logger.Warningf(ctx, "Invalid put cache request %v, err: %v", request, err) + m.systemMetrics.validationErrorCounter.Inc(ctx) + return nil, err + } + + cachedOutputModel, err := transformers.CreateCachedOutputModel(ctx, request.Key, request.Output) + if err != nil { + logger.Errorf(ctx, "Failed to create cached output model, err: %v", err) + m.systemMetrics.putFailureCounter.Inc(ctx) + return nil, errors.NewCacheServiceErrorf(codes.Internal, "Failed to create cached output model, err: %v", err) + } + + cachedOutput, err := m.dataStore.Get(ctx, request.Key) + var notFound bool + if err != nil { + if status.Code(err) != codes.NotFound { + logger.Errorf(ctx, "Failed to check if output with key %v is already in data store, err: %v", request.Key, err) + return nil, err + } + notFound = true + } + if !notFound && cachedOutput != nil { + if !request.Overwrite { + m.systemMetrics.alreadyExistsCount.Inc(ctx) + logger.Errorf(ctx, "Output with key %v already exists", request.Key) + return nil, errors.NewCacheServiceErrorf(codes.AlreadyExists, "Output with key %v already exists", request.Key) + } + if cachedOutput.OutputURI != "" { + err = m.outputStore.Delete(ctx, cachedOutput.OutputURI) + if err != nil { + logger.Errorf(ctx, "Failed to delete output in blob store before overwriting, err: %v", err) + return nil, err + } + } + } + + switch output := request.Output.Output.(type) { + case *cacheservice.CachedOutput_OutputLiterals: + if m.maxInlineSizeBytes == 0 || int64(proto.Size(output.OutputLiterals)) > m.maxInlineSizeBytes { + dataLocation, err := m.outputStore.Create(ctx, request.GetKey(), output.OutputLiterals) + if err != nil { + logger.Errorf(ctx, "Failed to put output in blob store, err: %v", err) + m.systemMetrics.createDataFailureCounter.Inc(ctx) + return nil, err + } + cachedOutputModel.OutputLiteral = nil + cachedOutputModel.OutputURI = dataLocation + } + err := m.dataStore.Put(ctx, request.Key, cachedOutputModel) + if err != nil { + logger.Errorf(ctx, "Failed to put output in data store, err: %v", err) + m.systemMetrics.putFailureCounter.Inc(ctx) + return nil, err + } + case *cacheservice.CachedOutput_OutputUri: + err := m.dataStore.Put(ctx, request.Key, cachedOutputModel) + if err != nil { + logger.Errorf(ctx, "Failed to put output uri in data store, err: %v", err) + m.systemMetrics.putFailureCounter.Inc(ctx) + return nil, err + } + default: + m.systemMetrics.validationErrorCounter.Inc(ctx) + return nil, errors.NewCacheServiceErrorf(codes.InvalidArgument, "Invalid output type %v", output) + } + + m.systemMetrics.putSuccessCounter.Inc(ctx) + return &cacheservice.PutCacheResponse{}, nil +} + +func (m *cacheManager) Delete(ctx context.Context, request *cacheservice.DeleteCacheRequest) (*cacheservice.DeleteCacheResponse, error) { + timer := m.systemMetrics.deleteResponseTime.Start(ctx) + defer timer.Stop() + + return nil, errors.NewCacheServiceErrorf(codes.Unimplemented, "Delete endpoint not implemented") +} + +// GetOrExtendReservation retrieves the reservation for the given key. If the reservation does not exist, a new reservation is created. +// If the reservation exists and is held by a different owner and not expired, the reservation is not extended and the existing reservation is returned. +func (m *cacheManager) GetOrExtendReservation(ctx context.Context, request *cacheservice.GetOrExtendReservationRequest, now time.Time) (*cacheservice.GetOrExtendReservationResponse, error) { + timer := m.systemMetrics.getReservationResponseTime.Start(ctx) + defer timer.Stop() + + err := validators.ValidateGetOrExtendReservationRequest(request) + if err != nil { + logger.Warningf(ctx, "Invalid GetOrExtendReservation request %v, err: %v", request, err) + m.systemMetrics.validationErrorCounter.Inc(ctx) + return nil, err + } + + resKey := fmt.Sprintf("%s:%s", "reservation", request.Key) + + reservationModel, err := m.reservationStore.Get(ctx, resKey) + reservationExists := true + if err != nil { + if status.Code(err) == codes.NotFound { + reservationExists = false + } else { + logger.Errorf(ctx, "Failed to Get reservation in reservation store, err: %v", err) + m.systemMetrics.getReservationFailureCounter.Inc(ctx) + return nil, err + } + } + + heartbeatInterval := m.maxHeartbeatInterval + if request.GetHeartbeatInterval() != nil && request.GetHeartbeatInterval().AsDuration() < m.maxHeartbeatInterval { + heartbeatInterval = request.GetHeartbeatInterval().AsDuration() + } + + newReservation := &models.Reservation{ + Key: resKey, + OwnerID: request.OwnerId, + ExpiresAt: now.Add(heartbeatInterval * m.heartbeatGracePeriodMultiplier), + } + + var storeError error + if reservationExists { + if reservationModel.ExpiresAt.Before(now) || reservationModel.OwnerID == request.OwnerId { + storeError = m.reservationStore.Update(ctx, newReservation, now) + } else { + logger.Debugf(ctx, "Reservation: %+v is held by %s", reservationModel.Key, reservationModel.OwnerID) + reservation := transformers.FromReservationModel(ctx, reservationModel) + return &cacheservice.GetOrExtendReservationResponse{Reservation: reservation}, nil + } + } else { + storeError = m.reservationStore.Create(ctx, newReservation, now) + } + + if storeError != nil { + if status.Code(storeError) == codes.AlreadyExists { + logger.Debugf(ctx, "Reservation: %+v already exists", newReservation.Key) + newReservation, err = m.reservationStore.Get(ctx, resKey) + if err != nil { + logger.Errorf(ctx, "Failed to Get reservation in reservation store, err: %v", err) + m.systemMetrics.getReservationFailureCounter.Inc(ctx) + return nil, err + } + } else { + logger.Errorf(ctx, "Failed to Create/Update reservation in reservation store, err: %v", storeError) + m.systemMetrics.getReservationFailureCounter.Inc(ctx) + return nil, storeError + } + } + + reservation := transformers.FromReservationModel(ctx, newReservation) + m.systemMetrics.getReservationSuccessCounter.Inc(ctx) + return &cacheservice.GetOrExtendReservationResponse{Reservation: reservation}, nil +} + +// ReleaseReservation releases the reservation for the given key and owner. If the reservation does not exist return gracefully +func (m *cacheManager) ReleaseReservation(ctx context.Context, request *cacheservice.ReleaseReservationRequest) (*cacheservice.ReleaseReservationResponse, error) { + timer := m.systemMetrics.releaseReservationResponseTime.Start(ctx) + defer timer.Stop() + + err := validators.ValidateReleaseReservationRequest(request) + if err != nil { + logger.Warningf(ctx, "Invalid ReleaseReservation request %v, err: %v", request, err) + m.systemMetrics.validationErrorCounter.Inc(ctx) + return nil, err + } + + resKey := fmt.Sprintf("%s:%s", "reservation", request.Key) + + err = m.reservationStore.Delete(ctx, resKey, request.OwnerId) + if err != nil { + if status.Code(err) == codes.NotFound { + logger.Debugf(ctx, "Reservation with key %v and owner %v not found", request.Key, request.OwnerId) + m.systemMetrics.notFoundCounter.Inc(ctx) + return &cacheservice.ReleaseReservationResponse{}, nil + } + m.systemMetrics.releaseReservationFailureCounter.Inc(ctx) + logger.Errorf(ctx, "Failed to Release reservation in reservation store, err: %v", err) + return nil, err + } + + m.systemMetrics.releaseReservationSuccessCounter.Inc(ctx) + return &cacheservice.ReleaseReservationResponse{}, nil +} + +func NewCacheManager(outputStore interfaces.CacheOutputBlobStore, dataStore interfaces.CacheDataStoreClient, reservationStore interfaces.ReservationDataStoreClient, maxInlineSizeBytes int64, cacheScope promutils.Scope, + heartbeatGracePeriodMultiplier time.Duration, maxHeartbeatInterval time.Duration) interfaces.CacheManager { + cacheMetrics := cacheMetrics{ + scope: cacheScope, + putResponseTime: labeled.NewStopWatch("put_duration", "The duration of creating new cached outputs", time.Millisecond, cacheScope, labeled.EmitUnlabeledMetric), + updateResponseTime: labeled.NewStopWatch("update_duration", "The duration of updating cached outputs", time.Millisecond, cacheScope, labeled.EmitUnlabeledMetric), + getResponseTime: labeled.NewStopWatch("get_duration", "The duration of fetching cached outputs", time.Millisecond, cacheScope, labeled.EmitUnlabeledMetric), + deleteResponseTime: labeled.NewStopWatch("delete_duration", "The duration of deleting cached outputs", time.Millisecond, cacheScope, labeled.EmitUnlabeledMetric), + getReservationResponseTime: labeled.NewStopWatch("get_reservation_duration", "The duration of getting or extending reservations", time.Millisecond, cacheScope, labeled.EmitUnlabeledMetric), + releaseReservationResponseTime: labeled.NewStopWatch("release_reservation_duration", "The duration of releasing reservations", time.Millisecond, cacheScope, labeled.EmitUnlabeledMetric), + validationErrorCounter: labeled.NewCounter("validation_error", "The number of cache service validation errors.", cacheScope, labeled.EmitUnlabeledMetric), + getFailureCounter: labeled.NewCounter("get_failure", "The number of cache get failures.", cacheScope, labeled.EmitUnlabeledMetric), + getSuccessCounter: labeled.NewCounter("get_success", "The number of cache get successes.", cacheScope, labeled.EmitUnlabeledMetric), + putFailureCounter: labeled.NewCounter("put_failure", "The number of cache put failures.", cacheScope, labeled.EmitUnlabeledMetric), + putSuccessCounter: labeled.NewCounter("put_success", "The number of cache put successes.", cacheScope, labeled.EmitUnlabeledMetric), + updateFailureCounter: labeled.NewCounter("update_failure", "The number of cache update failures.", cacheScope, labeled.EmitUnlabeledMetric), + updateSuccessCounter: labeled.NewCounter("update_success", "The number of cache update successes.", cacheScope, labeled.EmitUnlabeledMetric), + deleteFailureCounter: labeled.NewCounter("delete_failure", "The number of cache delete failures.", cacheScope, labeled.EmitUnlabeledMetric), + deleteSuccessCounter: labeled.NewCounter("delete_success", "The number of cache delete successes.", cacheScope, labeled.EmitUnlabeledMetric), + createDataFailureCounter: labeled.NewCounter("create_data_failure", "The number of create blob data failures.", cacheScope, labeled.EmitUnlabeledMetric), + getReservationSuccessCounter: labeled.NewCounter("get_reservation_success", "The number of get reservation successes.", cacheScope, labeled.EmitUnlabeledMetric), + createDataSuccessCounter: labeled.NewCounter("create_data_success", "The number of create blob data successes.", cacheScope, labeled.EmitUnlabeledMetric), + getReservationFailureCounter: labeled.NewCounter("get_reservation_failure", "The number of get reservation failures.", cacheScope, labeled.EmitUnlabeledMetric), + releaseReservationSuccessCounter: labeled.NewCounter("release_reservation_success", "The number of release reservation successes.", cacheScope, labeled.EmitUnlabeledMetric), + releaseReservationFailureCounter: labeled.NewCounter("release_reservation_failure", "The number of release reservation failures.", cacheScope, labeled.EmitUnlabeledMetric), + notFoundCounter: labeled.NewCounter("not_found", "The number of cache keys not found.", cacheScope, labeled.EmitUnlabeledMetric), + alreadyExistsCount: labeled.NewCounter("already_exists", "The number of cache keys already exists.", cacheScope, labeled.EmitUnlabeledMetric), + } + + return &cacheManager{ + outputStore: outputStore, + dataStore: dataStore, + reservationStore: reservationStore, + systemMetrics: cacheMetrics, + maxInlineSizeBytes: maxInlineSizeBytes, + heartbeatGracePeriodMultiplier: heartbeatGracePeriodMultiplier, + maxHeartbeatInterval: maxHeartbeatInterval, + } +} diff --git a/cacheservice/pkg/manager/impl/cache_manager_test.go b/cacheservice/pkg/manager/impl/cache_manager_test.go new file mode 100644 index 0000000000..1ca6d6b5e7 --- /dev/null +++ b/cacheservice/pkg/manager/impl/cache_manager_test.go @@ -0,0 +1,707 @@ +package impl + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/durationpb" + + "github.com/flyteorg/flyte/cacheservice/pkg/errors" + "github.com/flyteorg/flyte/cacheservice/pkg/manager/interfaces" + "github.com/flyteorg/flyte/cacheservice/pkg/manager/mocks" + "github.com/flyteorg/flyte/cacheservice/repositories/models" + "github.com/flyteorg/flyte/flyteidl/clients/go/coreutils" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" + "github.com/flyteorg/flyte/flytestdlib/contextutils" + mockScope "github.com/flyteorg/flyte/flytestdlib/promutils" + "github.com/flyteorg/flyte/flytestdlib/promutils/labeled" +) + +var sampleKey = "key" + +func init() { + labeled.SetMetricKeys(contextutils.AppNameKey) +} + +func TestCacheManager_Get(t *testing.T) { + ctx := context.Background() + + sampleOutput := &models.CachedOutput{} + malformedOutput := &models.CachedOutput{ + SerializedMetadata: []byte("malformed"), + } + + getError := errors.NewCacheServiceError(codes.Internal, "get error") + notFoundError := errors.NewNotFoundError("output", sampleKey) + + testCases := []struct { + name string + mockOutputStore interfaces.CacheOutputBlobStore + mockRequest *cacheservice.GetCacheRequest + mockDataStoreReturn *models.CachedOutput + mockDataStoreError error + expectError bool + expectedErrorStatusCode codes.Code + }{ + { + name: "failed validation", + mockRequest: &cacheservice.GetCacheRequest{}, + expectError: true, + expectedErrorStatusCode: codes.InvalidArgument, + }, + { + name: "get error", + mockRequest: &cacheservice.GetCacheRequest{Key: sampleKey}, + mockDataStoreReturn: nil, + mockDataStoreError: getError, + expectError: true, + expectedErrorStatusCode: codes.Internal, + }, + { + name: "not found error", + mockRequest: &cacheservice.GetCacheRequest{Key: sampleKey}, + mockDataStoreReturn: nil, + mockDataStoreError: notFoundError, + expectError: true, + expectedErrorStatusCode: codes.NotFound, + }, + { + name: "malformed output", + mockRequest: &cacheservice.GetCacheRequest{Key: sampleKey}, + mockDataStoreReturn: malformedOutput, + mockDataStoreError: nil, + expectError: true, + expectedErrorStatusCode: codes.Internal, + }, + { + name: "success", + mockRequest: &cacheservice.GetCacheRequest{Key: sampleKey}, + mockDataStoreReturn: sampleOutput, + mockDataStoreError: nil, + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + mockDataStore := &mocks.CacheDataStoreClient{} + mockDataStore.OnGetMatch( + ctx, + mock.MatchedBy(func(o string) bool { + assert.EqualValues(t, sampleKey, o) + return true + })).Return(tc.mockDataStoreReturn, tc.mockDataStoreError) + + m := NewCacheManager(&mocks.CacheOutputBlobStore{}, mockDataStore, &mocks.ReservationDataStoreClient{}, 1024, mockScope.NewTestScope(), time.Duration(1), time.Duration(1)) + + response, err := m.Get(ctx, tc.mockRequest) + + if tc.expectError { + assert.Error(t, err) + assert.EqualValues(t, tc.expectedErrorStatusCode, status.Code(err)) + } else { + assert.NoError(t, err) + assert.NotNil(t, response) + } + }) + } +} + +func TestCacheManager_Put(t *testing.T) { + ctx := context.Background() + + notFoundError := errors.NewNotFoundError("output", sampleKey) + sampleOutputURI := "outputUri" + sampleOutputLiteral, err := coreutils.MakeLiteralMap(map[string]interface{}{"c": 3}) + assert.NoError(t, err) + + validSourceIdentifier := &core.Identifier{} + validMetadata := &cacheservice.Metadata{SourceIdentifier: validSourceIdentifier} + + matchKeyFunc := func(key string) bool { + return assert.EqualValues(t, sampleKey, key) + } + + testCases := []struct { + name string + mockRequest *cacheservice.PutCacheRequest + dataGetReturn *models.CachedOutput + dataGetError error + dataPutMatchOutputFunc func(*models.CachedOutput) bool + dataPutError error + outputCreateMatchOutputFunc func(*core.LiteralMap) bool + outputCreateReturn string + outputCreateError error + outputDeleteMatchOutputFunc func(string) bool + outputDeleteError error + maxSizeBytes int64 + expectError bool + expectOutputDelete bool + expectedErrorStatusCode codes.Code + }{ + { + name: "failed validation", + mockRequest: &cacheservice.PutCacheRequest{}, + expectError: true, + expectedErrorStatusCode: codes.InvalidArgument, + }, + { + name: "output URI, not found, success", + mockRequest: &cacheservice.PutCacheRequest{ + Key: sampleKey, + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputUri{ + OutputUri: sampleOutputURI, + }, + Metadata: validMetadata, + }, + Overwrite: false, + }, + dataGetReturn: nil, + dataGetError: notFoundError, + dataPutMatchOutputFunc: func(cachedOutput *models.CachedOutput) bool { + return assert.EqualValues(t, sampleOutputURI, cachedOutput.OutputURI) && assert.Nil(t, cachedOutput.OutputLiteral) + }, + dataPutError: nil, + expectError: false, + }, + { + name: "output URI, error", + mockRequest: &cacheservice.PutCacheRequest{ + Key: sampleKey, + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputUri{ + OutputUri: sampleOutputURI, + }, + Metadata: validMetadata, + }, + Overwrite: false, + }, + dataGetReturn: nil, + dataGetError: notFoundError, + dataPutMatchOutputFunc: func(cachedOutput *models.CachedOutput) bool { + return assert.EqualValues(t, sampleOutputURI, cachedOutput.OutputURI) && assert.Nil(t, cachedOutput.OutputLiteral) + }, + dataPutError: errors.NewCacheServiceErrorf(codes.Internal, "data put error"), + expectError: true, + expectedErrorStatusCode: codes.Internal, + }, + { + name: "output literals, inline, success", + mockRequest: &cacheservice.PutCacheRequest{ + Key: sampleKey, + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputLiterals{ + OutputLiterals: sampleOutputLiteral, + }, + Metadata: validMetadata, + }, + }, + dataGetReturn: nil, + dataGetError: notFoundError, + dataPutMatchOutputFunc: func(cachedOutput *models.CachedOutput) bool { + return assert.NotNil(t, cachedOutput.OutputLiteral) && assert.EqualValues(t, "", cachedOutput.OutputURI) + }, + dataPutError: nil, + maxSizeBytes: 1000000, + expectError: false, + }, + { + name: "output literals, inline, error", + mockRequest: &cacheservice.PutCacheRequest{ + Key: sampleKey, + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputLiterals{ + OutputLiterals: sampleOutputLiteral, + }, + Metadata: validMetadata, + }, + }, + dataGetReturn: nil, + dataGetError: notFoundError, + dataPutMatchOutputFunc: func(cachedOutput *models.CachedOutput) bool { + return assert.NotNil(t, cachedOutput.OutputLiteral) && assert.EqualValues(t, "", cachedOutput.OutputURI) + }, + dataPutError: errors.NewCacheServiceErrorf(codes.Internal, "data put error"), + maxSizeBytes: 1000000, + expectError: true, + expectedErrorStatusCode: codes.Internal, + }, + { + name: "output literals, offload, success ", + mockRequest: &cacheservice.PutCacheRequest{ + Key: sampleKey, + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputLiterals{ + OutputLiterals: sampleOutputLiteral, + }, + Metadata: validMetadata, + }, + }, + dataGetReturn: nil, + dataGetError: notFoundError, + dataPutMatchOutputFunc: func(cachedOutput *models.CachedOutput) bool { + return assert.EqualValues(t, sampleOutputURI, cachedOutput.OutputURI) && assert.Nil(t, cachedOutput.OutputLiteral) + }, + dataPutError: nil, + outputCreateMatchOutputFunc: func(outputLiteral *core.LiteralMap) bool { + return assert.EqualValues(t, sampleOutputLiteral, outputLiteral) + }, + outputCreateReturn: sampleOutputURI, + outputCreateError: nil, + maxSizeBytes: 1, + expectError: false, + }, + { + name: "output literals, offload, error", + mockRequest: &cacheservice.PutCacheRequest{ + Key: sampleKey, + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputLiterals{ + OutputLiterals: sampleOutputLiteral, + }, + Metadata: validMetadata, + }, + }, + dataGetReturn: nil, + dataGetError: notFoundError, + outputCreateMatchOutputFunc: func(outputLiteral *core.LiteralMap) bool { + return assert.EqualValues(t, sampleOutputLiteral, outputLiteral) + }, + outputCreateReturn: sampleOutputURI, + outputCreateError: errors.NewCacheServiceError(codes.Internal, "output create error"), + maxSizeBytes: 1, + expectError: true, + expectedErrorStatusCode: codes.Internal, + }, + { + name: "output exists, don't overwrite, error", + mockRequest: &cacheservice.PutCacheRequest{ + Key: sampleKey, + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputUri{ + OutputUri: sampleOutputURI, + }, + Metadata: validMetadata, + }, + Overwrite: false, + }, + dataGetReturn: &models.CachedOutput{}, + dataGetError: nil, + expectError: true, + expectedErrorStatusCode: codes.AlreadyExists, + }, + { + name: "output exists, overwrite, success", + mockRequest: &cacheservice.PutCacheRequest{ + Key: sampleKey, + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputUri{ + OutputUri: sampleOutputURI, + }, + Metadata: validMetadata, + }, + Overwrite: true, + }, + dataGetReturn: &models.CachedOutput{ + OutputURI: sampleOutputURI, + }, + dataGetError: nil, + dataPutMatchOutputFunc: func(cachedOutput *models.CachedOutput) bool { + return assert.EqualValues(t, sampleOutputURI, cachedOutput.OutputURI) && assert.Nil(t, cachedOutput.OutputLiteral) + }, + outputDeleteMatchOutputFunc: func(outputUri string) bool { + return assert.EqualValues(t, sampleOutputURI, outputUri) + }, + outputDeleteError: nil, + outputCreateError: nil, + dataPutError: nil, + expectError: false, + expectOutputDelete: true, + }, + { + name: "output exists, overwrite fails, error", + mockRequest: &cacheservice.PutCacheRequest{ + Key: sampleKey, + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputUri{ + OutputUri: sampleOutputURI, + }, + Metadata: validMetadata, + }, + Overwrite: true, + }, + dataGetReturn: &models.CachedOutput{ + OutputURI: sampleOutputURI, + }, + dataGetError: nil, + dataPutMatchOutputFunc: func(cachedOutput *models.CachedOutput) bool { + return assert.EqualValues(t, sampleOutputURI, cachedOutput.OutputURI) && assert.Nil(t, cachedOutput.OutputLiteral) + }, + outputDeleteMatchOutputFunc: func(outputUri string) bool { + return assert.EqualValues(t, sampleOutputURI, outputUri) + }, + outputDeleteError: errors.NewCacheServiceErrorf(codes.Internal, "output delete error"), + expectError: true, + expectOutputDelete: true, + expectedErrorStatusCode: codes.Internal, + }, + { + name: "get error, error", + mockRequest: &cacheservice.PutCacheRequest{ + Key: sampleKey, + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputUri{ + OutputUri: sampleOutputURI, + }, + Metadata: validMetadata, + }, + Overwrite: false, + }, + dataGetReturn: nil, + dataGetError: errors.NewCacheServiceError(codes.Internal, "get output error"), + expectError: true, + expectedErrorStatusCode: codes.Internal, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + mockDataStore := &mocks.CacheDataStoreClient{} + mockDataStore.OnGetMatch( + ctx, + mock.MatchedBy(matchKeyFunc), + ).Return(tc.dataGetReturn, tc.dataGetError) + mockDataStore.OnPutMatch( + ctx, + mock.MatchedBy(matchKeyFunc), + mock.MatchedBy(tc.dataPutMatchOutputFunc), + ).Return(tc.dataPutError) + + mockOutputStore := &mocks.CacheOutputBlobStore{} + mockOutputStore.OnCreateMatch( + ctx, + mock.MatchedBy(matchKeyFunc), + mock.MatchedBy(tc.outputCreateMatchOutputFunc), + ).Return(tc.outputCreateReturn, tc.outputCreateError) + mockOutputStore.OnDeleteMatch( + ctx, + mock.MatchedBy(tc.outputDeleteMatchOutputFunc), + ).Return(tc.outputDeleteError) + + m := NewCacheManager(mockOutputStore, mockDataStore, &mocks.ReservationDataStoreClient{}, tc.maxSizeBytes, mockScope.NewTestScope(), time.Duration(1), time.Duration(1)) + + _, err := m.Put(ctx, tc.mockRequest) + + if tc.expectError { + assert.Error(t, err) + assert.EqualValues(t, tc.expectedErrorStatusCode, status.Code(err)) + } else { + assert.NoError(t, err) + } + + if tc.expectOutputDelete { + mockOutputStore.AssertCalled(t, "Delete", mock.Anything, mock.Anything) + } + }) + } +} + +func TestCacheManager_GetOrExtendReservation(t *testing.T) { + ctx := context.Background() + + heartbeatGracePeriodMultiplier := time.Duration(3) + maxHeartBeatInterval := durationpb.New(2 * time.Second).AsDuration() + + sampleOwner := "owner" + sampleOwner1 := "owner1" + sampleHeartBeatInterval := durationpb.New(1 * time.Second) + + now := time.Date(2024, time.January, 1, 0, 0, 0, 0, time.UTC) + + testCases := []struct { + name string + mockRequest *cacheservice.GetOrExtendReservationRequest + expectError bool + expectedErrorStatusCode codes.Code + deleteError error + getReturn *models.Reservation + getError error + getReturn1 *models.Reservation + getError1 error + createError error + updateError error + expectCreateCalled bool + expectUpdateCalled bool + expectedExpiresAtCall time.Time + }{ + { + name: "failed validation", + mockRequest: &cacheservice.GetOrExtendReservationRequest{}, + expectError: true, + expectedErrorStatusCode: codes.InvalidArgument, + }, + { + name: "no existing reservation, create", + mockRequest: &cacheservice.GetOrExtendReservationRequest{ + Key: sampleKey, + OwnerId: sampleOwner, + HeartbeatInterval: sampleHeartBeatInterval, + }, + getReturn: nil, + getError: errors.NewNotFoundError("reservation", sampleKey), + createError: nil, + expectError: false, + expectCreateCalled: true, + expectedExpiresAtCall: now.Add(sampleHeartBeatInterval.AsDuration() * heartbeatGracePeriodMultiplier), + }, + { + name: "exceeds max heartbeat interval", + mockRequest: &cacheservice.GetOrExtendReservationRequest{ + Key: sampleKey, + OwnerId: sampleOwner, + HeartbeatInterval: durationpb.New(maxHeartBeatInterval * 10), + }, + getReturn: nil, + getError: errors.NewNotFoundError("reservation", sampleKey), + createError: nil, + expectError: false, + expectCreateCalled: true, + expectedExpiresAtCall: now.Add(maxHeartBeatInterval * heartbeatGracePeriodMultiplier), + }, + { + name: "create fails - error", + mockRequest: &cacheservice.GetOrExtendReservationRequest{ + Key: sampleKey, + OwnerId: sampleOwner, + HeartbeatInterval: sampleHeartBeatInterval, + }, + getReturn: nil, + getError: errors.NewNotFoundError("reservation", sampleKey), + createError: errors.NewCacheServiceErrorf(codes.Internal, "create error"), + expectError: true, + expectedErrorStatusCode: codes.Internal, + expectCreateCalled: true, + expectedExpiresAtCall: now.Add(sampleHeartBeatInterval.AsDuration() * heartbeatGracePeriodMultiplier), + }, + { + name: "create fails - already exists", + mockRequest: &cacheservice.GetOrExtendReservationRequest{ + Key: sampleKey, + OwnerId: sampleOwner, + HeartbeatInterval: sampleHeartBeatInterval, + }, + getReturn: nil, + getError: errors.NewNotFoundError("reservation", sampleKey), + getReturn1: &models.Reservation{ + Key: sampleKey, + OwnerID: sampleOwner1, + ExpiresAt: now.Add(time.Hour), + }, + getError1: nil, + createError: errors.NewCacheServiceErrorf(codes.AlreadyExists, "create error"), + expectError: false, + expectCreateCalled: true, + expectedExpiresAtCall: now.Add(sampleHeartBeatInterval.AsDuration() * heartbeatGracePeriodMultiplier), + }, + { + name: "expired reservation, update", + mockRequest: &cacheservice.GetOrExtendReservationRequest{ + Key: sampleKey, + OwnerId: sampleOwner, + HeartbeatInterval: sampleHeartBeatInterval, + }, + getReturn: &models.Reservation{ + Key: sampleKey, + OwnerID: sampleOwner1, + ExpiresAt: now.Add(-time.Hour), + }, + getError: nil, + updateError: nil, + expectError: false, + expectUpdateCalled: true, + expectedExpiresAtCall: now.Add(sampleHeartBeatInterval.AsDuration() * heartbeatGracePeriodMultiplier), + }, + { + name: "active reservation with same owner, update", + mockRequest: &cacheservice.GetOrExtendReservationRequest{ + Key: sampleKey, + OwnerId: sampleOwner, + HeartbeatInterval: sampleHeartBeatInterval, + }, + getReturn: &models.Reservation{ + Key: sampleKey, + OwnerID: sampleOwner, + ExpiresAt: now.Add(time.Hour), + }, + getError: nil, + updateError: nil, + expectError: false, + expectUpdateCalled: true, + expectedExpiresAtCall: now.Add(sampleHeartBeatInterval.AsDuration() * heartbeatGracePeriodMultiplier), + }, + { + name: "active reservation, different owner", + mockRequest: &cacheservice.GetOrExtendReservationRequest{ + Key: sampleKey, + OwnerId: sampleOwner, + HeartbeatInterval: sampleHeartBeatInterval, + }, + getReturn: &models.Reservation{ + Key: sampleKey, + OwnerID: sampleOwner1, + ExpiresAt: now.Add(time.Hour), + }, + getError: nil, + updateError: nil, + expectError: false, + expectUpdateCalled: false, + expectCreateCalled: false, + expectedExpiresAtCall: now.Add(sampleHeartBeatInterval.AsDuration() * heartbeatGracePeriodMultiplier), + }, + } + + for _, tc := range testCases { + requestKey := fmt.Sprintf("%s:%s", "reservation", tc.mockRequest.Key) + t.Run(tc.name, func(t *testing.T) { + mockReservationStoreClient := &mocks.ReservationDataStoreClient{} + mockReservationStoreClient.OnGetMatch( + ctx, + mock.MatchedBy(func(o string) bool { + assert.Equal(t, requestKey, o) + return true + })).Return(tc.getReturn, tc.getError).Once() + mockReservationStoreClient.OnGetMatch( + ctx, + mock.MatchedBy(func(o string) bool { + assert.Equal(t, requestKey, o) + return true + })).Return(tc.getReturn1, tc.getError1) + mockReservationStoreClient.OnCreateMatch( + ctx, + mock.MatchedBy(func(reservation *models.Reservation) bool { + assert.Equal(t, requestKey, reservation.Key) + assert.Equal(t, tc.expectedExpiresAtCall, reservation.ExpiresAt) + return true + }), + mock.Anything, + ).Return(tc.createError) + mockReservationStoreClient.OnUpdateMatch( + ctx, + mock.MatchedBy(func(reservation *models.Reservation) bool { + assert.Equal(t, requestKey, reservation.Key) + assert.Equal(t, tc.expectedExpiresAtCall, reservation.ExpiresAt) + return true + }), + mock.Anything, + ).Return(tc.updateError) + + m := NewCacheManager(&mocks.CacheOutputBlobStore{}, &mocks.CacheDataStoreClient{}, mockReservationStoreClient, 0, mockScope.NewTestScope(), heartbeatGracePeriodMultiplier, maxHeartBeatInterval) + + reservation, err := m.GetOrExtendReservation(ctx, tc.mockRequest, now) + if tc.expectError { + assert.Error(t, err) + assert.EqualValues(t, tc.expectedErrorStatusCode, status.Code(err)) + } else { + assert.NoError(t, err) + assert.NotNil(t, reservation) + } + + if tc.expectCreateCalled { + mockReservationStoreClient.AssertCalled(t, "Create", mock.Anything, mock.Anything, mock.Anything) + } else { + mockReservationStoreClient.AssertNotCalled(t, "Create", mock.Anything, mock.Anything, mock.Anything) + } + + if tc.expectUpdateCalled { + mockReservationStoreClient.AssertCalled(t, "Update", mock.Anything, mock.Anything, mock.Anything) + } else { + mockReservationStoreClient.AssertNotCalled(t, "Update", mock.Anything, mock.Anything, mock.Anything) + } + }) + } +} + +func TestCacheManager_ReleaseReservation(t *testing.T) { + ctx := context.Background() + + sampleOwner := "owner" + + testCases := []struct { + name string + mockRequest *cacheservice.ReleaseReservationRequest + expectError bool + expectedErrorStatusCode codes.Code + deleteError error + }{ + { + name: "failed validation", + mockRequest: &cacheservice.ReleaseReservationRequest{}, + expectError: true, + expectedErrorStatusCode: codes.InvalidArgument, + }, + { + name: "success", + mockRequest: &cacheservice.ReleaseReservationRequest{ + Key: sampleKey, + OwnerId: sampleOwner, + }, + deleteError: nil, + expectError: false, + }, + { + name: "not found, success", + mockRequest: &cacheservice.ReleaseReservationRequest{ + Key: sampleKey, + OwnerId: sampleOwner, + }, + deleteError: errors.NewNotFoundError("reservation", sampleKey), + expectError: false, + }, + { + name: "delete error, error", + mockRequest: &cacheservice.ReleaseReservationRequest{ + Key: sampleKey, + OwnerId: sampleOwner, + }, + deleteError: errors.NewCacheServiceErrorf(codes.Internal, "delete error"), + expectError: true, + expectedErrorStatusCode: codes.Internal, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + requestKey := fmt.Sprintf("%s:%s", "reservation", tc.mockRequest.Key) + + mockReservationStoreClient := &mocks.ReservationDataStoreClient{} + mockReservationStoreClient.OnDeleteMatch( + ctx, + mock.MatchedBy(func(key string) bool { + assert.Equal(t, requestKey, key) + return true + }), mock.MatchedBy(func(ownerId string) bool { + assert.Equal(t, sampleOwner, ownerId) + return true + }), + ).Return(tc.deleteError) + + m := NewCacheManager(&mocks.CacheOutputBlobStore{}, &mocks.CacheDataStoreClient{}, mockReservationStoreClient, 0, mockScope.NewTestScope(), time.Duration(1), time.Duration(1)) + + reservation, err := m.ReleaseReservation(ctx, tc.mockRequest) + if tc.expectError { + assert.Error(t, err) + assert.EqualValues(t, tc.expectedErrorStatusCode, status.Code(err)) + } else { + assert.NoError(t, err) + assert.NotNil(t, reservation) + } + }) + } +} diff --git a/cacheservice/pkg/manager/impl/cache_output_blob_store.go b/cacheservice/pkg/manager/impl/cache_output_blob_store.go new file mode 100644 index 0000000000..ab514ed725 --- /dev/null +++ b/cacheservice/pkg/manager/impl/cache_output_blob_store.go @@ -0,0 +1,53 @@ +package impl + +import ( + "context" + + "google.golang.org/grpc/codes" + + "github.com/flyteorg/flyte/cacheservice/pkg/errors" + "github.com/flyteorg/flyte/cacheservice/pkg/manager/interfaces" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" + "github.com/flyteorg/flyte/flytestdlib/storage" +) + +var ( + _ interfaces.CacheOutputBlobStore = &cacheOutputBlobStore{} +) + +type cacheOutputBlobStore struct { + store *storage.DataStore + storagePrefix storage.DataReference +} + +func (m *cacheOutputBlobStore) Create(ctx context.Context, key string, output *core.LiteralMap) (string, error) { + reference, err := m.store.ConstructReference(ctx, m.storagePrefix, key) + if err != nil { + return "", errors.NewCacheServiceErrorf(codes.Internal, "Unable to construct reference for key %s, err %v", key, err) + } + + err = m.store.WriteProtobuf(ctx, reference, storage.Options{}, output) + if err != nil { + return "", errors.NewCacheServiceErrorf(codes.Internal, "Unable to store cache data in location %s, err %v", reference.String(), err) + } + return reference.String(), nil +} + +func (m *cacheOutputBlobStore) Delete(ctx context.Context, uri string) error { + reference, err := m.store.ConstructReference(ctx, m.storagePrefix, uri) + if err != nil { + return errors.NewCacheServiceErrorf(codes.Internal, "Unable to construct reference for uri %s, err %v", uri, err) + } + err = m.store.Delete(ctx, reference) + if err != nil { + return errors.NewCacheServiceErrorf(codes.Internal, "Unable to store delete data in location %s, err %v", reference.String(), err) + } + return nil +} + +func NewCacheOutputStore(store *storage.DataStore, storagePrefix storage.DataReference) interfaces.CacheOutputBlobStore { + return &cacheOutputBlobStore{ + store: store, + storagePrefix: storagePrefix, + } +} diff --git a/cacheservice/pkg/manager/impl/cache_output_blob_store_test.go b/cacheservice/pkg/manager/impl/cache_output_blob_store_test.go new file mode 100644 index 0000000000..4f9d22e382 --- /dev/null +++ b/cacheservice/pkg/manager/impl/cache_output_blob_store_test.go @@ -0,0 +1 @@ +package impl diff --git a/cacheservice/pkg/manager/impl/reservation_store.go b/cacheservice/pkg/manager/impl/reservation_store.go new file mode 100644 index 0000000000..57c6eadd99 --- /dev/null +++ b/cacheservice/pkg/manager/impl/reservation_store.go @@ -0,0 +1,161 @@ +package impl + +import ( + "context" + "encoding/json" + "time" + + "github.com/go-redis/redis/v8" + "google.golang.org/grpc/codes" + + "github.com/flyteorg/flyte/cacheservice/pkg/errors" + "github.com/flyteorg/flyte/cacheservice/pkg/manager/interfaces" + "github.com/flyteorg/flyte/cacheservice/pkg/runtime/configs" + "github.com/flyteorg/flyte/cacheservice/repositories/models" +) + +var ( + _ interfaces.ReservationDataStoreClient = &reservationMemClient{} +) + +type reservationMemClient struct { + keyValStore *map[string]*models.Reservation +} + +func (r reservationMemClient) Create(ctx context.Context, reservation *models.Reservation, now time.Time) error { + reservationStore := *r.keyValStore + if _, exists := reservationStore[reservation.Key]; exists { + return errors.NewCacheServiceErrorf(codes.AlreadyExists, "reservation with key %s already exists", reservation.Key) + } + reservationStore[reservation.Key] = reservation + return nil +} + +func (r reservationMemClient) Update(ctx context.Context, reservation *models.Reservation, now time.Time) error { + reservationStore := *r.keyValStore + reservationStore[reservation.Key] = reservation + return nil +} + +func (r reservationMemClient) Get(ctx context.Context, key string) (*models.Reservation, error) { + reservationStore := *r.keyValStore + if value, exists := reservationStore[key]; exists { + return value, nil + } + + return nil, errors.NewNotFoundError("reservation", key) +} + +func (r reservationMemClient) Delete(ctx context.Context, key string, ownerID string) error { + reservationStore := *r.keyValStore + delete(reservationStore, key) + return nil +} + +var ( + _ interfaces.ReservationDataStoreClient = &reservationRedisClient{} +) + +type reservationRedisClient struct { + RedisClient *redis.Client +} + +// Create a new reservation in the data store. If the reservation already exists, return an error. +func (r *reservationRedisClient) Create(ctx context.Context, reservation *models.Reservation, now time.Time) error { + ttl := reservation.ExpiresAt.Sub(now) + + marshaledReservation, err := json.Marshal(reservation) + if err != nil { + return errors.NewCacheServiceErrorf(codes.Internal, "Failed to marshal reservation with error: %v", err) + } + + setCmd := r.RedisClient.SetNX(ctx, reservation.Key, marshaledReservation, ttl) + if err := setCmd.Err(); err != nil { + return errors.NewCacheServiceErrorf(codes.Internal, "Failed to set reservation with key %s due to error: %v", reservation.Key, err) + } + + wasSet, err := setCmd.Result() + if err != nil { + return errors.NewCacheServiceErrorf(codes.Internal, "Failed to confirm setting of reservation with key %s", reservation.Key) + } + if !wasSet { + return errors.NewCacheServiceErrorf(codes.AlreadyExists, "Reservation with key %s already exists", reservation.Key) + } + + return nil +} + +// Update acts as an upsert operation. Since we already check in cache_manager for collision handling, we reduce the +// number of calls to Redis by upsert-ing as opposed to inserting +func (r *reservationRedisClient) Update(ctx context.Context, reservation *models.Reservation, now time.Time) error { + ttl := reservation.ExpiresAt.Sub(now) + + marshaledReservation, err := json.Marshal(reservation) + if err != nil { + return errors.NewCacheServiceErrorf(codes.Internal, "Failed to marshal reservation with error: %v", err) + } + + _, err = r.RedisClient.Set(ctx, reservation.Key, marshaledReservation, ttl).Result() + if err != nil { + return errors.NewCacheServiceErrorf(codes.Internal, "Failed to upsert reservation with key %s: %v", reservation.Key, err) + } + + return nil +} + +// Get a reservation from the data store. If the reservation does not exist, return an error. +func (r *reservationRedisClient) Get(ctx context.Context, key string) (*models.Reservation, error) { + val, err := r.RedisClient.Get(ctx, key).Result() + if err == redis.Nil { + return nil, errors.NewNotFoundError("reservation", key) + } else if err != nil { + return nil, errors.NewCacheServiceErrorf(codes.Internal, "Failed to get reservation with key %s", key) + } + + var reservation models.Reservation + err = json.Unmarshal([]byte(val), &reservation) + if err != nil { + return nil, errors.NewCacheServiceErrorf(codes.Internal, "Failed to unmarshal reservation with error %v", err) + } + + return &reservation, nil +} + +// Delete a reservation from the data store. +func (r *reservationRedisClient) Delete(ctx context.Context, key string, ownerID string) error { + _, err := r.RedisClient.Del(ctx, key).Result() + if err != nil { + return errors.NewCacheServiceErrorf(codes.Internal, "Failed deleting redis key %v with error %v", key, err) + } + return nil +} + +func NewReservationDataStore(ctx context.Context, serviceConfig configs.CacheServiceConfig) interfaces.ReservationDataStoreClient { + clientType := serviceConfig.ReservationDataStoreType + + switch clientType { + case configs.Mem: + keyValStore := make(map[string]*models.Reservation) + return &reservationMemClient{keyValStore: &keyValStore} + case configs.DynamoDB: + panic("dynamodb not supported for reservation data store") + case configs.Redis: + rdb := redis.NewClient( + &redis.Options{ + Addr: serviceConfig.RedisAddress, + Username: serviceConfig.RedisUsername, + Password: serviceConfig.RedisPassword, + }) + + _, err := rdb.Ping(ctx).Result() + if err != nil { + panic("failed to connect to redis " + err.Error()) + } + + return &reservationRedisClient{ + RedisClient: rdb, + } + } + + panic("unsupported reservation data store type") +} diff --git a/cacheservice/pkg/manager/impl/reservation_store_test.go b/cacheservice/pkg/manager/impl/reservation_store_test.go new file mode 100644 index 0000000000..4f9d22e382 --- /dev/null +++ b/cacheservice/pkg/manager/impl/reservation_store_test.go @@ -0,0 +1 @@ +package impl diff --git a/cacheservice/pkg/manager/impl/validators/cache_validator.go b/cacheservice/pkg/manager/impl/validators/cache_validator.go new file mode 100644 index 0000000000..0cb1f0c33c --- /dev/null +++ b/cacheservice/pkg/manager/impl/validators/cache_validator.go @@ -0,0 +1,146 @@ +package validators + +import ( + "github.com/flyteorg/flyte/cacheservice/pkg/errors" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" +) + +func validateCacheKey(key string) error { + if key == "" { + return errors.NewMissingArgumentError("key") + } + + return nil +} + +func validateOutputURI(outputURI string) error { + if outputURI == "" { + return errors.NewMissingArgumentError("output_uri") + } + + return nil +} + +func validateOutputLiteral(literal *core.LiteralMap) error { + if literal == nil { + return errors.NewMissingArgumentError("literal") + } + + return nil +} + +func validateOutputMetadata(metadata *cacheservice.Metadata) error { + if metadata.GetSourceIdentifier() == nil { + return errors.NewMissingArgumentError("source_identifier") + } + + return nil +} + +func validateOutput(cachedOutput *cacheservice.CachedOutput) error { + if cachedOutput == nil { + return errors.NewMissingArgumentError("output") + } + + if cachedOutput.Output == nil { + return errors.NewInvalidArgumentError("output", "") + } + + err := validateOutputMetadata(cachedOutput.Metadata) + if err != nil { + return err + } + + switch output := cachedOutput.Output.(type) { + case *cacheservice.CachedOutput_OutputLiterals: + err = validateOutputLiteral(output.OutputLiterals) + if err != nil { + return err + } + case *cacheservice.CachedOutput_OutputUri: + err = validateOutputURI(output.OutputUri) + if err != nil { + return err + } + default: + return errors.NewInvalidArgumentError("output", "unknown type") + } + + return nil +} + +func validateOwnerID(ownerID string) error { + if ownerID == "" { + return errors.NewMissingArgumentError("owner_id") + } + + return nil +} + +func ValidatePutCacheRequest(request *cacheservice.PutCacheRequest) error { + if request == nil { + return errors.NewMissingArgumentError("request") + } + + err := validateCacheKey(request.Key) + if err != nil { + return err + } + + err = validateOutput(request.Output) + if err != nil { + return err + } + + return nil +} + +func ValidateGetCacheRequest(request *cacheservice.GetCacheRequest) error { + if request == nil { + return errors.NewMissingArgumentError("request") + } + + err := validateCacheKey(request.Key) + if err != nil { + return err + } + + return nil +} + +func ValidateGetOrExtendReservationRequest(request *cacheservice.GetOrExtendReservationRequest) error { + if request == nil { + return errors.NewMissingArgumentError("request") + } + + err := validateCacheKey(request.Key) + if err != nil { + return err + } + + err = validateOwnerID(request.OwnerId) + if err != nil { + return err + } + + return nil +} + +func ValidateReleaseReservationRequest(request *cacheservice.ReleaseReservationRequest) error { + if request == nil { + return errors.NewMissingArgumentError("request") + } + + err := validateCacheKey(request.Key) + if err != nil { + return err + } + + err = validateOwnerID(request.OwnerId) + if err != nil { + return err + } + + return nil +} diff --git a/cacheservice/pkg/manager/impl/validators/cache_validator_test.go b/cacheservice/pkg/manager/impl/validators/cache_validator_test.go new file mode 100644 index 0000000000..166cf33cdb --- /dev/null +++ b/cacheservice/pkg/manager/impl/validators/cache_validator_test.go @@ -0,0 +1,399 @@ +package validators + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" +) + +var validKey = "key" + +func TestValidateCacheKey(t *testing.T) { + testCases := []struct { + name string + key string + expectError bool + }{ + { + name: "empty key", + key: "", + expectError: true, + }, + { + name: "valid key", + key: "key", + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := validateCacheKey(tc.key) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestValidateOutputUri(t *testing.T) { + testCases := []struct { + name string + outputURI string + expectError bool + }{ + { + name: "empty output uri", + outputURI: "", + expectError: true, + }, + { + name: "valid output uri", + outputURI: "uri", + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := validateOutputURI(tc.outputURI) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestValidateOutputLiteral(t *testing.T) { + testCases := []struct { + name string + literal *core.LiteralMap + expectError bool + }{ + { + name: "nil literal", + literal: nil, + expectError: true, + }, + { + name: "valid literal", + literal: &core.LiteralMap{}, + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := validateOutputLiteral(tc.literal) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestValidateOutputMeta(t *testing.T) { + testCases := []struct { + name string + metadata *cacheservice.Metadata + expectError bool + }{ + { + name: "nil metadata", + metadata: nil, + expectError: true, + }, + { + name: "nil source identifier", + metadata: &cacheservice.Metadata{}, + expectError: true, + }, + { + name: "valid metadata", + metadata: &cacheservice.Metadata{SourceIdentifier: &core.Identifier{}}, + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := validateOutputMetadata(tc.metadata) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestValidateOutput(t *testing.T) { + validSourceIdentifier := &core.Identifier{} + validMetadata := &cacheservice.Metadata{SourceIdentifier: validSourceIdentifier} + validOutput := &cacheservice.CachedOutput_OutputUri{OutputUri: "uri"} + + testCases := []struct { + name string + output *cacheservice.CachedOutput + expectError bool + }{ + { + name: "nil output", + output: nil, + expectError: true, + }, + { + name: "nil output field", + output: &cacheservice.CachedOutput{}, + expectError: true, + }, + { + name: "invalid metadata", + output: &cacheservice.CachedOutput{Output: &cacheservice.CachedOutput_OutputUri{OutputUri: "uri"}, Metadata: &cacheservice.Metadata{}}, + expectError: true, + }, + { + name: "invalid output uri", + output: &cacheservice.CachedOutput{Output: &cacheservice.CachedOutput_OutputUri{OutputUri: ""}, Metadata: validMetadata}, + expectError: true, + }, + { + name: "invalid output literal", + output: &cacheservice.CachedOutput{Output: &cacheservice.CachedOutput_OutputLiterals{OutputLiterals: nil}, Metadata: validMetadata}, + expectError: true, + }, + { + name: "valid output", + output: &cacheservice.CachedOutput{Output: validOutput, Metadata: validMetadata}, + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := validateOutput(tc.output) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestValidateOwnerID(t *testing.T) { + testCases := []struct { + name string + OwnerID string + expectError bool + }{ + { + name: "empty owner id", + OwnerID: "", + expectError: true, + }, + { + name: "valid owner id", + OwnerID: "owner", + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := validateOwnerID(tc.OwnerID) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestValidatePutCacheRequest(t *testing.T) { + validSourceIdentifier := &core.Identifier{} + validMetadata := &cacheservice.Metadata{SourceIdentifier: validSourceIdentifier} + validOutput := &cacheservice.CachedOutput_OutputUri{OutputUri: "uri"} + + invalidKey := "" + + testCases := []struct { + name string + req *cacheservice.PutCacheRequest + expectError bool + }{ + { + name: "nil request", + req: nil, + expectError: true, + }, + { + name: "nil output", + req: &cacheservice.PutCacheRequest{}, + expectError: true, + }, + { + name: "invalid key", + req: &cacheservice.PutCacheRequest{Key: invalidKey, Output: &cacheservice.CachedOutput{}}, + expectError: true, + }, + { + name: "invalid output", + req: &cacheservice.PutCacheRequest{Key: validKey, Output: &cacheservice.CachedOutput{}}, + expectError: true, + }, + { + name: "valid request", + req: &cacheservice.PutCacheRequest{Key: validKey, Output: &cacheservice.CachedOutput{Output: validOutput, Metadata: validMetadata}}, + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := ValidatePutCacheRequest(tc.req) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestValidateGetCacheRequest(t *testing.T) { + invalidKey := "" + + testCases := []struct { + name string + req *cacheservice.GetCacheRequest + expectError bool + }{ + { + name: "nil request", + req: nil, + expectError: true, + }, + { + name: "invalid key", + req: &cacheservice.GetCacheRequest{Key: invalidKey}, + expectError: true, + }, + { + name: "valid request", + req: &cacheservice.GetCacheRequest{Key: validKey}, + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := ValidateGetCacheRequest(tc.req) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestGetOrExtendReservationRequest(t *testing.T) { + invalidKey := "" + + validOwnerID := "owner" + invalidOwnerID := "" + + testCases := []struct { + name string + req *cacheservice.GetOrExtendReservationRequest + expectError bool + }{ + { + name: "nil request", + req: nil, + expectError: true, + }, + { + name: "invalid key", + req: &cacheservice.GetOrExtendReservationRequest{Key: invalidKey}, + expectError: true, + }, + { + name: "invalid owner id", + req: &cacheservice.GetOrExtendReservationRequest{Key: validKey, OwnerId: invalidOwnerID}, + expectError: true, + }, + { + name: "valid request", + req: &cacheservice.GetOrExtendReservationRequest{Key: validKey, OwnerId: validOwnerID}, + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := ValidateGetOrExtendReservationRequest(tc.req) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestReleaseReservationRequest(t *testing.T) { + invalidKey := "" + + validOwnerID := "owner" + invalidOwnerID := "" + + testCases := []struct { + name string + req *cacheservice.ReleaseReservationRequest + expectError bool + }{ + { + name: "nil request", + req: nil, + expectError: true, + }, + { + name: "invalid key", + req: &cacheservice.ReleaseReservationRequest{Key: invalidKey}, + expectError: true, + }, + { + name: "invalid owner id", + req: &cacheservice.ReleaseReservationRequest{Key: validKey, OwnerId: invalidOwnerID}, + expectError: true, + }, + { + name: "valid request", + req: &cacheservice.ReleaseReservationRequest{Key: validKey, OwnerId: validOwnerID}, + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := ValidateReleaseReservationRequest(tc.req) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/cacheservice/pkg/manager/interfaces/cache.go b/cacheservice/pkg/manager/interfaces/cache.go new file mode 100644 index 0000000000..28d275d15e --- /dev/null +++ b/cacheservice/pkg/manager/interfaces/cache.go @@ -0,0 +1,38 @@ +package interfaces + +import ( + "context" + "time" + + "github.com/flyteorg/flyte/cacheservice/repositories/models" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" +) + +//go:generate mockery -all -output=../mocks -case=underscore + +type CacheManager interface { + Get(ctx context.Context, request *cacheservice.GetCacheRequest) (*cacheservice.GetCacheResponse, error) + Put(ctx context.Context, request *cacheservice.PutCacheRequest) (*cacheservice.PutCacheResponse, error) + Delete(ctx context.Context, request *cacheservice.DeleteCacheRequest) (*cacheservice.DeleteCacheResponse, error) + GetOrExtendReservation(ctx context.Context, request *cacheservice.GetOrExtendReservationRequest, now time.Time) (*cacheservice.GetOrExtendReservationResponse, error) + ReleaseReservation(ctx context.Context, request *cacheservice.ReleaseReservationRequest) (*cacheservice.ReleaseReservationResponse, error) +} + +type CacheOutputBlobStore interface { + Create(ctx context.Context, key string, output *core.LiteralMap) (string, error) + Delete(ctx context.Context, uri string) error +} + +type CacheDataStoreClient interface { + Get(ctx context.Context, key string) (*models.CachedOutput, error) + Put(ctx context.Context, key string, cachedOutput *models.CachedOutput) error + Delete(ctx context.Context, key string) error +} + +type ReservationDataStoreClient interface { + Create(ctx context.Context, reservation *models.Reservation, now time.Time) error + Update(ctx context.Context, reservation *models.Reservation, now time.Time) error + Get(ctx context.Context, key string) (*models.Reservation, error) + Delete(ctx context.Context, key string, ownerID string) error +} diff --git a/cacheservice/pkg/manager/mocks/cache_data_store_client.go b/cacheservice/pkg/manager/mocks/cache_data_store_client.go new file mode 100644 index 0000000000..d97175ed57 --- /dev/null +++ b/cacheservice/pkg/manager/mocks/cache_data_store_client.go @@ -0,0 +1,121 @@ +// Code generated by mockery v1.0.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + models "github.com/flyteorg/flyte/cacheservice/repositories/models" +) + +// CacheDataStoreClient is an autogenerated mock type for the CacheDataStoreClient type +type CacheDataStoreClient struct { + mock.Mock +} + +type CacheDataStoreClient_Delete struct { + *mock.Call +} + +func (_m CacheDataStoreClient_Delete) Return(_a0 error) *CacheDataStoreClient_Delete { + return &CacheDataStoreClient_Delete{Call: _m.Call.Return(_a0)} +} + +func (_m *CacheDataStoreClient) OnDelete(ctx context.Context, key string) *CacheDataStoreClient_Delete { + c_call := _m.On("Delete", ctx, key) + return &CacheDataStoreClient_Delete{Call: c_call} +} + +func (_m *CacheDataStoreClient) OnDeleteMatch(matchers ...interface{}) *CacheDataStoreClient_Delete { + c_call := _m.On("Delete", matchers...) + return &CacheDataStoreClient_Delete{Call: c_call} +} + +// Delete provides a mock function with given fields: ctx, key +func (_m *CacheDataStoreClient) Delete(ctx context.Context, key string) error { + ret := _m.Called(ctx, key) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, key) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type CacheDataStoreClient_Get struct { + *mock.Call +} + +func (_m CacheDataStoreClient_Get) Return(_a0 *models.CachedOutput, _a1 error) *CacheDataStoreClient_Get { + return &CacheDataStoreClient_Get{Call: _m.Call.Return(_a0, _a1)} +} + +func (_m *CacheDataStoreClient) OnGet(ctx context.Context, key string) *CacheDataStoreClient_Get { + c_call := _m.On("Get", ctx, key) + return &CacheDataStoreClient_Get{Call: c_call} +} + +func (_m *CacheDataStoreClient) OnGetMatch(matchers ...interface{}) *CacheDataStoreClient_Get { + c_call := _m.On("Get", matchers...) + return &CacheDataStoreClient_Get{Call: c_call} +} + +// Get provides a mock function with given fields: ctx, key +func (_m *CacheDataStoreClient) Get(ctx context.Context, key string) (*models.CachedOutput, error) { + ret := _m.Called(ctx, key) + + var r0 *models.CachedOutput + if rf, ok := ret.Get(0).(func(context.Context, string) *models.CachedOutput); ok { + r0 = rf(ctx, key) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.CachedOutput) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, key) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type CacheDataStoreClient_Put struct { + *mock.Call +} + +func (_m CacheDataStoreClient_Put) Return(_a0 error) *CacheDataStoreClient_Put { + return &CacheDataStoreClient_Put{Call: _m.Call.Return(_a0)} +} + +func (_m *CacheDataStoreClient) OnPut(ctx context.Context, key string, cachedOutput *models.CachedOutput) *CacheDataStoreClient_Put { + c_call := _m.On("Put", ctx, key, cachedOutput) + return &CacheDataStoreClient_Put{Call: c_call} +} + +func (_m *CacheDataStoreClient) OnPutMatch(matchers ...interface{}) *CacheDataStoreClient_Put { + c_call := _m.On("Put", matchers...) + return &CacheDataStoreClient_Put{Call: c_call} +} + +// Put provides a mock function with given fields: ctx, key, cachedOutput +func (_m *CacheDataStoreClient) Put(ctx context.Context, key string, cachedOutput *models.CachedOutput) error { + ret := _m.Called(ctx, key, cachedOutput) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, *models.CachedOutput) error); ok { + r0 = rf(ctx, key, cachedOutput) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/cacheservice/pkg/manager/mocks/cache_manager.go b/cacheservice/pkg/manager/mocks/cache_manager.go new file mode 100644 index 0000000000..f4396785a0 --- /dev/null +++ b/cacheservice/pkg/manager/mocks/cache_manager.go @@ -0,0 +1,223 @@ +// Code generated by mockery v1.0.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + cacheservice "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" + + mock "github.com/stretchr/testify/mock" + + time "time" +) + +// CacheManager is an autogenerated mock type for the CacheManager type +type CacheManager struct { + mock.Mock +} + +type CacheManager_Delete struct { + *mock.Call +} + +func (_m CacheManager_Delete) Return(_a0 *cacheservice.DeleteCacheResponse, _a1 error) *CacheManager_Delete { + return &CacheManager_Delete{Call: _m.Call.Return(_a0, _a1)} +} + +func (_m *CacheManager) OnDelete(ctx context.Context, request *cacheservice.DeleteCacheRequest) *CacheManager_Delete { + c_call := _m.On("Delete", ctx, request) + return &CacheManager_Delete{Call: c_call} +} + +func (_m *CacheManager) OnDeleteMatch(matchers ...interface{}) *CacheManager_Delete { + c_call := _m.On("Delete", matchers...) + return &CacheManager_Delete{Call: c_call} +} + +// Delete provides a mock function with given fields: ctx, request +func (_m *CacheManager) Delete(ctx context.Context, request *cacheservice.DeleteCacheRequest) (*cacheservice.DeleteCacheResponse, error) { + ret := _m.Called(ctx, request) + + var r0 *cacheservice.DeleteCacheResponse + if rf, ok := ret.Get(0).(func(context.Context, *cacheservice.DeleteCacheRequest) *cacheservice.DeleteCacheResponse); ok { + r0 = rf(ctx, request) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*cacheservice.DeleteCacheResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *cacheservice.DeleteCacheRequest) error); ok { + r1 = rf(ctx, request) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type CacheManager_Get struct { + *mock.Call +} + +func (_m CacheManager_Get) Return(_a0 *cacheservice.GetCacheResponse, _a1 error) *CacheManager_Get { + return &CacheManager_Get{Call: _m.Call.Return(_a0, _a1)} +} + +func (_m *CacheManager) OnGet(ctx context.Context, request *cacheservice.GetCacheRequest) *CacheManager_Get { + c_call := _m.On("Get", ctx, request) + return &CacheManager_Get{Call: c_call} +} + +func (_m *CacheManager) OnGetMatch(matchers ...interface{}) *CacheManager_Get { + c_call := _m.On("Get", matchers...) + return &CacheManager_Get{Call: c_call} +} + +// Get provides a mock function with given fields: ctx, request +func (_m *CacheManager) Get(ctx context.Context, request *cacheservice.GetCacheRequest) (*cacheservice.GetCacheResponse, error) { + ret := _m.Called(ctx, request) + + var r0 *cacheservice.GetCacheResponse + if rf, ok := ret.Get(0).(func(context.Context, *cacheservice.GetCacheRequest) *cacheservice.GetCacheResponse); ok { + r0 = rf(ctx, request) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*cacheservice.GetCacheResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *cacheservice.GetCacheRequest) error); ok { + r1 = rf(ctx, request) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type CacheManager_GetOrExtendReservation struct { + *mock.Call +} + +func (_m CacheManager_GetOrExtendReservation) Return(_a0 *cacheservice.GetOrExtendReservationResponse, _a1 error) *CacheManager_GetOrExtendReservation { + return &CacheManager_GetOrExtendReservation{Call: _m.Call.Return(_a0, _a1)} +} + +func (_m *CacheManager) OnGetOrExtendReservation(ctx context.Context, request *cacheservice.GetOrExtendReservationRequest, now time.Time) *CacheManager_GetOrExtendReservation { + c_call := _m.On("GetOrExtendReservation", ctx, request, now) + return &CacheManager_GetOrExtendReservation{Call: c_call} +} + +func (_m *CacheManager) OnGetOrExtendReservationMatch(matchers ...interface{}) *CacheManager_GetOrExtendReservation { + c_call := _m.On("GetOrExtendReservation", matchers...) + return &CacheManager_GetOrExtendReservation{Call: c_call} +} + +// GetOrExtendReservation provides a mock function with given fields: ctx, request, now +func (_m *CacheManager) GetOrExtendReservation(ctx context.Context, request *cacheservice.GetOrExtendReservationRequest, now time.Time) (*cacheservice.GetOrExtendReservationResponse, error) { + ret := _m.Called(ctx, request, now) + + var r0 *cacheservice.GetOrExtendReservationResponse + if rf, ok := ret.Get(0).(func(context.Context, *cacheservice.GetOrExtendReservationRequest, time.Time) *cacheservice.GetOrExtendReservationResponse); ok { + r0 = rf(ctx, request, now) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*cacheservice.GetOrExtendReservationResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *cacheservice.GetOrExtendReservationRequest, time.Time) error); ok { + r1 = rf(ctx, request, now) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type CacheManager_Put struct { + *mock.Call +} + +func (_m CacheManager_Put) Return(_a0 *cacheservice.PutCacheResponse, _a1 error) *CacheManager_Put { + return &CacheManager_Put{Call: _m.Call.Return(_a0, _a1)} +} + +func (_m *CacheManager) OnPut(ctx context.Context, request *cacheservice.PutCacheRequest) *CacheManager_Put { + c_call := _m.On("Put", ctx, request) + return &CacheManager_Put{Call: c_call} +} + +func (_m *CacheManager) OnPutMatch(matchers ...interface{}) *CacheManager_Put { + c_call := _m.On("Put", matchers...) + return &CacheManager_Put{Call: c_call} +} + +// Put provides a mock function with given fields: ctx, request +func (_m *CacheManager) Put(ctx context.Context, request *cacheservice.PutCacheRequest) (*cacheservice.PutCacheResponse, error) { + ret := _m.Called(ctx, request) + + var r0 *cacheservice.PutCacheResponse + if rf, ok := ret.Get(0).(func(context.Context, *cacheservice.PutCacheRequest) *cacheservice.PutCacheResponse); ok { + r0 = rf(ctx, request) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*cacheservice.PutCacheResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *cacheservice.PutCacheRequest) error); ok { + r1 = rf(ctx, request) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type CacheManager_ReleaseReservation struct { + *mock.Call +} + +func (_m CacheManager_ReleaseReservation) Return(_a0 *cacheservice.ReleaseReservationResponse, _a1 error) *CacheManager_ReleaseReservation { + return &CacheManager_ReleaseReservation{Call: _m.Call.Return(_a0, _a1)} +} + +func (_m *CacheManager) OnReleaseReservation(ctx context.Context, request *cacheservice.ReleaseReservationRequest) *CacheManager_ReleaseReservation { + c_call := _m.On("ReleaseReservation", ctx, request) + return &CacheManager_ReleaseReservation{Call: c_call} +} + +func (_m *CacheManager) OnReleaseReservationMatch(matchers ...interface{}) *CacheManager_ReleaseReservation { + c_call := _m.On("ReleaseReservation", matchers...) + return &CacheManager_ReleaseReservation{Call: c_call} +} + +// ReleaseReservation provides a mock function with given fields: ctx, request +func (_m *CacheManager) ReleaseReservation(ctx context.Context, request *cacheservice.ReleaseReservationRequest) (*cacheservice.ReleaseReservationResponse, error) { + ret := _m.Called(ctx, request) + + var r0 *cacheservice.ReleaseReservationResponse + if rf, ok := ret.Get(0).(func(context.Context, *cacheservice.ReleaseReservationRequest) *cacheservice.ReleaseReservationResponse); ok { + r0 = rf(ctx, request) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*cacheservice.ReleaseReservationResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *cacheservice.ReleaseReservationRequest) error); ok { + r1 = rf(ctx, request) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/cacheservice/pkg/manager/mocks/cache_output_blob_store.go b/cacheservice/pkg/manager/mocks/cache_output_blob_store.go new file mode 100644 index 0000000000..ebc761770e --- /dev/null +++ b/cacheservice/pkg/manager/mocks/cache_output_blob_store.go @@ -0,0 +1,87 @@ +// Code generated by mockery v1.0.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + core "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" + + mock "github.com/stretchr/testify/mock" +) + +// CacheOutputBlobStore is an autogenerated mock type for the CacheOutputBlobStore type +type CacheOutputBlobStore struct { + mock.Mock +} + +type CacheOutputBlobStore_Create struct { + *mock.Call +} + +func (_m CacheOutputBlobStore_Create) Return(_a0 string, _a1 error) *CacheOutputBlobStore_Create { + return &CacheOutputBlobStore_Create{Call: _m.Call.Return(_a0, _a1)} +} + +func (_m *CacheOutputBlobStore) OnCreate(ctx context.Context, key string, output *core.LiteralMap) *CacheOutputBlobStore_Create { + c_call := _m.On("Create", ctx, key, output) + return &CacheOutputBlobStore_Create{Call: c_call} +} + +func (_m *CacheOutputBlobStore) OnCreateMatch(matchers ...interface{}) *CacheOutputBlobStore_Create { + c_call := _m.On("Create", matchers...) + return &CacheOutputBlobStore_Create{Call: c_call} +} + +// Create provides a mock function with given fields: ctx, key, output +func (_m *CacheOutputBlobStore) Create(ctx context.Context, key string, output *core.LiteralMap) (string, error) { + ret := _m.Called(ctx, key, output) + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string, *core.LiteralMap) string); ok { + r0 = rf(ctx, key, output) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, *core.LiteralMap) error); ok { + r1 = rf(ctx, key, output) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type CacheOutputBlobStore_Delete struct { + *mock.Call +} + +func (_m CacheOutputBlobStore_Delete) Return(_a0 error) *CacheOutputBlobStore_Delete { + return &CacheOutputBlobStore_Delete{Call: _m.Call.Return(_a0)} +} + +func (_m *CacheOutputBlobStore) OnDelete(ctx context.Context, uri string) *CacheOutputBlobStore_Delete { + c_call := _m.On("Delete", ctx, uri) + return &CacheOutputBlobStore_Delete{Call: c_call} +} + +func (_m *CacheOutputBlobStore) OnDeleteMatch(matchers ...interface{}) *CacheOutputBlobStore_Delete { + c_call := _m.On("Delete", matchers...) + return &CacheOutputBlobStore_Delete{Call: c_call} +} + +// Delete provides a mock function with given fields: ctx, uri +func (_m *CacheOutputBlobStore) Delete(ctx context.Context, uri string) error { + ret := _m.Called(ctx, uri) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, uri) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/cacheservice/pkg/manager/mocks/reservation_data_store_client.go b/cacheservice/pkg/manager/mocks/reservation_data_store_client.go new file mode 100644 index 0000000000..75751b6901 --- /dev/null +++ b/cacheservice/pkg/manager/mocks/reservation_data_store_client.go @@ -0,0 +1,155 @@ +// Code generated by mockery v1.0.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + models "github.com/flyteorg/flyte/cacheservice/repositories/models" + + time "time" +) + +// ReservationDataStoreClient is an autogenerated mock type for the ReservationDataStoreClient type +type ReservationDataStoreClient struct { + mock.Mock +} + +type ReservationDataStoreClient_Create struct { + *mock.Call +} + +func (_m ReservationDataStoreClient_Create) Return(_a0 error) *ReservationDataStoreClient_Create { + return &ReservationDataStoreClient_Create{Call: _m.Call.Return(_a0)} +} + +func (_m *ReservationDataStoreClient) OnCreate(ctx context.Context, reservation *models.Reservation, now time.Time) *ReservationDataStoreClient_Create { + c_call := _m.On("Create", ctx, reservation, now) + return &ReservationDataStoreClient_Create{Call: c_call} +} + +func (_m *ReservationDataStoreClient) OnCreateMatch(matchers ...interface{}) *ReservationDataStoreClient_Create { + c_call := _m.On("Create", matchers...) + return &ReservationDataStoreClient_Create{Call: c_call} +} + +// Create provides a mock function with given fields: ctx, reservation, now +func (_m *ReservationDataStoreClient) Create(ctx context.Context, reservation *models.Reservation, now time.Time) error { + ret := _m.Called(ctx, reservation, now) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *models.Reservation, time.Time) error); ok { + r0 = rf(ctx, reservation, now) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type ReservationDataStoreClient_Delete struct { + *mock.Call +} + +func (_m ReservationDataStoreClient_Delete) Return(_a0 error) *ReservationDataStoreClient_Delete { + return &ReservationDataStoreClient_Delete{Call: _m.Call.Return(_a0)} +} + +func (_m *ReservationDataStoreClient) OnDelete(ctx context.Context, key string, ownerID string) *ReservationDataStoreClient_Delete { + c_call := _m.On("Delete", ctx, key, ownerID) + return &ReservationDataStoreClient_Delete{Call: c_call} +} + +func (_m *ReservationDataStoreClient) OnDeleteMatch(matchers ...interface{}) *ReservationDataStoreClient_Delete { + c_call := _m.On("Delete", matchers...) + return &ReservationDataStoreClient_Delete{Call: c_call} +} + +// Delete provides a mock function with given fields: ctx, key, ownerID +func (_m *ReservationDataStoreClient) Delete(ctx context.Context, key string, ownerID string) error { + ret := _m.Called(ctx, key, ownerID) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, key, ownerID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type ReservationDataStoreClient_Get struct { + *mock.Call +} + +func (_m ReservationDataStoreClient_Get) Return(_a0 *models.Reservation, _a1 error) *ReservationDataStoreClient_Get { + return &ReservationDataStoreClient_Get{Call: _m.Call.Return(_a0, _a1)} +} + +func (_m *ReservationDataStoreClient) OnGet(ctx context.Context, key string) *ReservationDataStoreClient_Get { + c_call := _m.On("Get", ctx, key) + return &ReservationDataStoreClient_Get{Call: c_call} +} + +func (_m *ReservationDataStoreClient) OnGetMatch(matchers ...interface{}) *ReservationDataStoreClient_Get { + c_call := _m.On("Get", matchers...) + return &ReservationDataStoreClient_Get{Call: c_call} +} + +// Get provides a mock function with given fields: ctx, key +func (_m *ReservationDataStoreClient) Get(ctx context.Context, key string) (*models.Reservation, error) { + ret := _m.Called(ctx, key) + + var r0 *models.Reservation + if rf, ok := ret.Get(0).(func(context.Context, string) *models.Reservation); ok { + r0 = rf(ctx, key) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.Reservation) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, key) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type ReservationDataStoreClient_Update struct { + *mock.Call +} + +func (_m ReservationDataStoreClient_Update) Return(_a0 error) *ReservationDataStoreClient_Update { + return &ReservationDataStoreClient_Update{Call: _m.Call.Return(_a0)} +} + +func (_m *ReservationDataStoreClient) OnUpdate(ctx context.Context, reservation *models.Reservation, now time.Time) *ReservationDataStoreClient_Update { + c_call := _m.On("Update", ctx, reservation, now) + return &ReservationDataStoreClient_Update{Call: c_call} +} + +func (_m *ReservationDataStoreClient) OnUpdateMatch(matchers ...interface{}) *ReservationDataStoreClient_Update { + c_call := _m.On("Update", matchers...) + return &ReservationDataStoreClient_Update{Call: c_call} +} + +// Update provides a mock function with given fields: ctx, reservation, now +func (_m *ReservationDataStoreClient) Update(ctx context.Context, reservation *models.Reservation, now time.Time) error { + ret := _m.Called(ctx, reservation, now) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *models.Reservation, time.Time) error); ok { + r0 = rf(ctx, reservation, now) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/cacheservice/pkg/rpc/cacheservice/service.go b/cacheservice/pkg/rpc/cacheservice/service.go new file mode 100644 index 0000000000..dccf40b0f0 --- /dev/null +++ b/cacheservice/pkg/rpc/cacheservice/service.go @@ -0,0 +1,177 @@ +package cacheservice + +import ( + "context" + "fmt" + "net" + "net/http" + "runtime/debug" + "time" + + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" + "go.opentelemetry.io/otel/propagation" + "google.golang.org/grpc" + "google.golang.org/grpc/health" + "google.golang.org/grpc/health/grpc_health_v1" + "google.golang.org/grpc/reflection" + + "github.com/flyteorg/flyte/cacheservice/pkg/config" + "github.com/flyteorg/flyte/cacheservice/pkg/manager/impl" + "github.com/flyteorg/flyte/cacheservice/pkg/manager/interfaces" + "github.com/flyteorg/flyte/cacheservice/pkg/runtime" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" + "github.com/flyteorg/flyte/flytestdlib/contextutils" + "github.com/flyteorg/flyte/flytestdlib/logger" + "github.com/flyteorg/flyte/flytestdlib/otelutils" + "github.com/flyteorg/flyte/flytestdlib/promutils" + "github.com/flyteorg/flyte/flytestdlib/storage" +) + +type CacheService struct { + CacheManager interfaces.CacheManager +} + +func (s *CacheService) Get(ctx context.Context, request *cacheservice.GetCacheRequest) (*cacheservice.GetCacheResponse, error) { + return s.CacheManager.Get(ctx, request) +} + +func (s *CacheService) Put(ctx context.Context, request *cacheservice.PutCacheRequest) (*cacheservice.PutCacheResponse, error) { + return s.CacheManager.Put(ctx, request) +} + +func (s *CacheService) Delete(ctx context.Context, request *cacheservice.DeleteCacheRequest) (*cacheservice.DeleteCacheResponse, error) { + return s.CacheManager.Delete(ctx, request) +} + +func (s *CacheService) GetOrExtendReservation(ctx context.Context, request *cacheservice.GetOrExtendReservationRequest) (*cacheservice.GetOrExtendReservationResponse, error) { + return s.CacheManager.GetOrExtendReservation(ctx, request, time.Now()) +} + +func (s *CacheService) ReleaseReservation(ctx context.Context, request *cacheservice.ReleaseReservationRequest) (*cacheservice.ReleaseReservationResponse, error) { + return s.CacheManager.ReleaseReservation(ctx, request) +} + +func NewCacheService() *CacheService { + configProvider := runtime.NewConfigurationProvider() + cacheServiceConfig := configProvider.ApplicationConfiguration().GetCacheServiceConfig() + cacheServiceScope := promutils.NewScope(cacheServiceConfig.MetricsScope).NewSubScope("cacheservice") + ctx := contextutils.WithAppName(context.Background(), "cacheservice") + + defer func() { + if err := recover(); err != nil { + cacheServiceScope.MustNewCounter("initialization_panic", + "panics encountered initializing the cache service").Inc() + logger.Fatalf(context.Background(), fmt.Sprintf("caught panic: %v [%+v]", err, string(debug.Stack()))) + } + }() + + storeConfig := storage.GetConfig() + dataStorageClient, err := storage.NewDataStore(storeConfig, cacheServiceScope.NewSubScope("storage")) + if err != nil { + logger.Errorf(ctx, "Failed to create DataStore %v, err %v", storeConfig, err) + panic(err) + } + logger.Infof(ctx, "Created data storage.") + + baseStorageReference := dataStorageClient.GetBaseContainerFQN(ctx) + storagePrefix, err := dataStorageClient.ConstructReference(ctx, baseStorageReference, cacheServiceConfig.StoragePrefix) + if err != nil { + logger.Errorf(ctx, "Failed to create prefix %v, err %v", cacheServiceConfig.StoragePrefix, err) + panic(err) + } + + outputStore := impl.NewCacheOutputStore(dataStorageClient, storagePrefix) + dataStore := impl.NewCacheDataStore(ctx, cacheServiceConfig) + reservationStore := impl.NewReservationDataStore(ctx, cacheServiceConfig) + + return &CacheService{ + CacheManager: impl.NewCacheManager(outputStore, dataStore, reservationStore, cacheServiceConfig.MaxInlineSizeBytes, cacheServiceScope.NewSubScope("cache"), + time.Duration(cacheServiceConfig.HeartbeatGracePeriodMultiplier), cacheServiceConfig.MaxReservationHeartbeat.Duration), + } +} + +// Create and start the gRPC server +func ServeInsecure(ctx context.Context, cfg *config.Config) error { + grpcServer := newGRPCServer(ctx, cfg) + + grpcListener, err := net.Listen("tcp", cfg.GetGrpcHostAddress()) + if err != nil { + return err + } + + logger.Infof(ctx, "Serving CacheService Insecure on port %v", config.GetConfig().GetGrpcHostAddress()) + return grpcServer.Serve(grpcListener) +} + +// Creates a new GRPC Server with all the configuration +func newGRPCServer(_ context.Context, cfg *config.Config) *grpc.Server { + tracerProvider := otelutils.GetTracerProvider(otelutils.CacheServiceServerTracer) + grpcServer := grpc.NewServer( + grpc.UnaryInterceptor( + otelgrpc.UnaryServerInterceptor( + otelgrpc.WithTracerProvider(tracerProvider), + otelgrpc.WithPropagators(propagation.TraceContext{}), + ), + ), + ) + cacheservice.RegisterCacheServiceServer(grpcServer, NewCacheService()) + + healthServer := health.NewServer() + healthServer.SetServingStatus("", grpc_health_v1.HealthCheckResponse_SERVING) + grpc_health_v1.RegisterHealthServer(grpcServer, healthServer) + + if cfg.GrpcServerReflection { + reflection.Register(grpcServer) + } + return grpcServer +} + +// ServeHTTPHealthCheck create a http healthcheck endpoint +func ServeHTTPHealthCheck(ctx context.Context, cfg *config.Config) error { + mux := http.NewServeMux() + + // Register Health check + mux.HandleFunc("/healthcheck", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + + logger.Infof(ctx, "Serving CacheService http on port %v", cfg.GetHTTPHostAddress()) + + server := &http.Server{ + Addr: cfg.GetHTTPHostAddress(), + Handler: mux, + ReadHeaderTimeout: time.Duration(cfg.ReadHeaderTimeoutSeconds) * time.Second, + } + return server.ListenAndServe() +} + +// Create and start the gRPC server and http healthcheck endpoint +func Serve(ctx context.Context, cfg *config.Config) error { + grpcServer := newGRPCDummyServer(ctx, cfg) + + grpcListener, err := net.Listen("tcp", cfg.GetGrpcHostAddress()) + if err != nil { + return err + } + + logger.Infof(ctx, "Serving CacheService Insecure on port %v", cfg.GetGrpcHostAddress()) + return grpcServer.Serve(grpcListener) +} + +// Creates a new GRPC Server with all the configuration +func newGRPCDummyServer(_ context.Context, cfg *config.Config) *grpc.Server { + tracerProvider := otelutils.GetTracerProvider(otelutils.CacheServiceClientTracer) + grpcServer := grpc.NewServer( + grpc.UnaryInterceptor( + otelgrpc.UnaryServerInterceptor( + otelgrpc.WithTracerProvider(tracerProvider), + otelgrpc.WithPropagators(propagation.TraceContext{}), + ), + ), + ) + cacheservice.RegisterCacheServiceServer(grpcServer, &CacheService{}) + if cfg.GrpcServerReflection { + reflection.Register(grpcServer) + } + return grpcServer +} diff --git a/cacheservice/pkg/runtime/application_config_provider.go b/cacheservice/pkg/runtime/application_config_provider.go new file mode 100644 index 0000000000..7df01775e2 --- /dev/null +++ b/cacheservice/pkg/runtime/application_config_provider.go @@ -0,0 +1,25 @@ +package runtime + +import ( + "github.com/flyteorg/flyte/cacheservice/pkg/runtime/configs" + "github.com/flyteorg/flyte/flytestdlib/config" +) + +const cacheservice = "cacheservice" + +var cacheserviceConfig = config.MustRegisterSection(cacheservice, &configs.CacheServiceConfig{}) + +// Defines the interface to return top-level config structs necessary to start up a cacheservice application. +type ApplicationConfiguration interface { + GetCacheServiceConfig() configs.CacheServiceConfig +} + +type ApplicationConfigurationProvider struct{} + +func (p *ApplicationConfigurationProvider) GetCacheServiceConfig() configs.CacheServiceConfig { + return *cacheserviceConfig.GetConfig().(*configs.CacheServiceConfig) +} + +func NewApplicationConfigurationProvider() ApplicationConfiguration { + return &ApplicationConfigurationProvider{} +} diff --git a/cacheservice/pkg/runtime/configs/cache_service_config.go b/cacheservice/pkg/runtime/configs/cache_service_config.go new file mode 100644 index 0000000000..40c990c913 --- /dev/null +++ b/cacheservice/pkg/runtime/configs/cache_service_config.go @@ -0,0 +1,48 @@ +package configs + +import ( + "time" + + "github.com/flyteorg/flyte/flytestdlib/config" +) + +type DataStoreType = string + +const ( + Mem DataStoreType = "mem" + DynamoDB DataStoreType = "dynamodb" + Redis DataStoreType = "redis" +) + +//go:generate pflags CacheServiceConfig --default-var=defaultConfig + +var defaultConfig = &CacheServiceConfig{ + StoragePrefix: "cached_outputs", + MetricsScope: "cacheservice", + ProfilerPort: 10254, + HeartbeatGracePeriodMultiplier: 3, + MaxReservationHeartbeat: config.Duration{Duration: time.Second * 10}, + DataStoreType: Mem, + ReservationDataStoreType: Mem, + MaxInlineSizeBytes: 0, + AwsRegion: "us-west-2", + RedisAddress: "localhost:6379", + RedisUsername: "", + RedisPassword: "", +} + +// CacheServiceConfig is the base configuration to start cacheservice +type CacheServiceConfig struct { + StoragePrefix string `json:"storage-prefix" pflag:",StoragePrefix specifies the prefix where CacheService stores offloaded output in CloudStorage. If not ..."` + MetricsScope string `json:"metrics-scope" pflag:",Scope that the metrics will record under."` + ProfilerPort int `json:"profiler-port" pflag:",Port that the profiling service is listening on."` + HeartbeatGracePeriodMultiplier int `json:"heartbeat-grace-period-multiplier" pflag:",Number of heartbeats before a reservation expires without an extension."` + MaxReservationHeartbeat config.Duration `json:"max-reservation-heartbeat" pflag:",The maximum available reservation extension heartbeat interval."` + DataStoreType DataStoreType `json:"data-store-type" pflag:",Cache storage implementation to use"` + ReservationDataStoreType DataStoreType `json:"reservation-data-store-type" pflag:",Reservation storage implementation to use"` + MaxInlineSizeBytes int64 `json:"maxInlineSizeBytes" pflag:",The maximum size that an output literal will be stored in line. Default 0 means everything will be offloaded to blob storage."` + AwsRegion string `json:"aws-region" pflag:",Region to connect to."` + RedisAddress string `json:"redis-address" pflag:",Address of the Redis server."` + RedisUsername string `json:"redis-username" pflag:",Username for the Redis server."` + RedisPassword string `json:"redis-password" pflag:",Password for the Redis server."` +} diff --git a/cacheservice/pkg/runtime/configs/cacheserviceconfig_flags.go b/cacheservice/pkg/runtime/configs/cacheserviceconfig_flags.go new file mode 100755 index 0000000000..2414e77bf0 --- /dev/null +++ b/cacheservice/pkg/runtime/configs/cacheserviceconfig_flags.go @@ -0,0 +1,66 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots. + +package configs + +import ( + "encoding/json" + "reflect" + + "fmt" + + "github.com/spf13/pflag" +) + +// If v is a pointer, it will get its element value or the zero value of the element type. +// If v is not a pointer, it will return it as is. +func (CacheServiceConfig) elemValueOrNil(v interface{}) interface{} { + if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr { + if reflect.ValueOf(v).IsNil() { + return reflect.Zero(t.Elem()).Interface() + } else { + return reflect.ValueOf(v).Interface() + } + } else if v == nil { + return reflect.Zero(t).Interface() + } + + return v +} + +func (CacheServiceConfig) mustJsonMarshal(v interface{}) string { + raw, err := json.Marshal(v) + if err != nil { + panic(err) + } + + return string(raw) +} + +func (CacheServiceConfig) mustMarshalJSON(v json.Marshaler) string { + raw, err := v.MarshalJSON() + if err != nil { + panic(err) + } + + return string(raw) +} + +// GetPFlagSet will return strongly types pflags for all fields in CacheServiceConfig and its nested types. The format of the +// flags is json-name.json-sub-name... etc. +func (cfg CacheServiceConfig) GetPFlagSet(prefix string) *pflag.FlagSet { + cmdFlags := pflag.NewFlagSet("CacheServiceConfig", pflag.ExitOnError) + cmdFlags.String(fmt.Sprintf("%v%v", prefix, "storage-prefix"), defaultConfig.StoragePrefix, "StoragePrefix specifies the prefix where CacheService stores offloaded output in CloudStorage. If not ...") + cmdFlags.String(fmt.Sprintf("%v%v", prefix, "metrics-scope"), defaultConfig.MetricsScope, "Scope that the metrics will record under.") + cmdFlags.Int(fmt.Sprintf("%v%v", prefix, "profiler-port"), defaultConfig.ProfilerPort, "Port that the profiling service is listening on.") + cmdFlags.Int(fmt.Sprintf("%v%v", prefix, "heartbeat-grace-period-multiplier"), defaultConfig.HeartbeatGracePeriodMultiplier, "Number of heartbeats before a reservation expires without an extension.") + cmdFlags.String(fmt.Sprintf("%v%v", prefix, "max-reservation-heartbeat"), defaultConfig.MaxReservationHeartbeat.String(), "The maximum available reservation extension heartbeat interval.") + cmdFlags.String(fmt.Sprintf("%v%v", prefix, "data-store-type"), defaultConfig.DataStoreType, "Cache storage implementation to use") + cmdFlags.String(fmt.Sprintf("%v%v", prefix, "reservation-data-store-type"), defaultConfig.ReservationDataStoreType, "Reservation storage implementation to use") + cmdFlags.Int64(fmt.Sprintf("%v%v", prefix, "maxInlineSizeBytes"), defaultConfig.MaxInlineSizeBytes, "The maximum size that an output literal will be stored in line. Default 0 means everything will be offloaded to blob storage.") + cmdFlags.String(fmt.Sprintf("%v%v", prefix, "aws-region"), defaultConfig.AwsRegion, "Region to connect to.") + cmdFlags.String(fmt.Sprintf("%v%v", prefix, "redis-address"), defaultConfig.RedisAddress, "Address of the Redis server.") + cmdFlags.String(fmt.Sprintf("%v%v", prefix, "redis-username"), defaultConfig.RedisUsername, "Username for the Redis server.") + cmdFlags.String(fmt.Sprintf("%v%v", prefix, "redis-password"), defaultConfig.RedisPassword, "Password for the Redis server.") + return cmdFlags +} diff --git a/cacheservice/pkg/runtime/configs/cacheserviceconfig_flags_test.go b/cacheservice/pkg/runtime/configs/cacheserviceconfig_flags_test.go new file mode 100755 index 0000000000..83fbfd5335 --- /dev/null +++ b/cacheservice/pkg/runtime/configs/cacheserviceconfig_flags_test.go @@ -0,0 +1,270 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots. + +package configs + +import ( + "encoding/json" + "fmt" + "reflect" + "strings" + "testing" + + "github.com/mitchellh/mapstructure" + "github.com/stretchr/testify/assert" +) + +var dereferencableKindsCacheServiceConfig = map[reflect.Kind]struct{}{ + reflect.Array: {}, reflect.Chan: {}, reflect.Map: {}, reflect.Ptr: {}, reflect.Slice: {}, +} + +// Checks if t is a kind that can be dereferenced to get its underlying type. +func canGetElementCacheServiceConfig(t reflect.Kind) bool { + _, exists := dereferencableKindsCacheServiceConfig[t] + return exists +} + +// This decoder hook tests types for json unmarshaling capability. If implemented, it uses json unmarshal to build the +// object. Otherwise, it'll just pass on the original data. +func jsonUnmarshalerHookCacheServiceConfig(_, to reflect.Type, data interface{}) (interface{}, error) { + unmarshalerType := reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() + if to.Implements(unmarshalerType) || reflect.PtrTo(to).Implements(unmarshalerType) || + (canGetElementCacheServiceConfig(to.Kind()) && to.Elem().Implements(unmarshalerType)) { + + raw, err := json.Marshal(data) + if err != nil { + fmt.Printf("Failed to marshal Data: %v. Error: %v. Skipping jsonUnmarshalHook", data, err) + return data, nil + } + + res := reflect.New(to).Interface() + err = json.Unmarshal(raw, &res) + if err != nil { + fmt.Printf("Failed to umarshal Data: %v. Error: %v. Skipping jsonUnmarshalHook", data, err) + return data, nil + } + + return res, nil + } + + return data, nil +} + +func decode_CacheServiceConfig(input, result interface{}) error { + config := &mapstructure.DecoderConfig{ + TagName: "json", + WeaklyTypedInput: true, + Result: result, + DecodeHook: mapstructure.ComposeDecodeHookFunc( + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToSliceHookFunc(","), + jsonUnmarshalerHookCacheServiceConfig, + ), + } + + decoder, err := mapstructure.NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +func join_CacheServiceConfig(arr interface{}, sep string) string { + listValue := reflect.ValueOf(arr) + strs := make([]string, 0, listValue.Len()) + for i := 0; i < listValue.Len(); i++ { + strs = append(strs, fmt.Sprintf("%v", listValue.Index(i))) + } + + return strings.Join(strs, sep) +} + +func testDecodeJson_CacheServiceConfig(t *testing.T, val, result interface{}) { + assert.NoError(t, decode_CacheServiceConfig(val, result)) +} + +func testDecodeRaw_CacheServiceConfig(t *testing.T, vStringSlice, result interface{}) { + assert.NoError(t, decode_CacheServiceConfig(vStringSlice, result)) +} + +func TestCacheServiceConfig_GetPFlagSet(t *testing.T) { + val := CacheServiceConfig{} + cmdFlags := val.GetPFlagSet("") + assert.True(t, cmdFlags.HasFlags()) +} + +func TestCacheServiceConfig_SetFlags(t *testing.T) { + actual := CacheServiceConfig{} + cmdFlags := actual.GetPFlagSet("") + assert.True(t, cmdFlags.HasFlags()) + + t.Run("Test_storage-prefix", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("storage-prefix", testValue) + if vString, err := cmdFlags.GetString("storage-prefix"); err == nil { + testDecodeJson_CacheServiceConfig(t, fmt.Sprintf("%v", vString), &actual.StoragePrefix) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_metrics-scope", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("metrics-scope", testValue) + if vString, err := cmdFlags.GetString("metrics-scope"); err == nil { + testDecodeJson_CacheServiceConfig(t, fmt.Sprintf("%v", vString), &actual.MetricsScope) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_profiler-port", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("profiler-port", testValue) + if vInt, err := cmdFlags.GetInt("profiler-port"); err == nil { + testDecodeJson_CacheServiceConfig(t, fmt.Sprintf("%v", vInt), &actual.ProfilerPort) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_heartbeat-grace-period-multiplier", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("heartbeat-grace-period-multiplier", testValue) + if vInt, err := cmdFlags.GetInt("heartbeat-grace-period-multiplier"); err == nil { + testDecodeJson_CacheServiceConfig(t, fmt.Sprintf("%v", vInt), &actual.HeartbeatGracePeriodMultiplier) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_max-reservation-heartbeat", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := defaultConfig.MaxReservationHeartbeat.String() + + cmdFlags.Set("max-reservation-heartbeat", testValue) + if vString, err := cmdFlags.GetString("max-reservation-heartbeat"); err == nil { + testDecodeJson_CacheServiceConfig(t, fmt.Sprintf("%v", vString), &actual.MaxReservationHeartbeat) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_data-store-type", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("data-store-type", testValue) + if vString, err := cmdFlags.GetString("data-store-type"); err == nil { + testDecodeJson_CacheServiceConfig(t, fmt.Sprintf("%v", vString), &actual.DataStoreType) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_reservation-data-store-type", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("reservation-data-store-type", testValue) + if vString, err := cmdFlags.GetString("reservation-data-store-type"); err == nil { + testDecodeJson_CacheServiceConfig(t, fmt.Sprintf("%v", vString), &actual.ReservationDataStoreType) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_maxInlineSizeBytes", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("maxInlineSizeBytes", testValue) + if vInt64, err := cmdFlags.GetInt64("maxInlineSizeBytes"); err == nil { + testDecodeJson_CacheServiceConfig(t, fmt.Sprintf("%v", vInt64), &actual.MaxInlineSizeBytes) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_aws-region", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("aws-region", testValue) + if vString, err := cmdFlags.GetString("aws-region"); err == nil { + testDecodeJson_CacheServiceConfig(t, fmt.Sprintf("%v", vString), &actual.AwsRegion) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_redis-address", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("redis-address", testValue) + if vString, err := cmdFlags.GetString("redis-address"); err == nil { + testDecodeJson_CacheServiceConfig(t, fmt.Sprintf("%v", vString), &actual.RedisAddress) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_redis-username", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("redis-username", testValue) + if vString, err := cmdFlags.GetString("redis-username"); err == nil { + testDecodeJson_CacheServiceConfig(t, fmt.Sprintf("%v", vString), &actual.RedisUsername) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_redis-password", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("redis-password", testValue) + if vString, err := cmdFlags.GetString("redis-password"); err == nil { + testDecodeJson_CacheServiceConfig(t, fmt.Sprintf("%v", vString), &actual.RedisPassword) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) +} diff --git a/cacheservice/pkg/runtime/configuration_provider.go b/cacheservice/pkg/runtime/configuration_provider.go new file mode 100644 index 0000000000..fe11026c85 --- /dev/null +++ b/cacheservice/pkg/runtime/configuration_provider.go @@ -0,0 +1,21 @@ +package runtime + +// Interface for getting parsed values from a configuration file +type Configuration interface { + ApplicationConfiguration() ApplicationConfiguration +} + +// Implementation of a Configuration +type ConfigurationProvider struct { + applicationConfiguration ApplicationConfiguration +} + +func (p *ConfigurationProvider) ApplicationConfiguration() ApplicationConfiguration { + return p.applicationConfiguration +} + +func NewConfigurationProvider() Configuration { + return &ConfigurationProvider{ + applicationConfiguration: NewApplicationConfigurationProvider(), + } +} diff --git a/cacheservice/pull_request_template.md b/cacheservice/pull_request_template.md new file mode 100644 index 0000000000..9cdab99b46 --- /dev/null +++ b/cacheservice/pull_request_template.md @@ -0,0 +1,35 @@ +## _Read then delete this section_ + +_- Make sure to use a concise title for the pull-request._ + +_- Use #patch, #minor or #major in the pull-request title to bump the corresponding version. Otherwise, the patch version +will be bumped. [More details](https://github.com/marketplace/actions/github-tag-bump)_ + +# TL;DR +_Please replace this text with a description of what this PR accomplishes._ + +## Type + - [ ] Bug Fix + - [ ] Feature + - [ ] Plugin + +## Are all requirements met? + + - [ ] Code completed + - [ ] Smoke tested + - [ ] Unit tests added + - [ ] Code documentation added + - [ ] Any pending items have an associated Issue + +## Complete description + _How did you fix the bug, make the feature etc. Link to any design docs etc_ + +## Tracking Issue +_Remove the '*fixes*' keyword if there will be multiple PRs to fix the linked issue_ + +fixes https://github.com/flyteorg/flyte/issues/ + +## Follow-up issue +_NA_ +OR +_https://github.com/flyteorg/flyte/issues/_ diff --git a/cacheservice/repositories/models/cached_output.go b/cacheservice/repositories/models/cached_output.go new file mode 100644 index 0000000000..75937b8896 --- /dev/null +++ b/cacheservice/repositories/models/cached_output.go @@ -0,0 +1,20 @@ +package models + +import "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" + +type Identifier struct { + ResourceType core.ResourceType `dynamodbav:"resourceType"` + Project string `dynamodbav:"project"` + Domain string `dynamodbav:"domain"` + Name string `dynamodbav:"name"` + Version string `dynamodbav:"version"` + Org string `dynamodbav:"org"` +} + +type CachedOutput struct { + ID string `dynamodbav:"id"` + OutputURI string `dynamodbav:"outputUri"` + OutputLiteral []byte `dynamodbav:"outputLiteral"` + SerializedMetadata []byte `dynamodbav:"keyMap"` + Identifier Identifier `dynamodbav:"identifier"` +} diff --git a/cacheservice/repositories/models/reservation.go b/cacheservice/repositories/models/reservation.go new file mode 100644 index 0000000000..c713b550fd --- /dev/null +++ b/cacheservice/repositories/models/reservation.go @@ -0,0 +1,11 @@ +package models + +import ( + "time" +) + +type Reservation struct { + Key string + OwnerID string + ExpiresAt time.Time +} diff --git a/cacheservice/repositories/transformers/cached_output.go b/cacheservice/repositories/transformers/cached_output.go new file mode 100644 index 0000000000..d6894d4c25 --- /dev/null +++ b/cacheservice/repositories/transformers/cached_output.go @@ -0,0 +1,102 @@ +package transformers + +import ( + "context" + + "github.com/golang/protobuf/proto" + "google.golang.org/grpc/codes" + + "github.com/flyteorg/flyte/cacheservice/pkg/errors" + "github.com/flyteorg/flyte/cacheservice/repositories/models" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" + "github.com/flyteorg/flyte/flytestdlib/logger" +) + +func CreateCachedOutputModel(ctx context.Context, key string, cachedOutput *cacheservice.CachedOutput) (*models.CachedOutput, error) { + var outputLiteralBytes []byte + var err error + if cachedOutput.GetOutputLiterals() != nil { + outputLiteralBytes, err = proto.Marshal(cachedOutput.GetOutputLiterals()) + if err != nil { + logger.Debugf(ctx, "Failed to marshal output literal with error %v", err) + return nil, errors.NewCacheServiceErrorf(codes.Internal, "Failed to marshal output literal with error %v", err) + } + } + + var keyMap *cacheservice.KeyMapMetadata + if cachedOutput.GetMetadata() == nil || cachedOutput.GetMetadata().GetKeyMap() == nil { + keyMap = &cacheservice.KeyMapMetadata{} + } else { + keyMap = cachedOutput.GetMetadata().GetKeyMap() + } + + serializedMetadata, err := proto.Marshal(keyMap) + if err != nil { + logger.Debugf(ctx, "Failed to marshal output metadata with error %v", err) + return nil, errors.NewCacheServiceErrorf(codes.Internal, "Failed to marshal output metadata with error %v", err) + } + + return &models.CachedOutput{ + ID: key, + OutputURI: cachedOutput.GetOutputUri(), + OutputLiteral: outputLiteralBytes, + Identifier: models.Identifier{ + ResourceType: cachedOutput.GetMetadata().GetSourceIdentifier().GetResourceType(), + Project: cachedOutput.GetMetadata().GetSourceIdentifier().GetProject(), + Domain: cachedOutput.GetMetadata().GetSourceIdentifier().GetDomain(), + Name: cachedOutput.GetMetadata().GetSourceIdentifier().GetName(), + Version: cachedOutput.GetMetadata().GetSourceIdentifier().GetVersion(), + Org: cachedOutput.GetMetadata().GetSourceIdentifier().GetOrg(), + }, + SerializedMetadata: serializedMetadata, + }, nil +} + +func FromCachedOutputModel(ctx context.Context, cachedOutputModel *models.CachedOutput) (*cacheservice.CachedOutput, error) { + var keyMapMetadata cacheservice.KeyMapMetadata + err := proto.Unmarshal(cachedOutputModel.SerializedMetadata, &keyMapMetadata) + if err != nil { + logger.Debugf(ctx, "Failed to unmarshal output metadata with error %v", err) + return nil, errors.NewCacheServiceErrorf(codes.Internal, "Failed to unmarshal output metadata with error %v", err) + } + + if cachedOutputModel.OutputLiteral != nil { + outputLiteral := &core.LiteralMap{} + err := proto.Unmarshal(cachedOutputModel.OutputLiteral, outputLiteral) + if err != nil { + logger.Debugf(ctx, "Failed to unmarshal output literal with error %v", err) + return nil, errors.NewCacheServiceErrorf(codes.Internal, "Failed to unmarshal output literal with error %v", err) + } + + return &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputLiterals{OutputLiterals: outputLiteral}, + Metadata: &cacheservice.Metadata{ + SourceIdentifier: &core.Identifier{ + ResourceType: cachedOutputModel.Identifier.ResourceType, + Project: cachedOutputModel.Identifier.Project, + Domain: cachedOutputModel.Identifier.Domain, + Name: cachedOutputModel.Identifier.Name, + Version: cachedOutputModel.Identifier.Version, + Org: cachedOutputModel.Identifier.Org, + }, + KeyMap: &keyMapMetadata, + }, + }, nil + } + + return &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputUri{OutputUri: cachedOutputModel.OutputURI}, + Metadata: &cacheservice.Metadata{ + SourceIdentifier: &core.Identifier{ + ResourceType: cachedOutputModel.Identifier.ResourceType, + Project: cachedOutputModel.Identifier.Project, + Domain: cachedOutputModel.Identifier.Domain, + Name: cachedOutputModel.Identifier.Name, + Version: cachedOutputModel.Identifier.Version, + Org: cachedOutputModel.Identifier.Org, + }, + KeyMap: &keyMapMetadata, + }, + }, nil +} diff --git a/cacheservice/repositories/transformers/cached_output_test.go b/cacheservice/repositories/transformers/cached_output_test.go new file mode 100644 index 0000000000..185b0e9074 --- /dev/null +++ b/cacheservice/repositories/transformers/cached_output_test.go @@ -0,0 +1,142 @@ +package transformers + +import ( + "context" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc/codes" + + "github.com/flyteorg/flyte/cacheservice/repositories/models" + "github.com/flyteorg/flyte/flyteidl/clients/go/coreutils" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" +) + +func TestCreateCachedOutputModel(t *testing.T) { + ctx := context.Background() + + sampleKey := "test-key" + sampleURI := "test-uri" + sampleOutputLiteral, err := coreutils.MakeLiteralMap(map[string]interface{}{"c": 3}) + assert.NoError(t, err) + sampleOutputLiteralBytes, err := proto.Marshal(sampleOutputLiteral) + assert.NoError(t, err) + + sampleKeyMapValues := map[string]string{"a": "b"} + sampleKeyMap := &cacheservice.KeyMapMetadata{ + Values: sampleKeyMapValues, + } + sampleKeyMapBytes, err := proto.Marshal(sampleKeyMap) + assert.NoError(t, err) + + validOutputLiterals := &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputLiterals{ + OutputLiterals: sampleOutputLiteral, + }, + Metadata: &cacheservice.Metadata{ + SourceIdentifier: &core.Identifier{}, + }, + } + + validOutputKeyMap := &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputUri{ + OutputUri: sampleURI, + }, + Metadata: &cacheservice.Metadata{ + SourceIdentifier: &core.Identifier{}, + KeyMap: sampleKeyMap, + }, + } + + tests := []struct { + name string + key string + cachedOutput *cacheservice.CachedOutput + expectError bool + expectedOutput *models.CachedOutput + }{ + { + name: "valid output literals", + key: sampleKey, + cachedOutput: validOutputLiterals, + expectError: false, + expectedOutput: &models.CachedOutput{ + ID: sampleKey, + OutputURI: "", + OutputLiteral: sampleOutputLiteralBytes, + Identifier: models.Identifier{}, + SerializedMetadata: []byte{}, + }, + }, + { + name: "valid output key map", + key: sampleKey, + cachedOutput: validOutputKeyMap, + expectError: false, + expectedOutput: &models.CachedOutput{ + ID: sampleKey, + OutputURI: sampleURI, + OutputLiteral: nil, + Identifier: models.Identifier{}, + SerializedMetadata: sampleKeyMapBytes, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := CreateCachedOutputModel(ctx, tc.key, tc.cachedOutput) + + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.NotNil(t, result) + assert.EqualValues(t, tc.expectedOutput, result) + } + }) + } +} + +func TestFromCachedOutputModel(t *testing.T) { + ctx := context.Background() + + tests := []struct { + name string + cachedOutputModel *models.CachedOutput + expectError bool + errorCode codes.Code + }{ + { + name: "valid output literal", + cachedOutputModel: &models.CachedOutput{ + OutputLiteral: []byte{}, + Identifier: models.Identifier{}, + }, + expectError: false, + }, + { + name: "valid output URI", + cachedOutputModel: &models.CachedOutput{ + OutputURI: "some-uri", + Identifier: models.Identifier{}, + }, + expectError: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := FromCachedOutputModel(ctx, tc.cachedOutputModel) + + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.NotNil(t, result) + } + }) + } +} diff --git a/cacheservice/repositories/transformers/reservation.go b/cacheservice/repositories/transformers/reservation.go new file mode 100644 index 0000000000..0e6ac30f9d --- /dev/null +++ b/cacheservice/repositories/transformers/reservation.go @@ -0,0 +1,18 @@ +package transformers + +import ( + "context" + + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/flyteorg/flyte/cacheservice/repositories/models" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" +) + +func FromReservationModel(ctx context.Context, reservationModel *models.Reservation) *cacheservice.Reservation { + return &cacheservice.Reservation{ + Key: reservationModel.Key, + OwnerId: reservationModel.OwnerID, + ExpiresAt: timestamppb.New(reservationModel.ExpiresAt), + } +} diff --git a/cacheservice/repositories/transformers/reservation_test.go b/cacheservice/repositories/transformers/reservation_test.go new file mode 100644 index 0000000000..b26d853aab --- /dev/null +++ b/cacheservice/repositories/transformers/reservation_test.go @@ -0,0 +1,31 @@ +package transformers + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/flyteorg/flyte/cacheservice/repositories/models" +) + +func TestFromReservationModel(t *testing.T) { + t.Run("TestFromReservationModel", func(t *testing.T) { + + testKey := "test-key" + testOwnerID := "test-owner-id" + testTime := time.Date(2024, time.January, 1, 0, 0, 0, 0, time.UTC) + + mockReservationModel := &models.Reservation{ + Key: testKey, + OwnerID: testOwnerID, + ExpiresAt: testTime, + } + + reservation := FromReservationModel(context.TODO(), mockReservationModel) + assert.Equal(t, testKey, reservation.GetKey()) + assert.Equal(t, testOwnerID, reservation.GetOwnerId()) + assert.Equal(t, testTime, reservation.GetExpiresAt().AsTime()) + }) +} diff --git a/cmd/single/config.go b/cmd/single/config.go index adbabe7ae5..982f893c39 100644 --- a/cmd/single/config.go +++ b/cmd/single/config.go @@ -10,9 +10,10 @@ var ( ) type Config struct { - Propeller Propeller `json:"propeller" pflag:",Configuration to disable propeller or any of its components."` - Admin Admin `json:"admin" pflag:",Configuration to disable FlyteAdmin or any of its components"` - DataCatalog DataCatalog `json:"dataCatalog" pflag:",Configuration to disable DataCatalog or any of its components"` + Propeller Propeller `json:"propeller" pflag:",Configuration to disable propeller or any of its components."` + Admin Admin `json:"admin" pflag:",Configuration to disable FlyteAdmin or any of its components"` + DataCatalog DataCatalog `json:"dataCatalog" pflag:",Configuration to disable DataCatalog or any of its components"` + CacheService CacheService `json:"cacheService" pflag:",Configuration to disable CacheService or any of its components"` } type Propeller struct { @@ -31,6 +32,10 @@ type DataCatalog struct { Disabled bool `json:"disabled" pflag:",Disables datacatalog in the single binary mode"` } +type CacheService struct { + Disabled bool `json:"disabled" pflag:",Disables cacheservice in the single binary mode"` +} + // GetConfig returns a handle to the configuration for Flyte Single Binary func GetConfig() *Config { return configSection.GetConfig().(*Config) diff --git a/cmd/single/start.go b/cmd/single/start.go index d415f82111..2e145969d5 100644 --- a/cmd/single/start.go +++ b/cmd/single/start.go @@ -5,18 +5,8 @@ import ( "net/http" "os" - metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" - ctrlWebhook "sigs.k8s.io/controller-runtime/pkg/webhook" - - _ "github.com/golang/glog" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/spf13/cobra" - "golang.org/x/sync/errgroup" - _ "gorm.io/driver/postgres" // Required to import database driver. - "sigs.k8s.io/controller-runtime/pkg/cache" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/metrics" - + cacheserviceConfig "github.com/flyteorg/flyte/cacheservice/pkg/config" + "github.com/flyteorg/flyte/cacheservice/pkg/rpc/cacheservice" datacatalogConfig "github.com/flyteorg/flyte/datacatalog/pkg/config" datacatalogRepo "github.com/flyteorg/flyte/datacatalog/pkg/repositories" datacatalog "github.com/flyteorg/flyte/datacatalog/pkg/rpc/datacatalogservice" @@ -39,6 +29,16 @@ import ( "github.com/flyteorg/flyte/flytestdlib/promutils" "github.com/flyteorg/flyte/flytestdlib/promutils/labeled" "github.com/flyteorg/flyte/flytestdlib/storage" + _ "github.com/golang/glog" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/spf13/cobra" + "golang.org/x/sync/errgroup" + _ "gorm.io/driver/postgres" // Required to import database driver. + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/metrics" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + ctrlWebhook "sigs.k8s.io/controller-runtime/pkg/webhook" ) const defaultNamespace = "all" @@ -52,6 +52,11 @@ func startDataCatalog(ctx context.Context, _ DataCatalog) error { return datacatalog.ServeInsecure(ctx, catalogCfg) } +func startCacheService(ctx context.Context, _ CacheService) error { + cacheCfg := cacheserviceConfig.GetConfig() + return cacheservice.ServeInsecure(ctx, cacheCfg) +} + func startClusterResourceController(ctx context.Context) error { configuration := runtime.NewConfigurationProvider() scope := promutils.NewScope(configuration.ApplicationConfiguration().GetTopLevelConfig().MetricsScope).NewSubScope("clusterresource") @@ -241,6 +246,17 @@ var startCmd = &cobra.Command{ }) } + if !cfg.CacheService.Disabled { + g.Go(func() error { + err := startCacheService(childCtx, cfg.CacheService) + if err != nil { + logger.Panicf(childCtx, "Failed to start CacheService, err: %v", err) + return err + } + return nil + }) + } + return g.Wait() }, } diff --git a/flyteadmin/go.mod b/flyteadmin/go.mod index 492cc7d6c5..028823601b 100644 --- a/flyteadmin/go.mod +++ b/flyteadmin/go.mod @@ -221,6 +221,7 @@ require ( retract v1.1.94 replace ( + github.com/flyteorg/flyte/cacheservice => ../cacheservice github.com/flyteorg/flyte/datacatalog => ../datacatalog github.com/flyteorg/flyte/flyteadmin => ../flyteadmin github.com/flyteorg/flyte/flyteidl => ../flyteidl diff --git a/flyteplugins/go/tasks/pluginmachinery/catalog/hashing.go b/flyteplugins/go/tasks/pluginmachinery/catalog/hashing.go index 4cc2fbd5cd..ef5c0086bc 100644 --- a/flyteplugins/go/tasks/pluginmachinery/catalog/hashing.go +++ b/flyteplugins/go/tasks/pluginmachinery/catalog/hashing.go @@ -81,3 +81,22 @@ func HashLiteralMap(ctx context.Context, literalMap *core.LiteralMap, cacheIgnor return base64.RawURLEncoding.EncodeToString(inputsHash), nil } + +func HashIdentifierExceptVersion(ctx context.Context, id core.Identifier) (string, error) { + + // Exclude version from the ID hash to support cache hits across different versions of the same resource + idCopy := &core.Identifier{ + ResourceType: id.ResourceType, + Project: id.Project, + Domain: id.Domain, + Name: id.Name, + Org: id.Org, + } + + hash, err := pbhash.ComputeHashString(ctx, idCopy) + if err != nil { + return "", err + } + + return hash, nil +} diff --git a/flyteplugins/go/tasks/pluginmachinery/catalog/hashing_test.go b/flyteplugins/go/tasks/pluginmachinery/catalog/hashing_test.go index 51f2cdfe27..f45a0aa01c 100644 --- a/flyteplugins/go/tasks/pluginmachinery/catalog/hashing_test.go +++ b/flyteplugins/go/tasks/pluginmachinery/catalog/hashing_test.go @@ -669,3 +669,31 @@ func TestCacheIgnoreInputVars(t *testing.T) { assert.NoError(t, err) assert.Equal(t, hashDupe, hash) } + +func TestHashIdentifierExceptVersion(t *testing.T) { + identifier := core.Identifier{ + Project: "project_1", + Domain: "domain_1", + Name: "name_1", + Version: "0", + Org: "org_1", + } + + identifierDiffVersion := core.Identifier{ + Project: "project_1", + Domain: "domain_1", + Name: "name_1", + Version: "1", + Org: "org_1", + } + + expectedHashIdentifier := "+UmrGhEwHv3FesdpA4gliBluF3FUXz4tshmuOlw1FSk=" + + hashedIdentifier, err := HashIdentifierExceptVersion(context.TODO(), identifier) + assert.NoError(t, err) + assert.Equal(t, expectedHashIdentifier, hashedIdentifier) + + hashedIdentifierDiffVersion, err := HashIdentifierExceptVersion(context.TODO(), identifierDiffVersion) + assert.NoError(t, err) + assert.Equal(t, expectedHashIdentifier, hashedIdentifierDiffVersion) +} diff --git a/flyteplugins/go/tasks/pluginmachinery/ioutils/remote_file_output_reader.go b/flyteplugins/go/tasks/pluginmachinery/ioutils/remote_file_output_reader.go index 152644d828..cc3dc13fb1 100644 --- a/flyteplugins/go/tasks/pluginmachinery/ioutils/remote_file_output_reader.go +++ b/flyteplugins/go/tasks/pluginmachinery/ioutils/remote_file_output_reader.go @@ -12,19 +12,21 @@ import ( ) type RemoteFileOutputReader struct { - outPath io.OutputFilePaths + OutPath io.OutputFilePaths store storage.ComposedProtobufStore maxPayloadSize int64 } +var _ io.OutputReader = RemoteFileOutputReader{} + func (r RemoteFileOutputReader) IsError(ctx context.Context) (bool, error) { - metadata, err := r.store.Head(ctx, r.outPath.GetErrorPath()) + metadata, err := r.store.Head(ctx, r.OutPath.GetErrorPath()) if err != nil { - return false, errors.Wrapf(err, "failed to read error file @[%s]", r.outPath.GetErrorPath()) + return false, errors.Wrapf(err, "failed to read error file @[%s]", r.OutPath.GetErrorPath()) } if metadata.Exists() { if metadata.Size() > r.maxPayloadSize { - return false, errors.Wrapf(err, "error file @[%s] is too large [%d] bytes, max allowed [%d] bytes", r.outPath.GetErrorPath(), metadata.Size(), r.maxPayloadSize) + return false, errors.Wrapf(err, "error file @[%s] is too large [%d] bytes, max allowed [%d] bytes", r.OutPath.GetErrorPath(), metadata.Size(), r.maxPayloadSize) } return true, nil } @@ -33,7 +35,7 @@ func (r RemoteFileOutputReader) IsError(ctx context.Context) (bool, error) { func (r RemoteFileOutputReader) ReadError(ctx context.Context) (io.ExecutionError, error) { errorDoc := &core.ErrorDocument{} - err := r.store.ReadProtobuf(ctx, r.outPath.GetErrorPath(), errorDoc) + err := r.store.ReadProtobuf(ctx, r.OutPath.GetErrorPath(), errorDoc) if err != nil { if storage.IsNotFound(err) { return io.ExecutionError{ @@ -45,7 +47,7 @@ func (r RemoteFileOutputReader) ReadError(ctx context.Context) (io.ExecutionErro }, }, nil } - return io.ExecutionError{}, errors.Wrapf(err, "failed to read error data from task @[%s]", r.outPath.GetErrorPath()) + return io.ExecutionError{}, errors.Wrapf(err, "failed to read error data from task @[%s]", r.OutPath.GetErrorPath()) } if errorDoc.Error == nil { @@ -53,7 +55,7 @@ func (r RemoteFileOutputReader) ReadError(ctx context.Context) (io.ExecutionErro IsRecoverable: true, ExecutionError: &core.ExecutionError{ Code: "ErrorFileBadFormat", - Message: fmt.Sprintf("error not formatted correctly, nil error @path [%s]", r.outPath.GetErrorPath()), + Message: fmt.Sprintf("error not formatted correctly, nil error @path [%s]", r.OutPath.GetErrorPath()), Kind: core.ExecutionError_SYSTEM, }, }, nil @@ -75,13 +77,13 @@ func (r RemoteFileOutputReader) ReadError(ctx context.Context) (io.ExecutionErro } func (r RemoteFileOutputReader) Exists(ctx context.Context) (bool, error) { - md, err := r.store.Head(ctx, r.outPath.GetOutputPath()) + md, err := r.store.Head(ctx, r.OutPath.GetOutputPath()) if err != nil { return false, err } if md.Exists() { if md.Size() > r.maxPayloadSize { - return false, errors.Errorf("output file @[%s] is too large [%d] bytes, max allowed [%d] bytes", r.outPath.GetOutputPath(), md.Size(), r.maxPayloadSize) + return false, errors.Errorf("output file @[%s] is too large [%d] bytes, max allowed [%d] bytes", r.OutPath.GetOutputPath(), md.Size(), r.maxPayloadSize) } return true, nil } @@ -91,9 +93,9 @@ func (r RemoteFileOutputReader) Exists(ctx context.Context) (bool, error) { func (r RemoteFileOutputReader) Read(ctx context.Context) (*core.LiteralMap, *io.ExecutionError, error) { d := &core.LiteralMap{} - if err := r.store.ReadProtobuf(ctx, r.outPath.GetOutputPath(), d); err != nil { + if err := r.store.ReadProtobuf(ctx, r.OutPath.GetOutputPath(), d); err != nil { // TODO change flytestdlib to return protobuf unmarshal errors separately. As this can indicate malformed output and we should catch that - return nil, nil, fmt.Errorf("failed to read data from dataDir [%v]. Error: %v", r.outPath.GetOutputPath(), err) + return nil, nil, fmt.Errorf("failed to read data from dataDir [%v]. Error: %v", r.OutPath.GetOutputPath(), err) } if d.Literals == nil { @@ -101,7 +103,7 @@ func (r RemoteFileOutputReader) Read(ctx context.Context) (*core.LiteralMap, *io IsRecoverable: true, ExecutionError: &core.ExecutionError{ Code: "No outputs produced", - Message: fmt.Sprintf("outputs not found at [%s]", r.outPath.GetOutputPath()), + Message: fmt.Sprintf("outputs not found at [%s]", r.OutPath.GetOutputPath()), }, }, nil } @@ -114,7 +116,7 @@ func (r RemoteFileOutputReader) IsFile(ctx context.Context) bool { } func (r RemoteFileOutputReader) DeckExists(ctx context.Context) (bool, error) { - md, err := r.store.Head(ctx, r.outPath.GetDeckPath()) + md, err := r.store.Head(ctx, r.OutPath.GetDeckPath()) if err != nil { return false, err } @@ -124,7 +126,7 @@ func (r RemoteFileOutputReader) DeckExists(ctx context.Context) (bool, error) { func NewRemoteFileOutputReader(_ context.Context, store storage.ComposedProtobufStore, outPaths io.OutputFilePaths, maxDatasetSize int64) RemoteFileOutputReader { return RemoteFileOutputReader{ - outPath: outPaths, + OutPath: outPaths, store: store, maxPayloadSize: maxDatasetSize, } diff --git a/flyteplugins/go/tasks/pluginmachinery/ioutils/remote_file_output_reader_test.go b/flyteplugins/go/tasks/pluginmachinery/ioutils/remote_file_output_reader_test.go index 0e7ae179d9..981a98652b 100644 --- a/flyteplugins/go/tasks/pluginmachinery/ioutils/remote_file_output_reader_test.go +++ b/flyteplugins/go/tasks/pluginmachinery/ioutils/remote_file_output_reader_test.go @@ -61,7 +61,7 @@ func TestReadOrigin(t *testing.T) { }, nil) r := RemoteFileOutputReader{ - outPath: opath, + OutPath: opath, store: store, maxPayloadSize: 0, } @@ -93,7 +93,7 @@ func TestReadOrigin(t *testing.T) { }).Return(nil) r := RemoteFileOutputReader{ - outPath: opath, + OutPath: opath, store: store, maxPayloadSize: 0, } diff --git a/flytepropeller/cmd/controller/cmd/root.go b/flytepropeller/cmd/controller/cmd/root.go index e1069650ad..144bc055a8 100644 --- a/flytepropeller/cmd/controller/cmd/root.go +++ b/flytepropeller/cmd/controller/cmd/root.go @@ -120,7 +120,8 @@ func executeRootCmd(baseCtx context.Context, cfg *config2.Config) error { // register opentelementry tracer providers for _, serviceName := range []string{otelutils.AdminClientTracer, otelutils.BlobstoreClientTracer, - otelutils.DataCatalogClientTracer, otelutils.FlytePropellerTracer, otelutils.K8sClientTracer} { + otelutils.DataCatalogClientTracer, otelutils.CacheServiceClientTracer, + otelutils.FlytePropellerTracer, otelutils.K8sClientTracer} { if err := otelutils.RegisterTracerProvider(serviceName, otelutils.GetConfig()); err != nil { logger.Errorf(ctx, "Failed to create otel tracer provider. %v", err) return err diff --git a/flytepropeller/pkg/controller/controller.go b/flytepropeller/pkg/controller/controller.go index db2ec55261..d1f103ac95 100644 --- a/flytepropeller/pkg/controller/controller.go +++ b/flytepropeller/pkg/controller/controller.go @@ -412,10 +412,10 @@ func New(ctx context.Context, cfg *config.Config, kubeClientset kubernetes.Inter flytek8s.DefaultPodTemplateStore.SetDefaultNamespace(podNamespace) - logger.Info(ctx, "Setting up Catalog client.") - catalogClient, err := catalog.NewCatalogClient(ctx, authOpts...) + logger.Info(ctx, "Setting up Cache client.") + cacheClient, err := catalog.NewCacheClient(ctx, store, authOpts...) if err != nil { - return nil, errors.Wrapf(err, "Failed to create datacatalog client") + return nil, errors.Wrapf(err, "Failed to create cache client") } workQ, err := NewCompositeWorkQueue(ctx, cfg.Queue, scope) @@ -433,14 +433,14 @@ func New(ctx context.Context, cfg *config.Config, kubeClientset kubernetes.Inter recoveryClient := recovery.NewClient(adminClient) nodeHandlerFactory, err := factory.NewHandlerFactory(ctx, launchPlanActor, launchPlanActor, - kubeClient, kubeClientset, catalogClient, recoveryClient, &cfg.EventConfig, cfg.ClusterID, signalClient, scope) + kubeClient, kubeClientset, cacheClient, recoveryClient, &cfg.EventConfig, cfg.ClusterID, signalClient, scope) if err != nil { return nil, errors.Wrapf(err, "failed to create node handler factory") } nodeExecutor, err := nodes.NewExecutor(ctx, cfg.NodeConfig, store, controller.enqueueWorkflowForNodeUpdates, eventSink, launchPlanActor, launchPlanActor, cfg.MaxDatasetSizeBytes, storage.DataReference(cfg.DefaultRawOutputPrefix), kubeClient, - catalogClient, recoveryClient, &cfg.EventConfig, cfg.ClusterID, signalClient, nodeHandlerFactory, scope) + cacheClient, recoveryClient, &cfg.EventConfig, cfg.ClusterID, signalClient, nodeHandlerFactory, scope) if err != nil { return nil, errors.Wrapf(err, "Failed to create Controller.") } diff --git a/flytepropeller/pkg/controller/nodes/cache.go b/flytepropeller/pkg/controller/nodes/cache.go index f1807becc7..fa0d186b98 100644 --- a/flytepropeller/pkg/controller/nodes/cache.go +++ b/flytepropeller/pkg/controller/nodes/cache.go @@ -118,10 +118,10 @@ func updatePhaseCacheInfo(phaseInfo handler.PhaseInfo, cacheStatus *catalog.Stat func (n *nodeExecutor) CheckCatalogCache(ctx context.Context, nCtx interfaces.NodeExecutionContext, cacheHandler interfaces.CacheableNodeHandler) (catalog.Entry, error) { catalogKey, err := getCatalogKeyWithOverrides(ctx, nCtx, cacheHandler) if err != nil { - return catalog.Entry{}, errors.Wrapf(err, "failed to initialize the catalogKey") + return catalog.Entry{}, errors.Wrapf(err, "failed to initialize the cacheKey") } - entry, err := n.catalog.Get(ctx, catalogKey) + entry, err := n.cache.Get(ctx, catalogKey) if err != nil { causeErr := errors.Cause(err) if taskStatus, ok := status.FromError(causeErr); ok && taskStatus.Code() == codes.NotFound { @@ -185,7 +185,7 @@ func (n *nodeExecutor) GetOrExtendCatalogReservation(ctx context.Context, nCtx i errors.Wrapf(err, "failed to initialize the cache reservation ownerID") } - reservation, err := n.catalog.GetOrExtendReservation(ctx, catalogKey, ownerID, heartbeatInterval) + reservation, err := n.cache.GetOrExtendReservation(ctx, catalogKey, ownerID, heartbeatInterval) if err != nil { n.metrics.reservationGetFailureCount.Inc(ctx) logger.Errorf(ctx, "Catalog Failure: reservation get or extend failed. err: %v", err.Error()) @@ -222,7 +222,7 @@ func (n *nodeExecutor) ReleaseCatalogReservation(ctx context.Context, nCtx inter errors.Wrapf(err, "failed to initialize the cache reservation ownerID") } - err = n.catalog.ReleaseReservation(ctx, catalogKey, ownerID) + err = n.cache.ReleaseReservation(ctx, catalogKey, ownerID) if err != nil { n.metrics.reservationReleaseFailureCount.Inc(ctx) logger.Errorf(ctx, "Catalog Failure: release reservation failed. err: %v", err.Error()) @@ -238,9 +238,8 @@ func (n *nodeExecutor) ReleaseCatalogReservation(ctx context.Context, nCtx inter func (n *nodeExecutor) WriteCatalogCache(ctx context.Context, nCtx interfaces.NodeExecutionContext, cacheHandler interfaces.CacheableNodeHandler) (catalog.Status, error) { catalogKey, err := getCatalogKeyWithOverrides(ctx, nCtx, cacheHandler) if err != nil { - return catalog.NewStatus(core.CatalogCacheStatus_CACHE_DISABLED, nil), errors.Wrapf(err, "failed to initialize the catalogKey") + return catalog.NewStatus(core.CatalogCacheStatus_CACHE_DISABLED, nil), errors.Wrapf(err, "failed to initialize the cacheKey") } - iface := catalogKey.TypedInterface if iface.Outputs != nil && len(iface.Outputs.Variables) == 0 { return catalog.NewStatus(core.CatalogCacheStatus_CACHE_DISABLED, nil), nil @@ -265,9 +264,9 @@ func (n *nodeExecutor) WriteCatalogCache(ctx context.Context, nCtx interfaces.No // ignores discovery write failures var status catalog.Status if nCtx.ExecutionContext().GetExecutionConfig().OverwriteCache { - status, err = n.catalog.Update(ctx, catalogKey, outputReader, metadata) + status, err = n.cache.Update(ctx, catalogKey, outputReader, metadata) } else { - status, err = n.catalog.Put(ctx, catalogKey, outputReader, metadata) + status, err = n.cache.Put(ctx, catalogKey, outputReader, metadata) } if err != nil { n.metrics.catalogPutFailureCount.Inc(ctx) diff --git a/flytepropeller/pkg/controller/nodes/cache_test.go b/flytepropeller/pkg/controller/nodes/cache_test.go index b53650c977..1c437a26d8 100644 --- a/flytepropeller/pkg/controller/nodes/cache_test.go +++ b/flytepropeller/pkg/controller/nodes/cache_test.go @@ -228,7 +228,7 @@ func TestCheckCatalogCache(t *testing.T) { assert.NoError(t, err) nodeExecutor := &nodeExecutor{ - catalog: catalogClient, + cache: catalogClient, metrics: metrics, } nCtx := setupCacheableNodeExecutionContext(dataStore, nil) @@ -345,7 +345,7 @@ func TestGetOrExtendCatalogReservation(t *testing.T) { ) nodeExecutor := &nodeExecutor{ - catalog: catalogClient, + cache: catalogClient, metrics: metrics, } nCtx := setupCacheableNodeExecutionContext(nil, &core.TaskTemplate{}) @@ -401,7 +401,7 @@ func TestReleaseCatalogReservation(t *testing.T) { catalogClient.OnReleaseReservationMatch(mock.Anything, mock.Anything, mock.Anything).Return(test.releaseError) nodeExecutor := &nodeExecutor{ - catalog: catalogClient, + cache: catalogClient, metrics: metrics, } nCtx := setupCacheableNodeExecutionContext(nil, &core.TaskTemplate{}) @@ -483,7 +483,7 @@ func TestWriteCatalogCache(t *testing.T) { assert.NoError(t, err) nodeExecutor := &nodeExecutor{ - catalog: catalogClient, + cache: catalogClient, metrics: metrics, } nCtx := setupCacheableNodeExecutionContext(dataStore, &core.TaskTemplate{}) diff --git a/flytepropeller/pkg/controller/nodes/catalog/cacheservice/cache_client.go b/flytepropeller/pkg/controller/nodes/catalog/cacheservice/cache_client.go new file mode 100644 index 0000000000..54e367382f --- /dev/null +++ b/flytepropeller/pkg/controller/nodes/catalog/cacheservice/cache_client.go @@ -0,0 +1,272 @@ +package cacheservice + +import ( + "context" + "crypto/x509" + "fmt" + "time" + + "github.com/golang/protobuf/ptypes" + grpcRetry "github.com/grpc-ecosystem/go-grpc-middleware/retry" + grpcPrometheus "github.com/grpc-ecosystem/go-grpc-prometheus" + "github.com/pkg/errors" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" + "go.opentelemetry.io/otel/propagation" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/status" + + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" + catalogIdl "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/datacatalog" + "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/catalog" + "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/io" + "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/ioutils" + "github.com/flyteorg/flyte/flytestdlib/logger" + "github.com/flyteorg/flyte/flytestdlib/otelutils" + "github.com/flyteorg/flyte/flytestdlib/storage" +) + +var ( + _ catalog.Client = &CacheClient{} +) + +type CacheClient struct { + client cacheservice.CacheServiceClient + store *storage.DataStore + maxCacheAge time.Duration + inlineCache bool +} + +func (c *CacheClient) GetOrExtendReservation(ctx context.Context, key catalog.Key, ownerID string, heartbeatInterval time.Duration) (*catalogIdl.Reservation, error) { + cacheKey, err := GenerateCacheKey(ctx, key) + if err != nil { + logger.Errorf(ctx, "Failed to generate cache key for %v, err %v", key.Identifier, err) + return nil, errors.Wrapf(err, "Failed to generate cache key for %v", key.Identifier.String()) + } + + response, err := c.client.GetOrExtendReservation(ctx, &cacheservice.GetOrExtendReservationRequest{ + Key: cacheKey, + OwnerId: ownerID, + HeartbeatInterval: ptypes.DurationProto(heartbeatInterval), + }) + if err != nil { + return nil, err + } + + catalogReservation := &catalogIdl.Reservation{ + OwnerId: response.Reservation.OwnerId, + ExpiresAt: response.Reservation.ExpiresAt, + HeartbeatInterval: response.Reservation.HeartbeatInterval, + } + + return catalogReservation, nil +} + +func (c *CacheClient) ReleaseReservation(ctx context.Context, key catalog.Key, ownerID string) error { + cacheKey, err := GenerateCacheKey(ctx, key) + if err != nil { + logger.Errorf(ctx, "Failed to generate cache key for %v, err %v", key.Identifier, err) + return errors.Wrapf(err, "Failed to generate cache key for %v", key.Identifier.String()) + } + + _, err = c.client.ReleaseReservation(ctx, &cacheservice.ReleaseReservationRequest{ + Key: cacheKey, + OwnerId: ownerID, + }) + if err != nil { + return err + } + return nil +} + +func (c *CacheClient) Get(ctx context.Context, key catalog.Key) (catalog.Entry, error) { + cacheKey, err := GenerateCacheKey(ctx, key) + if err != nil { + logger.Errorf(ctx, "Failed to generate cache key for %v, err %v", key.Identifier, err) + return catalog.Entry{}, errors.Wrapf(err, "Failed to generate cache key for %v", key.Identifier.String()) + } + + resp, err := c.client.Get(ctx, &cacheservice.GetCacheRequest{ + Key: cacheKey, + }) + if err != nil { + logger.Debugf(ctx, "CacheService failed to get output for ID %s, err: %+v", key.Identifier.String(), err) + return catalog.Entry{}, errors.Wrapf(err, "CacheService failed to get output for ID %s", key.Identifier.String()) + } + + // validate response + if resp.GetOutput() == nil || resp.GetOutput().Output == nil || resp.GetOutput().GetMetadata() == nil { + logger.Errorf(ctx, "Received malformed response from cache service") + return catalog.Entry{}, status.Error(codes.Internal, "Received malformed response from cache service") + } + + if c.maxCacheAge > time.Duration(0) { + if time.Since(resp.GetOutput().GetMetadata().CreatedAt.AsTime()) > c.maxCacheAge { + logger.Infof(ctx, "Expired Cached Output %v created on %v, older than max age %v", + resp.GetOutput().GetMetadata().GetSourceIdentifier(), resp.GetOutput().GetMetadata().GetCreatedAt(), c.maxCacheAge) + return catalog.Entry{}, status.Error(codes.NotFound, "Artifact over age limit") + } + } + + outputs := &core.LiteralMap{} + switch output := resp.Output.Output.(type) { + case *cacheservice.CachedOutput_OutputLiterals: + outputs = output.OutputLiterals + case *cacheservice.CachedOutput_OutputUri: + err = c.store.ReadProtobuf(ctx, storage.DataReference(resp.GetOutput().GetOutputUri()), outputs) + if err != nil { + return catalog.Entry{}, errors.Wrapf(err, "Failed to read output data from '%s'", storage.DataReference(resp.GetOutput().GetOutputUri())) + } + default: + // should never happen + return catalog.Entry{}, status.Error(codes.Internal, "Received malformed response from cache service") + } + + source, err := GetSourceFromMetadata(resp.Output.Metadata) + if err != nil { + return catalog.Entry{}, errors.Wrapf(err, "failed to get source from output metadata") + } + if source == nil { + return catalog.Entry{}, errors.New("failed to get source from output metadata") + } + md := GenerateCatalogMetadata(source, resp.Output.Metadata) + + return catalog.NewCatalogEntry(ioutils.NewInMemoryOutputReader(outputs, nil, nil), catalog.NewStatus(core.CatalogCacheStatus_CACHE_HIT, md)), nil +} + +func (c *CacheClient) put(ctx context.Context, key catalog.Key, reader io.OutputReader, metadata catalog.Metadata, overwrite bool) (catalog.Status, error) { + cacheKey, err := GenerateCacheKey(ctx, key) + if err != nil { + logger.Errorf(ctx, "Failed to generate cache key for %v, err %v", key.Identifier, err) + return catalog.Status{}, errors.Wrapf(err, "Failed to generate cache key for %v", key.Identifier.String()) + } + + var cacheRequest *cacheservice.PutCacheRequest + if c.inlineCache { + outputs, executionErr, err := reader.Read(ctx) + if executionErr != nil { + logger.Errorf(ctx, "Failed to read output for %v, err %v", key.Identifier, executionErr) + return catalog.Status{}, errors.New(fmt.Sprintf("Failed to read output for %v, err %v", key.Identifier, executionErr)) + } + if err != nil { + logger.Errorf(ctx, "Failed to read output for %v, err %v", key.Identifier, err) + return catalog.Status{}, err + } + cacheRequest = &cacheservice.PutCacheRequest{ + Key: cacheKey, + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputLiterals{ + OutputLiterals: outputs, + }, + Metadata: GenerateCacheMetadata(key, metadata), + }, + Overwrite: overwrite, + } + } else { + remoteFileOutputReader, ok := reader.(ioutils.RemoteFileOutputReader) + if !ok { + logger.Warnf(ctx, "Remote file output reader is expected for non-inline caching") + return catalog.Status{}, errors.New("remote file output reader is expected for non-inline caching") + } + exists, err := remoteFileOutputReader.Exists(ctx) + if err != nil { + logger.Errorf(ctx, "Failed to check if output file exists for %v, err %v", key.Identifier, err) + return catalog.Status{}, errors.Wrapf(err, "failed to check if output file exists for %v", key.Identifier.String()) + } + if !exists { + logger.Errorf(ctx, "Output file does not exist for %v", key.Identifier) + return catalog.Status{}, status.Errorf(codes.NotFound, "Output file does not exist for %v", key.Identifier) + } + outputURI := remoteFileOutputReader.OutPath.GetOutputPath() + + cacheRequest = &cacheservice.PutCacheRequest{ + Key: cacheKey, + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputUri{ + OutputUri: outputURI.String(), + }, + Metadata: GenerateCacheMetadata(key, metadata), + }, + Overwrite: overwrite, + } + } + + _, err = c.client.Put(ctx, cacheRequest) + if err != nil { + logger.Errorf(ctx, "Caching output for %v returned err %v", key.Identifier, err) + return catalog.Status{}, err + } + + md := &core.CatalogMetadata{ + DatasetId: &key.Identifier, + } + + return catalog.NewStatus(core.CatalogCacheStatus_CACHE_POPULATED, md), nil +} + +func (c *CacheClient) Update(ctx context.Context, key catalog.Key, reader io.OutputReader, metadata catalog.Metadata) (catalog.Status, error) { + return c.put(ctx, key, reader, metadata, true) +} + +func (c *CacheClient) Put(ctx context.Context, key catalog.Key, reader io.OutputReader, metadata catalog.Metadata) (catalog.Status, error) { + return c.put(ctx, key, reader, metadata, false) +} + +func NewCacheClient(ctx context.Context, dataStore *storage.DataStore, endpoint string, insecureConnection bool, maxCacheAge time.Duration, + useAdminAuth bool, maxRetries int, maxPerRetryTimeout time.Duration, backOffScalar int, inlineCache bool, defaultServiceConfig string, authOpt ...grpc.DialOption) (*CacheClient, error) { + var opts []grpc.DialOption + if useAdminAuth && authOpt != nil { + opts = append(opts, authOpt...) + } + + grpcOptions := []grpcRetry.CallOption{ + grpcRetry.WithBackoff(grpcRetry.BackoffLinear(time.Duration(backOffScalar) * time.Millisecond)), + grpcRetry.WithCodes(codes.DeadlineExceeded, codes.Unavailable, codes.Canceled), + grpcRetry.WithMax(uint(maxRetries)), + grpcRetry.WithPerRetryTimeout(maxPerRetryTimeout), + } + + if insecureConnection { + logger.Debug(ctx, "Establishing insecure connection to CacheService") + opts = append(opts, grpc.WithInsecure()) + } else { + logger.Debug(ctx, "Establishing secure connection to CacheService") + pool, err := x509.SystemCertPool() + if err != nil { + return nil, err + } + + creds := credentials.NewClientTLSFromCert(pool, "") + opts = append(opts, grpc.WithTransportCredentials(creds)) + } + + if defaultServiceConfig != "" { + opts = append(opts, grpc.WithDefaultServiceConfig(defaultServiceConfig)) + } + + retryInterceptor := grpcRetry.UnaryClientInterceptor(grpcOptions...) + + tracerProvider := otelutils.GetTracerProvider(otelutils.CacheServiceClientTracer) + opts = append(opts, grpc.WithChainUnaryInterceptor( + grpcPrometheus.UnaryClientInterceptor, + otelgrpc.UnaryClientInterceptor( + otelgrpc.WithTracerProvider(tracerProvider), + otelgrpc.WithPropagators(propagation.TraceContext{}), + ), + retryInterceptor)) + clientConn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return nil, err + } + client := cacheservice.NewCacheServiceClient(clientConn) + + return &CacheClient{ + client: client, + store: dataStore, + maxCacheAge: maxCacheAge, + inlineCache: inlineCache, + }, nil + +} diff --git a/flytepropeller/pkg/controller/nodes/catalog/cacheservice/cache_client_test.go b/flytepropeller/pkg/controller/nodes/catalog/cacheservice/cache_client_test.go new file mode 100644 index 0000000000..362e1a2408 --- /dev/null +++ b/flytepropeller/pkg/controller/nodes/catalog/cacheservice/cache_client_test.go @@ -0,0 +1,595 @@ +package cacheservice + +import ( + "context" + "testing" + "time" + + "github.com/golang/protobuf/ptypes" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/flyteorg/flyte/flyteidl/clients/go/cacheservice/mocks" + "github.com/flyteorg/flyte/flyteidl/clients/go/coreutils" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" + "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/catalog" + "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/io" + mocks2 "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/io/mocks" + pluginsIOMock "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/io/mocks" + "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/ioutils" + "github.com/flyteorg/flyte/flytestdlib/storage" + storageMocks "github.com/flyteorg/flyte/flytestdlib/storage/mocks" +) + +var sampleIdentifier = core.Identifier{ + Project: "project_1", + Domain: "domain_1", + Name: "name_1", + Version: "0", + Org: "org_1", +} + +func generateCatalogKeys(ctx context.Context, t *testing.T) (catalog.Key, catalog.Key, string) { + sampleInputs, err := coreutils.MakeLiteralMap(map[string]interface{}{"a": 1, "b": 2}) + assert.NoError(t, err) + mockInputReader := &mocks2.InputReader{} + mockInputReader.On("Get", mock.Anything).Return(sampleInputs, nil, nil) + mockInputReaderErr := &mocks2.InputReader{} + mockInputReaderErr.On("Get", mock.Anything).Return(sampleInputs, errors.New("test error"), nil) + sampleInterface := core.TypedInterface{ + Inputs: &core.VariableMap{ + Variables: map[string]*core.Variable{ + "a": {Type: &core.LiteralType{Type: &core.LiteralType_Simple{Simple: core.SimpleType_INTEGER}}}, + "b": {Type: &core.LiteralType{Type: &core.LiteralType_Simple{Simple: core.SimpleType_INTEGER}}}, + }, + }, + } + sampleCatalogKey := catalog.Key{ + Identifier: sampleIdentifier, + CacheVersion: "1.0.0", + TypedInterface: sampleInterface, + InputReader: mockInputReader, + } + sampleCatalogKeyErr := catalog.Key{ + Identifier: sampleIdentifier, + CacheVersion: "1.0.0", + TypedInterface: sampleInterface, + InputReader: mockInputReaderErr, + } + sampleCacheKey, err := GenerateCacheKey(ctx, sampleCatalogKey) + assert.NoError(t, err) + _, err = GenerateCacheKey(ctx, sampleCatalogKeyErr) + assert.Error(t, err) + + return sampleCatalogKey, sampleCatalogKeyErr, sampleCacheKey +} + +func TestCache_Get(t *testing.T) { + ctx := context.Background() + + sampleCatalogKey, sampleCatalogKeyErr, sampleCacheKey := generateCatalogKeys(ctx, t) + + nonExpiredCreatedAt, err := ptypes.TimestampProto(time.Now().Add(time.Minute * 1)) + assert.NoError(t, err) + expiredCreatedAt, err := ptypes.TimestampProto(time.Now().Add(time.Minute * -61)) + assert.NoError(t, err) + sampleOutputLiteral, err := coreutils.MakeLiteralMap(map[string]interface{}{"c": 3}) + assert.NoError(t, err) + outputLiteral := &cacheservice.CachedOutput_OutputLiterals{ + OutputLiterals: sampleOutputLiteral, + } + outputURI := &cacheservice.CachedOutput_OutputUri{ + OutputUri: "s3://some-bucket/some-key", + } + + expiredResponse := &cacheservice.GetCacheResponse{ + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputLiterals{}, + Metadata: &cacheservice.Metadata{ + CreatedAt: expiredCreatedAt, + }, + }, + } + responseLiteral := &cacheservice.GetCacheResponse{ + Output: &cacheservice.CachedOutput{ + Output: outputLiteral, + Metadata: &cacheservice.Metadata{ + CreatedAt: nonExpiredCreatedAt, + SourceIdentifier: &sampleIdentifier, + }, + }, + } + responseURI := &cacheservice.GetCacheResponse{ + Output: &cacheservice.CachedOutput{ + Output: outputURI, + Metadata: &cacheservice.Metadata{ + CreatedAt: nonExpiredCreatedAt, + SourceIdentifier: &sampleIdentifier, + }, + }, + } + malformedOutputResponse := &cacheservice.GetCacheResponse{ + Output: &cacheservice.CachedOutput{ + Metadata: &cacheservice.Metadata{ + CreatedAt: nonExpiredCreatedAt, + SourceIdentifier: &sampleIdentifier, + }, + }, + } + nilMetadataResponse := &cacheservice.GetCacheResponse{ + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputUri{ + OutputUri: "s3://some-bucket/some-key", + }, + }, + } + malformedMetadataResponse := &cacheservice.GetCacheResponse{ + Output: &cacheservice.CachedOutput{ + Output: &cacheservice.CachedOutput_OutputUri{ + OutputUri: "s3://some-bucket/some-key", + }, + Metadata: &cacheservice.Metadata{ + CreatedAt: nonExpiredCreatedAt, + SourceIdentifier: nil, + }, + }, + } + + testCases := []struct { + name string + catalogKey catalog.Key + mockServiceReturnResponse *cacheservice.GetCacheResponse + mockServiceReturnError error + readPbError error + expectClientError bool + expectedClientStatus core.CatalogCacheStatus + expectedClientErrCode codes.Code + }{ + { + name: "generate cache key error", + catalogKey: sampleCatalogKeyErr, + mockServiceReturnResponse: nil, + mockServiceReturnError: nil, + expectClientError: true, + expectedClientStatus: core.CatalogCacheStatus_CACHE_DISABLED, + expectedClientErrCode: codes.Unknown, + }, + { + name: "cache miss", + catalogKey: sampleCatalogKey, + mockServiceReturnResponse: nil, + mockServiceReturnError: status.Error(codes.NotFound, "test not found"), + expectClientError: true, + expectedClientStatus: core.CatalogCacheStatus_CACHE_DISABLED, + expectedClientErrCode: codes.NotFound, + }, + { + name: "expired cache", + catalogKey: sampleCatalogKey, + mockServiceReturnResponse: expiredResponse, + mockServiceReturnError: nil, + expectClientError: true, + expectedClientStatus: core.CatalogCacheStatus_CACHE_DISABLED, + expectedClientErrCode: codes.NotFound, + }, + { + name: "non-expired cache - literal", + catalogKey: sampleCatalogKey, + mockServiceReturnResponse: responseLiteral, + mockServiceReturnError: nil, + expectClientError: false, + expectedClientStatus: core.CatalogCacheStatus_CACHE_HIT, + }, + { + name: "non-expired cache - uri", + catalogKey: sampleCatalogKey, + mockServiceReturnResponse: responseURI, + mockServiceReturnError: nil, + expectClientError: false, + expectedClientStatus: core.CatalogCacheStatus_CACHE_HIT, + }, + { + name: "non-expired cache - uri - read proto error", + catalogKey: sampleCatalogKey, + mockServiceReturnResponse: responseURI, + mockServiceReturnError: nil, + readPbError: errors.New("test error"), + expectClientError: true, + expectedClientStatus: core.CatalogCacheStatus_CACHE_DISABLED, + expectedClientErrCode: codes.Unknown, + }, + { + name: "malformed output response", + catalogKey: sampleCatalogKey, + mockServiceReturnResponse: malformedOutputResponse, + mockServiceReturnError: nil, + expectClientError: true, + expectedClientStatus: core.CatalogCacheStatus_CACHE_DISABLED, + expectedClientErrCode: codes.Internal, + }, + { + name: "nil metadata response", + catalogKey: sampleCatalogKey, + mockServiceReturnResponse: nilMetadataResponse, + mockServiceReturnError: nil, + expectClientError: true, + expectedClientStatus: core.CatalogCacheStatus_CACHE_DISABLED, + expectedClientErrCode: codes.Internal, + }, + { + name: "malformed metadata response", + catalogKey: sampleCatalogKey, + mockServiceReturnResponse: malformedMetadataResponse, + mockServiceReturnError: nil, + expectClientError: true, + expectedClientStatus: core.CatalogCacheStatus_CACHE_DISABLED, + expectedClientErrCode: codes.Unknown, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + mockPBStore := &storageMocks.ComposedProtobufStore{} + mockPBStore.On("ReadProtobuf", mock.Anything, mock.Anything, mock.Anything).Return(tc.readPbError) + store := &storage.DataStore{ + ComposedProtobufStore: mockPBStore, + ReferenceConstructor: &storageMocks.ReferenceConstructor{}, + } + mockServiceClient := &mocks.CacheServiceClient{} + mockServiceClient.On("Get", + ctx, + mock.MatchedBy(func(o *cacheservice.GetCacheRequest) bool { + assert.EqualValues(t, sampleCacheKey, o.Key) + return true + }), + ).Return(tc.mockServiceReturnResponse, tc.mockServiceReturnError) + + cacheClient := &CacheClient{ + client: mockServiceClient, + maxCacheAge: time.Hour, + store: store, + } + + resp, err := cacheClient.Get(ctx, tc.catalogKey) + if tc.expectClientError { + assert.Error(t, err) + assert.Equal(t, tc.expectedClientErrCode, status.Code(errors.Cause(err))) + } else { + assert.NoError(t, err) + assert.NotNil(t, resp) + } + assert.Equal(t, tc.expectedClientStatus, resp.GetStatus().GetCacheStatus()) + }) + } +} + +type MockStoreMetadata struct { + exists bool + size int64 + etag string +} + +func (m MockStoreMetadata) Size() int64 { + return m.size +} + +func (m MockStoreMetadata) Exists() bool { + return m.exists +} + +func (m MockStoreMetadata) Etag() string { + return m.etag +} + +func TestCache_Put(t *testing.T) { + ctx := context.Background() + + sampleCatalogKey, sampleCatalogKeyErr, sampleCacheKey := generateCatalogKeys(ctx, t) + + sampleOutputs, err := coreutils.MakeLiteralMap(map[string]interface{}{"c": 3}) + assert.NoError(t, err) + + mockOutputReader := &mocks2.OutputReader{} + mockOutputReader.On("Read", mock.Anything).Return(sampleOutputs, nil, nil) + mockOutputReader.On("GetOutputPath", mock.Anything).Return(storage.DataReference("s3://some-bucket/some-key"), nil) + + mockOutputReaderExecErr := &mocks2.OutputReader{} + mockOutputReaderExecErr.On("Read", mock.Anything).Return(nil, &io.ExecutionError{}, nil) + + mockOutputReaderErr := &mocks2.OutputReader{} + mockOutputReaderErr.On("Read", mock.Anything).Return(nil, nil, errors.New("test error")) + + opath := &pluginsIOMock.OutputFilePaths{} + opath.On("GetOutputPath").Return(storage.DataReference("s3://some-bucket/some-key")) + + composedProtobufStoreExists := &storageMocks.ComposedProtobufStore{} + composedProtobufStoreExists.On("Head", mock.Anything, mock.Anything).Return(MockStoreMetadata{exists: true}, nil) + mockRemoteFileOutputReader := ioutils.NewRemoteFileOutputReader(ctx, composedProtobufStoreExists, opath, 0) + + composedProtobufStoreNotExists := &storageMocks.ComposedProtobufStore{} + composedProtobufStoreNotExists.On("Head", mock.Anything, mock.Anything).Return(MockStoreMetadata{exists: false}, nil) + mockRemoteFileOutputReaderErr := ioutils.NewRemoteFileOutputReader(ctx, composedProtobufStoreNotExists, opath, 0) + + mockMetadata := catalog.Metadata{ + TaskExecutionIdentifier: &core.TaskExecutionIdentifier{}, + } + + testCases := []struct { + name string + catalogKey catalog.Key + mockOutputReader io.OutputReader + mockServiceReturnResponse *cacheservice.PutCacheResponse + mockServiceReturnError error + expectClientError bool + expectedClientStatus core.CatalogCacheStatus + expectedClientErrCode codes.Code + inlineCache bool + }{ + { + name: "successful put, literal", + catalogKey: sampleCatalogKey, + mockOutputReader: mockOutputReader, + mockServiceReturnResponse: &cacheservice.PutCacheResponse{}, + mockServiceReturnError: nil, + expectedClientStatus: core.CatalogCacheStatus_CACHE_POPULATED, + inlineCache: true, + }, + { + name: "output reader exec error", + catalogKey: sampleCatalogKey, + mockOutputReader: mockOutputReaderExecErr, + mockServiceReturnResponse: &cacheservice.PutCacheResponse{}, + mockServiceReturnError: nil, + expectedClientStatus: core.CatalogCacheStatus_CACHE_DISABLED, + expectClientError: true, + inlineCache: true, + }, + { + name: "output reader error", + catalogKey: sampleCatalogKey, + mockOutputReader: mockOutputReaderErr, + mockServiceReturnResponse: &cacheservice.PutCacheResponse{}, + mockServiceReturnError: nil, + expectedClientStatus: core.CatalogCacheStatus_CACHE_DISABLED, + expectClientError: true, + inlineCache: true, + }, + { + name: "cache service error", + catalogKey: sampleCatalogKey, + mockOutputReader: mockOutputReader, + mockServiceReturnResponse: nil, + mockServiceReturnError: status.Error(codes.NotFound, "test error"), + expectedClientStatus: core.CatalogCacheStatus_CACHE_DISABLED, + expectClientError: true, + inlineCache: true, + }, + { + name: "generate cache key error", + catalogKey: sampleCatalogKeyErr, + mockOutputReader: mockOutputReader, + mockServiceReturnResponse: nil, + mockServiceReturnError: nil, + expectedClientStatus: core.CatalogCacheStatus_CACHE_DISABLED, + expectClientError: true, + inlineCache: true, + }, + { + name: "successful put, uri", + catalogKey: sampleCatalogKey, + mockOutputReader: mockRemoteFileOutputReader, + mockServiceReturnResponse: &cacheservice.PutCacheResponse{}, + mockServiceReturnError: nil, + expectedClientStatus: core.CatalogCacheStatus_CACHE_POPULATED, + inlineCache: false, + }, + { + name: "output reader error - uri path does not exist", + catalogKey: sampleCatalogKey, + mockOutputReader: mockRemoteFileOutputReaderErr, + expectedClientStatus: core.CatalogCacheStatus_CACHE_DISABLED, + expectClientError: true, + inlineCache: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + mockServiceClient := &mocks.CacheServiceClient{} + mockServiceClient.On("Put", + ctx, + mock.MatchedBy(func(o *cacheservice.PutCacheRequest) bool { + assert.EqualValues(t, sampleCacheKey, o.Key) + assert.EqualValues(t, false, o.Overwrite) + if tc.inlineCache { + _, ok := o.Output.Output.(*cacheservice.CachedOutput_OutputLiterals) + assert.True(t, ok, "Expected output to be of type *cacheservice.CachedOutput_OutputLiterals") + } else { + _, ok := o.Output.Output.(*cacheservice.CachedOutput_OutputUri) + assert.True(t, ok, "Expected output to be of type *cacheservice.CachedOutput_OutputUri") + } + return true + }), + ).Return(tc.mockServiceReturnResponse, tc.mockServiceReturnError) + + cacheClient := &CacheClient{ + client: mockServiceClient, + maxCacheAge: time.Hour, + inlineCache: tc.inlineCache, + } + resp, err := cacheClient.Put(ctx, tc.catalogKey, tc.mockOutputReader, mockMetadata) + + if tc.expectClientError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.NotNil(t, resp) + } + assert.Equal(t, tc.expectedClientStatus, resp.GetCacheStatus()) + }) + } + + t.Run("Test Update overwrites", func(t *testing.T) { + mockClient := &mocks.CacheServiceClient{} + cacheClient := &CacheClient{ + client: mockClient, + maxCacheAge: time.Hour, + inlineCache: true, + } + mockClient.On("Put", + ctx, + mock.MatchedBy(func(o *cacheservice.PutCacheRequest) bool { + assert.EqualValues(t, sampleCacheKey, o.Key) + assert.EqualValues(t, true, o.Overwrite) + return true + }), + ).Return(&cacheservice.PutCacheResponse{}, nil) + _, _ = cacheClient.Update(ctx, sampleCatalogKey, mockOutputReader, mockMetadata) + }) +} + +func TestCache_ReleaseReservation(t *testing.T) { + ctx := context.Background() + + sampleCatalogKey, sampleCatalogKeyErr, sampleCacheKey := generateCatalogKeys(ctx, t) + owner := "owner" + + testCases := []struct { + name string + catalogKey catalog.Key + mockServiceReturnResponse *cacheservice.ReleaseReservationResponse + mockServiceReturnError error + expectClientError bool + expectedClientErrCode codes.Code + }{ + { + name: "generate cache key error", + catalogKey: sampleCatalogKeyErr, + mockServiceReturnResponse: nil, + mockServiceReturnError: nil, + expectClientError: true, + expectedClientErrCode: codes.Unknown, + }, + { + name: "release reservation error", + catalogKey: sampleCatalogKey, + mockServiceReturnResponse: nil, + mockServiceReturnError: status.Error(codes.Internal, "release reservation error"), + expectClientError: true, + expectedClientErrCode: codes.Internal, + }, + { + name: "successful release", + catalogKey: sampleCatalogKey, + mockServiceReturnResponse: nil, + mockServiceReturnError: nil, + expectClientError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + mockServiceClient := &mocks.CacheServiceClient{} + mockServiceClient.On("ReleaseReservation", + ctx, + mock.MatchedBy(func(r *cacheservice.ReleaseReservationRequest) bool { + assert.Equal(t, sampleCacheKey, r.Key) + assert.Equal(t, owner, r.OwnerId) + return true + }), + ).Return(tc.mockServiceReturnResponse, tc.mockServiceReturnError) + + cacheClient := &CacheClient{ + client: mockServiceClient, + maxCacheAge: time.Hour, + } + err := cacheClient.ReleaseReservation(ctx, tc.catalogKey, owner) + + if tc.expectClientError { + assert.Error(t, err) + assert.Equal(t, tc.expectedClientErrCode, status.Code(errors.Cause(err))) + } else { + assert.NoError(t, err) + } + + }) + } +} + +func TestCache_GetOrExtendReservation(t *testing.T) { + ctx := context.Background() + + sampleCatalogKey, sampleCatalogKeyErr, sampleCacheKey := generateCatalogKeys(ctx, t) + owner := "owner" + + testCases := []struct { + name string + catalogKey catalog.Key + mockServiceReturnResponse *cacheservice.GetOrExtendReservationResponse + mockServiceReturnError error + expectClientError bool + expectedClientErrCode codes.Code + }{ + { + name: "generate cache key error", + catalogKey: sampleCatalogKeyErr, + mockServiceReturnResponse: nil, + mockServiceReturnError: nil, + expectClientError: true, + expectedClientErrCode: codes.Unknown, + }, + { + name: "get or extend reservation error", + catalogKey: sampleCatalogKey, + mockServiceReturnResponse: nil, + mockServiceReturnError: status.Error(codes.Internal, "get or extend reservation error"), + expectClientError: true, + expectedClientErrCode: codes.Internal, + }, + { + name: "successful get or extend reservation", + catalogKey: sampleCatalogKey, + mockServiceReturnResponse: &cacheservice.GetOrExtendReservationResponse{ + Reservation: &cacheservice.Reservation{ + OwnerId: owner, + ExpiresAt: ptypes.TimestampNow(), + HeartbeatInterval: ptypes.DurationProto(time.Minute * 1), + }, + }, + mockServiceReturnError: nil, + expectClientError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + mockServiceClient := &mocks.CacheServiceClient{} + mockServiceClient.On("GetOrExtendReservation", + ctx, + mock.MatchedBy(func(r *cacheservice.GetOrExtendReservationRequest) bool { + assert.Equal(t, sampleCacheKey, r.Key) + assert.Equal(t, owner, r.OwnerId) + return true + }), + ).Return(tc.mockServiceReturnResponse, tc.mockServiceReturnError) + + cacheClient := &CacheClient{ + client: mockServiceClient, + maxCacheAge: time.Hour, + } + reservation, err := cacheClient.GetOrExtendReservation(ctx, tc.catalogKey, owner, time.Minute*1) + + if tc.expectClientError { + assert.Error(t, err) + assert.Equal(t, tc.expectedClientErrCode, status.Code(errors.Cause(err))) + } else { + assert.NoError(t, err) + assert.NotNil(t, reservation) + } + }) + } +} diff --git a/flytepropeller/pkg/controller/nodes/catalog/cacheservice/fallback_client.go b/flytepropeller/pkg/controller/nodes/catalog/cacheservice/fallback_client.go new file mode 100644 index 0000000000..b08cd736ad --- /dev/null +++ b/flytepropeller/pkg/controller/nodes/catalog/cacheservice/fallback_client.go @@ -0,0 +1,80 @@ +package cacheservice + +import ( + "context" + "time" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" + catalogIdl "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/datacatalog" + "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/catalog" + "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/io" + "github.com/flyteorg/flyte/flytestdlib/logger" +) + +var ( + _ catalog.Client = &FallbackClient{} +) + +type FallbackClient struct { + cacheClient catalog.Client + catalogClient catalog.Client +} + +func (c *FallbackClient) GetOrExtendReservation(ctx context.Context, key catalog.Key, ownerID string, heartbeatInterval time.Duration) (*catalogIdl.Reservation, error) { + return c.cacheClient.GetOrExtendReservation(ctx, key, ownerID, heartbeatInterval) +} + +func (c *FallbackClient) ReleaseReservation(ctx context.Context, key catalog.Key, ownerID string) error { + return c.cacheClient.ReleaseReservation(ctx, key, ownerID) +} + +func (c *FallbackClient) Get(ctx context.Context, key catalog.Key) (catalog.Entry, error) { + cacheEntry, err := c.cacheClient.Get(ctx, key) + if err != nil { + if grpcStatus, ok := status.FromError(err); ok && grpcStatus.Code() == codes.NotFound { + logger.Debugf(ctx, "Cache miss for key [%s], falling back to catalog", key) + } else { + return catalog.Entry{}, err + } + } else { + return cacheEntry, err + } + + catalogEntry, err := c.catalogClient.Get(ctx, key) + if err != nil { + return catalog.Entry{}, err + } + + metadata := catalog.Metadata{} + identifier := catalogEntry.GetStatus().GetMetadata().GetSourceExecution() + // TODO - pvditt update this when sub-workflow caching is supported + switch identifier.(type) { + case *core.CatalogMetadata_SourceTaskExecution: + metadata.TaskExecutionIdentifier = catalogEntry.GetStatus().GetMetadata().GetSourceTaskExecution() + } + + _, err = c.cacheClient.Put(ctx, key, catalogEntry.GetOutputs(), metadata) + if err != nil { + logger.Warnf(ctx, "Failed to cache entry for key [%s], err: %v", key, err) + } + + return catalogEntry, nil +} + +func (c *FallbackClient) Update(ctx context.Context, key catalog.Key, reader io.OutputReader, metadata catalog.Metadata) (catalog.Status, error) { + return c.cacheClient.Update(ctx, key, reader, metadata) +} + +func (c *FallbackClient) Put(ctx context.Context, key catalog.Key, reader io.OutputReader, metadata catalog.Metadata) (catalog.Status, error) { + return c.cacheClient.Put(ctx, key, reader, metadata) +} + +func NewFallbackClient(cacheClient catalog.Client, catalogClient catalog.Client) (*FallbackClient, error) { + return &FallbackClient{ + cacheClient: cacheClient, + catalogClient: catalogClient, + }, nil +} diff --git a/flytepropeller/pkg/controller/nodes/catalog/cacheservice/fallback_client_test.go b/flytepropeller/pkg/controller/nodes/catalog/cacheservice/fallback_client_test.go new file mode 100644 index 0000000000..68d60e136e --- /dev/null +++ b/flytepropeller/pkg/controller/nodes/catalog/cacheservice/fallback_client_test.go @@ -0,0 +1,129 @@ +package cacheservice + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" + "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/catalog" + catalogmocks "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/catalog/mocks" + mocks2 "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/io/mocks" +) + +func TestFallBack_Get(t *testing.T) { + ctx := context.Background() + + mockEntry := catalog.NewCatalogEntry(&mocks2.OutputReader{}, catalog.NewStatus(core.CatalogCacheStatus_CACHE_POPULATED, &core.CatalogMetadata{})) + + testCases := []struct { + name string + mockCacheServiceGetError error + mockCatalogClientGetError error + mockCatalogClientGetEntry catalog.Entry + mockCacheServicePurError error + expectCatalogClientGetCall bool + expectCacheServicePutCall bool + expectError bool + expectedClientErrCode codes.Code + }{ + { + name: "cache service get error", + mockCacheServiceGetError: status.Error(codes.Internal, "get error"), + expectCatalogClientGetCall: false, + expectCacheServicePutCall: false, + expectError: true, + }, + { + name: "cache service found", + mockCacheServiceGetError: nil, + expectCatalogClientGetCall: false, + expectCacheServicePutCall: false, + expectError: false, + }, + { + name: "cache service not found, catalog client get error", + mockCacheServiceGetError: status.Error(codes.NotFound, "not found"), + mockCatalogClientGetError: status.Error(codes.Internal, "get error"), + expectCatalogClientGetCall: true, + expectCacheServicePutCall: false, + expectError: true, + }, + { + name: "cache service not found, catalog client not found", + mockCacheServiceGetError: status.Error(codes.NotFound, "not found"), + mockCatalogClientGetError: status.Error(codes.NotFound, "get error"), + expectCatalogClientGetCall: true, + expectCacheServicePutCall: false, + expectError: true, + }, + { + name: "cache service not found, catalog client found", + mockCacheServiceGetError: status.Error(codes.NotFound, "not found"), + mockCatalogClientGetError: nil, + mockCatalogClientGetEntry: mockEntry, + mockCacheServicePurError: nil, + expectCatalogClientGetCall: true, + expectCacheServicePutCall: true, + expectError: false, + }, + { + name: "cache client put error", + mockCacheServiceGetError: status.Error(codes.NotFound, "not found"), + mockCatalogClientGetError: nil, + mockCacheServicePurError: status.Error(codes.Internal, "put error"), + expectCatalogClientGetCall: true, + expectCacheServicePutCall: true, + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + mockCacheClient := &catalogmocks.Client{} + mockCacheClient.On("Get", + ctx, + mock.Anything, + ).Return(catalog.Entry{}, tc.mockCacheServiceGetError) + mockCacheClient.On("Put", + ctx, + mock.Anything, + mock.Anything, + mock.Anything, + ).Return(catalog.NewStatus(core.CatalogCacheStatus_CACHE_POPULATED, nil), tc.mockCacheServicePurError) + + mockCatalogClient := &catalogmocks.Client{} + mockCatalogClient.On("Get", + ctx, + mock.Anything, + ).Return(tc.mockCatalogClientGetEntry, tc.mockCatalogClientGetError) + + fallbackClient, err := NewFallbackClient(mockCacheClient, mockCatalogClient) + assert.NoError(t, err) + + entry, err := fallbackClient.Get(ctx, catalog.Key{}) + if tc.expectError { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + assert.NotNil(t, entry) + } + + if tc.expectCatalogClientGetCall { + mockCatalogClient.AssertCalled(t, "Get", mock.Anything, mock.Anything) + } else { + mockCatalogClient.AssertNotCalled(t, "Get", mock.Anything, mock.Anything) + } + + if tc.expectCacheServicePutCall { + mockCacheClient.AssertCalled(t, "Put", mock.Anything, mock.Anything, mock.Anything, mock.Anything) + } else { + mockCacheClient.AssertNotCalled(t, "Put", mock.Anything, mock.Anything, mock.Anything, mock.Anything) + } + }) + } +} diff --git a/flytepropeller/pkg/controller/nodes/catalog/cacheservice/transformer.go b/flytepropeller/pkg/controller/nodes/catalog/cacheservice/transformer.go new file mode 100644 index 0000000000..0aceb68219 --- /dev/null +++ b/flytepropeller/pkg/controller/nodes/catalog/cacheservice/transformer.go @@ -0,0 +1,117 @@ +package cacheservice + +import ( + "context" + "fmt" + "strconv" + + "github.com/pkg/errors" + + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/cacheservice" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" + "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/catalog" + "github.com/flyteorg/flyte/flytepropeller/pkg/controller/nodes/catalog/datacatalog" +) + +// GenerateCacheKey creates a cache key utilizing hashes of the resource's identifier, signature, and inputs. +func GenerateCacheKey(ctx context.Context, key catalog.Key) (string, error) { + inputs := &core.LiteralMap{} + if key.TypedInterface.Inputs != nil { + retInputs, err := key.InputReader.Get(ctx) + if err != nil { + return "", errors.Wrap(err, "failed to read inputs when trying to query cache service") + } + inputs = retInputs + } + + identifierHash, err := catalog.HashIdentifierExceptVersion(ctx, key.Identifier) + if err != nil { + return "", err + } + + signatureHash, err := datacatalog.GenerateInterfaceSignatureHash(ctx, key.TypedInterface) + if err != nil { + return "", err + } + + inputsHash, err := catalog.HashLiteralMap(ctx, inputs, key.CacheIgnoreInputVars) + if err != nil { + return "", err + } + + cacheKey := fmt.Sprintf("%s-%s-%s-%s", identifierHash, signatureHash, inputsHash, key.CacheVersion) + return cacheKey, nil +} + +// GenerateCacheMetadata creates a cache metadata to identify the source of a cache entry +func GenerateCacheMetadata(key catalog.Key, metadata catalog.Metadata) *cacheservice.Metadata { + if metadata.TaskExecutionIdentifier == nil { + return &cacheservice.Metadata{ + SourceIdentifier: &key.Identifier, + } + } + + return &cacheservice.Metadata{ + SourceIdentifier: &key.Identifier, + KeyMap: &cacheservice.KeyMapMetadata{ + Values: map[string]string{ + datacatalog.TaskVersionKey: metadata.TaskExecutionIdentifier.TaskId.GetVersion(), + datacatalog.ExecProjectKey: metadata.TaskExecutionIdentifier.NodeExecutionId.GetExecutionId().GetProject(), + datacatalog.ExecDomainKey: metadata.TaskExecutionIdentifier.NodeExecutionId.GetExecutionId().GetDomain(), + datacatalog.ExecNameKey: metadata.TaskExecutionIdentifier.NodeExecutionId.GetExecutionId().GetName(), + datacatalog.ExecNodeIDKey: metadata.TaskExecutionIdentifier.NodeExecutionId.GetNodeId(), + datacatalog.ExecTaskAttemptKey: strconv.Itoa(int(metadata.TaskExecutionIdentifier.GetRetryAttempt())), + datacatalog.ExecOrgKey: metadata.TaskExecutionIdentifier.GetNodeExecutionId().GetExecutionId().GetOrg(), + }, + }, + } +} + +func GetSourceFromMetadata(metadata *cacheservice.Metadata) (*core.TaskExecutionIdentifier, error) { + if metadata == nil { + return nil, errors.Errorf("Output does not have metadata") + } + if metadata.SourceIdentifier == nil { + return nil, errors.Errorf("Output does not have source identifier") + } + + val := datacatalog.GetOrDefault(metadata.GetKeyMap().GetValues(), datacatalog.ExecTaskAttemptKey, "0") + attempt, err := strconv.ParseUint(val, 10, 32) + if err != nil { + return nil, err + } + + return &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: metadata.SourceIdentifier.ResourceType, + Project: metadata.SourceIdentifier.Project, + Domain: metadata.SourceIdentifier.Domain, + Name: metadata.SourceIdentifier.Name, + Version: datacatalog.GetOrDefault(metadata.GetKeyMap().GetValues(), datacatalog.TaskVersionKey, "unknown"), + Org: metadata.SourceIdentifier.Org, + }, + RetryAttempt: uint32(attempt), + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: datacatalog.GetOrDefault(metadata.GetKeyMap().GetValues(), datacatalog.ExecNodeIDKey, "unknown"), + ExecutionId: &core.WorkflowExecutionIdentifier{ + Project: datacatalog.GetOrDefault(metadata.GetKeyMap().GetValues(), datacatalog.ExecProjectKey, metadata.SourceIdentifier.GetProject()), + Domain: datacatalog.GetOrDefault(metadata.GetKeyMap().GetValues(), datacatalog.ExecDomainKey, metadata.SourceIdentifier.GetDomain()), + Name: datacatalog.GetOrDefault(metadata.GetKeyMap().GetValues(), datacatalog.ExecNameKey, "unknown"), + Org: datacatalog.GetOrDefault(metadata.GetKeyMap().GetValues(), datacatalog.ExecOrgKey, metadata.SourceIdentifier.GetOrg()), + }, + }, + }, nil +} + +func GenerateCatalogMetadata(source *core.TaskExecutionIdentifier, metadata *cacheservice.Metadata) *core.CatalogMetadata { + if metadata == nil { + return nil + } + + return &core.CatalogMetadata{ + DatasetId: metadata.SourceIdentifier, + SourceExecution: &core.CatalogMetadata_SourceTaskExecution{ + SourceTaskExecution: source, + }, + } +} diff --git a/flytepropeller/pkg/controller/nodes/catalog/cacheservice/transformer_test.go b/flytepropeller/pkg/controller/nodes/catalog/cacheservice/transformer_test.go new file mode 100644 index 0000000000..b9fbd8e4fd --- /dev/null +++ b/flytepropeller/pkg/controller/nodes/catalog/cacheservice/transformer_test.go @@ -0,0 +1,120 @@ +package cacheservice + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + "github.com/flyteorg/flyte/flyteidl/clients/go/coreutils" + "github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core" + "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/catalog" + "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/io/mocks" +) + +func TestGenerateCachedTaskKey(t *testing.T) { + + sampleInputs, err := coreutils.MakeLiteralMap(map[string]interface{}{"a": 1, "b": 2}) + assert.NoError(t, err) + mockInputReader := &mocks.InputReader{} + mockInputReader.On("Get", mock.Anything).Return(sampleInputs, nil, nil) + + sampleInterface := core.TypedInterface{ + Inputs: &core.VariableMap{ + Variables: map[string]*core.Variable{ + "a": {Type: &core.LiteralType{Type: &core.LiteralType_Simple{Simple: core.SimpleType_INTEGER}}}, + "b": {Type: &core.LiteralType{Type: &core.LiteralType_Simple{Simple: core.SimpleType_INTEGER}}}, + }, + }, + } + + testCases := []struct { + name string + key catalog.Key + expectedErr bool + expectedKey string + }{ + { + name: "without ignore vars", + key: catalog.Key{ + Identifier: core.Identifier{ + Project: "project_1", + Domain: "domain_1", + Name: "name_1", + Version: "0", + Org: "org_1", + }, + CacheVersion: "1.0.0", + TypedInterface: sampleInterface, + InputReader: mockInputReader, + }, + expectedErr: false, + expectedKey: "+UmrGhEwHv3FesdpA4gliBluF3FUXz4tshmuOlw1FSk=-gfjJTWtY-GKw-c0Pw-jwhb7XmCTEQeFc_pixCptPWTWg_hezuWfuZAwHJDwWQ-1.0.0", + }, + { + name: "different resource version produces same key", + key: catalog.Key{ + Identifier: core.Identifier{ + Project: "project_1", + Domain: "domain_1", + Name: "name_1", + Version: "1", + Org: "org_1", + }, + CacheVersion: "1.0.0", + TypedInterface: sampleInterface, + InputReader: mockInputReader, + }, + expectedErr: false, + expectedKey: "+UmrGhEwHv3FesdpA4gliBluF3FUXz4tshmuOlw1FSk=-gfjJTWtY-GKw-c0Pw-jwhb7XmCTEQeFc_pixCptPWTWg_hezuWfuZAwHJDwWQ-1.0.0", + }, + { + name: "ignore inputs", + key: catalog.Key{ + Identifier: core.Identifier{ + Project: "project_1", + Domain: "domain_1", + Name: "name_1", + Version: "0", + Org: "org_1", + }, + CacheVersion: "1.0.0", + TypedInterface: sampleInterface, + InputReader: mockInputReader, + CacheIgnoreInputVars: []string{"a"}, + }, + expectedErr: false, + expectedKey: "+UmrGhEwHv3FesdpA4gliBluF3FUXz4tshmuOlw1FSk=-gfjJTWtY-GKw-c0Pw-MNjvcaUwW4DzBce6jJ30Pl-A_9guXnrww5_6mn_PVrA-1.0.0", + }, + { + name: "different cache version", + key: catalog.Key{ + Identifier: core.Identifier{ + Project: "project_1", + Domain: "domain_1", + Name: "name_1", + Version: "0", + Org: "org_1", + }, + CacheVersion: "1.0.1", + TypedInterface: sampleInterface, + InputReader: mockInputReader, + }, + expectedErr: false, + expectedKey: "+UmrGhEwHv3FesdpA4gliBluF3FUXz4tshmuOlw1FSk=-gfjJTWtY-GKw-c0Pw-jwhb7XmCTEQeFc_pixCptPWTWg_hezuWfuZAwHJDwWQ-1.0.1", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + taskKey, err := GenerateCacheKey(context.TODO(), tc.key) + if tc.expectedErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tc.expectedKey, taskKey) + } + }) + } +} diff --git a/flytepropeller/pkg/controller/nodes/catalog/config.go b/flytepropeller/pkg/controller/nodes/catalog/config.go index 2b0c484fb7..32cd0bf11f 100644 --- a/flytepropeller/pkg/controller/nodes/catalog/config.go +++ b/flytepropeller/pkg/controller/nodes/catalog/config.go @@ -7,8 +7,10 @@ import ( "google.golang.org/grpc" "github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/catalog" + "github.com/flyteorg/flyte/flytepropeller/pkg/controller/nodes/catalog/cacheservice" "github.com/flyteorg/flyte/flytepropeller/pkg/controller/nodes/catalog/datacatalog" "github.com/flyteorg/flyte/flytestdlib/config" + "github.com/flyteorg/flyte/flytestdlib/storage" ) //go:generate pflags Config --default-var defaultConfig @@ -17,7 +19,10 @@ const ConfigSectionKey = "catalog-cache" var ( defaultConfig = &Config{ - Type: NoOpDiscoveryType, + Type: NoOpDiscoveryType, + MaxRetries: 5, + MaxPerRetryTimeout: config.Duration{Duration: 0}, + BackOffScalar: 100, } configSection = config.MustRegisterSection(ConfigSectionKey, defaultConfig) @@ -28,14 +33,21 @@ type DiscoveryType = string const ( NoOpDiscoveryType DiscoveryType = "noop" DataCatalogType DiscoveryType = "datacatalog" + CacheServiceType DiscoveryType = "cacheservice" + FallbackType DiscoveryType = "fallback" ) type Config struct { - Type DiscoveryType `json:"type" pflag:"\"noop\", Catalog Implementation to use"` - Endpoint string `json:"endpoint" pflag:"\"\", Endpoint for catalog service"` - Insecure bool `json:"insecure" pflag:"false, Use insecure grpc connection"` - MaxCacheAge config.Duration `json:"max-cache-age" pflag:", Cache entries past this age will incur cache miss. 0 means cache never expires"` - UseAdminAuth bool `json:"use-admin-auth" pflag:"false, Use the same gRPC credentials option as the flyteadmin client"` + Type DiscoveryType `json:"type" pflag:"\"noop\", Catalog Implementation to use"` + Endpoint string `json:"endpoint" pflag:"\"\", Endpoint for catalog service"` + CacheEndpoint string `json:"cache-endpoint" pflag:"\"\", Endpoint for cache service"` + Insecure bool `json:"insecure" pflag:"false, Use insecure grpc connection"` + MaxCacheAge config.Duration `json:"max-cache-age" pflag:", Cache entries past this age will incur cache miss. 0 means cache never expires"` + UseAdminAuth bool `json:"use-admin-auth" pflag:"false, Use the same gRPC credentials option as the flyteadmin client"` + MaxRetries int `json:"max-retries" pflag:",Max number of gRPC retries"` + MaxPerRetryTimeout config.Duration `json:"max-per-retry-timeout" pflag:",gRPC per retry timeout. O means no timeout."` + BackOffScalar int `json:"backoff-scalar" pflag:",gRPC backoff scalar in milliseconds"` + InlineCache bool `json:"inline-cache" pflag:"false, Attempt to use in-line cache"` // Set the gRPC service config formatted as a json string https://github.com/grpc/grpc/blob/master/doc/service_config.md // eg. {"loadBalancingConfig": [{"round_robin":{}}], "methodConfig": [{"name":[{"service": "foo", "method": "bar"}, {"service": "baz"}], "timeout": "1.000000001s"}]} @@ -49,10 +61,30 @@ func GetConfig() *Config { return configSection.GetConfig().(*Config) } -func NewCatalogClient(ctx context.Context, authOpt ...grpc.DialOption) (catalog.Client, error) { +func NewCacheClient(ctx context.Context, dataStore *storage.DataStore, authOpt ...grpc.DialOption) (catalog.Client, error) { catalogConfig := GetConfig() switch catalogConfig.Type { + case CacheServiceType: + return cacheservice.NewCacheClient(ctx, dataStore, catalogConfig.CacheEndpoint, catalogConfig.Insecure, + catalogConfig.MaxCacheAge.Duration, catalogConfig.UseAdminAuth, catalogConfig.MaxRetries, + catalogConfig.MaxPerRetryTimeout.Duration, catalogConfig.BackOffScalar, catalogConfig.InlineCache, + catalogConfig.DefaultServiceConfig, authOpt...) + case FallbackType: + cacheClient, err := cacheservice.NewCacheClient(ctx, dataStore, catalogConfig.CacheEndpoint, catalogConfig.Insecure, + catalogConfig.MaxCacheAge.Duration, catalogConfig.UseAdminAuth, catalogConfig.MaxRetries, + catalogConfig.MaxPerRetryTimeout.Duration, catalogConfig.BackOffScalar, catalogConfig.InlineCache, + catalogConfig.DefaultServiceConfig, authOpt...) + if err != nil { + return nil, err + } + catalogClient, err := datacatalog.NewDataCatalog(ctx, catalogConfig.Endpoint, catalogConfig.Insecure, + catalogConfig.MaxCacheAge.Duration, catalogConfig.UseAdminAuth, catalogConfig.DefaultServiceConfig, + authOpt...) + if err != nil { + return nil, err + } + return cacheservice.NewFallbackClient(cacheClient, catalogClient) case DataCatalogType: return datacatalog.NewDataCatalog(ctx, catalogConfig.Endpoint, catalogConfig.Insecure, catalogConfig.MaxCacheAge.Duration, catalogConfig.UseAdminAuth, catalogConfig.DefaultServiceConfig, diff --git a/flytepropeller/pkg/controller/nodes/catalog/config_flags.go b/flytepropeller/pkg/controller/nodes/catalog/config_flags.go index 4bd40b20b4..b640f3e558 100755 --- a/flytepropeller/pkg/controller/nodes/catalog/config_flags.go +++ b/flytepropeller/pkg/controller/nodes/catalog/config_flags.go @@ -52,9 +52,14 @@ func (cfg Config) GetPFlagSet(prefix string) *pflag.FlagSet { cmdFlags := pflag.NewFlagSet("Config", pflag.ExitOnError) cmdFlags.String(fmt.Sprintf("%v%v", prefix, "type"), defaultConfig.Type, " Catalog Implementation to use") cmdFlags.String(fmt.Sprintf("%v%v", prefix, "endpoint"), defaultConfig.Endpoint, " Endpoint for catalog service") + cmdFlags.String(fmt.Sprintf("%v%v", prefix, "cache-endpoint"), defaultConfig.CacheEndpoint, " Endpoint for cache service") cmdFlags.Bool(fmt.Sprintf("%v%v", prefix, "insecure"), defaultConfig.Insecure, " Use insecure grpc connection") cmdFlags.String(fmt.Sprintf("%v%v", prefix, "max-cache-age"), defaultConfig.MaxCacheAge.String(), " Cache entries past this age will incur cache miss. 0 means cache never expires") cmdFlags.Bool(fmt.Sprintf("%v%v", prefix, "use-admin-auth"), defaultConfig.UseAdminAuth, " Use the same gRPC credentials option as the flyteadmin client") + cmdFlags.Int(fmt.Sprintf("%v%v", prefix, "max-retries"), defaultConfig.MaxRetries, "Max number of gRPC retries") + cmdFlags.String(fmt.Sprintf("%v%v", prefix, "max-per-retry-timeout"), defaultConfig.MaxPerRetryTimeout.String(), "gRPC per retry timeout. O means no timeout.") + cmdFlags.Int(fmt.Sprintf("%v%v", prefix, "backoff-scalar"), defaultConfig.BackOffScalar, "gRPC backoff scalar in milliseconds") + cmdFlags.Bool(fmt.Sprintf("%v%v", prefix, "inline-cache"), defaultConfig.InlineCache, " Attempt to use in-line cache") cmdFlags.String(fmt.Sprintf("%v%v", prefix, "default-service-config"), defaultConfig.DefaultServiceConfig, " Set the default service config for the catalog gRPC client") return cmdFlags } diff --git a/flytepropeller/pkg/controller/nodes/catalog/config_flags_test.go b/flytepropeller/pkg/controller/nodes/catalog/config_flags_test.go index 3b18a9282d..c491d2a64c 100755 --- a/flytepropeller/pkg/controller/nodes/catalog/config_flags_test.go +++ b/flytepropeller/pkg/controller/nodes/catalog/config_flags_test.go @@ -127,6 +127,20 @@ func TestConfig_SetFlags(t *testing.T) { } }) }) + t.Run("Test_cache-endpoint", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("cache-endpoint", testValue) + if vString, err := cmdFlags.GetString("cache-endpoint"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.CacheEndpoint) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) t.Run("Test_insecure", func(t *testing.T) { t.Run("Override", func(t *testing.T) { @@ -169,6 +183,62 @@ func TestConfig_SetFlags(t *testing.T) { } }) }) + t.Run("Test_max-retries", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("max-retries", testValue) + if vInt, err := cmdFlags.GetInt("max-retries"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vInt), &actual.MaxRetries) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_max-per-retry-timeout", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := defaultConfig.MaxPerRetryTimeout.String() + + cmdFlags.Set("max-per-retry-timeout", testValue) + if vString, err := cmdFlags.GetString("max-per-retry-timeout"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.MaxPerRetryTimeout) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_backoff-scalar", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("backoff-scalar", testValue) + if vInt, err := cmdFlags.GetInt("backoff-scalar"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vInt), &actual.BackOffScalar) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_inline-cache", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("inline-cache", testValue) + if vBool, err := cmdFlags.GetBool("inline-cache"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vBool), &actual.InlineCache) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) t.Run("Test_default-service-config", func(t *testing.T) { t.Run("Override", func(t *testing.T) { diff --git a/flytepropeller/pkg/controller/nodes/catalog/datacatalog/datacatalog_test.go b/flytepropeller/pkg/controller/nodes/catalog/datacatalog/datacatalog_test.go index e63413284b..3a6ca16268 100644 --- a/flytepropeller/pkg/controller/nodes/catalog/datacatalog/datacatalog_test.go +++ b/flytepropeller/pkg/controller/nodes/catalog/datacatalog/datacatalog_test.go @@ -208,11 +208,11 @@ func TestCatalog_Get(t *testing.T) { }, } - assert.Equal(t, taskID.NodeExecutionId.ExecutionId.Name, sampleArtifact.GetMetadata().KeyMap[execNameKey]) - assert.Equal(t, taskID.NodeExecutionId.NodeId, sampleArtifact.GetMetadata().KeyMap[execNodeIDKey]) - assert.Equal(t, taskID.NodeExecutionId.ExecutionId.Project, sampleArtifact.GetMetadata().KeyMap[execProjectKey]) - assert.Equal(t, taskID.NodeExecutionId.ExecutionId.Domain, sampleArtifact.GetMetadata().KeyMap[execDomainKey]) - assert.Equal(t, strconv.Itoa(int(taskID.RetryAttempt)), sampleArtifact.GetMetadata().KeyMap[execTaskAttemptKey]) + assert.Equal(t, taskID.NodeExecutionId.ExecutionId.Name, sampleArtifact.GetMetadata().KeyMap[ExecNameKey]) + assert.Equal(t, taskID.NodeExecutionId.NodeId, sampleArtifact.GetMetadata().KeyMap[ExecNodeIDKey]) + assert.Equal(t, taskID.NodeExecutionId.ExecutionId.Project, sampleArtifact.GetMetadata().KeyMap[ExecProjectKey]) + assert.Equal(t, taskID.NodeExecutionId.ExecutionId.Domain, sampleArtifact.GetMetadata().KeyMap[ExecDomainKey]) + assert.Equal(t, strconv.Itoa(int(taskID.RetryAttempt)), sampleArtifact.GetMetadata().KeyMap[ExecTaskAttemptKey]) mockClient.On("GetArtifact", ctx, diff --git a/flytepropeller/pkg/controller/nodes/catalog/datacatalog/transformer.go b/flytepropeller/pkg/controller/nodes/catalog/datacatalog/transformer.go index c91db1e2cf..ef66b23037 100644 --- a/flytepropeller/pkg/controller/nodes/catalog/datacatalog/transformer.go +++ b/flytepropeller/pkg/controller/nodes/catalog/datacatalog/transformer.go @@ -82,7 +82,7 @@ func GenerateTaskOutputsFromArtifact(id core.Identifier, taskInterface core.Type } func generateDataSetVersion(ctx context.Context, taskInterface core.TypedInterface, cacheVersion string) (string, error) { - signatureHash, err := generateTaskSignatureHash(ctx, taskInterface) + signatureHash, err := GenerateInterfaceSignatureHash(ctx, taskInterface) if err != nil { return "", err } @@ -95,16 +95,16 @@ func generateDataSetVersion(ctx context.Context, taskInterface core.TypedInterfa return fmt.Sprintf("%s-%s", cacheVersion, signatureHash), nil } -func generateTaskSignatureHash(ctx context.Context, taskInterface core.TypedInterface) (string, error) { +func GenerateInterfaceSignatureHash(ctx context.Context, resourceInterface core.TypedInterface) (string, error) { taskInputs := &emptyVariableMap taskOutputs := &emptyVariableMap - if taskInterface.Inputs != nil && len(taskInterface.Inputs.Variables) != 0 { - taskInputs = taskInterface.Inputs + if resourceInterface.Inputs != nil && len(resourceInterface.Inputs.Variables) != 0 { + taskInputs = resourceInterface.Inputs } - if taskInterface.Outputs != nil && len(taskInterface.Outputs.Variables) != 0 { - taskOutputs = taskInterface.Outputs + if resourceInterface.Outputs != nil && len(resourceInterface.Outputs.Variables) != 0 { + taskOutputs = resourceInterface.Outputs } inputHash, err := pbhash.ComputeHash(ctx, taskInputs) @@ -174,13 +174,13 @@ func DatasetIDToIdentifier(id *datacatalog.DatasetID) *core.Identifier { // With Node-Node relationship this is bound to change. So lets keep it extensible const ( - taskVersionKey = "task-version" - execNameKey = "execution-name" - execDomainKey = "exec-domain" - execProjectKey = "exec-project" - execNodeIDKey = "exec-node" - execTaskAttemptKey = "exec-attempt" - execOrgKey = "exec-rog" + TaskVersionKey = "task-version" + ExecNameKey = "execution-name" + ExecDomainKey = "exec-domain" + ExecProjectKey = "exec-project" + ExecNodeIDKey = "exec-node" + ExecTaskAttemptKey = "exec-attempt" + ExecOrgKey = "exec-rog" ) // Understanding Catalog Identifiers @@ -195,7 +195,7 @@ func GetDatasetMetadataForSource(taskExecutionID *core.TaskExecutionIdentifier) } return &datacatalog.Metadata{ KeyMap: map[string]string{ - taskVersionKey: taskExecutionID.TaskId.Version, + TaskVersionKey: taskExecutionID.TaskId.Version, }, } } @@ -206,12 +206,12 @@ func GetArtifactMetadataForSource(taskExecutionID *core.TaskExecutionIdentifier) } return &datacatalog.Metadata{ KeyMap: map[string]string{ - execProjectKey: taskExecutionID.NodeExecutionId.GetExecutionId().GetProject(), - execDomainKey: taskExecutionID.NodeExecutionId.GetExecutionId().GetDomain(), - execNameKey: taskExecutionID.NodeExecutionId.GetExecutionId().GetName(), - execNodeIDKey: taskExecutionID.NodeExecutionId.GetNodeId(), - execTaskAttemptKey: strconv.Itoa(int(taskExecutionID.GetRetryAttempt())), - execOrgKey: taskExecutionID.GetNodeExecutionId().GetExecutionId().GetOrg(), + ExecProjectKey: taskExecutionID.NodeExecutionId.GetExecutionId().GetProject(), + ExecDomainKey: taskExecutionID.NodeExecutionId.GetExecutionId().GetDomain(), + ExecNameKey: taskExecutionID.NodeExecutionId.GetExecutionId().GetName(), + ExecNodeIDKey: taskExecutionID.NodeExecutionId.GetNodeId(), + ExecTaskAttemptKey: strconv.Itoa(int(taskExecutionID.GetRetryAttempt())), + ExecOrgKey: taskExecutionID.GetNodeExecutionId().GetExecutionId().GetOrg(), }, } } @@ -227,8 +227,8 @@ func GetSourceFromMetadata(datasetMd, artifactMd *datacatalog.Metadata, currentI artifactMd = &datacatalog.Metadata{KeyMap: map[string]string{}} } - // Jul-06-2020 DataCatalog stores only wfExecutionKey & taskVersionKey So we will default the project / domain to the current dataset's project domain - val := GetOrDefault(artifactMd.KeyMap, execTaskAttemptKey, "0") + // Jul-06-2020 DataCatalog stores only wfExecutionKey & TaskVersionKey So we will default the project / domain to the current dataset's project domain + val := GetOrDefault(artifactMd.KeyMap, ExecTaskAttemptKey, "0") attempt, err := strconv.ParseUint(val, 10, 32) if err != nil { return nil, fmt.Errorf("failed to parse [%v] to integer. Error: %w", val, err) @@ -240,17 +240,17 @@ func GetSourceFromMetadata(datasetMd, artifactMd *datacatalog.Metadata, currentI Project: currentID.Project, Domain: currentID.Domain, Name: currentID.Name, - Version: GetOrDefault(datasetMd.KeyMap, taskVersionKey, "unknown"), + Version: GetOrDefault(datasetMd.KeyMap, TaskVersionKey, "unknown"), Org: currentID.Org, }, RetryAttempt: uint32(attempt), NodeExecutionId: &core.NodeExecutionIdentifier{ - NodeId: GetOrDefault(artifactMd.KeyMap, execNodeIDKey, "unknown"), + NodeId: GetOrDefault(artifactMd.KeyMap, ExecNodeIDKey, "unknown"), ExecutionId: &core.WorkflowExecutionIdentifier{ - Project: GetOrDefault(artifactMd.KeyMap, execProjectKey, currentID.GetProject()), - Domain: GetOrDefault(artifactMd.KeyMap, execDomainKey, currentID.GetDomain()), - Name: GetOrDefault(artifactMd.KeyMap, execNameKey, "unknown"), - Org: GetOrDefault(artifactMd.KeyMap, execOrgKey, currentID.GetOrg()), + Project: GetOrDefault(artifactMd.KeyMap, ExecProjectKey, currentID.GetProject()), + Domain: GetOrDefault(artifactMd.KeyMap, ExecDomainKey, currentID.GetDomain()), + Name: GetOrDefault(artifactMd.KeyMap, ExecNameKey, "unknown"), + Org: GetOrDefault(artifactMd.KeyMap, ExecOrgKey, currentID.GetOrg()), }, }, }, nil diff --git a/flytepropeller/pkg/controller/nodes/catalog/datacatalog/transformer_test.go b/flytepropeller/pkg/controller/nodes/catalog/datacatalog/transformer_test.go index bbbea62736..3f9b44a448 100644 --- a/flytepropeller/pkg/controller/nodes/catalog/datacatalog/transformer_test.go +++ b/flytepropeller/pkg/controller/nodes/catalog/datacatalog/transformer_test.go @@ -176,12 +176,12 @@ func TestGetArtifactMetadataForSource(t *testing.T) { }{ {"nil TaskExec", args{}, nil}, {"TaskExec", args{tID}, map[string]string{ - execTaskAttemptKey: strconv.Itoa(int(tID.RetryAttempt)), - execProjectKey: tID.NodeExecutionId.ExecutionId.Project, - execDomainKey: tID.NodeExecutionId.ExecutionId.Domain, - execNodeIDKey: tID.NodeExecutionId.NodeId, - execNameKey: tID.NodeExecutionId.ExecutionId.Name, - execOrgKey: tID.NodeExecutionId.ExecutionId.Org, + ExecTaskAttemptKey: strconv.Itoa(int(tID.RetryAttempt)), + ExecProjectKey: tID.NodeExecutionId.ExecutionId.Project, + ExecDomainKey: tID.NodeExecutionId.ExecutionId.Domain, + ExecNodeIDKey: tID.NodeExecutionId.NodeId, + ExecNameKey: tID.NodeExecutionId.ExecutionId.Name, + ExecOrgKey: tID.NodeExecutionId.ExecutionId.Org, }}, } for _, tt := range tests { @@ -250,7 +250,7 @@ func TestGetSourceFromMetadata(t *testing.T) { }, RetryAttempt: 0, }}, - // In legacy only taskVersionKey is available + // In legacy only TaskVersionKey is available {"legacy", args{datasetMd: GetDatasetMetadataForSource(&tID).KeyMap, currentID: currentTaskID}, &core.TaskExecutionIdentifier{ TaskId: &core.Identifier{ ResourceType: core.ResourceType_TASK, diff --git a/flytepropeller/pkg/controller/nodes/executor.go b/flytepropeller/pkg/controller/nodes/executor.go index 1a5d787b1f..f0ebc3eb59 100644 --- a/flytepropeller/pkg/controller/nodes/executor.go +++ b/flytepropeller/pkg/controller/nodes/executor.go @@ -475,7 +475,7 @@ func (c *recursiveNodeExecutor) WithNodeExecutionContextBuilder(nCtxBuilder inte // nodeExecutor implements the NodeExecutor interface and is responsible for executing a single node. type nodeExecutor struct { - catalog catalog.Client + cache catalog.Client clusterID string enableCRDebugMetadata bool defaultActiveDeadline time.Duration @@ -1444,7 +1444,7 @@ func replaceRemotePrefix(ctx context.Context, s string) string { func NewExecutor(ctx context.Context, nodeConfig config.NodeConfig, store *storage.DataStore, enQWorkflow v1alpha1.EnqueueWorkflow, eventSink events.EventSink, workflowLauncher launchplan.Executor, launchPlanReader launchplan.Reader, maxDatasetSize int64, defaultRawOutputPrefix storage.DataReference, kubeClient executors.Client, - catalogClient catalog.Client, recoveryClient recovery.Client, eventConfig *config.EventConfig, clusterID string, signalClient service.SignalServiceClient, + cacheClient catalog.Client, recoveryClient recovery.Client, eventConfig *config.EventConfig, clusterID string, signalClient service.SignalServiceClient, nodeHandlerFactory interfaces.HandlerFactory, scope promutils.Scope) (interfaces.Node, error) { // TODO we may want to make this configurable. @@ -1488,7 +1488,7 @@ func NewExecutor(ctx context.Context, nodeConfig config.NodeConfig, store *stora } nodeExecutor := &nodeExecutor{ - catalog: catalogClient, + cache: cacheClient, clusterID: clusterID, enableCRDebugMetadata: nodeConfig.EnableCRDebugMetadata, defaultActiveDeadline: nodeConfig.DefaultDeadlines.DefaultNodeActiveDeadline.Duration, diff --git a/flytepropeller/pkg/controller/nodes/factory/handler_factory.go b/flytepropeller/pkg/controller/nodes/factory/handler_factory.go index 424bd15f10..57b80b6262 100644 --- a/flytepropeller/pkg/controller/nodes/factory/handler_factory.go +++ b/flytepropeller/pkg/controller/nodes/factory/handler_factory.go @@ -32,7 +32,7 @@ type handlerFactory struct { launchPlanReader launchplan.Reader kubeClient executors.Client kubeClientset kubernetes.Interface - catalogClient catalog.Client + cacheClient catalog.Client recoveryClient recovery.Client eventConfig *config.EventConfig clusterID string @@ -49,7 +49,7 @@ func (f *handlerFactory) GetHandler(kind v1alpha1.NodeKind) (interfaces.NodeHand } func (f *handlerFactory) Setup(ctx context.Context, executor interfaces.Node, setup interfaces.SetupContext) error { - t, err := task.New(ctx, f.kubeClient, f.kubeClientset, f.catalogClient, f.eventConfig, f.clusterID, f.scope) + t, err := task.New(ctx, f.kubeClient, f.kubeClientset, f.cacheClient, f.eventConfig, f.clusterID, f.scope) if err != nil { return err } @@ -78,7 +78,7 @@ func (f *handlerFactory) Setup(ctx context.Context, executor interfaces.Node, se } func NewHandlerFactory(ctx context.Context, workflowLauncher launchplan.Executor, launchPlanReader launchplan.Reader, - kubeClient executors.Client, kubeClientset kubernetes.Interface, catalogClient catalog.Client, recoveryClient recovery.Client, eventConfig *config.EventConfig, + kubeClient executors.Client, kubeClientset kubernetes.Interface, cacheClient catalog.Client, recoveryClient recovery.Client, eventConfig *config.EventConfig, clusterID string, signalClient service.SignalServiceClient, scope promutils.Scope) (interfaces.HandlerFactory, error) { return &handlerFactory{ @@ -86,7 +86,7 @@ func NewHandlerFactory(ctx context.Context, workflowLauncher launchplan.Executor launchPlanReader: launchPlanReader, kubeClient: kubeClient, kubeClientset: kubeClientset, - catalogClient: catalogClient, + cacheClient: cacheClient, recoveryClient: recoveryClient, eventConfig: eventConfig, clusterID: clusterID, diff --git a/flytepropeller/pkg/controller/workflow/executor_test.go b/flytepropeller/pkg/controller/workflow/executor_test.go index cc9910abc3..807b71e1f4 100644 --- a/flytepropeller/pkg/controller/workflow/executor_test.go +++ b/flytepropeller/pkg/controller/workflow/executor_test.go @@ -237,7 +237,7 @@ func TestWorkflowExecutor_HandleFlyteWorkflow_Error(t *testing.T) { enqueueWorkflow := func(workflowId v1alpha1.WorkflowID) {} eventSink := eventMocks.NewMockEventSink() - catalogClient, err := catalog.NewCatalogClient(ctx, nil) + catalogClient, err := catalog.NewCacheClient(ctx, nil) assert.NoError(t, err) recoveryClient := &recoveryMocks.Client{} adminClient := launchplan.NewFailFastLaunchPlanExecutor() @@ -320,7 +320,7 @@ func TestWorkflowExecutor_HandleFlyteWorkflow(t *testing.T) { enqueueWorkflow := func(workflowId v1alpha1.WorkflowID) {} eventSink := eventMocks.NewMockEventSink() - catalogClient, err := catalog.NewCatalogClient(ctx, nil) + catalogClient, err := catalog.NewCacheClient(ctx, nil) assert.NoError(t, err) recoveryClient := &recoveryMocks.Client{} adminClient := launchplan.NewFailFastLaunchPlanExecutor() @@ -387,7 +387,7 @@ func BenchmarkWorkflowExecutor(b *testing.B) { enqueueWorkflow := func(workflowId v1alpha1.WorkflowID) {} eventSink := eventMocks.NewMockEventSink() - catalogClient, err := catalog.NewCatalogClient(ctx, nil) + catalogClient, err := catalog.NewCacheClient(ctx, nil) assert.NoError(b, err) recoveryClient := &recoveryMocks.Client{} adminClient := launchplan.NewFailFastLaunchPlanExecutor() @@ -489,7 +489,7 @@ func TestWorkflowExecutor_HandleFlyteWorkflow_Failing(t *testing.T) { } return nil } - catalogClient, err := catalog.NewCatalogClient(ctx, nil) + catalogClient, err := catalog.NewCacheClient(ctx, nil) assert.NoError(t, err) recoveryClient := &recoveryMocks.Client{} adminClient := launchplan.NewFailFastLaunchPlanExecutor() @@ -598,7 +598,7 @@ func TestWorkflowExecutor_HandleFlyteWorkflow_Events(t *testing.T) { } return nil } - catalogClient, err := catalog.NewCatalogClient(ctx, nil) + catalogClient, err := catalog.NewCacheClient(ctx, nil) assert.NoError(t, err) adminClient := launchplan.NewFailFastLaunchPlanExecutor() recoveryClient := &recoveryMocks.Client{} @@ -659,7 +659,7 @@ func TestWorkflowExecutor_HandleFlyteWorkflow_EventFailure(t *testing.T) { assert.NoError(t, err) nodeEventSink := eventMocks.NewMockEventSink() - catalogClient, err := catalog.NewCatalogClient(ctx, nil) + catalogClient, err := catalog.NewCacheClient(ctx, nil) assert.NoError(t, err) recoveryClient := &recoveryMocks.Client{} diff --git a/flytestdlib/otelutils/factory.go b/flytestdlib/otelutils/factory.go index ef946362fd..80ea9cb3eb 100644 --- a/flytestdlib/otelutils/factory.go +++ b/flytestdlib/otelutils/factory.go @@ -18,15 +18,18 @@ import ( ) const ( - AdminClientTracer = "admin-client" - AdminGormTracer = "admin-gorm" - AdminServerTracer = "admin-server" - BlobstoreClientTracer = "blobstore-client" - DataCatalogClientTracer = "datacatalog-client" - DataCatalogGormTracer = "datacatalog-gorm" - DataCatalogServerTracer = "datacatalog-server" - FlytePropellerTracer = "flytepropeller" - K8sClientTracer = "k8s-client" + AdminClientTracer = "admin-client" + AdminGormTracer = "admin-gorm" + AdminServerTracer = "admin-server" + BlobstoreClientTracer = "blobstore-client" + DataCatalogClientTracer = "datacatalog-client" + DataCatalogGormTracer = "datacatalog-gorm" + DataCatalogServerTracer = "datacatalog-server" + CacheServiceClientTracer = "cacheservice-client" + CacheServiceGormTracer = "cacheservice-gorm" + CacheServiceServerTracer = "cacheservice-server" + FlytePropellerTracer = "flytepropeller" + K8sClientTracer = "k8s-client" ) var tracerProviders = make(map[string]*trace.TracerProvider) diff --git a/go.mod b/go.mod index 6f64bcf08b..e1742958b8 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/flyteorg/flyte go 1.21 require ( + github.com/flyteorg/flyte/cacheservice v0.0.0-00010101000000-000000000000 github.com/flyteorg/flyte/datacatalog v0.0.0-00010101000000-000000000000 github.com/flyteorg/flyte/flyteadmin v1.10.7-b0.0.20240109185447-d86f91995c44 github.com/flyteorg/flyte/flytepropeller v1.10.7-0.20240104005944-64548962d375 @@ -35,19 +36,23 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go v1.46.2 // indirect github.com/aws/aws-sdk-go-v2 v1.24.1 // indirect - github.com/aws/aws-sdk-go-v2/config v1.26.1 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.16.12 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect + github.com/aws/aws-sdk-go-v2/config v1.26.6 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.12.17 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect github.com/aws/aws-sdk-go-v2/service/athena v1.0.0 // indirect + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.27.1 // indirect + github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.18.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.8.11 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect github.com/aws/smithy-go v1.19.0 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/benlaurie/objecthash v0.0.0-20180202135721-d1e3d6079fc1 // indirect @@ -64,6 +69,7 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/eapache/go-resiliency v1.2.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect @@ -86,6 +92,7 @@ require ( github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.4 // indirect github.com/go-redis/redis v6.15.7+incompatible // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-test/deep v1.1.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect @@ -235,6 +242,7 @@ require ( ) replace ( + github.com/flyteorg/flyte/cacheservice => ./cacheservice github.com/flyteorg/flyte/datacatalog => ./datacatalog github.com/flyteorg/flyte/flyteadmin => ./flyteadmin github.com/flyteorg/flyte/flytecopilot => ./flytecopilot diff --git a/go.sum b/go.sum index 97f757e683..2598167994 100644 --- a/go.sum +++ b/go.sum @@ -118,32 +118,40 @@ github.com/aws/aws-sdk-go v1.46.2/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Ph github.com/aws/aws-sdk-go-v2 v1.0.0/go.mod h1:smfAbmpW+tcRVuNUjo3MOArSZmW72t62rkCzc2i0TWM= github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU= github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= -github.com/aws/aws-sdk-go-v2/config v1.26.1 h1:z6DqMxclFGL3Zfo+4Q0rLnAZ6yVkzCRxhRMsiRQnD1o= -github.com/aws/aws-sdk-go-v2/config v1.26.1/go.mod h1:ZB+CuKHRbb5v5F0oJtGdhFTelmrxd4iWO1lf0rQwSAg= -github.com/aws/aws-sdk-go-v2/credentials v1.16.12 h1:v/WgB8NxprNvr5inKIiVVrXPuuTegM+K8nncFkr1usU= -github.com/aws/aws-sdk-go-v2/credentials v1.16.12/go.mod h1:X21k0FjEJe+/pauud82HYiQbEr9jRKY3kXEIQ4hXeTQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw= +github.com/aws/aws-sdk-go-v2/config v1.26.6 h1:Z/7w9bUqlRI0FFQpetVuFYEsjzE3h7fpU6HuGmfPL/o= +github.com/aws/aws-sdk-go-v2/config v1.26.6/go.mod h1:uKU6cnDmYCvJ+pxO9S4cWDb2yWWIH5hra+32hVh1MI4= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.12.17 h1:jPuObStSZU1cGheSslAbF2nA4c/IgeIQA1X9frB60Oc= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.12.17/go.mod h1:df3uvEupLM3MkLim3BDkCaRpgAROW7wk41dwNQjw0kA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y= github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 h1:n3GDfwqF2tzEkXlv5cuy4iy7LpKDtqDMcNLfZDu9rls= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= github.com/aws/aws-sdk-go-v2/service/athena v1.0.0 h1:UfrZP3NMTTKpOsf/P8uCaOxz3U2CNGEizdQKcObY7Ds= github.com/aws/aws-sdk-go-v2/service/athena v1.0.0/go.mod h1:qY8QFbemf2ceqweXcS6hQqiiIe1z42WqTvHsK2Lb0rE= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.27.1 h1:plNo3WtooT2fYnhdyuzzsIJ4QWzcF5AT9oFbnrYC5Dw= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.27.1/go.mod h1:N5tqZcYMM0N1PN7UQYJNWuGyO886OfnMhf/3MAbqMcI= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.18.7 h1:srShyROqxzC7p18Ws8mqM2sqxJO/8L3Kpiqf+NboJLg= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.18.7/go.mod h1:9efZgg4nJCGRp91MuHhkwd2kvyp7PWLRYYk5WjEQ5ts= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9/go.mod h1:idky4TER38YIjr2cADF1/ugFMKvZV7p//pVeV5LZbF0= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.8.11 h1:e9AVb17H4x5FTE5KWIP5M1Du+9M86pS+Hw0lBUdN8EY= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.8.11/go.mod h1:B90ZQJa36xo0ph9HsoteI1+r8owgQH/U1QNfqZQkj1Q= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.1 h1:Sn3MAV9YeACCULaxNWWYFH1a6G4wYFwBn3/TA5MwE2Q= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.1/go.mod h1:qutL00aW8GSo2D0I6UEOqMvRS3ZyuBrOC1BLe5D2jPc= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 h1:5UYvv8JUvllZsRnfrcMQ+hJ9jNICmcgKPAO1CER25Wg= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.5/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U= github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04= github.com/aws/smithy-go v1.0.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= @@ -235,6 +243,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= @@ -389,6 +399,8 @@ github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7 github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8= github.com/go-redis/redis v6.15.7+incompatible h1:3skhDh95XQMpnqeqNftPkQD9jL9e5e36z/1SUm6dy1U= github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= diff --git a/script/generate_config_docs.sh b/script/generate_config_docs.sh index 2a1485aed8..15036d8700 100755 --- a/script/generate_config_docs.sh +++ b/script/generate_config_docs.sh @@ -8,6 +8,8 @@ ROOT_DIR=${CUR_DIR}/.. OUTPUT_DIR="${ROOT_DIR}"/docs/deployment/configuration/generated GOBIN=${GOPATH:-~/go}/bin +make -C cacheservice compile +mv cacheservice/bin/cacheservice ${GOBIN}/cacheservice make -C datacatalog compile mv datacatalog/bin/datacatalog ${GOBIN}/datacatalog make -C flyteadmin compile