Compare commits

...

43 Commits

Author SHA1 Message Date
Alexander Matyushentsev
259926ad99 fix: upgrade awscli version (#3774) 2020-06-16 10:11:34 -07:00
Alexander Matyushentsev
d0b54e6b8f fix: html encode login error/description before rendering it (#3773) 2020-06-15 16:34:32 -07:00
Im, Juno
6054497bbc fix: oidc should set samesite cookie (#3632)
* fix: oidc should set samesite cookie

* edit: adapt the path value for cookies from root path
2020-06-15 14:42:41 -07:00
Alexander Matyushentsev
3a2cceea4f fix: avoid panic in badge handler (#3741) 2020-06-15 12:02:37 -07:00
Alexander Matyushentsev
e7d1553cfc Update manifests to v1.5.7 2020-06-09 11:12:33 -07:00
Alexander Matyushentsev
3c629baf09 refactor: support disabling legacy diffing logic (#3720)
* refactor: support disabling legacy diffing logic

* apply reviewer suggestion
2020-06-07 23:40:16 -07:00
Alexander Matyushentsev
f46333ea82 Update manifests to v1.5.6 2020-06-02 11:00:39 -07:00
Alexander Matyushentsev
5f897118e1 feat: Upgrade kustomize to 3.6.1 2020-06-02 10:31:46 -07:00
jannfis
a94a8eb422 fix: Prevent possible nil pointer dereference when getting Helm client (#3613) 2020-06-02 10:31:31 -07:00
Alexander Matyushentsev
a37a50b808 fix: avoid deadlock in settings manager (#3637) 2020-05-22 16:43:22 -07:00
Chance Zibolski
468ed0a1c2 feat: Upgrade kustomize to 3.5.5 (#3619)
* feat: Upgrade kustomize to 3.5.5
2020-05-22 16:38:51 -07:00
Alexander Matyushentsev
0fdef4861e Update manifests to v1.5.5 2020-05-15 21:02:21 -07:00
Alexander Matyushentsev
eafbf929da fix: redis request failed with nil error should not be counted as failed (#3576) 2020-05-13 10:31:57 -07:00
Alexander Matyushentsev
a552df5625 fix: enable redis retries; add redis request duration metric (#3575) 2020-05-13 10:31:53 -07:00
May Zhang
2c551ee4be fix: when --rootpath is on, 404 is returned when URL contains encoded URI (#3564)
* Fix when --rootpath is on, 404 is returned when URL contains encoded URI

* Update doc

* Update doc
2020-05-13 10:31:50 -07:00
dthomson25
7af770b11f Add Rollout restart action (#3557) 2020-05-13 10:31:46 -07:00
Alexander Matyushentsev
36bade7a2d Update manifests to v1.5.4 2020-05-05 11:58:30 -07:00
May Zhang
5754bd3357 Fix version (#3544) 2020-05-05 11:54:35 -07:00
Alexander Matyushentsev
095c5d616b Update manifests to v1.5.3 2020-05-01 21:10:13 -07:00
Alexander Matyushentsev
c3b3a0fc58 Merge branch 'master' into release-1.5 2020-04-30 20:59:32 -07:00
Alexander Matyushentsev
c2c19f42ad Update manifests to v1.5.2 2020-04-15 09:20:36 -07:00
Alexander Matyushentsev
8a3b36bd28 Update manifests to v1.5.1 2020-04-06 08:53:21 -07:00
Alexander Matyushentsev
35a7350b74 fix: return 401 error code if username does not exist (#3369) 2020-04-06 08:19:49 -07:00
jannfis
241e6d0a6e fix: Do not panic while running hooks with short revision (#3368) 2020-04-06 08:19:45 -07:00
jannfis
dbd6b406ac chore: Keep autogenerated message in upstream.yaml for HA manifests (#3367)
* fix: Keep autogenerated message in upstream.yaml
2020-04-06 08:19:40 -07:00
jannfis
a069639135 fix: Increase HAProxy check interval to prevent intermittent failures (#3356)
* Increase HAProxy check interval to prevent intermittent failures/state flapping

* Restore original namespace
2020-04-06 08:19:33 -07:00
May Zhang
76241f9d3b fix: Helm v3 CRD are not deployed (#3345)
* Fixing could not find plugin issue when app sync and app diff

* Fixing codegen error

* Revert "Fixing codegen error"

This reverts commit b2dcfb81

* Fixing codegen error

* If user is logged in, settings API would return ConfigManagementPlugins

* For helm3, add flag --include-crds when calling helm template to support helm3 crd

* Fixing typo.

* Added further assertion of ResourceSyncStatusIs for CRD resources.
2020-04-06 08:19:22 -07:00
Alexander Matyushentsev
bdda410463 Update manifests to v1.5.0 2020-04-02 09:34:43 -07:00
dthomson25
2faa5c89d1 Add V0.8 changes to Rollouts healthcheck (#3331) 2020-04-02 09:01:19 -07:00
Alexander Matyushentsev
a12b7bdb74 fix: argocd fails to connect clusters with IAM authentication configuration (#3325) 2020-03-31 17:50:09 -07:00
Alexander Matyushentsev
9b21c25783 Update manifests to v1.5.0-rc3 2020-03-30 15:00:06 -07:00
Alexander Matyushentsev
e1deca2a9e fix: avoid nil pointer dereference in badge handler (#3316) 2020-03-30 14:30:38 -07:00
Alexander Matyushentsev
62621428b1 fix: pass APIVersions value to manifest generation request during app validation and during app manifests loading (#3312)
* fix: pass APIVersions value to manifest generation request during app validation and during app manifests loading
2020-03-30 13:38:15 -07:00
Shuwei Hao
ab1f9e4658 fix: update help info about argcd account can-i (#3310)
Signed-off-by: Shuwei Hao <haoshuwei24@gmail.com>
2020-03-30 13:23:30 -07:00
jannfis
36d1b42d5c Fix possible panic when generating Dex config from malformed YAML (#3303) 2020-03-30 13:23:26 -07:00
Alexander Matyushentsev
8b9d25f6e3 fix: SSO user unable to change local account password (#3297) (#3298)
* fix: SSO user unable to change local account password (#3297)

* apply code review notes
2020-03-30 13:23:22 -07:00
Alexander Matyushentsev
323af4d562 fix: use pagination while loading initial cluster state to avoid memory spikes (#3299) 2020-03-30 13:23:19 -07:00
Alexander Matyushentsev
a946b70b5e fix: fix Cannot read property 'length' of undefined error (#3296) 2020-03-30 13:23:15 -07:00
Alexander Matyushentsev
f9f1bdaabe Update manifests to v1.5.0-rc2 2020-03-25 22:12:54 -07:00
Alexander Matyushentsev
e66b6109f7 fix: implement workaround for helm/helm#6870 bug (#3290)
* fix: implement workaround for  helm/helm#6870 bug

* Update app_management_test.go
2020-03-25 22:11:46 -07:00
Jesse Suen
53897e5019 improvement: remove app name and project labels from reconcliation histogram to reduce cardinality (#3271) 2020-03-25 12:42:23 -07:00
Alexander Matyushentsev
7e0d8a490c fix: increase max connections count to support clusters with very large number of CRDs (#3278) 2020-03-25 10:03:40 -07:00
Alexander Matyushentsev
3684a10332 Update manifests to v1.5.0-rc1 2020-03-20 13:48:19 -07:00
35 changed files with 384 additions and 108 deletions

View File

@@ -95,7 +95,7 @@ commands:
jobs:
build:
docker:
- image: argoproj/argocd-test-tools:v0.4.0
- image: argoproj/argocd-test-tools:v0.5.0
working_directory: /go/src/github.com/argoproj/argo-cd
steps:
- prepare_environment
@@ -115,7 +115,7 @@ jobs:
codegen:
docker:
- image: argoproj/argocd-test-tools:v0.4.0
- image: argoproj/argocd-test-tools:v0.5.0
working_directory: /go/src/github.com/argoproj/argo-cd
steps:
- prepare_environment
@@ -138,7 +138,7 @@ jobs:
test:
working_directory: /go/src/github.com/argoproj/argo-cd
docker:
- image: argoproj/argocd-test-tools:v0.4.0
- image: argoproj/argocd-test-tools:v0.5.0
steps:
- prepare_environment
- checkout
@@ -165,7 +165,7 @@ jobs:
lint:
working_directory: /go/src/github.com/argoproj/argo-cd
docker:
- image: argoproj/argocd-test-tools:v0.4.0
- image: argoproj/argocd-test-tools:v0.5.0
steps:
- prepare_environment
- checkout
@@ -194,7 +194,7 @@ jobs:
sonarcloud:
working_directory: /go/src/github.com/argoproj/argo-cd
docker:
- image: argoproj/argocd-test-tools:v0.4.0
- image: argoproj/argocd-test-tools:v0.5.0
environment:
NODE_MODULES: /go/src/github.com/argoproj/argo-cd/ui/node_modules
steps:

View File

@@ -52,7 +52,7 @@ RUN groupadd -g 999 argocd && \
apt-get update && \
apt-get install -y git git-lfs python3-pip && \
apt-get clean && \
pip3 install awscli==1.17.7 && \
pip3 install awscli==1.18.80 && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY hack/git-ask-pass.sh /usr/local/bin/git-ask-pass.sh

View File

@@ -22,7 +22,7 @@ ARGOCD_PROCFILE?=Procfile
# Configuration for building argocd-test-tools image
TEST_TOOLS_NAMESPACE?=argoproj
TEST_TOOLS_IMAGE=argocd-test-tools
TEST_TOOLS_TAG?=v0.4.0
TEST_TOOLS_TAG?=v0.5.0
ifdef TEST_TOOLS_NAMESPACE
TEST_TOOLS_PREFIX=${TEST_TOOLS_NAMESPACE}/
endif

View File

@@ -1 +1 @@
1.6.0
1.5.7

View File

@@ -187,7 +187,7 @@
"ApplicationService"
],
"summary": "List returns list of applications",
"operationId": "ListMixin8",
"operationId": "List",
"parameters": [
{
"type": "string",
@@ -237,7 +237,7 @@
"ApplicationService"
],
"summary": "Create creates an application",
"operationId": "CreateMixin8",
"operationId": "Create",
"parameters": [
{
"name": "body",
@@ -264,7 +264,7 @@
"ApplicationService"
],
"summary": "Update updates an application",
"operationId": "UpdateMixin8",
"operationId": "Update",
"parameters": [
{
"type": "string",
@@ -395,7 +395,7 @@
"ApplicationService"
],
"summary": "Get returns an application by name",
"operationId": "GetMixin8",
"operationId": "Get",
"parameters": [
{
"type": "string",
@@ -445,7 +445,7 @@
"ApplicationService"
],
"summary": "Delete deletes an application",
"operationId": "DeleteMixin8",
"operationId": "Delete",
"parameters": [
{
"type": "string",
@@ -1084,7 +1084,7 @@
"ClusterService"
],
"summary": "List returns list of clusters",
"operationId": "List",
"operationId": "ListMixin4",
"parameters": [
{
"type": "string",
@@ -1106,7 +1106,7 @@
"ClusterService"
],
"summary": "Create creates a cluster",
"operationId": "Create",
"operationId": "CreateMixin4",
"parameters": [
{
"name": "body",
@@ -1133,7 +1133,7 @@
"ClusterService"
],
"summary": "Update updates a cluster",
"operationId": "Update",
"operationId": "UpdateMixin4",
"parameters": [
{
"type": "string",
@@ -1166,7 +1166,7 @@
"ClusterService"
],
"summary": "Get returns a cluster by server address",
"operationId": "GetMixin2",
"operationId": "GetMixin4",
"parameters": [
{
"type": "string",
@@ -1189,7 +1189,7 @@
"ClusterService"
],
"summary": "Delete deletes a cluster",
"operationId": "Delete",
"operationId": "DeleteMixin4",
"parameters": [
{
"type": "string",
@@ -1239,7 +1239,7 @@
"ProjectService"
],
"summary": "List returns list of projects",
"operationId": "ListMixin6",
"operationId": "ListMixin5",
"parameters": [
{
"type": "string",
@@ -1261,7 +1261,7 @@
"ProjectService"
],
"summary": "Create a new project.",
"operationId": "CreateMixin6",
"operationId": "CreateMixin5",
"parameters": [
{
"name": "body",
@@ -1288,7 +1288,7 @@
"ProjectService"
],
"summary": "Get returns a project by name",
"operationId": "GetMixin6",
"operationId": "GetMixin5",
"parameters": [
{
"type": "string",
@@ -1311,7 +1311,7 @@
"ProjectService"
],
"summary": "Delete deletes a project",
"operationId": "DeleteMixin6",
"operationId": "DeleteMixin5",
"parameters": [
{
"type": "string",
@@ -1386,7 +1386,7 @@
"ProjectService"
],
"summary": "Update updates a project",
"operationId": "UpdateMixin6",
"operationId": "UpdateMixin5",
"parameters": [
{
"type": "string",
@@ -1905,7 +1905,7 @@
"SettingsService"
],
"summary": "Get returns Argo CD settings",
"operationId": "Get",
"operationId": "GetMixin7",
"responses": {
"200": {
"description": "(empty)",

View File

@@ -7,7 +7,6 @@ import (
"time"
"github.com/argoproj/pkg/stats"
rediscache "github.com/go-redis/cache"
"github.com/go-redis/redis"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -25,8 +24,10 @@ import (
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
"github.com/argoproj/argo-cd/reposerver/apiclient"
cacheutil "github.com/argoproj/argo-cd/util/cache"
appstatecache "github.com/argoproj/argo-cd/util/cache/appstate"
"github.com/argoproj/argo-cd/util/cli"
"github.com/argoproj/argo-cd/util/diff"
"github.com/argoproj/argo-cd/util/kube"
"github.com/argoproj/argo-cd/util/settings"
)
@@ -81,6 +82,8 @@ func newCommand() *cobra.Command {
settingsMgr := settings.NewSettingsManager(ctx, kubeClient, namespace)
kubectl := &kube.KubectlCmd{}
legacyDiffDisabled := os.Getenv("ARGOCD_ENABLE_LEGACY_DIFF") == "false"
diff.SetPopulateLegacyDiff(!legacyDiffDisabled)
appController, err := controller.NewApplicationController(
namespace,
settingsMgr,
@@ -94,14 +97,7 @@ func newCommand() *cobra.Command {
metricsPort,
kubectlParallelismLimit)
errors.CheckError(err)
metricsServer := appController.GetMetricsServer()
redisClient.WrapProcess(func(oldProcess func(cmd redis.Cmder) error) func(cmd redis.Cmder) error {
return func(cmd redis.Cmder) error {
err := oldProcess(cmd)
metricsServer.IncRedisRequest(err != nil && err != rediscache.ErrCacheMiss)
return err
}
})
cacheutil.CollectMetrics(redisClient, appController.GetMetricsServer())
vers := common.GetVersion()
log.Infof("Application Controller (version: %s, built: %s) starting (namespace: %s)", vers.Version, vers.BuildDate, namespace)

View File

@@ -8,6 +8,7 @@ import (
"time"
"github.com/argoproj/pkg/stats"
"github.com/go-redis/redis"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -16,6 +17,7 @@ import (
"github.com/argoproj/argo-cd/reposerver"
reposervercache "github.com/argoproj/argo-cd/reposerver/cache"
"github.com/argoproj/argo-cd/reposerver/metrics"
cacheutil "github.com/argoproj/argo-cd/util/cache"
"github.com/argoproj/argo-cd/util/cli"
"github.com/argoproj/argo-cd/util/tls"
)
@@ -33,6 +35,7 @@ func newCommand() *cobra.Command {
metricsPort int
cacheSrc func() (*reposervercache.Cache, error)
tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error)
redisClient *redis.Client
)
var command = cobra.Command{
Use: cliName,
@@ -47,6 +50,7 @@ func newCommand() *cobra.Command {
errors.CheckError(err)
metricsServer := metrics.NewMetricsServer()
cacheutil.CollectMetrics(redisClient, metricsServer)
server, err := reposerver.NewServer(metricsServer, cache, tlsConfigCustomizer, parallelismLimit)
errors.CheckError(err)
@@ -72,7 +76,9 @@ func newCommand() *cobra.Command {
command.Flags().IntVar(&listenPort, "port", common.DefaultPortRepoServer, "Listen on given port for incoming connections")
command.Flags().IntVar(&metricsPort, "metrics-port", common.DefaultPortRepoServerMetrics, "Start metrics server on given port")
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(&command)
cacheSrc = reposervercache.AddCacheFlagsToCmd(&command)
cacheSrc = reposervercache.AddCacheFlagsToCmd(&command, func(client *redis.Client) {
redisClient = client
})
return &command
}

View File

@@ -27,6 +27,7 @@ type MetricsServer struct {
clusterEventsCounter *prometheus.CounterVec
redisRequestCounter *prometheus.CounterVec
reconcileHistogram *prometheus.HistogramVec
redisRequestHistogram *prometheus.HistogramVec
registry *prometheus.Registry
}
@@ -118,6 +119,15 @@ var (
},
[]string{"initiator", "failed"},
)
redisRequestHistogram = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "argocd_redis_request_duration",
Help: "Redis requests duration.",
Buckets: []float64{0.01, 0.05, 0.10, 0.25, .5, 1},
},
[]string{"initiator"},
)
)
// NewMetricsServer returns a new prometheus server which collects application metrics
@@ -139,6 +149,7 @@ func NewMetricsServer(addr string, appLister applister.ApplicationLister, health
registry.MustRegister(reconcileHistogram)
registry.MustRegister(clusterEventsCounter)
registry.MustRegister(redisRequestCounter)
registry.MustRegister(redisRequestHistogram)
return &MetricsServer{
registry: registry,
@@ -153,6 +164,7 @@ func NewMetricsServer(addr string, appLister applister.ApplicationLister, health
reconcileHistogram: reconcileHistogram,
clusterEventsCounter: clusterEventsCounter,
redisRequestCounter: redisRequestCounter,
redisRequestHistogram: redisRequestHistogram,
}
}
@@ -205,6 +217,11 @@ func (m *MetricsServer) IncRedisRequest(failed bool) {
m.redisRequestCounter.WithLabelValues("argocd-application-controller", strconv.FormatBool(failed)).Inc()
}
// ObserveRedisRequestDuration observes redis request duration
func (m *MetricsServer) ObserveRedisRequestDuration(duration time.Duration) {
m.redisRequestHistogram.WithLabelValues("argocd-application-controller").Observe(duration.Seconds())
}
// IncReconcile increments the reconcile counter for an application
func (m *MetricsServer) IncReconcile(app *argoappv1.Application, duration time.Duration) {
m.reconcileHistogram.WithLabelValues(app.Namespace, app.Spec.Destination.Server).Observe(duration.Seconds())

View File

@@ -246,6 +246,11 @@ http {
}
}
```
Flag ```--grpc-web-root-path ``` is used to provide a non-root path (e.g. /argo-cd)
```shell
$ argocd login <host>:<port> --grpc-web-root-path /argo-cd
```
## UI Base Path

View File

@@ -1,7 +1,7 @@
#!/bin/bash
set -eux -o pipefail
KUSTOMIZE_VERSION=${KUSTOMIZE_VERSION:-3.5.4}
KUSTOMIZE_VERSION=${KUSTOMIZE_VERSION:-3.6.1}
# Note that kustomize release URIs have changed for v3.2.1. Then again for
# v3.3.0. When upgrading to versions >= v3.3.0 please change the URI format. And

View File

@@ -12,4 +12,4 @@ bases:
images:
- name: argoproj/argocd
newName: argoproj/argocd
newTag: latest
newTag: v1.5.7

View File

@@ -18,4 +18,4 @@ bases:
images:
- name: argoproj/argocd
newName: argoproj/argocd
newTag: latest
newTag: v1.5.7

View File

@@ -2869,7 +2869,7 @@ spec:
- "10"
- --redis
- argocd-redis-ha-haproxy:6379
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2925,7 +2925,7 @@ spec:
- -n
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -2975,7 +2975,7 @@ spec:
- argocd-repo-server
- --redis
- argocd-redis-ha-haproxy:6379
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 5
@@ -3043,7 +3043,7 @@ spec:
- /shared/app
- --redis
- argocd-redis-ha-haproxy:6379
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -2784,7 +2784,7 @@ spec:
- "10"
- --redis
- argocd-redis-ha-haproxy:6379
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2840,7 +2840,7 @@ spec:
- -n
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -2890,7 +2890,7 @@ spec:
- argocd-repo-server
- --redis
- argocd-redis-ha-haproxy:6379
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 5
@@ -2958,7 +2958,7 @@ spec:
- /shared/app
- --redis
- argocd-redis-ha-haproxy:6379
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -2369,7 +2369,7 @@ spec:
- "20"
- --operation-processors
- "10"
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2425,7 +2425,7 @@ spec:
- -n
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -2489,7 +2489,7 @@ spec:
- argocd-repo-server
- --redis
- argocd-redis:6379
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 5
@@ -2540,7 +2540,7 @@ spec:
- argocd-server
- --staticassets
- /shared/app
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -2284,7 +2284,7 @@ spec:
- "20"
- --operation-processors
- "10"
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2340,7 +2340,7 @@ spec:
- -n
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -2404,7 +2404,7 @@ spec:
- argocd-repo-server
- --redis
- argocd-redis:6379
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 5
@@ -2455,7 +2455,7 @@ spec:
- argocd-server
- --staticassets
- /shared/app
image: argoproj/argocd:latest
image: argoproj/argocd:v1.5.7
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -56,7 +56,15 @@ func (c *client) executeRequest(fullMethodName string, msg []byte, md metadata.M
schema = "http"
}
rootPath := strings.TrimRight(strings.TrimLeft(c.GRPCWebRootPath, "/"), "/")
req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s://%s/%s%s", schema, c.ServerAddr, rootPath, fullMethodName), bytes.NewReader(toFrame(msg)))
var requestURL string
if rootPath != "" {
requestURL = fmt.Sprintf("%s://%s/%s%s", schema, c.ServerAddr, rootPath, fullMethodName)
} else {
requestURL = fmt.Sprintf("%s://%s%s", schema, c.ServerAddr, fullMethodName)
}
req, err := http.NewRequest(http.MethodPost, requestURL, bytes.NewReader(toFrame(msg)))
if err != nil {
return nil, err
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"time"
"github.com/go-redis/redis"
"github.com/spf13/cobra"
appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
@@ -23,12 +24,12 @@ func NewCache(cache *cacheutil.Cache, repoCacheExpiration time.Duration) *Cache
return &Cache{cache, repoCacheExpiration}
}
func AddCacheFlagsToCmd(cmd *cobra.Command) func() (*Cache, error) {
func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...func(client *redis.Client)) func() (*Cache, error) {
var repoCacheExpiration time.Duration
cmd.Flags().DurationVar(&repoCacheExpiration, "repo-cache-expiration", 24*time.Hour, "Cache expiration for repo state, incl. app lists, app details, manifest generation, revision meta-data")
repoFactory := cacheutil.AddCacheFlagsToCmd(cmd)
repoFactory := cacheutil.AddCacheFlagsToCmd(cmd, opts...)
return func() (*Cache, error) {
cache, err := repoFactory()

View File

@@ -2,6 +2,8 @@ package metrics
import (
"net/http"
"strconv"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
@@ -11,6 +13,8 @@ type MetricsServer struct {
handler http.Handler
gitRequestCounter *prometheus.CounterVec
repoPendingRequestsGauge *prometheus.GaugeVec
redisRequestCounter *prometheus.CounterVec
redisRequestHistogram *prometheus.HistogramVec
}
type GitRequestType string
@@ -44,10 +48,31 @@ func NewMetricsServer() *MetricsServer {
)
registry.MustRegister(repoPendingRequestsGauge)
redisRequestCounter := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "argocd_redis_request_total",
Help: "Number of kubernetes requests executed during application reconciliation.",
},
[]string{"initiator", "failed"},
)
registry.MustRegister(redisRequestCounter)
redisRequestHistogram := prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "argocd_redis_request_duration",
Help: "Redis requests duration.",
Buckets: []float64{0.1, 0.25, .5, 1, 2},
},
[]string{"initiator"},
)
registry.MustRegister(redisRequestHistogram)
return &MetricsServer{
handler: promhttp.HandlerFor(registry, promhttp.HandlerOpts{}),
gitRequestCounter: gitRequestCounter,
repoPendingRequestsGauge: repoPendingRequestsGauge,
redisRequestCounter: redisRequestCounter,
redisRequestHistogram: redisRequestHistogram,
}
}
@@ -67,3 +92,11 @@ func (m *MetricsServer) IncPendingRepoRequest(repo string) {
func (m *MetricsServer) DecPendingRepoRequest(repo string) {
m.repoPendingRequestsGauge.WithLabelValues(repo).Dec()
}
func (m *MetricsServer) IncRedisRequest(failed bool) {
m.redisRequestCounter.WithLabelValues("argocd-repo-server", strconv.FormatBool(failed)).Inc()
}
func (m *MetricsServer) ObserveRedisRequestDuration(duration time.Duration) {
m.redisRequestHistogram.WithLabelValues("argocd-repo-server").Observe(duration.Seconds())
}

View File

@@ -25,4 +25,7 @@ actionTests:
expectedOutputPath: testdata/pre_v0.6_not_paused_rollout.yaml
- action: resume
inputPath: testdata/has_pause_condition_rollout.yaml
expectedOutputPath: testdata/no_pause_condition_rollout.yaml
expectedOutputPath: testdata/no_pause_condition_rollout.yaml
- action: restart
inputPath: testdata/rollout_not_restarted.yaml
expectedOutputPath: testdata/rollout_restarted.yaml

View File

@@ -0,0 +1,3 @@
local os = require("os")
obj.spec.restartAt = os.date("!%Y-%m-%dT%XZ")
return obj

View File

@@ -0,0 +1,47 @@
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: canary-demo
namespace: default
spec:
replicas: 5
revisionHistoryLimit: 1
selector:
matchLabels:
app: canary-demo
strategy:
canary:
analysis:
args:
- name: ingress
value: canary-demo
templateName: success-rate
canaryService: canary-demo-preview
maxSurge: 1
maxUnavailable: 1
steps:
- setWeight: 40
- pause: {}
- setWeight: 60
- pause:
duration: 10
- setWeight: 80
- pause:
duration: 10
template:
metadata:
labels:
app: canary-demo
spec:
containers:
- image: argoproj/rollouts-demo:red
imagePullPolicy: Always
name: canary-demo
ports:
- containerPort: 8080
name: http
protocol: TCP
resources:
requests:
cpu: 5m
memory: 32Mi

View File

@@ -0,0 +1,48 @@
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: canary-demo
namespace: default
spec:
replicas: 5
restartAt: "0001-01-01T00:00:00Z"
revisionHistoryLimit: 1
selector:
matchLabels:
app: canary-demo
strategy:
canary:
analysis:
args:
- name: ingress
value: canary-demo
templateName: success-rate
canaryService: canary-demo-preview
maxSurge: 1
maxUnavailable: 1
steps:
- setWeight: 40
- pause: {}
- setWeight: 60
- pause:
duration: 10
- setWeight: 80
- pause:
duration: 10
template:
metadata:
labels:
app: canary-demo
spec:
containers:
- image: argoproj/rollouts-demo:red
imagePullPolicy: Always
name: canary-demo
ports:
- containerPort: 8080
name: http
protocol: TCP
resources:
requests:
cpu: 5m
memory: 32Mi

View File

@@ -122,7 +122,11 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
badge = svgWidthPattern.ReplaceAllString(badge, fmt.Sprintf(`<svg width="%d" $2`, svgWidthWithRevision))
badge = displayNonePattern.ReplaceAllString(badge, `display="inline"`)
badge = revisionRectColorPattern.ReplaceAllString(badge, fmt.Sprintf(`id="revisionRect" fill="%s" $2`, rightColorString))
badge = replaceFirstGroupSubMatch(revisionTextPattern, badge, fmt.Sprintf("(%s)", revision[:7]))
shortRevision := revision
if len(shortRevision) > 7 {
shortRevision = shortRevision[:7]
}
badge = replaceFirstGroupSubMatch(revisionTextPattern, badge, fmt.Sprintf("(%s)", shortRevision))
}
w.Header().Set("Content-Type", "image/svg+xml")

View File

@@ -110,6 +110,22 @@ func TestHandlerRevisionIsEnabledNoOperationState(t *testing.T) {
assert.NotContains(t, response, "(aa29b85)")
}
func TestHandlerRevisionIsEnabledShortCommitSHA(t *testing.T) {
app := testApp.DeepCopy()
app.Status.OperationState.SyncResult.Revision = "abc"
settingsMgr := settings.NewSettingsManager(context.Background(), fake.NewSimpleClientset(&argoCDCm, &argoCDSecret), "default")
handler := NewHandler(appclientset.NewSimpleClientset(app), settingsMgr, "default")
req, err := http.NewRequest("GET", "/api/badge?name=testApp&revision=true", nil)
assert.NoError(t, err)
rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
response := rr.Body.String()
assert.Contains(t, response, "(abc)")
}
func TestHandlerFeatureIsDisabled(t *testing.T) {
argoCDCmDisabled := argoCDCm.DeepCopy()

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"net/http"
"strconv"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
@@ -11,7 +12,8 @@ import (
type MetricsServer struct {
*http.Server
redisRequestCounter *prometheus.CounterVec
redisRequestCounter *prometheus.CounterVec
redisRequestHistogram *prometheus.HistogramVec
}
var (
@@ -22,6 +24,14 @@ var (
},
[]string{"initiator", "failed"},
)
redisRequestHistogram = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "argocd_redis_request_duration",
Help: "Redis requests duration.",
Buckets: []float64{0.1, 0.25, .5, 1, 2},
},
[]string{"initiator"},
)
)
// NewMetricsServer returns a new prometheus server which collects api server metrics
@@ -34,16 +44,23 @@ func NewMetricsServer(port int) *MetricsServer {
}, promhttp.HandlerOpts{}))
registry.MustRegister(redisRequestCounter)
registry.MustRegister(redisRequestHistogram)
return &MetricsServer{
Server: &http.Server{
Addr: fmt.Sprintf("0.0.0.0:%d", port),
Handler: mux,
},
redisRequestCounter: redisRequestCounter,
redisRequestCounter: redisRequestCounter,
redisRequestHistogram: redisRequestHistogram,
}
}
func (m *MetricsServer) IncRedisRequest(failed bool) {
m.redisRequestCounter.WithLabelValues("argocd-server", strconv.FormatBool(failed)).Inc()
}
// ObserveRedisRequestDuration observes redis request duration
func (m *MetricsServer) ObserveRedisRequestDuration(duration time.Duration) {
m.redisRequestHistogram.WithLabelValues("argocd-server").Observe(duration.Seconds())
}

View File

@@ -16,12 +16,12 @@ import (
"strings"
"time"
cacheutil "github.com/argoproj/argo-cd/util/cache"
"github.com/argoproj/argo-cd/util/healthz"
"github.com/argoproj/argo-cd/util/swagger"
"github.com/argoproj/argo-cd/util/webhook"
"github.com/dgrijalva/jwt-go"
rediscache "github.com/go-redis/cache"
"github.com/go-redis/redis"
golang_proto "github.com/golang/protobuf/proto"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
@@ -249,16 +249,14 @@ func (a *ArgoCDServer) Run(ctx context.Context, port int, metricsPort int) {
httpsS.Handler = withRootPath(httpsS.Handler, a)
}
}
httpS.Handler = &bug21955Workaround{handler: httpS.Handler}
if httpsS != nil {
httpsS.Handler = &bug21955Workaround{handler: httpsS.Handler}
}
metricsServ := metrics.NewMetricsServer(metricsPort)
if a.RedisClient != nil {
a.RedisClient.WrapProcess(func(oldProcess func(cmd redis.Cmder) error) func(cmd redis.Cmder) error {
return func(cmd redis.Cmder) error {
err := oldProcess(cmd)
metricsServ.IncRedisRequest(err != nil && err != rediscache.ErrCacheMiss)
return err
}
})
cacheutil.CollectMetrics(a.RedisClient, metricsServ)
}
// Start listener
@@ -580,7 +578,7 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
httpS := http.Server{
Addr: endpoint,
Handler: &handlerSwitcher{
handler: &bug21955Workaround{handler: mux},
handler: mux,
urlToHandler: map[string]http.Handler{
"/api/badge": badge.NewHandler(a.AppClientset, a.settingsMgr, a.Namespace),
},

15
util/cache/cache.go vendored
View File

@@ -2,6 +2,7 @@ package cache
import (
"fmt"
"math"
"os"
"time"
@@ -9,11 +10,16 @@ import (
"github.com/spf13/cobra"
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/util/env"
)
const (
// envRedisPassword is a env variable name which stores redis password
envRedisPassword = "REDIS_PASSWORD"
// envRedisRetryCount is a env variable name which stores redis retry count
envRedisRetryCount = "REDIS_RETRY_COUNT"
// defaultRedisRetryCount holds default number of retries
defaultRedisRetryCount = 3
)
func NewCache(client CacheClient) *Cache {
@@ -35,12 +41,14 @@ func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...func(client *redis.Client))
cmd.Flags().DurationVar(&defaultCacheExpiration, "default-cache-expiration", 24*time.Hour, "Cache expiration default")
return func() (*Cache, error) {
password := os.Getenv(envRedisPassword)
maxRetries := env.ParseNumFromEnv(envRedisRetryCount, defaultRedisRetryCount, 0, math.MaxInt32)
if len(sentinelAddresses) > 0 {
client := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: sentinelMaster,
SentinelAddrs: sentinelAddresses,
DB: redisDB,
Password: password,
MaxRetries: maxRetries,
})
for i := range opts {
opts[i](client)
@@ -52,9 +60,10 @@ func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...func(client *redis.Client))
redisAddress = common.DefaultRedisAddr
}
client := redis.NewClient(&redis.Options{
Addr: redisAddress,
Password: password,
DB: redisDB,
Addr: redisAddress,
Password: password,
DB: redisDB,
MaxRetries: maxRetries,
})
for i := range opts {
opts[i](client)

51
util/cache/redis.go vendored
View File

@@ -1,7 +1,6 @@
package cache
import (
"io"
"time"
rediscache "github.com/go-redis/cache"
@@ -29,39 +28,45 @@ type redisCache struct {
codec *rediscache.Codec
}
// if redis server goes down the first client request fails with EOF error
func doWithRetry(action func() error) error {
err := action()
if err == io.EOF {
return action()
}
return err
}
func (r *redisCache) Set(item *Item) error {
expiration := item.Expiration
if expiration == 0 {
expiration = r.expiration
}
return doWithRetry(func() error {
return r.codec.Set(&rediscache.Item{
Key: item.Key,
Object: item.Object,
Expiration: expiration,
})
return r.codec.Set(&rediscache.Item{
Key: item.Key,
Object: item.Object,
Expiration: expiration,
})
}
func (r *redisCache) Get(key string, obj interface{}) error {
return doWithRetry(func() error {
err := r.codec.Get(key, obj)
if err == rediscache.ErrCacheMiss {
return ErrCacheMiss
}
return err
})
err := r.codec.Get(key, obj)
if err == rediscache.ErrCacheMiss {
return ErrCacheMiss
}
return err
}
func (r *redisCache) Delete(key string) error {
return r.codec.Delete(key)
}
type MetricsRegistry interface {
IncRedisRequest(failed bool)
ObserveRedisRequestDuration(duration time.Duration)
}
// CollectMetrics add transport wrapper that pushes metrics into the specified metrics registry
func CollectMetrics(client *redis.Client, registry MetricsRegistry) {
client.WrapProcess(func(oldProcess func(cmd redis.Cmder) error) func(cmd redis.Cmder) error {
return func(cmd redis.Cmder) error {
startTime := time.Now()
err := oldProcess(cmd)
registry.IncRedisRequest(err != nil && err != redis.Nil)
duration := time.Since(startTime)
registry.ObserveRedisRequestDuration(duration)
return err
}
})
}

View File

@@ -27,6 +27,22 @@ import (
jsonutil "github.com/argoproj/argo-cd/util/json"
)
var (
emptyGoJSONDiff = gojsondiff.New().CompareObjects(map[string]interface{}{}, map[string]interface{}{})
populateLegacyDiff = true
)
func SetPopulateLegacyDiff(val bool) {
populateLegacyDiff = val
}
func calcGoJsonDiff(left map[string]interface{}, right map[string]interface{}) gojsondiff.Diff {
if !populateLegacyDiff {
return emptyGoJSONDiff
}
return gojsondiff.New().CompareObjects(left, right)
}
type DiffResult struct {
// Deprecated: Use PredictedLive and NormalizedLive instead
Diff gojsondiff.Diff
@@ -76,7 +92,7 @@ func getLegacyTwoWayDiff(config, live *unstructured.Unstructured) gojsondiff.Dif
if live != nil {
liveObj = jsonutil.RemoveMapFields(configObj, live.Object)
}
return gojsondiff.New().CompareObjects(liveObj, configObj)
return calcGoJsonDiff(liveObj, configObj)
}
// TwoWayDiff performs a three-way diff and uses specified config as a recently applied config
@@ -150,7 +166,7 @@ func ThreeWayDiff(orig, config, live *unstructured.Unstructured) (*DiffResult, e
NormalizedLive: liveBytes,
Modified: string(predictedLiveBytes) != string(liveBytes),
// legacy diff for backward compatibility
Diff: gojsondiff.New().CompareObjects(live.Object, predictedLive.Object),
Diff: calcGoJsonDiff(live.Object, predictedLive.Object),
}
return &dr, nil
}

View File

@@ -37,11 +37,11 @@ type Helm interface {
// NewHelmApp create a new wrapper to run commands on the `helm` command-line tool.
func NewHelmApp(workDir string, repos []HelmRepository, isLocal bool) (Helm, error) {
cmd, err := NewCmd(workDir)
cmd.IsLocal = isLocal
if err != nil {
return nil, err
}
cmd.IsLocal = isLocal
return &helm{repos: repos, cmd: *cmd}, nil
}

View File

@@ -3,11 +3,13 @@ package oidc
import (
"encoding/json"
"fmt"
"html"
"html/template"
"net"
"net/http"
"net/url"
"os"
"strings"
"time"
gooidc "github.com/coreos/go-oidc"
@@ -222,7 +224,8 @@ func (a *ClientApp) HandleCallback(w http.ResponseWriter, r *http.Request) {
}
log.Infof("Callback: %s", r.URL)
if errMsg := r.FormValue("error"); errMsg != "" {
http.Error(w, errMsg+": "+r.FormValue("error_description"), http.StatusBadRequest)
errorDesc := r.FormValue("error_description")
http.Error(w, html.EscapeString(errMsg)+": "+html.EscapeString(errorDesc), http.StatusBadRequest)
return
}
code := r.FormValue("code")
@@ -253,7 +256,12 @@ func (a *ClientApp) HandleCallback(w http.ResponseWriter, r *http.Request) {
http.Error(w, fmt.Sprintf("invalid session token: %v", err), http.StatusInternalServerError)
return
}
flags := []string{"path=/"}
path := "/"
if a.baseHRef != "" {
path = strings.TrimRight(strings.TrimLeft(a.baseHRef, "/"), "/")
}
cookiePath := fmt.Sprintf("path=/%s", path)
flags := []string{cookiePath, "SameSite=lax", "httpOnly"}
if a.secureCookie {
flags = append(flags, "Secure")
}

View File

@@ -3,12 +3,13 @@ package oidc
import (
"encoding/json"
"io/ioutil"
"net/http/httptest"
"net/url"
"testing"
"golang.org/x/oauth2"
gooidc "github.com/coreos/go-oidc"
"github.com/stretchr/testify/assert"
"golang.org/x/oauth2"
"github.com/argoproj/argo-cd/server/settings/oidc"
)
@@ -65,3 +66,33 @@ func TestIDTokenClaims(t *testing.T) {
assert.Equal(t, "{\"id_token\":{\"groups\":{\"essential\":true}}}", values.Get("claims"))
}
type fakeProvider struct {
}
func (p *fakeProvider) Endpoint() (*oauth2.Endpoint, error) {
return &oauth2.Endpoint{}, nil
}
func (p *fakeProvider) ParseConfig() (*OIDCConfiguration, error) {
return nil, nil
}
func (p *fakeProvider) Verify(_, _ string) (*gooidc.IDToken, error) {
return nil, nil
}
func TestHandleCallback(t *testing.T) {
app := ClientApp{provider: &fakeProvider{}}
req := httptest.NewRequest("GET", "http://example.com/foo", nil)
req.Form = url.Values{
"error": []string{"login-failed"},
"error_description": []string{"<script>alert('hello')</script>"},
}
w := httptest.NewRecorder()
app.HandleCallback(w, req)
assert.Equal(t, "login-failed: &lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;\n", w.Body.String())
}

View File

@@ -373,7 +373,7 @@ func (mgr *SessionManager) VerifyUsernamePassword(username string, password stri
// introduces random delay to protect from timing-based user enumeration attack
delayNanoseconds := verificationDelayNoiseMin.Nanoseconds() +
int64(rand.Intn(int(verificationDelayNoiseMax.Nanoseconds()-verificationDelayNoiseMin.Nanoseconds())))
// take into account amount of time spent since the request start
// take into account amount of time spent since the request start
delayNanoseconds = delayNanoseconds - time.Since(start).Nanoseconds()
if delayNanoseconds > 0 {
mgr.sleep(time.Duration(delayNanoseconds))

View File

@@ -1030,10 +1030,15 @@ func (mgr *SettingsManager) notifySubscribers(newSettings *ArgoCDSettings) {
mgr.mutex.Lock()
defer mgr.mutex.Unlock()
if len(mgr.subscribers) > 0 {
log.Infof("Notifying %d settings subscribers: %v", len(mgr.subscribers), mgr.subscribers)
for _, sub := range mgr.subscribers {
sub <- newSettings
}
subscribers := make([]chan<- *ArgoCDSettings, len(mgr.subscribers))
copy(subscribers, mgr.subscribers)
// make sure subscribes are notified in a separate thread to avoid potential deadlock
go func() {
log.Infof("Notifying %d settings subscribers: %v", len(subscribers), subscribers)
for _, sub := range subscribers {
sub <- newSettings
}
}()
}
}