From c39a116bbb949fa6b94ed28a67d84bca3ae27187 Mon Sep 17 00:00:00 2001 From: Zhenya Tikhonov Date: Wed, 17 Sep 2025 20:53:57 +0400 Subject: [PATCH 1/4] build: deprecate `venonactl` --- .gitignore | 2 - README.md | 3 +- venonactl/.gitignore | 2 - venonactl/.goreleaser.yml | 46 - venonactl/Dockerfile | 20 - venonactl/Makefile | 11 - venonactl/README.md | 262 ---- venonactl/VERSION | 1 - venonactl/build/ci.yaml | 129 -- venonactl/cmd/attach.go | 169 --- venonactl/cmd/cmdutils.go | 320 ----- venonactl/cmd/install-agent.go | 215 --- venonactl/cmd/install-app-proxy.go | 119 -- venonactl/cmd/install-monitor.go | 148 --- venonactl/cmd/install-runtime.go | 197 --- venonactl/cmd/install-venona.go | 58 - venonactl/cmd/install.go | 29 - venonactl/cmd/migrate.go | 70 - venonactl/cmd/root.go | 56 - venonactl/cmd/status.go | 132 -- venonactl/cmd/test.go | 145 --- venonactl/cmd/uninstall-agent.go | 91 -- venonactl/cmd/uninstall-app-proxy.go | 92 -- venonactl/cmd/uninstall-monitor.go | 103 -- venonactl/cmd/uninstall-runtime.go | 145 --- venonactl/cmd/uninstall.go | 29 - venonactl/cmd/upgrade-app-proxy.go | 90 -- venonactl/cmd/upgrade.go | 95 -- venonactl/cmd/version.go | 43 - venonactl/example/values-example.yaml | 308 ----- venonactl/go.mod | 134 -- venonactl/go.sum | 859 ------------ venonactl/hack/build-linux.sh | 11 - venonactl/hack/build.sh | 11 - venonactl/hack/fmt.sh | 3 - venonactl/hack/generate.go | 7 - venonactl/main.go | 69 - venonactl/main_windows.go | 42 - venonactl/pkg/certs/server_cert.go | 82 -- venonactl/pkg/codefresh/cfapi.go | 210 --- venonactl/pkg/kube/kube.go | 109 -- venonactl/pkg/logger/custom-logger.go | 28 - venonactl/pkg/logger/logger.go | 40 - venonactl/pkg/obj/kubeobj/kubeobj.go | 581 --------- venonactl/pkg/obj/kubeobj_generator.go | 202 --- venonactl/pkg/plugins/app-proxy.go | 132 -- venonactl/pkg/plugins/engine.go | 111 -- venonactl/pkg/plugins/helper.go | 367 ------ venonactl/pkg/plugins/monitor.go | 127 -- venonactl/pkg/plugins/network-tester.go | 238 ---- venonactl/pkg/plugins/plugin.go | 353 ----- venonactl/pkg/plugins/runtime-attach.go | 378 ------ venonactl/pkg/plugins/runtime-environment.go | 204 --- venonactl/pkg/plugins/types.go | 30 - venonactl/pkg/plugins/venona.go | 379 ------ venonactl/pkg/plugins/volume-provisioner.go | 195 --- venonactl/pkg/store/store.go | 232 ---- venonactl/pkg/templates/generate_template.go | 106 -- .../cluster-role-binding.app-proxy.yaml | 14 - ...le-binding.dind-volume-provisioner.vp.yaml | 17 - .../cluster-role-binding.venona.yaml | 14 - .../kubernetes/cluster-role.app-proxy.yaml | 13 - ...uster-role.dind-volume-provisioner.vp.yaml | 36 - .../codefresh-certs-server-secret.re.yaml | 13 - .../cron-job.dind-volume-cleanup.vp.yaml | 31 - .../daemonset.dind-lv-monitor.vp.yaml | 87 -- .../kubernetes/deployment.app-proxy.yaml | 75 -- ...deployment.dind-volume-provisioner.vp.yaml | 123 -- .../kubernetes/deployment.monitor.yaml | 81 -- .../kubernetes/deployment.venona.yaml | 106 -- .../kubernetes/dind-daemon-conf.re.yaml | 20 - .../kubernetes/dind-headless-service.re.yaml | 20 - .../kubernetes/ingress.app-proxy.yaml | 30 - .../kubernetes/pod.network-tester.yaml | 44 - .../kubernetes/role-binding.engine.yaml | 15 - .../templates/kubernetes/role-binding.re.yaml | 15 - .../pkg/templates/kubernetes/role.engine.yaml | 11 - .../templates/kubernetes/role.monitor.yaml | 49 - .../pkg/templates/kubernetes/role.re.yaml | 11 - .../kubernetes/rolebinding.monitor.yaml | 28 - .../rollback-role-binding.monitor.yaml | 24 - .../rollback-serviceaccount.monitor.yaml | 16 - .../secret.dind-volume-provisioner.vp.yaml | 18 - .../kubernetes/secret.runtime-attach.yaml | 10 - .../templates/kubernetes/secret.venona.yaml | 8 - .../kubernetes/service-account.app-proxy.yaml | 14 - ...ce-account.dind-volume-provisioner.vp.yaml | 14 - .../kubernetes/service-account.engine.yaml | 14 - .../kubernetes/service-account.monitor.yaml | 16 - .../kubernetes/service-account.re.yaml | 7 - .../kubernetes/service.app-proxy.yaml | 15 - .../templates/kubernetes/service.monitor.yaml | 19 - ...orageclass.dind-volume-provisioner.vp.yaml | 57 - .../pkg/templates/kubernetes/templates.go | 1155 ----------------- .../kubernetes/venonaconf.secret.venona.yaml | 10 - 95 files changed, 1 insertion(+), 10619 deletions(-) delete mode 100644 venonactl/.gitignore delete mode 100644 venonactl/.goreleaser.yml delete mode 100644 venonactl/Dockerfile delete mode 100644 venonactl/Makefile delete mode 100644 venonactl/README.md delete mode 100644 venonactl/VERSION delete mode 100644 venonactl/build/ci.yaml delete mode 100644 venonactl/cmd/attach.go delete mode 100644 venonactl/cmd/cmdutils.go delete mode 100644 venonactl/cmd/install-agent.go delete mode 100644 venonactl/cmd/install-app-proxy.go delete mode 100644 venonactl/cmd/install-monitor.go delete mode 100644 venonactl/cmd/install-runtime.go delete mode 100644 venonactl/cmd/install-venona.go delete mode 100644 venonactl/cmd/install.go delete mode 100644 venonactl/cmd/migrate.go delete mode 100644 venonactl/cmd/root.go delete mode 100644 venonactl/cmd/status.go delete mode 100644 venonactl/cmd/test.go delete mode 100644 venonactl/cmd/uninstall-agent.go delete mode 100644 venonactl/cmd/uninstall-app-proxy.go delete mode 100644 venonactl/cmd/uninstall-monitor.go delete mode 100644 venonactl/cmd/uninstall-runtime.go delete mode 100644 venonactl/cmd/uninstall.go delete mode 100644 venonactl/cmd/upgrade-app-proxy.go delete mode 100644 venonactl/cmd/upgrade.go delete mode 100644 venonactl/cmd/version.go delete mode 100644 venonactl/example/values-example.yaml delete mode 100644 venonactl/go.mod delete mode 100644 venonactl/go.sum delete mode 100755 venonactl/hack/build-linux.sh delete mode 100755 venonactl/hack/build.sh delete mode 100755 venonactl/hack/fmt.sh delete mode 100644 venonactl/hack/generate.go delete mode 100644 venonactl/main.go delete mode 100644 venonactl/main_windows.go delete mode 100644 venonactl/pkg/certs/server_cert.go delete mode 100644 venonactl/pkg/codefresh/cfapi.go delete mode 100644 venonactl/pkg/kube/kube.go delete mode 100644 venonactl/pkg/logger/custom-logger.go delete mode 100644 venonactl/pkg/logger/logger.go delete mode 100644 venonactl/pkg/obj/kubeobj/kubeobj.go delete mode 100644 venonactl/pkg/obj/kubeobj_generator.go delete mode 100644 venonactl/pkg/plugins/app-proxy.go delete mode 100644 venonactl/pkg/plugins/engine.go delete mode 100644 venonactl/pkg/plugins/helper.go delete mode 100644 venonactl/pkg/plugins/monitor.go delete mode 100644 venonactl/pkg/plugins/network-tester.go delete mode 100644 venonactl/pkg/plugins/plugin.go delete mode 100644 venonactl/pkg/plugins/runtime-attach.go delete mode 100644 venonactl/pkg/plugins/runtime-environment.go delete mode 100644 venonactl/pkg/plugins/types.go delete mode 100644 venonactl/pkg/plugins/venona.go delete mode 100644 venonactl/pkg/plugins/volume-provisioner.go delete mode 100644 venonactl/pkg/store/store.go delete mode 100644 venonactl/pkg/templates/generate_template.go delete mode 100644 venonactl/pkg/templates/kubernetes/cluster-role-binding.app-proxy.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/cluster-role-binding.dind-volume-provisioner.vp.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/cluster-role-binding.venona.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/cluster-role.app-proxy.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/cluster-role.dind-volume-provisioner.vp.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/codefresh-certs-server-secret.re.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/cron-job.dind-volume-cleanup.vp.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/daemonset.dind-lv-monitor.vp.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/deployment.app-proxy.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/deployment.dind-volume-provisioner.vp.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/deployment.monitor.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/deployment.venona.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/dind-daemon-conf.re.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/dind-headless-service.re.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/ingress.app-proxy.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/pod.network-tester.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/role-binding.engine.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/role-binding.re.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/role.engine.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/role.monitor.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/role.re.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/rolebinding.monitor.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/rollback-role-binding.monitor.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/rollback-serviceaccount.monitor.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/secret.dind-volume-provisioner.vp.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/secret.runtime-attach.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/secret.venona.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/service-account.app-proxy.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/service-account.dind-volume-provisioner.vp.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/service-account.engine.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/service-account.monitor.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/service-account.re.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/service.app-proxy.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/service.monitor.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/storageclass.dind-volume-provisioner.vp.yaml delete mode 100644 venonactl/pkg/templates/kubernetes/templates.go delete mode 100644 venonactl/pkg/templates/kubernetes/venonaconf.secret.venona.yaml diff --git a/.gitignore b/.gitignore index 1edfc8de..e6c98d53 100644 --- a/.gitignore +++ b/.gitignore @@ -13,8 +13,6 @@ encodings.xml yarn-error.log .idea/* telepresence.log -venonactl/dist/* -venonactl-linux venonalog.json .venonaconf .cover diff --git a/README.md b/README.md index 641676cf..7accd5c9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1 @@ -* [venonactl](venonactl/README.md) - Codefresh installer of Kubernetes YAML's. -* [venona](venona/README.md) - Codefresh runner process, [official docs](https://codefresh.io/docs/docs/administration/codefresh-runner/). \ No newline at end of file +* [venona](venona/README.md) - Codefresh runner process, [official docs](https://codefresh.io/docs/docs/administration/codefresh-runner/). diff --git a/venonactl/.gitignore b/venonactl/.gitignore deleted file mode 100644 index 1ddcf913..00000000 --- a/venonactl/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea/ -/vendor/ diff --git a/venonactl/.goreleaser.yml b/venonactl/.goreleaser.yml deleted file mode 100644 index 1f77807d..00000000 --- a/venonactl/.goreleaser.yml +++ /dev/null @@ -1,46 +0,0 @@ -before: - hooks: - - go mod tidy - -builds: -- goos: - - darwin - - linux - - windows - goarch: - - amd64 - - 386 - env: - - CGO_ENABLED=0 - ignore: - - goos: darwin - goarch: 386 - ldflags: - - -X github.com/codefresh-io/venona/venonactl/cmd.version={{.Version}} -X github.com/codefresh-io/venona/venonactl/cmd.commit={{.Commit}} -X github.com/codefresh-io/venona/venonactl/cmd.date={{.Date}} - -archives: -- - replacements: - darwin: Darwin - linux: Linux - windows: Windows - 386: i386 - amd64: x86_64 - name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" - format_overrides: - - goos: windows - format: zip -changelog: - sort: asc - filters: - exclude: - - '^docs:' - - '^test:' - - -release: - # If set to auto, will mark the release as not ready for production - # in case there is an indicator for this in the tag e.g. v1.0.0-rc1 - # If set to true, will mark the release as not ready for production. - # Default is false. - prerelease: false diff --git a/venonactl/Dockerfile b/venonactl/Dockerfile deleted file mode 100644 index 6fe267e2..00000000 --- a/venonactl/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM golang:1.21-alpine3.20 AS build -WORKDIR /venona -COPY go.mod . -RUN go mod download -RUN apk add git -COPY . . -ARG COMMIT -RUN VERSION=$(cat VERSION) \ - DATE=$(date -u "+%Y-%m-%dT%TZ") && \ - env CGO_ENABLED=0 \ - go build -ldflags="-w -X github.com/codefresh-io/venona/venonactl/cmd.version=${VERSION} \ - -X github.com/codefresh-io/venona/venonactl/cmd.commit=${COMMIT} -X github.com/codefresh-io/venona/venonactl/cmd.date=${DATE}" \ - -o venona - -FROM alpine:3.20 -RUN apk add --update ca-certificates -COPY --from=build /venona/venona /usr/local/bin/venona - -ENTRYPOINT [ "venona" ] -CMD [ "--help" ] diff --git a/venonactl/Makefile b/venonactl/Makefile deleted file mode 100644 index c9875dc9..00000000 --- a/venonactl/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -.PHONY: build -build: build-local - -build-local: - @sh ./hack/build.sh - -build-linux: - @sh ./hack/build-linux.sh - -fmt: - go fmt ./... diff --git a/venonactl/README.md b/venonactl/README.md deleted file mode 100644 index 4531081e..00000000 --- a/venonactl/README.md +++ /dev/null @@ -1,262 +0,0 @@ -# VENONACTL -Codefresh installer of Kubernetes YAML onto the cluster - -## Version 1.x.x -Version 1.x.x is is about to be released soon, read more about migration from older version [here](#Migration) -Meanwhile 1.x.x is to release and makred as pre-release we will maintain 2 branches: -* `master` - the previous version ( `version < 1.0.0` ) - * we will keep maintaing if (bugs, security issues) - this version will be intalled when installing `venona` on MacOS using brew - * `codefresh/venona:latest` will refer to this branch -* `release-1.0` it the new release, which will be used when running Codefresh CLI to install the agent -We highly suggest to use [Codefresh official CLI](https://codefresh-io.github.io/cli/) to install the agent: -```bash -codefresh runner init -``` - -The last command will: -1. Install the agent on the namespace `codefresh` (as you choose) -2. Install the runtime on the same namespace -3. Attach the runtime to the agent -4. Register cluster on codefresh platform -5. Create and run demo pipeline - -It is still possible, for advanced users to install all manually, for example: -One process of Venona can manage multiple runtime environments -NOTE: Please make sure that the process where Venona is installed there is a network connection to the clusters where the runtimes will be installed -```bash -# 1. Create namespace for the agent: -kubectl create namespace codefresh-agent - -# 2. Install the agent on the namespace ( give your agent a unique): -# Print a token that the Venona process will be using. -codefresh create agent $NAME -codefresh install agent --token $TOKEN --kube-namespace codefresh-agent - -# 3. Create namespace for the first runtime: -kubectl create namespace codefresh-runtime-1 - -# 4. Install the first runtime on the namespace -# 5. the runtime name is printed -codefresh install runtime --kube-namespace codefresh-runtime-1 - -# 6. Attach the first runtime to agent: -codefresh attach runtime --agent-name $AGENT_NAME --agent-kube-namespace codefresh-agent --runtime-name $RUNTIME_NAME --kube-namespace codefresh-runtime-1 - -# 7. Restart the venona pod in namespace `codefresh-agent` -kubectl delete pods $VENONA_POD - -# 8. Create namespace for the second runtime -kubectl create namespace codefresh-runtime-2 - -# 9. Install the second runtime on the namespace -codefresh install runtime --kube-namespace codefresh-runtime-2 - -# 10. Attach the second runtime to agent and restart the Venoa pod automatically -codefresh attach runtime --agent-name $AGENT_NAME --agent-kube-namespace codefresh-agent --runtime-name $RUNTIME_NAME --runtime-kube-namespace codefresh-runtime-1 --restart-agent - -``` - -## Migration -Migrating from Venona `< 1.x.x` to `> 1.x.x` is not done automatically, please run the follwing -```bash -codefresh runner upgrade -``` - - -## Installation - -### Prerequisite: -* [Kubernetes](https://kubernetes.io/docs/tasks/tools/install-kubectl/) - Used to create resource in your K8S cluster - * Kube Version > 1.10: - * [Instuction](#Install-on-cluster-version-<-1.10) to install on cluster version < 1.10 - * Disk size 50GB per node -* [Codefresh](https://codefresh-io.github.io/cli/) - Used to create resource in Codefresh - * Authenticated context exist under `$HOME/.cfconfig` or authenticate with [Codefesh CLI](https://codefresh-io.github.io/cli/getting-started/#authenticate) - -### Install venona - -* Download [venona's](https://github.com/codefresh-io/venona/releases) binary - * With homebrew: - * `brew tap codefresh-io/venona` - * `brew install venona` - - -#### Install on cluster version < 1.10 -* Make sure the `PersistentLocalVolumes` [feature gate](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) is turned on -* Venona's agent is trying to load avaliables apis using api `/openapi/v2` endpoint -Add this endpoint to ClusterRole `system:discovery` under `rules[0].nonResourceURLs` -```yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: system:discovery -rules: -- nonResourceURLs: - - ...other_resources - - /openapi - - /openapi/* - verbs: - - get -``` -#### Install using --values -`codefresh runner init --values [parameters]` -the values from values.yaml are applied to the templates in [pkg/templates/kubernetes](pkg/templates/kubernetes) - -See BuildValues() func in [store.go](pkg/store/store.go) for the format -Example with explanation is in [values-example.yaml](example/values-example.yaml) - -#### Install on GCP - * Make sure your user has `Kubernetes Engine Cluster Admin` role in google console - * Bind your user with cluster-admin kubernetes clusterrole - > `kubectl create clusterrolebinding NAME --clusterrole cluster-admin --user YOUR_USER` - -#### Pipeline Storage with docker cache support - -##### **GKE LocalSSD** -*Prerequisite:* [GKE custer with local SSD](https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/local-ssd) - -*Install venona for using GKE Local SSD:* -``` -codefresh install runtime [options] \ - --set-value=Storage.LocalVolumeParentDir=/mnt/disks/ssd0/codefresh-volumes - --kube-node-selector=cloud.google.com/gke-local-ssd=true -``` - -##### **GCE Disks** -*Prerequisite:* volume provisioner (dind-volume-provisioner) should have permissions to create/delete/get of google disks -There are 3 options to provide cloud credentials on GCE: -* run venona dind-volume-provisioniner on node with iam role which is allowed to create/delete/get of google disks -* create Google Service Account with ComputeEngine.StorageAdmin, download its key and pass it to venona installed with `--set-file=Storage.GooogleServiceAccount=/path/to/google-service-account.json` -* use [Google Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity) to assign iam role to `volume-provisioner-venona` service account - -*Note*: Builds will be running in single availability zone, so you must to specify AvailabilityZone params - - -*Install venona for using GKE Disks:* -``` -codefresh install runtime [options] \ - --set-value=Storage.Backend=gcedisk \ - --set-value=Storage.AvailabilityZone=us-central1-a \ - --kube-node-selector=failure-domain.beta.kubernetes.io/zone=us-central1-a \ - [--set-file=Storage.GoogleServiceAccount=/path/to/google-service-account.json] -``` - -##### **Amazon EBS** - -*Prerequisite:* volume provisioner (dind-volume-provisioner) should have permissions to create/delete/get of aws ebs -Minimal iam policy for dind-volume-provisioner: -```json -{ - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "ec2:AttachVolume", - "ec2:CreateSnapshot", - "ec2:CreateTags", - "ec2:CreateVolume", - "ec2:DeleteSnapshot", - "ec2:DeleteTags", - "ec2:DeleteVolume", - "ec2:DescribeInstances", - "ec2:DescribeSnapshots", - "ec2:DescribeTags", - "ec2:DescribeVolumes", - "ec2:DetachVolume" - ], - "Resource": "*" - } - ] -} -``` - -There are 3 options to provide cloud credentials on AWS: -* run venona dind-volume-provisioniner on node with the iam role - use `--set-value Storage.VolumeProvisioner.NodeSelector=node-label=value` option -* create AWS IAM User, assign it the permissions above and suppy aws credentials to venona installer `--set-value=Storage.AwsAccessKeyId=ABCDF --set-value=Storage.AwsSecretAccessKey=ZYXWV` - -* use [Aws Identity for Service Account](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) to assign iam role to `volume-provisioner-venona` service account - -*Notes*: -- Builds will be running in single availability zone, so you must specify AvailabilityZone parameter `--set-value=Storage.AvailabilityZone=` and build-node-selector `--build-node-selector=failure-domain.beta.kubernetes.io/zone=` in case of multizone cluster - -- We support both [in-tree ebs](https://kubernetes.io/docs/concepts/storage/volumes/#awselasticblockstore) (`--set-value=Storage.Backend=ebs`) volumes and ebs-csi(https://github.com/kubernetes-sigs/aws-ebs-csi-driver) (`--set-value=Storage.Backend=ebs-csi`) - -*Install Command to run pipelines on ebs volumes* -``` -codefresh install runtime [options] \ - --set-value=Storage.Backend=ebs \ - --set-value=Storage.AvailabilityZone=us-east-1d \ - --kube-node-selector=failure-domain.beta.kubernetes.io/zone=us-east-1d \ - [--set-value Storage.VolumeProvisioner.NodeSelector=kubernetes.io/role=master] \ - [--set-value Storage.AwsAccessKeyId=ABCDF --set-value Storage.AwsSecretAccessKey=ZYXWV]\ - [--set-value=Storage.Encrypted=true] \ - [--set-value=Storage.KmsKeyId=] -``` - -##### **Azure Disk** -*Prerequisite:* volume provisioner (dind-volume-provisioner) should have permissions to create/delete/get Auzure Disks - -Minimal iam Role for dind-volume-provisioner - dind-volume-provisioner-role.json: -```json -{ - "Name": "CodefreshDindVolumeProvisioner", - "Description": "Perform create/delete/get disks", - "IsCustom": true, - "Actions": [ - "Microsoft.Compute/disks/read", - "Microsoft.Compute/disks/write", - "Microsoft.Compute/disks/delete" - - ], - "AssignableScopes": ["/subscriptions/"] -} -``` -If you use AKS with managed [identities for node group](https://docs.microsoft.com/en-us/azure/aks/use-managed-identity), you can run the script below to assign CodefreshDindVolumeProvisioner role to aks node identity: -```bash -export ROLE_DEFINITIN_FILE=dind-volume-provisioner-role.json -export SUBSCRIPTION_ID=$(az account show --query "id" | xargs echo ) -export RESOURCE_GROUP=codefresh-rt1 -export AKS_NAME=codefresh-rt1 -export LOCATION=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query location | xargs echo) -export NODES_RESOURCE_GROUP=MC_${RESOURCE_GROUP}_${AKS_NAME}_${LOCATION} -export NODE_SERVICE_PRINCIPAL=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query identityProfile.kubeletidentity.objectId | xargs echo) - -az role definition create --role-definition @${ROLE_DEFINITIN_FILE} -az role assignment create --assignee $NODE_SERVICE_PRINCIPAL --scope /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$NODES_RESOURCE_GROUP --role CodefreshDindVolumeProvisioner -``` - -Now create runner with `--set-value Storage.Backend=azuredisk --set Storage.VolumeProvisioner.MountAzureJson=true`: -``` -codefresh runner init --set-value Storage.Backend=azuredisk --set Storage.VolumeProvisioner.MountAzureJson=true -``` -Or using runner-values.yaml file like below: -```yaml -# CodefreshHost: https://g.codefresh.io -# Token: ****** -# Namespace: default -# Context: codefresh-rt1 -# RuntimeInCluster: true -Storage: - Backend: azuredisk - VolumeProvisioner: - MountAzureJson: true -``` -``` -codefresh runner init --values runner-values.yaml -``` - -#### Kubernetes RBAC -Installation of Venona on Kubernetes cluster installing 2 groups of objects, -Each one has own RBAC needs and therefore, created roles(and cluster-roles) -The resource descriptors are avaliable [here](https://github.com/codefresh-io/venona/tree/master/venonactl/templates/kubernetes) -List of the resources that will be created -* Agent (grouped by `/.*.venona.yaml/`) - * `service-account.re.yaml` - The service account that the Venona pod will use to create the resource on the runtime namespace(the resoucre installed on the runtime namespace) - * `role.re.yaml` - Allow to GET, CREATE and DELETE pods and persistentvolumeclaims - * `role-binding.re.yaml` - The agent is spinning up pods and pvc, this biniding binds `role.venona.yaml` to `service-account.venona.yaml` - * `cluster-role-binding.venona.yaml` - The agent discovering K8S apis by calling to `openapi/v2`, this ClusterRoleBinding binds bootstraped ClusterRole by Kubernetes `system:discovery` to `service-account.venona.yaml`. This role has only permissions to make a GET calls to non resources urls -* Runtime-environment (grouped by `/.*.re.yaml/`) Kubernetes controller that spins up all required resources to provide a good caching expirience during pipeline execution - * `service-account.dind-volume-provisioner.re.yaml` - The service account that the controller will use - * `cluster-role.dind-volume-provisioner.re.yaml` Defines all the permission needed for the controller to operate correctly - * `cluster-role-binding.dind-volume-provisioner.yaml` - Binds the ClusterRole to `service-account.dind-volume-provisioner.re.yaml` diff --git a/venonactl/VERSION b/venonactl/VERSION deleted file mode 100644 index f1547e6d..00000000 --- a/venonactl/VERSION +++ /dev/null @@ -1 +0,0 @@ -2.0.7 diff --git a/venonactl/build/ci.yaml b/venonactl/build/ci.yaml deleted file mode 100644 index c6970987..00000000 --- a/venonactl/build/ci.yaml +++ /dev/null @@ -1,129 +0,0 @@ -version: '1.0' -mode: parallel -stages: -- Clone -- Build -- Push -- Release -steps: - - main_clone: - stage: Clone - title: Clone repository - type: git-clone - repo: https://github.com/${{CF_REPO_OWNER}}/${{CF_REPO_NAME}} - revision: ${{CF_BRANCH}} - credentials: - username: github - password: ${{secrets.hybrid.git}} - - export_version: - title: Compare version to venona - stage: Build - image: codefresh/semver - commands: - - export VENONACTL_VERSION=$(cat ./venonactl/VERSION) - - export VENONA_VERSION=$(cat ./venona/VERSION) - - echo "Venona version -> $VENONA_VERSION ---- Venonactl version -> $VENONACTL_VERSION" - - semver-cli equal $VENONACTL_VERSION $VENONA_VERSION - - cf_export VERSION=$VENONACTL_VERSION - when: - steps: - - name: main_clone - on: - - success - - build_cli_image: - title: "Building venona cli image" - type: build - stage: Build - tag: ${{CF_BRANCH_TAG_NORMALIZED}} - working_directory: ${{main_clone}}/venonactl - image_name: ${{IMAGE_NAME}} - build_arguments: - - COMMIT=${{CF_REVISION}} - when: - steps: - - name: export_version - on: - - success - - push_cli_image_dev: - title: "Push image with venona cli" - stage: Push - type: push - candidate: ${{build_cli_image}} - tags: - - ${{CF_BRANCH_TAG_NORMALIZED}} - when: - branch: - ignore: [ "${{RELEASE_BRANCH_NAME}}" ] - steps: - - name: build_cli_image - on: - - success - scale: - push_quay_dev: - registry: "${{REGISTRY_INTEGRATION_QUAY}}" - push_dockerhub_dev: - registry: "${{REGISTRY_INTEGRATION_DOCKERHUB}}" - push_gcr_enterprise_dev: - registry: "${{REGISTRY_INTEGRATION_ENTERPRISE}}" - - push_cli_image_prod: - title: "Push image with venona cli" - stage: Push - type: push - candidate: ${{build_cli_image}} - tags: - - ${{VERSION}} - - latest - when: - branch: - only: [ "${{RELEASE_BRANCH_NAME}}" ] - steps: - - name: build_cli_image - on: - - success - scale: - push_quay_prod: - registry: "${{REGISTRY_INTEGRATION_QUAY}}" - push_dockerhub_prod: - registry: "${{REGISTRY_INTEGRATION_DOCKERHUB}}" - push_gcr_enterprise_prod: - registry: "${{REGISTRY_INTEGRATION_ENTERPRISE}}" - - create_git_tag: - title: Push tag to git - image: quay.io/codefresh/ci-helpers:0.1.0 - stage: Release - commands: - - source /get-token/get-gh-token.sh && cf_export GITHUB_TOKEN - - export OLD_ORIGIN=$(git remote get-url origin) - - git remote rm origin - - git remote add origin https://${GITHUB_TOKEN}@github.com/${{CF_REPO_OWNER}}/venona.git - - git tag ${{VERSION}} - - git push --tags - - fail_fast: false - when: - branch: - only: [ "${{RELEASE_BRANCH_NAME}}" ] - steps: - - name: export_version - - name: main_clone - - release_binaries: - title: Create release in Github with venona CLI - image: goreleaser/goreleaser:v1.18.2 - stage: Release - commands: - - cd venonactl - - goreleaser release -f .goreleaser.yml --rm-dist --skip-validate # pre-release - when: - branch: - only: [ "${{RELEASE_BRANCH_NAME}}" ] - steps: - - name: create_git_tag - on: - - finished diff --git a/venonactl/cmd/attach.go b/venonactl/cmd/attach.go deleted file mode 100644 index 512edfbc..00000000 --- a/venonactl/cmd/attach.go +++ /dev/null @@ -1,169 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "fmt" - - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/codefresh-io/venona/venonactl/pkg/store" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var attachRuntimeCmdOptions struct { - runtimeEnvironmentName string - kube struct { - namespace string - inCluster bool - context string - kubePath string - serviceAccount string - host string - } - kubeVenona struct { - namespace string - kubePath string - context string - } - restartAgent bool - templateValues []string - templateFileValues []string - templateValueFiles []string - dryRun bool -} - -var attachRuntimeCmd = &cobra.Command{ - Use: "attach", - Short: "Attach Codefresh runtime to agent", - Run: func(cmd *cobra.Command, args []string) { - // get valuesMap from --values --set-value k=v --set-file k= - templateValuesMap, err := templateValuesToMap( - attachRuntimeCmdOptions.templateValueFiles, - attachRuntimeCmdOptions.templateValues, - attachRuntimeCmdOptions.templateFileValues) - if err != nil { - dieOnError(err) - } - // Merge cmd options with template - mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) - mergeValueStr(templateValuesMap, "ConfigPath", &attachRuntimeCmdOptions.kube.kubePath) - mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) - mergeValueStr(templateValuesMap, "Token", &cfAPIToken) - - mergeValueStr(templateValuesMap, "Namespace", &attachRuntimeCmdOptions.kube.namespace) - mergeValueStr(templateValuesMap, "Context", &attachRuntimeCmdOptions.kube.context) - mergeValueStr(templateValuesMap, "KubernetesHost", &attachRuntimeCmdOptions.kube.host) - mergeValueStr(templateValuesMap, "RuntimeEnvironmentName", &attachRuntimeCmdOptions.runtimeEnvironmentName) - mergeValueStr(templateValuesMap, "RuntimeServiceAccount", &attachRuntimeCmdOptions.kube.serviceAccount) - - s := store.GetStore() - lgr := createLogger("Attach-runtime", verbose, logFormatter) - buildBasicStore(lgr) - extendStoreWithKubeClient(lgr) - - s.CodefreshAPI = &store.CodefreshAPI{} - s.AgentAPI = &store.AgentAPI{} - - if attachRuntimeCmdOptions.kubeVenona.kubePath == "" { - attachRuntimeCmdOptions.kubeVenona.kubePath = kubeConfigPath - } - if attachRuntimeCmdOptions.kubeVenona.namespace == "" { - attachRuntimeCmdOptions.kubeVenona.namespace = attachRuntimeCmdOptions.kube.namespace - } - if attachRuntimeCmdOptions.kubeVenona.context == "" { - attachRuntimeCmdOptions.kubeVenona.context = attachRuntimeCmdOptions.kube.context - } - - if attachRuntimeCmdOptions.kube.serviceAccount == "" { - attachRuntimeCmdOptions.kube.serviceAccount = s.AppName - } - - if attachRuntimeCmdOptions.kube.kubePath == "" { - attachRuntimeCmdOptions.kube.kubePath = kubeConfigPath - } - - fillKubernetesAPI(lgr, attachRuntimeCmdOptions.kubeVenona.context, attachRuntimeCmdOptions.kubeVenona.namespace, false) - - builder := plugins.NewBuilder(lgr) - - builderInstallOpt := &plugins.InstallOptions{ - ClusterNamespace: attachRuntimeCmdOptions.kubeVenona.namespace, - ClusterHost: attachRuntimeCmdOptions.kube.host, - RuntimeEnvironment: attachRuntimeCmdOptions.runtimeEnvironmentName, - RuntimeNamespace: attachRuntimeCmdOptions.kube.namespace, - RuntimeServiceAccount: attachRuntimeCmdOptions.kube.serviceAccount, - RestartAgent: attachRuntimeCmdOptions.restartAgent, - DryRun: attachRuntimeCmdOptions.dryRun, - } - - // runtime - var runtimeInCluster bool - mergeValueBool(templateValuesMap, "RuntimeInCluster", &runtimeInCluster) - builderInstallOpt.KubeBuilder = getKubeClientBuilder(attachRuntimeCmdOptions.kube.context, attachRuntimeCmdOptions.kube.namespace, attachRuntimeCmdOptions.kube.kubePath, runtimeInCluster, attachRuntimeCmdOptions.dryRun) - - // agent - builderInstallOpt.AgentKubeBuilder = getKubeClientBuilder(attachRuntimeCmdOptions.kubeVenona.context, - attachRuntimeCmdOptions.kubeVenona.namespace, - attachRuntimeCmdOptions.kubeVenona.kubePath, - false, - attachRuntimeCmdOptions.dryRun) - - builder.Add(plugins.RuntimeAttachType) - - values := s.BuildValues() - values = mergeMaps(values, templateValuesMap) - spn := createSpinner("Attaching runtime to agent (might take a few seconds)", "") - spn.Start() - for _, p := range builder.Get() { - values, err = p.Install(cmd.Context(), builderInstallOpt, values) - if err != nil { - dieOnError(err) - } - } - spn.Stop() - lgr.Info("Attach to runtime completed Successfully") - - }, -} - -func init() { - rootCmd.AddCommand(attachRuntimeCmd) - viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") - viper.BindEnv("kube-context", "KUBE_CONTEXT") - - viper.SetDefault("kube-namespace", "default") - - attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kube.host, "kube-host", viper.GetString("kube-host"), "overrides the address of the api-server the runner will use") - attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona should be installed [$KUBE_NAMESPACE]") - attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which venona should be installed (default is current-context) [$KUBE_CONTEXT]") - attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kube.kubePath, "kube-config-path", viper.GetString("kubeconfig"), "Path to kubeconfig file (default is $HOME/.kube/config) [$KUBECONFIG]") - attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kube.serviceAccount, "kube-service-account", viper.GetString("kube-service-account"), fmt.Sprintf("Name of the kubernetes service account (default is %s)", plugins.AppName)) - - attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.runtimeEnvironmentName, "runtime-name", viper.GetString("runtime-name"), "Name of the runtime as in codefresh") - - attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kubeVenona.namespace, "kube-namespace-agent", viper.GetString("kube-namespace-agent"), "Name of the namespace where venona is installed [$KUBE_NAMESPACE]") - attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kubeVenona.context, "kube-context-name-agent", viper.GetString("kube-context-agent"), "Name of the kubernetes context on which venona is installed (default is current-context) [$KUBE_CONTEXT]") - attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kubeVenona.kubePath, "kube-config-path-agent", viper.GetString("kubeconfig-agent"), "Path to kubeconfig file (default is $HOME/.kube/config) for agent [$KUBECONFIG]") - attachRuntimeCmd.Flags().BoolVar(&attachRuntimeCmdOptions.restartAgent, "restart-agent", viper.GetBool("restart-agent"), "Restart agent after attach operation") - attachRuntimeCmd.Flags().BoolVar(&attachRuntimeCmdOptions.dryRun, "dry-run", false, "Set to true to simulate installation") - - attachRuntimeCmd.Flags().StringArrayVar(&attachRuntimeCmdOptions.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") - attachRuntimeCmd.Flags().StringArrayVar(&attachRuntimeCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") - attachRuntimeCmd.Flags().StringArrayVarP(&attachRuntimeCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") - -} diff --git a/venonactl/cmd/cmdutils.go b/venonactl/cmd/cmdutils.go deleted file mode 100644 index acb9fe06..00000000 --- a/venonactl/cmd/cmdutils.go +++ /dev/null @@ -1,320 +0,0 @@ -package cmd - -import ( - "fmt" - "os" - "os/user" - "path/filepath" - "strings" - "time" - - "encoding/json" - - "github.com/briandowns/spinner" - "github.com/codefresh-io/go-sdk/pkg/codefresh" - sdkUtils "github.com/codefresh-io/go-sdk/pkg/utils" - "github.com/codefresh-io/venona/venonactl/pkg/certs" - "github.com/codefresh-io/venona/venonactl/pkg/kube" - "github.com/codefresh-io/venona/venonactl/pkg/logger" - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/codefresh-io/venona/venonactl/pkg/store" - "github.com/olekukonko/tablewriter" - k8sApi "k8s.io/api/core/v1" - "k8s.io/client-go/tools/clientcmd" - - "github.com/stretchr/objx" - cliValues "helm.sh/helm/v3/pkg/cli/values" - "helm.sh/helm/v3/pkg/getter" -) - -var ( - version = "dev" - commit = "none" - date = "unknown" - - verbose bool - logFormatter string - - configPath string - cfAPIHost string - cfAPIToken string - cfContext string - - kubeConfigPath string -) - -func buildBasicStore(logger logger.Logger) { - s := store.GetStore() - s.Version = &store.Version{ - Current: &store.CurrentVersion{ - Version: version, - Commit: commit, - Date: date, - }, - } - - s.Image = &store.Image{ - Name: "codefresh/venona", - } - - s.Mode = store.ModeInCluster - - s.ServerCert = &certs.ServerCert{} - - s.AppName = store.ApplicationName - s.Image.Tag = s.Version.Current.Version -} - -func extendStoreWithCodefershClient(logger logger.Logger) error { - s := store.GetStore() - if configPath == "" { - currentUser, err := user.Current() - if err != nil { - return err - } - - configPath = filepath.Join(currentUser.HomeDir, ".cfconfig") - logger.Debug(fmt.Sprint("cfconfig path not set, using: ", configPath)) - } - - if _, err := os.Stat(configPath); err != nil { - return fmt.Errorf(".cfconfig file not found") - } - - if cfAPIHost == "" && cfAPIToken == "" { - context, err := sdkUtils.ReadAuthContext(configPath, cfContext) - if err != nil { - return err - } - cfAPIHost = context.URL - cfAPIToken = context.Token - logger.Debug("Using codefresh context", "Context-Name", context.Name, "Host", cfAPIHost) - } else { - logger.Debug("Reading credentials from environment variables") - if cfAPIHost == "" { - cfAPIHost = "https://g.codefresh.io" - } - } - - logger.Debug("Creating codefresh client", "host", cfAPIHost, "token", cfAPIToken) - - client := codefresh.New(&codefresh.ClientOptions{ - Auth: codefresh.AuthOptions{ - Token: cfAPIToken, - }, - Host: cfAPIHost, - }) - s.CodefreshAPI = &store.CodefreshAPI{ - Host: cfAPIHost, - Token: cfAPIToken, - Client: client, - } - - return nil -} - -func extendStoreWithKubeClient(logger logger.Logger) { - s := store.GetStore() - if kubeConfigPath == "" { - currentUser, _ := user.Current() - if currentUser != nil { - kubeConfigPath = filepath.Join(currentUser.HomeDir, ".kube", "config") - logger.Debug("Path to kubeconfig not set, using:", "kubeconfig", kubeConfigPath) - } - } - - s.KubernetesAPI = &store.KubernetesAPI{ - ConfigPath: kubeConfigPath, - } -} - -func setVerbosity(verbose bool) { - s := store.GetStore() - s.Verbose = verbose -} - -func setInsecure(insecure bool) { - s := store.GetStore() - s.Insecure = insecure -} - -func isUsingDefaultStorageClass(sc string) bool { - if sc == "" { - return true - } - return strings.HasPrefix(sc, plugins.DefaultStorageClassNamePrefix) -} - -func dieOnError(err error) { - if err != nil { - fmt.Printf("Error: %s\n", err.Error()) - os.Exit(1) - } -} - -func createTable() *tablewriter.Table { - table := tablewriter.NewWriter(os.Stdout) - table.SetBorder(false) - table.SetAlignment(tablewriter.ALIGN_LEFT) - table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) - table.SetRowLine(false) - table.SetHeaderLine(false) - table.SetColumnSeparator(" ") - table.SetColWidth(100) - return table -} - -func getKubeClientBuilder(context string, namespace string, path string, inCluster bool, dryRun bool) kube.Kube { - return kube.New(&kube.Options{ - ContextName: context, - Namespace: namespace, - PathToKubeConfig: path, - InCluster: inCluster, - DryRun: dryRun, - }) -} - -func createLogger(command string, verbose bool, logFormatter string) logger.Logger { - logFile := "venonalog.json" - os.Remove(logFile) - return logger.New(&logger.Options{ - Command: command, - Verbose: verbose, - LogToFile: logFile, - LogFormatter: logFormatter, - }) -} - -func createSpinner(prefix, suffix string) *spinner.Spinner { - s := spinner.New([]string{" ", ". ", ".. ", "..."}, 520*time.Millisecond) - s.Suffix = suffix - s.Prefix = prefix - return s -} - -func loadTolerationsFromFile(filename string) string { - data, err := os.ReadFile(filename) - if err != nil { - dieOnError(err) - } - - return string(data) -} - -func parseTolerations(s string) ([]k8sApi.Toleration, error) { - if s == "" { - return nil, nil - } - var data []k8sApi.Toleration - err := json.Unmarshal([]byte(s), &data) - if err != nil { - return nil, fmt.Errorf("can not parse tolerations: %s", err) - } - return data, err -} - -func fillKubernetesAPI(lgr logger.Logger, context string, namespace string, inCluster bool) { - - s := store.GetStore() - if context == "" { - config := clientcmd.GetConfigFromFileOrDie(s.KubernetesAPI.ConfigPath) - context = config.CurrentContext - lgr.Debug("Kube Context is not set, using current context", "Kube-Context-Name", context) - } - if namespace == "" { - namespace = "default" - } - - s.KubernetesAPI.InCluster = inCluster - s.KubernetesAPI.ContextName = context - s.KubernetesAPI.Namespace = namespace - -} - -func extendStoreWithAgentAPI(logger logger.Logger, token string, agentID string) { - s := store.GetStore() - logger.Debug("Using agent's token", "Token", token) - s.AgentAPI = &store.AgentAPI{ - Token: token, - Id: agentID, - } -} - -// Parsing helpers --set-value , --set-file -// by https://github.com/helm/helm/blob/ec1d1a3d3eb672232f896f9d3b3d0797e4f519e3/pkg/cli/values/options.go#L41 - -// templateValuesToMap - processes cmd --values --set-value k=v --set-file v= -// using helm libraries -func templateValuesToMap(templateValueFiles, templateValues, templateFileValues []string) (map[string]interface{}, error) { - valueOpts := &cliValues.Options{} - if len(templateValueFiles) > 0 { - for _, v := range templateValueFiles { - valueOpts.ValueFiles = append(valueOpts.ValueFiles, v) - } - } - - if len(templateValues) > 0 { - for _, v := range templateValues { - valueOpts.Values = append(valueOpts.Values, v) - } - } - - if len(templateFileValues) > 0 { - for _, v := range templateFileValues { - valueOpts.FileValues = append(valueOpts.FileValues, v) - } - } - valuesMap, err := valueOpts.MergeValues(getter.Providers{}) - return valuesMap, err -} - -func mergeMaps(a, b map[string]interface{}) map[string]interface{} { - out := make(map[string]interface{}, len(a)) - for k, v := range a { - out[k] = v - } - for k, v := range b { - if v, ok := v.(map[string]interface{}); ok { - if bv, ok := out[k]; ok { - if bv, ok := bv.(map[string]interface{}); ok { - out[k] = mergeMaps(bv, v) - continue - } - } - } - out[k] = v - } - return out -} - -// mergeValueStr - for merging cli parameters with mapped parameters -func mergeValueStr(valuesMap map[string]interface{}, key string, param *string, defaultValue ...string) { - mapX := objx.New(valuesMap) - if param != nil && *param != "" { - mapX.Set(key, *param) - return - } - val := mapX.Get(key).Str(defaultValue...) - *param = val -} - -// mergeValueBool - for merging cli parameters with mapped parameters -func mergeValueBool(valuesMap map[string]interface{}, key string, param *bool) { - mapX := objx.New(valuesMap) - if param != nil || *param == true { - mapX.Set(key, *param) - return - } - val := mapX.Get(key).Bool() - *param = val -} - -func mergeValueMSI(valuesMap map[string]interface{}, key string, param *map[string]interface{}, defaultValue ...map[string]interface{}) { - mapX := objx.New(valuesMap) - if param != nil && len(*param) > 0 { - mapX.Set(key, *param) - return - } - val := mapX.Get(key).MSI(defaultValue...) - *param = val -} diff --git a/venonactl/cmd/install-agent.go b/venonactl/cmd/install-agent.go deleted file mode 100644 index 79ffd2ea..00000000 --- a/venonactl/cmd/install-agent.go +++ /dev/null @@ -1,215 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "fmt" - "strings" - - "github.com/codefresh-io/venona/venonactl/pkg/logger" - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/codefresh-io/venona/venonactl/pkg/store" - "github.com/spf13/cobra" - "github.com/spf13/viper" - k8sApi "k8s.io/api/core/v1" - // cliValues "helm.sh/helm/v3/pkg/cli/values" - // "helm.sh/helm/v3/pkg/getter" -) - -var installAgentCmdOptions struct { - dryRun bool - kube struct { - namespace string - inCluster bool - context string - nodeSelector string - } - venona struct { - version string - } - agentToken string - agentID string - tolerations string - envVars []string - dockerRegistry string - templateValues []string - templateFileValues []string - templateValueFiles []string - resources map[string]interface{} -} - -var installAgentCmd = &cobra.Command{ - Use: "agent", - Short: "Install Codefresh's agent ", - Run: func(cmd *cobra.Command, args []string) { - - // get valuesMap from --values --set-value k=v --set-file k= - templateValuesMap, err := templateValuesToMap( - installAgentCmdOptions.templateValueFiles, - installAgentCmdOptions.templateValues, - installAgentCmdOptions.templateFileValues) - if err != nil { - dieOnError(err) - } - // Merge cmd options with template - mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) - mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) - mergeValueStr(templateValuesMap, "Token", &cfAPIToken) - mergeValueStr(templateValuesMap, "Namespace", &installAgentCmdOptions.kube.namespace) - mergeValueStr(templateValuesMap, "Context", &installAgentCmdOptions.kube.context) - mergeValueStr(templateValuesMap, "NodeSelector", &installAgentCmdOptions.kube.nodeSelector) - tolerations := getTolerations() - if tolerations != nil { - templateValuesMap["Tolerations"] = tolerations - } - mergeValueStr(templateValuesMap, "DockerRegistry", &installAgentCmdOptions.dockerRegistry) - - mergeValueStr(templateValuesMap, "AgentToken", &installAgentCmdOptions.agentToken) - mergeValueStr(templateValuesMap, "AgentId", &installAgentCmdOptions.agentID) - mergeValueStr(templateValuesMap, "Image.Tag", &installAgentCmdOptions.venona.version) - - mergeValueMSI(templateValuesMap, "Runner.resources", &installAgentCmdOptions.resources) - - //mergeValueStrArray(&installAgentCmdOptions.envVars, "envVars", nil, "More env vars to be declared \"key=value\"") - - mergeValueBool(templateValuesMap, "InCluster", &installAgentCmdOptions.kube.inCluster) - - s := store.GetStore() - lgr := createLogger("Install-agent", verbose, logFormatter) - buildBasicStore(lgr) - - extendStoreWithAgentAPI(lgr, installAgentCmdOptions.agentToken, installAgentCmdOptions.agentID) - extendStoreWithKubeClient(lgr) - fillCodefreshAPI(lgr) - builder := plugins.NewBuilder(lgr) - if cfAPIHost == "" { - cfAPIHost = "https://g.codefresh.io" - } - builderInstallOpt := &plugins.InstallOptions{ - CodefreshHost: cfAPIHost, - } - - if installAgentCmdOptions.agentToken == "" { - installAgentCmdOptions.agentToken = cfAPIToken - } - if installAgentCmdOptions.agentToken == "" { - dieOnError(fmt.Errorf("Agent token is required in order to install agent")) - } - - if installAgentCmdOptions.agentID == "" { - dieOnError(fmt.Errorf("Agent id is required in order to install agent")) - } - - fillKubernetesAPI(lgr, installAgentCmdOptions.kube.context, installAgentCmdOptions.kube.namespace, false) - s.Runner.Resources = installAgentCmdOptions.resources - - s.KubernetesAPI.Tolerations = tolerations - - if installAgentCmdOptions.venona.version != "" { - version := installAgentCmdOptions.venona.version - lgr.Info("Version set manually", "version", version) - s.Image.Tag = version - s.Version.Current.Version = version - } - s.DockerRegistry = installAgentCmdOptions.dockerRegistry - if installAgentCmdOptions.envVars != nil { - s.AdditionalEnvVars = make(map[string]string) - for _, part := range installAgentCmdOptions.envVars { - splited := strings.Split(part, "=") - s.AdditionalEnvVars[splited[0]] = splited[1] - } - } - - s.KubernetesAPI.NodeSelector = installAgentCmdOptions.kube.nodeSelector - - builderInstallOpt.ClusterName = s.KubernetesAPI.ContextName - builderInstallOpt.KubeBuilder = getKubeClientBuilder(builderInstallOpt.ClusterName, s.KubernetesAPI.Namespace, s.KubernetesAPI.ConfigPath, - s.KubernetesAPI.InCluster, - installAgentCmdOptions.dryRun) - builderInstallOpt.ClusterNamespace = s.KubernetesAPI.Namespace - builderInstallOpt.DryRun = installAgentCmdOptions.dryRun - - builder.Add(plugins.VenonaPluginType) - - values := s.BuildValues() - values = mergeMaps(values, templateValuesMap) - - for _, p := range builder.Get() { - values, err = p.Install(cmd.Context(), builderInstallOpt, values) - if err != nil { - dieOnError(err) - } - } - lgr.Info("Agent installation completed Successfully") - }, -} - -func getTolerations() []k8sApi.Toleration { - - if installAgentCmdOptions.tolerations != "" { - var tolerationsString string - - if installAgentCmdOptions.tolerations[0] == '@' { - tolerationsString = loadTolerationsFromFile(installAgentCmdOptions.tolerations[1:]) - } else { - tolerationsString = installAgentCmdOptions.tolerations - } - - tolerations, err := parseTolerations(tolerationsString) - if err != nil { - dieOnError(err) - } - return tolerations - - } - return nil -} - -func init() { - installCommand.AddCommand(installAgentCmd) - - viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") - viper.BindEnv("kube-context", "KUBE_CONTEXT") - - viper.SetDefault("kube-namespace", "default") - - installAgentCmd.Flags().StringVar(&installAgentCmdOptions.agentToken, "agentToken", "", "Agent token created by codefresh") - installAgentCmd.Flags().StringVar(&installAgentCmdOptions.agentID, "agentId", "", "Agent id created by codefresh") - installAgentCmd.Flags().StringVar(&installAgentCmdOptions.venona.version, "venona-version", "", "Version of venona to install (default is the latest)") - installAgentCmd.Flags().StringVar(&installAgentCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona should be installed [$KUBE_NAMESPACE]") - installAgentCmd.Flags().StringVar(&installAgentCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which venona should be installed (default is current-context) [$KUBE_CONTEXT]") - installAgentCmd.Flags().StringVar(&installAgentCmdOptions.kube.nodeSelector, "kube-node-selector", "", "The kubernetes node selector \"key=value\" to be used by venona resources (default is no node selector)") - installAgentCmd.Flags().StringVar(&installAgentCmdOptions.tolerations, "tolerations", "", "The kubernetes tolerations as JSON string to be used by venona resources (default is no tolerations)") - installAgentCmd.Flags().StringArrayVar(&installAgentCmdOptions.envVars, "envVars", nil, "More env vars to be declared \"key=value\"") - installAgentCmd.Flags().StringVar(&installAgentCmdOptions.dockerRegistry, "docker-registry", "", "The prefix for the container registry that will be used for pulling the required components images. Example: --docker-registry=\"docker.io\"") - - installAgentCmd.Flags().BoolVar(&installAgentCmdOptions.kube.inCluster, "in-cluster", false, "Set flag if venona is been installed from inside a cluster") - installAgentCmd.Flags().BoolVar(&installAgentCmdOptions.dryRun, "dry-run", false, "Set to true to simulate installation") - - installAgentCmd.Flags().StringArrayVar(&installAgentCmdOptions.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") - installAgentCmd.Flags().StringArrayVar(&installAgentCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") - installAgentCmd.Flags().StringArrayVarP(&installAgentCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") - -} - -func fillCodefreshAPI(logger logger.Logger) { - s := store.GetStore() - s.CodefreshAPI = &store.CodefreshAPI{ - Host: cfAPIHost, - } - -} diff --git a/venonactl/cmd/install-app-proxy.go b/venonactl/cmd/install-app-proxy.go deleted file mode 100644 index 925fa844..00000000 --- a/venonactl/cmd/install-app-proxy.go +++ /dev/null @@ -1,119 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "fmt" - - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/codefresh-io/venona/venonactl/pkg/store" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var installAppProxyCmdOptions struct { - kube struct { - namespace string - context string - } - dockerRegistry string - templateValues []string - templateFileValues []string - templateValueFiles []string - resources map[string]interface{} - host string - ingressClass string - dryRun bool -} - -var installAppProxyCmd = &cobra.Command{ - Use: "app-proxy", - Short: "Install App proxy ", - Run: func(cmd *cobra.Command, args []string) { - - templateValuesMap, err := templateValuesToMap( - installAppProxyCmdOptions.templateValueFiles, - installAppProxyCmdOptions.templateValues, - installAppProxyCmdOptions.templateFileValues) - if err != nil { - dieOnError(err) - } - - mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) - mergeValueStr(templateValuesMap, "Namespace", &installAppProxyCmdOptions.kube.namespace) - mergeValueStr(templateValuesMap, "Context", &installAppProxyCmdOptions.kube.context) - mergeValueStr(templateValuesMap, "AppProxy.Ingress.Host", &installAppProxyCmdOptions.host) - mergeValueStr(templateValuesMap, "AppProxy.Ingress.IngressClass", &installAppProxyCmdOptions.ingressClass) - mergeValueStr(templateValuesMap, "DockerRegistry", &installAppProxyCmdOptions.dockerRegistry) - mergeValueMSI(templateValuesMap, "AppProxy.resources", &installAppProxyCmdOptions.resources) - - s := store.GetStore() - lgr := createLogger("Install-agent", verbose, logFormatter) - buildBasicStore(lgr) - builder := plugins.NewBuilder(lgr) - if installAppProxyCmdOptions.host == "" { - dieOnError(fmt.Errorf("host options is required in order to install app-proxy")) - } - if cfAPIHost == "" { - cfAPIHost = "https://g.codefresh.io" - } - builderInstallOpt := &plugins.InstallOptions{ - CodefreshHost: cfAPIHost, - DryRun: installAppProxyCmdOptions.dryRun, - } - s.AppProxy.Resources = installAppProxyCmdOptions.resources - s.DockerRegistry = installAppProxyCmdOptions.dockerRegistry - extendStoreWithKubeClient(lgr) - fillCodefreshAPI(lgr) - fillKubernetesAPI(lgr, installAppProxyCmdOptions.kube.context, installAppProxyCmdOptions.kube.namespace, false) - s.AgentAPI = &store.AgentAPI{ - Token: "", - Id: "", - } - - builderInstallOpt.ClusterName = s.KubernetesAPI.ContextName - builderInstallOpt.KubeBuilder = getKubeClientBuilder(builderInstallOpt.ClusterName, s.KubernetesAPI.Namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, builderInstallOpt.DryRun) - builderInstallOpt.ClusterNamespace = s.KubernetesAPI.Namespace - builder.Add(plugins.AppProxyPluginType) - - values := s.BuildValues() - values = mergeMaps(values, templateValuesMap) - for _, p := range builder.Get() { - values, err = p.Install(cmd.Context(), builderInstallOpt, values) - if err != nil { - dieOnError(err) - } - } - - lgr.Info("App proxy installation completed Successfully") - }, -} - -func init() { - viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") - viper.BindEnv("kube-context", "KUBE_CONTEXT") - installCommand.AddCommand(installAppProxyCmd) - installAppProxyCmd.Flags().StringVar(&installAppProxyCmdOptions.dockerRegistry, "docker-registry", "", "The prefix for the container registry that will be used for pulling the required components images. Example: --docker-registry=\"docker.io\"") - installAppProxyCmd.Flags().StringVar(&installAppProxyCmdOptions.host, "host", "", "Host name that will be used by the ingress to route traffic to the App-Proxy service") - installAppProxyCmd.Flags().StringVar(&installAppProxyCmdOptions.ingressClass, "ingress-class", "", "The ingress class name that will be used by the App-Proxy ingress. If left empty, the default one will be used") - installAppProxyCmd.Flags().StringVar(&installAppProxyCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona should be installed [$KUBE_NAMESPACE]") - installAppProxyCmd.Flags().StringVar(&installAppProxyCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which venona should be installed (default is current-context) [$KUBE_CONTEXT]") - installAppProxyCmd.Flags().StringArrayVarP(&installAppProxyCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") - installAppProxyCmd.Flags().StringArrayVar(&installAppProxyCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") - installAppProxyCmd.Flags().StringArrayVar(&installAppProxyCmdOptions.templateValues, "set-value", []string{}, "Set values for templates, example: --set-value LocalVolumesDir=/mnt/disks/ssd0/codefresh-volumes") - installAppProxyCmd.Flags().BoolVar(&installAppProxyCmdOptions.dryRun, "dry-run", false, "Set to true to simulate installation") -} diff --git a/venonactl/cmd/install-monitor.go b/venonactl/cmd/install-monitor.go deleted file mode 100644 index 72690227..00000000 --- a/venonactl/cmd/install-monitor.go +++ /dev/null @@ -1,148 +0,0 @@ -package cmd - -/* -Copyright 2020 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "fmt" - - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/codefresh-io/venona/venonactl/pkg/store" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var installMonitorAgentCmdOptions struct { - kube struct { - namespace string - context string - nodeSelector string - } - clusterId string - helm3 bool - codefreshToken string - codefreshHost string - dockerRegistry string - templateValues []string - templateFileValues []string - templateValueFiles []string - resources map[string]interface{} - dryRun bool -} - -// installK8sAgentCmd represents the install command -var installMonitorAgentCmd = &cobra.Command{ - Use: "monitor", - Short: "Install Codefresh's monitor agent on cluster", - Run: func(cmd *cobra.Command, args []string) { - // get valuesMap from --values --set-value k=v --set-file k= - templateValuesMap, err := templateValuesToMap( - installMonitorAgentCmdOptions.templateValueFiles, - installMonitorAgentCmdOptions.templateValues, - installMonitorAgentCmdOptions.templateFileValues) - if err != nil { - dieOnError(err) - } - // Merge cmd options with template - mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) - mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) - mergeValueStr(templateValuesMap, "CodefreshHost", &installMonitorAgentCmdOptions.codefreshHost) - mergeValueStr(templateValuesMap, "Token", &cfAPIToken) - mergeValueStr(templateValuesMap, "Token", &installMonitorAgentCmdOptions.codefreshToken) - mergeValueStr(templateValuesMap, "Namespace", &installMonitorAgentCmdOptions.kube.namespace) - mergeValueStr(templateValuesMap, "Context", &installMonitorAgentCmdOptions.kube.context) - - mergeValueMSI(templateValuesMap, "Monitor.resources", &installMonitorAgentCmdOptions.resources) - - mergeValueStr(templateValuesMap, "DockerRegistry", &installMonitorAgentCmdOptions.dockerRegistry) - mergeValueStr(templateValuesMap, "ClusterId", &installMonitorAgentCmdOptions.clusterId) - mergeValueBool(templateValuesMap, "helm3", &installMonitorAgentCmdOptions.helm3) - - s := store.GetStore() - - lgr := createLogger("Install-monitor-agent", verbose, logFormatter) - buildBasicStore(lgr) - extendStoreWithKubeClient(lgr) - fillKubernetesAPI(lgr, installMonitorAgentCmdOptions.kube.context, installMonitorAgentCmdOptions.kube.namespace, false) - s.Monitor.Resources = installMonitorAgentCmdOptions.resources - - builder := plugins.NewBuilder(lgr) - builder.Add(plugins.MonitorAgentPluginType) - - builderInstallOpt := &plugins.InstallOptions{ - ClusterNamespace: s.KubernetesAPI.Namespace, - DryRun: installMonitorAgentCmdOptions.dryRun, - } - - builderInstallOpt.KubeBuilder = getKubeClientBuilder(s.KubernetesAPI.ContextName, s.KubernetesAPI.Namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, installMonitorAgentCmdOptions.dryRun) - - if installMonitorAgentCmdOptions.clusterId == "" { - dieOnError(fmt.Errorf("Cluster id is required in order to install monitor")) - } - - s.ClusterId = installMonitorAgentCmdOptions.clusterId - s.Helm3 = installMonitorAgentCmdOptions.helm3 - s.DockerRegistry = installMonitorAgentCmdOptions.dockerRegistry - - if installMonitorAgentCmdOptions.codefreshHost == "" { - installMonitorAgentCmdOptions.codefreshHost = "https://g.codefresh.io" - } - - if installMonitorAgentCmdOptions.codefreshToken == "" { - dieOnError(fmt.Errorf("Codefresh token is required in order to install monitor")) - } - - s.CodefreshAPI = &store.CodefreshAPI{ - Host: installMonitorAgentCmdOptions.codefreshHost, - Token: installMonitorAgentCmdOptions.codefreshToken, - } - - // stub , not need actually for monitor - s.AgentAPI = &store.AgentAPI{ - Token: "", - Id: "", - } - - values := s.BuildValues() - values = mergeMaps(values, templateValuesMap) - - for _, p := range builder.Get() { - _, err := p.Install(cmd.Context(), builderInstallOpt, values) - dieOnError(err) - } - lgr.Info("Monitor agent installation completed Successfully") - }, -} - -func init() { - installCommand.AddCommand(installMonitorAgentCmd) - - viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") - viper.BindEnv("kube-context", "KUBE_CONTEXT") - installMonitorAgentCmd.Flags().StringVar(&installMonitorAgentCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which monitor should be installed [$KUBE_NAMESPACE]") - installMonitorAgentCmd.Flags().StringVar(&installMonitorAgentCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which monitor should be installed (default is current-context) [$KUBE_CONTEXT]") - installMonitorAgentCmd.Flags().StringVar(&installMonitorAgentCmdOptions.clusterId, "clusterId", "", "Cluster Id") - installMonitorAgentCmd.Flags().StringVar(&installMonitorAgentCmdOptions.codefreshToken, "codefreshToken", "", "Codefresh token") - installMonitorAgentCmd.Flags().StringVar(&installMonitorAgentCmdOptions.dockerRegistry, "docker-registry", "", "The prefix for the container registry that will be used for pulling the required components images. Example: --docker-registry=\"docker.io\"") - - installMonitorAgentCmd.Flags().StringVar(&installMonitorAgentCmdOptions.codefreshHost, "codefreshHost", "", "Override codefresh host if you use your own codefresh installation") - installMonitorAgentCmd.Flags().BoolVar(&installMonitorAgentCmdOptions.dryRun, "dry-run", false, "Set to true to simulate installation") - installMonitorAgentCmd.Flags().BoolVar(&installMonitorAgentCmdOptions.helm3, "helm3", false, "Set flag if cluster use helm3") - installMonitorAgentCmd.Flags().StringArrayVar(&installMonitorAgentCmdOptions.templateValues, "set-value", []string{}, "Set values for templates, example: --set-value LocalVolumesDir=/mnt/disks/ssd0/codefresh-volumes") - installMonitorAgentCmd.Flags().StringArrayVar(&installMonitorAgentCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file, example: --set-file Storage.GoogleServiceAccount=/path/to/service-account.json") - installMonitorAgentCmd.Flags().StringArrayVarP(&installMonitorAgentCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") - -} diff --git a/venonactl/cmd/install-runtime.go b/venonactl/cmd/install-runtime.go deleted file mode 100644 index 6f840074..00000000 --- a/venonactl/cmd/install-runtime.go +++ /dev/null @@ -1,197 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "fmt" - - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/codefresh-io/venona/venonactl/pkg/store" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var installRuntimeCmdOptions struct { - codefreshToken string - dryRun bool - insecure bool - kube struct { - namespace string - inCluster bool - context string - nodeSelector string - } - storageClass string - dockerRegistry string - runtimeEnvironmentName string - tolerations string - templateValues []string - templateFileValues []string - templateValueFiles []string - volumeProvisioner map[string]interface{} - localVolumeMonitor map[string]interface{} -} - -var installRuntimeCmd = &cobra.Command{ - Use: "runtime", - Short: "Install Codefresh's runtime", - Run: func(cmd *cobra.Command, args []string) { - - // get valuesMap from --values --set-value k=v --set-file k= - templateValuesMap, err := templateValuesToMap( - installRuntimeCmdOptions.templateValueFiles, - installRuntimeCmdOptions.templateValues, - installRuntimeCmdOptions.templateFileValues) - if err != nil { - dieOnError(err) - } - // Merge cmd options with template - mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) - mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) - mergeValueStr(templateValuesMap, "Token", &cfAPIToken) - mergeValueStr(templateValuesMap, "Token", &installRuntimeCmdOptions.codefreshToken) - - mergeValueStr(templateValuesMap, "Namespace", &installRuntimeCmdOptions.kube.namespace) - mergeValueStr(templateValuesMap, "Context", &installRuntimeCmdOptions.kube.context) - mergeValueStr(templateValuesMap, "RuntimeEnvironmentName", &installRuntimeCmdOptions.runtimeEnvironmentName) - mergeValueStr(templateValuesMap, "NodeSelector", &installRuntimeCmdOptions.kube.nodeSelector) - tolerations := getTolerations() - if tolerations != nil { - templateValuesMap["Tolerations"] = tolerations - } - //mergeValueStrArray(&installAgentCmdOptions.envVars, "envVars", nil, "More env vars to be declared \"key=value\"") - mergeValueStr(templateValuesMap, "DockerRegistry", &installRuntimeCmdOptions.dockerRegistry) - mergeValueStr(templateValuesMap, "StorageClass", &installRuntimeCmdOptions.storageClass) - - defaultVolumeProvResources := map[string]interface{}{ - "limits": map[string]string{ - "cpu": "1000m", - "memory": "6000Mi", - }, - "requests": map[string]string{ - "cpu": "200m", - "memory": "200Mi", - }, - } - mergeValueMSI(templateValuesMap, "Storage.VolumeProvisioner.resources", &installRuntimeCmdOptions.volumeProvisioner, defaultVolumeProvResources) - mergeValueMSI(templateValuesMap, "Storage.LocalVolumeMonitor.resources", &installRuntimeCmdOptions.localVolumeMonitor) - - mergeValueBool(templateValuesMap, "InCluster", &installRuntimeCmdOptions.kube.inCluster) - mergeValueBool(templateValuesMap, "insecure", &installRuntimeCmdOptions.insecure) - - s := store.GetStore() - lgr := createLogger("Install-runtime", verbose, logFormatter) - buildBasicStore(lgr) - extendStoreWithAgentAPI(lgr, installRuntimeCmdOptions.codefreshToken, "") - extendStoreWithKubeClient(lgr) - - if installRuntimeCmdOptions.runtimeEnvironmentName == "" { - dieOnError(fmt.Errorf("Codefresh envrionment name is required")) - } - if cfAPIHost == "" { - cfAPIHost = "https://g.codefresh.io" - } - // This is temporarily and used for signing - s.CodefreshAPI = &store.CodefreshAPI{ - Host: cfAPIHost, - } - - s.KubernetesAPI.Tolerations = tolerations - - s.KubernetesAPI.NodeSelector = installRuntimeCmdOptions.kube.nodeSelector - s.DockerRegistry = installRuntimeCmdOptions.dockerRegistry - - builder := plugins.NewBuilder(lgr) - isDefault := isUsingDefaultStorageClass(installRuntimeCmdOptions.storageClass) - - builderInstallOpt := &plugins.InstallOptions{ - StorageClass: installRuntimeCmdOptions.storageClass, - IsDefaultStorageClass: isDefault, - DryRun: installRuntimeCmdOptions.dryRun, - CodefreshHost: cfAPIHost, - CodefreshToken: installRuntimeCmdOptions.codefreshToken, - RuntimeEnvironment: installRuntimeCmdOptions.runtimeEnvironmentName, - ClusterNamespace: installRuntimeCmdOptions.kube.namespace, - Insecure: installRuntimeCmdOptions.insecure, - } - - if isDefault { - builderInstallOpt.StorageClass = plugins.DefaultStorageClassNamePrefix - } - - fillKubernetesAPI(lgr, installRuntimeCmdOptions.kube.context, installRuntimeCmdOptions.kube.namespace, installRuntimeCmdOptions.kube.inCluster) - s.VolumeProvisioner.Resources = installRuntimeCmdOptions.volumeProvisioner - s.LocalVolumeMonitor.Resources = installRuntimeCmdOptions.localVolumeMonitor - - if installRuntimeCmdOptions.dryRun { - s.DryRun = installRuntimeCmdOptions.dryRun - lgr.Info("Running in dry-run mode") - } - - // s.ClusterInCodefresh = installRuntimeCmdOptions.clusterNameInCodefresh - - builder.Add(plugins.RuntimeEnvironmentPluginType) - builder.Add(plugins.EnginePluginType) - - if isDefault { - builder.Add(plugins.VolumeProvisionerPluginType) - } else { - lgr.Info("Custom StorageClass is set, skipping installation of default volume provisioner") - } - - builderInstallOpt.KubeBuilder = getKubeClientBuilder(s.KubernetesAPI.ContextName, s.KubernetesAPI.Namespace, s.KubernetesAPI.ConfigPath, - s.KubernetesAPI.InCluster, - installRuntimeCmdOptions.dryRun) - values := s.BuildValues() - values = mergeMaps(values, templateValuesMap) - - for _, p := range builder.Get() { - values, err = p.Install(cmd.Context(), builderInstallOpt, values) - if err != nil { - dieOnError(err) - } - } - lgr.Info("Runtime installation completed Successfully") - - }, -} - -func init() { - installCommand.AddCommand(installRuntimeCmd) - - viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") - viper.BindEnv("kube-context", "KUBE_CONTEXT") - - viper.SetDefault("kube-namespace", "default") - - installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.codefreshToken, "codefreshToken", "", "Codefresh token") - installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.runtimeEnvironmentName, "runtimeName", viper.GetString("runtimeName"), "Name of the runtime as in codefresh") - installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona should be installed [$KUBE_NAMESPACE]") - installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which venona should be installed (default is current-context) [$KUBE_CONTEXT]") - installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.storageClass, "storage-class", "", "Set a name of your custom storage class, note: this will not install volume provisioning components") - installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.dockerRegistry, "docker-registry", "", "The prefix for the container registry that will be used for pulling the required components images. Example: --docker-registry=\"docker.io\"") - - installRuntimeCmd.Flags().BoolVar(&installRuntimeCmdOptions.insecure, "insecure", false, "Set to true to disable TLS when communicating with the codefresh platform") - installRuntimeCmd.Flags().BoolVar(&installRuntimeCmdOptions.kube.inCluster, "in-cluster", false, "Set flag if venona is been installed from inside a cluster") - installRuntimeCmd.Flags().BoolVar(&installRuntimeCmdOptions.dryRun, "dry-run", false, "Set to true to simulate installation") - installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.kube.nodeSelector, "kube-node-selector", "", "The kubernetes node selector \"key=value\" to be used by venona resources (default is no node selector)") - installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.tolerations, "tolerations", "", "The kubernetes tolerations as JSON string to be used by venona resources (default is no tolerations)") - - installRuntimeCmd.Flags().StringArrayVar(&installRuntimeCmdOptions.templateValues, "set-value", []string{}, "Set values for templates, example: --set-value LocalVolumesDir=/mnt/disks/ssd0/codefresh-volumes") - installRuntimeCmd.Flags().StringArrayVar(&installRuntimeCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file, example: --set-file Storage.GoogleServiceAccount=/path/to/service-account.json") - installRuntimeCmd.Flags().StringArrayVarP(&installRuntimeCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") -} diff --git a/venonactl/cmd/install-venona.go b/venonactl/cmd/install-venona.go deleted file mode 100644 index 5bfe08e2..00000000 --- a/venonactl/cmd/install-venona.go +++ /dev/null @@ -1,58 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "github.com/spf13/cobra" -) - -const ( - clusterNameMaxLength = 20 - namespaceMaxLength = 20 -) - -var installCmdOptions struct { - dryRun bool - clusterNameInCodefresh string - kube struct { - namespace string - inCluster bool - context string - nodeSelector string - } - storageClass string - venona struct { - version string - } - setDefaultRuntime bool - installOnlyRuntimeEnvironment bool - skipRuntimeInstallation bool - runtimeEnvironmentName string - buildNodeSelector string - buildAnnotations []string - tolerationJSONString string -} - -// installVenonaCmd represents the install command -var installVenonaCmd = &cobra.Command{ - Use: "all", - Short: "Install Codefresh's resource on cluster", -} - -func init() { - installCommand.AddCommand(installVenonaCmd) -} diff --git a/venonactl/cmd/install.go b/venonactl/cmd/install.go deleted file mode 100644 index f1d681f3..00000000 --- a/venonactl/cmd/install.go +++ /dev/null @@ -1,29 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "github.com/spf13/cobra" -) - -var installCommand = &cobra.Command{ - Use: "install", - Short: "Install agent and runtime components", -} - -func init() { - rootCmd.AddCommand(installCommand) -} diff --git a/venonactl/cmd/migrate.go b/venonactl/cmd/migrate.go deleted file mode 100644 index 47358f7b..00000000 --- a/venonactl/cmd/migrate.go +++ /dev/null @@ -1,70 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/codefresh-io/venona/venonactl/pkg/store" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var migrateCmdOpt struct { - kube struct { - context string - namespace string - } -} - -var migrateCmd = &cobra.Command{ - Use: "migrate", - Short: "Migrate existing runtime-environment from 0.X to 1.X version", - Run: func(cmd *cobra.Command, args []string) { - lgr := createLogger("Migrate", verbose, logFormatter) - builder := plugins.NewBuilder(lgr) - builder.Add(plugins.VenonaPluginType) - builder.Add(plugins.RuntimeEnvironmentPluginType) - builder.Add(plugins.VolumeProvisionerPluginType) - s := store.GetStore() - buildBasicStore(lgr) - extendStoreWithKubeClient(lgr) - extendStoreWithCodefershClient(lgr) - extendStoreWithAgentAPI(lgr, "", "") - fillKubernetesAPI(lgr, migrateCmdOpt.kube.context, migrateCmdOpt.kube.namespace, false) - values := s.BuildValues() - values["AppName"] = "venona" // use old app name for migration - spn := createSpinner("Migrating runtime (might take a few seconds)", "") - spn.Start() - defer spn.Stop() - for _, p := range builder.Get() { - err := p.Migrate(cmd.Context(), &plugins.MigrateOptions{ - ClusterNamespace: migrateCmdOpt.kube.namespace, - ClusterName: migrateCmdOpt.kube.context, - KubeBuilder: getKubeClientBuilder(migrateCmdOpt.kube.context, migrateCmdOpt.kube.namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, false), - }, values) - if err != nil { - dieOnError(err) - } - } - }, -} - -func init() { - rootCmd.AddCommand(migrateCmd) - migrateCmd.Flags().StringVar(&migrateCmdOpt.kube.context, "kube-context-name", "", "Set name to overwrite the context name saved in Codefresh") - migrateCmd.Flags().StringVar(&migrateCmdOpt.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona is installed [$KUBE_NAMESPACE]") -} diff --git a/venonactl/cmd/root.go b/venonactl/cmd/root.go deleted file mode 100644 index a813a797..00000000 --- a/venonactl/cmd/root.go +++ /dev/null @@ -1,56 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "context" - - "github.com/spf13/viper" - - "github.com/spf13/cobra" -) - -var rootCmd = &cobra.Command{ - Use: "venona", - Short: "A command line application for Codefresh", -} - -// Execute - execute the root command -func Execute(ctx context.Context) { - err := rootCmd.ExecuteContext(ctx) - dieOnError(err) -} - -func init() { - viper.AutomaticEnv() - viper.BindEnv("kubeconfig", "KUBECONFIG") - viper.BindEnv("cfconfig", "CFCONFIG") - - viper.BindEnv("apihost", "CODEFRESH_API_HOST") - viper.BindEnv("apitoken", "CODEFRESH_API_TOKEN") - - rootCmd.PersistentFlags().StringVar(&configPath, "cfconfig", viper.GetString("cfconfig"), "Config file (default is $HOME/.cfconfig) [$CFCONFIG]") - rootCmd.PersistentFlags().StringVar(&cfAPIHost, "api-host", viper.GetString("apihost"), "Host of codefresh [$CODEFRESH_API_HOST]") - rootCmd.PersistentFlags().StringVar(&cfAPIToken, "api-token", viper.GetString("apitoken"), "Codefresh API token [$CODEFRESH_API_TOKEN]") - rootCmd.PersistentFlags().StringVar(&cfContext, "context", "", "Name of the context from --cfconfig (default is current-context)") - - rootCmd.PersistentFlags().StringVar(&kubeConfigPath, "kube-config-path", viper.GetString("kubeconfig"), "Path to kubeconfig file (default is $HOME/.kube/config) [$KUBECONFIG]") - - rootCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "Print logs") - rootCmd.PersistentFlags().StringVar(&logFormatter, "log-formtter", "Plain", "Print logs in custom format") - -} diff --git a/venonactl/cmd/status.go b/venonactl/cmd/status.go deleted file mode 100644 index 0e260a10..00000000 --- a/venonactl/cmd/status.go +++ /dev/null @@ -1,132 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "context" - "fmt" - - "github.com/codefresh-io/go-sdk/pkg/codefresh" - "github.com/codefresh-io/venona/venonactl/pkg/logger" - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/codefresh-io/venona/venonactl/pkg/store" - humanize "github.com/dustin/go-humanize" - - "github.com/spf13/cobra" -) - -var statusCmdOpt struct { - kube struct { - context string - } - dryRun bool -} - -// statusCmd represents the status command -var statusCmd = &cobra.Command{ - Use: "status [name]", - Short: "Get status of Codefresh's runtime-environment", - Long: "Pass the name of the runtime environment to see more details information about the underlying resources", - Run: func(cmd *cobra.Command, args []string) { - lgr := createLogger("Status", verbose, logFormatter) - - buildBasicStore(lgr) - extendStoreWithCodefershClient(lgr) - extendStoreWithKubeClient(lgr) - s := store.GetStore() - table := createTable() - // When requested status for specific runtime - if len(args) > 0 { - name := args[0] - re, err := s.CodefreshAPI.Client.RuntimeEnvironments().Get(name) - dieOnError(err) - if re == nil { - dieOnError(fmt.Errorf("Runtime-Environment %s not found", name)) - } - if re.Metadata.Agent == true { - table.SetHeader([]string{"Runtime Name", "Last Message", "Reported"}) - message := "Not reported any message yet" - time := "" - if re.Status.Message != "" { - message = re.Status.Message - time = humanize.Time(re.Status.UpdatedAt) - } - table.Append([]string{re.Metadata.Name, message, time}) - table.Render() - fmt.Println() - printTableWithKubernetesRelatedResources(cmd.Context(), re, statusCmdOpt.kube.context, lgr) - } else { - lgr.Debug("Runtime-Environment has not Venona's agent", "Name", name) - } - return - } - - // When requested status for all runtimes - res, err := s.CodefreshAPI.Client.RuntimeEnvironments().List() - dieOnError(err) - table.SetHeader([]string{"Runtime Name", "Last Message", "Reported"}) - for _, re := range res { - if re.Metadata.Agent == true { - message := "Not reported any message yet" - time := "" - if re.Status.Message != "" { - message = re.Status.Message - time = humanize.Time(re.Status.UpdatedAt) - } - table.Append([]string{re.Metadata.Name, message, time}) - } - } - table.Render() - - return - - }, -} - -func printTableWithKubernetesRelatedResources(ctx context.Context, re *codefresh.RuntimeEnvironment, context string, logger logger.Logger) { - builder := plugins.NewBuilder(logger) - - table := createTable() - table.SetHeader([]string{"Kind", "Name", "Status"}) - s := store.GetStore() - if re.RuntimeScheduler.Cluster.Namespace != "" { - if context == "" { - context = re.RuntimeScheduler.Cluster.ClusterProvider.Selector - } - s.KubernetesAPI.ContextName = context - s.KubernetesAPI.Namespace = re.RuntimeScheduler.Cluster.Namespace - builder. - Add(plugins.RuntimeEnvironmentPluginType). - Add(plugins.VenonaPluginType). - Add(plugins.VolumeProvisionerPluginType) - statusOpt := &plugins.StatusOptions{ - KubeBuilder: getKubeClientBuilder(context, re.RuntimeScheduler.Cluster.Namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, false), - ClusterNamespace: s.KubernetesAPI.Namespace, - } - for _, p := range builder.Get() { - rows, err := p.Status(ctx, statusOpt, s.BuildValues()) - dieOnError(err) - table.AppendBulk(rows) - } - } - table.Render() -} - -func init() { - rootCmd.AddCommand(statusCmd) - statusCmd.Flags().StringVar(&statusCmdOpt.kube.context, "kube-context-name", "", "Set name to overwrite the context name saved in Codefresh") -} diff --git a/venonactl/cmd/test.go b/venonactl/cmd/test.go deleted file mode 100644 index 5d87d5c2..00000000 --- a/venonactl/cmd/test.go +++ /dev/null @@ -1,145 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/codefresh-io/venona/venonactl/pkg/store" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var allTestPluginTypes = []string{ - plugins.RuntimeEnvironmentPluginType, - plugins.VenonaPluginType, - plugins.MonitorAgentPluginType, - plugins.VolumeProvisionerPluginType, - plugins.EnginePluginType, - plugins.RuntimeAttachType, - plugins.NetworkTesterPluginType, -} - -var testCommandOptions struct { - kube struct { - host string - namespace string - context string - inCluster bool - } - insecure bool - plugin []string - templateValues []string - templateFileValues []string - templateValueFiles []string -} - -var testCommand = &cobra.Command{ - Use: "test", - Short: "Run test on the target cluster prior installation", - Run: func(cmd *cobra.Command, args []string) { - // get valuesMap from --values --set-value k=v --set-file k= - templateValuesMap, err := templateValuesToMap( - testCommandOptions.templateValueFiles, - testCommandOptions.templateValues, - testCommandOptions.templateFileValues) - if err != nil { - dieOnError(err) - } - // Merge cmd options with template - mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) - mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) - mergeValueStr(templateValuesMap, "Token", &cfAPIToken) - mergeValueStr(templateValuesMap, "Namespace", &testCommandOptions.kube.namespace) - mergeValueStr(templateValuesMap, "Context", &testCommandOptions.kube.context) - mergeValueStr(templateValuesMap, "KubernetesHost", &testCommandOptions.kube.host) - mergeValueBool(templateValuesMap, "InCluster", &testCommandOptions.kube.inCluster) - mergeValueBool(templateValuesMap, "insecure", &testCommandOptions.insecure) - - lgr := createLogger("test", verbose, logFormatter) - s := store.GetStore() - buildBasicStore(lgr) - extendStoreWithKubeClient(lgr) - fillKubernetesAPI(lgr, testCommandOptions.kube.context, testCommandOptions.kube.namespace, testCommandOptions.kube.inCluster) - fillCodefreshAPI(lgr) - extendStoreWithAgentAPI(lgr, "", "") - setVerbosity(verbose) - setInsecure(testCommandOptions.insecure) - - builder := plugins.NewBuilder(lgr) - for _, p := range testCommandOptions.plugin { - if p == plugins.RuntimeEnvironmentPluginType { - builder.Add(plugins.RuntimeEnvironmentPluginType) - } - if p == plugins.VenonaPluginType { - builder.Add(plugins.VenonaPluginType) - } - if p == plugins.MonitorAgentPluginType { - builder.Add(plugins.MonitorAgentPluginType) - } - if p == plugins.VolumeProvisionerPluginType { - builder.Add(plugins.VolumeProvisionerPluginType) - } - if p == plugins.EnginePluginType { - builder.Add(plugins.EnginePluginType) - } - if p == plugins.RuntimeAttachType { - builder.Add(plugins.RuntimeAttachType) - } - if p == plugins.NetworkTesterPluginType { - builder.Add(plugins.NetworkTesterPluginType) - } - } - - options := &plugins.TestOptions{ - KubeBuilder: getKubeClientBuilder(s.KubernetesAPI.ContextName, s.KubernetesAPI.Namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, false), - ClusterNamespace: s.KubernetesAPI.Namespace, - } - - values := s.BuildValues() - values = mergeMaps(values, templateValuesMap) - - var finalerr error - lgr.Info("Testing requirements") - - for _, p := range builder.Get() { - err := p.Test(cmd.Context(), options, values) - if err != nil && finalerr == nil { - finalerr = err - } - } - dieOnError(finalerr) - - lgr.Info("Cluster passed acceptance test") - }, -} - -func init() { - viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") - viper.BindEnv("kube-context", "KUBE_CONTEXT") - - testCommand.Flags().StringVar(&testCommandOptions.kube.host, "kube-host", viper.GetString("kube-host"), "overrides the address of the api-server the runner will use") - testCommand.Flags().StringVar(&testCommandOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which monitor should be installed [$KUBE_NAMESPACE]") - testCommand.Flags().StringVar(&testCommandOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which monitor should be installed (default is current-context) [$KUBE_CONTEXT]") - testCommand.Flags().BoolVar(&testCommandOptions.insecure, "insecure", false, "Set to true to disable certificate validation when using TLS connections") - testCommand.Flags().BoolVar(&testCommandOptions.kube.inCluster, "in-cluster", false, "Set flag if the command is running inside a cluster") - testCommand.Flags().StringArrayVar(&testCommandOptions.plugin, "installer", allTestPluginTypes, "Which test to run, based on the installer type") - - testCommand.Flags().StringArrayVar(&testCommandOptions.templateValues, "set-value", []string{}, "Set values for templates, example: --set-value LocalVolumesDir=/mnt/disks/ssd0/codefresh-volumes") - testCommand.Flags().StringArrayVar(&testCommandOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file, example: --set-file Storage.GoogleServiceAccount=/path/to/service-account.json") - testCommand.Flags().StringArrayVarP(&testCommandOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") - - rootCmd.AddCommand(testCommand) -} diff --git a/venonactl/cmd/uninstall-agent.go b/venonactl/cmd/uninstall-agent.go deleted file mode 100644 index 6e290d3c..00000000 --- a/venonactl/cmd/uninstall-agent.go +++ /dev/null @@ -1,91 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/codefresh-io/venona/venonactl/pkg/store" - - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var uninstallAgentCmdOptions struct { - kube struct { - context string - namespace string - kubePath string - } - templateValues []string - templateFileValues []string - templateValueFiles []string -} - -var uninstallAgentCmd = &cobra.Command{ - Use: "agent", - Short: "Uninstall Codefresh's agent", - Run: func(cmd *cobra.Command, args []string) { - - // get valuesMap from --values --set-value k=v --set-file k= - templateValuesMap, err := templateValuesToMap( - uninstallAgentCmdOptions.templateValueFiles, - uninstallAgentCmdOptions.templateValues, - uninstallAgentCmdOptions.templateFileValues) - if err != nil { - dieOnError(err) - } - // Merge cmd options with template - mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) - mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) - mergeValueStr(templateValuesMap, "Token", &cfAPIToken) - mergeValueStr(templateValuesMap, "Namespace", &uninstallAgentCmdOptions.kube.namespace) - mergeValueStr(templateValuesMap, "Context", &uninstallAgentCmdOptions.kube.context) - - s := store.GetStore() - lgr := createLogger("UninstallAgent", verbose, logFormatter) - buildBasicStore(lgr) - extendStoreWithKubeClient(lgr) - - s.CodefreshAPI = &store.CodefreshAPI{} - s.AgentAPI = &store.AgentAPI{} - - builder := plugins.NewBuilder(lgr) - if uninstallAgentCmdOptions.kube.context == "" { - dieOnError(fmt.Errorf("Context name is required in order to uninstall agent")) - } - if uninstallAgentCmdOptions.kube.namespace == "" { - dieOnError(fmt.Errorf("Namespace name is required to in order to uninstall agent")) - } - - deleteOptions := &plugins.DeleteOptions{} - s.KubernetesAPI.ContextName = uninstallAgentCmdOptions.kube.context - s.KubernetesAPI.Namespace = uninstallAgentCmdOptions.kube.namespace - - builder.Add(plugins.VenonaPluginType) - deleteOptions.KubeBuilder = getKubeClientBuilder(s.KubernetesAPI.ContextName, s.KubernetesAPI.Namespace, s.KubernetesAPI.ConfigPath, false, false) - deleteOptions.ClusterNamespace = uninstallAgentCmdOptions.kube.namespace - - values := s.BuildValues() - values = mergeMaps(values, templateValuesMap) - for _, p := range builder.Get() { - err := p.Delete(cmd.Context(), deleteOptions, values) - if err != nil { - dieOnError(err) - } - } - - lgr.Info("Deletion of agent is completed") - }, -} - -func init() { - uninstallCommand.AddCommand(uninstallAgentCmd) - viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") - viper.BindEnv("kube-context", "KUBE_CONTEXT") - uninstallAgentCmd.Flags().StringVar(&uninstallAgentCmdOptions.kube.context, "kube-context-name", "", "Name of the kubernetes context on which venona should be uninstalled (default is current-context) [$KUBE_CONTEXT]") - uninstallAgentCmd.Flags().StringVar(&uninstallAgentCmdOptions.kube.namespace, "kube-namespace", "", "Name of the namespace on which venona should be uninstalled [$KUBE_NAMESPACE]") - uninstallAgentCmd.Flags().StringArrayVar(&uninstallAgentCmdOptions.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") - uninstallAgentCmd.Flags().StringArrayVar(&uninstallAgentCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") - uninstallAgentCmd.Flags().StringArrayVarP(&uninstallAgentCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") - -} diff --git a/venonactl/cmd/uninstall-app-proxy.go b/venonactl/cmd/uninstall-app-proxy.go deleted file mode 100644 index 0535eecf..00000000 --- a/venonactl/cmd/uninstall-app-proxy.go +++ /dev/null @@ -1,92 +0,0 @@ -package cmd - -import ( - "github.com/codefresh-io/venona/venonactl/pkg/store" - - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var uninstallAppProxyCmdOptions struct { - kube struct { - context string - namespace string - } - templateValues []string - templateFileValues []string - templateValueFiles []string -} - -var uninstallAppProxytCmd = &cobra.Command{ - Use: "app-proxy", - Short: "Uninstall Codefresh's App-Proxy component", - Run: func(cmd *cobra.Command, args []string) { - - // get valuesMap from --values --set-value k=v --set-file k= - templateValuesMap, err := templateValuesToMap( - uninstallAppProxyCmdOptions.templateValueFiles, - uninstallAppProxyCmdOptions.templateValues, - uninstallAppProxyCmdOptions.templateFileValues) - if err != nil { - dieOnError(err) - } - // Merge cmd options with template - mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) - mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) - mergeValueStr(templateValuesMap, "Namespace", &uninstallAppProxyCmdOptions.kube.namespace) - mergeValueStr(templateValuesMap, "Context", &uninstallAppProxyCmdOptions.kube.context) - - s := store.GetStore() - lgr := createLogger("UninstallAppProxy", verbose, logFormatter) - buildBasicStore(lgr) - extendStoreWithKubeClient(lgr) - fillKubernetesAPI(lgr, uninstallAppProxyCmdOptions.kube.context, uninstallAppProxyCmdOptions.kube.namespace, false) - - builder := plugins.NewBuilder(lgr) - - if cfAPIHost == "" { - cfAPIHost = "https://g.codefresh.io" - } - s.CodefreshAPI = &store.CodefreshAPI{ - Host: cfAPIHost, - } - s.AgentAPI = &store.AgentAPI{ - Token: "", - Id: "", - } - - deleteOptions := &plugins.DeleteOptions{} - deleteOptions.KubeBuilder = getKubeClientBuilder( - uninstallAppProxyCmdOptions.kube.context, - uninstallAppProxyCmdOptions.kube.namespace, - kubeConfigPath, - false, - false) - - builder.Add(plugins.AppProxyPluginType) - deleteOptions.ClusterNamespace = uninstallAppProxyCmdOptions.kube.namespace - values := s.BuildValues() - values = mergeMaps(values, templateValuesMap) - for _, p := range builder.Get() { - err := p.Delete(cmd.Context(), deleteOptions, values) - if err != nil { - dieOnError(err) - } - } - - lgr.Info("Deletion of app-proxy is completed") - }, -} - -func init() { - uninstallCommand.AddCommand(uninstallAppProxytCmd) - viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") - viper.BindEnv("kube-context", "KUBE_CONTEXT") - uninstallAppProxytCmd.Flags().StringVar(&uninstallAppProxyCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace from which the app-proxy should be uninstalled [$KUBE_NAMESPACE]") - uninstallAppProxytCmd.Flags().StringVar(&uninstallAppProxyCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context from which the app-proxy should be uninstalled (default is current-context) [$KUBE_CONTEXT]") - uninstallAppProxytCmd.Flags().StringArrayVar(&uninstallAppProxyCmdOptions.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") - uninstallAppProxytCmd.Flags().StringArrayVar(&uninstallAppProxyCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") - uninstallAppProxytCmd.Flags().StringArrayVarP(&uninstallAppProxyCmdOptions.templateValueFiles, "values", "f", []string{}, "Specify values in a YAML file") - -} diff --git a/venonactl/cmd/uninstall-monitor.go b/venonactl/cmd/uninstall-monitor.go deleted file mode 100644 index bd8f4b40..00000000 --- a/venonactl/cmd/uninstall-monitor.go +++ /dev/null @@ -1,103 +0,0 @@ -package cmd - -import ( - "github.com/codefresh-io/venona/venonactl/pkg/store" - - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var uninstallMonitorAgentCmdOptions struct { - kube struct { - context string - namespace string - kubePath string - } - templateValues []string - templateFileValues []string - templateValueFiles []string -} - -var uninstallMonitorAgentCmd = &cobra.Command{ - Use: "monitor", - Short: "Uninstall Codefresh's monitor", - Run: func(cmd *cobra.Command, args []string) { - - // get valuesMap from --values --set-value k=v --set-file k= - templateValuesMap, err := templateValuesToMap( - uninstallMonitorAgentCmdOptions.templateValueFiles, - uninstallMonitorAgentCmdOptions.templateValues, - uninstallMonitorAgentCmdOptions.templateFileValues) - if err != nil { - dieOnError(err) - } - // Merge cmd options with template - mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) - mergeValueStr(templateValuesMap, "ConfigPath", &uninstallMonitorAgentCmdOptions.kube.kubePath) - mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) - mergeValueStr(templateValuesMap, "Token", &cfAPIToken) - mergeValueStr(templateValuesMap, "Namespace", &uninstallMonitorAgentCmdOptions.kube.namespace) - mergeValueStr(templateValuesMap, "Context", &uninstallMonitorAgentCmdOptions.kube.context) - - s := store.GetStore() - lgr := createLogger("UninstallMonitor", verbose, logFormatter) - buildBasicStore(lgr) - extendStoreWithKubeClient(lgr) - fillKubernetesAPI(lgr, uninstallMonitorAgentCmdOptions.kube.context, uninstallMonitorAgentCmdOptions.kube.namespace, false) - - builder := plugins.NewBuilder(lgr) - - if uninstallMonitorAgentCmdOptions.kube.kubePath == "" { - uninstallMonitorAgentCmdOptions.kube.kubePath = kubeConfigPath - } - - if cfAPIHost == "" { - cfAPIHost = "https://g.codefresh.io" - } - // This is temporarily and used for signing - s.CodefreshAPI = &store.CodefreshAPI{ - Host: cfAPIHost, - } - - // stub , not need actually for monitor - s.AgentAPI = &store.AgentAPI{ - Token: "", - Id: "", - } - - deleteOptions := &plugins.DeleteOptions{} - // runtime - deleteOptions.KubeBuilder = getKubeClientBuilder(uninstallMonitorAgentCmdOptions.kube.context, - s.KubernetesAPI.Namespace, - uninstallMonitorAgentCmdOptions.kube.kubePath, - false, - false) - - builder.Add(plugins.MonitorAgentPluginType) - deleteOptions.ClusterNamespace = s.KubernetesAPI.Namespace - values := s.BuildValues() - values = mergeMaps(values, templateValuesMap) - for _, p := range builder.Get() { - err := p.Delete(cmd.Context(), deleteOptions, values) - if err != nil { - dieOnError(err) - } - } - - lgr.Info("Deletion of monitor is completed") - }, -} - -func init() { - uninstallCommand.AddCommand(uninstallMonitorAgentCmd) - viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") - viper.BindEnv("kube-context", "KUBE_CONTEXT") - uninstallMonitorAgentCmd.Flags().StringVar(&uninstallMonitorAgentCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which monitor should be uninstalled [$KUBE_NAMESPACE]") - uninstallMonitorAgentCmd.Flags().StringVar(&uninstallMonitorAgentCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which monitor should be uninstalled (default is current-context) [$KUBE_CONTEXT]") - uninstallMonitorAgentCmd.Flags().StringVar(&uninstallMonitorAgentCmdOptions.kube.kubePath, "kube-config-path", viper.GetString("kubeconfig"), "Path to kubeconfig file (default is $HOME/.kube/config) [$KUBECONFIG]") - uninstallMonitorAgentCmd.Flags().StringArrayVar(&uninstallMonitorAgentCmdOptions.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") - uninstallMonitorAgentCmd.Flags().StringArrayVar(&uninstallMonitorAgentCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") - uninstallMonitorAgentCmd.Flags().StringArrayVarP(&uninstallMonitorAgentCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") - -} diff --git a/venonactl/cmd/uninstall-runtime.go b/venonactl/cmd/uninstall-runtime.go deleted file mode 100644 index e1debd40..00000000 --- a/venonactl/cmd/uninstall-runtime.go +++ /dev/null @@ -1,145 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/codefresh-io/venona/venonactl/pkg/store" - - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var uninstallRunimeCmdOptions struct { - kube struct { - context string - namespace string - kubePath string - } - kubeVenona struct { - namespace string - kubePath string - context string - } - runtimeEnvironmentName string - storageClassName string - restartAgent bool - templateValues []string - templateFileValues []string - templateValueFiles []string -} - -var uninstallRuntimeCmd = &cobra.Command{ - Use: "runtime", - Short: "Uninstall Codefresh's runtime", - Run: func(cmd *cobra.Command, args []string) { - // get valuesMap from --values --set-value k=v --set-file k= - templateValuesMap, err := templateValuesToMap( - uninstallRunimeCmdOptions.templateValueFiles, - uninstallRunimeCmdOptions.templateValues, - uninstallRunimeCmdOptions.templateFileValues) - if err != nil { - dieOnError(err) - } - // Merge cmd options with template - mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) - mergeValueStr(templateValuesMap, "ConfigPath", &uninstallRunimeCmdOptions.kube.kubePath) - mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) - mergeValueStr(templateValuesMap, "Token", &cfAPIToken) - - mergeValueStr(templateValuesMap, "Namespace", &uninstallRunimeCmdOptions.kube.namespace) - mergeValueStr(templateValuesMap, "Context", &uninstallRunimeCmdOptions.kube.context) - mergeValueStr(templateValuesMap, "RuntimeEnvironmentName", &uninstallRunimeCmdOptions.runtimeEnvironmentName) - mergeValueStr(templateValuesMap, "StorageClass", &uninstallRunimeCmdOptions.storageClassName) - - s := store.GetStore() - lgr := createLogger("UninstallRuntime", verbose, logFormatter) - buildBasicStore(lgr) - extendStoreWithKubeClient(lgr) - - s.CodefreshAPI = &store.CodefreshAPI{} - s.AgentAPI = &store.AgentAPI{} - - builder := plugins.NewBuilder(lgr) - if uninstallRunimeCmdOptions.kube.context == "" { - dieOnError(fmt.Errorf("Context name is required in order to uninstall runtime")) - } - if uninstallRunimeCmdOptions.kube.namespace == "" { - dieOnError(fmt.Errorf("Namespace name is required to in order to uninstall runtime")) - } - s.KubernetesAPI.ContextName = uninstallRunimeCmdOptions.kube.context - s.KubernetesAPI.Namespace = uninstallRunimeCmdOptions.kube.namespace - - if uninstallRunimeCmdOptions.kubeVenona.kubePath == "" { - uninstallRunimeCmdOptions.kubeVenona.kubePath = kubeConfigPath - } - if uninstallRunimeCmdOptions.kubeVenona.namespace == "" { - uninstallRunimeCmdOptions.kubeVenona.namespace = uninstallRunimeCmdOptions.kube.namespace - } - if uninstallRunimeCmdOptions.kubeVenona.context == "" { - uninstallRunimeCmdOptions.kubeVenona.context = uninstallRunimeCmdOptions.kube.context - } - - if uninstallRunimeCmdOptions.kube.kubePath == "" { - uninstallRunimeCmdOptions.kube.kubePath = kubeConfigPath - } - - deleteOptions := &plugins.DeleteOptions{} - // runtime - deleteOptions.KubeBuilder = getKubeClientBuilder(uninstallRunimeCmdOptions.kube.context, - uninstallRunimeCmdOptions.kube.namespace, - uninstallRunimeCmdOptions.kube.kubePath, - false, - false) - - // agent - deleteOptions.AgentKubeBuilder = getKubeClientBuilder(uninstallRunimeCmdOptions.kubeVenona.context, - uninstallRunimeCmdOptions.kubeVenona.namespace, - uninstallRunimeCmdOptions.kubeVenona.kubePath, - false, - false) - - builder.Add(plugins.RuntimeEnvironmentPluginType) - if isUsingDefaultStorageClass(uninstallRunimeCmdOptions.storageClassName) { - builder.Add(plugins.VolumeProvisionerPluginType) - } - builder.Add(plugins.RuntimeAttachType) - builder.Add(plugins.EnginePluginType) - deleteOptions.ClusterNamespace = uninstallRunimeCmdOptions.kube.namespace - deleteOptions.AgentNamespace = uninstallRunimeCmdOptions.kubeVenona.namespace - deleteOptions.RuntimeEnvironment = uninstallRunimeCmdOptions.runtimeEnvironmentName - values := s.BuildValues() - values = mergeMaps(values, templateValuesMap) - for _, p := range builder.Get() { - err := p.Delete(cmd.Context(), deleteOptions, values) - if err != nil { - dieOnError(err) - } - } - - lgr.Info("Deletion of runtime is completed") - }, -} - -func init() { - uninstallCommand.AddCommand(uninstallRuntimeCmd) - viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") - viper.BindEnv("kube-context", "KUBE_CONTEXT") - uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona should be installed [$KUBE_NAMESPACE]") - uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which venona should be installed (default is current-context) [$KUBE_CONTEXT]") - uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.kube.kubePath, "kube-config-path", viper.GetString("kubeconfig"), "Path to kubeconfig file (default is $HOME/.kube/config) [$KUBECONFIG]") - - uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.runtimeEnvironmentName, "runtime-name", viper.GetString("runtime-name"), "Name of the runtime as in codefresh") - - uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.kubeVenona.namespace, "kube-namespace-agent", viper.GetString("kube-namespace-agent"), "Name of the namespace where venona is installed [$KUBE_NAMESPACE]") - uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.kubeVenona.context, "kube-context-name-agent", viper.GetString("kube-context-agent"), "Name of the kubernetes context on which venona is installed (default is current-context) [$KUBE_CONTEXT]") - uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.kubeVenona.kubePath, "kube-config-path-agent", viper.GetString("kubeconfig-agent"), "Path to kubeconfig file (default is $HOME/.kube/config) for agent [$KUBECONFIG]") - uninstallRuntimeCmd.Flags().BoolVar(&uninstallRunimeCmdOptions.restartAgent, "restart-agent", viper.GetBool("restart-agent"), "Restart agent after attach operation") - - uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.storageClassName, "storage-class-name", viper.GetString("storage-class-name"), "Storage class name of the runtime to be uninstalled") - - uninstallRuntimeCmd.Flags().StringArrayVar(&uninstallRunimeCmdOptions.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") - uninstallRuntimeCmd.Flags().StringArrayVar(&uninstallRunimeCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") - uninstallRuntimeCmd.Flags().StringArrayVarP(&uninstallRunimeCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") - -} diff --git a/venonactl/cmd/uninstall.go b/venonactl/cmd/uninstall.go deleted file mode 100644 index eeaedf7a..00000000 --- a/venonactl/cmd/uninstall.go +++ /dev/null @@ -1,29 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "github.com/spf13/cobra" -) - -var uninstallCommand = &cobra.Command{ - Use: "uninstall", - Short: "Uninstall agent and runtime components", -} - -func init() { - rootCmd.AddCommand(uninstallCommand) -} diff --git a/venonactl/cmd/upgrade-app-proxy.go b/venonactl/cmd/upgrade-app-proxy.go deleted file mode 100644 index 14322140..00000000 --- a/venonactl/cmd/upgrade-app-proxy.go +++ /dev/null @@ -1,90 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/codefresh-io/venona/venonactl/pkg/store" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var upgradeAppProxyCmdOptions struct { - kube struct { - context string - namespace string - } - templateValues []string - templateFileValues []string - templateValueFiles []string -} - -var upgradeAppProxyCmd = &cobra.Command{ - Use: "app-proxy", - Short: "Upgrade App proxy", - Run: func(cmd *cobra.Command, args []string) { - - templateValuesMap, err := templateValuesToMap( - upgradeAppProxyCmdOptions.templateValueFiles, - upgradeAppProxyCmdOptions.templateValues, - upgradeAppProxyCmdOptions.templateFileValues) - if err != nil { - dieOnError(err) - } - - mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) - mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) - mergeValueStr(templateValuesMap, "Namespace", &upgradeAppProxyCmdOptions.kube.namespace) - mergeValueStr(templateValuesMap, "Context", &upgradeAppProxyCmdOptions.kube.context) - - lgr := createLogger("Upgrade-AppProxy", verbose, logFormatter) - builder := plugins.NewBuilder(lgr) - - builder.Add(plugins.AppProxyPluginType) - - s := store.GetStore() - buildBasicStore(lgr) - extendStoreWithKubeClient(lgr) - dieOnError(extendStoreWithCodefershClient(lgr)) - extendStoreWithAgentAPI(lgr, "", "") - fillKubernetesAPI(lgr, upgradeAppProxyCmdOptions.kube.context, upgradeAppProxyCmdOptions.kube.namespace, false) - values := s.BuildValues() - values = mergeMaps(values, templateValuesMap) - - for _, p := range builder.Get() { - values, err = p.Upgrade(cmd.Context(), &plugins.UpgradeOptions{ - Name: store.AppProxyApplicationName, - ClusterNamespace: upgradeAppProxyCmdOptions.kube.namespace, - ClusterName: upgradeAppProxyCmdOptions.kube.namespace, - KubeBuilder: getKubeClientBuilder(upgradeAppProxyCmdOptions.kube.context, upgradeAppProxyCmdOptions.kube.namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, false), - }, values) - if err != nil { - dieOnError(err) - } - } - }, -} - -func init() { - viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") - viper.BindEnv("kube-context", "KUBE_CONTEXT") - upgradeCmd.AddCommand(upgradeAppProxyCmd) - upgradeAppProxyCmd.Flags().StringVar(&upgradeAppProxyCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona should be installed [$KUBE_NAMESPACE]") - upgradeAppProxyCmd.Flags().StringVar(&upgradeAppProxyCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which venona should be installed (default is current-context) [$KUBE_CONTEXT]") - upgradeAppProxyCmd.Flags().StringArrayVarP(&upgradeAppProxyCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") - upgradeAppProxyCmd.Flags().StringArrayVar(&upgradeAppProxyCmdOptions.templateValues, "set-value", []string{}, "Set values for templates, example: --set-value LocalVolumesDir=/mnt/disks/ssd0/codefresh-volumes") -} diff --git a/venonactl/cmd/upgrade.go b/venonactl/cmd/upgrade.go deleted file mode 100644 index c8c74db1..00000000 --- a/venonactl/cmd/upgrade.go +++ /dev/null @@ -1,95 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "github.com/codefresh-io/venona/venonactl/pkg/plugins" - "github.com/codefresh-io/venona/venonactl/pkg/store" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var upgradeCmdOpt struct { - kube struct { - context string - namespace string - } - templateValues []string - templateFileValues []string - templateValueFiles []string -} - -// upgradeCmd represents the upgrade command -var upgradeCmd = &cobra.Command{ - Use: "upgrade", - Short: "Upgrade existing 1.X runner", - Run: func(cmd *cobra.Command, args []string) { - // get valuesMap from --values --set-value k=v --set-file k= - templateValuesMap, err := templateValuesToMap( - uninstallAgentCmdOptions.templateValueFiles, - uninstallAgentCmdOptions.templateValues, - uninstallAgentCmdOptions.templateFileValues) - if err != nil { - dieOnError(err) - } - // Merge cmd options with template - mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) - mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) - mergeValueStr(templateValuesMap, "Token", &cfAPIToken) - mergeValueStr(templateValuesMap, "Namespace", &uninstallAgentCmdOptions.kube.namespace) - mergeValueStr(templateValuesMap, "Context", &uninstallAgentCmdOptions.kube.context) - - lgr := createLogger("Upgrade", verbose, logFormatter) - builder := plugins.NewBuilder(lgr) - builder.Add(plugins.VenonaPluginType) - - s := store.GetStore() - buildBasicStore(lgr) - extendStoreWithKubeClient(lgr) - dieOnError(extendStoreWithCodefershClient(lgr)) - extendStoreWithAgentAPI(lgr, "", "") - fillKubernetesAPI(lgr, upgradeCmdOpt.kube.context, upgradeCmdOpt.kube.namespace, false) - values := s.BuildValues() - values = mergeMaps(values, templateValuesMap) - - spn := createSpinner("Upgarding runtime (might take a few seconds)", "") - spn.Start() - defer spn.Stop() - - for _, p := range builder.Get() { - values, err = p.Upgrade(cmd.Context(), &plugins.UpgradeOptions{ - Name: s.AppName, - ClusterNamespace: upgradeCmdOpt.kube.namespace, - ClusterName: upgradeCmdOpt.kube.namespace, - KubeBuilder: getKubeClientBuilder(upgradeCmdOpt.kube.context, upgradeCmdOpt.kube.namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, false), - }, values) - if err != nil { - dieOnError(err) - } - } - }, -} - -func init() { - rootCmd.AddCommand(upgradeCmd) - upgradeCmd.Flags().StringVar(&upgradeCmdOpt.kube.context, "kube-context-name", "", "Set name to overwrite the context name saved in Codefresh") - upgradeCmd.Flags().StringVar(&upgradeCmdOpt.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona is installed [$KUBE_NAMESPACE]") - - upgradeCmd.Flags().StringArrayVar(&upgradeCmdOpt.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") - upgradeCmd.Flags().StringArrayVar(&upgradeCmdOpt.templateFileValues, "set-file", []string{}, "Set values for templates from file") - upgradeCmd.Flags().StringArrayVarP(&upgradeCmdOpt.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") -} diff --git a/venonactl/cmd/version.go b/venonactl/cmd/version.go deleted file mode 100644 index 3fa56510..00000000 --- a/venonactl/cmd/version.go +++ /dev/null @@ -1,43 +0,0 @@ -package cmd - -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "fmt" - - "github.com/codefresh-io/venona/venonactl/pkg/store" - "github.com/spf13/cobra" -) - -// versionCmd represents the version command -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print Venona version", - Run: func(cmd *cobra.Command, args []string) { - s := store.GetStore() - lgr := createLogger("Version", verbose, logFormatter) - buildBasicStore(lgr) - fmt.Printf("Date: %s\n", s.Version.Current.Date) - fmt.Printf("Commit: %s\n", s.Version.Current.Commit) - fmt.Printf("Local Version: %s\n", s.Version.Current.Version) - }, -} - -func init() { - rootCmd.AddCommand(versionCmd) - -} diff --git a/venonactl/example/values-example.yaml b/venonactl/example/values-example.yaml deleted file mode 100644 index 6010bce7..00000000 --- a/venonactl/example/values-example.yaml +++ /dev/null @@ -1,308 +0,0 @@ -### DEPRECATED! ### -### Use Helm chart to install Codefresh Runner! ### - -########################################################################################################################### -### This is a sample values yamls for usage with: ### -### venonactl install agent|runtime|monitor|app-proxy --values|-f values.yaml ### -### ### -### the values from values.yaml are applied to the templates in [pkg/templates/kubernetes](pkg/templates/kubernetes) ### -### See BuildValues() func in [store.go](pkg/store/store.go) for the format ### -########################################################################################################################### - -############################################## -### ### -### Codefresh Authentication ### -### ### -############################################## -### Codefresh host --api-host and token --api-token -# CodefreshHost: https://g.codefresh.io # for on-prem installations -# Token: XXXXXXXXXXXXXXXXX.YYYYYYYYYYYYYYY # generate a token here: https://g.codefresh.io/user/settings - -### insecure: skips certificates validation on TLS connections -### use this if you're getting TLS certificate validation -### errors during the installation -# insecure: true - -############################################## -### ### -### Kubernetes Context ### -### ### -############################################## -### ConfigPath: --kube-config-path $KUBECONFIG: kubeconfig path -# ConfigPath: # default is $(HOME)/.kube/config - -### Context: --context $KUBE_CONTEXT: which kubernetes context to use -# Context: some-context - -### Namespace --kube-namespace $KUBE_NAMESPACE: namespace for the runner, runtime, monitor, app-proxy -# Namespace: r1 - - -############################################## -### ### -### General Options ### -### ### -############################################## -### RuntimeEnvironmentName --runtimeName: used when installing a new runtime -### will be used to uniquely identify the runtime in Codefresh -# RuntimeEnvironmentName: my-unique-runtime-name - -### RuntimeServiceAccount --kube-service-account: used when attaching a runtime to a runner -### default is: runner -# RuntimeServiceAccount: runner - -### KubernetesHost: --kube-host: used when attaching a runtime to a runner to override the -### apiserver address that the runner will use to create resources on the runtime, -### by default we use the host from your kubeconfig. -# KubernetesHost: https://kubernetes.default.svc.cluster.local - -### SkipClusterTest: only set to true if you want to skip the acceptance tests during the installation -# SkipClusterTest: true - -### SkipClusterTest: if set to true, cluster integration will not be created in Codefresh -# SkipClusterIntegration: false - -### ClusterId --clusterId: used when installing the monitor component -### this is the name of the cluster integration in codefresh -# ClusterId: cluster-name - -### EnvVars: global environment variables that will be set on every component, -### including runtime components such as engine and dind. -### Use this if you need to set http_proxy variables -# EnvVars: -# HTTP_PROXY: http://123.123.123.123:8080 -# HTTPS_PROXY: http://123.123.123.123:8080 -# NO_PROXY: localhost - -### DockerRegistry --docker-registry: The docker registry from which all components images will be pulled [default: docker.io]. -### We will check connectivity from inside the cluster to this domain. -# DockerRegistry: docker.io - -### NewRelicLicense: If a license key is provided we will use newrelic monitoring in the venona agent -### and app-proxy components -# NewRelicLicense: XXXX - -# GitProviderURL: api.github.com # (optional) We will check connectivity to this URL when we run our acceptance tests. - - -############################################### -### Codefresh Runner ### -### ### -### Pulls and executes tasks from codefresh ### -############################################### -### Runner image: controls the runner pod image -# Image: -# Name: codefresh/venona -# Tag: 1.4.16 # default s.Version.Current.Version, - -### Control runner pod resources -# Runner: -# resources: -# limits: -# cpu: 400m -# memory: 1200Mi -# requests: -# cpu: 200m -# memory: 500Mi - -### AdditionalEnvVars --envVars: adds environment variables to the runner deployment -# AdditionalEnvVars: -# HTTP_PROXY: 10.20.0.35:8080 -# HTTPS_PROXY: 10.20.0.35:8080 -# NO_PROXY: 10.20.0.* - -### NodeSelector --kube-node-selector: controls runner and dind-volume-provisioner pods -# NodeSelector: app_type=codefresh,cloud.google.com/gke-nodepool=default-pool - -### Tolerations --tolerations: controls runner, dind-volume-provisioner and dind-lv-monitor -# Tolerations: -# - key: codefresh.io -# operator: Equal -# value: dinds -# effect: NoSchedule - -### Agent options: generally you should only use them if you deleted your runner by mistake -# AgentToken --agentToken: used by the runner pod to authenticate to codefresh -# AgentId --agentId: used by codefresh to identify the runner - - -############################################### -### Storage ### -### ### -### codefresh pipelines volume provisioning ### -################################################ -### StorageClass --storage-class: Use already existing storage class -### Note: when using this option volume provisioning components will -### not be installed. -# StorageClass: # storage class name - -### Storage parameters for dind-volume-provisoner and dind-lv-monitor -# Storage: -# Annotations: # will be set on the storage class -# foo: bar -# Backend: local -# StorageClassName: # default is: dind-local-volumes-runner- -# LocalVolumeParentDir: /var/lib/codefresh/dind-volumes -# AvailabilityZone: -# GoogleServiceAccount: -# AwsAccessKeyId: -# AwsSecretAccessKey: -# Encrypted: # encrypt volume, default is false -# VolumeProvisioner: -# Image: codefresh/dind-volume-provisioner:1.31.7 -# NodeSelector: -# Tolerations: -# resources: -# limits: -# cpu: 400m -# memory: 1200Mi -# requests: -# cpu: 200m -# memory: 500Mi -# ServiceAccount: -# Annotations: # will be set on VolumeProvisioner and LocalVolumeMonitor service account -# foo: bar -# LocalVolumeMonitor: -# resources: -# limits: -# cpu: 400m -# memory: 1200Mi -# requests: -# cpu: 200m -# memory: 500Mi - - -####################################### -### Storage configuration examples: ### -####################################### - -### Storage parameters example for Azure Disks -# Storage: -# Backend: azuredisk -# VolumeProvisioner: -# MountAzureJson: true - -### Storage parameters example for gke-local-ssd -# Storage: -# Backend: local -# LocalVolumeParentDir: /mnt/disks/ssd0/codefresh-volumes -# NodeSelector: cloud.google.com/gke-local-ssd=true - -### Storage parameter example for gke disks -# Storage: -# Backend: gcedisk -# AvailabilityZone: us-central1-a -# GoogleServiceAccount: > -# {serviceAccount.json context} -# NodeSelector: failure-domain.beta.kubernetes.io/zone=us-central1-a - -### Storage parameter example for aws ebs disks -# Storage: -# Backend: ebs -# AvailabilityZone: us-east-1d -# AwsAccessKeyId: ABCDF -# AwsSecretAccessKey: ZYXWV -# Encrypted: # encrypt volume, default is false -# VolumeProvisioner: -# NodeSelector: kubernetes.io/role=master -# NodeSelector: failure-domain.beta.kubernetes.io/zone=us-east-1d - - -################################################ -### Monitor ### -### ### -### reports cluster information to codefresh ### -################################################ -# Monitor: -# Image: -# Name: codefresh/agent -# Tag: stable -# resources: -# limits: -# cpu: 400m -# memory: 1200Mi -# requests: -# cpu: 200m -# memory: 500Mi -# AdditionalEnvVars: # will be set on monitor deployment -# SOME_VAR: SOME_VALUE -# Helm3: false # is the cluster using helm3 -# ServiceAccount: -# Annotations: -# foo: bar - - -######################################################## -### App-Proxy ### -### ### -### communicates with "behind-firewall" integrations ### -######################################################## -# AppProxy: -# Image: -# Name: codefresh/cf-app-proxy -# Tag: latest # default is latest -# resources: -# limits: -# cpu: 500m -# memory: 1200Mi -# requests: -# cpu: 200m -# memory: 500Mi -# AdditionalEnvVars: # will be set on app-proxy deployment -# SOME_VAR: SOME_VALUE -# Ingress: -# Host: example.com # The DNS hostname the ingress will use -# IngressClass: nginx # If you have multiple ingress-controllers in the cluster - specify the right ingress class -# TLSSecret: cert-secret-name # Use this to configure the TLS certs for the ingress -# PathPrefix: /app-proxy # default is '/'. Use this if you share the hostname with other services -# Annotations: # Extra annotations that will be set on the ingress object -# nginx.ingress.kubernetes.io/whitelist-source-range: 123.123.123.123/130 -# ServiceAccount: -# Annotations: -# foo: bar - - -######################################################## -### Codefresh Runtime ### -### ### -### configure engine and dind pods ### -######################################################## -# Runtime: -# NodeSelector: # dind and engine pods node-selector (--build-node-selector) -# foo: bar -# tolerations: # dind and engine pods tolerations -# - key: arch -# operator: Equal -# value: aarch64 -# effect: NoSchedule -# ServiceAccount: # will be used by the engine and dind pods -# Annotations: -# foo: bar -# AdditionalEnvVars: # will be set on engine and dind pods -# SOME_VAR: SOME_VALUE -# resources: # dind pod resources -# limits: -# cpu: 500m -# memory: 1200Mi -# requests: -# cpu: 200m -# memory: 500Mi -# userVolumeMounts: # will be set for dind pod and will be injcted for each container - https://codefresh.io/docs/docs/administration/codefresh-runner/#custom-volume-mounts -# my-test: -# name: test -# mountPath: /etc/ssl/cert -# readOnly: true -# userVolumes: # will be set for dind pod and will be injcted for each container - https://codefresh.io/docs/docs/administration/codefresh-runner/#custom-volume-mounts -# test: -# name: test -# secret: -# secretName: test-secret - - -######################################################## -### Logging ### -### ### -### configure build logging solution ### -######################################################## -# Logging: -# FirebaseHost: firebase.io # (optional) We will check connectivity to this URL when we run our acceptance tests. diff --git a/venonactl/go.mod b/venonactl/go.mod deleted file mode 100644 index 8b7a700d..00000000 --- a/venonactl/go.mod +++ /dev/null @@ -1,134 +0,0 @@ -module github.com/codefresh-io/venona/venonactl - -go 1.21 - -require ( - github.com/Masterminds/semver v1.5.0 - github.com/Masterminds/sprig v2.22.0+incompatible - github.com/briandowns/spinner v1.23.0 - github.com/codefresh-io/go-sdk v0.52.0 - github.com/dustin/go-humanize v1.0.1 - github.com/inconshreveable/log15 v2.16.0+incompatible - github.com/olekukonko/tablewriter v0.0.5 - github.com/spf13/cobra v1.8.0 - github.com/spf13/viper v1.15.0 - github.com/stretchr/objx v0.5.0 - gopkg.in/yaml.v2 v2.4.0 - helm.sh/helm/v3 v3.14.4 - k8s.io/api v0.29.0 - k8s.io/apimachinery v0.29.0 - k8s.io/client-go v0.29.0 -) - -require ( - github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect - github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect - github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect - github.com/Microsoft/hcsshim v0.11.4 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/containerd/containerd v1.7.12 // indirect - github.com/containerd/log v0.1.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/cli v24.0.6+incompatible // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v24.0.9+incompatible // indirect - github.com/docker/docker-credential-helpers v0.7.0 // indirect - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-metrics v0.0.1 // indirect - github.com/docker/go-units v0.5.0 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch v5.7.0+incompatible // indirect - github.com/fatih/color v1.14.1 // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-errors/errors v1.4.2 // indirect - github.com/go-logr/logr v1.3.0 // 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/go-stack/stack v1.8.1 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/btree v1.1.2 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-querystring v1.1.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/gorilla/mux v1.8.0 // indirect - github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect - github.com/huandu/xstrings v1.4.0 // indirect - github.com/imdario/mergo v0.3.13 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.0 // indirect - github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect - github.com/magiconair/properties v1.8.7 // indirect - github.com/mailru/easyjson v0.7.7 // 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.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/moby/locker v1.0.1 // indirect - github.com/moby/term v0.5.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect - github.com/morikuni/aec v1.0.0 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc5 // indirect - github.com/pelletier/go-toml/v2 v2.0.7 // indirect - github.com/peterbourgon/diskv v2.0.1+incompatible // indirect - github.com/pkg/errors v0.9.1 // 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/rivo/uniseg v0.4.4 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/afero v1.9.5 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/subosito/gotenv v1.4.2 // indirect - github.com/xlab/treeprint v1.2.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect - go.opentelemetry.io/otel v1.19.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.19.0 // indirect - go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect - golang.org/x/crypto v0.29.0 // indirect - golang.org/x/net v0.31.0 // indirect - golang.org/x/oauth2 v0.10.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/term v0.26.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/time v0.3.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/grpc v1.58.3 // indirect - google.golang.org/protobuf v1.33.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/cli-runtime v0.29.0 // indirect - k8s.io/klog/v2 v2.110.1 // indirect - k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect - oras.land/oras-go v1.2.4 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect - sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect -) diff --git a/venonactl/go.sum b/venonactl/go.sum deleted file mode 100644 index cca3869f..00000000 --- a/venonactl/go.sum +++ /dev/null @@ -1,859 +0,0 @@ -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/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -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/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= -github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -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/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A= -github.com/briandowns/spinner v1.23.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE= -github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= -github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/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/codefresh-io/go-sdk v0.52.0 h1:s+O87OebisNiDOEsh3qSAB8gDJ+Sc6WmBOh8AaFlm/o= -github.com/codefresh-io/go-sdk v0.52.0/go.mod h1:CcoVmTFWHGkbrSW8LyOGB/vJe5Vzr3iC/pNE2QIBTyg= -github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= -github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0= -github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk= -github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= -github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= -github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= -github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -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/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= -github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI= -github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= -github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= -github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= -github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= -github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= -github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= -github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= -github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= -github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= -github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= -github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -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-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-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -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.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= -github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -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/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -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/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/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/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -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/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/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= -github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -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.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/inconshreveable/log15 v2.16.0+incompatible h1:6nvMKxtGcpgm7q0KiGs+Vc+xDvUXaBqsPKHWKsinccw= -github.com/inconshreveable/log15 v2.16.0+incompatible/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -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.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/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/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= -github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/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.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/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -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.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.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -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/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg= -github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.0.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/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= -github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= -github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= -github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -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/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= -github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= -github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= -github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= -github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= -github.com/pkg/errors v0.8.0/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 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.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -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-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.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -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.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.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -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/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -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/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= -github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -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 v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -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.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= -github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= -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.3.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 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.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= -github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= -github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/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/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= -github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= -github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= -github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= -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/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= -go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-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-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/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.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -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-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-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-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.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= -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.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/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-20190801041406-cbf593c0f2f3/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-20210616094352-59db8d763f22/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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.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-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= -golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= -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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -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= -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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-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/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -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.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.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -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.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -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/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.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= -gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= -helm.sh/helm/v3 v3.14.4 h1:6FSpEfqyDalHq3kUr4gOMThhgY55kXUEjdQoyODYnrM= -helm.sh/helm/v3 v3.14.4/go.mod h1:Tje7LL4gprZpuBNTbG34d1Xn5NmRT3OWfBRwpOSer9I= -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.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= -k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= -k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= -k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= -k8s.io/cli-runtime v0.29.0 h1:q2kC3cex4rOBLfPOnMSzV2BIrrQlx97gxHJs21KxKS4= -k8s.io/cli-runtime v0.29.0/go.mod h1:VKudXp3X7wR45L+nER85YUzOQIru28HQpXr0mTdeCrk= -k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= -k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= -k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= -k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= -oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= -sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/venonactl/hack/build-linux.sh b/venonactl/hack/build-linux.sh deleted file mode 100755 index b745a7c4..00000000 --- a/venonactl/hack/build-linux.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -set -e -DIR=$(realpath $(dirname $0)/..) -OUTFILE=${DIR}/venonactl-linux -go generate ${DIR}/hack/generate.go -go fmt ${DIR}/pkg/obj/kubeobj/kubeobj.go -go fmt ${DIR}/pkg/templates/kubernetes/templates.go - -CGO_ENABLED=0 GOOS=linux go build -gcflags=all="-N -l" -ldflags '-X github.com/codefresh-io/venona/venonactl/cmd.localDevFlow=true' -o $OUTFILE ${DIR} - -chmod +x $OUTFILE diff --git a/venonactl/hack/build.sh b/venonactl/hack/build.sh deleted file mode 100755 index 8d044bfb..00000000 --- a/venonactl/hack/build.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -set -e -OUTFILE=/usr/local/bin/venonactl -go generate ${PWD}/hack/generate.go -go fmt ${PWD}/pkg/obj/kubeobj/kubeobj.go -go fmt ${PWD}/pkg/templates/kubernetes/templates.go -VERSION="$(cat VERSION)-$(git rev-parse --short HEAD)" -echo "Setting up version $VERSION" -CGO_ENABLED=0 go build -ldflags "-X github.com/codefresh-io/venona/venonactl/cmd.version=$VERSION" -v -o $OUTFILE main.go - -chmod +x $OUTFILE diff --git a/venonactl/hack/fmt.sh b/venonactl/hack/fmt.sh deleted file mode 100755 index fe4c3c6e..00000000 --- a/venonactl/hack/fmt.sh +++ /dev/null @@ -1,3 +0,0 @@ -echo "formating .go files" -gofmt -l -s -w . -echo "done!" \ No newline at end of file diff --git a/venonactl/hack/generate.go b/venonactl/hack/generate.go deleted file mode 100644 index 36d13f9e..00000000 --- a/venonactl/hack/generate.go +++ /dev/null @@ -1,7 +0,0 @@ -package hack - -/* -We are using generated template.go for serialized kubernetes assets -*/ -//go:generate go run github.com/codefresh-io/venona/venonactl/pkg/templates kubernetes -//go:generate go run github.com/codefresh-io/venona/venonactl/pkg/obj kubernetes diff --git a/venonactl/main.go b/venonactl/main.go deleted file mode 100644 index 5f516d74..00000000 --- a/venonactl/main.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build !windows - -package main - -import ( - "context" - "fmt" - "os" - "os/signal" - "syscall" - - "github.com/codefresh-io/venona/venonactl/cmd" -) - -const ( - waitForSignalEnv = "WAIT_FOR_DEBUGGER" - debuggerPort = "4321" -) - -func main() { - sigs := make(chan os.Signal, 1) - goOn := make(chan bool, 1) - ctx, cancel := context.WithCancel(context.Background()) - signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT, syscall.SIGUSR1) - - go func() { - for sig := range sigs { - if sig == syscall.SIGUSR1 { - goOn <- true - } else if sig == syscall.SIGTERM || sig == syscall.SIGINT { - fmt.Printf("signal received, aborting: %s", sig) - cancel() - } - } - }() - - if os.Getenv(waitForSignalEnv) != "" { - // Waiting for debugger attach in case if waitForSignalEnv!="" - // For debuging venonactl spawned by `codefresh runner ...` - fmt.Printf("%s env is set, waiting SIGUSR1.\nYou can run remote debug in vscode and attach dlv debugger:\n\n", waitForSignalEnv) - - pid := os.Getpid() - fmt.Printf("dlv attach --continue --accept-multiclient --headless --listen=:%s %d\n", debuggerPort, pid) - fmt.Printf("kill -SIGUSR1 %d\n", pid) - - select { - case <-goOn: - case <-ctx.Done(): - os.Exit(1) // abort - } - fmt.Printf("Continue ...") - } - - cmd.Execute(ctx) -} diff --git a/venonactl/main_windows.go b/venonactl/main_windows.go deleted file mode 100644 index c38b449a..00000000 --- a/venonactl/main_windows.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "fmt" - "os" - "os/signal" - "syscall" - - "github.com/codefresh-io/venona/venonactl/cmd" -) - -func main() { - sigs := make(chan os.Signal, 1) - ctx, cancel := context.WithCancel(context.Background()) - signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT) - - go func() { - for sig := range sigs { - if sig == syscall.SIGTERM || sig == syscall.SIGINT { - fmt.Printf("signal received, aborting: %s", sig) - cancel() - } - } - }() - - cmd.Execute(ctx) -} diff --git a/venonactl/pkg/certs/server_cert.go b/venonactl/pkg/certs/server_cert.go deleted file mode 100644 index bfc5b78a..00000000 --- a/venonactl/pkg/certs/server_cert.go +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package certs - -import ( - "bytes" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" -) - -const ( - defaultCertCN = "docker.codefresh.io" -) - -// ServerCert contains Server Cert pair -type ServerCert struct { - Key string - Csr string - Cert string - Ca string -} - -// NewServerCert - generates ServerCert with csr -func NewServerCert() (*ServerCert, error) { - - serverCert := &ServerCert{} - err := serverCert.GenerateCsr() - return serverCert, err -} - -// GenerateCsr - generates csr -func (u *ServerCert) GenerateCsr() error { - - certCN := defaultCertCN - privateKey, _ := rsa.GenerateKey(rand.Reader, 2048) - subj := pkix.Name{ - CommonName: certCN, - } - - template := x509.CertificateRequest{ - Subject: subj, - SignatureAlgorithm: x509.SHA256WithRSA, - } - - csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &template, privateKey) - if err != nil { - return err - } - - // Encoding Csr - csrBuf := bytes.NewBufferString("") - pem.Encode(csrBuf, &pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrBytes}) - u.Csr = csrBuf.String() - - // Encoding Key - keyBuf := bytes.NewBufferString("") - keyBlock := &pem.Block{ - Type: "PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(privateKey), - } - - pem.Encode(keyBuf, keyBlock) - u.Key = keyBuf.String() - return nil -} diff --git a/venonactl/pkg/codefresh/cfapi.go b/venonactl/pkg/codefresh/cfapi.go deleted file mode 100644 index b4c9b8e7..00000000 --- a/venonactl/pkg/codefresh/cfapi.go +++ /dev/null @@ -1,210 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package codefresh - -import ( - "bytes" - "crypto/tls" - "fmt" - "net/http" - - "archive/zip" - - "github.com/codefresh-io/go-sdk/pkg/codefresh" - "github.com/codefresh-io/venona/venonactl/pkg/certs" -) - -type ( - API interface { - RuntimeEnvironmentRegistrator - } - - APIOptions struct { - Logger logger - CodefreshHost string - CodefreshToken string - ClusterName string - ClusterNamespace string - RegisterWithAgent bool - MarkAsDefault bool - Insecure bool - StorageClass string - IsDefaultStorageClass bool - BuildNodeSelector map[string]string - Annotations map[string]string - } - - RuntimeEnvironmentRegistrator interface { - Validate() error - Sign() (*certs.ServerCert, error) - Register() (*codefresh.RuntimeEnvironment, error) - } - - api struct { - logger logger - codefresh codefresh.Codefresh - clustername string - clusternamespace string - registerWithAgent bool - markAsDefault bool - storageClass string - isDefaultStorageClass bool - buildNodeSelector map[string]string - annotations map[string]string - } - - logger interface { - Debug(message string, args ...interface{}) - } -) - -// NewCodefreshAPI - creates new codefresh api -func NewCodefreshAPI(opt *APIOptions) API { - httpClient := &http.Client{} - if opt.Insecure { - customTransport := &(*http.DefaultTransport.(*http.Transport)) // make shallow copy - // #nosec - customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - - httpClient = &http.Client{ - Transport: customTransport, - } - } - - return &api{ - logger: opt.Logger, - codefresh: codefresh.New(&codefresh.ClientOptions{ - Auth: codefresh.AuthOptions{ - Token: opt.CodefreshToken, - }, - Host: opt.CodefreshHost, - Client: httpClient, - }), - clustername: opt.ClusterName, - clusternamespace: opt.ClusterNamespace, - registerWithAgent: opt.RegisterWithAgent, - storageClass: opt.StorageClass, - isDefaultStorageClass: opt.IsDefaultStorageClass, - buildNodeSelector: opt.BuildNodeSelector, - annotations: opt.Annotations, - } -} - -func (a *api) Validate() error { - a.logger.Debug("Validating runtime-environment") - opt := codefresh.ValidateRuntimeOptions{ - Cluster: a.clustername, - Namespace: a.clusternamespace, - } - return a.codefresh.RuntimeEnvironments().Validate(&opt) -} - -func (a *api) Sign() (*certs.ServerCert, error) { - a.logger.Debug("Signing runtime-environment") - serverCert, err := certs.NewServerCert() - if err != nil { - return nil, err - } - certExtraSANs := fmt.Sprintf("IP:127.0.0.1,DNS:dind,DNS:*.dind.%s,DNS:*.dind.%s.svc,DNS:*.cf-cd.com,DNS:*.codefresh.io", a.clusternamespace, a.clusternamespace) - a.logger.Debug(fmt.Sprintf("certExtraSANs = %s", certExtraSANs)) - - byteArray, err := a.codefresh.RuntimeEnvironments().SignCertificate(&codefresh.SignCertificatesOptions{ - AltName: certExtraSANs, - CSR: serverCert.Csr, - }) - if err != nil { - a.logger.Debug("Failed to sign certificate") - return nil, err - } - - a.logger.Debug("Certificate was signed") - respBodyReaderAt := bytes.NewReader(byteArray) - zipReader, err := zip.NewReader(respBodyReaderAt, int64(len(byteArray))) - if err != nil { - a.logger.Debug("Failed to create zip reader from given certificate " + fmt.Sprintf("%s", byteArray)) - return nil, err - } - for _, zf := range zipReader.File { - a.logger.Debug("Reading file ", "name", zf.Name) - buf := new(bytes.Buffer) - src, _ := zf.Open() - defer src.Close() - buf.ReadFrom(src) - - if zf.Name == "cf-ca.pem" { - serverCert.Ca = buf.String() - } else if zf.Name == "cf-server-cert.pem" { - serverCert.Cert = buf.String() - } else { - a.logger.Debug(fmt.Sprintf("Warning: Unknown filename in sign responce %s", zf.Name)) - } - } - - // Validating serverCert - var missingCerts string - if serverCert.Csr == "" { - missingCerts += " csr" - } - if serverCert.Cert == "" { - missingCerts += " cert" - } - if serverCert.Key == "" { - missingCerts += " key" - } - if serverCert.Ca == "" { - missingCerts += " ca" - } - if missingCerts != "" { - return nil, fmt.Errorf("Failed to to generate and sign certificates: %s is missing", missingCerts) - } - - // update store with certs - return serverCert, nil -} - -func (a *api) Register() (*codefresh.RuntimeEnvironment, error) { - a.logger.Debug("Registering runtime-environment") - options := &codefresh.CreateRuntimeOptions{ - Namespace: a.clusternamespace, - HasAgent: a.registerWithAgent, - Cluster: a.clustername, - } - if len(a.buildNodeSelector) != 0 { - options.NodeSelector = a.buildNodeSelector - } - - options.StorageClass = a.storageClass - - if len(a.annotations) != 0 { - options.Annotations = a.annotations - } - - re, err := a.codefresh.RuntimeEnvironments().Create(options) - if err != nil { - return nil, err - } - - if a.markAsDefault { - a.logger.Debug("Setting runtime as deault") - _, err := a.codefresh.RuntimeEnvironments().Default(re.Metadata.Name) - if err != nil { - return nil, err - } - } - - return re, nil -} diff --git a/venonactl/pkg/kube/kube.go b/venonactl/pkg/kube/kube.go deleted file mode 100644 index bc643233..00000000 --- a/venonactl/pkg/kube/kube.go +++ /dev/null @@ -1,109 +0,0 @@ -package kube - -import ( - "context" - "errors" - "strings" - - v1Core "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" -) - -type ( - Kube interface { - BuildClient() (*kubernetes.Clientset, error) - BuildConfig() (*rest.Config, error) - EnsureNamespaceExists(ctx context.Context, cs *kubernetes.Clientset) error - } - - kube struct { - contextName string - namespace string - pathToKubeConfig string - inCluster bool - dryRun bool - } - - Options struct { - ContextName string - Namespace string - PathToKubeConfig string - InCluster bool - DryRun bool - } -) - -func New(o *Options) Kube { - return &kube{ - contextName: o.ContextName, - namespace: o.Namespace, - pathToKubeConfig: o.PathToKubeConfig, - inCluster: o.InCluster, - dryRun: o.DryRun, - } -} - -func (k *kube) BuildClient() (*kubernetes.Clientset, error) { - var config *rest.Config - var err error - if k.inCluster { - config, err = rest.InClusterConfig() - } else { - config, err = k.BuildConfig() - if err != nil { // if cannot create from kubeConfigPath, try in-cluster config - config, err = rest.InClusterConfig() - } - } - if err != nil { - return nil, err - } - cs, err := kubernetes.NewForConfig(config) - if err != nil { - if strings.Contains(err.Error(), "exec plugin: invalid apiVersion") { - return nil, errors.New("Kubeconfig user entry is using an invalid API version client.authentication.k8s.io/v1alpha1.\nSee details at https://support.codefresh.io/hc/en-us/articles/6947789386652-Failure-to-perform-actions-on-your-selected-Kubernetes-context") - } - - return nil, err - } - - return cs, nil -} - -func (k *kube) EnsureNamespaceExists(ctx context.Context, cs *kubernetes.Clientset) error { - if k.dryRun { - return nil - } - _, err := cs.CoreV1().Namespaces().Get(ctx, k.namespace, v1.GetOptions{}) - if err != nil { - nsSpec := &v1Core.Namespace{ObjectMeta: metav1.ObjectMeta{Name: k.namespace}} - _, err := cs.CoreV1().Namespaces().Create(ctx, nsSpec, v1.CreateOptions{}) - if err != nil { - return err - } - } - return nil -} - -func (k *kube) BuildConfig() (*rest.Config, error) { - config := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( - &clientcmd.ClientConfigLoadingRules{ExplicitPath: k.pathToKubeConfig}, - &clientcmd.ConfigOverrides{ - CurrentContext: k.contextName, - Context: clientcmdapi.Context{ - Namespace: k.namespace, - }, - }) - cc, err := config.ClientConfig() - - if err != nil { // if cannot create from kubeConfigPath, try in-cluster config - return rest.InClusterConfig() - } - - return cc, nil - -} diff --git a/venonactl/pkg/logger/custom-logger.go b/venonactl/pkg/logger/custom-logger.go deleted file mode 100644 index 5ada8f98..00000000 --- a/venonactl/pkg/logger/custom-logger.go +++ /dev/null @@ -1,28 +0,0 @@ -package logger - -import ( - "bytes" - "fmt" - "os" - - log "github.com/inconshreveable/log15" -) - -const ( - Plain = "plain" -) - -func PlainTextFormatter() log.Format { - return log.FormatFunc(func(r *log.Record) []byte { - buf := &bytes.Buffer{} - fmt.Fprintf(buf, "%s\n", r.Msg) - return buf.Bytes() - }) -} - -func getStdoutHanlder(o *Options) log.Handler { - if o.LogFormatter == Plain { - return log.StreamHandler(os.Stdout, PlainTextFormatter()) - } - return log.StdoutHandler -} diff --git a/venonactl/pkg/logger/logger.go b/venonactl/pkg/logger/logger.go deleted file mode 100644 index 4e0113b4..00000000 --- a/venonactl/pkg/logger/logger.go +++ /dev/null @@ -1,40 +0,0 @@ -package logger - -import ( - log "github.com/inconshreveable/log15" -) - -type ( - Logger interface { - log.Logger - } - - Options struct { - Command string - Verbose bool - LogToFile string - LogFormatter string - } -) - -func New(o *Options) Logger { - l := log.New(log.Ctx{ - "Command": o.Command, - }) - handlers := []log.Handler{} - lvl := log.LvlInfo - if o.Verbose { - lvl = log.LvlDebug - } - verboseHandler := log.LvlFilterHandler(lvl, getStdoutHanlder(o)) - handlers = append(handlers, verboseHandler) - if o.LogToFile != "" { - fileHandler := log.LvlFilterHandler(log.LvlDebug, log.Must.FileHandler(o.LogToFile, log.JsonFormat())) - callerHandler := log.CallerFuncHandler(fileHandler) - fileLineHandler := log.CallerFileHandler(callerHandler) - handlers = append(handlers, fileLineHandler) - - } - l.SetHandler(log.MultiHandler(handlers...)) - return l -} diff --git a/venonactl/pkg/obj/kubeobj/kubeobj.go b/venonactl/pkg/obj/kubeobj/kubeobj.go deleted file mode 100644 index 5392f470..00000000 --- a/venonactl/pkg/obj/kubeobj/kubeobj.go +++ /dev/null @@ -1,581 +0,0 @@ -// Code generated by go generate; DO NOT EDIT. - -package kubeobj - -import ( - "context" - "fmt" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes" - - appsv1 "k8s.io/api/apps/v1" - "k8s.io/api/core/v1" - v1beta1 "k8s.io/api/extensions/v1beta1" - netv1 "k8s.io/api/networking/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - rbacv1 "k8s.io/api/rbac/v1" - rbacv1beta1 "k8s.io/api/rbac/v1beta1" - - storagev1 "k8s.io/api/storage/v1" - - batchv1 "k8s.io/api/batch/v1" - batchv1beta1 "k8s.io/api/batch/v1beta1" -) - -// CreateObject - creates kubernetes object from *runtime.Object. Returns object name, kind and creation error -func CreateObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error) { - - var name, kind string - var err error - switch objT := obj.(type) { - - case *appsv1.DaemonSet: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.AppsV1().DaemonSets(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *appsv1.Deployment: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.AppsV1().Deployments(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *batchv1.Job: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.BatchV1().Jobs(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *batchv1beta1.CronJob: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.BatchV1beta1().CronJobs(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *netv1.Ingress: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.NetworkingV1().Ingresses(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *rbacv1.ClusterRole: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1().ClusterRoles().Create(ctx, objT, metav1.CreateOptions{}) - - case *rbacv1.ClusterRoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1().ClusterRoleBindings().Create(ctx, objT, metav1.CreateOptions{}) - - case *rbacv1.Role: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1().Roles(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *rbacv1.RoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1().RoleBindings(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *rbacv1beta1.ClusterRole: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1beta1().ClusterRoles().Create(ctx, objT, metav1.CreateOptions{}) - - case *rbacv1beta1.ClusterRoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1beta1().ClusterRoleBindings().Create(ctx, objT, metav1.CreateOptions{}) - - case *rbacv1beta1.Role: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1beta1().Roles(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *rbacv1beta1.RoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1beta1().RoleBindings(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *storagev1.StorageClass: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.StorageV1().StorageClasses().Create(ctx, objT, metav1.CreateOptions{}) - - case *v1.ConfigMap: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().ConfigMaps(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *v1.PersistentVolume: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().PersistentVolumes().Create(ctx, objT, metav1.CreateOptions{}) - - case *v1.PersistentVolumeClaim: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().PersistentVolumeClaims(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *v1.Pod: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().Pods(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *v1.Secret: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().Secrets(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *v1.Service: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().Services(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *v1.ServiceAccount: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().ServiceAccounts(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *v1beta1.DaemonSet: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.ExtensionsV1beta1().DaemonSets(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - case *v1beta1.Deployment: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.ExtensionsV1beta1().Deployments(namespace).Create(ctx, objT, metav1.CreateOptions{}) - - default: - return "", "", fmt.Errorf("Unknown object type %T\n ", objT) - } - return name, kind, err -} - -// CheckObject - checks kubernetes object from *runtime.Object. Returns object name, kind and creation error -func CheckObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error) { - - var name, kind string - var err error - switch objT := obj.(type) { - - case *appsv1.DaemonSet: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.AppsV1().DaemonSets(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *appsv1.Deployment: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *batchv1.Job: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *batchv1beta1.CronJob: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.BatchV1beta1().CronJobs(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *netv1.Ingress: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.NetworkingV1().Ingresses(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *rbacv1.ClusterRole: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1().ClusterRoles().Get(ctx, name, metav1.GetOptions{}) - - case *rbacv1.ClusterRoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1().ClusterRoleBindings().Get(ctx, name, metav1.GetOptions{}) - - case *rbacv1.Role: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1().Roles(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *rbacv1.RoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1().RoleBindings(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *rbacv1beta1.ClusterRole: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1beta1().ClusterRoles().Get(ctx, name, metav1.GetOptions{}) - - case *rbacv1beta1.ClusterRoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1beta1().ClusterRoleBindings().Get(ctx, name, metav1.GetOptions{}) - - case *rbacv1beta1.Role: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1beta1().Roles(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *rbacv1beta1.RoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1beta1().RoleBindings(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *storagev1.StorageClass: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.StorageV1().StorageClasses().Get(ctx, name, metav1.GetOptions{}) - - case *v1.ConfigMap: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().ConfigMaps(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *v1.PersistentVolume: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().PersistentVolumes().Get(ctx, name, metav1.GetOptions{}) - - case *v1.PersistentVolumeClaim: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *v1.Pod: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().Pods(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *v1.Secret: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().Secrets(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *v1.Service: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().Services(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *v1.ServiceAccount: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().ServiceAccounts(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *v1beta1.DaemonSet: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.ExtensionsV1beta1().DaemonSets(namespace).Get(ctx, name, metav1.GetOptions{}) - - case *v1beta1.Deployment: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.ExtensionsV1beta1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) - - default: - return "", "", fmt.Errorf("Unknown object type %T\n ", objT) - } - return name, kind, err -} - -// DeleteObject - checks kubernetes object from *runtime.Object. Returns object name, kind and creation error -func DeleteObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error) { - var propagationPolicy metav1.DeletionPropagation = "Background" - var name, kind string - var err error - switch objT := obj.(type) { - - case *appsv1.DaemonSet: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.AppsV1().DaemonSets(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *appsv1.Deployment: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.AppsV1().Deployments(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *batchv1.Job: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.BatchV1().Jobs(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *batchv1beta1.CronJob: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.BatchV1beta1().CronJobs(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *netv1.Ingress: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.NetworkingV1().Ingresses(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *rbacv1.ClusterRole: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.RbacV1().ClusterRoles().Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *rbacv1.ClusterRoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.RbacV1().ClusterRoleBindings().Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *rbacv1.Role: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.RbacV1().Roles(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *rbacv1.RoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.RbacV1().RoleBindings(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *rbacv1beta1.ClusterRole: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.RbacV1beta1().ClusterRoles().Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *rbacv1beta1.ClusterRoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.RbacV1beta1().ClusterRoleBindings().Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *rbacv1beta1.Role: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.RbacV1beta1().Roles(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *rbacv1beta1.RoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.RbacV1beta1().RoleBindings(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *storagev1.StorageClass: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.StorageV1().StorageClasses().Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *v1.ConfigMap: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.CoreV1().ConfigMaps(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *v1.PersistentVolume: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.CoreV1().PersistentVolumes().Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *v1.PersistentVolumeClaim: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.CoreV1().PersistentVolumeClaims(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *v1.Pod: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.CoreV1().Pods(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *v1.Secret: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.CoreV1().Secrets(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *v1.Service: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.CoreV1().Services(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *v1.ServiceAccount: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.CoreV1().ServiceAccounts(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *v1beta1.DaemonSet: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.ExtensionsV1beta1().DaemonSets(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - case *v1beta1.Deployment: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.ExtensionsV1beta1().Deployments(namespace).Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - - default: - return "", "", fmt.Errorf("Unknown object type %T\n ", objT) - } - return name, kind, err -} - -// ReplaceObject - replaces kubernetes object from *runtime.Object. Returns object name, kind and creation error -func ReplaceObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error) { - var name, kind string - var err error - switch objT := obj.(type) { - - case *appsv1.DaemonSet: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.AppsV1().DaemonSets(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *appsv1.Deployment: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.AppsV1().Deployments(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *batchv1.Job: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.BatchV1().Jobs(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *batchv1beta1.CronJob: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.BatchV1beta1().CronJobs(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *netv1.Ingress: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.NetworkingV1().Ingresses(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *rbacv1.ClusterRole: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1().ClusterRoles().Update(ctx, objT, metav1.UpdateOptions{}) - - case *rbacv1.ClusterRoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1().ClusterRoleBindings().Update(ctx, objT, metav1.UpdateOptions{}) - - case *rbacv1.Role: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1().Roles(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *rbacv1.RoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1().RoleBindings(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *rbacv1beta1.ClusterRole: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1beta1().ClusterRoles().Update(ctx, objT, metav1.UpdateOptions{}) - - case *rbacv1beta1.ClusterRoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1beta1().ClusterRoleBindings().Update(ctx, objT, metav1.UpdateOptions{}) - - case *rbacv1beta1.Role: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1beta1().Roles(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *rbacv1beta1.RoleBinding: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.RbacV1beta1().RoleBindings(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *storagev1.StorageClass: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.StorageV1().StorageClasses().Update(ctx, objT, metav1.UpdateOptions{}) - - case *v1.ConfigMap: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().ConfigMaps(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *v1.PersistentVolume: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().PersistentVolumes().Update(ctx, objT, metav1.UpdateOptions{}) - - case *v1.PersistentVolumeClaim: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().PersistentVolumeClaims(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *v1.Pod: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().Pods(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *v1.Secret: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().Secrets(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *v1.Service: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().Services(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *v1.ServiceAccount: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.CoreV1().ServiceAccounts(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *v1beta1.DaemonSet: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.ExtensionsV1beta1().DaemonSets(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - case *v1beta1.Deployment: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.ExtensionsV1beta1().Deployments(namespace).Update(ctx, objT, metav1.UpdateOptions{}) - - default: - return "", "", fmt.Errorf("Unknown object type %T\n ", objT) - } - return name, kind, err -} diff --git a/venonactl/pkg/obj/kubeobj_generator.go b/venonactl/pkg/obj/kubeobj_generator.go deleted file mode 100644 index e27368e4..00000000 --- a/venonactl/pkg/obj/kubeobj_generator.go +++ /dev/null @@ -1,202 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "fmt" - "os" - "path" - "path/filepath" - "runtime" - "strings" - "text/template" -) - -/* -for usage in -\\go:generate go run generate generate_template.go -reads all files in folder and appends them to template map -*/ - -var outfileBaseName = "kubeobj.go" -var functionsMap map[string]string = map[string]string{ - "v1.Secret": "CoreV1().Secrets(namespace)", - "v1.ConfigMap": "CoreV1().ConfigMaps(namespace)", - "v1.Service": "CoreV1().Services(namespace)", - "v1.Pod": "CoreV1().Pods(namespace)", - "v1.ServiceAccount": "CoreV1().ServiceAccounts(namespace)", - "v1.PersistentVolumeClaim": "CoreV1().PersistentVolumeClaims(namespace)", - "v1.PersistentVolume": "CoreV1().PersistentVolumes()", - - "v1beta1.Deployment": "ExtensionsV1beta1().Deployments(namespace)", - "v1beta1.DaemonSet": "ExtensionsV1beta1().DaemonSets(namespace)", - - "netv1.Ingress": "NetworkingV1().Ingresses(namespace)", - - "appsv1.Deployment": "AppsV1().Deployments(namespace)", - "appsv1.DaemonSet": "AppsV1().DaemonSets(namespace)", - - "rbacv1beta1.ClusterRole": "RbacV1beta1().ClusterRoles()", - "rbacv1beta1.ClusterRoleBinding": "RbacV1beta1().ClusterRoleBindings()", - "rbacv1beta1.Role": "RbacV1beta1().Roles(namespace)", - "rbacv1beta1.RoleBinding": "RbacV1beta1().RoleBindings(namespace)", - - "rbacv1.ClusterRole": "RbacV1().ClusterRoles()", - "rbacv1.ClusterRoleBinding": "RbacV1().ClusterRoleBindings()", - "rbacv1.Role": "RbacV1().Roles(namespace)", - "rbacv1.RoleBinding": "RbacV1().RoleBindings(namespace)", - - "storagev1.StorageClass": "StorageV1().StorageClasses()", - - "batchv1.Job": "BatchV1().Jobs(namespace)", - "batchv1beta1.CronJob": "BatchV1beta1().CronJobs(namespace)", -} - -var packageTemplate = template.Must(template.New("").Parse( - ` -// Code generated by go generate; DO NOT EDIT. - -package kubeobj - -import ( - "fmt" - "context" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/api/core/v1" - v1beta1 "k8s.io/api/extensions/v1beta1" - netv1 "k8s.io/api/networking/v1" - appsv1 "k8s.io/api/apps/v1" - - rbacv1beta1 "k8s.io/api/rbac/v1beta1" - rbacv1 "k8s.io/api/rbac/v1" - - storagev1 "k8s.io/api/storage/v1" - - batchv1 "k8s.io/api/batch/v1" - batchv1beta1 "k8s.io/api/batch/v1beta1" -) - -// CreateObject - creates kubernetes object from *runtime.Object. Returns object name, kind and creation error -func CreateObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error){ - - var name, kind string - var err error - switch objT := obj.(type) { - {{ range $key, $value := .FunctionsMap }} - case *{{ $key }}: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.{{ $value }}.Create(ctx, objT, metav1.CreateOptions{}) - {{ end }} - default: - return "", "", fmt.Errorf("Unknown object type %T\n ", objT) - } - return name, kind, err -} - -// CheckObject - checks kubernetes object from *runtime.Object. Returns object name, kind and creation error -func CheckObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error){ - - var name, kind string - var err error - switch objT := obj.(type) { - {{ range $key, $value := .FunctionsMap }} - case *{{ $key }}: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.{{ $value }}.Get(ctx, name, metav1.GetOptions{}) - {{ end }} - default: - return "", "", fmt.Errorf("Unknown object type %T\n ", objT) - } - return name, kind, err -} - -// DeleteObject - checks kubernetes object from *runtime.Object. Returns object name, kind and creation error -func DeleteObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error){ - var propagationPolicy metav1.DeletionPropagation = "Background" - var name, kind string - var err error - switch objT := obj.(type) { - {{ range $key, $value := .FunctionsMap }} - case *{{ $key }}: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - err = clientset.{{ $value }}.Delete(ctx, name, metav1.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) - {{ end }} - default: - return "", "", fmt.Errorf("Unknown object type %T\n ", objT) - } - return name, kind, err -} - -// ReplaceObject - replaces kubernetes object from *runtime.Object. Returns object name, kind and creation error -func ReplaceObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error){ - var name, kind string - var err error - switch objT := obj.(type) { - {{ range $key, $value := .FunctionsMap }} - case *{{ $key }}: - name = objT.ObjectMeta.Name - kind = objT.TypeMeta.Kind - _, err = clientset.{{ $value }}.Update(ctx, objT, metav1.UpdateOptions{}) - {{ end }} - default: - return "", "", fmt.Errorf("Unknown object type %T\n ", objT) - } - return name, kind, err -} - -`)) - -type tempateData struct { - FunctionsMap map[string]string -} - -func main() { - - var currentFilePath string - if strings.Contains(os.Args[0], "/go-build") { - _, currentFilePath, _, _ = runtime.Caller(0) - } else { - currentFilePath = os.Args[0] - } - - currentDir := filepath.Dir(currentFilePath) - var folderName = path.Join(currentDir, "kubeobj") - - outfileName := path.Join(folderName, "kubeobj.go") - outfile, err := os.Create(outfileName) - if err != nil { - fmt.Printf("ERROR: cannot create out file %v", err) - os.Exit(1) - } - defer outfile.Close() - - err = packageTemplate.Execute(outfile, tempateData{ - FunctionsMap: functionsMap, - }) - if err != nil { - fmt.Printf("generate_template ERROR: cannot generate template %v \n", err) - os.Exit(1) - } -} diff --git a/venonactl/pkg/plugins/app-proxy.go b/venonactl/pkg/plugins/app-proxy.go deleted file mode 100644 index 3446d393..00000000 --- a/venonactl/pkg/plugins/app-proxy.go +++ /dev/null @@ -1,132 +0,0 @@ -package plugins - -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import ( - "context" - "fmt" - - "github.com/codefresh-io/venona/venonactl/pkg/logger" - templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" - "github.com/stretchr/objx" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type appProxyPlugin struct { - logger logger.Logger -} - -const ( - appProxyFilesPattern = ".*.app-proxy.yaml" -) - -func (u *appProxyPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { - - cs, err := opt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) - return nil, err - } - err = install(ctx, &installOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: opt.ClusterNamespace, - matchPattern: appProxyFilesPattern, - dryRun: opt.DryRun, - operatorType: AppProxyPluginType, - }) - if err != nil { - u.logger.Error(fmt.Sprintf("AppProxy installation failed: %v", err)) - return nil, err - } - - host := objx.New(v["AppProxy"]).Get("Ingress.Host").Str() - pathPrefix := objx.New(v["AppProxy"]).Get("Ingress.PathPrefix").Str() - appProxyURL := fmt.Sprintf("https://%v%v", host, pathPrefix) - u.logger.Info(fmt.Sprintf("app proxy is running at: %v", appProxyURL)) - return v, nil -} - -func (u *appProxyPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { - return [][]string{}, nil -} - -func (u *appProxyPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { - cs, err := deleteOpt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return err - } - opt := &deleteOptions{ - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: deleteOpt.ClusterNamespace, - matchPattern: appProxyFilesPattern, - operatorType: AppProxyPluginType, - logger: u.logger, - } - return uninstall(ctx, opt) -} - -func (u *appProxyPlugin) Upgrade(ctx context.Context, opt *UpgradeOptions, v Values) (Values, error) { - kubeClientset, err := opt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - - list, err := kubeClientset.CoreV1().Pods(opt.ClusterNamespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("app=%v", opt.Name)}) - if err != nil { - u.logger.Error(fmt.Sprintf("Failed to list app-proxy pods: %v ", err)) - return nil, err - } - if len(list.Items) == 0 { - u.logger.Info("no app-proxy pods found") - return nil, nil - } - - for _, pod := range list.Items { - podName := pod.ObjectMeta.Name - u.logger.Debug(fmt.Sprintf("Deleting app-proxy pod: %v", podName)) - err = kubeClientset.CoreV1().Pods(opt.ClusterNamespace).Delete(ctx, podName, metav1.DeleteOptions{}) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot delete app-proxy pod: %v ", err)) - return nil, err - } - } - - return v, nil -} -func (u *appProxyPlugin) Migrate(context.Context, *MigrateOptions, Values) error { - return fmt.Errorf("not supported") -} - -func (u *appProxyPlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { - return nil -} - -func (u *appProxyPlugin) Name() string { - return AppProxyPluginType -} diff --git a/venonactl/pkg/plugins/engine.go b/venonactl/pkg/plugins/engine.go deleted file mode 100644 index c064521c..00000000 --- a/venonactl/pkg/plugins/engine.go +++ /dev/null @@ -1,111 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package plugins - -import ( - "context" - "fmt" - - "github.com/codefresh-io/venona/venonactl/pkg/logger" - templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" -) - -// enginePlugin installs assets on Kubernetes Dind runtimectl Env -type enginePlugin struct { - logger logger.Logger -} - -const ( - engineFilesPattern = ".*.engine.yaml" -) - -// Install venona agent -func (u *enginePlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { - cs, err := opt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) - return nil, err - } - return v, install(ctx, &installOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: opt.ClusterNamespace, - matchPattern: engineFilesPattern, - dryRun: opt.DryRun, - operatorType: EnginePluginType, - }) -} - -// Status of runtimectl environment -func (u *enginePlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { - cs, err := statusOpt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - opt := &statusOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: statusOpt.ClusterNamespace, - matchPattern: engineFilesPattern, - operatorType: EnginePluginType, - } - return status(ctx, opt) -} - -func (u *enginePlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { - cs, err := deleteOpt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil - } - opt := &deleteOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: deleteOpt.ClusterNamespace, - matchPattern: engineFilesPattern, - operatorType: EnginePluginType, - } - return uninstall(ctx, opt) -} - -func (u *enginePlugin) Upgrade(ctx context.Context, opt *UpgradeOptions, v Values) (Values, error) { - return v, nil -} - -func (u *enginePlugin) Migrate(context.Context, *MigrateOptions, Values) error { - return fmt.Errorf("not supported") -} - -func (u *enginePlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { - return nil -} - -func (u *enginePlugin) Name() string { - return EnginePluginType -} diff --git a/venonactl/pkg/plugins/helper.go b/venonactl/pkg/plugins/helper.go deleted file mode 100644 index 558066a2..00000000 --- a/venonactl/pkg/plugins/helper.go +++ /dev/null @@ -1,367 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package plugins - -import ( - "bytes" - "context" - "errors" - "fmt" - "html/template" - "regexp" - "strings" - - // import all cloud providers auth clients - "gopkg.in/yaml.v2" - authv1 "k8s.io/api/authorization/v1" - v1 "k8s.io/api/core/v1" - "k8s.io/client-go/kubernetes" - _ "k8s.io/client-go/plugin/pkg/client/auth" - - "github.com/Masterminds/sprig" - "github.com/codefresh-io/venona/venonactl/pkg/logger" - templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" - - "github.com/Masterminds/semver" - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/version" - "k8s.io/client-go/kubernetes/scheme" -) - -type ( - validationResult struct { - isValid bool - message []string - } - - validationRequest struct { - cpu string - localDiskMinimumSize string - momorySize string - rbac []rbacValidation - } - - rbacValidation struct { - Namespace string - Resource string - Verbs []string - Group string - } -) - -var requiredK8sVersion, _ = semver.NewConstraint(">= 1.10.0") - -func unescape(s string) template.HTML { - return template.HTML(s) -} - -// template function to parse values for nodeSelector in form "key1=value1,key2=value2" -func nodeSelectorParamToYaml(ns string) string { - nodeSelectorParts := strings.Split(ns, ",") - var nodeSelectorYaml string - for _, p := range nodeSelectorParts { - pSplit := strings.Split(p, "=") - if len(pSplit) != 2 { - continue - } - - if len(nodeSelectorYaml) > 0 { - nodeSelectorYaml += "\n" - } - nodeSelectorYaml += fmt.Sprintf("%s: %q", pSplit[0], pSplit[1]) - } - return nodeSelectorYaml -} - -func toYAML(v interface{}) string { - switch v.(type) { - case map[string]interface{}: - if len(v.(map[string]interface{})) == 0 { - return "" - } - case []v1.Toleration: - if len(v.([]v1.Toleration)) == 0 { - return "" - } - } - data, err := yaml.Marshal(v) - if err != nil { - // Swallow errors inside of a template. - return "" - } - return strings.TrimSuffix(string(data), "\n") -} - -func isString(v interface{}) bool { - _, ok := v.(string) - return ok -} - -func nodeSelectorToString(nodeSelectors map[string]string) string { - str := "" - for key, value := range nodeSelectors { - - //str = strings.Join([]string {str, fmt.Sprintf("%s=%s", key, value)} , ",") - str = fmt.Sprintf("%s,%s=%s", str, key, value) - - } - return strings.TrimPrefix(str, ",") -} -func tolerationsToSring(tolerations []v1.Toleration) string { - // [{\"effect\":\"NoSchedule\",\"key\":\"dedicated\",\"value\":\"codefresh\"},{\"effect\":\"NoSchedule\",\"key\":\"dedicated\",\"value\":\"codefresh\"}] - y, err := yaml.Marshal(&tolerations) - if err != nil { - return "" - } - return fmt.Sprintf("\n%s", string(y)) - -} - -// ExecuteTemplate - executes templates in tpl str with config as values -func ExecuteTemplate(tplStr string, data interface{}) (string, error) { - funcMap := template.FuncMap{ - "unescape": unescape, - "nodeSelectorParamToYaml": nodeSelectorParamToYaml, - "toYaml": toYAML, - "isString": isString, - } - template, err := template.New("base").Funcs(sprig.FuncMap()).Funcs(funcMap).Parse(tplStr) - if err != nil { - return "", err - } - - buf := bytes.NewBufferString("") - err = template.Execute(buf, data) - if err != nil { - return "", err - } - - return buf.String(), nil -} - -// ParseTemplates - parses and exexute templates and return map of strings with obj data -func ParseTemplates(templatesMap map[string]string, data interface{}, pattern string, logger logger.Logger) (map[string]string, error) { - parsedTemplates := make(map[string]string) - nonEmptyParsedTemplateFunc := regexp.MustCompile(`[a-zA-Z0-9]`).MatchString - for n, tpl := range templatesMap { - match, _ := regexp.MatchString(pattern, n) - if match != true { - logger.Debug(fmt.Sprintf("Skipping parsing, pattern does not match %s - %s", pattern, n)) - continue - } - logger.Debug(fmt.Sprintf("parsing template %s", n)) - tplEx, err := ExecuteTemplate(tpl, data) - if err != nil { - logger.Error(fmt.Sprintf("Failed to parse and execute template %s", n)) - return nil, err - } - - // we add only non-empty parsedTemplates - if nonEmptyParsedTemplateFunc(tplEx) { - parsedTemplates[n] = tplEx - } - } - return parsedTemplates, nil -} - -// KubeObjectsFromTemplates return map of runtime.Objects from templateMap -// see https://github.com/kubernetes/client-go/issues/193 for examples -func KubeObjectsFromTemplates(templatesMap map[string]string, data interface{}, pattern string, logger logger.Logger) (map[string]runtime.Object, error) { - parsedTemplates, err := ParseTemplates(templatesMap, data, pattern, logger) - if err != nil { - return nil, err - } - - // Deserializing all kube objects from parsedTemplates - // see https://github.com/kubernetes/client-go/issues/193 for examples - kubeDecode := scheme.Codecs.UniversalDeserializer().Decode - kubeObjects := make(map[string]runtime.Object) - for n, objStr := range parsedTemplates { - logger.Debug(fmt.Sprintf("Deserializing template %s %s", n, objStr)) - obj, groupVersionKind, err := kubeDecode([]byte(objStr), nil, nil) - if err != nil { - logger.Error(fmt.Sprintf("Cannot deserialize kuberentes object %s: %v", n, err)) - return nil, err - } - logger.Debug(fmt.Sprintf("deserializing template success %s group=%s", n, groupVersionKind.Group)) - kubeObjects[n] = obj - } - return kubeObjects, nil -} - -func getKubeObjectsFromTempalte(values map[string]interface{}, pattern string, logger logger.Logger) (map[string]runtime.Object, error) { - templatesMap := templates.TemplatesMap() - return KubeObjectsFromTemplates(templatesMap, values, pattern, logger) -} - -func ensureClusterRequirements(ctx context.Context, client *kubernetes.Clientset, req validationRequest, logger logger.Logger) (validationResult, error) { - result := validationResult{true, nil} - specs := []*authv1.SelfSubjectAccessReview{} - for _, rbac := range req.rbac { - for _, verb := range rbac.Verbs { - attr := &authv1.ResourceAttributes{ - Resource: rbac.Resource, - Verb: verb, - Group: rbac.Group, - } - if rbac.Namespace != "" { - attr.Namespace = rbac.Namespace - } - specs = append(specs, &authv1.SelfSubjectAccessReview{ - Spec: authv1.SelfSubjectAccessReviewSpec{ - ResourceAttributes: attr, - }, - }) - } - } - rbacres := testRBAC(ctx, client, specs) - if len(rbacres) > 0 { - result.isValid = false - for _, res := range rbacres { - result.message = append(result.message, res) - } - return result, nil - } - - v, err := client.ServerVersion() - if err != nil { - // should not fail if can't get version - logger.Warn("Failed to validate kubernetes version", "cause", err) - } else if res, err := testKubernetesVersion(v); !res { - if err != nil { - logger.Warn("Failed to validate kubernetes version", "cause", err) - } else { - result.isValid = false - result.message = append(result.message, fmt.Sprintf("Cluster does not meet the version requirements, minimum supported version is: '1.10.0' found version: '%v'", v)) - } - } - - nodes, err := client.CoreV1().Nodes().List(ctx, metav1.ListOptions{}) - if err != nil { - return result, err - } - if nodes == nil { - return result, errors.New("Nodes not found") - } - - if len(nodes.Items) == 0 { - result.message = append(result.message, "No nodes in cluster") - result.isValid = false - } - - atLeastOneMet := false - for _, n := range nodes.Items { - res := testNode(n, req) - if len(res) > 0 { - result.message = append(result.message, res...) - } else { - atLeastOneMet = true - } - } - if !atLeastOneMet { - result.isValid = false - return result, nil - } - return result, nil -} - -func handleValidationResult(res validationResult, logger logger.Logger) error { - if !res.isValid { - for _, m := range res.message { - logger.Error(m) - } - return errors.New("Failed to run acceptance test on cluster") - } - - for _, m := range res.message { - logger.Warn(m) - } - return nil -} - -func testKubernetesVersion(version *version.Info) (bool, error) { - v, err := semver.NewVersion(version.String()) - if err != nil { - return false, err - } - // extract only major, minor and patch - verStr := fmt.Sprintf("%v.%v.%v", v.Major(), v.Minor(), v.Patch()) - v, err = semver.NewVersion(verStr) - if err != nil { - return false, err - } - return requiredK8sVersion.Check(v), nil -} - -func testNode(n v1.Node, req validationRequest) []string { - result := []string{} - - if req.cpu != "" { - requiredCPU, err := resource.ParseQuantity(req.cpu) - if err != nil { - result = append(result, err.Error()) - return result - } - cpu := n.Status.Capacity.Cpu() - - if cpu != nil && cpu.Cmp(requiredCPU) == -1 { - msg := fmt.Sprintf("Insufficiant CPU on node %s, current: %s - required: %s", n.GetObjectMeta().GetName(), cpu.String(), requiredCPU.String()) - result = append(result, msg) - } - } - - if req.momorySize != "" { - requiredMemory, err := resource.ParseQuantity(req.momorySize) - if err != nil { - result = append(result, err.Error()) - return result - } - memory := n.Status.Capacity.Memory() - if memory != nil && memory.Cmp(requiredMemory) == -1 { - msg := fmt.Sprintf("Insufficiant Memory on node %s, current: %s - required: %s", n.GetObjectMeta().GetName(), memory.String(), requiredMemory.String()) - result = append(result, msg) - } - } - - return result -} - -func testRBAC(ctx context.Context, client *kubernetes.Clientset, specs []*authv1.SelfSubjectAccessReview) []string { - res := []string{} - for _, sar := range specs { - resp, err := client.AuthorizationV1().SelfSubjectAccessReviews().Create(ctx, sar, metav1.CreateOptions{}) - if err != nil { - res = append(res, err.Error()) - continue - } - if !resp.Status.Allowed { - verb := sar.Spec.ResourceAttributes.Verb - namespace := sar.Spec.ResourceAttributes.Namespace - resource := sar.Spec.ResourceAttributes.Resource - group := sar.Spec.ResourceAttributes.Group - msg := strings.Builder{} - msg.WriteString(fmt.Sprintf("Insufficient permission, %s %s/%s is not allowed", verb, group, resource)) - if namespace != "" { - msg.WriteString(fmt.Sprintf(" on namespace %s", namespace)) - } - res = append(res, msg.String()) - } - } - return res -} diff --git a/venonactl/pkg/plugins/monitor.go b/venonactl/pkg/plugins/monitor.go deleted file mode 100644 index bb4c17bc..00000000 --- a/venonactl/pkg/plugins/monitor.go +++ /dev/null @@ -1,127 +0,0 @@ -/* -Copyright 2020 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package plugins - -import ( - "context" - "fmt" - - "github.com/codefresh-io/venona/venonactl/pkg/logger" - templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" -) - -// k8sAgentPlugin installs assets on Kubernetes Dind runtimectl Env -type monitorAgentPlugin struct { - logger logger.Logger -} - -const ( - monitorFilesPattern = ".*.monitor.yaml" -) - -// Install k8sAgent agent -func (u *monitorAgentPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { - - cs, err := opt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) - return nil, err - } - return v, install(ctx, &installOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: opt.ClusterNamespace, - matchPattern: monitorFilesPattern, - dryRun: opt.DryRun, - operatorType: MonitorAgentPluginType, - }) -} - -func (u *monitorAgentPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { - return [][]string{}, nil -} - -func (u *monitorAgentPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { - cs, err := deleteOpt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return err - } - opt := &deleteOptions{ - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: deleteOpt.ClusterNamespace, - matchPattern: monitorFilesPattern, - operatorType: MonitorAgentPluginType, - logger: u.logger, - } - return uninstall(ctx, opt) -} - -func (u *monitorAgentPlugin) Upgrade(ctx context.Context, opt *UpgradeOptions, v Values) (Values, error) { - return nil, nil -} -func (u *monitorAgentPlugin) Migrate(context.Context, *MigrateOptions, Values) error { - return fmt.Errorf("not supported") -} - -func (u *monitorAgentPlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { - validationRequest := validationRequest{ - rbac: []rbacValidation{ - { - Group: "apps", - Resource: "*", - Verbs: []string{"get", "list", "watch"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "*", - Verbs: []string{"get", "list", "watch", "create", "delete"}, - Namespace: opt.ClusterNamespace, - }, - { - Group: "extensions", - Resource: "*", - Verbs: []string{"get", "list", "watch"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "pods", - Verbs: []string{"deletecollection"}, - Namespace: opt.ClusterNamespace, - }, - }, - } - return test(ctx, testOptions{ - logger: u.logger, - kubeBuilder: opt.KubeBuilder, - namespace: opt.ClusterNamespace, - validationRequest: validationRequest, - }) -} - -func (u *monitorAgentPlugin) Name() string { - return MonitorAgentPluginType -} diff --git a/venonactl/pkg/plugins/network-tester.go b/venonactl/pkg/plugins/network-tester.go deleted file mode 100644 index 7471fd43..00000000 --- a/venonactl/pkg/plugins/network-tester.go +++ /dev/null @@ -1,238 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package plugins - -import ( - "bytes" - "context" - "errors" - "fmt" - "io" - "strings" - "time" - - "github.com/codefresh-io/venona/venonactl/pkg/logger" - "github.com/codefresh-io/venona/venonactl/pkg/store" - templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" - "github.com/stretchr/objx" - v1 "k8s.io/api/core/v1" - kerrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type networkTesterPlugin struct { - logger logger.Logger -} - -const ( - networkTesterFilesPattern = ".*.network-tester.yaml" - networkTestsTimeout = 120 * time.Second - defaultRegistry = "https://docker.io" - defaultCodefreshHost = "https://g.codefresh.io" - defaultFirebaseHost = "https://codefresh-prod-public-builds-1.firebaseio.com" -) - -var ( - errNetworkTestFailed = errors.New(`Cluster network tests failed. -- If you are using a proxy, run again with the correct http proxy environment variables. -- Make sure that cluster host address in your kubeconfig is accessible from inside the cluster, - or specify a different one with: --set-value KubernetesHost=
. -For more details run again with --verbose`) -) - -func (u *networkTesterPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { - return nil, fmt.Errorf("not supported") -} - -func (u *networkTesterPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { - return nil, fmt.Errorf("not supported") -} - -func (u *networkTesterPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { - return fmt.Errorf("not supported") -} - -func (u *networkTesterPlugin) Upgrade(ctx context.Context, opt *UpgradeOptions, v Values) (Values, error) { - return v, fmt.Errorf("not supported") -} - -func (u *networkTesterPlugin) Migrate(context.Context, *MigrateOptions, Values) error { - return fmt.Errorf("not supported") -} - -func prepareTestDomains(v map[string]interface{}) []string { - testDomains := make([]string, 0, 10) - - vObj := objx.New(v) - // codefresh host - if cfHost := vObj.Get("CodefreshHost").Str(); cfHost != "" { - testDomains = append(testDomains, cfHost) - } else { - testDomains = append(testDomains, defaultCodefreshHost) - } - - // registry - if dockerRegistry := vObj.Get("DockerRegistry").Str(); dockerRegistry != "" { - testDomains = append(testDomains, dockerRegistry) - } else { - testDomains = append(testDomains, defaultRegistry) - } - - // logging - if firebaseURL := vObj.Get("Logging.FirebaseHost").Str(); firebaseURL != "" { - testDomains = append(testDomains, firebaseURL) - } else { - testDomains = append(testDomains, defaultFirebaseHost) - } - - // git url - if gitProviderURL := vObj.Get("GitProviderURL").Str(); gitProviderURL != "" { - testDomains = append(testDomains, gitProviderURL) - } - - return testDomains -} - -func getKubeHost(v map[string]interface{}, defaultHost string) string { - vObj := objx.New(v) - if host := vObj.Get("KubernetesHost").Str(); host != "" { - return host - } - - return defaultHost -} - -func (u *networkTesterPlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { - cs, err := opt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return err - } - err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) - return err - } - - conf, err := opt.KubeBuilder.BuildConfig() - if err != nil { - return fmt.Errorf("failed to build config: %w", err) - } - - testDomains := prepareTestDomains(v) - urls := strings.Join(testDomains, ",") - objx.New(v["NetworkTester"]).Set("AdditionalEnvVars.URLS", urls) - objx.New(v["NetworkTester"]).Set("AdditionalEnvVars.KUBERNETES_HOST", getKubeHost(v, conf.Host)) - - err = install(ctx, &installOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: opt.ClusterNamespace, - matchPattern: networkTesterFilesPattern, - operatorType: NetworkTesterPluginType, - }) - if err != nil { - u.logger.Error(fmt.Sprintf("Failed to run network-tester pod: %v", err)) - return err - } - // defer cleanup - defer func() { - err := uninstall(ctx, &deleteOptions{ - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: opt.ClusterNamespace, - matchPattern: networkTesterFilesPattern, - operatorType: NetworkTesterPluginType, - logger: u.logger, - }) - if err != nil { - u.logger.Error(fmt.Sprintf("Failed to cleanup network-tester pod: %v", err)) - } - }() - - u.logger.Info("Running network tests...") - - ticker := time.NewTicker(5 * time.Second) - defer ticker.Stop() - var podLastState *v1.Pod - timeoutChan := time.After(networkTestsTimeout) -Loop: - for { - select { - case <-ticker.C: - u.logger.Debug("Waiting for network tester to finish") - pod, err := cs.CoreV1().Pods(opt.ClusterNamespace).Get(ctx, store.NetworkTesterName, metav1.GetOptions{}) - if err != nil { - if statusError, errIsStatusError := err.(*kerrors.StatusError); errIsStatusError { - if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound { - u.logger.Debug("Network tester pod not found") - } - } - } - if len(pod.Status.ContainerStatuses) == 0 { - u.logger.Debug("Network tester pod: creating container") - continue - } - if pod.Status.ContainerStatuses[0].State.Running != nil { - u.logger.Debug("Network tester pod: running") - } - if pod.Status.ContainerStatuses[0].State.Waiting != nil { - u.logger.Debug("Network tester pod: waiting") - } - if pod.Status.ContainerStatuses[0].State.Terminated != nil { - u.logger.Debug("Network tester pod: terminated") - podLastState = pod - break Loop - } - case <-timeoutChan: - u.logger.Error("Network tests timeout reached!") - return fmt.Errorf("Network tests timeout reached") - } - } - - req := cs.CoreV1().Pods(opt.ClusterNamespace).GetLogs(store.NetworkTesterName, &v1.PodLogOptions{}) - podLogs, err := req.Stream(ctx) - if err != nil { - u.logger.Error(fmt.Sprintf("Failed to get network-tester pod logs: %v", err)) - return err - } - defer podLogs.Close() - - logsBuf := new(bytes.Buffer) - _, err = io.Copy(logsBuf, podLogs) - if err != nil { - u.logger.Error(fmt.Sprintf("Failed to read network-tester pod logs: %v", err)) - return err - } - logs := strings.Trim(logsBuf.String(), "\n") - u.logger.Debug(fmt.Sprintf("%s", logs)) - - if podLastState.Status.ContainerStatuses[0].State.Terminated.ExitCode != 0 { - terminationMessage := strings.Trim(podLastState.Status.ContainerStatuses[0].State.Terminated.Message, "\n") - u.logger.Error(fmt.Sprintf("Network tests failed with: %v", terminationMessage)) - return errNetworkTestFailed - } - - return nil -} - -func (u *networkTesterPlugin) Name() string { - return NetworkTesterPluginType -} diff --git a/venonactl/pkg/plugins/plugin.go b/venonactl/pkg/plugins/plugin.go deleted file mode 100644 index b6731afc..00000000 --- a/venonactl/pkg/plugins/plugin.go +++ /dev/null @@ -1,353 +0,0 @@ -package plugins - -import ( - "context" - "fmt" - "os" - - "github.com/codefresh-io/venona/venonactl/pkg/logger" - "github.com/codefresh-io/venona/venonactl/pkg/obj/kubeobj" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" -) - -const ( - RuntimeEnvironmentPluginType = "runtime-environment" - VenonaPluginType = "venona" - MonitorAgentPluginType = "monitor-agent" - VolumeProvisionerPluginType = "volume-provisioner" - EnginePluginType = "engine" - DefaultStorageClassNamePrefix = "dind-local-volumes-runner" - RuntimeAttachType = "runtime-attach" - AppProxyPluginType = "app-proxy" - NetworkTesterPluginType = "network-tester" -) - -type ( - Plugin interface { - Install(context.Context, *InstallOptions, Values) (Values, error) - Status(context.Context, *StatusOptions, Values) ([][]string, error) - Delete(context.Context, *DeleteOptions, Values) error - Upgrade(context.Context, *UpgradeOptions, Values) (Values, error) - Migrate(context.Context, *MigrateOptions, Values) error - Test(context.Context, *TestOptions, Values) error - Name() string - } - - PluginBuilder interface { - Add(string) PluginBuilder - Get() []Plugin - } - - KubeClientBuilder interface { - BuildClient() (*kubernetes.Clientset, error) - } - - pb struct { - logger logger.Logger - plugins []Plugin - } - - Values map[string]interface{} - - InstallOptions struct { - CodefreshHost string - CodefreshToken string - ClusterName string - ClusterNamespace string - ClusterHost string - RegisterWithAgent bool - MarkAsDefault bool - StorageClass string - DockerRegistry string - IsDefaultStorageClass bool - KubeBuilder interface { - BuildClient() (*kubernetes.Clientset, error) - BuildConfig() (*rest.Config, error) - EnsureNamespaceExists(ctx context.Context, cs *kubernetes.Clientset) error - } - AgentKubeBuilder interface { - BuildClient() (*kubernetes.Clientset, error) - EnsureNamespaceExists(ctx context.Context, cs *kubernetes.Clientset) error - } - DryRun bool - BuildNodeSelector map[string]string - Annotations map[string]string - RuntimeEnvironment string - RuntimeNamespace string - RuntimeServiceAccount string - RestartAgent bool - Insecure bool - } - - DeleteOptions struct { - KubeBuilder interface { - BuildClient() (*kubernetes.Clientset, error) - } - AgentKubeBuilder interface { - BuildClient() (*kubernetes.Clientset, error) - } - ClusterNamespace string // runtime - AgentNamespace string // agent - RuntimeEnvironment string - RestartAgent bool - } - - UpgradeOptions struct { - ClusterName string - ClusterNamespace string - Name string - KubeBuilder interface { - BuildClient() (*kubernetes.Clientset, error) - } - } - - MigrateOptions struct { - ClusterName string - ClusterNamespace string - KubeBuilder interface { - BuildClient() (*kubernetes.Clientset, error) - } - } - - TestOptions struct { - KubeBuilder interface { - BuildClient() (*kubernetes.Clientset, error) - BuildConfig() (*rest.Config, error) - EnsureNamespaceExists(ctx context.Context, cs *kubernetes.Clientset) error - } - ClusterNamespace string - } - - StatusOptions struct { - KubeBuilder interface { - BuildClient() (*kubernetes.Clientset, error) - } - ClusterNamespace string - } - - installOptions struct { - templates map[string]string - templateValues map[string]interface{} - kubeClientSet *kubernetes.Clientset - namespace string - matchPattern string - operatorType string - dryRun bool - kubeBuilder interface { - BuildClient() (*kubernetes.Clientset, error) - } - logger logger.Logger - } - - statusOptions struct { - templates map[string]string - templateValues map[string]interface{} - kubeClientSet *kubernetes.Clientset - namespace string - matchPattern string - operatorType string - logger logger.Logger - } - - deleteOptions struct { - templates map[string]string - templateValues map[string]interface{} - kubeClientSet *kubernetes.Clientset - namespace string - matchPattern string - operatorType string - logger logger.Logger - } - - testOptions struct { - logger logger.Logger - kubeBuilder interface { - BuildClient() (*kubernetes.Clientset, error) - } - namespace string - validationRequest validationRequest - } -) - -func NewBuilder(logger logger.Logger) PluginBuilder { - return &pb{ - logger: logger, - plugins: []Plugin{}, - } -} - -func (p *pb) Add(name string) PluginBuilder { - p.plugins = append(p.plugins, build(name, p.logger)) - return p -} - -func (p *pb) Get() []Plugin { - return p.plugins -} - -func build(t string, logger logger.Logger) Plugin { - if t == VenonaPluginType { - return &venonaPlugin{ - logger: logger.New("installer", VenonaPluginType), - } - } - - if t == RuntimeEnvironmentPluginType { - return &runtimeEnvironmentPlugin{ - logger: logger.New("installer", RuntimeEnvironmentPluginType), - } - } - - if t == VolumeProvisionerPluginType { - return &volumeProvisionerPlugin{ - logger: logger.New("installer", VolumeProvisionerPluginType), - } - } - - if t == EnginePluginType { - return &enginePlugin{ - logger: logger.New("installer", EnginePluginType), - } - } - - if t == RuntimeAttachType { - return &runtimeAttachPlugin{ - logger: logger.New("installer", RuntimeAttachType), - } - } - - if t == MonitorAgentPluginType { - return &monitorAgentPlugin{ - logger: logger.New("installer", MonitorAgentPluginType), - } - } - - if t == AppProxyPluginType { - return &appProxyPlugin{ - logger: logger.New("installer", AppProxyPluginType), - } - } - - if t == NetworkTesterPluginType { - return &networkTesterPlugin{ - logger: logger.New("network-tester", NetworkTesterPluginType), - } - } - - return nil -} - -func install(ctx context.Context, opt *installOptions) error { - - if opt.dryRun == true { - err := os.Mkdir("codefresh_manifests", 0755) - if err != nil { - opt.logger.Error("failed to create manifests folder", "File-Name", "Error", err) - } - parsedTemplates, err := ParseTemplates(opt.templates, opt.templateValues, opt.matchPattern, opt.logger) - for fileName, objStr := range parsedTemplates { - err = os.WriteFile(fmt.Sprintf("./codefresh_manifests/%s", fileName), []byte(objStr), 0644) - if err != nil { - opt.logger.Error(fmt.Sprintf("failed to write file %v", objStr), "File-Name", fileName, "Error", err) - } - } - return nil - } - - kubeObjects, err := KubeObjectsFromTemplates(opt.templates, opt.templateValues, opt.matchPattern, opt.logger) - if err != nil { - return err - } - - for _, obj := range kubeObjects { - - var createErr error - var kind, name string - name, kind, createErr = kubeobj.CreateObject(ctx, opt.kubeClientSet, obj, opt.namespace) - - if createErr == nil { - opt.logger.Debug(fmt.Sprintf("%s \"%s\" created", kind, name)) - } else if statusError, errIsStatusError := createErr.(*errors.StatusError); errIsStatusError { - if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { - opt.logger.Debug(fmt.Sprintf("%s \"%s\" already exists", kind, name)) - } else { - opt.logger.Debug(fmt.Sprintf("%s \"%s\" failed: %v ", kind, name, statusError)) - return statusError - } - } else { - opt.logger.Debug(fmt.Sprintf("%s \"%s\" failed: %v ", kind, name, createErr)) - return createErr - } - } - - return nil -} - -func status(ctx context.Context, opt *statusOptions) ([][]string, error) { - kubeObjects, err := KubeObjectsFromTemplates(opt.templates, opt.templateValues, opt.matchPattern, opt.logger) - if err != nil { - return nil, err - } - var getErr error - var kind, name string - var rows [][]string - for _, obj := range kubeObjects { - name, kind, getErr = kubeobj.CheckObject(ctx, opt.kubeClientSet, obj, opt.namespace) - if getErr == nil { - rows = append(rows, []string{kind, name, StatusInstalled}) - } else if statusError, errIsStatusError := getErr.(*errors.StatusError); errIsStatusError { - rows = append(rows, []string{kind, name, StatusNotInstalled, statusError.ErrStatus.Message}) - } else { - opt.logger.Debug(fmt.Sprintf("%s \"%s\" failed: %v ", kind, name, getErr)) - return nil, getErr - } - } - return rows, nil -} - -func uninstall(ctx context.Context, opt *deleteOptions) error { - - kubeObjects, err := KubeObjectsFromTemplates(opt.templates, opt.templateValues, opt.matchPattern, opt.logger) - if err != nil { - return err - } - var kind, name string - var deleteError error - for _, obj := range kubeObjects { - kind, name, deleteError = kubeobj.DeleteObject(ctx, opt.kubeClientSet, obj, opt.namespace) - if deleteError == nil { - opt.logger.Debug(fmt.Sprintf("%s \"%s\" deleted", kind, name)) - } else if statusError, errIsStatusError := deleteError.(*errors.StatusError); errIsStatusError { - if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { - opt.logger.Debug(fmt.Sprintf("%s \"%s\" already exist", kind, name)) - } else if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound { - opt.logger.Debug(fmt.Sprintf("%s \"%s\" not found", kind, name)) - } else { - opt.logger.Error(fmt.Sprintf("%s \"%s\" failed: %v ", kind, name, statusError)) - return statusError - } - } else { - opt.logger.Error(fmt.Sprintf("%s \"%s\" failed: %v ", kind, name, deleteError)) - return deleteError - } - } - return nil -} - -func test(ctx context.Context, opt testOptions) error { - lgr := opt.logger - cs, err := opt.kubeBuilder.BuildClient() - if err != nil { - lgr.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return err - } - lgr.Debug("Running acceptance tests") - res, err := ensureClusterRequirements(ctx, cs, opt.validationRequest, lgr) - if err != nil { - return err - } - return handleValidationResult(res, lgr) -} diff --git a/venonactl/pkg/plugins/runtime-attach.go b/venonactl/pkg/plugins/runtime-attach.go deleted file mode 100644 index ffc39703..00000000 --- a/venonactl/pkg/plugins/runtime-attach.go +++ /dev/null @@ -1,378 +0,0 @@ -package plugins - -import ( - "context" - "encoding/base64" - "fmt" - "strings" - "time" - - "github.com/codefresh-io/venona/venonactl/pkg/logger" - templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" - "gopkg.in/yaml.v2" - v1 "k8s.io/api/core/v1" - kerrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes" -) - -type runtimeAttachPlugin struct { - logger logger.Logger -} - -type RuntimeConfiguration struct { - Crt string `yaml:"crt"` - Token string `yaml:"token"` - Host string `yaml:"host"` - Name string `yaml:"name"` - Type string `yaml:"type"` -} - -type venonaConf struct { - Runtimes map[string]RuntimeConfiguration `yaml:"runtimes,omitempty"` -} - -const ( - runtimeAttachFilesPattern = ".*.runtime-attach.yaml" - runtimeSecretName = "runnerconf" -) - -func (u *runtimeAttachPlugin) buildRuntimeConfig(ctx context.Context, opt *InstallOptions, v Values) (RuntimeConfiguration, error) { - config, err := opt.KubeBuilder.BuildConfig() - if err != nil { - return RuntimeConfiguration{}, fmt.Errorf("Failed to get client config on runtime cluster: %v", err) - } - - cs, err := opt.KubeBuilder.BuildClient() - if err != nil { - return RuntimeConfiguration{}, fmt.Errorf("Failed to create client on runtime cluster: %v", err) - } - err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) - if err != nil { - return RuntimeConfiguration{}, fmt.Errorf("Failed to ensure namespace on runtime cluster: %v", err) - } - - secret, err := u.generateServiceAccountSecret(ctx, cs, opt.RuntimeNamespace, opt.RuntimeServiceAccount) - if err != nil { - return RuntimeConfiguration{}, fmt.Errorf("Failed to get secret from service account %s on runtime cluster: %v", - opt.RuntimeServiceAccount, err) - } - - crt := secret.Data["ca.crt"] - token := secret.Data["token"] - - host := config.Host - if opt.ClusterHost != "" { - host = opt.ClusterHost - } - - rc := RuntimeConfiguration{ - Crt: string(crt), - Token: string(token), - Host: host, - Name: opt.RuntimeEnvironment, - Type: "runtime", - } - - return rc, nil -} - -func (u *runtimeAttachPlugin) generateServiceAccountSecret(ctx context.Context, client kubernetes.Interface, namespace, saName string) (*v1.Secret, error) { - secret := &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: fmt.Sprintf("%s-token-", saName), - Annotations: map[string]string{ - "kubernetes.io/service-account.name": saName, - }, - }, - Type: v1.SecretTypeServiceAccountToken, - } - - u.logger.Debug("Creating secret for service-account token", "service-account", saName) - - secret, err := client.CoreV1().Secrets(namespace).Create(ctx, secret, metav1.CreateOptions{}) - if err != nil { - return nil, fmt.Errorf("failed to create service-account token secret: %w", err) - } - secretName := secret.Name - - u.logger.Debug("Created secret for service-account token", "service-account", saName, "secret", secret.Name) - - patch := []byte(fmt.Sprintf("{\"secrets\": [{\"name\": \"%s\"}]}", secretName)) - _, err = client.CoreV1().ServiceAccounts(namespace).Patch(ctx, saName, types.StrategicMergePatchType, patch, metav1.PatchOptions{}) - if err != nil { - return nil, fmt.Errorf("failed to patch service-account with new secret: %w", err) - } - - u.logger.Debug("Added secret to service-account secrets", "service-account", saName, "secret", secret.Name) - - // try to read the token from the secret - ticker := time.NewTicker(time.Second) - retries := 15 - defer ticker.Stop() - - for try := 0; try < retries; try++ { - select { - case <-ticker.C: - secret, err = client.CoreV1().Secrets(namespace).Get(ctx, secretName, metav1.GetOptions{}) - case <-ctx.Done(): - return nil, ctx.Err() - } - - u.logger.Debug("Checking secret for service-account token", "service-account", saName, "secret", secret.Name) - - if err != nil { - return nil, fmt.Errorf("failed to get service-account secret: %w", err) - } - - if secret.Data == nil || len(secret.Data["token"]) == 0 { - u.logger.Debug("Secret is missing service-account token", "service-account", saName, "secret", secret.Name) - continue - } - - u.logger.Debug("Got service-account token from secret", "service-account", saName, "secret", secret.Name) - - return secret, nil - } - - return nil, fmt.Errorf("timed out waiting for secret to contain token") -} - -func readCurrentVenonaConf(ctx context.Context, agentKubeBuilder KubeClientBuilder, clusterNamespace string) (venonaConf, error) { - - cs, err := agentKubeBuilder.BuildClient() - if err != nil { - return venonaConf{}, fmt.Errorf("Failed to create client on venona cluster: %v", err) - } - secret, err := cs.CoreV1().Secrets(clusterNamespace).Get(ctx, runtimeSecretName, metav1.GetOptions{}) - if err != nil { - return venonaConf{}, fmt.Errorf("Failed to get %s secret: %v", runtimeSecretName, err) - } - - conf := &venonaConf{ - Runtimes: make(map[string]RuntimeConfiguration), - } - for k, v := range secret.Data { - cnf := RuntimeConfiguration{} - if err := yaml.Unmarshal(v, &cnf); err != nil { - return venonaConf{}, fmt.Errorf("Failed to unmarshal yaml with error: %s", err.Error()) - } - conf.Runtimes[k] = cnf - } - return *conf, nil - -} - -func (u *runtimeAttachPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { - if opt.DryRun { - return v, nil - } - cs, err := opt.AgentKubeBuilder.BuildClient() // on the agent cluster - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - err = opt.AgentKubeBuilder.EnsureNamespaceExists(ctx, cs) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) - return nil, err - } - - // read current venona conf - currentVenonaConf, err := readCurrentVenonaConf(ctx, opt.AgentKubeBuilder, opt.ClusterNamespace) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot read runnerconf: %v ", err)) - return nil, err - } - - // new runtime configuration - rc, err := u.buildRuntimeConfig(ctx, opt, v) - if err != nil { - return nil, err - } - if currentVenonaConf.Runtimes == nil { - currentVenonaConf.Runtimes = make(map[string]RuntimeConfiguration) - } - // normalize the key in the secret to make sure we are not violating kube naming conventions - name := strings.ReplaceAll(opt.RuntimeEnvironment, "/", ".") - name = strings.ReplaceAll(name, "@", ".") - name = strings.ReplaceAll(name, ":", ".") - currentVenonaConf.Runtimes[fmt.Sprintf("%s.runtime.yaml", name)] = rc - runtimes := map[string]string{} - for name, runtime := range currentVenonaConf.Runtimes { - // marshel prior persist - d, err := yaml.Marshal(runtime) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot marshal merged runnerconf: %v ", err)) - return nil, err - } - - runtimes[name] = base64.StdEncoding.EncodeToString([]byte(d)) - } - v["runnerConf"] = runtimes - v["Namespace"] = opt.ClusterNamespace - - cs.CoreV1().Secrets(opt.ClusterNamespace).Delete(ctx, runtimeSecretName, metav1.DeleteOptions{}) - - err = install(ctx, &installOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: opt.ClusterNamespace, - matchPattern: runtimeAttachFilesPattern, - operatorType: RuntimeAttachType, - dryRun: opt.DryRun, - }) - - if err != nil { - return nil, err - } - - if opt.RestartAgent { - list, err := cs.CoreV1().Pods(opt.ClusterNamespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("app=%v", v["AppName"])}) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot find agent pod: %v ", err)) - return nil, err - } - if (len(list.Items) == 0) { - u.logger.Debug("Agent pod not created yet. skipping restart...") - return v, nil - } - podName := list.Items[0].ObjectMeta.Name - err = cs.CoreV1().Pods(opt.ClusterNamespace).Delete(ctx, podName, metav1.DeleteOptions{}) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot delete agent pod: %v ", err)) - return nil, err - } - - ticker := time.NewTicker(5 * time.Second) - for { - select { - case <-ticker.C: - u.logger.Debug("Validating old runner pod termination") - _, err = cs.CoreV1().Pods(opt.ClusterNamespace).Get(ctx, podName, metav1.GetOptions{}) - if err != nil { - if statusError, errIsStatusError := err.(*kerrors.StatusError); errIsStatusError { - if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound { - return v, nil - } - } - } - case <-time.After(60 * time.Second): - u.logger.Error("Failed to validate old venona pod termination") - return v, fmt.Errorf("Failed to validate old venona pod termination") - } - } - } - - return v, nil - -} - -func (u *runtimeAttachPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { - - cs, err := statusOpt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - opt := &statusOptions{ - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: statusOpt.ClusterNamespace, - matchPattern: runtimeAttachFilesPattern, - operatorType: RuntimeAttachType, - logger: u.logger, - } - return status(ctx, opt) - -} - -func (u *runtimeAttachPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { - cs, err := deleteOpt.AgentKubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return err - } - // Delete the entry from runnerconf - if this is the only , delete the secret - - // read current venona conf - currentVenonaConf, err := readCurrentVenonaConf(ctx, deleteOpt.AgentKubeBuilder, deleteOpt.AgentNamespace) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot read runnerconf: %v ", err)) - return err - } - name := strings.ReplaceAll(deleteOpt.RuntimeEnvironment, "/", ".") - name = fmt.Sprintf("%s.runtime.yaml", name) - if _, ok := currentVenonaConf.Runtimes[name]; ok { - delete(currentVenonaConf.Runtimes, name) - } - - // If only one runtime is defined, remove the secret , otherwise remove the entry and persist - shouldDelete := true - if len(currentVenonaConf.Runtimes) > 0 { - - runtimes := map[string]string{} - for name, runtime := range currentVenonaConf.Runtimes { - // marshel prior persist - d, err := yaml.Marshal(runtime) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot marshal merged runnerconf: %v ", err)) - return err - } - - runtimes[name] = base64.StdEncoding.EncodeToString([]byte(d)) - } - - shouldDelete = false - v["runnerConf"] = runtimes - - cs.CoreV1().Secrets(deleteOpt.AgentNamespace).Delete(ctx, runtimeSecretName, metav1.DeleteOptions{}) - - err = install(ctx, &installOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: deleteOpt.AgentNamespace, - matchPattern: runtimeAttachFilesPattern, - operatorType: RuntimeAttachType, - }) - return err - - } - - if shouldDelete { - opt := &deleteOptions{ - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: deleteOpt.AgentNamespace, - matchPattern: runtimeAttachFilesPattern, - operatorType: RuntimeAttachType, - logger: u.logger, - } - return uninstall(ctx, opt) - } - return nil - -} - -func (u *runtimeAttachPlugin) Upgrade(_ context.Context, _ *UpgradeOptions, v Values) (Values, error) { - return v, nil -} - -func (u *runtimeAttachPlugin) Migrate(context.Context, *MigrateOptions, Values) error { - return fmt.Errorf("not supported") -} - -func (u *runtimeAttachPlugin) Test(context.Context, *TestOptions, Values) error { - return nil -} - -func (u *runtimeAttachPlugin) Name() string { - return RuntimeAttachType -} diff --git a/venonactl/pkg/plugins/runtime-environment.go b/venonactl/pkg/plugins/runtime-environment.go deleted file mode 100644 index 75d2fafc..00000000 --- a/venonactl/pkg/plugins/runtime-environment.go +++ /dev/null @@ -1,204 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package plugins - -import ( - "context" - "encoding/base64" - "fmt" - - "github.com/codefresh-io/venona/venonactl/pkg/codefresh" - "github.com/codefresh-io/venona/venonactl/pkg/logger" - templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" -) - -// runtimeEnvironmentPlugin installs assets on Kubernetes Dind runtimectl Env -type runtimeEnvironmentPlugin struct { - logger logger.Logger -} - -const ( - runtimeEnvironmentFilesPattern = ".*.re.yaml" -) - -// Install runtimectl environment -func (u *runtimeEnvironmentPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { - cs, err := opt.KubeBuilder.BuildClient() - if err != nil { - return nil, fmt.Errorf("Cannot create kubernetes clientset: %v ", err) - } - - err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) - return nil, err - } - - cfOpt := &codefresh.APIOptions{ - Logger: u.logger, - CodefreshHost: opt.CodefreshHost, - CodefreshToken: opt.CodefreshToken, - ClusterName: opt.ClusterName, - RegisterWithAgent: opt.RegisterWithAgent, - ClusterNamespace: opt.ClusterNamespace, - MarkAsDefault: opt.MarkAsDefault, - StorageClass: opt.StorageClass, - IsDefaultStorageClass: opt.IsDefaultStorageClass, - BuildNodeSelector: opt.BuildNodeSelector, - Annotations: opt.Annotations, - Insecure: opt.Insecure, - } - - // Set storage Class by backend - if cfOpt.IsDefaultStorageClass { - storageParams := v["Storage"].(map[string]interface{}) - cfOpt.StorageClass = storageParams["StorageClassName"].(string) - } - - cf := codefresh.NewCodefreshAPI(cfOpt) - cert, err := cf.Sign() - if err != nil { - return nil, err - } - v["ServerCert"] = map[string]string{ - "Cert": base64.StdEncoding.EncodeToString([]byte(cert.Cert)), - "Key": base64.StdEncoding.EncodeToString([]byte(cert.Key)), - "Ca": base64.StdEncoding.EncodeToString([]byte(cert.Ca)), - } - - if err := cf.Validate(); err != nil { - return nil, err - } - - v["RuntimeEnvironment"] = opt.RuntimeEnvironment - err = install(ctx, &installOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: opt.ClusterNamespace, - matchPattern: runtimeEnvironmentFilesPattern, - operatorType: RuntimeEnvironmentPluginType, - dryRun: opt.DryRun, - }) - if err != nil { - return nil, err - } - - return v, nil -} - -func (u *runtimeEnvironmentPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { - cs, err := statusOpt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - opt := &statusOptions{ - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: statusOpt.ClusterNamespace, - matchPattern: runtimeEnvironmentFilesPattern, - operatorType: RuntimeEnvironmentPluginType, - logger: u.logger, - } - return status(ctx, opt) -} - -func (u *runtimeEnvironmentPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { - cs, err := deleteOpt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return err - } - opt := &deleteOptions{ - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: deleteOpt.ClusterNamespace, - matchPattern: runtimeEnvironmentFilesPattern, - operatorType: RuntimeEnvironmentPluginType, - logger: u.logger, - } - return uninstall(ctx, opt) -} - -func (u *runtimeEnvironmentPlugin) Upgrade(_ context.Context, _ *UpgradeOptions, v Values) (Values, error) { - return v, nil -} - -func (u *runtimeEnvironmentPlugin) Migrate(ctx context.Context, opt *MigrateOptions, v Values) error { - return u.Delete(ctx, &DeleteOptions{ - ClusterNamespace: opt.ClusterNamespace, - KubeBuilder: opt.KubeBuilder, - }, v) -} - -func (u *runtimeEnvironmentPlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { - validationRequest := validationRequest{ - rbac: []rbacValidation{ - { - Resource: "ServiceAccount", - Verbs: []string{"create", "delete"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "ConfigMap", - Verbs: []string{"create", "update", "delete"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "Service", - Verbs: []string{"create", "update", "delete"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "Role", - Group: "rbac.authorization.k8s.io", - Verbs: []string{"create", "update", "delete"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "RoleBinding", - Group: "rbac.authorization.k8s.io", - Verbs: []string{"create", "update", "delete"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "persistentvolumeclaims", - Namespace: opt.ClusterNamespace, - Verbs: []string{"create", "update", "delete"}, - }, - { - Resource: "pods", - Namespace: opt.ClusterNamespace, - Verbs: []string{"create", "update", "delete"}, - }, - }, - } - return test(ctx, testOptions{ - logger: u.logger, - kubeBuilder: opt.KubeBuilder, - namespace: opt.ClusterNamespace, - validationRequest: validationRequest, - }) -} - -func (u *runtimeEnvironmentPlugin) Name() string { - return RuntimeEnvironmentPluginType -} diff --git a/venonactl/pkg/plugins/types.go b/venonactl/pkg/plugins/types.go deleted file mode 100644 index 5f03b2e3..00000000 --- a/venonactl/pkg/plugins/types.go +++ /dev/null @@ -1,30 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package plugins - -const ( - // AppName - app name for config - AppName = "runner" - - // TypeKubernetesDind - name for Kubernetes Dind runtimectl - TypeKubernetesDind = "kubernetesDind" - //typeDockerd = "dockerd" - - // StatusInstalled - status installed - StatusInstalled = "Installed" - // StatusNotInstalled - status installed - StatusNotInstalled = "Not Installed" -) diff --git a/venonactl/pkg/plugins/venona.go b/venonactl/pkg/plugins/venona.go deleted file mode 100644 index 8fd4b83a..00000000 --- a/venonactl/pkg/plugins/venona.go +++ /dev/null @@ -1,379 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package plugins - -import ( - "context" - "encoding/json" - "fmt" - "os" - "time" - - "github.com/codefresh-io/go-sdk/pkg/codefresh" - "github.com/codefresh-io/venona/venonactl/pkg/logger" - "github.com/codefresh-io/venona/venonactl/pkg/obj/kubeobj" - templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" - v1 "k8s.io/api/core/v1" - kerrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -// venonaPlugin installs assets on Kubernetes Dind runtimectl Env -type venonaPlugin struct { - logger logger.Logger -} - -type migrationData struct { - NodeSelector map[string]string `json:"nodeSelector,omitempty"` - Tolerations []v1.Toleration `json:"tolerations,omitempty"` - Env map[string]string `json:"env,omitempty"` -} - -const ( - venonaFilesPattern = ".*.venona.yaml" -) - -// Install venona agent -func (u *venonaPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { - if v["AgentToken"] == "" { - u.logger.Debug("Generating token for agent") - tokenName := fmt.Sprintf("generated-%s", time.Now().Format("20060102150405")) - u.logger.Debug(fmt.Sprintf("Token candidate name: %s", tokenName)) - - client := codefresh.New(&codefresh.ClientOptions{ - Auth: codefresh.AuthOptions{ - Token: opt.CodefreshToken, - }, - Host: opt.CodefreshHost, - }) - - token, err := client.Tokens().Create(tokenName, v["RuntimeEnvironment"].(string)) - if err != nil { - return nil, err - } - u.logger.Debug("Token created") - v["AgentToken"] = token.Value - if err != nil { - return nil, err - } - } - - cs, err := opt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) - return nil, err - } - - return v, install(ctx, &installOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: opt.ClusterNamespace, - matchPattern: venonaFilesPattern, - dryRun: opt.DryRun, - operatorType: VenonaPluginType, - }) -} - -// Status of runtimectl environment -func (u *venonaPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { - cs, err := statusOpt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - opt := &statusOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: statusOpt.ClusterNamespace, - matchPattern: venonaFilesPattern, - operatorType: VenonaPluginType, - } - return status(ctx, opt) -} - -func (u *venonaPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { - cs, err := deleteOpt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil - } - opt := &deleteOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: deleteOpt.ClusterNamespace, - matchPattern: venonaFilesPattern, - operatorType: VenonaPluginType, - } - return uninstall(ctx, opt) -} - -func (u *venonaPlugin) Upgrade(ctx context.Context, opt *UpgradeOptions, v Values) (Values, error) { - - // replace of sa creates new secert with sa creds - // avoid it till patch fully implemented - var skipUpgradeFor = map[string]interface{}{ - "service-account.venona.yaml": nil, - "deployment.venona.yaml": nil, - "venonaconf.secret.venona.yaml": nil, - } - - var deletePriorUpgrade = map[string]interface{}{ - "deployment.venona.yaml": nil, - } - - var err error - - kubeClientset, err := opt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - - // special case when we need to get the token from the remote to no regenrate it - // whole flow should be more like kubectl apply that build a patch - // based on remote object and candidate object - - secret, err := kubeClientset.CoreV1().Secrets(opt.ClusterNamespace).Get(ctx, opt.Name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - token := string(secret.Data["codefresh.token"]) - v["AgentToken"] = token - - kubeObjects, err := getKubeObjectsFromTempalte(v, venonaFilesPattern, u.logger) - if err != nil { - return nil, err - } - v, err = updateValuesBasedOnPreviousDeployment(ctx, opt.ClusterNamespace, kubeClientset, v) - - for fileName, local := range kubeObjects { - if _, ok := deletePriorUpgrade[fileName]; ok { - u.logger.Debug(fmt.Sprintf("Deleting previous deplopyment of %s", fileName)) - delOpt := &deleteOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: kubeClientset, - namespace: opt.ClusterNamespace, - matchPattern: fileName, - operatorType: VenonaPluginType, - } - err := uninstall(ctx, delOpt) - if err != nil { - return nil, err - } - installOpt := &installOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: kubeClientset, - namespace: opt.ClusterNamespace, - matchPattern: fileName, - operatorType: VenonaPluginType, - } - err = install(ctx, installOpt) - if err != nil { - return nil, err - } - } - - if _, ok := skipUpgradeFor[fileName]; ok { - u.logger.Debug(fmt.Sprintf("Skipping upgrade of %s: should be ignored", fileName)) - continue - } - - _, _, err := kubeobj.ReplaceObject(ctx, kubeClientset, local, opt.ClusterNamespace) - if err != nil { - return nil, err - } - } - - return v, nil -} - -func updateValuesBasedOnPreviousDeployment(ctx context.Context, ns string, kubeClientset *kubernetes.Clientset, v Values) (Values, error) { - - runnerDeployment, err := kubeClientset.AppsV1().Deployments(ns).Get(ctx, AppName, metav1.GetOptions{}) - if err != nil { - return nil, err - } - // Update the values with existing deployment values - if runnerDeployment.Spec.Template.Spec.NodeSelector != nil { - - } - if runnerDeployment.Spec.Template.Spec.NodeSelector != nil { - v["NodeSelector"] = nodeSelectorToString(runnerDeployment.Spec.Template.Spec.NodeSelector) - } - if runnerDeployment.Spec.Template.Spec.Tolerations != nil { - v["Tolerations"] = tolerationsToSring(runnerDeployment.Spec.Template.Spec.Tolerations) - } - - for _, envVar := range runnerDeployment.Spec.Template.Spec.Containers[0].Env { - if envVar.Name == "DOCKER_REGISTRY" { - v["DockerRegistry"] = envVar.Value - } else if envVar.Name == "AGENT_ID" { - v["AgentId"] = envVar.Value - } - } - - v["AdditionalEnvVars"] = getEnvVarsFromDeployment(runnerDeployment.Spec.Template.Spec.Containers) - return v, nil - -} - -func getEnvVarsFromDeployment(containers []v1.Container) map[string]string { - // Get env for containers - preDefinedEnvVars := map[string]interface{}{} - newEnvVars := map[string]string{} - preDefinedEnvVars["SELF_DEPLOYMENT_NAME"] = "SELF_DEPLOYMENT_NAME" - preDefinedEnvVars["CODEFRESH_TOKEN"] = "CODEFRESH_TOKEN" - preDefinedEnvVars["CODEFRESH_HOST"] = "CODEFRESH_HOST" - preDefinedEnvVars["AGENT_MODE"] = "AGENT_MODE" - preDefinedEnvVars["AGENT_NAME"] = "AGENT_NAME" - preDefinedEnvVars["AGENT_ID"] = "AGENT_ID" - preDefinedEnvVars["VENONA_CONFIG_DIR"] = "VENONA_CONFIG_DIR" - - for _, container := range containers { - for _, envVar := range container.Env { - if preDefinedEnvVars[envVar.Name] == nil { - newEnvVars[envVar.Name] = envVar.Value - } - } - } - return newEnvVars -} - -func (u *venonaPlugin) Migrate(ctx context.Context, opt *MigrateOptions, v Values) error { - var deletePriorUpgrade = map[string]interface{}{ - "deployment.venona.yaml": nil, - "secret.venona.yaml": nil, - } - - kubeClientset, err := opt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return err - } - kubeObjects, err := getKubeObjectsFromTempalte(v, venonaFilesPattern, u.logger) - if err != nil { - return err - } - list, err := kubeClientset.CoreV1().Pods(opt.ClusterNamespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("app=%v", v["AppName"])}) - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot find agent pod: %v ", err)) - return err - } - if len(list.Items) == 0 { - u.logger.Debug("Runner pod not found , existing migration") - return nil - } - migrationData := migrationData{ - Tolerations: list.Items[0].Spec.Tolerations, - NodeSelector: list.Items[0].Spec.NodeSelector, - Env: getEnvVarsFromDeployment(list.Items[0].Spec.Containers), - } - var jsonData []byte - jsonData, err = json.Marshal(migrationData) - err = os.WriteFile("migration.json", jsonData, 0644) - if err != nil { - u.logger.Error("Cannot write migration json") - } - - podName := list.Items[0].ObjectMeta.Name - for fileName := range kubeObjects { - if _, ok := deletePriorUpgrade[fileName]; ok { - u.logger.Debug(fmt.Sprintf("Deleting previous deplopyment of %s", fileName)) - delOpt := &deleteOptions{ - logger: u.logger, - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: kubeClientset, - namespace: opt.ClusterNamespace, - matchPattern: fileName, - operatorType: VenonaPluginType, - } - err := uninstall(ctx, delOpt) - if err != nil { - return err - } - } - } - ticker := time.NewTicker(5 * time.Second) - for { - select { - case <-ticker.C: - u.logger.Debug("Validating old runner pod termination") - _, err = kubeClientset.CoreV1().Pods(opt.ClusterNamespace).Get(ctx, podName, metav1.GetOptions{}) - if err != nil { - if statusError, errIsStatusError := err.(*kerrors.StatusError); errIsStatusError { - if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound { - return nil - } - } - } - case <-time.After(60 * time.Second): - u.logger.Error("Failed to validate old venona pod termination") - return fmt.Errorf("Failed to validate old venona pod termination") - } - } -} - -func (u *venonaPlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { - validationRequest := validationRequest{ - cpu: "500m", - momorySize: "1Gi", - rbac: []rbacValidation{ - { - Resource: "deployment", - Verbs: []string{"create", "update", "delete"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "secret", - Verbs: []string{"create", "update", "delete"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "ClusterRoleBinding", - Group: "rbac.authorization.k8s.io", - Verbs: []string{"create", "update", "delete"}, - }, - }, - } - return test(ctx, testOptions{ - logger: u.logger, - kubeBuilder: opt.KubeBuilder, - namespace: opt.ClusterNamespace, - validationRequest: validationRequest, - }) -} - -func (u *venonaPlugin) Name() string { - return VenonaPluginType -} diff --git a/venonactl/pkg/plugins/volume-provisioner.go b/venonactl/pkg/plugins/volume-provisioner.go deleted file mode 100644 index 9194de30..00000000 --- a/venonactl/pkg/plugins/volume-provisioner.go +++ /dev/null @@ -1,195 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package plugins - -import ( - "context" - "fmt" - - "github.com/codefresh-io/venona/venonactl/pkg/logger" - "github.com/codefresh-io/venona/venonactl/pkg/obj/kubeobj" - templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" -) - -// volumeProvisionerPlugin installs assets on Kubernetes Dind runtimectl Env -type volumeProvisionerPlugin struct { - logger logger.Logger -} - -const ( - volumeProvisionerFilesPattern = ".*.vp.yaml" -) - -// Install runtimectl environment -func (u *volumeProvisionerPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { - cs, err := opt.KubeBuilder.BuildClient() - if err != nil { - return nil, fmt.Errorf("Cannot create kubernetes clientset: %v", err) - } - return v, install(ctx, &installOptions{ - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - namespace: opt.ClusterNamespace, - matchPattern: volumeProvisionerFilesPattern, - dryRun: opt.DryRun, - operatorType: VolumeProvisionerPluginType, - logger: u.logger, - }) -} - -func (u *volumeProvisionerPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { - cs, err := statusOpt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - opt := &statusOptions{ - templates: templates.TemplatesMap(), - templateValues: v, - kubeClientSet: cs, - logger: u.logger, - namespace: statusOpt.ClusterNamespace, - matchPattern: volumeProvisionerFilesPattern, - operatorType: VolumeProvisionerPluginType, - } - return status(ctx, opt) -} - -func (u *volumeProvisionerPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { - cs, err := deleteOpt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return err - } - opt := &deleteOptions{ - templates: templates.TemplatesMap(), - templateValues: v, - logger: u.logger, - kubeClientSet: cs, - namespace: deleteOpt.ClusterNamespace, - matchPattern: volumeProvisionerFilesPattern, - operatorType: VolumeProvisionerPluginType, - } - return uninstall(ctx, opt) -} - -func (u *volumeProvisionerPlugin) Upgrade(ctx context.Context, opt *UpgradeOptions, v Values) (Values, error) { - var err error - kubeClientset, err := opt.KubeBuilder.BuildClient() - if err != nil { - u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) - return nil, err - } - kubeObjects, err := getKubeObjectsFromTempalte(v, volumeProvisionerFilesPattern, u.logger) - if err != nil { - return nil, err - } - for _, local := range kubeObjects { - - _, _, err := kubeobj.ReplaceObject(ctx, kubeClientset, local, opt.ClusterNamespace) - if err != nil { - return nil, err - } - } - return v, nil - -} -func (u *volumeProvisionerPlugin) Migrate(ctx context.Context, opt *MigrateOptions, v Values) error { - return u.Delete(ctx, &DeleteOptions{ - ClusterNamespace: opt.ClusterNamespace, - KubeBuilder: opt.KubeBuilder, - }, v) -} - -func (u *volumeProvisionerPlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { - validationRequest := validationRequest{ - rbac: []rbacValidation{ - { - Resource: "persistentvolumes", - Verbs: []string{"get", "list", "watch", "create", "delete", "patch"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "persistentvolumeclaims", - Verbs: []string{"get", "list", "watch", "update"}, - }, - { - Resource: "storageclasses", - Group: "storage.k8s.io", - Verbs: []string{"get", "list", "watch"}, - }, - { - Resource: "events", - Group: "", - Verbs: []string{"list", "watch", "create", "update", "patch"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "secrets", - Group: "", - Verbs: []string{"get", "list"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "nodes", - Group: "", - Verbs: []string{"get", "list", "watch"}, - }, - { - Resource: "pods", - Group: "", - Verbs: []string{"get", "list", "watch", "create", "delete", "patch"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "endpoints", - Group: "", - Verbs: []string{"get", "list", "watch", "create", "update", "delete"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "DaemonSet", - Group: "", - Verbs: []string{"get", "create", "update", "delete"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "CronJob", - Group: "batch", - Verbs: []string{"get", "create", "update", "delete"}, - Namespace: opt.ClusterNamespace, - }, - { - Resource: "ServiceAccount", - Group: "", - Verbs: []string{"get", "create", "update", "delete"}, - Namespace: opt.ClusterNamespace, - }, - }, - } - return test(ctx, testOptions{ - logger: u.logger, - kubeBuilder: opt.KubeBuilder, - namespace: opt.ClusterNamespace, - validationRequest: validationRequest, - }) -} - -func (u *volumeProvisionerPlugin) Name() string { - return VolumeProvisionerPluginType -} diff --git a/venonactl/pkg/store/store.go b/venonactl/pkg/store/store.go deleted file mode 100644 index 257c5643..00000000 --- a/venonactl/pkg/store/store.go +++ /dev/null @@ -1,232 +0,0 @@ -package store - -import ( - "fmt" - - "github.com/codefresh-io/go-sdk/pkg/codefresh" - "github.com/codefresh-io/venona/venonactl/pkg/certs" - k8sApi "k8s.io/api/core/v1" -) - -const ( - ModeInCluster = "InCluster" - ApplicationName = "runner" - MonitorApplicationName = "monitor" - AppProxyApplicationName = "app-proxy" - EngineAppName = "codefresh-engine" - NetworkTesterName = "cf-venona-network-tester" -) - -var ( - store *Values -) - -type ( - Values struct { - AppName string - - Mode string - Image *Image - DockerRegistry string - AgentToken string - - ServerCert *certs.ServerCert - - CodefreshAPI *CodefreshAPI - - KubernetesAPI *KubernetesAPI - - Runner Runner - - VolumeProvisioner VolumeProvisioner - - LocalVolumeMonitor LocalVolumeMonitor - - Monitor Monitor - - AppProxy AppProxy - - AgentAPI *AgentAPI - - ClusterInCodefresh string - - DryRun bool - - Verbose bool - - Insecure bool - - RuntimeEnvironment string - - Version *Version - - ClusterId string - - Helm3 bool - - // need for define if monitor use cluster role or just role - UseNamespaceWithRole bool - - AdditionalEnvVars map[string]string - } - - KubernetesAPI struct { - ConfigPath string - Namespace string - ContextName string - InCluster bool - NodeSelector string - Tolerations []k8sApi.Toleration - } - - CodefreshAPI struct { - Host string - Token string - Client codefresh.Codefresh - BuildNodeSelector map[string]string - } - - AgentAPI struct { - Token string - Id string - } - - Image struct { - Name string - Tag string - } - - Version struct { - Current *CurrentVersion - } - - CurrentVersion struct { - Version string - Commit string - Date string - } - - Runner struct { - Resources map[string]interface{} - } - VolumeProvisioner struct { - Resources map[string]interface{} - } - - LocalVolumeMonitor struct { - Resources map[string]interface{} - } - Monitor struct { - Resources map[string]interface{} - } - AppProxy struct { - Resources map[string]interface{} - } -) - -func GetStore() *Values { - if store == nil { - store = &Values{} - return store - } - return store -} - -func (s *Values) BuildValues() map[string]interface{} { - return map[string]interface{}{ - "AppName": ApplicationName, - "ClusterId": s.ClusterId, - "Version": s.Version.Current.Version, - "CodefreshHost": s.CodefreshAPI.Host, - "Token": s.CodefreshAPI.Token, - "Mode": ModeInCluster, - "Verbose": s.Verbose, - "Insecure": s.Insecure, - "Image": map[string]string{ - "Name": "codefresh/venona", - "Tag": s.Version.Current.Version, - }, - "AdditionalEnvVars": s.AdditionalEnvVars, - "Namespace": s.KubernetesAPI.Namespace, - "ConfigPath": s.KubernetesAPI.ConfigPath, - "Context": s.KubernetesAPI.ContextName, - "NodeSelector": s.KubernetesAPI.NodeSelector, - "DockerRegistry": s.DockerRegistry, - "Tolerations": s.KubernetesAPI.Tolerations, - "AgentToken": s.AgentAPI.Token, - "AgentId": s.AgentAPI.Id, - "ServerCert": map[string]string{ - "Cert": "", - "Key": "", - "Ca": "", - }, - "Runner": map[string]interface{}{ - "Resources": s.Runner.Resources, - }, - "CreateRbac": true, - "Storage": map[string]interface{}{ - "Backend": "local", - "CreateStorageClass": true, - "StorageClassName": fmt.Sprintf("dind-local-volumes-%s-%s", ApplicationName, s.KubernetesAPI.Namespace), - "LocalVolumeParentDir": "/var/lib/codefresh/dind-volumes", - "AvailabilityZone": "", - "GoogleServiceAccount": "", - "AwsAccessKeyId": "", - "AwsSecretAccessKey": "", - "VolumeProvisioner": map[string]interface{}{ - "Image": "codefresh/dind-volume-provisioner:1.34.3", - "NodeSelector": s.KubernetesAPI.NodeSelector, - "Resources": s.VolumeProvisioner.Resources, - "MountAzureJson": false, - }, - "LocalVolumeMonitor": map[string]interface{}{ - "Resources": s.LocalVolumeMonitor.Resources, - "Image": map[string]string{ - "Name": "codefresh/dind-volume-utils", - "Tag": "1.29.4", - }, - }, - "VolumeCleaner": map[string]interface{}{ - "Image": map[string]string{ - "Name": "codefresh/dind-volume-cleanup", - "Tag": "1.2.0", - }, - }, - }, - "Monitor": map[string]interface{}{ - "Enabled": true, - "UseNamespaceWithRole": s.UseNamespaceWithRole, - //TODO: need verify it on cluster level - "RbacEnabled": true, - "Helm3": s.Helm3, - "AppName": MonitorApplicationName, - "Image": map[string]string{ - "Name": "codefresh/cf-k8s-agent", - "Tag": "1.3.19", - }, - "Resources": s.Monitor.Resources, - }, - "AppProxy": map[string]interface{}{ - "AppName": AppProxyApplicationName, - "Image": map[string]string{ - "Name": "codefresh/cf-app-proxy", - "Tag": "latest", - }, - "Resources": s.AppProxy.Resources, - "Ingress": map[string]interface{}{ - "Host": "", - "IngressClass": "", - }, - }, - "Runtime": map[string]interface{}{ - "EngineAppName": EngineAppName, - }, - "NetworkTester": map[string]interface{}{ - "PodName": NetworkTesterName, - "Image": map[string]string{ - "Name": "codefresh/cf-venona-network-tester", - "Tag": "latest", - }, - }, - } -} diff --git a/venonactl/pkg/templates/generate_template.go b/venonactl/pkg/templates/generate_template.go deleted file mode 100644 index 5483a774..00000000 --- a/venonactl/pkg/templates/generate_template.go +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "fmt" - "os" - "path" - "path/filepath" - "runtime" - "strings" - "text/template" -) - -/* -for usage in -\\go:generate go run generate generate_template.go -reads all files in folder and appends them to template map -*/ - -var outfileBaseName = "templates.go" -var packageTemplate = template.Must(template.New("").Parse( - ` -// Code generated by go generate; DO NOT EDIT. -// using data from templates/{{ .FolderName }} -package {{ .PackageName }} - -func TemplatesMap() map[string]string { - templatesMap := make(map[string]string)` + - - "\n{{ range $key, $value := .TemplateFilesMap }}" + - "\ntemplatesMap[\"{{ $key }}\"] = `{{ $value }}` \n" + - "{{ end }}" + ` - return templatesMap -} -`)) - -type packageTempateData struct { - PackageName string - FolderName string - TemplateFilesMap map[string]string -} - -func main() { - if len(os.Args) < 2 { - fmt.Println("generate_template ERROR: missing folder name") - os.Exit(1) - } - - var currentFilePath string - if strings.Contains(os.Args[0], "/go-build") { - _, currentFilePath, _, _ = runtime.Caller(0) - } else { - currentFilePath = os.Args[0] - } - - currentDir := filepath.Dir(currentFilePath) - templatesDirParam := os.Args[1] - var folderName = path.Join(currentDir, templatesDirParam) - - // Fill Tempalte Map - templateFilesMap := make(map[string]string) - filepath.Walk(folderName, func(name string, info os.FileInfo, err error) error { - if !info.IsDir() && path.Base(name) != outfileBaseName { - b, _ := os.ReadFile(name) - templateFilesMap[filepath.Base(name)] = string(b) - } - return nil - }) - - if len(templateFilesMap) == 0 { - fmt.Printf("No files in %s\n", folderName) - } - - outfileName := path.Join(folderName, "templates.go") - outfile, err := os.Create(outfileName) - if err != nil { - fmt.Printf("generate_template ERROR: cannot create out file %s, %v \n", outfileName, err) - os.Exit(1) - } - defer outfile.Close() - - err = packageTemplate.Execute(outfile, packageTempateData{ - PackageName: path.Base(folderName), - FolderName: templatesDirParam, - TemplateFilesMap: templateFilesMap, - }) - if err != nil { - fmt.Printf("generate_template ERROR: cannot generate template %v \n", err) - os.Exit(1) - } -} diff --git a/venonactl/pkg/templates/kubernetes/cluster-role-binding.app-proxy.yaml b/venonactl/pkg/templates/kubernetes/cluster-role-binding.app-proxy.yaml deleted file mode 100644 index c5430b55..00000000 --- a/venonactl/pkg/templates/kubernetes/cluster-role-binding.app-proxy.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{- if .CreateRbac }} -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .AppProxy.AppName }}-cluster-reader-{{ .Namespace }} -subjects: -- kind: ServiceAccount - name: {{ .AppProxy.AppName }} # this service account can get secrets cluster-wide (all namespaces) - namespace: {{ .Namespace }} -roleRef: - kind: ClusterRole - name: {{ .AppProxy.AppName }}-cluster-reader-{{ .Namespace }} - apiGroup: rbac.authorization.k8s.io -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/cluster-role-binding.dind-volume-provisioner.vp.yaml b/venonactl/pkg/templates/kubernetes/cluster-role-binding.dind-volume-provisioner.vp.yaml deleted file mode 100644 index 9f1dc576..00000000 --- a/venonactl/pkg/templates/kubernetes/cluster-role-binding.dind-volume-provisioner.vp.yaml +++ /dev/null @@ -1,17 +0,0 @@ -{{- if .CreateRbac }} ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: volume-provisioner-{{ .AppName }}-{{ .Namespace }} - labels: - app: dind-volume-provisioner-{{ .AppName }} -subjects: - - kind: ServiceAccount - name: volume-provisioner-{{ .AppName }} - namespace: {{ .Namespace }} -roleRef: - kind: ClusterRole - name: volume-provisioner-{{ .AppName }}-{{ .Namespace }} - apiGroup: rbac.authorization.k8s.io -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/cluster-role-binding.venona.yaml b/venonactl/pkg/templates/kubernetes/cluster-role-binding.venona.yaml deleted file mode 100644 index 7829fa38..00000000 --- a/venonactl/pkg/templates/kubernetes/cluster-role-binding.venona.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{- if .CreateRbac }} -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .AppName }}-{{ .Namespace }} -subjects: -- kind: ServiceAccount - name: {{ .AppName }} - namespace: {{ .Namespace }} -roleRef: - kind: ClusterRole - name: system:discovery - apiGroup: rbac.authorization.k8s.io -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/cluster-role.app-proxy.yaml b/venonactl/pkg/templates/kubernetes/cluster-role.app-proxy.yaml deleted file mode 100644 index 898e3363..00000000 --- a/venonactl/pkg/templates/kubernetes/cluster-role.app-proxy.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- if .CreateRbac }} -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .AppProxy.AppName }}-cluster-reader-{{ .Namespace }} - labels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} -rules: -- apiGroups: [""] - resources: ["secrets"] - verbs: ["get"] -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/cluster-role.dind-volume-provisioner.vp.yaml b/venonactl/pkg/templates/kubernetes/cluster-role.dind-volume-provisioner.vp.yaml deleted file mode 100644 index 3650435b..00000000 --- a/venonactl/pkg/templates/kubernetes/cluster-role.dind-volume-provisioner.vp.yaml +++ /dev/null @@ -1,36 +0,0 @@ -{{- if .CreateRbac }} -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: volume-provisioner-{{ .AppName }}-{{ .Namespace }} - labels: - app: dind-volume-provisioner -rules: - - apiGroups: [""] - resources: ["persistentvolumes"] - verbs: ["get", "list", "watch", "create", "delete", "patch"] - - apiGroups: [""] - resources: ["persistentvolumeclaims"] - verbs: ["get", "list", "watch", "update", "delete"] - - apiGroups: ["storage.k8s.io"] - resources: ["storageclasses"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["events"] - verbs: ["list", "watch", "create", "update", "patch"] - - apiGroups: [""] - resources: ["secrets"] - verbs: ["get", "list"] - - apiGroups: [""] - resources: ["nodes"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["pods"] - verbs: ["get", "list", "watch", "create", "delete", "patch"] - - apiGroups: [""] - resources: ["endpoints"] - verbs: ["get", "list", "watch", "create", "update", "delete"] - - apiGroups: ["coordination.k8s.io"] - resources: ["leases"] - verbs: ["get", "create", "update"] -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/codefresh-certs-server-secret.re.yaml b/venonactl/pkg/templates/kubernetes/codefresh-certs-server-secret.re.yaml deleted file mode 100644 index e9bbbbcd..00000000 --- a/venonactl/pkg/templates/kubernetes/codefresh-certs-server-secret.re.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -type: Opaque -kind: Secret -metadata: - labels: - app: venona - name: codefresh-certs-server - namespace: {{ .Namespace }} -data: - server-cert.pem: {{ .ServerCert.Cert }} - server-key.pem: {{ .ServerCert.Key }} - ca.pem: {{ .ServerCert.Ca }} - diff --git a/venonactl/pkg/templates/kubernetes/cron-job.dind-volume-cleanup.vp.yaml b/venonactl/pkg/templates/kubernetes/cron-job.dind-volume-cleanup.vp.yaml deleted file mode 100644 index e837f877..00000000 --- a/venonactl/pkg/templates/kubernetes/cron-job.dind-volume-cleanup.vp.yaml +++ /dev/null @@ -1,31 +0,0 @@ -{{- if not (eq .Storage.Backend "local") }} -apiVersion: batch/v1beta1 -kind: CronJob -metadata: - name: dind-volume-cleanup-{{ .AppName }} - namespace: {{ .Namespace }} - labels: - app: dind-volume-cleanup -spec: - schedule: "0,10,20,30,40,50 * * * *" - concurrencyPolicy: Forbid - {{- if eq .Storage.Backend "local" }} - suspend: true - {{- end }} - jobTemplate: - spec: - template: - spec: - serviceAccountName: volume-provisioner-{{ .AppName }} - restartPolicy: Never - containers: - - name: dind-volume-cleanup - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Storage.VolumeCleaner.Image.Name }}:{{ .Storage.VolumeCleaner.Image.Tag }} {{- else }}{{- .Storage.VolumeCleaner.Image.Name }}:{{ .Storage.VolumeCleaner.Image.Tag }} {{- end}} - env: - - name: PROVISIONED_BY - value: codefresh.io/dind-volume-provisioner-{{ .AppName }}-{{ .Namespace }} - securityContext: - fsGroup: 3000 - runAsGroup: 3000 - runAsUser: 3000 -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/daemonset.dind-lv-monitor.vp.yaml b/venonactl/pkg/templates/kubernetes/daemonset.dind-lv-monitor.vp.yaml deleted file mode 100644 index 89d54abf..00000000 --- a/venonactl/pkg/templates/kubernetes/daemonset.dind-lv-monitor.vp.yaml +++ /dev/null @@ -1,87 +0,0 @@ -{{- if eq .Storage.Backend "local" -}} -{{- $localVolumeParentDir := ( .Storage.LocalVolumeParentDir | default "/var/lib/codefresh/dind-volumes" ) }} -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: dind-lv-monitor-{{ .AppName }} - namespace: {{ .Namespace }} - labels: - app: dind-lv-monitor -spec: - selector: - matchLabels: - app: dind-lv-monitor - template: - metadata: - labels: - app: dind-lv-monitor - annotations: - prometheus_port: "9100" - prometheus_scrape: "true" - spec: - serviceAccountName: volume-provisioner-{{ .AppName }} - tolerations: - - key: 'codefresh/dind' - operator: 'Exists' - effect: 'NoSchedule' - -{{ toYaml .Tolerations | indent 8 | unescape}} - securityContext: - fsGroup: 1000 - initContainers: - - command: - - chown - - -R - - 1000:1000 - - /var/lib/codefresh/dind-volumes - image: alpine - imagePullPolicy: Always - name: fs-change-owner - resources: {} - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - volumeMounts: - - mountPath: /var/lib/codefresh/dind-volumes - name: dind-volume-dir - containers: - - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Storage.LocalVolumeMonitor.Image.Name }}:{{ .Storage.LocalVolumeMonitor.Image.Tag }} {{- else }}{{- .Storage.LocalVolumeMonitor.Image.Name }}:{{ .Storage.LocalVolumeMonitor.Image.Tag }} {{- end}} - name: lv-cleaner - resources: -{{ toYaml .Storage.LocalVolumeMonitor.Resources | indent 10 }} - imagePullPolicy: Always - command: - - /home/dind-volume-utils/bin/local-volumes-agent - env: - {{- if $.EnvVars }} - {{- range $key, $value := $.EnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: VOLUME_PARENT_DIR - value: {{ $localVolumeParentDir }} -# Debug: -# - name: DRY_RUN -# value: "1" -# - name: DEBUG -# value: "1" -# - name: SLEEP_INTERVAL -# value: "3" -# - name: LOG_DF_EVERY -# value: "60" -# - name: KB_USAGE_THRESHOLD -# value: "20" - - volumeMounts: - - mountPath: {{ $localVolumeParentDir }} - readOnly: false - name: dind-volume-dir - volumes: - - name: dind-volume-dir - hostPath: - path: {{ $localVolumeParentDir }} -{{- end -}} diff --git a/venonactl/pkg/templates/kubernetes/deployment.app-proxy.yaml b/venonactl/pkg/templates/kubernetes/deployment.app-proxy.yaml deleted file mode 100644 index aa081683..00000000 --- a/venonactl/pkg/templates/kubernetes/deployment.app-proxy.yaml +++ /dev/null @@ -1,75 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} - name: {{ .AppProxy.AppName }} - namespace: {{ .Namespace }} -spec: - selector: - matchLabels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} - replicas: 1 - revisionHistoryLimit: 5 - strategy: - rollingUpdate: - maxSurge: 50% - maxUnavailable: 50% - type: RollingUpdate - template: - metadata: - labels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} - spec: - {{- if .CreateRbac }} - serviceAccountName: {{ .AppProxy.AppName }} - {{- end }} - containers: - - name: {{ .AppProxy.AppName }} - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .AppProxy.Image.Name }}:{{ .AppProxy.Image.Tag }} {{- else }} {{- .AppProxy.Image.Name }}:{{ .AppProxy.Image.Tag }} {{- end}} - imagePullPolicy: Always - resources: -{{ toYaml .AppProxy.resources | indent 10 }} - env: - {{- if $.EnvVars }} - {{- range $key, $value := $.EnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - {{- if $.AppProxy.AdditionalEnvVars }} - {{- range $key, $value := $.AppProxy.AdditionalEnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - - name: PORT - value: "3000" - - name: CODEFRESH_HOST - value: {{ .CodefreshHost }} - {{ if .AppProxy.Ingress.PathPrefix }} - - name: API_PATH_PREFIX - value: {{ .AppProxy.Ingress.PathPrefix }} - {{ end }} - {{- if .NewRelicLicense }} - - name: NEWRELIC_LICENSE_KEY - {{- if isString .NewRelicLicense }} - value: {{ .NewRelicLicense }} - {{- else }} -{{ toYaml .NewRelicLicense | indent 12 }} - {{- end }} - {{- end }} - ports: - - containerPort: 3000 - protocol: TCP - readinessProbe: - httpGet: - path: /health - port: 3000 - periodSeconds: 5 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 5 diff --git a/venonactl/pkg/templates/kubernetes/deployment.dind-volume-provisioner.vp.yaml b/venonactl/pkg/templates/kubernetes/deployment.dind-volume-provisioner.vp.yaml deleted file mode 100644 index 6550b68a..00000000 --- a/venonactl/pkg/templates/kubernetes/deployment.dind-volume-provisioner.vp.yaml +++ /dev/null @@ -1,123 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: dind-volume-provisioner-{{ .AppName }} - namespace: {{ .Namespace }} - labels: - app: dind-volume-provisioner -spec: - selector: - matchLabels: - app: dind-volume-provisioner - replicas: 1 - strategy: - type: Recreate - template: - metadata: - labels: - app: dind-volume-provisioner - spec: - {{ if .Storage.VolumeProvisioner.NodeSelector }} - nodeSelector: -{{ .Storage.VolumeProvisioner.NodeSelector | nodeSelectorParamToYaml | indent 8 | unescape}} - {{ end }} - serviceAccount: volume-provisioner-{{ .AppName }} - securityContext: - runAsUser: 3000 - runAsGroup: 3000 - fsGroup: 3000 - tolerations: - - effect: NoSchedule - key: node-role.kubernetes.io/master - operator: "Exists" - -{{ toYaml .Tolerations | indent 8 | unescape}} - - containers: - - name: dind-volume-provisioner - resources: -{{ toYaml .Storage.VolumeProvisioner.Resources | indent 10 }} - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Storage.VolumeProvisioner.Image }} {{- else }} {{- .Storage.VolumeProvisioner.Image }} {{- end}} - imagePullPolicy: Always - command: - - /usr/local/bin/dind-volume-provisioner - - -v=4 - - --resync-period=50s - env: - {{- if $.EnvVars }} - {{- range $key, $value := $.EnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - - name: PROVISIONER_NAME - value: codefresh.io/dind-volume-provisioner-{{ .AppName }}-{{ .Namespace }} - {{- if ne .DockerRegistry "" }} - - name: DOCKER_REGISTRY - value: {{ .DockerRegistry }} - {{- end }} - {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits }} - {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.CPU }} - - name: CREATE_DIND_LIMIT_CPU - value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.CPU }} - {{- end }} - {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.Memory }} - - name: CREATE_DIND_LIMIT_MEMORY - value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.Memory }} - {{- end }} - {{- end }} - {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests }} - {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.CPU }} - - name: CREATE_DIND_REQUESTS_CPU - value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.CPU }} - {{- end }} - {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.Memory }} - - name: CREATE_DIND_REQUESTS_MEMORY - value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.Memory }} - {{- end }} - {{- end }} - {{- if .Storage.AwsAccessKeyId }} - - name: AWS_ACCESS_KEY_ID - valueFrom: - secretKeyRef: - name: dind-volume-provisioner-{{ .AppName }} - key: aws_access_key_id - {{- end }} - {{- if .Storage.AwsSecretAccessKey }} - - name: AWS_SECRET_ACCESS_KEY - valueFrom: - secretKeyRef: - name: dind-volume-provisioner-{{ .AppName }} - key: aws_secret_access_key - {{- end }} - {{- if .Storage.GoogleServiceAccount }} - - name: GOOGLE_APPLICATION_CREDENTIALS - value: /etc/dind-volume-provisioner/credentials/google-service-account.json - {{- end }} - {{- if .Storage.VolumeProvisioner.MountAzureJson }} - - name: AZURE_CREDENTIAL_FILE - value: "/etc/kubernetes/azure.json" - {{- end }} - volumeMounts: - {{- if .Storage.VolumeProvisioner.MountAzureJson }} - - name: azure-json - readOnly: true - mountPath: "/etc/kubernetes/azure.json" - {{- end }} - {{- if .Storage.GoogleServiceAccount }} - - name: credentials - readOnly: true - mountPath: "/etc/dind-volume-provisioner/credentials" - {{- end }} - volumes: - {{- if .Storage.VolumeProvisioner.MountAzureJson }} - - name: azure-json - hostPath: - path: /etc/kubernetes/azure.json - type: File - {{- end }} - {{- if .Storage.GoogleServiceAccount }} - - name: credentials - secret: - secretName: dind-volume-provisioner-{{ .AppName }} - {{- end }} diff --git a/venonactl/pkg/templates/kubernetes/deployment.monitor.yaml b/venonactl/pkg/templates/kubernetes/deployment.monitor.yaml deleted file mode 100644 index 46690637..00000000 --- a/venonactl/pkg/templates/kubernetes/deployment.monitor.yaml +++ /dev/null @@ -1,81 +0,0 @@ -{{- if .Monitor.Enabled }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ .Monitor.AppName }} - namespace: {{ .Namespace }} - labels: - app: {{ .AppName }} - version: {{ .Version }} -spec: - replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 50% - maxSurge: 50% - selector: - matchLabels: - app: {{ .Monitor.AppName }} - template: - metadata: - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} - spec: - {{- if .Monitor.RbacEnabled}} - serviceAccountName: {{ .Monitor.AppName }} - {{- end }} - containers: - - name: {{ .Monitor.AppName }} - resources: -{{ toYaml .Monitor.resources | indent 10 }} - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Monitor.Image.Name }}:{{ .Monitor.Image.Tag }} {{- else }} {{- .Monitor.Image.Name }}:{{ .Monitor.Image.Tag }} {{- end}} - imagePullPolicy: Always - env: - {{- if $.EnvVars }} - {{- range $key, $value := $.EnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - {{- if $.Monitor.AdditionalEnvVars }} - {{- range $key, $value := $.Monitor.AdditionalEnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - - name: SERVICE_NAME - value: {{ .Monitor.AppName }} - {{- if .Monitor.UseNamespaceWithRole }} - - name: ROLE_BINDING - value: "true" - {{- end }} - - name: PORT - value: "9020" - - name: API_TOKEN - value: {{ .Token }} - - name: CLUSTER_ID - value: {{ .ClusterId }} - - name: API_URL - value: {{ .CodefreshHost }}/api/k8s-monitor/events - - name: ACCOUNT_ID - value: user - - name: HELM3 - value: "{{ .Monitor.Helm3 }}" - - name: NAMESPACE - value: "{{ .Namespace }}" - - name: NODE_OPTIONS - value: "--max_old_space_size=4096" - ports: - - containerPort: 9020 - protocol: TCP - readinessProbe: - httpGet: - path: /api/ping - port: 9020 - periodSeconds: 5 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 5 -{{- end }} diff --git a/venonactl/pkg/templates/kubernetes/deployment.venona.yaml b/venonactl/pkg/templates/kubernetes/deployment.venona.yaml deleted file mode 100644 index 7cb7c21f..00000000 --- a/venonactl/pkg/templates/kubernetes/deployment.venona.yaml +++ /dev/null @@ -1,106 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: {{ .AppName }} - version: {{ .Version }} - name: {{ .AppName }} - namespace: {{ .Namespace }} -spec: - selector: - matchLabels: - app: {{ .AppName }} - version: {{ .Version }} - replicas: 1 - revisionHistoryLimit: 5 - strategy: - rollingUpdate: - maxSurge: 50% - maxUnavailable: 50% - type: RollingUpdate - template: - metadata: - labels: - app: {{ .AppName }} - version: {{ .Version }} - spec: - volumes: - - name: runnerconf - secret: - secretName: runnerconf - {{ if ne .NodeSelector "" }} - nodeSelector: -{{ .NodeSelector | nodeSelectorParamToYaml | indent 8 | unescape }} - {{ end }} - tolerations: -{{ toYaml .Tolerations | indent 8 | unescape }} - containers: - - env: - {{- if $.EnvVars }} - {{- range $key, $value := $.EnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - {{- if $.AdditionalEnvVars }} - {{- range $key, $value := $.AdditionalEnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - - name: SELF_DEPLOYMENT_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: CODEFRESH_TOKEN - valueFrom: - secretKeyRef: - name: {{ .AppName }} - key: codefresh.token - - name: CODEFRESH_HOST - value: {{ .CodefreshHost }} - - name: AGENT_MODE - value: {{ .Mode }} - - name: AGENT_NAME - value: {{ .AppName }} - - name: "AGENT_ID" - value: {{ .AgentId }} - - name: VENONA_CONFIG_DIR - value: "/etc/secrets" - {{- if ne .DockerRegistry "" }} - - name: DOCKER_REGISTRY - value: {{ .DockerRegistry }} - {{- end }} - {{- if .NewRelicLicense }} - - name: NEWRELIC_LICENSE_KEY - {{- if isString .NewRelicLicense }} - value: {{ .NewRelicLicense }} - {{- else }} -{{ toYaml .NewRelicLicense | indent 10}} - {{- end }} - {{- end }} - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Image.Name }} {{- else }} {{- .Image.Name }}{{- end}}:{{ .Image.Tag | default "latest"}} - ports: - - containerPort: 8080 - protocol: TCP - readinessProbe: - httpGet: - path: /health - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 5 - volumeMounts: - - name: runnerconf - mountPath: "/etc/secrets" - readOnly: true - imagePullPolicy: Always - name: {{ .AppName }} - resources: -{{ toYaml .Runner.Resources | indent 10 }} - securityContext: - runAsUser: 10001 - runAsGroup: 10001 - fsGroup: 10001 - restartPolicy: Always diff --git a/venonactl/pkg/templates/kubernetes/dind-daemon-conf.re.yaml b/venonactl/pkg/templates/kubernetes/dind-daemon-conf.re.yaml deleted file mode 100644 index b3af9262..00000000 --- a/venonactl/pkg/templates/kubernetes/dind-daemon-conf.re.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: codefresh-dind-config - namespace: {{ .Namespace }} -data: - daemon.json: | - { - "hosts": [ "unix:///var/run/docker.sock", - "tcp://0.0.0.0:1300"], - "tlsverify": true, - "tls": true, - "tlscacert": "/etc/ssl/cf-client/ca.pem", - "tlscert": "/etc/ssl/cf/server-cert.pem", - "tlskey": "/etc/ssl/cf/server-key.pem", - "insecure-registries" : ["192.168.99.100:5000"], - "metrics-addr" : "0.0.0.0:9323", - "experimental" : true - } diff --git a/venonactl/pkg/templates/kubernetes/dind-headless-service.re.yaml b/venonactl/pkg/templates/kubernetes/dind-headless-service.re.yaml deleted file mode 100644 index 464bd35a..00000000 --- a/venonactl/pkg/templates/kubernetes/dind-headless-service.re.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: dind - name: dind - namespace: {{ .Namespace }} -spec: - ports: - - name: "dind-port" - port: 1300 - protocol: TCP - - # This is a headless service, Kubernetes won't assign a VIP for it. - # *.dind.default.svc.cluster.local - clusterIP: None - selector: - app: dind - diff --git a/venonactl/pkg/templates/kubernetes/ingress.app-proxy.yaml b/venonactl/pkg/templates/kubernetes/ingress.app-proxy.yaml deleted file mode 100644 index 69f11e53..00000000 --- a/venonactl/pkg/templates/kubernetes/ingress.app-proxy.yaml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - {{ range $key, $value := .AppProxy.Ingress.Annotations }} - {{ $key }}: {{ $value | quote | unescape }} - {{ end }} - name: app-proxy - namespace: {{ .Namespace }} -spec: - {{ if ne .AppProxy.Ingress.IngressClass "" }} - ingressClassName: {{ .AppProxy.Ingress.IngressClass }} - {{ end }} - rules: - - host: {{ .AppProxy.Ingress.Host }} - http: - paths: - - path: {{ if .AppProxy.Ingress.PathPrefix }}{{ .AppProxy.Ingress.PathPrefix }}{{ else }}'/'{{end}} - pathType: ImplementationSpecific - backend: - service: - name: app-proxy - port: - number: 80 - {{ if .AppProxy.Ingress.TLSSecret }} - tls: - - hosts: - - {{ .AppProxy.Ingress.Host }} - secretName: {{ .AppProxy.Ingress.TLSSecret }} - {{ end }} diff --git a/venonactl/pkg/templates/kubernetes/pod.network-tester.yaml b/venonactl/pkg/templates/kubernetes/pod.network-tester.yaml deleted file mode 100644 index 2789e18c..00000000 --- a/venonactl/pkg/templates/kubernetes/pod.network-tester.yaml +++ /dev/null @@ -1,44 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: {{ .NetworkTester.PodName }} - namespace: {{ .Namespace }} - labels: - app: {{ .AppName }} - version: {{ .Version }} -spec: - containers: - - name: {{ .NetworkTester.PodName }} - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .NetworkTester.Image.Name }}:{{ .NetworkTester.Image.Tag }} {{- else }} {{- .NetworkTester.Image.Name }}:{{ .NetworkTester.Image.Tag }} {{- end}} - imagePullPolicy: Always - restartPolicy: Never - resources: - limits: - cpu: 400m - memory: 500Mi - requests: - cpu: 200m - memory: 300Mi - env: - {{- if $.EnvVars }} - {{- range $key, $value := $.EnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - {{- if $.NetworkTester.AdditionalEnvVars }} - {{- range $key, $value := $.NetworkTester.AdditionalEnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - {{- if .Verbose }} - - name: DEBUG - value: '1' - {{- end }} - {{- if .Insecure }} - - name: INSECURE - value: '1' - {{- end }} - - name: IN_CLUSTER - value: '1' \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/role-binding.engine.yaml b/venonactl/pkg/templates/kubernetes/role-binding.engine.yaml deleted file mode 100644 index 0555f0d9..00000000 --- a/venonactl/pkg/templates/kubernetes/role-binding.engine.yaml +++ /dev/null @@ -1,15 +0,0 @@ -{{- if .CreateRbac }} -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .Runtime.EngineAppName }} - namespace: {{ .Namespace }} -subjects: -- kind: ServiceAccount - name: {{ .Runtime.EngineAppName }} - namespace: {{ .Namespace }} -roleRef: - kind: Role - name: {{ .Runtime.EngineAppName }} - apiGroup: rbac.authorization.k8s.io -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/role-binding.re.yaml b/venonactl/pkg/templates/kubernetes/role-binding.re.yaml deleted file mode 100644 index bb1c618c..00000000 --- a/venonactl/pkg/templates/kubernetes/role-binding.re.yaml +++ /dev/null @@ -1,15 +0,0 @@ -{{- if .CreateRbac }} -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .AppName }} - namespace: {{ .Namespace }} -subjects: -- kind: ServiceAccount - name: {{ .AppName }} - namespace: {{ .Namespace }} -roleRef: - kind: Role - name: {{ .AppName }} - apiGroup: rbac.authorization.k8s.io -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/role.engine.yaml b/venonactl/pkg/templates/kubernetes/role.engine.yaml deleted file mode 100644 index c662a93a..00000000 --- a/venonactl/pkg/templates/kubernetes/role.engine.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- if .CreateRbac }} -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .Runtime.EngineAppName }} - namespace: {{ .Namespace }} -rules: -- apiGroups: [""] - resources: ["secrets"] - verbs: ["get"] -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/role.monitor.yaml b/venonactl/pkg/templates/kubernetes/role.monitor.yaml deleted file mode 100644 index 0e33c320..00000000 --- a/venonactl/pkg/templates/kubernetes/role.monitor.yaml +++ /dev/null @@ -1,49 +0,0 @@ -{{- if .CreateRbac }} -{{- if and .Monitor.Enabled .Monitor.RbacEnabled }} -{{- if .Monitor.UseNamespaceWithRole }} -kind: Role -{{- else }} -kind: ClusterRole -{{- end }} -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .Monitor.AppName }}-cluster-reader - namespace: {{ .Namespace }} - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} -rules: -- apiGroups: - - "" - resources: ["*"] - verbs: - - get - - list - - watch - - create - - delete -- apiGroups: - - "" - resources: ["pods"] - verbs: - - get - - list - - watch - - create - - deletecollection -- apiGroups: - - extensions - resources: ["*"] - verbs: - - get - - list - - watch -- apiGroups: - - apps - resources: ["*"] - verbs: - - get - - list - - watch -{{- end }} -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/role.re.yaml b/venonactl/pkg/templates/kubernetes/role.re.yaml deleted file mode 100644 index cee35c57..00000000 --- a/venonactl/pkg/templates/kubernetes/role.re.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- if .CreateRbac }} -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .AppName }} - namespace: {{ .Namespace }} -rules: -- apiGroups: [""] - resources: ["pods", "persistentvolumeclaims"] - verbs: ["get", "create", "delete"] -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/rolebinding.monitor.yaml b/venonactl/pkg/templates/kubernetes/rolebinding.monitor.yaml deleted file mode 100644 index 755c03b1..00000000 --- a/venonactl/pkg/templates/kubernetes/rolebinding.monitor.yaml +++ /dev/null @@ -1,28 +0,0 @@ -{{- if .CreateRbac }} -{{- if and .Monitor.Enabled .Monitor.RbacEnabled }} -{{- if .Monitor.UseNamespaceWithRole }} -kind: RoleBinding -{{- else }} -kind: ClusterRoleBinding -{{- end }} -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .Monitor.AppName }}-cluster-reader - namespace: {{ .Namespace }} - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} -subjects: -- kind: ServiceAccount - namespace: {{ .Namespace }} - name: {{ .Monitor.AppName }} -roleRef: - apiGroup: rbac.authorization.k8s.io - {{- if .Monitor.UseNamespaceWithRole }} - kind: Role - {{- else }} - kind: ClusterRole - {{- end }} - name: {{ .Monitor.AppName }}-cluster-reader -{{- end }} -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/rollback-role-binding.monitor.yaml b/venonactl/pkg/templates/kubernetes/rollback-role-binding.monitor.yaml deleted file mode 100644 index 27d1669b..00000000 --- a/venonactl/pkg/templates/kubernetes/rollback-role-binding.monitor.yaml +++ /dev/null @@ -1,24 +0,0 @@ -{{- if .CreateRbac }} -{{- if .Monitor.RbacEnabled }} -{{- if .Monitor.UseNamespaceWithRole }} -kind: RoleBinding -{{- else }} -kind: ClusterRoleBinding -{{- end }} -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .Monitor.AppName }}-rollback - namespace: {{ .Namespace }} - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} -subjects: - - kind: ServiceAccount - namespace: {{ .Namespace }} - name: {{ .Monitor.AppName }}-rollback -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin - {{- end }} -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/rollback-serviceaccount.monitor.yaml b/venonactl/pkg/templates/kubernetes/rollback-serviceaccount.monitor.yaml deleted file mode 100644 index 38532b1b..00000000 --- a/venonactl/pkg/templates/kubernetes/rollback-serviceaccount.monitor.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{- if .CreateRbac }} -{{- if and .Monitor.RbacEnabled (not .Monitor.UseNamespaceWithRole) }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .Monitor.AppName }}-rollback - namespace: {{ .Namespace }} - annotations: - {{ range $key, $value := .Monitor.ServiceAccount.Annotations }} - {{ $key }}: {{ $value }} - {{ end }} - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} -{{- end }} -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/secret.dind-volume-provisioner.vp.yaml b/venonactl/pkg/templates/kubernetes/secret.dind-volume-provisioner.vp.yaml deleted file mode 100644 index f1dcc47f..00000000 --- a/venonactl/pkg/templates/kubernetes/secret.dind-volume-provisioner.vp.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: v1 -kind: Secret -type: Opaque -metadata: - name: dind-volume-provisioner-{{ .AppName }} - namespace: {{ .Namespace }} - labels: - app: dind-volume-provisioner -stringData: -{{- if .Storage.GoogleServiceAccount }} - google-service-account.json: {{ .Storage.GoogleServiceAccount }} -{{- end }} -{{- if .Storage.AwsAccessKeyId }} - aws_access_key_id: {{ .Storage.AwsAccessKeyId }} -{{- end }} -{{- if .Storage.AwsSecretAccessKey }} - aws_secret_access_key: {{ .Storage.AwsSecretAccessKey }} -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/secret.runtime-attach.yaml b/venonactl/pkg/templates/kubernetes/secret.runtime-attach.yaml deleted file mode 100644 index 26f0821e..00000000 --- a/venonactl/pkg/templates/kubernetes/secret.runtime-attach.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: Secret -type: Opaque -metadata: - name: {{ .AppName }}conf - namespace: {{ .Namespace }} -data: -{{ range $key, $value := .runnerConf }} - {{ $key }}: {{ $value }} -{{ end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/secret.venona.yaml b/venonactl/pkg/templates/kubernetes/secret.venona.yaml deleted file mode 100644 index 640b275f..00000000 --- a/venonactl/pkg/templates/kubernetes/secret.venona.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: Secret -type: Opaque -metadata: - name: {{ .AppName }} - namespace: {{ .Namespace }} -stringData: - codefresh.token: {{ .AgentToken }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/service-account.app-proxy.yaml b/venonactl/pkg/templates/kubernetes/service-account.app-proxy.yaml deleted file mode 100644 index 2b03a76e..00000000 --- a/venonactl/pkg/templates/kubernetes/service-account.app-proxy.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{- if .CreateRbac }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .AppProxy.AppName }} - namespace: {{ .Namespace }} - annotations: - {{ range $key, $value := .AppProxy.ServiceAccount.Annotations }} - {{ $key }}: {{ $value | quote | unescape }} - {{ end }} - labels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} -{{- end }} diff --git a/venonactl/pkg/templates/kubernetes/service-account.dind-volume-provisioner.vp.yaml b/venonactl/pkg/templates/kubernetes/service-account.dind-volume-provisioner.vp.yaml deleted file mode 100644 index 36502abc..00000000 --- a/venonactl/pkg/templates/kubernetes/service-account.dind-volume-provisioner.vp.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{- if .CreateRbac }} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: volume-provisioner-{{ .AppName }} - namespace: {{ .Namespace }} - annotations: - {{ range $key, $value := .Storage.VolumeProvisioner.ServiceAccount.Annotations }} - {{ $key }}: {{ $value }} - {{ end }} - labels: - app: dind-volume-provisioner -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/service-account.engine.yaml b/venonactl/pkg/templates/kubernetes/service-account.engine.yaml deleted file mode 100644 index ef2ea5c5..00000000 --- a/venonactl/pkg/templates/kubernetes/service-account.engine.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{- if .CreateRbac }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .Runtime.EngineAppName }} - namespace: {{ .Namespace }} - annotations: - {{ range $key, $value := .Runtime.ServiceAccount.Annotations }} - {{ $key }}: {{ $value }} - {{ end }} - labels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} -{{- end }} diff --git a/venonactl/pkg/templates/kubernetes/service-account.monitor.yaml b/venonactl/pkg/templates/kubernetes/service-account.monitor.yaml deleted file mode 100644 index f3eebf39..00000000 --- a/venonactl/pkg/templates/kubernetes/service-account.monitor.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{- if .CreateRbac }} -{{- if and .Monitor.Enabled .Monitor.RbacEnabled }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .Monitor.AppName }} - namespace: {{ .Namespace }} - annotations: - {{ range $key, $value := .Monitor.ServiceAccount.Annotations }} - {{ $key }}: {{ $value }} - {{ end }} - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} -{{- end }} -{{- end }} diff --git a/venonactl/pkg/templates/kubernetes/service-account.re.yaml b/venonactl/pkg/templates/kubernetes/service-account.re.yaml deleted file mode 100644 index 8a543cef..00000000 --- a/venonactl/pkg/templates/kubernetes/service-account.re.yaml +++ /dev/null @@ -1,7 +0,0 @@ -{{- if .CreateRbac }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .AppName }} - namespace: {{ .Namespace }} -{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/service.app-proxy.yaml b/venonactl/pkg/templates/kubernetes/service.app-proxy.yaml deleted file mode 100644 index 7aba3562..00000000 --- a/venonactl/pkg/templates/kubernetes/service.app-proxy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: app-proxy - namespace: {{ .Namespace }} - labels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} -spec: - selector: - app: {{ .AppProxy.AppName }} - ports: - - protocol: TCP - port: 80 - targetPort: 3000 diff --git a/venonactl/pkg/templates/kubernetes/service.monitor.yaml b/venonactl/pkg/templates/kubernetes/service.monitor.yaml deleted file mode 100644 index ef25b735..00000000 --- a/venonactl/pkg/templates/kubernetes/service.monitor.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- if .CreateRbac }} -apiVersion: v1 -kind: Service -metadata: - name: {{ .Monitor.AppName }} - namespace: {{ .Namespace }} - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} -spec: - type: ClusterIP - ports: - - name: "http" - port: 80 - protocol: TCP - targetPort: 9020 - selector: - app: {{ .Monitor.AppName }} -{{- end }} diff --git a/venonactl/pkg/templates/kubernetes/storageclass.dind-volume-provisioner.vp.yaml b/venonactl/pkg/templates/kubernetes/storageclass.dind-volume-provisioner.vp.yaml deleted file mode 100644 index 6b3495ad..00000000 --- a/venonactl/pkg/templates/kubernetes/storageclass.dind-volume-provisioner.vp.yaml +++ /dev/null @@ -1,57 +0,0 @@ -{{- if .Storage.CreateStorageClass }} ---- -kind: StorageClass -apiVersion: storage.k8s.io/v1 -metadata: - name: {{ .Storage.StorageClassName }} - labels: - app: dind-volume-provisioner - annotations: - {{ range $key, $value := .Storage.Annotations }} - {{ $key }}: {{ $value }} - {{ end }} -provisioner: codefresh.io/dind-volume-provisioner-{{ .AppName }}-{{ .Namespace }} -parameters: -{{- if eq .Storage.Backend "local" }} - volumeBackend: local - volumeParentDir: {{ .Storage.LocalVolumeParentDir | default "/var/lib/codefresh/dind-volumes" }} -{{- else if eq .Storage.Backend "gcedisk" }} - volumeBackend: {{ .Storage.Backend }} - # pd-ssd or pd-standard - type: {{ .Storage.VolumeType | default "pd-ssd" }} - # Valid zone in GCP - zone: {{ .Storage.AvailabilityZone }} - # ext4 or xfs (default to ext4 because xfs is not installed on GKE by default ) - fsType: {{ .Storage.FsType | default "ext4" }} -{{- else if or (eq .Storage.Backend "ebs") (eq .Storage.Backend "ebs-csi")}} - # ebs or ebs-csi - volumeBackend: {{ .Storage.Backend }} - # gp2 or io1 - VolumeType: {{ .Storage.VolumeType | default "gp2" }} - # Valid zone in aws (us-east-1c, ...) - AvailabilityZone: {{ .Storage.AvailabilityZone }} - # ext4 or xfs (default to ext4 ) - fsType: {{ .Storage.FsType | default "ext4" }} - - # "true" or "false" (default - "false") - encrypted: "{{ .Storage.Encrypted | default "false" }}" - {{ if .Storage.KmsKeyId }} - # KMS Key ID - kmsKeyId: {{ .Storage.KmsKeyId }} - {{- end }} -{{- else if or (eq .Storage.Backend "azuredisk") (eq .Storage.Backend "azuredisk-csi")}} - ## azuredisk or azuredisk-csi - volumeBackend: {{ .Storage.Backend }} - - kind: managed - skuName: {{ .Storage.SkuName | default "Premium_LRS" }} - fsType: {{ .Storage.FsType | default "ext4" }} - cachingMode: {{ .Storage.CachingMode | default "None" }} - {{- if .Storage.AzureLocation }} - location: {{ .Storage.AzureLocation }} - {{- end }} - {{- if .Storage.AzureResourceGroup }} - resourceGroup: {{ .Storage.AzureResourceGroup }} - {{- end }} -{{- end }} -{{- end }} diff --git a/venonactl/pkg/templates/kubernetes/templates.go b/venonactl/pkg/templates/kubernetes/templates.go deleted file mode 100644 index 72868a92..00000000 --- a/venonactl/pkg/templates/kubernetes/templates.go +++ /dev/null @@ -1,1155 +0,0 @@ -// Code generated by go generate; DO NOT EDIT. -// using data from templates/kubernetes -package kubernetes - -func TemplatesMap() map[string]string { - templatesMap := make(map[string]string) - - templatesMap["cluster-role-binding.app-proxy.yaml"] = `{{- if .CreateRbac }} -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .AppProxy.AppName }}-cluster-reader-{{ .Namespace }} -subjects: -- kind: ServiceAccount - name: {{ .AppProxy.AppName }} # this service account can get secrets cluster-wide (all namespaces) - namespace: {{ .Namespace }} -roleRef: - kind: ClusterRole - name: {{ .AppProxy.AppName }}-cluster-reader-{{ .Namespace }} - apiGroup: rbac.authorization.k8s.io -{{- end }}` - - templatesMap["cluster-role-binding.dind-volume-provisioner.vp.yaml"] = `{{- if .CreateRbac }} ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: volume-provisioner-{{ .AppName }}-{{ .Namespace }} - labels: - app: dind-volume-provisioner-{{ .AppName }} -subjects: - - kind: ServiceAccount - name: volume-provisioner-{{ .AppName }} - namespace: {{ .Namespace }} -roleRef: - kind: ClusterRole - name: volume-provisioner-{{ .AppName }}-{{ .Namespace }} - apiGroup: rbac.authorization.k8s.io -{{- end }}` - - templatesMap["cluster-role-binding.venona.yaml"] = `{{- if .CreateRbac }} -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .AppName }}-{{ .Namespace }} -subjects: -- kind: ServiceAccount - name: {{ .AppName }} - namespace: {{ .Namespace }} -roleRef: - kind: ClusterRole - name: system:discovery - apiGroup: rbac.authorization.k8s.io -{{- end }}` - - templatesMap["cluster-role.app-proxy.yaml"] = `{{- if .CreateRbac }} -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .AppProxy.AppName }}-cluster-reader-{{ .Namespace }} - labels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} -rules: -- apiGroups: [""] - resources: ["secrets"] - verbs: ["get"] -{{- end }}` - - templatesMap["cluster-role.dind-volume-provisioner.vp.yaml"] = `{{- if .CreateRbac }} -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: volume-provisioner-{{ .AppName }}-{{ .Namespace }} - labels: - app: dind-volume-provisioner -rules: - - apiGroups: [""] - resources: ["persistentvolumes"] - verbs: ["get", "list", "watch", "create", "delete", "patch"] - - apiGroups: [""] - resources: ["persistentvolumeclaims"] - verbs: ["get", "list", "watch", "update", "delete"] - - apiGroups: ["storage.k8s.io"] - resources: ["storageclasses"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["events"] - verbs: ["list", "watch", "create", "update", "patch"] - - apiGroups: [""] - resources: ["secrets"] - verbs: ["get", "list"] - - apiGroups: [""] - resources: ["nodes"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["pods"] - verbs: ["get", "list", "watch", "create", "delete", "patch"] - - apiGroups: [""] - resources: ["endpoints"] - verbs: ["get", "list", "watch", "create", "update", "delete"] - - apiGroups: ["coordination.k8s.io"] - resources: ["leases"] - verbs: ["get", "create", "update"] -{{- end }}` - - templatesMap["codefresh-certs-server-secret.re.yaml"] = `apiVersion: v1 -type: Opaque -kind: Secret -metadata: - labels: - app: venona - name: codefresh-certs-server - namespace: {{ .Namespace }} -data: - server-cert.pem: {{ .ServerCert.Cert }} - server-key.pem: {{ .ServerCert.Key }} - ca.pem: {{ .ServerCert.Ca }} - -` - - templatesMap["cron-job.dind-volume-cleanup.vp.yaml"] = `{{- if not (eq .Storage.Backend "local") }} -apiVersion: batch/v1beta1 -kind: CronJob -metadata: - name: dind-volume-cleanup-{{ .AppName }} - namespace: {{ .Namespace }} - labels: - app: dind-volume-cleanup -spec: - schedule: "0,10,20,30,40,50 * * * *" - concurrencyPolicy: Forbid - {{- if eq .Storage.Backend "local" }} - suspend: true - {{- end }} - jobTemplate: - spec: - template: - spec: - serviceAccountName: volume-provisioner-{{ .AppName }} - restartPolicy: Never - containers: - - name: dind-volume-cleanup - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Storage.VolumeCleaner.Image.Name }}:{{ .Storage.VolumeCleaner.Image.Tag }} {{- else }}{{- .Storage.VolumeCleaner.Image.Name }}:{{ .Storage.VolumeCleaner.Image.Tag }} {{- end}} - env: - - name: PROVISIONED_BY - value: codefresh.io/dind-volume-provisioner-{{ .AppName }}-{{ .Namespace }} - securityContext: - fsGroup: 3000 - runAsGroup: 3000 - runAsUser: 3000 -{{- end }}` - - templatesMap["daemonset.dind-lv-monitor.vp.yaml"] = `{{- if eq .Storage.Backend "local" -}} -{{- $localVolumeParentDir := ( .Storage.LocalVolumeParentDir | default "/var/lib/codefresh/dind-volumes" ) }} -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: dind-lv-monitor-{{ .AppName }} - namespace: {{ .Namespace }} - labels: - app: dind-lv-monitor -spec: - selector: - matchLabels: - app: dind-lv-monitor - template: - metadata: - labels: - app: dind-lv-monitor - annotations: - prometheus_port: "9100" - prometheus_scrape: "true" - spec: - serviceAccountName: volume-provisioner-{{ .AppName }} - tolerations: - - key: 'codefresh/dind' - operator: 'Exists' - effect: 'NoSchedule' - -{{ toYaml .Tolerations | indent 8 | unescape}} - securityContext: - fsGroup: 1000 - initContainers: - - command: - - chown - - -R - - 1000:1000 - - /var/lib/codefresh/dind-volumes - image: alpine - imagePullPolicy: Always - name: fs-change-owner - resources: {} - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - volumeMounts: - - mountPath: /var/lib/codefresh/dind-volumes - name: dind-volume-dir - containers: - - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Storage.LocalVolumeMonitor.Image.Name }}:{{ .Storage.LocalVolumeMonitor.Image.Tag }} {{- else }}{{- .Storage.LocalVolumeMonitor.Image.Name }}:{{ .Storage.LocalVolumeMonitor.Image.Tag }} {{- end}} - name: lv-cleaner - resources: -{{ toYaml .Storage.LocalVolumeMonitor.Resources | indent 10 }} - imagePullPolicy: Always - command: - - /home/dind-volume-utils/bin/local-volumes-agent - env: - {{- if $.EnvVars }} - {{- range $key, $value := $.EnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: VOLUME_PARENT_DIR - value: {{ $localVolumeParentDir }} -# Debug: -# - name: DRY_RUN -# value: "1" -# - name: DEBUG -# value: "1" -# - name: SLEEP_INTERVAL -# value: "3" -# - name: LOG_DF_EVERY -# value: "60" -# - name: KB_USAGE_THRESHOLD -# value: "20" - - volumeMounts: - - mountPath: {{ $localVolumeParentDir }} - readOnly: false - name: dind-volume-dir - volumes: - - name: dind-volume-dir - hostPath: - path: {{ $localVolumeParentDir }} -{{- end -}} -` - - templatesMap["deployment.app-proxy.yaml"] = `apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} - name: {{ .AppProxy.AppName }} - namespace: {{ .Namespace }} -spec: - selector: - matchLabels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} - replicas: 1 - revisionHistoryLimit: 5 - strategy: - rollingUpdate: - maxSurge: 50% - maxUnavailable: 50% - type: RollingUpdate - template: - metadata: - labels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} - spec: - {{- if .CreateRbac }} - serviceAccountName: {{ .AppProxy.AppName }} - {{- end }} - containers: - - name: {{ .AppProxy.AppName }} - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .AppProxy.Image.Name }}:{{ .AppProxy.Image.Tag }} {{- else }} {{- .AppProxy.Image.Name }}:{{ .AppProxy.Image.Tag }} {{- end}} - imagePullPolicy: Always - resources: -{{ toYaml .AppProxy.resources | indent 10 }} - env: - {{- if $.EnvVars }} - {{- range $key, $value := $.EnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - {{- if $.AppProxy.AdditionalEnvVars }} - {{- range $key, $value := $.AppProxy.AdditionalEnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - - name: PORT - value: "3000" - - name: CODEFRESH_HOST - value: {{ .CodefreshHost }} - {{ if .AppProxy.Ingress.PathPrefix }} - - name: API_PATH_PREFIX - value: {{ .AppProxy.Ingress.PathPrefix }} - {{ end }} - {{- if .NewRelicLicense }} - - name: NEWRELIC_LICENSE_KEY - {{- if isString .NewRelicLicense }} - value: {{ .NewRelicLicense }} - {{- else }} -{{ toYaml .NewRelicLicense | indent 12 }} - {{- end }} - {{- end }} - ports: - - containerPort: 3000 - protocol: TCP - readinessProbe: - httpGet: - path: /health - port: 3000 - periodSeconds: 5 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 5 -` - - templatesMap["deployment.dind-volume-provisioner.vp.yaml"] = `apiVersion: apps/v1 -kind: Deployment -metadata: - name: dind-volume-provisioner-{{ .AppName }} - namespace: {{ .Namespace }} - labels: - app: dind-volume-provisioner -spec: - selector: - matchLabels: - app: dind-volume-provisioner - replicas: 1 - strategy: - type: Recreate - template: - metadata: - labels: - app: dind-volume-provisioner - spec: - {{ if .Storage.VolumeProvisioner.NodeSelector }} - nodeSelector: -{{ .Storage.VolumeProvisioner.NodeSelector | nodeSelectorParamToYaml | indent 8 | unescape}} - {{ end }} - serviceAccount: volume-provisioner-{{ .AppName }} - securityContext: - runAsUser: 3000 - runAsGroup: 3000 - fsGroup: 3000 - tolerations: - - effect: NoSchedule - key: node-role.kubernetes.io/master - operator: "Exists" - -{{ toYaml .Tolerations | indent 8 | unescape}} - - containers: - - name: dind-volume-provisioner - resources: -{{ toYaml .Storage.VolumeProvisioner.Resources | indent 10 }} - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Storage.VolumeProvisioner.Image }} {{- else }} {{- .Storage.VolumeProvisioner.Image }} {{- end}} - imagePullPolicy: Always - command: - - /usr/local/bin/dind-volume-provisioner - - -v=4 - - --resync-period=50s - env: - {{- if $.EnvVars }} - {{- range $key, $value := $.EnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - - name: PROVISIONER_NAME - value: codefresh.io/dind-volume-provisioner-{{ .AppName }}-{{ .Namespace }} - {{- if ne .DockerRegistry "" }} - - name: DOCKER_REGISTRY - value: {{ .DockerRegistry }} - {{- end }} - {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits }} - {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.CPU }} - - name: CREATE_DIND_LIMIT_CPU - value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.CPU }} - {{- end }} - {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.Memory }} - - name: CREATE_DIND_LIMIT_MEMORY - value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.Memory }} - {{- end }} - {{- end }} - {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests }} - {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.CPU }} - - name: CREATE_DIND_REQUESTS_CPU - value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.CPU }} - {{- end }} - {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.Memory }} - - name: CREATE_DIND_REQUESTS_MEMORY - value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.Memory }} - {{- end }} - {{- end }} - {{- if .Storage.AwsAccessKeyId }} - - name: AWS_ACCESS_KEY_ID - valueFrom: - secretKeyRef: - name: dind-volume-provisioner-{{ .AppName }} - key: aws_access_key_id - {{- end }} - {{- if .Storage.AwsSecretAccessKey }} - - name: AWS_SECRET_ACCESS_KEY - valueFrom: - secretKeyRef: - name: dind-volume-provisioner-{{ .AppName }} - key: aws_secret_access_key - {{- end }} - {{- if .Storage.GoogleServiceAccount }} - - name: GOOGLE_APPLICATION_CREDENTIALS - value: /etc/dind-volume-provisioner/credentials/google-service-account.json - {{- end }} - {{- if .Storage.VolumeProvisioner.MountAzureJson }} - - name: AZURE_CREDENTIAL_FILE - value: "/etc/kubernetes/azure.json" - {{- end }} - volumeMounts: - {{- if .Storage.VolumeProvisioner.MountAzureJson }} - - name: azure-json - readOnly: true - mountPath: "/etc/kubernetes/azure.json" - {{- end }} - {{- if .Storage.GoogleServiceAccount }} - - name: credentials - readOnly: true - mountPath: "/etc/dind-volume-provisioner/credentials" - {{- end }} - volumes: - {{- if .Storage.VolumeProvisioner.MountAzureJson }} - - name: azure-json - hostPath: - path: /etc/kubernetes/azure.json - type: File - {{- end }} - {{- if .Storage.GoogleServiceAccount }} - - name: credentials - secret: - secretName: dind-volume-provisioner-{{ .AppName }} - {{- end }} -` - - templatesMap["deployment.monitor.yaml"] = `{{- if .Monitor.Enabled }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ .Monitor.AppName }} - namespace: {{ .Namespace }} - labels: - app: {{ .AppName }} - version: {{ .Version }} -spec: - replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 50% - maxSurge: 50% - selector: - matchLabels: - app: {{ .Monitor.AppName }} - template: - metadata: - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} - spec: - {{- if .Monitor.RbacEnabled}} - serviceAccountName: {{ .Monitor.AppName }} - {{- end }} - containers: - - name: {{ .Monitor.AppName }} - resources: -{{ toYaml .Monitor.resources | indent 10 }} - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Monitor.Image.Name }}:{{ .Monitor.Image.Tag }} {{- else }} {{- .Monitor.Image.Name }}:{{ .Monitor.Image.Tag }} {{- end}} - imagePullPolicy: Always - env: - {{- if $.EnvVars }} - {{- range $key, $value := $.EnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - {{- if $.Monitor.AdditionalEnvVars }} - {{- range $key, $value := $.Monitor.AdditionalEnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - - name: SERVICE_NAME - value: {{ .Monitor.AppName }} - {{- if .Monitor.UseNamespaceWithRole }} - - name: ROLE_BINDING - value: "true" - {{- end }} - - name: PORT - value: "9020" - - name: API_TOKEN - value: {{ .Token }} - - name: CLUSTER_ID - value: {{ .ClusterId }} - - name: API_URL - value: {{ .CodefreshHost }}/api/k8s-monitor/events - - name: ACCOUNT_ID - value: user - - name: HELM3 - value: "{{ .Monitor.Helm3 }}" - - name: NAMESPACE - value: "{{ .Namespace }}" - - name: NODE_OPTIONS - value: "--max_old_space_size=4096" - ports: - - containerPort: 9020 - protocol: TCP - readinessProbe: - httpGet: - path: /api/ping - port: 9020 - periodSeconds: 5 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 5 -{{- end }} -` - - templatesMap["deployment.venona.yaml"] = `apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: {{ .AppName }} - version: {{ .Version }} - name: {{ .AppName }} - namespace: {{ .Namespace }} -spec: - selector: - matchLabels: - app: {{ .AppName }} - version: {{ .Version }} - replicas: 1 - revisionHistoryLimit: 5 - strategy: - rollingUpdate: - maxSurge: 50% - maxUnavailable: 50% - type: RollingUpdate - template: - metadata: - labels: - app: {{ .AppName }} - version: {{ .Version }} - spec: - volumes: - - name: runnerconf - secret: - secretName: runnerconf - {{ if ne .NodeSelector "" }} - nodeSelector: -{{ .NodeSelector | nodeSelectorParamToYaml | indent 8 | unescape }} - {{ end }} - tolerations: -{{ toYaml .Tolerations | indent 8 | unescape }} - containers: - - env: - {{- if $.EnvVars }} - {{- range $key, $value := $.EnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - {{- if $.AdditionalEnvVars }} - {{- range $key, $value := $.AdditionalEnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - - name: SELF_DEPLOYMENT_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: CODEFRESH_TOKEN - valueFrom: - secretKeyRef: - name: {{ .AppName }} - key: codefresh.token - - name: CODEFRESH_HOST - value: {{ .CodefreshHost }} - - name: AGENT_MODE - value: {{ .Mode }} - - name: AGENT_NAME - value: {{ .AppName }} - - name: "AGENT_ID" - value: {{ .AgentId }} - - name: VENONA_CONFIG_DIR - value: "/etc/secrets" - {{- if ne .DockerRegistry "" }} - - name: DOCKER_REGISTRY - value: {{ .DockerRegistry }} - {{- end }} - {{- if .NewRelicLicense }} - - name: NEWRELIC_LICENSE_KEY - {{- if isString .NewRelicLicense }} - value: {{ .NewRelicLicense }} - {{- else }} -{{ toYaml .NewRelicLicense | indent 10}} - {{- end }} - {{- end }} - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Image.Name }} {{- else }} {{- .Image.Name }}{{- end}}:{{ .Image.Tag | default "latest"}} - ports: - - containerPort: 8080 - protocol: TCP - readinessProbe: - httpGet: - path: /health - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 5 - volumeMounts: - - name: runnerconf - mountPath: "/etc/secrets" - readOnly: true - imagePullPolicy: Always - name: {{ .AppName }} - resources: -{{ toYaml .Runner.Resources | indent 10 }} - securityContext: - runAsUser: 10001 - runAsGroup: 10001 - fsGroup: 10001 - restartPolicy: Always -` - - templatesMap["dind-daemon-conf.re.yaml"] = `--- -apiVersion: v1 -kind: ConfigMap -metadata: - name: codefresh-dind-config - namespace: {{ .Namespace }} -data: - daemon.json: | - { - "hosts": [ "unix:///var/run/docker.sock", - "tcp://0.0.0.0:1300"], - "tlsverify": true, - "tls": true, - "tlscacert": "/etc/ssl/cf-client/ca.pem", - "tlscert": "/etc/ssl/cf/server-cert.pem", - "tlskey": "/etc/ssl/cf/server-key.pem", - "insecure-registries" : ["192.168.99.100:5000"], - "metrics-addr" : "0.0.0.0:9323", - "experimental" : true - } -` - - templatesMap["dind-headless-service.re.yaml"] = `--- -apiVersion: v1 -kind: Service -metadata: - labels: - app: dind - name: dind - namespace: {{ .Namespace }} -spec: - ports: - - name: "dind-port" - port: 1300 - protocol: TCP - - # This is a headless service, Kubernetes won't assign a VIP for it. - # *.dind.default.svc.cluster.local - clusterIP: None - selector: - app: dind - -` - - templatesMap["ingress.app-proxy.yaml"] = `apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - {{ range $key, $value := .AppProxy.Ingress.Annotations }} - {{ $key }}: {{ $value | quote | unescape }} - {{ end }} - name: app-proxy - namespace: {{ .Namespace }} -spec: - {{ if ne .AppProxy.Ingress.IngressClass "" }} - ingressClassName: {{ .AppProxy.Ingress.IngressClass }} - {{ end }} - rules: - - host: {{ .AppProxy.Ingress.Host }} - http: - paths: - - path: {{ if .AppProxy.Ingress.PathPrefix }}{{ .AppProxy.Ingress.PathPrefix }}{{ else }}'/'{{end}} - pathType: ImplementationSpecific - backend: - service: - name: app-proxy - port: - number: 80 - {{ if .AppProxy.Ingress.TLSSecret }} - tls: - - hosts: - - {{ .AppProxy.Ingress.Host }} - secretName: {{ .AppProxy.Ingress.TLSSecret }} - {{ end }} -` - - templatesMap["pod.network-tester.yaml"] = `apiVersion: v1 -kind: Pod -metadata: - name: {{ .NetworkTester.PodName }} - namespace: {{ .Namespace }} - labels: - app: {{ .AppName }} - version: {{ .Version }} -spec: - containers: - - name: {{ .NetworkTester.PodName }} - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .NetworkTester.Image.Name }}:{{ .NetworkTester.Image.Tag }} {{- else }} {{- .NetworkTester.Image.Name }}:{{ .NetworkTester.Image.Tag }} {{- end}} - imagePullPolicy: Always - restartPolicy: Never - resources: - limits: - cpu: 400m - memory: 500Mi - requests: - cpu: 200m - memory: 300Mi - env: - {{- if $.EnvVars }} - {{- range $key, $value := $.EnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - {{- if $.NetworkTester.AdditionalEnvVars }} - {{- range $key, $value := $.NetworkTester.AdditionalEnvVars }} - - name: {{ $key }} - value: "{{ $value}}" - {{- end}} - {{- end}} - {{- if .Verbose }} - - name: DEBUG - value: '1' - {{- end }} - {{- if .Insecure }} - - name: INSECURE - value: '1' - {{- end }} - - name: IN_CLUSTER - value: '1'` - - templatesMap["role-binding.engine.yaml"] = `{{- if .CreateRbac }} -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .Runtime.EngineAppName }} - namespace: {{ .Namespace }} -subjects: -- kind: ServiceAccount - name: {{ .Runtime.EngineAppName }} - namespace: {{ .Namespace }} -roleRef: - kind: Role - name: {{ .Runtime.EngineAppName }} - apiGroup: rbac.authorization.k8s.io -{{- end }}` - - templatesMap["role-binding.re.yaml"] = `{{- if .CreateRbac }} -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .AppName }} - namespace: {{ .Namespace }} -subjects: -- kind: ServiceAccount - name: {{ .AppName }} - namespace: {{ .Namespace }} -roleRef: - kind: Role - name: {{ .AppName }} - apiGroup: rbac.authorization.k8s.io -{{- end }}` - - templatesMap["role.engine.yaml"] = `{{- if .CreateRbac }} -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .Runtime.EngineAppName }} - namespace: {{ .Namespace }} -rules: -- apiGroups: [""] - resources: ["secrets"] - verbs: ["get"] -{{- end }}` - - templatesMap["role.monitor.yaml"] = `{{- if .CreateRbac }} -{{- if and .Monitor.Enabled .Monitor.RbacEnabled }} -{{- if .Monitor.UseNamespaceWithRole }} -kind: Role -{{- else }} -kind: ClusterRole -{{- end }} -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .Monitor.AppName }}-cluster-reader - namespace: {{ .Namespace }} - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} -rules: -- apiGroups: - - "" - resources: ["*"] - verbs: - - get - - list - - watch - - create - - delete -- apiGroups: - - "" - resources: ["pods"] - verbs: - - get - - list - - watch - - create - - deletecollection -- apiGroups: - - extensions - resources: ["*"] - verbs: - - get - - list - - watch -- apiGroups: - - apps - resources: ["*"] - verbs: - - get - - list - - watch -{{- end }} -{{- end }}` - - templatesMap["role.re.yaml"] = `{{- if .CreateRbac }} -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .AppName }} - namespace: {{ .Namespace }} -rules: -- apiGroups: [""] - resources: ["pods", "persistentvolumeclaims"] - verbs: ["get", "create", "delete"] -{{- end }}` - - templatesMap["rolebinding.monitor.yaml"] = `{{- if .CreateRbac }} -{{- if and .Monitor.Enabled .Monitor.RbacEnabled }} -{{- if .Monitor.UseNamespaceWithRole }} -kind: RoleBinding -{{- else }} -kind: ClusterRoleBinding -{{- end }} -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .Monitor.AppName }}-cluster-reader - namespace: {{ .Namespace }} - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} -subjects: -- kind: ServiceAccount - namespace: {{ .Namespace }} - name: {{ .Monitor.AppName }} -roleRef: - apiGroup: rbac.authorization.k8s.io - {{- if .Monitor.UseNamespaceWithRole }} - kind: Role - {{- else }} - kind: ClusterRole - {{- end }} - name: {{ .Monitor.AppName }}-cluster-reader -{{- end }} -{{- end }}` - - templatesMap["rollback-role-binding.monitor.yaml"] = `{{- if .CreateRbac }} -{{- if .Monitor.RbacEnabled }} -{{- if .Monitor.UseNamespaceWithRole }} -kind: RoleBinding -{{- else }} -kind: ClusterRoleBinding -{{- end }} -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ .Monitor.AppName }}-rollback - namespace: {{ .Namespace }} - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} -subjects: - - kind: ServiceAccount - namespace: {{ .Namespace }} - name: {{ .Monitor.AppName }}-rollback -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin - {{- end }} -{{- end }}` - - templatesMap["rollback-serviceaccount.monitor.yaml"] = `{{- if .CreateRbac }} -{{- if and .Monitor.RbacEnabled (not .Monitor.UseNamespaceWithRole) }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .Monitor.AppName }}-rollback - namespace: {{ .Namespace }} - annotations: - {{ range $key, $value := .Monitor.ServiceAccount.Annotations }} - {{ $key }}: {{ $value }} - {{ end }} - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} -{{- end }} -{{- end }}` - - templatesMap["secret.dind-volume-provisioner.vp.yaml"] = `apiVersion: v1 -kind: Secret -type: Opaque -metadata: - name: dind-volume-provisioner-{{ .AppName }} - namespace: {{ .Namespace }} - labels: - app: dind-volume-provisioner -data: -{{- if .Storage.GoogleServiceAccount }} - google-service-account.json: {{ .Storage.GoogleServiceAccount | b64enc }} -{{- end }} -{{- if .Storage.AwsAccessKeyId }} - aws_access_key_id: {{ .Storage.AwsAccessKeyId | b64enc }} -{{- end }} -{{- if .Storage.AwsSecretAccessKey }} - aws_secret_access_key: {{ .Storage.AwsSecretAccessKey | b64enc }} -{{- end }}` - - templatesMap["secret.runtime-attach.yaml"] = `apiVersion: v1 -kind: Secret -type: Opaque -metadata: - name: {{ .AppName }}conf - namespace: {{ .Namespace }} -data: -{{ range $key, $value := .runnerConf }} - {{ $key }}: {{ $value }} -{{ end }}` - - templatesMap["secret.venona.yaml"] = `apiVersion: v1 -kind: Secret -type: Opaque -metadata: - name: {{ .AppName }} - namespace: {{ .Namespace }} -data: - codefresh.token: {{ .AgentToken | b64enc }}` - - templatesMap["service-account.app-proxy.yaml"] = `{{- if .CreateRbac }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .AppProxy.AppName }} - namespace: {{ .Namespace }} - annotations: - {{ range $key, $value := .AppProxy.ServiceAccount.Annotations }} - {{ $key }}: {{ $value | quote | unescape }} - {{ end }} - labels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} -{{- end }} -` - - templatesMap["service-account.dind-volume-provisioner.vp.yaml"] = `{{- if .CreateRbac }} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: volume-provisioner-{{ .AppName }} - namespace: {{ .Namespace }} - annotations: - {{ range $key, $value := .Storage.VolumeProvisioner.ServiceAccount.Annotations }} - {{ $key }}: {{ $value }} - {{ end }} - labels: - app: dind-volume-provisioner -{{- end }}` - - templatesMap["service-account.engine.yaml"] = `{{- if .CreateRbac }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .Runtime.EngineAppName }} - namespace: {{ .Namespace }} - annotations: - {{ range $key, $value := .Runtime.ServiceAccount.Annotations }} - {{ $key }}: {{ $value }} - {{ end }} - labels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} -{{- end }} -` - - templatesMap["service-account.monitor.yaml"] = `{{- if .CreateRbac }} -{{- if and .Monitor.Enabled .Monitor.RbacEnabled }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .Monitor.AppName }} - namespace: {{ .Namespace }} - annotations: - {{ range $key, $value := .Monitor.ServiceAccount.Annotations }} - {{ $key }}: {{ $value }} - {{ end }} - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} -{{- end }} -{{- end }} -` - - templatesMap["service-account.re.yaml"] = `{{- if .CreateRbac }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .AppName }} - namespace: {{ .Namespace }} -{{- end }}` - - templatesMap["service.app-proxy.yaml"] = `apiVersion: v1 -kind: Service -metadata: - name: app-proxy - namespace: {{ .Namespace }} - labels: - app: {{ .AppProxy.AppName }} - version: {{ .Version }} -spec: - selector: - app: {{ .AppProxy.AppName }} - ports: - - protocol: TCP - port: 80 - targetPort: 3000 -` - - templatesMap["service.monitor.yaml"] = `{{- if .CreateRbac }} -apiVersion: v1 -kind: Service -metadata: - name: {{ .Monitor.AppName }} - namespace: {{ .Namespace }} - labels: - app: {{ .Monitor.AppName }} - version: {{ .Version }} -spec: - type: ClusterIP - ports: - - name: "http" - port: 80 - protocol: TCP - targetPort: 9020 - selector: - app: {{ .Monitor.AppName }} -{{- end }} -` - - templatesMap["storageclass.dind-volume-provisioner.vp.yaml"] = `{{- if .Storage.CreateStorageClass }} ---- -kind: StorageClass -apiVersion: storage.k8s.io/v1 -metadata: - name: {{ .Storage.StorageClassName }} - labels: - app: dind-volume-provisioner - annotations: - {{ range $key, $value := .Storage.Annotations }} - {{ $key }}: {{ $value }} - {{ end }} -provisioner: codefresh.io/dind-volume-provisioner-{{ .AppName }}-{{ .Namespace }} -parameters: -{{- if eq .Storage.Backend "local" }} - volumeBackend: local - volumeParentDir: {{ .Storage.LocalVolumeParentDir | default "/var/lib/codefresh/dind-volumes" }} -{{- else if eq .Storage.Backend "gcedisk" }} - volumeBackend: {{ .Storage.Backend }} - # pd-ssd or pd-standard - type: {{ .Storage.VolumeType | default "pd-ssd" }} - # Valid zone in GCP - zone: {{ .Storage.AvailabilityZone }} - # ext4 or xfs (default to ext4 because xfs is not installed on GKE by default ) - fsType: {{ .Storage.FsType | default "ext4" }} -{{- else if or (eq .Storage.Backend "ebs") (eq .Storage.Backend "ebs-csi")}} - # ebs or ebs-csi - volumeBackend: {{ .Storage.Backend }} - # gp2 or io1 - VolumeType: {{ .Storage.VolumeType | default "gp2" }} - # Valid zone in aws (us-east-1c, ...) - AvailabilityZone: {{ .Storage.AvailabilityZone }} - # ext4 or xfs (default to ext4 ) - fsType: {{ .Storage.FsType | default "ext4" }} - - # "true" or "false" (default - "false") - encrypted: "{{ .Storage.Encrypted | default "false" }}" - {{ if .Storage.KmsKeyId }} - # KMS Key ID - kmsKeyId: {{ .Storage.KmsKeyId }} - {{- end }} -{{- else if or (eq .Storage.Backend "azuredisk") (eq .Storage.Backend "azuredisk-csi")}} - ## azuredisk or azuredisk-csi - volumeBackend: {{ .Storage.Backend }} - - kind: managed - skuName: {{ .Storage.SkuName | default "Premium_LRS" }} - fsType: {{ .Storage.FsType | default "ext4" }} - cachingMode: {{ .Storage.CachingMode | default "None" }} - {{- if .Storage.AzureLocation }} - location: {{ .Storage.AzureLocation }} - {{- end }} - {{- if .Storage.AzureResourceGroup }} - resourceGroup: {{ .Storage.AzureResourceGroup }} - {{- end }} -{{- end }} -{{- end }} -` - - templatesMap["venonaconf.secret.venona.yaml"] = `apiVersion: v1 -kind: Secret -type: Opaque -metadata: - name: {{ .AppName }}conf - namespace: {{ .Namespace }} -data: -{{ range $key, $value := .runnerConf }} - {{ $key }}: {{ $value }} -{{ end }}` - - return templatesMap -} diff --git a/venonactl/pkg/templates/kubernetes/venonaconf.secret.venona.yaml b/venonactl/pkg/templates/kubernetes/venonaconf.secret.venona.yaml deleted file mode 100644 index 26f0821e..00000000 --- a/venonactl/pkg/templates/kubernetes/venonaconf.secret.venona.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: Secret -type: Opaque -metadata: - name: {{ .AppName }}conf - namespace: {{ .Namespace }} -data: -{{ range $key, $value := .runnerConf }} - {{ $key }}: {{ $value }} -{{ end }} \ No newline at end of file From 100bf8734f5b55900268992e65917c4d3a373308 Mon Sep 17 00:00:00 2001 From: Zhenya Tikhonov Date: Wed, 17 Sep 2025 20:53:57 +0400 Subject: [PATCH 2/4] build: upgrade `venona` --- charts/cf-runtime/Chart.yaml | 6 ++++-- charts/cf-runtime/README.md | 4 ++-- charts/cf-runtime/values.yaml | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/charts/cf-runtime/Chart.yaml b/charts/cf-runtime/Chart.yaml index c14cc21b..87b6cc5d 100644 --- a/charts/cf-runtime/Chart.yaml +++ b/charts/cf-runtime/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 description: A Helm chart for Codefresh Runner name: cf-runtime -version: 8.3.6 +version: 8.3.7 keywords: - codefresh - runner @@ -17,8 +17,10 @@ annotations: artifacthub.io/containsSecurityUpdates: "true" # Supported kinds: `added`, `changed`, `deprecated`, `removed`, `fixed`, `security`: artifacthub.io/changes: | + - kind: changed + description: "Update \"runner\" (aka \"venona\") to 2.0.7" - kind: security - description: "Security fix in cf-docker-builder, cf-docker-puller, cf-docker-pusher, compose, pikolo, cf-debugger." + description: "Fix CVE-2025-4575, CVE-2025-22868, CVE-2025-22872, CVE-2025-22870, CVE-2024-45338, CVE-2025-4575" dependencies: - name: cf-common repository: oci://quay.io/codefresh/charts diff --git a/charts/cf-runtime/README.md b/charts/cf-runtime/README.md index 521bd5d2..c5ad630b 100644 --- a/charts/cf-runtime/README.md +++ b/charts/cf-runtime/README.md @@ -1,6 +1,6 @@ ## Codefresh Runner -![Version: 8.3.6](https://img.shields.io/badge/Version-8.3.6-informational?style=flat-square) +![Version: 8.3.7](https://img.shields.io/badge/Version-8.3.7-informational?style=flat-square) Helm chart for deploying [Codefresh Runner](https://codefresh.io/docs/docs/installation/codefresh-runner/) to Kubernetes. @@ -1276,7 +1276,7 @@ Install the Helm chart | runner.affinity | object | `{}` | Set affinity | | runner.enabled | bool | `true` | Enable the runner | | runner.env | object | `{}` | Add additional env vars | -| runner.image | object | `{"digest":"sha256:d00c6645039c3716e778217cc22fb44ae2324fd3349d8e782dd3a8af05dc0e2d","registry":"quay.io","repository":"codefresh/venona","tag":"2.0.6"}` | Set image | +| runner.image | object | `{"digest":"sha256:96a8696ab418c3327e2e5fcf8ab08359b332167ef750b543ddd245ac4270153f","registry":"quay.io","repository":"codefresh/venona","tag":"2.0.7"}` | Set image | | runner.init | object | `{"image":{"digest":"sha256:bbf49935b078eb0f282fec4ff674eea55f880b101809c6415e3ead7a0c729261","registry":"quay.io","repository":"codefresh/cli","tag":"0.89.3-rootless"},"resources":{"limits":{"cpu":"1","memory":"512Mi"},"requests":{"cpu":"0.2","memory":"256Mi"}}}` | Init container | | runner.name | string | `""` | Set runner deployment name | | runner.nodeSelector | object | `{}` | Set node selector | diff --git a/charts/cf-runtime/values.yaml b/charts/cf-runtime/values.yaml index 231009bb..e8e164d8 100644 --- a/charts/cf-runtime/values.yaml +++ b/charts/cf-runtime/values.yaml @@ -74,8 +74,8 @@ runner: image: registry: quay.io repository: codefresh/venona - tag: 2.0.6 - digest: sha256:d00c6645039c3716e778217cc22fb44ae2324fd3349d8e782dd3a8af05dc0e2d + tag: 2.0.7 + digest: sha256:96a8696ab418c3327e2e5fcf8ab08359b332167ef750b543ddd245ac4270153f # -- Init container init: image: From 95af577026f0b86803f01e3d73c315933e718685 Mon Sep 17 00:00:00 2001 From: Zhenya Tikhonov Date: Wed, 17 Sep 2025 20:54:41 +0400 Subject: [PATCH 3/4] Revert "build: deprecate `venonactl`" This reverts commit c39a116bbb949fa6b94ed28a67d84bca3ae27187. --- .gitignore | 2 + README.md | 3 +- venonactl/.gitignore | 2 + venonactl/.goreleaser.yml | 46 + venonactl/Dockerfile | 20 + venonactl/Makefile | 11 + venonactl/README.md | 262 ++++ venonactl/VERSION | 1 + venonactl/build/ci.yaml | 129 ++ venonactl/cmd/attach.go | 169 +++ venonactl/cmd/cmdutils.go | 320 +++++ venonactl/cmd/install-agent.go | 215 +++ venonactl/cmd/install-app-proxy.go | 119 ++ venonactl/cmd/install-monitor.go | 148 +++ venonactl/cmd/install-runtime.go | 197 +++ venonactl/cmd/install-venona.go | 58 + venonactl/cmd/install.go | 29 + venonactl/cmd/migrate.go | 70 + venonactl/cmd/root.go | 56 + venonactl/cmd/status.go | 132 ++ venonactl/cmd/test.go | 145 +++ venonactl/cmd/uninstall-agent.go | 91 ++ venonactl/cmd/uninstall-app-proxy.go | 92 ++ venonactl/cmd/uninstall-monitor.go | 103 ++ venonactl/cmd/uninstall-runtime.go | 145 +++ venonactl/cmd/uninstall.go | 29 + venonactl/cmd/upgrade-app-proxy.go | 90 ++ venonactl/cmd/upgrade.go | 95 ++ venonactl/cmd/version.go | 43 + venonactl/example/values-example.yaml | 308 +++++ venonactl/go.mod | 134 ++ venonactl/go.sum | 859 ++++++++++++ venonactl/hack/build-linux.sh | 11 + venonactl/hack/build.sh | 11 + venonactl/hack/fmt.sh | 3 + venonactl/hack/generate.go | 7 + venonactl/main.go | 69 + venonactl/main_windows.go | 42 + venonactl/pkg/certs/server_cert.go | 82 ++ venonactl/pkg/codefresh/cfapi.go | 210 +++ venonactl/pkg/kube/kube.go | 109 ++ venonactl/pkg/logger/custom-logger.go | 28 + venonactl/pkg/logger/logger.go | 40 + venonactl/pkg/obj/kubeobj/kubeobj.go | 581 +++++++++ venonactl/pkg/obj/kubeobj_generator.go | 202 +++ venonactl/pkg/plugins/app-proxy.go | 132 ++ venonactl/pkg/plugins/engine.go | 111 ++ venonactl/pkg/plugins/helper.go | 367 ++++++ venonactl/pkg/plugins/monitor.go | 127 ++ venonactl/pkg/plugins/network-tester.go | 238 ++++ venonactl/pkg/plugins/plugin.go | 353 +++++ venonactl/pkg/plugins/runtime-attach.go | 378 ++++++ venonactl/pkg/plugins/runtime-environment.go | 204 +++ venonactl/pkg/plugins/types.go | 30 + venonactl/pkg/plugins/venona.go | 379 ++++++ venonactl/pkg/plugins/volume-provisioner.go | 195 +++ venonactl/pkg/store/store.go | 232 ++++ venonactl/pkg/templates/generate_template.go | 106 ++ .../cluster-role-binding.app-proxy.yaml | 14 + ...le-binding.dind-volume-provisioner.vp.yaml | 17 + .../cluster-role-binding.venona.yaml | 14 + .../kubernetes/cluster-role.app-proxy.yaml | 13 + ...uster-role.dind-volume-provisioner.vp.yaml | 36 + .../codefresh-certs-server-secret.re.yaml | 13 + .../cron-job.dind-volume-cleanup.vp.yaml | 31 + .../daemonset.dind-lv-monitor.vp.yaml | 87 ++ .../kubernetes/deployment.app-proxy.yaml | 75 ++ ...deployment.dind-volume-provisioner.vp.yaml | 123 ++ .../kubernetes/deployment.monitor.yaml | 81 ++ .../kubernetes/deployment.venona.yaml | 106 ++ .../kubernetes/dind-daemon-conf.re.yaml | 20 + .../kubernetes/dind-headless-service.re.yaml | 20 + .../kubernetes/ingress.app-proxy.yaml | 30 + .../kubernetes/pod.network-tester.yaml | 44 + .../kubernetes/role-binding.engine.yaml | 15 + .../templates/kubernetes/role-binding.re.yaml | 15 + .../pkg/templates/kubernetes/role.engine.yaml | 11 + .../templates/kubernetes/role.monitor.yaml | 49 + .../pkg/templates/kubernetes/role.re.yaml | 11 + .../kubernetes/rolebinding.monitor.yaml | 28 + .../rollback-role-binding.monitor.yaml | 24 + .../rollback-serviceaccount.monitor.yaml | 16 + .../secret.dind-volume-provisioner.vp.yaml | 18 + .../kubernetes/secret.runtime-attach.yaml | 10 + .../templates/kubernetes/secret.venona.yaml | 8 + .../kubernetes/service-account.app-proxy.yaml | 14 + ...ce-account.dind-volume-provisioner.vp.yaml | 14 + .../kubernetes/service-account.engine.yaml | 14 + .../kubernetes/service-account.monitor.yaml | 16 + .../kubernetes/service-account.re.yaml | 7 + .../kubernetes/service.app-proxy.yaml | 15 + .../templates/kubernetes/service.monitor.yaml | 19 + ...orageclass.dind-volume-provisioner.vp.yaml | 57 + .../pkg/templates/kubernetes/templates.go | 1155 +++++++++++++++++ .../kubernetes/venonaconf.secret.venona.yaml | 10 + 95 files changed, 10619 insertions(+), 1 deletion(-) create mode 100644 venonactl/.gitignore create mode 100644 venonactl/.goreleaser.yml create mode 100644 venonactl/Dockerfile create mode 100644 venonactl/Makefile create mode 100644 venonactl/README.md create mode 100644 venonactl/VERSION create mode 100644 venonactl/build/ci.yaml create mode 100644 venonactl/cmd/attach.go create mode 100644 venonactl/cmd/cmdutils.go create mode 100644 venonactl/cmd/install-agent.go create mode 100644 venonactl/cmd/install-app-proxy.go create mode 100644 venonactl/cmd/install-monitor.go create mode 100644 venonactl/cmd/install-runtime.go create mode 100644 venonactl/cmd/install-venona.go create mode 100644 venonactl/cmd/install.go create mode 100644 venonactl/cmd/migrate.go create mode 100644 venonactl/cmd/root.go create mode 100644 venonactl/cmd/status.go create mode 100644 venonactl/cmd/test.go create mode 100644 venonactl/cmd/uninstall-agent.go create mode 100644 venonactl/cmd/uninstall-app-proxy.go create mode 100644 venonactl/cmd/uninstall-monitor.go create mode 100644 venonactl/cmd/uninstall-runtime.go create mode 100644 venonactl/cmd/uninstall.go create mode 100644 venonactl/cmd/upgrade-app-proxy.go create mode 100644 venonactl/cmd/upgrade.go create mode 100644 venonactl/cmd/version.go create mode 100644 venonactl/example/values-example.yaml create mode 100644 venonactl/go.mod create mode 100644 venonactl/go.sum create mode 100755 venonactl/hack/build-linux.sh create mode 100755 venonactl/hack/build.sh create mode 100755 venonactl/hack/fmt.sh create mode 100644 venonactl/hack/generate.go create mode 100644 venonactl/main.go create mode 100644 venonactl/main_windows.go create mode 100644 venonactl/pkg/certs/server_cert.go create mode 100644 venonactl/pkg/codefresh/cfapi.go create mode 100644 venonactl/pkg/kube/kube.go create mode 100644 venonactl/pkg/logger/custom-logger.go create mode 100644 venonactl/pkg/logger/logger.go create mode 100644 venonactl/pkg/obj/kubeobj/kubeobj.go create mode 100644 venonactl/pkg/obj/kubeobj_generator.go create mode 100644 venonactl/pkg/plugins/app-proxy.go create mode 100644 venonactl/pkg/plugins/engine.go create mode 100644 venonactl/pkg/plugins/helper.go create mode 100644 venonactl/pkg/plugins/monitor.go create mode 100644 venonactl/pkg/plugins/network-tester.go create mode 100644 venonactl/pkg/plugins/plugin.go create mode 100644 venonactl/pkg/plugins/runtime-attach.go create mode 100644 venonactl/pkg/plugins/runtime-environment.go create mode 100644 venonactl/pkg/plugins/types.go create mode 100644 venonactl/pkg/plugins/venona.go create mode 100644 venonactl/pkg/plugins/volume-provisioner.go create mode 100644 venonactl/pkg/store/store.go create mode 100644 venonactl/pkg/templates/generate_template.go create mode 100644 venonactl/pkg/templates/kubernetes/cluster-role-binding.app-proxy.yaml create mode 100644 venonactl/pkg/templates/kubernetes/cluster-role-binding.dind-volume-provisioner.vp.yaml create mode 100644 venonactl/pkg/templates/kubernetes/cluster-role-binding.venona.yaml create mode 100644 venonactl/pkg/templates/kubernetes/cluster-role.app-proxy.yaml create mode 100644 venonactl/pkg/templates/kubernetes/cluster-role.dind-volume-provisioner.vp.yaml create mode 100644 venonactl/pkg/templates/kubernetes/codefresh-certs-server-secret.re.yaml create mode 100644 venonactl/pkg/templates/kubernetes/cron-job.dind-volume-cleanup.vp.yaml create mode 100644 venonactl/pkg/templates/kubernetes/daemonset.dind-lv-monitor.vp.yaml create mode 100644 venonactl/pkg/templates/kubernetes/deployment.app-proxy.yaml create mode 100644 venonactl/pkg/templates/kubernetes/deployment.dind-volume-provisioner.vp.yaml create mode 100644 venonactl/pkg/templates/kubernetes/deployment.monitor.yaml create mode 100644 venonactl/pkg/templates/kubernetes/deployment.venona.yaml create mode 100644 venonactl/pkg/templates/kubernetes/dind-daemon-conf.re.yaml create mode 100644 venonactl/pkg/templates/kubernetes/dind-headless-service.re.yaml create mode 100644 venonactl/pkg/templates/kubernetes/ingress.app-proxy.yaml create mode 100644 venonactl/pkg/templates/kubernetes/pod.network-tester.yaml create mode 100644 venonactl/pkg/templates/kubernetes/role-binding.engine.yaml create mode 100644 venonactl/pkg/templates/kubernetes/role-binding.re.yaml create mode 100644 venonactl/pkg/templates/kubernetes/role.engine.yaml create mode 100644 venonactl/pkg/templates/kubernetes/role.monitor.yaml create mode 100644 venonactl/pkg/templates/kubernetes/role.re.yaml create mode 100644 venonactl/pkg/templates/kubernetes/rolebinding.monitor.yaml create mode 100644 venonactl/pkg/templates/kubernetes/rollback-role-binding.monitor.yaml create mode 100644 venonactl/pkg/templates/kubernetes/rollback-serviceaccount.monitor.yaml create mode 100644 venonactl/pkg/templates/kubernetes/secret.dind-volume-provisioner.vp.yaml create mode 100644 venonactl/pkg/templates/kubernetes/secret.runtime-attach.yaml create mode 100644 venonactl/pkg/templates/kubernetes/secret.venona.yaml create mode 100644 venonactl/pkg/templates/kubernetes/service-account.app-proxy.yaml create mode 100644 venonactl/pkg/templates/kubernetes/service-account.dind-volume-provisioner.vp.yaml create mode 100644 venonactl/pkg/templates/kubernetes/service-account.engine.yaml create mode 100644 venonactl/pkg/templates/kubernetes/service-account.monitor.yaml create mode 100644 venonactl/pkg/templates/kubernetes/service-account.re.yaml create mode 100644 venonactl/pkg/templates/kubernetes/service.app-proxy.yaml create mode 100644 venonactl/pkg/templates/kubernetes/service.monitor.yaml create mode 100644 venonactl/pkg/templates/kubernetes/storageclass.dind-volume-provisioner.vp.yaml create mode 100644 venonactl/pkg/templates/kubernetes/templates.go create mode 100644 venonactl/pkg/templates/kubernetes/venonaconf.secret.venona.yaml diff --git a/.gitignore b/.gitignore index e6c98d53..1edfc8de 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,8 @@ encodings.xml yarn-error.log .idea/* telepresence.log +venonactl/dist/* +venonactl-linux venonalog.json .venonaconf .cover diff --git a/README.md b/README.md index 7accd5c9..641676cf 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -* [venona](venona/README.md) - Codefresh runner process, [official docs](https://codefresh.io/docs/docs/administration/codefresh-runner/). +* [venonactl](venonactl/README.md) - Codefresh installer of Kubernetes YAML's. +* [venona](venona/README.md) - Codefresh runner process, [official docs](https://codefresh.io/docs/docs/administration/codefresh-runner/). \ No newline at end of file diff --git a/venonactl/.gitignore b/venonactl/.gitignore new file mode 100644 index 00000000..1ddcf913 --- /dev/null +++ b/venonactl/.gitignore @@ -0,0 +1,2 @@ +.idea/ +/vendor/ diff --git a/venonactl/.goreleaser.yml b/venonactl/.goreleaser.yml new file mode 100644 index 00000000..1f77807d --- /dev/null +++ b/venonactl/.goreleaser.yml @@ -0,0 +1,46 @@ +before: + hooks: + - go mod tidy + +builds: +- goos: + - darwin + - linux + - windows + goarch: + - amd64 + - 386 + env: + - CGO_ENABLED=0 + ignore: + - goos: darwin + goarch: 386 + ldflags: + - -X github.com/codefresh-io/venona/venonactl/cmd.version={{.Version}} -X github.com/codefresh-io/venona/venonactl/cmd.commit={{.Commit}} -X github.com/codefresh-io/venona/venonactl/cmd.date={{.Date}} + +archives: +- + replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 + name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + format_overrides: + - goos: windows + format: zip +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' + + +release: + # If set to auto, will mark the release as not ready for production + # in case there is an indicator for this in the tag e.g. v1.0.0-rc1 + # If set to true, will mark the release as not ready for production. + # Default is false. + prerelease: false diff --git a/venonactl/Dockerfile b/venonactl/Dockerfile new file mode 100644 index 00000000..6fe267e2 --- /dev/null +++ b/venonactl/Dockerfile @@ -0,0 +1,20 @@ +FROM golang:1.21-alpine3.20 AS build +WORKDIR /venona +COPY go.mod . +RUN go mod download +RUN apk add git +COPY . . +ARG COMMIT +RUN VERSION=$(cat VERSION) \ + DATE=$(date -u "+%Y-%m-%dT%TZ") && \ + env CGO_ENABLED=0 \ + go build -ldflags="-w -X github.com/codefresh-io/venona/venonactl/cmd.version=${VERSION} \ + -X github.com/codefresh-io/venona/venonactl/cmd.commit=${COMMIT} -X github.com/codefresh-io/venona/venonactl/cmd.date=${DATE}" \ + -o venona + +FROM alpine:3.20 +RUN apk add --update ca-certificates +COPY --from=build /venona/venona /usr/local/bin/venona + +ENTRYPOINT [ "venona" ] +CMD [ "--help" ] diff --git a/venonactl/Makefile b/venonactl/Makefile new file mode 100644 index 00000000..c9875dc9 --- /dev/null +++ b/venonactl/Makefile @@ -0,0 +1,11 @@ +.PHONY: build +build: build-local + +build-local: + @sh ./hack/build.sh + +build-linux: + @sh ./hack/build-linux.sh + +fmt: + go fmt ./... diff --git a/venonactl/README.md b/venonactl/README.md new file mode 100644 index 00000000..4531081e --- /dev/null +++ b/venonactl/README.md @@ -0,0 +1,262 @@ +# VENONACTL +Codefresh installer of Kubernetes YAML onto the cluster + +## Version 1.x.x +Version 1.x.x is is about to be released soon, read more about migration from older version [here](#Migration) +Meanwhile 1.x.x is to release and makred as pre-release we will maintain 2 branches: +* `master` - the previous version ( `version < 1.0.0` ) + * we will keep maintaing if (bugs, security issues) - this version will be intalled when installing `venona` on MacOS using brew + * `codefresh/venona:latest` will refer to this branch +* `release-1.0` it the new release, which will be used when running Codefresh CLI to install the agent +We highly suggest to use [Codefresh official CLI](https://codefresh-io.github.io/cli/) to install the agent: +```bash +codefresh runner init +``` + +The last command will: +1. Install the agent on the namespace `codefresh` (as you choose) +2. Install the runtime on the same namespace +3. Attach the runtime to the agent +4. Register cluster on codefresh platform +5. Create and run demo pipeline + +It is still possible, for advanced users to install all manually, for example: +One process of Venona can manage multiple runtime environments +NOTE: Please make sure that the process where Venona is installed there is a network connection to the clusters where the runtimes will be installed +```bash +# 1. Create namespace for the agent: +kubectl create namespace codefresh-agent + +# 2. Install the agent on the namespace ( give your agent a unique): +# Print a token that the Venona process will be using. +codefresh create agent $NAME +codefresh install agent --token $TOKEN --kube-namespace codefresh-agent + +# 3. Create namespace for the first runtime: +kubectl create namespace codefresh-runtime-1 + +# 4. Install the first runtime on the namespace +# 5. the runtime name is printed +codefresh install runtime --kube-namespace codefresh-runtime-1 + +# 6. Attach the first runtime to agent: +codefresh attach runtime --agent-name $AGENT_NAME --agent-kube-namespace codefresh-agent --runtime-name $RUNTIME_NAME --kube-namespace codefresh-runtime-1 + +# 7. Restart the venona pod in namespace `codefresh-agent` +kubectl delete pods $VENONA_POD + +# 8. Create namespace for the second runtime +kubectl create namespace codefresh-runtime-2 + +# 9. Install the second runtime on the namespace +codefresh install runtime --kube-namespace codefresh-runtime-2 + +# 10. Attach the second runtime to agent and restart the Venoa pod automatically +codefresh attach runtime --agent-name $AGENT_NAME --agent-kube-namespace codefresh-agent --runtime-name $RUNTIME_NAME --runtime-kube-namespace codefresh-runtime-1 --restart-agent + +``` + +## Migration +Migrating from Venona `< 1.x.x` to `> 1.x.x` is not done automatically, please run the follwing +```bash +codefresh runner upgrade +``` + + +## Installation + +### Prerequisite: +* [Kubernetes](https://kubernetes.io/docs/tasks/tools/install-kubectl/) - Used to create resource in your K8S cluster + * Kube Version > 1.10: + * [Instuction](#Install-on-cluster-version-<-1.10) to install on cluster version < 1.10 + * Disk size 50GB per node +* [Codefresh](https://codefresh-io.github.io/cli/) - Used to create resource in Codefresh + * Authenticated context exist under `$HOME/.cfconfig` or authenticate with [Codefesh CLI](https://codefresh-io.github.io/cli/getting-started/#authenticate) + +### Install venona + +* Download [venona's](https://github.com/codefresh-io/venona/releases) binary + * With homebrew: + * `brew tap codefresh-io/venona` + * `brew install venona` + + +#### Install on cluster version < 1.10 +* Make sure the `PersistentLocalVolumes` [feature gate](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) is turned on +* Venona's agent is trying to load avaliables apis using api `/openapi/v2` endpoint +Add this endpoint to ClusterRole `system:discovery` under `rules[0].nonResourceURLs` +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: system:discovery +rules: +- nonResourceURLs: + - ...other_resources + - /openapi + - /openapi/* + verbs: + - get +``` +#### Install using --values +`codefresh runner init --values [parameters]` +the values from values.yaml are applied to the templates in [pkg/templates/kubernetes](pkg/templates/kubernetes) + +See BuildValues() func in [store.go](pkg/store/store.go) for the format +Example with explanation is in [values-example.yaml](example/values-example.yaml) + +#### Install on GCP + * Make sure your user has `Kubernetes Engine Cluster Admin` role in google console + * Bind your user with cluster-admin kubernetes clusterrole + > `kubectl create clusterrolebinding NAME --clusterrole cluster-admin --user YOUR_USER` + +#### Pipeline Storage with docker cache support + +##### **GKE LocalSSD** +*Prerequisite:* [GKE custer with local SSD](https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/local-ssd) + +*Install venona for using GKE Local SSD:* +``` +codefresh install runtime [options] \ + --set-value=Storage.LocalVolumeParentDir=/mnt/disks/ssd0/codefresh-volumes + --kube-node-selector=cloud.google.com/gke-local-ssd=true +``` + +##### **GCE Disks** +*Prerequisite:* volume provisioner (dind-volume-provisioner) should have permissions to create/delete/get of google disks +There are 3 options to provide cloud credentials on GCE: +* run venona dind-volume-provisioniner on node with iam role which is allowed to create/delete/get of google disks +* create Google Service Account with ComputeEngine.StorageAdmin, download its key and pass it to venona installed with `--set-file=Storage.GooogleServiceAccount=/path/to/google-service-account.json` +* use [Google Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity) to assign iam role to `volume-provisioner-venona` service account + +*Note*: Builds will be running in single availability zone, so you must to specify AvailabilityZone params + + +*Install venona for using GKE Disks:* +``` +codefresh install runtime [options] \ + --set-value=Storage.Backend=gcedisk \ + --set-value=Storage.AvailabilityZone=us-central1-a \ + --kube-node-selector=failure-domain.beta.kubernetes.io/zone=us-central1-a \ + [--set-file=Storage.GoogleServiceAccount=/path/to/google-service-account.json] +``` + +##### **Amazon EBS** + +*Prerequisite:* volume provisioner (dind-volume-provisioner) should have permissions to create/delete/get of aws ebs +Minimal iam policy for dind-volume-provisioner: +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:AttachVolume", + "ec2:CreateSnapshot", + "ec2:CreateTags", + "ec2:CreateVolume", + "ec2:DeleteSnapshot", + "ec2:DeleteTags", + "ec2:DeleteVolume", + "ec2:DescribeInstances", + "ec2:DescribeSnapshots", + "ec2:DescribeTags", + "ec2:DescribeVolumes", + "ec2:DetachVolume" + ], + "Resource": "*" + } + ] +} +``` + +There are 3 options to provide cloud credentials on AWS: +* run venona dind-volume-provisioniner on node with the iam role - use `--set-value Storage.VolumeProvisioner.NodeSelector=node-label=value` option +* create AWS IAM User, assign it the permissions above and suppy aws credentials to venona installer `--set-value=Storage.AwsAccessKeyId=ABCDF --set-value=Storage.AwsSecretAccessKey=ZYXWV` + +* use [Aws Identity for Service Account](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) to assign iam role to `volume-provisioner-venona` service account + +*Notes*: +- Builds will be running in single availability zone, so you must specify AvailabilityZone parameter `--set-value=Storage.AvailabilityZone=` and build-node-selector `--build-node-selector=failure-domain.beta.kubernetes.io/zone=` in case of multizone cluster + +- We support both [in-tree ebs](https://kubernetes.io/docs/concepts/storage/volumes/#awselasticblockstore) (`--set-value=Storage.Backend=ebs`) volumes and ebs-csi(https://github.com/kubernetes-sigs/aws-ebs-csi-driver) (`--set-value=Storage.Backend=ebs-csi`) + +*Install Command to run pipelines on ebs volumes* +``` +codefresh install runtime [options] \ + --set-value=Storage.Backend=ebs \ + --set-value=Storage.AvailabilityZone=us-east-1d \ + --kube-node-selector=failure-domain.beta.kubernetes.io/zone=us-east-1d \ + [--set-value Storage.VolumeProvisioner.NodeSelector=kubernetes.io/role=master] \ + [--set-value Storage.AwsAccessKeyId=ABCDF --set-value Storage.AwsSecretAccessKey=ZYXWV]\ + [--set-value=Storage.Encrypted=true] \ + [--set-value=Storage.KmsKeyId=] +``` + +##### **Azure Disk** +*Prerequisite:* volume provisioner (dind-volume-provisioner) should have permissions to create/delete/get Auzure Disks + +Minimal iam Role for dind-volume-provisioner - dind-volume-provisioner-role.json: +```json +{ + "Name": "CodefreshDindVolumeProvisioner", + "Description": "Perform create/delete/get disks", + "IsCustom": true, + "Actions": [ + "Microsoft.Compute/disks/read", + "Microsoft.Compute/disks/write", + "Microsoft.Compute/disks/delete" + + ], + "AssignableScopes": ["/subscriptions/"] +} +``` +If you use AKS with managed [identities for node group](https://docs.microsoft.com/en-us/azure/aks/use-managed-identity), you can run the script below to assign CodefreshDindVolumeProvisioner role to aks node identity: +```bash +export ROLE_DEFINITIN_FILE=dind-volume-provisioner-role.json +export SUBSCRIPTION_ID=$(az account show --query "id" | xargs echo ) +export RESOURCE_GROUP=codefresh-rt1 +export AKS_NAME=codefresh-rt1 +export LOCATION=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query location | xargs echo) +export NODES_RESOURCE_GROUP=MC_${RESOURCE_GROUP}_${AKS_NAME}_${LOCATION} +export NODE_SERVICE_PRINCIPAL=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query identityProfile.kubeletidentity.objectId | xargs echo) + +az role definition create --role-definition @${ROLE_DEFINITIN_FILE} +az role assignment create --assignee $NODE_SERVICE_PRINCIPAL --scope /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$NODES_RESOURCE_GROUP --role CodefreshDindVolumeProvisioner +``` + +Now create runner with `--set-value Storage.Backend=azuredisk --set Storage.VolumeProvisioner.MountAzureJson=true`: +``` +codefresh runner init --set-value Storage.Backend=azuredisk --set Storage.VolumeProvisioner.MountAzureJson=true +``` +Or using runner-values.yaml file like below: +```yaml +# CodefreshHost: https://g.codefresh.io +# Token: ****** +# Namespace: default +# Context: codefresh-rt1 +# RuntimeInCluster: true +Storage: + Backend: azuredisk + VolumeProvisioner: + MountAzureJson: true +``` +``` +codefresh runner init --values runner-values.yaml +``` + +#### Kubernetes RBAC +Installation of Venona on Kubernetes cluster installing 2 groups of objects, +Each one has own RBAC needs and therefore, created roles(and cluster-roles) +The resource descriptors are avaliable [here](https://github.com/codefresh-io/venona/tree/master/venonactl/templates/kubernetes) +List of the resources that will be created +* Agent (grouped by `/.*.venona.yaml/`) + * `service-account.re.yaml` - The service account that the Venona pod will use to create the resource on the runtime namespace(the resoucre installed on the runtime namespace) + * `role.re.yaml` - Allow to GET, CREATE and DELETE pods and persistentvolumeclaims + * `role-binding.re.yaml` - The agent is spinning up pods and pvc, this biniding binds `role.venona.yaml` to `service-account.venona.yaml` + * `cluster-role-binding.venona.yaml` - The agent discovering K8S apis by calling to `openapi/v2`, this ClusterRoleBinding binds bootstraped ClusterRole by Kubernetes `system:discovery` to `service-account.venona.yaml`. This role has only permissions to make a GET calls to non resources urls +* Runtime-environment (grouped by `/.*.re.yaml/`) Kubernetes controller that spins up all required resources to provide a good caching expirience during pipeline execution + * `service-account.dind-volume-provisioner.re.yaml` - The service account that the controller will use + * `cluster-role.dind-volume-provisioner.re.yaml` Defines all the permission needed for the controller to operate correctly + * `cluster-role-binding.dind-volume-provisioner.yaml` - Binds the ClusterRole to `service-account.dind-volume-provisioner.re.yaml` diff --git a/venonactl/VERSION b/venonactl/VERSION new file mode 100644 index 00000000..f1547e6d --- /dev/null +++ b/venonactl/VERSION @@ -0,0 +1 @@ +2.0.7 diff --git a/venonactl/build/ci.yaml b/venonactl/build/ci.yaml new file mode 100644 index 00000000..c6970987 --- /dev/null +++ b/venonactl/build/ci.yaml @@ -0,0 +1,129 @@ +version: '1.0' +mode: parallel +stages: +- Clone +- Build +- Push +- Release +steps: + + main_clone: + stage: Clone + title: Clone repository + type: git-clone + repo: https://github.com/${{CF_REPO_OWNER}}/${{CF_REPO_NAME}} + revision: ${{CF_BRANCH}} + credentials: + username: github + password: ${{secrets.hybrid.git}} + + export_version: + title: Compare version to venona + stage: Build + image: codefresh/semver + commands: + - export VENONACTL_VERSION=$(cat ./venonactl/VERSION) + - export VENONA_VERSION=$(cat ./venona/VERSION) + - echo "Venona version -> $VENONA_VERSION ---- Venonactl version -> $VENONACTL_VERSION" + - semver-cli equal $VENONACTL_VERSION $VENONA_VERSION + - cf_export VERSION=$VENONACTL_VERSION + when: + steps: + - name: main_clone + on: + - success + + build_cli_image: + title: "Building venona cli image" + type: build + stage: Build + tag: ${{CF_BRANCH_TAG_NORMALIZED}} + working_directory: ${{main_clone}}/venonactl + image_name: ${{IMAGE_NAME}} + build_arguments: + - COMMIT=${{CF_REVISION}} + when: + steps: + - name: export_version + on: + - success + + push_cli_image_dev: + title: "Push image with venona cli" + stage: Push + type: push + candidate: ${{build_cli_image}} + tags: + - ${{CF_BRANCH_TAG_NORMALIZED}} + when: + branch: + ignore: [ "${{RELEASE_BRANCH_NAME}}" ] + steps: + - name: build_cli_image + on: + - success + scale: + push_quay_dev: + registry: "${{REGISTRY_INTEGRATION_QUAY}}" + push_dockerhub_dev: + registry: "${{REGISTRY_INTEGRATION_DOCKERHUB}}" + push_gcr_enterprise_dev: + registry: "${{REGISTRY_INTEGRATION_ENTERPRISE}}" + + push_cli_image_prod: + title: "Push image with venona cli" + stage: Push + type: push + candidate: ${{build_cli_image}} + tags: + - ${{VERSION}} + - latest + when: + branch: + only: [ "${{RELEASE_BRANCH_NAME}}" ] + steps: + - name: build_cli_image + on: + - success + scale: + push_quay_prod: + registry: "${{REGISTRY_INTEGRATION_QUAY}}" + push_dockerhub_prod: + registry: "${{REGISTRY_INTEGRATION_DOCKERHUB}}" + push_gcr_enterprise_prod: + registry: "${{REGISTRY_INTEGRATION_ENTERPRISE}}" + + create_git_tag: + title: Push tag to git + image: quay.io/codefresh/ci-helpers:0.1.0 + stage: Release + commands: + - source /get-token/get-gh-token.sh && cf_export GITHUB_TOKEN + - export OLD_ORIGIN=$(git remote get-url origin) + - git remote rm origin + - git remote add origin https://${GITHUB_TOKEN}@github.com/${{CF_REPO_OWNER}}/venona.git + - git tag ${{VERSION}} + - git push --tags + + fail_fast: false + when: + branch: + only: [ "${{RELEASE_BRANCH_NAME}}" ] + steps: + - name: export_version + - name: main_clone + + release_binaries: + title: Create release in Github with venona CLI + image: goreleaser/goreleaser:v1.18.2 + stage: Release + commands: + - cd venonactl + - goreleaser release -f .goreleaser.yml --rm-dist --skip-validate # pre-release + when: + branch: + only: [ "${{RELEASE_BRANCH_NAME}}" ] + steps: + - name: create_git_tag + on: + - finished diff --git a/venonactl/cmd/attach.go b/venonactl/cmd/attach.go new file mode 100644 index 00000000..512edfbc --- /dev/null +++ b/venonactl/cmd/attach.go @@ -0,0 +1,169 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "fmt" + + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/codefresh-io/venona/venonactl/pkg/store" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var attachRuntimeCmdOptions struct { + runtimeEnvironmentName string + kube struct { + namespace string + inCluster bool + context string + kubePath string + serviceAccount string + host string + } + kubeVenona struct { + namespace string + kubePath string + context string + } + restartAgent bool + templateValues []string + templateFileValues []string + templateValueFiles []string + dryRun bool +} + +var attachRuntimeCmd = &cobra.Command{ + Use: "attach", + Short: "Attach Codefresh runtime to agent", + Run: func(cmd *cobra.Command, args []string) { + // get valuesMap from --values --set-value k=v --set-file k= + templateValuesMap, err := templateValuesToMap( + attachRuntimeCmdOptions.templateValueFiles, + attachRuntimeCmdOptions.templateValues, + attachRuntimeCmdOptions.templateFileValues) + if err != nil { + dieOnError(err) + } + // Merge cmd options with template + mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) + mergeValueStr(templateValuesMap, "ConfigPath", &attachRuntimeCmdOptions.kube.kubePath) + mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) + mergeValueStr(templateValuesMap, "Token", &cfAPIToken) + + mergeValueStr(templateValuesMap, "Namespace", &attachRuntimeCmdOptions.kube.namespace) + mergeValueStr(templateValuesMap, "Context", &attachRuntimeCmdOptions.kube.context) + mergeValueStr(templateValuesMap, "KubernetesHost", &attachRuntimeCmdOptions.kube.host) + mergeValueStr(templateValuesMap, "RuntimeEnvironmentName", &attachRuntimeCmdOptions.runtimeEnvironmentName) + mergeValueStr(templateValuesMap, "RuntimeServiceAccount", &attachRuntimeCmdOptions.kube.serviceAccount) + + s := store.GetStore() + lgr := createLogger("Attach-runtime", verbose, logFormatter) + buildBasicStore(lgr) + extendStoreWithKubeClient(lgr) + + s.CodefreshAPI = &store.CodefreshAPI{} + s.AgentAPI = &store.AgentAPI{} + + if attachRuntimeCmdOptions.kubeVenona.kubePath == "" { + attachRuntimeCmdOptions.kubeVenona.kubePath = kubeConfigPath + } + if attachRuntimeCmdOptions.kubeVenona.namespace == "" { + attachRuntimeCmdOptions.kubeVenona.namespace = attachRuntimeCmdOptions.kube.namespace + } + if attachRuntimeCmdOptions.kubeVenona.context == "" { + attachRuntimeCmdOptions.kubeVenona.context = attachRuntimeCmdOptions.kube.context + } + + if attachRuntimeCmdOptions.kube.serviceAccount == "" { + attachRuntimeCmdOptions.kube.serviceAccount = s.AppName + } + + if attachRuntimeCmdOptions.kube.kubePath == "" { + attachRuntimeCmdOptions.kube.kubePath = kubeConfigPath + } + + fillKubernetesAPI(lgr, attachRuntimeCmdOptions.kubeVenona.context, attachRuntimeCmdOptions.kubeVenona.namespace, false) + + builder := plugins.NewBuilder(lgr) + + builderInstallOpt := &plugins.InstallOptions{ + ClusterNamespace: attachRuntimeCmdOptions.kubeVenona.namespace, + ClusterHost: attachRuntimeCmdOptions.kube.host, + RuntimeEnvironment: attachRuntimeCmdOptions.runtimeEnvironmentName, + RuntimeNamespace: attachRuntimeCmdOptions.kube.namespace, + RuntimeServiceAccount: attachRuntimeCmdOptions.kube.serviceAccount, + RestartAgent: attachRuntimeCmdOptions.restartAgent, + DryRun: attachRuntimeCmdOptions.dryRun, + } + + // runtime + var runtimeInCluster bool + mergeValueBool(templateValuesMap, "RuntimeInCluster", &runtimeInCluster) + builderInstallOpt.KubeBuilder = getKubeClientBuilder(attachRuntimeCmdOptions.kube.context, attachRuntimeCmdOptions.kube.namespace, attachRuntimeCmdOptions.kube.kubePath, runtimeInCluster, attachRuntimeCmdOptions.dryRun) + + // agent + builderInstallOpt.AgentKubeBuilder = getKubeClientBuilder(attachRuntimeCmdOptions.kubeVenona.context, + attachRuntimeCmdOptions.kubeVenona.namespace, + attachRuntimeCmdOptions.kubeVenona.kubePath, + false, + attachRuntimeCmdOptions.dryRun) + + builder.Add(plugins.RuntimeAttachType) + + values := s.BuildValues() + values = mergeMaps(values, templateValuesMap) + spn := createSpinner("Attaching runtime to agent (might take a few seconds)", "") + spn.Start() + for _, p := range builder.Get() { + values, err = p.Install(cmd.Context(), builderInstallOpt, values) + if err != nil { + dieOnError(err) + } + } + spn.Stop() + lgr.Info("Attach to runtime completed Successfully") + + }, +} + +func init() { + rootCmd.AddCommand(attachRuntimeCmd) + viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") + viper.BindEnv("kube-context", "KUBE_CONTEXT") + + viper.SetDefault("kube-namespace", "default") + + attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kube.host, "kube-host", viper.GetString("kube-host"), "overrides the address of the api-server the runner will use") + attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona should be installed [$KUBE_NAMESPACE]") + attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which venona should be installed (default is current-context) [$KUBE_CONTEXT]") + attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kube.kubePath, "kube-config-path", viper.GetString("kubeconfig"), "Path to kubeconfig file (default is $HOME/.kube/config) [$KUBECONFIG]") + attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kube.serviceAccount, "kube-service-account", viper.GetString("kube-service-account"), fmt.Sprintf("Name of the kubernetes service account (default is %s)", plugins.AppName)) + + attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.runtimeEnvironmentName, "runtime-name", viper.GetString("runtime-name"), "Name of the runtime as in codefresh") + + attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kubeVenona.namespace, "kube-namespace-agent", viper.GetString("kube-namespace-agent"), "Name of the namespace where venona is installed [$KUBE_NAMESPACE]") + attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kubeVenona.context, "kube-context-name-agent", viper.GetString("kube-context-agent"), "Name of the kubernetes context on which venona is installed (default is current-context) [$KUBE_CONTEXT]") + attachRuntimeCmd.Flags().StringVar(&attachRuntimeCmdOptions.kubeVenona.kubePath, "kube-config-path-agent", viper.GetString("kubeconfig-agent"), "Path to kubeconfig file (default is $HOME/.kube/config) for agent [$KUBECONFIG]") + attachRuntimeCmd.Flags().BoolVar(&attachRuntimeCmdOptions.restartAgent, "restart-agent", viper.GetBool("restart-agent"), "Restart agent after attach operation") + attachRuntimeCmd.Flags().BoolVar(&attachRuntimeCmdOptions.dryRun, "dry-run", false, "Set to true to simulate installation") + + attachRuntimeCmd.Flags().StringArrayVar(&attachRuntimeCmdOptions.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") + attachRuntimeCmd.Flags().StringArrayVar(&attachRuntimeCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") + attachRuntimeCmd.Flags().StringArrayVarP(&attachRuntimeCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") + +} diff --git a/venonactl/cmd/cmdutils.go b/venonactl/cmd/cmdutils.go new file mode 100644 index 00000000..acb9fe06 --- /dev/null +++ b/venonactl/cmd/cmdutils.go @@ -0,0 +1,320 @@ +package cmd + +import ( + "fmt" + "os" + "os/user" + "path/filepath" + "strings" + "time" + + "encoding/json" + + "github.com/briandowns/spinner" + "github.com/codefresh-io/go-sdk/pkg/codefresh" + sdkUtils "github.com/codefresh-io/go-sdk/pkg/utils" + "github.com/codefresh-io/venona/venonactl/pkg/certs" + "github.com/codefresh-io/venona/venonactl/pkg/kube" + "github.com/codefresh-io/venona/venonactl/pkg/logger" + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/codefresh-io/venona/venonactl/pkg/store" + "github.com/olekukonko/tablewriter" + k8sApi "k8s.io/api/core/v1" + "k8s.io/client-go/tools/clientcmd" + + "github.com/stretchr/objx" + cliValues "helm.sh/helm/v3/pkg/cli/values" + "helm.sh/helm/v3/pkg/getter" +) + +var ( + version = "dev" + commit = "none" + date = "unknown" + + verbose bool + logFormatter string + + configPath string + cfAPIHost string + cfAPIToken string + cfContext string + + kubeConfigPath string +) + +func buildBasicStore(logger logger.Logger) { + s := store.GetStore() + s.Version = &store.Version{ + Current: &store.CurrentVersion{ + Version: version, + Commit: commit, + Date: date, + }, + } + + s.Image = &store.Image{ + Name: "codefresh/venona", + } + + s.Mode = store.ModeInCluster + + s.ServerCert = &certs.ServerCert{} + + s.AppName = store.ApplicationName + s.Image.Tag = s.Version.Current.Version +} + +func extendStoreWithCodefershClient(logger logger.Logger) error { + s := store.GetStore() + if configPath == "" { + currentUser, err := user.Current() + if err != nil { + return err + } + + configPath = filepath.Join(currentUser.HomeDir, ".cfconfig") + logger.Debug(fmt.Sprint("cfconfig path not set, using: ", configPath)) + } + + if _, err := os.Stat(configPath); err != nil { + return fmt.Errorf(".cfconfig file not found") + } + + if cfAPIHost == "" && cfAPIToken == "" { + context, err := sdkUtils.ReadAuthContext(configPath, cfContext) + if err != nil { + return err + } + cfAPIHost = context.URL + cfAPIToken = context.Token + logger.Debug("Using codefresh context", "Context-Name", context.Name, "Host", cfAPIHost) + } else { + logger.Debug("Reading credentials from environment variables") + if cfAPIHost == "" { + cfAPIHost = "https://g.codefresh.io" + } + } + + logger.Debug("Creating codefresh client", "host", cfAPIHost, "token", cfAPIToken) + + client := codefresh.New(&codefresh.ClientOptions{ + Auth: codefresh.AuthOptions{ + Token: cfAPIToken, + }, + Host: cfAPIHost, + }) + s.CodefreshAPI = &store.CodefreshAPI{ + Host: cfAPIHost, + Token: cfAPIToken, + Client: client, + } + + return nil +} + +func extendStoreWithKubeClient(logger logger.Logger) { + s := store.GetStore() + if kubeConfigPath == "" { + currentUser, _ := user.Current() + if currentUser != nil { + kubeConfigPath = filepath.Join(currentUser.HomeDir, ".kube", "config") + logger.Debug("Path to kubeconfig not set, using:", "kubeconfig", kubeConfigPath) + } + } + + s.KubernetesAPI = &store.KubernetesAPI{ + ConfigPath: kubeConfigPath, + } +} + +func setVerbosity(verbose bool) { + s := store.GetStore() + s.Verbose = verbose +} + +func setInsecure(insecure bool) { + s := store.GetStore() + s.Insecure = insecure +} + +func isUsingDefaultStorageClass(sc string) bool { + if sc == "" { + return true + } + return strings.HasPrefix(sc, plugins.DefaultStorageClassNamePrefix) +} + +func dieOnError(err error) { + if err != nil { + fmt.Printf("Error: %s\n", err.Error()) + os.Exit(1) + } +} + +func createTable() *tablewriter.Table { + table := tablewriter.NewWriter(os.Stdout) + table.SetBorder(false) + table.SetAlignment(tablewriter.ALIGN_LEFT) + table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) + table.SetRowLine(false) + table.SetHeaderLine(false) + table.SetColumnSeparator(" ") + table.SetColWidth(100) + return table +} + +func getKubeClientBuilder(context string, namespace string, path string, inCluster bool, dryRun bool) kube.Kube { + return kube.New(&kube.Options{ + ContextName: context, + Namespace: namespace, + PathToKubeConfig: path, + InCluster: inCluster, + DryRun: dryRun, + }) +} + +func createLogger(command string, verbose bool, logFormatter string) logger.Logger { + logFile := "venonalog.json" + os.Remove(logFile) + return logger.New(&logger.Options{ + Command: command, + Verbose: verbose, + LogToFile: logFile, + LogFormatter: logFormatter, + }) +} + +func createSpinner(prefix, suffix string) *spinner.Spinner { + s := spinner.New([]string{" ", ". ", ".. ", "..."}, 520*time.Millisecond) + s.Suffix = suffix + s.Prefix = prefix + return s +} + +func loadTolerationsFromFile(filename string) string { + data, err := os.ReadFile(filename) + if err != nil { + dieOnError(err) + } + + return string(data) +} + +func parseTolerations(s string) ([]k8sApi.Toleration, error) { + if s == "" { + return nil, nil + } + var data []k8sApi.Toleration + err := json.Unmarshal([]byte(s), &data) + if err != nil { + return nil, fmt.Errorf("can not parse tolerations: %s", err) + } + return data, err +} + +func fillKubernetesAPI(lgr logger.Logger, context string, namespace string, inCluster bool) { + + s := store.GetStore() + if context == "" { + config := clientcmd.GetConfigFromFileOrDie(s.KubernetesAPI.ConfigPath) + context = config.CurrentContext + lgr.Debug("Kube Context is not set, using current context", "Kube-Context-Name", context) + } + if namespace == "" { + namespace = "default" + } + + s.KubernetesAPI.InCluster = inCluster + s.KubernetesAPI.ContextName = context + s.KubernetesAPI.Namespace = namespace + +} + +func extendStoreWithAgentAPI(logger logger.Logger, token string, agentID string) { + s := store.GetStore() + logger.Debug("Using agent's token", "Token", token) + s.AgentAPI = &store.AgentAPI{ + Token: token, + Id: agentID, + } +} + +// Parsing helpers --set-value , --set-file +// by https://github.com/helm/helm/blob/ec1d1a3d3eb672232f896f9d3b3d0797e4f519e3/pkg/cli/values/options.go#L41 + +// templateValuesToMap - processes cmd --values --set-value k=v --set-file v= +// using helm libraries +func templateValuesToMap(templateValueFiles, templateValues, templateFileValues []string) (map[string]interface{}, error) { + valueOpts := &cliValues.Options{} + if len(templateValueFiles) > 0 { + for _, v := range templateValueFiles { + valueOpts.ValueFiles = append(valueOpts.ValueFiles, v) + } + } + + if len(templateValues) > 0 { + for _, v := range templateValues { + valueOpts.Values = append(valueOpts.Values, v) + } + } + + if len(templateFileValues) > 0 { + for _, v := range templateFileValues { + valueOpts.FileValues = append(valueOpts.FileValues, v) + } + } + valuesMap, err := valueOpts.MergeValues(getter.Providers{}) + return valuesMap, err +} + +func mergeMaps(a, b map[string]interface{}) map[string]interface{} { + out := make(map[string]interface{}, len(a)) + for k, v := range a { + out[k] = v + } + for k, v := range b { + if v, ok := v.(map[string]interface{}); ok { + if bv, ok := out[k]; ok { + if bv, ok := bv.(map[string]interface{}); ok { + out[k] = mergeMaps(bv, v) + continue + } + } + } + out[k] = v + } + return out +} + +// mergeValueStr - for merging cli parameters with mapped parameters +func mergeValueStr(valuesMap map[string]interface{}, key string, param *string, defaultValue ...string) { + mapX := objx.New(valuesMap) + if param != nil && *param != "" { + mapX.Set(key, *param) + return + } + val := mapX.Get(key).Str(defaultValue...) + *param = val +} + +// mergeValueBool - for merging cli parameters with mapped parameters +func mergeValueBool(valuesMap map[string]interface{}, key string, param *bool) { + mapX := objx.New(valuesMap) + if param != nil || *param == true { + mapX.Set(key, *param) + return + } + val := mapX.Get(key).Bool() + *param = val +} + +func mergeValueMSI(valuesMap map[string]interface{}, key string, param *map[string]interface{}, defaultValue ...map[string]interface{}) { + mapX := objx.New(valuesMap) + if param != nil && len(*param) > 0 { + mapX.Set(key, *param) + return + } + val := mapX.Get(key).MSI(defaultValue...) + *param = val +} diff --git a/venonactl/cmd/install-agent.go b/venonactl/cmd/install-agent.go new file mode 100644 index 00000000..79ffd2ea --- /dev/null +++ b/venonactl/cmd/install-agent.go @@ -0,0 +1,215 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "fmt" + "strings" + + "github.com/codefresh-io/venona/venonactl/pkg/logger" + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/codefresh-io/venona/venonactl/pkg/store" + "github.com/spf13/cobra" + "github.com/spf13/viper" + k8sApi "k8s.io/api/core/v1" + // cliValues "helm.sh/helm/v3/pkg/cli/values" + // "helm.sh/helm/v3/pkg/getter" +) + +var installAgentCmdOptions struct { + dryRun bool + kube struct { + namespace string + inCluster bool + context string + nodeSelector string + } + venona struct { + version string + } + agentToken string + agentID string + tolerations string + envVars []string + dockerRegistry string + templateValues []string + templateFileValues []string + templateValueFiles []string + resources map[string]interface{} +} + +var installAgentCmd = &cobra.Command{ + Use: "agent", + Short: "Install Codefresh's agent ", + Run: func(cmd *cobra.Command, args []string) { + + // get valuesMap from --values --set-value k=v --set-file k= + templateValuesMap, err := templateValuesToMap( + installAgentCmdOptions.templateValueFiles, + installAgentCmdOptions.templateValues, + installAgentCmdOptions.templateFileValues) + if err != nil { + dieOnError(err) + } + // Merge cmd options with template + mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) + mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) + mergeValueStr(templateValuesMap, "Token", &cfAPIToken) + mergeValueStr(templateValuesMap, "Namespace", &installAgentCmdOptions.kube.namespace) + mergeValueStr(templateValuesMap, "Context", &installAgentCmdOptions.kube.context) + mergeValueStr(templateValuesMap, "NodeSelector", &installAgentCmdOptions.kube.nodeSelector) + tolerations := getTolerations() + if tolerations != nil { + templateValuesMap["Tolerations"] = tolerations + } + mergeValueStr(templateValuesMap, "DockerRegistry", &installAgentCmdOptions.dockerRegistry) + + mergeValueStr(templateValuesMap, "AgentToken", &installAgentCmdOptions.agentToken) + mergeValueStr(templateValuesMap, "AgentId", &installAgentCmdOptions.agentID) + mergeValueStr(templateValuesMap, "Image.Tag", &installAgentCmdOptions.venona.version) + + mergeValueMSI(templateValuesMap, "Runner.resources", &installAgentCmdOptions.resources) + + //mergeValueStrArray(&installAgentCmdOptions.envVars, "envVars", nil, "More env vars to be declared \"key=value\"") + + mergeValueBool(templateValuesMap, "InCluster", &installAgentCmdOptions.kube.inCluster) + + s := store.GetStore() + lgr := createLogger("Install-agent", verbose, logFormatter) + buildBasicStore(lgr) + + extendStoreWithAgentAPI(lgr, installAgentCmdOptions.agentToken, installAgentCmdOptions.agentID) + extendStoreWithKubeClient(lgr) + fillCodefreshAPI(lgr) + builder := plugins.NewBuilder(lgr) + if cfAPIHost == "" { + cfAPIHost = "https://g.codefresh.io" + } + builderInstallOpt := &plugins.InstallOptions{ + CodefreshHost: cfAPIHost, + } + + if installAgentCmdOptions.agentToken == "" { + installAgentCmdOptions.agentToken = cfAPIToken + } + if installAgentCmdOptions.agentToken == "" { + dieOnError(fmt.Errorf("Agent token is required in order to install agent")) + } + + if installAgentCmdOptions.agentID == "" { + dieOnError(fmt.Errorf("Agent id is required in order to install agent")) + } + + fillKubernetesAPI(lgr, installAgentCmdOptions.kube.context, installAgentCmdOptions.kube.namespace, false) + s.Runner.Resources = installAgentCmdOptions.resources + + s.KubernetesAPI.Tolerations = tolerations + + if installAgentCmdOptions.venona.version != "" { + version := installAgentCmdOptions.venona.version + lgr.Info("Version set manually", "version", version) + s.Image.Tag = version + s.Version.Current.Version = version + } + s.DockerRegistry = installAgentCmdOptions.dockerRegistry + if installAgentCmdOptions.envVars != nil { + s.AdditionalEnvVars = make(map[string]string) + for _, part := range installAgentCmdOptions.envVars { + splited := strings.Split(part, "=") + s.AdditionalEnvVars[splited[0]] = splited[1] + } + } + + s.KubernetesAPI.NodeSelector = installAgentCmdOptions.kube.nodeSelector + + builderInstallOpt.ClusterName = s.KubernetesAPI.ContextName + builderInstallOpt.KubeBuilder = getKubeClientBuilder(builderInstallOpt.ClusterName, s.KubernetesAPI.Namespace, s.KubernetesAPI.ConfigPath, + s.KubernetesAPI.InCluster, + installAgentCmdOptions.dryRun) + builderInstallOpt.ClusterNamespace = s.KubernetesAPI.Namespace + builderInstallOpt.DryRun = installAgentCmdOptions.dryRun + + builder.Add(plugins.VenonaPluginType) + + values := s.BuildValues() + values = mergeMaps(values, templateValuesMap) + + for _, p := range builder.Get() { + values, err = p.Install(cmd.Context(), builderInstallOpt, values) + if err != nil { + dieOnError(err) + } + } + lgr.Info("Agent installation completed Successfully") + }, +} + +func getTolerations() []k8sApi.Toleration { + + if installAgentCmdOptions.tolerations != "" { + var tolerationsString string + + if installAgentCmdOptions.tolerations[0] == '@' { + tolerationsString = loadTolerationsFromFile(installAgentCmdOptions.tolerations[1:]) + } else { + tolerationsString = installAgentCmdOptions.tolerations + } + + tolerations, err := parseTolerations(tolerationsString) + if err != nil { + dieOnError(err) + } + return tolerations + + } + return nil +} + +func init() { + installCommand.AddCommand(installAgentCmd) + + viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") + viper.BindEnv("kube-context", "KUBE_CONTEXT") + + viper.SetDefault("kube-namespace", "default") + + installAgentCmd.Flags().StringVar(&installAgentCmdOptions.agentToken, "agentToken", "", "Agent token created by codefresh") + installAgentCmd.Flags().StringVar(&installAgentCmdOptions.agentID, "agentId", "", "Agent id created by codefresh") + installAgentCmd.Flags().StringVar(&installAgentCmdOptions.venona.version, "venona-version", "", "Version of venona to install (default is the latest)") + installAgentCmd.Flags().StringVar(&installAgentCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona should be installed [$KUBE_NAMESPACE]") + installAgentCmd.Flags().StringVar(&installAgentCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which venona should be installed (default is current-context) [$KUBE_CONTEXT]") + installAgentCmd.Flags().StringVar(&installAgentCmdOptions.kube.nodeSelector, "kube-node-selector", "", "The kubernetes node selector \"key=value\" to be used by venona resources (default is no node selector)") + installAgentCmd.Flags().StringVar(&installAgentCmdOptions.tolerations, "tolerations", "", "The kubernetes tolerations as JSON string to be used by venona resources (default is no tolerations)") + installAgentCmd.Flags().StringArrayVar(&installAgentCmdOptions.envVars, "envVars", nil, "More env vars to be declared \"key=value\"") + installAgentCmd.Flags().StringVar(&installAgentCmdOptions.dockerRegistry, "docker-registry", "", "The prefix for the container registry that will be used for pulling the required components images. Example: --docker-registry=\"docker.io\"") + + installAgentCmd.Flags().BoolVar(&installAgentCmdOptions.kube.inCluster, "in-cluster", false, "Set flag if venona is been installed from inside a cluster") + installAgentCmd.Flags().BoolVar(&installAgentCmdOptions.dryRun, "dry-run", false, "Set to true to simulate installation") + + installAgentCmd.Flags().StringArrayVar(&installAgentCmdOptions.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") + installAgentCmd.Flags().StringArrayVar(&installAgentCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") + installAgentCmd.Flags().StringArrayVarP(&installAgentCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") + +} + +func fillCodefreshAPI(logger logger.Logger) { + s := store.GetStore() + s.CodefreshAPI = &store.CodefreshAPI{ + Host: cfAPIHost, + } + +} diff --git a/venonactl/cmd/install-app-proxy.go b/venonactl/cmd/install-app-proxy.go new file mode 100644 index 00000000..925fa844 --- /dev/null +++ b/venonactl/cmd/install-app-proxy.go @@ -0,0 +1,119 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "fmt" + + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/codefresh-io/venona/venonactl/pkg/store" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var installAppProxyCmdOptions struct { + kube struct { + namespace string + context string + } + dockerRegistry string + templateValues []string + templateFileValues []string + templateValueFiles []string + resources map[string]interface{} + host string + ingressClass string + dryRun bool +} + +var installAppProxyCmd = &cobra.Command{ + Use: "app-proxy", + Short: "Install App proxy ", + Run: func(cmd *cobra.Command, args []string) { + + templateValuesMap, err := templateValuesToMap( + installAppProxyCmdOptions.templateValueFiles, + installAppProxyCmdOptions.templateValues, + installAppProxyCmdOptions.templateFileValues) + if err != nil { + dieOnError(err) + } + + mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) + mergeValueStr(templateValuesMap, "Namespace", &installAppProxyCmdOptions.kube.namespace) + mergeValueStr(templateValuesMap, "Context", &installAppProxyCmdOptions.kube.context) + mergeValueStr(templateValuesMap, "AppProxy.Ingress.Host", &installAppProxyCmdOptions.host) + mergeValueStr(templateValuesMap, "AppProxy.Ingress.IngressClass", &installAppProxyCmdOptions.ingressClass) + mergeValueStr(templateValuesMap, "DockerRegistry", &installAppProxyCmdOptions.dockerRegistry) + mergeValueMSI(templateValuesMap, "AppProxy.resources", &installAppProxyCmdOptions.resources) + + s := store.GetStore() + lgr := createLogger("Install-agent", verbose, logFormatter) + buildBasicStore(lgr) + builder := plugins.NewBuilder(lgr) + if installAppProxyCmdOptions.host == "" { + dieOnError(fmt.Errorf("host options is required in order to install app-proxy")) + } + if cfAPIHost == "" { + cfAPIHost = "https://g.codefresh.io" + } + builderInstallOpt := &plugins.InstallOptions{ + CodefreshHost: cfAPIHost, + DryRun: installAppProxyCmdOptions.dryRun, + } + s.AppProxy.Resources = installAppProxyCmdOptions.resources + s.DockerRegistry = installAppProxyCmdOptions.dockerRegistry + extendStoreWithKubeClient(lgr) + fillCodefreshAPI(lgr) + fillKubernetesAPI(lgr, installAppProxyCmdOptions.kube.context, installAppProxyCmdOptions.kube.namespace, false) + s.AgentAPI = &store.AgentAPI{ + Token: "", + Id: "", + } + + builderInstallOpt.ClusterName = s.KubernetesAPI.ContextName + builderInstallOpt.KubeBuilder = getKubeClientBuilder(builderInstallOpt.ClusterName, s.KubernetesAPI.Namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, builderInstallOpt.DryRun) + builderInstallOpt.ClusterNamespace = s.KubernetesAPI.Namespace + builder.Add(plugins.AppProxyPluginType) + + values := s.BuildValues() + values = mergeMaps(values, templateValuesMap) + for _, p := range builder.Get() { + values, err = p.Install(cmd.Context(), builderInstallOpt, values) + if err != nil { + dieOnError(err) + } + } + + lgr.Info("App proxy installation completed Successfully") + }, +} + +func init() { + viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") + viper.BindEnv("kube-context", "KUBE_CONTEXT") + installCommand.AddCommand(installAppProxyCmd) + installAppProxyCmd.Flags().StringVar(&installAppProxyCmdOptions.dockerRegistry, "docker-registry", "", "The prefix for the container registry that will be used for pulling the required components images. Example: --docker-registry=\"docker.io\"") + installAppProxyCmd.Flags().StringVar(&installAppProxyCmdOptions.host, "host", "", "Host name that will be used by the ingress to route traffic to the App-Proxy service") + installAppProxyCmd.Flags().StringVar(&installAppProxyCmdOptions.ingressClass, "ingress-class", "", "The ingress class name that will be used by the App-Proxy ingress. If left empty, the default one will be used") + installAppProxyCmd.Flags().StringVar(&installAppProxyCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona should be installed [$KUBE_NAMESPACE]") + installAppProxyCmd.Flags().StringVar(&installAppProxyCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which venona should be installed (default is current-context) [$KUBE_CONTEXT]") + installAppProxyCmd.Flags().StringArrayVarP(&installAppProxyCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") + installAppProxyCmd.Flags().StringArrayVar(&installAppProxyCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") + installAppProxyCmd.Flags().StringArrayVar(&installAppProxyCmdOptions.templateValues, "set-value", []string{}, "Set values for templates, example: --set-value LocalVolumesDir=/mnt/disks/ssd0/codefresh-volumes") + installAppProxyCmd.Flags().BoolVar(&installAppProxyCmdOptions.dryRun, "dry-run", false, "Set to true to simulate installation") +} diff --git a/venonactl/cmd/install-monitor.go b/venonactl/cmd/install-monitor.go new file mode 100644 index 00000000..72690227 --- /dev/null +++ b/venonactl/cmd/install-monitor.go @@ -0,0 +1,148 @@ +package cmd + +/* +Copyright 2020 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "fmt" + + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/codefresh-io/venona/venonactl/pkg/store" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var installMonitorAgentCmdOptions struct { + kube struct { + namespace string + context string + nodeSelector string + } + clusterId string + helm3 bool + codefreshToken string + codefreshHost string + dockerRegistry string + templateValues []string + templateFileValues []string + templateValueFiles []string + resources map[string]interface{} + dryRun bool +} + +// installK8sAgentCmd represents the install command +var installMonitorAgentCmd = &cobra.Command{ + Use: "monitor", + Short: "Install Codefresh's monitor agent on cluster", + Run: func(cmd *cobra.Command, args []string) { + // get valuesMap from --values --set-value k=v --set-file k= + templateValuesMap, err := templateValuesToMap( + installMonitorAgentCmdOptions.templateValueFiles, + installMonitorAgentCmdOptions.templateValues, + installMonitorAgentCmdOptions.templateFileValues) + if err != nil { + dieOnError(err) + } + // Merge cmd options with template + mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) + mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) + mergeValueStr(templateValuesMap, "CodefreshHost", &installMonitorAgentCmdOptions.codefreshHost) + mergeValueStr(templateValuesMap, "Token", &cfAPIToken) + mergeValueStr(templateValuesMap, "Token", &installMonitorAgentCmdOptions.codefreshToken) + mergeValueStr(templateValuesMap, "Namespace", &installMonitorAgentCmdOptions.kube.namespace) + mergeValueStr(templateValuesMap, "Context", &installMonitorAgentCmdOptions.kube.context) + + mergeValueMSI(templateValuesMap, "Monitor.resources", &installMonitorAgentCmdOptions.resources) + + mergeValueStr(templateValuesMap, "DockerRegistry", &installMonitorAgentCmdOptions.dockerRegistry) + mergeValueStr(templateValuesMap, "ClusterId", &installMonitorAgentCmdOptions.clusterId) + mergeValueBool(templateValuesMap, "helm3", &installMonitorAgentCmdOptions.helm3) + + s := store.GetStore() + + lgr := createLogger("Install-monitor-agent", verbose, logFormatter) + buildBasicStore(lgr) + extendStoreWithKubeClient(lgr) + fillKubernetesAPI(lgr, installMonitorAgentCmdOptions.kube.context, installMonitorAgentCmdOptions.kube.namespace, false) + s.Monitor.Resources = installMonitorAgentCmdOptions.resources + + builder := plugins.NewBuilder(lgr) + builder.Add(plugins.MonitorAgentPluginType) + + builderInstallOpt := &plugins.InstallOptions{ + ClusterNamespace: s.KubernetesAPI.Namespace, + DryRun: installMonitorAgentCmdOptions.dryRun, + } + + builderInstallOpt.KubeBuilder = getKubeClientBuilder(s.KubernetesAPI.ContextName, s.KubernetesAPI.Namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, installMonitorAgentCmdOptions.dryRun) + + if installMonitorAgentCmdOptions.clusterId == "" { + dieOnError(fmt.Errorf("Cluster id is required in order to install monitor")) + } + + s.ClusterId = installMonitorAgentCmdOptions.clusterId + s.Helm3 = installMonitorAgentCmdOptions.helm3 + s.DockerRegistry = installMonitorAgentCmdOptions.dockerRegistry + + if installMonitorAgentCmdOptions.codefreshHost == "" { + installMonitorAgentCmdOptions.codefreshHost = "https://g.codefresh.io" + } + + if installMonitorAgentCmdOptions.codefreshToken == "" { + dieOnError(fmt.Errorf("Codefresh token is required in order to install monitor")) + } + + s.CodefreshAPI = &store.CodefreshAPI{ + Host: installMonitorAgentCmdOptions.codefreshHost, + Token: installMonitorAgentCmdOptions.codefreshToken, + } + + // stub , not need actually for monitor + s.AgentAPI = &store.AgentAPI{ + Token: "", + Id: "", + } + + values := s.BuildValues() + values = mergeMaps(values, templateValuesMap) + + for _, p := range builder.Get() { + _, err := p.Install(cmd.Context(), builderInstallOpt, values) + dieOnError(err) + } + lgr.Info("Monitor agent installation completed Successfully") + }, +} + +func init() { + installCommand.AddCommand(installMonitorAgentCmd) + + viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") + viper.BindEnv("kube-context", "KUBE_CONTEXT") + installMonitorAgentCmd.Flags().StringVar(&installMonitorAgentCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which monitor should be installed [$KUBE_NAMESPACE]") + installMonitorAgentCmd.Flags().StringVar(&installMonitorAgentCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which monitor should be installed (default is current-context) [$KUBE_CONTEXT]") + installMonitorAgentCmd.Flags().StringVar(&installMonitorAgentCmdOptions.clusterId, "clusterId", "", "Cluster Id") + installMonitorAgentCmd.Flags().StringVar(&installMonitorAgentCmdOptions.codefreshToken, "codefreshToken", "", "Codefresh token") + installMonitorAgentCmd.Flags().StringVar(&installMonitorAgentCmdOptions.dockerRegistry, "docker-registry", "", "The prefix for the container registry that will be used for pulling the required components images. Example: --docker-registry=\"docker.io\"") + + installMonitorAgentCmd.Flags().StringVar(&installMonitorAgentCmdOptions.codefreshHost, "codefreshHost", "", "Override codefresh host if you use your own codefresh installation") + installMonitorAgentCmd.Flags().BoolVar(&installMonitorAgentCmdOptions.dryRun, "dry-run", false, "Set to true to simulate installation") + installMonitorAgentCmd.Flags().BoolVar(&installMonitorAgentCmdOptions.helm3, "helm3", false, "Set flag if cluster use helm3") + installMonitorAgentCmd.Flags().StringArrayVar(&installMonitorAgentCmdOptions.templateValues, "set-value", []string{}, "Set values for templates, example: --set-value LocalVolumesDir=/mnt/disks/ssd0/codefresh-volumes") + installMonitorAgentCmd.Flags().StringArrayVar(&installMonitorAgentCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file, example: --set-file Storage.GoogleServiceAccount=/path/to/service-account.json") + installMonitorAgentCmd.Flags().StringArrayVarP(&installMonitorAgentCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") + +} diff --git a/venonactl/cmd/install-runtime.go b/venonactl/cmd/install-runtime.go new file mode 100644 index 00000000..6f840074 --- /dev/null +++ b/venonactl/cmd/install-runtime.go @@ -0,0 +1,197 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "fmt" + + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/codefresh-io/venona/venonactl/pkg/store" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var installRuntimeCmdOptions struct { + codefreshToken string + dryRun bool + insecure bool + kube struct { + namespace string + inCluster bool + context string + nodeSelector string + } + storageClass string + dockerRegistry string + runtimeEnvironmentName string + tolerations string + templateValues []string + templateFileValues []string + templateValueFiles []string + volumeProvisioner map[string]interface{} + localVolumeMonitor map[string]interface{} +} + +var installRuntimeCmd = &cobra.Command{ + Use: "runtime", + Short: "Install Codefresh's runtime", + Run: func(cmd *cobra.Command, args []string) { + + // get valuesMap from --values --set-value k=v --set-file k= + templateValuesMap, err := templateValuesToMap( + installRuntimeCmdOptions.templateValueFiles, + installRuntimeCmdOptions.templateValues, + installRuntimeCmdOptions.templateFileValues) + if err != nil { + dieOnError(err) + } + // Merge cmd options with template + mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) + mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) + mergeValueStr(templateValuesMap, "Token", &cfAPIToken) + mergeValueStr(templateValuesMap, "Token", &installRuntimeCmdOptions.codefreshToken) + + mergeValueStr(templateValuesMap, "Namespace", &installRuntimeCmdOptions.kube.namespace) + mergeValueStr(templateValuesMap, "Context", &installRuntimeCmdOptions.kube.context) + mergeValueStr(templateValuesMap, "RuntimeEnvironmentName", &installRuntimeCmdOptions.runtimeEnvironmentName) + mergeValueStr(templateValuesMap, "NodeSelector", &installRuntimeCmdOptions.kube.nodeSelector) + tolerations := getTolerations() + if tolerations != nil { + templateValuesMap["Tolerations"] = tolerations + } + //mergeValueStrArray(&installAgentCmdOptions.envVars, "envVars", nil, "More env vars to be declared \"key=value\"") + mergeValueStr(templateValuesMap, "DockerRegistry", &installRuntimeCmdOptions.dockerRegistry) + mergeValueStr(templateValuesMap, "StorageClass", &installRuntimeCmdOptions.storageClass) + + defaultVolumeProvResources := map[string]interface{}{ + "limits": map[string]string{ + "cpu": "1000m", + "memory": "6000Mi", + }, + "requests": map[string]string{ + "cpu": "200m", + "memory": "200Mi", + }, + } + mergeValueMSI(templateValuesMap, "Storage.VolumeProvisioner.resources", &installRuntimeCmdOptions.volumeProvisioner, defaultVolumeProvResources) + mergeValueMSI(templateValuesMap, "Storage.LocalVolumeMonitor.resources", &installRuntimeCmdOptions.localVolumeMonitor) + + mergeValueBool(templateValuesMap, "InCluster", &installRuntimeCmdOptions.kube.inCluster) + mergeValueBool(templateValuesMap, "insecure", &installRuntimeCmdOptions.insecure) + + s := store.GetStore() + lgr := createLogger("Install-runtime", verbose, logFormatter) + buildBasicStore(lgr) + extendStoreWithAgentAPI(lgr, installRuntimeCmdOptions.codefreshToken, "") + extendStoreWithKubeClient(lgr) + + if installRuntimeCmdOptions.runtimeEnvironmentName == "" { + dieOnError(fmt.Errorf("Codefresh envrionment name is required")) + } + if cfAPIHost == "" { + cfAPIHost = "https://g.codefresh.io" + } + // This is temporarily and used for signing + s.CodefreshAPI = &store.CodefreshAPI{ + Host: cfAPIHost, + } + + s.KubernetesAPI.Tolerations = tolerations + + s.KubernetesAPI.NodeSelector = installRuntimeCmdOptions.kube.nodeSelector + s.DockerRegistry = installRuntimeCmdOptions.dockerRegistry + + builder := plugins.NewBuilder(lgr) + isDefault := isUsingDefaultStorageClass(installRuntimeCmdOptions.storageClass) + + builderInstallOpt := &plugins.InstallOptions{ + StorageClass: installRuntimeCmdOptions.storageClass, + IsDefaultStorageClass: isDefault, + DryRun: installRuntimeCmdOptions.dryRun, + CodefreshHost: cfAPIHost, + CodefreshToken: installRuntimeCmdOptions.codefreshToken, + RuntimeEnvironment: installRuntimeCmdOptions.runtimeEnvironmentName, + ClusterNamespace: installRuntimeCmdOptions.kube.namespace, + Insecure: installRuntimeCmdOptions.insecure, + } + + if isDefault { + builderInstallOpt.StorageClass = plugins.DefaultStorageClassNamePrefix + } + + fillKubernetesAPI(lgr, installRuntimeCmdOptions.kube.context, installRuntimeCmdOptions.kube.namespace, installRuntimeCmdOptions.kube.inCluster) + s.VolumeProvisioner.Resources = installRuntimeCmdOptions.volumeProvisioner + s.LocalVolumeMonitor.Resources = installRuntimeCmdOptions.localVolumeMonitor + + if installRuntimeCmdOptions.dryRun { + s.DryRun = installRuntimeCmdOptions.dryRun + lgr.Info("Running in dry-run mode") + } + + // s.ClusterInCodefresh = installRuntimeCmdOptions.clusterNameInCodefresh + + builder.Add(plugins.RuntimeEnvironmentPluginType) + builder.Add(plugins.EnginePluginType) + + if isDefault { + builder.Add(plugins.VolumeProvisionerPluginType) + } else { + lgr.Info("Custom StorageClass is set, skipping installation of default volume provisioner") + } + + builderInstallOpt.KubeBuilder = getKubeClientBuilder(s.KubernetesAPI.ContextName, s.KubernetesAPI.Namespace, s.KubernetesAPI.ConfigPath, + s.KubernetesAPI.InCluster, + installRuntimeCmdOptions.dryRun) + values := s.BuildValues() + values = mergeMaps(values, templateValuesMap) + + for _, p := range builder.Get() { + values, err = p.Install(cmd.Context(), builderInstallOpt, values) + if err != nil { + dieOnError(err) + } + } + lgr.Info("Runtime installation completed Successfully") + + }, +} + +func init() { + installCommand.AddCommand(installRuntimeCmd) + + viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") + viper.BindEnv("kube-context", "KUBE_CONTEXT") + + viper.SetDefault("kube-namespace", "default") + + installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.codefreshToken, "codefreshToken", "", "Codefresh token") + installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.runtimeEnvironmentName, "runtimeName", viper.GetString("runtimeName"), "Name of the runtime as in codefresh") + installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona should be installed [$KUBE_NAMESPACE]") + installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which venona should be installed (default is current-context) [$KUBE_CONTEXT]") + installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.storageClass, "storage-class", "", "Set a name of your custom storage class, note: this will not install volume provisioning components") + installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.dockerRegistry, "docker-registry", "", "The prefix for the container registry that will be used for pulling the required components images. Example: --docker-registry=\"docker.io\"") + + installRuntimeCmd.Flags().BoolVar(&installRuntimeCmdOptions.insecure, "insecure", false, "Set to true to disable TLS when communicating with the codefresh platform") + installRuntimeCmd.Flags().BoolVar(&installRuntimeCmdOptions.kube.inCluster, "in-cluster", false, "Set flag if venona is been installed from inside a cluster") + installRuntimeCmd.Flags().BoolVar(&installRuntimeCmdOptions.dryRun, "dry-run", false, "Set to true to simulate installation") + installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.kube.nodeSelector, "kube-node-selector", "", "The kubernetes node selector \"key=value\" to be used by venona resources (default is no node selector)") + installRuntimeCmd.Flags().StringVar(&installRuntimeCmdOptions.tolerations, "tolerations", "", "The kubernetes tolerations as JSON string to be used by venona resources (default is no tolerations)") + + installRuntimeCmd.Flags().StringArrayVar(&installRuntimeCmdOptions.templateValues, "set-value", []string{}, "Set values for templates, example: --set-value LocalVolumesDir=/mnt/disks/ssd0/codefresh-volumes") + installRuntimeCmd.Flags().StringArrayVar(&installRuntimeCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file, example: --set-file Storage.GoogleServiceAccount=/path/to/service-account.json") + installRuntimeCmd.Flags().StringArrayVarP(&installRuntimeCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") +} diff --git a/venonactl/cmd/install-venona.go b/venonactl/cmd/install-venona.go new file mode 100644 index 00000000..5bfe08e2 --- /dev/null +++ b/venonactl/cmd/install-venona.go @@ -0,0 +1,58 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "github.com/spf13/cobra" +) + +const ( + clusterNameMaxLength = 20 + namespaceMaxLength = 20 +) + +var installCmdOptions struct { + dryRun bool + clusterNameInCodefresh string + kube struct { + namespace string + inCluster bool + context string + nodeSelector string + } + storageClass string + venona struct { + version string + } + setDefaultRuntime bool + installOnlyRuntimeEnvironment bool + skipRuntimeInstallation bool + runtimeEnvironmentName string + buildNodeSelector string + buildAnnotations []string + tolerationJSONString string +} + +// installVenonaCmd represents the install command +var installVenonaCmd = &cobra.Command{ + Use: "all", + Short: "Install Codefresh's resource on cluster", +} + +func init() { + installCommand.AddCommand(installVenonaCmd) +} diff --git a/venonactl/cmd/install.go b/venonactl/cmd/install.go new file mode 100644 index 00000000..f1d681f3 --- /dev/null +++ b/venonactl/cmd/install.go @@ -0,0 +1,29 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "github.com/spf13/cobra" +) + +var installCommand = &cobra.Command{ + Use: "install", + Short: "Install agent and runtime components", +} + +func init() { + rootCmd.AddCommand(installCommand) +} diff --git a/venonactl/cmd/migrate.go b/venonactl/cmd/migrate.go new file mode 100644 index 00000000..47358f7b --- /dev/null +++ b/venonactl/cmd/migrate.go @@ -0,0 +1,70 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/codefresh-io/venona/venonactl/pkg/store" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var migrateCmdOpt struct { + kube struct { + context string + namespace string + } +} + +var migrateCmd = &cobra.Command{ + Use: "migrate", + Short: "Migrate existing runtime-environment from 0.X to 1.X version", + Run: func(cmd *cobra.Command, args []string) { + lgr := createLogger("Migrate", verbose, logFormatter) + builder := plugins.NewBuilder(lgr) + builder.Add(plugins.VenonaPluginType) + builder.Add(plugins.RuntimeEnvironmentPluginType) + builder.Add(plugins.VolumeProvisionerPluginType) + s := store.GetStore() + buildBasicStore(lgr) + extendStoreWithKubeClient(lgr) + extendStoreWithCodefershClient(lgr) + extendStoreWithAgentAPI(lgr, "", "") + fillKubernetesAPI(lgr, migrateCmdOpt.kube.context, migrateCmdOpt.kube.namespace, false) + values := s.BuildValues() + values["AppName"] = "venona" // use old app name for migration + spn := createSpinner("Migrating runtime (might take a few seconds)", "") + spn.Start() + defer spn.Stop() + for _, p := range builder.Get() { + err := p.Migrate(cmd.Context(), &plugins.MigrateOptions{ + ClusterNamespace: migrateCmdOpt.kube.namespace, + ClusterName: migrateCmdOpt.kube.context, + KubeBuilder: getKubeClientBuilder(migrateCmdOpt.kube.context, migrateCmdOpt.kube.namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, false), + }, values) + if err != nil { + dieOnError(err) + } + } + }, +} + +func init() { + rootCmd.AddCommand(migrateCmd) + migrateCmd.Flags().StringVar(&migrateCmdOpt.kube.context, "kube-context-name", "", "Set name to overwrite the context name saved in Codefresh") + migrateCmd.Flags().StringVar(&migrateCmdOpt.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona is installed [$KUBE_NAMESPACE]") +} diff --git a/venonactl/cmd/root.go b/venonactl/cmd/root.go new file mode 100644 index 00000000..a813a797 --- /dev/null +++ b/venonactl/cmd/root.go @@ -0,0 +1,56 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "context" + + "github.com/spf13/viper" + + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "venona", + Short: "A command line application for Codefresh", +} + +// Execute - execute the root command +func Execute(ctx context.Context) { + err := rootCmd.ExecuteContext(ctx) + dieOnError(err) +} + +func init() { + viper.AutomaticEnv() + viper.BindEnv("kubeconfig", "KUBECONFIG") + viper.BindEnv("cfconfig", "CFCONFIG") + + viper.BindEnv("apihost", "CODEFRESH_API_HOST") + viper.BindEnv("apitoken", "CODEFRESH_API_TOKEN") + + rootCmd.PersistentFlags().StringVar(&configPath, "cfconfig", viper.GetString("cfconfig"), "Config file (default is $HOME/.cfconfig) [$CFCONFIG]") + rootCmd.PersistentFlags().StringVar(&cfAPIHost, "api-host", viper.GetString("apihost"), "Host of codefresh [$CODEFRESH_API_HOST]") + rootCmd.PersistentFlags().StringVar(&cfAPIToken, "api-token", viper.GetString("apitoken"), "Codefresh API token [$CODEFRESH_API_TOKEN]") + rootCmd.PersistentFlags().StringVar(&cfContext, "context", "", "Name of the context from --cfconfig (default is current-context)") + + rootCmd.PersistentFlags().StringVar(&kubeConfigPath, "kube-config-path", viper.GetString("kubeconfig"), "Path to kubeconfig file (default is $HOME/.kube/config) [$KUBECONFIG]") + + rootCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "Print logs") + rootCmd.PersistentFlags().StringVar(&logFormatter, "log-formtter", "Plain", "Print logs in custom format") + +} diff --git a/venonactl/cmd/status.go b/venonactl/cmd/status.go new file mode 100644 index 00000000..0e260a10 --- /dev/null +++ b/venonactl/cmd/status.go @@ -0,0 +1,132 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "context" + "fmt" + + "github.com/codefresh-io/go-sdk/pkg/codefresh" + "github.com/codefresh-io/venona/venonactl/pkg/logger" + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/codefresh-io/venona/venonactl/pkg/store" + humanize "github.com/dustin/go-humanize" + + "github.com/spf13/cobra" +) + +var statusCmdOpt struct { + kube struct { + context string + } + dryRun bool +} + +// statusCmd represents the status command +var statusCmd = &cobra.Command{ + Use: "status [name]", + Short: "Get status of Codefresh's runtime-environment", + Long: "Pass the name of the runtime environment to see more details information about the underlying resources", + Run: func(cmd *cobra.Command, args []string) { + lgr := createLogger("Status", verbose, logFormatter) + + buildBasicStore(lgr) + extendStoreWithCodefershClient(lgr) + extendStoreWithKubeClient(lgr) + s := store.GetStore() + table := createTable() + // When requested status for specific runtime + if len(args) > 0 { + name := args[0] + re, err := s.CodefreshAPI.Client.RuntimeEnvironments().Get(name) + dieOnError(err) + if re == nil { + dieOnError(fmt.Errorf("Runtime-Environment %s not found", name)) + } + if re.Metadata.Agent == true { + table.SetHeader([]string{"Runtime Name", "Last Message", "Reported"}) + message := "Not reported any message yet" + time := "" + if re.Status.Message != "" { + message = re.Status.Message + time = humanize.Time(re.Status.UpdatedAt) + } + table.Append([]string{re.Metadata.Name, message, time}) + table.Render() + fmt.Println() + printTableWithKubernetesRelatedResources(cmd.Context(), re, statusCmdOpt.kube.context, lgr) + } else { + lgr.Debug("Runtime-Environment has not Venona's agent", "Name", name) + } + return + } + + // When requested status for all runtimes + res, err := s.CodefreshAPI.Client.RuntimeEnvironments().List() + dieOnError(err) + table.SetHeader([]string{"Runtime Name", "Last Message", "Reported"}) + for _, re := range res { + if re.Metadata.Agent == true { + message := "Not reported any message yet" + time := "" + if re.Status.Message != "" { + message = re.Status.Message + time = humanize.Time(re.Status.UpdatedAt) + } + table.Append([]string{re.Metadata.Name, message, time}) + } + } + table.Render() + + return + + }, +} + +func printTableWithKubernetesRelatedResources(ctx context.Context, re *codefresh.RuntimeEnvironment, context string, logger logger.Logger) { + builder := plugins.NewBuilder(logger) + + table := createTable() + table.SetHeader([]string{"Kind", "Name", "Status"}) + s := store.GetStore() + if re.RuntimeScheduler.Cluster.Namespace != "" { + if context == "" { + context = re.RuntimeScheduler.Cluster.ClusterProvider.Selector + } + s.KubernetesAPI.ContextName = context + s.KubernetesAPI.Namespace = re.RuntimeScheduler.Cluster.Namespace + builder. + Add(plugins.RuntimeEnvironmentPluginType). + Add(plugins.VenonaPluginType). + Add(plugins.VolumeProvisionerPluginType) + statusOpt := &plugins.StatusOptions{ + KubeBuilder: getKubeClientBuilder(context, re.RuntimeScheduler.Cluster.Namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, false), + ClusterNamespace: s.KubernetesAPI.Namespace, + } + for _, p := range builder.Get() { + rows, err := p.Status(ctx, statusOpt, s.BuildValues()) + dieOnError(err) + table.AppendBulk(rows) + } + } + table.Render() +} + +func init() { + rootCmd.AddCommand(statusCmd) + statusCmd.Flags().StringVar(&statusCmdOpt.kube.context, "kube-context-name", "", "Set name to overwrite the context name saved in Codefresh") +} diff --git a/venonactl/cmd/test.go b/venonactl/cmd/test.go new file mode 100644 index 00000000..5d87d5c2 --- /dev/null +++ b/venonactl/cmd/test.go @@ -0,0 +1,145 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/codefresh-io/venona/venonactl/pkg/store" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var allTestPluginTypes = []string{ + plugins.RuntimeEnvironmentPluginType, + plugins.VenonaPluginType, + plugins.MonitorAgentPluginType, + plugins.VolumeProvisionerPluginType, + plugins.EnginePluginType, + plugins.RuntimeAttachType, + plugins.NetworkTesterPluginType, +} + +var testCommandOptions struct { + kube struct { + host string + namespace string + context string + inCluster bool + } + insecure bool + plugin []string + templateValues []string + templateFileValues []string + templateValueFiles []string +} + +var testCommand = &cobra.Command{ + Use: "test", + Short: "Run test on the target cluster prior installation", + Run: func(cmd *cobra.Command, args []string) { + // get valuesMap from --values --set-value k=v --set-file k= + templateValuesMap, err := templateValuesToMap( + testCommandOptions.templateValueFiles, + testCommandOptions.templateValues, + testCommandOptions.templateFileValues) + if err != nil { + dieOnError(err) + } + // Merge cmd options with template + mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) + mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) + mergeValueStr(templateValuesMap, "Token", &cfAPIToken) + mergeValueStr(templateValuesMap, "Namespace", &testCommandOptions.kube.namespace) + mergeValueStr(templateValuesMap, "Context", &testCommandOptions.kube.context) + mergeValueStr(templateValuesMap, "KubernetesHost", &testCommandOptions.kube.host) + mergeValueBool(templateValuesMap, "InCluster", &testCommandOptions.kube.inCluster) + mergeValueBool(templateValuesMap, "insecure", &testCommandOptions.insecure) + + lgr := createLogger("test", verbose, logFormatter) + s := store.GetStore() + buildBasicStore(lgr) + extendStoreWithKubeClient(lgr) + fillKubernetesAPI(lgr, testCommandOptions.kube.context, testCommandOptions.kube.namespace, testCommandOptions.kube.inCluster) + fillCodefreshAPI(lgr) + extendStoreWithAgentAPI(lgr, "", "") + setVerbosity(verbose) + setInsecure(testCommandOptions.insecure) + + builder := plugins.NewBuilder(lgr) + for _, p := range testCommandOptions.plugin { + if p == plugins.RuntimeEnvironmentPluginType { + builder.Add(plugins.RuntimeEnvironmentPluginType) + } + if p == plugins.VenonaPluginType { + builder.Add(plugins.VenonaPluginType) + } + if p == plugins.MonitorAgentPluginType { + builder.Add(plugins.MonitorAgentPluginType) + } + if p == plugins.VolumeProvisionerPluginType { + builder.Add(plugins.VolumeProvisionerPluginType) + } + if p == plugins.EnginePluginType { + builder.Add(plugins.EnginePluginType) + } + if p == plugins.RuntimeAttachType { + builder.Add(plugins.RuntimeAttachType) + } + if p == plugins.NetworkTesterPluginType { + builder.Add(plugins.NetworkTesterPluginType) + } + } + + options := &plugins.TestOptions{ + KubeBuilder: getKubeClientBuilder(s.KubernetesAPI.ContextName, s.KubernetesAPI.Namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, false), + ClusterNamespace: s.KubernetesAPI.Namespace, + } + + values := s.BuildValues() + values = mergeMaps(values, templateValuesMap) + + var finalerr error + lgr.Info("Testing requirements") + + for _, p := range builder.Get() { + err := p.Test(cmd.Context(), options, values) + if err != nil && finalerr == nil { + finalerr = err + } + } + dieOnError(finalerr) + + lgr.Info("Cluster passed acceptance test") + }, +} + +func init() { + viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") + viper.BindEnv("kube-context", "KUBE_CONTEXT") + + testCommand.Flags().StringVar(&testCommandOptions.kube.host, "kube-host", viper.GetString("kube-host"), "overrides the address of the api-server the runner will use") + testCommand.Flags().StringVar(&testCommandOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which monitor should be installed [$KUBE_NAMESPACE]") + testCommand.Flags().StringVar(&testCommandOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which monitor should be installed (default is current-context) [$KUBE_CONTEXT]") + testCommand.Flags().BoolVar(&testCommandOptions.insecure, "insecure", false, "Set to true to disable certificate validation when using TLS connections") + testCommand.Flags().BoolVar(&testCommandOptions.kube.inCluster, "in-cluster", false, "Set flag if the command is running inside a cluster") + testCommand.Flags().StringArrayVar(&testCommandOptions.plugin, "installer", allTestPluginTypes, "Which test to run, based on the installer type") + + testCommand.Flags().StringArrayVar(&testCommandOptions.templateValues, "set-value", []string{}, "Set values for templates, example: --set-value LocalVolumesDir=/mnt/disks/ssd0/codefresh-volumes") + testCommand.Flags().StringArrayVar(&testCommandOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file, example: --set-file Storage.GoogleServiceAccount=/path/to/service-account.json") + testCommand.Flags().StringArrayVarP(&testCommandOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") + + rootCmd.AddCommand(testCommand) +} diff --git a/venonactl/cmd/uninstall-agent.go b/venonactl/cmd/uninstall-agent.go new file mode 100644 index 00000000..6e290d3c --- /dev/null +++ b/venonactl/cmd/uninstall-agent.go @@ -0,0 +1,91 @@ +package cmd + +import ( + "fmt" + + "github.com/codefresh-io/venona/venonactl/pkg/store" + + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var uninstallAgentCmdOptions struct { + kube struct { + context string + namespace string + kubePath string + } + templateValues []string + templateFileValues []string + templateValueFiles []string +} + +var uninstallAgentCmd = &cobra.Command{ + Use: "agent", + Short: "Uninstall Codefresh's agent", + Run: func(cmd *cobra.Command, args []string) { + + // get valuesMap from --values --set-value k=v --set-file k= + templateValuesMap, err := templateValuesToMap( + uninstallAgentCmdOptions.templateValueFiles, + uninstallAgentCmdOptions.templateValues, + uninstallAgentCmdOptions.templateFileValues) + if err != nil { + dieOnError(err) + } + // Merge cmd options with template + mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) + mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) + mergeValueStr(templateValuesMap, "Token", &cfAPIToken) + mergeValueStr(templateValuesMap, "Namespace", &uninstallAgentCmdOptions.kube.namespace) + mergeValueStr(templateValuesMap, "Context", &uninstallAgentCmdOptions.kube.context) + + s := store.GetStore() + lgr := createLogger("UninstallAgent", verbose, logFormatter) + buildBasicStore(lgr) + extendStoreWithKubeClient(lgr) + + s.CodefreshAPI = &store.CodefreshAPI{} + s.AgentAPI = &store.AgentAPI{} + + builder := plugins.NewBuilder(lgr) + if uninstallAgentCmdOptions.kube.context == "" { + dieOnError(fmt.Errorf("Context name is required in order to uninstall agent")) + } + if uninstallAgentCmdOptions.kube.namespace == "" { + dieOnError(fmt.Errorf("Namespace name is required to in order to uninstall agent")) + } + + deleteOptions := &plugins.DeleteOptions{} + s.KubernetesAPI.ContextName = uninstallAgentCmdOptions.kube.context + s.KubernetesAPI.Namespace = uninstallAgentCmdOptions.kube.namespace + + builder.Add(plugins.VenonaPluginType) + deleteOptions.KubeBuilder = getKubeClientBuilder(s.KubernetesAPI.ContextName, s.KubernetesAPI.Namespace, s.KubernetesAPI.ConfigPath, false, false) + deleteOptions.ClusterNamespace = uninstallAgentCmdOptions.kube.namespace + + values := s.BuildValues() + values = mergeMaps(values, templateValuesMap) + for _, p := range builder.Get() { + err := p.Delete(cmd.Context(), deleteOptions, values) + if err != nil { + dieOnError(err) + } + } + + lgr.Info("Deletion of agent is completed") + }, +} + +func init() { + uninstallCommand.AddCommand(uninstallAgentCmd) + viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") + viper.BindEnv("kube-context", "KUBE_CONTEXT") + uninstallAgentCmd.Flags().StringVar(&uninstallAgentCmdOptions.kube.context, "kube-context-name", "", "Name of the kubernetes context on which venona should be uninstalled (default is current-context) [$KUBE_CONTEXT]") + uninstallAgentCmd.Flags().StringVar(&uninstallAgentCmdOptions.kube.namespace, "kube-namespace", "", "Name of the namespace on which venona should be uninstalled [$KUBE_NAMESPACE]") + uninstallAgentCmd.Flags().StringArrayVar(&uninstallAgentCmdOptions.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") + uninstallAgentCmd.Flags().StringArrayVar(&uninstallAgentCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") + uninstallAgentCmd.Flags().StringArrayVarP(&uninstallAgentCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") + +} diff --git a/venonactl/cmd/uninstall-app-proxy.go b/venonactl/cmd/uninstall-app-proxy.go new file mode 100644 index 00000000..0535eecf --- /dev/null +++ b/venonactl/cmd/uninstall-app-proxy.go @@ -0,0 +1,92 @@ +package cmd + +import ( + "github.com/codefresh-io/venona/venonactl/pkg/store" + + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var uninstallAppProxyCmdOptions struct { + kube struct { + context string + namespace string + } + templateValues []string + templateFileValues []string + templateValueFiles []string +} + +var uninstallAppProxytCmd = &cobra.Command{ + Use: "app-proxy", + Short: "Uninstall Codefresh's App-Proxy component", + Run: func(cmd *cobra.Command, args []string) { + + // get valuesMap from --values --set-value k=v --set-file k= + templateValuesMap, err := templateValuesToMap( + uninstallAppProxyCmdOptions.templateValueFiles, + uninstallAppProxyCmdOptions.templateValues, + uninstallAppProxyCmdOptions.templateFileValues) + if err != nil { + dieOnError(err) + } + // Merge cmd options with template + mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) + mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) + mergeValueStr(templateValuesMap, "Namespace", &uninstallAppProxyCmdOptions.kube.namespace) + mergeValueStr(templateValuesMap, "Context", &uninstallAppProxyCmdOptions.kube.context) + + s := store.GetStore() + lgr := createLogger("UninstallAppProxy", verbose, logFormatter) + buildBasicStore(lgr) + extendStoreWithKubeClient(lgr) + fillKubernetesAPI(lgr, uninstallAppProxyCmdOptions.kube.context, uninstallAppProxyCmdOptions.kube.namespace, false) + + builder := plugins.NewBuilder(lgr) + + if cfAPIHost == "" { + cfAPIHost = "https://g.codefresh.io" + } + s.CodefreshAPI = &store.CodefreshAPI{ + Host: cfAPIHost, + } + s.AgentAPI = &store.AgentAPI{ + Token: "", + Id: "", + } + + deleteOptions := &plugins.DeleteOptions{} + deleteOptions.KubeBuilder = getKubeClientBuilder( + uninstallAppProxyCmdOptions.kube.context, + uninstallAppProxyCmdOptions.kube.namespace, + kubeConfigPath, + false, + false) + + builder.Add(plugins.AppProxyPluginType) + deleteOptions.ClusterNamespace = uninstallAppProxyCmdOptions.kube.namespace + values := s.BuildValues() + values = mergeMaps(values, templateValuesMap) + for _, p := range builder.Get() { + err := p.Delete(cmd.Context(), deleteOptions, values) + if err != nil { + dieOnError(err) + } + } + + lgr.Info("Deletion of app-proxy is completed") + }, +} + +func init() { + uninstallCommand.AddCommand(uninstallAppProxytCmd) + viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") + viper.BindEnv("kube-context", "KUBE_CONTEXT") + uninstallAppProxytCmd.Flags().StringVar(&uninstallAppProxyCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace from which the app-proxy should be uninstalled [$KUBE_NAMESPACE]") + uninstallAppProxytCmd.Flags().StringVar(&uninstallAppProxyCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context from which the app-proxy should be uninstalled (default is current-context) [$KUBE_CONTEXT]") + uninstallAppProxytCmd.Flags().StringArrayVar(&uninstallAppProxyCmdOptions.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") + uninstallAppProxytCmd.Flags().StringArrayVar(&uninstallAppProxyCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") + uninstallAppProxytCmd.Flags().StringArrayVarP(&uninstallAppProxyCmdOptions.templateValueFiles, "values", "f", []string{}, "Specify values in a YAML file") + +} diff --git a/venonactl/cmd/uninstall-monitor.go b/venonactl/cmd/uninstall-monitor.go new file mode 100644 index 00000000..bd8f4b40 --- /dev/null +++ b/venonactl/cmd/uninstall-monitor.go @@ -0,0 +1,103 @@ +package cmd + +import ( + "github.com/codefresh-io/venona/venonactl/pkg/store" + + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var uninstallMonitorAgentCmdOptions struct { + kube struct { + context string + namespace string + kubePath string + } + templateValues []string + templateFileValues []string + templateValueFiles []string +} + +var uninstallMonitorAgentCmd = &cobra.Command{ + Use: "monitor", + Short: "Uninstall Codefresh's monitor", + Run: func(cmd *cobra.Command, args []string) { + + // get valuesMap from --values --set-value k=v --set-file k= + templateValuesMap, err := templateValuesToMap( + uninstallMonitorAgentCmdOptions.templateValueFiles, + uninstallMonitorAgentCmdOptions.templateValues, + uninstallMonitorAgentCmdOptions.templateFileValues) + if err != nil { + dieOnError(err) + } + // Merge cmd options with template + mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) + mergeValueStr(templateValuesMap, "ConfigPath", &uninstallMonitorAgentCmdOptions.kube.kubePath) + mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) + mergeValueStr(templateValuesMap, "Token", &cfAPIToken) + mergeValueStr(templateValuesMap, "Namespace", &uninstallMonitorAgentCmdOptions.kube.namespace) + mergeValueStr(templateValuesMap, "Context", &uninstallMonitorAgentCmdOptions.kube.context) + + s := store.GetStore() + lgr := createLogger("UninstallMonitor", verbose, logFormatter) + buildBasicStore(lgr) + extendStoreWithKubeClient(lgr) + fillKubernetesAPI(lgr, uninstallMonitorAgentCmdOptions.kube.context, uninstallMonitorAgentCmdOptions.kube.namespace, false) + + builder := plugins.NewBuilder(lgr) + + if uninstallMonitorAgentCmdOptions.kube.kubePath == "" { + uninstallMonitorAgentCmdOptions.kube.kubePath = kubeConfigPath + } + + if cfAPIHost == "" { + cfAPIHost = "https://g.codefresh.io" + } + // This is temporarily and used for signing + s.CodefreshAPI = &store.CodefreshAPI{ + Host: cfAPIHost, + } + + // stub , not need actually for monitor + s.AgentAPI = &store.AgentAPI{ + Token: "", + Id: "", + } + + deleteOptions := &plugins.DeleteOptions{} + // runtime + deleteOptions.KubeBuilder = getKubeClientBuilder(uninstallMonitorAgentCmdOptions.kube.context, + s.KubernetesAPI.Namespace, + uninstallMonitorAgentCmdOptions.kube.kubePath, + false, + false) + + builder.Add(plugins.MonitorAgentPluginType) + deleteOptions.ClusterNamespace = s.KubernetesAPI.Namespace + values := s.BuildValues() + values = mergeMaps(values, templateValuesMap) + for _, p := range builder.Get() { + err := p.Delete(cmd.Context(), deleteOptions, values) + if err != nil { + dieOnError(err) + } + } + + lgr.Info("Deletion of monitor is completed") + }, +} + +func init() { + uninstallCommand.AddCommand(uninstallMonitorAgentCmd) + viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") + viper.BindEnv("kube-context", "KUBE_CONTEXT") + uninstallMonitorAgentCmd.Flags().StringVar(&uninstallMonitorAgentCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which monitor should be uninstalled [$KUBE_NAMESPACE]") + uninstallMonitorAgentCmd.Flags().StringVar(&uninstallMonitorAgentCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which monitor should be uninstalled (default is current-context) [$KUBE_CONTEXT]") + uninstallMonitorAgentCmd.Flags().StringVar(&uninstallMonitorAgentCmdOptions.kube.kubePath, "kube-config-path", viper.GetString("kubeconfig"), "Path to kubeconfig file (default is $HOME/.kube/config) [$KUBECONFIG]") + uninstallMonitorAgentCmd.Flags().StringArrayVar(&uninstallMonitorAgentCmdOptions.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") + uninstallMonitorAgentCmd.Flags().StringArrayVar(&uninstallMonitorAgentCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") + uninstallMonitorAgentCmd.Flags().StringArrayVarP(&uninstallMonitorAgentCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") + +} diff --git a/venonactl/cmd/uninstall-runtime.go b/venonactl/cmd/uninstall-runtime.go new file mode 100644 index 00000000..e1debd40 --- /dev/null +++ b/venonactl/cmd/uninstall-runtime.go @@ -0,0 +1,145 @@ +package cmd + +import ( + "fmt" + + "github.com/codefresh-io/venona/venonactl/pkg/store" + + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var uninstallRunimeCmdOptions struct { + kube struct { + context string + namespace string + kubePath string + } + kubeVenona struct { + namespace string + kubePath string + context string + } + runtimeEnvironmentName string + storageClassName string + restartAgent bool + templateValues []string + templateFileValues []string + templateValueFiles []string +} + +var uninstallRuntimeCmd = &cobra.Command{ + Use: "runtime", + Short: "Uninstall Codefresh's runtime", + Run: func(cmd *cobra.Command, args []string) { + // get valuesMap from --values --set-value k=v --set-file k= + templateValuesMap, err := templateValuesToMap( + uninstallRunimeCmdOptions.templateValueFiles, + uninstallRunimeCmdOptions.templateValues, + uninstallRunimeCmdOptions.templateFileValues) + if err != nil { + dieOnError(err) + } + // Merge cmd options with template + mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) + mergeValueStr(templateValuesMap, "ConfigPath", &uninstallRunimeCmdOptions.kube.kubePath) + mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) + mergeValueStr(templateValuesMap, "Token", &cfAPIToken) + + mergeValueStr(templateValuesMap, "Namespace", &uninstallRunimeCmdOptions.kube.namespace) + mergeValueStr(templateValuesMap, "Context", &uninstallRunimeCmdOptions.kube.context) + mergeValueStr(templateValuesMap, "RuntimeEnvironmentName", &uninstallRunimeCmdOptions.runtimeEnvironmentName) + mergeValueStr(templateValuesMap, "StorageClass", &uninstallRunimeCmdOptions.storageClassName) + + s := store.GetStore() + lgr := createLogger("UninstallRuntime", verbose, logFormatter) + buildBasicStore(lgr) + extendStoreWithKubeClient(lgr) + + s.CodefreshAPI = &store.CodefreshAPI{} + s.AgentAPI = &store.AgentAPI{} + + builder := plugins.NewBuilder(lgr) + if uninstallRunimeCmdOptions.kube.context == "" { + dieOnError(fmt.Errorf("Context name is required in order to uninstall runtime")) + } + if uninstallRunimeCmdOptions.kube.namespace == "" { + dieOnError(fmt.Errorf("Namespace name is required to in order to uninstall runtime")) + } + s.KubernetesAPI.ContextName = uninstallRunimeCmdOptions.kube.context + s.KubernetesAPI.Namespace = uninstallRunimeCmdOptions.kube.namespace + + if uninstallRunimeCmdOptions.kubeVenona.kubePath == "" { + uninstallRunimeCmdOptions.kubeVenona.kubePath = kubeConfigPath + } + if uninstallRunimeCmdOptions.kubeVenona.namespace == "" { + uninstallRunimeCmdOptions.kubeVenona.namespace = uninstallRunimeCmdOptions.kube.namespace + } + if uninstallRunimeCmdOptions.kubeVenona.context == "" { + uninstallRunimeCmdOptions.kubeVenona.context = uninstallRunimeCmdOptions.kube.context + } + + if uninstallRunimeCmdOptions.kube.kubePath == "" { + uninstallRunimeCmdOptions.kube.kubePath = kubeConfigPath + } + + deleteOptions := &plugins.DeleteOptions{} + // runtime + deleteOptions.KubeBuilder = getKubeClientBuilder(uninstallRunimeCmdOptions.kube.context, + uninstallRunimeCmdOptions.kube.namespace, + uninstallRunimeCmdOptions.kube.kubePath, + false, + false) + + // agent + deleteOptions.AgentKubeBuilder = getKubeClientBuilder(uninstallRunimeCmdOptions.kubeVenona.context, + uninstallRunimeCmdOptions.kubeVenona.namespace, + uninstallRunimeCmdOptions.kubeVenona.kubePath, + false, + false) + + builder.Add(plugins.RuntimeEnvironmentPluginType) + if isUsingDefaultStorageClass(uninstallRunimeCmdOptions.storageClassName) { + builder.Add(plugins.VolumeProvisionerPluginType) + } + builder.Add(plugins.RuntimeAttachType) + builder.Add(plugins.EnginePluginType) + deleteOptions.ClusterNamespace = uninstallRunimeCmdOptions.kube.namespace + deleteOptions.AgentNamespace = uninstallRunimeCmdOptions.kubeVenona.namespace + deleteOptions.RuntimeEnvironment = uninstallRunimeCmdOptions.runtimeEnvironmentName + values := s.BuildValues() + values = mergeMaps(values, templateValuesMap) + for _, p := range builder.Get() { + err := p.Delete(cmd.Context(), deleteOptions, values) + if err != nil { + dieOnError(err) + } + } + + lgr.Info("Deletion of runtime is completed") + }, +} + +func init() { + uninstallCommand.AddCommand(uninstallRuntimeCmd) + viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") + viper.BindEnv("kube-context", "KUBE_CONTEXT") + uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona should be installed [$KUBE_NAMESPACE]") + uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which venona should be installed (default is current-context) [$KUBE_CONTEXT]") + uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.kube.kubePath, "kube-config-path", viper.GetString("kubeconfig"), "Path to kubeconfig file (default is $HOME/.kube/config) [$KUBECONFIG]") + + uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.runtimeEnvironmentName, "runtime-name", viper.GetString("runtime-name"), "Name of the runtime as in codefresh") + + uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.kubeVenona.namespace, "kube-namespace-agent", viper.GetString("kube-namespace-agent"), "Name of the namespace where venona is installed [$KUBE_NAMESPACE]") + uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.kubeVenona.context, "kube-context-name-agent", viper.GetString("kube-context-agent"), "Name of the kubernetes context on which venona is installed (default is current-context) [$KUBE_CONTEXT]") + uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.kubeVenona.kubePath, "kube-config-path-agent", viper.GetString("kubeconfig-agent"), "Path to kubeconfig file (default is $HOME/.kube/config) for agent [$KUBECONFIG]") + uninstallRuntimeCmd.Flags().BoolVar(&uninstallRunimeCmdOptions.restartAgent, "restart-agent", viper.GetBool("restart-agent"), "Restart agent after attach operation") + + uninstallRuntimeCmd.Flags().StringVar(&uninstallRunimeCmdOptions.storageClassName, "storage-class-name", viper.GetString("storage-class-name"), "Storage class name of the runtime to be uninstalled") + + uninstallRuntimeCmd.Flags().StringArrayVar(&uninstallRunimeCmdOptions.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") + uninstallRuntimeCmd.Flags().StringArrayVar(&uninstallRunimeCmdOptions.templateFileValues, "set-file", []string{}, "Set values for templates from file") + uninstallRuntimeCmd.Flags().StringArrayVarP(&uninstallRunimeCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") + +} diff --git a/venonactl/cmd/uninstall.go b/venonactl/cmd/uninstall.go new file mode 100644 index 00000000..eeaedf7a --- /dev/null +++ b/venonactl/cmd/uninstall.go @@ -0,0 +1,29 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "github.com/spf13/cobra" +) + +var uninstallCommand = &cobra.Command{ + Use: "uninstall", + Short: "Uninstall agent and runtime components", +} + +func init() { + rootCmd.AddCommand(uninstallCommand) +} diff --git a/venonactl/cmd/upgrade-app-proxy.go b/venonactl/cmd/upgrade-app-proxy.go new file mode 100644 index 00000000..14322140 --- /dev/null +++ b/venonactl/cmd/upgrade-app-proxy.go @@ -0,0 +1,90 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/codefresh-io/venona/venonactl/pkg/store" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var upgradeAppProxyCmdOptions struct { + kube struct { + context string + namespace string + } + templateValues []string + templateFileValues []string + templateValueFiles []string +} + +var upgradeAppProxyCmd = &cobra.Command{ + Use: "app-proxy", + Short: "Upgrade App proxy", + Run: func(cmd *cobra.Command, args []string) { + + templateValuesMap, err := templateValuesToMap( + upgradeAppProxyCmdOptions.templateValueFiles, + upgradeAppProxyCmdOptions.templateValues, + upgradeAppProxyCmdOptions.templateFileValues) + if err != nil { + dieOnError(err) + } + + mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) + mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) + mergeValueStr(templateValuesMap, "Namespace", &upgradeAppProxyCmdOptions.kube.namespace) + mergeValueStr(templateValuesMap, "Context", &upgradeAppProxyCmdOptions.kube.context) + + lgr := createLogger("Upgrade-AppProxy", verbose, logFormatter) + builder := plugins.NewBuilder(lgr) + + builder.Add(plugins.AppProxyPluginType) + + s := store.GetStore() + buildBasicStore(lgr) + extendStoreWithKubeClient(lgr) + dieOnError(extendStoreWithCodefershClient(lgr)) + extendStoreWithAgentAPI(lgr, "", "") + fillKubernetesAPI(lgr, upgradeAppProxyCmdOptions.kube.context, upgradeAppProxyCmdOptions.kube.namespace, false) + values := s.BuildValues() + values = mergeMaps(values, templateValuesMap) + + for _, p := range builder.Get() { + values, err = p.Upgrade(cmd.Context(), &plugins.UpgradeOptions{ + Name: store.AppProxyApplicationName, + ClusterNamespace: upgradeAppProxyCmdOptions.kube.namespace, + ClusterName: upgradeAppProxyCmdOptions.kube.namespace, + KubeBuilder: getKubeClientBuilder(upgradeAppProxyCmdOptions.kube.context, upgradeAppProxyCmdOptions.kube.namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, false), + }, values) + if err != nil { + dieOnError(err) + } + } + }, +} + +func init() { + viper.BindEnv("kube-namespace", "KUBE_NAMESPACE") + viper.BindEnv("kube-context", "KUBE_CONTEXT") + upgradeCmd.AddCommand(upgradeAppProxyCmd) + upgradeAppProxyCmd.Flags().StringVar(&upgradeAppProxyCmdOptions.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona should be installed [$KUBE_NAMESPACE]") + upgradeAppProxyCmd.Flags().StringVar(&upgradeAppProxyCmdOptions.kube.context, "kube-context-name", viper.GetString("kube-context"), "Name of the kubernetes context on which venona should be installed (default is current-context) [$KUBE_CONTEXT]") + upgradeAppProxyCmd.Flags().StringArrayVarP(&upgradeAppProxyCmdOptions.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") + upgradeAppProxyCmd.Flags().StringArrayVar(&upgradeAppProxyCmdOptions.templateValues, "set-value", []string{}, "Set values for templates, example: --set-value LocalVolumesDir=/mnt/disks/ssd0/codefresh-volumes") +} diff --git a/venonactl/cmd/upgrade.go b/venonactl/cmd/upgrade.go new file mode 100644 index 00000000..c8c74db1 --- /dev/null +++ b/venonactl/cmd/upgrade.go @@ -0,0 +1,95 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "github.com/codefresh-io/venona/venonactl/pkg/plugins" + "github.com/codefresh-io/venona/venonactl/pkg/store" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var upgradeCmdOpt struct { + kube struct { + context string + namespace string + } + templateValues []string + templateFileValues []string + templateValueFiles []string +} + +// upgradeCmd represents the upgrade command +var upgradeCmd = &cobra.Command{ + Use: "upgrade", + Short: "Upgrade existing 1.X runner", + Run: func(cmd *cobra.Command, args []string) { + // get valuesMap from --values --set-value k=v --set-file k= + templateValuesMap, err := templateValuesToMap( + uninstallAgentCmdOptions.templateValueFiles, + uninstallAgentCmdOptions.templateValues, + uninstallAgentCmdOptions.templateFileValues) + if err != nil { + dieOnError(err) + } + // Merge cmd options with template + mergeValueStr(templateValuesMap, "ConfigPath", &kubeConfigPath) + mergeValueStr(templateValuesMap, "CodefreshHost", &cfAPIHost) + mergeValueStr(templateValuesMap, "Token", &cfAPIToken) + mergeValueStr(templateValuesMap, "Namespace", &uninstallAgentCmdOptions.kube.namespace) + mergeValueStr(templateValuesMap, "Context", &uninstallAgentCmdOptions.kube.context) + + lgr := createLogger("Upgrade", verbose, logFormatter) + builder := plugins.NewBuilder(lgr) + builder.Add(plugins.VenonaPluginType) + + s := store.GetStore() + buildBasicStore(lgr) + extendStoreWithKubeClient(lgr) + dieOnError(extendStoreWithCodefershClient(lgr)) + extendStoreWithAgentAPI(lgr, "", "") + fillKubernetesAPI(lgr, upgradeCmdOpt.kube.context, upgradeCmdOpt.kube.namespace, false) + values := s.BuildValues() + values = mergeMaps(values, templateValuesMap) + + spn := createSpinner("Upgarding runtime (might take a few seconds)", "") + spn.Start() + defer spn.Stop() + + for _, p := range builder.Get() { + values, err = p.Upgrade(cmd.Context(), &plugins.UpgradeOptions{ + Name: s.AppName, + ClusterNamespace: upgradeCmdOpt.kube.namespace, + ClusterName: upgradeCmdOpt.kube.namespace, + KubeBuilder: getKubeClientBuilder(upgradeCmdOpt.kube.context, upgradeCmdOpt.kube.namespace, s.KubernetesAPI.ConfigPath, s.KubernetesAPI.InCluster, false), + }, values) + if err != nil { + dieOnError(err) + } + } + }, +} + +func init() { + rootCmd.AddCommand(upgradeCmd) + upgradeCmd.Flags().StringVar(&upgradeCmdOpt.kube.context, "kube-context-name", "", "Set name to overwrite the context name saved in Codefresh") + upgradeCmd.Flags().StringVar(&upgradeCmdOpt.kube.namespace, "kube-namespace", viper.GetString("kube-namespace"), "Name of the namespace on which venona is installed [$KUBE_NAMESPACE]") + + upgradeCmd.Flags().StringArrayVar(&upgradeCmdOpt.templateValues, "set-value", []string{}, "Set values for templates --set-value agentId=12345") + upgradeCmd.Flags().StringArrayVar(&upgradeCmdOpt.templateFileValues, "set-file", []string{}, "Set values for templates from file") + upgradeCmd.Flags().StringArrayVarP(&upgradeCmdOpt.templateValueFiles, "values", "f", []string{}, "specify values in a YAML file") +} diff --git a/venonactl/cmd/version.go b/venonactl/cmd/version.go new file mode 100644 index 00000000..3fa56510 --- /dev/null +++ b/venonactl/cmd/version.go @@ -0,0 +1,43 @@ +package cmd + +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "fmt" + + "github.com/codefresh-io/venona/venonactl/pkg/store" + "github.com/spf13/cobra" +) + +// versionCmd represents the version command +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print Venona version", + Run: func(cmd *cobra.Command, args []string) { + s := store.GetStore() + lgr := createLogger("Version", verbose, logFormatter) + buildBasicStore(lgr) + fmt.Printf("Date: %s\n", s.Version.Current.Date) + fmt.Printf("Commit: %s\n", s.Version.Current.Commit) + fmt.Printf("Local Version: %s\n", s.Version.Current.Version) + }, +} + +func init() { + rootCmd.AddCommand(versionCmd) + +} diff --git a/venonactl/example/values-example.yaml b/venonactl/example/values-example.yaml new file mode 100644 index 00000000..6010bce7 --- /dev/null +++ b/venonactl/example/values-example.yaml @@ -0,0 +1,308 @@ +### DEPRECATED! ### +### Use Helm chart to install Codefresh Runner! ### + +########################################################################################################################### +### This is a sample values yamls for usage with: ### +### venonactl install agent|runtime|monitor|app-proxy --values|-f values.yaml ### +### ### +### the values from values.yaml are applied to the templates in [pkg/templates/kubernetes](pkg/templates/kubernetes) ### +### See BuildValues() func in [store.go](pkg/store/store.go) for the format ### +########################################################################################################################### + +############################################## +### ### +### Codefresh Authentication ### +### ### +############################################## +### Codefresh host --api-host and token --api-token +# CodefreshHost: https://g.codefresh.io # for on-prem installations +# Token: XXXXXXXXXXXXXXXXX.YYYYYYYYYYYYYYY # generate a token here: https://g.codefresh.io/user/settings + +### insecure: skips certificates validation on TLS connections +### use this if you're getting TLS certificate validation +### errors during the installation +# insecure: true + +############################################## +### ### +### Kubernetes Context ### +### ### +############################################## +### ConfigPath: --kube-config-path $KUBECONFIG: kubeconfig path +# ConfigPath: # default is $(HOME)/.kube/config + +### Context: --context $KUBE_CONTEXT: which kubernetes context to use +# Context: some-context + +### Namespace --kube-namespace $KUBE_NAMESPACE: namespace for the runner, runtime, monitor, app-proxy +# Namespace: r1 + + +############################################## +### ### +### General Options ### +### ### +############################################## +### RuntimeEnvironmentName --runtimeName: used when installing a new runtime +### will be used to uniquely identify the runtime in Codefresh +# RuntimeEnvironmentName: my-unique-runtime-name + +### RuntimeServiceAccount --kube-service-account: used when attaching a runtime to a runner +### default is: runner +# RuntimeServiceAccount: runner + +### KubernetesHost: --kube-host: used when attaching a runtime to a runner to override the +### apiserver address that the runner will use to create resources on the runtime, +### by default we use the host from your kubeconfig. +# KubernetesHost: https://kubernetes.default.svc.cluster.local + +### SkipClusterTest: only set to true if you want to skip the acceptance tests during the installation +# SkipClusterTest: true + +### SkipClusterTest: if set to true, cluster integration will not be created in Codefresh +# SkipClusterIntegration: false + +### ClusterId --clusterId: used when installing the monitor component +### this is the name of the cluster integration in codefresh +# ClusterId: cluster-name + +### EnvVars: global environment variables that will be set on every component, +### including runtime components such as engine and dind. +### Use this if you need to set http_proxy variables +# EnvVars: +# HTTP_PROXY: http://123.123.123.123:8080 +# HTTPS_PROXY: http://123.123.123.123:8080 +# NO_PROXY: localhost + +### DockerRegistry --docker-registry: The docker registry from which all components images will be pulled [default: docker.io]. +### We will check connectivity from inside the cluster to this domain. +# DockerRegistry: docker.io + +### NewRelicLicense: If a license key is provided we will use newrelic monitoring in the venona agent +### and app-proxy components +# NewRelicLicense: XXXX + +# GitProviderURL: api.github.com # (optional) We will check connectivity to this URL when we run our acceptance tests. + + +############################################### +### Codefresh Runner ### +### ### +### Pulls and executes tasks from codefresh ### +############################################### +### Runner image: controls the runner pod image +# Image: +# Name: codefresh/venona +# Tag: 1.4.16 # default s.Version.Current.Version, + +### Control runner pod resources +# Runner: +# resources: +# limits: +# cpu: 400m +# memory: 1200Mi +# requests: +# cpu: 200m +# memory: 500Mi + +### AdditionalEnvVars --envVars: adds environment variables to the runner deployment +# AdditionalEnvVars: +# HTTP_PROXY: 10.20.0.35:8080 +# HTTPS_PROXY: 10.20.0.35:8080 +# NO_PROXY: 10.20.0.* + +### NodeSelector --kube-node-selector: controls runner and dind-volume-provisioner pods +# NodeSelector: app_type=codefresh,cloud.google.com/gke-nodepool=default-pool + +### Tolerations --tolerations: controls runner, dind-volume-provisioner and dind-lv-monitor +# Tolerations: +# - key: codefresh.io +# operator: Equal +# value: dinds +# effect: NoSchedule + +### Agent options: generally you should only use them if you deleted your runner by mistake +# AgentToken --agentToken: used by the runner pod to authenticate to codefresh +# AgentId --agentId: used by codefresh to identify the runner + + +############################################### +### Storage ### +### ### +### codefresh pipelines volume provisioning ### +################################################ +### StorageClass --storage-class: Use already existing storage class +### Note: when using this option volume provisioning components will +### not be installed. +# StorageClass: # storage class name + +### Storage parameters for dind-volume-provisoner and dind-lv-monitor +# Storage: +# Annotations: # will be set on the storage class +# foo: bar +# Backend: local +# StorageClassName: # default is: dind-local-volumes-runner- +# LocalVolumeParentDir: /var/lib/codefresh/dind-volumes +# AvailabilityZone: +# GoogleServiceAccount: +# AwsAccessKeyId: +# AwsSecretAccessKey: +# Encrypted: # encrypt volume, default is false +# VolumeProvisioner: +# Image: codefresh/dind-volume-provisioner:1.31.7 +# NodeSelector: +# Tolerations: +# resources: +# limits: +# cpu: 400m +# memory: 1200Mi +# requests: +# cpu: 200m +# memory: 500Mi +# ServiceAccount: +# Annotations: # will be set on VolumeProvisioner and LocalVolumeMonitor service account +# foo: bar +# LocalVolumeMonitor: +# resources: +# limits: +# cpu: 400m +# memory: 1200Mi +# requests: +# cpu: 200m +# memory: 500Mi + + +####################################### +### Storage configuration examples: ### +####################################### + +### Storage parameters example for Azure Disks +# Storage: +# Backend: azuredisk +# VolumeProvisioner: +# MountAzureJson: true + +### Storage parameters example for gke-local-ssd +# Storage: +# Backend: local +# LocalVolumeParentDir: /mnt/disks/ssd0/codefresh-volumes +# NodeSelector: cloud.google.com/gke-local-ssd=true + +### Storage parameter example for gke disks +# Storage: +# Backend: gcedisk +# AvailabilityZone: us-central1-a +# GoogleServiceAccount: > +# {serviceAccount.json context} +# NodeSelector: failure-domain.beta.kubernetes.io/zone=us-central1-a + +### Storage parameter example for aws ebs disks +# Storage: +# Backend: ebs +# AvailabilityZone: us-east-1d +# AwsAccessKeyId: ABCDF +# AwsSecretAccessKey: ZYXWV +# Encrypted: # encrypt volume, default is false +# VolumeProvisioner: +# NodeSelector: kubernetes.io/role=master +# NodeSelector: failure-domain.beta.kubernetes.io/zone=us-east-1d + + +################################################ +### Monitor ### +### ### +### reports cluster information to codefresh ### +################################################ +# Monitor: +# Image: +# Name: codefresh/agent +# Tag: stable +# resources: +# limits: +# cpu: 400m +# memory: 1200Mi +# requests: +# cpu: 200m +# memory: 500Mi +# AdditionalEnvVars: # will be set on monitor deployment +# SOME_VAR: SOME_VALUE +# Helm3: false # is the cluster using helm3 +# ServiceAccount: +# Annotations: +# foo: bar + + +######################################################## +### App-Proxy ### +### ### +### communicates with "behind-firewall" integrations ### +######################################################## +# AppProxy: +# Image: +# Name: codefresh/cf-app-proxy +# Tag: latest # default is latest +# resources: +# limits: +# cpu: 500m +# memory: 1200Mi +# requests: +# cpu: 200m +# memory: 500Mi +# AdditionalEnvVars: # will be set on app-proxy deployment +# SOME_VAR: SOME_VALUE +# Ingress: +# Host: example.com # The DNS hostname the ingress will use +# IngressClass: nginx # If you have multiple ingress-controllers in the cluster - specify the right ingress class +# TLSSecret: cert-secret-name # Use this to configure the TLS certs for the ingress +# PathPrefix: /app-proxy # default is '/'. Use this if you share the hostname with other services +# Annotations: # Extra annotations that will be set on the ingress object +# nginx.ingress.kubernetes.io/whitelist-source-range: 123.123.123.123/130 +# ServiceAccount: +# Annotations: +# foo: bar + + +######################################################## +### Codefresh Runtime ### +### ### +### configure engine and dind pods ### +######################################################## +# Runtime: +# NodeSelector: # dind and engine pods node-selector (--build-node-selector) +# foo: bar +# tolerations: # dind and engine pods tolerations +# - key: arch +# operator: Equal +# value: aarch64 +# effect: NoSchedule +# ServiceAccount: # will be used by the engine and dind pods +# Annotations: +# foo: bar +# AdditionalEnvVars: # will be set on engine and dind pods +# SOME_VAR: SOME_VALUE +# resources: # dind pod resources +# limits: +# cpu: 500m +# memory: 1200Mi +# requests: +# cpu: 200m +# memory: 500Mi +# userVolumeMounts: # will be set for dind pod and will be injcted for each container - https://codefresh.io/docs/docs/administration/codefresh-runner/#custom-volume-mounts +# my-test: +# name: test +# mountPath: /etc/ssl/cert +# readOnly: true +# userVolumes: # will be set for dind pod and will be injcted for each container - https://codefresh.io/docs/docs/administration/codefresh-runner/#custom-volume-mounts +# test: +# name: test +# secret: +# secretName: test-secret + + +######################################################## +### Logging ### +### ### +### configure build logging solution ### +######################################################## +# Logging: +# FirebaseHost: firebase.io # (optional) We will check connectivity to this URL when we run our acceptance tests. diff --git a/venonactl/go.mod b/venonactl/go.mod new file mode 100644 index 00000000..8b7a700d --- /dev/null +++ b/venonactl/go.mod @@ -0,0 +1,134 @@ +module github.com/codefresh-io/venona/venonactl + +go 1.21 + +require ( + github.com/Masterminds/semver v1.5.0 + github.com/Masterminds/sprig v2.22.0+incompatible + github.com/briandowns/spinner v1.23.0 + github.com/codefresh-io/go-sdk v0.52.0 + github.com/dustin/go-humanize v1.0.1 + github.com/inconshreveable/log15 v2.16.0+incompatible + github.com/olekukonko/tablewriter v0.0.5 + github.com/spf13/cobra v1.8.0 + github.com/spf13/viper v1.15.0 + github.com/stretchr/objx v0.5.0 + gopkg.in/yaml.v2 v2.4.0 + helm.sh/helm/v3 v3.14.4 + k8s.io/api v0.29.0 + k8s.io/apimachinery v0.29.0 + k8s.io/client-go v0.29.0 +) + +require ( + github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Microsoft/hcsshim v0.11.4 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/containerd/containerd v1.7.12 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/docker/cli v24.0.6+incompatible // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/docker v24.0.9+incompatible // indirect + github.com/docker/docker-credential-helpers v0.7.0 // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-metrics v0.0.1 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/evanphx/json-patch v5.7.0+incompatible // indirect + github.com/fatih/color v1.14.1 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/go-logr/logr v1.3.0 // 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/go-stack/stack v1.8.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/btree v1.1.2 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/huandu/xstrings v1.4.0 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.16.0 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // 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.14 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/locker v1.0.1 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc5 // indirect + github.com/pelletier/go-toml/v2 v2.0.7 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // 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/rivo/uniseg v0.4.4 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.4.2 // indirect + github.com/xlab/treeprint v1.2.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect + golang.org/x/crypto v0.29.0 // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/term v0.26.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/time v0.3.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/grpc v1.58.3 // indirect + google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/cli-runtime v0.29.0 // indirect + k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + oras.land/oras-go v1.2.4 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect + sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) diff --git a/venonactl/go.sum b/venonactl/go.sum new file mode 100644 index 00000000..cca3869f --- /dev/null +++ b/venonactl/go.sum @@ -0,0 +1,859 @@ +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/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +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/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= +github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +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/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A= +github.com/briandowns/spinner v1.23.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/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/codefresh-io/go-sdk v0.52.0 h1:s+O87OebisNiDOEsh3qSAB8gDJ+Sc6WmBOh8AaFlm/o= +github.com/codefresh-io/go-sdk v0.52.0/go.mod h1:CcoVmTFWHGkbrSW8LyOGB/vJe5Vzr3iC/pNE2QIBTyg= +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0= +github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk= +github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= +github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +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/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= +github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI= +github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= +github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= +github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= +github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= +github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= +github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +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-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-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +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.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= +github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +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/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/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/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +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/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/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= +github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +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.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/log15 v2.16.0+incompatible h1:6nvMKxtGcpgm7q0KiGs+Vc+xDvUXaBqsPKHWKsinccw= +github.com/inconshreveable/log15 v2.16.0+incompatible/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +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.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/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/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/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.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/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +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.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.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +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/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg= +github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.0.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/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +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/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= +github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= +github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= +github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/pkg/errors v0.8.0/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 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.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +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-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.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +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.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.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +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/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +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/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +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 v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +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.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= +github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= +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.3.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 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.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/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/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +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/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-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-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/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.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +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-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-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-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.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +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.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/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-20190801041406-cbf593c0f2f3/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-20210616094352-59db8d763f22/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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.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-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= +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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +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= +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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-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/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +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.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.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= +google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +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.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +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/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.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +helm.sh/helm/v3 v3.14.4 h1:6FSpEfqyDalHq3kUr4gOMThhgY55kXUEjdQoyODYnrM= +helm.sh/helm/v3 v3.14.4/go.mod h1:Tje7LL4gprZpuBNTbG34d1Xn5NmRT3OWfBRwpOSer9I= +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.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= +k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= +k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= +k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= +k8s.io/cli-runtime v0.29.0 h1:q2kC3cex4rOBLfPOnMSzV2BIrrQlx97gxHJs21KxKS4= +k8s.io/cli-runtime v0.29.0/go.mod h1:VKudXp3X7wR45L+nER85YUzOQIru28HQpXr0mTdeCrk= +k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= +k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= +oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= +sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= +sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= +sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/venonactl/hack/build-linux.sh b/venonactl/hack/build-linux.sh new file mode 100755 index 00000000..b745a7c4 --- /dev/null +++ b/venonactl/hack/build-linux.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e +DIR=$(realpath $(dirname $0)/..) +OUTFILE=${DIR}/venonactl-linux +go generate ${DIR}/hack/generate.go +go fmt ${DIR}/pkg/obj/kubeobj/kubeobj.go +go fmt ${DIR}/pkg/templates/kubernetes/templates.go + +CGO_ENABLED=0 GOOS=linux go build -gcflags=all="-N -l" -ldflags '-X github.com/codefresh-io/venona/venonactl/cmd.localDevFlow=true' -o $OUTFILE ${DIR} + +chmod +x $OUTFILE diff --git a/venonactl/hack/build.sh b/venonactl/hack/build.sh new file mode 100755 index 00000000..8d044bfb --- /dev/null +++ b/venonactl/hack/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e +OUTFILE=/usr/local/bin/venonactl +go generate ${PWD}/hack/generate.go +go fmt ${PWD}/pkg/obj/kubeobj/kubeobj.go +go fmt ${PWD}/pkg/templates/kubernetes/templates.go +VERSION="$(cat VERSION)-$(git rev-parse --short HEAD)" +echo "Setting up version $VERSION" +CGO_ENABLED=0 go build -ldflags "-X github.com/codefresh-io/venona/venonactl/cmd.version=$VERSION" -v -o $OUTFILE main.go + +chmod +x $OUTFILE diff --git a/venonactl/hack/fmt.sh b/venonactl/hack/fmt.sh new file mode 100755 index 00000000..fe4c3c6e --- /dev/null +++ b/venonactl/hack/fmt.sh @@ -0,0 +1,3 @@ +echo "formating .go files" +gofmt -l -s -w . +echo "done!" \ No newline at end of file diff --git a/venonactl/hack/generate.go b/venonactl/hack/generate.go new file mode 100644 index 00000000..36d13f9e --- /dev/null +++ b/venonactl/hack/generate.go @@ -0,0 +1,7 @@ +package hack + +/* +We are using generated template.go for serialized kubernetes assets +*/ +//go:generate go run github.com/codefresh-io/venona/venonactl/pkg/templates kubernetes +//go:generate go run github.com/codefresh-io/venona/venonactl/pkg/obj kubernetes diff --git a/venonactl/main.go b/venonactl/main.go new file mode 100644 index 00000000..5f516d74 --- /dev/null +++ b/venonactl/main.go @@ -0,0 +1,69 @@ +// Copyright © 2018 NAME HERE +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !windows + +package main + +import ( + "context" + "fmt" + "os" + "os/signal" + "syscall" + + "github.com/codefresh-io/venona/venonactl/cmd" +) + +const ( + waitForSignalEnv = "WAIT_FOR_DEBUGGER" + debuggerPort = "4321" +) + +func main() { + sigs := make(chan os.Signal, 1) + goOn := make(chan bool, 1) + ctx, cancel := context.WithCancel(context.Background()) + signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT, syscall.SIGUSR1) + + go func() { + for sig := range sigs { + if sig == syscall.SIGUSR1 { + goOn <- true + } else if sig == syscall.SIGTERM || sig == syscall.SIGINT { + fmt.Printf("signal received, aborting: %s", sig) + cancel() + } + } + }() + + if os.Getenv(waitForSignalEnv) != "" { + // Waiting for debugger attach in case if waitForSignalEnv!="" + // For debuging venonactl spawned by `codefresh runner ...` + fmt.Printf("%s env is set, waiting SIGUSR1.\nYou can run remote debug in vscode and attach dlv debugger:\n\n", waitForSignalEnv) + + pid := os.Getpid() + fmt.Printf("dlv attach --continue --accept-multiclient --headless --listen=:%s %d\n", debuggerPort, pid) + fmt.Printf("kill -SIGUSR1 %d\n", pid) + + select { + case <-goOn: + case <-ctx.Done(): + os.Exit(1) // abort + } + fmt.Printf("Continue ...") + } + + cmd.Execute(ctx) +} diff --git a/venonactl/main_windows.go b/venonactl/main_windows.go new file mode 100644 index 00000000..c38b449a --- /dev/null +++ b/venonactl/main_windows.go @@ -0,0 +1,42 @@ +// Copyright © 2018 NAME HERE +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "context" + "fmt" + "os" + "os/signal" + "syscall" + + "github.com/codefresh-io/venona/venonactl/cmd" +) + +func main() { + sigs := make(chan os.Signal, 1) + ctx, cancel := context.WithCancel(context.Background()) + signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT) + + go func() { + for sig := range sigs { + if sig == syscall.SIGTERM || sig == syscall.SIGINT { + fmt.Printf("signal received, aborting: %s", sig) + cancel() + } + } + }() + + cmd.Execute(ctx) +} diff --git a/venonactl/pkg/certs/server_cert.go b/venonactl/pkg/certs/server_cert.go new file mode 100644 index 00000000..bfc5b78a --- /dev/null +++ b/venonactl/pkg/certs/server_cert.go @@ -0,0 +1,82 @@ +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package certs + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" +) + +const ( + defaultCertCN = "docker.codefresh.io" +) + +// ServerCert contains Server Cert pair +type ServerCert struct { + Key string + Csr string + Cert string + Ca string +} + +// NewServerCert - generates ServerCert with csr +func NewServerCert() (*ServerCert, error) { + + serverCert := &ServerCert{} + err := serverCert.GenerateCsr() + return serverCert, err +} + +// GenerateCsr - generates csr +func (u *ServerCert) GenerateCsr() error { + + certCN := defaultCertCN + privateKey, _ := rsa.GenerateKey(rand.Reader, 2048) + subj := pkix.Name{ + CommonName: certCN, + } + + template := x509.CertificateRequest{ + Subject: subj, + SignatureAlgorithm: x509.SHA256WithRSA, + } + + csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &template, privateKey) + if err != nil { + return err + } + + // Encoding Csr + csrBuf := bytes.NewBufferString("") + pem.Encode(csrBuf, &pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrBytes}) + u.Csr = csrBuf.String() + + // Encoding Key + keyBuf := bytes.NewBufferString("") + keyBlock := &pem.Block{ + Type: "PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(privateKey), + } + + pem.Encode(keyBuf, keyBlock) + u.Key = keyBuf.String() + return nil +} diff --git a/venonactl/pkg/codefresh/cfapi.go b/venonactl/pkg/codefresh/cfapi.go new file mode 100644 index 00000000..b4c9b8e7 --- /dev/null +++ b/venonactl/pkg/codefresh/cfapi.go @@ -0,0 +1,210 @@ +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package codefresh + +import ( + "bytes" + "crypto/tls" + "fmt" + "net/http" + + "archive/zip" + + "github.com/codefresh-io/go-sdk/pkg/codefresh" + "github.com/codefresh-io/venona/venonactl/pkg/certs" +) + +type ( + API interface { + RuntimeEnvironmentRegistrator + } + + APIOptions struct { + Logger logger + CodefreshHost string + CodefreshToken string + ClusterName string + ClusterNamespace string + RegisterWithAgent bool + MarkAsDefault bool + Insecure bool + StorageClass string + IsDefaultStorageClass bool + BuildNodeSelector map[string]string + Annotations map[string]string + } + + RuntimeEnvironmentRegistrator interface { + Validate() error + Sign() (*certs.ServerCert, error) + Register() (*codefresh.RuntimeEnvironment, error) + } + + api struct { + logger logger + codefresh codefresh.Codefresh + clustername string + clusternamespace string + registerWithAgent bool + markAsDefault bool + storageClass string + isDefaultStorageClass bool + buildNodeSelector map[string]string + annotations map[string]string + } + + logger interface { + Debug(message string, args ...interface{}) + } +) + +// NewCodefreshAPI - creates new codefresh api +func NewCodefreshAPI(opt *APIOptions) API { + httpClient := &http.Client{} + if opt.Insecure { + customTransport := &(*http.DefaultTransport.(*http.Transport)) // make shallow copy + // #nosec + customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + + httpClient = &http.Client{ + Transport: customTransport, + } + } + + return &api{ + logger: opt.Logger, + codefresh: codefresh.New(&codefresh.ClientOptions{ + Auth: codefresh.AuthOptions{ + Token: opt.CodefreshToken, + }, + Host: opt.CodefreshHost, + Client: httpClient, + }), + clustername: opt.ClusterName, + clusternamespace: opt.ClusterNamespace, + registerWithAgent: opt.RegisterWithAgent, + storageClass: opt.StorageClass, + isDefaultStorageClass: opt.IsDefaultStorageClass, + buildNodeSelector: opt.BuildNodeSelector, + annotations: opt.Annotations, + } +} + +func (a *api) Validate() error { + a.logger.Debug("Validating runtime-environment") + opt := codefresh.ValidateRuntimeOptions{ + Cluster: a.clustername, + Namespace: a.clusternamespace, + } + return a.codefresh.RuntimeEnvironments().Validate(&opt) +} + +func (a *api) Sign() (*certs.ServerCert, error) { + a.logger.Debug("Signing runtime-environment") + serverCert, err := certs.NewServerCert() + if err != nil { + return nil, err + } + certExtraSANs := fmt.Sprintf("IP:127.0.0.1,DNS:dind,DNS:*.dind.%s,DNS:*.dind.%s.svc,DNS:*.cf-cd.com,DNS:*.codefresh.io", a.clusternamespace, a.clusternamespace) + a.logger.Debug(fmt.Sprintf("certExtraSANs = %s", certExtraSANs)) + + byteArray, err := a.codefresh.RuntimeEnvironments().SignCertificate(&codefresh.SignCertificatesOptions{ + AltName: certExtraSANs, + CSR: serverCert.Csr, + }) + if err != nil { + a.logger.Debug("Failed to sign certificate") + return nil, err + } + + a.logger.Debug("Certificate was signed") + respBodyReaderAt := bytes.NewReader(byteArray) + zipReader, err := zip.NewReader(respBodyReaderAt, int64(len(byteArray))) + if err != nil { + a.logger.Debug("Failed to create zip reader from given certificate " + fmt.Sprintf("%s", byteArray)) + return nil, err + } + for _, zf := range zipReader.File { + a.logger.Debug("Reading file ", "name", zf.Name) + buf := new(bytes.Buffer) + src, _ := zf.Open() + defer src.Close() + buf.ReadFrom(src) + + if zf.Name == "cf-ca.pem" { + serverCert.Ca = buf.String() + } else if zf.Name == "cf-server-cert.pem" { + serverCert.Cert = buf.String() + } else { + a.logger.Debug(fmt.Sprintf("Warning: Unknown filename in sign responce %s", zf.Name)) + } + } + + // Validating serverCert + var missingCerts string + if serverCert.Csr == "" { + missingCerts += " csr" + } + if serverCert.Cert == "" { + missingCerts += " cert" + } + if serverCert.Key == "" { + missingCerts += " key" + } + if serverCert.Ca == "" { + missingCerts += " ca" + } + if missingCerts != "" { + return nil, fmt.Errorf("Failed to to generate and sign certificates: %s is missing", missingCerts) + } + + // update store with certs + return serverCert, nil +} + +func (a *api) Register() (*codefresh.RuntimeEnvironment, error) { + a.logger.Debug("Registering runtime-environment") + options := &codefresh.CreateRuntimeOptions{ + Namespace: a.clusternamespace, + HasAgent: a.registerWithAgent, + Cluster: a.clustername, + } + if len(a.buildNodeSelector) != 0 { + options.NodeSelector = a.buildNodeSelector + } + + options.StorageClass = a.storageClass + + if len(a.annotations) != 0 { + options.Annotations = a.annotations + } + + re, err := a.codefresh.RuntimeEnvironments().Create(options) + if err != nil { + return nil, err + } + + if a.markAsDefault { + a.logger.Debug("Setting runtime as deault") + _, err := a.codefresh.RuntimeEnvironments().Default(re.Metadata.Name) + if err != nil { + return nil, err + } + } + + return re, nil +} diff --git a/venonactl/pkg/kube/kube.go b/venonactl/pkg/kube/kube.go new file mode 100644 index 00000000..bc643233 --- /dev/null +++ b/venonactl/pkg/kube/kube.go @@ -0,0 +1,109 @@ +package kube + +import ( + "context" + "errors" + "strings" + + v1Core "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" +) + +type ( + Kube interface { + BuildClient() (*kubernetes.Clientset, error) + BuildConfig() (*rest.Config, error) + EnsureNamespaceExists(ctx context.Context, cs *kubernetes.Clientset) error + } + + kube struct { + contextName string + namespace string + pathToKubeConfig string + inCluster bool + dryRun bool + } + + Options struct { + ContextName string + Namespace string + PathToKubeConfig string + InCluster bool + DryRun bool + } +) + +func New(o *Options) Kube { + return &kube{ + contextName: o.ContextName, + namespace: o.Namespace, + pathToKubeConfig: o.PathToKubeConfig, + inCluster: o.InCluster, + dryRun: o.DryRun, + } +} + +func (k *kube) BuildClient() (*kubernetes.Clientset, error) { + var config *rest.Config + var err error + if k.inCluster { + config, err = rest.InClusterConfig() + } else { + config, err = k.BuildConfig() + if err != nil { // if cannot create from kubeConfigPath, try in-cluster config + config, err = rest.InClusterConfig() + } + } + if err != nil { + return nil, err + } + cs, err := kubernetes.NewForConfig(config) + if err != nil { + if strings.Contains(err.Error(), "exec plugin: invalid apiVersion") { + return nil, errors.New("Kubeconfig user entry is using an invalid API version client.authentication.k8s.io/v1alpha1.\nSee details at https://support.codefresh.io/hc/en-us/articles/6947789386652-Failure-to-perform-actions-on-your-selected-Kubernetes-context") + } + + return nil, err + } + + return cs, nil +} + +func (k *kube) EnsureNamespaceExists(ctx context.Context, cs *kubernetes.Clientset) error { + if k.dryRun { + return nil + } + _, err := cs.CoreV1().Namespaces().Get(ctx, k.namespace, v1.GetOptions{}) + if err != nil { + nsSpec := &v1Core.Namespace{ObjectMeta: metav1.ObjectMeta{Name: k.namespace}} + _, err := cs.CoreV1().Namespaces().Create(ctx, nsSpec, v1.CreateOptions{}) + if err != nil { + return err + } + } + return nil +} + +func (k *kube) BuildConfig() (*rest.Config, error) { + config := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( + &clientcmd.ClientConfigLoadingRules{ExplicitPath: k.pathToKubeConfig}, + &clientcmd.ConfigOverrides{ + CurrentContext: k.contextName, + Context: clientcmdapi.Context{ + Namespace: k.namespace, + }, + }) + cc, err := config.ClientConfig() + + if err != nil { // if cannot create from kubeConfigPath, try in-cluster config + return rest.InClusterConfig() + } + + return cc, nil + +} diff --git a/venonactl/pkg/logger/custom-logger.go b/venonactl/pkg/logger/custom-logger.go new file mode 100644 index 00000000..5ada8f98 --- /dev/null +++ b/venonactl/pkg/logger/custom-logger.go @@ -0,0 +1,28 @@ +package logger + +import ( + "bytes" + "fmt" + "os" + + log "github.com/inconshreveable/log15" +) + +const ( + Plain = "plain" +) + +func PlainTextFormatter() log.Format { + return log.FormatFunc(func(r *log.Record) []byte { + buf := &bytes.Buffer{} + fmt.Fprintf(buf, "%s\n", r.Msg) + return buf.Bytes() + }) +} + +func getStdoutHanlder(o *Options) log.Handler { + if o.LogFormatter == Plain { + return log.StreamHandler(os.Stdout, PlainTextFormatter()) + } + return log.StdoutHandler +} diff --git a/venonactl/pkg/logger/logger.go b/venonactl/pkg/logger/logger.go new file mode 100644 index 00000000..4e0113b4 --- /dev/null +++ b/venonactl/pkg/logger/logger.go @@ -0,0 +1,40 @@ +package logger + +import ( + log "github.com/inconshreveable/log15" +) + +type ( + Logger interface { + log.Logger + } + + Options struct { + Command string + Verbose bool + LogToFile string + LogFormatter string + } +) + +func New(o *Options) Logger { + l := log.New(log.Ctx{ + "Command": o.Command, + }) + handlers := []log.Handler{} + lvl := log.LvlInfo + if o.Verbose { + lvl = log.LvlDebug + } + verboseHandler := log.LvlFilterHandler(lvl, getStdoutHanlder(o)) + handlers = append(handlers, verboseHandler) + if o.LogToFile != "" { + fileHandler := log.LvlFilterHandler(log.LvlDebug, log.Must.FileHandler(o.LogToFile, log.JsonFormat())) + callerHandler := log.CallerFuncHandler(fileHandler) + fileLineHandler := log.CallerFileHandler(callerHandler) + handlers = append(handlers, fileLineHandler) + + } + l.SetHandler(log.MultiHandler(handlers...)) + return l +} diff --git a/venonactl/pkg/obj/kubeobj/kubeobj.go b/venonactl/pkg/obj/kubeobj/kubeobj.go new file mode 100644 index 00000000..5392f470 --- /dev/null +++ b/venonactl/pkg/obj/kubeobj/kubeobj.go @@ -0,0 +1,581 @@ +// Code generated by go generate; DO NOT EDIT. + +package kubeobj + +import ( + "context" + "fmt" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + + appsv1 "k8s.io/api/apps/v1" + "k8s.io/api/core/v1" + v1beta1 "k8s.io/api/extensions/v1beta1" + netv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + rbacv1 "k8s.io/api/rbac/v1" + rbacv1beta1 "k8s.io/api/rbac/v1beta1" + + storagev1 "k8s.io/api/storage/v1" + + batchv1 "k8s.io/api/batch/v1" + batchv1beta1 "k8s.io/api/batch/v1beta1" +) + +// CreateObject - creates kubernetes object from *runtime.Object. Returns object name, kind and creation error +func CreateObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error) { + + var name, kind string + var err error + switch objT := obj.(type) { + + case *appsv1.DaemonSet: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.AppsV1().DaemonSets(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *appsv1.Deployment: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.AppsV1().Deployments(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *batchv1.Job: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.BatchV1().Jobs(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *batchv1beta1.CronJob: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.BatchV1beta1().CronJobs(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *netv1.Ingress: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.NetworkingV1().Ingresses(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *rbacv1.ClusterRole: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1().ClusterRoles().Create(ctx, objT, metav1.CreateOptions{}) + + case *rbacv1.ClusterRoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1().ClusterRoleBindings().Create(ctx, objT, metav1.CreateOptions{}) + + case *rbacv1.Role: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1().Roles(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *rbacv1.RoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1().RoleBindings(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *rbacv1beta1.ClusterRole: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1beta1().ClusterRoles().Create(ctx, objT, metav1.CreateOptions{}) + + case *rbacv1beta1.ClusterRoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1beta1().ClusterRoleBindings().Create(ctx, objT, metav1.CreateOptions{}) + + case *rbacv1beta1.Role: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1beta1().Roles(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *rbacv1beta1.RoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1beta1().RoleBindings(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *storagev1.StorageClass: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.StorageV1().StorageClasses().Create(ctx, objT, metav1.CreateOptions{}) + + case *v1.ConfigMap: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().ConfigMaps(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *v1.PersistentVolume: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().PersistentVolumes().Create(ctx, objT, metav1.CreateOptions{}) + + case *v1.PersistentVolumeClaim: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().PersistentVolumeClaims(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *v1.Pod: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().Pods(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *v1.Secret: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().Secrets(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *v1.Service: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().Services(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *v1.ServiceAccount: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().ServiceAccounts(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *v1beta1.DaemonSet: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.ExtensionsV1beta1().DaemonSets(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + case *v1beta1.Deployment: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.ExtensionsV1beta1().Deployments(namespace).Create(ctx, objT, metav1.CreateOptions{}) + + default: + return "", "", fmt.Errorf("Unknown object type %T\n ", objT) + } + return name, kind, err +} + +// CheckObject - checks kubernetes object from *runtime.Object. Returns object name, kind and creation error +func CheckObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error) { + + var name, kind string + var err error + switch objT := obj.(type) { + + case *appsv1.DaemonSet: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.AppsV1().DaemonSets(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *appsv1.Deployment: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *batchv1.Job: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *batchv1beta1.CronJob: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.BatchV1beta1().CronJobs(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *netv1.Ingress: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.NetworkingV1().Ingresses(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *rbacv1.ClusterRole: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1().ClusterRoles().Get(ctx, name, metav1.GetOptions{}) + + case *rbacv1.ClusterRoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1().ClusterRoleBindings().Get(ctx, name, metav1.GetOptions{}) + + case *rbacv1.Role: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1().Roles(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *rbacv1.RoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1().RoleBindings(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *rbacv1beta1.ClusterRole: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1beta1().ClusterRoles().Get(ctx, name, metav1.GetOptions{}) + + case *rbacv1beta1.ClusterRoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1beta1().ClusterRoleBindings().Get(ctx, name, metav1.GetOptions{}) + + case *rbacv1beta1.Role: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1beta1().Roles(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *rbacv1beta1.RoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1beta1().RoleBindings(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *storagev1.StorageClass: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.StorageV1().StorageClasses().Get(ctx, name, metav1.GetOptions{}) + + case *v1.ConfigMap: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().ConfigMaps(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *v1.PersistentVolume: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().PersistentVolumes().Get(ctx, name, metav1.GetOptions{}) + + case *v1.PersistentVolumeClaim: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *v1.Pod: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().Pods(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *v1.Secret: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().Secrets(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *v1.Service: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().Services(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *v1.ServiceAccount: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().ServiceAccounts(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *v1beta1.DaemonSet: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.ExtensionsV1beta1().DaemonSets(namespace).Get(ctx, name, metav1.GetOptions{}) + + case *v1beta1.Deployment: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.ExtensionsV1beta1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) + + default: + return "", "", fmt.Errorf("Unknown object type %T\n ", objT) + } + return name, kind, err +} + +// DeleteObject - checks kubernetes object from *runtime.Object. Returns object name, kind and creation error +func DeleteObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error) { + var propagationPolicy metav1.DeletionPropagation = "Background" + var name, kind string + var err error + switch objT := obj.(type) { + + case *appsv1.DaemonSet: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.AppsV1().DaemonSets(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *appsv1.Deployment: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.AppsV1().Deployments(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *batchv1.Job: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.BatchV1().Jobs(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *batchv1beta1.CronJob: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.BatchV1beta1().CronJobs(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *netv1.Ingress: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.NetworkingV1().Ingresses(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *rbacv1.ClusterRole: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.RbacV1().ClusterRoles().Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *rbacv1.ClusterRoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.RbacV1().ClusterRoleBindings().Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *rbacv1.Role: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.RbacV1().Roles(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *rbacv1.RoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.RbacV1().RoleBindings(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *rbacv1beta1.ClusterRole: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.RbacV1beta1().ClusterRoles().Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *rbacv1beta1.ClusterRoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.RbacV1beta1().ClusterRoleBindings().Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *rbacv1beta1.Role: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.RbacV1beta1().Roles(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *rbacv1beta1.RoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.RbacV1beta1().RoleBindings(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *storagev1.StorageClass: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.StorageV1().StorageClasses().Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *v1.ConfigMap: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.CoreV1().ConfigMaps(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *v1.PersistentVolume: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.CoreV1().PersistentVolumes().Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *v1.PersistentVolumeClaim: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.CoreV1().PersistentVolumeClaims(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *v1.Pod: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.CoreV1().Pods(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *v1.Secret: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.CoreV1().Secrets(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *v1.Service: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.CoreV1().Services(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *v1.ServiceAccount: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.CoreV1().ServiceAccounts(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *v1beta1.DaemonSet: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.ExtensionsV1beta1().DaemonSets(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + case *v1beta1.Deployment: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.ExtensionsV1beta1().Deployments(namespace).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + + default: + return "", "", fmt.Errorf("Unknown object type %T\n ", objT) + } + return name, kind, err +} + +// ReplaceObject - replaces kubernetes object from *runtime.Object. Returns object name, kind and creation error +func ReplaceObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error) { + var name, kind string + var err error + switch objT := obj.(type) { + + case *appsv1.DaemonSet: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.AppsV1().DaemonSets(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *appsv1.Deployment: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.AppsV1().Deployments(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *batchv1.Job: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.BatchV1().Jobs(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *batchv1beta1.CronJob: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.BatchV1beta1().CronJobs(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *netv1.Ingress: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.NetworkingV1().Ingresses(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *rbacv1.ClusterRole: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1().ClusterRoles().Update(ctx, objT, metav1.UpdateOptions{}) + + case *rbacv1.ClusterRoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1().ClusterRoleBindings().Update(ctx, objT, metav1.UpdateOptions{}) + + case *rbacv1.Role: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1().Roles(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *rbacv1.RoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1().RoleBindings(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *rbacv1beta1.ClusterRole: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1beta1().ClusterRoles().Update(ctx, objT, metav1.UpdateOptions{}) + + case *rbacv1beta1.ClusterRoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1beta1().ClusterRoleBindings().Update(ctx, objT, metav1.UpdateOptions{}) + + case *rbacv1beta1.Role: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1beta1().Roles(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *rbacv1beta1.RoleBinding: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.RbacV1beta1().RoleBindings(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *storagev1.StorageClass: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.StorageV1().StorageClasses().Update(ctx, objT, metav1.UpdateOptions{}) + + case *v1.ConfigMap: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().ConfigMaps(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *v1.PersistentVolume: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().PersistentVolumes().Update(ctx, objT, metav1.UpdateOptions{}) + + case *v1.PersistentVolumeClaim: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().PersistentVolumeClaims(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *v1.Pod: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().Pods(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *v1.Secret: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().Secrets(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *v1.Service: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().Services(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *v1.ServiceAccount: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.CoreV1().ServiceAccounts(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *v1beta1.DaemonSet: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.ExtensionsV1beta1().DaemonSets(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + case *v1beta1.Deployment: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.ExtensionsV1beta1().Deployments(namespace).Update(ctx, objT, metav1.UpdateOptions{}) + + default: + return "", "", fmt.Errorf("Unknown object type %T\n ", objT) + } + return name, kind, err +} diff --git a/venonactl/pkg/obj/kubeobj_generator.go b/venonactl/pkg/obj/kubeobj_generator.go new file mode 100644 index 00000000..e27368e4 --- /dev/null +++ b/venonactl/pkg/obj/kubeobj_generator.go @@ -0,0 +1,202 @@ +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "os" + "path" + "path/filepath" + "runtime" + "strings" + "text/template" +) + +/* +for usage in +\\go:generate go run generate generate_template.go +reads all files in folder and appends them to template map +*/ + +var outfileBaseName = "kubeobj.go" +var functionsMap map[string]string = map[string]string{ + "v1.Secret": "CoreV1().Secrets(namespace)", + "v1.ConfigMap": "CoreV1().ConfigMaps(namespace)", + "v1.Service": "CoreV1().Services(namespace)", + "v1.Pod": "CoreV1().Pods(namespace)", + "v1.ServiceAccount": "CoreV1().ServiceAccounts(namespace)", + "v1.PersistentVolumeClaim": "CoreV1().PersistentVolumeClaims(namespace)", + "v1.PersistentVolume": "CoreV1().PersistentVolumes()", + + "v1beta1.Deployment": "ExtensionsV1beta1().Deployments(namespace)", + "v1beta1.DaemonSet": "ExtensionsV1beta1().DaemonSets(namespace)", + + "netv1.Ingress": "NetworkingV1().Ingresses(namespace)", + + "appsv1.Deployment": "AppsV1().Deployments(namespace)", + "appsv1.DaemonSet": "AppsV1().DaemonSets(namespace)", + + "rbacv1beta1.ClusterRole": "RbacV1beta1().ClusterRoles()", + "rbacv1beta1.ClusterRoleBinding": "RbacV1beta1().ClusterRoleBindings()", + "rbacv1beta1.Role": "RbacV1beta1().Roles(namespace)", + "rbacv1beta1.RoleBinding": "RbacV1beta1().RoleBindings(namespace)", + + "rbacv1.ClusterRole": "RbacV1().ClusterRoles()", + "rbacv1.ClusterRoleBinding": "RbacV1().ClusterRoleBindings()", + "rbacv1.Role": "RbacV1().Roles(namespace)", + "rbacv1.RoleBinding": "RbacV1().RoleBindings(namespace)", + + "storagev1.StorageClass": "StorageV1().StorageClasses()", + + "batchv1.Job": "BatchV1().Jobs(namespace)", + "batchv1beta1.CronJob": "BatchV1beta1().CronJobs(namespace)", +} + +var packageTemplate = template.Must(template.New("").Parse( + ` +// Code generated by go generate; DO NOT EDIT. + +package kubeobj + +import ( + "fmt" + "context" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/api/core/v1" + v1beta1 "k8s.io/api/extensions/v1beta1" + netv1 "k8s.io/api/networking/v1" + appsv1 "k8s.io/api/apps/v1" + + rbacv1beta1 "k8s.io/api/rbac/v1beta1" + rbacv1 "k8s.io/api/rbac/v1" + + storagev1 "k8s.io/api/storage/v1" + + batchv1 "k8s.io/api/batch/v1" + batchv1beta1 "k8s.io/api/batch/v1beta1" +) + +// CreateObject - creates kubernetes object from *runtime.Object. Returns object name, kind and creation error +func CreateObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error){ + + var name, kind string + var err error + switch objT := obj.(type) { + {{ range $key, $value := .FunctionsMap }} + case *{{ $key }}: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.{{ $value }}.Create(ctx, objT, metav1.CreateOptions{}) + {{ end }} + default: + return "", "", fmt.Errorf("Unknown object type %T\n ", objT) + } + return name, kind, err +} + +// CheckObject - checks kubernetes object from *runtime.Object. Returns object name, kind and creation error +func CheckObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error){ + + var name, kind string + var err error + switch objT := obj.(type) { + {{ range $key, $value := .FunctionsMap }} + case *{{ $key }}: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.{{ $value }}.Get(ctx, name, metav1.GetOptions{}) + {{ end }} + default: + return "", "", fmt.Errorf("Unknown object type %T\n ", objT) + } + return name, kind, err +} + +// DeleteObject - checks kubernetes object from *runtime.Object. Returns object name, kind and creation error +func DeleteObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error){ + var propagationPolicy metav1.DeletionPropagation = "Background" + var name, kind string + var err error + switch objT := obj.(type) { + {{ range $key, $value := .FunctionsMap }} + case *{{ $key }}: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + err = clientset.{{ $value }}.Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &propagationPolicy, + }) + {{ end }} + default: + return "", "", fmt.Errorf("Unknown object type %T\n ", objT) + } + return name, kind, err +} + +// ReplaceObject - replaces kubernetes object from *runtime.Object. Returns object name, kind and creation error +func ReplaceObject(ctx context.Context, clientset *kubernetes.Clientset, obj runtime.Object, namespace string) (string, string, error){ + var name, kind string + var err error + switch objT := obj.(type) { + {{ range $key, $value := .FunctionsMap }} + case *{{ $key }}: + name = objT.ObjectMeta.Name + kind = objT.TypeMeta.Kind + _, err = clientset.{{ $value }}.Update(ctx, objT, metav1.UpdateOptions{}) + {{ end }} + default: + return "", "", fmt.Errorf("Unknown object type %T\n ", objT) + } + return name, kind, err +} + +`)) + +type tempateData struct { + FunctionsMap map[string]string +} + +func main() { + + var currentFilePath string + if strings.Contains(os.Args[0], "/go-build") { + _, currentFilePath, _, _ = runtime.Caller(0) + } else { + currentFilePath = os.Args[0] + } + + currentDir := filepath.Dir(currentFilePath) + var folderName = path.Join(currentDir, "kubeobj") + + outfileName := path.Join(folderName, "kubeobj.go") + outfile, err := os.Create(outfileName) + if err != nil { + fmt.Printf("ERROR: cannot create out file %v", err) + os.Exit(1) + } + defer outfile.Close() + + err = packageTemplate.Execute(outfile, tempateData{ + FunctionsMap: functionsMap, + }) + if err != nil { + fmt.Printf("generate_template ERROR: cannot generate template %v \n", err) + os.Exit(1) + } +} diff --git a/venonactl/pkg/plugins/app-proxy.go b/venonactl/pkg/plugins/app-proxy.go new file mode 100644 index 00000000..3446d393 --- /dev/null +++ b/venonactl/pkg/plugins/app-proxy.go @@ -0,0 +1,132 @@ +package plugins + +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "context" + "fmt" + + "github.com/codefresh-io/venona/venonactl/pkg/logger" + templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" + "github.com/stretchr/objx" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type appProxyPlugin struct { + logger logger.Logger +} + +const ( + appProxyFilesPattern = ".*.app-proxy.yaml" +) + +func (u *appProxyPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { + + cs, err := opt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) + return nil, err + } + err = install(ctx, &installOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: opt.ClusterNamespace, + matchPattern: appProxyFilesPattern, + dryRun: opt.DryRun, + operatorType: AppProxyPluginType, + }) + if err != nil { + u.logger.Error(fmt.Sprintf("AppProxy installation failed: %v", err)) + return nil, err + } + + host := objx.New(v["AppProxy"]).Get("Ingress.Host").Str() + pathPrefix := objx.New(v["AppProxy"]).Get("Ingress.PathPrefix").Str() + appProxyURL := fmt.Sprintf("https://%v%v", host, pathPrefix) + u.logger.Info(fmt.Sprintf("app proxy is running at: %v", appProxyURL)) + return v, nil +} + +func (u *appProxyPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { + return [][]string{}, nil +} + +func (u *appProxyPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { + cs, err := deleteOpt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return err + } + opt := &deleteOptions{ + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: deleteOpt.ClusterNamespace, + matchPattern: appProxyFilesPattern, + operatorType: AppProxyPluginType, + logger: u.logger, + } + return uninstall(ctx, opt) +} + +func (u *appProxyPlugin) Upgrade(ctx context.Context, opt *UpgradeOptions, v Values) (Values, error) { + kubeClientset, err := opt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + + list, err := kubeClientset.CoreV1().Pods(opt.ClusterNamespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("app=%v", opt.Name)}) + if err != nil { + u.logger.Error(fmt.Sprintf("Failed to list app-proxy pods: %v ", err)) + return nil, err + } + if len(list.Items) == 0 { + u.logger.Info("no app-proxy pods found") + return nil, nil + } + + for _, pod := range list.Items { + podName := pod.ObjectMeta.Name + u.logger.Debug(fmt.Sprintf("Deleting app-proxy pod: %v", podName)) + err = kubeClientset.CoreV1().Pods(opt.ClusterNamespace).Delete(ctx, podName, metav1.DeleteOptions{}) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot delete app-proxy pod: %v ", err)) + return nil, err + } + } + + return v, nil +} +func (u *appProxyPlugin) Migrate(context.Context, *MigrateOptions, Values) error { + return fmt.Errorf("not supported") +} + +func (u *appProxyPlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { + return nil +} + +func (u *appProxyPlugin) Name() string { + return AppProxyPluginType +} diff --git a/venonactl/pkg/plugins/engine.go b/venonactl/pkg/plugins/engine.go new file mode 100644 index 00000000..c064521c --- /dev/null +++ b/venonactl/pkg/plugins/engine.go @@ -0,0 +1,111 @@ +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugins + +import ( + "context" + "fmt" + + "github.com/codefresh-io/venona/venonactl/pkg/logger" + templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" +) + +// enginePlugin installs assets on Kubernetes Dind runtimectl Env +type enginePlugin struct { + logger logger.Logger +} + +const ( + engineFilesPattern = ".*.engine.yaml" +) + +// Install venona agent +func (u *enginePlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { + cs, err := opt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) + return nil, err + } + return v, install(ctx, &installOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: opt.ClusterNamespace, + matchPattern: engineFilesPattern, + dryRun: opt.DryRun, + operatorType: EnginePluginType, + }) +} + +// Status of runtimectl environment +func (u *enginePlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { + cs, err := statusOpt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + opt := &statusOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: statusOpt.ClusterNamespace, + matchPattern: engineFilesPattern, + operatorType: EnginePluginType, + } + return status(ctx, opt) +} + +func (u *enginePlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { + cs, err := deleteOpt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil + } + opt := &deleteOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: deleteOpt.ClusterNamespace, + matchPattern: engineFilesPattern, + operatorType: EnginePluginType, + } + return uninstall(ctx, opt) +} + +func (u *enginePlugin) Upgrade(ctx context.Context, opt *UpgradeOptions, v Values) (Values, error) { + return v, nil +} + +func (u *enginePlugin) Migrate(context.Context, *MigrateOptions, Values) error { + return fmt.Errorf("not supported") +} + +func (u *enginePlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { + return nil +} + +func (u *enginePlugin) Name() string { + return EnginePluginType +} diff --git a/venonactl/pkg/plugins/helper.go b/venonactl/pkg/plugins/helper.go new file mode 100644 index 00000000..558066a2 --- /dev/null +++ b/venonactl/pkg/plugins/helper.go @@ -0,0 +1,367 @@ +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugins + +import ( + "bytes" + "context" + "errors" + "fmt" + "html/template" + "regexp" + "strings" + + // import all cloud providers auth clients + "gopkg.in/yaml.v2" + authv1 "k8s.io/api/authorization/v1" + v1 "k8s.io/api/core/v1" + "k8s.io/client-go/kubernetes" + _ "k8s.io/client-go/plugin/pkg/client/auth" + + "github.com/Masterminds/sprig" + "github.com/codefresh-io/venona/venonactl/pkg/logger" + templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" + + "github.com/Masterminds/semver" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/version" + "k8s.io/client-go/kubernetes/scheme" +) + +type ( + validationResult struct { + isValid bool + message []string + } + + validationRequest struct { + cpu string + localDiskMinimumSize string + momorySize string + rbac []rbacValidation + } + + rbacValidation struct { + Namespace string + Resource string + Verbs []string + Group string + } +) + +var requiredK8sVersion, _ = semver.NewConstraint(">= 1.10.0") + +func unescape(s string) template.HTML { + return template.HTML(s) +} + +// template function to parse values for nodeSelector in form "key1=value1,key2=value2" +func nodeSelectorParamToYaml(ns string) string { + nodeSelectorParts := strings.Split(ns, ",") + var nodeSelectorYaml string + for _, p := range nodeSelectorParts { + pSplit := strings.Split(p, "=") + if len(pSplit) != 2 { + continue + } + + if len(nodeSelectorYaml) > 0 { + nodeSelectorYaml += "\n" + } + nodeSelectorYaml += fmt.Sprintf("%s: %q", pSplit[0], pSplit[1]) + } + return nodeSelectorYaml +} + +func toYAML(v interface{}) string { + switch v.(type) { + case map[string]interface{}: + if len(v.(map[string]interface{})) == 0 { + return "" + } + case []v1.Toleration: + if len(v.([]v1.Toleration)) == 0 { + return "" + } + } + data, err := yaml.Marshal(v) + if err != nil { + // Swallow errors inside of a template. + return "" + } + return strings.TrimSuffix(string(data), "\n") +} + +func isString(v interface{}) bool { + _, ok := v.(string) + return ok +} + +func nodeSelectorToString(nodeSelectors map[string]string) string { + str := "" + for key, value := range nodeSelectors { + + //str = strings.Join([]string {str, fmt.Sprintf("%s=%s", key, value)} , ",") + str = fmt.Sprintf("%s,%s=%s", str, key, value) + + } + return strings.TrimPrefix(str, ",") +} +func tolerationsToSring(tolerations []v1.Toleration) string { + // [{\"effect\":\"NoSchedule\",\"key\":\"dedicated\",\"value\":\"codefresh\"},{\"effect\":\"NoSchedule\",\"key\":\"dedicated\",\"value\":\"codefresh\"}] + y, err := yaml.Marshal(&tolerations) + if err != nil { + return "" + } + return fmt.Sprintf("\n%s", string(y)) + +} + +// ExecuteTemplate - executes templates in tpl str with config as values +func ExecuteTemplate(tplStr string, data interface{}) (string, error) { + funcMap := template.FuncMap{ + "unescape": unescape, + "nodeSelectorParamToYaml": nodeSelectorParamToYaml, + "toYaml": toYAML, + "isString": isString, + } + template, err := template.New("base").Funcs(sprig.FuncMap()).Funcs(funcMap).Parse(tplStr) + if err != nil { + return "", err + } + + buf := bytes.NewBufferString("") + err = template.Execute(buf, data) + if err != nil { + return "", err + } + + return buf.String(), nil +} + +// ParseTemplates - parses and exexute templates and return map of strings with obj data +func ParseTemplates(templatesMap map[string]string, data interface{}, pattern string, logger logger.Logger) (map[string]string, error) { + parsedTemplates := make(map[string]string) + nonEmptyParsedTemplateFunc := regexp.MustCompile(`[a-zA-Z0-9]`).MatchString + for n, tpl := range templatesMap { + match, _ := regexp.MatchString(pattern, n) + if match != true { + logger.Debug(fmt.Sprintf("Skipping parsing, pattern does not match %s - %s", pattern, n)) + continue + } + logger.Debug(fmt.Sprintf("parsing template %s", n)) + tplEx, err := ExecuteTemplate(tpl, data) + if err != nil { + logger.Error(fmt.Sprintf("Failed to parse and execute template %s", n)) + return nil, err + } + + // we add only non-empty parsedTemplates + if nonEmptyParsedTemplateFunc(tplEx) { + parsedTemplates[n] = tplEx + } + } + return parsedTemplates, nil +} + +// KubeObjectsFromTemplates return map of runtime.Objects from templateMap +// see https://github.com/kubernetes/client-go/issues/193 for examples +func KubeObjectsFromTemplates(templatesMap map[string]string, data interface{}, pattern string, logger logger.Logger) (map[string]runtime.Object, error) { + parsedTemplates, err := ParseTemplates(templatesMap, data, pattern, logger) + if err != nil { + return nil, err + } + + // Deserializing all kube objects from parsedTemplates + // see https://github.com/kubernetes/client-go/issues/193 for examples + kubeDecode := scheme.Codecs.UniversalDeserializer().Decode + kubeObjects := make(map[string]runtime.Object) + for n, objStr := range parsedTemplates { + logger.Debug(fmt.Sprintf("Deserializing template %s %s", n, objStr)) + obj, groupVersionKind, err := kubeDecode([]byte(objStr), nil, nil) + if err != nil { + logger.Error(fmt.Sprintf("Cannot deserialize kuberentes object %s: %v", n, err)) + return nil, err + } + logger.Debug(fmt.Sprintf("deserializing template success %s group=%s", n, groupVersionKind.Group)) + kubeObjects[n] = obj + } + return kubeObjects, nil +} + +func getKubeObjectsFromTempalte(values map[string]interface{}, pattern string, logger logger.Logger) (map[string]runtime.Object, error) { + templatesMap := templates.TemplatesMap() + return KubeObjectsFromTemplates(templatesMap, values, pattern, logger) +} + +func ensureClusterRequirements(ctx context.Context, client *kubernetes.Clientset, req validationRequest, logger logger.Logger) (validationResult, error) { + result := validationResult{true, nil} + specs := []*authv1.SelfSubjectAccessReview{} + for _, rbac := range req.rbac { + for _, verb := range rbac.Verbs { + attr := &authv1.ResourceAttributes{ + Resource: rbac.Resource, + Verb: verb, + Group: rbac.Group, + } + if rbac.Namespace != "" { + attr.Namespace = rbac.Namespace + } + specs = append(specs, &authv1.SelfSubjectAccessReview{ + Spec: authv1.SelfSubjectAccessReviewSpec{ + ResourceAttributes: attr, + }, + }) + } + } + rbacres := testRBAC(ctx, client, specs) + if len(rbacres) > 0 { + result.isValid = false + for _, res := range rbacres { + result.message = append(result.message, res) + } + return result, nil + } + + v, err := client.ServerVersion() + if err != nil { + // should not fail if can't get version + logger.Warn("Failed to validate kubernetes version", "cause", err) + } else if res, err := testKubernetesVersion(v); !res { + if err != nil { + logger.Warn("Failed to validate kubernetes version", "cause", err) + } else { + result.isValid = false + result.message = append(result.message, fmt.Sprintf("Cluster does not meet the version requirements, minimum supported version is: '1.10.0' found version: '%v'", v)) + } + } + + nodes, err := client.CoreV1().Nodes().List(ctx, metav1.ListOptions{}) + if err != nil { + return result, err + } + if nodes == nil { + return result, errors.New("Nodes not found") + } + + if len(nodes.Items) == 0 { + result.message = append(result.message, "No nodes in cluster") + result.isValid = false + } + + atLeastOneMet := false + for _, n := range nodes.Items { + res := testNode(n, req) + if len(res) > 0 { + result.message = append(result.message, res...) + } else { + atLeastOneMet = true + } + } + if !atLeastOneMet { + result.isValid = false + return result, nil + } + return result, nil +} + +func handleValidationResult(res validationResult, logger logger.Logger) error { + if !res.isValid { + for _, m := range res.message { + logger.Error(m) + } + return errors.New("Failed to run acceptance test on cluster") + } + + for _, m := range res.message { + logger.Warn(m) + } + return nil +} + +func testKubernetesVersion(version *version.Info) (bool, error) { + v, err := semver.NewVersion(version.String()) + if err != nil { + return false, err + } + // extract only major, minor and patch + verStr := fmt.Sprintf("%v.%v.%v", v.Major(), v.Minor(), v.Patch()) + v, err = semver.NewVersion(verStr) + if err != nil { + return false, err + } + return requiredK8sVersion.Check(v), nil +} + +func testNode(n v1.Node, req validationRequest) []string { + result := []string{} + + if req.cpu != "" { + requiredCPU, err := resource.ParseQuantity(req.cpu) + if err != nil { + result = append(result, err.Error()) + return result + } + cpu := n.Status.Capacity.Cpu() + + if cpu != nil && cpu.Cmp(requiredCPU) == -1 { + msg := fmt.Sprintf("Insufficiant CPU on node %s, current: %s - required: %s", n.GetObjectMeta().GetName(), cpu.String(), requiredCPU.String()) + result = append(result, msg) + } + } + + if req.momorySize != "" { + requiredMemory, err := resource.ParseQuantity(req.momorySize) + if err != nil { + result = append(result, err.Error()) + return result + } + memory := n.Status.Capacity.Memory() + if memory != nil && memory.Cmp(requiredMemory) == -1 { + msg := fmt.Sprintf("Insufficiant Memory on node %s, current: %s - required: %s", n.GetObjectMeta().GetName(), memory.String(), requiredMemory.String()) + result = append(result, msg) + } + } + + return result +} + +func testRBAC(ctx context.Context, client *kubernetes.Clientset, specs []*authv1.SelfSubjectAccessReview) []string { + res := []string{} + for _, sar := range specs { + resp, err := client.AuthorizationV1().SelfSubjectAccessReviews().Create(ctx, sar, metav1.CreateOptions{}) + if err != nil { + res = append(res, err.Error()) + continue + } + if !resp.Status.Allowed { + verb := sar.Spec.ResourceAttributes.Verb + namespace := sar.Spec.ResourceAttributes.Namespace + resource := sar.Spec.ResourceAttributes.Resource + group := sar.Spec.ResourceAttributes.Group + msg := strings.Builder{} + msg.WriteString(fmt.Sprintf("Insufficient permission, %s %s/%s is not allowed", verb, group, resource)) + if namespace != "" { + msg.WriteString(fmt.Sprintf(" on namespace %s", namespace)) + } + res = append(res, msg.String()) + } + } + return res +} diff --git a/venonactl/pkg/plugins/monitor.go b/venonactl/pkg/plugins/monitor.go new file mode 100644 index 00000000..bb4c17bc --- /dev/null +++ b/venonactl/pkg/plugins/monitor.go @@ -0,0 +1,127 @@ +/* +Copyright 2020 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugins + +import ( + "context" + "fmt" + + "github.com/codefresh-io/venona/venonactl/pkg/logger" + templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" +) + +// k8sAgentPlugin installs assets on Kubernetes Dind runtimectl Env +type monitorAgentPlugin struct { + logger logger.Logger +} + +const ( + monitorFilesPattern = ".*.monitor.yaml" +) + +// Install k8sAgent agent +func (u *monitorAgentPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { + + cs, err := opt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) + return nil, err + } + return v, install(ctx, &installOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: opt.ClusterNamespace, + matchPattern: monitorFilesPattern, + dryRun: opt.DryRun, + operatorType: MonitorAgentPluginType, + }) +} + +func (u *monitorAgentPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { + return [][]string{}, nil +} + +func (u *monitorAgentPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { + cs, err := deleteOpt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return err + } + opt := &deleteOptions{ + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: deleteOpt.ClusterNamespace, + matchPattern: monitorFilesPattern, + operatorType: MonitorAgentPluginType, + logger: u.logger, + } + return uninstall(ctx, opt) +} + +func (u *monitorAgentPlugin) Upgrade(ctx context.Context, opt *UpgradeOptions, v Values) (Values, error) { + return nil, nil +} +func (u *monitorAgentPlugin) Migrate(context.Context, *MigrateOptions, Values) error { + return fmt.Errorf("not supported") +} + +func (u *monitorAgentPlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { + validationRequest := validationRequest{ + rbac: []rbacValidation{ + { + Group: "apps", + Resource: "*", + Verbs: []string{"get", "list", "watch"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "*", + Verbs: []string{"get", "list", "watch", "create", "delete"}, + Namespace: opt.ClusterNamespace, + }, + { + Group: "extensions", + Resource: "*", + Verbs: []string{"get", "list", "watch"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "pods", + Verbs: []string{"deletecollection"}, + Namespace: opt.ClusterNamespace, + }, + }, + } + return test(ctx, testOptions{ + logger: u.logger, + kubeBuilder: opt.KubeBuilder, + namespace: opt.ClusterNamespace, + validationRequest: validationRequest, + }) +} + +func (u *monitorAgentPlugin) Name() string { + return MonitorAgentPluginType +} diff --git a/venonactl/pkg/plugins/network-tester.go b/venonactl/pkg/plugins/network-tester.go new file mode 100644 index 00000000..7471fd43 --- /dev/null +++ b/venonactl/pkg/plugins/network-tester.go @@ -0,0 +1,238 @@ +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugins + +import ( + "bytes" + "context" + "errors" + "fmt" + "io" + "strings" + "time" + + "github.com/codefresh-io/venona/venonactl/pkg/logger" + "github.com/codefresh-io/venona/venonactl/pkg/store" + templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" + "github.com/stretchr/objx" + v1 "k8s.io/api/core/v1" + kerrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type networkTesterPlugin struct { + logger logger.Logger +} + +const ( + networkTesterFilesPattern = ".*.network-tester.yaml" + networkTestsTimeout = 120 * time.Second + defaultRegistry = "https://docker.io" + defaultCodefreshHost = "https://g.codefresh.io" + defaultFirebaseHost = "https://codefresh-prod-public-builds-1.firebaseio.com" +) + +var ( + errNetworkTestFailed = errors.New(`Cluster network tests failed. +- If you are using a proxy, run again with the correct http proxy environment variables. +- Make sure that cluster host address in your kubeconfig is accessible from inside the cluster, + or specify a different one with: --set-value KubernetesHost=
. +For more details run again with --verbose`) +) + +func (u *networkTesterPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { + return nil, fmt.Errorf("not supported") +} + +func (u *networkTesterPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { + return nil, fmt.Errorf("not supported") +} + +func (u *networkTesterPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { + return fmt.Errorf("not supported") +} + +func (u *networkTesterPlugin) Upgrade(ctx context.Context, opt *UpgradeOptions, v Values) (Values, error) { + return v, fmt.Errorf("not supported") +} + +func (u *networkTesterPlugin) Migrate(context.Context, *MigrateOptions, Values) error { + return fmt.Errorf("not supported") +} + +func prepareTestDomains(v map[string]interface{}) []string { + testDomains := make([]string, 0, 10) + + vObj := objx.New(v) + // codefresh host + if cfHost := vObj.Get("CodefreshHost").Str(); cfHost != "" { + testDomains = append(testDomains, cfHost) + } else { + testDomains = append(testDomains, defaultCodefreshHost) + } + + // registry + if dockerRegistry := vObj.Get("DockerRegistry").Str(); dockerRegistry != "" { + testDomains = append(testDomains, dockerRegistry) + } else { + testDomains = append(testDomains, defaultRegistry) + } + + // logging + if firebaseURL := vObj.Get("Logging.FirebaseHost").Str(); firebaseURL != "" { + testDomains = append(testDomains, firebaseURL) + } else { + testDomains = append(testDomains, defaultFirebaseHost) + } + + // git url + if gitProviderURL := vObj.Get("GitProviderURL").Str(); gitProviderURL != "" { + testDomains = append(testDomains, gitProviderURL) + } + + return testDomains +} + +func getKubeHost(v map[string]interface{}, defaultHost string) string { + vObj := objx.New(v) + if host := vObj.Get("KubernetesHost").Str(); host != "" { + return host + } + + return defaultHost +} + +func (u *networkTesterPlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { + cs, err := opt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return err + } + err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) + return err + } + + conf, err := opt.KubeBuilder.BuildConfig() + if err != nil { + return fmt.Errorf("failed to build config: %w", err) + } + + testDomains := prepareTestDomains(v) + urls := strings.Join(testDomains, ",") + objx.New(v["NetworkTester"]).Set("AdditionalEnvVars.URLS", urls) + objx.New(v["NetworkTester"]).Set("AdditionalEnvVars.KUBERNETES_HOST", getKubeHost(v, conf.Host)) + + err = install(ctx, &installOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: opt.ClusterNamespace, + matchPattern: networkTesterFilesPattern, + operatorType: NetworkTesterPluginType, + }) + if err != nil { + u.logger.Error(fmt.Sprintf("Failed to run network-tester pod: %v", err)) + return err + } + // defer cleanup + defer func() { + err := uninstall(ctx, &deleteOptions{ + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: opt.ClusterNamespace, + matchPattern: networkTesterFilesPattern, + operatorType: NetworkTesterPluginType, + logger: u.logger, + }) + if err != nil { + u.logger.Error(fmt.Sprintf("Failed to cleanup network-tester pod: %v", err)) + } + }() + + u.logger.Info("Running network tests...") + + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + var podLastState *v1.Pod + timeoutChan := time.After(networkTestsTimeout) +Loop: + for { + select { + case <-ticker.C: + u.logger.Debug("Waiting for network tester to finish") + pod, err := cs.CoreV1().Pods(opt.ClusterNamespace).Get(ctx, store.NetworkTesterName, metav1.GetOptions{}) + if err != nil { + if statusError, errIsStatusError := err.(*kerrors.StatusError); errIsStatusError { + if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound { + u.logger.Debug("Network tester pod not found") + } + } + } + if len(pod.Status.ContainerStatuses) == 0 { + u.logger.Debug("Network tester pod: creating container") + continue + } + if pod.Status.ContainerStatuses[0].State.Running != nil { + u.logger.Debug("Network tester pod: running") + } + if pod.Status.ContainerStatuses[0].State.Waiting != nil { + u.logger.Debug("Network tester pod: waiting") + } + if pod.Status.ContainerStatuses[0].State.Terminated != nil { + u.logger.Debug("Network tester pod: terminated") + podLastState = pod + break Loop + } + case <-timeoutChan: + u.logger.Error("Network tests timeout reached!") + return fmt.Errorf("Network tests timeout reached") + } + } + + req := cs.CoreV1().Pods(opt.ClusterNamespace).GetLogs(store.NetworkTesterName, &v1.PodLogOptions{}) + podLogs, err := req.Stream(ctx) + if err != nil { + u.logger.Error(fmt.Sprintf("Failed to get network-tester pod logs: %v", err)) + return err + } + defer podLogs.Close() + + logsBuf := new(bytes.Buffer) + _, err = io.Copy(logsBuf, podLogs) + if err != nil { + u.logger.Error(fmt.Sprintf("Failed to read network-tester pod logs: %v", err)) + return err + } + logs := strings.Trim(logsBuf.String(), "\n") + u.logger.Debug(fmt.Sprintf("%s", logs)) + + if podLastState.Status.ContainerStatuses[0].State.Terminated.ExitCode != 0 { + terminationMessage := strings.Trim(podLastState.Status.ContainerStatuses[0].State.Terminated.Message, "\n") + u.logger.Error(fmt.Sprintf("Network tests failed with: %v", terminationMessage)) + return errNetworkTestFailed + } + + return nil +} + +func (u *networkTesterPlugin) Name() string { + return NetworkTesterPluginType +} diff --git a/venonactl/pkg/plugins/plugin.go b/venonactl/pkg/plugins/plugin.go new file mode 100644 index 00000000..b6731afc --- /dev/null +++ b/venonactl/pkg/plugins/plugin.go @@ -0,0 +1,353 @@ +package plugins + +import ( + "context" + "fmt" + "os" + + "github.com/codefresh-io/venona/venonactl/pkg/logger" + "github.com/codefresh-io/venona/venonactl/pkg/obj/kubeobj" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" +) + +const ( + RuntimeEnvironmentPluginType = "runtime-environment" + VenonaPluginType = "venona" + MonitorAgentPluginType = "monitor-agent" + VolumeProvisionerPluginType = "volume-provisioner" + EnginePluginType = "engine" + DefaultStorageClassNamePrefix = "dind-local-volumes-runner" + RuntimeAttachType = "runtime-attach" + AppProxyPluginType = "app-proxy" + NetworkTesterPluginType = "network-tester" +) + +type ( + Plugin interface { + Install(context.Context, *InstallOptions, Values) (Values, error) + Status(context.Context, *StatusOptions, Values) ([][]string, error) + Delete(context.Context, *DeleteOptions, Values) error + Upgrade(context.Context, *UpgradeOptions, Values) (Values, error) + Migrate(context.Context, *MigrateOptions, Values) error + Test(context.Context, *TestOptions, Values) error + Name() string + } + + PluginBuilder interface { + Add(string) PluginBuilder + Get() []Plugin + } + + KubeClientBuilder interface { + BuildClient() (*kubernetes.Clientset, error) + } + + pb struct { + logger logger.Logger + plugins []Plugin + } + + Values map[string]interface{} + + InstallOptions struct { + CodefreshHost string + CodefreshToken string + ClusterName string + ClusterNamespace string + ClusterHost string + RegisterWithAgent bool + MarkAsDefault bool + StorageClass string + DockerRegistry string + IsDefaultStorageClass bool + KubeBuilder interface { + BuildClient() (*kubernetes.Clientset, error) + BuildConfig() (*rest.Config, error) + EnsureNamespaceExists(ctx context.Context, cs *kubernetes.Clientset) error + } + AgentKubeBuilder interface { + BuildClient() (*kubernetes.Clientset, error) + EnsureNamespaceExists(ctx context.Context, cs *kubernetes.Clientset) error + } + DryRun bool + BuildNodeSelector map[string]string + Annotations map[string]string + RuntimeEnvironment string + RuntimeNamespace string + RuntimeServiceAccount string + RestartAgent bool + Insecure bool + } + + DeleteOptions struct { + KubeBuilder interface { + BuildClient() (*kubernetes.Clientset, error) + } + AgentKubeBuilder interface { + BuildClient() (*kubernetes.Clientset, error) + } + ClusterNamespace string // runtime + AgentNamespace string // agent + RuntimeEnvironment string + RestartAgent bool + } + + UpgradeOptions struct { + ClusterName string + ClusterNamespace string + Name string + KubeBuilder interface { + BuildClient() (*kubernetes.Clientset, error) + } + } + + MigrateOptions struct { + ClusterName string + ClusterNamespace string + KubeBuilder interface { + BuildClient() (*kubernetes.Clientset, error) + } + } + + TestOptions struct { + KubeBuilder interface { + BuildClient() (*kubernetes.Clientset, error) + BuildConfig() (*rest.Config, error) + EnsureNamespaceExists(ctx context.Context, cs *kubernetes.Clientset) error + } + ClusterNamespace string + } + + StatusOptions struct { + KubeBuilder interface { + BuildClient() (*kubernetes.Clientset, error) + } + ClusterNamespace string + } + + installOptions struct { + templates map[string]string + templateValues map[string]interface{} + kubeClientSet *kubernetes.Clientset + namespace string + matchPattern string + operatorType string + dryRun bool + kubeBuilder interface { + BuildClient() (*kubernetes.Clientset, error) + } + logger logger.Logger + } + + statusOptions struct { + templates map[string]string + templateValues map[string]interface{} + kubeClientSet *kubernetes.Clientset + namespace string + matchPattern string + operatorType string + logger logger.Logger + } + + deleteOptions struct { + templates map[string]string + templateValues map[string]interface{} + kubeClientSet *kubernetes.Clientset + namespace string + matchPattern string + operatorType string + logger logger.Logger + } + + testOptions struct { + logger logger.Logger + kubeBuilder interface { + BuildClient() (*kubernetes.Clientset, error) + } + namespace string + validationRequest validationRequest + } +) + +func NewBuilder(logger logger.Logger) PluginBuilder { + return &pb{ + logger: logger, + plugins: []Plugin{}, + } +} + +func (p *pb) Add(name string) PluginBuilder { + p.plugins = append(p.plugins, build(name, p.logger)) + return p +} + +func (p *pb) Get() []Plugin { + return p.plugins +} + +func build(t string, logger logger.Logger) Plugin { + if t == VenonaPluginType { + return &venonaPlugin{ + logger: logger.New("installer", VenonaPluginType), + } + } + + if t == RuntimeEnvironmentPluginType { + return &runtimeEnvironmentPlugin{ + logger: logger.New("installer", RuntimeEnvironmentPluginType), + } + } + + if t == VolumeProvisionerPluginType { + return &volumeProvisionerPlugin{ + logger: logger.New("installer", VolumeProvisionerPluginType), + } + } + + if t == EnginePluginType { + return &enginePlugin{ + logger: logger.New("installer", EnginePluginType), + } + } + + if t == RuntimeAttachType { + return &runtimeAttachPlugin{ + logger: logger.New("installer", RuntimeAttachType), + } + } + + if t == MonitorAgentPluginType { + return &monitorAgentPlugin{ + logger: logger.New("installer", MonitorAgentPluginType), + } + } + + if t == AppProxyPluginType { + return &appProxyPlugin{ + logger: logger.New("installer", AppProxyPluginType), + } + } + + if t == NetworkTesterPluginType { + return &networkTesterPlugin{ + logger: logger.New("network-tester", NetworkTesterPluginType), + } + } + + return nil +} + +func install(ctx context.Context, opt *installOptions) error { + + if opt.dryRun == true { + err := os.Mkdir("codefresh_manifests", 0755) + if err != nil { + opt.logger.Error("failed to create manifests folder", "File-Name", "Error", err) + } + parsedTemplates, err := ParseTemplates(opt.templates, opt.templateValues, opt.matchPattern, opt.logger) + for fileName, objStr := range parsedTemplates { + err = os.WriteFile(fmt.Sprintf("./codefresh_manifests/%s", fileName), []byte(objStr), 0644) + if err != nil { + opt.logger.Error(fmt.Sprintf("failed to write file %v", objStr), "File-Name", fileName, "Error", err) + } + } + return nil + } + + kubeObjects, err := KubeObjectsFromTemplates(opt.templates, opt.templateValues, opt.matchPattern, opt.logger) + if err != nil { + return err + } + + for _, obj := range kubeObjects { + + var createErr error + var kind, name string + name, kind, createErr = kubeobj.CreateObject(ctx, opt.kubeClientSet, obj, opt.namespace) + + if createErr == nil { + opt.logger.Debug(fmt.Sprintf("%s \"%s\" created", kind, name)) + } else if statusError, errIsStatusError := createErr.(*errors.StatusError); errIsStatusError { + if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { + opt.logger.Debug(fmt.Sprintf("%s \"%s\" already exists", kind, name)) + } else { + opt.logger.Debug(fmt.Sprintf("%s \"%s\" failed: %v ", kind, name, statusError)) + return statusError + } + } else { + opt.logger.Debug(fmt.Sprintf("%s \"%s\" failed: %v ", kind, name, createErr)) + return createErr + } + } + + return nil +} + +func status(ctx context.Context, opt *statusOptions) ([][]string, error) { + kubeObjects, err := KubeObjectsFromTemplates(opt.templates, opt.templateValues, opt.matchPattern, opt.logger) + if err != nil { + return nil, err + } + var getErr error + var kind, name string + var rows [][]string + for _, obj := range kubeObjects { + name, kind, getErr = kubeobj.CheckObject(ctx, opt.kubeClientSet, obj, opt.namespace) + if getErr == nil { + rows = append(rows, []string{kind, name, StatusInstalled}) + } else if statusError, errIsStatusError := getErr.(*errors.StatusError); errIsStatusError { + rows = append(rows, []string{kind, name, StatusNotInstalled, statusError.ErrStatus.Message}) + } else { + opt.logger.Debug(fmt.Sprintf("%s \"%s\" failed: %v ", kind, name, getErr)) + return nil, getErr + } + } + return rows, nil +} + +func uninstall(ctx context.Context, opt *deleteOptions) error { + + kubeObjects, err := KubeObjectsFromTemplates(opt.templates, opt.templateValues, opt.matchPattern, opt.logger) + if err != nil { + return err + } + var kind, name string + var deleteError error + for _, obj := range kubeObjects { + kind, name, deleteError = kubeobj.DeleteObject(ctx, opt.kubeClientSet, obj, opt.namespace) + if deleteError == nil { + opt.logger.Debug(fmt.Sprintf("%s \"%s\" deleted", kind, name)) + } else if statusError, errIsStatusError := deleteError.(*errors.StatusError); errIsStatusError { + if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { + opt.logger.Debug(fmt.Sprintf("%s \"%s\" already exist", kind, name)) + } else if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound { + opt.logger.Debug(fmt.Sprintf("%s \"%s\" not found", kind, name)) + } else { + opt.logger.Error(fmt.Sprintf("%s \"%s\" failed: %v ", kind, name, statusError)) + return statusError + } + } else { + opt.logger.Error(fmt.Sprintf("%s \"%s\" failed: %v ", kind, name, deleteError)) + return deleteError + } + } + return nil +} + +func test(ctx context.Context, opt testOptions) error { + lgr := opt.logger + cs, err := opt.kubeBuilder.BuildClient() + if err != nil { + lgr.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return err + } + lgr.Debug("Running acceptance tests") + res, err := ensureClusterRequirements(ctx, cs, opt.validationRequest, lgr) + if err != nil { + return err + } + return handleValidationResult(res, lgr) +} diff --git a/venonactl/pkg/plugins/runtime-attach.go b/venonactl/pkg/plugins/runtime-attach.go new file mode 100644 index 00000000..ffc39703 --- /dev/null +++ b/venonactl/pkg/plugins/runtime-attach.go @@ -0,0 +1,378 @@ +package plugins + +import ( + "context" + "encoding/base64" + "fmt" + "strings" + "time" + + "github.com/codefresh-io/venona/venonactl/pkg/logger" + templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" + "gopkg.in/yaml.v2" + v1 "k8s.io/api/core/v1" + kerrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes" +) + +type runtimeAttachPlugin struct { + logger logger.Logger +} + +type RuntimeConfiguration struct { + Crt string `yaml:"crt"` + Token string `yaml:"token"` + Host string `yaml:"host"` + Name string `yaml:"name"` + Type string `yaml:"type"` +} + +type venonaConf struct { + Runtimes map[string]RuntimeConfiguration `yaml:"runtimes,omitempty"` +} + +const ( + runtimeAttachFilesPattern = ".*.runtime-attach.yaml" + runtimeSecretName = "runnerconf" +) + +func (u *runtimeAttachPlugin) buildRuntimeConfig(ctx context.Context, opt *InstallOptions, v Values) (RuntimeConfiguration, error) { + config, err := opt.KubeBuilder.BuildConfig() + if err != nil { + return RuntimeConfiguration{}, fmt.Errorf("Failed to get client config on runtime cluster: %v", err) + } + + cs, err := opt.KubeBuilder.BuildClient() + if err != nil { + return RuntimeConfiguration{}, fmt.Errorf("Failed to create client on runtime cluster: %v", err) + } + err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) + if err != nil { + return RuntimeConfiguration{}, fmt.Errorf("Failed to ensure namespace on runtime cluster: %v", err) + } + + secret, err := u.generateServiceAccountSecret(ctx, cs, opt.RuntimeNamespace, opt.RuntimeServiceAccount) + if err != nil { + return RuntimeConfiguration{}, fmt.Errorf("Failed to get secret from service account %s on runtime cluster: %v", + opt.RuntimeServiceAccount, err) + } + + crt := secret.Data["ca.crt"] + token := secret.Data["token"] + + host := config.Host + if opt.ClusterHost != "" { + host = opt.ClusterHost + } + + rc := RuntimeConfiguration{ + Crt: string(crt), + Token: string(token), + Host: host, + Name: opt.RuntimeEnvironment, + Type: "runtime", + } + + return rc, nil +} + +func (u *runtimeAttachPlugin) generateServiceAccountSecret(ctx context.Context, client kubernetes.Interface, namespace, saName string) (*v1.Secret, error) { + secret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: fmt.Sprintf("%s-token-", saName), + Annotations: map[string]string{ + "kubernetes.io/service-account.name": saName, + }, + }, + Type: v1.SecretTypeServiceAccountToken, + } + + u.logger.Debug("Creating secret for service-account token", "service-account", saName) + + secret, err := client.CoreV1().Secrets(namespace).Create(ctx, secret, metav1.CreateOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to create service-account token secret: %w", err) + } + secretName := secret.Name + + u.logger.Debug("Created secret for service-account token", "service-account", saName, "secret", secret.Name) + + patch := []byte(fmt.Sprintf("{\"secrets\": [{\"name\": \"%s\"}]}", secretName)) + _, err = client.CoreV1().ServiceAccounts(namespace).Patch(ctx, saName, types.StrategicMergePatchType, patch, metav1.PatchOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to patch service-account with new secret: %w", err) + } + + u.logger.Debug("Added secret to service-account secrets", "service-account", saName, "secret", secret.Name) + + // try to read the token from the secret + ticker := time.NewTicker(time.Second) + retries := 15 + defer ticker.Stop() + + for try := 0; try < retries; try++ { + select { + case <-ticker.C: + secret, err = client.CoreV1().Secrets(namespace).Get(ctx, secretName, metav1.GetOptions{}) + case <-ctx.Done(): + return nil, ctx.Err() + } + + u.logger.Debug("Checking secret for service-account token", "service-account", saName, "secret", secret.Name) + + if err != nil { + return nil, fmt.Errorf("failed to get service-account secret: %w", err) + } + + if secret.Data == nil || len(secret.Data["token"]) == 0 { + u.logger.Debug("Secret is missing service-account token", "service-account", saName, "secret", secret.Name) + continue + } + + u.logger.Debug("Got service-account token from secret", "service-account", saName, "secret", secret.Name) + + return secret, nil + } + + return nil, fmt.Errorf("timed out waiting for secret to contain token") +} + +func readCurrentVenonaConf(ctx context.Context, agentKubeBuilder KubeClientBuilder, clusterNamespace string) (venonaConf, error) { + + cs, err := agentKubeBuilder.BuildClient() + if err != nil { + return venonaConf{}, fmt.Errorf("Failed to create client on venona cluster: %v", err) + } + secret, err := cs.CoreV1().Secrets(clusterNamespace).Get(ctx, runtimeSecretName, metav1.GetOptions{}) + if err != nil { + return venonaConf{}, fmt.Errorf("Failed to get %s secret: %v", runtimeSecretName, err) + } + + conf := &venonaConf{ + Runtimes: make(map[string]RuntimeConfiguration), + } + for k, v := range secret.Data { + cnf := RuntimeConfiguration{} + if err := yaml.Unmarshal(v, &cnf); err != nil { + return venonaConf{}, fmt.Errorf("Failed to unmarshal yaml with error: %s", err.Error()) + } + conf.Runtimes[k] = cnf + } + return *conf, nil + +} + +func (u *runtimeAttachPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { + if opt.DryRun { + return v, nil + } + cs, err := opt.AgentKubeBuilder.BuildClient() // on the agent cluster + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + err = opt.AgentKubeBuilder.EnsureNamespaceExists(ctx, cs) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) + return nil, err + } + + // read current venona conf + currentVenonaConf, err := readCurrentVenonaConf(ctx, opt.AgentKubeBuilder, opt.ClusterNamespace) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot read runnerconf: %v ", err)) + return nil, err + } + + // new runtime configuration + rc, err := u.buildRuntimeConfig(ctx, opt, v) + if err != nil { + return nil, err + } + if currentVenonaConf.Runtimes == nil { + currentVenonaConf.Runtimes = make(map[string]RuntimeConfiguration) + } + // normalize the key in the secret to make sure we are not violating kube naming conventions + name := strings.ReplaceAll(opt.RuntimeEnvironment, "/", ".") + name = strings.ReplaceAll(name, "@", ".") + name = strings.ReplaceAll(name, ":", ".") + currentVenonaConf.Runtimes[fmt.Sprintf("%s.runtime.yaml", name)] = rc + runtimes := map[string]string{} + for name, runtime := range currentVenonaConf.Runtimes { + // marshel prior persist + d, err := yaml.Marshal(runtime) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot marshal merged runnerconf: %v ", err)) + return nil, err + } + + runtimes[name] = base64.StdEncoding.EncodeToString([]byte(d)) + } + v["runnerConf"] = runtimes + v["Namespace"] = opt.ClusterNamespace + + cs.CoreV1().Secrets(opt.ClusterNamespace).Delete(ctx, runtimeSecretName, metav1.DeleteOptions{}) + + err = install(ctx, &installOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: opt.ClusterNamespace, + matchPattern: runtimeAttachFilesPattern, + operatorType: RuntimeAttachType, + dryRun: opt.DryRun, + }) + + if err != nil { + return nil, err + } + + if opt.RestartAgent { + list, err := cs.CoreV1().Pods(opt.ClusterNamespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("app=%v", v["AppName"])}) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot find agent pod: %v ", err)) + return nil, err + } + if (len(list.Items) == 0) { + u.logger.Debug("Agent pod not created yet. skipping restart...") + return v, nil + } + podName := list.Items[0].ObjectMeta.Name + err = cs.CoreV1().Pods(opt.ClusterNamespace).Delete(ctx, podName, metav1.DeleteOptions{}) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot delete agent pod: %v ", err)) + return nil, err + } + + ticker := time.NewTicker(5 * time.Second) + for { + select { + case <-ticker.C: + u.logger.Debug("Validating old runner pod termination") + _, err = cs.CoreV1().Pods(opt.ClusterNamespace).Get(ctx, podName, metav1.GetOptions{}) + if err != nil { + if statusError, errIsStatusError := err.(*kerrors.StatusError); errIsStatusError { + if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound { + return v, nil + } + } + } + case <-time.After(60 * time.Second): + u.logger.Error("Failed to validate old venona pod termination") + return v, fmt.Errorf("Failed to validate old venona pod termination") + } + } + } + + return v, nil + +} + +func (u *runtimeAttachPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { + + cs, err := statusOpt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + opt := &statusOptions{ + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: statusOpt.ClusterNamespace, + matchPattern: runtimeAttachFilesPattern, + operatorType: RuntimeAttachType, + logger: u.logger, + } + return status(ctx, opt) + +} + +func (u *runtimeAttachPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { + cs, err := deleteOpt.AgentKubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return err + } + // Delete the entry from runnerconf - if this is the only , delete the secret + + // read current venona conf + currentVenonaConf, err := readCurrentVenonaConf(ctx, deleteOpt.AgentKubeBuilder, deleteOpt.AgentNamespace) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot read runnerconf: %v ", err)) + return err + } + name := strings.ReplaceAll(deleteOpt.RuntimeEnvironment, "/", ".") + name = fmt.Sprintf("%s.runtime.yaml", name) + if _, ok := currentVenonaConf.Runtimes[name]; ok { + delete(currentVenonaConf.Runtimes, name) + } + + // If only one runtime is defined, remove the secret , otherwise remove the entry and persist + shouldDelete := true + if len(currentVenonaConf.Runtimes) > 0 { + + runtimes := map[string]string{} + for name, runtime := range currentVenonaConf.Runtimes { + // marshel prior persist + d, err := yaml.Marshal(runtime) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot marshal merged runnerconf: %v ", err)) + return err + } + + runtimes[name] = base64.StdEncoding.EncodeToString([]byte(d)) + } + + shouldDelete = false + v["runnerConf"] = runtimes + + cs.CoreV1().Secrets(deleteOpt.AgentNamespace).Delete(ctx, runtimeSecretName, metav1.DeleteOptions{}) + + err = install(ctx, &installOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: deleteOpt.AgentNamespace, + matchPattern: runtimeAttachFilesPattern, + operatorType: RuntimeAttachType, + }) + return err + + } + + if shouldDelete { + opt := &deleteOptions{ + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: deleteOpt.AgentNamespace, + matchPattern: runtimeAttachFilesPattern, + operatorType: RuntimeAttachType, + logger: u.logger, + } + return uninstall(ctx, opt) + } + return nil + +} + +func (u *runtimeAttachPlugin) Upgrade(_ context.Context, _ *UpgradeOptions, v Values) (Values, error) { + return v, nil +} + +func (u *runtimeAttachPlugin) Migrate(context.Context, *MigrateOptions, Values) error { + return fmt.Errorf("not supported") +} + +func (u *runtimeAttachPlugin) Test(context.Context, *TestOptions, Values) error { + return nil +} + +func (u *runtimeAttachPlugin) Name() string { + return RuntimeAttachType +} diff --git a/venonactl/pkg/plugins/runtime-environment.go b/venonactl/pkg/plugins/runtime-environment.go new file mode 100644 index 00000000..75d2fafc --- /dev/null +++ b/venonactl/pkg/plugins/runtime-environment.go @@ -0,0 +1,204 @@ +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugins + +import ( + "context" + "encoding/base64" + "fmt" + + "github.com/codefresh-io/venona/venonactl/pkg/codefresh" + "github.com/codefresh-io/venona/venonactl/pkg/logger" + templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" +) + +// runtimeEnvironmentPlugin installs assets on Kubernetes Dind runtimectl Env +type runtimeEnvironmentPlugin struct { + logger logger.Logger +} + +const ( + runtimeEnvironmentFilesPattern = ".*.re.yaml" +) + +// Install runtimectl environment +func (u *runtimeEnvironmentPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { + cs, err := opt.KubeBuilder.BuildClient() + if err != nil { + return nil, fmt.Errorf("Cannot create kubernetes clientset: %v ", err) + } + + err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) + return nil, err + } + + cfOpt := &codefresh.APIOptions{ + Logger: u.logger, + CodefreshHost: opt.CodefreshHost, + CodefreshToken: opt.CodefreshToken, + ClusterName: opt.ClusterName, + RegisterWithAgent: opt.RegisterWithAgent, + ClusterNamespace: opt.ClusterNamespace, + MarkAsDefault: opt.MarkAsDefault, + StorageClass: opt.StorageClass, + IsDefaultStorageClass: opt.IsDefaultStorageClass, + BuildNodeSelector: opt.BuildNodeSelector, + Annotations: opt.Annotations, + Insecure: opt.Insecure, + } + + // Set storage Class by backend + if cfOpt.IsDefaultStorageClass { + storageParams := v["Storage"].(map[string]interface{}) + cfOpt.StorageClass = storageParams["StorageClassName"].(string) + } + + cf := codefresh.NewCodefreshAPI(cfOpt) + cert, err := cf.Sign() + if err != nil { + return nil, err + } + v["ServerCert"] = map[string]string{ + "Cert": base64.StdEncoding.EncodeToString([]byte(cert.Cert)), + "Key": base64.StdEncoding.EncodeToString([]byte(cert.Key)), + "Ca": base64.StdEncoding.EncodeToString([]byte(cert.Ca)), + } + + if err := cf.Validate(); err != nil { + return nil, err + } + + v["RuntimeEnvironment"] = opt.RuntimeEnvironment + err = install(ctx, &installOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: opt.ClusterNamespace, + matchPattern: runtimeEnvironmentFilesPattern, + operatorType: RuntimeEnvironmentPluginType, + dryRun: opt.DryRun, + }) + if err != nil { + return nil, err + } + + return v, nil +} + +func (u *runtimeEnvironmentPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { + cs, err := statusOpt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + opt := &statusOptions{ + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: statusOpt.ClusterNamespace, + matchPattern: runtimeEnvironmentFilesPattern, + operatorType: RuntimeEnvironmentPluginType, + logger: u.logger, + } + return status(ctx, opt) +} + +func (u *runtimeEnvironmentPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { + cs, err := deleteOpt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return err + } + opt := &deleteOptions{ + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: deleteOpt.ClusterNamespace, + matchPattern: runtimeEnvironmentFilesPattern, + operatorType: RuntimeEnvironmentPluginType, + logger: u.logger, + } + return uninstall(ctx, opt) +} + +func (u *runtimeEnvironmentPlugin) Upgrade(_ context.Context, _ *UpgradeOptions, v Values) (Values, error) { + return v, nil +} + +func (u *runtimeEnvironmentPlugin) Migrate(ctx context.Context, opt *MigrateOptions, v Values) error { + return u.Delete(ctx, &DeleteOptions{ + ClusterNamespace: opt.ClusterNamespace, + KubeBuilder: opt.KubeBuilder, + }, v) +} + +func (u *runtimeEnvironmentPlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { + validationRequest := validationRequest{ + rbac: []rbacValidation{ + { + Resource: "ServiceAccount", + Verbs: []string{"create", "delete"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "ConfigMap", + Verbs: []string{"create", "update", "delete"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "Service", + Verbs: []string{"create", "update", "delete"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "Role", + Group: "rbac.authorization.k8s.io", + Verbs: []string{"create", "update", "delete"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "RoleBinding", + Group: "rbac.authorization.k8s.io", + Verbs: []string{"create", "update", "delete"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "persistentvolumeclaims", + Namespace: opt.ClusterNamespace, + Verbs: []string{"create", "update", "delete"}, + }, + { + Resource: "pods", + Namespace: opt.ClusterNamespace, + Verbs: []string{"create", "update", "delete"}, + }, + }, + } + return test(ctx, testOptions{ + logger: u.logger, + kubeBuilder: opt.KubeBuilder, + namespace: opt.ClusterNamespace, + validationRequest: validationRequest, + }) +} + +func (u *runtimeEnvironmentPlugin) Name() string { + return RuntimeEnvironmentPluginType +} diff --git a/venonactl/pkg/plugins/types.go b/venonactl/pkg/plugins/types.go new file mode 100644 index 00000000..5f03b2e3 --- /dev/null +++ b/venonactl/pkg/plugins/types.go @@ -0,0 +1,30 @@ +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package plugins + +const ( + // AppName - app name for config + AppName = "runner" + + // TypeKubernetesDind - name for Kubernetes Dind runtimectl + TypeKubernetesDind = "kubernetesDind" + //typeDockerd = "dockerd" + + // StatusInstalled - status installed + StatusInstalled = "Installed" + // StatusNotInstalled - status installed + StatusNotInstalled = "Not Installed" +) diff --git a/venonactl/pkg/plugins/venona.go b/venonactl/pkg/plugins/venona.go new file mode 100644 index 00000000..8fd4b83a --- /dev/null +++ b/venonactl/pkg/plugins/venona.go @@ -0,0 +1,379 @@ +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugins + +import ( + "context" + "encoding/json" + "fmt" + "os" + "time" + + "github.com/codefresh-io/go-sdk/pkg/codefresh" + "github.com/codefresh-io/venona/venonactl/pkg/logger" + "github.com/codefresh-io/venona/venonactl/pkg/obj/kubeobj" + templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" + v1 "k8s.io/api/core/v1" + kerrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +// venonaPlugin installs assets on Kubernetes Dind runtimectl Env +type venonaPlugin struct { + logger logger.Logger +} + +type migrationData struct { + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + Tolerations []v1.Toleration `json:"tolerations,omitempty"` + Env map[string]string `json:"env,omitempty"` +} + +const ( + venonaFilesPattern = ".*.venona.yaml" +) + +// Install venona agent +func (u *venonaPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { + if v["AgentToken"] == "" { + u.logger.Debug("Generating token for agent") + tokenName := fmt.Sprintf("generated-%s", time.Now().Format("20060102150405")) + u.logger.Debug(fmt.Sprintf("Token candidate name: %s", tokenName)) + + client := codefresh.New(&codefresh.ClientOptions{ + Auth: codefresh.AuthOptions{ + Token: opt.CodefreshToken, + }, + Host: opt.CodefreshHost, + }) + + token, err := client.Tokens().Create(tokenName, v["RuntimeEnvironment"].(string)) + if err != nil { + return nil, err + } + u.logger.Debug("Token created") + v["AgentToken"] = token.Value + if err != nil { + return nil, err + } + } + + cs, err := opt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + err = opt.KubeBuilder.EnsureNamespaceExists(ctx, cs) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot ensure namespace exists: %v", err)) + return nil, err + } + + return v, install(ctx, &installOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: opt.ClusterNamespace, + matchPattern: venonaFilesPattern, + dryRun: opt.DryRun, + operatorType: VenonaPluginType, + }) +} + +// Status of runtimectl environment +func (u *venonaPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { + cs, err := statusOpt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + opt := &statusOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: statusOpt.ClusterNamespace, + matchPattern: venonaFilesPattern, + operatorType: VenonaPluginType, + } + return status(ctx, opt) +} + +func (u *venonaPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { + cs, err := deleteOpt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil + } + opt := &deleteOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: deleteOpt.ClusterNamespace, + matchPattern: venonaFilesPattern, + operatorType: VenonaPluginType, + } + return uninstall(ctx, opt) +} + +func (u *venonaPlugin) Upgrade(ctx context.Context, opt *UpgradeOptions, v Values) (Values, error) { + + // replace of sa creates new secert with sa creds + // avoid it till patch fully implemented + var skipUpgradeFor = map[string]interface{}{ + "service-account.venona.yaml": nil, + "deployment.venona.yaml": nil, + "venonaconf.secret.venona.yaml": nil, + } + + var deletePriorUpgrade = map[string]interface{}{ + "deployment.venona.yaml": nil, + } + + var err error + + kubeClientset, err := opt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + + // special case when we need to get the token from the remote to no regenrate it + // whole flow should be more like kubectl apply that build a patch + // based on remote object and candidate object + + secret, err := kubeClientset.CoreV1().Secrets(opt.ClusterNamespace).Get(ctx, opt.Name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + token := string(secret.Data["codefresh.token"]) + v["AgentToken"] = token + + kubeObjects, err := getKubeObjectsFromTempalte(v, venonaFilesPattern, u.logger) + if err != nil { + return nil, err + } + v, err = updateValuesBasedOnPreviousDeployment(ctx, opt.ClusterNamespace, kubeClientset, v) + + for fileName, local := range kubeObjects { + if _, ok := deletePriorUpgrade[fileName]; ok { + u.logger.Debug(fmt.Sprintf("Deleting previous deplopyment of %s", fileName)) + delOpt := &deleteOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: kubeClientset, + namespace: opt.ClusterNamespace, + matchPattern: fileName, + operatorType: VenonaPluginType, + } + err := uninstall(ctx, delOpt) + if err != nil { + return nil, err + } + installOpt := &installOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: kubeClientset, + namespace: opt.ClusterNamespace, + matchPattern: fileName, + operatorType: VenonaPluginType, + } + err = install(ctx, installOpt) + if err != nil { + return nil, err + } + } + + if _, ok := skipUpgradeFor[fileName]; ok { + u.logger.Debug(fmt.Sprintf("Skipping upgrade of %s: should be ignored", fileName)) + continue + } + + _, _, err := kubeobj.ReplaceObject(ctx, kubeClientset, local, opt.ClusterNamespace) + if err != nil { + return nil, err + } + } + + return v, nil +} + +func updateValuesBasedOnPreviousDeployment(ctx context.Context, ns string, kubeClientset *kubernetes.Clientset, v Values) (Values, error) { + + runnerDeployment, err := kubeClientset.AppsV1().Deployments(ns).Get(ctx, AppName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + // Update the values with existing deployment values + if runnerDeployment.Spec.Template.Spec.NodeSelector != nil { + + } + if runnerDeployment.Spec.Template.Spec.NodeSelector != nil { + v["NodeSelector"] = nodeSelectorToString(runnerDeployment.Spec.Template.Spec.NodeSelector) + } + if runnerDeployment.Spec.Template.Spec.Tolerations != nil { + v["Tolerations"] = tolerationsToSring(runnerDeployment.Spec.Template.Spec.Tolerations) + } + + for _, envVar := range runnerDeployment.Spec.Template.Spec.Containers[0].Env { + if envVar.Name == "DOCKER_REGISTRY" { + v["DockerRegistry"] = envVar.Value + } else if envVar.Name == "AGENT_ID" { + v["AgentId"] = envVar.Value + } + } + + v["AdditionalEnvVars"] = getEnvVarsFromDeployment(runnerDeployment.Spec.Template.Spec.Containers) + return v, nil + +} + +func getEnvVarsFromDeployment(containers []v1.Container) map[string]string { + // Get env for containers + preDefinedEnvVars := map[string]interface{}{} + newEnvVars := map[string]string{} + preDefinedEnvVars["SELF_DEPLOYMENT_NAME"] = "SELF_DEPLOYMENT_NAME" + preDefinedEnvVars["CODEFRESH_TOKEN"] = "CODEFRESH_TOKEN" + preDefinedEnvVars["CODEFRESH_HOST"] = "CODEFRESH_HOST" + preDefinedEnvVars["AGENT_MODE"] = "AGENT_MODE" + preDefinedEnvVars["AGENT_NAME"] = "AGENT_NAME" + preDefinedEnvVars["AGENT_ID"] = "AGENT_ID" + preDefinedEnvVars["VENONA_CONFIG_DIR"] = "VENONA_CONFIG_DIR" + + for _, container := range containers { + for _, envVar := range container.Env { + if preDefinedEnvVars[envVar.Name] == nil { + newEnvVars[envVar.Name] = envVar.Value + } + } + } + return newEnvVars +} + +func (u *venonaPlugin) Migrate(ctx context.Context, opt *MigrateOptions, v Values) error { + var deletePriorUpgrade = map[string]interface{}{ + "deployment.venona.yaml": nil, + "secret.venona.yaml": nil, + } + + kubeClientset, err := opt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return err + } + kubeObjects, err := getKubeObjectsFromTempalte(v, venonaFilesPattern, u.logger) + if err != nil { + return err + } + list, err := kubeClientset.CoreV1().Pods(opt.ClusterNamespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("app=%v", v["AppName"])}) + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot find agent pod: %v ", err)) + return err + } + if len(list.Items) == 0 { + u.logger.Debug("Runner pod not found , existing migration") + return nil + } + migrationData := migrationData{ + Tolerations: list.Items[0].Spec.Tolerations, + NodeSelector: list.Items[0].Spec.NodeSelector, + Env: getEnvVarsFromDeployment(list.Items[0].Spec.Containers), + } + var jsonData []byte + jsonData, err = json.Marshal(migrationData) + err = os.WriteFile("migration.json", jsonData, 0644) + if err != nil { + u.logger.Error("Cannot write migration json") + } + + podName := list.Items[0].ObjectMeta.Name + for fileName := range kubeObjects { + if _, ok := deletePriorUpgrade[fileName]; ok { + u.logger.Debug(fmt.Sprintf("Deleting previous deplopyment of %s", fileName)) + delOpt := &deleteOptions{ + logger: u.logger, + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: kubeClientset, + namespace: opt.ClusterNamespace, + matchPattern: fileName, + operatorType: VenonaPluginType, + } + err := uninstall(ctx, delOpt) + if err != nil { + return err + } + } + } + ticker := time.NewTicker(5 * time.Second) + for { + select { + case <-ticker.C: + u.logger.Debug("Validating old runner pod termination") + _, err = kubeClientset.CoreV1().Pods(opt.ClusterNamespace).Get(ctx, podName, metav1.GetOptions{}) + if err != nil { + if statusError, errIsStatusError := err.(*kerrors.StatusError); errIsStatusError { + if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound { + return nil + } + } + } + case <-time.After(60 * time.Second): + u.logger.Error("Failed to validate old venona pod termination") + return fmt.Errorf("Failed to validate old venona pod termination") + } + } +} + +func (u *venonaPlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { + validationRequest := validationRequest{ + cpu: "500m", + momorySize: "1Gi", + rbac: []rbacValidation{ + { + Resource: "deployment", + Verbs: []string{"create", "update", "delete"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "secret", + Verbs: []string{"create", "update", "delete"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "ClusterRoleBinding", + Group: "rbac.authorization.k8s.io", + Verbs: []string{"create", "update", "delete"}, + }, + }, + } + return test(ctx, testOptions{ + logger: u.logger, + kubeBuilder: opt.KubeBuilder, + namespace: opt.ClusterNamespace, + validationRequest: validationRequest, + }) +} + +func (u *venonaPlugin) Name() string { + return VenonaPluginType +} diff --git a/venonactl/pkg/plugins/volume-provisioner.go b/venonactl/pkg/plugins/volume-provisioner.go new file mode 100644 index 00000000..9194de30 --- /dev/null +++ b/venonactl/pkg/plugins/volume-provisioner.go @@ -0,0 +1,195 @@ +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugins + +import ( + "context" + "fmt" + + "github.com/codefresh-io/venona/venonactl/pkg/logger" + "github.com/codefresh-io/venona/venonactl/pkg/obj/kubeobj" + templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" +) + +// volumeProvisionerPlugin installs assets on Kubernetes Dind runtimectl Env +type volumeProvisionerPlugin struct { + logger logger.Logger +} + +const ( + volumeProvisionerFilesPattern = ".*.vp.yaml" +) + +// Install runtimectl environment +func (u *volumeProvisionerPlugin) Install(ctx context.Context, opt *InstallOptions, v Values) (Values, error) { + cs, err := opt.KubeBuilder.BuildClient() + if err != nil { + return nil, fmt.Errorf("Cannot create kubernetes clientset: %v", err) + } + return v, install(ctx, &installOptions{ + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + namespace: opt.ClusterNamespace, + matchPattern: volumeProvisionerFilesPattern, + dryRun: opt.DryRun, + operatorType: VolumeProvisionerPluginType, + logger: u.logger, + }) +} + +func (u *volumeProvisionerPlugin) Status(ctx context.Context, statusOpt *StatusOptions, v Values) ([][]string, error) { + cs, err := statusOpt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + opt := &statusOptions{ + templates: templates.TemplatesMap(), + templateValues: v, + kubeClientSet: cs, + logger: u.logger, + namespace: statusOpt.ClusterNamespace, + matchPattern: volumeProvisionerFilesPattern, + operatorType: VolumeProvisionerPluginType, + } + return status(ctx, opt) +} + +func (u *volumeProvisionerPlugin) Delete(ctx context.Context, deleteOpt *DeleteOptions, v Values) error { + cs, err := deleteOpt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return err + } + opt := &deleteOptions{ + templates: templates.TemplatesMap(), + templateValues: v, + logger: u.logger, + kubeClientSet: cs, + namespace: deleteOpt.ClusterNamespace, + matchPattern: volumeProvisionerFilesPattern, + operatorType: VolumeProvisionerPluginType, + } + return uninstall(ctx, opt) +} + +func (u *volumeProvisionerPlugin) Upgrade(ctx context.Context, opt *UpgradeOptions, v Values) (Values, error) { + var err error + kubeClientset, err := opt.KubeBuilder.BuildClient() + if err != nil { + u.logger.Error(fmt.Sprintf("Cannot create kubernetes clientset: %v ", err)) + return nil, err + } + kubeObjects, err := getKubeObjectsFromTempalte(v, volumeProvisionerFilesPattern, u.logger) + if err != nil { + return nil, err + } + for _, local := range kubeObjects { + + _, _, err := kubeobj.ReplaceObject(ctx, kubeClientset, local, opt.ClusterNamespace) + if err != nil { + return nil, err + } + } + return v, nil + +} +func (u *volumeProvisionerPlugin) Migrate(ctx context.Context, opt *MigrateOptions, v Values) error { + return u.Delete(ctx, &DeleteOptions{ + ClusterNamespace: opt.ClusterNamespace, + KubeBuilder: opt.KubeBuilder, + }, v) +} + +func (u *volumeProvisionerPlugin) Test(ctx context.Context, opt *TestOptions, v Values) error { + validationRequest := validationRequest{ + rbac: []rbacValidation{ + { + Resource: "persistentvolumes", + Verbs: []string{"get", "list", "watch", "create", "delete", "patch"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "persistentvolumeclaims", + Verbs: []string{"get", "list", "watch", "update"}, + }, + { + Resource: "storageclasses", + Group: "storage.k8s.io", + Verbs: []string{"get", "list", "watch"}, + }, + { + Resource: "events", + Group: "", + Verbs: []string{"list", "watch", "create", "update", "patch"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "secrets", + Group: "", + Verbs: []string{"get", "list"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "nodes", + Group: "", + Verbs: []string{"get", "list", "watch"}, + }, + { + Resource: "pods", + Group: "", + Verbs: []string{"get", "list", "watch", "create", "delete", "patch"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "endpoints", + Group: "", + Verbs: []string{"get", "list", "watch", "create", "update", "delete"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "DaemonSet", + Group: "", + Verbs: []string{"get", "create", "update", "delete"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "CronJob", + Group: "batch", + Verbs: []string{"get", "create", "update", "delete"}, + Namespace: opt.ClusterNamespace, + }, + { + Resource: "ServiceAccount", + Group: "", + Verbs: []string{"get", "create", "update", "delete"}, + Namespace: opt.ClusterNamespace, + }, + }, + } + return test(ctx, testOptions{ + logger: u.logger, + kubeBuilder: opt.KubeBuilder, + namespace: opt.ClusterNamespace, + validationRequest: validationRequest, + }) +} + +func (u *volumeProvisionerPlugin) Name() string { + return VolumeProvisionerPluginType +} diff --git a/venonactl/pkg/store/store.go b/venonactl/pkg/store/store.go new file mode 100644 index 00000000..257c5643 --- /dev/null +++ b/venonactl/pkg/store/store.go @@ -0,0 +1,232 @@ +package store + +import ( + "fmt" + + "github.com/codefresh-io/go-sdk/pkg/codefresh" + "github.com/codefresh-io/venona/venonactl/pkg/certs" + k8sApi "k8s.io/api/core/v1" +) + +const ( + ModeInCluster = "InCluster" + ApplicationName = "runner" + MonitorApplicationName = "monitor" + AppProxyApplicationName = "app-proxy" + EngineAppName = "codefresh-engine" + NetworkTesterName = "cf-venona-network-tester" +) + +var ( + store *Values +) + +type ( + Values struct { + AppName string + + Mode string + Image *Image + DockerRegistry string + AgentToken string + + ServerCert *certs.ServerCert + + CodefreshAPI *CodefreshAPI + + KubernetesAPI *KubernetesAPI + + Runner Runner + + VolumeProvisioner VolumeProvisioner + + LocalVolumeMonitor LocalVolumeMonitor + + Monitor Monitor + + AppProxy AppProxy + + AgentAPI *AgentAPI + + ClusterInCodefresh string + + DryRun bool + + Verbose bool + + Insecure bool + + RuntimeEnvironment string + + Version *Version + + ClusterId string + + Helm3 bool + + // need for define if monitor use cluster role or just role + UseNamespaceWithRole bool + + AdditionalEnvVars map[string]string + } + + KubernetesAPI struct { + ConfigPath string + Namespace string + ContextName string + InCluster bool + NodeSelector string + Tolerations []k8sApi.Toleration + } + + CodefreshAPI struct { + Host string + Token string + Client codefresh.Codefresh + BuildNodeSelector map[string]string + } + + AgentAPI struct { + Token string + Id string + } + + Image struct { + Name string + Tag string + } + + Version struct { + Current *CurrentVersion + } + + CurrentVersion struct { + Version string + Commit string + Date string + } + + Runner struct { + Resources map[string]interface{} + } + VolumeProvisioner struct { + Resources map[string]interface{} + } + + LocalVolumeMonitor struct { + Resources map[string]interface{} + } + Monitor struct { + Resources map[string]interface{} + } + AppProxy struct { + Resources map[string]interface{} + } +) + +func GetStore() *Values { + if store == nil { + store = &Values{} + return store + } + return store +} + +func (s *Values) BuildValues() map[string]interface{} { + return map[string]interface{}{ + "AppName": ApplicationName, + "ClusterId": s.ClusterId, + "Version": s.Version.Current.Version, + "CodefreshHost": s.CodefreshAPI.Host, + "Token": s.CodefreshAPI.Token, + "Mode": ModeInCluster, + "Verbose": s.Verbose, + "Insecure": s.Insecure, + "Image": map[string]string{ + "Name": "codefresh/venona", + "Tag": s.Version.Current.Version, + }, + "AdditionalEnvVars": s.AdditionalEnvVars, + "Namespace": s.KubernetesAPI.Namespace, + "ConfigPath": s.KubernetesAPI.ConfigPath, + "Context": s.KubernetesAPI.ContextName, + "NodeSelector": s.KubernetesAPI.NodeSelector, + "DockerRegistry": s.DockerRegistry, + "Tolerations": s.KubernetesAPI.Tolerations, + "AgentToken": s.AgentAPI.Token, + "AgentId": s.AgentAPI.Id, + "ServerCert": map[string]string{ + "Cert": "", + "Key": "", + "Ca": "", + }, + "Runner": map[string]interface{}{ + "Resources": s.Runner.Resources, + }, + "CreateRbac": true, + "Storage": map[string]interface{}{ + "Backend": "local", + "CreateStorageClass": true, + "StorageClassName": fmt.Sprintf("dind-local-volumes-%s-%s", ApplicationName, s.KubernetesAPI.Namespace), + "LocalVolumeParentDir": "/var/lib/codefresh/dind-volumes", + "AvailabilityZone": "", + "GoogleServiceAccount": "", + "AwsAccessKeyId": "", + "AwsSecretAccessKey": "", + "VolumeProvisioner": map[string]interface{}{ + "Image": "codefresh/dind-volume-provisioner:1.34.3", + "NodeSelector": s.KubernetesAPI.NodeSelector, + "Resources": s.VolumeProvisioner.Resources, + "MountAzureJson": false, + }, + "LocalVolumeMonitor": map[string]interface{}{ + "Resources": s.LocalVolumeMonitor.Resources, + "Image": map[string]string{ + "Name": "codefresh/dind-volume-utils", + "Tag": "1.29.4", + }, + }, + "VolumeCleaner": map[string]interface{}{ + "Image": map[string]string{ + "Name": "codefresh/dind-volume-cleanup", + "Tag": "1.2.0", + }, + }, + }, + "Monitor": map[string]interface{}{ + "Enabled": true, + "UseNamespaceWithRole": s.UseNamespaceWithRole, + //TODO: need verify it on cluster level + "RbacEnabled": true, + "Helm3": s.Helm3, + "AppName": MonitorApplicationName, + "Image": map[string]string{ + "Name": "codefresh/cf-k8s-agent", + "Tag": "1.3.19", + }, + "Resources": s.Monitor.Resources, + }, + "AppProxy": map[string]interface{}{ + "AppName": AppProxyApplicationName, + "Image": map[string]string{ + "Name": "codefresh/cf-app-proxy", + "Tag": "latest", + }, + "Resources": s.AppProxy.Resources, + "Ingress": map[string]interface{}{ + "Host": "", + "IngressClass": "", + }, + }, + "Runtime": map[string]interface{}{ + "EngineAppName": EngineAppName, + }, + "NetworkTester": map[string]interface{}{ + "PodName": NetworkTesterName, + "Image": map[string]string{ + "Name": "codefresh/cf-venona-network-tester", + "Tag": "latest", + }, + }, + } +} diff --git a/venonactl/pkg/templates/generate_template.go b/venonactl/pkg/templates/generate_template.go new file mode 100644 index 00000000..5483a774 --- /dev/null +++ b/venonactl/pkg/templates/generate_template.go @@ -0,0 +1,106 @@ +/* +Copyright 2019 The Codefresh Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "os" + "path" + "path/filepath" + "runtime" + "strings" + "text/template" +) + +/* +for usage in +\\go:generate go run generate generate_template.go +reads all files in folder and appends them to template map +*/ + +var outfileBaseName = "templates.go" +var packageTemplate = template.Must(template.New("").Parse( + ` +// Code generated by go generate; DO NOT EDIT. +// using data from templates/{{ .FolderName }} +package {{ .PackageName }} + +func TemplatesMap() map[string]string { + templatesMap := make(map[string]string)` + + + "\n{{ range $key, $value := .TemplateFilesMap }}" + + "\ntemplatesMap[\"{{ $key }}\"] = `{{ $value }}` \n" + + "{{ end }}" + ` + return templatesMap +} +`)) + +type packageTempateData struct { + PackageName string + FolderName string + TemplateFilesMap map[string]string +} + +func main() { + if len(os.Args) < 2 { + fmt.Println("generate_template ERROR: missing folder name") + os.Exit(1) + } + + var currentFilePath string + if strings.Contains(os.Args[0], "/go-build") { + _, currentFilePath, _, _ = runtime.Caller(0) + } else { + currentFilePath = os.Args[0] + } + + currentDir := filepath.Dir(currentFilePath) + templatesDirParam := os.Args[1] + var folderName = path.Join(currentDir, templatesDirParam) + + // Fill Tempalte Map + templateFilesMap := make(map[string]string) + filepath.Walk(folderName, func(name string, info os.FileInfo, err error) error { + if !info.IsDir() && path.Base(name) != outfileBaseName { + b, _ := os.ReadFile(name) + templateFilesMap[filepath.Base(name)] = string(b) + } + return nil + }) + + if len(templateFilesMap) == 0 { + fmt.Printf("No files in %s\n", folderName) + } + + outfileName := path.Join(folderName, "templates.go") + outfile, err := os.Create(outfileName) + if err != nil { + fmt.Printf("generate_template ERROR: cannot create out file %s, %v \n", outfileName, err) + os.Exit(1) + } + defer outfile.Close() + + err = packageTemplate.Execute(outfile, packageTempateData{ + PackageName: path.Base(folderName), + FolderName: templatesDirParam, + TemplateFilesMap: templateFilesMap, + }) + if err != nil { + fmt.Printf("generate_template ERROR: cannot generate template %v \n", err) + os.Exit(1) + } +} diff --git a/venonactl/pkg/templates/kubernetes/cluster-role-binding.app-proxy.yaml b/venonactl/pkg/templates/kubernetes/cluster-role-binding.app-proxy.yaml new file mode 100644 index 00000000..c5430b55 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/cluster-role-binding.app-proxy.yaml @@ -0,0 +1,14 @@ +{{- if .CreateRbac }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .AppProxy.AppName }}-cluster-reader-{{ .Namespace }} +subjects: +- kind: ServiceAccount + name: {{ .AppProxy.AppName }} # this service account can get secrets cluster-wide (all namespaces) + namespace: {{ .Namespace }} +roleRef: + kind: ClusterRole + name: {{ .AppProxy.AppName }}-cluster-reader-{{ .Namespace }} + apiGroup: rbac.authorization.k8s.io +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/cluster-role-binding.dind-volume-provisioner.vp.yaml b/venonactl/pkg/templates/kubernetes/cluster-role-binding.dind-volume-provisioner.vp.yaml new file mode 100644 index 00000000..9f1dc576 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/cluster-role-binding.dind-volume-provisioner.vp.yaml @@ -0,0 +1,17 @@ +{{- if .CreateRbac }} +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: volume-provisioner-{{ .AppName }}-{{ .Namespace }} + labels: + app: dind-volume-provisioner-{{ .AppName }} +subjects: + - kind: ServiceAccount + name: volume-provisioner-{{ .AppName }} + namespace: {{ .Namespace }} +roleRef: + kind: ClusterRole + name: volume-provisioner-{{ .AppName }}-{{ .Namespace }} + apiGroup: rbac.authorization.k8s.io +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/cluster-role-binding.venona.yaml b/venonactl/pkg/templates/kubernetes/cluster-role-binding.venona.yaml new file mode 100644 index 00000000..7829fa38 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/cluster-role-binding.venona.yaml @@ -0,0 +1,14 @@ +{{- if .CreateRbac }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .AppName }}-{{ .Namespace }} +subjects: +- kind: ServiceAccount + name: {{ .AppName }} + namespace: {{ .Namespace }} +roleRef: + kind: ClusterRole + name: system:discovery + apiGroup: rbac.authorization.k8s.io +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/cluster-role.app-proxy.yaml b/venonactl/pkg/templates/kubernetes/cluster-role.app-proxy.yaml new file mode 100644 index 00000000..898e3363 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/cluster-role.app-proxy.yaml @@ -0,0 +1,13 @@ +{{- if .CreateRbac }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .AppProxy.AppName }}-cluster-reader-{{ .Namespace }} + labels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get"] +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/cluster-role.dind-volume-provisioner.vp.yaml b/venonactl/pkg/templates/kubernetes/cluster-role.dind-volume-provisioner.vp.yaml new file mode 100644 index 00000000..3650435b --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/cluster-role.dind-volume-provisioner.vp.yaml @@ -0,0 +1,36 @@ +{{- if .CreateRbac }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: volume-provisioner-{{ .AppName }}-{{ .Namespace }} + labels: + app: dind-volume-provisioner +rules: + - apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch", "create", "delete", "patch"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch", "update", "delete"] + - apiGroups: ["storage.k8s.io"] + resources: ["storageclasses"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["list", "watch", "create", "update", "patch"] + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch", "create", "delete", "patch"] + - apiGroups: [""] + resources: ["endpoints"] + verbs: ["get", "list", "watch", "create", "update", "delete"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "create", "update"] +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/codefresh-certs-server-secret.re.yaml b/venonactl/pkg/templates/kubernetes/codefresh-certs-server-secret.re.yaml new file mode 100644 index 00000000..e9bbbbcd --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/codefresh-certs-server-secret.re.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +type: Opaque +kind: Secret +metadata: + labels: + app: venona + name: codefresh-certs-server + namespace: {{ .Namespace }} +data: + server-cert.pem: {{ .ServerCert.Cert }} + server-key.pem: {{ .ServerCert.Key }} + ca.pem: {{ .ServerCert.Ca }} + diff --git a/venonactl/pkg/templates/kubernetes/cron-job.dind-volume-cleanup.vp.yaml b/venonactl/pkg/templates/kubernetes/cron-job.dind-volume-cleanup.vp.yaml new file mode 100644 index 00000000..e837f877 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/cron-job.dind-volume-cleanup.vp.yaml @@ -0,0 +1,31 @@ +{{- if not (eq .Storage.Backend "local") }} +apiVersion: batch/v1beta1 +kind: CronJob +metadata: + name: dind-volume-cleanup-{{ .AppName }} + namespace: {{ .Namespace }} + labels: + app: dind-volume-cleanup +spec: + schedule: "0,10,20,30,40,50 * * * *" + concurrencyPolicy: Forbid + {{- if eq .Storage.Backend "local" }} + suspend: true + {{- end }} + jobTemplate: + spec: + template: + spec: + serviceAccountName: volume-provisioner-{{ .AppName }} + restartPolicy: Never + containers: + - name: dind-volume-cleanup + image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Storage.VolumeCleaner.Image.Name }}:{{ .Storage.VolumeCleaner.Image.Tag }} {{- else }}{{- .Storage.VolumeCleaner.Image.Name }}:{{ .Storage.VolumeCleaner.Image.Tag }} {{- end}} + env: + - name: PROVISIONED_BY + value: codefresh.io/dind-volume-provisioner-{{ .AppName }}-{{ .Namespace }} + securityContext: + fsGroup: 3000 + runAsGroup: 3000 + runAsUser: 3000 +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/daemonset.dind-lv-monitor.vp.yaml b/venonactl/pkg/templates/kubernetes/daemonset.dind-lv-monitor.vp.yaml new file mode 100644 index 00000000..89d54abf --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/daemonset.dind-lv-monitor.vp.yaml @@ -0,0 +1,87 @@ +{{- if eq .Storage.Backend "local" -}} +{{- $localVolumeParentDir := ( .Storage.LocalVolumeParentDir | default "/var/lib/codefresh/dind-volumes" ) }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: dind-lv-monitor-{{ .AppName }} + namespace: {{ .Namespace }} + labels: + app: dind-lv-monitor +spec: + selector: + matchLabels: + app: dind-lv-monitor + template: + metadata: + labels: + app: dind-lv-monitor + annotations: + prometheus_port: "9100" + prometheus_scrape: "true" + spec: + serviceAccountName: volume-provisioner-{{ .AppName }} + tolerations: + - key: 'codefresh/dind' + operator: 'Exists' + effect: 'NoSchedule' + +{{ toYaml .Tolerations | indent 8 | unescape}} + securityContext: + fsGroup: 1000 + initContainers: + - command: + - chown + - -R + - 1000:1000 + - /var/lib/codefresh/dind-volumes + image: alpine + imagePullPolicy: Always + name: fs-change-owner + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /var/lib/codefresh/dind-volumes + name: dind-volume-dir + containers: + - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Storage.LocalVolumeMonitor.Image.Name }}:{{ .Storage.LocalVolumeMonitor.Image.Tag }} {{- else }}{{- .Storage.LocalVolumeMonitor.Image.Name }}:{{ .Storage.LocalVolumeMonitor.Image.Tag }} {{- end}} + name: lv-cleaner + resources: +{{ toYaml .Storage.LocalVolumeMonitor.Resources | indent 10 }} + imagePullPolicy: Always + command: + - /home/dind-volume-utils/bin/local-volumes-agent + env: + {{- if $.EnvVars }} + {{- range $key, $value := $.EnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: VOLUME_PARENT_DIR + value: {{ $localVolumeParentDir }} +# Debug: +# - name: DRY_RUN +# value: "1" +# - name: DEBUG +# value: "1" +# - name: SLEEP_INTERVAL +# value: "3" +# - name: LOG_DF_EVERY +# value: "60" +# - name: KB_USAGE_THRESHOLD +# value: "20" + + volumeMounts: + - mountPath: {{ $localVolumeParentDir }} + readOnly: false + name: dind-volume-dir + volumes: + - name: dind-volume-dir + hostPath: + path: {{ $localVolumeParentDir }} +{{- end -}} diff --git a/venonactl/pkg/templates/kubernetes/deployment.app-proxy.yaml b/venonactl/pkg/templates/kubernetes/deployment.app-proxy.yaml new file mode 100644 index 00000000..aa081683 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/deployment.app-proxy.yaml @@ -0,0 +1,75 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} + name: {{ .AppProxy.AppName }} + namespace: {{ .Namespace }} +spec: + selector: + matchLabels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} + replicas: 1 + revisionHistoryLimit: 5 + strategy: + rollingUpdate: + maxSurge: 50% + maxUnavailable: 50% + type: RollingUpdate + template: + metadata: + labels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} + spec: + {{- if .CreateRbac }} + serviceAccountName: {{ .AppProxy.AppName }} + {{- end }} + containers: + - name: {{ .AppProxy.AppName }} + image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .AppProxy.Image.Name }}:{{ .AppProxy.Image.Tag }} {{- else }} {{- .AppProxy.Image.Name }}:{{ .AppProxy.Image.Tag }} {{- end}} + imagePullPolicy: Always + resources: +{{ toYaml .AppProxy.resources | indent 10 }} + env: + {{- if $.EnvVars }} + {{- range $key, $value := $.EnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + {{- if $.AppProxy.AdditionalEnvVars }} + {{- range $key, $value := $.AppProxy.AdditionalEnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + - name: PORT + value: "3000" + - name: CODEFRESH_HOST + value: {{ .CodefreshHost }} + {{ if .AppProxy.Ingress.PathPrefix }} + - name: API_PATH_PREFIX + value: {{ .AppProxy.Ingress.PathPrefix }} + {{ end }} + {{- if .NewRelicLicense }} + - name: NEWRELIC_LICENSE_KEY + {{- if isString .NewRelicLicense }} + value: {{ .NewRelicLicense }} + {{- else }} +{{ toYaml .NewRelicLicense | indent 12 }} + {{- end }} + {{- end }} + ports: + - containerPort: 3000 + protocol: TCP + readinessProbe: + httpGet: + path: /health + port: 3000 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 diff --git a/venonactl/pkg/templates/kubernetes/deployment.dind-volume-provisioner.vp.yaml b/venonactl/pkg/templates/kubernetes/deployment.dind-volume-provisioner.vp.yaml new file mode 100644 index 00000000..6550b68a --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/deployment.dind-volume-provisioner.vp.yaml @@ -0,0 +1,123 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dind-volume-provisioner-{{ .AppName }} + namespace: {{ .Namespace }} + labels: + app: dind-volume-provisioner +spec: + selector: + matchLabels: + app: dind-volume-provisioner + replicas: 1 + strategy: + type: Recreate + template: + metadata: + labels: + app: dind-volume-provisioner + spec: + {{ if .Storage.VolumeProvisioner.NodeSelector }} + nodeSelector: +{{ .Storage.VolumeProvisioner.NodeSelector | nodeSelectorParamToYaml | indent 8 | unescape}} + {{ end }} + serviceAccount: volume-provisioner-{{ .AppName }} + securityContext: + runAsUser: 3000 + runAsGroup: 3000 + fsGroup: 3000 + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + operator: "Exists" + +{{ toYaml .Tolerations | indent 8 | unescape}} + + containers: + - name: dind-volume-provisioner + resources: +{{ toYaml .Storage.VolumeProvisioner.Resources | indent 10 }} + image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Storage.VolumeProvisioner.Image }} {{- else }} {{- .Storage.VolumeProvisioner.Image }} {{- end}} + imagePullPolicy: Always + command: + - /usr/local/bin/dind-volume-provisioner + - -v=4 + - --resync-period=50s + env: + {{- if $.EnvVars }} + {{- range $key, $value := $.EnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + - name: PROVISIONER_NAME + value: codefresh.io/dind-volume-provisioner-{{ .AppName }}-{{ .Namespace }} + {{- if ne .DockerRegistry "" }} + - name: DOCKER_REGISTRY + value: {{ .DockerRegistry }} + {{- end }} + {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits }} + {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.CPU }} + - name: CREATE_DIND_LIMIT_CPU + value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.CPU }} + {{- end }} + {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.Memory }} + - name: CREATE_DIND_LIMIT_MEMORY + value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.Memory }} + {{- end }} + {{- end }} + {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests }} + {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.CPU }} + - name: CREATE_DIND_REQUESTS_CPU + value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.CPU }} + {{- end }} + {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.Memory }} + - name: CREATE_DIND_REQUESTS_MEMORY + value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.Memory }} + {{- end }} + {{- end }} + {{- if .Storage.AwsAccessKeyId }} + - name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: dind-volume-provisioner-{{ .AppName }} + key: aws_access_key_id + {{- end }} + {{- if .Storage.AwsSecretAccessKey }} + - name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: dind-volume-provisioner-{{ .AppName }} + key: aws_secret_access_key + {{- end }} + {{- if .Storage.GoogleServiceAccount }} + - name: GOOGLE_APPLICATION_CREDENTIALS + value: /etc/dind-volume-provisioner/credentials/google-service-account.json + {{- end }} + {{- if .Storage.VolumeProvisioner.MountAzureJson }} + - name: AZURE_CREDENTIAL_FILE + value: "/etc/kubernetes/azure.json" + {{- end }} + volumeMounts: + {{- if .Storage.VolumeProvisioner.MountAzureJson }} + - name: azure-json + readOnly: true + mountPath: "/etc/kubernetes/azure.json" + {{- end }} + {{- if .Storage.GoogleServiceAccount }} + - name: credentials + readOnly: true + mountPath: "/etc/dind-volume-provisioner/credentials" + {{- end }} + volumes: + {{- if .Storage.VolumeProvisioner.MountAzureJson }} + - name: azure-json + hostPath: + path: /etc/kubernetes/azure.json + type: File + {{- end }} + {{- if .Storage.GoogleServiceAccount }} + - name: credentials + secret: + secretName: dind-volume-provisioner-{{ .AppName }} + {{- end }} diff --git a/venonactl/pkg/templates/kubernetes/deployment.monitor.yaml b/venonactl/pkg/templates/kubernetes/deployment.monitor.yaml new file mode 100644 index 00000000..46690637 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/deployment.monitor.yaml @@ -0,0 +1,81 @@ +{{- if .Monitor.Enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Monitor.AppName }} + namespace: {{ .Namespace }} + labels: + app: {{ .AppName }} + version: {{ .Version }} +spec: + replicas: 1 + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 50% + maxSurge: 50% + selector: + matchLabels: + app: {{ .Monitor.AppName }} + template: + metadata: + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} + spec: + {{- if .Monitor.RbacEnabled}} + serviceAccountName: {{ .Monitor.AppName }} + {{- end }} + containers: + - name: {{ .Monitor.AppName }} + resources: +{{ toYaml .Monitor.resources | indent 10 }} + image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Monitor.Image.Name }}:{{ .Monitor.Image.Tag }} {{- else }} {{- .Monitor.Image.Name }}:{{ .Monitor.Image.Tag }} {{- end}} + imagePullPolicy: Always + env: + {{- if $.EnvVars }} + {{- range $key, $value := $.EnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + {{- if $.Monitor.AdditionalEnvVars }} + {{- range $key, $value := $.Monitor.AdditionalEnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + - name: SERVICE_NAME + value: {{ .Monitor.AppName }} + {{- if .Monitor.UseNamespaceWithRole }} + - name: ROLE_BINDING + value: "true" + {{- end }} + - name: PORT + value: "9020" + - name: API_TOKEN + value: {{ .Token }} + - name: CLUSTER_ID + value: {{ .ClusterId }} + - name: API_URL + value: {{ .CodefreshHost }}/api/k8s-monitor/events + - name: ACCOUNT_ID + value: user + - name: HELM3 + value: "{{ .Monitor.Helm3 }}" + - name: NAMESPACE + value: "{{ .Namespace }}" + - name: NODE_OPTIONS + value: "--max_old_space_size=4096" + ports: + - containerPort: 9020 + protocol: TCP + readinessProbe: + httpGet: + path: /api/ping + port: 9020 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 +{{- end }} diff --git a/venonactl/pkg/templates/kubernetes/deployment.venona.yaml b/venonactl/pkg/templates/kubernetes/deployment.venona.yaml new file mode 100644 index 00000000..7cb7c21f --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/deployment.venona.yaml @@ -0,0 +1,106 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: {{ .AppName }} + version: {{ .Version }} + name: {{ .AppName }} + namespace: {{ .Namespace }} +spec: + selector: + matchLabels: + app: {{ .AppName }} + version: {{ .Version }} + replicas: 1 + revisionHistoryLimit: 5 + strategy: + rollingUpdate: + maxSurge: 50% + maxUnavailable: 50% + type: RollingUpdate + template: + metadata: + labels: + app: {{ .AppName }} + version: {{ .Version }} + spec: + volumes: + - name: runnerconf + secret: + secretName: runnerconf + {{ if ne .NodeSelector "" }} + nodeSelector: +{{ .NodeSelector | nodeSelectorParamToYaml | indent 8 | unescape }} + {{ end }} + tolerations: +{{ toYaml .Tolerations | indent 8 | unescape }} + containers: + - env: + {{- if $.EnvVars }} + {{- range $key, $value := $.EnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + {{- if $.AdditionalEnvVars }} + {{- range $key, $value := $.AdditionalEnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + - name: SELF_DEPLOYMENT_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: CODEFRESH_TOKEN + valueFrom: + secretKeyRef: + name: {{ .AppName }} + key: codefresh.token + - name: CODEFRESH_HOST + value: {{ .CodefreshHost }} + - name: AGENT_MODE + value: {{ .Mode }} + - name: AGENT_NAME + value: {{ .AppName }} + - name: "AGENT_ID" + value: {{ .AgentId }} + - name: VENONA_CONFIG_DIR + value: "/etc/secrets" + {{- if ne .DockerRegistry "" }} + - name: DOCKER_REGISTRY + value: {{ .DockerRegistry }} + {{- end }} + {{- if .NewRelicLicense }} + - name: NEWRELIC_LICENSE_KEY + {{- if isString .NewRelicLicense }} + value: {{ .NewRelicLicense }} + {{- else }} +{{ toYaml .NewRelicLicense | indent 10}} + {{- end }} + {{- end }} + image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Image.Name }} {{- else }} {{- .Image.Name }}{{- end}}:{{ .Image.Tag | default "latest"}} + ports: + - containerPort: 8080 + protocol: TCP + readinessProbe: + httpGet: + path: /health + port: 8080 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + volumeMounts: + - name: runnerconf + mountPath: "/etc/secrets" + readOnly: true + imagePullPolicy: Always + name: {{ .AppName }} + resources: +{{ toYaml .Runner.Resources | indent 10 }} + securityContext: + runAsUser: 10001 + runAsGroup: 10001 + fsGroup: 10001 + restartPolicy: Always diff --git a/venonactl/pkg/templates/kubernetes/dind-daemon-conf.re.yaml b/venonactl/pkg/templates/kubernetes/dind-daemon-conf.re.yaml new file mode 100644 index 00000000..b3af9262 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/dind-daemon-conf.re.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: codefresh-dind-config + namespace: {{ .Namespace }} +data: + daemon.json: | + { + "hosts": [ "unix:///var/run/docker.sock", + "tcp://0.0.0.0:1300"], + "tlsverify": true, + "tls": true, + "tlscacert": "/etc/ssl/cf-client/ca.pem", + "tlscert": "/etc/ssl/cf/server-cert.pem", + "tlskey": "/etc/ssl/cf/server-key.pem", + "insecure-registries" : ["192.168.99.100:5000"], + "metrics-addr" : "0.0.0.0:9323", + "experimental" : true + } diff --git a/venonactl/pkg/templates/kubernetes/dind-headless-service.re.yaml b/venonactl/pkg/templates/kubernetes/dind-headless-service.re.yaml new file mode 100644 index 00000000..464bd35a --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/dind-headless-service.re.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: dind + name: dind + namespace: {{ .Namespace }} +spec: + ports: + - name: "dind-port" + port: 1300 + protocol: TCP + + # This is a headless service, Kubernetes won't assign a VIP for it. + # *.dind.default.svc.cluster.local + clusterIP: None + selector: + app: dind + diff --git a/venonactl/pkg/templates/kubernetes/ingress.app-proxy.yaml b/venonactl/pkg/templates/kubernetes/ingress.app-proxy.yaml new file mode 100644 index 00000000..69f11e53 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/ingress.app-proxy.yaml @@ -0,0 +1,30 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + {{ range $key, $value := .AppProxy.Ingress.Annotations }} + {{ $key }}: {{ $value | quote | unescape }} + {{ end }} + name: app-proxy + namespace: {{ .Namespace }} +spec: + {{ if ne .AppProxy.Ingress.IngressClass "" }} + ingressClassName: {{ .AppProxy.Ingress.IngressClass }} + {{ end }} + rules: + - host: {{ .AppProxy.Ingress.Host }} + http: + paths: + - path: {{ if .AppProxy.Ingress.PathPrefix }}{{ .AppProxy.Ingress.PathPrefix }}{{ else }}'/'{{end}} + pathType: ImplementationSpecific + backend: + service: + name: app-proxy + port: + number: 80 + {{ if .AppProxy.Ingress.TLSSecret }} + tls: + - hosts: + - {{ .AppProxy.Ingress.Host }} + secretName: {{ .AppProxy.Ingress.TLSSecret }} + {{ end }} diff --git a/venonactl/pkg/templates/kubernetes/pod.network-tester.yaml b/venonactl/pkg/templates/kubernetes/pod.network-tester.yaml new file mode 100644 index 00000000..2789e18c --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/pod.network-tester.yaml @@ -0,0 +1,44 @@ +apiVersion: v1 +kind: Pod +metadata: + name: {{ .NetworkTester.PodName }} + namespace: {{ .Namespace }} + labels: + app: {{ .AppName }} + version: {{ .Version }} +spec: + containers: + - name: {{ .NetworkTester.PodName }} + image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .NetworkTester.Image.Name }}:{{ .NetworkTester.Image.Tag }} {{- else }} {{- .NetworkTester.Image.Name }}:{{ .NetworkTester.Image.Tag }} {{- end}} + imagePullPolicy: Always + restartPolicy: Never + resources: + limits: + cpu: 400m + memory: 500Mi + requests: + cpu: 200m + memory: 300Mi + env: + {{- if $.EnvVars }} + {{- range $key, $value := $.EnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + {{- if $.NetworkTester.AdditionalEnvVars }} + {{- range $key, $value := $.NetworkTester.AdditionalEnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + {{- if .Verbose }} + - name: DEBUG + value: '1' + {{- end }} + {{- if .Insecure }} + - name: INSECURE + value: '1' + {{- end }} + - name: IN_CLUSTER + value: '1' \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/role-binding.engine.yaml b/venonactl/pkg/templates/kubernetes/role-binding.engine.yaml new file mode 100644 index 00000000..0555f0d9 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/role-binding.engine.yaml @@ -0,0 +1,15 @@ +{{- if .CreateRbac }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Runtime.EngineAppName }} + namespace: {{ .Namespace }} +subjects: +- kind: ServiceAccount + name: {{ .Runtime.EngineAppName }} + namespace: {{ .Namespace }} +roleRef: + kind: Role + name: {{ .Runtime.EngineAppName }} + apiGroup: rbac.authorization.k8s.io +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/role-binding.re.yaml b/venonactl/pkg/templates/kubernetes/role-binding.re.yaml new file mode 100644 index 00000000..bb1c618c --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/role-binding.re.yaml @@ -0,0 +1,15 @@ +{{- if .CreateRbac }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .AppName }} + namespace: {{ .Namespace }} +subjects: +- kind: ServiceAccount + name: {{ .AppName }} + namespace: {{ .Namespace }} +roleRef: + kind: Role + name: {{ .AppName }} + apiGroup: rbac.authorization.k8s.io +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/role.engine.yaml b/venonactl/pkg/templates/kubernetes/role.engine.yaml new file mode 100644 index 00000000..c662a93a --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/role.engine.yaml @@ -0,0 +1,11 @@ +{{- if .CreateRbac }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Runtime.EngineAppName }} + namespace: {{ .Namespace }} +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get"] +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/role.monitor.yaml b/venonactl/pkg/templates/kubernetes/role.monitor.yaml new file mode 100644 index 00000000..0e33c320 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/role.monitor.yaml @@ -0,0 +1,49 @@ +{{- if .CreateRbac }} +{{- if and .Monitor.Enabled .Monitor.RbacEnabled }} +{{- if .Monitor.UseNamespaceWithRole }} +kind: Role +{{- else }} +kind: ClusterRole +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Monitor.AppName }}-cluster-reader + namespace: {{ .Namespace }} + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} +rules: +- apiGroups: + - "" + resources: ["*"] + verbs: + - get + - list + - watch + - create + - delete +- apiGroups: + - "" + resources: ["pods"] + verbs: + - get + - list + - watch + - create + - deletecollection +- apiGroups: + - extensions + resources: ["*"] + verbs: + - get + - list + - watch +- apiGroups: + - apps + resources: ["*"] + verbs: + - get + - list + - watch +{{- end }} +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/role.re.yaml b/venonactl/pkg/templates/kubernetes/role.re.yaml new file mode 100644 index 00000000..cee35c57 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/role.re.yaml @@ -0,0 +1,11 @@ +{{- if .CreateRbac }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .AppName }} + namespace: {{ .Namespace }} +rules: +- apiGroups: [""] + resources: ["pods", "persistentvolumeclaims"] + verbs: ["get", "create", "delete"] +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/rolebinding.monitor.yaml b/venonactl/pkg/templates/kubernetes/rolebinding.monitor.yaml new file mode 100644 index 00000000..755c03b1 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/rolebinding.monitor.yaml @@ -0,0 +1,28 @@ +{{- if .CreateRbac }} +{{- if and .Monitor.Enabled .Monitor.RbacEnabled }} +{{- if .Monitor.UseNamespaceWithRole }} +kind: RoleBinding +{{- else }} +kind: ClusterRoleBinding +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Monitor.AppName }}-cluster-reader + namespace: {{ .Namespace }} + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} +subjects: +- kind: ServiceAccount + namespace: {{ .Namespace }} + name: {{ .Monitor.AppName }} +roleRef: + apiGroup: rbac.authorization.k8s.io + {{- if .Monitor.UseNamespaceWithRole }} + kind: Role + {{- else }} + kind: ClusterRole + {{- end }} + name: {{ .Monitor.AppName }}-cluster-reader +{{- end }} +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/rollback-role-binding.monitor.yaml b/venonactl/pkg/templates/kubernetes/rollback-role-binding.monitor.yaml new file mode 100644 index 00000000..27d1669b --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/rollback-role-binding.monitor.yaml @@ -0,0 +1,24 @@ +{{- if .CreateRbac }} +{{- if .Monitor.RbacEnabled }} +{{- if .Monitor.UseNamespaceWithRole }} +kind: RoleBinding +{{- else }} +kind: ClusterRoleBinding +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Monitor.AppName }}-rollback + namespace: {{ .Namespace }} + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} +subjects: + - kind: ServiceAccount + namespace: {{ .Namespace }} + name: {{ .Monitor.AppName }}-rollback +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin + {{- end }} +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/rollback-serviceaccount.monitor.yaml b/venonactl/pkg/templates/kubernetes/rollback-serviceaccount.monitor.yaml new file mode 100644 index 00000000..38532b1b --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/rollback-serviceaccount.monitor.yaml @@ -0,0 +1,16 @@ +{{- if .CreateRbac }} +{{- if and .Monitor.RbacEnabled (not .Monitor.UseNamespaceWithRole) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Monitor.AppName }}-rollback + namespace: {{ .Namespace }} + annotations: + {{ range $key, $value := .Monitor.ServiceAccount.Annotations }} + {{ $key }}: {{ $value }} + {{ end }} + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/secret.dind-volume-provisioner.vp.yaml b/venonactl/pkg/templates/kubernetes/secret.dind-volume-provisioner.vp.yaml new file mode 100644 index 00000000..f1dcc47f --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/secret.dind-volume-provisioner.vp.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: dind-volume-provisioner-{{ .AppName }} + namespace: {{ .Namespace }} + labels: + app: dind-volume-provisioner +stringData: +{{- if .Storage.GoogleServiceAccount }} + google-service-account.json: {{ .Storage.GoogleServiceAccount }} +{{- end }} +{{- if .Storage.AwsAccessKeyId }} + aws_access_key_id: {{ .Storage.AwsAccessKeyId }} +{{- end }} +{{- if .Storage.AwsSecretAccessKey }} + aws_secret_access_key: {{ .Storage.AwsSecretAccessKey }} +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/secret.runtime-attach.yaml b/venonactl/pkg/templates/kubernetes/secret.runtime-attach.yaml new file mode 100644 index 00000000..26f0821e --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/secret.runtime-attach.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ .AppName }}conf + namespace: {{ .Namespace }} +data: +{{ range $key, $value := .runnerConf }} + {{ $key }}: {{ $value }} +{{ end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/secret.venona.yaml b/venonactl/pkg/templates/kubernetes/secret.venona.yaml new file mode 100644 index 00000000..640b275f --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/secret.venona.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ .AppName }} + namespace: {{ .Namespace }} +stringData: + codefresh.token: {{ .AgentToken }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/service-account.app-proxy.yaml b/venonactl/pkg/templates/kubernetes/service-account.app-proxy.yaml new file mode 100644 index 00000000..2b03a76e --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/service-account.app-proxy.yaml @@ -0,0 +1,14 @@ +{{- if .CreateRbac }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .AppProxy.AppName }} + namespace: {{ .Namespace }} + annotations: + {{ range $key, $value := .AppProxy.ServiceAccount.Annotations }} + {{ $key }}: {{ $value | quote | unescape }} + {{ end }} + labels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} +{{- end }} diff --git a/venonactl/pkg/templates/kubernetes/service-account.dind-volume-provisioner.vp.yaml b/venonactl/pkg/templates/kubernetes/service-account.dind-volume-provisioner.vp.yaml new file mode 100644 index 00000000..36502abc --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/service-account.dind-volume-provisioner.vp.yaml @@ -0,0 +1,14 @@ +{{- if .CreateRbac }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: volume-provisioner-{{ .AppName }} + namespace: {{ .Namespace }} + annotations: + {{ range $key, $value := .Storage.VolumeProvisioner.ServiceAccount.Annotations }} + {{ $key }}: {{ $value }} + {{ end }} + labels: + app: dind-volume-provisioner +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/service-account.engine.yaml b/venonactl/pkg/templates/kubernetes/service-account.engine.yaml new file mode 100644 index 00000000..ef2ea5c5 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/service-account.engine.yaml @@ -0,0 +1,14 @@ +{{- if .CreateRbac }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Runtime.EngineAppName }} + namespace: {{ .Namespace }} + annotations: + {{ range $key, $value := .Runtime.ServiceAccount.Annotations }} + {{ $key }}: {{ $value }} + {{ end }} + labels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} +{{- end }} diff --git a/venonactl/pkg/templates/kubernetes/service-account.monitor.yaml b/venonactl/pkg/templates/kubernetes/service-account.monitor.yaml new file mode 100644 index 00000000..f3eebf39 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/service-account.monitor.yaml @@ -0,0 +1,16 @@ +{{- if .CreateRbac }} +{{- if and .Monitor.Enabled .Monitor.RbacEnabled }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Monitor.AppName }} + namespace: {{ .Namespace }} + annotations: + {{ range $key, $value := .Monitor.ServiceAccount.Annotations }} + {{ $key }}: {{ $value }} + {{ end }} + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} +{{- end }} +{{- end }} diff --git a/venonactl/pkg/templates/kubernetes/service-account.re.yaml b/venonactl/pkg/templates/kubernetes/service-account.re.yaml new file mode 100644 index 00000000..8a543cef --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/service-account.re.yaml @@ -0,0 +1,7 @@ +{{- if .CreateRbac }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .AppName }} + namespace: {{ .Namespace }} +{{- end }} \ No newline at end of file diff --git a/venonactl/pkg/templates/kubernetes/service.app-proxy.yaml b/venonactl/pkg/templates/kubernetes/service.app-proxy.yaml new file mode 100644 index 00000000..7aba3562 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/service.app-proxy.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: app-proxy + namespace: {{ .Namespace }} + labels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} +spec: + selector: + app: {{ .AppProxy.AppName }} + ports: + - protocol: TCP + port: 80 + targetPort: 3000 diff --git a/venonactl/pkg/templates/kubernetes/service.monitor.yaml b/venonactl/pkg/templates/kubernetes/service.monitor.yaml new file mode 100644 index 00000000..ef25b735 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/service.monitor.yaml @@ -0,0 +1,19 @@ +{{- if .CreateRbac }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Monitor.AppName }} + namespace: {{ .Namespace }} + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} +spec: + type: ClusterIP + ports: + - name: "http" + port: 80 + protocol: TCP + targetPort: 9020 + selector: + app: {{ .Monitor.AppName }} +{{- end }} diff --git a/venonactl/pkg/templates/kubernetes/storageclass.dind-volume-provisioner.vp.yaml b/venonactl/pkg/templates/kubernetes/storageclass.dind-volume-provisioner.vp.yaml new file mode 100644 index 00000000..6b3495ad --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/storageclass.dind-volume-provisioner.vp.yaml @@ -0,0 +1,57 @@ +{{- if .Storage.CreateStorageClass }} +--- +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: {{ .Storage.StorageClassName }} + labels: + app: dind-volume-provisioner + annotations: + {{ range $key, $value := .Storage.Annotations }} + {{ $key }}: {{ $value }} + {{ end }} +provisioner: codefresh.io/dind-volume-provisioner-{{ .AppName }}-{{ .Namespace }} +parameters: +{{- if eq .Storage.Backend "local" }} + volumeBackend: local + volumeParentDir: {{ .Storage.LocalVolumeParentDir | default "/var/lib/codefresh/dind-volumes" }} +{{- else if eq .Storage.Backend "gcedisk" }} + volumeBackend: {{ .Storage.Backend }} + # pd-ssd or pd-standard + type: {{ .Storage.VolumeType | default "pd-ssd" }} + # Valid zone in GCP + zone: {{ .Storage.AvailabilityZone }} + # ext4 or xfs (default to ext4 because xfs is not installed on GKE by default ) + fsType: {{ .Storage.FsType | default "ext4" }} +{{- else if or (eq .Storage.Backend "ebs") (eq .Storage.Backend "ebs-csi")}} + # ebs or ebs-csi + volumeBackend: {{ .Storage.Backend }} + # gp2 or io1 + VolumeType: {{ .Storage.VolumeType | default "gp2" }} + # Valid zone in aws (us-east-1c, ...) + AvailabilityZone: {{ .Storage.AvailabilityZone }} + # ext4 or xfs (default to ext4 ) + fsType: {{ .Storage.FsType | default "ext4" }} + + # "true" or "false" (default - "false") + encrypted: "{{ .Storage.Encrypted | default "false" }}" + {{ if .Storage.KmsKeyId }} + # KMS Key ID + kmsKeyId: {{ .Storage.KmsKeyId }} + {{- end }} +{{- else if or (eq .Storage.Backend "azuredisk") (eq .Storage.Backend "azuredisk-csi")}} + ## azuredisk or azuredisk-csi + volumeBackend: {{ .Storage.Backend }} + + kind: managed + skuName: {{ .Storage.SkuName | default "Premium_LRS" }} + fsType: {{ .Storage.FsType | default "ext4" }} + cachingMode: {{ .Storage.CachingMode | default "None" }} + {{- if .Storage.AzureLocation }} + location: {{ .Storage.AzureLocation }} + {{- end }} + {{- if .Storage.AzureResourceGroup }} + resourceGroup: {{ .Storage.AzureResourceGroup }} + {{- end }} +{{- end }} +{{- end }} diff --git a/venonactl/pkg/templates/kubernetes/templates.go b/venonactl/pkg/templates/kubernetes/templates.go new file mode 100644 index 00000000..72868a92 --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/templates.go @@ -0,0 +1,1155 @@ +// Code generated by go generate; DO NOT EDIT. +// using data from templates/kubernetes +package kubernetes + +func TemplatesMap() map[string]string { + templatesMap := make(map[string]string) + + templatesMap["cluster-role-binding.app-proxy.yaml"] = `{{- if .CreateRbac }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .AppProxy.AppName }}-cluster-reader-{{ .Namespace }} +subjects: +- kind: ServiceAccount + name: {{ .AppProxy.AppName }} # this service account can get secrets cluster-wide (all namespaces) + namespace: {{ .Namespace }} +roleRef: + kind: ClusterRole + name: {{ .AppProxy.AppName }}-cluster-reader-{{ .Namespace }} + apiGroup: rbac.authorization.k8s.io +{{- end }}` + + templatesMap["cluster-role-binding.dind-volume-provisioner.vp.yaml"] = `{{- if .CreateRbac }} +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: volume-provisioner-{{ .AppName }}-{{ .Namespace }} + labels: + app: dind-volume-provisioner-{{ .AppName }} +subjects: + - kind: ServiceAccount + name: volume-provisioner-{{ .AppName }} + namespace: {{ .Namespace }} +roleRef: + kind: ClusterRole + name: volume-provisioner-{{ .AppName }}-{{ .Namespace }} + apiGroup: rbac.authorization.k8s.io +{{- end }}` + + templatesMap["cluster-role-binding.venona.yaml"] = `{{- if .CreateRbac }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .AppName }}-{{ .Namespace }} +subjects: +- kind: ServiceAccount + name: {{ .AppName }} + namespace: {{ .Namespace }} +roleRef: + kind: ClusterRole + name: system:discovery + apiGroup: rbac.authorization.k8s.io +{{- end }}` + + templatesMap["cluster-role.app-proxy.yaml"] = `{{- if .CreateRbac }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .AppProxy.AppName }}-cluster-reader-{{ .Namespace }} + labels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get"] +{{- end }}` + + templatesMap["cluster-role.dind-volume-provisioner.vp.yaml"] = `{{- if .CreateRbac }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: volume-provisioner-{{ .AppName }}-{{ .Namespace }} + labels: + app: dind-volume-provisioner +rules: + - apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch", "create", "delete", "patch"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch", "update", "delete"] + - apiGroups: ["storage.k8s.io"] + resources: ["storageclasses"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["list", "watch", "create", "update", "patch"] + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch", "create", "delete", "patch"] + - apiGroups: [""] + resources: ["endpoints"] + verbs: ["get", "list", "watch", "create", "update", "delete"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "create", "update"] +{{- end }}` + + templatesMap["codefresh-certs-server-secret.re.yaml"] = `apiVersion: v1 +type: Opaque +kind: Secret +metadata: + labels: + app: venona + name: codefresh-certs-server + namespace: {{ .Namespace }} +data: + server-cert.pem: {{ .ServerCert.Cert }} + server-key.pem: {{ .ServerCert.Key }} + ca.pem: {{ .ServerCert.Ca }} + +` + + templatesMap["cron-job.dind-volume-cleanup.vp.yaml"] = `{{- if not (eq .Storage.Backend "local") }} +apiVersion: batch/v1beta1 +kind: CronJob +metadata: + name: dind-volume-cleanup-{{ .AppName }} + namespace: {{ .Namespace }} + labels: + app: dind-volume-cleanup +spec: + schedule: "0,10,20,30,40,50 * * * *" + concurrencyPolicy: Forbid + {{- if eq .Storage.Backend "local" }} + suspend: true + {{- end }} + jobTemplate: + spec: + template: + spec: + serviceAccountName: volume-provisioner-{{ .AppName }} + restartPolicy: Never + containers: + - name: dind-volume-cleanup + image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Storage.VolumeCleaner.Image.Name }}:{{ .Storage.VolumeCleaner.Image.Tag }} {{- else }}{{- .Storage.VolumeCleaner.Image.Name }}:{{ .Storage.VolumeCleaner.Image.Tag }} {{- end}} + env: + - name: PROVISIONED_BY + value: codefresh.io/dind-volume-provisioner-{{ .AppName }}-{{ .Namespace }} + securityContext: + fsGroup: 3000 + runAsGroup: 3000 + runAsUser: 3000 +{{- end }}` + + templatesMap["daemonset.dind-lv-monitor.vp.yaml"] = `{{- if eq .Storage.Backend "local" -}} +{{- $localVolumeParentDir := ( .Storage.LocalVolumeParentDir | default "/var/lib/codefresh/dind-volumes" ) }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: dind-lv-monitor-{{ .AppName }} + namespace: {{ .Namespace }} + labels: + app: dind-lv-monitor +spec: + selector: + matchLabels: + app: dind-lv-monitor + template: + metadata: + labels: + app: dind-lv-monitor + annotations: + prometheus_port: "9100" + prometheus_scrape: "true" + spec: + serviceAccountName: volume-provisioner-{{ .AppName }} + tolerations: + - key: 'codefresh/dind' + operator: 'Exists' + effect: 'NoSchedule' + +{{ toYaml .Tolerations | indent 8 | unescape}} + securityContext: + fsGroup: 1000 + initContainers: + - command: + - chown + - -R + - 1000:1000 + - /var/lib/codefresh/dind-volumes + image: alpine + imagePullPolicy: Always + name: fs-change-owner + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /var/lib/codefresh/dind-volumes + name: dind-volume-dir + containers: + - image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Storage.LocalVolumeMonitor.Image.Name }}:{{ .Storage.LocalVolumeMonitor.Image.Tag }} {{- else }}{{- .Storage.LocalVolumeMonitor.Image.Name }}:{{ .Storage.LocalVolumeMonitor.Image.Tag }} {{- end}} + name: lv-cleaner + resources: +{{ toYaml .Storage.LocalVolumeMonitor.Resources | indent 10 }} + imagePullPolicy: Always + command: + - /home/dind-volume-utils/bin/local-volumes-agent + env: + {{- if $.EnvVars }} + {{- range $key, $value := $.EnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: VOLUME_PARENT_DIR + value: {{ $localVolumeParentDir }} +# Debug: +# - name: DRY_RUN +# value: "1" +# - name: DEBUG +# value: "1" +# - name: SLEEP_INTERVAL +# value: "3" +# - name: LOG_DF_EVERY +# value: "60" +# - name: KB_USAGE_THRESHOLD +# value: "20" + + volumeMounts: + - mountPath: {{ $localVolumeParentDir }} + readOnly: false + name: dind-volume-dir + volumes: + - name: dind-volume-dir + hostPath: + path: {{ $localVolumeParentDir }} +{{- end -}} +` + + templatesMap["deployment.app-proxy.yaml"] = `apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} + name: {{ .AppProxy.AppName }} + namespace: {{ .Namespace }} +spec: + selector: + matchLabels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} + replicas: 1 + revisionHistoryLimit: 5 + strategy: + rollingUpdate: + maxSurge: 50% + maxUnavailable: 50% + type: RollingUpdate + template: + metadata: + labels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} + spec: + {{- if .CreateRbac }} + serviceAccountName: {{ .AppProxy.AppName }} + {{- end }} + containers: + - name: {{ .AppProxy.AppName }} + image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .AppProxy.Image.Name }}:{{ .AppProxy.Image.Tag }} {{- else }} {{- .AppProxy.Image.Name }}:{{ .AppProxy.Image.Tag }} {{- end}} + imagePullPolicy: Always + resources: +{{ toYaml .AppProxy.resources | indent 10 }} + env: + {{- if $.EnvVars }} + {{- range $key, $value := $.EnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + {{- if $.AppProxy.AdditionalEnvVars }} + {{- range $key, $value := $.AppProxy.AdditionalEnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + - name: PORT + value: "3000" + - name: CODEFRESH_HOST + value: {{ .CodefreshHost }} + {{ if .AppProxy.Ingress.PathPrefix }} + - name: API_PATH_PREFIX + value: {{ .AppProxy.Ingress.PathPrefix }} + {{ end }} + {{- if .NewRelicLicense }} + - name: NEWRELIC_LICENSE_KEY + {{- if isString .NewRelicLicense }} + value: {{ .NewRelicLicense }} + {{- else }} +{{ toYaml .NewRelicLicense | indent 12 }} + {{- end }} + {{- end }} + ports: + - containerPort: 3000 + protocol: TCP + readinessProbe: + httpGet: + path: /health + port: 3000 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 +` + + templatesMap["deployment.dind-volume-provisioner.vp.yaml"] = `apiVersion: apps/v1 +kind: Deployment +metadata: + name: dind-volume-provisioner-{{ .AppName }} + namespace: {{ .Namespace }} + labels: + app: dind-volume-provisioner +spec: + selector: + matchLabels: + app: dind-volume-provisioner + replicas: 1 + strategy: + type: Recreate + template: + metadata: + labels: + app: dind-volume-provisioner + spec: + {{ if .Storage.VolumeProvisioner.NodeSelector }} + nodeSelector: +{{ .Storage.VolumeProvisioner.NodeSelector | nodeSelectorParamToYaml | indent 8 | unescape}} + {{ end }} + serviceAccount: volume-provisioner-{{ .AppName }} + securityContext: + runAsUser: 3000 + runAsGroup: 3000 + fsGroup: 3000 + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + operator: "Exists" + +{{ toYaml .Tolerations | indent 8 | unescape}} + + containers: + - name: dind-volume-provisioner + resources: +{{ toYaml .Storage.VolumeProvisioner.Resources | indent 10 }} + image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Storage.VolumeProvisioner.Image }} {{- else }} {{- .Storage.VolumeProvisioner.Image }} {{- end}} + imagePullPolicy: Always + command: + - /usr/local/bin/dind-volume-provisioner + - -v=4 + - --resync-period=50s + env: + {{- if $.EnvVars }} + {{- range $key, $value := $.EnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + - name: PROVISIONER_NAME + value: codefresh.io/dind-volume-provisioner-{{ .AppName }}-{{ .Namespace }} + {{- if ne .DockerRegistry "" }} + - name: DOCKER_REGISTRY + value: {{ .DockerRegistry }} + {{- end }} + {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits }} + {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.CPU }} + - name: CREATE_DIND_LIMIT_CPU + value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.CPU }} + {{- end }} + {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.Memory }} + - name: CREATE_DIND_LIMIT_MEMORY + value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Limits.Memory }} + {{- end }} + {{- end }} + {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests }} + {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.CPU }} + - name: CREATE_DIND_REQUESTS_CPU + value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.CPU }} + {{- end }} + {{- if .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.Memory }} + - name: CREATE_DIND_REQUESTS_MEMORY + value: {{ .Storage.VolumeProvisioner.CreateDindVolDirResouces.Requests.Memory }} + {{- end }} + {{- end }} + {{- if .Storage.AwsAccessKeyId }} + - name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: dind-volume-provisioner-{{ .AppName }} + key: aws_access_key_id + {{- end }} + {{- if .Storage.AwsSecretAccessKey }} + - name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: dind-volume-provisioner-{{ .AppName }} + key: aws_secret_access_key + {{- end }} + {{- if .Storage.GoogleServiceAccount }} + - name: GOOGLE_APPLICATION_CREDENTIALS + value: /etc/dind-volume-provisioner/credentials/google-service-account.json + {{- end }} + {{- if .Storage.VolumeProvisioner.MountAzureJson }} + - name: AZURE_CREDENTIAL_FILE + value: "/etc/kubernetes/azure.json" + {{- end }} + volumeMounts: + {{- if .Storage.VolumeProvisioner.MountAzureJson }} + - name: azure-json + readOnly: true + mountPath: "/etc/kubernetes/azure.json" + {{- end }} + {{- if .Storage.GoogleServiceAccount }} + - name: credentials + readOnly: true + mountPath: "/etc/dind-volume-provisioner/credentials" + {{- end }} + volumes: + {{- if .Storage.VolumeProvisioner.MountAzureJson }} + - name: azure-json + hostPath: + path: /etc/kubernetes/azure.json + type: File + {{- end }} + {{- if .Storage.GoogleServiceAccount }} + - name: credentials + secret: + secretName: dind-volume-provisioner-{{ .AppName }} + {{- end }} +` + + templatesMap["deployment.monitor.yaml"] = `{{- if .Monitor.Enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Monitor.AppName }} + namespace: {{ .Namespace }} + labels: + app: {{ .AppName }} + version: {{ .Version }} +spec: + replicas: 1 + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 50% + maxSurge: 50% + selector: + matchLabels: + app: {{ .Monitor.AppName }} + template: + metadata: + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} + spec: + {{- if .Monitor.RbacEnabled}} + serviceAccountName: {{ .Monitor.AppName }} + {{- end }} + containers: + - name: {{ .Monitor.AppName }} + resources: +{{ toYaml .Monitor.resources | indent 10 }} + image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Monitor.Image.Name }}:{{ .Monitor.Image.Tag }} {{- else }} {{- .Monitor.Image.Name }}:{{ .Monitor.Image.Tag }} {{- end}} + imagePullPolicy: Always + env: + {{- if $.EnvVars }} + {{- range $key, $value := $.EnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + {{- if $.Monitor.AdditionalEnvVars }} + {{- range $key, $value := $.Monitor.AdditionalEnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + - name: SERVICE_NAME + value: {{ .Monitor.AppName }} + {{- if .Monitor.UseNamespaceWithRole }} + - name: ROLE_BINDING + value: "true" + {{- end }} + - name: PORT + value: "9020" + - name: API_TOKEN + value: {{ .Token }} + - name: CLUSTER_ID + value: {{ .ClusterId }} + - name: API_URL + value: {{ .CodefreshHost }}/api/k8s-monitor/events + - name: ACCOUNT_ID + value: user + - name: HELM3 + value: "{{ .Monitor.Helm3 }}" + - name: NAMESPACE + value: "{{ .Namespace }}" + - name: NODE_OPTIONS + value: "--max_old_space_size=4096" + ports: + - containerPort: 9020 + protocol: TCP + readinessProbe: + httpGet: + path: /api/ping + port: 9020 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 +{{- end }} +` + + templatesMap["deployment.venona.yaml"] = `apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: {{ .AppName }} + version: {{ .Version }} + name: {{ .AppName }} + namespace: {{ .Namespace }} +spec: + selector: + matchLabels: + app: {{ .AppName }} + version: {{ .Version }} + replicas: 1 + revisionHistoryLimit: 5 + strategy: + rollingUpdate: + maxSurge: 50% + maxUnavailable: 50% + type: RollingUpdate + template: + metadata: + labels: + app: {{ .AppName }} + version: {{ .Version }} + spec: + volumes: + - name: runnerconf + secret: + secretName: runnerconf + {{ if ne .NodeSelector "" }} + nodeSelector: +{{ .NodeSelector | nodeSelectorParamToYaml | indent 8 | unescape }} + {{ end }} + tolerations: +{{ toYaml .Tolerations | indent 8 | unescape }} + containers: + - env: + {{- if $.EnvVars }} + {{- range $key, $value := $.EnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + {{- if $.AdditionalEnvVars }} + {{- range $key, $value := $.AdditionalEnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + - name: SELF_DEPLOYMENT_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: CODEFRESH_TOKEN + valueFrom: + secretKeyRef: + name: {{ .AppName }} + key: codefresh.token + - name: CODEFRESH_HOST + value: {{ .CodefreshHost }} + - name: AGENT_MODE + value: {{ .Mode }} + - name: AGENT_NAME + value: {{ .AppName }} + - name: "AGENT_ID" + value: {{ .AgentId }} + - name: VENONA_CONFIG_DIR + value: "/etc/secrets" + {{- if ne .DockerRegistry "" }} + - name: DOCKER_REGISTRY + value: {{ .DockerRegistry }} + {{- end }} + {{- if .NewRelicLicense }} + - name: NEWRELIC_LICENSE_KEY + {{- if isString .NewRelicLicense }} + value: {{ .NewRelicLicense }} + {{- else }} +{{ toYaml .NewRelicLicense | indent 10}} + {{- end }} + {{- end }} + image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .Image.Name }} {{- else }} {{- .Image.Name }}{{- end}}:{{ .Image.Tag | default "latest"}} + ports: + - containerPort: 8080 + protocol: TCP + readinessProbe: + httpGet: + path: /health + port: 8080 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + volumeMounts: + - name: runnerconf + mountPath: "/etc/secrets" + readOnly: true + imagePullPolicy: Always + name: {{ .AppName }} + resources: +{{ toYaml .Runner.Resources | indent 10 }} + securityContext: + runAsUser: 10001 + runAsGroup: 10001 + fsGroup: 10001 + restartPolicy: Always +` + + templatesMap["dind-daemon-conf.re.yaml"] = `--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: codefresh-dind-config + namespace: {{ .Namespace }} +data: + daemon.json: | + { + "hosts": [ "unix:///var/run/docker.sock", + "tcp://0.0.0.0:1300"], + "tlsverify": true, + "tls": true, + "tlscacert": "/etc/ssl/cf-client/ca.pem", + "tlscert": "/etc/ssl/cf/server-cert.pem", + "tlskey": "/etc/ssl/cf/server-key.pem", + "insecure-registries" : ["192.168.99.100:5000"], + "metrics-addr" : "0.0.0.0:9323", + "experimental" : true + } +` + + templatesMap["dind-headless-service.re.yaml"] = `--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: dind + name: dind + namespace: {{ .Namespace }} +spec: + ports: + - name: "dind-port" + port: 1300 + protocol: TCP + + # This is a headless service, Kubernetes won't assign a VIP for it. + # *.dind.default.svc.cluster.local + clusterIP: None + selector: + app: dind + +` + + templatesMap["ingress.app-proxy.yaml"] = `apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + {{ range $key, $value := .AppProxy.Ingress.Annotations }} + {{ $key }}: {{ $value | quote | unescape }} + {{ end }} + name: app-proxy + namespace: {{ .Namespace }} +spec: + {{ if ne .AppProxy.Ingress.IngressClass "" }} + ingressClassName: {{ .AppProxy.Ingress.IngressClass }} + {{ end }} + rules: + - host: {{ .AppProxy.Ingress.Host }} + http: + paths: + - path: {{ if .AppProxy.Ingress.PathPrefix }}{{ .AppProxy.Ingress.PathPrefix }}{{ else }}'/'{{end}} + pathType: ImplementationSpecific + backend: + service: + name: app-proxy + port: + number: 80 + {{ if .AppProxy.Ingress.TLSSecret }} + tls: + - hosts: + - {{ .AppProxy.Ingress.Host }} + secretName: {{ .AppProxy.Ingress.TLSSecret }} + {{ end }} +` + + templatesMap["pod.network-tester.yaml"] = `apiVersion: v1 +kind: Pod +metadata: + name: {{ .NetworkTester.PodName }} + namespace: {{ .Namespace }} + labels: + app: {{ .AppName }} + version: {{ .Version }} +spec: + containers: + - name: {{ .NetworkTester.PodName }} + image: {{ if ne .DockerRegistry ""}} {{- .DockerRegistry }}/{{ .NetworkTester.Image.Name }}:{{ .NetworkTester.Image.Tag }} {{- else }} {{- .NetworkTester.Image.Name }}:{{ .NetworkTester.Image.Tag }} {{- end}} + imagePullPolicy: Always + restartPolicy: Never + resources: + limits: + cpu: 400m + memory: 500Mi + requests: + cpu: 200m + memory: 300Mi + env: + {{- if $.EnvVars }} + {{- range $key, $value := $.EnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + {{- if $.NetworkTester.AdditionalEnvVars }} + {{- range $key, $value := $.NetworkTester.AdditionalEnvVars }} + - name: {{ $key }} + value: "{{ $value}}" + {{- end}} + {{- end}} + {{- if .Verbose }} + - name: DEBUG + value: '1' + {{- end }} + {{- if .Insecure }} + - name: INSECURE + value: '1' + {{- end }} + - name: IN_CLUSTER + value: '1'` + + templatesMap["role-binding.engine.yaml"] = `{{- if .CreateRbac }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Runtime.EngineAppName }} + namespace: {{ .Namespace }} +subjects: +- kind: ServiceAccount + name: {{ .Runtime.EngineAppName }} + namespace: {{ .Namespace }} +roleRef: + kind: Role + name: {{ .Runtime.EngineAppName }} + apiGroup: rbac.authorization.k8s.io +{{- end }}` + + templatesMap["role-binding.re.yaml"] = `{{- if .CreateRbac }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .AppName }} + namespace: {{ .Namespace }} +subjects: +- kind: ServiceAccount + name: {{ .AppName }} + namespace: {{ .Namespace }} +roleRef: + kind: Role + name: {{ .AppName }} + apiGroup: rbac.authorization.k8s.io +{{- end }}` + + templatesMap["role.engine.yaml"] = `{{- if .CreateRbac }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Runtime.EngineAppName }} + namespace: {{ .Namespace }} +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get"] +{{- end }}` + + templatesMap["role.monitor.yaml"] = `{{- if .CreateRbac }} +{{- if and .Monitor.Enabled .Monitor.RbacEnabled }} +{{- if .Monitor.UseNamespaceWithRole }} +kind: Role +{{- else }} +kind: ClusterRole +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Monitor.AppName }}-cluster-reader + namespace: {{ .Namespace }} + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} +rules: +- apiGroups: + - "" + resources: ["*"] + verbs: + - get + - list + - watch + - create + - delete +- apiGroups: + - "" + resources: ["pods"] + verbs: + - get + - list + - watch + - create + - deletecollection +- apiGroups: + - extensions + resources: ["*"] + verbs: + - get + - list + - watch +- apiGroups: + - apps + resources: ["*"] + verbs: + - get + - list + - watch +{{- end }} +{{- end }}` + + templatesMap["role.re.yaml"] = `{{- if .CreateRbac }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .AppName }} + namespace: {{ .Namespace }} +rules: +- apiGroups: [""] + resources: ["pods", "persistentvolumeclaims"] + verbs: ["get", "create", "delete"] +{{- end }}` + + templatesMap["rolebinding.monitor.yaml"] = `{{- if .CreateRbac }} +{{- if and .Monitor.Enabled .Monitor.RbacEnabled }} +{{- if .Monitor.UseNamespaceWithRole }} +kind: RoleBinding +{{- else }} +kind: ClusterRoleBinding +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Monitor.AppName }}-cluster-reader + namespace: {{ .Namespace }} + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} +subjects: +- kind: ServiceAccount + namespace: {{ .Namespace }} + name: {{ .Monitor.AppName }} +roleRef: + apiGroup: rbac.authorization.k8s.io + {{- if .Monitor.UseNamespaceWithRole }} + kind: Role + {{- else }} + kind: ClusterRole + {{- end }} + name: {{ .Monitor.AppName }}-cluster-reader +{{- end }} +{{- end }}` + + templatesMap["rollback-role-binding.monitor.yaml"] = `{{- if .CreateRbac }} +{{- if .Monitor.RbacEnabled }} +{{- if .Monitor.UseNamespaceWithRole }} +kind: RoleBinding +{{- else }} +kind: ClusterRoleBinding +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Monitor.AppName }}-rollback + namespace: {{ .Namespace }} + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} +subjects: + - kind: ServiceAccount + namespace: {{ .Namespace }} + name: {{ .Monitor.AppName }}-rollback +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin + {{- end }} +{{- end }}` + + templatesMap["rollback-serviceaccount.monitor.yaml"] = `{{- if .CreateRbac }} +{{- if and .Monitor.RbacEnabled (not .Monitor.UseNamespaceWithRole) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Monitor.AppName }}-rollback + namespace: {{ .Namespace }} + annotations: + {{ range $key, $value := .Monitor.ServiceAccount.Annotations }} + {{ $key }}: {{ $value }} + {{ end }} + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} +{{- end }} +{{- end }}` + + templatesMap["secret.dind-volume-provisioner.vp.yaml"] = `apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: dind-volume-provisioner-{{ .AppName }} + namespace: {{ .Namespace }} + labels: + app: dind-volume-provisioner +data: +{{- if .Storage.GoogleServiceAccount }} + google-service-account.json: {{ .Storage.GoogleServiceAccount | b64enc }} +{{- end }} +{{- if .Storage.AwsAccessKeyId }} + aws_access_key_id: {{ .Storage.AwsAccessKeyId | b64enc }} +{{- end }} +{{- if .Storage.AwsSecretAccessKey }} + aws_secret_access_key: {{ .Storage.AwsSecretAccessKey | b64enc }} +{{- end }}` + + templatesMap["secret.runtime-attach.yaml"] = `apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ .AppName }}conf + namespace: {{ .Namespace }} +data: +{{ range $key, $value := .runnerConf }} + {{ $key }}: {{ $value }} +{{ end }}` + + templatesMap["secret.venona.yaml"] = `apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ .AppName }} + namespace: {{ .Namespace }} +data: + codefresh.token: {{ .AgentToken | b64enc }}` + + templatesMap["service-account.app-proxy.yaml"] = `{{- if .CreateRbac }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .AppProxy.AppName }} + namespace: {{ .Namespace }} + annotations: + {{ range $key, $value := .AppProxy.ServiceAccount.Annotations }} + {{ $key }}: {{ $value | quote | unescape }} + {{ end }} + labels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} +{{- end }} +` + + templatesMap["service-account.dind-volume-provisioner.vp.yaml"] = `{{- if .CreateRbac }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: volume-provisioner-{{ .AppName }} + namespace: {{ .Namespace }} + annotations: + {{ range $key, $value := .Storage.VolumeProvisioner.ServiceAccount.Annotations }} + {{ $key }}: {{ $value }} + {{ end }} + labels: + app: dind-volume-provisioner +{{- end }}` + + templatesMap["service-account.engine.yaml"] = `{{- if .CreateRbac }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Runtime.EngineAppName }} + namespace: {{ .Namespace }} + annotations: + {{ range $key, $value := .Runtime.ServiceAccount.Annotations }} + {{ $key }}: {{ $value }} + {{ end }} + labels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} +{{- end }} +` + + templatesMap["service-account.monitor.yaml"] = `{{- if .CreateRbac }} +{{- if and .Monitor.Enabled .Monitor.RbacEnabled }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Monitor.AppName }} + namespace: {{ .Namespace }} + annotations: + {{ range $key, $value := .Monitor.ServiceAccount.Annotations }} + {{ $key }}: {{ $value }} + {{ end }} + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} +{{- end }} +{{- end }} +` + + templatesMap["service-account.re.yaml"] = `{{- if .CreateRbac }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .AppName }} + namespace: {{ .Namespace }} +{{- end }}` + + templatesMap["service.app-proxy.yaml"] = `apiVersion: v1 +kind: Service +metadata: + name: app-proxy + namespace: {{ .Namespace }} + labels: + app: {{ .AppProxy.AppName }} + version: {{ .Version }} +spec: + selector: + app: {{ .AppProxy.AppName }} + ports: + - protocol: TCP + port: 80 + targetPort: 3000 +` + + templatesMap["service.monitor.yaml"] = `{{- if .CreateRbac }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Monitor.AppName }} + namespace: {{ .Namespace }} + labels: + app: {{ .Monitor.AppName }} + version: {{ .Version }} +spec: + type: ClusterIP + ports: + - name: "http" + port: 80 + protocol: TCP + targetPort: 9020 + selector: + app: {{ .Monitor.AppName }} +{{- end }} +` + + templatesMap["storageclass.dind-volume-provisioner.vp.yaml"] = `{{- if .Storage.CreateStorageClass }} +--- +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: {{ .Storage.StorageClassName }} + labels: + app: dind-volume-provisioner + annotations: + {{ range $key, $value := .Storage.Annotations }} + {{ $key }}: {{ $value }} + {{ end }} +provisioner: codefresh.io/dind-volume-provisioner-{{ .AppName }}-{{ .Namespace }} +parameters: +{{- if eq .Storage.Backend "local" }} + volumeBackend: local + volumeParentDir: {{ .Storage.LocalVolumeParentDir | default "/var/lib/codefresh/dind-volumes" }} +{{- else if eq .Storage.Backend "gcedisk" }} + volumeBackend: {{ .Storage.Backend }} + # pd-ssd or pd-standard + type: {{ .Storage.VolumeType | default "pd-ssd" }} + # Valid zone in GCP + zone: {{ .Storage.AvailabilityZone }} + # ext4 or xfs (default to ext4 because xfs is not installed on GKE by default ) + fsType: {{ .Storage.FsType | default "ext4" }} +{{- else if or (eq .Storage.Backend "ebs") (eq .Storage.Backend "ebs-csi")}} + # ebs or ebs-csi + volumeBackend: {{ .Storage.Backend }} + # gp2 or io1 + VolumeType: {{ .Storage.VolumeType | default "gp2" }} + # Valid zone in aws (us-east-1c, ...) + AvailabilityZone: {{ .Storage.AvailabilityZone }} + # ext4 or xfs (default to ext4 ) + fsType: {{ .Storage.FsType | default "ext4" }} + + # "true" or "false" (default - "false") + encrypted: "{{ .Storage.Encrypted | default "false" }}" + {{ if .Storage.KmsKeyId }} + # KMS Key ID + kmsKeyId: {{ .Storage.KmsKeyId }} + {{- end }} +{{- else if or (eq .Storage.Backend "azuredisk") (eq .Storage.Backend "azuredisk-csi")}} + ## azuredisk or azuredisk-csi + volumeBackend: {{ .Storage.Backend }} + + kind: managed + skuName: {{ .Storage.SkuName | default "Premium_LRS" }} + fsType: {{ .Storage.FsType | default "ext4" }} + cachingMode: {{ .Storage.CachingMode | default "None" }} + {{- if .Storage.AzureLocation }} + location: {{ .Storage.AzureLocation }} + {{- end }} + {{- if .Storage.AzureResourceGroup }} + resourceGroup: {{ .Storage.AzureResourceGroup }} + {{- end }} +{{- end }} +{{- end }} +` + + templatesMap["venonaconf.secret.venona.yaml"] = `apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ .AppName }}conf + namespace: {{ .Namespace }} +data: +{{ range $key, $value := .runnerConf }} + {{ $key }}: {{ $value }} +{{ end }}` + + return templatesMap +} diff --git a/venonactl/pkg/templates/kubernetes/venonaconf.secret.venona.yaml b/venonactl/pkg/templates/kubernetes/venonaconf.secret.venona.yaml new file mode 100644 index 00000000..26f0821e --- /dev/null +++ b/venonactl/pkg/templates/kubernetes/venonaconf.secret.venona.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ .AppName }}conf + namespace: {{ .Namespace }} +data: +{{ range $key, $value := .runnerConf }} + {{ $key }}: {{ $value }} +{{ end }} \ No newline at end of file From f61a81d62634b4f8538df5cd02510a55692ce81a Mon Sep 17 00:00:00 2001 From: Zhenya Tikhonov Date: Thu, 18 Sep 2025 13:13:30 +0400 Subject: [PATCH 4/4] ci: trigger ci