Initial commit
Change-Id: Iac0a2e0b278431d53645acafac5556e492f2fbb0 Signed-off-by: Ruslan Aliev <raliev@mirantis.com>
This commit is contained in:
parent
08fc332aa7
commit
165edb9133
3
.dockerignore
Normal file
3
.dockerignore
Normal file
@ -0,0 +1,3 @@
|
||||
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
|
||||
# Ignore build and test binaries.
|
||||
bin/
|
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
bin/*
|
||||
Dockerfile.cross
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Kubernetes Generated files - skip generated files, except for vendored files
|
||||
|
||||
!vendor/**/zz_generated.*
|
||||
|
||||
# editor and IDE paraphernalia
|
||||
.idea
|
||||
.vscode
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
89
.zuul.yaml
Normal file
89
.zuul.yaml
Normal file
@ -0,0 +1,89 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
- project:
|
||||
check:
|
||||
jobs:
|
||||
- armada-operator-docker-build-gate-ubuntu_focal
|
||||
|
||||
gate:
|
||||
jobs:
|
||||
- armada-operator-docker-build-gate-ubuntu_focal
|
||||
|
||||
post:
|
||||
jobs:
|
||||
- armada-operator-docker-publish-ubuntu_focal
|
||||
|
||||
|
||||
- nodeset:
|
||||
name: armada-operator-single-node-focal
|
||||
nodes:
|
||||
- name: primary
|
||||
label: ubuntu-focal
|
||||
|
||||
|
||||
- job:
|
||||
name: armada-operator-docker-build-gate-ubuntu_focal
|
||||
timeout: 3600
|
||||
run: tools/gate/playbooks/docker-image-build.yaml
|
||||
nodeset: armada-single-node-focal
|
||||
vars:
|
||||
publish: false
|
||||
distro: ubuntu_focal
|
||||
tags:
|
||||
dynamic:
|
||||
patch_set: true
|
||||
|
||||
|
||||
- job:
|
||||
name: armada-operator-docker-publish-ubuntu_focal
|
||||
timeout: 3600
|
||||
run: tools/gate/playbooks/docker-image-build.yaml
|
||||
nodeset: armada-single-node-focal
|
||||
secrets:
|
||||
- airship_armada_operator_quay_creds
|
||||
vars:
|
||||
publish: true
|
||||
distro: ubuntu_focal
|
||||
tags:
|
||||
dynamic:
|
||||
branch: true
|
||||
commit: true
|
||||
static:
|
||||
- latest
|
||||
|
||||
|
||||
- secret:
|
||||
name: airship_armada_operator_quay_creds
|
||||
data:
|
||||
username: !encrypted/pkcs1-oaep
|
||||
- DjQA+Mkrg0oNfTcPFBCOwx0K+B7LsV9ceV7MK9C83sZDKUC5aKfhdn/myvKQKunIth4B8
|
||||
y++q+ano+rk3fteyT5hAT73e59koN0EkHrMknqdm8C0AMXoGJ2ktZFwho0ehzj8WX43hW
|
||||
67cWRYUHImOxuUn9oaMT11ZrDCBbAz1gKLRGPgtiYaEnKjaksiAcaBY1xIIjvr+DFbBZ3
|
||||
CmZ39EKRwhJxfGBA7nKbC4fFTQpR9GQD6SBR5kz8J6nIzeywJ4KQQEoICb9kwa0y4us0D
|
||||
efxej72cEI31FXGeV9Hm6YpaKSBL/Ko67rrBU2P8+kdqtI5mTKyj97yMwEMqPn6E2RkQZ
|
||||
44l9OAOSJIYtHQyvdCfpoYhzojZRabpcKkgB1Lq///ysmRdDWA3CBTurIyR8zjJdGreaY
|
||||
DYiWFen50tlAgRwewWgWEIqPnmEKYCGKLF5BAK49NQWkcr/2d+TQLcyE7IYWJtp1VEHnb
|
||||
8t8gzvhwWcR0AKmxOMGO/TUuBw70nCl5FUl/lxBFVvlQS0eGM8ZcDvs3survIgjmHsyyI
|
||||
6LGuB6Yh+Qbw+YmBxSsp75mm9D+v0mFtdxCgs9JMTPFI3d40CGhDbAXfCYHqTrh71pSCq
|
||||
a+ZWtixKOqhmIY6T9QCyFvBPB2ozQbmfgIlrRcs5pcNzO/xQfGf8JDiIceG7nE=
|
||||
password: !encrypted/pkcs1-oaep
|
||||
- c3cKJlMVv6mXnkCPPVyfJ9Vra140TOZKIK041eaajHnqoxR+R2sI50PrvF3r0rqnCJ4hs
|
||||
955XM9Idk5Y6urkkg5XAPDXLU7scBwN/WxO6KWadwtoxSFgn3sF/bctE55m18PZakUo3u
|
||||
oB05pBRlS0NITf6PCvwi0CphJbJEayVsPuNGP2EqP5WJ8xOrRu48SiuOlF0UuTA05oCta
|
||||
oYMG691bTt8EdDawaVpqtDcOcGEEqjXfizCoTiZhSYbtU8u86QXysdhKTFkPZiVd5kKiH
|
||||
q3zKLH3DEjK2XdSv4vouarmgKFymJ1+1hfUdfR2zNiJDM7a1YjEkOKlC+MaTBbjaoL7TF
|
||||
DfYgBkef10U+pp8VpM+zaU8/nJgeAn1rJzEm6IbYqW8Cd6N7IC1qLPU8GG1d0QtrYy7FP
|
||||
xr/5aAtiGFQ9dyUuwqBgNGngu5RXKJdnXD0yaUQ2Ptju5fwUo/vnQId/K+L8KIOjjRd9h
|
||||
SYsOer9caZOZ8Sin7udDzH/L/yFQQeu/HCZqWNtMJR49a2TvI31v75TtoY2Z2JhkEIGs7
|
||||
PryaAxEZywk1xP701FLFsdIWPbpvu+TElNnbEc+dI6HXtdpV6hArHI1LY0qplLtNV7c/g
|
||||
GRXIKFyn7yVMpdRMt9i+IncN2m/xskSIn4IOgcLbTD4giFDE2ZBdpEareD4kEA=
|
239
Makefile
Normal file
239
Makefile
Normal file
@ -0,0 +1,239 @@
|
||||
# APP INFO
|
||||
BUILD_DIR := $(shell mktemp -d)
|
||||
DOCKER_REGISTRY ?= quay.io
|
||||
IMAGE_PREFIX ?= airshipit
|
||||
IMAGE_NAME ?= armada-operator
|
||||
IMAGE_TAG ?= latest
|
||||
PROXY ?= http://proxy.foo.com:8000
|
||||
NO_PROXY ?= localhost,127.0.0.1,.svc.cluster.local
|
||||
USE_PROXY ?= false
|
||||
PUSH_IMAGE ?= false
|
||||
# use this variable for image labels added in internal build process
|
||||
LABEL ?= org.airshipit.build=community
|
||||
COMMIT ?= $(shell git rev-parse HEAD)
|
||||
PYTHON = python3
|
||||
CHARTS := $(filter-out deps, $(patsubst charts/%/.,%,$(wildcard charts/*/.)))
|
||||
DISTRO ?= ubuntu_focal
|
||||
IMAGE := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${IMAGE_NAME}:${IMAGE_TAG}-${DISTRO}
|
||||
UBUNTU_BASE_IMAGE ?=
|
||||
|
||||
# VERSION INFO
|
||||
GIT_COMMIT = $(shell git rev-parse HEAD)
|
||||
GIT_SHA = $(shell git rev-parse --short HEAD)
|
||||
GIT_TAG = $(shell git describe --tags --abbrev=0 --exact-match 2>/dev/null)
|
||||
GIT_DIRTY = $(shell test -n "`git status --porcelain`" && echo "dirty" || echo "clean")
|
||||
|
||||
ifdef VERSION
|
||||
DOCKER_VERSION = $(VERSION)
|
||||
endif
|
||||
|
||||
SHELL = /bin/bash
|
||||
|
||||
info:
|
||||
@echo "Version: ${VERSION}"
|
||||
@echo "Git Tag: ${GIT_TAG}"
|
||||
@echo "Git Commit: ${GIT_COMMIT}"
|
||||
@echo "Git Tree State: ${GIT_DIRTY}"
|
||||
@echo "Docker Version: ${DOCKER_VERSION}"
|
||||
@echo "Registry: ${DOCKER_REGISTRY}"
|
||||
# Image URL to use all building/pushing image targets
|
||||
IMG ?= quay.io/airshipit/armada-operator:latest
|
||||
#IMG ?= docker-open-nc.zc1.cti.att.com/upstream-local/raliev12/armada-controller:latest
|
||||
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
|
||||
ENVTEST_K8S_VERSION = 1.28.0
|
||||
|
||||
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
|
||||
ifeq (,$(shell go env GOBIN))
|
||||
GOBIN=$(shell go env GOPATH)/bin
|
||||
else
|
||||
GOBIN=$(shell go env GOBIN)
|
||||
endif
|
||||
|
||||
# CONTAINER_TOOL defines the container tool to be used for building images.
|
||||
# Be aware that the target commands are only tested with Docker which is
|
||||
# scaffolded by default. However, you might want to replace it to use other
|
||||
# tools. (i.e. podman)
|
||||
CONTAINER_TOOL ?= docker
|
||||
|
||||
# Setting SHELL to bash allows bash commands to be executed by recipes.
|
||||
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
|
||||
SHELL = /usr/bin/env bash -o pipefail
|
||||
.SHELLFLAGS = -ec
|
||||
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
||||
##@ General
|
||||
|
||||
# The help target prints out all targets with their descriptions organized
|
||||
# beneath their categories. The categories are represented by '##@' and the
|
||||
# target descriptions by '##'. The awk command is responsible for reading the
|
||||
# entire set of makefiles included in this invocation, looking for lines of the
|
||||
# file as xyz: ## something, and then pretty-format the target and help. Then,
|
||||
# if there's a line with ##@ something, that gets pretty-printed as a category.
|
||||
# More info on the usage of ANSI control characters for terminal formatting:
|
||||
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
|
||||
# More info on the awk command:
|
||||
# http://linuxcommand.org/lc3_adv_awk.php
|
||||
|
||||
.PHONY: help
|
||||
help: ## Display this help.
|
||||
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
||||
|
||||
##@ Development
|
||||
|
||||
.PHONY: manifests
|
||||
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
|
||||
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
|
||||
|
||||
.PHONY: generate
|
||||
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
|
||||
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
|
||||
|
||||
.PHONY: fmt
|
||||
fmt: ## Run go fmt against code.
|
||||
go fmt ./...
|
||||
|
||||
.PHONY: vet
|
||||
vet: ## Run go vet against code.
|
||||
go vet ./...
|
||||
|
||||
.PHONY: test
|
||||
test: manifests generate fmt vet envtest ## Run tests.
|
||||
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out
|
||||
|
||||
##@ Build
|
||||
|
||||
.PHONY: build
|
||||
build: manifests generate fmt vet ## Build manager binary.
|
||||
go build -o bin/manager cmd/main.go
|
||||
|
||||
.PHONY: run
|
||||
run: manifests generate fmt vet ## Run a controller from your host.
|
||||
go run ./cmd/main.go
|
||||
|
||||
# If you wish to build the manager image targeting other platforms you can use the --platform flag.
|
||||
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
|
||||
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
|
||||
.PHONY: docker-build
|
||||
docker-build: ## Build docker image with the manager.
|
||||
$(CONTAINER_TOOL) build -t ${IMG} .
|
||||
|
||||
.PHONY: docker-push
|
||||
docker-push: ## Push docker image with the manager.
|
||||
$(CONTAINER_TOOL) push ${IMG}
|
||||
|
||||
# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
|
||||
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
|
||||
# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
|
||||
# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
|
||||
# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=<myregistry/image:<tag>> then the export will fail)
|
||||
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
|
||||
PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
|
||||
.PHONY: docker-buildx
|
||||
docker-buildx: ## Build and push docker image for the manager for cross-platform support
|
||||
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
|
||||
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
|
||||
- $(CONTAINER_TOOL) buildx create --name project-v3-builder
|
||||
$(CONTAINER_TOOL) buildx use project-v3-builder
|
||||
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
|
||||
- $(CONTAINER_TOOL) buildx rm project-v3-builder
|
||||
rm Dockerfile.cross
|
||||
|
||||
check-docker:
|
||||
@if [ -z $$(which docker) ]; then \
|
||||
echo "Missing \`docker\` client which is required for development"; \
|
||||
exit 2; \
|
||||
fi
|
||||
|
||||
images: check-docker build_armada_operator
|
||||
|
||||
_BASE_IMAGE_ARG := $(if $(UBUNTU_BASE_IMAGE),--build-arg FROM="${UBUNTU_BASE_IMAGE}" ,)
|
||||
|
||||
build_armada_operator:
|
||||
ifeq ($(USE_PROXY), true)
|
||||
docker build --network host -t $(IMAGE) --label $(LABEL) \
|
||||
--label "org.opencontainers.image.revision=$(COMMIT)" \
|
||||
--label "org.opencontainers.image.created=$(shell date --rfc-3339=seconds --utc)" \
|
||||
--label "org.opencontainers.image.title=$(IMAGE_NAME)" \
|
||||
-f images/armada-operator/Dockerfile.$(DISTRO) \
|
||||
$(_BASE_IMAGE_ARG) \
|
||||
--build-arg HELM_ARTIFACT_URL=$(HELM_ARTIFACT_URL) \
|
||||
--build-arg http_proxy=$(PROXY) \
|
||||
--build-arg https_proxy=$(PROXY) \
|
||||
--build-arg HTTP_PROXY=$(PROXY) \
|
||||
--build-arg HTTPS_PROXY=$(PROXY) \
|
||||
--build-arg no_proxy=$(NO_PROXY) \
|
||||
--build-arg NO_PROXY=$(NO_PROXY) .
|
||||
else
|
||||
docker build --network host -t $(IMAGE) --label $(LABEL) \
|
||||
--label "org.opencontainers.image.revision=$(COMMIT)" \
|
||||
--label "org.opencontainers.image.created=$(shell date --rfc-3339=seconds --utc)" \
|
||||
--label "org.opencontainers.image.title=$(IMAGE_NAME)" \
|
||||
-f images/armada-operator/Dockerfile.$(DISTRO) \
|
||||
$(_BASE_IMAGE_ARG) \
|
||||
--build-arg HELM_ARTIFACT_URL=$(HELM_ARTIFACT_URL) .
|
||||
endif
|
||||
ifeq ($(PUSH_IMAGE), true)
|
||||
docker push $(IMAGE)
|
||||
endif
|
||||
|
||||
##@ Deployment
|
||||
|
||||
ifndef ignore-not-found
|
||||
ignore-not-found = false
|
||||
endif
|
||||
|
||||
.PHONY: install
|
||||
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
|
||||
$(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f -
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
|
||||
$(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
|
||||
|
||||
.PHONY: deploy
|
||||
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
|
||||
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
|
||||
$(KUSTOMIZE) build config/default | $(KUBECTL) apply -f -
|
||||
|
||||
.PHONY: undeploy
|
||||
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
|
||||
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
|
||||
|
||||
##@ Build Dependencies
|
||||
|
||||
## Location to install dependencies to
|
||||
LOCALBIN ?= $(shell pwd)/bin
|
||||
$(LOCALBIN):
|
||||
mkdir -p $(LOCALBIN)
|
||||
|
||||
## Tool Binaries
|
||||
KUBECTL ?= kubectl
|
||||
KUSTOMIZE ?= $(LOCALBIN)/kustomize
|
||||
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
|
||||
ENVTEST ?= $(LOCALBIN)/setup-envtest
|
||||
|
||||
## Tool Versions
|
||||
KUSTOMIZE_VERSION ?= v5.1.1
|
||||
CONTROLLER_TOOLS_VERSION ?= v0.13.0
|
||||
|
||||
.PHONY: kustomize
|
||||
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading.
|
||||
$(KUSTOMIZE): $(LOCALBIN)
|
||||
@if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q $(KUSTOMIZE_VERSION); then \
|
||||
echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \
|
||||
rm -rf $(LOCALBIN)/kustomize; \
|
||||
fi
|
||||
test -s $(LOCALBIN)/kustomize || GOBIN=$(LOCALBIN) GO111MODULE=on go install sigs.k8s.io/kustomize/kustomize/v5@$(KUSTOMIZE_VERSION)
|
||||
|
||||
.PHONY: controller-gen
|
||||
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten.
|
||||
$(CONTROLLER_GEN): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/controller-gen && $(LOCALBIN)/controller-gen --version | grep -q $(CONTROLLER_TOOLS_VERSION) || \
|
||||
GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)
|
||||
|
||||
.PHONY: envtest
|
||||
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
|
||||
$(ENVTEST): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
|
20
PROJECT
Normal file
20
PROJECT
Normal file
@ -0,0 +1,20 @@
|
||||
# Code generated by tool. DO NOT EDIT.
|
||||
# This file is used to track the info used to scaffold your project
|
||||
# and allow the plugins properly work.
|
||||
# More info: https://book.kubebuilder.io/reference/project-config.html
|
||||
domain: airshipit.org
|
||||
layout:
|
||||
- go.kubebuilder.io/v4
|
||||
projectName: armada-operator
|
||||
repo: opendev.org/airship/armada-operator
|
||||
resources:
|
||||
- api:
|
||||
crdVersion: v1
|
||||
namespaced: true
|
||||
controller: true
|
||||
domain: airshipit.org
|
||||
group: armada
|
||||
kind: ArmadaChart
|
||||
path: opendev.org/airship/armada-operator/api/v1
|
||||
version: v1
|
||||
version: "3"
|
94
README.md
Normal file
94
README.md
Normal file
@ -0,0 +1,94 @@
|
||||
# armada-operator
|
||||
|
||||
|
||||
## Description
|
||||
// TODO(user): An in-depth paragraph about your project and overview of use
|
||||
|
||||
## Getting Started
|
||||
You’ll need a Kubernetes cluster to run against. You can use [KIND](https://sigs.k8s.io/kind) to get a local cluster for testing, or run against a remote cluster.
|
||||
**Note:** Your controller will automatically use the current context in your kubeconfig file (i.e. whatever cluster `kubectl cluster-info` shows).
|
||||
|
||||
### Running on the cluster
|
||||
1. Install Instances of Custom Resources:
|
||||
|
||||
```sh
|
||||
kubectl apply -k config/samples/
|
||||
```
|
||||
|
||||
2. Build and push your image to the location specified by `IMG`:
|
||||
|
||||
```sh
|
||||
make docker-build docker-push IMG=<some-registry>/armada-operator:tag
|
||||
```
|
||||
|
||||
3. Deploy the controller to the cluster with the image specified by `IMG`:
|
||||
|
||||
```sh
|
||||
make deploy IMG=<some-registry>/armada-operator:tag
|
||||
```
|
||||
|
||||
### Uninstall CRDs
|
||||
To delete the CRDs from the cluster:
|
||||
|
||||
```sh
|
||||
make uninstall
|
||||
```
|
||||
|
||||
### Undeploy controller
|
||||
UnDeploy the controller from the cluster:
|
||||
|
||||
```sh
|
||||
make undeploy
|
||||
```
|
||||
|
||||
## Contributing
|
||||
// TODO(user): Add detailed information on how you would like others to contribute to this project
|
||||
|
||||
### How it works
|
||||
This project aims to follow the Kubernetes [Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/).
|
||||
|
||||
It uses [Controllers](https://kubernetes.io/docs/concepts/architecture/controller/),
|
||||
which provide a reconcile function responsible for synchronizing resources until the desired state is reached on the cluster.
|
||||
|
||||
### Test It Out
|
||||
1. Install the CRDs into the cluster:
|
||||
|
||||
```sh
|
||||
make install
|
||||
```
|
||||
|
||||
2. Run your controller (this will run in the foreground, so switch to a new terminal if you want to leave it running):
|
||||
|
||||
```sh
|
||||
make run
|
||||
```
|
||||
|
||||
**NOTE:** You can also run this in one step by running: `make install run`
|
||||
|
||||
### Modifying the API definitions
|
||||
If you are editing the API definitions, generate the manifests such as CRs or CRDs using:
|
||||
|
||||
```sh
|
||||
make manifests
|
||||
```
|
||||
|
||||
**NOTE:** Run `make --help` for more information on all potential `make` targets
|
||||
|
||||
More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html)
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2023.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
309
api/v1/armadachart_types.go
Normal file
309
api/v1/armadachart_types.go
Normal file
@ -0,0 +1,309 @@
|
||||
/*
|
||||
Copyright 2023.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
const ArmadaChartKind = "ArmadaChart"
|
||||
const ArmadaChartAPIVersion = "armada.airshipit.org/v1"
|
||||
const ArmadaChartPlural = "armadacharts"
|
||||
const ArmadaChartGroup = "armada.airshipit.org"
|
||||
const ArmadaChartVersion = "v1"
|
||||
const ArmadaChartLabel = "armada.airshipit.org/release-name"
|
||||
const ArmadaChartFinalizer = "finalizers.armada.airshipit.org"
|
||||
|
||||
const ReadyCondition string = "Ready"
|
||||
const ReconcilingCondition string = "Reconciling"
|
||||
const ProgressingReason string = "Progressing"
|
||||
|
||||
// ArmadaChartSpec defines the specification of ArmadaChart
|
||||
type ArmadaChartSpec struct {
|
||||
// ChartName is name of ArmadaChart
|
||||
ChartName string `json:"chart_name,omitempty"`
|
||||
// Namespace is a namespace for ArmadaChart
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
// Release is a name of corresponding Helm Release of ArmadaChart
|
||||
Release string `json:"release,omitempty"`
|
||||
|
||||
// Source is a source location of Helm Chart *.tgz
|
||||
Source ArmadaChartSource `json:"source,omitempty"`
|
||||
|
||||
// Values holds the values for this Helm release.
|
||||
// +optional
|
||||
Values *apiextensionsv1.JSON `json:"values,omitempty"`
|
||||
|
||||
// Wait holds the wait options for this Helm release.
|
||||
// +optional
|
||||
Wait ArmadaChartWait `json:"wait,omitempty"`
|
||||
|
||||
// Test holds the test parameters for this Helm release.
|
||||
// +optional
|
||||
Test ArmadaChartTestOptions `json:"test,omitempty"`
|
||||
|
||||
// Upgrade holds the upgrade options for this Helm release.
|
||||
// +optional
|
||||
Upgrade ArmadaChartUpgrade `json:"upgrade,omitempty"`
|
||||
}
|
||||
|
||||
// ArmadaChartSource defines the location options of Helm Release for ArmadaChart
|
||||
type ArmadaChartSource struct {
|
||||
Location string `json:"location,omitempty"`
|
||||
Subpath string `json:"subpath,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// ArmadaChartWait defines the wait options of ArmadaChart
|
||||
type ArmadaChartWait struct {
|
||||
// Timeout is the time to wait for full reconciliation of Helm release.
|
||||
// +optional
|
||||
Timeout int `json:"timeout,omitempty"`
|
||||
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
|
||||
// +optional
|
||||
ArmadaChartWaitResources []ArmadaChartWaitResource `json:"resources"`
|
||||
|
||||
// +optional
|
||||
Native *ArmadaChartWaitNative `json:"native,omitempty"`
|
||||
}
|
||||
|
||||
// ArmadaChartWaitResource defines the wait options of ArmadaChart
|
||||
type ArmadaChartWaitResource struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
|
||||
// +optional
|
||||
MinReady string `json:"min_ready,omitempty"`
|
||||
}
|
||||
|
||||
type ArmadaChartUpgrade struct {
|
||||
PreUpgrade ArmadaChartPreUpgrade `json:"pre,omitempty"`
|
||||
}
|
||||
|
||||
type ArmadaChartPreUpgrade struct {
|
||||
Delete []ArmadaChartDeleteResource `json:"delete,omitempty"`
|
||||
}
|
||||
|
||||
// ArmadaChartDeleteResource defines the delete options of ArmadaChart
|
||||
type ArmadaChartDeleteResource struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
// ArmadaChartWaitNative defines the wait options of ArmadaChart
|
||||
type ArmadaChartWaitNative struct {
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
}
|
||||
|
||||
// ArmadaChartTestOptions defines the test options of ArmadaChart
|
||||
type ArmadaChartTestOptions struct {
|
||||
// Enabled is an example field of ArmadaChart. Edit armadachart_types.go to remove/update
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
}
|
||||
|
||||
// ArmadaChartStatus defines the observed state of ArmadaChart
|
||||
type ArmadaChartStatus struct {
|
||||
// ObservedGeneration is the last observed generation.
|
||||
// +optional
|
||||
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
|
||||
|
||||
// Conditions holds the conditions for the ArmadaChart.
|
||||
// +optional
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||
|
||||
// LastAppliedRevision is the revision of the last successfully applied source.
|
||||
// +optional
|
||||
LastAppliedRevision string `json:"lastAppliedRevision,omitempty"`
|
||||
|
||||
// LastAttemptedRevision is the revision of the last reconciliation attempt.
|
||||
// +optional
|
||||
LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"`
|
||||
|
||||
// LastAttemptedValuesChecksum is the SHA1 checksum of the values of the last
|
||||
// reconciliation attempt.
|
||||
// +optional
|
||||
LastAttemptedValuesChecksum string `json:"lastAttemptedValuesChecksum,omitempty"`
|
||||
|
||||
// LastReleaseRevision is the revision of the last successful Helm release.
|
||||
// +optional
|
||||
LastReleaseRevision int `json:"lastReleaseRevision,omitempty"`
|
||||
|
||||
// HelmChart is the namespaced name of the HelmChart resource created by
|
||||
// the controller for the ArmadaChart.
|
||||
// +optional
|
||||
HelmChart string `json:"helmChart,omitempty"`
|
||||
|
||||
// Failures is the reconciliation failure count against the latest desired
|
||||
// state. It is reset after a successful reconciliation.
|
||||
// +optional
|
||||
Failures int64 `json:"failures,omitempty"`
|
||||
|
||||
// InstallFailures is the install failure count against the latest desired
|
||||
// state. It is reset after a successful reconciliation.
|
||||
// +optional
|
||||
InstallFailures int64 `json:"installFailures,omitempty"`
|
||||
|
||||
// UpgradeFailures is the upgrade failure count against the latest desired
|
||||
// state. It is reset after a successful reconciliation.
|
||||
// +optional
|
||||
UpgradeFailures int64 `json:"upgradeFailures,omitempty"`
|
||||
|
||||
// Tested is the bool value whether the Helm Release was successfully
|
||||
// tested or not.
|
||||
// +optional
|
||||
Tested bool `json:"tested,omitempty"`
|
||||
}
|
||||
|
||||
// ArmadaChartProgressing resets any failures and registers progress toward
|
||||
// reconciling the given ArmadaChart by setting the ReadyCondition to
|
||||
// 'Unknown' for ProgressingReason.
|
||||
func ArmadaChartProgressing(ac ArmadaChart) ArmadaChart {
|
||||
ac.Status.Conditions = []metav1.Condition{}
|
||||
newCondition := metav1.Condition{
|
||||
Type: ReadyCondition,
|
||||
Status: metav1.ConditionUnknown,
|
||||
Reason: ProgressingReason,
|
||||
Message: "Reconciliation in progress",
|
||||
}
|
||||
apimeta.SetStatusCondition(ac.GetStatusConditions(), newCondition)
|
||||
resetFailureCounts(&ac)
|
||||
resetTested(&ac)
|
||||
return ac
|
||||
}
|
||||
|
||||
// ArmadaChartNotReady registers a failed reconciliation of the given ArmadaChart.
|
||||
func ArmadaChartNotReady(ac ArmadaChart, reason, message string) ArmadaChart {
|
||||
newCondition := metav1.Condition{
|
||||
Type: ReadyCondition,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: reason,
|
||||
Message: message,
|
||||
}
|
||||
apimeta.SetStatusCondition(ac.GetStatusConditions(), newCondition)
|
||||
ac.Status.Failures++
|
||||
resetTested(&ac)
|
||||
return ac
|
||||
}
|
||||
|
||||
// ArmadaChartReady registers a successful reconciliation of the given ArmadaChart.
|
||||
func ArmadaChartReady(ac ArmadaChart) ArmadaChart {
|
||||
newCondition := metav1.Condition{
|
||||
Type: ReadyCondition,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: "ReconciliationSucceeded",
|
||||
Message: "Release reconciliation succeeded",
|
||||
}
|
||||
apimeta.SetStatusCondition(ac.GetStatusConditions(), newCondition)
|
||||
ac.Status.LastAppliedRevision = ac.Status.LastAttemptedRevision
|
||||
resetFailureCounts(&ac)
|
||||
setTested(&ac)
|
||||
return ac
|
||||
}
|
||||
|
||||
func resetFailureCounts(hr *ArmadaChart) {
|
||||
hr.Status.Failures = 0
|
||||
hr.Status.InstallFailures = 0
|
||||
hr.Status.UpgradeFailures = 0
|
||||
}
|
||||
|
||||
func resetTested(hr *ArmadaChart) {
|
||||
hr.Status.Tested = false
|
||||
}
|
||||
|
||||
func setTested(hr *ArmadaChart) {
|
||||
hr.Status.Tested = true
|
||||
}
|
||||
|
||||
func NewForConfigOrDie(c *rest.Config) *rest.RESTClient {
|
||||
cs, err := NewForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return cs
|
||||
}
|
||||
|
||||
func NewForConfig(c *rest.Config) (*rest.RESTClient, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := rest.UnversionedRESTClientFor(&config)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func setConfigDefaults(config *rest.Config) error {
|
||||
gv := schema.GroupVersion{Group: ArmadaChartGroup, Version: ArmadaChartVersion}
|
||||
config.GroupVersion = &gv
|
||||
config.APIPath = "/apis"
|
||||
|
||||
sch := runtime.NewScheme()
|
||||
if err := AddToScheme(sch); err != nil {
|
||||
return err
|
||||
}
|
||||
sch.AddUnversionedTypes(gv, &ArmadaChart{}, &ArmadaChartList{})
|
||||
config.NegotiatedSerializer = serializer.NewCodecFactory(sch)
|
||||
|
||||
if config.UserAgent == "" {
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//+kubebuilder:object:root=true
|
||||
//+kubebuilder:subresource:status
|
||||
|
||||
// ArmadaChart is the Schema for the armadacharts API
|
||||
type ArmadaChart struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ArmadaChartSpec `json:"data,omitempty"`
|
||||
Status ArmadaChartStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// GetStatusConditions returns a pointer to the Status.Conditions slice.
|
||||
func (in *ArmadaChart) GetStatusConditions() *[]metav1.Condition {
|
||||
return &in.Status.Conditions
|
||||
}
|
||||
|
||||
//+kubebuilder:object:root=true
|
||||
|
||||
// ArmadaChartList contains a list of ArmadaChart
|
||||
type ArmadaChartList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []ArmadaChart `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&ArmadaChart{}, &ArmadaChartList{})
|
||||
}
|
36
api/v1/groupversion_info.go
Normal file
36
api/v1/groupversion_info.go
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
Copyright 2023.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package v1 contains API Schema definitions for the armada v1 API group
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=armada.airshipit.org
|
||||
package v1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/scheme"
|
||||
)
|
||||
|
||||
var (
|
||||
// GroupVersion is group version used to register these objects
|
||||
GroupVersion = schema.GroupVersion{Group: "armada.airshipit.org", Version: "v1"}
|
||||
|
||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
|
||||
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
|
||||
|
||||
// AddToScheme adds the types in this group-version to the given scheme.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
293
api/v1/zz_generated.deepcopy.go
Normal file
293
api/v1/zz_generated.deepcopy.go
Normal file
@ -0,0 +1,293 @@
|
||||
//go:build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2023.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by controller-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArmadaChart) DeepCopyInto(out *ArmadaChart) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArmadaChart.
|
||||
func (in *ArmadaChart) DeepCopy() *ArmadaChart {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArmadaChart)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ArmadaChart) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArmadaChartDeleteResource) DeepCopyInto(out *ArmadaChartDeleteResource) {
|
||||
*out = *in
|
||||
if in.Labels != nil {
|
||||
in, out := &in.Labels, &out.Labels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArmadaChartDeleteResource.
|
||||
func (in *ArmadaChartDeleteResource) DeepCopy() *ArmadaChartDeleteResource {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArmadaChartDeleteResource)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArmadaChartList) DeepCopyInto(out *ArmadaChartList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ArmadaChart, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArmadaChartList.
|
||||
func (in *ArmadaChartList) DeepCopy() *ArmadaChartList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArmadaChartList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ArmadaChartList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArmadaChartPreUpgrade) DeepCopyInto(out *ArmadaChartPreUpgrade) {
|
||||
*out = *in
|
||||
if in.Delete != nil {
|
||||
in, out := &in.Delete, &out.Delete
|
||||
*out = make([]ArmadaChartDeleteResource, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArmadaChartPreUpgrade.
|
||||
func (in *ArmadaChartPreUpgrade) DeepCopy() *ArmadaChartPreUpgrade {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArmadaChartPreUpgrade)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArmadaChartSource) DeepCopyInto(out *ArmadaChartSource) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArmadaChartSource.
|
||||
func (in *ArmadaChartSource) DeepCopy() *ArmadaChartSource {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArmadaChartSource)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArmadaChartSpec) DeepCopyInto(out *ArmadaChartSpec) {
|
||||
*out = *in
|
||||
out.Source = in.Source
|
||||
if in.Values != nil {
|
||||
in, out := &in.Values, &out.Values
|
||||
*out = new(apiextensionsv1.JSON)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
in.Wait.DeepCopyInto(&out.Wait)
|
||||
out.Test = in.Test
|
||||
in.Upgrade.DeepCopyInto(&out.Upgrade)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArmadaChartSpec.
|
||||
func (in *ArmadaChartSpec) DeepCopy() *ArmadaChartSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArmadaChartSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArmadaChartStatus) DeepCopyInto(out *ArmadaChartStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]metav1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArmadaChartStatus.
|
||||
func (in *ArmadaChartStatus) DeepCopy() *ArmadaChartStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArmadaChartStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArmadaChartTestOptions) DeepCopyInto(out *ArmadaChartTestOptions) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArmadaChartTestOptions.
|
||||
func (in *ArmadaChartTestOptions) DeepCopy() *ArmadaChartTestOptions {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArmadaChartTestOptions)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArmadaChartUpgrade) DeepCopyInto(out *ArmadaChartUpgrade) {
|
||||
*out = *in
|
||||
in.PreUpgrade.DeepCopyInto(&out.PreUpgrade)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArmadaChartUpgrade.
|
||||
func (in *ArmadaChartUpgrade) DeepCopy() *ArmadaChartUpgrade {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArmadaChartUpgrade)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArmadaChartWait) DeepCopyInto(out *ArmadaChartWait) {
|
||||
*out = *in
|
||||
if in.Labels != nil {
|
||||
in, out := &in.Labels, &out.Labels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.ArmadaChartWaitResources != nil {
|
||||
in, out := &in.ArmadaChartWaitResources, &out.ArmadaChartWaitResources
|
||||
*out = make([]ArmadaChartWaitResource, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Native != nil {
|
||||
in, out := &in.Native, &out.Native
|
||||
*out = new(ArmadaChartWaitNative)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArmadaChartWait.
|
||||
func (in *ArmadaChartWait) DeepCopy() *ArmadaChartWait {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArmadaChartWait)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArmadaChartWaitNative) DeepCopyInto(out *ArmadaChartWaitNative) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArmadaChartWaitNative.
|
||||
func (in *ArmadaChartWaitNative) DeepCopy() *ArmadaChartWaitNative {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArmadaChartWaitNative)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArmadaChartWaitResource) DeepCopyInto(out *ArmadaChartWaitResource) {
|
||||
*out = *in
|
||||
if in.Labels != nil {
|
||||
in, out := &in.Labels, &out.Labels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArmadaChartWaitResource.
|
||||
func (in *ArmadaChartWaitResource) DeepCopy() *ArmadaChartWaitResource {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArmadaChartWaitResource)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
138
cmd/main.go
Normal file
138
cmd/main.go
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
Copyright 2023.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||
// to ensure that exec-entrypoint and run can make use of them.
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
"k8s.io/klog/v2"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
ctrlcfg "sigs.k8s.io/controller-runtime/pkg/config"
|
||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||||
|
||||
armadav1 "opendev.org/airship/armada-operator/api/v1"
|
||||
"opendev.org/airship/armada-operator/internal/controller"
|
||||
//+kubebuilder:scaffold:imports
|
||||
)
|
||||
|
||||
var (
|
||||
scheme = runtime.NewScheme()
|
||||
setupLog = ctrl.Log.WithName("setup")
|
||||
)
|
||||
|
||||
func init() {
|
||||
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||
|
||||
utilruntime.Must(armadav1.AddToScheme(scheme))
|
||||
//+kubebuilder:scaffold:scheme
|
||||
}
|
||||
|
||||
func main() {
|
||||
var metricsAddr string
|
||||
var enableLeaderElection bool
|
||||
var probeAddr string
|
||||
var leaderElectNamespace string
|
||||
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
|
||||
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
|
||||
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
|
||||
"Enable leader election for controller manager. "+
|
||||
"Enabling this will ensure there is only one active controller manager.")
|
||||
flag.StringVar(&leaderElectNamespace, "leader-elect-namespace", "", "Specify leader election namespace")
|
||||
flag.StringVar(&leaderElectNamespace, "log-to-file", "", "Specify leader election namespace")
|
||||
opts := zap.Options{
|
||||
Development: true,
|
||||
}
|
||||
opts.BindFlags(flag.CommandLine)
|
||||
flag.Parse()
|
||||
|
||||
managerLogger := zap.New()
|
||||
ctrl.SetLogger(managerLogger)
|
||||
klog.SetLoggerWithOptions(managerLogger.WithName("runtime"), klog.ContextualLogger(true))
|
||||
|
||||
leaseDuration := 35 * time.Second
|
||||
renewDeadline := 30 * time.Second
|
||||
retryPeriod := 5 * time.Second
|
||||
managerOpts := ctrl.Options{
|
||||
Scheme: scheme,
|
||||
Metrics: metricsserver.Options{BindAddress: metricsAddr},
|
||||
HealthProbeBindAddress: probeAddr,
|
||||
LeaderElection: enableLeaderElection,
|
||||
LeaderElectionID: "cac83074.airshipit.org",
|
||||
LeaseDuration: &leaseDuration,
|
||||
RenewDeadline: &renewDeadline,
|
||||
RetryPeriod: &retryPeriod,
|
||||
Controller: ctrlcfg.Controller{
|
||||
MaxConcurrentReconciles: 20,
|
||||
},
|
||||
Logger: ctrl.Log,
|
||||
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
|
||||
// when the Manager ends. This requires the binary to immediately end when the
|
||||
// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
|
||||
// speeds up voluntary leader transitions as the new leader don't have to wait
|
||||
// LeaseDuration time first.
|
||||
//
|
||||
// In the default scaffold provided, the program ends immediately after
|
||||
// the manager stops, so would be fine to enable this option. However,
|
||||
// if you are doing or is intended to do any operation such as perform cleanups
|
||||
// after the manager stops then its usage might be unsafe.
|
||||
// LeaderElectionReleaseOnCancel: true,
|
||||
}
|
||||
|
||||
if leaderElectNamespace != "" {
|
||||
managerOpts.LeaderElectionNamespace = leaderElectNamespace
|
||||
}
|
||||
|
||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), managerOpts)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to start manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err = (&controller.ArmadaChartReconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
}).SetupWithManager(mgr); err != nil {
|
||||
setupLog.Error(err, "unable to create controller", "controller", "ArmadaChart")
|
||||
os.Exit(1)
|
||||
}
|
||||
//+kubebuilder:scaffold:builder
|
||||
|
||||
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
||||
setupLog.Error(err, "unable to set up health check")
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
|
||||
setupLog.Error(err, "unable to set up ready check")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
setupLog.Info("starting manager")
|
||||
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
|
||||
setupLog.Error(err, "problem running manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
242
config/crd/bases/armada.airshipit.org_armadacharts.yaml
Normal file
242
config/crd/bases/armada.airshipit.org_armadacharts.yaml
Normal file
@ -0,0 +1,242 @@
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.13.0
|
||||
name: armadacharts.armada.airshipit.org
|
||||
spec:
|
||||
group: armada.airshipit.org
|
||||
names:
|
||||
kind: ArmadaChart
|
||||
listKind: ArmadaChartList
|
||||
plural: armadacharts
|
||||
singular: armadachart
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: ArmadaChart is the Schema for the armadacharts API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
data:
|
||||
description: ArmadaChartSpec defines the specification of ArmadaChart
|
||||
properties:
|
||||
chart_name:
|
||||
description: ChartName is name of ArmadaChart
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is a namespace for ArmadaChart
|
||||
type: string
|
||||
release:
|
||||
description: Release is a name of corresponding Helm Release of ArmadaChart
|
||||
type: string
|
||||
source:
|
||||
description: Source is a source location of Helm Chart *.tgz
|
||||
properties:
|
||||
location:
|
||||
type: string
|
||||
subpath:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
type: object
|
||||
test:
|
||||
description: Test holds the test parameters for this Helm release.
|
||||
properties:
|
||||
enabled:
|
||||
description: Enabled is an example field of ArmadaChart. Edit
|
||||
armadachart_types.go to remove/update
|
||||
type: boolean
|
||||
type: object
|
||||
upgrade:
|
||||
description: Upgrade holds the upgrade options for this Helm release.
|
||||
properties:
|
||||
pre:
|
||||
properties:
|
||||
delete:
|
||||
items:
|
||||
description: ArmadaChartDeleteResource defines the delete
|
||||
options of ArmadaChart
|
||||
properties:
|
||||
labels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
type:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
values:
|
||||
description: Values holds the values for this Helm release.
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
wait:
|
||||
description: Wait holds the wait options for this Helm release.
|
||||
properties:
|
||||
labels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
native:
|
||||
description: ArmadaChartWaitNative defines the wait options of
|
||||
ArmadaChart
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
type: object
|
||||
resources:
|
||||
items:
|
||||
description: ArmadaChartWaitResource defines the wait options
|
||||
of ArmadaChart
|
||||
properties:
|
||||
labels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
min_ready:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
description: Timeout is the time to wait for full reconciliation
|
||||
of Helm release.
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
status:
|
||||
description: ArmadaChartStatus defines the observed state of ArmadaChart
|
||||
properties:
|
||||
conditions:
|
||||
description: Conditions holds the conditions for the ArmadaChart.
|
||||
items:
|
||||
description: "Condition contains details for one aspect of the current
|
||||
state of this API Resource. --- This struct is intended for direct
|
||||
use as an array at the field path .status.conditions. For example,
|
||||
\n type FooStatus struct{ // Represents the observations of a
|
||||
foo's current state. // Known .status.conditions.type are: \"Available\",
|
||||
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
|
||||
// +listType=map // +listMapKey=type Conditions []metav1.Condition
|
||||
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
|
||||
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: lastTransitionTime is the last time the condition
|
||||
transitioned from one status to another. This should be when
|
||||
the underlying condition changed. If that is not known, then
|
||||
using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: message is a human readable message indicating
|
||||
details about the transition. This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: observedGeneration represents the .metadata.generation
|
||||
that the condition was set based upon. For instance, if .metadata.generation
|
||||
is currently 12, but the .status.conditions[x].observedGeneration
|
||||
is 9, the condition is out of date with respect to the current
|
||||
state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: reason contains a programmatic identifier indicating
|
||||
the reason for the condition's last transition. Producers
|
||||
of specific condition types may define expected values and
|
||||
meanings for this field, and whether the values are considered
|
||||
a guaranteed API. The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
--- Many .condition.type values are consistent across resources
|
||||
like Available, but because arbitrary conditions can be useful
|
||||
(see .node.status.conditions), the ability to deconflict is
|
||||
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- message
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
failures:
|
||||
description: Failures is the reconciliation failure count against
|
||||
the latest desired state. It is reset after a successful reconciliation.
|
||||
format: int64
|
||||
type: integer
|
||||
helmChart:
|
||||
description: HelmChart is the namespaced name of the HelmChart resource
|
||||
created by the controller for the ArmadaChart.
|
||||
type: string
|
||||
installFailures:
|
||||
description: InstallFailures is the install failure count against
|
||||
the latest desired state. It is reset after a successful reconciliation.
|
||||
format: int64
|
||||
type: integer
|
||||
lastAppliedRevision:
|
||||
description: LastAppliedRevision is the revision of the last successfully
|
||||
applied source.
|
||||
type: string
|
||||
lastAttemptedRevision:
|
||||
description: LastAttemptedRevision is the revision of the last reconciliation
|
||||
attempt.
|
||||
type: string
|
||||
lastAttemptedValuesChecksum:
|
||||
description: LastAttemptedValuesChecksum is the SHA1 checksum of the
|
||||
values of the last reconciliation attempt.
|
||||
type: string
|
||||
lastReleaseRevision:
|
||||
description: LastReleaseRevision is the revision of the last successful
|
||||
Helm release.
|
||||
type: integer
|
||||
observedGeneration:
|
||||
description: ObservedGeneration is the last observed generation.
|
||||
format: int64
|
||||
type: integer
|
||||
tested:
|
||||
description: Tested is the bool value whether the Helm Release was
|
||||
successfully tested or not.
|
||||
type: boolean
|
||||
upgradeFailures:
|
||||
description: UpgradeFailures is the upgrade failure count against
|
||||
the latest desired state. It is reset after a successful reconciliation.
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
21
config/crd/kustomization.yaml
Normal file
21
config/crd/kustomization.yaml
Normal file
@ -0,0 +1,21 @@
|
||||
# This kustomization.yaml is not intended to be run by itself,
|
||||
# since it depends on service name and namespace that are out of this kustomize package.
|
||||
# It should be run by config/default
|
||||
resources:
|
||||
- bases/armada.airshipit.org_armadacharts.yaml
|
||||
#+kubebuilder:scaffold:crdkustomizeresource
|
||||
|
||||
patches:
|
||||
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
|
||||
# patches here are for enabling the conversion webhook for each CRD
|
||||
#- path: patches/webhook_in_armadacharts.yaml
|
||||
#+kubebuilder:scaffold:crdkustomizewebhookpatch
|
||||
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
|
||||
# patches here are for enabling the CA injection for each CRD
|
||||
#- path: patches/cainjection_in_armadacharts.yaml
|
||||
#+kubebuilder:scaffold:crdkustomizecainjectionpatch
|
||||
|
||||
# the following config is for teaching kustomize how to do kustomization for CRDs.
|
||||
configurations:
|
||||
- kustomizeconfig.yaml
|
19
config/crd/kustomizeconfig.yaml
Normal file
19
config/crd/kustomizeconfig.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
# This file is for teaching kustomize how to substitute name and namespace reference in CRD
|
||||
nameReference:
|
||||
- kind: Service
|
||||
version: v1
|
||||
fieldSpecs:
|
||||
- kind: CustomResourceDefinition
|
||||
version: v1
|
||||
group: apiextensions.k8s.io
|
||||
path: spec/conversion/webhook/clientConfig/service/name
|
||||
|
||||
namespace:
|
||||
- kind: CustomResourceDefinition
|
||||
version: v1
|
||||
group: apiextensions.k8s.io
|
||||
path: spec/conversion/webhook/clientConfig/service/namespace
|
||||
create: false
|
||||
|
||||
varReference:
|
||||
- path: metadata/annotations
|
7
config/crd/patches/cainjection_in_armadacharts.yaml
Normal file
7
config/crd/patches/cainjection_in_armadacharts.yaml
Normal file
@ -0,0 +1,7 @@
|
||||
# The following patch adds a directive for certmanager to inject CA into the CRD
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
|
||||
name: armadacharts.armada.airshipit.org
|
16
config/crd/patches/webhook_in_armadacharts.yaml
Normal file
16
config/crd/patches/webhook_in_armadacharts.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
# The following patch enables a conversion webhook for the CRD
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: armadacharts.armada.airshipit.org
|
||||
spec:
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhook:
|
||||
clientConfig:
|
||||
service:
|
||||
namespace: system
|
||||
name: webhook-service
|
||||
path: /convert
|
||||
conversionReviewVersions:
|
||||
- v1
|
144
config/default/kustomization.yaml
Normal file
144
config/default/kustomization.yaml
Normal file
@ -0,0 +1,144 @@
|
||||
# Adds namespace to all resources.
|
||||
namespace: armada-operator-system
|
||||
|
||||
# Value of this field is prepended to the
|
||||
# names of all resources, e.g. a deployment named
|
||||
# "wordpress" becomes "alices-wordpress".
|
||||
# Note that it should also match with the prefix (text before '-') of the namespace
|
||||
# field above.
|
||||
namePrefix: armada-operator-
|
||||
|
||||
# Labels to add to all resources and selectors.
|
||||
#labels:
|
||||
#- includeSelectors: true
|
||||
# pairs:
|
||||
# someName: someValue
|
||||
|
||||
resources:
|
||||
- ../crd
|
||||
- ../rbac
|
||||
- ../manager
|
||||
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||
# crd/kustomization.yaml
|
||||
#- ../webhook
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
|
||||
#- ../certmanager
|
||||
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
|
||||
#- ../prometheus
|
||||
|
||||
patchesStrategicMerge:
|
||||
# Protect the /metrics endpoint by putting it behind auth.
|
||||
# If you want your controller-manager to expose the /metrics
|
||||
# endpoint w/o any authn/z, please comment the following line.
|
||||
- manager_auth_proxy_patch.yaml
|
||||
|
||||
|
||||
|
||||
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||
# crd/kustomization.yaml
|
||||
#- manager_webhook_patch.yaml
|
||||
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
|
||||
# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
|
||||
# 'CERTMANAGER' needs to be enabled to use ca injection
|
||||
#- webhookcainjection_patch.yaml
|
||||
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
|
||||
# Uncomment the following replacements to add the cert-manager CA injection annotations
|
||||
#replacements:
|
||||
# - source: # Add cert-manager annotation to ValidatingWebhookConfiguration, MutatingWebhookConfiguration and CRDs
|
||||
# kind: Certificate
|
||||
# group: cert-manager.io
|
||||
# version: v1
|
||||
# name: serving-cert # this name should match the one in certificate.yaml
|
||||
# fieldPath: .metadata.namespace # namespace of the certificate CR
|
||||
# targets:
|
||||
# - select:
|
||||
# kind: ValidatingWebhookConfiguration
|
||||
# fieldPaths:
|
||||
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
|
||||
# options:
|
||||
# delimiter: '/'
|
||||
# index: 0
|
||||
# create: true
|
||||
# - select:
|
||||
# kind: MutatingWebhookConfiguration
|
||||
# fieldPaths:
|
||||
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
|
||||
# options:
|
||||
# delimiter: '/'
|
||||
# index: 0
|
||||
# create: true
|
||||
# - select:
|
||||
# kind: CustomResourceDefinition
|
||||
# fieldPaths:
|
||||
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
|
||||
# options:
|
||||
# delimiter: '/'
|
||||
# index: 0
|
||||
# create: true
|
||||
# - source:
|
||||
# kind: Certificate
|
||||
# group: cert-manager.io
|
||||
# version: v1
|
||||
# name: serving-cert # this name should match the one in certificate.yaml
|
||||
# fieldPath: .metadata.name
|
||||
# targets:
|
||||
# - select:
|
||||
# kind: ValidatingWebhookConfiguration
|
||||
# fieldPaths:
|
||||
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
|
||||
# options:
|
||||
# delimiter: '/'
|
||||
# index: 1
|
||||
# create: true
|
||||
# - select:
|
||||
# kind: MutatingWebhookConfiguration
|
||||
# fieldPaths:
|
||||
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
|
||||
# options:
|
||||
# delimiter: '/'
|
||||
# index: 1
|
||||
# create: true
|
||||
# - select:
|
||||
# kind: CustomResourceDefinition
|
||||
# fieldPaths:
|
||||
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
|
||||
# options:
|
||||
# delimiter: '/'
|
||||
# index: 1
|
||||
# create: true
|
||||
# - source: # Add cert-manager annotation to the webhook Service
|
||||
# kind: Service
|
||||
# version: v1
|
||||
# name: webhook-service
|
||||
# fieldPath: .metadata.name # namespace of the service
|
||||
# targets:
|
||||
# - select:
|
||||
# kind: Certificate
|
||||
# group: cert-manager.io
|
||||
# version: v1
|
||||
# fieldPaths:
|
||||
# - .spec.dnsNames.0
|
||||
# - .spec.dnsNames.1
|
||||
# options:
|
||||
# delimiter: '.'
|
||||
# index: 0
|
||||
# create: true
|
||||
# - source:
|
||||
# kind: Service
|
||||
# version: v1
|
||||
# name: webhook-service
|
||||
# fieldPath: .metadata.namespace # namespace of the service
|
||||
# targets:
|
||||
# - select:
|
||||
# kind: Certificate
|
||||
# group: cert-manager.io
|
||||
# version: v1
|
||||
# fieldPaths:
|
||||
# - .spec.dnsNames.0
|
||||
# - .spec.dnsNames.1
|
||||
# options:
|
||||
# delimiter: '.'
|
||||
# index: 1
|
||||
# create: true
|
39
config/default/manager_auth_proxy_patch.yaml
Normal file
39
config/default/manager_auth_proxy_patch.yaml
Normal file
@ -0,0 +1,39 @@
|
||||
# This patch inject a sidecar container which is a HTTP proxy for the
|
||||
# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews.
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: controller-manager
|
||||
namespace: system
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: kube-rbac-proxy
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- "ALL"
|
||||
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.14.1
|
||||
args:
|
||||
- "--secure-listen-address=0.0.0.0:8443"
|
||||
- "--upstream=http://127.0.0.1:8080/"
|
||||
- "--logtostderr=true"
|
||||
- "--v=0"
|
||||
ports:
|
||||
- containerPort: 8443
|
||||
protocol: TCP
|
||||
name: https
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 5m
|
||||
memory: 64Mi
|
||||
- name: manager
|
||||
args:
|
||||
- "--health-probe-bind-address=:8081"
|
||||
- "--metrics-bind-address=127.0.0.1:8080"
|
||||
- "--leader-elect"
|
10
config/default/manager_config_patch.yaml
Normal file
10
config/default/manager_config_patch.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: controller-manager
|
||||
namespace: system
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: manager
|
8
config/manager/kustomization.yaml
Normal file
8
config/manager/kustomization.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
resources:
|
||||
- manager.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
images:
|
||||
- name: controller
|
||||
newName: quay.io/raliev12/armada-controller
|
||||
newTag: latest
|
102
config/manager/manager.yaml
Normal file
102
config/manager/manager.yaml
Normal file
@ -0,0 +1,102 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
app.kubernetes.io/name: namespace
|
||||
app.kubernetes.io/instance: system
|
||||
app.kubernetes.io/component: manager
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: system
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: controller-manager
|
||||
namespace: system
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
app.kubernetes.io/name: deployment
|
||||
app.kubernetes.io/instance: controller-manager
|
||||
app.kubernetes.io/component: manager
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
kubectl.kubernetes.io/default-container: manager
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
spec:
|
||||
# TODO(user): Uncomment the following code to configure the nodeAffinity expression
|
||||
# according to the platforms which are supported by your solution.
|
||||
# It is considered best practice to support multiple architectures. You can
|
||||
# build your manager image using the makefile target docker-buildx.
|
||||
# affinity:
|
||||
# nodeAffinity:
|
||||
# requiredDuringSchedulingIgnoredDuringExecution:
|
||||
# nodeSelectorTerms:
|
||||
# - matchExpressions:
|
||||
# - key: kubernetes.io/arch
|
||||
# operator: In
|
||||
# values:
|
||||
# - amd64
|
||||
# - arm64
|
||||
# - ppc64le
|
||||
# - s390x
|
||||
# - key: kubernetes.io/os
|
||||
# operator: In
|
||||
# values:
|
||||
# - linux
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
# TODO(user): For common cases that do not require escalating privileges
|
||||
# it is recommended to ensure that all your Pods/Containers are restrictive.
|
||||
# More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted
|
||||
# Please uncomment the following code if your project does NOT have to work on old Kubernetes
|
||||
# versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ).
|
||||
# seccompProfile:
|
||||
# type: RuntimeDefault
|
||||
containers:
|
||||
- command:
|
||||
- /manager
|
||||
args:
|
||||
- --leader-elect
|
||||
image: controller:latest
|
||||
name: manager
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- "ALL"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8081
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 20
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 8081
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
# TODO(user): Configure the resources accordingly based on the project requirements.
|
||||
# More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 64Mi
|
||||
serviceAccountName: controller-manager
|
||||
terminationGracePeriodSeconds: 10
|
2
config/prometheus/kustomization.yaml
Normal file
2
config/prometheus/kustomization.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
resources:
|
||||
- monitor.yaml
|
26
config/prometheus/monitor.yaml
Normal file
26
config/prometheus/monitor.yaml
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
# Prometheus Monitor Service (Metrics)
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
app.kubernetes.io/name: servicemonitor
|
||||
app.kubernetes.io/instance: controller-manager-metrics-monitor
|
||||
app.kubernetes.io/component: metrics
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: controller-manager-metrics-monitor
|
||||
namespace: system
|
||||
spec:
|
||||
endpoints:
|
||||
- path: /metrics
|
||||
port: https
|
||||
scheme: https
|
||||
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
tlsConfig:
|
||||
insecureSkipVerify: true
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
31
config/rbac/armadachart_editor_role.yaml
Normal file
31
config/rbac/armadachart_editor_role.yaml
Normal file
@ -0,0 +1,31 @@
|
||||
# permissions for end users to edit armadacharts.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: clusterrole
|
||||
app.kubernetes.io/instance: armadachart-editor-role
|
||||
app.kubernetes.io/component: rbac
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: armadachart-editor-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- armada.airshipit.org
|
||||
resources:
|
||||
- armadacharts
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- armada.airshipit.org
|
||||
resources:
|
||||
- armadacharts/status
|
||||
verbs:
|
||||
- get
|
27
config/rbac/armadachart_viewer_role.yaml
Normal file
27
config/rbac/armadachart_viewer_role.yaml
Normal file
@ -0,0 +1,27 @@
|
||||
# permissions for end users to view armadacharts.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: clusterrole
|
||||
app.kubernetes.io/instance: armadachart-viewer-role
|
||||
app.kubernetes.io/component: rbac
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: armadachart-viewer-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- armada.airshipit.org
|
||||
resources:
|
||||
- armadacharts
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- armada.airshipit.org
|
||||
resources:
|
||||
- armadacharts/status
|
||||
verbs:
|
||||
- get
|
16
config/rbac/auth_proxy_client_clusterrole.yaml
Normal file
16
config/rbac/auth_proxy_client_clusterrole.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: clusterrole
|
||||
app.kubernetes.io/instance: metrics-reader
|
||||
app.kubernetes.io/component: kube-rbac-proxy
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: metrics-reader
|
||||
rules:
|
||||
- nonResourceURLs:
|
||||
- "/metrics"
|
||||
verbs:
|
||||
- get
|
24
config/rbac/auth_proxy_role.yaml
Normal file
24
config/rbac/auth_proxy_role.yaml
Normal file
@ -0,0 +1,24 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: clusterrole
|
||||
app.kubernetes.io/instance: proxy-role
|
||||
app.kubernetes.io/component: kube-rbac-proxy
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: proxy-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- subjectaccessreviews
|
||||
verbs:
|
||||
- create
|
19
config/rbac/auth_proxy_role_binding.yaml
Normal file
19
config/rbac/auth_proxy_role_binding.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: clusterrolebinding
|
||||
app.kubernetes.io/instance: proxy-rolebinding
|
||||
app.kubernetes.io/component: kube-rbac-proxy
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: proxy-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: proxy-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: default
|
21
config/rbac/auth_proxy_service.yaml
Normal file
21
config/rbac/auth_proxy_service.yaml
Normal file
@ -0,0 +1,21 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
app.kubernetes.io/name: service
|
||||
app.kubernetes.io/instance: controller-manager-metrics-service
|
||||
app.kubernetes.io/component: kube-rbac-proxy
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: controller-manager-metrics-service
|
||||
namespace: system
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
protocol: TCP
|
||||
targetPort: https
|
||||
selector:
|
||||
control-plane: controller-manager
|
10
config/rbac/cluster_role.yaml
Normal file
10
config/rbac/cluster_role.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: reconciler-role
|
||||
rules:
|
||||
- apiGroups: ['*']
|
||||
resources: ['*']
|
||||
verbs: ['*']
|
||||
- nonResourceURLs: ['*']
|
||||
verbs: ['*']
|
12
config/rbac/cluster_role_binding.yaml
Normal file
12
config/rbac/cluster_role_binding.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: reconciler-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: reconciler-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: controller-manager
|
||||
namespace: system
|
20
config/rbac/kustomization.yaml
Normal file
20
config/rbac/kustomization.yaml
Normal file
@ -0,0 +1,20 @@
|
||||
resources:
|
||||
# All RBAC will be applied under this service account in
|
||||
# the deployment namespace. You may comment out this resource
|
||||
# if your manager will use a service account that exists at
|
||||
# runtime. Be sure to update RoleBinding and ClusterRoleBinding
|
||||
# subjects if changing service account names.
|
||||
- service_account.yaml
|
||||
#- role.yaml
|
||||
#- role_binding.yaml
|
||||
- leader_election_role.yaml
|
||||
- leader_election_role_binding.yaml
|
||||
- cluster_role.yaml
|
||||
- cluster_role_binding.yaml
|
||||
# Comment the following 4 lines if you want to disable
|
||||
# the auth proxy (https://github.com/brancz/kube-rbac-proxy)
|
||||
# which protects your /metrics endpoint.
|
||||
#- auth_proxy_service.yaml
|
||||
#- auth_proxy_role.yaml
|
||||
#- auth_proxy_role_binding.yaml
|
||||
#- auth_proxy_client_clusterrole.yaml
|
44
config/rbac/leader_election_role.yaml
Normal file
44
config/rbac/leader_election_role.yaml
Normal file
@ -0,0 +1,44 @@
|
||||
# permissions to do leader election.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: role
|
||||
app.kubernetes.io/instance: leader-election-role
|
||||
app.kubernetes.io/component: rbac
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: leader-election-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- coordination.k8s.io
|
||||
resources:
|
||||
- leases
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
19
config/rbac/leader_election_role_binding.yaml
Normal file
19
config/rbac/leader_election_role_binding.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: rolebinding
|
||||
app.kubernetes.io/instance: leader-election-rolebinding
|
||||
app.kubernetes.io/component: rbac
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: leader-election-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: leader-election-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: default
|
32
config/rbac/role.yaml
Normal file
32
config/rbac/role.yaml
Normal file
@ -0,0 +1,32 @@
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: manager-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- armada.airshipit.org
|
||||
resources:
|
||||
- armadacharts
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- armada.airshipit.org
|
||||
resources:
|
||||
- armadacharts/finalizers
|
||||
verbs:
|
||||
- update
|
||||
- apiGroups:
|
||||
- armada.airshipit.org
|
||||
resources:
|
||||
- armadacharts/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
19
config/rbac/role_binding.yaml
Normal file
19
config/rbac/role_binding.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: clusterrolebinding
|
||||
app.kubernetes.io/instance: manager-rolebinding
|
||||
app.kubernetes.io/component: rbac
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: manager-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: manager-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: controller-manager
|
||||
namespace: system
|
12
config/rbac/service_account.yaml
Normal file
12
config/rbac/service_account.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: serviceaccount
|
||||
app.kubernetes.io/instance: controller-manager-sa
|
||||
app.kubernetes.io/component: rbac
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: controller-manager
|
||||
namespace: system
|
12
config/samples/armada_v1_armadachart.yaml
Normal file
12
config/samples/armada_v1_armadachart.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: armada.airshipit.org/v1
|
||||
kind: ArmadaChart
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: armadachart
|
||||
app.kubernetes.io/instance: armadachart-sample
|
||||
app.kubernetes.io/part-of: armada-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
app.kubernetes.io/created-by: armada-operator
|
||||
name: armadachart-sample
|
||||
spec:
|
||||
# TODO(user): Add fields here
|
4
config/samples/kustomization.yaml
Normal file
4
config/samples/kustomization.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
## Append samples of your project ##
|
||||
resources:
|
||||
- armada_v1_armadachart.yaml
|
||||
#+kubebuilder:scaffold:manifestskustomizesamples
|
155
go.mod
Normal file
155
go.mod
Normal file
@ -0,0 +1,155 @@
|
||||
module opendev.org/airship/armada-operator
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/go-logr/logr v1.2.4
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/hashicorp/go-retryablehttp v0.7.4
|
||||
github.com/onsi/ginkgo/v2 v2.11.0
|
||||
github.com/onsi/gomega v1.27.10
|
||||
helm.sh/helm/v3 v3.12.2
|
||||
k8s.io/api v0.28.3
|
||||
k8s.io/apiextensions-apiserver v0.28.3
|
||||
k8s.io/apimachinery v0.28.3
|
||||
k8s.io/cli-runtime v0.28.2
|
||||
k8s.io/client-go v0.28.3
|
||||
k8s.io/klog/v2 v2.100.1
|
||||
sigs.k8s.io/controller-runtime v0.16.3
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/Masterminds/squirrel v1.5.4 // indirect
|
||||
github.com/Microsoft/hcsshim v0.11.0 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/containerd/containerd v1.7.6 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // 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.6+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.2.4 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // 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/gosuri/uitable v0.0.4 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // 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/jmoiron/sqlx v1.3.5 // 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/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // 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.9 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // 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/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/rubenv/sql-migrate v1.5.2 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/cobra v1.7.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
go.opentelemetry.io/otel v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.25.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/oauth2 v0.8.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/term v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.9.3 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
|
||||
google.golang.org/grpc v1.54.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiserver v0.28.3 // indirect
|
||||
k8s.io/component-base v0.28.3 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect
|
||||
k8s.io/kubectl v0.28.2 // indirect
|
||||
k8s.io/utils v0.0.0-20230505201702-9f6742963106 // 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.3.0 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
574
go.sum
Normal file
574
go.sum
Normal file
@ -0,0 +1,574 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
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-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
||||
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||
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/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
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/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
|
||||
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/hcsshim v0.11.0 h1:7EFNIY4igHEXUdj1zXgAyU3fLc7QfOKHbkldRVTBdiM=
|
||||
github.com/Microsoft/hcsshim v0.11.0/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
|
||||
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/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||
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/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
|
||||
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng=
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
|
||||
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/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
|
||||
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
|
||||
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/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/containerd v1.7.6 h1:oNAVsnhPoy4BTPQivLgTzI9Oleml9l/+eYIDYXRCYo8=
|
||||
github.com/containerd/containerd v1.7.6/go.mod h1:SY6lrkkuJT40BVNO37tlYTSnKJnP5AXBc0fhx0q+TJ4=
|
||||
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
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/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.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE=
|
||||
github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.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-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/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
|
||||
github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
|
||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
|
||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
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-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
|
||||
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
|
||||
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.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
|
||||
github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
|
||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU=
|
||||
github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0=
|
||||
github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/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-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.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/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.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.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/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/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
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.1/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/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
|
||||
github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
|
||||
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/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
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-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||
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/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
|
||||
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/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/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/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
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/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
|
||||
github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY=
|
||||
github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
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.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
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/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
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-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
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/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
|
||||
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/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/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/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/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
|
||||
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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0=
|
||||
github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
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/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
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/cast v1.3.1/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 v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
|
||||
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI=
|
||||
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE=
|
||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
|
||||
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
|
||||
go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
|
||||
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
|
||||
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=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
|
||||
go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
|
||||
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-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.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
|
||||
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
|
||||
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.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.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/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=
|
||||
helm.sh/helm/v3 v3.12.2 h1:kFyDBr/mgJUlyGzVTCieG4wW0zmo7fcNRWK0+FKkxqU=
|
||||
helm.sh/helm/v3 v3.12.2/go.mod h1:v1PMayudIfZAvec3Wp4wAErensvK/rv5fu/xCiE6t3I=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM=
|
||||
k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc=
|
||||
k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08=
|
||||
k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc=
|
||||
k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A=
|
||||
k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8=
|
||||
k8s.io/apiserver v0.28.3 h1:8Ov47O1cMyeDzTXz0rwcfIIGAP/dP7L8rWbEljRcg5w=
|
||||
k8s.io/apiserver v0.28.3/go.mod h1:YIpM+9wngNAv8Ctt0rHG4vQuX/I5rvkEMtZtsxW2rNM=
|
||||
k8s.io/cli-runtime v0.28.2 h1:64meB2fDj10/ThIMEJLO29a1oujSm0GQmKzh1RtA/uk=
|
||||
k8s.io/cli-runtime v0.28.2/go.mod h1:bTpGOvpdsPtDKoyfG4EG041WIyFZLV9qq4rPlkyYfDA=
|
||||
k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4=
|
||||
k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo=
|
||||
k8s.io/component-base v0.28.3 h1:rDy68eHKxq/80RiMb2Ld/tbH8uAE75JdCqJyi6lXMzI=
|
||||
k8s.io/component-base v0.28.3/go.mod h1:fDJ6vpVNSk6cRo5wmDa6eKIG7UlIQkaFmZN2fYgIUD8=
|
||||
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
|
||||
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ=
|
||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM=
|
||||
k8s.io/kubectl v0.28.2 h1:fOWOtU6S0smdNjG1PB9WFbqEIMlkzU5ahyHkc7ESHgM=
|
||||
k8s.io/kubectl v0.28.2/go.mod h1:6EQWTPySF1fn7yKoQZHYf9TPwIl2AygHEcJoxFekr64=
|
||||
k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU=
|
||||
k8s.io/utils v0.0.0-20230505201702-9f6742963106/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=
|
||||
sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4=
|
||||
sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0=
|
||||
sigs.k8s.io/json v0.0.0-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.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.3.0/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=
|
15
hack/boilerplate.go.txt
Normal file
15
hack/boilerplate.go.txt
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
Copyright 2023.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
36
images/armada-operator/Dockerfile.ubuntu_focal
Normal file
36
images/armada-operator/Dockerfile.ubuntu_focal
Normal file
@ -0,0 +1,36 @@
|
||||
ARG FROM=ubuntu:20.04
|
||||
# Build the manager binary
|
||||
FROM golang:1.20-bullseye as builder
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
||||
WORKDIR /workspace
|
||||
# Copy the Go Modules manifests
|
||||
COPY go.mod go.mod
|
||||
COPY go.sum go.sum
|
||||
# cache deps before building and copying source so that we don't need to re-download as much
|
||||
# and so that source changes don't invalidate our downloaded layer
|
||||
RUN go mod download
|
||||
|
||||
# Copy the go source
|
||||
COPY cmd/main.go cmd/main.go
|
||||
COPY api/ api/
|
||||
COPY internal/ internal/
|
||||
|
||||
# Build
|
||||
# the GOARCH has not a default value to allow the binary be built according to the host where the command
|
||||
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
|
||||
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
|
||||
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
|
||||
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go
|
||||
|
||||
# Use distroless as minimal base image to package the manager binary
|
||||
# Refer to https://github.com/GoogleContainerTools/distroless for more details
|
||||
# NOTE: distroless has been switched to alpine
|
||||
#FROM gcr.io/distroless/static:nonroot
|
||||
FROM ${FROM}
|
||||
WORKDIR /
|
||||
COPY --from=builder /workspace/manager .
|
||||
USER 65532:65532
|
||||
|
||||
ENTRYPOINT ["/manager"]
|
417
internal/controller/armadachart_controller.go
Normal file
417
internal/controller/armadachart_controller.go
Normal file
@ -0,0 +1,417 @@
|
||||
/*
|
||||
Copyright 2023.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/go-retryablehttp"
|
||||
//"golang.org/x/exp/maps"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/chartutil"
|
||||
"helm.sh/helm/v3/pkg/release"
|
||||
"helm.sh/helm/v3/pkg/storage/driver"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
|
||||
armadav1 "opendev.org/airship/armada-operator/api/v1"
|
||||
"opendev.org/airship/armada-operator/internal/kube"
|
||||
"opendev.org/airship/armada-operator/internal/runner"
|
||||
)
|
||||
|
||||
// ArmadaChartReconciler reconciles a ArmadaChart object
|
||||
type ArmadaChartReconciler struct {
|
||||
client.Client
|
||||
|
||||
ControllerName string
|
||||
|
||||
Scheme *runtime.Scheme
|
||||
httpClient *retryablehttp.Client
|
||||
}
|
||||
|
||||
//+kubebuilder:rbac:groups=armada.airshipit.org,resources=armadacharts,verbs=get;list;watch;create;update;patch;delete
|
||||
//+kubebuilder:rbac:groups=armada.airshipit.org,resources=armadacharts/status,verbs=get;update;patch
|
||||
//+kubebuilder:rbac:groups=armada.airshipit.org,resources=armadacharts/finalizers,verbs=update
|
||||
|
||||
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||
// move the current state of the cluster closer to the desired state.
|
||||
func (r *ArmadaChartReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
start := time.Now()
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
|
||||
log.Info("reconciling has started")
|
||||
|
||||
// Retrieve the custom resource
|
||||
var ac armadav1.ArmadaChart
|
||||
if err := r.Get(ctx, req.NamespacedName, &ac); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
// Add our finalizer if it does not exist
|
||||
if !controllerutil.ContainsFinalizer(&ac, armadav1.ArmadaChartFinalizer) {
|
||||
patch := client.MergeFrom(ac.DeepCopy())
|
||||
controllerutil.AddFinalizer(&ac, armadav1.ArmadaChartFinalizer)
|
||||
if err := r.Patch(ctx, &ac, patch); err != nil {
|
||||
log.Error(err, "unable to register finalizer")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
// Examine if the object is under deletion
|
||||
if !ac.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
log.Info("object is under deletion, uninstalling corresponding helm release")
|
||||
return r.reconcileDelete(ctx, &ac)
|
||||
}
|
||||
|
||||
// Perform reconciliation
|
||||
ac, result, err := r.reconcile(ctx, ac)
|
||||
if updateStatusErr := r.patchStatus(ctx, &ac); updateStatusErr != nil {
|
||||
log.Error(updateStatusErr, "unable to update status after reconciliation")
|
||||
return ctrl.Result{Requeue: false}, updateStatusErr
|
||||
}
|
||||
|
||||
// Log reconciliation duration
|
||||
durationMsg := fmt.Sprintf("reconciliation finished in %s", time.Since(start).String())
|
||||
if result.RequeueAfter > 0 {
|
||||
durationMsg = fmt.Sprintf("%s, next run in %s", durationMsg, result.RequeueAfter.String())
|
||||
}
|
||||
log.Info(durationMsg)
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (r *ArmadaChartReconciler) reconcile(ctx context.Context, ac armadav1.ArmadaChart) (armadav1.ArmadaChart, ctrl.Result, error) {
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
|
||||
// Observe HelmRelease generation.
|
||||
if ac.Status.ObservedGeneration != ac.Generation {
|
||||
ac.Status.ObservedGeneration = ac.Generation
|
||||
ac = armadav1.ArmadaChartProgressing(ac)
|
||||
if updateStatusErr := r.patchStatus(ctx, &ac); updateStatusErr != nil {
|
||||
log.Error(updateStatusErr, "unable to update status after generation update")
|
||||
return ac, ctrl.Result{Requeue: true}, updateStatusErr
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare values
|
||||
var vals map[string]interface{}
|
||||
if ac.Spec.Values != nil {
|
||||
var vals_err error
|
||||
vals, vals_err = chartutil.ReadValues(ac.Spec.Values.Raw)
|
||||
if vals_err != nil {
|
||||
return armadav1.ArmadaChartNotReady(ac, "InitFailed", vals_err.Error()), ctrl.Result{}, vals_err
|
||||
}
|
||||
}
|
||||
// Load chart from artifact
|
||||
chrt, err := r.loadHelmChart(ctx, ac, ac.Spec.Source.Location)
|
||||
if err != nil {
|
||||
return armadav1.ArmadaChartNotReady(ac, "ArtifactFailed", err.Error()), ctrl.Result{}, err
|
||||
}
|
||||
|
||||
reconAc, reconErr := r.reconcileChart(ctx, *ac.DeepCopy(), chrt, vals)
|
||||
|
||||
return reconAc, ctrl.Result{}, reconErr
|
||||
}
|
||||
|
||||
func (r *ArmadaChartReconciler) reconcileChart(ctx context.Context,
|
||||
ac armadav1.ArmadaChart, chrt *chart.Chart, vals chartutil.Values) (armadav1.ArmadaChart, error) {
|
||||
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
gettr, err := r.buildRESTClientGetter(ctx, ac)
|
||||
if err != nil {
|
||||
return armadav1.ArmadaChartNotReady(ac, "InitFailed", err.Error()), err
|
||||
}
|
||||
|
||||
run, err := runner.NewRunner(gettr, ac.Namespace, log)
|
||||
if err != nil {
|
||||
return armadav1.ArmadaChartNotReady(ac, "InitFailed", "failed to initialize Helm action runner"), err
|
||||
}
|
||||
|
||||
// Determine last release revision.
|
||||
rel, observeLastReleaseErr := run.ObserveLastRelease(ac)
|
||||
if observeLastReleaseErr != nil {
|
||||
err = fmt.Errorf("failed to get last release revision: %w", observeLastReleaseErr)
|
||||
return armadav1.ArmadaChartNotReady(ac, "GetLastReleaseFailed", "failed to get last release revision"), err
|
||||
}
|
||||
|
||||
testRel := func() (armadav1.ArmadaChart, error) {
|
||||
if ac.Spec.Test.Enabled && !ac.Status.Tested {
|
||||
log.Info("performing tests")
|
||||
rel, err = run.Test(ac)
|
||||
if err != nil {
|
||||
return armadav1.ArmadaChartNotReady(ac, "TestFailed", err.Error()), err
|
||||
}
|
||||
}
|
||||
return armadav1.ArmadaChartReady(ac), err
|
||||
}
|
||||
|
||||
if rel == nil {
|
||||
log.Info("helm install has started")
|
||||
rel, err = run.Install(ctx, ac, chrt, vals)
|
||||
} else {
|
||||
if rel.Info.Status == release.StatusDeployed && !isUpdateRequired(ctx, rel, chrt, vals) {
|
||||
log.Info("no updates found, skipping upgrade")
|
||||
return testRel()
|
||||
}
|
||||
|
||||
if rel.Info.Status.IsPending() {
|
||||
log.Info("warning: release in pending state, unlocking")
|
||||
rel.SetStatus(release.StatusFailed, fmt.Sprintf("release unlocked from stale state"))
|
||||
} else {
|
||||
for _, delRes := range ac.Spec.Upgrade.PreUpgrade.Delete {
|
||||
log.Info(fmt.Sprintf("deleting all %ss in %s ns with labels %v", delRes.Type, ac.Spec.Namespace, delRes.Labels))
|
||||
switch delRes.Type {
|
||||
case "", "job":
|
||||
err = r.DeleteAllOf(ctx, &batchv1.Job{}, client.MatchingLabels(delRes.Labels), client.InNamespace(ac.Spec.Namespace))
|
||||
if err != nil {
|
||||
return armadav1.ArmadaChartNotReady(ac, "DeleteFailed", err.Error()), err
|
||||
}
|
||||
case "pod":
|
||||
err = r.DeleteAllOf(ctx, &corev1.Pod{}, client.MatchingLabels(delRes.Labels), client.InNamespace(ac.Spec.Namespace))
|
||||
if err != nil {
|
||||
return armadav1.ArmadaChartNotReady(ac, "DeleteFailed", err.Error()), err
|
||||
}
|
||||
case "cronjob":
|
||||
err = r.DeleteAllOf(ctx, &batchv1.CronJob{}, client.MatchingLabels(delRes.Labels), client.InNamespace(ac.Spec.Namespace))
|
||||
if err != nil {
|
||||
return armadav1.ArmadaChartNotReady(ac, "DeleteFailed", err.Error()), err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("helm upgrade has started")
|
||||
rel, err = run.Upgrade(ctx, ac, chrt, vals)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to install/upgrade helm release: %s", err.Error())
|
||||
return armadav1.ArmadaChartNotReady(ac, "InstallUpgradeFailed", err.Error()), err
|
||||
}
|
||||
|
||||
if ac.Spec.Wait.Timeout > 0 && len(ac.Spec.Wait.Labels) > 0 {
|
||||
log.Info("preparing to wait resources")
|
||||
resCfg, err := gettr.ToRESTConfig()
|
||||
if err != nil {
|
||||
return armadav1.ArmadaChartNotReady(ac, "WaitFailed", err.Error()), err
|
||||
}
|
||||
err = r.waitRelease(ctx, resCfg, ac)
|
||||
if err != nil {
|
||||
return armadav1.ArmadaChartNotReady(ac, "WaitFailed", err.Error()), err
|
||||
}
|
||||
}
|
||||
|
||||
return testRel()
|
||||
}
|
||||
|
||||
func (r *ArmadaChartReconciler) waitRelease(ctx context.Context, restCfg *rest.Config, hr armadav1.ArmadaChart) error {
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
|
||||
if hr.Spec.Wait.ArmadaChartWaitResources == nil {
|
||||
log.Info(fmt.Sprintf("there are no explicitly defined resources to wait: %s, using default ones", hr.Name))
|
||||
hr.Spec.Wait.ArmadaChartWaitResources = []armadav1.ArmadaChartWaitResource{{Type: "job"}, {Type: "pod"}}
|
||||
}
|
||||
if len(hr.Spec.Wait.ArmadaChartWaitResources) == 0 {
|
||||
log.Info(fmt.Sprintf("there are none resources to wait: %s", hr.Name))
|
||||
}
|
||||
if hr.Spec.Wait.Labels == nil {
|
||||
hr.Spec.Wait.Labels = make(map[string]string)
|
||||
}
|
||||
|
||||
for _, res := range hr.Spec.Wait.ArmadaChartWaitResources {
|
||||
log.Info(fmt.Sprintf("processing wait resource %v", res))
|
||||
if res.Labels == nil || len(res.Labels) == 0 {
|
||||
res.Labels = make(map[string]string)
|
||||
}
|
||||
|
||||
for kk, vv := range hr.Spec.Wait.Labels {
|
||||
res.Labels[kk] = vv
|
||||
}
|
||||
|
||||
if len(res.Labels) == 0 {
|
||||
log.Info("no selectors applied, continuing...")
|
||||
continue
|
||||
}
|
||||
|
||||
log.Info(fmt.Sprintf("Resolved `wait.resources` list: %v", res))
|
||||
|
||||
var labelSelector string
|
||||
for k, v := range res.Labels {
|
||||
if len(labelSelector) > 0 {
|
||||
labelSelector = fmt.Sprintf("%s,%s=%s", labelSelector, k, v)
|
||||
} else {
|
||||
labelSelector = fmt.Sprintf("%s=%s", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
opts := kube.WaitOptions{
|
||||
RestConfig: *restCfg,
|
||||
Namespace: hr.Spec.Namespace,
|
||||
LabelSelector: labelSelector,
|
||||
ResourceType: fmt.Sprintf("%ss", res.Type),
|
||||
Timeout: time.Second * time.Duration(hr.Spec.Wait.Timeout),
|
||||
MinReady: res.MinReady,
|
||||
Logger: log,
|
||||
}
|
||||
err := opts.Wait(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("all resources are ready")
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadHelmChart attempts to download the artifact from the provided source,
|
||||
// loads it into a chart.Chart, and removes the downloaded artifact.
|
||||
// It returns the loaded chart.Chart on success, or an error.
|
||||
func (r *ArmadaChartReconciler) loadHelmChart(ctx context.Context, hr armadav1.ArmadaChart, source string) (*chart.Chart, error) {
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
f, err := os.CreateTemp("", fmt.Sprintf("%s-%s-*.tgz", hr.GetNamespace(), hr.GetName()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
req, err := retryablehttp.NewRequest(http.MethodGet, source, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create a new request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := r.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to download artifact, error: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("artifact '%s' download failed (status code: %s)", source, resp.Status)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(f, resp.Body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Info(fmt.Sprintf("helm chart downloaded to %s", f.Name()))
|
||||
return loader.Load(f.Name())
|
||||
}
|
||||
|
||||
func (r *ArmadaChartReconciler) buildRESTClientGetter(_ context.Context, hr armadav1.ArmadaChart) (genericclioptions.RESTClientGetter, error) {
|
||||
opts := []kube.Option{
|
||||
kube.WithNamespace(hr.Spec.Namespace),
|
||||
kube.WithPersistent(true),
|
||||
}
|
||||
|
||||
return kube.NewInClusterMemoryRESTClientGetter(opts...)
|
||||
}
|
||||
|
||||
func (r *ArmadaChartReconciler) patchStatus(ctx context.Context, ac *armadav1.ArmadaChart) error {
|
||||
latest := &armadav1.ArmadaChart{}
|
||||
if err := r.Client.Get(ctx, client.ObjectKeyFromObject(ac), latest); err != nil {
|
||||
return err
|
||||
}
|
||||
patch := client.MergeFrom(latest.DeepCopy())
|
||||
latest.Status = ac.Status
|
||||
return r.Client.Status().Patch(ctx, latest, patch, client.FieldOwner(r.ControllerName))
|
||||
}
|
||||
|
||||
// reconcileDelete deletes the Helm Release of the ArmadaChart,
|
||||
// and uninstalls the Helm release if the resource has not been suspended.
|
||||
// It only performs a Helm uninstall if the ServiceAccount to be impersonated
|
||||
// exists.
|
||||
func (r *ArmadaChartReconciler) reconcileDelete(ctx context.Context, ac *armadav1.ArmadaChart) (ctrl.Result, error) {
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
|
||||
getter, err := r.buildRESTClientGetter(ctx, *ac)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
run, err := runner.NewRunner(getter, ac.Spec.Namespace, ctrl.LoggerFrom(ctx))
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
if err := run.Uninstall(*ac); err != nil && !errors.Is(err, driver.ErrReleaseNotFound) {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
log.Info("uninstalled Helm release for deleted resource")
|
||||
|
||||
// Remove our finalizer from the list and update it.
|
||||
controllerutil.RemoveFinalizer(ac, armadav1.ArmadaChartFinalizer)
|
||||
if err := r.Update(ctx, ac); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// SetupWithManager sets up the controller with the Manager.
|
||||
func (r *ArmadaChartReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
httpClient := retryablehttp.NewClient()
|
||||
httpClient.RetryWaitMin = 5 * time.Second
|
||||
httpClient.RetryWaitMax = 30 * time.Second
|
||||
httpClient.RetryMax = 3
|
||||
httpClient.Logger = nil
|
||||
r.httpClient = httpClient
|
||||
|
||||
r.ControllerName = "armada-controller"
|
||||
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&armadav1.ArmadaChart{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).Complete(r)
|
||||
}
|
||||
|
||||
func isUpdateRequired(ctx context.Context, release *release.Release, chrt *chart.Chart, vals chartutil.Values) bool {
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
|
||||
switch {
|
||||
case !cmp.Equal(release.Chart.Templates, chrt.Templates, cmpopts.EquateEmpty()):
|
||||
log.Info("There are chart template diffs found")
|
||||
log.Info(cmp.Diff(release.Chart.Templates, chrt.Templates))
|
||||
return true
|
||||
|
||||
//case !cmp.Equal(release.Chart.Values, chrt.Values, cmpopts.EquateEmpty()):
|
||||
// log.Info("There are CHART DEF VALUES diffs")
|
||||
// log.Info(cmp.Diff(release.Chart.Values, chrt.Values, cmpopts.EquateEmpty()))
|
||||
// return true
|
||||
|
||||
case !cmp.Equal(release.Config, vals.AsMap(), cmpopts.EquateEmpty()):
|
||||
log.Info("There are CHART VALUES diffs")
|
||||
log.Info(cmp.Diff(release.Config, vals.AsMap(), cmpopts.EquateEmpty()))
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
90
internal/controller/suite_test.go
Normal file
90
internal/controller/suite_test.go
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2023.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
armadav1 "opendev.org/airship/armada-operator/api/v1"
|
||||
//+kubebuilder:scaffold:imports
|
||||
)
|
||||
|
||||
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
|
||||
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
|
||||
|
||||
var cfg *rest.Config
|
||||
var k8sClient client.Client
|
||||
var testEnv *envtest.Environment
|
||||
|
||||
func TestControllers(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
|
||||
RunSpecs(t, "Controller Suite")
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
|
||||
|
||||
By("bootstrapping test environment")
|
||||
testEnv = &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
|
||||
ErrorIfCRDPathMissing: true,
|
||||
|
||||
// The BinaryAssetsDirectory is only required if you want to run the tests directly
|
||||
// without call the makefile target test. If not informed it will look for the
|
||||
// default path defined in controller-runtime which is /usr/local/kubebuilder/.
|
||||
// Note that you must have the required binaries setup under the bin directory to perform
|
||||
// the tests directly. When we run make test it will be setup and used automatically.
|
||||
BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s",
|
||||
fmt.Sprintf("1.28.0-%s-%s", runtime.GOOS, runtime.GOARCH)),
|
||||
}
|
||||
|
||||
var err error
|
||||
// cfg is defined in this file globally.
|
||||
cfg, err = testEnv.Start()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(cfg).NotTo(BeNil())
|
||||
|
||||
err = armadav1.AddToScheme(scheme.Scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
//+kubebuilder:scaffold:scheme
|
||||
|
||||
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(k8sClient).NotTo(BeNil())
|
||||
|
||||
})
|
||||
|
||||
var _ = AfterSuite(func() {
|
||||
By("tearing down the test environment")
|
||||
err := testEnv.Stop()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
213
internal/kube/client.go
Normal file
213
internal/kube/client.go
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
Copyright 2023.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/discovery/cached/memory"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/restmapper"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
)
|
||||
|
||||
// Option is a function that configures an MemoryRESTClientGetter.
|
||||
type Option func(*MemoryRESTClientGetter)
|
||||
|
||||
// WithNamespace sets the namespace to use for the client.
|
||||
func WithNamespace(namespace string) Option {
|
||||
return func(c *MemoryRESTClientGetter) {
|
||||
c.namespace = namespace
|
||||
}
|
||||
}
|
||||
|
||||
// WithPersistent sets whether the client should persist the underlying client
|
||||
// config, REST mapper, and discovery client.
|
||||
func WithPersistent(persist bool) Option {
|
||||
return func(c *MemoryRESTClientGetter) {
|
||||
c.persistent = persist
|
||||
}
|
||||
}
|
||||
|
||||
// MemoryRESTClientGetter is a resource.RESTClientGetter that uses an
|
||||
// in-memory REST config, REST mapper, and discovery client.
|
||||
// If configured, the client config, REST mapper, and discovery client are
|
||||
// lazily initialized, and cached for subsequent calls.
|
||||
type MemoryRESTClientGetter struct {
|
||||
// namespace is the namespace to use for the client.
|
||||
namespace string
|
||||
// impersonate is the username to use for the client.
|
||||
impersonate string
|
||||
// persistent indicates whether the client should persist the restMapper,
|
||||
// clientCfg, and discoveryClient. Rather than re-initializing them on
|
||||
// every call, they will be cached and reused.
|
||||
persistent bool
|
||||
|
||||
cfg *rest.Config
|
||||
|
||||
restMapper meta.RESTMapper
|
||||
restMapperMu sync.Mutex
|
||||
|
||||
discoveryClient discovery.CachedDiscoveryInterface
|
||||
discoveryMu sync.Mutex
|
||||
|
||||
clientCfg clientcmd.ClientConfig
|
||||
clientCfgMu sync.Mutex
|
||||
}
|
||||
|
||||
// setDefaults sets the default values for the MemoryRESTClientGetter.
|
||||
func (c *MemoryRESTClientGetter) setDefaults() {
|
||||
if c.namespace == "" {
|
||||
c.namespace = "default"
|
||||
}
|
||||
}
|
||||
|
||||
// NewMemoryRESTClientGetter returns a new MemoryRESTClientGetter.
|
||||
func NewMemoryRESTClientGetter(cfg *rest.Config, opts ...Option) *MemoryRESTClientGetter {
|
||||
g := &MemoryRESTClientGetter{
|
||||
cfg: cfg,
|
||||
}
|
||||
for _, opts := range opts {
|
||||
opts(g)
|
||||
}
|
||||
g.setDefaults()
|
||||
return g
|
||||
}
|
||||
|
||||
// NewInClusterMemoryRESTClientGetter returns a new MemoryRESTClientGetter
|
||||
// that uses the in-cluster REST config. It returns an error if the in-cluster
|
||||
// REST config cannot be obtained.
|
||||
func NewInClusterMemoryRESTClientGetter(opts ...Option) (*MemoryRESTClientGetter, error) {
|
||||
cfg, err := ctrl.GetConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get config for in-cluster REST client: %w", err)
|
||||
}
|
||||
return NewMemoryRESTClientGetter(cfg, opts...), nil
|
||||
}
|
||||
|
||||
// ToRESTConfig returns the in-memory REST config.
|
||||
func (c *MemoryRESTClientGetter) ToRESTConfig() (*rest.Config, error) {
|
||||
if c.cfg == nil {
|
||||
return nil, fmt.Errorf("MemoryRESTClientGetter has no REST config")
|
||||
}
|
||||
return c.cfg, nil
|
||||
}
|
||||
|
||||
// ToDiscoveryClient returns a memory cached discovery client. Calling it
|
||||
// multiple times will return the same instance.
|
||||
func (c *MemoryRESTClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
|
||||
if c.persistent {
|
||||
return c.toPersistentDiscoveryClient()
|
||||
}
|
||||
return c.toDiscoveryClient()
|
||||
}
|
||||
|
||||
func (c *MemoryRESTClientGetter) toPersistentDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
|
||||
c.discoveryMu.Lock()
|
||||
defer c.discoveryMu.Unlock()
|
||||
|
||||
if c.discoveryClient == nil {
|
||||
discoveryClient, err := c.toDiscoveryClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.discoveryClient = discoveryClient
|
||||
}
|
||||
return c.discoveryClient, nil
|
||||
}
|
||||
|
||||
func (c *MemoryRESTClientGetter) toDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
|
||||
config, err := c.ToRESTConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return memory.NewMemCacheClient(discoveryClient), nil
|
||||
}
|
||||
|
||||
// ToRESTMapper returns a meta.RESTMapper using the discovery client. Calling
|
||||
// it multiple times will return the same instance.
|
||||
func (c *MemoryRESTClientGetter) ToRESTMapper() (meta.RESTMapper, error) {
|
||||
if c.persistent {
|
||||
return c.toPersistentRESTMapper()
|
||||
}
|
||||
return c.toRESTMapper()
|
||||
}
|
||||
|
||||
func (c *MemoryRESTClientGetter) toPersistentRESTMapper() (meta.RESTMapper, error) {
|
||||
c.restMapperMu.Lock()
|
||||
defer c.restMapperMu.Unlock()
|
||||
|
||||
if c.restMapper == nil {
|
||||
restMapper, err := c.toRESTMapper()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.restMapper = restMapper
|
||||
}
|
||||
return c.restMapper, nil
|
||||
}
|
||||
|
||||
func (c *MemoryRESTClientGetter) toRESTMapper() (meta.RESTMapper, error) {
|
||||
discoveryClient, err := c.ToDiscoveryClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
|
||||
return restmapper.NewShortcutExpander(mapper, discoveryClient), nil
|
||||
}
|
||||
|
||||
// ToRawKubeConfigLoader returns a clientcmd.ClientConfig using
|
||||
// clientcmd.DefaultClientConfig. With clientcmd.ClusterDefaults, namespace, and
|
||||
// impersonate configured as overwrites.
|
||||
func (c *MemoryRESTClientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig {
|
||||
if c.persistent {
|
||||
return c.toPersistentRawKubeConfigLoader()
|
||||
}
|
||||
return c.toRawKubeConfigLoader()
|
||||
}
|
||||
|
||||
func (c *MemoryRESTClientGetter) toPersistentRawKubeConfigLoader() clientcmd.ClientConfig {
|
||||
c.clientCfgMu.Lock()
|
||||
defer c.clientCfgMu.Unlock()
|
||||
|
||||
if c.clientCfg == nil {
|
||||
c.clientCfg = c.toRawKubeConfigLoader()
|
||||
}
|
||||
return c.clientCfg
|
||||
}
|
||||
|
||||
func (c *MemoryRESTClientGetter) toRawKubeConfigLoader() clientcmd.ClientConfig {
|
||||
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
// use the standard defaults for this client command
|
||||
// DEPRECATED: remove and replace with something more accurate
|
||||
loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
|
||||
|
||||
overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults}
|
||||
overrides.Context.Namespace = c.namespace
|
||||
overrides.AuthInfo.Impersonate = c.impersonate
|
||||
|
||||
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)
|
||||
}
|
382
internal/kube/wait.go
Normal file
382
internal/kube/wait.go
Normal file
@ -0,0 +1,382 @@
|
||||
/*
|
||||
Copyright 2023.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
watchtools "k8s.io/client-go/tools/watch"
|
||||
)
|
||||
|
||||
type StatusType string
|
||||
|
||||
type Status struct {
|
||||
StatusType
|
||||
Msg string
|
||||
}
|
||||
|
||||
type MinReady struct {
|
||||
int32
|
||||
Percent bool
|
||||
}
|
||||
|
||||
const (
|
||||
Ready StatusType = "READY"
|
||||
Skipped StatusType = "SKIPPED"
|
||||
Unready StatusType = "UNREADY"
|
||||
Error StatusType = "ERROR"
|
||||
)
|
||||
|
||||
// WaitOptions phase run command
|
||||
type WaitOptions struct {
|
||||
RestConfig rest.Config
|
||||
Namespace string
|
||||
LabelSelector string
|
||||
ResourceType string
|
||||
Timeout time.Duration
|
||||
Out io.Writer
|
||||
MinReady string
|
||||
Logger logr.Logger
|
||||
}
|
||||
|
||||
func getObjectStatus(obj interface{}, minReady *MinReady) Status {
|
||||
switch v := obj.(type) {
|
||||
case *corev1.Pod:
|
||||
return isPodReady(v)
|
||||
case *batchv1.Job:
|
||||
return isJobReady(v)
|
||||
case *appsv1.Deployment:
|
||||
return isDeploymentReady(v, minReady)
|
||||
case appsv1.Deployment:
|
||||
return isDeploymentReady(&v, minReady)
|
||||
case *appsv1.DaemonSet:
|
||||
return isDaemonSetReady(v, minReady)
|
||||
case *appsv1.StatefulSet:
|
||||
return isStatefulSetReady(v, minReady)
|
||||
default:
|
||||
return Status{Error, fmt.Sprintf("Unable to cast an object to any type %s\n", obj)}
|
||||
}
|
||||
}
|
||||
|
||||
func allMatch(logger logr.Logger, store cache.Store, minReady *MinReady, obj runtime.Object) (bool, error) {
|
||||
logger.Info(fmt.Sprintf("verifying ready status for %d number of objects", len(store.List())))
|
||||
for _, item := range store.List() {
|
||||
if obj != nil && item == obj {
|
||||
logger.Info(fmt.Sprintf("Skipping the item as status is already computed"))
|
||||
continue
|
||||
}
|
||||
status := getObjectStatus(item, minReady)
|
||||
logger.Info(fmt.Sprintf("object %T status computed: %s %s\n", item, status.StatusType, status.Msg))
|
||||
if status.StatusType != Ready && status.StatusType != Skipped {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
logger.Info("all objects are ready\n")
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func processEvent(logger logr.Logger, event watch.Event, minReady *MinReady) (StatusType, error) {
|
||||
metaObj, err := meta.Accessor(event.Object)
|
||||
if err != nil {
|
||||
return Error, err
|
||||
}
|
||||
metaObj.GetResourceVersion()
|
||||
logger.Info(fmt.Sprintf("watch event: type=%s, name=%s, namespace=%s, resource_ver %s",
|
||||
event.Type, metaObj.GetName(), metaObj.GetNamespace(), metaObj.GetResourceVersion()))
|
||||
|
||||
if event.Type == "ERROR" {
|
||||
return Error, errors.New(fmt.Sprintf("resource %s: got error event %s", metaObj.GetName(), event.Object))
|
||||
}
|
||||
|
||||
status := getObjectStatus(event.Object, minReady)
|
||||
logger.Info(fmt.Sprintf("object type: %T, status: %s", event.Object, status.Msg))
|
||||
return status.StatusType, nil
|
||||
}
|
||||
|
||||
func isPodReady(pod *corev1.Pod) Status {
|
||||
if isTestPod(pod) || pod.Status.Phase == "Evicted" || hasOwner(&pod.ObjectMeta, "Job") {
|
||||
return Status{Skipped,
|
||||
fmt.Sprintf("Excluding Pod %s from wait: either test pod, owned by job or evicted", pod.GetName())}
|
||||
}
|
||||
|
||||
phase := pod.Status.Phase
|
||||
if phase == "Succeeded" {
|
||||
return Status{Ready, fmt.Sprintf("Pod %s succeeded", pod.GetName())}
|
||||
}
|
||||
|
||||
if phase == "Running" {
|
||||
for _, cond := range pod.Status.Conditions {
|
||||
if cond.Type == "Ready" && cond.Status == "True" {
|
||||
return Status{Ready, fmt.Sprintf("Pod %s ready", pod.GetName())}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Status{Unready, fmt.Sprintf("Waiting for pod %s to be ready", pod.GetName())}
|
||||
}
|
||||
|
||||
func isJobReady(job *batchv1.Job) Status {
|
||||
if hasOwner(&job.ObjectMeta, "CronJob") {
|
||||
return Status{Skipped, fmt.Sprintf("Excluding Job %s from wait: owned by CronJob", job.GetName())}
|
||||
}
|
||||
|
||||
expected := int32(0)
|
||||
if job.Spec.Completions != nil {
|
||||
expected = *job.Spec.Completions
|
||||
}
|
||||
completed := job.Status.Succeeded
|
||||
|
||||
if expected != completed {
|
||||
return Status{Unready, fmt.Sprintf("Waiting for job %s to be successfully completed...", job.GetName())}
|
||||
}
|
||||
|
||||
return Status{Ready, fmt.Sprintf("Job %s successfully completed", job.GetName())}
|
||||
}
|
||||
|
||||
func isDeploymentReady(deployment *appsv1.Deployment, minReady *MinReady) Status {
|
||||
name := deployment.GetName()
|
||||
spec := deployment.Spec
|
||||
status := deployment.Status
|
||||
gen := deployment.GetGeneration()
|
||||
observed := status.ObservedGeneration
|
||||
|
||||
if gen <= observed {
|
||||
for _, cond := range status.Conditions {
|
||||
if cond.Type == "Progressing" && cond.Reason == "ProgressDeadlineExceeded" {
|
||||
return Status{Unready, fmt.Sprintf("Deployment %s exceeded its progress deadline\n", name)}
|
||||
}
|
||||
}
|
||||
replicas := int32(0)
|
||||
if spec.Replicas != nil {
|
||||
replicas = *spec.Replicas
|
||||
}
|
||||
updated := status.UpdatedReplicas
|
||||
available := status.AvailableReplicas
|
||||
if updated < replicas {
|
||||
return Status{Unready, fmt.Sprintf("Waiting for deployment %s rollout to finish: %d"+
|
||||
" out of %d new replicas have been updated...\n", name, updated, replicas)}
|
||||
}
|
||||
if replicas > updated {
|
||||
pending := replicas - updated
|
||||
return Status{Unready, fmt.Sprintf("Waiting for deployment %s rollout to finish: %d old "+
|
||||
"replicas are pending termination...\n", name, pending)}
|
||||
}
|
||||
|
||||
if minReady.Percent {
|
||||
minReady.int32 = int32(math.Ceil(float64((minReady.int32 / 100) * updated)))
|
||||
}
|
||||
|
||||
if available < minReady.int32 {
|
||||
return Status{Unready, fmt.Sprintf("Waiting for deployment %s rollout to finish: %d of %d "+
|
||||
"updated replicas are available, with min_ready=%d\n", name, available, updated, minReady.int32)}
|
||||
}
|
||||
|
||||
return Status{Ready, fmt.Sprintf("deployment %s successfully rolled out\n", name)}
|
||||
}
|
||||
|
||||
return Status{Unready, fmt.Sprintf("Waiting for deployment %s spec update to be observed...\n", name)}
|
||||
}
|
||||
|
||||
func isDaemonSetReady(daemonSet *appsv1.DaemonSet, minReady *MinReady) Status {
|
||||
name := daemonSet.GetName()
|
||||
status := daemonSet.Status
|
||||
gen := daemonSet.GetGeneration()
|
||||
observed := status.ObservedGeneration
|
||||
|
||||
if gen <= observed {
|
||||
updated := status.UpdatedNumberScheduled
|
||||
desired := status.DesiredNumberScheduled
|
||||
available := status.NumberAvailable
|
||||
|
||||
if updated < desired {
|
||||
return Status{Unready, fmt.Sprintf("Waiting for daemon set %s rollout to finish: %d out "+
|
||||
"of %d new pods have been updated...", name, updated, desired)}
|
||||
}
|
||||
|
||||
if minReady.Percent {
|
||||
minReady.int32 = int32(math.Ceil(float64((minReady.int32 / 100) * desired)))
|
||||
}
|
||||
if available < minReady.int32 {
|
||||
return Status{Unready, fmt.Sprintf("Waiting for daemon set %s rollout to finish: %d of %d "+
|
||||
"updated pods are available, with min_ready=%d", name, available, desired, minReady.int32)}
|
||||
}
|
||||
|
||||
return Status{Ready, fmt.Sprintf("daemon set %s successfully rolled out", name)}
|
||||
}
|
||||
return Status{Unready, fmt.Sprintf("Waiting for daemon set spec update to be observed...")}
|
||||
}
|
||||
|
||||
func isStatefulSetReady(statefulSet *appsv1.StatefulSet, minReady *MinReady) Status {
|
||||
name := statefulSet.GetName()
|
||||
spec := statefulSet.Spec
|
||||
status := statefulSet.Status
|
||||
gen := statefulSet.GetGeneration()
|
||||
observed := status.ObservedGeneration
|
||||
replicas := int32(0)
|
||||
if spec.Replicas != nil {
|
||||
replicas = *spec.Replicas
|
||||
}
|
||||
ready := status.ReadyReplicas
|
||||
updated := status.UpdatedReplicas
|
||||
current := status.CurrentReplicas
|
||||
|
||||
if observed == 0 || gen > observed {
|
||||
return Status{Unready, fmt.Sprintf("Waiting for statefulset spec update to be observed...")}
|
||||
}
|
||||
|
||||
if minReady.Percent {
|
||||
minReady.int32 = int32(math.Ceil(float64((minReady.int32 / 100) * replicas)))
|
||||
}
|
||||
|
||||
if replicas > 0 && ready < minReady.int32 {
|
||||
return Status{Unready, fmt.Sprintf("Waiting for statefulset %s rollout to finish: %d of %d "+
|
||||
"pods are ready, with min_ready=%d", name, ready, replicas, minReady.int32)}
|
||||
}
|
||||
|
||||
updateRev := status.UpdateRevision
|
||||
currentRev := status.CurrentRevision
|
||||
if updateRev != currentRev {
|
||||
return Status{Unready, fmt.Sprintf("waiting for statefulset rolling update to complete %d "+
|
||||
"pods at revision %s...", updated, updateRev)}
|
||||
}
|
||||
|
||||
return Status{Ready, fmt.Sprintf("statefulset rolling update complete %d pods at revision %s...",
|
||||
current, currentRev)}
|
||||
}
|
||||
|
||||
func isTestPod(u *corev1.Pod) bool {
|
||||
annotations := u.GetAnnotations()
|
||||
var testHooks []string
|
||||
if len(annotations) > 0 {
|
||||
if val, ok := annotations["helm.sh/hook"]; ok {
|
||||
hooks := strings.Split(val, ",")
|
||||
for _, h := range hooks {
|
||||
if h == "test" || h == "test-success" || h == "test-failure" {
|
||||
testHooks = append(testHooks, h)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return len(testHooks) > 0
|
||||
}
|
||||
|
||||
func hasOwner(ometa *metav1.ObjectMeta, kind string) bool {
|
||||
ownerRefs := ometa.GetOwnerReferences()
|
||||
for _, owner := range ownerRefs {
|
||||
if kind == owner.Kind {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getClient(resource string, config *rest.Config) (rest.Interface, error) {
|
||||
cs, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch resource {
|
||||
case "jobs":
|
||||
return cs.BatchV1().RESTClient(), nil
|
||||
case "pods":
|
||||
return cs.CoreV1().RESTClient(), nil
|
||||
case "daemonsets", "deployments", "statefulsets":
|
||||
return cs.AppsV1().RESTClient(), nil
|
||||
}
|
||||
|
||||
return nil, errors.New(fmt.Sprintf("Unable to find a client for resource '%s'", resource))
|
||||
}
|
||||
|
||||
func getMinReady(minReady string) (*MinReady, error) {
|
||||
ret := &MinReady{0, false}
|
||||
if minReady != "" {
|
||||
if strings.HasSuffix(minReady, "%") {
|
||||
ret.Percent = true
|
||||
}
|
||||
//var err error
|
||||
val, err := strconv.Atoi(strings.ReplaceAll(minReady, "%", ""))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.int32 = int32(val)
|
||||
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (c *WaitOptions) Wait(parent context.Context) error {
|
||||
c.Logger.Info(fmt.Sprintf("armada-operator wait , namespace %s labels %s type %s timeout %s", c.Namespace, c.LabelSelector, c.ResourceType, c.Timeout))
|
||||
|
||||
clientSet, err := getClient(c.ResourceType, &c.RestConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := watchtools.ContextWithOptionalTimeout(parent, c.Timeout)
|
||||
defer cancelFunc()
|
||||
|
||||
lw := cache.NewFilteredListWatchFromClient(clientSet, c.ResourceType, c.Namespace, func(options *metav1.ListOptions) {
|
||||
options.LabelSelector = c.LabelSelector
|
||||
c.Logger.Info(fmt.Sprintf("Label selector applied %s", options))
|
||||
})
|
||||
|
||||
minReady, err := getMinReady(c.MinReady)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var cacheStore cache.Store
|
||||
|
||||
cpu := func(store cache.Store) (bool, error) {
|
||||
cacheStore = store
|
||||
c.Logger.Info(fmt.Sprintf("number of objects to watch: %d", len(store.List())))
|
||||
if len(store.List()) == 0 {
|
||||
c.Logger.Info(fmt.Sprintf("Skipping non-required wait, no resources found.\n"))
|
||||
return true, nil
|
||||
}
|
||||
return allMatch(c.Logger, cacheStore, minReady, nil)
|
||||
}
|
||||
|
||||
cfu := func(event watch.Event) (bool, error) {
|
||||
if ready, err := processEvent(c.Logger, event, minReady); ready != Ready || err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return allMatch(c.Logger, cacheStore, minReady, event.Object)
|
||||
}
|
||||
|
||||
_, err = watchtools.UntilWithSync(ctx, lw, nil, cpu, cfu)
|
||||
return err
|
||||
}
|
85
internal/runner/log_buffer.go
Normal file
85
internal/runner/log_buffer.go
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright 2023.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runner
|
||||
|
||||
import (
|
||||
"container/ring"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
)
|
||||
|
||||
const defaultBufferSize = 5
|
||||
|
||||
func NewDebugLog(log logr.Logger) action.DebugLog {
|
||||
return func(format string, v ...interface{}) {
|
||||
log.Info(fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
type LogBuffer struct {
|
||||
mu sync.Mutex
|
||||
log action.DebugLog
|
||||
buffer *ring.Ring
|
||||
}
|
||||
|
||||
func NewLogBuffer(log action.DebugLog, size int) *LogBuffer {
|
||||
if size <= 0 {
|
||||
size = defaultBufferSize
|
||||
}
|
||||
return &LogBuffer{
|
||||
log: log,
|
||||
buffer: ring.New(size),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LogBuffer) Log(format string, v ...interface{}) {
|
||||
l.mu.Lock()
|
||||
|
||||
// Filter out duplicate log lines, this happens for example when
|
||||
// Helm is waiting on workloads to become ready.
|
||||
msg := fmt.Sprintf(format, v...)
|
||||
if prev := l.buffer.Prev(); prev.Value != msg {
|
||||
l.buffer.Value = msg
|
||||
l.buffer = l.buffer.Next()
|
||||
}
|
||||
|
||||
l.mu.Unlock()
|
||||
l.log(format, v...)
|
||||
}
|
||||
|
||||
func (l *LogBuffer) Reset() {
|
||||
l.mu.Lock()
|
||||
l.buffer = ring.New(l.buffer.Len())
|
||||
l.mu.Unlock()
|
||||
}
|
||||
|
||||
func (l *LogBuffer) String() string {
|
||||
var str string
|
||||
l.mu.Lock()
|
||||
l.buffer.Do(func(s interface{}) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
str += s.(string) + "\n"
|
||||
})
|
||||
l.mu.Unlock()
|
||||
return strings.TrimSpace(str)
|
||||
}
|
169
internal/runner/runner.go
Normal file
169
internal/runner/runner.go
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
Copyright 2023.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chartutil"
|
||||
"helm.sh/helm/v3/pkg/kube"
|
||||
"helm.sh/helm/v3/pkg/release"
|
||||
"helm.sh/helm/v3/pkg/storage/driver"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
|
||||
armadav1 "opendev.org/airship/armada-operator/api/v1"
|
||||
)
|
||||
|
||||
// Runner represents a Helm action runner capable of performing Helm
|
||||
// operations for a ArmadaChart.
|
||||
type Runner struct {
|
||||
mu sync.Mutex
|
||||
config *action.Configuration
|
||||
logBuffer *LogBuffer
|
||||
}
|
||||
|
||||
type ActionError struct {
|
||||
Err error
|
||||
CapturedLogs string
|
||||
}
|
||||
|
||||
func (e ActionError) Error() string {
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
func (e ActionError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// NewRunner constructs a new Runner configured to run Helm actions with the
|
||||
// given genericclioptions.RESTClientGetter, and the release and storage
|
||||
// namespace configured to the provided values.
|
||||
func NewRunner(getter genericclioptions.RESTClientGetter, storageNamespace string, logger logr.Logger) (*Runner, error) {
|
||||
runner := &Runner{
|
||||
logBuffer: NewLogBuffer(NewDebugLog(logger.V(2)), defaultBufferSize),
|
||||
}
|
||||
|
||||
// Default to the trace level logger for the Helm action configuration,
|
||||
// to ensure storage logs are captured.
|
||||
cfg := new(action.Configuration)
|
||||
if err := cfg.Init(getter, storageNamespace, "secret", NewDebugLog(logger)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Override the logger used by the Helm actions and Kube client with the log buffer,
|
||||
// which provides useful information in the event of an error.
|
||||
cfg.Log = runner.logBuffer.Log
|
||||
if kc, ok := cfg.KubeClient.(*kube.Client); ok {
|
||||
kc.Log = runner.logBuffer.Log
|
||||
}
|
||||
runner.config = cfg
|
||||
|
||||
return runner, nil
|
||||
}
|
||||
|
||||
// Install runs a Helm install action for the given ArmadaChart.
|
||||
func (r *Runner) Install(ctx context.Context, ac armadav1.ArmadaChart, chart *chart.Chart, values chartutil.Values) (*release.Release, error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
defer r.logBuffer.Reset()
|
||||
|
||||
install := action.NewInstall(r.config)
|
||||
install.ReleaseName = ac.Name
|
||||
install.Namespace = ac.Namespace
|
||||
|
||||
if ac.Spec.Wait.Native != nil && ac.Spec.Wait.Native.Enabled && ac.Spec.Wait.Timeout > 0 {
|
||||
install.Wait = true
|
||||
install.Timeout = time.Duration(int64(time.Second) * int64(ac.Spec.Wait.Timeout))
|
||||
}
|
||||
install.DisableOpenAPIValidation = true
|
||||
install.CreateNamespace = true
|
||||
|
||||
rel, err := install.RunWithContext(ctx, chart, values.AsMap())
|
||||
return rel, wrapActionErr(r.logBuffer, err)
|
||||
}
|
||||
|
||||
// Upgrade runs an Helm upgrade action for the given ArmadaChart.
|
||||
func (r *Runner) Upgrade(ctx context.Context, ac armadav1.ArmadaChart, chart *chart.Chart, values chartutil.Values) (*release.Release, error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
defer r.logBuffer.Reset()
|
||||
|
||||
upgrade := action.NewUpgrade(r.config)
|
||||
upgrade.Namespace = ac.Spec.Namespace
|
||||
if ac.Spec.Wait.Native != nil && ac.Spec.Wait.Native.Enabled && ac.Spec.Wait.Timeout > 0 {
|
||||
upgrade.Wait = true
|
||||
upgrade.Timeout = time.Duration(int64(time.Second) * int64(ac.Spec.Wait.Timeout))
|
||||
}
|
||||
upgrade.DisableOpenAPIValidation = true
|
||||
|
||||
rel, err := upgrade.RunWithContext(ctx, ac.Name, chart, values.AsMap())
|
||||
return rel, wrapActionErr(r.logBuffer, err)
|
||||
}
|
||||
|
||||
// Test runs an Helm test action for the given ArmadaChart.
|
||||
func (r *Runner) Test(ac armadav1.ArmadaChart) (*release.Release, error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
defer r.logBuffer.Reset()
|
||||
|
||||
r.logBuffer.Log("performing test")
|
||||
test := action.NewReleaseTesting(r.config)
|
||||
test.Namespace = ac.Spec.Namespace
|
||||
test.Timeout = time.Duration(int64(time.Second) * int64(ac.Spec.Wait.Timeout))
|
||||
|
||||
rel, err := test.Run(ac.Name)
|
||||
return rel, wrapActionErr(r.logBuffer, err)
|
||||
}
|
||||
|
||||
// Uninstall runs an Helm uninstall action
|
||||
func (r *Runner) Uninstall(ac armadav1.ArmadaChart) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
defer r.logBuffer.Reset()
|
||||
|
||||
uninstall := action.NewUninstall(r.config)
|
||||
|
||||
_, err := uninstall.Run(ac.Name)
|
||||
return wrapActionErr(r.logBuffer, err)
|
||||
}
|
||||
|
||||
// ObserveLastRelease observes the last revision, if there is one,
|
||||
// for the actual Helm release associated with the given ArmadaChart.
|
||||
func (r *Runner) ObserveLastRelease(ac armadav1.ArmadaChart) (*release.Release, error) {
|
||||
rel, err := r.config.Releases.Last(ac.Name)
|
||||
if err != nil && errors.Is(err, driver.ErrReleaseNotFound) {
|
||||
err = nil
|
||||
}
|
||||
return rel, err
|
||||
}
|
||||
|
||||
func wrapActionErr(log *LogBuffer, err error) error {
|
||||
if err == nil {
|
||||
return err
|
||||
}
|
||||
err = &ActionError{
|
||||
Err: err,
|
||||
CapturedLogs: log.String(),
|
||||
}
|
||||
return err
|
||||
}
|
126
tools/gate/playbooks/docker-image-build.yaml
Normal file
126
tools/gate/playbooks/docker-image-build.yaml
Normal file
@ -0,0 +1,126 @@
|
||||
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
- hosts: primary
|
||||
roles:
|
||||
- bindep
|
||||
- ensure-docker
|
||||
- ensure-python
|
||||
- ensure-pip
|
||||
|
||||
tasks:
|
||||
- include_vars: vars.yaml
|
||||
|
||||
- name: Debug tag generation inputs
|
||||
block:
|
||||
- debug:
|
||||
var: publish
|
||||
- debug:
|
||||
var: distro
|
||||
- debug:
|
||||
var: tags
|
||||
- debug:
|
||||
var: zuul
|
||||
- debug:
|
||||
msg: "{{ tags | to_json }}"
|
||||
|
||||
- name: Determine tags
|
||||
shell: echo '{{ tags | to_json }}' | python3 {{ zuul.project.src_dir }}/tools/image_tags.py
|
||||
environment:
|
||||
BRANCH: "{{ zuul.branch | default('') }}"
|
||||
CHANGE: "{{ zuul.change | default('') }}"
|
||||
COMMIT: "{{ zuul.newrev | default('') }}"
|
||||
PATCHSET: "{{ zuul.patchset | default('') }}"
|
||||
register: image_tags
|
||||
|
||||
- name: Debug computed tags
|
||||
debug:
|
||||
var: image_tags
|
||||
|
||||
- name: Install Docker python module for ansible docker login
|
||||
block:
|
||||
- pip:
|
||||
name: docker
|
||||
version: 4.4.4
|
||||
executable: pip3
|
||||
become: True
|
||||
|
||||
- name: Install tox python module for ansible docker login
|
||||
block:
|
||||
- pip:
|
||||
name: tox
|
||||
version: 3.28.0
|
||||
executable: pip3
|
||||
become: True
|
||||
|
||||
|
||||
# - name: Run images
|
||||
# when: not publish
|
||||
# shell: |
|
||||
# set -ex
|
||||
# sudo -E -H pip3 install tox==3.28.0
|
||||
# make run_images
|
||||
# args:
|
||||
# chdir: "{{ zuul.project.src_dir }}"
|
||||
# executable: /bin/bash
|
||||
# become: True
|
||||
|
||||
|
||||
|
||||
- name: Make images
|
||||
when: not publish
|
||||
block:
|
||||
- make:
|
||||
chdir: "{{ zuul.project.src_dir }}"
|
||||
target: images
|
||||
params:
|
||||
DISTRO: "{{ distro }}"
|
||||
IMAGE_TAG: "{{ item }}"
|
||||
with_items: "{{ image_tags.stdout_lines }}"
|
||||
|
||||
- shell: "docker images"
|
||||
register: docker_images
|
||||
|
||||
- debug:
|
||||
var: docker_images
|
||||
|
||||
become: True
|
||||
|
||||
- name: Publish images
|
||||
block:
|
||||
- docker_login:
|
||||
username: "{{ airship_armada_operator_quay_creds.username }}"
|
||||
password: "{{ airship_armada_operator_quay_creds.password }}"
|
||||
registry_url: "https://quay.io/api/v1/"
|
||||
|
||||
- make:
|
||||
chdir: "{{ zuul.project.src_dir }}"
|
||||
target: images
|
||||
params:
|
||||
DOCKER_REGISTRY: "quay.io"
|
||||
IMAGE_PREFIX: "airshipit"
|
||||
DISTRO: "{{ distro }}"
|
||||
IMAGE_TAG: "{{ item }}"
|
||||
COMMIT: "{{ zuul.newrev | default('') }}"
|
||||
PUSH_IMAGE: "true"
|
||||
with_items: "{{ image_tags.stdout_lines }}"
|
||||
|
||||
- shell: "docker images"
|
||||
register: docker_images
|
||||
|
||||
- debug:
|
||||
var: docker_images
|
||||
|
||||
when: publish
|
||||
become: True
|
19
tools/gate/playbooks/vars.yaml
Normal file
19
tools/gate/playbooks/vars.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
# Copyright 2017 The Openstack-Helm Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
docker_daemon:
|
||||
group: zuul
|
||||
registry-mirrors:
|
||||
- "http://{{ zuul_site_mirror_fqdn }}:8082/"
|
||||
storage-driver: overlay2
|
@ -0,0 +1,37 @@
|
||||
# Copyright 2020 AT&T Intellectual Property. All other rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
- name: Disable systemd-resolved service
|
||||
systemd:
|
||||
state: stopped
|
||||
enabled: no
|
||||
masked: yes
|
||||
daemon_reload: yes
|
||||
name: systemd-resolved
|
||||
become: yes
|
||||
|
||||
- name: Remove local stub dns from resolv.conf, if it exists
|
||||
lineinfile:
|
||||
path: /etc/resolv.conf
|
||||
state: absent
|
||||
regexp: '^nameserver.*127.0.0.1'
|
||||
become: yes
|
||||
|
||||
- name: Add upstream nameservers in resolv.conf
|
||||
blockinfile:
|
||||
path: /etc/resolv.conf
|
||||
block: |
|
||||
nameserver 8.8.8.8
|
||||
nameserver 8.8.4.4
|
||||
become: yes
|
15
tools/gate/roles/disable-systemd-resolved/tasks/main.yaml
Normal file
15
tools/gate/roles/disable-systemd-resolved/tasks/main.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright 2020 AT&T Intellectual Property. All other rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
- include: disable-systemd-resolved.yaml
|
126
tools/image_tags.py
Normal file
126
tools/image_tags.py
Normal file
@ -0,0 +1,126 @@
|
||||
#!/usr/bin/python3
|
||||
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT 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 json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
LOG_FORMAT = '%(asctime)s %(levelname)-8s %(name)s:%(filename)s:%(lineno)3d:%(funcName)s %(message)s' # noqa
|
||||
|
||||
|
||||
class TagGenExeception(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def read_config(stream, env):
|
||||
config = {}
|
||||
try:
|
||||
config['tags'] = json.load(stream)
|
||||
except ValueError:
|
||||
LOG.exception('Failed to decode JSON from input stream')
|
||||
config['tags'] = {}
|
||||
|
||||
LOG.debug('Configuration after reading stream: %s', config)
|
||||
|
||||
config['context'] = {
|
||||
'branch': env.get('BRANCH'),
|
||||
'change': env.get('CHANGE'),
|
||||
'commit': env.get('COMMIT'),
|
||||
'ps': env.get('PATCHSET'),
|
||||
}
|
||||
|
||||
LOG.info('Final configuration: %s', config)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def build_tags(config):
|
||||
tags = config.get('tags', {}).get('static', [])
|
||||
LOG.debug('Dynamic tags: %s', tags)
|
||||
tags.extend(build_dynamic_tags(config))
|
||||
LOG.info('All tags: %s', tags)
|
||||
return tags
|
||||
|
||||
|
||||
def build_dynamic_tags(config):
|
||||
dynamic_tags = []
|
||||
|
||||
dynamic_tags.extend(_build_branch_tag(config))
|
||||
dynamic_tags.extend(_build_commit_tag(config))
|
||||
dynamic_tags.extend(_build_ps_tag(config))
|
||||
|
||||
return dynamic_tags
|
||||
|
||||
|
||||
def _build_branch_tag(config):
|
||||
if _valid_dg(config, 'branch'):
|
||||
return [config['context']['branch']]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def _build_commit_tag(config):
|
||||
if _valid_dg(config, 'commit'):
|
||||
return [config['context']['commit']]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def _build_ps_tag(config):
|
||||
if _valid_dg(config, 'patch_set', 'change') and _valid_dg(
|
||||
config, 'patch_set', 'ps'):
|
||||
return [
|
||||
'%s-%s' % (config['context']['change'], config['context']['ps'])
|
||||
]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def _valid_dg(config, dynamic_tag, context_name=None):
|
||||
if context_name is None:
|
||||
context_name = dynamic_tag
|
||||
|
||||
if config.get('tags', {}).get('dynamic', {}).get(dynamic_tag):
|
||||
if config.get('context', {}).get(context_name):
|
||||
return True
|
||||
else:
|
||||
raise TagGenExeception('Dynamic tag "%s" requested, but "%s"'
|
||||
' not found in context' % (dynamic_tag,
|
||||
context_name))
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
config = read_config(sys.stdin, os.environ)
|
||||
tags = build_tags(config)
|
||||
|
||||
for tag in tags:
|
||||
print(tag)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig(format=LOG_FORMAT, level=logging.WARNING)
|
||||
try:
|
||||
main()
|
||||
except TagGenExeception:
|
||||
LOG.exception('Failed to generate tags')
|
||||
sys.exit(1)
|
||||
except Exception:
|
||||
LOG.exception('Unexpected exception')
|
||||
sys.exit(2)
|
Loading…
Reference in New Issue
Block a user