mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-20 09:38:49 +01:00
Compare commits
55 Commits
dependabot
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3aaca0bbe8 | ||
|
|
85f62dff9e | ||
|
|
97f08aaf4c | ||
|
|
ad7a69a798 | ||
|
|
fc588538bc | ||
|
|
675ae6a991 | ||
|
|
6cc0fd8b8c | ||
|
|
26e1cf0438 | ||
|
|
30d3fcb84a | ||
|
|
3a3a7f5044 | ||
|
|
6c34dd828f | ||
|
|
de7003f530 | ||
|
|
8981903603 | ||
|
|
509c567a40 | ||
|
|
c722a71820 | ||
|
|
1aaf76f230 | ||
|
|
71ad60e89f | ||
|
|
9c46f77bb1 | ||
|
|
b6256aae9f | ||
|
|
f802190a24 | ||
|
|
e07c1edece | ||
|
|
ed15da5271 | ||
|
|
d34dbeac0d | ||
|
|
c4d3a54126 | ||
|
|
622671ece4 | ||
|
|
cf6a7abd30 | ||
|
|
a6a394ba93 | ||
|
|
d315814020 | ||
|
|
d46872d7e8 | ||
|
|
ba7f0fcb47 | ||
|
|
5fcfc22298 | ||
|
|
9e486dfad4 | ||
|
|
674978cd58 | ||
|
|
020d284a00 | ||
|
|
09b874613d | ||
|
|
44cb2ce51a | ||
|
|
6eaed1e64e | ||
|
|
2a63b44af0 | ||
|
|
5571cf1333 | ||
|
|
ed0add3087 | ||
|
|
d27849cdc4 | ||
|
|
3a3f490abf | ||
|
|
2dc95fffb7 | ||
|
|
9cf978c168 | ||
|
|
3891b29d82 | ||
|
|
ed916702d6 | ||
|
|
c4eba32f0e | ||
|
|
046a62420e | ||
|
|
1b393bc473 | ||
|
|
d8c38bb45b | ||
|
|
249ce9317f | ||
|
|
a094d5abb8 | ||
|
|
3f31224a6e | ||
|
|
649b1b7b75 | ||
|
|
2c691a874b |
@@ -60,10 +60,8 @@ commands:
|
||||
name: Install Go deps
|
||||
command: |
|
||||
set -x
|
||||
go get github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||
go get github.com/jstemmer/go-junit-report
|
||||
go get github.com/mattn/goreman
|
||||
go get golang.org/x/tools/cmd/goimports
|
||||
install_tools:
|
||||
steps:
|
||||
- run:
|
||||
@@ -71,7 +69,14 @@ commands:
|
||||
command: mkdir -p /tmp/dl
|
||||
- restore_cache:
|
||||
keys:
|
||||
- dl-v6
|
||||
- dl-v7
|
||||
- run:
|
||||
name: Install Kubectl v1.14.0
|
||||
command: |
|
||||
set -x
|
||||
[ -e /tmp/dl/kubectl ] || curl -sLf -C - -o /tmp/dl/kubectl https://storage.googleapis.com/kubernetes-release/release/v1.14.0/bin/linux/amd64/kubectl
|
||||
sudo cp /tmp/dl/kubectl /usr/local/bin/kubectl
|
||||
sudo chmod +x /usr/local/bin/kubectl
|
||||
- run:
|
||||
name: Install Kubectx v0.6.3
|
||||
command: |
|
||||
@@ -118,17 +123,8 @@ commands:
|
||||
sudo cp /tmp/dl/kustomize_${VER} /usr/local/go/bin/kustomize
|
||||
sudo chmod +x /usr/local/go/bin/kustomize
|
||||
kustomize version
|
||||
- run:
|
||||
name: Install Git LFS plugin
|
||||
command: |
|
||||
set -x
|
||||
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
|
||||
sleep 5
|
||||
sudo killall -9 apt-get || true
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y git-lfs openssh-client
|
||||
- save_cache:
|
||||
key: dl-v6
|
||||
key: dl-v7
|
||||
paths:
|
||||
- /tmp/dl
|
||||
save_go_cache:
|
||||
@@ -217,14 +213,13 @@ jobs:
|
||||
name: Create namespace
|
||||
command: |
|
||||
set -x
|
||||
cat /etc/rancher/k3s/k3s.yaml | sed "s/localhost/`hostname`/" | tee ~/.kube/config
|
||||
echo "127.0.0.1 `hostname`" | sudo tee -a /etc/hosts
|
||||
kubectl create ns argocd-e2e
|
||||
kubens argocd-e2e
|
||||
# install the certificates (not 100% sure we need this)
|
||||
sudo cp /var/lib/rancher/k3s/server/tls/token-ca.crt /usr/local/share/ca-certificates/k3s.crt
|
||||
sudo update-ca-certificates
|
||||
# create the kubecfg, again - not sure we need this
|
||||
cat /etc/rancher/k3s/k3s.yaml | sed "s/localhost/`hostname`/" | tee ~/.kube/config
|
||||
echo "127.0.0.1 `hostname`" | sudo tee -a /etc/hosts
|
||||
- run:
|
||||
name: Apply manifests
|
||||
command: kustomize build test/manifests/base | kubectl apply -f -
|
||||
|
||||
@@ -77,7 +77,9 @@ RUN echo 'deb http://deb.debian.org/debian stretch-backports main' >> /etc/apt/s
|
||||
RUN groupadd -g 999 argocd && \
|
||||
useradd -r -u 999 -g argocd argocd && \
|
||||
mkdir -p /home/argocd && \
|
||||
chown argocd:argocd /home/argocd && \
|
||||
chown argocd:0 /home/argocd && \
|
||||
chmod g=u /home/argocd && \
|
||||
chmod g=u /etc/passwd && \
|
||||
apt-get update && \
|
||||
apt-get install -y git git-lfs && \
|
||||
apt-get clean && \
|
||||
@@ -89,6 +91,9 @@ COPY --from=builder /usr/local/bin/helm /usr/local/bin/helm
|
||||
COPY --from=builder /usr/local/bin/kubectl /usr/local/bin/kubectl
|
||||
COPY --from=builder /usr/local/bin/kustomize /usr/local/bin/kustomize
|
||||
COPY --from=builder /usr/local/bin/aws-iam-authenticator /usr/local/bin/aws-iam-authenticator
|
||||
# script to add current (possibly arbitrary) user to /etc/passwd at runtime
|
||||
# (if it's not already there, to be openshift friendly)
|
||||
COPY uid_entrypoint.sh /usr/local/bin/uid_entrypoint.sh
|
||||
|
||||
# support for mounting configuration from a configmap
|
||||
RUN mkdir -p /app/config/ssh && \
|
||||
|
||||
10
Gopkg.lock
generated
10
Gopkg.lock
generated
@@ -89,6 +89,14 @@
|
||||
pruneopts = ""
|
||||
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a6ee710e45210bafe11f2f28963571be2ac8809f9a7b675a6d2c02302a1ce1a9"
|
||||
name = "github.com/bouk/monkey"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "5df1f207ff77e025801505ae4d903133a0b4353f"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e04162bd6a6d4950541bae744c968108e14913b1cebccf29f7650b573f44adb3"
|
||||
name = "github.com/casbin/casbin"
|
||||
@@ -1589,6 +1597,7 @@
|
||||
"github.com/argoproj/pkg/errors",
|
||||
"github.com/argoproj/pkg/exec",
|
||||
"github.com/argoproj/pkg/time",
|
||||
"github.com/bouk/monkey",
|
||||
"github.com/casbin/casbin",
|
||||
"github.com/casbin/casbin/model",
|
||||
"github.com/casbin/casbin/persist",
|
||||
@@ -1646,6 +1655,7 @@
|
||||
"github.com/yuin/gopher-lua",
|
||||
"golang.org/x/crypto/bcrypt",
|
||||
"golang.org/x/crypto/ssh",
|
||||
"golang.org/x/crypto/ssh/knownhosts",
|
||||
"golang.org/x/crypto/ssh/terminal",
|
||||
"golang.org/x/net/context",
|
||||
"golang.org/x/oauth2",
|
||||
|
||||
18
Makefile
18
Makefile
@@ -18,7 +18,7 @@ PATH:=$(PATH):$(PWD)/hack
|
||||
|
||||
# docker image publishing options
|
||||
DOCKER_PUSH?=false
|
||||
IMAGE_TAG?=latest
|
||||
IMAGE_TAG?=
|
||||
# perform static compilation
|
||||
STATIC_BUILD?=true
|
||||
# build development images
|
||||
@@ -27,7 +27,9 @@ DEV_IMAGE?=false
|
||||
LINT_GOGC?=off
|
||||
LINT_CONCURRENCY?=8
|
||||
# Set timeout for linter
|
||||
LINT_DEADLINE?=1m0s
|
||||
LINT_DEADLINE?=4m0s
|
||||
CODEGEN=true
|
||||
LINT=true
|
||||
|
||||
override LDFLAGS += \
|
||||
-X ${PACKAGE}.version=${VERSION} \
|
||||
@@ -74,7 +76,7 @@ codegen-local: protogen clientgen openapigen manifests-local
|
||||
|
||||
.PHONY: codegen
|
||||
codegen: dev-tools-image
|
||||
$(call run-in-dev-tool,make codegen-local)
|
||||
@if [ "$(CODGEN)" = "true" ]; then $(call run-in-dev-tool,make codegen-local) ; fi
|
||||
|
||||
.PHONY: cli
|
||||
cli: clean-debug
|
||||
@@ -153,12 +155,16 @@ builder-image:
|
||||
dep-ensure:
|
||||
dep ensure -no-vendor
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
.PHONY: lint-local
|
||||
lint-local: build
|
||||
# golangci-lint does not do a good job of formatting imports
|
||||
goimports -local github.com/argoproj/argo-cd -w `find . ! -path './vendor/*' ! -path './pkg/client/*' -type f -name '*.go'`
|
||||
goimports -local github.com/argoproj/argo-cd -w `find . ! -path './vendor/*' ! -path './pkg/client/*' ! -path '*.pb.go' ! -path '*.gw.go' -type f -name '*.go'`
|
||||
GOGC=$(LINT_GOGC) golangci-lint run --fix --verbose --concurrency $(LINT_CONCURRENCY) --deadline $(LINT_DEADLINE)
|
||||
|
||||
.PHONY: lint
|
||||
lint: dev-tools-image
|
||||
@if [ "$(LINT)" = "true" ]; then $(call run-in-dev-tool,make lint-local LINT_CONCURRENCY=$(LINT_CONCURRENCY) LINT_DEADLINE=$(LINT_DEADLINE) LINT_GOGC=$(LINT_GOGC)); fi
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
go build -v `go list ./... | grep -v 'resource_customizations\|test/e2e'`
|
||||
|
||||
4
Procfile
4
Procfile
@@ -2,6 +2,6 @@ controller: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/a
|
||||
api-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-server/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --staticassets ui/dist/app"
|
||||
dex: sh -c "go run ./cmd/argocd-util/main.go gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml quay.io/dexidp/dex:v2.14.0 serve /dex.yaml"
|
||||
redis: docker run --rm --name argocd-redis -i -p ${ARGOCD_E2E_REDIS_PORT:-6379}:${ARGOCD_E2E_REDIS_PORT:-6379} redis:5.0.3-alpine --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}
|
||||
repo-server: sh -c "FORCE_LOG_COLORS=1 go run ./cmd/argocd-repo-server/main.go --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"
|
||||
repo-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-repo-server/main.go --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"
|
||||
ui: sh -c 'cd ui && ${ARGOCD_E2E_YARN_CMD:-yarn} start'
|
||||
git-server: test/fixture/testrepos/start-git.sh
|
||||
git-server: test/fixture/testrepos/start-git.sh
|
||||
|
||||
@@ -1740,6 +1740,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"clusterHelp": {
|
||||
"type": "object",
|
||||
"title": "Help settings",
|
||||
"properties": {
|
||||
"chatText": {
|
||||
"type": "string",
|
||||
"title": "the text for getting chat help, defaults to \"Chat now!\""
|
||||
},
|
||||
"chatUrl": {
|
||||
"type": "string",
|
||||
"title": "the URL for getting chat help, this will typically be your Slack channel for support"
|
||||
}
|
||||
}
|
||||
},
|
||||
"clusterOIDCConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1775,6 +1789,9 @@
|
||||
"googleAnalytics": {
|
||||
"$ref": "#/definitions/clusterGoogleAnalyticsConfig"
|
||||
},
|
||||
"help": {
|
||||
"$ref": "#/definitions/clusterHelp"
|
||||
},
|
||||
"kustomizeOptions": {
|
||||
"$ref": "#/definitions/v1alpha1KustomizeOptions"
|
||||
},
|
||||
@@ -3380,6 +3397,10 @@
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"hook": {
|
||||
"type": "boolean",
|
||||
"format": "boolean"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -46,6 +46,7 @@ func newCommand() *cobra.Command {
|
||||
logLevel string
|
||||
glogLevel int
|
||||
metricsPort int
|
||||
kubectlParallelismLimit int64
|
||||
cacheSrc func() (*cache.Cache, error)
|
||||
)
|
||||
var command = cobra.Command{
|
||||
@@ -84,7 +85,8 @@ func newCommand() *cobra.Command {
|
||||
cache,
|
||||
resyncDuration,
|
||||
time.Duration(selfHealTimeoutSeconds)*time.Second,
|
||||
metricsPort)
|
||||
metricsPort,
|
||||
kubectlParallelismLimit)
|
||||
errors.CheckError(err)
|
||||
|
||||
log.Infof("Application Controller (version: %s) starting (namespace: %s)", common.GetVersion(), namespace)
|
||||
@@ -109,6 +111,7 @@ func newCommand() *cobra.Command {
|
||||
command.Flags().IntVar(&glogLevel, "gloglevel", 0, "Set the glog logging level")
|
||||
command.Flags().IntVar(&metricsPort, "metrics-port", common.DefaultPortArgoCDMetrics, "Start metrics server on given port")
|
||||
command.Flags().IntVar(&selfHealTimeoutSeconds, "self-heal-timeout-seconds", 5, "Specifies timeout between application self heal attempts")
|
||||
command.Flags().Int64Var(&kubectlParallelismLimit, "kubectl-parallelism-limit", 0, "Number of allowed concurrent kubectl fork/execs.")
|
||||
|
||||
cacheSrc = cache.AddCacheFlagsToCmd(&command)
|
||||
return &command
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"syscall"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
@@ -108,7 +109,7 @@ func NewRunDexCommand() *cobra.Command {
|
||||
} else {
|
||||
err = ioutil.WriteFile("/tmp/dex.yaml", dexCfgBytes, 0644)
|
||||
errors.CheckError(err)
|
||||
log.Info(string(dexCfgBytes))
|
||||
log.Info(redactor(string(dexCfgBytes)))
|
||||
cmd = exec.Command("dex", "serve", "/tmp/dex.yaml")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
@@ -554,6 +555,11 @@ func NewClusterConfig() *cobra.Command {
|
||||
return command
|
||||
}
|
||||
|
||||
func redactor(dirtyString string) string {
|
||||
dirtyString = regexp.MustCompile("(clientSecret: )[^ \n]*").ReplaceAllString(dirtyString, "$1********")
|
||||
return regexp.MustCompile("(secret: )[^ \n]*").ReplaceAllString(dirtyString, "$1********")
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := NewCommand().Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
|
||||
73
cmd/argocd-util/main_test.go
Normal file
73
cmd/argocd-util/main_test.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var textToRedact = `
|
||||
- config:
|
||||
clientID: aabbccddeeff00112233
|
||||
clientSecret: $dex.github.clientSecret
|
||||
orgs:
|
||||
- name: your-github-org
|
||||
redirectURI: https://argocd.example.com/api/dex/callback
|
||||
id: github
|
||||
name: GitHub
|
||||
type: github
|
||||
grpc:
|
||||
addr: 0.0.0.0:5557
|
||||
issuer: https://argocd.example.com/api/dex
|
||||
oauth2:
|
||||
skipApprovalScreen: true
|
||||
staticClients:
|
||||
- id: argo-cd
|
||||
name: Argo CD
|
||||
redirectURIs:
|
||||
- https://argocd.example.com/auth/callback
|
||||
secret: Dis9M-GA11oTwZVQQWdDklPQw-sWXZkWJFyyEhMs
|
||||
- id: argo-cd-cli
|
||||
name: Argo CD CLI
|
||||
public: true
|
||||
redirectURIs:
|
||||
- http://localhost
|
||||
storage:
|
||||
type: memory
|
||||
web:
|
||||
http: 0.0.0.0:5556`
|
||||
|
||||
var expectedRedaction = `
|
||||
- config:
|
||||
clientID: aabbccddeeff00112233
|
||||
clientSecret: ********
|
||||
orgs:
|
||||
- name: your-github-org
|
||||
redirectURI: https://argocd.example.com/api/dex/callback
|
||||
id: github
|
||||
name: GitHub
|
||||
type: github
|
||||
grpc:
|
||||
addr: 0.0.0.0:5557
|
||||
issuer: https://argocd.example.com/api/dex
|
||||
oauth2:
|
||||
skipApprovalScreen: true
|
||||
staticClients:
|
||||
- id: argo-cd
|
||||
name: Argo CD
|
||||
redirectURIs:
|
||||
- https://argocd.example.com/auth/callback
|
||||
secret: ********
|
||||
- id: argo-cd-cli
|
||||
name: Argo CD CLI
|
||||
public: true
|
||||
redirectURIs:
|
||||
- http://localhost
|
||||
storage:
|
||||
type: memory
|
||||
web:
|
||||
http: 0.0.0.0:5556`
|
||||
|
||||
func TestSecretsRedactor(t *testing.T) {
|
||||
assert.Equal(t, expectedRedaction, redactor(textToRedact))
|
||||
}
|
||||
@@ -5,11 +5,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
@@ -20,7 +17,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/google/shlex"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
@@ -444,6 +440,12 @@ func setAppOptions(flags *pflag.FlagSet, app *argoappv1.Application, appOpts *ap
|
||||
}
|
||||
app.Spec.SyncPolicy.Automated.Prune = appOpts.autoPrune
|
||||
}
|
||||
if flags.Changed("self-heal") {
|
||||
if app.Spec.SyncPolicy == nil || app.Spec.SyncPolicy.Automated == nil {
|
||||
log.Fatal("Cannot set --self-helf: application not configured with automatic sync")
|
||||
}
|
||||
app.Spec.SyncPolicy.Automated.SelfHeal = appOpts.selfHeal
|
||||
}
|
||||
|
||||
return visited
|
||||
}
|
||||
@@ -544,6 +546,7 @@ type appOptions struct {
|
||||
project string
|
||||
syncPolicy string
|
||||
autoPrune bool
|
||||
selfHeal bool
|
||||
namePrefix string
|
||||
directoryRecurse bool
|
||||
configManagementPlugin string
|
||||
@@ -565,6 +568,7 @@ func addAppFlags(command *cobra.Command, opts *appOptions) {
|
||||
command.Flags().StringVar(&opts.project, "project", "", "Application project name")
|
||||
command.Flags().StringVar(&opts.syncPolicy, "sync-policy", "", "Set the sync policy (one of: automated, none)")
|
||||
command.Flags().BoolVar(&opts.autoPrune, "auto-prune", false, "Set automatic pruning when sync is automated")
|
||||
command.Flags().BoolVar(&opts.selfHeal, "self-heal", false, "Set self healing when sync is automated")
|
||||
command.Flags().StringVar(&opts.namePrefix, "nameprefix", "", "Kustomize nameprefix")
|
||||
command.Flags().BoolVar(&opts.directoryRecurse, "directory-recurse", false, "Recurse directory")
|
||||
command.Flags().StringVar(&opts.configManagementPlugin, "config-management-plugin", "", "Config management plugin name")
|
||||
@@ -744,7 +748,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
Short: shortDesc,
|
||||
Long: shortDesc + "\nUses 'diff' to render the difference. KUBECTL_EXTERNAL_DIFF environment variable can be used to select your own diff tool.\nReturns the following exit codes: 2 on general errors, 1 when a diff is found, and 0 when no diff is found",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
if len(args) != 1 {
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(2)
|
||||
}
|
||||
@@ -844,8 +848,10 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
}
|
||||
|
||||
foundDiffs := false
|
||||
for i := range items {
|
||||
item := items[i]
|
||||
for _, item := range items {
|
||||
if item.target != nil && hook.IsHook(item.target) || item.live != nil && hook.IsHook(item.live) {
|
||||
continue
|
||||
}
|
||||
overrides := make(map[string]argoappv1.ResourceOverride)
|
||||
for k := range argoSettings.ResourceOverrides {
|
||||
val := argoSettings.ResourceOverrides[k]
|
||||
@@ -869,7 +875,8 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
}
|
||||
|
||||
foundDiffs = true
|
||||
printDiff(item.key.Name, target, live)
|
||||
err = diff.PrintDiff(item.key.Name, target, live)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
}
|
||||
if foundDiffs {
|
||||
@@ -884,43 +891,6 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
return command
|
||||
}
|
||||
|
||||
func printDiff(name string, live *unstructured.Unstructured, target *unstructured.Unstructured) {
|
||||
tempDir, err := ioutil.TempDir("", "argocd-diff")
|
||||
errors.CheckError(err)
|
||||
|
||||
targetFile := path.Join(tempDir, name)
|
||||
targetData := []byte("")
|
||||
if target != nil {
|
||||
targetData, err = yaml.Marshal(target)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
err = ioutil.WriteFile(targetFile, targetData, 0644)
|
||||
errors.CheckError(err)
|
||||
|
||||
liveFile := path.Join(tempDir, fmt.Sprintf("%s-live.yaml", name))
|
||||
liveData := []byte("")
|
||||
if live != nil {
|
||||
liveData, err = yaml.Marshal(live)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
err = ioutil.WriteFile(liveFile, liveData, 0644)
|
||||
errors.CheckError(err)
|
||||
|
||||
cmdBinary := "diff"
|
||||
var args []string
|
||||
if envDiff := os.Getenv("KUBECTL_EXTERNAL_DIFF"); envDiff != "" {
|
||||
parts, err := shlex.Split(envDiff)
|
||||
errors.CheckError(err)
|
||||
cmdBinary = parts[0]
|
||||
args = parts[1:]
|
||||
}
|
||||
|
||||
cmd := exec.Command(cmdBinary, append(args, liveFile, targetFile)...)
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = os.Stdout
|
||||
_ = cmd.Run()
|
||||
}
|
||||
|
||||
// NewApplicationDeleteCommand returns a new instance of an `argocd app delete` command
|
||||
func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
@@ -1213,7 +1183,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
var localObjsStrings []string
|
||||
if local != "" {
|
||||
app, err := appIf.Get(context.Background(), &applicationpkg.ApplicationQuery{Name: &appName})
|
||||
|
||||
errors.CheckError(err)
|
||||
if app.Spec.SyncPolicy != nil && app.Spec.SyncPolicy.Automated != nil {
|
||||
log.Fatal("Cannot use local sync when Automatic Sync Policy is enabled")
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/semaphore"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -85,6 +86,7 @@ type ApplicationController struct {
|
||||
refreshRequestedApps map[string]CompareWith
|
||||
refreshRequestedAppsMutex *sync.Mutex
|
||||
metricsServer *metrics.MetricsServer
|
||||
kubectlSemaphore *semaphore.Weighted
|
||||
}
|
||||
|
||||
type ApplicationControllerConfig struct {
|
||||
@@ -103,6 +105,7 @@ func NewApplicationController(
|
||||
appResyncPeriod time.Duration,
|
||||
selfHealTimeout time.Duration,
|
||||
metricsPort int,
|
||||
kubectlParallelismLimit int64,
|
||||
) (*ApplicationController, error) {
|
||||
db := db.NewDB(namespace, settingsMgr, kubeClientset)
|
||||
kubectlCmd := kube.KubectlCmd{}
|
||||
@@ -123,7 +126,12 @@ func NewApplicationController(
|
||||
settingsMgr: settingsMgr,
|
||||
selfHealTimeout: selfHealTimeout,
|
||||
}
|
||||
if kubectlParallelismLimit > 0 {
|
||||
ctrl.kubectlSemaphore = semaphore.NewWeighted(kubectlParallelismLimit)
|
||||
}
|
||||
kubectlCmd.OnKubectlRun = ctrl.onKubectlRun
|
||||
appInformer, appLister := ctrl.newApplicationInformerAndLister()
|
||||
|
||||
projInformer := v1alpha1.NewAppProjectInformer(applicationClientset, namespace, appResyncPeriod, cache.Indexers{})
|
||||
metricsAddr := fmt.Sprintf("0.0.0.0:%d", metricsPort)
|
||||
ctrl.metricsServer = metrics.NewMetricsServer(metricsAddr, appLister, func() error {
|
||||
@@ -141,6 +149,23 @@ func NewApplicationController(
|
||||
return &ctrl, nil
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) onKubectlRun(command string) (util.Closer, error) {
|
||||
ctrl.metricsServer.IncKubectlExec(command)
|
||||
if ctrl.kubectlSemaphore != nil {
|
||||
if err := ctrl.kubectlSemaphore.Acquire(context.Background(), 1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctrl.metricsServer.IncKubectlExecPending(command)
|
||||
}
|
||||
return util.NewCloser(func() error {
|
||||
if ctrl.kubectlSemaphore != nil {
|
||||
ctrl.kubectlSemaphore.Release(1)
|
||||
ctrl.metricsServer.DecKubectlExecPending(command)
|
||||
}
|
||||
return nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func isSelfReferencedApp(app *appv1.Application, ref v1.ObjectReference) bool {
|
||||
gvk := ref.GroupVersionKind()
|
||||
return ref.UID == app.UID &&
|
||||
@@ -233,6 +258,7 @@ func (ctrl *ApplicationController) managedResources(comparisonResult *comparison
|
||||
Name: res.Name,
|
||||
Group: res.Group,
|
||||
Kind: res.Kind,
|
||||
Hook: res.Hook,
|
||||
}
|
||||
|
||||
target := res.Target
|
||||
@@ -646,7 +672,13 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
||||
defer func() {
|
||||
reconcileDuration := time.Since(startTime)
|
||||
ctrl.metricsServer.IncReconcile(origApp, reconcileDuration)
|
||||
logCtx := log.WithFields(log.Fields{"application": origApp.Name, "time_ms": reconcileDuration.Seconds() * 1e3, "level": comparisonLevel})
|
||||
logCtx := log.WithFields(log.Fields{
|
||||
"application": origApp.Name,
|
||||
"time_ms": reconcileDuration.Seconds() * 1e3,
|
||||
"level": comparisonLevel,
|
||||
"dest-server": origApp.Spec.Destination.Server,
|
||||
"dest-namespace": origApp.Spec.Destination.Namespace,
|
||||
})
|
||||
logCtx.Info("Reconciliation completed")
|
||||
}()
|
||||
|
||||
@@ -682,7 +714,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
||||
}
|
||||
|
||||
var localManifests []string
|
||||
if opState := app.Status.OperationState; opState != nil {
|
||||
if opState := app.Status.OperationState; opState != nil && opState.Operation.Sync != nil {
|
||||
localManifests = opState.Operation.Sync.Manifests
|
||||
}
|
||||
|
||||
@@ -690,13 +722,14 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
||||
if comparisonLevel == CompareWithRecent {
|
||||
revision = app.Status.Sync.Revision
|
||||
}
|
||||
compareResult, err := ctrl.appStateManager.CompareAppState(app, revision, app.Spec.Source, refreshType == appv1.RefreshTypeHard, localManifests)
|
||||
if err != nil {
|
||||
conditions = append(conditions, appv1.ApplicationCondition{Type: appv1.ApplicationConditionComparisonError, Message: err.Error()})
|
||||
} else {
|
||||
ctrl.normalizeApplication(origApp, app, compareResult.appSourceType)
|
||||
conditions = append(conditions, compareResult.conditions...)
|
||||
}
|
||||
|
||||
observedAt := metav1.Now()
|
||||
compareResult := ctrl.appStateManager.CompareAppState(app, revision, app.Spec.Source, refreshType == appv1.RefreshTypeHard, localManifests)
|
||||
|
||||
ctrl.normalizeApplication(origApp, app, compareResult.appSourceType)
|
||||
|
||||
conditions = append(conditions, compareResult.conditions...)
|
||||
|
||||
tree, err := ctrl.setAppManagedResources(app, compareResult)
|
||||
if err != nil {
|
||||
logCtx.Errorf("Failed to cache app resources: %v", err)
|
||||
@@ -709,8 +742,10 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
||||
conditions = append(conditions, *syncErrCond)
|
||||
}
|
||||
|
||||
app.Status.ObservedAt = &compareResult.reconciledAt
|
||||
app.Status.ReconciledAt = &compareResult.reconciledAt
|
||||
if app.Status.ReconciledAt == nil || comparisonLevel == CompareWithLatest {
|
||||
app.Status.ReconciledAt = &observedAt
|
||||
}
|
||||
app.Status.ObservedAt = &observedAt
|
||||
app.Status.Sync = *compareResult.syncStatus
|
||||
app.Status.Health = *compareResult.healthStatus
|
||||
app.Status.Resources = compareResult.resources
|
||||
@@ -730,21 +765,22 @@ func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application,
|
||||
compareWith := CompareWithLatest
|
||||
refreshType := appv1.RefreshTypeNormal
|
||||
expired := app.Status.ReconciledAt == nil || app.Status.ReconciledAt.Add(statusRefreshTimeout).Before(time.Now().UTC())
|
||||
|
||||
if requestedType, ok := app.IsRefreshRequested(); ok {
|
||||
// user requested app refresh.
|
||||
refreshType = requestedType
|
||||
reason = fmt.Sprintf("%s refresh requested", refreshType)
|
||||
} else if requested, level := ctrl.isRefreshRequested(app.Name); requested {
|
||||
compareWith = level
|
||||
reason = fmt.Sprintf("controller refresh requested")
|
||||
} else if app.Status.Sync.Status == appv1.SyncStatusCodeUnknown && expired {
|
||||
reason = "comparison status unknown"
|
||||
} else if expired {
|
||||
reason = fmt.Sprintf("comparison expired. reconciledAt: %v, expiry: %v", app.Status.ReconciledAt, statusRefreshTimeout)
|
||||
} else if !app.Spec.Source.Equals(app.Status.Sync.ComparedTo.Source) {
|
||||
reason = "spec.source differs"
|
||||
} else if !app.Spec.Destination.Equals(app.Status.Sync.ComparedTo.Destination) {
|
||||
reason = "spec.destination differs"
|
||||
} else if expired {
|
||||
reason = fmt.Sprintf("comparison expired. reconciledAt: %v, expiry: %v", app.Status.ReconciledAt, statusRefreshTimeout)
|
||||
} else if requested, level := ctrl.isRefreshRequested(app.Name); requested {
|
||||
compareWith = level
|
||||
reason = fmt.Sprintf("controller refresh requested")
|
||||
}
|
||||
|
||||
if reason != "" {
|
||||
logCtx.Infof("Refreshing app status (%s), level (%d)", reason, compareWith)
|
||||
return true, refreshType, compareWith
|
||||
|
||||
@@ -2,6 +2,7 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -35,6 +36,7 @@ type fakeData struct {
|
||||
apps []runtime.Object
|
||||
manifestResponse *apiclient.ManifestResponse
|
||||
managedLiveObjs map[kube.ResourceKey]*unstructured.Unstructured
|
||||
configMapData map[string]string
|
||||
}
|
||||
|
||||
func newFakeController(data *fakeData) *ApplicationController {
|
||||
@@ -68,7 +70,7 @@ func newFakeController(data *fakeData) *ApplicationController {
|
||||
"app.kubernetes.io/part-of": "argocd",
|
||||
},
|
||||
},
|
||||
Data: nil,
|
||||
Data: data.configMapData,
|
||||
}
|
||||
kubeClient := fake.NewSimpleClientset(&clust, &cm, &secret)
|
||||
settingsMgr := settings.NewSettingsManager(context.Background(), kubeClient, test.FakeArgoCDNamespace)
|
||||
@@ -82,6 +84,7 @@ func newFakeController(data *fakeData) *ApplicationController {
|
||||
time.Minute,
|
||||
time.Minute,
|
||||
common.DefaultPortArgoCDMetrics,
|
||||
0,
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -523,13 +526,107 @@ func TestNeedRefreshAppStatus(t *testing.T) {
|
||||
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
|
||||
assert.Equal(t, CompareWithLatest, compareWith)
|
||||
|
||||
// execute hard refresh if app has refresh annotation
|
||||
app.Annotations = map[string]string{
|
||||
common.AnnotationKeyRefresh: string(argoappv1.RefreshTypeHard),
|
||||
{
|
||||
// refresh app using the 'latest' level if comparison expired
|
||||
app := app.DeepCopy()
|
||||
ctrl.requestAppRefresh(app.Name, CompareWithRecent)
|
||||
reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour))
|
||||
app.Status.ReconciledAt = &reconciledAt
|
||||
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Minute)
|
||||
assert.True(t, needRefresh)
|
||||
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
|
||||
assert.Equal(t, CompareWithLatest, compareWith)
|
||||
}
|
||||
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour)
|
||||
assert.True(t, needRefresh)
|
||||
assert.Equal(t, argoappv1.RefreshTypeHard, refreshType)
|
||||
assert.Equal(t, CompareWithLatest, compareWith)
|
||||
|
||||
{
|
||||
app := app.DeepCopy()
|
||||
// execute hard refresh if app has refresh annotation
|
||||
reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour))
|
||||
app.Status.ReconciledAt = &reconciledAt
|
||||
app.Annotations = map[string]string{
|
||||
common.AnnotationKeyRefresh: string(argoappv1.RefreshTypeHard),
|
||||
}
|
||||
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour)
|
||||
assert.True(t, needRefresh)
|
||||
assert.Equal(t, argoappv1.RefreshTypeHard, refreshType)
|
||||
assert.Equal(t, CompareWithLatest, compareWith)
|
||||
}
|
||||
|
||||
{
|
||||
app := app.DeepCopy()
|
||||
// ensure that CompareWithLatest level is used if application source has changed
|
||||
ctrl.requestAppRefresh(app.Name, ComparisonWithNothing)
|
||||
// sample app source change
|
||||
app.Spec.Source.Helm = &argoappv1.ApplicationSourceHelm{
|
||||
Parameters: []argoappv1.HelmParameter{{
|
||||
Name: "foo",
|
||||
Value: "bar",
|
||||
}},
|
||||
}
|
||||
|
||||
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour)
|
||||
assert.True(t, needRefresh)
|
||||
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
|
||||
assert.Equal(t, CompareWithLatest, compareWith)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateReconciledAt(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
reconciledAt := metav1.NewTime(time.Now().Add(-1 * time.Second))
|
||||
app.Status = argoappv1.ApplicationStatus{ReconciledAt: &reconciledAt}
|
||||
app.Status.Sync = argoappv1.SyncStatus{ComparedTo: argoappv1.ComparedTo{Source: app.Spec.Source, Destination: app.Spec.Destination}}
|
||||
ctrl := newFakeController(&fakeData{
|
||||
apps: []runtime.Object{app, &defaultProj},
|
||||
manifestResponse: &apiclient.ManifestResponse{
|
||||
Manifests: []string{},
|
||||
Namespace: test.FakeDestNamespace,
|
||||
Server: test.FakeClusterURL,
|
||||
Revision: "abc123",
|
||||
},
|
||||
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
|
||||
})
|
||||
key, _ := cache.MetaNamespaceKeyFunc(app)
|
||||
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
|
||||
fakeAppCs.ReactionChain = nil
|
||||
receivedPatch := map[string]interface{}{}
|
||||
fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
if patchAction, ok := action.(kubetesting.PatchAction); ok {
|
||||
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
|
||||
}
|
||||
return true, nil, nil
|
||||
})
|
||||
|
||||
t.Run("UpdatedOnFullReconciliation", func(t *testing.T) {
|
||||
receivedPatch = map[string]interface{}{}
|
||||
ctrl.requestAppRefresh(app.Name, CompareWithLatest)
|
||||
ctrl.appRefreshQueue.Add(key)
|
||||
|
||||
ctrl.processAppRefreshQueueItem()
|
||||
|
||||
_, updated, err := unstructured.NestedString(receivedPatch, "status", "reconciledAt")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, updated)
|
||||
|
||||
_, updated, err = unstructured.NestedString(receivedPatch, "status", "observedAt")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, updated)
|
||||
})
|
||||
|
||||
t.Run("NotUpdatedOnPartialReconciliation", func(t *testing.T) {
|
||||
receivedPatch = map[string]interface{}{}
|
||||
ctrl.appRefreshQueue.Add(key)
|
||||
ctrl.requestAppRefresh(app.Name, CompareWithRecent)
|
||||
|
||||
ctrl.processAppRefreshQueueItem()
|
||||
|
||||
_, updated, err := unstructured.NestedString(receivedPatch, "status", "reconciledAt")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, updated)
|
||||
|
||||
_, updated, err = unstructured.NestedString(receivedPatch, "status", "observedAt")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, updated)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
8
controller/cache/cluster.go
vendored
8
controller/cache/cluster.go
vendored
@@ -87,6 +87,14 @@ func (c *clusterInfo) replaceResourceCache(gk schema.GroupKind, resourceVersion
|
||||
|
||||
func (c *clusterInfo) createObjInfo(un *unstructured.Unstructured, appInstanceLabel string) *node {
|
||||
ownerRefs := un.GetOwnerReferences()
|
||||
// Special case for endpoint. Remove after https://github.com/kubernetes/kubernetes/issues/28483 is fixed
|
||||
if un.GroupVersionKind().Group == "" && un.GetKind() == kube.EndpointsKind && len(un.GetOwnerReferences()) == 0 {
|
||||
ownerRefs = append(ownerRefs, metav1.OwnerReference{
|
||||
Name: un.GetName(),
|
||||
Kind: kube.ServiceKind,
|
||||
APIVersion: "v1",
|
||||
})
|
||||
}
|
||||
nodeInfo := &node{
|
||||
resourceVersion: un.GetResourceVersion(),
|
||||
ref: kube.GetObjectRef(un),
|
||||
|
||||
2
controller/cache/cluster_test.go
vendored
2
controller/cache/cluster_test.go
vendored
@@ -87,6 +87,7 @@ var (
|
||||
name: helm-guestbook
|
||||
namespace: default
|
||||
resourceVersion: "123"
|
||||
uid: "4"
|
||||
spec:
|
||||
selector:
|
||||
app: guestbook
|
||||
@@ -102,6 +103,7 @@ var (
|
||||
metadata:
|
||||
name: helm-guestbook
|
||||
namespace: default
|
||||
uid: "4"
|
||||
spec:
|
||||
backend:
|
||||
serviceName: not-found-service
|
||||
|
||||
13
controller/cache/node.go
vendored
13
controller/cache/node.go
vendored
@@ -35,12 +35,15 @@ func (n *node) resourceKey() kube.ResourceKey {
|
||||
}
|
||||
|
||||
func (n *node) isParentOf(child *node) bool {
|
||||
// Special case for endpoint. Remove after https://github.com/kubernetes/kubernetes/issues/28483 is fixed
|
||||
if len(child.ownerRefs) == 0 && child.ref.APIVersion == "v1" && child.ref.Kind == kube.EndpointsKind && n.ref.APIVersion == "v1" && n.ref.Kind == kube.ServiceKind && n.ref.Name == child.ref.Name {
|
||||
child.ownerRefs = []metav1.OwnerReference{{Name: n.ref.Name, Kind: n.ref.Kind, APIVersion: n.ref.APIVersion, UID: n.ref.UID}}
|
||||
}
|
||||
for i, ownerRef := range child.ownerRefs {
|
||||
|
||||
// backfill UID of inferred owner child references
|
||||
if ownerRef.UID == "" && n.ref.Kind == ownerRef.Kind && n.ref.APIVersion == ownerRef.APIVersion && n.ref.Name == ownerRef.Name {
|
||||
ownerRef.UID = n.ref.UID
|
||||
child.ownerRefs[i] = ownerRef
|
||||
return true
|
||||
}
|
||||
|
||||
for _, ownerRef := range child.ownerRefs {
|
||||
if n.ref.UID == ownerRef.UID {
|
||||
return true
|
||||
}
|
||||
|
||||
1
controller/cache/node_test.go
vendored
1
controller/cache/node_test.go
vendored
@@ -51,5 +51,6 @@ metadata:
|
||||
parent := c.createObjInfo(testService, "")
|
||||
|
||||
assert.True(t, parent.isParentOf(matchingNameEndPoint))
|
||||
assert.Equal(t, parent.ref.UID, matchingNameEndPoint.ownerRefs[0].UID)
|
||||
assert.False(t, parent.isParentOf(nonMatchingNameEndPoint))
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ import (
|
||||
|
||||
type MetricsServer struct {
|
||||
*http.Server
|
||||
syncCounter *prometheus.CounterVec
|
||||
k8sRequestCounter *prometheus.CounterVec
|
||||
reconcileHistogram *prometheus.HistogramVec
|
||||
syncCounter *prometheus.CounterVec
|
||||
k8sRequestCounter *prometheus.CounterVec
|
||||
kubectlExecCounter *prometheus.CounterVec
|
||||
kubectlExecPendingGauge *prometheus.GaugeVec
|
||||
reconcileHistogram *prometheus.HistogramVec
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -76,6 +78,16 @@ func NewMetricsServer(addr string, appLister applister.ApplicationLister, health
|
||||
append(descAppDefaultLabels, "phase"),
|
||||
)
|
||||
appRegistry.MustRegister(syncCounter)
|
||||
kubectlExecCounter := prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "argocd_kubectl_exec_total",
|
||||
Help: "Number of kubectl executions",
|
||||
}, []string{"command"})
|
||||
appRegistry.MustRegister(kubectlExecCounter)
|
||||
kubectlExecPendingGauge := prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: "argocd_kubectl_exec_pending",
|
||||
Help: "Number of pending kubectl executions",
|
||||
}, []string{"command"})
|
||||
appRegistry.MustRegister(kubectlExecPendingGauge)
|
||||
k8sRequestCounter := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "argocd_app_k8s_request_total",
|
||||
@@ -102,9 +114,11 @@ func NewMetricsServer(addr string, appLister applister.ApplicationLister, health
|
||||
Addr: addr,
|
||||
Handler: mux,
|
||||
},
|
||||
syncCounter: syncCounter,
|
||||
k8sRequestCounter: k8sRequestCounter,
|
||||
reconcileHistogram: reconcileHistogram,
|
||||
syncCounter: syncCounter,
|
||||
k8sRequestCounter: k8sRequestCounter,
|
||||
reconcileHistogram: reconcileHistogram,
|
||||
kubectlExecCounter: kubectlExecCounter,
|
||||
kubectlExecPendingGauge: kubectlExecPendingGauge,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +140,18 @@ func (m *MetricsServer) IncReconcile(app *argoappv1.Application, duration time.D
|
||||
m.reconcileHistogram.WithLabelValues(app.Namespace, app.Name, app.Spec.GetProject()).Observe(duration.Seconds())
|
||||
}
|
||||
|
||||
func (m *MetricsServer) IncKubectlExec(command string) {
|
||||
m.kubectlExecCounter.WithLabelValues(command).Inc()
|
||||
}
|
||||
|
||||
func (m *MetricsServer) IncKubectlExecPending(command string) {
|
||||
m.kubectlExecPendingGauge.WithLabelValues(command).Inc()
|
||||
}
|
||||
|
||||
func (m *MetricsServer) DecKubectlExecPending(command string) {
|
||||
m.kubectlExecPendingGauge.WithLabelValues(command).Dec()
|
||||
}
|
||||
|
||||
type appCollector struct {
|
||||
store applister.ApplicationLister
|
||||
}
|
||||
|
||||
@@ -56,12 +56,11 @@ type ResourceInfoProvider interface {
|
||||
|
||||
// AppStateManager defines methods which allow to compare application spec and actual application state.
|
||||
type AppStateManager interface {
|
||||
CompareAppState(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, noCache bool, localObjects []string) (*comparisonResult, error)
|
||||
CompareAppState(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, noCache bool, localObjects []string) *comparisonResult
|
||||
SyncAppState(app *v1alpha1.Application, state *v1alpha1.OperationState)
|
||||
}
|
||||
|
||||
type comparisonResult struct {
|
||||
reconciledAt metav1.Time
|
||||
syncStatus *v1alpha1.SyncStatus
|
||||
healthStatus *v1alpha1.HealthStatus
|
||||
resources []v1alpha1.ResourceStatus
|
||||
@@ -135,10 +134,11 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
targetObjs, hooks, nil := unmarshalManifests(manifestInfo.Manifests)
|
||||
targetObjs, hooks, err := unmarshalManifests(manifestInfo.Manifests)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return targetObjs, hooks, manifestInfo, nil
|
||||
|
||||
}
|
||||
|
||||
func unmarshalManifests(manifests []string) ([]*unstructured.Unstructured, []*unstructured.Unstructured, error) {
|
||||
@@ -234,28 +234,46 @@ func dedupLiveResources(targetObjs []*unstructured.Unstructured, liveObjsByKey m
|
||||
}
|
||||
}
|
||||
|
||||
// CompareAppState compares application git state to the live app state, using the specified
|
||||
// revision and supplied source. If revision or overrides are empty, then compares against
|
||||
// revision and overrides in the app spec.
|
||||
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, noCache bool, localManifests []string) (*comparisonResult, error) {
|
||||
func (m *appStateManager) getComparisonSettings(app *appv1.Application) (string, map[string]v1alpha1.ResourceOverride, diff.Normalizer, error) {
|
||||
resourceOverrides, err := m.settingsMgr.GetResourceOverrides()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, nil, err
|
||||
}
|
||||
appLabelKey, err := m.settingsMgr.GetAppInstanceLabelKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, nil, err
|
||||
}
|
||||
diffNormalizer, err := argo.NewDiffNormalizer(app.Spec.IgnoreDifferences, resourceOverrides)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, nil, err
|
||||
}
|
||||
logCtx := log.WithField("application", app.Name)
|
||||
logCtx.Infof("Comparing app state (cluster: %s, namespace: %s)", app.Spec.Destination.Server, app.Spec.Destination.Namespace)
|
||||
observedAt := metav1.Now()
|
||||
return appLabelKey, resourceOverrides, diffNormalizer, nil
|
||||
}
|
||||
|
||||
// CompareAppState compares application git state to the live app state, using the specified
|
||||
// revision and supplied source. If revision or overrides are empty, then compares against
|
||||
// revision and overrides in the app spec.
|
||||
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, noCache bool, localManifests []string) *comparisonResult {
|
||||
appLabelKey, resourceOverrides, diffNormalizer, err := m.getComparisonSettings(app)
|
||||
|
||||
// return unknown comparison result if basic comparison settings cannot be loaded
|
||||
if err != nil {
|
||||
return &comparisonResult{
|
||||
syncStatus: &v1alpha1.SyncStatus{
|
||||
ComparedTo: appv1.ComparedTo{Source: source, Destination: app.Spec.Destination},
|
||||
Status: appv1.SyncStatusCodeUnknown,
|
||||
},
|
||||
healthStatus: &appv1.HealthStatus{Status: appv1.HealthStatusUnknown},
|
||||
}
|
||||
}
|
||||
|
||||
// do best effort loading live and target state to present as much information about app state as possible
|
||||
failedToLoadObjs := false
|
||||
conditions := make([]v1alpha1.ApplicationCondition, 0)
|
||||
|
||||
logCtx := log.WithField("application", app.Name)
|
||||
logCtx.Infof("Comparing app state (cluster: %s, namespace: %s)", app.Spec.Destination.Server, app.Spec.Destination.Namespace)
|
||||
|
||||
var targetObjs []*unstructured.Unstructured
|
||||
var hooks []*unstructured.Unstructured
|
||||
var manifestInfo *apiclient.ManifestResponse
|
||||
@@ -348,7 +366,9 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision st
|
||||
// Do the actual comparison
|
||||
diffResults, err := diff.DiffArray(targetObjs, managedLiveObj, diffNormalizer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
diffResults = &diff.DiffResultList{}
|
||||
failedToLoadObjs = true
|
||||
conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error()})
|
||||
}
|
||||
|
||||
syncCode := v1alpha1.SyncStatusCodeSynced
|
||||
@@ -392,6 +412,10 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision st
|
||||
} else {
|
||||
resState.Status = v1alpha1.SyncStatusCodeSynced
|
||||
}
|
||||
// we can't say anything about the status if we were unable to get the target objects
|
||||
if failedToLoadObjs {
|
||||
resState.Status = v1alpha1.SyncStatusCodeUnknown
|
||||
}
|
||||
managedResources[i] = managedResource{
|
||||
Name: resState.Name,
|
||||
Namespace: resState.Namespace,
|
||||
@@ -429,7 +453,6 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision st
|
||||
}
|
||||
|
||||
compRes := comparisonResult{
|
||||
reconciledAt: observedAt,
|
||||
syncStatus: &syncStatus,
|
||||
healthStatus: healthStatus,
|
||||
resources: resourceSummaries,
|
||||
@@ -441,7 +464,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision st
|
||||
if manifestInfo != nil {
|
||||
compRes.appSourceType = v1alpha1.ApplicationSourceType(manifestInfo.SourceType)
|
||||
}
|
||||
return &compRes, nil
|
||||
return &compRes
|
||||
}
|
||||
|
||||
func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource) error {
|
||||
|
||||
@@ -30,8 +30,7 @@ func TestCompareAppStateEmpty(t *testing.T) {
|
||||
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
|
||||
}
|
||||
ctrl := newFakeController(&data)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
assert.NoError(t, err)
|
||||
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
|
||||
assert.Equal(t, 0, len(compRes.resources))
|
||||
@@ -53,8 +52,7 @@ func TestCompareAppStateMissing(t *testing.T) {
|
||||
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
|
||||
}
|
||||
ctrl := newFakeController(&data)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
assert.NoError(t, err)
|
||||
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.Equal(t, argoappv1.SyncStatusCodeOutOfSync, compRes.syncStatus.Status)
|
||||
assert.Equal(t, 1, len(compRes.resources))
|
||||
@@ -80,8 +78,7 @@ func TestCompareAppStateExtra(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctrl := newFakeController(&data)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
assert.NoError(t, err)
|
||||
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.Equal(t, argoappv1.SyncStatusCodeOutOfSync, compRes.syncStatus.Status)
|
||||
assert.Equal(t, 1, len(compRes.resources))
|
||||
@@ -107,8 +104,7 @@ func TestCompareAppStateHook(t *testing.T) {
|
||||
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
|
||||
}
|
||||
ctrl := newFakeController(&data)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
assert.NoError(t, err)
|
||||
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
|
||||
assert.Equal(t, 0, len(compRes.resources))
|
||||
@@ -134,9 +130,8 @@ func TestCompareAppStateCompareOptionIgnoreExtraneous(t *testing.T) {
|
||||
}
|
||||
ctrl := newFakeController(&data)
|
||||
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, compRes)
|
||||
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
|
||||
assert.Len(t, compRes.resources, 0)
|
||||
@@ -163,8 +158,8 @@ func TestCompareAppStateExtraHook(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctrl := newFakeController(&data)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
assert.NoError(t, err)
|
||||
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
|
||||
assert.NotNil(t, compRes)
|
||||
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
|
||||
assert.Equal(t, 1, len(compRes.resources))
|
||||
@@ -200,8 +195,8 @@ func TestCompareAppStateDuplicatedNamespacedResources(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctrl := newFakeController(&data)
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
assert.NoError(t, err)
|
||||
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
|
||||
assert.NotNil(t, compRes)
|
||||
assert.Contains(t, compRes.conditions, argoappv1.ApplicationCondition{
|
||||
Message: "Resource /Pod/fake-dest-ns/my-pod appeared 2 times among application resources.",
|
||||
@@ -251,8 +246,7 @@ func TestSetHealth(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
assert.NoError(t, err)
|
||||
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
|
||||
assert.Equal(t, compRes.healthStatus.Status, argoappv1.HealthStatusHealthy)
|
||||
}
|
||||
@@ -284,8 +278,7 @@ func TestSetHealthSelfReferencedApp(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
assert.NoError(t, err)
|
||||
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
|
||||
|
||||
assert.Equal(t, compRes.healthStatus.Status, argoappv1.HealthStatusHealthy)
|
||||
}
|
||||
|
||||
@@ -101,12 +101,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
|
||||
revision = syncOp.Revision
|
||||
}
|
||||
|
||||
compareResult, err := m.CompareAppState(app, revision, source, false, syncOp.Manifests)
|
||||
if err != nil {
|
||||
state.Phase = v1alpha1.OperationError
|
||||
state.Message = err.Error()
|
||||
return
|
||||
}
|
||||
compareResult := m.CompareAppState(app, revision, source, false, syncOp.Manifests)
|
||||
|
||||
// If there are any error conditions, do not perform the operation
|
||||
errConditions := make([]v1alpha1.ApplicationCondition, 0)
|
||||
@@ -264,8 +259,11 @@ func (sc *syncContext) sync() {
|
||||
}
|
||||
}
|
||||
|
||||
// any running tasks, lets wait...
|
||||
if tasks.Any(func(t *syncTask) bool { return t.running() }) {
|
||||
// if (a) we are multi-step and we have any running tasks,
|
||||
// or (b) there are any running hooks,
|
||||
// then wait...
|
||||
multiStep := tasks.multiStep()
|
||||
if tasks.Any(func(t *syncTask) bool { return (multiStep || t.isHook()) && t.running() }) {
|
||||
sc.setOperationPhase(v1alpha1.OperationRunning, "one or more tasks are running")
|
||||
return
|
||||
}
|
||||
@@ -279,9 +277,9 @@ func (sc *syncContext) sync() {
|
||||
return
|
||||
}
|
||||
|
||||
sc.log.WithFields(log.Fields{"tasks": tasks}).Debug("filtering out completed tasks")
|
||||
sc.log.WithFields(log.Fields{"tasks": tasks}).Debug("filtering out non-pending tasks")
|
||||
// remove tasks that are completed, we can assume that there are no running tasks
|
||||
tasks = tasks.Filter(func(t *syncTask) bool { return !t.completed() })
|
||||
tasks = tasks.Filter(func(t *syncTask) bool { return t.pending() })
|
||||
|
||||
// If no sync tasks were generated (e.g., in case all application manifests have been removed),
|
||||
// the sync operation is successful.
|
||||
|
||||
@@ -94,6 +94,10 @@ func (t *syncTask) namespace() string {
|
||||
return t.obj().GetNamespace()
|
||||
}
|
||||
|
||||
func (t *syncTask) pending() bool {
|
||||
return t.operationState == ""
|
||||
}
|
||||
|
||||
func (t *syncTask) running() bool {
|
||||
return t.operationState == v1alpha1.OperationRunning
|
||||
}
|
||||
|
||||
@@ -165,3 +165,21 @@ func (s syncTasks) wave() int {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s syncTasks) lastPhase() v1alpha1.SyncPhase {
|
||||
if len(s) > 0 {
|
||||
return s[len(s)-1].phase
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s syncTasks) lastWave() int {
|
||||
if len(s) > 0 {
|
||||
return s[len(s)-1].wave()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s syncTasks) multiStep() bool {
|
||||
return s.wave() != s.lastWave() || s.phase() != s.lastPhase()
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ import (
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
. "github.com/argoproj/argo-cd/test"
|
||||
)
|
||||
|
||||
func Test_syncTasks_kindOrder(t *testing.T) {
|
||||
@@ -366,3 +368,25 @@ func TestSyncNamespaceAgainstCRD(t *testing.T) {
|
||||
|
||||
assert.Equal(t, syncTasks{namespace, crd}, unsorted)
|
||||
}
|
||||
|
||||
func Test_syncTasks_multiStep(t *testing.T) {
|
||||
t.Run("Single", func(t *testing.T) {
|
||||
tasks := syncTasks{{liveObj: Annotate(NewPod(), common.AnnotationSyncWave, "-1"), phase: SyncPhaseSync}}
|
||||
assert.Equal(t, SyncPhaseSync, tasks.phase())
|
||||
assert.Equal(t, -1, tasks.wave())
|
||||
assert.Equal(t, SyncPhaseSync, tasks.lastPhase())
|
||||
assert.Equal(t, -1, tasks.lastWave())
|
||||
assert.False(t, tasks.multiStep())
|
||||
})
|
||||
t.Run("Double", func(t *testing.T) {
|
||||
tasks := syncTasks{
|
||||
{liveObj: Annotate(NewPod(), common.AnnotationSyncWave, "-1"), phase: SyncPhasePreSync},
|
||||
{liveObj: Annotate(NewPod(), common.AnnotationSyncWave, "1"), phase: SyncPhasePostSync},
|
||||
}
|
||||
assert.Equal(t, SyncPhasePreSync, tasks.phase())
|
||||
assert.Equal(t, -1, tasks.wave())
|
||||
assert.Equal(t, SyncPhasePostSync, tasks.lastPhase())
|
||||
assert.Equal(t, 1, tasks.lastWave())
|
||||
assert.True(t, tasks.multiStep())
|
||||
})
|
||||
}
|
||||
|
||||
35
docs/faq.md
35
docs/faq.md
@@ -91,4 +91,37 @@ Argo CD automatically sets the `app.kubernetes.io/instance` label and uses it to
|
||||
|
||||
!!! note When you make this change your applications will become out of sync and will need re-syncing.
|
||||
|
||||
See [#1482](https://github.com/argoproj/argo-cd/issues/1482).
|
||||
See [#1482](https://github.com/argoproj/argo-cd/issues/1482).
|
||||
|
||||
|
||||
# How Do I Fix "invalid cookie, longer than max length 4093"?
|
||||
|
||||
Argo CD uses a JWT as the auth token. You likely are part of many groups and have gone over the 4KB limit which is set for cookies.
|
||||
You can get the list of groups by opening "developer tools -> network"
|
||||
|
||||
* Click log in
|
||||
* Find the call to `<argocd_instance>/auth/callback?code=<random_string>`
|
||||
|
||||
Decode the token at https://jwt.io/. That will provide the list of teams that you can remove yourself from.
|
||||
|
||||
See [#2165](https://github.com/argoproj/argo-cd/issues/2165).
|
||||
|
||||
## Why Am I Getting `rpc error: code = Unavailable desc = transport is closing` When Using The CLI?
|
||||
|
||||
Maybe you're behind a proxy that does not support HTTP 2? Try the `--grcp-web` flag.:
|
||||
|
||||
```bash
|
||||
argocd ... --grcp-web
|
||||
```
|
||||
|
||||
## Why Am I Getting `x509: certificate signed by unknown authority` When Using The CLI?
|
||||
|
||||
Your not running your server with correct certs.
|
||||
|
||||
If you're not running in a production system (e.g. you're testing Argo CD out), try the `--insecure` flag:
|
||||
|
||||
```bash
|
||||
argocd ... --insecure
|
||||
```
|
||||
|
||||
!!! warning "Do not use `--insecure` in production"
|
||||
|
||||
@@ -18,6 +18,11 @@ data:
|
||||
# Unless set to 'false' then user ids are hashed before sending to google analytics
|
||||
ga.anonymizeusers: 'false'
|
||||
|
||||
# the URL for getting chat help, this will typically be your Slack channel for support
|
||||
help.chatUrl: 'https://mycorp.slack.com/argo-cd'
|
||||
# the text for getting chat help, defaults to "Chat now!"
|
||||
help.chatText: 'Chat now!'
|
||||
|
||||
# A dex connector configuration (optional). See SSO configuration documentation:
|
||||
# https://github.com/argoproj/argo-cd/blob/master/docs/sso.md
|
||||
# https://github.com/dexidp/dex/tree/master/Documentation/connectors
|
||||
|
||||
@@ -11,6 +11,10 @@ func CheckError(err error) {
|
||||
}
|
||||
}
|
||||
|
||||
func FailOnErr(_ interface{}, err error) {
|
||||
// panics if there is an error.
|
||||
// This returns the first value so you can use it if you cast it:
|
||||
// text := FailOrErr(Foo)).(string)
|
||||
func FailOnErr(v interface{}, err error) interface{} {
|
||||
CheckError(err)
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -10,7 +10,20 @@ AUTOGENMSG="# This is an auto-generated file. DO NOT EDIT"
|
||||
cd ${SRCROOT}/manifests/ha/base/redis-ha && ./generate.sh
|
||||
|
||||
IMAGE_NAMESPACE="${IMAGE_NAMESPACE:-argoproj}"
|
||||
IMAGE_TAG="${IMAGE_TAG:-latest}"
|
||||
IMAGE_TAG="${IMAGE_TAG:-}"
|
||||
|
||||
# if the tag has not been declared, and we are on a release branch, use the VERSION file.
|
||||
if [ "$IMAGE_TAG" = "" ]; then
|
||||
branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
if [[ $branch = release-* ]]; then
|
||||
pwd
|
||||
IMAGE_TAG=v$(cat $SRCROOT/VERSION)
|
||||
fi
|
||||
fi
|
||||
# otherwise, use latest
|
||||
if [ "$IMAGE_TAG" = "" ]; then
|
||||
IMAGE_TAG=latest
|
||||
fi
|
||||
|
||||
cd ${SRCROOT}/manifests/base && kustomize edit set image argoproj/argocd=${IMAGE_NAMESPACE}/argocd:${IMAGE_TAG} argoproj/argocd-ui=${IMAGE_NAMESPACE}/argocd-ui:${IMAGE_TAG}
|
||||
cd ${SRCROOT}/manifests/ha/base && kustomize edit set image argoproj/argocd=${IMAGE_NAMESPACE}/argocd:${IMAGE_TAG} argoproj/argocd-ui=${IMAGE_NAMESPACE}/argocd-ui:${IMAGE_TAG}
|
||||
|
||||
@@ -12,7 +12,7 @@ bases:
|
||||
images:
|
||||
- name: argoproj/argocd
|
||||
newName: argoproj/argocd
|
||||
newTag: latest
|
||||
newTag: v1.2.5
|
||||
- name: argoproj/argocd-ui
|
||||
newName: argoproj/argocd-ui
|
||||
newTag: latest
|
||||
newTag: v1.2.5
|
||||
|
||||
@@ -21,6 +21,7 @@ spec:
|
||||
image: argoproj/argocd:latest
|
||||
imagePullPolicy: Always
|
||||
command:
|
||||
- uid_entrypoint.sh
|
||||
- argocd-repo-server
|
||||
- --redis
|
||||
- argocd-redis:6379
|
||||
|
||||
@@ -1020,6 +1020,8 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
observedAt:
|
||||
description: ObservedAt indicates when the application state was updated
|
||||
without querying latest git state
|
||||
format: date-time
|
||||
type: string
|
||||
operationState:
|
||||
@@ -1486,6 +1488,8 @@ spec:
|
||||
- startedAt
|
||||
type: object
|
||||
reconciledAt:
|
||||
description: ReconciledAt indicates when the application state was reconciled
|
||||
using the latest git version
|
||||
format: date-time
|
||||
type: string
|
||||
resources:
|
||||
|
||||
@@ -18,7 +18,7 @@ bases:
|
||||
images:
|
||||
- name: argoproj/argocd
|
||||
newName: argoproj/argocd
|
||||
newTag: latest
|
||||
newTag: v1.2.5
|
||||
- name: argoproj/argocd-ui
|
||||
newName: argoproj/argocd-ui
|
||||
newTag: latest
|
||||
newTag: v1.2.5
|
||||
|
||||
@@ -23,6 +23,7 @@ spec:
|
||||
containers:
|
||||
- name: argocd-repo-server
|
||||
command:
|
||||
- uid_entrypoint.sh
|
||||
- argocd-repo-server
|
||||
- --sentinel
|
||||
- argocd-redis-ha-announce-0:26379
|
||||
|
||||
@@ -1021,6 +1021,8 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
observedAt:
|
||||
description: ObservedAt indicates when the application state was updated
|
||||
without querying latest git state
|
||||
format: date-time
|
||||
type: string
|
||||
operationState:
|
||||
@@ -1487,6 +1489,8 @@ spec:
|
||||
- startedAt
|
||||
type: object
|
||||
reconciledAt:
|
||||
description: ReconciledAt indicates when the application state was reconciled
|
||||
using the latest git version
|
||||
format: date-time
|
||||
type: string
|
||||
resources:
|
||||
@@ -2901,7 +2905,7 @@ spec:
|
||||
- argocd-redis-ha-announce-2:26379
|
||||
- --sentinelmaster
|
||||
- argocd
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2955,7 +2959,7 @@ spec:
|
||||
- cp
|
||||
- /usr/local/bin/argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -3001,6 +3005,7 @@ spec:
|
||||
automountServiceAccountToken: false
|
||||
containers:
|
||||
- command:
|
||||
- uid_entrypoint.sh
|
||||
- argocd-repo-server
|
||||
- --sentinel
|
||||
- argocd-redis-ha-announce-0:26379
|
||||
@@ -3010,7 +3015,7 @@ spec:
|
||||
- argocd-redis-ha-announce-2:26379
|
||||
- --sentinelmaster
|
||||
- argocd
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 5
|
||||
@@ -3084,7 +3089,7 @@ spec:
|
||||
- argocd-redis-ha-announce-2:26379
|
||||
- --sentinelmaster
|
||||
- argocd
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -1021,6 +1021,8 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
observedAt:
|
||||
description: ObservedAt indicates when the application state was updated
|
||||
without querying latest git state
|
||||
format: date-time
|
||||
type: string
|
||||
operationState:
|
||||
@@ -1487,6 +1489,8 @@ spec:
|
||||
- startedAt
|
||||
type: object
|
||||
reconciledAt:
|
||||
description: ReconciledAt indicates when the application state was reconciled
|
||||
using the latest git version
|
||||
format: date-time
|
||||
type: string
|
||||
resources:
|
||||
@@ -2816,7 +2820,7 @@ spec:
|
||||
- argocd-redis-ha-announce-2:26379
|
||||
- --sentinelmaster
|
||||
- argocd
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2870,7 +2874,7 @@ spec:
|
||||
- cp
|
||||
- /usr/local/bin/argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -2916,6 +2920,7 @@ spec:
|
||||
automountServiceAccountToken: false
|
||||
containers:
|
||||
- command:
|
||||
- uid_entrypoint.sh
|
||||
- argocd-repo-server
|
||||
- --sentinel
|
||||
- argocd-redis-ha-announce-0:26379
|
||||
@@ -2925,7 +2930,7 @@ spec:
|
||||
- argocd-redis-ha-announce-2:26379
|
||||
- --sentinelmaster
|
||||
- argocd
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 5
|
||||
@@ -2999,7 +3004,7 @@ spec:
|
||||
- argocd-redis-ha-announce-2:26379
|
||||
- --sentinelmaster
|
||||
- argocd
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -1021,6 +1021,8 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
observedAt:
|
||||
description: ObservedAt indicates when the application state was updated
|
||||
without querying latest git state
|
||||
format: date-time
|
||||
type: string
|
||||
operationState:
|
||||
@@ -1487,6 +1489,8 @@ spec:
|
||||
- startedAt
|
||||
type: object
|
||||
reconciledAt:
|
||||
description: ReconciledAt indicates when the application state was reconciled
|
||||
using the latest git version
|
||||
format: date-time
|
||||
type: string
|
||||
resources:
|
||||
@@ -2665,7 +2669,7 @@ spec:
|
||||
- "20"
|
||||
- --operation-processors
|
||||
- "10"
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2719,7 +2723,7 @@ spec:
|
||||
- cp
|
||||
- /usr/local/bin/argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -2779,10 +2783,11 @@ spec:
|
||||
automountServiceAccountToken: false
|
||||
containers:
|
||||
- command:
|
||||
- uid_entrypoint.sh
|
||||
- argocd-repo-server
|
||||
- --redis
|
||||
- argocd-redis:6379
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 5
|
||||
@@ -2833,7 +2838,7 @@ spec:
|
||||
- argocd-server
|
||||
- --staticassets
|
||||
- /shared/app
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -1021,6 +1021,8 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
observedAt:
|
||||
description: ObservedAt indicates when the application state was updated
|
||||
without querying latest git state
|
||||
format: date-time
|
||||
type: string
|
||||
operationState:
|
||||
@@ -1487,6 +1489,8 @@ spec:
|
||||
- startedAt
|
||||
type: object
|
||||
reconciledAt:
|
||||
description: ReconciledAt indicates when the application state was reconciled
|
||||
using the latest git version
|
||||
format: date-time
|
||||
type: string
|
||||
resources:
|
||||
@@ -2580,7 +2584,7 @@ spec:
|
||||
- "20"
|
||||
- --operation-processors
|
||||
- "10"
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2634,7 +2638,7 @@ spec:
|
||||
- cp
|
||||
- /usr/local/bin/argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -2694,10 +2698,11 @@ spec:
|
||||
automountServiceAccountToken: false
|
||||
containers:
|
||||
- command:
|
||||
- uid_entrypoint.sh
|
||||
- argocd-repo-server
|
||||
- --redis
|
||||
- argocd-redis:6379
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 5
|
||||
@@ -2748,7 +2753,7 @@ spec:
|
||||
- argocd-server
|
||||
- --staticassets
|
||||
- /shared/app
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.2.5
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -36,6 +36,7 @@ import (
|
||||
versionpkg "github.com/argoproj/argo-cd/pkg/apiclient/version"
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
argoappv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
grpc_util "github.com/argoproj/argo-cd/util/grpc"
|
||||
"github.com/argoproj/argo-cd/util/localconfig"
|
||||
oidcutil "github.com/argoproj/argo-cd/util/oidc"
|
||||
@@ -387,7 +388,7 @@ func (c *client) newConn() (*grpc.ClientConn, io.Closer, error) {
|
||||
}
|
||||
conn, e := grpc_util.BlockingDial(context.Background(), network, serverAddr, creds, dialOpts...)
|
||||
closers = append(closers, conn)
|
||||
return conn, &inlineCloser{close: func() error {
|
||||
return conn, util.NewCloser(func() error {
|
||||
var firstErr error
|
||||
for i := range closers {
|
||||
err := closers[i].Close()
|
||||
@@ -396,7 +397,7 @@ func (c *client) newConn() (*grpc.ClientConn, io.Closer, error) {
|
||||
}
|
||||
}
|
||||
return firstErr
|
||||
}}, e
|
||||
}), e
|
||||
}
|
||||
|
||||
func (c *client) tlsConfig() (*tls.Config, error) {
|
||||
|
||||
@@ -43,14 +43,6 @@ func (noopCodec) String() string {
|
||||
return "bytes"
|
||||
}
|
||||
|
||||
type inlineCloser struct {
|
||||
close func() error
|
||||
}
|
||||
|
||||
func (c *inlineCloser) Close() error {
|
||||
return c.close()
|
||||
}
|
||||
|
||||
func toFrame(msg []byte) []byte {
|
||||
frame := append([]byte{0, 0, 0, 0}, msg...)
|
||||
binary.BigEndian.PutUint32(frame, uint32(len(msg)))
|
||||
@@ -185,7 +177,7 @@ func (c *client) useGRPCProxy() (net.Addr, io.Closer, error) {
|
||||
}
|
||||
c.proxyUsersCount = c.proxyUsersCount + 1
|
||||
|
||||
return c.proxyListener.Addr(), &inlineCloser{close: func() error {
|
||||
return c.proxyListener.Addr(), util.NewCloser(func() error {
|
||||
c.proxyMutex.Lock()
|
||||
defer c.proxyMutex.Unlock()
|
||||
c.proxyUsersCount = c.proxyUsersCount - 1
|
||||
@@ -196,5 +188,5 @@ func (c *client) useGRPCProxy() (net.Addr, io.Closer, error) {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func (m *SettingsQuery) Reset() { *m = SettingsQuery{} }
|
||||
func (m *SettingsQuery) String() string { return proto.CompactTextString(m) }
|
||||
func (*SettingsQuery) ProtoMessage() {}
|
||||
func (*SettingsQuery) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_settings_7350a88adeab0893, []int{0}
|
||||
return fileDescriptor_settings_ab575d97e47167cb, []int{0}
|
||||
}
|
||||
func (m *SettingsQuery) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -73,24 +73,26 @@ func (m *SettingsQuery) XXX_DiscardUnknown() {
|
||||
var xxx_messageInfo_SettingsQuery proto.InternalMessageInfo
|
||||
|
||||
type Settings struct {
|
||||
URL string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
|
||||
DexConfig *DexConfig `protobuf:"bytes,2,opt,name=dexConfig" json:"dexConfig,omitempty"`
|
||||
OIDCConfig *OIDCConfig `protobuf:"bytes,3,opt,name=oidcConfig" json:"oidcConfig,omitempty"`
|
||||
AppLabelKey string `protobuf:"bytes,4,opt,name=appLabelKey,proto3" json:"appLabelKey,omitempty"`
|
||||
ResourceOverrides map[string]*v1alpha1.ResourceOverride `protobuf:"bytes,5,rep,name=resourceOverrides" json:"resourceOverrides,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"`
|
||||
StatusBadgeEnabled bool `protobuf:"varint,6,opt,name=statusBadgeEnabled,proto3" json:"statusBadgeEnabled,omitempty"`
|
||||
GoogleAnalytics *GoogleAnalyticsConfig `protobuf:"bytes,7,opt,name=googleAnalytics" json:"googleAnalytics,omitempty"`
|
||||
KustomizeOptions *v1alpha1.KustomizeOptions `protobuf:"bytes,8,opt,name=kustomizeOptions" json:"kustomizeOptions,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
URL string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
|
||||
DexConfig *DexConfig `protobuf:"bytes,2,opt,name=dexConfig" json:"dexConfig,omitempty"`
|
||||
OIDCConfig *OIDCConfig `protobuf:"bytes,3,opt,name=oidcConfig" json:"oidcConfig,omitempty"`
|
||||
AppLabelKey string `protobuf:"bytes,4,opt,name=appLabelKey,proto3" json:"appLabelKey,omitempty"`
|
||||
ResourceOverrides map[string]*v1alpha1.ResourceOverride `protobuf:"bytes,5,rep,name=resourceOverrides" json:"resourceOverrides,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"`
|
||||
StatusBadgeEnabled bool `protobuf:"varint,6,opt,name=statusBadgeEnabled,proto3" json:"statusBadgeEnabled,omitempty"`
|
||||
GoogleAnalytics *GoogleAnalyticsConfig `protobuf:"bytes,7,opt,name=googleAnalytics" json:"googleAnalytics,omitempty"`
|
||||
KustomizeOptions *v1alpha1.KustomizeOptions `protobuf:"bytes,8,opt,name=kustomizeOptions" json:"kustomizeOptions,omitempty"`
|
||||
// Help settings
|
||||
Help *Help `protobuf:"bytes,9,opt,name=help" json:"help,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Settings) Reset() { *m = Settings{} }
|
||||
func (m *Settings) String() string { return proto.CompactTextString(m) }
|
||||
func (*Settings) ProtoMessage() {}
|
||||
func (*Settings) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_settings_7350a88adeab0893, []int{1}
|
||||
return fileDescriptor_settings_ab575d97e47167cb, []int{1}
|
||||
}
|
||||
func (m *Settings) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -175,6 +177,13 @@ func (m *Settings) GetKustomizeOptions() *v1alpha1.KustomizeOptions {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Settings) GetHelp() *Help {
|
||||
if m != nil {
|
||||
return m.Help
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GoogleAnalyticsConfig struct {
|
||||
TrackingID string `protobuf:"bytes,1,opt,name=trackingID,proto3" json:"trackingID,omitempty"`
|
||||
AnonymizeUsers bool `protobuf:"varint,2,opt,name=anonymizeUsers,proto3" json:"anonymizeUsers,omitempty"`
|
||||
@@ -187,7 +196,7 @@ func (m *GoogleAnalyticsConfig) Reset() { *m = GoogleAnalyticsConfig{} }
|
||||
func (m *GoogleAnalyticsConfig) String() string { return proto.CompactTextString(m) }
|
||||
func (*GoogleAnalyticsConfig) ProtoMessage() {}
|
||||
func (*GoogleAnalyticsConfig) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_settings_7350a88adeab0893, []int{2}
|
||||
return fileDescriptor_settings_ab575d97e47167cb, []int{2}
|
||||
}
|
||||
func (m *GoogleAnalyticsConfig) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -230,6 +239,64 @@ func (m *GoogleAnalyticsConfig) GetAnonymizeUsers() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Help settings
|
||||
type Help struct {
|
||||
// the URL for getting chat help, this will typically be your Slack channel for support
|
||||
ChatUrl string `protobuf:"bytes,1,opt,name=chatUrl,proto3" json:"chatUrl,omitempty"`
|
||||
// the text for getting chat help, defaults to "Chat now!"
|
||||
ChatText string `protobuf:"bytes,2,opt,name=chatText,proto3" json:"chatText,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Help) Reset() { *m = Help{} }
|
||||
func (m *Help) String() string { return proto.CompactTextString(m) }
|
||||
func (*Help) ProtoMessage() {}
|
||||
func (*Help) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_settings_ab575d97e47167cb, []int{3}
|
||||
}
|
||||
func (m *Help) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *Help) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_Help.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalTo(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (dst *Help) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Help.Merge(dst, src)
|
||||
}
|
||||
func (m *Help) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *Help) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Help.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Help proto.InternalMessageInfo
|
||||
|
||||
func (m *Help) GetChatUrl() string {
|
||||
if m != nil {
|
||||
return m.ChatUrl
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Help) GetChatText() string {
|
||||
if m != nil {
|
||||
return m.ChatText
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type DexConfig struct {
|
||||
Connectors []*Connector `protobuf:"bytes,1,rep,name=connectors" json:"connectors,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
@@ -241,7 +308,7 @@ func (m *DexConfig) Reset() { *m = DexConfig{} }
|
||||
func (m *DexConfig) String() string { return proto.CompactTextString(m) }
|
||||
func (*DexConfig) ProtoMessage() {}
|
||||
func (*DexConfig) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_settings_7350a88adeab0893, []int{3}
|
||||
return fileDescriptor_settings_ab575d97e47167cb, []int{4}
|
||||
}
|
||||
func (m *DexConfig) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -289,7 +356,7 @@ func (m *Connector) Reset() { *m = Connector{} }
|
||||
func (m *Connector) String() string { return proto.CompactTextString(m) }
|
||||
func (*Connector) ProtoMessage() {}
|
||||
func (*Connector) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_settings_7350a88adeab0893, []int{4}
|
||||
return fileDescriptor_settings_ab575d97e47167cb, []int{5}
|
||||
}
|
||||
func (m *Connector) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -347,7 +414,7 @@ func (m *OIDCConfig) Reset() { *m = OIDCConfig{} }
|
||||
func (m *OIDCConfig) String() string { return proto.CompactTextString(m) }
|
||||
func (*OIDCConfig) ProtoMessage() {}
|
||||
func (*OIDCConfig) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_settings_7350a88adeab0893, []int{5}
|
||||
return fileDescriptor_settings_ab575d97e47167cb, []int{6}
|
||||
}
|
||||
func (m *OIDCConfig) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -416,6 +483,7 @@ func init() {
|
||||
proto.RegisterType((*Settings)(nil), "cluster.Settings")
|
||||
proto.RegisterMapType((map[string]*v1alpha1.ResourceOverride)(nil), "cluster.Settings.ResourceOverridesEntry")
|
||||
proto.RegisterType((*GoogleAnalyticsConfig)(nil), "cluster.GoogleAnalyticsConfig")
|
||||
proto.RegisterType((*Help)(nil), "cluster.Help")
|
||||
proto.RegisterType((*DexConfig)(nil), "cluster.DexConfig")
|
||||
proto.RegisterType((*Connector)(nil), "cluster.Connector")
|
||||
proto.RegisterType((*OIDCConfig)(nil), "cluster.OIDCConfig")
|
||||
@@ -621,6 +689,16 @@ func (m *Settings) MarshalTo(dAtA []byte) (int, error) {
|
||||
}
|
||||
i += n5
|
||||
}
|
||||
if m.Help != nil {
|
||||
dAtA[i] = 0x4a
|
||||
i++
|
||||
i = encodeVarintSettings(dAtA, i, uint64(m.Help.Size()))
|
||||
n6, err := m.Help.MarshalTo(dAtA[i:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i += n6
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
i += copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
@@ -664,6 +742,39 @@ func (m *GoogleAnalyticsConfig) MarshalTo(dAtA []byte) (int, error) {
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *Help) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *Help) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.ChatUrl) > 0 {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintSettings(dAtA, i, uint64(len(m.ChatUrl)))
|
||||
i += copy(dAtA[i:], m.ChatUrl)
|
||||
}
|
||||
if len(m.ChatText) > 0 {
|
||||
dAtA[i] = 0x12
|
||||
i++
|
||||
i = encodeVarintSettings(dAtA, i, uint64(len(m.ChatText)))
|
||||
i += copy(dAtA[i:], m.ChatText)
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
i += copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *DexConfig) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
@@ -851,6 +962,10 @@ func (m *Settings) Size() (n int) {
|
||||
l = m.KustomizeOptions.Size()
|
||||
n += 1 + l + sovSettings(uint64(l))
|
||||
}
|
||||
if m.Help != nil {
|
||||
l = m.Help.Size()
|
||||
n += 1 + l + sovSettings(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
@@ -873,6 +988,23 @@ func (m *GoogleAnalyticsConfig) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *Help) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.ChatUrl)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovSettings(uint64(l))
|
||||
}
|
||||
l = len(m.ChatText)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovSettings(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *DexConfig) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
@@ -1362,6 +1494,39 @@ func (m *Settings) Unmarshal(dAtA []byte) error {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 9:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Help", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.Help == nil {
|
||||
m.Help = &Help{}
|
||||
}
|
||||
if err := m.Help.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSettings(dAtA[iNdEx:])
|
||||
@@ -1484,6 +1649,115 @@ func (m *GoogleAnalyticsConfig) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *Help) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Help: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Help: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ChatUrl", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ChatUrl = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ChatText", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ChatText = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSettings(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *DexConfig) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
@@ -1977,53 +2251,56 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("server/settings/settings.proto", fileDescriptor_settings_7350a88adeab0893)
|
||||
proto.RegisterFile("server/settings/settings.proto", fileDescriptor_settings_ab575d97e47167cb)
|
||||
}
|
||||
|
||||
var fileDescriptor_settings_7350a88adeab0893 = []byte{
|
||||
// 699 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xcd, 0x6e, 0xd3, 0x40,
|
||||
0x10, 0x96, 0x9b, 0xfe, 0x24, 0x13, 0x68, 0xda, 0x05, 0x2a, 0x13, 0xa1, 0x24, 0xca, 0x01, 0xe5,
|
||||
0x82, 0x4d, 0xd2, 0x0b, 0xe2, 0x02, 0x24, 0xa9, 0x4a, 0x68, 0xa5, 0x8a, 0xad, 0xca, 0x01, 0x09,
|
||||
0x55, 0x1b, 0x7b, 0x71, 0x4d, 0xdc, 0x5d, 0x6b, 0x77, 0x1d, 0x08, 0x47, 0xde, 0x00, 0x71, 0xe6,
|
||||
0x11, 0x78, 0x0f, 0x8e, 0x48, 0xdc, 0x23, 0x14, 0xf1, 0x20, 0xc8, 0xeb, 0x9f, 0x84, 0x24, 0x07,
|
||||
0x24, 0x6e, 0xe3, 0xef, 0xdb, 0x6f, 0x76, 0x66, 0xfd, 0xcd, 0x40, 0x4d, 0x52, 0x31, 0xa6, 0xc2,
|
||||
0x96, 0x54, 0x29, 0x9f, 0x79, 0x32, 0x0f, 0xac, 0x50, 0x70, 0xc5, 0xd1, 0x8e, 0x13, 0x44, 0x52,
|
||||
0x51, 0x51, 0xbd, 0xed, 0x71, 0x8f, 0x6b, 0xcc, 0x8e, 0xa3, 0x84, 0xae, 0xde, 0xf3, 0x38, 0xf7,
|
||||
0x02, 0x6a, 0x93, 0xd0, 0xb7, 0x09, 0x63, 0x5c, 0x11, 0xe5, 0x73, 0x96, 0x8a, 0xab, 0x03, 0xcf,
|
||||
0x57, 0x57, 0xd1, 0xd0, 0x72, 0xf8, 0xb5, 0x4d, 0x84, 0x96, 0xbf, 0xd3, 0xc1, 0x03, 0xc7, 0xb5,
|
||||
0xc3, 0x91, 0x17, 0xcb, 0xa4, 0x4d, 0xc2, 0x30, 0xf0, 0x1d, 0x2d, 0xb4, 0xc7, 0x6d, 0x12, 0x84,
|
||||
0x57, 0xa4, 0x6d, 0x7b, 0x94, 0x51, 0x41, 0x14, 0x75, 0x93, 0x54, 0xcd, 0x0a, 0xdc, 0x3c, 0x4f,
|
||||
0x2b, 0x7b, 0x19, 0x51, 0x31, 0x69, 0x7e, 0xdd, 0x82, 0x62, 0x86, 0xa0, 0xbb, 0x50, 0x88, 0x44,
|
||||
0x60, 0x1a, 0x0d, 0xa3, 0x55, 0xea, 0xee, 0xcc, 0xa6, 0xf5, 0xc2, 0x05, 0x3e, 0xc5, 0x31, 0x86,
|
||||
0x1e, 0x42, 0xc9, 0xa5, 0x1f, 0x7a, 0x9c, 0xbd, 0xf5, 0x3d, 0x73, 0xa3, 0x61, 0xb4, 0xca, 0x1d,
|
||||
0x64, 0xa5, 0x4d, 0x59, 0xfd, 0x8c, 0xc1, 0xf3, 0x43, 0xa8, 0x07, 0xc0, 0x7d, 0xd7, 0x49, 0x25,
|
||||
0x05, 0x2d, 0xb9, 0x95, 0x4b, 0xce, 0x06, 0xfd, 0x5e, 0x42, 0x75, 0x77, 0x67, 0xd3, 0x3a, 0xcc,
|
||||
0xbf, 0xf1, 0x82, 0x0c, 0x35, 0xa0, 0x4c, 0xc2, 0xf0, 0x94, 0x0c, 0x69, 0x70, 0x42, 0x27, 0xe6,
|
||||
0x66, 0x5c, 0x19, 0x5e, 0x84, 0xd0, 0x2b, 0xd8, 0x17, 0x54, 0xf2, 0x48, 0x38, 0xf4, 0x6c, 0x4c,
|
||||
0x85, 0xf0, 0x5d, 0x2a, 0xcd, 0xad, 0x46, 0xa1, 0x55, 0xee, 0xb4, 0xf2, 0xdb, 0xb2, 0x0e, 0x2d,
|
||||
0xbc, 0x7c, 0xf4, 0x88, 0x29, 0x31, 0xc1, 0xab, 0x29, 0x90, 0x05, 0x48, 0x2a, 0xa2, 0x22, 0xd9,
|
||||
0x25, 0xae, 0x47, 0x8f, 0x18, 0x19, 0x06, 0xd4, 0x35, 0xb7, 0x1b, 0x46, 0xab, 0x88, 0xd7, 0x30,
|
||||
0xe8, 0x39, 0x54, 0x92, 0x9f, 0xf8, 0x8c, 0x91, 0x60, 0xa2, 0x7c, 0x47, 0x9a, 0x3b, 0xba, 0xe7,
|
||||
0x5a, 0x5e, 0xc5, 0xf1, 0xdf, 0x7c, 0xda, 0xee, 0xb2, 0x0c, 0xbd, 0x87, 0xbd, 0x51, 0x24, 0x15,
|
||||
0xbf, 0xf6, 0x3f, 0xd2, 0xb3, 0x50, 0x1b, 0xc1, 0x2c, 0xea, 0x54, 0x27, 0xd6, 0xdc, 0x09, 0x56,
|
||||
0xe6, 0x04, 0x1d, 0x5c, 0x3a, 0xae, 0x15, 0x8e, 0x3c, 0x2b, 0x76, 0x82, 0xb5, 0xe0, 0x04, 0x2b,
|
||||
0x73, 0x82, 0x75, 0xb2, 0x94, 0x12, 0xaf, 0x5c, 0x52, 0xfd, 0x6c, 0xc0, 0xc1, 0xfa, 0x07, 0x42,
|
||||
0x7b, 0x50, 0x18, 0xd1, 0x49, 0xe2, 0x0c, 0x1c, 0x87, 0x88, 0xc0, 0xd6, 0x98, 0x04, 0x11, 0x4d,
|
||||
0xcd, 0xf0, 0x3f, 0xa5, 0x2d, 0xdf, 0x89, 0x93, 0xcc, 0x8f, 0x37, 0x1e, 0x19, 0xcd, 0x4b, 0xb8,
|
||||
0xb3, 0xf6, 0xd9, 0x50, 0x0d, 0x40, 0x09, 0xe2, 0x8c, 0x7c, 0xe6, 0x0d, 0xfa, 0x69, 0x61, 0x0b,
|
||||
0x08, 0xba, 0x0f, 0xbb, 0x84, 0x71, 0x36, 0x89, 0x1b, 0xbc, 0x90, 0x54, 0x48, 0x5d, 0x68, 0x11,
|
||||
0x2f, 0xa1, 0xcd, 0x27, 0x50, 0xca, 0xed, 0x8b, 0x3a, 0x00, 0x0e, 0x67, 0x8c, 0x3a, 0x8a, 0x0b,
|
||||
0x69, 0x1a, 0xda, 0x45, 0x73, 0x9b, 0xf7, 0x32, 0x0a, 0x2f, 0x9c, 0x6a, 0x1e, 0x42, 0x29, 0x27,
|
||||
0x10, 0x82, 0x4d, 0x46, 0xae, 0x69, 0x5a, 0x8f, 0x8e, 0x63, 0x4c, 0x4d, 0xc2, 0xe4, 0xa1, 0x4a,
|
||||
0x58, 0xc7, 0xcd, 0x6f, 0x06, 0x2c, 0x58, 0x7e, 0xad, 0xec, 0x00, 0xb6, 0x7d, 0x29, 0x23, 0x2a,
|
||||
0x52, 0x61, 0xfa, 0x85, 0x5a, 0x50, 0x74, 0x02, 0x9f, 0x32, 0x35, 0xe8, 0xeb, 0xa9, 0x2a, 0x75,
|
||||
0x6f, 0xcc, 0xa6, 0xf5, 0x62, 0x2f, 0xc5, 0x70, 0xce, 0xa2, 0x36, 0x94, 0x9d, 0xc0, 0xcf, 0x88,
|
||||
0x64, 0x78, 0xba, 0x95, 0xd9, 0xb4, 0x5e, 0xee, 0x9d, 0x0e, 0xf2, 0xf3, 0x8b, 0x67, 0xe2, 0x4b,
|
||||
0xa5, 0xc3, 0xc3, 0x74, 0x84, 0x4a, 0x38, 0xfd, 0xea, 0xbc, 0x81, 0x4a, 0x36, 0x43, 0xe7, 0x54,
|
||||
0x8c, 0x7d, 0x87, 0xa2, 0x17, 0x50, 0x38, 0xa6, 0x0a, 0x1d, 0xac, 0x0c, 0x99, 0x5e, 0x2c, 0xd5,
|
||||
0xfd, 0x15, 0xbc, 0x69, 0x7e, 0xfa, 0xf9, 0xfb, 0xcb, 0x06, 0x42, 0x7b, 0x7a, 0xcf, 0x8d, 0xdb,
|
||||
0xf9, 0x92, 0xec, 0x3e, 0xfd, 0x3e, 0xab, 0x19, 0x3f, 0x66, 0x35, 0xe3, 0xd7, 0xac, 0x66, 0xbc,
|
||||
0xee, 0xfc, 0xc3, 0xbe, 0x4b, 0x9a, 0xcc, 0x33, 0x0c, 0xb7, 0xf5, 0x7e, 0x3b, 0xfc, 0x13, 0x00,
|
||||
0x00, 0xff, 0xff, 0x5b, 0xcc, 0xdb, 0x51, 0x89, 0x05, 0x00, 0x00,
|
||||
var fileDescriptor_settings_ab575d97e47167cb = []byte{
|
||||
// 750 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xcd, 0x6e, 0x23, 0x45,
|
||||
0x10, 0xd6, 0xc4, 0xf9, 0xf1, 0x94, 0xd9, 0x4d, 0xb6, 0x81, 0x68, 0xb0, 0x90, 0x63, 0xe6, 0x80,
|
||||
0x7c, 0x61, 0x86, 0x78, 0x2f, 0x08, 0x21, 0x01, 0x76, 0x56, 0xbb, 0x26, 0x91, 0x22, 0x7a, 0x09,
|
||||
0x07, 0x24, 0xb4, 0xea, 0xf4, 0x14, 0xe3, 0xc1, 0x93, 0xee, 0x51, 0x77, 0x8f, 0x59, 0x73, 0xe4,
|
||||
0x0d, 0x10, 0xcf, 0xc1, 0x3b, 0x70, 0xe4, 0x88, 0xc4, 0xdd, 0x42, 0x16, 0x0f, 0x82, 0xa6, 0xe7,
|
||||
0xc7, 0xc6, 0xf6, 0x01, 0x89, 0x5b, 0x55, 0x7d, 0xf5, 0xd5, 0x4f, 0x77, 0x55, 0x41, 0x4f, 0xa3,
|
||||
0x9a, 0xa3, 0x0a, 0x35, 0x1a, 0x93, 0x88, 0x58, 0x37, 0x42, 0x90, 0x29, 0x69, 0x24, 0x39, 0xe1,
|
||||
0x69, 0xae, 0x0d, 0xaa, 0xee, 0x5b, 0xb1, 0x8c, 0xa5, 0xb5, 0x85, 0x85, 0x54, 0xc2, 0xdd, 0x77,
|
||||
0x63, 0x29, 0xe3, 0x14, 0x43, 0x96, 0x25, 0x21, 0x13, 0x42, 0x1a, 0x66, 0x12, 0x29, 0x2a, 0x72,
|
||||
0x77, 0x12, 0x27, 0x66, 0x9a, 0xdf, 0x07, 0x5c, 0x3e, 0x84, 0x4c, 0x59, 0xfa, 0xf7, 0x56, 0xf8,
|
||||
0x80, 0x47, 0x61, 0x36, 0x8b, 0x0b, 0x9a, 0x0e, 0x59, 0x96, 0xa5, 0x09, 0xb7, 0xc4, 0x70, 0x7e,
|
||||
0xc9, 0xd2, 0x6c, 0xca, 0x2e, 0xc3, 0x18, 0x05, 0x2a, 0x66, 0x30, 0x2a, 0x43, 0xf9, 0xa7, 0xf0,
|
||||
0xe8, 0x65, 0x55, 0xd9, 0x97, 0x39, 0xaa, 0x85, 0xff, 0xdb, 0x11, 0xb4, 0x6b, 0x0b, 0x79, 0x07,
|
||||
0x5a, 0xb9, 0x4a, 0x3d, 0xa7, 0xef, 0x0c, 0xdc, 0xd1, 0xc9, 0x6a, 0x79, 0xd1, 0xba, 0xa3, 0x37,
|
||||
0xb4, 0xb0, 0x91, 0x0f, 0xc1, 0x8d, 0xf0, 0xf5, 0x58, 0x8a, 0xef, 0x92, 0xd8, 0x3b, 0xe8, 0x3b,
|
||||
0x83, 0xce, 0x90, 0x04, 0x55, 0x53, 0xc1, 0x55, 0x8d, 0xd0, 0xb5, 0x13, 0x19, 0x03, 0xc8, 0x24,
|
||||
0xe2, 0x15, 0xa5, 0x65, 0x29, 0x6f, 0x36, 0x94, 0xdb, 0xc9, 0xd5, 0xb8, 0x84, 0x46, 0x8f, 0x57,
|
||||
0xcb, 0x0b, 0x58, 0xeb, 0x74, 0x83, 0x46, 0xfa, 0xd0, 0x61, 0x59, 0x76, 0xc3, 0xee, 0x31, 0xbd,
|
||||
0xc6, 0x85, 0x77, 0x58, 0x54, 0x46, 0x37, 0x4d, 0xe4, 0x6b, 0x78, 0xa2, 0x50, 0xcb, 0x5c, 0x71,
|
||||
0xbc, 0x9d, 0xa3, 0x52, 0x49, 0x84, 0xda, 0x3b, 0xea, 0xb7, 0x06, 0x9d, 0xe1, 0xa0, 0xc9, 0x56,
|
||||
0x77, 0x18, 0xd0, 0x6d, 0xd7, 0x67, 0xc2, 0xa8, 0x05, 0xdd, 0x0d, 0x41, 0x02, 0x20, 0xda, 0x30,
|
||||
0x93, 0xeb, 0x11, 0x8b, 0x62, 0x7c, 0x26, 0xd8, 0x7d, 0x8a, 0x91, 0x77, 0xdc, 0x77, 0x06, 0x6d,
|
||||
0xba, 0x07, 0x21, 0x2f, 0xe0, 0xb4, 0xfc, 0xc4, 0xcf, 0x05, 0x4b, 0x17, 0x26, 0xe1, 0xda, 0x3b,
|
||||
0xb1, 0x3d, 0xf7, 0x9a, 0x2a, 0x9e, 0xff, 0x1b, 0xaf, 0xda, 0xdd, 0xa6, 0x91, 0x1f, 0xe0, 0x6c,
|
||||
0x96, 0x6b, 0x23, 0x1f, 0x92, 0x1f, 0xf1, 0x36, 0xb3, 0x83, 0xe0, 0xb5, 0x6d, 0xa8, 0xeb, 0x60,
|
||||
0x3d, 0x09, 0x41, 0x3d, 0x09, 0x56, 0x78, 0xc5, 0xa3, 0x20, 0x9b, 0xc5, 0x41, 0x31, 0x09, 0xc1,
|
||||
0xc6, 0x24, 0x04, 0xf5, 0x24, 0x04, 0xd7, 0x5b, 0x21, 0xe9, 0x4e, 0x12, 0xf2, 0x1e, 0x1c, 0x4e,
|
||||
0x31, 0xcd, 0x3c, 0xd7, 0x26, 0x7b, 0xd4, 0xd4, 0xfd, 0x02, 0xd3, 0x8c, 0x5a, 0xa8, 0xfb, 0xb3,
|
||||
0x03, 0xe7, 0xfb, 0xdf, 0x90, 0x9c, 0x41, 0x6b, 0x86, 0x8b, 0x72, 0x78, 0x68, 0x21, 0x12, 0x06,
|
||||
0x47, 0x73, 0x96, 0xe6, 0x58, 0xcd, 0xcb, 0xff, 0xa9, 0x7e, 0x3b, 0x27, 0x2d, 0x23, 0x7f, 0x7c,
|
||||
0xf0, 0x91, 0xe3, 0xbf, 0x82, 0xb7, 0xf7, 0xbe, 0x2c, 0xe9, 0x01, 0x18, 0xc5, 0xf8, 0x2c, 0x11,
|
||||
0xf1, 0xe4, 0xaa, 0x2a, 0x6c, 0xc3, 0x42, 0xde, 0x87, 0xc7, 0x4c, 0x48, 0xb1, 0x28, 0xde, 0xe0,
|
||||
0x4e, 0xa3, 0xd2, 0xb6, 0xd0, 0x36, 0xdd, 0xb2, 0xfa, 0x9f, 0xc0, 0x61, 0xf1, 0x04, 0xc4, 0x83,
|
||||
0x13, 0x3e, 0x65, 0xe6, 0xae, 0x5e, 0x11, 0x5a, 0xab, 0xa4, 0x0b, 0xed, 0x42, 0xfc, 0x0a, 0x5f,
|
||||
0x1b, 0x1b, 0xc3, 0xa5, 0x8d, 0xee, 0x7f, 0x0a, 0x6e, 0xb3, 0x1f, 0x64, 0x08, 0xc0, 0xa5, 0x10,
|
||||
0xc8, 0x8d, 0x54, 0xda, 0x73, 0xec, 0x98, 0xae, 0xf7, 0x68, 0x5c, 0x43, 0x74, 0xc3, 0xcb, 0x7f,
|
||||
0x0a, 0x6e, 0x03, 0x10, 0x02, 0x87, 0x82, 0x3d, 0x60, 0x55, 0x80, 0x95, 0x0b, 0x9b, 0x59, 0x64,
|
||||
0x58, 0x65, 0xb6, 0xb2, 0xff, 0xab, 0x03, 0x1b, 0x3b, 0xb5, 0x97, 0x76, 0x0e, 0xc7, 0x89, 0xd6,
|
||||
0x39, 0xaa, 0x8a, 0x58, 0x69, 0x64, 0x00, 0x6d, 0x9e, 0x26, 0x28, 0xcc, 0xe4, 0xca, 0xae, 0xad,
|
||||
0x3b, 0x7a, 0x63, 0xb5, 0xbc, 0x68, 0x8f, 0x2b, 0x1b, 0x6d, 0x50, 0x72, 0x09, 0x1d, 0x9e, 0x26,
|
||||
0x35, 0x50, 0x6e, 0xe7, 0xe8, 0x74, 0xb5, 0xbc, 0xe8, 0x8c, 0x6f, 0x26, 0x8d, 0xff, 0xa6, 0x4f,
|
||||
0x91, 0x54, 0x73, 0x99, 0x55, 0x3b, 0xea, 0xd2, 0x4a, 0x1b, 0x7e, 0x0b, 0xa7, 0xf5, 0x92, 0xbe,
|
||||
0x44, 0x35, 0x4f, 0x38, 0x92, 0x2f, 0xa0, 0xf5, 0x1c, 0x0d, 0x39, 0xdf, 0xd9, 0x62, 0x7b, 0xb9,
|
||||
0xba, 0x4f, 0x76, 0xec, 0xbe, 0xf7, 0xd3, 0x9f, 0x7f, 0xff, 0x72, 0x40, 0xc8, 0x99, 0x3d, 0xa4,
|
||||
0xf3, 0xcb, 0xe6, 0x0a, 0x8f, 0x3e, 0xfb, 0x7d, 0xd5, 0x73, 0xfe, 0x58, 0xf5, 0x9c, 0xbf, 0x56,
|
||||
0x3d, 0xe7, 0x9b, 0xe1, 0x7f, 0x38, 0xa8, 0x65, 0x93, 0x4d, 0x84, 0xfb, 0x63, 0x7b, 0x40, 0x9f,
|
||||
0xfe, 0x13, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xa4, 0xe4, 0xcb, 0xea, 0x05, 0x00, 0x00,
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -224,10 +224,12 @@ message ApplicationStatus {
|
||||
|
||||
repeated ApplicationCondition conditions = 5;
|
||||
|
||||
// ReconciledAt indicates when the application state was reconciled using the latest git version
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time reconciledAt = 6;
|
||||
|
||||
optional OperationState operationState = 7;
|
||||
|
||||
// ObservedAt indicates when the application state was updated without querying latest git state
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time observedAt = 8;
|
||||
|
||||
optional string sourceType = 9;
|
||||
@@ -584,6 +586,8 @@ message ResourceDiff {
|
||||
optional string liveState = 6;
|
||||
|
||||
optional string diff = 7;
|
||||
|
||||
optional bool hook = 8;
|
||||
}
|
||||
|
||||
// ResourceIgnoreDifferences contains resource filter and list of json paths which should be ignored during comparison with live state.
|
||||
|
||||
@@ -861,7 +861,8 @@ func schema_pkg_apis_application_v1alpha1_ApplicationStatus(ref common.Reference
|
||||
},
|
||||
"reconciledAt": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
|
||||
Description: "ReconciledAt indicates when the application state was reconciled using the latest git version",
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
|
||||
},
|
||||
},
|
||||
"operationState": {
|
||||
@@ -871,7 +872,8 @@ func schema_pkg_apis_application_v1alpha1_ApplicationStatus(ref common.Reference
|
||||
},
|
||||
"observedAt": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
|
||||
Description: "ObservedAt indicates when the application state was updated without querying latest git state",
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
|
||||
},
|
||||
},
|
||||
"sourceType": {
|
||||
@@ -2097,6 +2099,12 @@ func schema_pkg_apis_application_v1alpha1_ResourceDiff(ref common.ReferenceCallb
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"hook": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -288,16 +288,18 @@ type ApplicationDestination struct {
|
||||
|
||||
// ApplicationStatus contains information about application sync, health status
|
||||
type ApplicationStatus struct {
|
||||
Resources []ResourceStatus `json:"resources,omitempty" protobuf:"bytes,1,opt,name=resources"`
|
||||
Sync SyncStatus `json:"sync,omitempty" protobuf:"bytes,2,opt,name=sync"`
|
||||
Health HealthStatus `json:"health,omitempty" protobuf:"bytes,3,opt,name=health"`
|
||||
History []RevisionHistory `json:"history,omitempty" protobuf:"bytes,4,opt,name=history"`
|
||||
Conditions []ApplicationCondition `json:"conditions,omitempty" protobuf:"bytes,5,opt,name=conditions"`
|
||||
ReconciledAt *metav1.Time `json:"reconciledAt,omitempty" protobuf:"bytes,6,opt,name=reconciledAt"`
|
||||
OperationState *OperationState `json:"operationState,omitempty" protobuf:"bytes,7,opt,name=operationState"`
|
||||
ObservedAt *metav1.Time `json:"observedAt,omitempty" protobuf:"bytes,8,opt,name=observedAt"`
|
||||
SourceType ApplicationSourceType `json:"sourceType,omitempty" protobuf:"bytes,9,opt,name=sourceType"`
|
||||
Summary ApplicationSummary `json:"summary,omitempty" protobuf:"bytes,10,opt,name=summary"`
|
||||
Resources []ResourceStatus `json:"resources,omitempty" protobuf:"bytes,1,opt,name=resources"`
|
||||
Sync SyncStatus `json:"sync,omitempty" protobuf:"bytes,2,opt,name=sync"`
|
||||
Health HealthStatus `json:"health,omitempty" protobuf:"bytes,3,opt,name=health"`
|
||||
History []RevisionHistory `json:"history,omitempty" protobuf:"bytes,4,opt,name=history"`
|
||||
Conditions []ApplicationCondition `json:"conditions,omitempty" protobuf:"bytes,5,opt,name=conditions"`
|
||||
// ReconciledAt indicates when the application state was reconciled using the latest git version
|
||||
ReconciledAt *metav1.Time `json:"reconciledAt,omitempty" protobuf:"bytes,6,opt,name=reconciledAt"`
|
||||
OperationState *OperationState `json:"operationState,omitempty" protobuf:"bytes,7,opt,name=operationState"`
|
||||
// ObservedAt indicates when the application state was updated without querying latest git state
|
||||
ObservedAt *metav1.Time `json:"observedAt,omitempty" protobuf:"bytes,8,opt,name=observedAt"`
|
||||
SourceType ApplicationSourceType `json:"sourceType,omitempty" protobuf:"bytes,9,opt,name=sourceType"`
|
||||
Summary ApplicationSummary `json:"summary,omitempty" protobuf:"bytes,10,opt,name=summary"`
|
||||
}
|
||||
|
||||
// Operation contains requested operation parameters.
|
||||
@@ -786,6 +788,7 @@ type ResourceDiff struct {
|
||||
TargetState string `json:"targetState,omitempty" protobuf:"bytes,5,opt,name=targetState"`
|
||||
LiveState string `json:"liveState,omitempty" protobuf:"bytes,6,opt,name=liveState"`
|
||||
Diff string `json:"diff,omitempty" protobuf:"bytes,7,opt,name=diff"`
|
||||
Hook bool `json:"hook,omitempty" protobuf:"bytes,8,opt,name=hook"`
|
||||
}
|
||||
|
||||
// ConnectionStatus represents connection status
|
||||
|
||||
@@ -189,28 +189,33 @@ func (s *Service) GenerateManifest(c context.Context, q *apiclient.ManifestReque
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func checkPath(root, path string) error {
|
||||
info, err := os.Stat(filepath.Join(root, path))
|
||||
func appPath(root, path string) (string, error) {
|
||||
if filepath.IsAbs(path) {
|
||||
return "", fmt.Errorf("%s: app path is absolute", path)
|
||||
}
|
||||
appPath := filepath.Join(root, path)
|
||||
if !strings.HasPrefix(appPath, filepath.Clean(root)) {
|
||||
return "", fmt.Errorf("%s: app path outside repo", path)
|
||||
}
|
||||
info, err := os.Stat(appPath)
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("%s: app path does not exist", path)
|
||||
return "", fmt.Errorf("%s: app path does not exist", path)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return fmt.Errorf("%s: app path is not a directory", path)
|
||||
return "", fmt.Errorf("%s: app path is not a directory", path)
|
||||
}
|
||||
return nil
|
||||
return appPath, nil
|
||||
}
|
||||
|
||||
// GenerateManifests generates manifests from a path
|
||||
func GenerateManifests(root, path string, q *apiclient.ManifestRequest) (*apiclient.ManifestResponse, error) {
|
||||
err := checkPath(root, path)
|
||||
appPath, err := appPath(root, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
appPath := filepath.Join(root, path)
|
||||
var targetObjs []*unstructured.Unstructured
|
||||
var dest *v1alpha1.ApplicationDestination
|
||||
|
||||
|
||||
@@ -90,16 +90,51 @@ func TestRecurseManifestsInDir(t *testing.T) {
|
||||
assert.Equal(t, 2, len(res1.Manifests))
|
||||
}
|
||||
|
||||
func TestPathRoot(t *testing.T) {
|
||||
_, err := appPath("./testdata", "/")
|
||||
assert.EqualError(t, err, "/: app path is absolute")
|
||||
}
|
||||
|
||||
func TestPathAbsolute(t *testing.T) {
|
||||
_, err := appPath("./testdata", "/etc/passwd")
|
||||
assert.EqualError(t, err, "/etc/passwd: app path is absolute")
|
||||
}
|
||||
|
||||
func TestPathDotDot(t *testing.T) {
|
||||
_, err := appPath("./testdata", "..")
|
||||
assert.EqualError(t, err, "..: app path outside repo")
|
||||
}
|
||||
|
||||
func TestPathDotDotSlash(t *testing.T) {
|
||||
_, err := appPath("./testdata", "../")
|
||||
assert.EqualError(t, err, "../: app path outside repo")
|
||||
}
|
||||
|
||||
func TestPathDot(t *testing.T) {
|
||||
_, err := appPath("./testdata", ".")
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestPathDotSlash(t *testing.T) {
|
||||
_, err := appPath("./testdata", "./")
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestNonExistentPath(t *testing.T) {
|
||||
_, err := GenerateManifests("./testdata", "does-not-exist", nil)
|
||||
_, err := appPath("./testdata", "does-not-exist")
|
||||
assert.EqualError(t, err, "does-not-exist: app path does not exist")
|
||||
}
|
||||
|
||||
func TestPathNotDir(t *testing.T) {
|
||||
_, err := GenerateManifests("./testdata", "file.txt", nil)
|
||||
_, err := appPath("./testdata", "file.txt")
|
||||
assert.EqualError(t, err, "file.txt: app path is not a directory")
|
||||
}
|
||||
|
||||
func TestGenerateManifests_NonExistentPath(t *testing.T) {
|
||||
_, err := GenerateManifests("./testdata", "does-not-exist", nil)
|
||||
assert.EqualError(t, err, "does-not-exist: app path does not exist")
|
||||
}
|
||||
|
||||
func TestGenerateJsonnetManifestInDir(t *testing.T) {
|
||||
q := apiclient.ManifestRequest{
|
||||
ApplicationSource: &argoappv1.ApplicationSource{
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
actionTests:
|
||||
- action: restart
|
||||
inputPath: testdata/daemonset.yaml
|
||||
expectedOutputPath: testdata/daemonset-restarted.yaml
|
||||
@@ -0,0 +1,3 @@
|
||||
actions = {}
|
||||
actions["restart"] = {}
|
||||
return actions
|
||||
@@ -0,0 +1,9 @@
|
||||
local os = require("os")
|
||||
if obj.spec.template.metadata == nil then
|
||||
obj.spec.template.metadata = {}
|
||||
end
|
||||
if obj.spec.template.metadata.annotations == nil then
|
||||
obj.spec.template.metadata.annotations = {}
|
||||
end
|
||||
obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ")
|
||||
return obj
|
||||
50
resource_customizations/apps/DaemonSet/actions/testdata/daemonset-restarted.yaml
vendored
Normal file
50
resource_customizations/apps/DaemonSet/actions/testdata/daemonset-restarted.yaml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
annotations:
|
||||
deprecated.daemonset.template.generation: "3"
|
||||
creationTimestamp: "2019-09-13T08:52:50Z"
|
||||
generation: 3
|
||||
labels:
|
||||
app.kubernetes.io/instance: extensions
|
||||
name: daemonset
|
||||
namespace: statefulset
|
||||
resourceVersion: "7472656"
|
||||
selfLink: /apis/apps/v1/namespaces/statefulset/daemonsets/daemonset
|
||||
uid: de04d075-d603-11e9-9e69-42010aa8005f
|
||||
spec:
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
name: daemonset
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
kubectl.kubernetes.io/restartedAt: "0001-01-01T00:00:00Z"
|
||||
labels:
|
||||
name: daemonset
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/nginx-slim:0.8
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: nginx
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 30
|
||||
updateStrategy:
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
type: RollingUpdate
|
||||
status:
|
||||
currentNumberScheduled: 4
|
||||
desiredNumberScheduled: 4
|
||||
numberAvailable: 4
|
||||
numberMisscheduled: 0
|
||||
numberReady: 4
|
||||
observedGeneration: 3
|
||||
updatedNumberScheduled: 4
|
||||
48
resource_customizations/apps/DaemonSet/actions/testdata/daemonset.yaml
vendored
Normal file
48
resource_customizations/apps/DaemonSet/actions/testdata/daemonset.yaml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
annotations:
|
||||
deprecated.daemonset.template.generation: "3"
|
||||
creationTimestamp: "2019-09-13T08:52:50Z"
|
||||
generation: 3
|
||||
labels:
|
||||
app.kubernetes.io/instance: extensions
|
||||
name: daemonset
|
||||
namespace: statefulset
|
||||
resourceVersion: "7472656"
|
||||
selfLink: /apis/apps/v1/namespaces/statefulset/daemonsets/daemonset
|
||||
uid: de04d075-d603-11e9-9e69-42010aa8005f
|
||||
spec:
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
name: daemonset
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: daemonset
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/nginx-slim:0.8
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: nginx
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 30
|
||||
updateStrategy:
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
type: RollingUpdate
|
||||
status:
|
||||
currentNumberScheduled: 4
|
||||
desiredNumberScheduled: 4
|
||||
numberAvailable: 4
|
||||
numberMisscheduled: 0
|
||||
numberReady: 4
|
||||
observedGeneration: 3
|
||||
updatedNumberScheduled: 4
|
||||
@@ -0,0 +1,4 @@
|
||||
actionTests:
|
||||
- action: restart
|
||||
inputPath: testdata/deployment.yaml
|
||||
expectedOutputPath: testdata/deployment-restarted.yaml
|
||||
@@ -0,0 +1,3 @@
|
||||
actions = {}
|
||||
actions["restart"] = {}
|
||||
return actions
|
||||
@@ -0,0 +1,9 @@
|
||||
local os = require("os")
|
||||
if obj.spec.template.metadata == nil then
|
||||
obj.spec.template.metadata = {}
|
||||
end
|
||||
if obj.spec.template.metadata.annotations == nil then
|
||||
obj.spec.template.metadata.annotations = {}
|
||||
end
|
||||
obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ")
|
||||
return obj
|
||||
63
resource_customizations/apps/Deployment/actions/testdata/deployment-restarted.yaml
vendored
Normal file
63
resource_customizations/apps/Deployment/actions/testdata/deployment-restarted.yaml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
annotations:
|
||||
deployment.kubernetes.io/revision: "1"
|
||||
creationTimestamp: "2019-09-12T01:33:53Z"
|
||||
generation: 1
|
||||
name: nginx-deploy
|
||||
namespace: default
|
||||
resourceVersion: "6897444"
|
||||
selfLink: /apis/apps/v1/namespaces/default/deployments/nginx-deploy
|
||||
uid: 61689d6d-d4fd-11e9-9e69-42010aa8005f
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
replicas: 3
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
maxUnavailable: 25%
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
annotations:
|
||||
kubectl.kubernetes.io/restartedAt: "0001-01-01T00:00:00Z"
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:latest
|
||||
imagePullPolicy: Always
|
||||
name: nginx
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 30
|
||||
status:
|
||||
availableReplicas: 2
|
||||
conditions:
|
||||
- lastTransitionTime: "2019-09-12T01:33:53Z"
|
||||
lastUpdateTime: "2019-09-12T01:33:53Z"
|
||||
message: Deployment does not have minimum availability.
|
||||
reason: MinimumReplicasUnavailable
|
||||
status: "False"
|
||||
type: Available
|
||||
- lastTransitionTime: "2019-09-12T01:33:53Z"
|
||||
lastUpdateTime: "2019-09-12T01:34:05Z"
|
||||
message: ReplicaSet "nginx-deploy-9cb4784bd" is progressing.
|
||||
reason: ReplicaSetUpdated
|
||||
status: "True"
|
||||
type: Progressing
|
||||
observedGeneration: 1
|
||||
readyReplicas: 2
|
||||
replicas: 3
|
||||
unavailableReplicas: 1
|
||||
updatedReplicas: 3
|
||||
61
resource_customizations/apps/Deployment/actions/testdata/deployment.yaml
vendored
Normal file
61
resource_customizations/apps/Deployment/actions/testdata/deployment.yaml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
annotations:
|
||||
deployment.kubernetes.io/revision: "1"
|
||||
creationTimestamp: "2019-09-12T01:33:53Z"
|
||||
generation: 1
|
||||
name: nginx-deploy
|
||||
namespace: default
|
||||
resourceVersion: "6897444"
|
||||
selfLink: /apis/apps/v1/namespaces/default/deployments/nginx-deploy
|
||||
uid: 61689d6d-d4fd-11e9-9e69-42010aa8005f
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
replicas: 3
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
maxUnavailable: 25%
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:latest
|
||||
imagePullPolicy: Always
|
||||
name: nginx
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 30
|
||||
status:
|
||||
availableReplicas: 2
|
||||
conditions:
|
||||
- lastTransitionTime: "2019-09-12T01:33:53Z"
|
||||
lastUpdateTime: "2019-09-12T01:33:53Z"
|
||||
message: Deployment does not have minimum availability.
|
||||
reason: MinimumReplicasUnavailable
|
||||
status: "False"
|
||||
type: Available
|
||||
- lastTransitionTime: "2019-09-12T01:33:53Z"
|
||||
lastUpdateTime: "2019-09-12T01:34:05Z"
|
||||
message: ReplicaSet "nginx-deploy-9cb4784bd" is progressing.
|
||||
reason: ReplicaSetUpdated
|
||||
status: "True"
|
||||
type: Progressing
|
||||
observedGeneration: 1
|
||||
readyReplicas: 2
|
||||
replicas: 3
|
||||
unavailableReplicas: 1
|
||||
updatedReplicas: 3
|
||||
@@ -0,0 +1,4 @@
|
||||
actionTests:
|
||||
- action: restart
|
||||
inputPath: testdata/statefulset.yaml
|
||||
expectedOutputPath: testdata/statefulset-restarted.yaml
|
||||
@@ -0,0 +1,3 @@
|
||||
actions = {}
|
||||
actions["restart"] = {}
|
||||
return actions
|
||||
@@ -0,0 +1,9 @@
|
||||
local os = require("os")
|
||||
if obj.spec.template.metadata == nil then
|
||||
obj.spec.template.metadata = {}
|
||||
end
|
||||
if obj.spec.template.metadata.annotations == nil then
|
||||
obj.spec.template.metadata.annotations = {}
|
||||
end
|
||||
obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ")
|
||||
return obj
|
||||
52
resource_customizations/apps/StatefulSet/actions/testdata/statefulset-restarted.yaml
vendored
Normal file
52
resource_customizations/apps/StatefulSet/actions/testdata/statefulset-restarted.yaml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
creationTimestamp: "2019-09-13T08:52:54Z"
|
||||
generation: 2
|
||||
labels:
|
||||
app.kubernetes.io/instance: extensions
|
||||
name: statefulset
|
||||
namespace: statefulset
|
||||
resourceVersion: "7471813"
|
||||
selfLink: /apis/apps/v1/namespaces/statefulset/statefulsets/statefulset
|
||||
uid: dfe8fadf-d603-11e9-9e69-42010aa8005f
|
||||
spec:
|
||||
podManagementPolicy: OrderedReady
|
||||
replicas: 3
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
app: statefulset
|
||||
serviceName: statefulset
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: statefulset
|
||||
annotations:
|
||||
kubectl.kubernetes.io/restartedAt: "0001-01-01T00:00:00Z"
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/nginx-slim:0.8
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: nginx
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 30
|
||||
updateStrategy:
|
||||
rollingUpdate:
|
||||
partition: 0
|
||||
type: RollingUpdate
|
||||
status:
|
||||
collisionCount: 0
|
||||
currentReplicas: 3
|
||||
currentRevision: statefulset-85b7f767c6
|
||||
observedGeneration: 2
|
||||
readyReplicas: 3
|
||||
replicas: 3
|
||||
updateRevision: statefulset-85b7f767c6
|
||||
updatedReplicas: 3
|
||||
50
resource_customizations/apps/StatefulSet/actions/testdata/statefulset.yaml
vendored
Normal file
50
resource_customizations/apps/StatefulSet/actions/testdata/statefulset.yaml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
creationTimestamp: "2019-09-13T08:52:54Z"
|
||||
generation: 2
|
||||
labels:
|
||||
app.kubernetes.io/instance: extensions
|
||||
name: statefulset
|
||||
namespace: statefulset
|
||||
resourceVersion: "7471813"
|
||||
selfLink: /apis/apps/v1/namespaces/statefulset/statefulsets/statefulset
|
||||
uid: dfe8fadf-d603-11e9-9e69-42010aa8005f
|
||||
spec:
|
||||
podManagementPolicy: OrderedReady
|
||||
replicas: 3
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
app: statefulset
|
||||
serviceName: statefulset
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: statefulset
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/nginx-slim:0.8
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: nginx
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 30
|
||||
updateStrategy:
|
||||
rollingUpdate:
|
||||
partition: 0
|
||||
type: RollingUpdate
|
||||
status:
|
||||
collisionCount: 0
|
||||
currentReplicas: 3
|
||||
currentRevision: statefulset-85b7f767c6
|
||||
observedGeneration: 2
|
||||
readyReplicas: 3
|
||||
replicas: 3
|
||||
updateRevision: statefulset-85b7f767c6
|
||||
updatedReplicas: 3
|
||||
@@ -7,13 +7,13 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bouk/monkey"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/yudai/gojsondiff/formatter"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/util/diff"
|
||||
"github.com/argoproj/argo-cd/util/lua"
|
||||
@@ -47,14 +47,14 @@ func TestLuaResourceActionsScript(t *testing.T) {
|
||||
if !strings.Contains(path, "action_test.yaml") {
|
||||
return nil
|
||||
}
|
||||
errors.CheckError(err)
|
||||
assert.NoError(t, err)
|
||||
dir := filepath.Dir(path)
|
||||
//TODO: Change to path
|
||||
yamlBytes, err := ioutil.ReadFile(dir + "/action_test.yaml")
|
||||
errors.CheckError(err)
|
||||
assert.NoError(t, err)
|
||||
var resourceTest ActionTestStructure
|
||||
err = yaml.Unmarshal(yamlBytes, &resourceTest)
|
||||
errors.CheckError(err)
|
||||
assert.NoError(t, err)
|
||||
for i := range resourceTest.DiscoveryTests {
|
||||
test := resourceTest.DiscoveryTests[i]
|
||||
testName := fmt.Sprintf("discovery/%s", test.InputPath)
|
||||
@@ -64,9 +64,9 @@ func TestLuaResourceActionsScript(t *testing.T) {
|
||||
}
|
||||
obj := getObj(filepath.Join(dir, test.InputPath))
|
||||
discoveryLua, err := vm.GetResourceActionDiscovery(obj)
|
||||
errors.CheckError(err)
|
||||
assert.NoError(t, err)
|
||||
result, err := vm.ExecuteResourceActionDiscovery(obj, discoveryLua)
|
||||
errors.CheckError(err)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, test.Result, result)
|
||||
})
|
||||
}
|
||||
@@ -75,20 +75,28 @@ func TestLuaResourceActionsScript(t *testing.T) {
|
||||
testName := fmt.Sprintf("actions/%s/%s", test.Action, test.InputPath)
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
vm := lua.VM{
|
||||
UseOpenLibs: true,
|
||||
// Uncomment the following line if you need to use lua libraries debugging
|
||||
// purposes. Otherwise, leave this false to ensure tests reflect the same
|
||||
// privileges that API server has.
|
||||
//UseOpenLibs: true,
|
||||
}
|
||||
obj := getObj(filepath.Join(dir, test.InputPath))
|
||||
action, err := vm.GetResourceAction(obj, test.Action)
|
||||
errors.CheckError(err)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// freeze time so that lua test has predictable time output (will return 0001-01-01T00:00:00Z)
|
||||
patch := monkey.Patch(time.Now, func() time.Time { return time.Time{} })
|
||||
result, err := vm.ExecuteResourceAction(obj, action.ActionLua)
|
||||
errors.CheckError(err)
|
||||
patch.Unpatch()
|
||||
|
||||
assert.NoError(t, err)
|
||||
expectedObj := getObj(filepath.Join(dir, test.ExpectedOutputPath))
|
||||
// Ideally, we would use a assert.Equal to detect the difference, but the Lua VM returns a object with float64 instead of the originial int32. As a result, the assert.Equal is never true despite that the change has been applied.
|
||||
// Ideally, we would use a assert.Equal to detect the difference, but the Lua VM returns a object with float64 instead of the original int32. As a result, the assert.Equal is never true despite that the change has been applied.
|
||||
diffResult := diff.Diff(expectedObj, result, testNormalizer{})
|
||||
if diffResult.Modified {
|
||||
output, err := diffResult.ASCIIFormat(expectedObj, formatter.AsciiFormatterConfig{})
|
||||
errors.CheckError(err)
|
||||
assert.Fail(t, "Output does not match input:", output)
|
||||
t.Error("Output does not match input:")
|
||||
err = diff.PrintDiff(test.Action, expectedObj, result)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
actionTests:
|
||||
- action: restart
|
||||
inputPath: testdata/daemonset.yaml
|
||||
expectedOutputPath: testdata/daemonset-restarted.yaml
|
||||
@@ -0,0 +1,3 @@
|
||||
actions = {}
|
||||
actions["restart"] = {}
|
||||
return actions
|
||||
@@ -0,0 +1,9 @@
|
||||
local os = require("os")
|
||||
if obj.spec.template.metadata == nil then
|
||||
obj.spec.template.metadata = {}
|
||||
end
|
||||
if obj.spec.template.metadata.annotations == nil then
|
||||
obj.spec.template.metadata.annotations = {}
|
||||
end
|
||||
obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ")
|
||||
return obj
|
||||
47
resource_customizations/extensions/DaemonSet/actions/testdata/daemonset-restarted.yaml
vendored
Normal file
47
resource_customizations/extensions/DaemonSet/actions/testdata/daemonset-restarted.yaml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
annotations:
|
||||
creationTimestamp: "2019-09-13T08:52:50Z"
|
||||
generation: 2
|
||||
labels:
|
||||
app.kubernetes.io/instance: extensions
|
||||
name: extensions-daemonset
|
||||
namespace: statefulset
|
||||
resourceVersion: "7471358"
|
||||
selfLink: /apis/extensions/v1beta1/namespaces/statefulset/daemonsets/extensions-daemonset
|
||||
uid: de09964a-d603-11e9-9e69-42010aa8005f
|
||||
spec:
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
name: extensions-daemonset
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
kubectl.kubernetes.io/restartedAt: "0001-01-01T00:00:00Z"
|
||||
labels:
|
||||
name: extensions-daemonset
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/nginx-slim:0.8
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: nginx
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 30
|
||||
templateGeneration: 2
|
||||
updateStrategy:
|
||||
type: OnDelete
|
||||
status:
|
||||
currentNumberScheduled: 4
|
||||
desiredNumberScheduled: 4
|
||||
numberAvailable: 4
|
||||
numberMisscheduled: 0
|
||||
numberReady: 4
|
||||
observedGeneration: 2
|
||||
45
resource_customizations/extensions/DaemonSet/actions/testdata/daemonset.yaml
vendored
Normal file
45
resource_customizations/extensions/DaemonSet/actions/testdata/daemonset.yaml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
annotations:
|
||||
creationTimestamp: "2019-09-13T08:52:50Z"
|
||||
generation: 2
|
||||
labels:
|
||||
app.kubernetes.io/instance: extensions
|
||||
name: extensions-daemonset
|
||||
namespace: statefulset
|
||||
resourceVersion: "7471358"
|
||||
selfLink: /apis/extensions/v1beta1/namespaces/statefulset/daemonsets/extensions-daemonset
|
||||
uid: de09964a-d603-11e9-9e69-42010aa8005f
|
||||
spec:
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
name: extensions-daemonset
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: extensions-daemonset
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/nginx-slim:0.8
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: nginx
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 30
|
||||
templateGeneration: 2
|
||||
updateStrategy:
|
||||
type: OnDelete
|
||||
status:
|
||||
currentNumberScheduled: 4
|
||||
desiredNumberScheduled: 4
|
||||
numberAvailable: 4
|
||||
numberMisscheduled: 0
|
||||
numberReady: 4
|
||||
observedGeneration: 2
|
||||
@@ -0,0 +1,4 @@
|
||||
actionTests:
|
||||
- action: restart
|
||||
inputPath: testdata/deployment.yaml
|
||||
expectedOutputPath: testdata/deployment-restarted.yaml
|
||||
@@ -0,0 +1,3 @@
|
||||
actions = {}
|
||||
actions["restart"] = {}
|
||||
return actions
|
||||
@@ -0,0 +1,9 @@
|
||||
local os = require("os")
|
||||
if obj.spec.template.metadata == nil then
|
||||
obj.spec.template.metadata = {}
|
||||
end
|
||||
if obj.spec.template.metadata.annotations == nil then
|
||||
obj.spec.template.metadata.annotations = {}
|
||||
end
|
||||
obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ")
|
||||
return obj
|
||||
63
resource_customizations/extensions/Deployment/actions/testdata/deployment-restarted.yaml
vendored
Normal file
63
resource_customizations/extensions/Deployment/actions/testdata/deployment-restarted.yaml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
annotations:
|
||||
deployment.kubernetes.io/revision: "1"
|
||||
creationTimestamp: "2019-09-12T01:33:53Z"
|
||||
generation: 1
|
||||
name: nginx-deploy
|
||||
namespace: default
|
||||
resourceVersion: "6897444"
|
||||
selfLink: /apis/apps/v1/namespaces/default/deployments/nginx-deploy
|
||||
uid: 61689d6d-d4fd-11e9-9e69-42010aa8005f
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
replicas: 3
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
maxUnavailable: 25%
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
annotations:
|
||||
kubectl.kubernetes.io/restartedAt: "0001-01-01T00:00:00Z"
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:latest
|
||||
imagePullPolicy: Always
|
||||
name: nginx
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 30
|
||||
status:
|
||||
availableReplicas: 2
|
||||
conditions:
|
||||
- lastTransitionTime: "2019-09-12T01:33:53Z"
|
||||
lastUpdateTime: "2019-09-12T01:33:53Z"
|
||||
message: Deployment does not have minimum availability.
|
||||
reason: MinimumReplicasUnavailable
|
||||
status: "False"
|
||||
type: Available
|
||||
- lastTransitionTime: "2019-09-12T01:33:53Z"
|
||||
lastUpdateTime: "2019-09-12T01:34:05Z"
|
||||
message: ReplicaSet "nginx-deploy-9cb4784bd" is progressing.
|
||||
reason: ReplicaSetUpdated
|
||||
status: "True"
|
||||
type: Progressing
|
||||
observedGeneration: 1
|
||||
readyReplicas: 2
|
||||
replicas: 3
|
||||
unavailableReplicas: 1
|
||||
updatedReplicas: 3
|
||||
61
resource_customizations/extensions/Deployment/actions/testdata/deployment.yaml
vendored
Normal file
61
resource_customizations/extensions/Deployment/actions/testdata/deployment.yaml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
annotations:
|
||||
deployment.kubernetes.io/revision: "1"
|
||||
creationTimestamp: "2019-09-12T01:33:53Z"
|
||||
generation: 1
|
||||
name: nginx-deploy
|
||||
namespace: default
|
||||
resourceVersion: "6897444"
|
||||
selfLink: /apis/apps/v1/namespaces/default/deployments/nginx-deploy
|
||||
uid: 61689d6d-d4fd-11e9-9e69-42010aa8005f
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
replicas: 3
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
maxUnavailable: 25%
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:latest
|
||||
imagePullPolicy: Always
|
||||
name: nginx
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 30
|
||||
status:
|
||||
availableReplicas: 2
|
||||
conditions:
|
||||
- lastTransitionTime: "2019-09-12T01:33:53Z"
|
||||
lastUpdateTime: "2019-09-12T01:33:53Z"
|
||||
message: Deployment does not have minimum availability.
|
||||
reason: MinimumReplicasUnavailable
|
||||
status: "False"
|
||||
type: Available
|
||||
- lastTransitionTime: "2019-09-12T01:33:53Z"
|
||||
lastUpdateTime: "2019-09-12T01:34:05Z"
|
||||
message: ReplicaSet "nginx-deploy-9cb4784bd" is progressing.
|
||||
reason: ReplicaSetUpdated
|
||||
status: "True"
|
||||
type: Progressing
|
||||
observedGeneration: 1
|
||||
readyReplicas: 2
|
||||
replicas: 3
|
||||
unavailableReplicas: 1
|
||||
updatedReplicas: 3
|
||||
@@ -121,6 +121,9 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
badge = replaceFirstGroupSubMatch(rightText1Pattern, badge, rightText)
|
||||
badge = replaceFirstGroupSubMatch(rightText2Pattern, badge, rightText)
|
||||
w.Header().Set("Content-Type", "image/svg+xml")
|
||||
|
||||
//Ask cache's to not cache the contents in order prevent the badge from becoming stale
|
||||
w.Header().Set("Cache-Control", "private, no-store")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte(badge))
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ func TestHandlerFeatureIsEnabled(t *testing.T) {
|
||||
rr := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control"))
|
||||
|
||||
response := rr.Body.String()
|
||||
assert.Equal(t, success, leftPathColorPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, success, rightPathColorPattern.FindStringSubmatch(response)[1])
|
||||
@@ -74,6 +76,8 @@ func TestHandlerFeatureIsDisabled(t *testing.T) {
|
||||
rr := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control"))
|
||||
|
||||
response := rr.Body.String()
|
||||
assert.Equal(t, unknown, leftPathColorPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, unknown, rightPathColorPattern.FindStringSubmatch(response)[1])
|
||||
|
||||
@@ -419,6 +419,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
|
||||
"/account.AccountService/UpdatePassword": true,
|
||||
"/repository.RepositoryService/Create": true,
|
||||
"/repository.RepositoryService/Update": true,
|
||||
"/repository.RepositoryService/ValidateAccess": true,
|
||||
"/application.ApplicationService/PatchResource": true,
|
||||
}
|
||||
// NOTE: notice we do not configure the gRPC server here with TLS (e.g. grpc.Creds(creds))
|
||||
@@ -660,6 +661,14 @@ func newAPIServerMetricsServer(port int) *http.Server {
|
||||
}
|
||||
}
|
||||
|
||||
func fileExists(filename string) bool {
|
||||
info, err := os.Stat(filename)
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return !info.IsDir()
|
||||
}
|
||||
|
||||
// newStaticAssetsHandler returns an HTTP handler to serve UI static assets
|
||||
func newStaticAssetsHandler(dir string, baseHRef string) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -670,7 +679,7 @@ func newStaticAssetsHandler(dir string, baseHRef string) func(http.ResponseWrite
|
||||
break
|
||||
}
|
||||
}
|
||||
fileRequest := r.URL.Path != "/index.html" && strings.Contains(r.URL.Path, ".")
|
||||
fileRequest := r.URL.Path != "/index.html" && fileExists(path.Join(dir, r.URL.Path))
|
||||
|
||||
// serve index.html for non file requests to support HTML5 History API
|
||||
if acceptHTML && !fileRequest && (r.Method == "GET" || r.Method == "HEAD") {
|
||||
|
||||
@@ -39,6 +39,10 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
help, err := s.mgr.GetHelp()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
overrides := make(map[string]*v1alpha1.ResourceOverride)
|
||||
for k := range resourceOverrides {
|
||||
@@ -58,6 +62,10 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin
|
||||
TrackingID: gaSettings.TrackingID,
|
||||
AnonymizeUsers: gaSettings.AnonymizeUsers,
|
||||
},
|
||||
Help: &settingspkg.Help{
|
||||
ChatUrl: help.ChatURL,
|
||||
ChatText: help.ChatText,
|
||||
},
|
||||
}
|
||||
if argoCDSettings.DexConfig != "" {
|
||||
var cfg settingspkg.DexConfig
|
||||
|
||||
@@ -23,6 +23,8 @@ message Settings {
|
||||
bool statusBadgeEnabled = 6;
|
||||
GoogleAnalyticsConfig googleAnalytics = 7;
|
||||
github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.KustomizeOptions kustomizeOptions = 8;
|
||||
// Help settings
|
||||
Help help = 9;
|
||||
}
|
||||
|
||||
message GoogleAnalyticsConfig {
|
||||
@@ -30,6 +32,14 @@ message GoogleAnalyticsConfig {
|
||||
bool anonymizeUsers = 2;
|
||||
}
|
||||
|
||||
// Help settings
|
||||
message Help {
|
||||
// the URL for getting chat help, this will typically be your Slack channel for support
|
||||
string chatUrl = 1;
|
||||
// the text for getting chat help, defaults to "Chat now!"
|
||||
string chatText = 2;
|
||||
}
|
||||
|
||||
message DexConfig {
|
||||
repeated Connector connectors = 1;
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@ func TestDeletingAppStuckInSync(t *testing.T) {
|
||||
Path("hook").
|
||||
When().
|
||||
PatchFile("hook.yaml", `[{"op": "replace", "path": "/spec/containers/0/command", "value": ["sh", "-c", "until ls /tmp/done; do sleep 0.1; done"]}]`).
|
||||
PatchFile("pod.yaml", `[{"op": "add", "path": "/metadata/annotations", "value": {"argocd.argoproj.io/sync-wave": "1"}}]`).
|
||||
Create().
|
||||
Sync().
|
||||
Then().
|
||||
// stuck in running state
|
||||
Expect(OperationPhaseIs(OperationRunning)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
Expect(ResourceResultNumbering(2)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
When().
|
||||
Delete(true).
|
||||
Then().
|
||||
|
||||
@@ -17,12 +17,12 @@ import (
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
. "github.com/argoproj/argo-cd/errors"
|
||||
applicationpkg "github.com/argoproj/argo-cd/pkg/apiclient/application"
|
||||
repositorypkg "github.com/argoproj/argo-cd/pkg/apiclient/repository"
|
||||
. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/reposerver/apiclient"
|
||||
"github.com/argoproj/argo-cd/test/e2e/fixture"
|
||||
. "github.com/argoproj/argo-cd/test/e2e/fixture"
|
||||
. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
. "github.com/argoproj/argo-cd/util/argo"
|
||||
@@ -44,18 +44,18 @@ func TestAppCreation(t *testing.T) {
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
And(func(app *Application) {
|
||||
assert.Equal(t, fixture.Name(), app.Name)
|
||||
assert.Equal(t, fixture.RepoURL(fixture.RepoURLTypeFile), app.Spec.Source.RepoURL)
|
||||
assert.Equal(t, Name(), app.Name)
|
||||
assert.Equal(t, RepoURL(RepoURLTypeFile), app.Spec.Source.RepoURL)
|
||||
assert.Equal(t, guestbookPath, app.Spec.Source.Path)
|
||||
assert.Equal(t, fixture.DeploymentNamespace(), app.Spec.Destination.Namespace)
|
||||
assert.Equal(t, DeploymentNamespace(), app.Spec.Destination.Namespace)
|
||||
assert.Equal(t, common.KubernetesInternalAPIServerAddr, app.Spec.Destination.Server)
|
||||
}).
|
||||
Expect(Event(EventReasonResourceCreated, "create")).
|
||||
And(func(_ *Application) {
|
||||
// app should be listed
|
||||
output, err := fixture.RunCli("app", "list")
|
||||
output, err := RunCli("app", "list")
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, output, fixture.Name())
|
||||
assert.Contains(t, output, Name())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -83,9 +83,9 @@ func TestAppDeletion(t *testing.T) {
|
||||
Expect(DoesNotExist()).
|
||||
Expect(Event(EventReasonResourceDeleted, "delete"))
|
||||
|
||||
output, err := fixture.RunCli("app", "list")
|
||||
output, err := RunCli("app", "list")
|
||||
assert.NoError(t, err)
|
||||
assert.NotContains(t, output, fixture.Name())
|
||||
assert.NotContains(t, output, Name())
|
||||
}
|
||||
|
||||
func TestTrackAppStateAndSyncApp(t *testing.T) {
|
||||
@@ -95,10 +95,10 @@ func TestTrackAppStateAndSyncApp(t *testing.T) {
|
||||
Create().
|
||||
Sync().
|
||||
Then().
|
||||
Expect(Success(fmt.Sprintf("apps Deployment %s guestbook-ui OutOfSync Missing", fixture.DeploymentNamespace()))).
|
||||
Expect(Success(fmt.Sprintf("Service %s guestbook-ui OutOfSync Missing", fixture.DeploymentNamespace()))).
|
||||
Expect(Success(fmt.Sprintf("Service %s guestbook-ui Synced Healthy service/guestbook-ui created", fixture.DeploymentNamespace()))).
|
||||
Expect(Success(fmt.Sprintf("apps Deployment %s guestbook-ui Synced Healthy deployment.apps/guestbook-ui created", fixture.DeploymentNamespace()))).
|
||||
Expect(Success(fmt.Sprintf("apps Deployment %s guestbook-ui OutOfSync Missing", DeploymentNamespace()))).
|
||||
Expect(Success(fmt.Sprintf("Service %s guestbook-ui OutOfSync Missing", DeploymentNamespace()))).
|
||||
Expect(Success(fmt.Sprintf("Service %s guestbook-ui Synced Healthy service/guestbook-ui created", DeploymentNamespace()))).
|
||||
Expect(Success(fmt.Sprintf("apps Deployment %s guestbook-ui Synced Healthy deployment.apps/guestbook-ui created", DeploymentNamespace()))).
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
Expect(Event(EventReasonResourceUpdated, "sync")).
|
||||
@@ -134,11 +134,11 @@ func TestAppRollbackSuccessful(t *testing.T) {
|
||||
patch, _, err := diff.CreateTwoWayMergePatch(app, appWithHistory, &Application{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
app, err = fixture.AppClientset.ArgoprojV1alpha1().Applications(fixture.ArgoCDNamespace).Patch(app.Name, types.MergePatchType, patch)
|
||||
app, err = AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Patch(app.Name, types.MergePatchType, patch)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// sync app and make sure it reaches InSync state
|
||||
_, err = fixture.RunCli("app", "rollback", app.Name, "1")
|
||||
_, err = RunCli("app", "rollback", app.Name, "1")
|
||||
assert.NoError(t, err)
|
||||
|
||||
}).
|
||||
@@ -184,7 +184,7 @@ func TestManipulateApplicationResources(t *testing.T) {
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
And(func(app *Application) {
|
||||
manifests, err := fixture.RunCli("app", "manifests", app.Name, "--source", "live")
|
||||
manifests, err := RunCli("app", "manifests", app.Name, "--source", "live")
|
||||
assert.NoError(t, err)
|
||||
resources, err := kube.SplitYAML(manifests)
|
||||
assert.NoError(t, err)
|
||||
@@ -201,7 +201,7 @@ func TestManipulateApplicationResources(t *testing.T) {
|
||||
|
||||
deployment := resources[index]
|
||||
|
||||
closer, client, err := fixture.ArgoCDClientset.NewApplicationClient()
|
||||
closer, client, err := ArgoCDClientset.NewApplicationClient()
|
||||
assert.NoError(t, err)
|
||||
defer util.Close(closer)
|
||||
|
||||
@@ -243,7 +243,7 @@ func assetSecretDataHidden(t *testing.T, manifest string) {
|
||||
}
|
||||
|
||||
func TestAppWithSecrets(t *testing.T) {
|
||||
closer, client, err := fixture.ArgoCDClientset.NewApplicationClient()
|
||||
closer, client, err := ArgoCDClientset.NewApplicationClient()
|
||||
assert.NoError(t, err)
|
||||
defer util.Close(closer)
|
||||
|
||||
@@ -255,49 +255,45 @@ func TestAppWithSecrets(t *testing.T) {
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
And(func(app *Application) {
|
||||
res, err := client.GetResource(context.Background(), &applicationpkg.ApplicationResourceRequest{
|
||||
res := FailOnErr(client.GetResource(context.Background(), &applicationpkg.ApplicationResourceRequest{
|
||||
Namespace: app.Spec.Destination.Namespace,
|
||||
Kind: kube.SecretKind,
|
||||
Group: "",
|
||||
Name: &app.Name,
|
||||
Version: "v1",
|
||||
ResourceName: "test-secret",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
})).(*applicationpkg.ApplicationResourceResponse)
|
||||
assetSecretDataHidden(t, res.Manifest)
|
||||
|
||||
diffOutput, err := fixture.RunCli("app", "diff", app.Name)
|
||||
assert.NoError(t, err)
|
||||
diffOutput := FailOnErr(RunCli("app", "diff", app.Name)).(string)
|
||||
assert.Empty(t, diffOutput)
|
||||
|
||||
// patch secret and make sure app is out of sync and diff detects the change
|
||||
_, err = fixture.KubeClientset.CoreV1().Secrets(fixture.DeploymentNamespace()).Patch(
|
||||
"test-secret", types.JSONPatchType, []byte(`[{"op": "remove", "path": "/data/username"}]`))
|
||||
assert.NoError(t, err)
|
||||
FailOnErr(KubeClientset.CoreV1().Secrets(DeploymentNamespace()).Patch(
|
||||
"test-secret", types.JSONPatchType, []byte(`[
|
||||
{"op": "remove", "path": "/data/username"},
|
||||
{"op": "add", "path": "/stringData", "value": {"password": "foo"}}
|
||||
]`)))
|
||||
}).
|
||||
When().
|
||||
Refresh(RefreshTypeNormal).
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
And(func(app *Application) {
|
||||
|
||||
diffOutput, err := fixture.RunCli("app", "diff", app.Name)
|
||||
diffOutput, err := RunCli("app", "diff", app.Name)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, diffOutput, "username: '*********'")
|
||||
assert.Contains(t, diffOutput, "username: ++++++++")
|
||||
assert.Contains(t, diffOutput, "password: ++++++++++++")
|
||||
|
||||
// local diff should ignore secrets
|
||||
diffOutput, err = fixture.RunCli("app", "diff", app.Name, "--local", "testdata/secrets")
|
||||
assert.NoError(t, err)
|
||||
diffOutput = FailOnErr(RunCli("app", "diff", app.Name, "--local", "testdata/secrets")).(string)
|
||||
assert.Empty(t, diffOutput)
|
||||
|
||||
// ignore missing field and make sure diff shows no difference
|
||||
app.Spec.IgnoreDifferences = []ResourceIgnoreDifferences{{
|
||||
Kind: kube.SecretKind, JSONPointers: []string{"/data/username"},
|
||||
Kind: kube.SecretKind, JSONPointers: []string{"/data/username", "/data/password"},
|
||||
}}
|
||||
_, err = client.UpdateSpec(context.Background(), &applicationpkg.ApplicationUpdateSpecRequest{Name: &app.Name, Spec: app.Spec})
|
||||
|
||||
assert.NoError(t, err)
|
||||
FailOnErr(client.UpdateSpec(context.Background(), &applicationpkg.ApplicationUpdateSpecRequest{Name: &app.Name, Spec: app.Spec}))
|
||||
}).
|
||||
When().
|
||||
Refresh(RefreshTypeNormal).
|
||||
@@ -305,8 +301,7 @@ func TestAppWithSecrets(t *testing.T) {
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
And(func(app *Application) {
|
||||
diffOutput, err := fixture.RunCli("app", "diff", app.Name)
|
||||
assert.NoError(t, err)
|
||||
diffOutput := FailOnErr(RunCli("app", "diff", app.Name)).(string)
|
||||
assert.Empty(t, diffOutput)
|
||||
})
|
||||
}
|
||||
@@ -321,7 +316,7 @@ func TestResourceDiffing(t *testing.T) {
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
And(func(app *Application) {
|
||||
// Patch deployment
|
||||
_, err := fixture.KubeClientset.AppsV1().Deployments(fixture.DeploymentNamespace()).Patch(
|
||||
_, err := KubeClientset.AppsV1().Deployments(DeploymentNamespace()).Patch(
|
||||
"guestbook-ui", types.JSONPatchType, []byte(`[{ "op": "replace", "path": "/spec/template/spec/containers/0/image", "value": "test" }]`))
|
||||
assert.NoError(t, err)
|
||||
}).
|
||||
@@ -330,9 +325,9 @@ func TestResourceDiffing(t *testing.T) {
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
And(func(app *Application) {
|
||||
diffOutput, err := fixture.RunCli("app", "diff", app.Name, "--local", "testdata/guestbook")
|
||||
diffOutput, err := RunCli("app", "diff", app.Name, "--local", "testdata/guestbook")
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, diffOutput, fmt.Sprintf("===== apps/Deployment %s/guestbook-ui ======", fixture.DeploymentNamespace()))
|
||||
assert.Contains(t, diffOutput, fmt.Sprintf("===== apps/Deployment %s/guestbook-ui ======", DeploymentNamespace()))
|
||||
}).
|
||||
Given().
|
||||
ResourceOverrides(map[string]ResourceOverride{"apps/Deployment": {IgnoreDifferences: ` jsonPointers: ["/spec/template/spec/containers/0/image"]`}}).
|
||||
@@ -341,7 +336,7 @@ func TestResourceDiffing(t *testing.T) {
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
And(func(app *Application) {
|
||||
diffOutput, err := fixture.RunCli("app", "diff", app.Name, "--local", "testdata/guestbook")
|
||||
diffOutput, err := RunCli("app", "diff", app.Name, "--local", "testdata/guestbook")
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, diffOutput)
|
||||
})
|
||||
@@ -366,7 +361,7 @@ func TestConfigMap(t *testing.T) {
|
||||
func TestFailedConversion(t *testing.T) {
|
||||
|
||||
defer func() {
|
||||
errors.FailOnErr(fixture.Run("", "kubectl", "delete", "apiservice", "v1beta1.metrics.k8s.io"))
|
||||
FailOnErr(Run("", "kubectl", "delete", "apiservice", "v1beta1.metrics.k8s.io"))
|
||||
}()
|
||||
|
||||
testEdgeCasesApplicationResources(t, "failed-conversion", HealthStatusProgressing)
|
||||
@@ -383,7 +378,7 @@ func testEdgeCasesApplicationResources(t *testing.T, appPath string, statusCode
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
Expect(HealthIs(statusCode)).
|
||||
And(func(app *Application) {
|
||||
diffOutput, err := fixture.RunCli("app", "diff", app.Name, "--local", path.Join("testdata", appPath))
|
||||
diffOutput, err := RunCli("app", "diff", app.Name, "--local", path.Join("testdata", appPath))
|
||||
assert.Empty(t, diffOutput)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
@@ -401,7 +396,7 @@ func TestKsonnetApp(t *testing.T) {
|
||||
Sync().
|
||||
Then().
|
||||
And(func(app *Application) {
|
||||
closer, client, err := fixture.ArgoCDClientset.NewRepoClient()
|
||||
closer, client, err := ArgoCDClientset.NewRepoClient()
|
||||
assert.NoError(t, err)
|
||||
defer util.Close(closer)
|
||||
|
||||
@@ -440,7 +435,7 @@ func TestResourceAction(t *testing.T) {
|
||||
Then().
|
||||
And(func(app *Application) {
|
||||
|
||||
closer, client, err := fixture.ArgoCDClientset.NewApplicationClient()
|
||||
closer, client, err := ArgoCDClientset.NewApplicationClient()
|
||||
assert.NoError(t, err)
|
||||
defer util.Close(closer)
|
||||
|
||||
@@ -449,7 +444,7 @@ func TestResourceAction(t *testing.T) {
|
||||
Group: "apps",
|
||||
Kind: "Deployment",
|
||||
Version: "v1",
|
||||
Namespace: fixture.DeploymentNamespace(),
|
||||
Namespace: DeploymentNamespace(),
|
||||
ResourceName: "guestbook-ui",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
@@ -459,13 +454,13 @@ func TestResourceAction(t *testing.T) {
|
||||
Group: "apps",
|
||||
Kind: "Deployment",
|
||||
Version: "v1",
|
||||
Namespace: fixture.DeploymentNamespace(),
|
||||
Namespace: DeploymentNamespace(),
|
||||
ResourceName: "guestbook-ui",
|
||||
Action: "sample",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
deployment, err := fixture.KubeClientset.AppsV1().Deployments(fixture.DeploymentNamespace()).Get("guestbook-ui", metav1.GetOptions{})
|
||||
deployment, err := KubeClientset.AppsV1().Deployments(DeploymentNamespace()).Get("guestbook-ui", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "test", deployment.Labels["sample"])
|
||||
@@ -480,11 +475,11 @@ func TestSyncResourceByLabel(t *testing.T) {
|
||||
Sync().
|
||||
Then().
|
||||
And(func(app *Application) {
|
||||
_, _ = fixture.RunCli("app", "sync", app.Name, "--label", fmt.Sprintf("app.kubernetes.io/instance=%s", app.Name))
|
||||
_, _ = RunCli("app", "sync", app.Name, "--label", fmt.Sprintf("app.kubernetes.io/instance=%s", app.Name))
|
||||
}).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
And(func(app *Application) {
|
||||
_, err := fixture.RunCli("app", "sync", app.Name, "--label", "this-label=does-not-exist")
|
||||
_, err := RunCli("app", "sync", app.Name, "--label", "this-label=does-not-exist")
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "level=fatal")
|
||||
})
|
||||
@@ -498,7 +493,7 @@ func TestLocalManifestSync(t *testing.T) {
|
||||
Sync().
|
||||
Then().
|
||||
And(func(app *Application) {
|
||||
res, _ := fixture.RunCli("app", "manifests", app.Name)
|
||||
res, _ := RunCli("app", "manifests", app.Name)
|
||||
assert.Contains(t, res, "containerPort: 80")
|
||||
assert.Contains(t, res, "image: gcr.io/heptio-images/ks-guestbook-demo:0.2")
|
||||
}).
|
||||
@@ -509,7 +504,7 @@ func TestLocalManifestSync(t *testing.T) {
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
And(func(app *Application) {
|
||||
res, _ := fixture.RunCli("app", "manifests", app.Name)
|
||||
res, _ := RunCli("app", "manifests", app.Name)
|
||||
assert.Contains(t, res, "containerPort: 81")
|
||||
assert.Contains(t, res, "image: gcr.io/heptio-images/ks-guestbook-demo:0.3")
|
||||
}).
|
||||
@@ -520,7 +515,7 @@ func TestLocalManifestSync(t *testing.T) {
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
And(func(app *Application) {
|
||||
res, _ := fixture.RunCli("app", "manifests", app.Name)
|
||||
res, _ := RunCli("app", "manifests", app.Name)
|
||||
assert.Contains(t, res, "containerPort: 80")
|
||||
assert.Contains(t, res, "image: gcr.io/heptio-images/ks-guestbook-demo:0.2")
|
||||
})
|
||||
@@ -534,10 +529,10 @@ func TestNoLocalSyncWithAutosyncEnabled(t *testing.T) {
|
||||
Sync().
|
||||
Then().
|
||||
And(func(app *Application) {
|
||||
_, err := fixture.RunCli("app", "set", app.Name, "--sync-policy", "automated")
|
||||
_, err := RunCli("app", "set", app.Name, "--sync-policy", "automated")
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = fixture.RunCli("app", "sync", app.Name, "--local", guestbookPathLocal)
|
||||
_, err = RunCli("app", "sync", app.Name, "--local", guestbookPathLocal)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
@@ -556,44 +551,44 @@ func TestSyncAsync(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPermissions(t *testing.T) {
|
||||
fixture.EnsureCleanState(t)
|
||||
appName := fixture.Name()
|
||||
_, err := fixture.RunCli("proj", "create", "test")
|
||||
EnsureCleanState(t)
|
||||
appName := Name()
|
||||
_, err := RunCli("proj", "create", "test")
|
||||
assert.NoError(t, err)
|
||||
|
||||
// make sure app cannot be created without permissions in project
|
||||
_, err = fixture.RunCli("app", "create", appName, "--repo", fixture.RepoURL(fixture.RepoURLTypeFile),
|
||||
"--path", guestbookPath, "--project", "test", "--dest-server", common.KubernetesInternalAPIServerAddr, "--dest-namespace", fixture.DeploymentNamespace())
|
||||
_, err = RunCli("app", "create", appName, "--repo", RepoURL(RepoURLTypeFile),
|
||||
"--path", guestbookPath, "--project", "test", "--dest-server", common.KubernetesInternalAPIServerAddr, "--dest-namespace", DeploymentNamespace())
|
||||
assert.Error(t, err)
|
||||
sourceError := fmt.Sprintf("application repo %s is not permitted in project 'test'", fixture.RepoURL(fixture.RepoURLTypeFile))
|
||||
destinationError := fmt.Sprintf("application destination {%s %s} is not permitted in project 'test'", common.KubernetesInternalAPIServerAddr, fixture.DeploymentNamespace())
|
||||
sourceError := fmt.Sprintf("application repo %s is not permitted in project 'test'", RepoURL(RepoURLTypeFile))
|
||||
destinationError := fmt.Sprintf("application destination {%s %s} is not permitted in project 'test'", common.KubernetesInternalAPIServerAddr, DeploymentNamespace())
|
||||
|
||||
assert.Contains(t, err.Error(), sourceError)
|
||||
assert.Contains(t, err.Error(), destinationError)
|
||||
|
||||
proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get("test", metav1.GetOptions{})
|
||||
proj, err := AppClientset.ArgoprojV1alpha1().AppProjects(ArgoCDNamespace).Get("test", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
proj.Spec.Destinations = []ApplicationDestination{{Server: "*", Namespace: "*"}}
|
||||
proj.Spec.SourceRepos = []string{"*"}
|
||||
proj, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Update(proj)
|
||||
proj, err = AppClientset.ArgoprojV1alpha1().AppProjects(ArgoCDNamespace).Update(proj)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// make sure controller report permissions issues in conditions
|
||||
_, err = fixture.RunCli("app", "create", appName, "--repo", fixture.RepoURL(fixture.RepoURLTypeFile),
|
||||
"--path", guestbookPath, "--project", "test", "--dest-server", common.KubernetesInternalAPIServerAddr, "--dest-namespace", fixture.DeploymentNamespace())
|
||||
_, err = RunCli("app", "create", appName, "--repo", RepoURL(RepoURLTypeFile),
|
||||
"--path", guestbookPath, "--project", "test", "--dest-server", common.KubernetesInternalAPIServerAddr, "--dest-namespace", DeploymentNamespace())
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
err = fixture.AppClientset.ArgoprojV1alpha1().Applications(fixture.ArgoCDNamespace).Delete(appName, &metav1.DeleteOptions{})
|
||||
err = AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Delete(appName, &metav1.DeleteOptions{})
|
||||
assert.NoError(t, err)
|
||||
}()
|
||||
|
||||
proj.Spec.Destinations = []ApplicationDestination{}
|
||||
proj.Spec.SourceRepos = []string{}
|
||||
_, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Update(proj)
|
||||
_, err = AppClientset.ArgoprojV1alpha1().AppProjects(ArgoCDNamespace).Update(proj)
|
||||
assert.NoError(t, err)
|
||||
time.Sleep(1 * time.Second)
|
||||
closer, client, err := fixture.ArgoCDClientset.NewApplicationClient()
|
||||
closer, client, err := ArgoCDClientset.NewApplicationClient()
|
||||
assert.NoError(t, err)
|
||||
defer util.Close(closer)
|
||||
|
||||
@@ -697,7 +692,7 @@ func TestSelfManagedApps(t *testing.T) {
|
||||
Given(t).
|
||||
Path("self-managed-app").
|
||||
When().
|
||||
PatchFile("resources.yaml", fmt.Sprintf(`[{"op": "replace", "path": "/spec/source/repoURL", "value": "%s"}]`, fixture.RepoURL(fixture.RepoURLTypeFile))).
|
||||
PatchFile("resources.yaml", fmt.Sprintf(`[{"op": "replace", "path": "/spec/source/repoURL", "value": "%s"}]`, RepoURL(RepoURLTypeFile))).
|
||||
Create().
|
||||
Sync().
|
||||
Then().
|
||||
@@ -709,7 +704,7 @@ func TestSelfManagedApps(t *testing.T) {
|
||||
|
||||
reconciledCount := 0
|
||||
var lastReconciledAt *metav1.Time
|
||||
for event := range fixture.ArgoCDClientset.WatchApplicationWithRetry(ctx, a.Name) {
|
||||
for event := range ArgoCDClientset.WatchApplicationWithRetry(ctx, a.Name) {
|
||||
reconciledAt := event.Application.Status.ReconciledAt
|
||||
if reconciledAt == nil {
|
||||
reconciledAt = &metav1.Time{}
|
||||
|
||||
@@ -19,11 +19,12 @@ func TestCliAppCommand(t *testing.T) {
|
||||
output, err := RunCli("app", "sync", Name(), "--timeout", "90")
|
||||
assert.NoError(t, err)
|
||||
vars := map[string]interface{}{"Name": Name(), "Namespace": DeploymentNamespace()}
|
||||
assert.Contains(t, NormalizeOutput(output), Tmpl(`Pod {{.Namespace}} pod Synced Healthy pod/pod created`, vars))
|
||||
assert.Contains(t, NormalizeOutput(output), Tmpl(`Pod {{.Namespace}} pod Synced Progressing pod/pod created`, vars))
|
||||
assert.Contains(t, NormalizeOutput(output), Tmpl(`Pod {{.Namespace}} hook Succeeded Sync pod/hook created`, vars))
|
||||
}).
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(HealthIs(HealthStatusHealthy)).
|
||||
And(func(_ *Application) {
|
||||
output, err := RunCli("app", "list")
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -35,7 +35,7 @@ type Context struct {
|
||||
|
||||
func Given(t *testing.T) *Context {
|
||||
fixture.EnsureCleanState(t)
|
||||
return &Context{t: t, destServer: KubernetesInternalAPIServerAddr, repoURLType: fixture.RepoURLTypeFile, name: fixture.Name(), timeout: 5, project: "default", prune: true}
|
||||
return &Context{t: t, destServer: KubernetesInternalAPIServerAddr, repoURLType: fixture.RepoURLTypeFile, name: fixture.Name(), timeout: 10, project: "default", prune: true}
|
||||
}
|
||||
|
||||
func (c *Context) CustomCACertAdded() *Context {
|
||||
@@ -43,6 +43,11 @@ func (c *Context) CustomCACertAdded() *Context {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Context) CustomSSHKnownHostsAdded() *Context {
|
||||
certs.AddCustomSSHKnownHostsKeys()
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Context) HTTPSRepoURLAdded() *Context {
|
||||
repos.AddHTTPSRepo(false)
|
||||
return c
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
"github.com/argoproj/argo-cd/test/e2e/fixture"
|
||||
)
|
||||
|
||||
// Add a custom CA certificate to the test and also create the certificate file
|
||||
// on the file system, so argocd-server and argocd-repo-server can use it.
|
||||
func AddCustomCACert() {
|
||||
caCertPath, err := filepath.Abs("../fixture/certs/argocd-test-ca.crt")
|
||||
errors.CheckError(err)
|
||||
@@ -14,4 +17,23 @@ func AddCustomCACert() {
|
||||
errors.FailOnErr(fixture.RunCli(args...))
|
||||
args = []string{"cert", "add-tls", "127.0.0.1", "--from", caCertPath}
|
||||
errors.FailOnErr(fixture.RunCli(args...))
|
||||
|
||||
certData, err := ioutil.ReadFile(caCertPath)
|
||||
errors.CheckError(err)
|
||||
err = ioutil.WriteFile(fixture.TmpDir+"/app/config/tls/localhost", certData, 0644)
|
||||
errors.CheckError(err)
|
||||
err = ioutil.WriteFile(fixture.TmpDir+"/app/config/tls/127.0.0.1", certData, 0644)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
|
||||
func AddCustomSSHKnownHostsKeys() {
|
||||
knownHostsPath, err := filepath.Abs("../fixture/certs/ssh_known_hosts")
|
||||
errors.CheckError(err)
|
||||
args := []string{"cert", "add-ssh", "--batch", "--from", knownHostsPath}
|
||||
errors.FailOnErr(fixture.RunCli(args...))
|
||||
|
||||
knownHostsData, err := ioutil.ReadFile(knownHostsPath)
|
||||
errors.CheckError(err)
|
||||
err = ioutil.WriteFile(fixture.TmpDir+"/app/config/ssh/ssh_known_hosts", knownHostsData, 0644)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ const (
|
||||
ArgoCDNamespace = "argocd-e2e"
|
||||
|
||||
// ensure all repos are in one directory tree, so we can easily clean them up
|
||||
tmpDir = "/tmp/argo-e2e"
|
||||
TmpDir = "/tmp/argo-e2e"
|
||||
repoDir = "testdata.git"
|
||||
|
||||
GuestbookPath = "guestbook"
|
||||
@@ -127,7 +127,7 @@ func Name() string {
|
||||
}
|
||||
|
||||
func repoDirectory() string {
|
||||
return path.Join(tmpDir, repoDir)
|
||||
return path.Join(TmpDir, repoDir)
|
||||
}
|
||||
|
||||
func RepoURL(urlType RepoURLType) string {
|
||||
@@ -336,7 +336,7 @@ func EnsureCleanState(t *testing.T) {
|
||||
SetTLSCerts()
|
||||
|
||||
// remove tmp dir
|
||||
CheckError(os.RemoveAll(tmpDir))
|
||||
CheckError(os.RemoveAll(TmpDir))
|
||||
|
||||
// name based on test name
|
||||
name = dnsFriendly(t.Name())
|
||||
@@ -344,11 +344,11 @@ func EnsureCleanState(t *testing.T) {
|
||||
id = name + "-" + strings.ToLower(rand.RandString(5))
|
||||
|
||||
// create tmp dir
|
||||
FailOnErr(Run("", "mkdir", "-p", tmpDir))
|
||||
FailOnErr(Run("", "mkdir", "-p", TmpDir))
|
||||
|
||||
// create TLS and SSH certificate directories
|
||||
FailOnErr(Run("", "mkdir", "-p", tmpDir+"/app/config/tls"))
|
||||
FailOnErr(Run("", "mkdir", "-p", tmpDir+"/app/config/ssh"))
|
||||
FailOnErr(Run("", "mkdir", "-p", TmpDir+"/app/config/tls"))
|
||||
FailOnErr(Run("", "mkdir", "-p", TmpDir+"/app/config/ssh"))
|
||||
|
||||
// set-up tmp repo, must have unique name
|
||||
FailOnErr(Run("", "cp", "-Rf", "testdata", repoDirectory()))
|
||||
|
||||
@@ -29,6 +29,7 @@ func TestPostSyncHookSuccessful(t *testing.T) {
|
||||
// make sure we can run a standard sync hook
|
||||
func testHookSuccessful(t *testing.T, hookType HookType, podHookPhase OperationPhase) {
|
||||
Given(t).
|
||||
Timeout(10).
|
||||
Path("hook").
|
||||
When().
|
||||
PatchFile("hook.yaml", fmt.Sprintf(`[{"op": "replace", "path": "/metadata/annotations", "value": {"argocd.argoproj.io/hook": "%s"}}]`, hookType)).
|
||||
@@ -45,6 +46,21 @@ func testHookSuccessful(t *testing.T, hookType HookType, podHookPhase OperationP
|
||||
Expect(ResourceResultIs(ResourceResult{Version: "v1", Kind: "Pod", Namespace: DeploymentNamespace(), Name: "hook", Message: "pod/hook created", HookType: hookType, HookPhase: OperationSucceeded, SyncPhase: SyncPhase(hookType)}))
|
||||
}
|
||||
|
||||
// make sure that that hooks do not appear in "argocd app diff"
|
||||
func TestHookDiff(t *testing.T) {
|
||||
Given(t).
|
||||
Path("hook").
|
||||
When().
|
||||
Create().
|
||||
Then().
|
||||
And(func(_ *Application) {
|
||||
output, err := RunCli("app", "diff", Name())
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, output, "name: pod")
|
||||
assert.NotContains(t, output, "name: hook")
|
||||
})
|
||||
}
|
||||
|
||||
// make sure that if pre-sync fails, we fail the app and we do not create the pod
|
||||
func TestPreSyncHookFailure(t *testing.T) {
|
||||
Given(t).
|
||||
@@ -67,7 +83,7 @@ func TestPreSyncHookFailure(t *testing.T) {
|
||||
Expect(ResourceSyncStatusIs("Pod", "pod", SyncStatusCodeOutOfSync))
|
||||
}
|
||||
|
||||
// make sure that if pre-sync fails, we fail the app and we did create the pod
|
||||
// make sure that if sync fails, we fail the app and we did create the pod
|
||||
func TestSyncHookFailure(t *testing.T) {
|
||||
Given(t).
|
||||
Path("hook").
|
||||
@@ -85,6 +101,19 @@ func TestSyncHookFailure(t *testing.T) {
|
||||
Expect(ResourceSyncStatusIs("Pod", "pod", SyncStatusCodeSynced))
|
||||
}
|
||||
|
||||
// make sure that if the deployments fails, we still get success and synced
|
||||
func TestSyncHookResourceFailure(t *testing.T) {
|
||||
Given(t).
|
||||
Path("hook-and-deployment").
|
||||
When().
|
||||
Create().
|
||||
Sync().
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
Expect(HealthIs(HealthStatusProgressing))
|
||||
}
|
||||
|
||||
// make sure that if post-sync fails, we fail the app and we did not create the pod
|
||||
func TestPostSyncHookFailure(t *testing.T) {
|
||||
Given(t).
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
|
||||
)
|
||||
|
||||
func TestCanAccessSSHRepo(t *testing.T) {
|
||||
func TestCanAccessInsecureSSHRepo(t *testing.T) {
|
||||
Given(t).
|
||||
SSHInsecureRepoURLAdded().
|
||||
RepoURLType(fixture.RepoURLTypeSSH).
|
||||
@@ -20,3 +20,16 @@ func TestCanAccessSSHRepo(t *testing.T) {
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded))
|
||||
}
|
||||
|
||||
func TestCanAccessSSHRepo(t *testing.T) {
|
||||
Given(t).
|
||||
CustomSSHKnownHostsAdded().
|
||||
SSHRepoURLAdded().
|
||||
RepoURLType(fixture.RepoURLTypeSSH).
|
||||
Path("config-map").
|
||||
When().
|
||||
Create().
|
||||
Sync().
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded))
|
||||
}
|
||||
|
||||
28
test/e2e/testdata/hook-and-deployment/deployment.yaml
vendored
Normal file
28
test/e2e/testdata/hook-and-deployment/deployment.yaml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-app
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
containers:
|
||||
- name: main
|
||||
image: nginx:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
failureThreshold: 3
|
||||
httpGet:
|
||||
path: /does-not-exist
|
||||
port: 8080
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
successThreshold: 3
|
||||
timeoutSeconds: 1
|
||||
16
test/e2e/testdata/hook-and-deployment/hook.yaml
vendored
Normal file
16
test/e2e/testdata/hook-and-deployment/hook.yaml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: my-hook
|
||||
annotations:
|
||||
argocd.argoproj.io/hook: Sync
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- "true"
|
||||
image: "alpine:latest"
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: main
|
||||
restartPolicy: Never
|
||||
3
test/fixture/certs/ssh_known_hosts
Normal file
3
test/fixture/certs/ssh_known_hosts
Normal file
@@ -0,0 +1,3 @@
|
||||
[localhost]:2222 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLle3IiLWy+Cwz6/JT3K8PSGAEZAJnaxiWk0u9wkAvbZ9wHTffctg25coBa8J4Oo1l5GTIkezib2C4PjCE01BZM=
|
||||
[localhost]:2222 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDhRWyu6rg0Kd0ugLxNGZ8gzUjasF4Z0oT16RUC/L9EkJWATAu4TkkoozZ5AcejlS29jUZXTkKt0La4dmIooeMDNd8b5vg1dWzSDDHwxd8Wa/4XZsUlL6zkUFrnqOPaFc/7EwM3I30064zT/Gt0BVvQUxKoT/TTea2KhQqeLmlWh4cVWJBuhZ8YODUf2VD4TSYfvpcqW/jVw2oG8Pj3WIaaG2+Bcp4Q4sJS2K+2kkiqmZ/hiPK1X/UbMRN2zWQBp5UPWFY2ctuC9B8yhLwAyMkHzuWLfB39dNEdn1jTjDsOUWbC3kDsWHsY5gtBxN30NizBWC+83NpaWbrzAlGb0JV1
|
||||
[localhost]:2222 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2t7Tcavp5oUqbbSwEKRaGwEq94b8BFK16AEBbgRCTp
|
||||
@@ -1,15 +1,30 @@
|
||||
import { Layout, NavigationManager, Notifications, NotificationsManager, PageContext, Popup, PopupManager, PopupProps } from 'argo-ui';
|
||||
import {
|
||||
DataLoader,
|
||||
Layout,
|
||||
NavigationManager,
|
||||
Notifications,
|
||||
NotificationsManager,
|
||||
PageContext,
|
||||
Popup,
|
||||
PopupManager,
|
||||
PopupProps,
|
||||
} from 'argo-ui';
|
||||
import * as cookie from 'cookie';
|
||||
import { createBrowserHistory } from 'history';
|
||||
import {createBrowserHistory} from 'history';
|
||||
import * as jwtDecode from 'jwt-decode';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import * as React from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Redirect, Route, RouteComponentProps, Router, Switch } from 'react-router';
|
||||
import {Helmet} from 'react-helmet';
|
||||
import {Redirect, Route, RouteComponentProps, Router, Switch} from 'react-router';
|
||||
|
||||
import { services } from './shared/services';
|
||||
import applications from './applications';
|
||||
import help from './help';
|
||||
import login from './login';
|
||||
import settings from './settings';
|
||||
import {Provider} from './shared/context';
|
||||
import {services} from './shared/services';
|
||||
import requests from './shared/services/requests';
|
||||
import { hashCode } from './shared/utils';
|
||||
import {hashCode} from './shared/utils';
|
||||
|
||||
services.viewPreferences.init();
|
||||
const bases = document.getElementsByTagName('base');
|
||||
@@ -17,12 +32,6 @@ const base = bases.length > 0 ? bases[0].getAttribute('href') || '/' : '/';
|
||||
export const history = createBrowserHistory({ basename: base });
|
||||
requests.setApiRoot(`${base}api/v1`);
|
||||
|
||||
import applications from './applications';
|
||||
import help from './help';
|
||||
import login from './login';
|
||||
import settings from './settings';
|
||||
import { Provider } from './shared/context';
|
||||
|
||||
const routes: {[path: string]: { component: React.ComponentType<RouteComponentProps<any>>, noLayout?: boolean } } = {
|
||||
'/login': { component: login.component as any, noLayout: true },
|
||||
'/applications': { component: applications.component },
|
||||
@@ -165,6 +174,13 @@ export class App extends React.Component<{}, { popupProps: PopupProps, error: Er
|
||||
<Redirect path='*' to='/'/>
|
||||
</Switch>
|
||||
</Router>
|
||||
<DataLoader load={() => services.authService.settings()}>{(s) => (
|
||||
s.help && s.help.chatUrl && <div style={{position: 'fixed', right: 10, bottom: 10}}>
|
||||
<a href={s.help.chatUrl} className='argo-button argo-button--special'>
|
||||
<i className='fas fa-comment-alt'/> {s.help.chatText}
|
||||
</a>
|
||||
</div> || null
|
||||
)}</DataLoader>
|
||||
</Provider>
|
||||
</PageContext.Provider>
|
||||
<Notifications notifications={this.notificationsManager.notifications}/>
|
||||
|
||||
@@ -33,10 +33,13 @@ export const ApplicationResourcesDiff = (props: ApplicationResourcesDiffProps) =
|
||||
return {
|
||||
a: live ? jsYaml.safeDump(live, {indent: 2}) : '',
|
||||
b: target ? jsYaml.safeDump(target, {indent: 2}) : '',
|
||||
hook: state.hook,
|
||||
// doubles as sort order
|
||||
name: (state.group || '') + '/' + state.kind + '/' + state.namespace + '/' + state.name,
|
||||
};
|
||||
}).filter((i) => i.a !== i.b)
|
||||
})
|
||||
.filter((i) => !i.hook)
|
||||
.filter((i) => i.a !== i.b)
|
||||
.map((i) => {
|
||||
const context = pref.appDetails.compactDiff ? 2 : Number.MAX_SAFE_INTEGER;
|
||||
// react-diff-view, awesome as it is, does not accept unidiff format, you must add a git header section
|
||||
|
||||
@@ -16,7 +16,7 @@ export const ApplicationSyncPanel = ({application, selectedResource, hide}: {
|
||||
const [form, setForm] = React.useState<FormApi>(null);
|
||||
const isVisible = !!(selectedResource && application);
|
||||
const appResources = (application && selectedResource && application.status && application.status.resources || []).sort(
|
||||
(first, second) => nodeKey(first).localeCompare(nodeKey(second)));
|
||||
(first, second) => nodeKey(first).localeCompare(nodeKey(second))).filter((item) => !item.hook);
|
||||
const syncResIndex = appResources.findIndex((item) => nodeKey(item) === selectedResource);
|
||||
const syncStrategy = {} as models.SyncStrategy;
|
||||
|
||||
@@ -36,7 +36,7 @@ export const ApplicationSyncPanel = ({application, selectedResource, hide}: {
|
||||
<Form
|
||||
defaultValues={{
|
||||
revision: application.spec.source.targetRevision || 'HEAD',
|
||||
resources: appResources.filter((item) => !item.hook).map((_, i) => i === syncResIndex || syncResIndex === -1),
|
||||
resources: appResources.map((_, i) => i === syncResIndex || syncResIndex === -1),
|
||||
}}
|
||||
validateError={(values) => ({
|
||||
resources: values.resources.every((item: boolean) => !item) && 'Select at least one resource',
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DropDownMenu, Tooltip } from 'argo-ui';
|
||||
import * as React from 'react';
|
||||
const GitUrlParse = require('git-url-parse');
|
||||
|
||||
import { Cluster } from '../../../shared/components';
|
||||
import { Consumer } from '../../../shared/context';
|
||||
@@ -10,7 +11,7 @@ import * as AppUtils from '../utils';
|
||||
require('./applications-table.scss');
|
||||
|
||||
function shortRepo(repo: string) {
|
||||
const url = new URL(repo);
|
||||
const url = GitUrlParse(repo);
|
||||
return <Tooltip content={repo}><span>{url.pathname.slice(1)}</span></Tooltip>;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,12 @@ import {repoUrl, revisionUrl} from './urls';
|
||||
|
||||
function testExample(http: string, ssl: string, revision: string, expectedRepoUrl: string, expectedRevisionUrl: string) {
|
||||
expect(repoUrl(http)).toBe(expectedRepoUrl);
|
||||
expect(repoUrl(ssl)).toBe(expectedRepoUrl);
|
||||
expect(revisionUrl(http, revision)).toBe(expectedRevisionUrl);
|
||||
expect(revisionUrl(ssl, revision)).toBe(expectedRevisionUrl);
|
||||
expect(repoUrl(http)).toBe(expectedRepoUrl);
|
||||
expect(revisionUrl(http, revision)).toBe(expectedRevisionUrl);
|
||||
expect(revisionUrl(ssl, revision)).toBe(expectedRevisionUrl);
|
||||
}
|
||||
|
||||
test('github.com', () => {
|
||||
@@ -16,6 +19,15 @@ test('github.com', () => {
|
||||
'https://github.com/argoproj/argo-cd/commit/024dee09f543ce7bb5af7ca50260504d89dfda94');
|
||||
});
|
||||
|
||||
// for enterprise github installations
|
||||
test('github.my-enterprise.com', () => {
|
||||
testExample(
|
||||
'https://github.my-enterprise.com/my-org/my-repo.git',
|
||||
'git@github.my-enterprise.com:my-org/my-repo.git',
|
||||
'a06f2be80a4da89abb8ced904beab75b3ec6db0e',
|
||||
'https://github.my-enterprise.com/my-org/my-repo',
|
||||
'https://github.my-enterprise.com/my-org/my-repo/commit/a06f2be80a4da89abb8ced904beab75b3ec6db0e');
|
||||
});
|
||||
|
||||
test('gitlab.com', () => {
|
||||
testExample(
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import {GitUrl} from 'git-url-parse';
|
||||
|
||||
const GitUrlParse = require('git-url-parse');
|
||||
|
||||
function supportedSource(source: string): boolean {
|
||||
return ['github.com', 'gitlab.com', 'bitbucket.org'].indexOf(source) >= 0;
|
||||
function supportedSource(parsed: GitUrl): boolean {
|
||||
return parsed.resource.startsWith('github') || ['gitlab.com', 'bitbucket.org'].indexOf(parsed.source) >= 0;
|
||||
}
|
||||
|
||||
function protocol(proto: string): string {
|
||||
@@ -11,7 +13,7 @@ function protocol(proto: string): string {
|
||||
export function repoUrl(url: string): string {
|
||||
const parsed = GitUrlParse(url);
|
||||
|
||||
if (!supportedSource(parsed.source)) {
|
||||
if (!supportedSource(parsed)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -22,7 +24,7 @@ export function revisionUrl(url: string, revision: string): string {
|
||||
|
||||
const parsed = GitUrlParse(url);
|
||||
|
||||
if (!supportedSource(parsed.source)) {
|
||||
if (!supportedSource(parsed)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ export interface OperationState {
|
||||
finishedAt: models.Time;
|
||||
}
|
||||
|
||||
export type HookType = 'PreSync' | 'Sync' | 'PostSync' | 'Skip';
|
||||
export type HookType = 'PreSync' | 'Sync' | 'PostSync' | 'SyncFail' | 'Skip';
|
||||
|
||||
export interface RevisionMetadata {
|
||||
author: string;
|
||||
@@ -278,6 +278,7 @@ export interface ResourceDiff {
|
||||
targetState: State;
|
||||
liveState: State;
|
||||
diff: string;
|
||||
hook: boolean;
|
||||
}
|
||||
|
||||
export interface SyncStatus {
|
||||
@@ -328,6 +329,10 @@ export interface AuthSettings {
|
||||
oidcConfig: {
|
||||
name: string;
|
||||
};
|
||||
help: {
|
||||
chatUrl: string;
|
||||
chatText: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type ConnectionStatus = 'Unknown' | 'Successful' | 'Failed';
|
||||
|
||||
12
uid_entrypoint.sh
Executable file
12
uid_entrypoint.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Make sure that if we are using an arbitrary UID that it appears in /etc/passwd,
|
||||
# otherwise this will cause issues with things like cloning with git+ssh
|
||||
# reference: https://access.redhat.com/documentation/en-us/openshift_container_platform/3.11/html/creating_images/creating-images-guidelines#use-uid
|
||||
if ! whoami &> /dev/null; then
|
||||
if [ -w /etc/passwd ]; then
|
||||
echo "${USER_NAME:-default}:x:$(id -u):0:${USER_NAME:-default} user:/home/argocd:/sbin/nologin" >> /etc/passwd
|
||||
fi
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
@@ -65,10 +65,10 @@ const (
|
||||
)
|
||||
|
||||
// Regular expression that matches a valid hostname
|
||||
var validHostNameRegexp = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]))*$`)
|
||||
var validHostNameRegexp = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]))*(\.){0,1}$`)
|
||||
|
||||
// Regular expression that matches a valid FQDN
|
||||
var validFQDNRegexp = regexp.MustCompile(`^([a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$`)
|
||||
var validFQDNRegexp = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]))*(\.){1}$`)
|
||||
|
||||
// Can be used to test whether a given string represents a valid hostname
|
||||
// If fqdn is true, given string must also be a FQDN representation.
|
||||
|
||||
@@ -357,31 +357,58 @@ func Test_SSHFingerPrintSHA256FromString(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_ServerNameWithoutPort(t *testing.T) {
|
||||
hostNameList := []string{"localhost", "localhost:9443", "localhost:", "localhost:abc"}
|
||||
for _, hostName := range hostNameList {
|
||||
assert.Equal(t, "localhost", ServerNameWithoutPort(hostName))
|
||||
hostNames := map[string]string{
|
||||
"localhost": "localhost",
|
||||
"localhost:9443": "localhost",
|
||||
"localhost:": "localhost",
|
||||
"localhost:abc": "localhost",
|
||||
"localhost.:22": "localhost.",
|
||||
"foo.example.com:443": "foo.example.com",
|
||||
"foo.example.com.:443": "foo.example.com.",
|
||||
}
|
||||
for inp, res := range hostNames {
|
||||
assert.Equal(t, res, ServerNameWithoutPort(inp))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ValidHostnames(t *testing.T) {
|
||||
hostNameList := []string{"localhost", "localhost.localdomain", "foo.example.com", "argocd-server.svc.kubernetes.local"}
|
||||
for idx, hostName := range hostNameList {
|
||||
assert.Equal(t, true, IsValidHostname(hostName, false))
|
||||
if idx != 0 {
|
||||
assert.Equal(t, true, IsValidHostname(hostName, true))
|
||||
} else {
|
||||
assert.Equal(t, false, IsValidHostname(hostName, true))
|
||||
}
|
||||
hostNames := map[string]bool{
|
||||
"localhost": true,
|
||||
"localhost.localdomain": true,
|
||||
"foo.example.com": true,
|
||||
"argocd-server.svc.kubernetes.local": true,
|
||||
"localhost.": true,
|
||||
"github.com.": true,
|
||||
"localhost..": false,
|
||||
"localhost..localdomain": false,
|
||||
".localhost": false,
|
||||
"local_host": false,
|
||||
"localhost.local_domain": false,
|
||||
}
|
||||
|
||||
for hostName, valid := range hostNames {
|
||||
assert.Equal(t, valid, IsValidHostname(hostName, false))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_InvalidHostnames(t *testing.T) {
|
||||
hostNameList := []string{"localhost.a", "localhost.", "localhost..localdomain", ".foo.example.com", "argocd_server.svc.kubernetes.local"}
|
||||
for idx, hostName := range hostNameList {
|
||||
if idx == 0 {
|
||||
assert.Equal(t, false, IsValidHostname(hostName, true))
|
||||
} else {
|
||||
assert.Equal(t, false, IsValidHostname(hostName, false))
|
||||
}
|
||||
func Test_ValidFQDNs(t *testing.T) {
|
||||
hostNames := map[string]bool{
|
||||
"localhost": false,
|
||||
"localhost.localdomain": false,
|
||||
"foo.example.com.": true,
|
||||
"argocd-server.svc.kubernetes.local": false,
|
||||
"localhost.": true,
|
||||
"github.com.": true,
|
||||
"localhost..": false,
|
||||
"localhost..localdomain": false,
|
||||
"localhost..localdomain.": false,
|
||||
".localhost": false,
|
||||
"local_host": false,
|
||||
"localhost.local_domain": false,
|
||||
"localhost.local_domain.": false,
|
||||
}
|
||||
|
||||
for hostName, valid := range hostNames {
|
||||
assert.Equal(t, valid, IsValidHostname(hostName, true))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@ package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
certutil "github.com/argoproj/argo-cd/util/cert"
|
||||
@@ -169,9 +172,24 @@ func (db *db) CreateRepoCertificate(ctx context.Context, certificates *appsv1.Re
|
||||
// Each request can contain multiple certificates of different types, so we
|
||||
// make sure to handle each request accordingly.
|
||||
for _, certificate := range certificates.Items {
|
||||
// Ensure valid repo server name was given
|
||||
if !certutil.IsValidHostname(certificate.ServerName, false) {
|
||||
// Ensure valid repo server name was given only for https certificates.
|
||||
// For SSH known host entries, we let Go's ssh library do the validation
|
||||
// later on.
|
||||
if certificate.CertType == "https" && !certutil.IsValidHostname(certificate.ServerName, false) {
|
||||
return nil, fmt.Errorf("Invalid hostname in request: %s", certificate.ServerName)
|
||||
} else if certificate.CertType == "ssh" {
|
||||
// Matches "[hostname]:port" format
|
||||
reExtract := regexp.MustCompile(`^\[(.*)\]\:[0-9]+$`)
|
||||
matches := reExtract.FindStringSubmatch(certificate.ServerName)
|
||||
var hostnameToCheck string
|
||||
if len(matches) == 0 {
|
||||
hostnameToCheck = certificate.ServerName
|
||||
} else {
|
||||
hostnameToCheck = matches[1]
|
||||
}
|
||||
if !certutil.IsValidHostname(hostnameToCheck, false) {
|
||||
return nil, fmt.Errorf("Invalid hostname in request: %s", hostnameToCheck)
|
||||
}
|
||||
}
|
||||
|
||||
if certificate.CertType == "ssh" {
|
||||
@@ -201,14 +219,18 @@ func (db *db) CreateRepoCertificate(ctx context.Context, certificates *appsv1.Re
|
||||
}
|
||||
|
||||
// Make sure that we received a valid public host key by parsing it
|
||||
_, _, rawKeyData, _, _, err := ssh.ParseKnownHosts([]byte(fmt.Sprintf("%s %s %s", certificate.ServerName, certificate.CertSubType, certificate.CertData)))
|
||||
_, hostnames, rawKeyData, _, _, err := ssh.ParseKnownHosts([]byte(fmt.Sprintf("%s %s %s", certificate.ServerName, certificate.CertSubType, certificate.CertData)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(hostnames) == 0 {
|
||||
log.Errorf("Could not parse hostname for key from token %s", certificate.ServerName)
|
||||
}
|
||||
|
||||
if newEntry {
|
||||
sshKnownHostsList = append(sshKnownHostsList, &SSHKnownHostsEntry{
|
||||
Host: certificate.ServerName,
|
||||
Host: hostnames[0],
|
||||
Data: string(certificate.CertData),
|
||||
SubType: certificate.CertSubType,
|
||||
})
|
||||
|
||||
@@ -292,9 +292,9 @@ func Test_ListCertificate(t *testing.T) {
|
||||
HostNamePattern: "*",
|
||||
CertType: "ssh",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, len(certList.Items), Test_NumSSHKnownHostsExpected)
|
||||
assert.Len(t, certList.Items, Test_NumSSHKnownHostsExpected)
|
||||
for idx, entry := range certList.Items {
|
||||
assert.Equal(t, entry.ServerName, Test_SSH_Hostname_Entries[idx])
|
||||
assert.Equal(t, entry.CertSubType, Test_SSH_Subtypes[idx])
|
||||
@@ -306,9 +306,9 @@ func Test_ListCertificate(t *testing.T) {
|
||||
HostNamePattern: "*",
|
||||
CertType: "https",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, len(certList.Items), Test_NumTLSCertificatesExpected)
|
||||
assert.Len(t, certList.Items, Test_NumTLSCertificatesExpected)
|
||||
|
||||
// List all certificates using selector
|
||||
// Expected: List of 10 entries
|
||||
@@ -316,16 +316,16 @@ func Test_ListCertificate(t *testing.T) {
|
||||
HostNamePattern: "*",
|
||||
CertType: "*",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, len(certList.Items), Test_NumTLSCertificatesExpected+Test_NumSSHKnownHostsExpected)
|
||||
assert.Len(t, certList.Items, Test_NumTLSCertificatesExpected+Test_NumSSHKnownHostsExpected)
|
||||
|
||||
// List all certificates using nil selector
|
||||
// Expected: List of 10 entries
|
||||
certList, err = db.ListRepoCertificates(context.Background(), nil)
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, len(certList.Items), Test_NumTLSCertificatesExpected+Test_NumSSHKnownHostsExpected)
|
||||
assert.Len(t, certList.Items, Test_NumTLSCertificatesExpected+Test_NumSSHKnownHostsExpected)
|
||||
|
||||
// List all certificates matching a host name pattern
|
||||
// Expected: List of 4 entries, all with servername gitlab.com
|
||||
@@ -333,9 +333,9 @@ func Test_ListCertificate(t *testing.T) {
|
||||
HostNamePattern: "gitlab.com",
|
||||
CertType: "*",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 4, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 4)
|
||||
for _, entry := range certList.Items {
|
||||
assert.Equal(t, "gitlab.com", entry.ServerName)
|
||||
}
|
||||
@@ -345,9 +345,9 @@ func Test_ListCertificate(t *testing.T) {
|
||||
HostNamePattern: "gitlab.com",
|
||||
CertType: "https",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 1, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 1)
|
||||
assert.Equal(t, "gitlab.com", certList.Items[0].ServerName)
|
||||
assert.Equal(t, "https", certList.Items[0].CertType)
|
||||
}
|
||||
@@ -367,9 +367,23 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 1, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 1)
|
||||
|
||||
// Valid known hosts entry
|
||||
certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{
|
||||
Items: []v1alpha1.RepositoryCertificate{
|
||||
{
|
||||
ServerName: "[foo.example.com]:2222",
|
||||
CertType: "ssh",
|
||||
CertData: []byte("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDioSMcGxdVkHaQzRjP71nY4mgVHXjuZiYN9NBiUxNZ0DYGjTIENI3uV45XxrS6PQfoyekUlVlHK2jwpcPrqAg6rlAdMD5WIxzvCnFjCuPA6Ljk8p0ZmYbvriDcgtj+UfGEdyUTgxH2gch6KwTY0eAbLue15IuXtoNzpLxk29iGRi5ZXNAbSBjeB3hm2PKLa6LnDqdkvc+nqoYqn1Fvx7ZJIh0apBCJpOtHPON4rnl7QQvNg9pWulZ5GKcpYMRfTpvHyFTEyrsVT5GH38l9s355GqU7GxQ/i6Tj1D0MKrIB2WmdjOnujM/ELLsrkYspMhn8ZRpCphN/LTcrOWsb0AM69drvYlhc6cnNAtC4UXp0GUy1HsBiJCsUm9/1Gz23VLDRvWop8yE8+PE3Ho5eL7ad9wmOG0mSOYEqVvAstmd8vzbD6oRuY8qV8X3tt9ph2tMAve0Qbo0NN3c51c9OfdXtJaSyckjEjaK7zjnArnYfladZZVlf2Tv8FsV0sJmfSAE="),
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Len(t, certList.Items, 1)
|
||||
|
||||
// Invalid hostname
|
||||
// Result: Error
|
||||
@@ -382,7 +396,7 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, certList)
|
||||
|
||||
// Check if it really was added
|
||||
@@ -391,9 +405,9 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
|
||||
HostNamePattern: "foo.example.com",
|
||||
CertType: "ssh",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 1, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 1)
|
||||
|
||||
// Existing cert, same data, no upsert
|
||||
// Result: no error, should return 0 added certificates
|
||||
@@ -406,9 +420,9 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 0, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 0)
|
||||
|
||||
// Existing cert, different data, no upsert
|
||||
// Result: Error
|
||||
@@ -421,7 +435,7 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, certList)
|
||||
|
||||
// Existing cert, different data, upsert
|
||||
@@ -434,9 +448,9 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, true)
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 1, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 1)
|
||||
|
||||
// Invalid known hosts entry, case 1: key sub type missing
|
||||
// Result: Error
|
||||
@@ -449,7 +463,7 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, certList)
|
||||
|
||||
// Invalid known hosts entry, case 2: invalid base64 data
|
||||
@@ -463,7 +477,7 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, certList)
|
||||
}
|
||||
|
||||
@@ -483,22 +497,22 @@ func Test_CreateTLSCertificates(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 1, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 1)
|
||||
|
||||
// Invalid hostname
|
||||
// Result: Error
|
||||
certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{
|
||||
Items: []v1alpha1.RepositoryCertificate{
|
||||
{
|
||||
ServerName: "foo.example.",
|
||||
ServerName: "foo..example",
|
||||
CertType: "https",
|
||||
CertData: []byte(Test_TLSValidSingleCert),
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, certList)
|
||||
|
||||
// Check if it really was added
|
||||
@@ -507,9 +521,9 @@ func Test_CreateTLSCertificates(t *testing.T) {
|
||||
HostNamePattern: "foo.example.com",
|
||||
CertType: "https",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 1, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 1)
|
||||
|
||||
// Valid TLS certificates, multiple PEMs in data
|
||||
// Expected: List of 2 entry
|
||||
@@ -522,9 +536,9 @@ func Test_CreateTLSCertificates(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 2, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 2)
|
||||
|
||||
// Check if it really was added
|
||||
// Result: Return new certificate
|
||||
@@ -532,9 +546,9 @@ func Test_CreateTLSCertificates(t *testing.T) {
|
||||
HostNamePattern: "bar.example.com",
|
||||
CertType: "https",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 2, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 2)
|
||||
|
||||
// Valid TLS certificate, existing cert, same data, no upsert
|
||||
// Expected: List of 0 entry
|
||||
@@ -547,9 +561,9 @@ func Test_CreateTLSCertificates(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 0, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 0)
|
||||
|
||||
// Valid TLS certificate, existing cert, different data, no upsert
|
||||
// Expected: Error
|
||||
@@ -562,7 +576,7 @@ func Test_CreateTLSCertificates(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, certList)
|
||||
|
||||
// Valid TLS certificate, existing cert, different data, upsert
|
||||
@@ -576,9 +590,9 @@ func Test_CreateTLSCertificates(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, true)
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 2, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 2)
|
||||
|
||||
// Check if upsert was successful
|
||||
// Expected: List of 2 entries, matching hostnames & cert types
|
||||
@@ -586,9 +600,9 @@ func Test_CreateTLSCertificates(t *testing.T) {
|
||||
HostNamePattern: "foo.example.com",
|
||||
CertType: "https",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 2, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 2)
|
||||
for _, entry := range certList.Items {
|
||||
assert.Equal(t, "foo.example.com", entry.ServerName)
|
||||
assert.Equal(t, "https", entry.CertType)
|
||||
@@ -605,7 +619,7 @@ func Test_CreateTLSCertificates(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, certList)
|
||||
|
||||
// Valid PEM data, new cert, but invalid certificate
|
||||
@@ -619,7 +633,7 @@ func Test_CreateTLSCertificates(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, false)
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, certList)
|
||||
|
||||
// Invalid PEM data, existing cert, upsert
|
||||
@@ -633,7 +647,7 @@ func Test_CreateTLSCertificates(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, true)
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, certList)
|
||||
|
||||
// Valid PEM data, existing cert, but invalid certificate, upsert
|
||||
@@ -647,7 +661,7 @@ func Test_CreateTLSCertificates(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, true)
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, certList)
|
||||
|
||||
}
|
||||
@@ -663,9 +677,9 @@ func Test_RemoveSSHKnownHosts(t *testing.T) {
|
||||
HostNamePattern: "github.com",
|
||||
CertType: "ssh",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 1, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 1)
|
||||
|
||||
// Check whether entry was really removed
|
||||
// Expected: List of 0 entries
|
||||
@@ -673,9 +687,9 @@ func Test_RemoveSSHKnownHosts(t *testing.T) {
|
||||
HostNamePattern: "github.com",
|
||||
CertType: "ssh",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 0, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 0)
|
||||
|
||||
// Remove single SSH known hosts entry by sub type
|
||||
// Expected: List of 1 entry
|
||||
@@ -683,9 +697,9 @@ func Test_RemoveSSHKnownHosts(t *testing.T) {
|
||||
CertType: "ssh",
|
||||
CertSubType: "ssh-ed25519",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 1, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 1)
|
||||
|
||||
// Check whether entry was really removed
|
||||
// Expected: List of 0 entries
|
||||
@@ -693,27 +707,27 @@ func Test_RemoveSSHKnownHosts(t *testing.T) {
|
||||
CertType: "ssh",
|
||||
CertSubType: "ssh-ed25519",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 0, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 0)
|
||||
|
||||
// Remove all remaining SSH known hosts entries
|
||||
// Expected: List of 5 entry
|
||||
certList, err = db.RemoveRepoCertificates(context.Background(), &CertificateListSelector{
|
||||
CertType: "ssh",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 5, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 5)
|
||||
|
||||
// Check whether the entries were really removed
|
||||
// Expected: List of 0 entries
|
||||
certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{
|
||||
CertType: "ssh",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 0, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 0)
|
||||
}
|
||||
|
||||
func Test_RemoveTLSCertificates(t *testing.T) {
|
||||
@@ -727,9 +741,9 @@ func Test_RemoveTLSCertificates(t *testing.T) {
|
||||
HostNamePattern: "gitlab.com",
|
||||
CertType: "https",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 1, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 1)
|
||||
|
||||
// Check whether entry was really removed
|
||||
// Expected: List of 0 entries
|
||||
@@ -737,9 +751,9 @@ func Test_RemoveTLSCertificates(t *testing.T) {
|
||||
HostNamePattern: "gitlab.com",
|
||||
CertType: "https",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 0, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 0)
|
||||
|
||||
// Remove all TLS certificate entry for hostname
|
||||
// Expected: List of 2 entry
|
||||
@@ -747,9 +761,9 @@ func Test_RemoveTLSCertificates(t *testing.T) {
|
||||
HostNamePattern: "test.example.com",
|
||||
CertType: "https",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 2, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 2)
|
||||
|
||||
// Check whether entries were really removed
|
||||
// Expected: List of 0 entries
|
||||
@@ -757,8 +771,8 @@ func Test_RemoveTLSCertificates(t *testing.T) {
|
||||
HostNamePattern: "test.example.com",
|
||||
CertType: "https",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, certList)
|
||||
assert.Equal(t, 0, len(certList.Items))
|
||||
assert.Len(t, certList.Items, 0)
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user