Compare commits

...

26 Commits

Author SHA1 Message Date
Alexander Matyushentsev
593715038c Update manifests to v1.3.0-rc4 2019-11-03 22:05:34 -08:00
jannfis
4f84498265 Assume git as default repository type (fixes #2622) (#2628)
* Assume git as default repository type

* Add helm repo with name in E2E tests
2019-11-03 20:19:54 -08:00
Alexander Matyushentsev
8186ff0bb9 Issue #2626 - Repo server executes unnecessary ls-remotes (#2627) 2019-11-02 23:26:00 -07:00
Alexander Matyushentsev
0432a85832 Issue #2620 - Cluster list page fails if any cluster is not reachable (#2621) 2019-11-01 15:36:10 -07:00
Alexander Matyushentsev
a0d37654b4 Issue #2616 - argocd app diff prints only first difference (#2617) 2019-11-01 15:23:07 -07:00
Alexander Matyushentsev
fe3b17322a Bump min client cache version (#2619) 2019-11-01 15:23:03 -07:00
Alexander Matyushentsev
59623b85fe Execute application label filtering on client side (#2605) 2019-10-31 11:23:42 -07:00
Alex Collins
905a8b0d75 Fix lint and merge issues 2019-10-30 17:04:43 -07:00
Alex Collins
30935e2019 Adds timeout to Helm commands. (#2570) 2019-10-30 16:42:06 -07:00
Alex Collins
f3e0e097de UI fixes for "Sync Apps" panel. (#2604) 2019-10-30 16:41:26 -07:00
Alex Collins
e1ff01cb56 Upgrade Helm to v2.15.2. Closes #2587 (#2590) 2019-10-30 15:32:58 -07:00
Alex Collins
e0de3300d2 Sets app status to unknown if there is an error. Closes #2577 (#2578) 2019-10-29 11:45:56 -07:00
Alex Collins
40cb6fa9ce Merge test from master 2019-10-29 11:45:22 -07:00
Alex Collins
11de95cbac Fixes merge issue 2019-10-29 11:37:12 -07:00
Alex Collins
c7cd2e92bb Update manifests to v1.3.0-rc3 2019-10-29 11:10:34 -07:00
Alex Collins
a4f13f5f29 codegen 2019-10-29 11:01:22 -07:00
Alexander Matyushentsev
6460de9d03 Issue #2339 - Don't update 'status.reconciledAt' unless compared with latest git version (#2581) 2019-10-29 10:54:31 -07:00
Alex Collins
6f6b03f74c Allows Helm charts to have arbitrary file names. Fixes #2549 (#2569) 2019-10-28 10:53:40 -07:00
Alex Collins
36775ae1bb Fixes panic when creating repo (#2568) 2019-10-25 12:35:47 -07:00
Alex Collins
4a360cf9f4 Update manifests to v1.3.0-rc2 2019-10-22 18:16:31 -07:00
Alexander Matyushentsev
6e56302fa4 Issue #2339 - Controller should compare with latest git revision if app has changed (#2543) 2019-10-22 15:31:20 -07:00
Alexander Matyushentsev
3d82d5aab7 Unknown child app should not affect app health (#2544) 2019-10-22 15:31:14 -07:00
Simon Behar
7df03b3c89 Redact secrets in dex logs (#2538)
* Done

* Pre-commit

* Added test

* Pre-commit

* Goimports
2019-10-22 10:46:46 -07:00
Alex Collins
e059760906 Allows Helm parameters that contains arrays or maps. (#2525) 2019-10-18 15:31:48 -07:00
jannfis
8925b52bc8 Set cookie policy to SameSite=lax and httpOnly (#2498) 2019-10-17 11:29:39 -07:00
Alex Collins
8a43840f0b Update manifests to v1.3.0-rc1 2019-10-16 13:56:05 -07:00
43 changed files with 1031 additions and 442 deletions

View File

@@ -1 +1 @@
1.3.0
1.3.0-rc4

View File

@@ -8,6 +8,7 @@ import (
"io/ioutil"
"os"
"os/exec"
"regexp"
"syscall"
"github.com/ghodss/yaml"
@@ -108,7 +109,7 @@ func NewRunDexCommand() *cobra.Command {
} else {
err = ioutil.WriteFile("/tmp/dex.yaml", dexCfgBytes, 0644)
errors.CheckError(err)
log.Info(string(dexCfgBytes))
log.Info(redactor(string(dexCfgBytes)))
cmd = exec.Command("dex", "serve", "/tmp/dex.yaml")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
@@ -532,6 +533,11 @@ func NewClusterConfig() *cobra.Command {
return command
}
func redactor(dirtyString string) string {
dirtyString = regexp.MustCompile("(clientSecret: )[^ \n]*").ReplaceAllString(dirtyString, "$1********")
return regexp.MustCompile("(secret: )[^ \n]*").ReplaceAllString(dirtyString, "$1********")
}
func main() {
if err := NewCommand().Execute(); err != nil {
fmt.Println(err)

View File

@@ -0,0 +1,73 @@
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
var textToRedact = `
- config:
clientID: aabbccddeeff00112233
clientSecret: $dex.github.clientSecret
orgs:
- name: your-github-org
redirectURI: https://argocd.example.com/api/dex/callback
id: github
name: GitHub
type: github
grpc:
addr: 0.0.0.0:5557
issuer: https://argocd.example.com/api/dex
oauth2:
skipApprovalScreen: true
staticClients:
- id: argo-cd
name: Argo CD
redirectURIs:
- https://argocd.example.com/auth/callback
secret: Dis9M-GA11oTwZVQQWdDklPQw-sWXZkWJFyyEhMs
- id: argo-cd-cli
name: Argo CD CLI
public: true
redirectURIs:
- http://localhost
storage:
type: memory
web:
http: 0.0.0.0:5556`
var expectedRedaction = `
- config:
clientID: aabbccddeeff00112233
clientSecret: ********
orgs:
- name: your-github-org
redirectURI: https://argocd.example.com/api/dex/callback
id: github
name: GitHub
type: github
grpc:
addr: 0.0.0.0:5557
issuer: https://argocd.example.com/api/dex
oauth2:
skipApprovalScreen: true
staticClients:
- id: argo-cd
name: Argo CD
redirectURIs:
- https://argocd.example.com/auth/callback
secret: ********
- id: argo-cd-cli
name: Argo CD CLI
public: true
redirectURIs:
- http://localhost
storage:
type: memory
web:
http: 0.0.0.0:5556`
func TestSecretsRedactor(t *testing.T) {
assert.Equal(t, expectedRedaction, redactor(textToRedact))
}

View File

@@ -972,8 +972,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
}
foundDiffs = true
err = diff.PrintDiff(item.key.Name, target, live)
errors.CheckError(err)
_ = diff.PrintDiff(item.key.Name, target, live)
}
}
if foundDiffs {

View File

@@ -10,6 +10,7 @@ import (
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/errors"
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
repositorypkg "github.com/argoproj/argo-cd/pkg/apiclient/repository"
@@ -50,13 +51,20 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
)
// For better readability and easier formatting
var repoAddExamples = `
Add a SSH repository using a private key for authentication, ignoring the server's host key:",
$ argocd repo add git@git.example.com --insecure-ignore-host-key --ssh-private-key-path ~/id_rsa",
Add a HTTPS repository using username/password and TLS client certificates:",
$ argocd repo add https://git.example.com --username git --password secret --tls-client-cert-path ~/mycert.crt --tls-client-cert-key-path ~/mycert.key",
Add a HTTPS repository using username/password without verifying the server's TLS certificate:",
$ argocd repo add https://git.example.com --username git --password secret --insecure-skip-server-verification",
var repoAddExamples = ` # Add a Git repository via SSH using a private key for authentication, ignoring the server's host key:
argocd repo add git@git.example.com:repos/repo --insecure-ignore-host-key --ssh-private-key-path ~/id_rsa
# Add a private Git repository via HTTPS using username/password and TLS client certificates:
argocd repo add https://git.example.com/repos/repo --username git --password secret --tls-client-cert-path ~/mycert.crt --tls-client-cert-key-path ~/mycert.key
# Add a private Git repository via HTTPS using username/password without verifying the server's TLS certificate
argocd repo add https://git.example.com/repos/repo --username git --password secret --insecure-skip-server-verification
# Add a public Helm repository named 'stable' via HTTPS
argocd repo add https://kubernetes-charts.storage.googleapis.com --type helm --name stable
# Add a private Helm repository named 'stable' via HTTPS
argocd repo add https://kubernetes-charts.storage.googleapis.com --type helm --name stable --username test --password test
`
var command = &cobra.Command{
@@ -113,6 +121,10 @@ Add a HTTPS repository using username/password without verifying the server's TL
repo.Insecure = insecureSkipServerVerification
repo.EnableLFS = enableLfs
if repo.Type == "helm" && repo.Name == "" {
errors.CheckError(fmt.Errorf("Must specify --name for repos of type 'helm'"))
}
conn, repoIf := argocdclient.NewClientOrDie(clientOpts).NewRepoClientOrDie()
defer util.Close(conn)
@@ -148,8 +160,8 @@ Add a HTTPS repository using username/password without verifying the server's TL
fmt.Printf("repository '%s' added\n", createdRepo.Repo)
},
}
command.Flags().StringVar(&repo.Type, "type", "", "type of the repository, \"git\" or \"helm\"")
command.Flags().StringVar(&repo.Name, "name", "", "name of the repository")
command.Flags().StringVar(&repo.Type, "type", common.DefaultRepoType, "type of the repository, \"git\" or \"helm\"")
command.Flags().StringVar(&repo.Name, "name", "", "name of the repository, mandatory for repositories of type helm")
command.Flags().StringVar(&repo.Username, "username", "", "username to the repository")
command.Flags().StringVar(&repo.Password, "password", "", "password to the repository")
command.Flags().StringVar(&sshPrivateKeyPath, "ssh-private-key-path", "", "path to the private ssh key (e.g. ~/.ssh/id_rsa)")

View File

@@ -21,9 +21,10 @@ const (
ArgoCDTLSCertsConfigMapName = "argocd-tls-certs-cm"
)
// Default system namespace
// Some default configurables
const (
DefaultSystemNamespace = "kube-system"
DefaultRepoType = "git"
)
// Default listener ports for ArgoCD components

View File

@@ -803,6 +803,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
revision = app.Status.Sync.Revision
}
observedAt := metav1.Now()
compareResult := ctrl.appStateManager.CompareAppState(app, revision, app.Spec.Source, refreshType == appv1.RefreshTypeHard, localManifests)
ctrl.normalizeApplication(origApp, app)
@@ -830,8 +831,10 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
}
}
app.Status.ObservedAt = &compareResult.reconciledAt
app.Status.ReconciledAt = &compareResult.reconciledAt
if app.Status.ReconciledAt == nil || comparisonLevel == CompareWithLatest {
app.Status.ReconciledAt = &observedAt
}
app.Status.ObservedAt = &observedAt
app.Status.Sync = *compareResult.syncStatus
app.Status.Health = *compareResult.healthStatus
app.Status.Resources = compareResult.resources
@@ -850,23 +853,22 @@ func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application,
compareWith := CompareWithLatest
refreshType := appv1.RefreshTypeNormal
expired := app.Status.ReconciledAt == nil || app.Status.ReconciledAt.Add(statusRefreshTimeout).Before(time.Now().UTC())
if requestedType, ok := app.IsRefreshRequested(); ok || expired {
if ok {
refreshType = requestedType
reason = fmt.Sprintf("%s refresh requested", refreshType)
} else if expired {
reason = fmt.Sprintf("comparison expired. reconciledAt: %v, expiry: %v", app.Status.ReconciledAt, statusRefreshTimeout)
}
} else if requested, level := ctrl.isRefreshRequested(app.Name); requested {
compareWith = level
reason = fmt.Sprintf("controller refresh requested")
} else if app.Status.Sync.Status == appv1.SyncStatusCodeUnknown && expired {
reason = "comparison status unknown"
if requestedType, ok := app.IsRefreshRequested(); ok {
// user requested app refresh.
refreshType = requestedType
reason = fmt.Sprintf("%s refresh requested", refreshType)
} else if expired {
reason = fmt.Sprintf("comparison expired. reconciledAt: %v, expiry: %v", app.Status.ReconciledAt, statusRefreshTimeout)
} else if !app.Spec.Source.Equals(app.Status.Sync.ComparedTo.Source) {
reason = "spec.source differs"
} else if !app.Spec.Destination.Equals(app.Status.Sync.ComparedTo.Destination) {
reason = "spec.destination differs"
} else if requested, level := ctrl.isRefreshRequested(app.Name); requested {
compareWith = level
reason = fmt.Sprintf("controller refresh requested")
}
if reason != "" {
logCtx.Infof("Refreshing app status (%s), level (%d)", reason, compareWith)
return true, refreshType, compareWith

View File

@@ -2,6 +2,7 @@ package controller
import (
"context"
"encoding/json"
"testing"
"time"
@@ -597,6 +598,24 @@ func TestNeedRefreshAppStatus(t *testing.T) {
assert.Equal(t, argoappv1.RefreshTypeHard, refreshType)
assert.Equal(t, CompareWithLatest, compareWith)
}
{
app := app.DeepCopy()
// ensure that CompareWithLatest level is used if application source has changed
ctrl.requestAppRefresh(app.Name, ComparisonWithNothing)
// sample app source change
app.Spec.Source.Helm = &argoappv1.ApplicationSourceHelm{
Parameters: []argoappv1.HelmParameter{{
Name: "foo",
Value: "bar",
}},
}
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour)
assert.True(t, needRefresh)
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
assert.Equal(t, CompareWithLatest, compareWith)
}
}
func TestRefreshAppConditions(t *testing.T) {
@@ -651,3 +670,63 @@ func TestRefreshAppConditions(t *testing.T) {
assert.Equal(t, "Application referencing project wrong project which does not exist", app.Status.Conditions[0].Message)
})
}
func TestUpdateReconciledAt(t *testing.T) {
app := newFakeApp()
reconciledAt := metav1.NewTime(time.Now().Add(-1 * time.Second))
app.Status = argoappv1.ApplicationStatus{ReconciledAt: &reconciledAt}
app.Status.Sync = argoappv1.SyncStatus{ComparedTo: argoappv1.ComparedTo{Source: app.Spec.Source, Destination: app.Spec.Destination}}
ctrl := newFakeController(&fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
Namespace: test.FakeDestNamespace,
Server: test.FakeClusterURL,
Revision: "abc123",
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
})
key, _ := cache.MetaNamespaceKeyFunc(app)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
fakeAppCs.ReactionChain = nil
receivedPatch := map[string]interface{}{}
fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
if patchAction, ok := action.(kubetesting.PatchAction); ok {
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
}
return true, nil, nil
})
t.Run("UpdatedOnFullReconciliation", func(t *testing.T) {
receivedPatch = map[string]interface{}{}
ctrl.requestAppRefresh(app.Name, CompareWithLatest)
ctrl.appRefreshQueue.Add(key)
ctrl.processAppRefreshQueueItem()
_, updated, err := unstructured.NestedString(receivedPatch, "status", "reconciledAt")
assert.NoError(t, err)
assert.True(t, updated)
_, updated, err = unstructured.NestedString(receivedPatch, "status", "observedAt")
assert.NoError(t, err)
assert.True(t, updated)
})
t.Run("NotUpdatedOnPartialReconciliation", func(t *testing.T) {
receivedPatch = map[string]interface{}{}
ctrl.appRefreshQueue.Add(key)
ctrl.requestAppRefresh(app.Name, CompareWithRecent)
ctrl.processAppRefreshQueueItem()
_, updated, err := unstructured.NestedString(receivedPatch, "status", "reconciledAt")
assert.NoError(t, err)
assert.False(t, updated)
_, updated, err = unstructured.NestedString(receivedPatch, "status", "observedAt")
assert.NoError(t, err)
assert.True(t, updated)
})
}

View File

@@ -63,7 +63,6 @@ type AppStateManager interface {
}
type comparisonResult struct {
reconciledAt metav1.Time
syncStatus *v1alpha1.SyncStatus
healthStatus *v1alpha1.HealthStatus
resources []v1alpha1.ResourceStatus
@@ -275,13 +274,11 @@ func (m *appStateManager) getComparisonSettings(app *appv1.Application) (string,
// revision and supplied source. If revision or overrides are empty, then compares against
// revision and overrides in the app spec.
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, noCache bool, localManifests []string) *comparisonResult {
reconciledAt := metav1.Now()
appLabelKey, resourceOverrides, diffNormalizer, err := m.getComparisonSettings(app)
// return unknown comparison result if basic comparison settings cannot be loaded
if err != nil {
return &comparisonResult{
reconciledAt: reconciledAt,
syncStatus: &v1alpha1.SyncStatus{
ComparedTo: appv1.ComparedTo{Source: source, Destination: app.Spec.Destination},
Status: appv1.SyncStatusCodeUnknown,
@@ -435,6 +432,10 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision st
} else {
resState.Status = v1alpha1.SyncStatusCodeSynced
}
// we can't say anything about the status if we were unable to get the target objects
if failedToLoadObjs {
resState.Status = v1alpha1.SyncStatusCodeUnknown
}
managedResources[i] = managedResource{
Name: resState.Name,
Namespace: resState.Namespace,
@@ -472,7 +473,6 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision st
}
compRes := comparisonResult{
reconciledAt: reconciledAt,
syncStatus: &syncStatus,
healthStatus: healthStatus,
resources: resourceSummaries,

View File

@@ -354,7 +354,6 @@ func TestReturnUnknownComparisonStateOnSettingLoadError(t *testing.T) {
assert.Equal(t, argoappv1.HealthStatusUnknown, compRes.healthStatus.Status)
assert.Equal(t, argoappv1.SyncStatusCodeUnknown, compRes.syncStatus.Status)
assert.NotNil(t, compRes.reconciledAt)
}
func TestSetManagedResourcesKnownOrphanedResourceExceptions(t *testing.T) {

View File

@@ -1,7 +1,7 @@
#!/bin/bash
set -eux -o pipefail
[ -e $DOWNLOADS/helm.tar.gz ] || curl -sLf --retry 3 -o $DOWNLOADS/helm.tar.gz https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz
[ -e $DOWNLOADS/helm.tar.gz ] || curl -sLf --retry 3 -o $DOWNLOADS/helm.tar.gz https://storage.googleapis.com/kubernetes-helm/helm-v2.15.2-linux-amd64.tar.gz
tar -C /tmp/ -xf $DOWNLOADS/helm.tar.gz
cp /tmp/linux-amd64/helm $BIN/helm
helm version --client

View File

@@ -12,7 +12,7 @@ bases:
images:
- name: argoproj/argocd
newName: argoproj/argocd
newTag: latest
newTag: v1.3.0-rc4
- name: argoproj/argocd-ui
newName: argoproj/argocd-ui
newTag: latest
newTag: v1.3.0-rc4

View File

@@ -1032,6 +1032,8 @@ spec:
type: object
type: array
observedAt:
description: ObservedAt indicates when the application state was updated
without querying latest git state
format: date-time
type: string
operationState:
@@ -1509,6 +1511,8 @@ spec:
- startedAt
type: object
reconciledAt:
description: ReconciledAt indicates when the application state was reconciled
using the latest git version
format: date-time
type: string
resources:

View File

@@ -18,7 +18,7 @@ bases:
images:
- name: argoproj/argocd
newName: argoproj/argocd
newTag: latest
newTag: v1.3.0-rc4
- name: argoproj/argocd-ui
newName: argoproj/argocd-ui
newTag: latest
newTag: v1.3.0-rc4

View File

@@ -1033,6 +1033,8 @@ spec:
type: object
type: array
observedAt:
description: ObservedAt indicates when the application state was updated
without querying latest git state
format: date-time
type: string
operationState:
@@ -1510,6 +1512,8 @@ spec:
- startedAt
type: object
reconciledAt:
description: ReconciledAt indicates when the application state was reconciled
using the latest git version
format: date-time
type: string
resources:
@@ -2978,7 +2982,7 @@ spec:
- argocd-redis-ha-announce-2:26379
- --sentinelmaster
- argocd
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -3032,7 +3036,7 @@ spec:
- cp
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -3088,7 +3092,7 @@ spec:
- argocd-redis-ha-announce-2:26379
- --sentinelmaster
- argocd
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 5
@@ -3162,7 +3166,7 @@ spec:
- argocd-redis-ha-announce-2:26379
- --sentinelmaster
- argocd
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -1033,6 +1033,8 @@ spec:
type: object
type: array
observedAt:
description: ObservedAt indicates when the application state was updated
without querying latest git state
format: date-time
type: string
operationState:
@@ -1510,6 +1512,8 @@ spec:
- startedAt
type: object
reconciledAt:
description: ReconciledAt indicates when the application state was reconciled
using the latest git version
format: date-time
type: string
resources:
@@ -2893,7 +2897,7 @@ spec:
- argocd-redis-ha-announce-2:26379
- --sentinelmaster
- argocd
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2947,7 +2951,7 @@ spec:
- cp
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -3003,7 +3007,7 @@ spec:
- argocd-redis-ha-announce-2:26379
- --sentinelmaster
- argocd
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 5
@@ -3077,7 +3081,7 @@ spec:
- argocd-redis-ha-announce-2:26379
- --sentinelmaster
- argocd
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -1033,6 +1033,8 @@ spec:
type: object
type: array
observedAt:
description: ObservedAt indicates when the application state was updated
without querying latest git state
format: date-time
type: string
operationState:
@@ -1510,6 +1512,8 @@ spec:
- startedAt
type: object
reconciledAt:
description: ReconciledAt indicates when the application state was reconciled
using the latest git version
format: date-time
type: string
resources:
@@ -2742,7 +2746,7 @@ spec:
- "20"
- --operation-processors
- "10"
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2796,7 +2800,7 @@ spec:
- cp
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -2860,7 +2864,7 @@ spec:
- argocd-repo-server
- --redis
- argocd-redis:6379
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 5
@@ -2911,7 +2915,7 @@ spec:
- argocd-server
- --staticassets
- /shared/app
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -1033,6 +1033,8 @@ spec:
type: object
type: array
observedAt:
description: ObservedAt indicates when the application state was updated
without querying latest git state
format: date-time
type: string
operationState:
@@ -1510,6 +1512,8 @@ spec:
- startedAt
type: object
reconciledAt:
description: ReconciledAt indicates when the application state was reconciled
using the latest git version
format: date-time
type: string
resources:
@@ -2657,7 +2661,7 @@ spec:
- "20"
- --operation-processors
- "10"
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2711,7 +2715,7 @@ spec:
- cp
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -2775,7 +2779,7 @@ spec:
- argocd-repo-server
- --redis
- argocd-redis:6379
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 5
@@ -2826,7 +2830,7 @@ spec:
- argocd-server
- --staticassets
- /shared/app
image: argoproj/argocd:latest
image: argoproj/argocd:v1.3.0-rc4
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -33,7 +33,7 @@ const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
func (m *AWSAuthConfig) Reset() { *m = AWSAuthConfig{} }
func (*AWSAuthConfig) ProtoMessage() {}
func (*AWSAuthConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{0}
return fileDescriptor_generated_b34c2064a02cfa33, []int{0}
}
func (m *AWSAuthConfig) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -61,7 +61,7 @@ var xxx_messageInfo_AWSAuthConfig proto.InternalMessageInfo
func (m *AppProject) Reset() { *m = AppProject{} }
func (*AppProject) ProtoMessage() {}
func (*AppProject) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{1}
return fileDescriptor_generated_b34c2064a02cfa33, []int{1}
}
func (m *AppProject) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -89,7 +89,7 @@ var xxx_messageInfo_AppProject proto.InternalMessageInfo
func (m *AppProjectList) Reset() { *m = AppProjectList{} }
func (*AppProjectList) ProtoMessage() {}
func (*AppProjectList) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{2}
return fileDescriptor_generated_b34c2064a02cfa33, []int{2}
}
func (m *AppProjectList) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -117,7 +117,7 @@ var xxx_messageInfo_AppProjectList proto.InternalMessageInfo
func (m *AppProjectSpec) Reset() { *m = AppProjectSpec{} }
func (*AppProjectSpec) ProtoMessage() {}
func (*AppProjectSpec) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{3}
return fileDescriptor_generated_b34c2064a02cfa33, []int{3}
}
func (m *AppProjectSpec) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -145,7 +145,7 @@ var xxx_messageInfo_AppProjectSpec proto.InternalMessageInfo
func (m *Application) Reset() { *m = Application{} }
func (*Application) ProtoMessage() {}
func (*Application) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{4}
return fileDescriptor_generated_b34c2064a02cfa33, []int{4}
}
func (m *Application) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -173,7 +173,7 @@ var xxx_messageInfo_Application proto.InternalMessageInfo
func (m *ApplicationCondition) Reset() { *m = ApplicationCondition{} }
func (*ApplicationCondition) ProtoMessage() {}
func (*ApplicationCondition) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{5}
return fileDescriptor_generated_b34c2064a02cfa33, []int{5}
}
func (m *ApplicationCondition) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -201,7 +201,7 @@ var xxx_messageInfo_ApplicationCondition proto.InternalMessageInfo
func (m *ApplicationDestination) Reset() { *m = ApplicationDestination{} }
func (*ApplicationDestination) ProtoMessage() {}
func (*ApplicationDestination) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{6}
return fileDescriptor_generated_b34c2064a02cfa33, []int{6}
}
func (m *ApplicationDestination) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -229,7 +229,7 @@ var xxx_messageInfo_ApplicationDestination proto.InternalMessageInfo
func (m *ApplicationList) Reset() { *m = ApplicationList{} }
func (*ApplicationList) ProtoMessage() {}
func (*ApplicationList) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{7}
return fileDescriptor_generated_b34c2064a02cfa33, []int{7}
}
func (m *ApplicationList) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -257,7 +257,7 @@ var xxx_messageInfo_ApplicationList proto.InternalMessageInfo
func (m *ApplicationSource) Reset() { *m = ApplicationSource{} }
func (*ApplicationSource) ProtoMessage() {}
func (*ApplicationSource) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{8}
return fileDescriptor_generated_b34c2064a02cfa33, []int{8}
}
func (m *ApplicationSource) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -285,7 +285,7 @@ var xxx_messageInfo_ApplicationSource proto.InternalMessageInfo
func (m *ApplicationSourceDirectory) Reset() { *m = ApplicationSourceDirectory{} }
func (*ApplicationSourceDirectory) ProtoMessage() {}
func (*ApplicationSourceDirectory) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{9}
return fileDescriptor_generated_b34c2064a02cfa33, []int{9}
}
func (m *ApplicationSourceDirectory) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -313,7 +313,7 @@ var xxx_messageInfo_ApplicationSourceDirectory proto.InternalMessageInfo
func (m *ApplicationSourceHelm) Reset() { *m = ApplicationSourceHelm{} }
func (*ApplicationSourceHelm) ProtoMessage() {}
func (*ApplicationSourceHelm) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{10}
return fileDescriptor_generated_b34c2064a02cfa33, []int{10}
}
func (m *ApplicationSourceHelm) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -341,7 +341,7 @@ var xxx_messageInfo_ApplicationSourceHelm proto.InternalMessageInfo
func (m *ApplicationSourceJsonnet) Reset() { *m = ApplicationSourceJsonnet{} }
func (*ApplicationSourceJsonnet) ProtoMessage() {}
func (*ApplicationSourceJsonnet) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{11}
return fileDescriptor_generated_b34c2064a02cfa33, []int{11}
}
func (m *ApplicationSourceJsonnet) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -369,7 +369,7 @@ var xxx_messageInfo_ApplicationSourceJsonnet proto.InternalMessageInfo
func (m *ApplicationSourceKsonnet) Reset() { *m = ApplicationSourceKsonnet{} }
func (*ApplicationSourceKsonnet) ProtoMessage() {}
func (*ApplicationSourceKsonnet) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{12}
return fileDescriptor_generated_b34c2064a02cfa33, []int{12}
}
func (m *ApplicationSourceKsonnet) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -397,7 +397,7 @@ var xxx_messageInfo_ApplicationSourceKsonnet proto.InternalMessageInfo
func (m *ApplicationSourceKustomize) Reset() { *m = ApplicationSourceKustomize{} }
func (*ApplicationSourceKustomize) ProtoMessage() {}
func (*ApplicationSourceKustomize) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{13}
return fileDescriptor_generated_b34c2064a02cfa33, []int{13}
}
func (m *ApplicationSourceKustomize) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -425,7 +425,7 @@ var xxx_messageInfo_ApplicationSourceKustomize proto.InternalMessageInfo
func (m *ApplicationSourcePlugin) Reset() { *m = ApplicationSourcePlugin{} }
func (*ApplicationSourcePlugin) ProtoMessage() {}
func (*ApplicationSourcePlugin) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{14}
return fileDescriptor_generated_b34c2064a02cfa33, []int{14}
}
func (m *ApplicationSourcePlugin) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -453,7 +453,7 @@ var xxx_messageInfo_ApplicationSourcePlugin proto.InternalMessageInfo
func (m *ApplicationSpec) Reset() { *m = ApplicationSpec{} }
func (*ApplicationSpec) ProtoMessage() {}
func (*ApplicationSpec) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{15}
return fileDescriptor_generated_b34c2064a02cfa33, []int{15}
}
func (m *ApplicationSpec) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -481,7 +481,7 @@ var xxx_messageInfo_ApplicationSpec proto.InternalMessageInfo
func (m *ApplicationStatus) Reset() { *m = ApplicationStatus{} }
func (*ApplicationStatus) ProtoMessage() {}
func (*ApplicationStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{16}
return fileDescriptor_generated_b34c2064a02cfa33, []int{16}
}
func (m *ApplicationStatus) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -509,7 +509,7 @@ var xxx_messageInfo_ApplicationStatus proto.InternalMessageInfo
func (m *ApplicationSummary) Reset() { *m = ApplicationSummary{} }
func (*ApplicationSummary) ProtoMessage() {}
func (*ApplicationSummary) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{17}
return fileDescriptor_generated_b34c2064a02cfa33, []int{17}
}
func (m *ApplicationSummary) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -537,7 +537,7 @@ var xxx_messageInfo_ApplicationSummary proto.InternalMessageInfo
func (m *ApplicationTree) Reset() { *m = ApplicationTree{} }
func (*ApplicationTree) ProtoMessage() {}
func (*ApplicationTree) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{18}
return fileDescriptor_generated_b34c2064a02cfa33, []int{18}
}
func (m *ApplicationTree) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -565,7 +565,7 @@ var xxx_messageInfo_ApplicationTree proto.InternalMessageInfo
func (m *ApplicationWatchEvent) Reset() { *m = ApplicationWatchEvent{} }
func (*ApplicationWatchEvent) ProtoMessage() {}
func (*ApplicationWatchEvent) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{19}
return fileDescriptor_generated_b34c2064a02cfa33, []int{19}
}
func (m *ApplicationWatchEvent) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -593,7 +593,7 @@ var xxx_messageInfo_ApplicationWatchEvent proto.InternalMessageInfo
func (m *Cluster) Reset() { *m = Cluster{} }
func (*Cluster) ProtoMessage() {}
func (*Cluster) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{20}
return fileDescriptor_generated_b34c2064a02cfa33, []int{20}
}
func (m *Cluster) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -621,7 +621,7 @@ var xxx_messageInfo_Cluster proto.InternalMessageInfo
func (m *ClusterConfig) Reset() { *m = ClusterConfig{} }
func (*ClusterConfig) ProtoMessage() {}
func (*ClusterConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{21}
return fileDescriptor_generated_b34c2064a02cfa33, []int{21}
}
func (m *ClusterConfig) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -649,7 +649,7 @@ var xxx_messageInfo_ClusterConfig proto.InternalMessageInfo
func (m *ClusterList) Reset() { *m = ClusterList{} }
func (*ClusterList) ProtoMessage() {}
func (*ClusterList) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{22}
return fileDescriptor_generated_b34c2064a02cfa33, []int{22}
}
func (m *ClusterList) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -677,7 +677,7 @@ var xxx_messageInfo_ClusterList proto.InternalMessageInfo
func (m *Command) Reset() { *m = Command{} }
func (*Command) ProtoMessage() {}
func (*Command) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{23}
return fileDescriptor_generated_b34c2064a02cfa33, []int{23}
}
func (m *Command) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -705,7 +705,7 @@ var xxx_messageInfo_Command proto.InternalMessageInfo
func (m *ComparedTo) Reset() { *m = ComparedTo{} }
func (*ComparedTo) ProtoMessage() {}
func (*ComparedTo) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{24}
return fileDescriptor_generated_b34c2064a02cfa33, []int{24}
}
func (m *ComparedTo) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -733,7 +733,7 @@ var xxx_messageInfo_ComparedTo proto.InternalMessageInfo
func (m *ComponentParameter) Reset() { *m = ComponentParameter{} }
func (*ComponentParameter) ProtoMessage() {}
func (*ComponentParameter) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{25}
return fileDescriptor_generated_b34c2064a02cfa33, []int{25}
}
func (m *ComponentParameter) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -761,7 +761,7 @@ var xxx_messageInfo_ComponentParameter proto.InternalMessageInfo
func (m *ConfigManagementPlugin) Reset() { *m = ConfigManagementPlugin{} }
func (*ConfigManagementPlugin) ProtoMessage() {}
func (*ConfigManagementPlugin) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{26}
return fileDescriptor_generated_b34c2064a02cfa33, []int{26}
}
func (m *ConfigManagementPlugin) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -789,7 +789,7 @@ var xxx_messageInfo_ConfigManagementPlugin proto.InternalMessageInfo
func (m *ConnectionState) Reset() { *m = ConnectionState{} }
func (*ConnectionState) ProtoMessage() {}
func (*ConnectionState) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{27}
return fileDescriptor_generated_b34c2064a02cfa33, []int{27}
}
func (m *ConnectionState) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -817,7 +817,7 @@ var xxx_messageInfo_ConnectionState proto.InternalMessageInfo
func (m *EnvEntry) Reset() { *m = EnvEntry{} }
func (*EnvEntry) ProtoMessage() {}
func (*EnvEntry) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{28}
return fileDescriptor_generated_b34c2064a02cfa33, []int{28}
}
func (m *EnvEntry) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -845,7 +845,7 @@ var xxx_messageInfo_EnvEntry proto.InternalMessageInfo
func (m *HealthStatus) Reset() { *m = HealthStatus{} }
func (*HealthStatus) ProtoMessage() {}
func (*HealthStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{29}
return fileDescriptor_generated_b34c2064a02cfa33, []int{29}
}
func (m *HealthStatus) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -873,7 +873,7 @@ var xxx_messageInfo_HealthStatus proto.InternalMessageInfo
func (m *HelmParameter) Reset() { *m = HelmParameter{} }
func (*HelmParameter) ProtoMessage() {}
func (*HelmParameter) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{30}
return fileDescriptor_generated_b34c2064a02cfa33, []int{30}
}
func (m *HelmParameter) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -901,7 +901,7 @@ var xxx_messageInfo_HelmParameter proto.InternalMessageInfo
func (m *Info) Reset() { *m = Info{} }
func (*Info) ProtoMessage() {}
func (*Info) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{31}
return fileDescriptor_generated_b34c2064a02cfa33, []int{31}
}
func (m *Info) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -929,7 +929,7 @@ var xxx_messageInfo_Info proto.InternalMessageInfo
func (m *InfoItem) Reset() { *m = InfoItem{} }
func (*InfoItem) ProtoMessage() {}
func (*InfoItem) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{32}
return fileDescriptor_generated_b34c2064a02cfa33, []int{32}
}
func (m *InfoItem) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -957,7 +957,7 @@ var xxx_messageInfo_InfoItem proto.InternalMessageInfo
func (m *JWTToken) Reset() { *m = JWTToken{} }
func (*JWTToken) ProtoMessage() {}
func (*JWTToken) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{33}
return fileDescriptor_generated_b34c2064a02cfa33, []int{33}
}
func (m *JWTToken) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -985,7 +985,7 @@ var xxx_messageInfo_JWTToken proto.InternalMessageInfo
func (m *JsonnetVar) Reset() { *m = JsonnetVar{} }
func (*JsonnetVar) ProtoMessage() {}
func (*JsonnetVar) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{34}
return fileDescriptor_generated_b34c2064a02cfa33, []int{34}
}
func (m *JsonnetVar) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1013,7 +1013,7 @@ var xxx_messageInfo_JsonnetVar proto.InternalMessageInfo
func (m *KsonnetParameter) Reset() { *m = KsonnetParameter{} }
func (*KsonnetParameter) ProtoMessage() {}
func (*KsonnetParameter) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{35}
return fileDescriptor_generated_b34c2064a02cfa33, []int{35}
}
func (m *KsonnetParameter) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1041,7 +1041,7 @@ var xxx_messageInfo_KsonnetParameter proto.InternalMessageInfo
func (m *KustomizeOptions) Reset() { *m = KustomizeOptions{} }
func (*KustomizeOptions) ProtoMessage() {}
func (*KustomizeOptions) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{36}
return fileDescriptor_generated_b34c2064a02cfa33, []int{36}
}
func (m *KustomizeOptions) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1069,7 +1069,7 @@ var xxx_messageInfo_KustomizeOptions proto.InternalMessageInfo
func (m *Operation) Reset() { *m = Operation{} }
func (*Operation) ProtoMessage() {}
func (*Operation) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{37}
return fileDescriptor_generated_b34c2064a02cfa33, []int{37}
}
func (m *Operation) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1097,7 +1097,7 @@ var xxx_messageInfo_Operation proto.InternalMessageInfo
func (m *OperationState) Reset() { *m = OperationState{} }
func (*OperationState) ProtoMessage() {}
func (*OperationState) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{38}
return fileDescriptor_generated_b34c2064a02cfa33, []int{38}
}
func (m *OperationState) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1125,7 +1125,7 @@ var xxx_messageInfo_OperationState proto.InternalMessageInfo
func (m *OrphanedResourcesMonitorSettings) Reset() { *m = OrphanedResourcesMonitorSettings{} }
func (*OrphanedResourcesMonitorSettings) ProtoMessage() {}
func (*OrphanedResourcesMonitorSettings) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{39}
return fileDescriptor_generated_b34c2064a02cfa33, []int{39}
}
func (m *OrphanedResourcesMonitorSettings) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1153,7 +1153,7 @@ var xxx_messageInfo_OrphanedResourcesMonitorSettings proto.InternalMessageInfo
func (m *ProjectRole) Reset() { *m = ProjectRole{} }
func (*ProjectRole) ProtoMessage() {}
func (*ProjectRole) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{40}
return fileDescriptor_generated_b34c2064a02cfa33, []int{40}
}
func (m *ProjectRole) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1181,7 +1181,7 @@ var xxx_messageInfo_ProjectRole proto.InternalMessageInfo
func (m *Repository) Reset() { *m = Repository{} }
func (*Repository) ProtoMessage() {}
func (*Repository) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{41}
return fileDescriptor_generated_b34c2064a02cfa33, []int{41}
}
func (m *Repository) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1209,7 +1209,7 @@ var xxx_messageInfo_Repository proto.InternalMessageInfo
func (m *RepositoryCertificate) Reset() { *m = RepositoryCertificate{} }
func (*RepositoryCertificate) ProtoMessage() {}
func (*RepositoryCertificate) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{42}
return fileDescriptor_generated_b34c2064a02cfa33, []int{42}
}
func (m *RepositoryCertificate) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1237,7 +1237,7 @@ var xxx_messageInfo_RepositoryCertificate proto.InternalMessageInfo
func (m *RepositoryCertificateList) Reset() { *m = RepositoryCertificateList{} }
func (*RepositoryCertificateList) ProtoMessage() {}
func (*RepositoryCertificateList) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{43}
return fileDescriptor_generated_b34c2064a02cfa33, []int{43}
}
func (m *RepositoryCertificateList) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1265,7 +1265,7 @@ var xxx_messageInfo_RepositoryCertificateList proto.InternalMessageInfo
func (m *RepositoryList) Reset() { *m = RepositoryList{} }
func (*RepositoryList) ProtoMessage() {}
func (*RepositoryList) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{44}
return fileDescriptor_generated_b34c2064a02cfa33, []int{44}
}
func (m *RepositoryList) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1293,7 +1293,7 @@ var xxx_messageInfo_RepositoryList proto.InternalMessageInfo
func (m *ResourceAction) Reset() { *m = ResourceAction{} }
func (*ResourceAction) ProtoMessage() {}
func (*ResourceAction) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{45}
return fileDescriptor_generated_b34c2064a02cfa33, []int{45}
}
func (m *ResourceAction) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1321,7 +1321,7 @@ var xxx_messageInfo_ResourceAction proto.InternalMessageInfo
func (m *ResourceActionDefinition) Reset() { *m = ResourceActionDefinition{} }
func (*ResourceActionDefinition) ProtoMessage() {}
func (*ResourceActionDefinition) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{46}
return fileDescriptor_generated_b34c2064a02cfa33, []int{46}
}
func (m *ResourceActionDefinition) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1349,7 +1349,7 @@ var xxx_messageInfo_ResourceActionDefinition proto.InternalMessageInfo
func (m *ResourceActionParam) Reset() { *m = ResourceActionParam{} }
func (*ResourceActionParam) ProtoMessage() {}
func (*ResourceActionParam) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{47}
return fileDescriptor_generated_b34c2064a02cfa33, []int{47}
}
func (m *ResourceActionParam) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1377,7 +1377,7 @@ var xxx_messageInfo_ResourceActionParam proto.InternalMessageInfo
func (m *ResourceActions) Reset() { *m = ResourceActions{} }
func (*ResourceActions) ProtoMessage() {}
func (*ResourceActions) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{48}
return fileDescriptor_generated_b34c2064a02cfa33, []int{48}
}
func (m *ResourceActions) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1405,7 +1405,7 @@ var xxx_messageInfo_ResourceActions proto.InternalMessageInfo
func (m *ResourceDiff) Reset() { *m = ResourceDiff{} }
func (*ResourceDiff) ProtoMessage() {}
func (*ResourceDiff) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{49}
return fileDescriptor_generated_b34c2064a02cfa33, []int{49}
}
func (m *ResourceDiff) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1433,7 +1433,7 @@ var xxx_messageInfo_ResourceDiff proto.InternalMessageInfo
func (m *ResourceIgnoreDifferences) Reset() { *m = ResourceIgnoreDifferences{} }
func (*ResourceIgnoreDifferences) ProtoMessage() {}
func (*ResourceIgnoreDifferences) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{50}
return fileDescriptor_generated_b34c2064a02cfa33, []int{50}
}
func (m *ResourceIgnoreDifferences) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1461,7 +1461,7 @@ var xxx_messageInfo_ResourceIgnoreDifferences proto.InternalMessageInfo
func (m *ResourceNetworkingInfo) Reset() { *m = ResourceNetworkingInfo{} }
func (*ResourceNetworkingInfo) ProtoMessage() {}
func (*ResourceNetworkingInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{51}
return fileDescriptor_generated_b34c2064a02cfa33, []int{51}
}
func (m *ResourceNetworkingInfo) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1489,7 +1489,7 @@ var xxx_messageInfo_ResourceNetworkingInfo proto.InternalMessageInfo
func (m *ResourceNode) Reset() { *m = ResourceNode{} }
func (*ResourceNode) ProtoMessage() {}
func (*ResourceNode) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{52}
return fileDescriptor_generated_b34c2064a02cfa33, []int{52}
}
func (m *ResourceNode) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1517,7 +1517,7 @@ var xxx_messageInfo_ResourceNode proto.InternalMessageInfo
func (m *ResourceOverride) Reset() { *m = ResourceOverride{} }
func (*ResourceOverride) ProtoMessage() {}
func (*ResourceOverride) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{53}
return fileDescriptor_generated_b34c2064a02cfa33, []int{53}
}
func (m *ResourceOverride) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1545,7 +1545,7 @@ var xxx_messageInfo_ResourceOverride proto.InternalMessageInfo
func (m *ResourceRef) Reset() { *m = ResourceRef{} }
func (*ResourceRef) ProtoMessage() {}
func (*ResourceRef) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{54}
return fileDescriptor_generated_b34c2064a02cfa33, []int{54}
}
func (m *ResourceRef) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1573,7 +1573,7 @@ var xxx_messageInfo_ResourceRef proto.InternalMessageInfo
func (m *ResourceResult) Reset() { *m = ResourceResult{} }
func (*ResourceResult) ProtoMessage() {}
func (*ResourceResult) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{55}
return fileDescriptor_generated_b34c2064a02cfa33, []int{55}
}
func (m *ResourceResult) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1601,7 +1601,7 @@ var xxx_messageInfo_ResourceResult proto.InternalMessageInfo
func (m *ResourceStatus) Reset() { *m = ResourceStatus{} }
func (*ResourceStatus) ProtoMessage() {}
func (*ResourceStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{56}
return fileDescriptor_generated_b34c2064a02cfa33, []int{56}
}
func (m *ResourceStatus) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1629,7 +1629,7 @@ var xxx_messageInfo_ResourceStatus proto.InternalMessageInfo
func (m *RevisionHistory) Reset() { *m = RevisionHistory{} }
func (*RevisionHistory) ProtoMessage() {}
func (*RevisionHistory) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{57}
return fileDescriptor_generated_b34c2064a02cfa33, []int{57}
}
func (m *RevisionHistory) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1657,7 +1657,7 @@ var xxx_messageInfo_RevisionHistory proto.InternalMessageInfo
func (m *RevisionMetadata) Reset() { *m = RevisionMetadata{} }
func (*RevisionMetadata) ProtoMessage() {}
func (*RevisionMetadata) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{58}
return fileDescriptor_generated_b34c2064a02cfa33, []int{58}
}
func (m *RevisionMetadata) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1685,7 +1685,7 @@ var xxx_messageInfo_RevisionMetadata proto.InternalMessageInfo
func (m *SyncOperation) Reset() { *m = SyncOperation{} }
func (*SyncOperation) ProtoMessage() {}
func (*SyncOperation) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{59}
return fileDescriptor_generated_b34c2064a02cfa33, []int{59}
}
func (m *SyncOperation) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1713,7 +1713,7 @@ var xxx_messageInfo_SyncOperation proto.InternalMessageInfo
func (m *SyncOperationResource) Reset() { *m = SyncOperationResource{} }
func (*SyncOperationResource) ProtoMessage() {}
func (*SyncOperationResource) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{60}
return fileDescriptor_generated_b34c2064a02cfa33, []int{60}
}
func (m *SyncOperationResource) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1741,7 +1741,7 @@ var xxx_messageInfo_SyncOperationResource proto.InternalMessageInfo
func (m *SyncOperationResult) Reset() { *m = SyncOperationResult{} }
func (*SyncOperationResult) ProtoMessage() {}
func (*SyncOperationResult) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{61}
return fileDescriptor_generated_b34c2064a02cfa33, []int{61}
}
func (m *SyncOperationResult) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1769,7 +1769,7 @@ var xxx_messageInfo_SyncOperationResult proto.InternalMessageInfo
func (m *SyncPolicy) Reset() { *m = SyncPolicy{} }
func (*SyncPolicy) ProtoMessage() {}
func (*SyncPolicy) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{62}
return fileDescriptor_generated_b34c2064a02cfa33, []int{62}
}
func (m *SyncPolicy) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1797,7 +1797,7 @@ var xxx_messageInfo_SyncPolicy proto.InternalMessageInfo
func (m *SyncPolicyAutomated) Reset() { *m = SyncPolicyAutomated{} }
func (*SyncPolicyAutomated) ProtoMessage() {}
func (*SyncPolicyAutomated) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{63}
return fileDescriptor_generated_b34c2064a02cfa33, []int{63}
}
func (m *SyncPolicyAutomated) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1825,7 +1825,7 @@ var xxx_messageInfo_SyncPolicyAutomated proto.InternalMessageInfo
func (m *SyncStatus) Reset() { *m = SyncStatus{} }
func (*SyncStatus) ProtoMessage() {}
func (*SyncStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{64}
return fileDescriptor_generated_b34c2064a02cfa33, []int{64}
}
func (m *SyncStatus) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1853,7 +1853,7 @@ var xxx_messageInfo_SyncStatus proto.InternalMessageInfo
func (m *SyncStrategy) Reset() { *m = SyncStrategy{} }
func (*SyncStrategy) ProtoMessage() {}
func (*SyncStrategy) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{65}
return fileDescriptor_generated_b34c2064a02cfa33, []int{65}
}
func (m *SyncStrategy) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1881,7 +1881,7 @@ var xxx_messageInfo_SyncStrategy proto.InternalMessageInfo
func (m *SyncStrategyApply) Reset() { *m = SyncStrategyApply{} }
func (*SyncStrategyApply) ProtoMessage() {}
func (*SyncStrategyApply) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{66}
return fileDescriptor_generated_b34c2064a02cfa33, []int{66}
}
func (m *SyncStrategyApply) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1909,7 +1909,7 @@ var xxx_messageInfo_SyncStrategyApply proto.InternalMessageInfo
func (m *SyncStrategyHook) Reset() { *m = SyncStrategyHook{} }
func (*SyncStrategyHook) ProtoMessage() {}
func (*SyncStrategyHook) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{67}
return fileDescriptor_generated_b34c2064a02cfa33, []int{67}
}
func (m *SyncStrategyHook) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1937,7 +1937,7 @@ var xxx_messageInfo_SyncStrategyHook proto.InternalMessageInfo
func (m *SyncWindow) Reset() { *m = SyncWindow{} }
func (*SyncWindow) ProtoMessage() {}
func (*SyncWindow) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{68}
return fileDescriptor_generated_b34c2064a02cfa33, []int{68}
}
func (m *SyncWindow) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1965,7 +1965,7 @@ var xxx_messageInfo_SyncWindow proto.InternalMessageInfo
func (m *TLSClientConfig) Reset() { *m = TLSClientConfig{} }
func (*TLSClientConfig) ProtoMessage() {}
func (*TLSClientConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_generated_622b11e42e23cc72, []int{69}
return fileDescriptor_generated_b34c2064a02cfa33, []int{69}
}
func (m *TLSClientConfig) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -18635,10 +18635,10 @@ var (
)
func init() {
proto.RegisterFile("github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1/generated.proto", fileDescriptor_generated_622b11e42e23cc72)
proto.RegisterFile("github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1/generated.proto", fileDescriptor_generated_b34c2064a02cfa33)
}
var fileDescriptor_generated_622b11e42e23cc72 = []byte{
var fileDescriptor_generated_b34c2064a02cfa33 = []byte{
// 4679 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x3c, 0x5b, 0x8c, 0x1c, 0xd9,
0x55, 0xae, 0x7e, 0xcf, 0x99, 0x87, 0x3d, 0x77, 0xd7, 0x9b, 0xce, 0x68, 0xe3, 0xb1, 0xca, 0x4a,

View File

@@ -236,10 +236,12 @@ message ApplicationStatus {
repeated ApplicationCondition conditions = 5;
// ReconciledAt indicates when the application state was reconciled using the latest git version
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time reconciledAt = 6;
optional OperationState operationState = 7;
// ObservedAt indicates when the application state was updated without querying latest git state
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time observedAt = 8;
optional string sourceType = 9;

View File

@@ -895,7 +895,8 @@ func schema_pkg_apis_application_v1alpha1_ApplicationStatus(ref common.Reference
},
"reconciledAt": {
SchemaProps: spec.SchemaProps{
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
Description: "ReconciledAt indicates when the application state was reconciled using the latest git version",
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
},
},
"operationState": {
@@ -905,7 +906,8 @@ func schema_pkg_apis_application_v1alpha1_ApplicationStatus(ref common.Reference
},
"observedAt": {
SchemaProps: spec.SchemaProps{
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
Description: "ObservedAt indicates when the application state was updated without querying latest git state",
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
},
},
"sourceType": {

View File

@@ -331,16 +331,18 @@ type ApplicationDestination struct {
// ApplicationStatus contains information about application sync, health status
type ApplicationStatus struct {
Resources []ResourceStatus `json:"resources,omitempty" protobuf:"bytes,1,opt,name=resources"`
Sync SyncStatus `json:"sync,omitempty" protobuf:"bytes,2,opt,name=sync"`
Health HealthStatus `json:"health,omitempty" protobuf:"bytes,3,opt,name=health"`
History []RevisionHistory `json:"history,omitempty" protobuf:"bytes,4,opt,name=history"`
Conditions []ApplicationCondition `json:"conditions,omitempty" protobuf:"bytes,5,opt,name=conditions"`
ReconciledAt *metav1.Time `json:"reconciledAt,omitempty" protobuf:"bytes,6,opt,name=reconciledAt"`
OperationState *OperationState `json:"operationState,omitempty" protobuf:"bytes,7,opt,name=operationState"`
ObservedAt *metav1.Time `json:"observedAt,omitempty" protobuf:"bytes,8,opt,name=observedAt"`
SourceType ApplicationSourceType `json:"sourceType,omitempty" protobuf:"bytes,9,opt,name=sourceType"`
Summary ApplicationSummary `json:"summary,omitempty" protobuf:"bytes,10,opt,name=summary"`
Resources []ResourceStatus `json:"resources,omitempty" protobuf:"bytes,1,opt,name=resources"`
Sync SyncStatus `json:"sync,omitempty" protobuf:"bytes,2,opt,name=sync"`
Health HealthStatus `json:"health,omitempty" protobuf:"bytes,3,opt,name=health"`
History []RevisionHistory `json:"history,omitempty" protobuf:"bytes,4,opt,name=history"`
Conditions []ApplicationCondition `json:"conditions,omitempty" protobuf:"bytes,5,opt,name=conditions"`
// ReconciledAt indicates when the application state was reconciled using the latest git version
ReconciledAt *metav1.Time `json:"reconciledAt,omitempty" protobuf:"bytes,6,opt,name=reconciledAt"`
OperationState *OperationState `json:"operationState,omitempty" protobuf:"bytes,7,opt,name=operationState"`
// ObservedAt indicates when the application state was updated without querying latest git state
ObservedAt *metav1.Time `json:"observedAt,omitempty" protobuf:"bytes,8,opt,name=observedAt"`
SourceType ApplicationSourceType `json:"sourceType,omitempty" protobuf:"bytes,9,opt,name=sourceType"`
Summary ApplicationSummary `json:"summary,omitempty" protobuf:"bytes,10,opt,name=summary"`
}
// Operation contains requested operation parameters.

View File

@@ -257,8 +257,6 @@ func TestAppProject_InvalidPolicyRules(t *testing.T) {
errmsg string
}
badPolicies := []badPolicy{
// should have spaces
{"p,proj:my-proj:my-role,applications,get,my-proj/*,allow", "syntax"},
// incorrect form
{"g, proj:my-proj:my-role, applications, get, my-proj/*, allow", "must be of the form: 'p, sub, res, act, obj, eft'"},
{"p, not, enough, parts", "must be of the form: 'p, sub, res, act, obj, eft'"},

View File

@@ -111,6 +111,7 @@ type operationSettings struct {
// runRepoOperation downloads either git folder or helm chart and executes specified operation
func (s *Service) runRepoOperation(
c context.Context,
revision string,
repo *v1alpha1.Repository,
source *v1alpha1.ApplicationSource,
getCached func(revision string) bool,
@@ -119,9 +120,9 @@ func (s *Service) runRepoOperation(
var gitClient git.Client
var err error
revision := source.TargetRevision
revision = util.FirstNonEmpty(revision, source.TargetRevision)
if !source.IsHelm() {
gitClient, revision, err = s.newClientResolveRevision(repo, source.TargetRevision)
gitClient, revision, err = s.newClientResolveRevision(repo, revision)
if err != nil {
return err
}
@@ -188,7 +189,7 @@ func (s *Service) GenerateManifest(c context.Context, q *apiclient.ManifestReque
}
return false
}
err := s.runRepoOperation(c, q.Repo, q.ApplicationSource, getCached, func(appPath string, revision string) error {
err := s.runRepoOperation(c, q.Revision, q.Repo, q.ApplicationSource, getCached, func(appPath string, revision string) error {
var err error
res, err = GenerateManifests(appPath, q)
if err != nil {
@@ -584,7 +585,7 @@ func (s *Service) GetAppDetails(ctx context.Context, q *apiclient.RepoServerAppD
return false
}
err := s.runRepoOperation(ctx, q.Repo, q.Source, getCached, func(appPath string, revision string) error {
err := s.runRepoOperation(ctx, q.Source.TargetRevision, q.Repo, q.Source, getCached, func(appPath string, revision string) error {
appSourceType, err := GetAppSourceType(q.Source, appPath)
if err != nil {
return err

View File

@@ -88,6 +88,19 @@ func TestGenerateYamlManifestInDir(t *testing.T) {
}
}
func TestGenerateManifestsUseExactRevision(t *testing.T) {
service, gitClient, _ := newServiceWithMocks(".")
src := argoappv1.ApplicationSource{Path: "./testdata/recurse", Directory: &argoappv1.ApplicationSourceDirectory{Recurse: true}}
q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, Revision: "abc"}
res1, err := service.GenerateManifest(context.Background(), &q)
assert.Nil(t, err)
assert.Equal(t, 2, len(res1.Manifests))
assert.Equal(t, gitClient.Calls[0].Arguments[0], "abc")
}
func TestRecurseManifestsInDir(t *testing.T) {
service := newService(".")

View File

@@ -41,37 +41,38 @@ func NewServer(db db.ArgoDB, enf *rbac.Enforcer, cache *cache.Cache, kubectl kub
}
}
func (s *Server) getConnectionState(cluster appv1.Cluster, errorMessage string) appv1.ConnectionState {
if connectionState, err := s.cache.GetClusterConnectionState(cluster.Server); err == nil {
return connectionState
func (s *Server) getConnectionState(cluster appv1.Cluster, errorMessage string) (appv1.ConnectionState, string) {
if clusterInfo, err := s.cache.GetClusterInfo(cluster.Server); err == nil {
return clusterInfo.ConnectionState, clusterInfo.Version
}
now := v1.Now()
connectionState := appv1.ConnectionState{
Status: appv1.ConnectionStatusSuccessful,
ModifiedAt: &now,
clusterInfo := cache.ClusterInfo{
ConnectionState: appv1.ConnectionState{
Status: appv1.ConnectionStatusSuccessful,
ModifiedAt: &now,
},
}
config := cluster.RESTConfig()
config.Timeout = time.Second
kubeClientset, err := kubernetes.NewForConfig(config)
if err == nil {
_, err = kubeClientset.Discovery().ServerVersion()
}
version, err := s.kubectl.GetServerVersion(config)
if err != nil {
connectionState.Status = appv1.ConnectionStatusFailed
connectionState.Message = fmt.Sprintf("Unable to connect to cluster: %v", err)
clusterInfo.Status = appv1.ConnectionStatusFailed
clusterInfo.Message = fmt.Sprintf("Unable to connect to cluster: %v", err)
} else {
clusterInfo.Version = version
}
if errorMessage != "" {
connectionState.Status = appv1.ConnectionStatusFailed
connectionState.Message = fmt.Sprintf("%s %s", errorMessage, connectionState.Message)
clusterInfo.Status = appv1.ConnectionStatusFailed
clusterInfo.Message = fmt.Sprintf("%s %s", errorMessage, clusterInfo.Message)
}
err = s.cache.SetClusterConnectionState(cluster.Server, &connectionState)
err = s.cache.SetClusterInfo(cluster.Server, &clusterInfo)
if err != nil {
log.Warnf("getConnectionState cache set error %s: %v", cluster.Server, err)
log.Warnf("getClusterInfo cache set error %s: %v", cluster.Server, err)
}
return connectionState
return clusterInfo.ConnectionState, clusterInfo.Version
}
// List returns list of clusters
@@ -100,11 +101,9 @@ func (s *Server) List(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Clus
warningMessage = fmt.Sprintf("There are %d credentials configured this cluster.", len(clusters))
}
if clust.ConnectionState.Status == "" {
clust.ConnectionState = s.getConnectionState(clust, warningMessage)
}
clust.ServerVersion, err = s.kubectl.GetServerVersion(clust.RESTConfig())
if err != nil {
return err
state, serverVersion := s.getConnectionState(clust, warningMessage)
clust.ConnectionState = state
clust.ServerVersion = serverVersion
}
items[i] = *redact(&clust)
return nil

View File

@@ -10,6 +10,7 @@ import (
"google.golang.org/grpc/status"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/argoproj/argo-cd/common"
repositorypkg "github.com/argoproj/argo-cd/pkg/apiclient/repository"
appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/reposerver/apiclient"
@@ -82,10 +83,15 @@ func (s *Server) List(ctx context.Context, q *repositorypkg.RepoQuery) (*appsv1.
items := appsv1.Repositories{}
for _, repo := range repos {
if s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceRepositories, rbacpolicy.ActionGet, repo.Repo) {
// For backwards compatibility, if we have no repo type set assume a default
rType := repo.Type
if rType == "" {
rType = common.DefaultRepoType
}
// remove secrets
items = append(items, &appsv1.Repository{
Repo: repo.Repo,
Type: repo.Type,
Type: rType,
Name: repo.Name,
Username: repo.Username,
Insecure: repo.IsInsecure(),
@@ -222,7 +228,10 @@ func (s *Server) Create(ctx context.Context, q *repositorypkg.RepoCreateRequest)
return nil, status.Errorf(codes.InvalidArgument, "existing repository spec is different; use upsert flag to force update")
}
}
return &appsv1.Repository{Repo: repo.Repo, Type: repo.Type, Name: repo.Name}, err
if err != nil {
return nil, err
}
return &appsv1.Repository{Repo: repo.Repo, Type: repo.Type, Name: repo.Name}, nil
}
// Update updates a repository

View File

@@ -478,7 +478,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
// TranslateGrpcCookieHeader conditionally sets a cookie on the response.
func (a *ArgoCDServer) translateGrpcCookieHeader(ctx context.Context, w http.ResponseWriter, resp golang_proto.Message) error {
if sessionResp, ok := resp.(*sessionpkg.SessionResponse); ok {
flags := []string{"path=/"}
flags := []string{"path=/", "SameSite=lax", "httpOnly"}
if !a.Insecure {
flags = append(flags, "Secure")
}

View File

@@ -90,7 +90,7 @@ func TestDeclarativeHelmInvalidValuesFile(t *testing.T) {
func TestHelmRepo(t *testing.T) {
Given(t).
CustomCACertAdded().
HelmRepoAdded("").
HelmRepoAdded("custom-repo").
RepoURLType(RepoURLTypeHelm).
Chart("helm").
Revision("1.0.0").

9
ui/.prettierrc Normal file
View File

@@ -0,0 +1,9 @@
{
"bracketSpacing": false,
"jsxSingleQuote": true,
"printWidth": 180,
"singleQuote": true,
"tabWidth": 4,
"jsxBracketSameLine": true,
"quoteProps": "consistent"
}

View File

@@ -1,21 +1,23 @@
import { ErrorNotification, MockupList, NotificationType, SlidingPanel } from 'argo-ui';
import {ErrorNotification, MockupList, NotificationType, SlidingPanel} from 'argo-ui';
import * as classNames from 'classnames';
import * as minimatch from 'minimatch';
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import { Observable } from 'rxjs';
import {RouteComponentProps} from 'react-router';
import {Observable} from 'rxjs';
import { Autocomplete, ClusterCtx, DataLoader, EmptyState, ObservableQuery, Page, Paginate, Query } from '../../../shared/components';
import { Consumer } from '../../../shared/context';
import {Autocomplete, ClusterCtx, DataLoader, EmptyState, ObservableQuery, Page, Paginate, Query} from '../../../shared/components';
import {Consumer} from '../../../shared/context';
import * as models from '../../../shared/models';
import { AppsListPreferences, AppsListViewType, services } from '../../../shared/services';
import { ApplicationCreatePanel } from '../application-create-panel/application-create-panel';
import { ApplicationSyncPanel } from '../application-sync-panel/application-sync-panel';
import {AppsListPreferences, AppsListViewType, services} from '../../../shared/services';
import {ApplicationCreatePanel} from '../application-create-panel/application-create-panel';
import {ApplicationSyncPanel} from '../application-sync-panel/application-sync-panel';
import {ApplicationsSyncPanel} from '../applications-sync-panel/applications-sync-panel';
import * as LabelSelector from '../label-selector';
import * as AppUtils from '../utils';
import { ApplicationsFilter } from './applications-filter';
import { ApplicationsSummary } from './applications-summary';
import { ApplicationsTable } from './applications-table';
import { ApplicationTiles } from './applications-tiles';
import {ApplicationsFilter} from './applications-filter';
import {ApplicationsSummary} from './applications-summary';
import {ApplicationsTable} from './applications-table';
import {ApplicationTiles} from './applications-tiles';
require('./applications-list.scss');
@@ -25,93 +27,125 @@ const APP_FIELDS = [
'metadata.labels',
'metadata.resourceVersion',
'metadata.creationTimestamp',
'metadata.deletionTimestamp',
'spec',
'operation.sync',
'status.sync.status',
'status.health',
'status.summary'];
'status.operationState.phase',
'status.operationState.operation.sync',
'status.summary',
];
const APP_LIST_FIELDS = APP_FIELDS.map((field) => `items.${field}`);
const APP_WATCH_FIELDS = ['result.type', ...APP_FIELDS.map((field) => `result.application.${field}`)];
function loadApplications(selector: string): Observable<models.Application[]> {
return Observable.fromPromise(services.applications.list([], { fields: APP_LIST_FIELDS, selector })).flatMap((applications) =>
function loadApplications(): Observable<models.Application[]> {
return Observable.fromPromise(services.applications.list([], {fields: APP_LIST_FIELDS})).flatMap((applications) =>
Observable.merge(
Observable.from([applications]),
services.applications.watch(null, { fields: APP_WATCH_FIELDS, selector }).map((appChange) => {
const index = applications.findIndex((item) => item.metadata.name === appChange.application.metadata.name);
if (index > -1 && appChange.application.metadata.resourceVersion === applications[index].metadata.resourceVersion) {
return {applications, updated: false};
}
switch (appChange.type) {
case 'DELETED':
if (index > -1) {
applications.splice(index, 1);
}
break;
default:
if (index > -1) {
applications[index] = appChange.application;
} else {
applications.unshift(appChange.application);
}
break;
}
return {applications, updated: true};
}).filter((item) => item.updated).map((item) => item.applications),
services.applications
.watch(null, {fields: APP_WATCH_FIELDS})
.map((appChange) => {
const index = applications.findIndex((item) => item.metadata.name === appChange.application.metadata.name);
if (index > -1 && appChange.application.metadata.resourceVersion === applications[index].metadata.resourceVersion) {
return {applications, updated: false};
}
switch (appChange.type) {
case 'DELETED':
if (index > -1) {
applications.splice(index, 1);
}
break;
default:
if (index > -1) {
applications[index] = appChange.application;
} else {
applications.unshift(appChange.application);
}
break;
}
return {applications, updated: true};
})
.filter((item) => item.updated)
.map((item) => item.applications),
),
);
}
const ViewPref = ({children}: { children: (pref: AppsListPreferences & { page: number, search: string }) => React.ReactNode }) => (
const ViewPref = ({children}: {children: (pref: AppsListPreferences & {page: number; search: string}) => React.ReactNode}) => (
<ObservableQuery>
{(q) => (
<DataLoader load={() => Observable.combineLatest(
services.viewPreferences.getPreferences().map((item) => item.appList), q).map((items) => {
const params = items[1];
const viewPref: AppsListPreferences = {...items[0]};
if (params.get('proj') != null) {
viewPref.projectsFilter = params.get('proj').split(',').filter((item) => !!item);
}
if (params.get('sync') != null) {
viewPref.syncFilter = params.get('sync').split(',').filter((item) => !!item);
}
if (params.get('health') != null) {
viewPref.healthFilter = params.get('health').split(',').filter((item) => !!item);
}
if (params.get('namespace') != null) {
viewPref.namespacesFilter = params.get('namespace').split(',').filter((item) => !!item);
}
if (params.get('cluster') != null) {
viewPref.clustersFilter = params.get('cluster').split(',').filter((item) => !!item);
}
if (params.get('view') != null) {
viewPref.view = params.get('view') as AppsListViewType;
}
if (params.get('labels') != null) {
viewPref.labelsFilter = params.get('labels').split(',').filter((item) => !!item);
}
return {...viewPref, page: parseInt(params.get('page') || '0', 10), search: params.get('search') || ''};
})}>
{(pref) => children(pref)}
<DataLoader
load={() =>
Observable.combineLatest(services.viewPreferences.getPreferences().map((item) => item.appList), q).map((items) => {
const params = items[1];
const viewPref: AppsListPreferences = {...items[0]};
if (params.get('proj') != null) {
viewPref.projectsFilter = params
.get('proj')
.split(',')
.filter((item) => !!item);
}
if (params.get('sync') != null) {
viewPref.syncFilter = params
.get('sync')
.split(',')
.filter((item) => !!item);
}
if (params.get('health') != null) {
viewPref.healthFilter = params
.get('health')
.split(',')
.filter((item) => !!item);
}
if (params.get('namespace') != null) {
viewPref.namespacesFilter = params
.get('namespace')
.split(',')
.filter((item) => !!item);
}
if (params.get('cluster') != null) {
viewPref.clustersFilter = params
.get('cluster')
.split(',')
.filter((item) => !!item);
}
if (params.get('view') != null) {
viewPref.view = params.get('view') as AppsListViewType;
}
if (params.get('labels') != null) {
viewPref.labelsFilter = params
.get('labels')
.split(',')
.map(decodeURIComponent)
.filter((item) => !!item);
}
return {...viewPref, page: parseInt(params.get('page') || '0', 10), search: params.get('search') || ''};
})
}>
{(pref) => children(pref)}
</DataLoader>
)}
</ObservableQuery>
);
function filterApps(applications: models.Application[], pref: AppsListPreferences, search: string) {
return applications.filter((app) =>
(search === '' || app.metadata.name.includes(search)) &&
(pref.projectsFilter.length === 0 || pref.projectsFilter.includes(app.spec.project)) &&
(pref.reposFilter.length === 0 || pref.reposFilter.includes(app.spec.source.repoURL)) &&
(pref.syncFilter.length === 0 || pref.syncFilter.includes(app.status.sync.status)) &&
(pref.healthFilter.length === 0 || pref.healthFilter.includes(app.status.health.status)) &&
(pref.namespacesFilter.length === 0 || pref.namespacesFilter.some((ns) => minimatch(app.spec.destination.namespace, ns))) &&
(pref.clustersFilter.length === 0 || pref.clustersFilter.some((server) => minimatch(app.spec.destination.server, server))),
return applications.filter(
(app) =>
(search === '' || app.metadata.name.includes(search)) &&
(pref.projectsFilter.length === 0 || pref.projectsFilter.includes(app.spec.project)) &&
(pref.reposFilter.length === 0 || pref.reposFilter.includes(app.spec.source.repoURL)) &&
(pref.syncFilter.length === 0 || pref.syncFilter.includes(app.status.sync.status)) &&
(pref.healthFilter.length === 0 || pref.healthFilter.includes(app.status.health.status)) &&
(pref.namespacesFilter.length === 0 || pref.namespacesFilter.some((ns) => minimatch(app.spec.destination.namespace, ns))) &&
(pref.clustersFilter.length === 0 || pref.clustersFilter.some((server) => minimatch(app.spec.destination.server, server))) &&
(pref.labelsFilter.length === 0 || pref.labelsFilter.every((selector) => LabelSelector.match(selector, app.metadata.labels))),
);
}
function tryJsonParse(input: string) {
try {
return input && JSON.parse(input) || null;
return (input && JSON.parse(input)) || null;
} catch {
return null;
}
@@ -120,179 +154,234 @@ function tryJsonParse(input: string) {
export const ApplicationsList = (props: RouteComponentProps<{}>) => {
const query = new URLSearchParams(props.location.search);
const appInput = tryJsonParse(query.get('new'));
const syncAppsInput = tryJsonParse(query.get('syncApps'));
const [createApi, setCreateApi] = React.useState(null);
const clusters = React.useMemo(() => services.clusters.list(), []);
return (
<ClusterCtx.Provider value={clusters}>
<Consumer>{
(ctx) => (
<Page title='Applications' toolbar={services.viewPreferences.getPreferences().map((pref) => ({
breadcrumbs: [{ title: 'Applications', path: '/applications' }],
tools: (
<React.Fragment key='app-list-tools'>
<span className='applications-list__view-type'>
<i className={classNames('fa fa-th', {selected: pref.appList.view === 'tiles'})} onClick={() => {
ctx.navigation.goto('.', { view: 'tiles'});
services.viewPreferences.updatePreferences({ appList: {...pref.appList, view: 'tiles'} });
}} />
<i className={classNames('fa fa-th-list', {selected: pref.appList.view === 'list'})} onClick={() => {
ctx.navigation.goto('.', { view: 'list'});
services.viewPreferences.updatePreferences({ appList: {...pref.appList, view: 'list'} });
}} />
<i className={classNames('fa fa-chart-pie', {selected: pref.appList.view === 'summary'})} onClick={() => {
ctx.navigation.goto('.', { view: 'summary'});
services.viewPreferences.updatePreferences({ appList: {...pref.appList, view: 'summary'} });
}} />
</span>
</React.Fragment>
),
actionMenu: {
className: 'fa fa-plus',
items: [{
title: 'New Application',
action: () => ctx.navigation.goto('.', { new: '{}' }),
}],
},
}))}>
<div className='applications-list'>
<ViewPref>
{(pref) =>
<DataLoader
input={(pref.labelsFilter || []).join(',')}
load={(selector) => loadApplications(selector)}
loadingRenderer={() => (<div className='argo-container'><MockupList height={100} marginTop={30}/></div>)}>
{(applications: models.Application[]) => (
applications.length === 0 && (pref.labelsFilter || []).length === 0 ? (
<EmptyState icon='argo-icon-application'>
<h4>No applications yet</h4>
<h5>Create new application to start managing resources in your cluster</h5>
<button className='argo-button argo-button--base' onClick={() => ctx.navigation.goto('.', { new: JSON.stringify({}) })}>Create application</button>
</EmptyState>
) : (
<div className='row'>
<div className='columns small-12 xxlarge-2'>
<Query>
{(q) => (
<div className='applications-list__search'>
<i className='fa fa-search'/>
{q.get('search') && (
<i className='fa fa-times' onClick={() => ctx.navigation.goto('.', { search: null }, { replace: true })}/>
)}
<Autocomplete
filterSuggestions={true}
renderInput={(inputProps) => (
<input {...inputProps} onFocus={(e) => {
e.target.select();
if (inputProps.onFocus) {
inputProps.onFocus(e);
}
}} className='argo-field' />
)}
renderItem={(item) => (
<React.Fragment>
<i className='icon argo-icon-application'/> {item.label}
</React.Fragment>
)}
onSelect={(val) => {
ctx.navigation.goto(`./${val}`);
<ClusterCtx.Provider value={clusters}>
<Consumer>
{(ctx) => (
<Page
title='Applications'
toolbar={services.viewPreferences.getPreferences().map((pref) => ({
breadcrumbs: [{title: 'Applications', path: '/applications'}],
tools: (
<React.Fragment key='app-list-tools'>
<span className='applications-list__view-type'>
<i
className={classNames('fa fa-th', {selected: pref.appList.view === 'tiles'})}
onClick={() => {
ctx.navigation.goto('.', {view: 'tiles'});
services.viewPreferences.updatePreferences({appList: {...pref.appList, view: 'tiles'}});
}}
onChange={(e) => ctx.navigation.goto('.', { search: e.target.value }, { replace: true })}
value={q.get('search') || ''} items={applications.map((app) => app.metadata.name)}/>
</div>
)}
</Query>
<ApplicationsFilter applications={applications} pref={pref} onChange={(newPref) => {
services.viewPreferences.updatePreferences({appList: newPref});
ctx.navigation.goto('.', {
proj: newPref.projectsFilter.join(','),
sync: newPref.syncFilter.join(','),
health: newPref.healthFilter.join(','),
namespace: newPref.namespacesFilter.join(','),
cluster: newPref.clustersFilter.join(','),
labels: newPref.labelsFilter.join(','),
});
}} />
</div>
<div className='columns small-12 xxlarge-10'>
{pref.view === 'summary' && (
<ApplicationsSummary applications={filterApps(applications, pref, pref.search)} />
) || (
<Paginate
preferencesKey='applications-list'
page={pref.page}
emptyState={() => (
<EmptyState icon='fa fa-search'>
<h4>No applications found</h4>
<h5>Try to change filter criteria</h5>
</EmptyState>
)}
data={filterApps(applications, pref, pref.search)} onPageChange={(page) => ctx.navigation.goto('.', { page })} >
{(data) => (
pref.view === 'tiles' && (
<ApplicationTiles
applications={data}
syncApplication={(appName) => ctx.navigation.goto('.', { syncApp: appName })}
refreshApplication={(appName) => services.applications.get(appName, 'normal')}
deleteApplication={(appName) => AppUtils.deleteApplication(appName, ctx)}
/>
) || (
<ApplicationsTable applications={data}
syncApplication={(appName) => ctx.navigation.goto('.', { syncApp: appName })}
refreshApplication={(appName) => services.applications.get(appName, 'normal')}
deleteApplication={(appName) => AppUtils.deleteApplication(appName, ctx)}
<i
className={classNames('fa fa-th-list', {selected: pref.appList.view === 'list'})}
onClick={() => {
ctx.navigation.goto('.', {view: 'list'});
services.viewPreferences.updatePreferences({appList: {...pref.appList, view: 'list'}});
}}
/>
)
<i
className={classNames('fa fa-chart-pie', {selected: pref.appList.view === 'summary'})}
onClick={() => {
ctx.navigation.goto('.', {view: 'summary'});
services.viewPreferences.updatePreferences({appList: {...pref.appList, view: 'summary'}});
}}
/>
</span>
</React.Fragment>
),
actionMenu: {
items: [
{
title: 'New App',
iconClassName: 'fa fa-plus',
action: () => ctx.navigation.goto('.', {new: '{}'}),
},
{
title: 'Sync Apps',
iconClassName: 'fa fa-sync',
action: () => ctx.navigation.goto('.', {syncApps: true}),
},
],
},
}))}>
<div className='applications-list'>
<ViewPref>
{(pref) => (
<DataLoader
load={() => loadApplications()}
loadingRenderer={() => (
<div className='argo-container'>
<MockupList height={100} marginTop={30} />
</div>
)}>
{(applications: models.Application[]) =>
applications.length === 0 && (pref.labelsFilter || []).length === 0 ? (
<EmptyState icon='argo-icon-application'>
<h4>No applications yet</h4>
<h5>Create new application to start managing resources in your cluster</h5>
<button className='argo-button argo-button--base' onClick={() => ctx.navigation.goto('.', {new: JSON.stringify({})})}>
Create application
</button>
</EmptyState>
) : (
<div className='row'>
<div className='columns small-12 xxlarge-2'>
<Query>
{(q) => (
<div className='applications-list__search'>
<i className='fa fa-search' />
{q.get('search') && (
<i className='fa fa-times' onClick={() => ctx.navigation.goto('.', {search: null}, {replace: true})} />
)}
<Autocomplete
filterSuggestions={true}
renderInput={(inputProps) => (
<input
{...inputProps}
onFocus={(e) => {
e.target.select();
if (inputProps.onFocus) {
inputProps.onFocus(e);
}
}}
className='argo-field'
/>
)}
renderItem={(item) => (
<React.Fragment>
<i className='icon argo-icon-application' /> {item.label}
</React.Fragment>
)}
onSelect={(val) => {
ctx.navigation.goto(`./${val}`);
}}
onChange={(e) => ctx.navigation.goto('.', {search: e.target.value}, {replace: true})}
value={q.get('search') || ''}
items={applications.map((app) => app.metadata.name)}
/>
</div>
)}
</Query>
<ApplicationsFilter
applications={applications}
pref={pref}
onChange={(newPref) => {
services.viewPreferences.updatePreferences({appList: newPref});
ctx.navigation.goto('.', {
proj: newPref.projectsFilter.join(','),
sync: newPref.syncFilter.join(','),
health: newPref.healthFilter.join(','),
namespace: newPref.namespacesFilter.join(','),
cluster: newPref.clustersFilter.join(','),
labels: newPref.labelsFilter.map(encodeURIComponent).join(','),
});
}}
/>
{syncAppsInput && (
<ApplicationsSyncPanel
key='syncsPanel'
show={syncAppsInput}
hide={() => ctx.navigation.goto('.', {syncApps: null})}
apps={filterApps(applications, pref, pref.search)}
/>
)}
</div>
<div className='columns small-12 xxlarge-10'>
{(pref.view === 'summary' && <ApplicationsSummary applications={filterApps(applications, pref, pref.search)} />) || (
<Paginate
preferencesKey='applications-list'
page={pref.page}
emptyState={() => (
<EmptyState icon='fa fa-search'>
<h4>No applications found</h4>
<h5>Try to change filter criteria</h5>
</EmptyState>
)}
data={filterApps(applications, pref, pref.search)}
onPageChange={(page) => ctx.navigation.goto('.', {page})}>
{(data) =>
(pref.view === 'tiles' && (
<ApplicationTiles
applications={data}
syncApplication={(appName) => ctx.navigation.goto('.', {syncApp: appName})}
refreshApplication={(appName) => services.applications.get(appName, 'normal')}
deleteApplication={(appName) => AppUtils.deleteApplication(appName, ctx)}
/>
)) || (
<ApplicationsTable
applications={data}
syncApplication={(appName) => ctx.navigation.goto('.', {syncApp: appName})}
refreshApplication={(appName) => services.applications.get(appName, 'normal')}
deleteApplication={(appName) => AppUtils.deleteApplication(appName, ctx)}
/>
)
}
</Paginate>
)}
</div>
</div>
)
}
</DataLoader>
)}
</Paginate>
)}
</div>
</ViewPref>
</div>
)
<ObservableQuery>
{(q) => (
<DataLoader
load={() =>
q.flatMap((params) => {
const syncApp = params.get('syncApp');
return (syncApp && Observable.fromPromise(services.applications.get(syncApp))) || Observable.from([null]);
})
}>
{(app) => (
<ApplicationSyncPanel key='syncPanel' application={app} selectedResource={'all'} hide={() => ctx.navigation.goto('.', {syncApp: null})} />
)}
</DataLoader>
)}
</ObservableQuery>
<SlidingPanel
isShown={!!appInput}
onClose={() => ctx.navigation.goto('.', {new: null})}
header={
<div>
<button className='argo-button argo-button--base' onClick={() => createApi && createApi.submitForm(null)}>
Create
</button>{' '}
<button onClick={() => ctx.navigation.goto('.', {new: null})} className='argo-button argo-button--base-o'>
Cancel
</button>
</div>
}>
{appInput && (
<ApplicationCreatePanel
getFormApi={(api) => {
setCreateApi(api);
}}
createApp={async (app) => {
try {
await services.applications.create(app);
ctx.navigation.goto('.', {new: null});
} catch (e) {
ctx.notifications.show({
content: <ErrorNotification title='Unable to create application' e={e} />,
type: NotificationType.Error,
});
}
}}
app={appInput}
onAppChanged={(app) => ctx.navigation.goto('.', {new: JSON.stringify(app)}, {replace: true})}
/>
)}
</SlidingPanel>
</Page>
)}
</DataLoader>
}</ViewPref>
</div>
<ObservableQuery>
{(q) => (
<DataLoader load={() => q.flatMap((params) => {
const syncApp = params.get('syncApp');
return syncApp && Observable.fromPromise(services.applications.get(syncApp)) || Observable.from([null]);
}) }>
{(app) => (
<ApplicationSyncPanel key='syncPanel' application={app} selectedResource={'all'} hide={() => ctx.navigation.goto('.', { syncApp: null })} />
)}
</DataLoader>
)}
</ObservableQuery>
<SlidingPanel isShown={!!appInput} onClose={() => ctx.navigation.goto('.', { new: null })} header={
<div>
<button className='argo-button argo-button--base'
onClick={() => createApi && createApi.submitForm(null)}>
Create
</button> <button onClick={() => ctx.navigation.goto('.', { new: null })} className='argo-button argo-button--base-o'>
Cancel
</button>
</div>
}>
{appInput && <ApplicationCreatePanel getFormApi={(api) => {
setCreateApi(api);
}} createApp={ async (app) => {
try {
await services.applications.create(app);
ctx.navigation.goto('.', { new: null });
} catch (e) {
ctx.notifications.show({
content: <ErrorNotification title='Unable to create application' e={e}/>,
type: NotificationType.Error,
});
}
}}
app={appInput}
onAppChanged={(app) => ctx.navigation.goto('.', { new: JSON.stringify(app) }, { replace: true })} />}
</SlidingPanel>
</Page>
)}
</Consumer>
</ClusterCtx.Provider>);
</Consumer>
</ClusterCtx.Provider>
);
};

View File

@@ -0,0 +1,109 @@
import {ErrorNotification, NotificationType, SlidingPanel} from 'argo-ui';
import * as React from 'react';
import {Checkbox, Form, FormApi} from 'react-form';
import {Consumer} from '../../../shared/context';
import * as models from '../../../shared/models';
import {services} from '../../../shared/services';
import {ComparisonStatusIcon, HealthStatusIcon} from '../utils';
export const ApplicationsSyncPanel = ({show, apps, hide}: {show: boolean; apps: models.Application[]; hide: () => void}) => {
const [form, setForm] = React.useState<FormApi>(null);
const getSelectedApps = (params: any) => apps.filter((app) => params['app/' + app.metadata.name]);
return (
<Consumer>
{(ctx) => (
<SlidingPanel
isMiddle={true}
isShown={show}
onClose={() => hide()}
header={
<div>
<button className='argo-button argo-button--base' onClick={() => form.submitForm(null)}>
Sync
</button>{' '}
<button onClick={() => hide()} className='argo-button argo-button--base-o'>
Cancel
</button>
</div>
}>
<Form
onSubmit={async (params: any) => {
const selectedApps = getSelectedApps(params);
if (selectedApps.length === 0) {
ctx.notifications.show({content: `No apps selected`, type: NotificationType.Error});
return;
}
ctx.notifications.show({
content: `Syncing ${selectedApps.length} app(s)`,
type: NotificationType.Success,
});
const syncStrategy = (params.applyOnly ? {apply: {force: params.force}} : {hook: {force: params.force}}) as models.SyncStrategy;
for (const app of selectedApps) {
await services.applications.sync(app.metadata.name, app.spec.source.targetRevision, params.prune, params.dryRun, syncStrategy, null).catch((e) => {
ctx.notifications.show({
content: <ErrorNotification title={`Unable to sync ${app.metadata.name}`} e={e} />,
type: NotificationType.Error,
});
});
}
hide();
}}
getApi={setForm}>
{(formApi) => (
<React.Fragment>
<div className='argo-form-row'>
<h4>Sync app(s)</h4>
<label>Options:</label>
<div style={{paddingLeft: '1em'}}>
<label>
<Checkbox field='prune' /> Prune
</label>
&nbsp;
<label>
<Checkbox field='dryRun' /> Dry Run
</label>
&nbsp;
<label>
<Checkbox field='applyOnly' /> Apply Only
</label>
&nbsp;
<label>
<Checkbox field='force' /> Force
</label>
</div>
<label>
Apps (<a
onClick={() => apps.forEach((app) => formApi.setValue('app/' + app.metadata.name, true))}>all</a>/
<a
onClick={() =>
apps.forEach((app) => formApi.setValue('app/' + app.metadata.name, app.status.sync.status === models.SyncStatuses.OutOfSync))
}>
out of sync
</a>
/<a
onClick={() => apps.forEach((app) => formApi.setValue('app/' + app.metadata.name, false))}>none</a>
):
</label>
<div style={{paddingLeft: '1em'}}>
{apps.map((app) => (
<label key={app.metadata.name}>
<Checkbox field={`app/${app.metadata.name}`} />
&nbsp;
{app.metadata.name}
&nbsp;
<ComparisonStatusIcon status={app.status.sync.status} />
&nbsp;
<HealthStatusIcon state={app.status.health} />
<br />
</label>
))}
</div>
</div>
</React.Fragment>
)}
</Form>
</SlidingPanel>
)}
</Consumer>
);
};

View File

@@ -0,0 +1,44 @@
import * as LabelSelector from './label-selector';
test('exists', () => {
expect(LabelSelector.match('test', {test: 'hello'})).toBeTruthy();
expect(LabelSelector.match('test1', {test: 'hello'})).toBeFalsy();
});
test('not exists', () => {
expect(LabelSelector.match('!test', {test: 'hello'})).toBeFalsy();
expect(LabelSelector.match('!test1', {test: 'hello'})).toBeTruthy();
});
test('in', () => {
expect(LabelSelector.match('test in 1, 2, 3', {test: '1'})).toBeTruthy();
expect(LabelSelector.match('test in 1, 2, 3', {test: '4'})).toBeFalsy();
expect(LabelSelector.match('test in 1, 2, 3', {test1: '1'})).toBeFalsy();
});
test('notIn', () => {
expect(LabelSelector.match('test notin 1, 2, 3', {test: '1'})).toBeFalsy();
expect(LabelSelector.match('test notin 1, 2, 3', {test: '4'})).toBeTruthy();
expect(LabelSelector.match('test notin 1, 2, 3', {test1: '1'})).toBeTruthy();
});
test('equal', () => {
expect(LabelSelector.match('test=hello', {test: 'hello'})).toBeTruthy();
expect(LabelSelector.match('test=world', {test: 'hello'})).toBeFalsy();
expect(LabelSelector.match('test==hello', {test: 'hello'})).toBeTruthy();
});
test('notEqual', () => {
expect(LabelSelector.match('test!=hello', {test: 'hello'})).toBeFalsy();
expect(LabelSelector.match('test!=world', {test: 'hello'})).toBeTruthy();
});
test('greaterThen', () => {
expect(LabelSelector.match('test gt 1', {test: '2'})).toBeTruthy();
expect(LabelSelector.match('test gt 3', {test: '2'})).toBeFalsy();
});
test('lessThen', () => {
expect(LabelSelector.match('test lt 1', {test: '2'})).toBeFalsy();
expect(LabelSelector.match('test lt 3', {test: '2'})).toBeTruthy();
});

View File

@@ -0,0 +1,39 @@
type operatorFn = (labels: {[name: string]: string}, key: string, values: string[]) => boolean;
const operators: {[type: string]: operatorFn} = {
'!=': (labels, key, values) => labels[key] !== values[0],
'==': (labels, key, values) => labels[key] === values[0],
'=': (labels, key, values) => labels[key] === values[0],
'notin': (labels, key, values) => !values.includes(labels[key]),
'in': (labels, key, values) => values.includes(labels[key]),
'gt': (labels, key, values) => parseFloat(labels[key]) > parseFloat(values[0]),
'lt': (labels, key, values) => parseFloat(labels[key]) < parseFloat(values[0]),
};
function split(input: string, delimiter: string): string[] {
return input
.split(delimiter)
.map((part) => part.trim())
.filter((part) => part !== '');
}
export type LabelSelector = (labels: {[name: string]: string}) => boolean;
export function parse(selector: string): LabelSelector {
for (const type of Object.keys(operators)) {
const operator = operators[type];
const parts = split(selector, type);
if (parts.length > 1) {
const values = split(parts[1], ',');
return (labels) => operator(labels, parts[0], values);
}
}
if (selector.startsWith('!')) {
return (labels) => !labels.hasOwnProperty(selector.slice(1));
}
return (labels) => labels.hasOwnProperty(selector);
}
export function match(selector: string, labels: {[name: string]: string}): boolean {
return parse(selector)(labels || {});
}

View File

@@ -34,7 +34,7 @@ export interface ViewPreferences {
const VIEW_PREFERENCES_KEY = 'view_preferences';
const minVer = 3;
const minVer = 4;
const DEFAULT_PREFERENCES: ViewPreferences = {
version: 1,

11
util/cache/cache.go vendored
View File

@@ -30,6 +30,11 @@ type OIDCState struct {
ReturnURL string `json:"returnURL"`
}
type ClusterInfo struct {
appv1.ConnectionState
Version string
}
// NewCache creates new instance of Cache
func NewCache(cacheClient CacheClient) *Cache {
return &Cache{client: cacheClient}
@@ -153,13 +158,13 @@ func (c *Cache) SetAppResourcesTree(appName string, resourcesTree *appv1.Applica
return c.setItem(appResourcesTreeKey(appName), resourcesTree, appStateCacheExpiration, resourcesTree == nil)
}
func (c *Cache) GetClusterConnectionState(server string) (appv1.ConnectionState, error) {
res := appv1.ConnectionState{}
func (c *Cache) GetClusterInfo(server string) (ClusterInfo, error) {
res := ClusterInfo{}
err := c.getItem(clusterConnectionStateKey(server), &res)
return res, err
}
func (c *Cache) SetClusterConnectionState(server string, state *appv1.ConnectionState) error {
func (c *Cache) SetClusterInfo(server string, state *ClusterInfo) error {
return c.setItem(clusterConnectionStateKey(server), &state, connectionStatusCacheExpiration, state == nil)
}

View File

@@ -65,7 +65,7 @@ func ignoreLiveObjectHealth(liveObj *unstructured.Unstructured, resHealth appv1.
return true
}
gvk := liveObj.GroupVersionKind()
if gvk.Group == "argoproj.io" && gvk.Kind == "Application" && resHealth.Status == appv1.HealthStatusMissing {
if gvk.Group == "argoproj.io" && gvk.Kind == "Application" && (resHealth.Status == appv1.HealthStatusMissing || resHealth.Status == appv1.HealthStatusUnknown) {
// Covers the app-of-apps corner case where child app is deployed but that app itself
// has a status of 'Missing', which we don't want to cause the parent's health status
// to also be Missing

View File

@@ -115,6 +115,7 @@ func TestAppOfAppsHealth(t *testing.T) {
}
missingApp, missingStatus := newAppLiveObj("foo", appv1.HealthStatusMissing)
unknownApp, unknownStatus := newAppLiveObj("fooz", appv1.HealthStatusUnknown)
healthyApp, healthyStatus := newAppLiveObj("bar", appv1.HealthStatusHealthy)
degradedApp, degradedStatus := newAppLiveObj("baz", appv1.HealthStatusDegraded)
@@ -127,6 +128,15 @@ func TestAppOfAppsHealth(t *testing.T) {
assert.Equal(t, appv1.HealthStatusHealthy, healthStatus.Status)
}
// verify unknown child app does not affect app health
{
unknownAndHealthyStatuses := []appv1.ResourceStatus{unknownStatus, healthyStatus}
unknownAndHealthyLiveObjects := []*unstructured.Unstructured{unknownApp, healthyApp}
healthStatus, err := SetApplicationHealth(unknownAndHealthyStatuses, unknownAndHealthyLiveObjects, nil, noFilter)
assert.NoError(t, err)
assert.Equal(t, appv1.HealthStatusHealthy, healthStatus.Status)
}
// verify degraded does affect
{
degradedAndHealthyStatuses := []appv1.ResourceStatus{degradedStatus, healthyStatus}

View File

@@ -21,6 +21,7 @@ import (
"gopkg.in/yaml.v2"
"github.com/argoproj/argo-cd/util"
"github.com/argoproj/argo-cd/util/config"
)
var (
@@ -128,22 +129,41 @@ func (c *nativeHelmChart) ExtractChart(chart string, version string) (string, ut
return "", nil, err
}
// download chart tar file into persistent helm repository directory
_, err = helmCmd.Fetch(c.repoURL, chart, version, c.creds)
// (1) because `helm fetch` downloads an arbitrary file name, we download to an empty temp directory
tempDest, err := ioutil.TempDir("", "helm")
if err != nil {
return "", nil, err
}
defer func() { _ = os.RemoveAll(tempDest) }()
_, err = helmCmd.Fetch(c.repoURL, chart, version, tempDest, c.creds)
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("", "")
tempDir, err := ioutil.TempDir("", "helm")
if err != nil {
return "", nil, err
}
cmd := exec.Command("tar", "-zxvf", chartPath)
cmd.Dir = tempDir
_, err = argoexec.RunCommandExt(cmd, argoexec.CmdOpts{})
_, err = argoexec.RunCommandExt(cmd, config.CmdOpts())
if err != nil {
_ = os.RemoveAll(tempDir)
return "", nil, err
}
return path.Join(tempDir, chart), util.NewCloser(func() error {
return os.RemoveAll(tempDir)

View File

@@ -1,27 +1,43 @@
package helm
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/argoproj/argo-cd/util"
)
func TestIndex(t *testing.T) {
t.Run("Invalid", func(t *testing.T) {
_, err := NewClient("", Creds{}).GetIndex()
client := NewClient("", Creds{})
_, err := client.GetIndex()
assert.Error(t, err)
})
t.Run("Stable", func(t *testing.T) {
index, err := NewClient("https://kubernetes-charts.storage.googleapis.com", Creds{}).GetIndex()
client := NewClient("https://argoproj.github.io/argo-helm", Creds{})
index, err := client.GetIndex()
assert.NoError(t, err)
assert.NotNil(t, index)
})
t.Run("BasicAuth", func(t *testing.T) {
index, err := NewClient("https://kubernetes-charts.storage.googleapis.com", Creds{
client := NewClient("https://argoproj.github.io/argo-helm", Creds{
Username: "my-password",
Password: "my-username",
}).GetIndex()
})
index, err := client.GetIndex()
assert.NoError(t, err)
assert.NotNil(t, index)
})
}
func Test_nativeHelmChart_ExtractChart(t *testing.T) {
client := NewClient("https://argoproj.github.io/argo-helm", Creds{})
path, closer, err := client.ExtractChart("argo-cd", "0.7.1")
defer util.Close(closer)
assert.NoError(t, err)
info, err := os.Stat(path)
assert.NoError(t, err)
assert.True(t, info.IsDir())
}

View File

@@ -12,6 +12,7 @@ import (
argoexec "github.com/argoproj/pkg/exec"
"github.com/argoproj/argo-cd/util"
"github.com/argoproj/argo-cd/util/config"
"github.com/argoproj/argo-cd/util/security"
)
@@ -39,6 +40,7 @@ func (c Cmd) run(args ...string) (string, error) {
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, fmt.Sprintf("HELM_HOME=%s", c.helmHome))
return argoexec.RunCommandExt(cmd, argoexec.CmdOpts{
Timeout: config.CmdOpts().Timeout,
Redactor: redactor,
})
}
@@ -117,31 +119,31 @@ func writeToTmp(data []byte) (string, io.Closer, error) {
}), nil
}
func (c *Cmd) Fetch(repo, chartName string, version string, opts Creds) (string, error) {
args := []string{"fetch"}
func (c *Cmd) Fetch(repo, chartName, version, destination string, creds Creds) (string, error) {
args := []string{"fetch", "--destination", destination}
if version != "" {
args = append(args, "--version", version)
}
if opts.Username != "" {
args = append(args, "--username", opts.Username)
if creds.Username != "" {
args = append(args, "--username", creds.Username)
}
if opts.Password != "" {
args = append(args, "--password", opts.Password)
if creds.Password != "" {
args = append(args, "--password", creds.Password)
}
if opts.CAPath != "" {
args = append(args, "--ca-file", opts.CAPath)
if creds.CAPath != "" {
args = append(args, "--ca-file", creds.CAPath)
}
if len(opts.CertData) > 0 {
filePath, closer, err := writeToTmp(opts.CertData)
if len(creds.CertData) > 0 {
filePath, closer, err := writeToTmp(creds.CertData)
if err != nil {
return "", err
}
defer util.Close(closer)
args = append(args, "--cert-file", filePath)
}
if len(opts.KeyData) > 0 {
filePath, closer, err := writeToTmp(opts.KeyData)
if len(creds.KeyData) > 0 {
filePath, closer, err := writeToTmp(creds.KeyData)
if err != nil {
return "", err
}

View File

@@ -10,9 +10,8 @@ import (
"regexp"
"strings"
"github.com/ghodss/yaml"
argoexec "github.com/argoproj/pkg/exec"
"github.com/ghodss/yaml"
"github.com/argoproj/argo-cd/util/config"
)
@@ -89,6 +88,7 @@ func (h *helm) Dispose() {
func Version() (string, error) {
cmd := exec.Command("helm", "version", "--client")
out, err := argoexec.RunCommandExt(cmd, argoexec.CmdOpts{
Timeout: config.CmdOpts().Timeout,
Redactor: redactor,
})
if err != nil {
@@ -138,12 +138,17 @@ func (h *helm) GetParameters(valuesFiles []string) (map[string]string, error) {
return output, nil
}
func flatVals(input map[string]interface{}, output map[string]string, prefixes ...string) {
for key, val := range input {
if subMap, ok := val.(map[string]interface{}); ok {
flatVals(subMap, output, append(prefixes, fmt.Sprintf("%v", key))...)
} else {
output[strings.Join(append(prefixes, fmt.Sprintf("%v", key)), ".")] = fmt.Sprintf("%v", val)
func flatVals(input interface{}, output map[string]string, prefixes ...string) {
switch i := input.(type) {
case map[string]interface{}:
for k, v := range i {
flatVals(v, output, append(prefixes, k)...)
}
case []interface{}:
for j, v := range i {
flatVals(v, output, append(prefixes[0:len(prefixes)-1], fmt.Sprintf("%s[%v]", prefixes[len(prefixes)-1], j))...)
}
default:
output[strings.Join(prefixes, ".")] = fmt.Sprintf("%v", i)
}
}

View File

@@ -164,3 +164,27 @@ func TestVersion(t *testing.T) {
re := regexp.MustCompile(SemverRegexValidation)
assert.True(t, re.MatchString(ver))
}
func Test_flatVals(t *testing.T) {
t.Run("Map", func(t *testing.T) {
output := map[string]string{}
flatVals(map[string]interface{}{"foo": map[string]interface{}{"bar": "baz"}}, output)
assert.Equal(t, map[string]string{"foo.bar": "baz"}, output)
})
t.Run("Array", func(t *testing.T) {
output := map[string]string{}
flatVals(map[string]interface{}{"foo": []interface{}{"bar"}}, output)
assert.Equal(t, map[string]string{"foo[0]": "bar"}, output)
})
t.Run("Val", func(t *testing.T) {
output := map[string]string{}
flatVals(map[string]interface{}{"foo": 1}, output)
assert.Equal(t, map[string]string{"foo": "1"}, output)
})
}