Initial commit
Change-Id: I7e9a2194a2e83a04dc3e91b26978e063c3c9b6aa Signed-off-by: Ruslan Aliev <raliev@mirantis.com>
This commit is contained in:
parent
d2b43f3f1f
commit
828339c24e
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-go-docker-build-gate-ubuntu_focal
|
||||
|
||||
gate:
|
||||
jobs:
|
||||
- armada-go-docker-build-gate-ubuntu_focal
|
||||
|
||||
post:
|
||||
jobs:
|
||||
- armada-go-docker-publish-ubuntu_focal
|
||||
|
||||
|
||||
- nodeset:
|
||||
name: armada-go-single-node-focal
|
||||
nodes:
|
||||
- name: primary
|
||||
label: ubuntu-focal
|
||||
|
||||
|
||||
- job:
|
||||
name: armada-go-docker-build-gate-ubuntu_focal
|
||||
timeout: 3600
|
||||
run: tools/gate/playbooks/docker-image-build.yaml
|
||||
nodeset: armada-go-single-node-focal
|
||||
vars:
|
||||
publish: false
|
||||
distro: ubuntu_focal
|
||||
tags:
|
||||
dynamic:
|
||||
patch_set: true
|
||||
|
||||
|
||||
- job:
|
||||
name: armada-go-docker-publish-ubuntu_focal
|
||||
timeout: 3600
|
||||
run: tools/gate/playbooks/docker-image-build.yaml
|
||||
nodeset: armada-go-single-node-focal
|
||||
secrets:
|
||||
- airship_armada_go_quay_creds
|
||||
vars:
|
||||
publish: true
|
||||
distro: ubuntu_focal
|
||||
tags:
|
||||
dynamic:
|
||||
branch: true
|
||||
commit: true
|
||||
static:
|
||||
- latest
|
||||
|
||||
|
||||
- secret:
|
||||
name: airship_armada_go_quay_creds
|
||||
data:
|
||||
username: !encrypted/pkcs1-oaep
|
||||
- WT0T3twqEWlkYWkvqmuWvvU/cYXMVurCPjELm0ilZqVBBj9traoHaUgURfYiNJSu6+u+X
|
||||
vSugo9uaPgCXM5oQbAyWmtwDH+WHVOmdflx+Q2usmaym7JEET+PYh7DEKsrf3/YRtotn3
|
||||
3r8hEXFbaq0+k5MJdc+byQ6CX2PS2W4I8TTRbH+jMDEDttEAXNDpG1C63Geol9deo7c2u
|
||||
eQXdzTVcyZ+fn0/nb8bMdAjC+KpWCpU6O2/kMYStdDQYr105JYD1e36YVeGheSDAHqHIj
|
||||
1LDHqtjGMeiliimizZ08Lero/yjZiUpQCUGVYqyqi9Tpk5OmecJR9ub0W5pTBPmEMkbiN
|
||||
R/8owZMczjWdhD7/Vej9rJAu8iHGnRMJoWYCtLD0De0q6OxQEpSWJl6c7aKsmRorAB3Jt
|
||||
sM+GuVwEBllaj67l176Ql4T662zIBVaSUckcsVjQef+JMMj6CKgF+U43pylwFUk/ilnP5
|
||||
HJfo8AUtW1P5hpU8xLB4mcS1h5K0ynneWIydiB2aUBsQ34e0T/u1OLfKiLdMBaaPS4Olu
|
||||
ks16VnS1VDNXlt0hKEylS4IX77oxtXnRnFpV/3Z3ohlrccvT23FiUr2k0maFTsqQYBs2F
|
||||
KJxMTtI/x9G4kk7FtZKyg2w6BYhEgOhmajcqksfEGSgytmhugVq6RC22hHROTM=
|
||||
password: !encrypted/pkcs1-oaep
|
||||
- bNJ9MY8MvMpwIsvGmY9GsZz1b9XCUeOAlpvL/KAXRGT7sBjt15nvobF+Y/RXjGia+kq/C
|
||||
Y8Yz8DEwHAZ9EjqsY20uhoIC89ArjziGxq+ZFl89HHvmWkgs+TYuBh9A0MZUiAOJNkJR4
|
||||
yQIWPYvfzknutFqZXGzQ2GPGvp+Lk45PZJs4io91+WQX1DT16fdWpB/CtVfZCrFOyLswM
|
||||
58f+K56wf+I2tly9KoAp83gYVE+mGwkqqBUdv6jNcnm9/UMxTGFj1zgKNJdF0sSpT1T1I
|
||||
DwynMkKDcvJCsUoH0S0EO/JYd2ne5VsKrI5/4EU2gmBrvvQFyCqccjYHc3557TN+bAe0H
|
||||
6xtQSZfM31i/IiGBhR1fqQbyAWVmA27i5pmn5TcekI7YpELCeoIRY5M/BQ5slqpTvbp4C
|
||||
VEez4iQvXoHepfRtpFN3/zATFolTqhCldJN+bh6wdg3d8lSecsetD6cU3Fm7aHJuLYoSr
|
||||
a4xPhx6s7B1J6wq0P14ADGl5/0CmzeZ3uGw94PRGvg8YAWswUV/DXWogbOH/EEStdsOia
|
||||
JaXpU/oVkmC5NcIp3A+6F3NCft8gQCTKecoFBt9/7suvjmCIY9y26SBQ0gOHEjbUzfikT
|
||||
FuwYIUDaaLDU+Dz+PfdrKSM63O/uBhrDO+yo+ovqu5PPLksBu42sOrZleAbZIA=
|
201
LICENSE
Normal file
201
LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
132
Makefile
Normal file
132
Makefile
Normal file
@ -0,0 +1,132 @@
|
||||
# APP INFO
|
||||
BUILD_DIR := $(shell mktemp -d)
|
||||
DOCKER_REGISTRY ?= quay.io
|
||||
IMAGE_PREFIX ?= airshipit
|
||||
IMAGE_NAME ?= armada-go
|
||||
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-go: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)
|
||||
|
||||
##@ Build
|
||||
|
||||
.PHONY: build
|
||||
build: ## Build manager binary.
|
||||
go build -o bin/armada-go main.go
|
||||
|
||||
.PHONY: run
|
||||
run: ## Run a controller from your host.
|
||||
go run 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}
|
||||
|
||||
check-docker:
|
||||
@if [ -z $$(which docker) ]; then \
|
||||
echo "Missing \`docker\` client which is required for development"; \
|
||||
exit 2; \
|
||||
fi
|
||||
images: check-docker build_armada_go
|
||||
_BASE_IMAGE_ARG := $(if $(UBUNTU_BASE_IMAGE),--build-arg FROM="${UBUNTU_BASE_IMAGE}" ,)
|
||||
build_armada_go:
|
||||
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-go/Dockerfile.$(DISTRO) \
|
||||
$(_BASE_IMAGE_ARG) \
|
||||
--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-go/Dockerfile.$(DISTRO) \
|
||||
$(_BASE_IMAGE_ARG) \
|
||||
--build-arg HELM_ARTIFACT_URL=$(HELM_ARTIFACT_URL) .
|
||||
endif
|
||||
ifeq ($(PUSH_IMAGE), true)
|
||||
docker push $(IMAGE)
|
||||
endif
|
2
README.md
Normal file
2
README.md
Normal file
@ -0,0 +1,2 @@
|
||||
# armada-go
|
||||
A Golang-based orchestrator for managing a collection of Kubernetes Helm charts
|
45
cmd/apply.go
Normal file
45
cmd/apply.go
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"opendev.org/airship/armada-go/pkg/apply"
|
||||
"opendev.org/airship/armada-go/pkg/config"
|
||||
)
|
||||
|
||||
// NewApplyCommand creates a command to apply armada manifests
|
||||
func NewApplyCommand(cfgFactory config.Factory) *cobra.Command {
|
||||
p := &apply.RunCommand{Factory: cfgFactory}
|
||||
|
||||
runCmd := &cobra.Command{
|
||||
Use: "apply",
|
||||
Short: "armada-go command to apply manifests",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
p.Manifests = args[0]
|
||||
p.Out = cmd.OutOrStdout()
|
||||
return p.RunE()
|
||||
},
|
||||
}
|
||||
|
||||
var metricsOutput string
|
||||
flags := runCmd.Flags()
|
||||
flags.StringVar(&p.TargetManifest, "target-manifest", "", "target manifest")
|
||||
flags.StringVar(&metricsOutput, "metrics-output", "", "metrics output")
|
||||
|
||||
return runCmd
|
||||
}
|
81
cmd/root.go
Normal file
81
cmd/root.go
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
cfg "opendev.org/airship/armada-go/pkg/config"
|
||||
"opendev.org/airship/armada-go/pkg/log"
|
||||
)
|
||||
|
||||
const longRoot = `Armada-Go is a tool for managing multiple Helm charts with dependencies by centralizing
|
||||
all configurations in a single Armada YAML and providing life-cycle hooks for all Helm releases.`
|
||||
|
||||
// RootOptions stores global flags values
|
||||
type RootOptions struct {
|
||||
Debug bool
|
||||
ArmadaConfigPath string
|
||||
}
|
||||
|
||||
// NewArmadaCommand creates a root `armada` command with the default commands attached
|
||||
func NewArmadaCommand(out io.Writer) *cobra.Command {
|
||||
rootCmd, settings := NewRootCommand(out)
|
||||
return AddDefaultArmadaCommands(rootCmd,
|
||||
cfg.CreateFactory(&settings.ArmadaConfigPath))
|
||||
}
|
||||
|
||||
// NewRootCommand creates the root `armada` command. All other commands are
|
||||
// subcommands branching from this one
|
||||
func NewRootCommand(out io.Writer) (*cobra.Command, *RootOptions) {
|
||||
options := &RootOptions{}
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "armada",
|
||||
Short: "A Golang-based orchestrator for managing a collection of Kubernetes Helm charts",
|
||||
Long: longRoot,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
log.Init(options.Debug, cmd.ErrOrStderr())
|
||||
},
|
||||
}
|
||||
rootCmd.SetOut(out)
|
||||
initFlags(options, rootCmd)
|
||||
|
||||
return rootCmd, options
|
||||
}
|
||||
|
||||
// AddDefaultArmadaCommands is a convenience function for adding all the
|
||||
// default commands to armada-go
|
||||
func AddDefaultArmadaCommands(cmd *cobra.Command, factory cfg.Factory) *cobra.Command {
|
||||
cmd.AddCommand(NewServerCommand(factory))
|
||||
cmd.AddCommand(NewApplyCommand(factory))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func initFlags(options *RootOptions, cmd *cobra.Command) {
|
||||
flags := cmd.PersistentFlags()
|
||||
flags.BoolVar(&options.Debug, "debug", false, "enable verbose output")
|
||||
|
||||
defaultArmadaConfigDir := filepath.Join("$HOME", ".armada")
|
||||
|
||||
defaultArmadaConfigPath := filepath.Join(defaultArmadaConfigDir, "config")
|
||||
flags.StringVar(&options.ArmadaConfigPath, "armadaconf", "",
|
||||
`path to the armada-go configuration file. Defaults to "`+defaultArmadaConfigPath+`"`)
|
||||
}
|
50
cmd/server.go
Normal file
50
cmd/server.go
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"opendev.org/airship/armada-go/pkg/config"
|
||||
"opendev.org/airship/armada-go/pkg/server"
|
||||
)
|
||||
|
||||
const (
|
||||
runLong = `
|
||||
Run armada-go in server mode
|
||||
`
|
||||
runExample = `
|
||||
Run armada-go server
|
||||
# armada-go server
|
||||
`
|
||||
)
|
||||
|
||||
// NewServerCommand creates a command to run specific phase
|
||||
func NewServerCommand(cfgFactory config.Factory) *cobra.Command {
|
||||
p := &server.RunCommand{Factory: cfgFactory}
|
||||
|
||||
runCmd := &cobra.Command{
|
||||
Use: "server",
|
||||
Short: "armada-go command to run server",
|
||||
Long: runLong[1:],
|
||||
Args: cobra.ExactArgs(0),
|
||||
Example: runExample,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return p.RunE()
|
||||
},
|
||||
}
|
||||
|
||||
return runCmd
|
||||
}
|
242
crd.yaml
Normal file
242
crd.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: {}
|
72
go.mod
Normal file
72
go.mod
Normal file
@ -0,0 +1,72 @@
|
||||
module opendev.org/airship/armada-go
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-logr/logr v1.2.4
|
||||
github.com/spf13/cobra v1.7.0
|
||||
golang.org/x/sync v0.3.0
|
||||
k8s.io/api v0.28.4
|
||||
k8s.io/apiextensions-apiserver v0.28.3
|
||||
k8s.io/apimachinery v0.28.4
|
||||
k8s.io/client-go v0.28.4
|
||||
k8s.io/klog/v2 v2.100.1
|
||||
opendev.org/airship/armada-operator v0.0.0-20240131234736-165edb913367
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.9.1 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/oauth2 v0.8.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
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect
|
||||
k8s.io/utils v0.0.0-20230505201702-9f6742963106 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.16.3 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect
|
||||
)
|
211
go.sum
Normal file
211
go.sum
Normal file
@ -0,0 +1,211 @@
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/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/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-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-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
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/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.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/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
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/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
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/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
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.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
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-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.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-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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.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.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.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-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.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
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.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-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.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY=
|
||||
k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0=
|
||||
k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08=
|
||||
k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc=
|
||||
k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8=
|
||||
k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg=
|
||||
k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY=
|
||||
k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4=
|
||||
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/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU=
|
||||
k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
opendev.org/airship/armada-operator v0.0.0-20240131234736-165edb913367 h1:Ae/TMu6lXzpF4KlLGpshu6oL9BZ8OwYYNGNvnLyBnVw=
|
||||
opendev.org/airship/armada-operator v0.0.0-20240131234736-165edb913367/go.mod h1:0hmfND6t5ZuyHB3R7TmsAreqzF4vfc/q3LwX18gFldI=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
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/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.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
38
images/armada-go/Dockerfile.ubuntu_focal
Normal file
38
images/armada-go/Dockerfile.ubuntu_focal
Normal file
@ -0,0 +1,38 @@
|
||||
ARG FROM=ubuntu:20.04
|
||||
ARG GO_IMAGE=golang:1.20.5-buster
|
||||
FROM ${GO_IMAGE} as builder
|
||||
|
||||
ENV PATH "/usr/local/go/bin:$PATH"
|
||||
ENV CGO_ENABLED=0
|
||||
WORKDIR /go/src/
|
||||
COPY go.mod /go.sum ./
|
||||
RUN go mod download
|
||||
COPY . ./
|
||||
RUN go build -v -o /usr/local/bin/armada-go ./
|
||||
|
||||
FROM ${FROM} as release
|
||||
|
||||
LABEL org.opencontainers.image.authors='airship-discuss@lists.airshipit.org, irc://#airshipit@freenode' \
|
||||
org.opencontainers.image.url='https://airshipit.org' \
|
||||
org.opencontainers.image.documentation='https://docs.airshipit.org/armada-go' \
|
||||
org.opencontainers.image.source='https://opendev.org/airship/armada-go' \
|
||||
org.opencontainers.image.vendor='The Airship Authors' \
|
||||
org.opencontainers.image.licenses='Apache-2.0'
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV LANG=C.UTF-8
|
||||
ENV LC_ALL=C.UTF-8
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
WORKDIR /armada
|
||||
COPY --from=builder /usr/local/bin/armada-go /usr/local-bin/armada
|
||||
COPY crd.yaml /armada/crd.yaml
|
||||
|
||||
# Add armada user
|
||||
RUN useradd -u 1000 -g users -d $(pwd) armada
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/armada"]
|
||||
CMD ["server"]
|
||||
|
||||
USER armada
|
29
main.go
Normal file
29
main.go
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"opendev.org/airship/armada-go/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := cmd.NewArmadaCommand(os.Stdout).Execute(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
383
pkg/apply/apply.go
Normal file
383
pkg/apply/apply.go
Normal file
@ -0,0 +1,383 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package apply
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextension "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilyaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"opendev.org/airship/armada-go/pkg/config"
|
||||
armadawait "opendev.org/airship/armada-go/pkg/wait"
|
||||
armadav1 "opendev.org/airship/armada-operator/api/v1"
|
||||
)
|
||||
|
||||
// RunCommand phase run command
|
||||
type RunCommand struct {
|
||||
Factory config.Factory
|
||||
Manifests string
|
||||
TargetManifest string
|
||||
Out io.Writer
|
||||
|
||||
airManifest *AirshipManifest
|
||||
airGroups map[string]*AirshipChartGroup
|
||||
airCharts map[string]*AirshipChart
|
||||
}
|
||||
|
||||
type AirshipDocument struct {
|
||||
Schema string `json:"schema,omitempty"`
|
||||
Metadata AirshipMetadata `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type AirshipMetadata struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type AirshipManifest struct {
|
||||
AirshipDocument
|
||||
AirshipManifestSpec `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type AirshipManifestSpec struct {
|
||||
ChartGroups []string `json:"chart_groups,omitempty"`
|
||||
ReleasePrefix string `json:"release_prefix,omitempty"`
|
||||
}
|
||||
|
||||
type AirshipChartGroup struct {
|
||||
AirshipDocument
|
||||
AirshipChartGroupSpec `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type AirshipChartGroupSpec struct {
|
||||
ChartGroup []string `json:"chart_group,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Sequenced bool `json:"sequenced,omitempty"`
|
||||
}
|
||||
|
||||
type AirshipChart struct {
|
||||
AirshipDocument
|
||||
armadav1.ArmadaChartSpec `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// RunE runs the phase
|
||||
func (c *RunCommand) RunE() error {
|
||||
klog.InitFlags(nil)
|
||||
klog.SetOutput(c.Out)
|
||||
if err := flag.Set("v", "5"); err != nil {
|
||||
return err
|
||||
}
|
||||
klog.V(2).Infof("armada-go apply, manifests path %s", c.Manifests)
|
||||
|
||||
if err := c.ParseManifests(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k8sConfig, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
klog.V(2).Infoln("Unable to load in-cluster kubeconfig, reason: ", err)
|
||||
k8sConfig, err = clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
|
||||
clientcmd.NewDefaultClientConfigLoadingRules(), &clientcmd.ConfigOverrides{}).ClientConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.VerifyNamespaces(k8sConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dc := dynamic.NewForConfigOrDie(k8sConfig)
|
||||
resClient := dc.Resource(schema.GroupVersionResource{
|
||||
Group: armadav1.ArmadaChartGroup,
|
||||
Version: armadav1.ArmadaChartVersion,
|
||||
Resource: armadav1.ArmadaChartPlural,
|
||||
})
|
||||
|
||||
acClient := armadav1.NewForConfigOrDie(k8sConfig)
|
||||
|
||||
if err := c.CheckCRD(k8sConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, cgName := range c.airManifest.ChartGroups {
|
||||
cg := c.airGroups[cgName]
|
||||
klog.V(5).Infof("processing chart group %s, sequenced %s", cgName, cg.Sequenced)
|
||||
if !cg.Sequenced {
|
||||
eg := errgroup.Group{}
|
||||
for _, cName := range cg.ChartGroup {
|
||||
klog.V(5).Infof("adding 1 chart to wg %s", cName)
|
||||
chp := c.airCharts[cName]
|
||||
chpc := c.ConvertChart(chp)
|
||||
eg.Go(func() error {
|
||||
return c.InstallChart(chpc, resClient, acClient)
|
||||
})
|
||||
}
|
||||
if err := eg.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
for _, cName := range cg.ChartGroup {
|
||||
klog.V(5).Infof("sequential chart install %s", cName)
|
||||
if err = c.InstallChart(c.ConvertChart(c.airCharts[cName]), resClient, acClient); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RunCommand) InstallChart(
|
||||
chart *armadav1.ArmadaChart,
|
||||
resClient dynamic.NamespaceableResourceInterface,
|
||||
restConfig *rest.RESTClient) error {
|
||||
|
||||
klog.V(5).Infof("installing chart %s %s %s", chart.GetName(), chart.Name, chart.Namespace)
|
||||
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(chart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if oldObj, err := resClient.Namespace(chart.Namespace).Get(
|
||||
context.Background(), chart.GetName(), metav1.GetOptions{}); err != nil {
|
||||
klog.V(5).Infof("unable to get chart %s: %s, creating", chart.Name, err.Error())
|
||||
if _, err = resClient.Namespace(chart.Namespace).Create(
|
||||
context.Background(), &unstructured.Unstructured{Object: obj}, metav1.CreateOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
klog.V(5).Infof("chart has been successfully created %s", chart.Name)
|
||||
} else {
|
||||
uObj := &unstructured.Unstructured{Object: obj}
|
||||
uObj.SetResourceVersion(oldObj.GetResourceVersion())
|
||||
klog.V(5).Infof("chart %s was found, updating", chart.Name)
|
||||
if _, err = resClient.Namespace(chart.Namespace).Update(
|
||||
context.Background(), uObj, metav1.UpdateOptions{}); err != nil {
|
||||
klog.V(5).Infof("resource update error: %s", err.Error())
|
||||
if strings.Contains(err.Error(), "the object has been modified") {
|
||||
klog.V(5).Infof("resource expired, retrying %s", err.Error())
|
||||
return c.InstallChart(chart, resClient, restConfig)
|
||||
}
|
||||
return err
|
||||
}
|
||||
klog.V(5).Infof("chart has been successfully updated %s", chart.Name)
|
||||
}
|
||||
|
||||
wOpts := armadawait.WaitOptions{
|
||||
Getter: restConfig,
|
||||
Namespace: chart.Namespace,
|
||||
LabelSelector: fmt.Sprintf("%s=%s", armadav1.ArmadaChartLabel,
|
||||
fmt.Sprintf("%s-%s", c.airManifest.ReleasePrefix, chart.Spec.Release)),
|
||||
ResourceType: "armadacharts.armada.airshipit.io",
|
||||
Timeout: time.Second * time.Duration(chart.Spec.Wait.Timeout),
|
||||
Logger: klog.FromContext(context.Background()),
|
||||
}
|
||||
|
||||
err = wOpts.Wait(context.Background())
|
||||
klog.V(5).Infof("finished with chart %s", chart.GetName())
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *RunCommand) ConvertChart(chart *AirshipChart) *armadav1.ArmadaChart {
|
||||
return &armadav1.ArmadaChart{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: armadav1.ArmadaChartKind,
|
||||
APIVersion: armadav1.ArmadaChartAPIVersion,
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("%s-%s", c.airManifest.ReleasePrefix, chart.Release),
|
||||
Namespace: chart.Namespace,
|
||||
Labels: map[string]string{
|
||||
armadav1.ArmadaChartLabel: fmt.Sprintf("%s-%s", c.airManifest.ReleasePrefix, chart.Release),
|
||||
},
|
||||
},
|
||||
Spec: chart.ArmadaChartSpec,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RunCommand) CheckCRD(restConfig *rest.Config) error {
|
||||
crdClient := apiextension.NewForConfigOrDie(restConfig)
|
||||
if _, err := crdClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.Background(), "armadacharts.armada.airshipit.io", metav1.GetOptions{}); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
klog.V(5).Infof("armadacharts CRD not found, creating: %s", err.Error())
|
||||
objToapp, err := c.ReadCRD()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = crdClient.ApiextensionsV1().CustomResourceDefinitions().Create(context.Background(), objToapp, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
klog.V(5).Infof("error while creating crd %t", err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RunCommand) ReadCRD() (*apiextv1.CustomResourceDefinition, error) {
|
||||
sch := runtime.NewScheme()
|
||||
_ = scheme.AddToScheme(sch)
|
||||
_ = apiextv1.AddToScheme(sch)
|
||||
|
||||
decode := serializer.NewCodecFactory(sch).UniversalDeserializer().Decode
|
||||
data, err := os.ReadFile("crd.yaml")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
obj, _, err := decode(data, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
crdTo := obj.(*apiextv1.CustomResourceDefinition)
|
||||
return crdTo, nil
|
||||
}
|
||||
|
||||
func (c *RunCommand) VerifyNamespaces(rsc *rest.Config) error {
|
||||
cs := kubernetes.NewForConfigOrDie(rsc)
|
||||
|
||||
namespaces := make(map[string]bool)
|
||||
for _, cgname := range c.airManifest.ChartGroups {
|
||||
cg := c.airGroups[cgname]
|
||||
for _, chrt := range cg.ChartGroup {
|
||||
ns := c.airCharts[chrt].Namespace
|
||||
if _, ok := namespaces[ns]; !ok {
|
||||
namespaces[ns] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, _ := range namespaces {
|
||||
klog.V(5).Infof("processing namespace %s", k)
|
||||
if _, err := cs.CoreV1().Namespaces().Get(context.Background(), k, metav1.GetOptions{}); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
klog.V(5).Infof("namespace %s not found, creating", k)
|
||||
if _, err = cs.CoreV1().Namespaces().Create(context.Background(), &v1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: k}}, metav1.CreateOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
klog.V(5).Infof("all namespaces validated successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RunCommand) ValidateManifests() error {
|
||||
if c.airManifest == nil {
|
||||
return errors.New("no or multiple armada manifest found")
|
||||
}
|
||||
|
||||
for _, cgname := range c.airManifest.ChartGroups {
|
||||
if cg, ok := c.airGroups[cgname]; ok {
|
||||
for _, cName := range cg.ChartGroup {
|
||||
if chrt, ok := c.airCharts[cName]; ok {
|
||||
if chrt.Release == "" || chrt.Namespace == "" {
|
||||
return errors.New(fmt.Sprintf("chart document with name %s found does not have release or ns", cName))
|
||||
}
|
||||
} else {
|
||||
return errors.New(fmt.Sprintf("no chart document with name %s found", cName))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return errors.New(fmt.Sprintf("no group document with name %s found", cgname))
|
||||
}
|
||||
}
|
||||
klog.V(5).Infof("all airship manifests validated successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RunCommand) ParseManifests() error {
|
||||
klog.V(5).Infof("parsing manifests started, path: %s", c.Manifests)
|
||||
f, err := os.Open(c.Manifests)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
c.airCharts = map[string]*AirshipChart{}
|
||||
c.airGroups = map[string]*AirshipChartGroup{}
|
||||
multidocReader := utilyaml.NewYAMLReader(bufio.NewReader(f))
|
||||
for {
|
||||
buf, err := multidocReader.Read()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
var typeMeta AirshipDocument
|
||||
if err := yaml.Unmarshal(buf, &typeMeta); err != nil {
|
||||
klog.V(2).Infof("unmarshalling error %s, continuing...", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
if typeMeta.Schema == "armada/Manifest/v1" {
|
||||
if (c.TargetManifest != "" && typeMeta.Metadata.Name == c.TargetManifest) ||
|
||||
(c.TargetManifest == "" && c.airManifest == nil) {
|
||||
var airManifest AirshipManifest
|
||||
if err := yaml.Unmarshal(buf, &airManifest); err != nil {
|
||||
return err
|
||||
}
|
||||
klog.V(2).Infof("found airship manifest %s", airManifest.Metadata.Name)
|
||||
c.airManifest = &airManifest
|
||||
}
|
||||
}
|
||||
if typeMeta.Schema == "armada/ChartGroup/v1" {
|
||||
var cg AirshipChartGroup
|
||||
if err := yaml.Unmarshal(buf, &cg); err != nil {
|
||||
return err
|
||||
}
|
||||
c.airGroups[typeMeta.Metadata.Name] = &cg
|
||||
}
|
||||
|
||||
if typeMeta.Schema == "armada/Chart/v1" {
|
||||
var chrt AirshipChart
|
||||
if err := yaml.Unmarshal(buf, &chrt); err != nil {
|
||||
return err
|
||||
}
|
||||
c.airCharts[typeMeta.Metadata.Name] = &chrt
|
||||
}
|
||||
}
|
||||
|
||||
return c.ValidateManifests()
|
||||
}
|
169
pkg/config/config.go
Normal file
169
pkg/config/config.go
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"opendev.org/airship/armada-go/pkg/log"
|
||||
"opendev.org/airship/armada-go/pkg/util"
|
||||
)
|
||||
|
||||
// Where possible, json tags match the cli argument names.
|
||||
// Top level config objects and all values required for proper functioning are not "omitempty".
|
||||
// Any truly optional piece of config is allowed to be omitted.
|
||||
|
||||
// Config holds the information required by armada-go commands
|
||||
// It is somewhat a superset of what a kubeconfig looks like
|
||||
type Config struct {
|
||||
// +optional
|
||||
Kind string `json:"kind,omitempty"`
|
||||
|
||||
// loadedConfigPath is the full path to the location of the config
|
||||
// file from which this config was loaded
|
||||
// +not persisted in file
|
||||
loadedConfigPath string
|
||||
//fileSystem kustfs.FileSystem
|
||||
}
|
||||
|
||||
// Factory is a function which returns ready to use config object and error (if any)
|
||||
type Factory func() (*Config, error)
|
||||
|
||||
// CreateFactory returns function which creates ready to use Config object
|
||||
func CreateFactory(armadaConfigPath *string) Factory {
|
||||
return func() (*Config, error) {
|
||||
cfg := NewEmptyConfig()
|
||||
|
||||
var acp string
|
||||
if armadaConfigPath != nil {
|
||||
acp = *armadaConfigPath
|
||||
}
|
||||
|
||||
cfg.initConfigPath(acp)
|
||||
err := cfg.LoadConfig()
|
||||
if err != nil {
|
||||
// Should stop armada-go
|
||||
log.Print("Failed to load or initialize config: ", err)
|
||||
CreateConfig(acp, true)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
}
|
||||
|
||||
// CreateConfig saves default config to the specified path
|
||||
func CreateConfig(armadaConfigPath string, overwrite bool) error {
|
||||
cfg := NewConfig()
|
||||
cfg.initConfigPath(armadaConfigPath)
|
||||
return cfg.PersistConfig(overwrite)
|
||||
}
|
||||
|
||||
// initConfigPath - Initializes loadedConfigPath variable for Config object
|
||||
func (c *Config) initConfigPath(armadaConfigPath string) {
|
||||
switch {
|
||||
case armadaConfigPath != "":
|
||||
// The loadedConfigPath may already have been received as a command line argument
|
||||
c.loadedConfigPath = armadaConfigPath
|
||||
case os.Getenv("ARMADA_CONFIG") != "":
|
||||
// Otherwise, we can check if we got the path via ENVIRONMENT variable
|
||||
c.loadedConfigPath = os.Getenv("ARMADA_CONFIG")
|
||||
default:
|
||||
// Otherwise, we'll try putting it in the home directory
|
||||
c.loadedConfigPath = filepath.Join(util.UserHomeDir(), ".armada", "config")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) LoadConfig() error {
|
||||
// If I can read from the file, load from it
|
||||
// throw an error otherwise
|
||||
data, err := os.ReadFile(c.loadedConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return yaml.Unmarshal(data, c)
|
||||
}
|
||||
|
||||
// NewEmptyConfig returns an initialized Config object with no default values
|
||||
func NewEmptyConfig() *Config {
|
||||
return &Config{}
|
||||
}
|
||||
|
||||
// NewConfig returns a newly initialized Config object
|
||||
func NewConfig() *Config {
|
||||
return &Config{
|
||||
Kind: "kind",
|
||||
//fileSystem: kustfs.MakeFsInMemory(),
|
||||
}
|
||||
}
|
||||
|
||||
// ErrConfigFileExists is returned when there is an existing file at specified location
|
||||
type ErrConfigFileExists struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
func (e ErrConfigFileExists) Error() string {
|
||||
return fmt.Sprintf("could not create default config at %s, file already exists", e.Path)
|
||||
}
|
||||
|
||||
// ToYaml returns a YAML document
|
||||
// It serializes the given Config object to a valid YAML document
|
||||
func (c *Config) ToYaml() ([]byte, error) {
|
||||
return yaml.Marshal(&c)
|
||||
}
|
||||
|
||||
// PersistConfig updates the airshipctl config file to match
|
||||
// the current Config object.
|
||||
// If file did not previously exist, the file will be created.
|
||||
// The file will be overwritten if overwrite argument set to true
|
||||
func (c *Config) PersistConfig(overwrite bool) error {
|
||||
if _, err := os.Stat(c.loadedConfigPath); err == nil && !overwrite {
|
||||
return ErrConfigFileExists{Path: c.loadedConfigPath}
|
||||
}
|
||||
|
||||
airshipConfigYaml, err := c.ToYaml()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteFile doesn't create the directory, create it if needed
|
||||
dir := filepath.Dir(c.loadedConfigPath)
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Change the permission of directory
|
||||
err = os.Chmod(dir, os.FileMode(0755))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write the Airship Config file
|
||||
err = os.WriteFile(c.loadedConfigPath, airshipConfigYaml, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Change the permission of config file
|
||||
err = os.Chmod(c.loadedConfigPath, os.FileMode(0644))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
92
pkg/log/log.go
Normal file
92
pkg/log/log.go
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
debug = false
|
||||
armadaLog = log.New(os.Stderr, "[armada-go] ", log.LstdFlags)
|
||||
)
|
||||
|
||||
// Init initializes settings related to logging
|
||||
func Init(debugFlag bool, out io.Writer) {
|
||||
debug = debugFlag
|
||||
if debug {
|
||||
armadaLog.SetFlags(log.LstdFlags | log.Llongfile)
|
||||
}
|
||||
armadaLog.SetOutput(out)
|
||||
}
|
||||
|
||||
// DebugEnabled returns whether the debug level is set
|
||||
func DebugEnabled() bool {
|
||||
return debug
|
||||
}
|
||||
|
||||
// Debug is a wrapper for log.Debug
|
||||
func Debug(v ...interface{}) {
|
||||
if debug {
|
||||
writeLog(v...)
|
||||
}
|
||||
}
|
||||
|
||||
// Debugf is a wrapper for log.Debugf
|
||||
func Debugf(format string, v ...interface{}) {
|
||||
if debug {
|
||||
writeLog(fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Print is a wrapper for log.Print
|
||||
func Print(v ...interface{}) {
|
||||
writeLog(v...)
|
||||
}
|
||||
|
||||
// Printf is a wrapper for log.Printf
|
||||
func Printf(format string, v ...interface{}) {
|
||||
writeLog(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Fatal is a wrapper for log.Fatal
|
||||
func Fatal(v ...interface{}) {
|
||||
armadaLog.Fatal(v...)
|
||||
}
|
||||
|
||||
// Fatalf is a wrapper for log.Fatalf
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
armadaLog.Fatalf(format, v...)
|
||||
}
|
||||
|
||||
// Writer returns log output writer object
|
||||
func Writer() io.Writer {
|
||||
return armadaLog.Writer()
|
||||
}
|
||||
|
||||
func writeLog(v ...interface{}) {
|
||||
if debug {
|
||||
err := armadaLog.Output(3, fmt.Sprint(v...))
|
||||
if err != nil {
|
||||
log.Print(v...)
|
||||
log.Print(err)
|
||||
}
|
||||
} else {
|
||||
armadaLog.Print(v...)
|
||||
}
|
||||
}
|
42
pkg/server/server.go
Normal file
42
pkg/server/server.go
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"opendev.org/airship/armada-go/pkg/config"
|
||||
"opendev.org/airship/armada-go/pkg/log"
|
||||
)
|
||||
|
||||
// RunCommand phase run command
|
||||
type RunCommand struct {
|
||||
Factory config.Factory
|
||||
}
|
||||
|
||||
func Apply(c *gin.Context) {
|
||||
}
|
||||
|
||||
// RunE runs the phase
|
||||
func (c *RunCommand) RunE() error {
|
||||
_, err := c.Factory()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("armada-go server has been started")
|
||||
r := gin.Default()
|
||||
r.GET("/apply", Apply)
|
||||
return r.Run(":8000")
|
||||
}
|
49
pkg/util/homedir.go
Normal file
49
pkg/util/homedir.go
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UserHomeDir is a utility function that wraps os.UserHomeDir and returns no
|
||||
// errors. If the user has no home directory, the returned value will be the
|
||||
// empty string
|
||||
func UserHomeDir() string {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
homeDir = ""
|
||||
}
|
||||
return homeDir
|
||||
}
|
||||
|
||||
// ExpandTilde expands the path to include the home directory if the path
|
||||
// is prefixed with `~`. If it isn't prefixed with `~` or has no slash after tilde,
|
||||
// the path is returned as-is.
|
||||
func ExpandTilde(path string) string {
|
||||
// Just tilde - return current $HOME dir
|
||||
if path == "~" {
|
||||
return UserHomeDir()
|
||||
}
|
||||
// If path starts with ~/ - expand it
|
||||
if strings.HasPrefix(path, "~/") {
|
||||
return filepath.Join(UserHomeDir(), path[1:])
|
||||
}
|
||||
|
||||
// empty strings, absolute paths, ~<(dir/file)name> return as-is
|
||||
return path
|
||||
}
|
147
pkg/wait/wait.go
Normal file
147
pkg/wait/wait.go
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package wait
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
watchtools "k8s.io/client-go/tools/watch"
|
||||
|
||||
armadav1 "opendev.org/airship/armada-operator/api/v1"
|
||||
)
|
||||
|
||||
type StatusType string
|
||||
|
||||
type Status struct {
|
||||
StatusType
|
||||
Msg string
|
||||
}
|
||||
|
||||
const (
|
||||
Ready StatusType = "READY"
|
||||
Skipped StatusType = "SKIPPED"
|
||||
Unready StatusType = "UNREADY"
|
||||
Error StatusType = "ERROR"
|
||||
)
|
||||
|
||||
// WaitOptions phase run command
|
||||
type WaitOptions struct {
|
||||
Getter cache.Getter
|
||||
Namespace string
|
||||
LabelSelector string
|
||||
ResourceType string
|
||||
Timeout time.Duration
|
||||
Logger logr.Logger
|
||||
}
|
||||
|
||||
func getObjectStatus(obj interface{}) Status {
|
||||
switch v := obj.(type) {
|
||||
case *armadav1.ArmadaChart:
|
||||
return isArmadaChartReady(v)
|
||||
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, obj runtime.Object) (bool, error) {
|
||||
for _, item := range store.List() {
|
||||
if obj != nil && item == obj {
|
||||
continue
|
||||
}
|
||||
status := getObjectStatus(item)
|
||||
logger.Info(fmt.Sprintf("all match object %T is ready returned %s\n", item, status.StatusType))
|
||||
logger.Info(status.Msg)
|
||||
if status.StatusType != Ready && status.StatusType != Skipped {
|
||||
logger.Info(fmt.Sprintf("all match exiting false due to %s\n", status.StatusType))
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
logger.Info("all objects are ready\n")
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func processEvent(logger logr.Logger, event watch.Event) (StatusType, error) {
|
||||
metaObj, err := meta.Accessor(event.Object)
|
||||
if err != nil {
|
||||
return Error, err
|
||||
}
|
||||
|
||||
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)
|
||||
logger.Info(fmt.Sprintf("object type: %T, status: %s", event.Object, status.Msg))
|
||||
return status.StatusType, nil
|
||||
}
|
||||
|
||||
func isArmadaChartReady(ac *armadav1.ArmadaChart) Status {
|
||||
if ac.Status.ObservedGeneration == ac.Generation {
|
||||
for _, cond := range ac.Status.Conditions {
|
||||
if cond.Type == "Ready" && cond.Status == "True" {
|
||||
return Status{Ready, fmt.Sprintf("armadachart %s ready", ac.GetName())}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Status{Unready, fmt.Sprintf("Waiting for armadachart %s to be ready", ac.GetName())}
|
||||
}
|
||||
|
||||
// Wait runs the phase
|
||||
func (c *WaitOptions) Wait(parent context.Context) error {
|
||||
c.Logger.Info(fmt.Sprintf("armada-go wait , namespace %s labels %s type %s timeout %s", c.Namespace, c.LabelSelector, c.ResourceType, c.Timeout))
|
||||
|
||||
ctx, cancelFunc := watchtools.ContextWithOptionalTimeout(parent, c.Timeout)
|
||||
defer cancelFunc()
|
||||
|
||||
lw := cache.NewFilteredListWatchFromClient(c.Getter, "armadacharts", c.Namespace, func(options *metav1.ListOptions) {
|
||||
options.LabelSelector = c.LabelSelector
|
||||
c.Logger.Info(fmt.Sprintf("Label selector applied %s", options))
|
||||
})
|
||||
|
||||
var cacheStore cache.Store
|
||||
|
||||
cpu := func(store cache.Store) (bool, error) {
|
||||
cacheStore = store
|
||||
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, nil)
|
||||
}
|
||||
|
||||
cfu := func(event watch.Event) (bool, error) {
|
||||
if ready, err := processEvent(c.Logger, event); ready != Ready || err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return allMatch(c.Logger, cacheStore, event.Object)
|
||||
}
|
||||
|
||||
_, err := watchtools.UntilWithSync(ctx, lw, nil, cpu, cfu)
|
||||
c.Logger.Info(fmt.Sprintf("wait completed %s\n", c.LabelSelector))
|
||||
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_go_quay_creds.username }}"
|
||||
password: "{{ airship_armada_go_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
|
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…
x
Reference in New Issue
Block a user