mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-20 09:38:49 +01:00
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94017f2c8d | ||
|
|
3c53ea6cff | ||
|
|
7b2946962d | ||
|
|
df3422798d | ||
|
|
f44855fa4d | ||
|
|
1f4a052da3 | ||
|
|
74f5eae750 | ||
|
|
36a9465d85 | ||
|
|
9e6c04700e | ||
|
|
8abe96ad9a | ||
|
|
10de6e7cfc | ||
|
|
e57071a150 | ||
|
|
41db5fc010 | ||
|
|
31f257e957 | ||
|
|
5fd93a7db5 | ||
|
|
c2547dca95 | ||
|
|
522ed90f38 | ||
|
|
7a0266f0fb | ||
|
|
30348417a9 | ||
|
|
910eddbbf3 | ||
|
|
f150ba18fb | ||
|
|
97d030b4b2 | ||
|
|
5df269b3fa | ||
|
|
775f9711e7 | ||
|
|
3f974825a6 | ||
|
|
1d55439f7f | ||
|
|
41daf71851 | ||
|
|
f4796398a8 | ||
|
|
0f0b6ce278 | ||
|
|
aee4dfaa1e | ||
|
|
74a92c6031 | ||
|
|
4237c6f00f | ||
|
|
0f3d74fa58 | ||
|
|
868516f0bd | ||
|
|
e50c43fb3f | ||
|
|
9b6a0dc3cd | ||
|
|
1f63e99b78 | ||
|
|
589ad5d2ac | ||
|
|
4464f99df7 | ||
|
|
65a2d9f1ff | ||
|
|
bcaabc51a1 | ||
|
|
9140fea0fb | ||
|
|
d83e0ddb56 | ||
|
|
25ca589bff |
8
.github/workflows/release.yaml
vendored
8
.github/workflows/release.yaml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
# Target version must match major.minor.patch and optional -rcX suffix
|
||||
# where X must be a number.
|
||||
TARGET_VERSION=${SOURCE_TAG#*release-v}
|
||||
if ! echo ${TARGET_VERSION} | egrep '^[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)*$'; then
|
||||
if ! echo "${TARGET_VERSION}" | egrep '^[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)*$'; then
|
||||
echo "::error::Target version '${TARGET_VERSION}' is malformed, refusing to continue." >&2
|
||||
exit 1
|
||||
fi
|
||||
@@ -101,16 +101,16 @@ jobs:
|
||||
# Whatever is in commit history for the tag, we only want that
|
||||
# annotation from our tag. We discard everything else.
|
||||
if test "$begin" = "false"; then
|
||||
if echo $line | grep -q "tag ${SOURCE_TAG#refs/tags/}"; then begin="true"; fi
|
||||
if echo "$line" | grep -q "tag ${SOURCE_TAG#refs/tags/}"; then begin="true"; fi
|
||||
continue
|
||||
fi
|
||||
if test "$prefix" = "true"; then
|
||||
if test -z "$line"; then prefix=false; fi
|
||||
else
|
||||
if echo $line | egrep -q '^commit [0-9a-f]+'; then
|
||||
if echo "$line" | egrep -q '^commit [0-9a-f]+'; then
|
||||
break
|
||||
fi
|
||||
echo $line >> ${RELEASE_NOTES}
|
||||
echo "$line" >> ${RELEASE_NOTES}
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
58
CHANGELOG.md
58
CHANGELOG.md
@@ -1,5 +1,63 @@
|
||||
# Changelog
|
||||
|
||||
## v1.8.0 (Unreleased)
|
||||
|
||||
### Mono-Repository Improvements
|
||||
|
||||
Enhanced performance during manifest generation from mono-repository - the repository that represents the
|
||||
desired state of the whole cluster and contains hundreds of applications. The improved argocd-repo-server
|
||||
now able to concurrently generate manifests from the same repository and for the same commit SHA. This
|
||||
might provide 10x performance improvement of manifests generation.
|
||||
|
||||
### Annotation Based Path Detection
|
||||
|
||||
The feature that allows specifying which source repository directories influence the application manifest generation
|
||||
using the `argocd.argoproj.io/manifest-generate-paths` annotation. The annotation improves the Git webhook handler
|
||||
behavior. The webhook avoids related applications reconciliation if no related files have been changed by the Git commit
|
||||
and even allows to skip manifests generation for new commit by re-using generation manifests for the previous commit.
|
||||
|
||||
### Horizontal Controller Scaling
|
||||
|
||||
This release allows scaling the `argocd-application-controller` horizontally. This allows you to manage as many Kubernetes clusters
|
||||
as needed using a single Argo CD instance.
|
||||
|
||||
## New Core Functionality Features
|
||||
|
||||
Besides performance improvements, Argo CD got a lot of usability enhancements and new features:
|
||||
|
||||
* Namespace and CRD creation [#4354](https://github.com/argoproj/argo-cd/issues/4354)
|
||||
* Unknown fields of built-in K8S types [#1787](https://github.com/argoproj/argo-cd/issues/1787)
|
||||
* Endpoints Diffing [#1816](https://github.com/argoproj/argo-cd/issues/1816)
|
||||
* Better compatibility with Helm Hooks [#1816](https://github.com/argoproj/argo-cd/issues/1816)
|
||||
* App-of-Apps Health Assessment [#3781](https://github.com/argoproj/argo-cd/issues/3781)
|
||||
|
||||
## Global Projects
|
||||
|
||||
This release makes it easy to manage an Argo CD that has hundreds of Projects. Instead of duplicating the same organization-wide rules in all projects
|
||||
you can put such rules into one project and make this project “global” for all other projects. Rules defined in the global project are inherited by all
|
||||
other projects and therefore don’t have to be duplicated. The sample below demonstrates how you can create a global project and specify which project should
|
||||
inherit global project rules using Kubernetes labels.
|
||||
|
||||
## User Interface Improvements
|
||||
|
||||
The Argo CD user interface is an important part of a project and we keep working hard on improving the user experience. Here is an incomplete list of implemented improvements:
|
||||
|
||||
* Improved Applications Filters [#4622](https://github.com/argoproj/argo-cd/issues/4622)
|
||||
* Git tags and branches autocompletion [#4713](https://github.com/argoproj/argo-cd/issues/4713)
|
||||
* Project Details Page [#4400](https://github.com/argoproj/argo-cd/issues/4400)
|
||||
* New version information panel [#4376](https://github.com/argoproj/argo-cd/issues/4376)
|
||||
* Progress Indicators [#4411](https://github.com/argoproj/argo-cd/issues/4411)
|
||||
* External links annotations [#4380](https://github.com/argoproj/argo-cd/issues/4380) and more!
|
||||
|
||||
## Config Management Tools Enhancements
|
||||
|
||||
* OCI Based Repositories [#4018](https://github.com/argoproj/argo-cd/issues/4018)
|
||||
* Configurable Helm Versions [#4111](https://github.com/argoproj/argo-cd/issues/4111)
|
||||
|
||||
## Bug fixes and under the hood changes
|
||||
|
||||
In addition to new features and enhancements, we’ve fixed more than 50 bugs and upgraded third-party components and libraries that Argo CD relies on.
|
||||
|
||||
## v1.7.9 (2020-11-17)
|
||||
|
||||
- fix: improve commit verification tolerance (#4825)
|
||||
|
||||
2
Procfile
2
Procfile
@@ -1,6 +1,6 @@
|
||||
controller: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} go run ./cmd/argocd-application-controller/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
|
||||
api-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} go run ./cmd/argocd-server/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --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 github.com/argoproj/argo-cd/cmd/argocd-util 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.25.0 serve /dex.yaml"
|
||||
dex: sh -c "go run github.com/argoproj/argo-cd/cmd/argocd-util 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 ghcr.io/dexidp/dex:v2.27.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.10-alpine --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}
|
||||
repo-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} 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'
|
||||
|
||||
@@ -12,9 +12,11 @@ import (
|
||||
"github.com/go-redis/redis/v8"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc/health/grpc_health_v1"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
"github.com/argoproj/argo-cd/reposerver/apiclient"
|
||||
reposervercache "github.com/argoproj/argo-cd/reposerver/cache"
|
||||
"github.com/argoproj/argo-cd/reposerver/metrics"
|
||||
"github.com/argoproj/argo-cd/reposerver/repository"
|
||||
@@ -23,6 +25,8 @@ import (
|
||||
"github.com/argoproj/argo-cd/util/env"
|
||||
"github.com/argoproj/argo-cd/util/errors"
|
||||
"github.com/argoproj/argo-cd/util/gpg"
|
||||
"github.com/argoproj/argo-cd/util/healthz"
|
||||
ioutil "github.com/argoproj/argo-cd/util/io"
|
||||
"github.com/argoproj/argo-cd/util/tls"
|
||||
)
|
||||
|
||||
@@ -32,8 +36,8 @@ const (
|
||||
gnuPGSourcePath = "/app/config/gpg/source"
|
||||
|
||||
defaultPauseGenerationAfterFailedGenerationAttempts = 3
|
||||
defaultPauseGenerationOnFailureForMinutes = 0
|
||||
defaultPauseGenerationOnFailureForRequests = 12
|
||||
defaultPauseGenerationOnFailureForMinutes = 60
|
||||
defaultPauseGenerationOnFailureForRequests = 0
|
||||
)
|
||||
|
||||
func getGnuPGSourcePath() string {
|
||||
@@ -96,6 +100,28 @@ func NewCommand() *cobra.Command {
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", listenPort))
|
||||
errors.CheckError(err)
|
||||
|
||||
healthz.ServeHealthCheck(http.DefaultServeMux, func(r *http.Request) error {
|
||||
if val, ok := r.URL.Query()["full"]; ok && len(val) > 0 && val[0] == "true" {
|
||||
// connect to itself to make sure repo server is able to serve connection
|
||||
// used by liveness probe to auto restart repo server
|
||||
// see https://github.com/argoproj/argo-cd/issues/5110 for more information
|
||||
conn, err := apiclient.NewConnection(fmt.Sprintf("localhost:%d", listenPort), 60)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ioutil.Close(conn)
|
||||
client := grpc_health_v1.NewHealthClient(conn)
|
||||
res, err := client.Check(r.Context(), &grpc_health_v1.HealthCheckRequest{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.Status != grpc_health_v1.HealthCheckResponse_SERVING {
|
||||
return fmt.Errorf("grpc health check status is '%v'", res.Status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
})
|
||||
http.Handle("/metrics", metricsServer.GetHandler())
|
||||
go func() { errors.CheckError(http.ListenAndServe(fmt.Sprintf(":%d", metricsPort), nil)) }()
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
"time"
|
||||
@@ -278,7 +279,7 @@ func reconcileApplications(
|
||||
projLister := appInformerFactory.Argoproj().V1alpha1().AppProjects().Lister()
|
||||
server, err := metrics.NewMetricsServer("", appLister, func(obj interface{}) bool {
|
||||
return true
|
||||
}, func() error {
|
||||
}, func(r *http.Request) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/skratchdot/open-golang/open"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -113,7 +113,7 @@ func NewLoginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Comman
|
||||
}
|
||||
|
||||
parser := &jwt.Parser{
|
||||
SkipClaimsValidation: true,
|
||||
ValidationHelper: jwt.NewValidationHelper(jwt.WithoutClaimsValidation()),
|
||||
}
|
||||
claims := jwt.MapClaims{}
|
||||
_, _, err := parser.ParseUnverified(tokenString, &claims)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
timeutil "github.com/argoproj/pkg/time"
|
||||
jwtgo "github.com/dgrijalva/jwt-go"
|
||||
jwtgo "github.com/dgrijalva/jwt-go/v4"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
|
||||
|
||||
@@ -85,6 +85,8 @@ const (
|
||||
DexAPIEndpoint = "/api/dex"
|
||||
// LoginEndpoint is Argo CD's shorthand login endpoint which redirects to dex's OAuth 2.0 provider's consent page
|
||||
LoginEndpoint = "/auth/login"
|
||||
// LogoutEndpoint is Argo CD's shorthand logout endpoint which invalidates OIDC session after logout
|
||||
LogoutEndpoint = "/auth/logout"
|
||||
// CallbackEndpoint is Argo CD's final callback endpoint we reach after OAuth 2.0 login flow has been completed
|
||||
CallbackEndpoint = "/auth/callback"
|
||||
// DexCallbackEndpoint is Argo CD's final callback endpoint when Dex is configured
|
||||
@@ -180,6 +182,8 @@ const (
|
||||
EnvControllerReplicas = "ARGOCD_CONTROLLER_REPLICAS"
|
||||
// EnvControllerShard is the shard number that should be handled by controller
|
||||
EnvControllerShard = "ARGOCD_CONTROLLER_SHARD"
|
||||
// EnvEnableGRPCTimeHistogramEnv enables gRPC metrics collection
|
||||
EnvEnableGRPCTimeHistogramEnv = "ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -189,7 +193,7 @@ const (
|
||||
MinClientVersion = "1.4.0"
|
||||
// CacheVersion is a objects version cached using util/cache/cache.go.
|
||||
// Number should be bumped in case of backward incompatible change to make sure cache is invalidated after upgrade.
|
||||
CacheVersion = "1.8.1"
|
||||
CacheVersion = "1.8.3"
|
||||
)
|
||||
|
||||
// GetGnuPGHomePath retrieves the path to use for GnuPG home directory, which is either taken from GNUPGHOME environment or a default value
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
@@ -13,12 +14,11 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
logutils "github.com/argoproj/argo-cd/util/log"
|
||||
|
||||
"github.com/argoproj/gitops-engine/pkg/diff"
|
||||
"github.com/argoproj/gitops-engine/pkg/health"
|
||||
synccommon "github.com/argoproj/gitops-engine/pkg/sync/common"
|
||||
"github.com/argoproj/gitops-engine/pkg/utils/kube"
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/semaphore"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
@@ -26,9 +26,11 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
apiruntime "k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
@@ -42,7 +44,6 @@ import (
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application"
|
||||
appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
appinformers "github.com/argoproj/argo-cd/pkg/client/informers/externalversions"
|
||||
"github.com/argoproj/argo-cd/pkg/client/informers/externalversions/application/v1alpha1"
|
||||
applisters "github.com/argoproj/argo-cd/pkg/client/listers/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/reposerver/apiclient"
|
||||
@@ -51,6 +52,7 @@ import (
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
"github.com/argoproj/argo-cd/util/errors"
|
||||
"github.com/argoproj/argo-cd/util/glob"
|
||||
logutils "github.com/argoproj/argo-cd/util/log"
|
||||
settings_util "github.com/argoproj/argo-cd/util/settings"
|
||||
)
|
||||
|
||||
@@ -151,10 +153,7 @@ func NewApplicationController(
|
||||
ctrl.kubectlSemaphore = semaphore.NewWeighted(kubectlParallelismLimit)
|
||||
}
|
||||
kubectl.SetOnKubectlRun(ctrl.onKubectlRun)
|
||||
appInformer, appLister, err := ctrl.newApplicationInformerAndLister()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appInformer, appLister := ctrl.newApplicationInformerAndLister()
|
||||
indexers := cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}
|
||||
projInformer := v1alpha1.NewAppProjectInformer(applicationClientset, namespace, appResyncPeriod, indexers)
|
||||
projInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
@@ -175,7 +174,8 @@ func NewApplicationController(
|
||||
},
|
||||
})
|
||||
metricsAddr := fmt.Sprintf("0.0.0.0:%d", metricsPort)
|
||||
ctrl.metricsServer, err = metrics.NewMetricsServer(metricsAddr, appLister, ctrl.canProcessApp, func() error {
|
||||
var err error
|
||||
ctrl.metricsServer, err = metrics.NewMetricsServer(metricsAddr, appLister, ctrl.canProcessApp, func(r *http.Request) error {
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@@ -854,6 +854,11 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
||||
ctrl.requestAppRefresh(app.Name, CompareWithLatest.Pointer(), &retryAfter)
|
||||
return
|
||||
} else {
|
||||
// retrying operation. remove previous failure time in app since it is used as a trigger
|
||||
// that previous failed and operation should be retried
|
||||
state.FinishedAt = nil
|
||||
ctrl.setOperationState(app, state)
|
||||
// Get rid of sync results and null out previous operation completion time
|
||||
state.SyncResult = nil
|
||||
}
|
||||
} else {
|
||||
@@ -944,6 +949,13 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if app.Status.OperationState != nil && app.Status.OperationState.FinishedAt != nil && state.FinishedAt == nil {
|
||||
patchJSON, err = jsonpatch.MergeMergePatches(patchJSON, []byte(`{"status": {"operationState": {"finishedAt": null}}}`))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace)
|
||||
_, err = appClient.Patch(context.Background(), app.Name, types.MergePatchType, patchJSON, metav1.PatchOptions{})
|
||||
if err != nil {
|
||||
@@ -1392,11 +1404,6 @@ func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool {
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
err := argo.ValidateDestination(context.Background(), &app.Spec.Destination, ctrl.db)
|
||||
if err != nil {
|
||||
ctrl.setAppCondition(app, appv1.ApplicationCondition{Type: appv1.ApplicationConditionInvalidSpecError, Message: err.Error()})
|
||||
return false
|
||||
}
|
||||
if ctrl.clusterFilter != nil {
|
||||
cluster, err := ctrl.db.GetCluster(context.Background(), app.Spec.Destination.Server)
|
||||
if err != nil {
|
||||
@@ -1408,15 +1415,47 @@ func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.SharedIndexInformer, applisters.ApplicationLister, error) {
|
||||
appInformerFactory := appinformers.NewFilteredSharedInformerFactory(
|
||||
ctrl.applicationClientset,
|
||||
func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.SharedIndexInformer, applisters.ApplicationLister) {
|
||||
informer := cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (apiruntime.Object, error) {
|
||||
return ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).List(context.TODO(), options)
|
||||
},
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
return ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).Watch(context.TODO(), options)
|
||||
},
|
||||
},
|
||||
&appv1.Application{},
|
||||
ctrl.statusRefreshTimeout,
|
||||
ctrl.namespace,
|
||||
func(options *metav1.ListOptions) {},
|
||||
cache.Indexers{
|
||||
cache.NamespaceIndex: func(obj interface{}) ([]string, error) {
|
||||
app, ok := obj.(*appv1.Application)
|
||||
if ok {
|
||||
if err := argo.ValidateDestination(context.Background(), &app.Spec.Destination, ctrl.db); err != nil {
|
||||
ctrl.setAppCondition(app, appv1.ApplicationCondition{Type: appv1.ApplicationConditionInvalidSpecError, Message: err.Error()})
|
||||
}
|
||||
}
|
||||
|
||||
return cache.MetaNamespaceIndexFunc(obj)
|
||||
},
|
||||
orphanedIndex: func(obj interface{}) (i []string, e error) {
|
||||
app, ok := obj.(*appv1.Application)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
proj, err := ctrl.getAppProj(app)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
if proj.Spec.OrphanedResources != nil {
|
||||
return []string{app.Spec.Destination.Namespace}, nil
|
||||
}
|
||||
return nil, nil
|
||||
},
|
||||
},
|
||||
)
|
||||
informer := appInformerFactory.Argoproj().V1alpha1().Applications().Informer()
|
||||
lister := appInformerFactory.Argoproj().V1alpha1().Applications().Lister()
|
||||
lister := applisters.NewApplicationLister(informer.GetIndexer())
|
||||
informer.AddEventHandler(
|
||||
cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
@@ -1461,24 +1500,7 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar
|
||||
},
|
||||
},
|
||||
)
|
||||
err := informer.AddIndexers(cache.Indexers{
|
||||
orphanedIndex: func(obj interface{}) (i []string, e error) {
|
||||
app, ok := obj.(*appv1.Application)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
proj, err := ctrl.getAppProj(app)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
if proj.Spec.OrphanedResources != nil {
|
||||
return []string{app.Spec.Destination.Namespace}, nil
|
||||
}
|
||||
return nil, nil
|
||||
},
|
||||
})
|
||||
return informer, lister, err
|
||||
return informer, lister
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) RegisterClusterSecretUpdater(ctx context.Context) {
|
||||
|
||||
@@ -1006,26 +1006,6 @@ func TestUpdateReconciledAt(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestCanProcessApp_DestNameIsValid(t *testing.T) {
|
||||
app := newFakeAppWithDestName()
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}})
|
||||
|
||||
ok := ctrl.canProcessApp(app)
|
||||
assert.True(t, ok)
|
||||
assert.Len(t, app.Status.Conditions, 0)
|
||||
}
|
||||
|
||||
func TestCanProcessApp_BothDestNameAndServer(t *testing.T) {
|
||||
app := newFakeAppWithDestMismatch()
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}})
|
||||
|
||||
ok := ctrl.canProcessApp(app)
|
||||
assert.False(t, ok)
|
||||
assert.Len(t, app.Status.Conditions, 1)
|
||||
assert.Equal(t, argoappv1.ApplicationConditionInvalidSpecError, app.Status.Conditions[0].Type)
|
||||
assert.Equal(t, "application destination can't have both name and server defined: another-cluster https://localhost:6443", app.Status.Conditions[0].Message)
|
||||
}
|
||||
|
||||
func TestFinalizeProjectDeletion_HasApplications(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
proj := &argoappv1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace}}
|
||||
|
||||
@@ -133,7 +133,7 @@ var (
|
||||
)
|
||||
|
||||
// NewMetricsServer returns a new prometheus server which collects application metrics
|
||||
func NewMetricsServer(addr string, appLister applister.ApplicationLister, appFilter func(obj interface{}) bool, healthCheck func() error) (*MetricsServer, error) {
|
||||
func NewMetricsServer(addr string, appLister applister.ApplicationLister, appFilter func(obj interface{}) bool, healthCheck func(r *http.Request) error) (*MetricsServer, error) {
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -112,7 +112,7 @@ status:
|
||||
status: Healthy
|
||||
`
|
||||
|
||||
var noOpHealthCheck = func() error {
|
||||
var noOpHealthCheck = func(r *http.Request) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ and might fail. To avoid failed syncs use `ARGOCD_GIT_ATTEMPTS_COUNT` environmen
|
||||
|
||||
* `argocd_git_request_total` - Number of git requests. The metric provides two tags: `repo` - Git repo URL; `request_type` - `ls-remote` or `fetch`.
|
||||
|
||||
* `ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM` (v1.8+) - environment variable that enables collecting RPC performance metrics. Enable it if you need to troubleshoot performance issue. Note: metric is expensive to both query and store!
|
||||
|
||||
### argocd-application-controller
|
||||
|
||||
**settings:**
|
||||
@@ -82,6 +84,8 @@ spec:
|
||||
value: "2"
|
||||
```
|
||||
|
||||
* `ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM` (v1.8+)- environment variable that enables collecting RPC performance metrics. Enable it if you need to troubleshoot performance issue. Note: metric is expensive to both query and store!
|
||||
|
||||
**metrics**
|
||||
|
||||
* `argocd_app_reconcile` - reports application reconciliation duration. Can be used to build reconciliation duration heat map to get high-level reconciliation performance picture.
|
||||
@@ -92,6 +96,11 @@ non-preferred version and causes performance issues.
|
||||
|
||||
The `argocd-server` is stateless and probably least likely to cause issues. You might consider increasing number of replicas to 3 or more to ensure there is no downtime during upgrades.
|
||||
|
||||
**settings:**
|
||||
|
||||
* The `ARGOCD_GRPC_MAX_SIZE_MB` environment variable allows specifying the max size of the server response message in megabytes.
|
||||
The default value is 200. You might need to increase for an Argo CD instance that manages 3000+ applications.
|
||||
|
||||
### argocd-dex-server, argocd-redis
|
||||
|
||||
The `argocd-dex-server` uses an in-memory database, and two or more instances would have inconsistent data. `argocd-redis` is pre-configured with the understanding of only three total redis servers/sentinels.
|
||||
|
||||
47
docs/operator-manual/upgrading/1.7-1.8.md
Normal file
47
docs/operator-manual/upgrading/1.7-1.8.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# v1.7 to 1.8
|
||||
|
||||
## The argocd-application-controller converted to StatefulSet
|
||||
|
||||
The `argocd-application-controller` has been converted to StatefulSet. That means you need to manually delete `argocd-application-controller` Deployment after upgrading.
|
||||
Similarly if you decided to rollback to v1.7 don't forget to delete `argocd-application-controller` StatefulSet.
|
||||
|
||||
|
||||
## Health assessement of argoproj.io/Application CRD has been removed
|
||||
|
||||
The health assessement of `argoproj.io/Application` CRD has been removed (see [#3781](https://github.com/argoproj/argo-cd/issues/3781) for more information).
|
||||
You might need to restore it if you are using app-of-apps pattern and orchestrating syncronization using sync waves. Add the following resource customization in
|
||||
`argocd-cm` ConfigMap:
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-cm
|
||||
namespace: argocd
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-cm
|
||||
app.kubernetes.io/part-of: argocd
|
||||
data:
|
||||
resource.customizations: |
|
||||
argoproj.io/Application:
|
||||
health.lua: |
|
||||
hs = {}
|
||||
hs.status = "Healthy"
|
||||
hs.message = ""
|
||||
if obj.status ~= nil then
|
||||
if obj.status.health ~= nil then
|
||||
hs.status = obj.status.health.status
|
||||
hs.message = obj.status.health.message
|
||||
end
|
||||
end
|
||||
return hs
|
||||
```
|
||||
|
||||
## gRPC metrics are disabled by default
|
||||
|
||||
The gRPC metrics are not exposed by default by `argocd-server` and `argocd-repo-server` anymore. These metrics appear
|
||||
to be too expensive so we've decided to disable them by default. Metrics can be enabled using
|
||||
`ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM=true` environment variable.
|
||||
|
||||
From here on you can follow the [regular upgrade process](./overview.md).
|
||||
@@ -37,6 +37,7 @@ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/<v
|
||||
|
||||
<hr/>
|
||||
|
||||
* [v1.7 to v1.8](./1.7-1.8.md)
|
||||
* [v1.6 to v1.7](./1.6-1.7.md)
|
||||
* [v1.5 to v1.6](./1.5-1.6.md)
|
||||
* [v1.4 to v1.5](./1.4-1.5.md)
|
||||
|
||||
@@ -263,3 +263,29 @@ For a simple case this can be:
|
||||
oidc.config: |
|
||||
requestedIDTokenClaims: {"groups": {"essential": true}}
|
||||
```
|
||||
### Configuring a custom logout URL for your OIDC provider
|
||||
|
||||
Optionally, if your OIDC provider exposes a logout API and you wish to configure a custom logout URL for the purposes of invalidating
|
||||
any active session post logout, you can do so by specifying it as follows:
|
||||
|
||||
```yaml
|
||||
oidc.config: |
|
||||
name: example-OIDC-provider
|
||||
issuer: https://example-OIDC-provider.com
|
||||
clientID: xxxxxxxxx
|
||||
clientSecret: xxxxxxxxx
|
||||
requestedScopes: ["openid", "profile", "email", "groups"]
|
||||
requestedIDTokenClaims: {"groups": {"essential": true}}
|
||||
logoutURL: https://example-OIDC-provider.com/logout?id_token_hint={{token}}
|
||||
```
|
||||
By default, this would take the user to their OIDC provider's login page after logout. If you also wish to redirect the user back to Argo CD after logout, you can specify the logout URL as follows:
|
||||
|
||||
```yaml
|
||||
...
|
||||
logoutURL: https://example-OIDC-provider.com/logout?id_token_hint={{token}}&post_logout_redirect_uri={{logoutRedirectURL}}
|
||||
```
|
||||
|
||||
You are not required to specify a logoutRedirectURL as this is automatically generated by ArgoCD as your base ArgoCD url + Rootpath
|
||||
|
||||
!!! note
|
||||
The post logout redirect URI may need to be whitelisted against your OIDC provider's client settings for ArgoCD.
|
||||
24
go.mod
24
go.mod
@@ -7,13 +7,13 @@ require (
|
||||
github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d
|
||||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect
|
||||
github.com/alicebob/miniredis v2.5.0+incompatible
|
||||
github.com/argoproj/gitops-engine v0.1.3-0.20201113084616-069a5e64fb79
|
||||
github.com/argoproj/gitops-engine v0.2.1
|
||||
github.com/argoproj/pkg v0.2.0
|
||||
github.com/bombsimon/logrusr v1.0.0
|
||||
github.com/casbin/casbin v1.9.1
|
||||
github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1
|
||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/evanphx/json-patch v4.9.0+incompatible
|
||||
@@ -23,19 +23,19 @@ require (
|
||||
github.com/go-openapi/loads v0.19.4
|
||||
github.com/go-openapi/runtime v0.19.4
|
||||
github.com/go-openapi/spec v0.19.3
|
||||
github.com/go-redis/cache/v8 v8.0.0-beta.11
|
||||
github.com/go-redis/redis/v8 v8.0.0-beta.9
|
||||
github.com/go-redis/cache/v8 v8.2.1
|
||||
github.com/go-redis/redis/v8 v8.3.2
|
||||
github.com/gobuffalo/packr v1.11.0
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/gogits/go-gogs-client v0.0.0-20190616193657-5a05380e4bc2
|
||||
github.com/gogo/protobuf v1.3.1
|
||||
github.com/golang/protobuf v1.4.2
|
||||
github.com/golang/protobuf v1.4.3
|
||||
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
||||
github.com/google/go-cmp v0.5.1
|
||||
github.com/google/go-jsonnet v0.16.0
|
||||
github.com/google/go-cmp v0.5.2
|
||||
github.com/google/go-jsonnet v0.17.0
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gorilla/handlers v1.5.0
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||
@@ -43,6 +43,7 @@ require (
|
||||
github.com/improbable-eng/grpc-web v0.0.0-20181111100011-16092bd1d58a
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8 // indirect
|
||||
github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf // indirect
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
@@ -57,11 +58,13 @@ require (
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/undefinedlabs/go-mpatch v1.0.6
|
||||
github.com/vmihailenco/msgpack/v5 v5.1.0 // indirect
|
||||
github.com/yuin/gopher-lua v0.0.0-20190115140932-732aa6820ec4
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||
golang.org/x/exp v0.0.0-20200821190819-94841d0725da // indirect
|
||||
golang.org/x/net v0.0.0-20201024042810-be3efd7ff127
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013
|
||||
google.golang.org/grpc v1.29.1
|
||||
gopkg.in/go-playground/webhooks.v5 v5.11.0
|
||||
@@ -85,6 +88,7 @@ require (
|
||||
|
||||
replace (
|
||||
github.com/golang/protobuf => github.com/golang/protobuf v1.4.2
|
||||
github.com/gorilla/websocket => github.com/gorilla/websocket v1.4.2
|
||||
github.com/grpc-ecosystem/grpc-gateway => github.com/grpc-ecosystem/grpc-gateway v1.12.2
|
||||
github.com/improbable-eng/grpc-web => github.com/improbable-eng/grpc-web v0.0.0-20181111100011-16092bd1d58a
|
||||
|
||||
|
||||
107
go.sum
107
go.sum
@@ -42,7 +42,6 @@ github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VY
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
|
||||
github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20200415212048-7901bc822317/go.mod h1:DF8FZRxMHMGv/vP2lQP6h+dYzzjpuRn24VeRiYn3qjQ=
|
||||
github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
|
||||
@@ -64,8 +63,6 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d h1:WtAMR0fPCOfK7TPGZ8ZpLLY18HRvL7XJ3xcs0wnREgo=
|
||||
github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d/go.mod h1:WML6KOYjeU8N6YyusMjj2qRvaPNUEvrQvaxuFcMRFJY=
|
||||
github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw=
|
||||
github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||
@@ -78,14 +75,12 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 h1:45bxf7AZMw
|
||||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||
github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI=
|
||||
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
|
||||
github.com/argoproj/gitops-engine v0.1.3-0.20201113084616-069a5e64fb79 h1:+VXKYb/FNTag/vnSoH9/Pey/kXK/jBKDyOtwRfnmMMw=
|
||||
github.com/argoproj/gitops-engine v0.1.3-0.20201113084616-069a5e64fb79/go.mod h1:OxXp8YaT73rw9gEBnGBWg55af80nkV/uIjWCbJu1Nw0=
|
||||
github.com/argoproj/gitops-engine v0.2.1 h1:iXmTCCM0m2u/YVLMhJatU21awuAscGiirscn13rYQtE=
|
||||
github.com/argoproj/gitops-engine v0.2.1/go.mod h1:OxXp8YaT73rw9gEBnGBWg55af80nkV/uIjWCbJu1Nw0=
|
||||
github.com/argoproj/pkg v0.2.0 h1:ETgC600kr8WcAi3MEVY5sA1H7H/u1/IysYOobwsZ8No=
|
||||
github.com/argoproj/pkg v0.2.0/go.mod h1:F4TZgInLUEjzsWFB/BTJBsewoEy0ucnKSq6vmQiD/yc=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
@@ -99,7 +94,6 @@ github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:
|
||||
github.com/aws/aws-sdk-go v1.6.10/go.mod h1:ZRmQr0FajVIyZ4ZzBYKG5P3ZqPz9IHG41ZoMu1ADI3k=
|
||||
github.com/aws/aws-sdk-go v1.28.2/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.33.16/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/benbjohnson/clock v1.0.0/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@@ -167,6 +161,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
@@ -174,6 +170,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbYd8tQGRWacE9kU=
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
@@ -291,11 +289,10 @@ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2K
|
||||
github.com/go-openapi/validate v0.19.5 h1:QhCBKRYqZR+SKo4gl1lPhPahope8/RLt6EVgY8X80w0=
|
||||
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
|
||||
github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU=
|
||||
github.com/go-redis/cache/v8 v8.0.0-beta.11 h1:6QdpDYemSFQ2yrDkDkEofHpXid6Mm3UctqaVUzxGdn8=
|
||||
github.com/go-redis/cache/v8 v8.0.0-beta.11/go.mod h1:4wxD/neK+Uw+SteOR+AXtlyQYMBlI/D1u7UahfDCBAI=
|
||||
github.com/go-redis/redis/v8 v8.0.0-beta.2/go.mod h1:o1M7JtsgfDYyv3o+gBn/jJ1LkqpnCrmil7PSppZGBak=
|
||||
github.com/go-redis/redis/v8 v8.0.0-beta.9 h1:gcRNXZvs4PFi/mptho1D3hXant8JsbQKQxQ+0W3QGPw=
|
||||
github.com/go-redis/redis/v8 v8.0.0-beta.9/go.mod h1:CCWlPAL3uftOyyBOGpJ+A0ps2WpG3+hqo14fVs5aQ6A=
|
||||
github.com/go-redis/cache/v8 v8.2.1 h1:G4CtEQDT3JsiERPob1nUL/KTkiC317rAJvHx6GdWjiM=
|
||||
github.com/go-redis/cache/v8 v8.2.1/go.mod h1:8PFGBZrRqG2nToSHw76mSsozxgSKrn3vsZerq/NJtt8=
|
||||
github.com/go-redis/redis/v8 v8.3.2 h1:1bJscgN2yGtKLW6MsTRosa2LHyeq94j0hnNAgRZzj/M=
|
||||
github.com/go-redis/redis/v8 v8.3.2/go.mod h1:jszGxBCez8QA1HWSmQxJO9Y82kNibbUmeYhKWrBejTU=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
@@ -326,8 +323,6 @@ github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho=
|
||||
github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8=
|
||||
github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk=
|
||||
@@ -341,10 +336,11 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-jsonnet v0.16.0 h1:Nb4EEOp+rdeGGyB1rQ5eisgSAqrTnhf9ip+X6lzZbY0=
|
||||
github.com/google/go-jsonnet v0.16.0/go.mod h1:sOcuej3UW1vpPTZOr8L7RQimqai1a57bt5j22LzGZCw=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-jsonnet v0.17.0 h1:/9NIEfhK1NQRKl3sP2536b2+x5HnZMdql7x3yK/l8JY=
|
||||
github.com/google/go-jsonnet v0.17.0/go.mod h1:sOcuej3UW1vpPTZOr8L7RQimqai1a57bt5j22LzGZCw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -365,12 +361,11 @@ github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3i
|
||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/handlers v1.5.0 h1:4wjo3sf9azi99c8hTmyaxp9y5S+pFszsy3pP0rAw/lw=
|
||||
github.com/gorilla/handlers v1.5.0/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
@@ -425,8 +420,8 @@ github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.10.5 h1:7q6vHIqubShURwQz8cQK6yIe/xC3IF0Vm7TGfqjewrc=
|
||||
github.com/klauspost/compress v1.10.5/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.1 h1:bPb7nMRdOZYDrpPMTA3EInUQrdgoBinqUuSwlGdKDdE=
|
||||
github.com/klauspost/compress v1.11.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -487,12 +482,12 @@ github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9
|
||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mmcloughlin/avo v0.0.0-20200504053806-fa88270b07e4 h1:HqABfvSTSz0ipb7ArOwybHX8/5lSzn0eU7BDYiBU/XY=
|
||||
github.com/mmcloughlin/avo v0.0.0-20200504053806-fa88270b07e4/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls=
|
||||
github.com/moby/ipvs v1.0.1/go.mod h1:2pngiyseZbIKXNv7hsKj3O9UEz30c53MT9005gt2hxQ=
|
||||
github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o=
|
||||
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd h1:aY7OQNf2XqY/JQ6qREWamhI/81os/agb2BAGpcx5yWI=
|
||||
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
|
||||
github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf h1:Un6PNx5oMK6CCwO3QTUyPiK2mtZnPrpDl5UnZ64eCkw=
|
||||
github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -512,18 +507,26 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
||||
github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
|
||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M=
|
||||
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=
|
||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
@@ -535,7 +538,6 @@ github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
|
||||
github.com/opencontainers/selinux v1.5.2/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
|
||||
github.com/opentracing/opentracing-go v1.1.1-0.20190913142402-a7454ce5950e/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
@@ -654,11 +656,13 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17
|
||||
github.com/vishvananda/netns v0.0.0-20200520041808-52d707b772fe/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/vmihailenco/bufpool v0.1.11 h1:gOq2WmBrq0i2yW5QJ16ykccQ4wH9UyEsgLm6czKAd94=
|
||||
github.com/vmihailenco/bufpool v0.1.11/go.mod h1:AFf/MOy3l2CFTKbxwt0mp2MwnqjNEs5H/UxrkA5jxTQ=
|
||||
github.com/vmihailenco/msgpack/v4 v4.3.11/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
||||
github.com/vmihailenco/msgpack/v5 v5.0.0-alpha.2 h1:0jVpYJSRJzGY7m21n9V5uIkl7Zre64W8DR1dxEKX2g4=
|
||||
github.com/vmihailenco/msgpack/v5 v5.0.0-alpha.2/go.mod h1:LDfrk4wJpSFwkzNOJxrCWiSm8c7Iqw/hXNPT2fzQfE8=
|
||||
github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
|
||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
github.com/vmihailenco/go-tinylfu v0.1.0 h1:wNwKigNq50gfiyQDPpseEuGK4TZtFyjduJSg0M6gBns=
|
||||
github.com/vmihailenco/go-tinylfu v0.1.0/go.mod h1:qZbD6U3F10Sfuxyy4c5wMq5CM4/t5I3eJJS9yMQoXU0=
|
||||
github.com/vmihailenco/msgpack/v5 v5.0.0-beta.5/go.mod h1:MPECSZPg8yittBek5Gq2MhEDJpB9FrbSzQOSWmJm38A=
|
||||
github.com/vmihailenco/msgpack/v5 v5.1.0 h1:+od5YbEXxW95SPlW6beocmt8nOtlh83zqat5Ip9Hwdc=
|
||||
github.com/vmihailenco/msgpack/v5 v5.1.0/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI=
|
||||
github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc=
|
||||
github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
|
||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
@@ -679,14 +683,12 @@ go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/otel v0.5.0/go.mod h1:jzBIgIzK43Iu1BpDAXwqOd6UPsSAk+ewVZ5ofSXw4Ek=
|
||||
go.opentelemetry.io/otel v0.11.0 h1:IN2tzQa9Gc4ZVKnTaMbPVcHjvzOdg5n9QfnmlqiET7E=
|
||||
go.opentelemetry.io/otel v0.11.0/go.mod h1:G8UCk+KooF2HLkgo8RHX9epABH/aRGYET7gQOqBVdB0=
|
||||
go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
|
||||
go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -755,18 +757,20 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201022231255-08b38378de70/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201024042810-be3efd7ff127 h1:pZPp9+iYUqwYKLjht0SDBbRCRK/9gAXDy7pz5fRDpjo=
|
||||
golang.org/x/net v0.0.0-20201024042810-be3efd7ff127/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -780,6 +784,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -803,10 +809,10 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -823,9 +829,13 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8=
|
||||
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
@@ -866,8 +876,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054 h1:HHeAlu5H9b71C+Fx0K+1dGgVFN1DM1/wz4aoGOA5qS8=
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -892,8 +900,8 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -903,7 +911,6 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
@@ -914,6 +921,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -949,7 +958,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
@@ -957,6 +965,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# The checksum of this file is used as cache key in our integration toolchain
|
||||
#
|
||||
helm2_version=2.17.0
|
||||
helm3_version=3.4.0
|
||||
helm3_version=3.4.1
|
||||
jq_version=1.6
|
||||
ksonnet_version=0.13.1
|
||||
kubectl_version=1.17.8
|
||||
|
||||
@@ -42,3 +42,18 @@ spec:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
serviceAccountName: argocd-application-controller
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-application-controller
|
||||
topologyKey: kubernetes.io/hostname
|
||||
- weight: 5
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
|
||||
@@ -26,7 +26,7 @@ spec:
|
||||
name: static-files
|
||||
containers:
|
||||
- name: dex
|
||||
image: quay.io/dexidp/dex:v2.25.0
|
||||
image: ghcr.io/dexidp/dex:v2.27.0
|
||||
imagePullPolicy: Always
|
||||
command: [/shared/argocd-util, rundex]
|
||||
ports:
|
||||
@@ -39,3 +39,12 @@ spec:
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: static-files
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 5
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
|
||||
@@ -5,7 +5,7 @@ kind: Kustomization
|
||||
images:
|
||||
- name: argoproj/argocd
|
||||
newName: argoproj/argocd
|
||||
newTag: latest
|
||||
newTag: v1.8.2
|
||||
resources:
|
||||
- ./application-controller
|
||||
- ./dex
|
||||
|
||||
@@ -32,3 +32,18 @@ spec:
|
||||
- "no"
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-redis
|
||||
topologyKey: kubernetes.io/hostname
|
||||
- weight: 5
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
|
||||
@@ -28,9 +28,17 @@ spec:
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
- containerPort: 8084
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz?full=true
|
||||
port: 8084
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 5
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: 8081
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8084
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
volumeMounts:
|
||||
@@ -54,3 +62,18 @@ spec:
|
||||
name: argocd-gpg-keys-cm
|
||||
- name: gpg-keyring
|
||||
emptyDir: {}
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-repo-server
|
||||
topologyKey: kubernetes.io/hostname
|
||||
- weight: 5
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
|
||||
@@ -29,6 +29,12 @@ spec:
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
- containerPort: 8083
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz?full=true
|
||||
port: 8080
|
||||
initialDelaySeconds: 3
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
@@ -44,3 +50,18 @@ spec:
|
||||
- name: tls-certs
|
||||
configMap:
|
||||
name: argocd-tls-certs-cm
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
topologyKey: kubernetes.io/hostname
|
||||
- weight: 5
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
|
||||
@@ -11,7 +11,7 @@ patchesStrategicMerge:
|
||||
images:
|
||||
- name: argoproj/argocd
|
||||
newName: argoproj/argocd
|
||||
newTag: latest
|
||||
newTag: v1.8.2
|
||||
resources:
|
||||
- ../../base/application-controller
|
||||
- ../../base/dex
|
||||
|
||||
@@ -2835,11 +2835,20 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-dex-server
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
containers:
|
||||
- command:
|
||||
- /shared/argocd-util
|
||||
- rundex
|
||||
image: quay.io/dexidp/dex:v2.25.0
|
||||
image: ghcr.io/dexidp/dex:v2.27.0
|
||||
imagePullPolicy: Always
|
||||
name: dex
|
||||
ports:
|
||||
@@ -2855,7 +2864,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -2993,17 +3002,25 @@ spec:
|
||||
- argocd-repo-server
|
||||
- --redis
|
||||
- argocd-redis-ha-haproxy:6379
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
httpGet:
|
||||
path: /healthz?full=true
|
||||
port: 8084
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 5
|
||||
name: argocd-repo-server
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
- containerPort: 8084
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8084
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
tcpSocket:
|
||||
port: 8081
|
||||
volumeMounts:
|
||||
- mountPath: /app/config/ssh
|
||||
name: ssh-known-hosts
|
||||
@@ -3067,8 +3084,14 @@ spec:
|
||||
env:
|
||||
- name: ARGOCD_API_SERVER_REPLICAS
|
||||
value: "2"
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz?full=true
|
||||
port: 8080
|
||||
initialDelaySeconds: 3
|
||||
periodSeconds: 30
|
||||
name: argocd-server
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -3113,6 +3136,21 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-application-controller
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-application-controller
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 100
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
containers:
|
||||
- command:
|
||||
- argocd-application-controller
|
||||
@@ -3122,7 +3160,7 @@ spec:
|
||||
- "10"
|
||||
- --redis
|
||||
- argocd-redis-ha-haproxy:6379
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -2750,11 +2750,20 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-dex-server
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
containers:
|
||||
- command:
|
||||
- /shared/argocd-util
|
||||
- rundex
|
||||
image: quay.io/dexidp/dex:v2.25.0
|
||||
image: ghcr.io/dexidp/dex:v2.27.0
|
||||
imagePullPolicy: Always
|
||||
name: dex
|
||||
ports:
|
||||
@@ -2770,7 +2779,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -2908,17 +2917,25 @@ spec:
|
||||
- argocd-repo-server
|
||||
- --redis
|
||||
- argocd-redis-ha-haproxy:6379
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
httpGet:
|
||||
path: /healthz?full=true
|
||||
port: 8084
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 5
|
||||
name: argocd-repo-server
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
- containerPort: 8084
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8084
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
tcpSocket:
|
||||
port: 8081
|
||||
volumeMounts:
|
||||
- mountPath: /app/config/ssh
|
||||
name: ssh-known-hosts
|
||||
@@ -2982,8 +2999,14 @@ spec:
|
||||
env:
|
||||
- name: ARGOCD_API_SERVER_REPLICAS
|
||||
value: "2"
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz?full=true
|
||||
port: 8080
|
||||
initialDelaySeconds: 3
|
||||
periodSeconds: 30
|
||||
name: argocd-server
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -3028,6 +3051,21 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-application-controller
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-application-controller
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 100
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
containers:
|
||||
- command:
|
||||
- argocd-application-controller
|
||||
@@ -3037,7 +3075,7 @@ spec:
|
||||
- "10"
|
||||
- --redis
|
||||
- argocd-redis-ha-haproxy:6379
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -2424,11 +2424,20 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-dex-server
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
containers:
|
||||
- command:
|
||||
- /shared/argocd-util
|
||||
- rundex
|
||||
image: quay.io/dexidp/dex:v2.25.0
|
||||
image: ghcr.io/dexidp/dex:v2.27.0
|
||||
imagePullPolicy: Always
|
||||
name: dex
|
||||
ports:
|
||||
@@ -2444,7 +2453,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -2472,6 +2481,21 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-redis
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-redis
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 100
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
containers:
|
||||
- args:
|
||||
- --save
|
||||
@@ -2507,6 +2531,21 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-repo-server
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-repo-server
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 100
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
automountServiceAccountToken: false
|
||||
containers:
|
||||
- command:
|
||||
@@ -2514,17 +2553,25 @@ spec:
|
||||
- argocd-repo-server
|
||||
- --redis
|
||||
- argocd-redis:6379
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
httpGet:
|
||||
path: /healthz?full=true
|
||||
port: 8084
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 5
|
||||
name: argocd-repo-server
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
- containerPort: 8084
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8084
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
tcpSocket:
|
||||
port: 8081
|
||||
volumeMounts:
|
||||
- mountPath: /app/config/ssh
|
||||
name: ssh-known-hosts
|
||||
@@ -2564,13 +2611,34 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 100
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
containers:
|
||||
- command:
|
||||
- argocd-server
|
||||
- --staticassets
|
||||
- /shared/app
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz?full=true
|
||||
port: 8080
|
||||
initialDelaySeconds: 3
|
||||
periodSeconds: 30
|
||||
name: argocd-server
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -2616,6 +2684,21 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-application-controller
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-application-controller
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 100
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
containers:
|
||||
- command:
|
||||
- argocd-application-controller
|
||||
@@ -2623,7 +2706,7 @@ spec:
|
||||
- "20"
|
||||
- --operation-processors
|
||||
- "10"
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -2339,11 +2339,20 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-dex-server
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
containers:
|
||||
- command:
|
||||
- /shared/argocd-util
|
||||
- rundex
|
||||
image: quay.io/dexidp/dex:v2.25.0
|
||||
image: ghcr.io/dexidp/dex:v2.27.0
|
||||
imagePullPolicy: Always
|
||||
name: dex
|
||||
ports:
|
||||
@@ -2359,7 +2368,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -2387,6 +2396,21 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-redis
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-redis
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 100
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
containers:
|
||||
- args:
|
||||
- --save
|
||||
@@ -2422,6 +2446,21 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-repo-server
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-repo-server
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 100
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
automountServiceAccountToken: false
|
||||
containers:
|
||||
- command:
|
||||
@@ -2429,17 +2468,25 @@ spec:
|
||||
- argocd-repo-server
|
||||
- --redis
|
||||
- argocd-redis:6379
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
httpGet:
|
||||
path: /healthz?full=true
|
||||
port: 8084
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 5
|
||||
name: argocd-repo-server
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
- containerPort: 8084
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8084
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
tcpSocket:
|
||||
port: 8081
|
||||
volumeMounts:
|
||||
- mountPath: /app/config/ssh
|
||||
name: ssh-known-hosts
|
||||
@@ -2479,13 +2526,34 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 100
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
containers:
|
||||
- command:
|
||||
- argocd-server
|
||||
- --staticassets
|
||||
- /shared/app
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz?full=true
|
||||
port: 8080
|
||||
initialDelaySeconds: 3
|
||||
periodSeconds: 30
|
||||
name: argocd-server
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -2531,6 +2599,21 @@ spec:
|
||||
labels:
|
||||
app.kubernetes.io/name: argocd-application-controller
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: argocd-application-controller
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 100
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 5
|
||||
containers:
|
||||
- command:
|
||||
- argocd-application-controller
|
||||
@@ -2538,7 +2621,7 @@ spec:
|
||||
- "20"
|
||||
- --operation-processors
|
||||
- "10"
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.8.2
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -16,7 +17,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/oauth2"
|
||||
"google.golang.org/grpc"
|
||||
@@ -39,6 +40,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/env"
|
||||
grpc_util "github.com/argoproj/argo-cd/util/grpc"
|
||||
argoio "github.com/argoproj/argo-cd/util/io"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
@@ -53,8 +55,13 @@ const (
|
||||
EnvArgoCDServer = "ARGOCD_SERVER"
|
||||
// EnvArgoCDAuthToken is the environment variable to look for an Argo CD auth token
|
||||
EnvArgoCDAuthToken = "ARGOCD_AUTH_TOKEN"
|
||||
// EnvArgoCDgRPCMaxSizeMB is the environment variable to look for a max gRPC message size
|
||||
EnvArgoCDgRPCMaxSizeMB = "ARGOCD_GRPC_MAX_SIZE_MB"
|
||||
)
|
||||
|
||||
var (
|
||||
// MaxGRPCMessageSize contains max grpc message size
|
||||
MaxGRPCMessageSize = 100 * 1024 * 1024
|
||||
MaxGRPCMessageSize = env.ParseNumFromEnv(EnvArgoCDgRPCMaxSizeMB, 200, 0, math.MaxInt32) * 1024 * 1024
|
||||
)
|
||||
|
||||
// Client defines an interface for interaction with an Argo CD server.
|
||||
@@ -321,14 +328,14 @@ func (c *client) refreshAuthToken(localCfg *localconfig.LocalConfig, ctxName, co
|
||||
return err
|
||||
}
|
||||
parser := &jwt.Parser{
|
||||
SkipClaimsValidation: true,
|
||||
ValidationHelper: jwt.NewValidationHelper(jwt.WithoutClaimsValidation()),
|
||||
}
|
||||
var claims jwt.StandardClaims
|
||||
_, _, err = parser.ParseUnverified(configCtx.User.AuthToken, &claims)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if claims.Valid() == nil {
|
||||
if claims.Valid(jwt.DefaultValidationHelper) == nil {
|
||||
// token is still valid
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -170,10 +170,7 @@ func (a *ApplicationSource) IsHelmOci() bool {
|
||||
if a.Chart == "" {
|
||||
return false
|
||||
}
|
||||
if _, _, ok := helm.IsHelmOci(a.Chart); ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return helm.IsHelmOciChart(a.Chart)
|
||||
}
|
||||
|
||||
func (a *ApplicationSource) IsZero() bool {
|
||||
@@ -2398,6 +2395,17 @@ func (source *ApplicationSource) ExplicitType() (*ApplicationSourceType, error)
|
||||
|
||||
// Equals compares two instances of ApplicationDestination and return true if instances are equal.
|
||||
func (dest ApplicationDestination) Equals(other ApplicationDestination) bool {
|
||||
// ignore destination cluster name and isServerInferred fields during comparison
|
||||
// since server URL is inferred from cluster name
|
||||
if dest.isServerInferred {
|
||||
dest.Server = ""
|
||||
dest.isServerInferred = false
|
||||
}
|
||||
|
||||
if other.isServerInferred {
|
||||
other.Server = ""
|
||||
other.isServerInferred = false
|
||||
}
|
||||
return reflect.DeepEqual(dest, other)
|
||||
}
|
||||
|
||||
|
||||
@@ -429,6 +429,21 @@ func TestAppDestinationEquality(t *testing.T) {
|
||||
assert.False(t, left.Equals(*right))
|
||||
}
|
||||
|
||||
func TestAppDestinationEquality_InferredServerURL(t *testing.T) {
|
||||
left := ApplicationDestination{
|
||||
Name: "in-cluster",
|
||||
Namespace: "default",
|
||||
}
|
||||
right := ApplicationDestination{
|
||||
Name: "in-cluster",
|
||||
Server: "https://kubernetes.default.svc",
|
||||
Namespace: "default",
|
||||
isServerInferred: true,
|
||||
}
|
||||
assert.True(t, left.Equals(right))
|
||||
assert.True(t, right.Equals(left))
|
||||
}
|
||||
|
||||
func TestAppProjectSpec_DestinationClusters(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -30,13 +30,21 @@ type clientSet struct {
|
||||
}
|
||||
|
||||
func (c *clientSet) NewRepoServerClient() (io.Closer, RepoServerServiceClient, error) {
|
||||
conn, err := NewConnection(c.address, c.timeoutSeconds)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return conn, NewRepoServerServiceClient(conn), nil
|
||||
}
|
||||
|
||||
func NewConnection(address string, timeoutSeconds int) (*grpc.ClientConn, error) {
|
||||
retryOpts := []grpc_retry.CallOption{
|
||||
grpc_retry.WithMax(3),
|
||||
grpc_retry.WithBackoff(grpc_retry.BackoffLinear(1000 * time.Millisecond)),
|
||||
}
|
||||
unaryInterceptors := []grpc.UnaryClientInterceptor{grpc_retry.UnaryClientInterceptor(retryOpts...)}
|
||||
if c.timeoutSeconds > 0 {
|
||||
unaryInterceptors = append(unaryInterceptors, argogrpc.WithTimeout(time.Duration(c.timeoutSeconds)*time.Second))
|
||||
if timeoutSeconds > 0 {
|
||||
unaryInterceptors = append(unaryInterceptors, argogrpc.WithTimeout(time.Duration(timeoutSeconds)*time.Second))
|
||||
}
|
||||
opts := []grpc.DialOption{
|
||||
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})),
|
||||
@@ -45,12 +53,12 @@ func (c *clientSet) NewRepoServerClient() (io.Closer, RepoServerServiceClient, e
|
||||
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(MaxGRPCMessageSize), grpc.MaxCallSendMsgSize(MaxGRPCMessageSize)),
|
||||
}
|
||||
|
||||
conn, err := grpc.Dial(c.address, opts...)
|
||||
conn, err := grpc.Dial(address, opts...)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to connect to repository service with address %s", c.address)
|
||||
return nil, nil, err
|
||||
log.Errorf("Unable to connect to repository service with address %s", address)
|
||||
return nil, err
|
||||
}
|
||||
return conn, NewRepoServerServiceClient(conn), nil
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// NewRepoServerClientset creates new instance of repo server Clientset
|
||||
|
||||
4
reposerver/cache/cache.go
vendored
4
reposerver/cache/cache.go
vendored
@@ -127,11 +127,11 @@ func appDetailsCacheKey(revision string, appSrc *appv1.ApplicationSource) string
|
||||
return fmt.Sprintf("appdetails|%s|%d", revision, appSourceKey(appSrc))
|
||||
}
|
||||
|
||||
func (c *Cache) GetAppDetails(revision string, appSrc *appv1.ApplicationSource, res interface{}) error {
|
||||
func (c *Cache) GetAppDetails(revision string, appSrc *appv1.ApplicationSource, res *apiclient.RepoAppDetailsResponse) error {
|
||||
return c.cache.GetItem(appDetailsCacheKey(revision, appSrc), res)
|
||||
}
|
||||
|
||||
func (c *Cache) SetAppDetails(revision string, appSrc *appv1.ApplicationSource, res interface{}) error {
|
||||
func (c *Cache) SetAppDetails(revision string, appSrc *appv1.ApplicationSource, res *apiclient.RepoAppDetailsResponse) error {
|
||||
return c.cache.SetItem(appDetailsCacheKey(revision, appSrc), res, c.repoCacheExpiration, res == nil)
|
||||
}
|
||||
|
||||
|
||||
@@ -164,6 +164,23 @@ type operationSettings struct {
|
||||
allowConcurrent bool
|
||||
}
|
||||
|
||||
// operationContext contains request values which are generated by runRepoOperation (on demand) by a call to the
|
||||
// provided operationContextSrc function.
|
||||
type operationContext struct {
|
||||
|
||||
// application path or helm chart path
|
||||
appPath string
|
||||
|
||||
// output of 'git verify-(tag/commit)', if signature verifiction is enabled (otherwise "")
|
||||
verificationResult string
|
||||
}
|
||||
|
||||
// The 'operation' function parameter of 'runRepoOperation' may call this function to retrieve
|
||||
// the appPath or GPG verificationResult.
|
||||
// Failure to generate either of these values will return an error which may be cached by
|
||||
// the calling function (for example, 'runManifestGen')
|
||||
type operationContextSrc = func() (*operationContext, error)
|
||||
|
||||
// runRepoOperation downloads either git folder or helm chart and executes specified operation
|
||||
// - Returns a value from the cache if present (by calling getCached(...)); if no value is present, the
|
||||
// provide operation(...) is called. The specific return type of this function is determined by the
|
||||
@@ -175,13 +192,12 @@ func (s *Service) runRepoOperation(
|
||||
source *v1alpha1.ApplicationSource,
|
||||
verifyCommit bool,
|
||||
getCached func(cacheKey string, firstInvocation bool) (bool, interface{}, error),
|
||||
operation func(appPath, repoRoot, commitSHA, cacheKey, verifyResult string) (interface{}, error),
|
||||
operation func(repoRoot, commitSHA, cacheKey string, ctxSrc operationContextSrc) (interface{}, error),
|
||||
settings operationSettings) (interface{}, error) {
|
||||
|
||||
var gitClient git.Client
|
||||
var helmClient helm.Client
|
||||
var err error
|
||||
var signature string
|
||||
revision = textutils.FirstNonEmpty(revision, source.TargetRevision)
|
||||
if source.IsHelm() {
|
||||
helmClient, revision, err = s.newHelmClientResolveRevision(repo, revision, source.Chart)
|
||||
@@ -229,7 +245,9 @@ func (s *Service) runRepoOperation(
|
||||
return nil, err
|
||||
}
|
||||
defer io.Close(closer)
|
||||
return operation(chartPath, chartPath, revision, revision, "")
|
||||
return operation(chartPath, revision, revision, func() (*operationContext, error) {
|
||||
return &operationContext{chartPath, ""}, nil
|
||||
})
|
||||
} else {
|
||||
closer, err := s.repoLock.Lock(gitClient.Root(), revision, settings.allowConcurrent, func() error {
|
||||
return checkoutRevision(gitClient, revision)
|
||||
@@ -253,19 +271,22 @@ func (s *Service) runRepoOperation(
|
||||
return obj, err
|
||||
}
|
||||
}
|
||||
if verifyCommit {
|
||||
signature, err = gitClient.VerifyCommitSignature(revision)
|
||||
// Here commitSHA refers to the SHA of the actual commit, whereas revision refers to the branch/tag name etc
|
||||
// We use the commitSHA to generate manifests and store them in cache, and revision to retrieve them from cache
|
||||
return operation(gitClient.Root(), commitSHA, revision, func() (*operationContext, error) {
|
||||
var signature string
|
||||
if verifyCommit {
|
||||
signature, err = gitClient.VerifyCommitSignature(revision)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
appPath, err := argopath.Path(gitClient.Root(), source.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
appPath, err := argopath.Path(gitClient.Root(), source.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Here commitSHA refers to the SHA of the actual commit, whereas revision refers to the branch/tag name etc
|
||||
// We use the commitSHA to generate manifests and store them in cache, and revision to retrieve them from cache
|
||||
return operation(appPath, gitClient.Root(), commitSHA, revision, signature)
|
||||
return &operationContext{appPath, signature}, nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,8 +294,8 @@ func (s *Service) GenerateManifest(ctx context.Context, q *apiclient.ManifestReq
|
||||
resultUncast, err := s.runRepoOperation(ctx, q.Revision, q.Repo, q.ApplicationSource, q.VerifySignature,
|
||||
func(cacheKey string, firstInvocation bool) (bool, interface{}, error) {
|
||||
return s.getManifestCacheEntry(cacheKey, q, firstInvocation)
|
||||
}, func(appPath, repoRoot, commitSHA, cacheKey, verifyResult string) (interface{}, error) {
|
||||
return s.runManifestGen(appPath, repoRoot, commitSHA, cacheKey, verifyResult, q)
|
||||
}, func(repoRoot, commitSHA, cacheKey string, ctxSrc operationContextSrc) (interface{}, error) {
|
||||
return s.runManifestGen(repoRoot, commitSHA, cacheKey, ctxSrc, q)
|
||||
}, operationSettings{sem: s.parallelismLimitSemaphore, noCache: q.NoCache, allowConcurrent: q.ApplicationSource.AllowsConcurrentProcessing()})
|
||||
result, ok := resultUncast.(*apiclient.ManifestResponse)
|
||||
if result != nil && !ok {
|
||||
@@ -289,8 +310,12 @@ func (s *Service) GenerateManifest(ctx context.Context, q *apiclient.ManifestReq
|
||||
// - or, the cache does contain a value for this key, but it is an expired manifest generation entry
|
||||
// - or, NoCache is true
|
||||
// Returns a ManifestResponse, or an error, but not both
|
||||
func (s *Service) runManifestGen(appPath, repoRoot, commitSHA, cacheKey, verifyResult string, q *apiclient.ManifestRequest) (interface{}, error) {
|
||||
manifestGenResult, err := GenerateManifests(appPath, repoRoot, commitSHA, q, false)
|
||||
func (s *Service) runManifestGen(repoRoot, commitSHA, cacheKey string, ctxSrc operationContextSrc, q *apiclient.ManifestRequest) (interface{}, error) {
|
||||
var manifestGenResult *apiclient.ManifestResponse
|
||||
ctx, err := ctxSrc()
|
||||
if err == nil {
|
||||
manifestGenResult, err = GenerateManifests(ctx.appPath, repoRoot, commitSHA, q, false)
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
// If manifest generation error caching is enabled
|
||||
@@ -332,7 +357,7 @@ func (s *Service) runManifestGen(appPath, repoRoot, commitSHA, cacheKey, verifyR
|
||||
MostRecentError: "",
|
||||
}
|
||||
manifestGenResult.Revision = commitSHA
|
||||
manifestGenResult.VerifyResult = verifyResult
|
||||
manifestGenResult.VerifyResult = ctx.verificationResult
|
||||
err = s.cache.SetManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppLabelValue, &manifestGenCacheEntry)
|
||||
if err != nil {
|
||||
log.Warnf("manifest cache set error %s/%s: %v", q.ApplicationSource.String(), cacheKey, err)
|
||||
@@ -742,7 +767,7 @@ func mergeSourceParameters(source *v1alpha1.ApplicationSource, path string) erro
|
||||
func GetAppSourceType(source *v1alpha1.ApplicationSource, path string) (v1alpha1.ApplicationSourceType, error) {
|
||||
err := mergeSourceParameters(source, path)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error while parsing .argocd-app.yaml: %v", err)
|
||||
return "", fmt.Errorf("error while parsing .argocd-source.yaml: %v", err)
|
||||
}
|
||||
|
||||
appSourceType, err := source.ExplicitType()
|
||||
@@ -837,23 +862,12 @@ func findManifests(appPath string, repoRoot string, env *v1alpha1.Env, directory
|
||||
return nil
|
||||
}
|
||||
|
||||
out, err := utfutil.ReadFile(path, utfutil.UTF8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(f.Name(), ".json") {
|
||||
var obj unstructured.Unstructured
|
||||
err = json.Unmarshal(out, &obj)
|
||||
if err != nil {
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
|
||||
}
|
||||
objs = append(objs, &obj)
|
||||
} else if strings.HasSuffix(f.Name(), ".jsonnet") {
|
||||
if strings.HasSuffix(f.Name(), ".jsonnet") {
|
||||
vm, err := makeJsonnetVm(appPath, repoRoot, directory.Jsonnet, env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
jsonStr, err := vm.EvaluateSnippet(path, string(out))
|
||||
jsonStr, err := vm.EvaluateFile(path)
|
||||
if err != nil {
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to evaluate jsonnet %q: %v", f.Name(), err)
|
||||
}
|
||||
@@ -872,24 +886,37 @@ func findManifests(appPath string, repoRoot string, env *v1alpha1.Env, directory
|
||||
objs = append(objs, &jsonObj)
|
||||
}
|
||||
} else {
|
||||
yamlObjs, err := kube.SplitYAML(out)
|
||||
out, err := utfutil.ReadFile(path, utfutil.UTF8)
|
||||
if err != nil {
|
||||
if len(yamlObjs) > 0 {
|
||||
// If we get here, we had a multiple objects in a single YAML file which had some
|
||||
// valid k8s objects, but errors parsing others (within the same file). It's very
|
||||
// likely the user messed up a portion of the YAML, so report on that.
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
|
||||
}
|
||||
// Otherwise, let's see if it looks like a resource, if yes, we return error
|
||||
if bytes.Contains(out, []byte("apiVersion:")) &&
|
||||
bytes.Contains(out, []byte("kind:")) &&
|
||||
bytes.Contains(out, []byte("metadata:")) {
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
|
||||
}
|
||||
// Otherwise, it might be a unrelated YAML file which we will ignore
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(f.Name(), ".json") {
|
||||
var obj unstructured.Unstructured
|
||||
err = json.Unmarshal(out, &obj)
|
||||
if err != nil {
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
|
||||
}
|
||||
objs = append(objs, &obj)
|
||||
} else {
|
||||
yamlObjs, err := kube.SplitYAML(out)
|
||||
if err != nil {
|
||||
if len(yamlObjs) > 0 {
|
||||
// If we get here, we had a multiple objects in a single YAML file which had some
|
||||
// valid k8s objects, but errors parsing others (within the same file). It's very
|
||||
// likely the user messed up a portion of the YAML, so report on that.
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
|
||||
}
|
||||
// Otherwise, let's see if it looks like a resource, if yes, we return error
|
||||
if bytes.Contains(out, []byte("apiVersion:")) &&
|
||||
bytes.Contains(out, []byte("kind:")) &&
|
||||
bytes.Contains(out, []byte("metadata:")) {
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
|
||||
}
|
||||
// Otherwise, it might be a unrelated YAML file which we will ignore
|
||||
return nil
|
||||
}
|
||||
objs = append(objs, yamlObjs...)
|
||||
}
|
||||
objs = append(objs, yamlObjs...)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -999,7 +1026,7 @@ func (s *Service) GetAppDetails(ctx context.Context, q *apiclient.RepoServerAppD
|
||||
|
||||
getCached := func(revision string, _ bool) (bool, interface{}, error) {
|
||||
res := &apiclient.RepoAppDetailsResponse{}
|
||||
err := s.cache.GetAppDetails(revision, q.Source, &res)
|
||||
err := s.cache.GetAppDetails(revision, q.Source, res)
|
||||
if err == nil {
|
||||
log.Infof("app details cache hit: %s/%s", revision, q.Source.Path)
|
||||
return true, res, nil
|
||||
@@ -1014,7 +1041,12 @@ func (s *Service) GetAppDetails(ctx context.Context, q *apiclient.RepoServerAppD
|
||||
|
||||
}
|
||||
|
||||
resultUncast, err := s.runRepoOperation(ctx, q.Source.TargetRevision, q.Repo, q.Source, false, getCached, func(appPath, repoRoot, commitSHA, revision, verifyResult string) (interface{}, error) {
|
||||
resultUncast, err := s.runRepoOperation(ctx, q.Source.TargetRevision, q.Repo, q.Source, false, getCached, func(repoRoot, commitSHA, revision string, ctxSrc operationContextSrc) (interface{}, error) {
|
||||
ctx, err := ctxSrc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appPath := ctx.appPath
|
||||
|
||||
res := &apiclient.RepoAppDetailsResponse{}
|
||||
appSourceType, err := GetAppSourceType(q.Source, appPath)
|
||||
@@ -1245,10 +1277,13 @@ func (s *Service) newClientResolveRevision(repo *v1alpha1.Repository, revision s
|
||||
}
|
||||
|
||||
func (s *Service) newHelmClientResolveRevision(repo *v1alpha1.Repository, revision string, chart string) (helm.Client, string, error) {
|
||||
helmClient := s.newHelmClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI)
|
||||
helmClient := s.newHelmClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI || helm.IsHelmOciChart(chart))
|
||||
if helm.IsVersion(revision) {
|
||||
return helmClient, revision, nil
|
||||
}
|
||||
if repo.EnableOCI {
|
||||
return nil, "", errors.New("OCI helm registers don't support semver ranges. Exact revision must be specified.")
|
||||
}
|
||||
constraints, err := semver.NewConstraint(revision)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("invalid revision '%s': %v", revision, err)
|
||||
|
||||
@@ -2,7 +2,19 @@ package reposerver
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"os"
|
||||
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
|
||||
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/health"
|
||||
"google.golang.org/grpc/health/grpc_health_v1"
|
||||
"google.golang.org/grpc/reflection"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
versionpkg "github.com/argoproj/argo-cd/pkg/apiclient/version"
|
||||
"github.com/argoproj/argo-cd/reposerver/apiclient"
|
||||
reposervercache "github.com/argoproj/argo-cd/reposerver/cache"
|
||||
@@ -11,14 +23,6 @@ import (
|
||||
"github.com/argoproj/argo-cd/server/version"
|
||||
grpc_util "github.com/argoproj/argo-cd/util/grpc"
|
||||
tlsutil "github.com/argoproj/argo-cd/util/tls"
|
||||
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
|
||||
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
// ArgoCDRepoServer is the repo server implementation
|
||||
@@ -49,7 +53,9 @@ func NewServer(metricsServer *metrics.MetricsServer, cache *reposervercache.Cach
|
||||
tlsConfig := &tls.Config{Certificates: []tls.Certificate{*cert}}
|
||||
tlsConfCustomizer(tlsConfig)
|
||||
|
||||
grpc_prometheus.EnableHandlingTimeHistogram()
|
||||
if os.Getenv(common.EnvEnableGRPCTimeHistogramEnv) == "true" {
|
||||
grpc_prometheus.EnableHandlingTimeHistogram()
|
||||
}
|
||||
|
||||
serverLog := log.NewEntry(log.StandardLogger())
|
||||
streamInterceptors := []grpc.StreamServerInterceptor{grpc_logrus.StreamServerInterceptor(serverLog), grpc_prometheus.StreamServerInterceptor, grpc_util.PanicLoggerStreamServerInterceptor(serverLog)}
|
||||
@@ -77,6 +83,9 @@ func (a *ArgoCDRepoServer) CreateGRPC() *grpc.Server {
|
||||
manifestService := repository.NewService(a.metricsServer, a.cache, a.initConstants)
|
||||
apiclient.RegisterRepoServerServiceServer(server, manifestService)
|
||||
|
||||
healthService := health.NewServer()
|
||||
grpc_health_v1.RegisterHealthServer(server, healthService)
|
||||
|
||||
// Register reflection service on gRPC server.
|
||||
reflection.Register(server)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ actions["retry"] = {["disabled"] = fullyPromoted or not(obj.status.abort)}
|
||||
actions["promote-full"] = {["disabled"] = true}
|
||||
if obj.status ~= nil and not(fullyPromoted) then
|
||||
generation = tonumber(obj.status.observedGeneration)
|
||||
if generation == nil then
|
||||
if generation == nil or generation > obj.metadata.generation then
|
||||
-- rollouts v0.9 - full promotion only supported for canary
|
||||
actions["promote-full"] = {["disabled"] = obj.spec.strategy.blueGreen ~= nil}
|
||||
else
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
if obj.status ~= nil then
|
||||
generation = tonumber(obj.status.observedGeneration)
|
||||
if generation == nil then
|
||||
if generation == nil or generation > obj.metadata.generation then
|
||||
-- rollouts v0.9 and below
|
||||
obj.status.abort = nil
|
||||
if obj.spec.strategy.canary.steps ~= nil then
|
||||
|
||||
@@ -51,15 +51,23 @@ function checkPaused(obj)
|
||||
return nil
|
||||
end
|
||||
|
||||
hs = {}
|
||||
if obj.status == nil or obj.status.observedGeneration == nil then
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for rollout spec update to be observed"
|
||||
return hs
|
||||
-- isGenerationObserved determines if the rollout spec has been observed by the controller. This
|
||||
-- only applies to v0.10 rollout which uses a numeric status.observedGeneration. For v0.9 rollouts
|
||||
-- and below this function always returns true.
|
||||
function isGenerationObserved(obj)
|
||||
if obj.status == nil then
|
||||
return false
|
||||
end
|
||||
observedGeneration = tonumber(obj.status.observedGeneration)
|
||||
if observedGeneration == nil or observedGeneration > obj.metadata.generation then
|
||||
-- if we get here, the rollout is a v0.9 rollout
|
||||
return true
|
||||
end
|
||||
return observedGeneration == obj.metadata.generation
|
||||
end
|
||||
|
||||
generation = tonumber(obj.status.observedGeneration)
|
||||
if generation ~= nil and generation ~= obj.metadata.generation then
|
||||
hs = {}
|
||||
if not isGenerationObserved(obj) then
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for rollout spec update to be observed"
|
||||
return hs
|
||||
|
||||
@@ -11,6 +11,10 @@ tests:
|
||||
status: Healthy
|
||||
message: ""
|
||||
inputPath: testdata/healthy_legacy_v0.9_observedGeneration.yaml
|
||||
- healthStatus:
|
||||
status: Healthy
|
||||
message: ""
|
||||
inputPath: testdata/healthy_legacy_v0.9_observedGeneration_numeric.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "The Rollout \"basic\" is invalid: spec.strategy.strategy: Required value: Rollout has missing field '.spec.strategy.canary or .spec.strategy.blueGreen'"
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Rollout
|
||||
metadata:
|
||||
creationTimestamp: "2020-11-13T00:44:55Z"
|
||||
generation: 1
|
||||
name: basic
|
||||
namespace: argocd-e2e
|
||||
resourceVersion: "182108"
|
||||
selfLink: /apis/argoproj.io/v1alpha1/namespaces/argocd-e2e/rollouts/basic
|
||||
uid: 34e4bbfc-222c-4968-bd60-2b30ae81110d
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: basic
|
||||
strategy:
|
||||
canary:
|
||||
steps:
|
||||
- setWeight: 50
|
||||
- pause: {}
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: basic
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:1.19-alpine
|
||||
name: basic
|
||||
resources:
|
||||
requests:
|
||||
cpu: 1m
|
||||
memory: 16Mi
|
||||
status:
|
||||
HPAReplicas: 1
|
||||
availableReplicas: 1
|
||||
blueGreen: {}
|
||||
canary: {}
|
||||
conditions:
|
||||
- lastTransitionTime: "2020-11-13T00:48:20Z"
|
||||
lastUpdateTime: "2020-11-13T00:48:22Z"
|
||||
message: ReplicaSet "basic-754cb84d5" has successfully progressed.
|
||||
reason: NewReplicaSetAvailable
|
||||
status: "True"
|
||||
type: Progressing
|
||||
- lastTransitionTime: "2020-11-13T00:48:22Z"
|
||||
lastUpdateTime: "2020-11-13T00:48:22Z"
|
||||
message: Rollout has minimum availability
|
||||
reason: AvailableReason
|
||||
status: "True"
|
||||
type: Available
|
||||
currentPodHash: 754cb84d5
|
||||
currentStepHash: 757f5f97b
|
||||
currentStepIndex: 2
|
||||
observedGeneration: "8575574967" ## <---- uses legacy observedGeneration hash which are numbers
|
||||
readyReplicas: 1
|
||||
replicas: 1
|
||||
selector: app=basic
|
||||
stableRS: 754cb84d5
|
||||
updatedReplicas: 1
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
@@ -89,7 +89,7 @@ func ssoAdminContext(ctx context.Context, iat time.Time) context.Context {
|
||||
return context.WithValue(ctx, "claims", &jwt.StandardClaims{
|
||||
Subject: "admin",
|
||||
Issuer: "https://myargocdhost.com/api/dex",
|
||||
IssuedAt: iat.Unix(),
|
||||
IssuedAt: jwt.At(iat),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -576,11 +576,12 @@ func (s *Server) Patch(ctx context.Context, q *application.ApplicationPatchReque
|
||||
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Patch type '%s' is not supported", q.PatchType))
|
||||
}
|
||||
|
||||
err = json.Unmarshal(patchApp, &app)
|
||||
newApp := &v1alpha1.Application{}
|
||||
err = json.Unmarshal(patchApp, newApp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.validateAndUpdateApp(ctx, app, false, true)
|
||||
return s.validateAndUpdateApp(ctx, newApp, false, true)
|
||||
}
|
||||
|
||||
// Delete removes an application and all associated resources
|
||||
@@ -747,12 +748,12 @@ func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Applica
|
||||
return err
|
||||
}
|
||||
|
||||
if err := argo.ValidateDestination(ctx, &app.Spec.Destination, s.db); err != nil {
|
||||
return status.Errorf(codes.InvalidArgument, "application destination spec is invalid: %s", err.Error())
|
||||
}
|
||||
|
||||
var conditions []appv1.ApplicationCondition
|
||||
if validate {
|
||||
if err := argo.ValidateDestination(ctx, &app.Spec.Destination, s.db); err != nil {
|
||||
return status.Errorf(codes.InvalidArgument, "application destination spec is invalid: %s", err.Error())
|
||||
}
|
||||
|
||||
conditions, err = argo.ValidateRepo(ctx, app, s.repoClientset, s.db, kustomizeOptions, plugins, s.kubectl)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1292,7 +1293,7 @@ func (s *Server) resolveRevision(ctx context.Context, app *appv1.Application, sy
|
||||
if helm.IsVersion(ambiguousRevision) {
|
||||
return ambiguousRevision, ambiguousRevision, nil
|
||||
}
|
||||
client := helm.NewClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI)
|
||||
client := helm.NewClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI || app.Spec.Source.IsHelmOci())
|
||||
index, err := client.GetIndex()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
synccommon "github.com/argoproj/gitops-engine/pkg/sync/common"
|
||||
"github.com/argoproj/gitops-engine/pkg/utils/kube/kubetest"
|
||||
"github.com/argoproj/pkg/sync"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
@@ -215,6 +215,26 @@ spec:
|
||||
name: fake-cluster
|
||||
`
|
||||
|
||||
const fakeAppWithAnnotations = `
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: test-app
|
||||
namespace: default
|
||||
annotations:
|
||||
test.annotation: test
|
||||
spec:
|
||||
source:
|
||||
path: some/path
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps.git
|
||||
targetRevision: HEAD
|
||||
ksonnet:
|
||||
environment: default
|
||||
destination:
|
||||
namespace: ` + test.FakeDestNamespace + `
|
||||
server: https://cluster-api.com
|
||||
`
|
||||
|
||||
func newTestAppWithDestName(opts ...func(app *appsv1.Application)) *appsv1.Application {
|
||||
return createTestApp(fakeAppWithDestName, opts...)
|
||||
}
|
||||
@@ -223,6 +243,10 @@ func newTestApp(opts ...func(app *appsv1.Application)) *appsv1.Application {
|
||||
return createTestApp(fakeApp, opts...)
|
||||
}
|
||||
|
||||
func newTestAppWithAnnotations(opts ...func(app *appsv1.Application)) *appsv1.Application {
|
||||
return createTestApp(fakeAppWithAnnotations, opts...)
|
||||
}
|
||||
|
||||
func createTestApp(testApp string, opts ...func(app *appsv1.Application)) *appsv1.Application {
|
||||
var app appsv1.Application
|
||||
err := yaml.Unmarshal([]byte(testApp), &app)
|
||||
@@ -499,7 +523,7 @@ p, admin, applications, update, my-proj/test-app, allow
|
||||
}
|
||||
|
||||
func TestAppJsonPatch(t *testing.T) {
|
||||
testApp := newTestApp()
|
||||
testApp := newTestAppWithAnnotations()
|
||||
ctx := context.Background()
|
||||
// nolint:staticcheck
|
||||
ctx = context.WithValue(ctx, "claims", &jwt.StandardClaims{Subject: "admin"})
|
||||
@@ -517,6 +541,10 @@ func TestAppJsonPatch(t *testing.T) {
|
||||
app, err = appServer.Patch(ctx, &application.ApplicationPatchRequest{Name: &testApp.Name, Patch: `[{"op": "replace", "path": "/spec/source/path", "value": "foo"}]`})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "foo", app.Spec.Source.Path)
|
||||
|
||||
app, err = appServer.Patch(ctx, &application.ApplicationPatchRequest{Name: &testApp.Name, Patch: `[{"op": "remove", "path": "/metadata/annotations/test.annotation"}]`})
|
||||
assert.NoError(t, err)
|
||||
assert.NotContains(t, app.Annotations, "test.annotation")
|
||||
}
|
||||
|
||||
func TestAppMergePatch(t *testing.T) {
|
||||
|
||||
97
server/logout/logout.go
Normal file
97
server/logout/logout.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package logout
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"github.com/argoproj/argo-cd/util/session"
|
||||
"github.com/argoproj/argo-cd/util/settings"
|
||||
|
||||
jwtutil "github.com/argoproj/argo-cd/util/jwt"
|
||||
)
|
||||
|
||||
//NewHandler creates handler serving to do api/logout endpoint
|
||||
func NewHandler(appClientset versioned.Interface, settingsMrg *settings.SettingsManager, sessionMgr *session.SessionManager, rootPath, namespace string) *Handler {
|
||||
return &Handler{
|
||||
appClientset: appClientset,
|
||||
namespace: namespace,
|
||||
settingsMgr: settingsMrg,
|
||||
rootPath: rootPath,
|
||||
verifyToken: sessionMgr.VerifyToken,
|
||||
}
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
namespace string
|
||||
appClientset versioned.Interface
|
||||
settingsMgr *settings.SettingsManager
|
||||
rootPath string
|
||||
verifyToken func(tokenString string) (jwt.Claims, error)
|
||||
}
|
||||
|
||||
var (
|
||||
tokenPattern = regexp.MustCompile(`{{token}}`)
|
||||
logoutRedirectURLPattern = regexp.MustCompile(`{{logoutRedirectURL}}`)
|
||||
)
|
||||
|
||||
func constructLogoutURL(logoutURL, token, logoutRedirectURL string) string {
|
||||
constructedLogoutURL := tokenPattern.ReplaceAllString(logoutURL, token)
|
||||
return logoutRedirectURLPattern.ReplaceAllString(constructedLogoutURL, logoutRedirectURL)
|
||||
}
|
||||
|
||||
// ServeHTTP is the logout handler for ArgoCD and constructs OIDC logout URL and redirects to it for OIDC issued sessions,
|
||||
// and redirects user to '/login' for argocd issued sessions
|
||||
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
var tokenString string
|
||||
var oidcConfig *settings.OIDCConfig
|
||||
|
||||
argoCDSettings, err := h.settingsMgr.GetSettings()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
http.Error(w, "Failed to retrieve argoCD settings: "+fmt.Sprintf("%s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
logoutRedirectURL := strings.TrimRight(strings.TrimLeft(argoCDSettings.URL, "/"), "/") + strings.TrimRight(strings.TrimLeft(h.rootPath, "/"), "/")
|
||||
|
||||
argocdCookie, err := r.Cookie(common.AuthCookieName)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
http.Error(w, "Failed to retrieve ArgoCD auth token: "+fmt.Sprintf("%s", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
tokenString = argocdCookie.Value
|
||||
|
||||
argocdCookie.Value = ""
|
||||
argocdCookie.Path = fmt.Sprintf("/%s", strings.TrimRight(strings.TrimLeft(h.rootPath, "/"), "/"))
|
||||
w.Header().Set("Set-Cookie", argocdCookie.String())
|
||||
|
||||
claims, err := h.verifyToken(tokenString)
|
||||
if err != nil {
|
||||
http.Redirect(w, r, logoutRedirectURL, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
mapClaims, err := jwtutil.MapClaims(claims)
|
||||
if err != nil {
|
||||
http.Redirect(w, r, logoutRedirectURL, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
issuer := jwtutil.GetField(mapClaims, "iss")
|
||||
|
||||
if argoCDSettings.OIDCConfig() == nil || argoCDSettings.OIDCConfig().LogoutURL == "" || issuer == session.SessionManagerClaimsIssuer {
|
||||
http.Redirect(w, r, logoutRedirectURL, http.StatusSeeOther)
|
||||
} else {
|
||||
oidcConfig = argoCDSettings.OIDCConfig()
|
||||
logoutURL := constructLogoutURL(oidcConfig.LogoutURL, tokenString, logoutRedirectURL)
|
||||
http.Redirect(w, r, logoutURL, http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
291
server/logout/logout_test.go
Normal file
291
server/logout/logout_test.go
Normal file
@@ -0,0 +1,291 @@
|
||||
package logout
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/util/session"
|
||||
"github.com/argoproj/argo-cd/util/settings"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned/fake"
|
||||
)
|
||||
|
||||
var (
|
||||
validJWTPattern = regexp.MustCompile(`[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+`)
|
||||
baseURL = "http://localhost:4000"
|
||||
baseLogoutURL = "http://localhost:4000/logout"
|
||||
baseLogoutURLwithToken = "http://localhost:4000/logout?id_token_hint={{token}}"
|
||||
baseLogoutURLwithRedirectURL = "http://localhost:4000/logout?post_logout_redirect_uri={{logoutRedirectURL}}"
|
||||
baseLogoutURLwithTokenAndRedirectURL = "http://localhost:4000/logout?id_token_hint={{token}}&post_logout_redirect_uri={{logoutRedirectURL}}"
|
||||
invalidToken = "sample-token"
|
||||
oidcToken = "eyJraWQiOiJYQi1MM3ZFdHhYWXJLcmRSQnVEV0NwdnZsSnk3SEJVb2d5N253M1U1Z1ZZIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIwMHVqNnM1NDVyNU5peVNLcjVkNSIsIm5hbWUiOiJqZCByIiwiZW1haWwiOiJqYWlkZWVwMTdydWx6QGdtYWlsLmNvbSIsInZlciI6MSwiaXNzIjoiaHR0cHM6Ly9kZXYtNTY5NTA5OC5va3RhLmNvbSIsImF1ZCI6IjBvYWowM2FmSEtqN3laWXJwNWQ1IiwiaWF0IjoxNjA1NTcyMzU5LCJleHAiOjE2MDU1NzU5NTksImp0aSI6IklELl9ORDJxVG5iREFtc3hIZUt2U2ZHeVBqTXRicXFEQXdkdlRQTDZCTnpfR3ciLCJhbXIiOlsicHdkIl0sImlkcCI6IjAwb2lnaGZmdkpRTDYzWjhoNWQ1IiwicHJlZmVycmVkX3VzZXJuYW1lIjoiamFpZGVlcDE3cnVsekBnbWFpbC5jb20iLCJhdXRoX3RpbWUiOjE2MDU1NzIzNTcsImF0X2hhc2giOiJqZVEwRml2ak9nNGI2TUpXRDIxOWxnIn0.GHkqwXgW-lrAhJdypW7SVjW0YdNLFQiRL8iwgT6DHJxP9Nb0OtkH2NKcBYAA5N6bTPLRQUHgYwWcgm5zSXmvqa7ciIgPF3tiQI8UmJA9VFRRDR-x9ExX15nskCbXfiQ67MriLslUrQUyzSCfUrSjXKwnDxbKGQncrtmRsh5asfCzJFb9excn311W9HKbT3KA0Ot7eOMnVS6V7SGfXxnKs6szcXIEMa_FhB4zDAVLr-dnxvSG_uuWcHrAkLTUVhHbdQQXF7hXIEfyr5lkMJN-drjdz-bn40GaYulEmUvO1bjcL9toCVQ3Ismypyr0b8phj4w3uRsLDZQxTxK7jAXlyQ"
|
||||
nonOidcToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2MDU1NzQyMTIsImlzcyI6ImFyZ29jZCIsIm5iZiI6MTYwNTU3NDIxMiwic3ViIjoiYWRtaW4ifQ.zDJ4piwWnwsHON-oPusHMXWINlnrRDTQykYogT7afeE"
|
||||
expectedNonOIDCLogoutURL = "http://localhost:4000"
|
||||
expectedOIDCLogoutURL = "https://dev-5695098.okta.com/oauth2/v1/logout?id_token_hint=" + oidcToken + "&post_logout_redirect_uri=" + baseURL
|
||||
)
|
||||
|
||||
func TestConstructLogoutURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
logoutURL string
|
||||
token string
|
||||
logoutRedirectURL string
|
||||
expectedLogoutURL string
|
||||
}{
|
||||
{
|
||||
name: "Case: No additional parameters passed to logout URL",
|
||||
logoutURL: baseLogoutURL,
|
||||
token: oidcToken,
|
||||
logoutRedirectURL: baseURL,
|
||||
expectedLogoutURL: baseLogoutURL,
|
||||
},
|
||||
{
|
||||
name: "Case: ID token passed to logout URL",
|
||||
logoutURL: baseLogoutURLwithToken,
|
||||
token: oidcToken,
|
||||
logoutRedirectURL: baseURL,
|
||||
expectedLogoutURL: "http://localhost:4000/logout?id_token_hint=" + oidcToken,
|
||||
},
|
||||
{
|
||||
name: "Case: Redirect required",
|
||||
logoutURL: baseLogoutURLwithRedirectURL,
|
||||
token: oidcToken,
|
||||
logoutRedirectURL: baseURL,
|
||||
expectedLogoutURL: "http://localhost:4000/logout?post_logout_redirect_uri=" + baseURL,
|
||||
},
|
||||
{
|
||||
name: "Case: ID token and redirect URL passed to logout URL",
|
||||
logoutURL: baseLogoutURLwithTokenAndRedirectURL,
|
||||
token: oidcToken,
|
||||
logoutRedirectURL: baseURL,
|
||||
expectedLogoutURL: "http://localhost:4000/logout?id_token_hint=" + oidcToken + "&post_logout_redirect_uri=" + baseURL,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
constructedLogoutURL := constructLogoutURL(tt.logoutURL, tt.token, tt.logoutRedirectURL)
|
||||
assert.Equal(t, constructedLogoutURL, tt.expectedLogoutURL)
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestHandlerConstructLogoutURL(t *testing.T) {
|
||||
kubeClientWithOIDCConfig := fake.NewSimpleClientset(
|
||||
&corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: common.ArgoCDConfigMapName,
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "argocd",
|
||||
},
|
||||
},
|
||||
Data: map[string]string{
|
||||
"oidc.config": "name: Okta \n" +
|
||||
"issuer: https://dev-5695098.okta.com \n" +
|
||||
"requestedScopes: [\"openid\", \"profile\", \"email\", \"groups\"] \n" +
|
||||
"requestedIDTokenClaims: {\"groups\": {\"essential\": true}} \n" +
|
||||
"logoutURL: https://dev-5695098.okta.com/oauth2/v1/logout?id_token_hint={{token}}&post_logout_redirect_uri={{logoutRedirectURL}}",
|
||||
"url": "http://localhost:4000",
|
||||
},
|
||||
},
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: common.ArgoCDSecretName,
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "argocd",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"admin.password": nil,
|
||||
"server.secretkey": nil,
|
||||
},
|
||||
},
|
||||
)
|
||||
kubeClientWithOIDCConfigButNoLogoutURL := fake.NewSimpleClientset(
|
||||
&corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: common.ArgoCDConfigMapName,
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "argocd",
|
||||
},
|
||||
},
|
||||
Data: map[string]string{
|
||||
"oidc.config": "name: Okta \n" +
|
||||
"issuer: https://dev-5695098.okta.com \n" +
|
||||
"requestedScopes: [\"openid\", \"profile\", \"email\", \"groups\"] \n" +
|
||||
"requestedIDTokenClaims: {\"groups\": {\"essential\": true}} \n",
|
||||
"url": "http://localhost:4000",
|
||||
},
|
||||
},
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: common.ArgoCDSecretName,
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "argocd",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"admin.password": nil,
|
||||
"server.secretkey": nil,
|
||||
},
|
||||
},
|
||||
)
|
||||
kubeClientWithoutOIDCConfig := fake.NewSimpleClientset(
|
||||
&corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: common.ArgoCDConfigMapName,
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "argocd",
|
||||
},
|
||||
},
|
||||
Data: map[string]string{
|
||||
"url": "http://localhost:4000",
|
||||
},
|
||||
},
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: common.ArgoCDSecretName,
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "argocd",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"admin.password": nil,
|
||||
"server.secretkey": nil,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
settingsManagerWithOIDCConfig := settings.NewSettingsManager(context.Background(), kubeClientWithOIDCConfig, "default")
|
||||
settingsManagerWithoutOIDCConfig := settings.NewSettingsManager(context.Background(), kubeClientWithoutOIDCConfig, "default")
|
||||
settingsManagerWithOIDCConfigButNoLogoutURL := settings.NewSettingsManager(context.Background(), kubeClientWithOIDCConfigButNoLogoutURL, "default")
|
||||
|
||||
sessionManager := session.NewSessionManager(settingsManagerWithOIDCConfig, "", session.NewInMemoryUserStateStorage())
|
||||
|
||||
oidcHandler := NewHandler(appclientset.NewSimpleClientset(), settingsManagerWithOIDCConfig, sessionManager, "", "default")
|
||||
oidcHandler.verifyToken = func(tokenString string) (jwt.Claims, error) {
|
||||
if !validJWTPattern.MatchString(tokenString) {
|
||||
return nil, errors.New("invalid jwt")
|
||||
}
|
||||
return &jwt.StandardClaims{Issuer: "okta"}, nil
|
||||
}
|
||||
nonoidcHandler := NewHandler(appclientset.NewSimpleClientset(), settingsManagerWithoutOIDCConfig, sessionManager, "", "default")
|
||||
nonoidcHandler.verifyToken = func(tokenString string) (jwt.Claims, error) {
|
||||
if !validJWTPattern.MatchString(tokenString) {
|
||||
return nil, errors.New("invalid jwt")
|
||||
}
|
||||
return &jwt.StandardClaims{Issuer: session.SessionManagerClaimsIssuer}, nil
|
||||
}
|
||||
oidcHandlerWithoutLogoutURL := NewHandler(appclientset.NewSimpleClientset(), settingsManagerWithOIDCConfigButNoLogoutURL, sessionManager, "", "default")
|
||||
oidcHandlerWithoutLogoutURL.verifyToken = func(tokenString string) (jwt.Claims, error) {
|
||||
if !validJWTPattern.MatchString(tokenString) {
|
||||
return nil, errors.New("invalid jwt")
|
||||
}
|
||||
return &jwt.StandardClaims{Issuer: "okta"}, nil
|
||||
}
|
||||
|
||||
oidcTokenHeader := make(map[string][]string)
|
||||
oidcTokenHeader["Cookie"] = []string{"argocd.token=" + oidcToken}
|
||||
nonOidcTokenHeader := make(map[string][]string)
|
||||
nonOidcTokenHeader["Cookie"] = []string{"argocd.token=" + nonOidcToken}
|
||||
invalidHeader := make(map[string][]string)
|
||||
invalidHeader["Cookie"] = []string{"argocd.token=" + invalidToken}
|
||||
|
||||
oidcRequest, err := http.NewRequest("GET", "http://localhost:4000/api/logout", nil)
|
||||
assert.NoError(t, err)
|
||||
oidcRequest.Header = oidcTokenHeader
|
||||
nonoidcRequest, err := http.NewRequest("GET", "http://localhost:4000/api/logout", nil)
|
||||
assert.NoError(t, err)
|
||||
nonoidcRequest.Header = nonOidcTokenHeader
|
||||
assert.NoError(t, err)
|
||||
requestWithInvalidToken, err := http.NewRequest("GET", "http://localhost:4000/api/logout", nil)
|
||||
assert.NoError(t, err)
|
||||
requestWithInvalidToken.Header = invalidHeader
|
||||
invalidRequest, err := http.NewRequest("GET", "http://localhost:4000/api/logout", nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
kubeClient *fake.Clientset
|
||||
handler http.Handler
|
||||
request *http.Request
|
||||
responseRecorder *httptest.ResponseRecorder
|
||||
expectedLogoutURL string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Case: OIDC logout request with valid token",
|
||||
handler: oidcHandler,
|
||||
request: oidcRequest,
|
||||
responseRecorder: httptest.NewRecorder(),
|
||||
expectedLogoutURL: expectedOIDCLogoutURL,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Case: non-OIDC logout request with valid token",
|
||||
handler: nonoidcHandler,
|
||||
request: nonoidcRequest,
|
||||
responseRecorder: httptest.NewRecorder(),
|
||||
expectedLogoutURL: expectedNonOIDCLogoutURL,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Case: Logout request with invalid token",
|
||||
handler: nonoidcHandler,
|
||||
request: requestWithInvalidToken,
|
||||
responseRecorder: httptest.NewRecorder(),
|
||||
expectedLogoutURL: expectedNonOIDCLogoutURL,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Case: Logout request with missing token",
|
||||
handler: oidcHandler,
|
||||
request: invalidRequest,
|
||||
responseRecorder: httptest.NewRecorder(),
|
||||
expectedLogoutURL: expectedNonOIDCLogoutURL,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Case:OIDC Logout request with missing logout URL configuration in config map",
|
||||
handler: oidcHandlerWithoutLogoutURL,
|
||||
request: oidcRequest,
|
||||
responseRecorder: httptest.NewRecorder(),
|
||||
expectedLogoutURL: expectedNonOIDCLogoutURL,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.handler.ServeHTTP(tt.responseRecorder, tt.request)
|
||||
if status := tt.responseRecorder.Code; status != http.StatusSeeOther {
|
||||
if !tt.wantErr {
|
||||
t.Errorf(tt.responseRecorder.Body.String())
|
||||
t.Errorf("handler returned wrong status code: " + fmt.Sprintf("%d", tt.responseRecorder.Code))
|
||||
}
|
||||
} else {
|
||||
if tt.wantErr {
|
||||
t.Errorf("expected error but did not get one")
|
||||
} else {
|
||||
assert.Equal(t, tt.expectedLogoutURL, tt.responseRecorder.Result().Header["Location"][0])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/argoproj/pkg/sync"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
@@ -108,16 +108,21 @@ func (s *Server) CreateToken(ctx context.Context, q *project.ProjectTokenCreateR
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
parser := &jwt.Parser{
|
||||
SkipClaimsValidation: true,
|
||||
ValidationHelper: jwt.NewValidationHelper(jwt.WithoutClaimsValidation()),
|
||||
}
|
||||
claims := jwt.StandardClaims{}
|
||||
_, _, err = parser.ParseUnverified(jwtToken, &claims)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
issuedAt := claims.IssuedAt
|
||||
expiresAt := claims.ExpiresAt
|
||||
id = claims.Id
|
||||
var issuedAt, expiresAt int64
|
||||
if claims.IssuedAt != nil {
|
||||
issuedAt = claims.IssuedAt.Unix()
|
||||
}
|
||||
if claims.ExpiresAt != nil {
|
||||
expiresAt = claims.ExpiresAt.Unix()
|
||||
}
|
||||
id = claims.ID
|
||||
|
||||
items := append(prj.Status.JWTTokensByRole[q.Role].Items, v1alpha1.JWTToken{IssuedAt: issuedAt, ExpiresAt: expiresAt, ID: id})
|
||||
if _, found := prj.Status.JWTTokensByRole[q.Role]; found {
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
k8scache "k8s.io/client-go/tools/cache"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/pkg/apiclient/project"
|
||||
|
||||
@@ -3,7 +3,7 @@ package rbacpolicy
|
||||
import (
|
||||
"strings"
|
||||
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
jwt "github.com/dgrijalva/jwt-go/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
jwt "github.com/dgrijalva/jwt-go/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
@@ -65,6 +65,9 @@ func (s *Server) ListRepositoryCredentials(ctx context.Context, q *repocredspkg.
|
||||
|
||||
// CreateRepositoryCredentials creates a new credential set in the configuration
|
||||
func (s *Server) CreateRepositoryCredentials(ctx context.Context, q *repocredspkg.RepoCredsCreateRequest) (*appsv1.RepoCreds, error) {
|
||||
if q.Creds == nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "missing payload in request")
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceRepositories, rbacpolicy.ActionCreate, q.Creds.URL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -96,6 +99,9 @@ func (s *Server) CreateRepositoryCredentials(ctx context.Context, q *repocredspk
|
||||
|
||||
// UpdateRepositoryCredentials updates a repository credential set
|
||||
func (s *Server) UpdateRepositoryCredentials(ctx context.Context, q *repocredspkg.RepoCredsUpdateRequest) (*appsv1.RepoCreds, error) {
|
||||
if q.Creds == nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "missing payload in request")
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceRepositories, rbacpolicy.ActionUpdate, q.Creds.URL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -205,6 +205,9 @@ func (s *Server) ListApps(ctx context.Context, q *repositorypkg.RepoAppsQuery) (
|
||||
}
|
||||
|
||||
func (s *Server) GetAppDetails(ctx context.Context, q *repositorypkg.RepoAppDetailsQuery) (*apiclient.RepoAppDetailsResponse, error) {
|
||||
if q.Source == nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "missing payload in request")
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceRepositories, rbacpolicy.ActionGet, q.Source.RepoURL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -262,6 +265,9 @@ func (s *Server) Create(ctx context.Context, q *repositorypkg.RepoCreateRequest)
|
||||
|
||||
// CreateRepository creates a repository configuration
|
||||
func (s *Server) CreateRepository(ctx context.Context, q *repositorypkg.RepoCreateRequest) (*appsv1.Repository, error) {
|
||||
if q.Repo == nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "missing payload in request")
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceRepositories, rbacpolicy.ActionCreate, q.Repo.Repo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -320,6 +326,9 @@ func (s *Server) Update(ctx context.Context, q *repositorypkg.RepoUpdateRequest)
|
||||
|
||||
// UpdateRepository updates a repository configuration
|
||||
func (s *Server) UpdateRepository(ctx context.Context, q *repositorypkg.RepoUpdateRequest) (*appsv1.Repository, error) {
|
||||
if q.Repo == nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "missing payload in request")
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceRepositories, rbacpolicy.ActionUpdate, q.Repo.Repo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
"github.com/argoproj/pkg/jwt/zjwt"
|
||||
"github.com/argoproj/pkg/sync"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/gorilla/handlers"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
@@ -73,6 +73,7 @@ import (
|
||||
"github.com/argoproj/argo-cd/server/certificate"
|
||||
"github.com/argoproj/argo-cd/server/cluster"
|
||||
"github.com/argoproj/argo-cd/server/gpgkey"
|
||||
"github.com/argoproj/argo-cd/server/logout"
|
||||
"github.com/argoproj/argo-cd/server/metrics"
|
||||
"github.com/argoproj/argo-cd/server/project"
|
||||
"github.com/argoproj/argo-cd/server/rbacpolicy"
|
||||
@@ -104,7 +105,6 @@ import (
|
||||
|
||||
const maxConcurrentLoginRequestsCountEnv = "ARGOCD_MAX_CONCURRENT_LOGIN_REQUESTS_COUNT"
|
||||
const replicasCountEnv = "ARGOCD_API_SERVER_REPLICAS"
|
||||
const enableGRPCTimeHistogramEnv = "ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM"
|
||||
|
||||
// ErrNoSession indicates no auth token was supplied as part of a request
|
||||
var ErrNoSession = status.Errorf(codes.Unauthenticated, "no session information")
|
||||
@@ -138,7 +138,7 @@ func init() {
|
||||
if replicasCount > 0 {
|
||||
maxConcurrentLoginRequestsCount = maxConcurrentLoginRequestsCount / replicasCount
|
||||
}
|
||||
enableGRPCTimeHistogram = os.Getenv(enableGRPCTimeHistogramEnv) != "false"
|
||||
enableGRPCTimeHistogram = os.Getenv(common.EnvEnableGRPCTimeHistogramEnv) == "true"
|
||||
}
|
||||
|
||||
// ArgoCDServer is the API server for Argo CD
|
||||
@@ -241,6 +241,22 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer {
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// catches corrupted informer state; see https://github.com/argoproj/argo-cd/issues/4960 for more information
|
||||
notObjectErrMsg = "object does not implement the Object interfaces"
|
||||
)
|
||||
|
||||
func (a *ArgoCDServer) healthCheck(r *http.Request) error {
|
||||
if val, ok := r.URL.Query()["full"]; ok && len(val) > 0 && val[0] == "true" {
|
||||
argoDB := db.NewDB(a.Namespace, a.settingsMgr, a.KubeClientset)
|
||||
_, err := argoDB.ListClusters(r.Context())
|
||||
if err != nil && strings.Contains(err.Error(), notObjectErrMsg) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run runs the API Server
|
||||
// We use k8s.io/code-generator/cmd/go-to-protobuf to generate the .proto files from the API types.
|
||||
// k8s.io/ go-to-protobuf uses protoc-gen-gogo, which comes from gogo/protobuf (a fork of
|
||||
@@ -596,9 +612,7 @@ func withRootPath(handler http.Handler, a *ArgoCDServer) http.Handler {
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/"+root+"/", http.StripPrefix("/"+root, handler))
|
||||
|
||||
healthz.ServeHealthCheck(mux, func() error {
|
||||
return nil
|
||||
})
|
||||
healthz.ServeHealthCheck(mux, a.healthCheck)
|
||||
|
||||
return mux
|
||||
}
|
||||
@@ -624,7 +638,8 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
|
||||
Handler: &handlerSwitcher{
|
||||
handler: mux,
|
||||
urlToHandler: map[string]http.Handler{
|
||||
"/api/badge": badge.NewHandler(a.AppClientset, a.settingsMgr, a.Namespace),
|
||||
"/api/badge": badge.NewHandler(a.AppClientset, a.settingsMgr, a.Namespace),
|
||||
common.LogoutEndpoint: logout.NewHandler(a.AppClientset, a.settingsMgr, a.sessionMgr, a.ArgoCDServerOpts.RootPath, a.Namespace),
|
||||
},
|
||||
contentTypeToHandler: map[string]http.Handler{
|
||||
"application/grpc-web+proto": grpcWebHandler,
|
||||
@@ -680,9 +695,7 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
|
||||
|
||||
// Swagger UI
|
||||
swagger.ServeSwaggerUI(mux, assets.SwaggerJSON, "/swagger-ui", a.RootPath)
|
||||
healthz.ServeHealthCheck(mux, func() error {
|
||||
return nil
|
||||
})
|
||||
healthz.ServeHealthCheck(mux, a.healthCheck)
|
||||
|
||||
// Dex reverse proxy and client app and OAuth2 login/callback
|
||||
a.registerDexHandlers(mux)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
controller: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-application-controller/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
|
||||
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=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --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 "test $ARGOCD_IN_CI = true && exit 0; go run github.com/argoproj/argo-cd/cmd/argocd-util 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.25.0 serve /dex.yaml"
|
||||
dex: sh -c "test $ARGOCD_IN_CI = true && exit 0; go run github.com/argoproj/argo-cd/cmd/argocd-util 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 ghcr.io/dexidp/dex:v2.27.0 serve /dex.yaml"
|
||||
redis: sh -c "/usr/local/bin/redis-server --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}"
|
||||
repo-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} 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 "test $ARGOCD_IN_CI = true && exit 0; cd ui && ARGOCD_E2E_YARN_HOST=0.0.0.0 ${ARGOCD_E2E_YARN_CMD:-yarn} start"
|
||||
|
||||
@@ -1370,10 +1370,11 @@ func TestNamespaceAutoCreation(t *testing.T) {
|
||||
|
||||
func TestFailedSyncWithRetry(t *testing.T) {
|
||||
Given(t).
|
||||
Path(guestbookPath).
|
||||
Path("hook").
|
||||
When().
|
||||
// app should be attempted to auto-synced once and marked with error after failed attempt detected
|
||||
PatchFile("guestbook-ui-deployment.yaml", `[{"op": "replace", "path": "/spec/revisionHistoryLimit", "value": "badValue"}]`).
|
||||
PatchFile("hook.yaml", `[{"op": "replace", "path": "/metadata/annotations", "value": {"argocd.argoproj.io/hook": "PreSync"}}]`).
|
||||
// make hook fail
|
||||
PatchFile("hook.yaml", `[{"op": "replace", "path": "/spec/containers/0/command", "value": ["false"]}]`).
|
||||
Create().
|
||||
IgnoreErrors().
|
||||
Sync("--retry-limit=1", "--retry-backoff-duration=1s").
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {AutocompleteField, DropDownMenu, FormField, FormSelect, HelpIcon, PopupApi} from 'argo-ui';
|
||||
import * as React from 'react';
|
||||
import {FormApi, Text} from 'react-form';
|
||||
import {Cluster, DataLoader, EditablePanel, EditablePanelItem, Expandable, MapInputField, Repo, Revision, RevisionHelpIcon} from '../../../shared/components';
|
||||
import {Cluster, DataLoader, EditablePanel, EditablePanelItem, Expandable, MapInputField, NumberField, Repo, Revision, RevisionHelpIcon} from '../../../shared/components';
|
||||
import {BadgePanel, Spinner} from '../../../shared/components';
|
||||
import {Consumer} from '../../../shared/context';
|
||||
import * as models from '../../../shared/models';
|
||||
@@ -202,7 +202,7 @@ export const ApplicationSummary = (props: {app: models.Application; updateApp: (
|
||||
view: app.spec.revisionHistoryLimit,
|
||||
edit: (formApi: FormApi) => (
|
||||
<div style={{position: 'relative'}}>
|
||||
<FormField formApi={formApi} field='spec.revisionHistoryLimit' component={Text} />
|
||||
<FormField formApi={formApi} field='spec.revisionHistoryLimit' componentProps={{style: {paddingRight: '1em'}, placeholder: '10'}} component={NumberField} />
|
||||
<div style={{position: 'absolute', right: '0', top: '0'}}>
|
||||
<HelpIcon
|
||||
title='This limits this number of items kept in the apps revision history.
|
||||
|
||||
@@ -23,3 +23,4 @@ export * from './revision';
|
||||
export * from './timestamp';
|
||||
export * from './spinner';
|
||||
export * from './badge-panel/badge-panel';
|
||||
export * from './number-field';
|
||||
|
||||
11
ui/src/app/shared/components/number-field.tsx
Normal file
11
ui/src/app/shared/components/number-field.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import * as ReactForm from 'react-form';
|
||||
|
||||
export const NumberField = ReactForm.FormField((props: {fieldApi: ReactForm.FieldApi; className: string}) => {
|
||||
const {
|
||||
fieldApi: {getValue, setValue},
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
return <input {...rest} className={props.className} type='number' value={getValue()} onChange={el => setValue(parseInt(el.target.value, 10))} />;
|
||||
});
|
||||
@@ -4,7 +4,7 @@ import * as React from 'react';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {AppContext} from '../context';
|
||||
import {services} from '../services';
|
||||
|
||||
import requests from '../services/requests';
|
||||
const mostRecentLoggedIn = new BehaviorSubject<boolean>(false);
|
||||
|
||||
function isLoggedIn(): Observable<boolean> {
|
||||
@@ -51,9 +51,10 @@ export class Page extends React.Component<{title: string; toolbar?: Toolbar | Ob
|
||||
|
||||
private async goToLogin(logout = false) {
|
||||
if (logout) {
|
||||
await services.users.logout();
|
||||
window.location.href = requests.toAbsURL('/auth/logout');
|
||||
} else {
|
||||
this.appContext.history.push('/login');
|
||||
}
|
||||
this.appContext.history.push('/login');
|
||||
}
|
||||
|
||||
private get appContext(): AppContext {
|
||||
|
||||
@@ -22,7 +22,7 @@ export class ClustersService {
|
||||
public update(cluster: models.Cluster, ...paths: string[]): Promise<models.Cluster> {
|
||||
return requests
|
||||
.put(`/clusters/${encodeURIComponent(cluster.server)}`)
|
||||
.query({updatedPaths: paths})
|
||||
.query({updatedFields: paths})
|
||||
.send(cluster)
|
||||
.then(res => res.body as models.Cluster);
|
||||
}
|
||||
|
||||
@@ -131,12 +131,8 @@ func TestRepoWithKnownType(repo *argoappv1.Repository, isHelm bool, isHelmOci bo
|
||||
} else {
|
||||
repo.Type = "git"
|
||||
}
|
||||
repo.EnableOCI = repo.EnableOCI || isHelmOci
|
||||
|
||||
if isHelmOci {
|
||||
repo.EnableOCI = true
|
||||
} else {
|
||||
repo.EnableOCI = false
|
||||
}
|
||||
return TestRepo(repo)
|
||||
}
|
||||
|
||||
|
||||
6
util/cache/cache.go
vendored
6
util/cache/cache.go
vendored
@@ -79,13 +79,13 @@ type Cache struct {
|
||||
}
|
||||
|
||||
func (c *Cache) SetItem(key string, item interface{}, expiration time.Duration, delete bool) error {
|
||||
if item == nil {
|
||||
return fmt.Errorf("cannot set item to nil for key %s", key)
|
||||
}
|
||||
key = fmt.Sprintf("%s|%s", key, common.CacheVersion)
|
||||
if delete {
|
||||
return c.client.Delete(key)
|
||||
} else {
|
||||
if item == nil {
|
||||
return fmt.Errorf("cannot set item to nil for key %s", key)
|
||||
}
|
||||
return c.client.Set(&Item{Object: item, Key: key, Expiration: expiration})
|
||||
}
|
||||
}
|
||||
|
||||
19
util/cache/redis.go
vendored
19
util/cache/redis.go
vendored
@@ -2,6 +2,7 @@ package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
ioutil "github.com/argoproj/argo-cd/util/io"
|
||||
@@ -30,20 +31,28 @@ func (r *redisCache) Set(item *Item) error {
|
||||
expiration = r.expiration
|
||||
}
|
||||
|
||||
val, err := json.Marshal(item.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.cache.Set(&rediscache.Item{
|
||||
Key: item.Key,
|
||||
Value: item.Object,
|
||||
Value: val,
|
||||
TTL: expiration,
|
||||
})
|
||||
}
|
||||
|
||||
func (r *redisCache) Get(key string, obj interface{}) error {
|
||||
err := r.cache.Get(context.TODO(), key, obj)
|
||||
|
||||
var data []byte
|
||||
err := r.cache.Get(context.TODO(), key, &data)
|
||||
if err == rediscache.ErrCacheMiss {
|
||||
return ErrCacheMiss
|
||||
err = ErrCacheMiss
|
||||
}
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, obj)
|
||||
}
|
||||
|
||||
func (r *redisCache) Delete(key string) error {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
jwt "github.com/dgrijalva/jwt-go/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
@@ -296,14 +296,14 @@ type ServiceAccountClaims struct {
|
||||
}
|
||||
|
||||
// Valid satisfies the jwt.Claims interface to enable JWT parsing
|
||||
func (sac *ServiceAccountClaims) Valid() error {
|
||||
func (sac *ServiceAccountClaims) Valid(helper *jwt.ValidationHelper) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseServiceAccountToken parses a Kubernetes service account token
|
||||
func ParseServiceAccountToken(token string) (*ServiceAccountClaims, error) {
|
||||
parser := &jwt.Parser{
|
||||
SkipClaimsValidation: true,
|
||||
ValidationHelper: jwt.NewValidationHelper(jwt.WithoutClaimsValidation()),
|
||||
}
|
||||
var claims ServiceAccountClaims
|
||||
_, _, err := parser.ParseUnverified(token, &claims)
|
||||
|
||||
@@ -53,6 +53,7 @@ func GenerateDexConfigYAML(settings *settings.ArgoCDSettings) ([]byte, error) {
|
||||
"public": true,
|
||||
"redirectURIs": []string{
|
||||
"http://localhost",
|
||||
"http://localhost:8085/auth/callback",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
|
||||
// ServeHealthCheck serves the health check endpoint.
|
||||
// ServeHealthCheck relies on the provided function to return an error if unhealthy and nil otherwise.
|
||||
func ServeHealthCheck(mux *http.ServeMux, f func() error) {
|
||||
func ServeHealthCheck(mux *http.ServeMux, f func(r *http.Request) error) {
|
||||
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := f(); err != nil {
|
||||
if err := f(r); err != nil {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
log.Errorln(w, err)
|
||||
} else {
|
||||
|
||||
@@ -21,7 +21,7 @@ func TestHealthCheck(t *testing.T) {
|
||||
c <- listener.Addr().String()
|
||||
|
||||
mux := http.NewServeMux()
|
||||
ServeHealthCheck(mux, func() error {
|
||||
ServeHealthCheck(mux, func(r *http.Request) error {
|
||||
if sentinel {
|
||||
return fmt.Errorf("This is a dummy error")
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ func (c *nativeHelmChart) ensureHelmChartRepoPath() error {
|
||||
}
|
||||
|
||||
func (c *nativeHelmChart) CleanChartCache(chart string, version *semver.Version) error {
|
||||
return os.RemoveAll(c.getChartPath(chart, version))
|
||||
return os.RemoveAll(c.getCachedChartPath(chart, version))
|
||||
}
|
||||
|
||||
func (c *nativeHelmChart) ExtractChart(chart string, version *semver.Version) (string, io.Closer, error) {
|
||||
@@ -98,77 +98,99 @@ func (c *nativeHelmChart) ExtractChart(chart string, version *semver.Version) (s
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
chartPath := c.getChartPath(chart, version)
|
||||
|
||||
c.repoLock.Lock(chartPath)
|
||||
defer c.repoLock.Unlock(chartPath)
|
||||
// always use Helm V3 since we don't have chart content to determine correct Helm version
|
||||
helmCmd, err := NewCmdWithVersion(c.repoPath, HelmV3, c.enableOci)
|
||||
|
||||
exists, err := fileExist(chartPath)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer helmCmd.Close()
|
||||
|
||||
_, err = helmCmd.Init()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// throw away temp directory that stores extracted chart and should be deleted as soon as no longer needed by returned closer
|
||||
tempDir, err := ioutil.TempDir("", "helm")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
cachedChartPath := c.getCachedChartPath(chart, version)
|
||||
|
||||
c.repoLock.Lock(cachedChartPath)
|
||||
defer c.repoLock.Unlock(cachedChartPath)
|
||||
|
||||
// check if chart tar is already downloaded
|
||||
exists, err := fileExist(cachedChartPath)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
// always use Helm V3 since we don't have chart content to determine correct Helm version
|
||||
helmCmd, err := NewCmdWithVersion(c.repoPath, HelmV3, c.enableOci)
|
||||
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer helmCmd.Close()
|
||||
|
||||
_, err = helmCmd.Init()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if c.enableOci {
|
||||
_, err = helmCmd.Login(c.repoURL, c.creds)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer func() {
|
||||
_, _ = helmCmd.Logout(c.repoURL, c.creds)
|
||||
}()
|
||||
}
|
||||
|
||||
// (1) because `helm fetch` downloads an arbitrary file name, we download to an empty temp directory
|
||||
// create empty temp directory to extract chart from the registry
|
||||
tempDest, err := ioutil.TempDir("", "helm")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer func() { _ = os.RemoveAll(tempDest) }()
|
||||
_, err = helmCmd.Fetch(c.repoURL, chart, version.String(), tempDest, c.creds)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if c.enableOci {
|
||||
_, err = helmCmd.Export(c.repoURL, chart, version.String(), tempDest)
|
||||
if c.creds.Password != "" && c.creds.Username != "" {
|
||||
_, err = helmCmd.Login(c.repoURL, c.creds)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_, _ = helmCmd.Logout(c.repoURL, c.creds)
|
||||
}()
|
||||
}
|
||||
|
||||
// 'helm chart pull' ensures that chart is downloaded into local repository cache
|
||||
_, err = helmCmd.ChartPull(c.repoURL, chart, version.String())
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// 'helm chart export' copies cached chart into temp directory
|
||||
_, err = helmCmd.ChartExport(c.repoURL, chart, version.String(), tempDest)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// use downloaded chart content to produce tar file in expected cache location
|
||||
cmd := exec.Command("tar", "-zcvf", cachedChartPath, normalizeChartName(chart))
|
||||
cmd.Dir = tempDest
|
||||
_, err = executil.Run(cmd)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
} else {
|
||||
_, err = helmCmd.Fetch(c.repoURL, chart, version.String(), tempDest, c.creds)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// 'helm fetch' file downloads chart into the tgz file and we move that to where we want it
|
||||
infos, err := ioutil.ReadDir(tempDest)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if len(infos) != 1 {
|
||||
return "", nil, fmt.Errorf("expected 1 file, found %v", len(infos))
|
||||
}
|
||||
err = os.Rename(filepath.Join(tempDest, infos[0].Name()), cachedChartPath)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// (2) then we assume that the only file downloaded into the directory is the tgz file
|
||||
// and we move that to where we want it
|
||||
infos, err := ioutil.ReadDir(tempDest)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if len(infos) != 1 {
|
||||
return "", nil, fmt.Errorf("expected 1 file, found %v", len(infos))
|
||||
}
|
||||
err = os.Rename(filepath.Join(tempDest, infos[0].Name()), chartPath)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
// untar helm chart into throw away temp directory which should be deleted as soon as no longer needed
|
||||
tempDir, err := ioutil.TempDir("", "helm")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
cmd := exec.Command("tar", "-zxvf", chartPath)
|
||||
|
||||
cmd := exec.Command("tar", "-zxvf", cachedChartPath)
|
||||
cmd.Dir = tempDir
|
||||
_, err = executil.Run(cmd)
|
||||
if err != nil {
|
||||
@@ -214,16 +236,19 @@ func (c *nativeHelmChart) TestHelmOCI() (bool, error) {
|
||||
}
|
||||
defer helmCmd.Close()
|
||||
|
||||
_, err = helmCmd.Login(c.repoURL, c.creds)
|
||||
if err != nil {
|
||||
return false, err
|
||||
// Looks like there is no good way to test access to OCI repo if credentials are not provided
|
||||
// just assume it is accessible
|
||||
if c.creds.Username != "" && c.creds.Password != "" {
|
||||
_, err = helmCmd.Login(c.repoURL, c.creds)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer func() {
|
||||
_, _ = helmCmd.Logout(c.repoURL, c.creds)
|
||||
}()
|
||||
|
||||
log.WithFields(log.Fields{"seconds": time.Since(start).Seconds()}).Info("took to test helm oci repository")
|
||||
}
|
||||
defer func() {
|
||||
_, _ = helmCmd.Logout(c.repoURL, c.creds)
|
||||
}()
|
||||
|
||||
log.WithFields(log.Fields{"seconds": time.Since(start).Seconds()}).Info("took to test helm oci repository")
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -293,6 +318,7 @@ func newTLSConfig(creds Creds) (*tls.Config, error) {
|
||||
|
||||
// Normalize a chart name for file system use, that is, if chart name is foo/bar/baz, returns the last component as chart name.
|
||||
func normalizeChartName(chart string) string {
|
||||
strings.Join(strings.Split(chart, "/"), "_")
|
||||
_, nc := path.Split(chart)
|
||||
// We do not want to return the empty string or something else related to filesystem access
|
||||
// Instead, return original string
|
||||
@@ -302,17 +328,11 @@ func normalizeChartName(chart string) string {
|
||||
return nc
|
||||
}
|
||||
|
||||
func (c *nativeHelmChart) getChartPath(chart string, version *semver.Version) string {
|
||||
if repoNamespace, chartName, isHelmOci := IsHelmOci(chart); isHelmOci {
|
||||
return path.Join(c.repoPath, fmt.Sprintf("%s-%s-%v.tgz", repoNamespace, normalizeChartName(chartName), version))
|
||||
}
|
||||
return path.Join(c.repoPath, fmt.Sprintf("%s-%v.tgz", normalizeChartName(chart), version))
|
||||
func (c *nativeHelmChart) getCachedChartPath(chart string, version *semver.Version) string {
|
||||
return path.Join(c.repoPath, fmt.Sprintf("%s-%v.tgz", strings.ReplaceAll(chart, "/", "_"), version))
|
||||
}
|
||||
|
||||
func IsHelmOci(chart string) (string, string, bool) {
|
||||
chartArray := strings.Split(chart, "/")
|
||||
if len(chartArray) == 2 {
|
||||
return chartArray[0], chartArray[1], true
|
||||
}
|
||||
return "", "", false
|
||||
// Only OCI registries support storing charts under sub-directories.
|
||||
func IsHelmOciChart(chart string) bool {
|
||||
return strings.Contains(chart, "/")
|
||||
}
|
||||
|
||||
@@ -211,26 +211,18 @@ func writeToTmp(data []byte) (string, io.Closer, error) {
|
||||
}
|
||||
|
||||
func (c *Cmd) Fetch(repo, chartName, version, destination string, creds Creds) (string, error) {
|
||||
args := []string{}
|
||||
|
||||
if _, _, isHelmOci := IsHelmOci(chartName); isHelmOci {
|
||||
args = append(args, "chart", "pull")
|
||||
repoUrl := fmt.Sprintf(repo + "/" + chartName + ":" + version)
|
||||
args = append(args, repoUrl)
|
||||
} else {
|
||||
args = append(args, c.pullCommand, "--destination", destination)
|
||||
if version != "" {
|
||||
args = append(args, "--version", version)
|
||||
}
|
||||
if creds.Username != "" {
|
||||
args = append(args, "--username", creds.Username)
|
||||
}
|
||||
if creds.Password != "" {
|
||||
args = append(args, "--password", creds.Password)
|
||||
}
|
||||
|
||||
args = append(args, "--repo", repo, chartName)
|
||||
args := []string{c.pullCommand, "--destination", destination}
|
||||
if version != "" {
|
||||
args = append(args, "--version", version)
|
||||
}
|
||||
if creds.Username != "" {
|
||||
args = append(args, "--username", creds.Username)
|
||||
}
|
||||
if creds.Password != "" {
|
||||
args = append(args, "--password", creds.Password)
|
||||
}
|
||||
|
||||
args = append(args, "--repo", repo, chartName)
|
||||
|
||||
if creds.CAPath != "" {
|
||||
args = append(args, "--ca-file", creds.CAPath)
|
||||
@@ -255,29 +247,16 @@ func (c *Cmd) Fetch(repo, chartName, version, destination string, creds Creds) (
|
||||
return c.run(args...)
|
||||
}
|
||||
|
||||
func (c *Cmd) Export(repo, chartName, version, destination string) (string, error) {
|
||||
output := ""
|
||||
var err error
|
||||
func (c *Cmd) ChartPull(repo string, chart string, version string) (string, error) {
|
||||
return c.run("chart", "pull", fmt.Sprintf("%s/%s:%s", repo, chart, version))
|
||||
}
|
||||
|
||||
func (c *Cmd) ChartExport(repo string, chartName string, version string, destination string) (string, error) {
|
||||
args := []string{"chart", "export"}
|
||||
repoUrl := fmt.Sprintf(repo + "/" + chartName + ":" + version)
|
||||
args = append(args, repoUrl, "--destination", destination)
|
||||
chartURL := fmt.Sprintf(repo + "/" + chartName + ":" + version)
|
||||
args = append(args, chartURL, "--destination", destination)
|
||||
|
||||
output, err = c.run(args...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// tar helm chart
|
||||
repoNamespace, repoName, _ := IsHelmOci(chartName)
|
||||
cmd := exec.Command("tar", "-zcvf", repoNamespace+"-"+repoName+"-"+version+".tgz", repoName)
|
||||
cmd.Dir = destination
|
||||
_, err = executil.Run(cmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer func() { _ = os.RemoveAll(destination + "/" + repoName) }()
|
||||
|
||||
return output, nil
|
||||
return c.run(args...)
|
||||
}
|
||||
|
||||
func (c *Cmd) dependencyBuild() (string, error) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
jwtgo "github.com/dgrijalva/jwt-go"
|
||||
jwtgo "github.com/dgrijalva/jwt-go/v4"
|
||||
)
|
||||
|
||||
// MapClaims converts a jwt.Claims to a MapClaims
|
||||
|
||||
@@ -3,7 +3,7 @@ package jwt
|
||||
import (
|
||||
"testing"
|
||||
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
jwt "github.com/dgrijalva/jwt-go/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"os/user"
|
||||
"path"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
|
||||
configUtil "github.com/argoproj/argo-cd/util/config"
|
||||
)
|
||||
@@ -64,7 +64,7 @@ type User struct {
|
||||
// Claims returns the standard claims from the JWT claims
|
||||
func (u *User) Claims() (*jwt.StandardClaims, error) {
|
||||
parser := &jwt.Parser{
|
||||
SkipClaimsValidation: true,
|
||||
ValidationHelper: jwt.NewValidationHelper(jwt.WithoutClaimsValidation()),
|
||||
}
|
||||
claims := jwt.StandardClaims{}
|
||||
_, _, err := parser.ParseUnverified(u.AuthToken, &claims)
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
|
||||
"github.com/argoproj/pkg/jwt/zjwt"
|
||||
gooidc "github.com/coreos/go-oidc"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
"github.com/casbin/casbin"
|
||||
"github.com/casbin/casbin/model"
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
jwt "github.com/dgrijalva/jwt-go/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
@@ -318,19 +318,19 @@ func TestEnforceErrorMessage(t *testing.T) {
|
||||
iat := time.Unix(int64(1593035962), 0).Format(time.RFC3339)
|
||||
exp := fmt.Sprintf("rpc error: code = PermissionDenied desc = permission denied: project, sub: proj:default:admin, iat: %s", iat)
|
||||
// nolint:staticcheck
|
||||
ctx = context.WithValue(context.Background(), "claims", &jwt.StandardClaims{Subject: "proj:default:admin", IssuedAt: 1593035962})
|
||||
ctx = context.WithValue(context.Background(), "claims", &jwt.StandardClaims{Subject: "proj:default:admin", IssuedAt: jwt.NewTime(1593035962)})
|
||||
err = enf.EnforceErr(ctx.Value("claims"), "project")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, exp, err.Error())
|
||||
|
||||
// nolint:staticcheck
|
||||
ctx = context.WithValue(context.Background(), "claims", &jwt.StandardClaims{ExpiresAt: 1})
|
||||
ctx = context.WithValue(context.Background(), "claims", &jwt.StandardClaims{ExpiresAt: jwt.NewTime(1)})
|
||||
err = enf.EnforceErr(ctx.Value("claims"), "project")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "rpc error: code = PermissionDenied desc = permission denied: project", err.Error())
|
||||
|
||||
// nolint:staticcheck
|
||||
ctx = context.WithValue(context.Background(), "claims", &jwt.StandardClaims{Subject: "proj:default:admin", IssuedAt: 0})
|
||||
ctx = context.WithValue(context.Background(), "claims", &jwt.StandardClaims{Subject: "proj:default:admin", IssuedAt: nil})
|
||||
err = enf.EnforceErr(ctx.Value("claims"), "project")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "rpc error: code = PermissionDenied desc = permission denied: project, sub: proj:default:admin", err.Error())
|
||||
|
||||
@@ -11,7 +11,8 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
oidc "github.com/coreos/go-oidc"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
@@ -172,15 +173,15 @@ func (mgr *SessionManager) Create(subject string, secondsBeforeExpiry int64, id
|
||||
// you would like it to contain.
|
||||
now := time.Now().UTC()
|
||||
claims := jwt.StandardClaims{
|
||||
IssuedAt: now.Unix(),
|
||||
IssuedAt: jwt.At(now),
|
||||
Issuer: SessionManagerClaimsIssuer,
|
||||
NotBefore: now.Unix(),
|
||||
NotBefore: jwt.At(now),
|
||||
Subject: subject,
|
||||
Id: id,
|
||||
ID: id,
|
||||
}
|
||||
if secondsBeforeExpiry > 0 {
|
||||
expires := now.Add(time.Duration(secondsBeforeExpiry) * time.Second)
|
||||
claims.ExpiresAt = expires.Unix()
|
||||
claims.ExpiresAt = jwt.At(expires)
|
||||
}
|
||||
|
||||
return mgr.signClaims(claims)
|
||||
@@ -422,7 +423,7 @@ func (mgr *SessionManager) VerifyUsernamePassword(username string, password stri
|
||||
// We choose how to verify based on the issuer.
|
||||
func (mgr *SessionManager) VerifyToken(tokenString string) (jwt.Claims, error) {
|
||||
parser := &jwt.Parser{
|
||||
SkipClaimsValidation: true,
|
||||
ValidationHelper: jwt.NewValidationHelper(jwt.WithoutClaimsValidation()),
|
||||
}
|
||||
var claims jwt.StandardClaims
|
||||
_, _, err := parser.ParseUnverified(tokenString, &claims)
|
||||
@@ -439,7 +440,16 @@ func (mgr *SessionManager) VerifyToken(tokenString string) (jwt.Claims, error) {
|
||||
if err != nil {
|
||||
return claims, err
|
||||
}
|
||||
idToken, err := prov.Verify(claims.Audience, tokenString)
|
||||
|
||||
// Token must be verified for at least one audience
|
||||
// TODO(jannfis): Is this the right way? Shouldn't we know our audience and only validate for the correct one?
|
||||
var idToken *oidc.IDToken
|
||||
for _, aud := range claims.Audience {
|
||||
idToken, err = prov.Verify(aud, tokenString)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return claims, err
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
@@ -97,6 +97,7 @@ type OIDCConfig struct {
|
||||
CLIClientID string `json:"cliClientID,omitempty"`
|
||||
RequestedScopes []string `json:"requestedScopes,omitempty"`
|
||||
RequestedIDTokenClaims map[string]*oidc.Claim `json:"requestedIDTokenClaims,omitempty"`
|
||||
LogoutURL string `json:"logoutURL,omitempty"`
|
||||
}
|
||||
|
||||
// DEPRECATED. Helm repository credentials are now managed using RepoCredentials
|
||||
|
||||
Reference in New Issue
Block a user