Compare commits

...

23 Commits

Author SHA1 Message Date
Alexander Matyushentsev
674978cd58 Update manifests to v1.2.0 2019-09-04 13:51:54 -07:00
Alexander Matyushentsev
020d284a00 Add missing pending method 2019-09-04 11:49:13 -07:00
Alex Collins
09b874613d If there is only one wave and no pre/post hooks, we should be synced.… (#2217) 2019-08-27 08:57:42 -07:00
Alex Collins
44cb2ce51a codegen 2019-08-26 13:56:25 -07:00
Alex Collins
6eaed1e64e Fix for displaying hooks in app diff view. Fixes #2215 (#2218)
* Duct tape fix for displaying hooks in app diff view. Fixes #2215

* ""operationId": "ListMixin7"," to swagger.json

* "for _, item := range items {" to app.go
2019-08-26 13:51:18 -07:00
Alex Collins
2a63b44af0 Redact secrets using "+" rather than "*" as this is base 64 compatiba… (#2119) 2019-08-23 13:46:34 -07:00
Alexander Matyushentsev
5571cf1333 Update codegen 2019-08-21 08:20:45 -07:00
Alexander Matyushentsev
ed0add3087 Update manifests to v1.2.0-rc2 2019-08-20 15:45:24 -07:00
Alex Collins
d27849cdc4 Adds a floating action button with help and chat links to every page.… (#2125) 2019-08-20 10:35:31 -07:00
Alexander Matyushentsev
3a3f490abf Issue #2174 - Fix git repo url parsing on application list view (#2175) 2019-08-20 09:30:33 -07:00
Alexander Matyushentsev
2dc95fffb7 Issue #2146 - Fix nil pointer dereference error during app reconciliation (#2170) 2019-08-20 08:56:43 -07:00
Alexander Matyushentsev
9cf978c168 Temporary disable Git LFS test to unblock release (#2172) 2019-08-20 08:20:10 -07:00
Alex Collins
3891b29d82 Determine the manifest version from the VERSION file when on release branch (#2166) 2019-08-20 08:20:06 -07:00
Alexander Matyushentsev
ed916702d6 Issue #2114 - Fix history api fallback implementation to support app names with dots (#2168) 2019-08-20 08:20:02 -07:00
Alex Collins
c4eba32f0e Enhances cookie warning with actual length to help users fix their co… (#2134) 2019-08-16 14:08:03 -07:00
Alex Collins
046a62420e Fixes some code issues related to Kustomize build options. See #2146 (#2151) 2019-08-16 12:56:06 -07:00
Simon Behar
1b393bc473 Added 'SyncFail' to possible HookTypes in UI (#2153) 2019-08-14 14:29:48 -07:00
jannfis
d8c38bb45b Fix and enhance end-to-end testing for SSH repositories (#2101)
* Fix and enhance end-to-end testing for SSH repositories
2019-08-14 10:42:23 -07:00
Alex Collins
249ce9317f Adds checks around valid paths for apps (#2133) 2019-08-09 14:26:31 -07:00
Alex Collins
a094d5abb8 Minor CLI bug fixes (#2132) 2019-08-09 13:27:02 -07:00
Alexander Matyushentsev
3f31224a6e Issue #2060 - Enpoint incorrectly considered top level managed resource (#2129) 2019-08-09 11:52:55 -07:00
jannfis
649b1b7b75 Allow adding certs for hostnames ending on a dot (fixes #2116) (#2120) 2019-08-08 17:14:33 -07:00
Alexander Matyushentsev
2c691a874b Update manifests to v1.2.0-rc1 2019-08-06 10:40:47 -07:00
67 changed files with 1495 additions and 810 deletions

View File

@@ -118,15 +118,6 @@ commands:
sudo cp /tmp/dl/kustomize_${VER} /usr/local/go/bin/kustomize
sudo chmod +x /usr/local/go/bin/kustomize
kustomize version
- run:
name: Install Git LFS plugin
command: |
set -x
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
sleep 5
sudo killall -9 apt-get || true
sudo apt-get update
sudo apt-get install -y git-lfs openssh-client
- save_cache:
key: dl-v6
paths:

1
Gopkg.lock generated
View File

@@ -1646,6 +1646,7 @@
"github.com/yuin/gopher-lua",
"golang.org/x/crypto/bcrypt",
"golang.org/x/crypto/ssh",
"golang.org/x/crypto/ssh/knownhosts",
"golang.org/x/crypto/ssh/terminal",
"golang.org/x/net/context",
"golang.org/x/oauth2",

View File

@@ -18,7 +18,7 @@ PATH:=$(PATH):$(PWD)/hack
# docker image publishing options
DOCKER_PUSH?=false
IMAGE_TAG?=latest
IMAGE_TAG?=
# perform static compilation
STATIC_BUILD?=true
# build development images

View File

@@ -2,6 +2,6 @@ controller: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/a
api-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-server/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --staticassets ui/dist/app"
dex: sh -c "go run ./cmd/argocd-util/main.go gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml quay.io/dexidp/dex:v2.14.0 serve /dex.yaml"
redis: docker run --rm --name argocd-redis -i -p ${ARGOCD_E2E_REDIS_PORT:-6379}:${ARGOCD_E2E_REDIS_PORT:-6379} redis:5.0.3-alpine --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}
repo-server: sh -c "FORCE_LOG_COLORS=1 go run ./cmd/argocd-repo-server/main.go --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"
repo-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true go run ./cmd/argocd-repo-server/main.go --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"
ui: sh -c 'cd ui && ${ARGOCD_E2E_YARN_CMD:-yarn} start'
git-server: test/fixture/testrepos/start-git.sh
git-server: test/fixture/testrepos/start-git.sh

View File

@@ -1 +1 @@
1.1.2
1.2.0

View File

@@ -1740,6 +1740,20 @@
}
}
},
"clusterHelp": {
"type": "object",
"title": "Help settings",
"properties": {
"chatText": {
"type": "string",
"title": "the text for getting chat help, defaults to \"Chat now!\""
},
"chatUrl": {
"type": "string",
"title": "the URL for getting chat help, this will typically be your Slack channel for support"
}
}
},
"clusterOIDCConfig": {
"type": "object",
"properties": {
@@ -1775,6 +1789,9 @@
"googleAnalytics": {
"$ref": "#/definitions/clusterGoogleAnalyticsConfig"
},
"help": {
"$ref": "#/definitions/clusterHelp"
},
"kustomizeOptions": {
"$ref": "#/definitions/v1alpha1KustomizeOptions"
},
@@ -3380,6 +3397,10 @@
"group": {
"type": "string"
},
"hook": {
"type": "boolean",
"format": "boolean"
},
"kind": {
"type": "string"
},

View File

@@ -744,7 +744,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
Short: shortDesc,
Long: shortDesc + "\nUses 'diff' to render the difference. KUBECTL_EXTERNAL_DIFF environment variable can be used to select your own diff tool.\nReturns the following exit codes: 2 on general errors, 1 when a diff is found, and 0 when no diff is found",
Run: func(c *cobra.Command, args []string) {
if len(args) == 0 {
if len(args) != 1 {
c.HelpFunc()(c, args)
os.Exit(2)
}
@@ -844,8 +844,10 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
}
foundDiffs := false
for i := range items {
item := items[i]
for _, item := range items {
if item.target != nil && hook.IsHook(item.target) || item.live != nil && hook.IsHook(item.live) {
continue
}
overrides := make(map[string]argoappv1.ResourceOverride)
for k := range argoSettings.ResourceOverrides {
val := argoSettings.ResourceOverrides[k]
@@ -1213,7 +1215,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
var localObjsStrings []string
if local != "" {
app, err := appIf.Get(context.Background(), &applicationpkg.ApplicationQuery{Name: &appName})
errors.CheckError(err)
if app.Spec.SyncPolicy != nil && app.Spec.SyncPolicy.Automated != nil {
log.Fatal("Cannot use local sync when Automatic Sync Policy is enabled")
}

View File

@@ -233,6 +233,7 @@ func (ctrl *ApplicationController) managedResources(comparisonResult *comparison
Name: res.Name,
Group: res.Group,
Kind: res.Kind,
Hook: res.Hook,
}
target := res.Target
@@ -690,13 +691,13 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
if comparisonLevel == CompareWithRecent {
revision = app.Status.Sync.Revision
}
compareResult, err := ctrl.appStateManager.CompareAppState(app, revision, app.Spec.Source, refreshType == appv1.RefreshTypeHard, localManifests)
if err != nil {
conditions = append(conditions, appv1.ApplicationCondition{Type: appv1.ApplicationConditionComparisonError, Message: err.Error()})
} else {
ctrl.normalizeApplication(origApp, app, compareResult.appSourceType)
conditions = append(conditions, compareResult.conditions...)
}
compareResult := ctrl.appStateManager.CompareAppState(app, revision, app.Spec.Source, refreshType == appv1.RefreshTypeHard, localManifests)
ctrl.normalizeApplication(origApp, app, compareResult.appSourceType)
conditions = append(conditions, compareResult.conditions...)
tree, err := ctrl.setAppManagedResources(app, compareResult)
if err != nil {
logCtx.Errorf("Failed to cache app resources: %v", err)

View File

@@ -35,6 +35,7 @@ type fakeData struct {
apps []runtime.Object
manifestResponse *apiclient.ManifestResponse
managedLiveObjs map[kube.ResourceKey]*unstructured.Unstructured
configMapData map[string]string
}
func newFakeController(data *fakeData) *ApplicationController {
@@ -68,7 +69,7 @@ func newFakeController(data *fakeData) *ApplicationController {
"app.kubernetes.io/part-of": "argocd",
},
},
Data: nil,
Data: data.configMapData,
}
kubeClient := fake.NewSimpleClientset(&clust, &cm, &secret)
settingsMgr := settings.NewSettingsManager(context.Background(), kubeClient, test.FakeArgoCDNamespace)

View File

@@ -87,6 +87,14 @@ func (c *clusterInfo) replaceResourceCache(gk schema.GroupKind, resourceVersion
func (c *clusterInfo) createObjInfo(un *unstructured.Unstructured, appInstanceLabel string) *node {
ownerRefs := un.GetOwnerReferences()
// Special case for endpoint. Remove after https://github.com/kubernetes/kubernetes/issues/28483 is fixed
if un.GroupVersionKind().Group == "" && un.GetKind() == kube.EndpointsKind && len(un.GetOwnerReferences()) == 0 {
ownerRefs = append(ownerRefs, metav1.OwnerReference{
Name: un.GetName(),
Kind: kube.ServiceKind,
APIVersion: "v1",
})
}
nodeInfo := &node{
resourceVersion: un.GetResourceVersion(),
ref: kube.GetObjectRef(un),

View File

@@ -87,6 +87,7 @@ var (
name: helm-guestbook
namespace: default
resourceVersion: "123"
uid: "4"
spec:
selector:
app: guestbook
@@ -102,6 +103,7 @@ var (
metadata:
name: helm-guestbook
namespace: default
uid: "4"
spec:
backend:
serviceName: not-found-service

View File

@@ -35,12 +35,15 @@ func (n *node) resourceKey() kube.ResourceKey {
}
func (n *node) isParentOf(child *node) bool {
// Special case for endpoint. Remove after https://github.com/kubernetes/kubernetes/issues/28483 is fixed
if len(child.ownerRefs) == 0 && child.ref.APIVersion == "v1" && child.ref.Kind == kube.EndpointsKind && n.ref.APIVersion == "v1" && n.ref.Kind == kube.ServiceKind && n.ref.Name == child.ref.Name {
child.ownerRefs = []metav1.OwnerReference{{Name: n.ref.Name, Kind: n.ref.Kind, APIVersion: n.ref.APIVersion, UID: n.ref.UID}}
}
for i, ownerRef := range child.ownerRefs {
// backfill UID of inferred owner child references
if ownerRef.UID == "" && n.ref.Kind == ownerRef.Kind && n.ref.APIVersion == ownerRef.APIVersion && n.ref.Name == ownerRef.Name {
ownerRef.UID = n.ref.UID
child.ownerRefs[i] = ownerRef
return true
}
for _, ownerRef := range child.ownerRefs {
if n.ref.UID == ownerRef.UID {
return true
}

View File

@@ -51,5 +51,6 @@ metadata:
parent := c.createObjInfo(testService, "")
assert.True(t, parent.isParentOf(matchingNameEndPoint))
assert.Equal(t, parent.ref.UID, matchingNameEndPoint.ownerRefs[0].UID)
assert.False(t, parent.isParentOf(nonMatchingNameEndPoint))
}

View File

@@ -56,7 +56,7 @@ type ResourceInfoProvider interface {
// AppStateManager defines methods which allow to compare application spec and actual application state.
type AppStateManager interface {
CompareAppState(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, noCache bool, localObjects []string) (*comparisonResult, error)
CompareAppState(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, noCache bool, localObjects []string) *comparisonResult
SyncAppState(app *v1alpha1.Application, state *v1alpha1.OperationState)
}
@@ -135,10 +135,11 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
if err != nil {
return nil, nil, nil, err
}
targetObjs, hooks, nil := unmarshalManifests(manifestInfo.Manifests)
targetObjs, hooks, err := unmarshalManifests(manifestInfo.Manifests)
if err != nil {
return nil, nil, nil, err
}
return targetObjs, hooks, manifestInfo, nil
}
func unmarshalManifests(manifests []string) ([]*unstructured.Unstructured, []*unstructured.Unstructured, error) {
@@ -234,28 +235,48 @@ func dedupLiveResources(targetObjs []*unstructured.Unstructured, liveObjsByKey m
}
}
// CompareAppState compares application git state to the live app state, using the specified
// revision and supplied source. If revision or overrides are empty, then compares against
// revision and overrides in the app spec.
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, noCache bool, localManifests []string) (*comparisonResult, error) {
func (m *appStateManager) getComparisonSettings(app *appv1.Application) (string, map[string]v1alpha1.ResourceOverride, diff.Normalizer, error) {
resourceOverrides, err := m.settingsMgr.GetResourceOverrides()
if err != nil {
return nil, err
return "", nil, nil, err
}
appLabelKey, err := m.settingsMgr.GetAppInstanceLabelKey()
if err != nil {
return nil, err
return "", nil, nil, err
}
diffNormalizer, err := argo.NewDiffNormalizer(app.Spec.IgnoreDifferences, resourceOverrides)
if err != nil {
return nil, err
return "", nil, nil, err
}
logCtx := log.WithField("application", app.Name)
logCtx.Infof("Comparing app state (cluster: %s, namespace: %s)", app.Spec.Destination.Server, app.Spec.Destination.Namespace)
observedAt := metav1.Now()
return appLabelKey, resourceOverrides, diffNormalizer, nil
}
// CompareAppState compares application git state to the live app state, using the specified
// revision and supplied source. If revision or overrides are empty, then compares against
// revision and overrides in the app spec.
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, noCache bool, localManifests []string) *comparisonResult {
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,
},
healthStatus: &appv1.HealthStatus{Status: appv1.HealthStatusUnknown},
}
}
// do best effort loading live and target state to present as much information about app state as possible
failedToLoadObjs := false
conditions := make([]v1alpha1.ApplicationCondition, 0)
logCtx := log.WithField("application", app.Name)
logCtx.Infof("Comparing app state (cluster: %s, namespace: %s)", app.Spec.Destination.Server, app.Spec.Destination.Namespace)
var targetObjs []*unstructured.Unstructured
var hooks []*unstructured.Unstructured
var manifestInfo *apiclient.ManifestResponse
@@ -348,7 +369,9 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision st
// Do the actual comparison
diffResults, err := diff.DiffArray(targetObjs, managedLiveObj, diffNormalizer)
if err != nil {
return nil, err
diffResults = &diff.DiffResultList{}
failedToLoadObjs = true
conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error()})
}
syncCode := v1alpha1.SyncStatusCodeSynced
@@ -429,7 +452,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision st
}
compRes := comparisonResult{
reconciledAt: observedAt,
reconciledAt: reconciledAt,
syncStatus: &syncStatus,
healthStatus: healthStatus,
resources: resourceSummaries,
@@ -441,7 +464,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision st
if manifestInfo != nil {
compRes.appSourceType = v1alpha1.ApplicationSourceType(manifestInfo.SourceType)
}
return &compRes, nil
return &compRes
}
func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource) error {

View File

@@ -30,8 +30,7 @@ func TestCompareAppStateEmpty(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NoError(t, err)
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NotNil(t, compRes)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
assert.Equal(t, 0, len(compRes.resources))
@@ -53,8 +52,7 @@ func TestCompareAppStateMissing(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NoError(t, err)
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NotNil(t, compRes)
assert.Equal(t, argoappv1.SyncStatusCodeOutOfSync, compRes.syncStatus.Status)
assert.Equal(t, 1, len(compRes.resources))
@@ -80,8 +78,7 @@ func TestCompareAppStateExtra(t *testing.T) {
},
}
ctrl := newFakeController(&data)
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NoError(t, err)
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NotNil(t, compRes)
assert.Equal(t, argoappv1.SyncStatusCodeOutOfSync, compRes.syncStatus.Status)
assert.Equal(t, 1, len(compRes.resources))
@@ -107,8 +104,7 @@ func TestCompareAppStateHook(t *testing.T) {
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data)
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NoError(t, err)
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NotNil(t, compRes)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
assert.Equal(t, 0, len(compRes.resources))
@@ -134,9 +130,8 @@ func TestCompareAppStateCompareOptionIgnoreExtraneous(t *testing.T) {
}
ctrl := newFakeController(&data)
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NoError(t, err)
assert.NotNil(t, compRes)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
assert.Len(t, compRes.resources, 0)
@@ -163,8 +158,8 @@ func TestCompareAppStateExtraHook(t *testing.T) {
},
}
ctrl := newFakeController(&data)
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NoError(t, err)
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NotNil(t, compRes)
assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status)
assert.Equal(t, 1, len(compRes.resources))
@@ -200,8 +195,8 @@ func TestCompareAppStateDuplicatedNamespacedResources(t *testing.T) {
},
}
ctrl := newFakeController(&data)
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NoError(t, err)
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NotNil(t, compRes)
assert.Contains(t, compRes.conditions, argoappv1.ApplicationCondition{
Message: "Resource /Pod/fake-dest-ns/my-pod appeared 2 times among application resources.",
@@ -251,8 +246,7 @@ func TestSetHealth(t *testing.T) {
},
})
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NoError(t, err)
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.Equal(t, compRes.healthStatus.Status, argoappv1.HealthStatusHealthy)
}
@@ -284,8 +278,7 @@ func TestSetHealthSelfReferencedApp(t *testing.T) {
},
})
compRes, err := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.NoError(t, err)
compRes := ctrl.appStateManager.CompareAppState(app, "", app.Spec.Source, false, nil)
assert.Equal(t, compRes.healthStatus.Status, argoappv1.HealthStatusHealthy)
}

View File

@@ -101,12 +101,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
revision = syncOp.Revision
}
compareResult, err := m.CompareAppState(app, revision, source, false, syncOp.Manifests)
if err != nil {
state.Phase = v1alpha1.OperationError
state.Message = err.Error()
return
}
compareResult := m.CompareAppState(app, revision, source, false, syncOp.Manifests)
// If there are any error conditions, do not perform the operation
errConditions := make([]v1alpha1.ApplicationCondition, 0)
@@ -264,8 +259,11 @@ func (sc *syncContext) sync() {
}
}
// any running tasks, lets wait...
if tasks.Any(func(t *syncTask) bool { return t.running() }) {
// if (a) we are multi-step and we have any running tasks,
// or (b) there are any running hooks,
// then wait...
multiStep := tasks.multiStep()
if tasks.Any(func(t *syncTask) bool { return (multiStep || t.isHook()) && t.running() }) {
sc.setOperationPhase(v1alpha1.OperationRunning, "one or more tasks are running")
return
}
@@ -279,9 +277,9 @@ func (sc *syncContext) sync() {
return
}
sc.log.WithFields(log.Fields{"tasks": tasks}).Debug("filtering out completed tasks")
sc.log.WithFields(log.Fields{"tasks": tasks}).Debug("filtering out non-pending tasks")
// remove tasks that are completed, we can assume that there are no running tasks
tasks = tasks.Filter(func(t *syncTask) bool { return !t.completed() })
tasks = tasks.Filter(func(t *syncTask) bool { return t.pending() })
// If no sync tasks were generated (e.g., in case all application manifests have been removed),
// the sync operation is successful.

View File

@@ -94,6 +94,10 @@ func (t *syncTask) namespace() string {
return t.obj().GetNamespace()
}
func (t *syncTask) pending() bool {
return t.operationState == ""
}
func (t *syncTask) running() bool {
return t.operationState == v1alpha1.OperationRunning
}

View File

@@ -165,3 +165,21 @@ func (s syncTasks) wave() int {
}
return 0
}
func (s syncTasks) lastPhase() v1alpha1.SyncPhase {
if len(s) > 0 {
return s[len(s)-1].phase
}
return ""
}
func (s syncTasks) lastWave() int {
if len(s) > 0 {
return s[len(s)-1].wave()
}
return 0
}
func (s syncTasks) multiStep() bool {
return s.wave() != s.lastWave() || s.phase() != s.lastPhase()
}

View File

@@ -8,7 +8,9 @@ import (
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/argoproj/argo-cd/common"
. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
. "github.com/argoproj/argo-cd/test"
)
func Test_syncTasks_kindOrder(t *testing.T) {
@@ -366,3 +368,25 @@ func TestSyncNamespaceAgainstCRD(t *testing.T) {
assert.Equal(t, syncTasks{namespace, crd}, unsorted)
}
func Test_syncTasks_multiStep(t *testing.T) {
t.Run("Single", func(t *testing.T) {
tasks := syncTasks{{liveObj: Annotate(NewPod(), common.AnnotationSyncWave, "-1"), phase: SyncPhaseSync}}
assert.Equal(t, SyncPhaseSync, tasks.phase())
assert.Equal(t, -1, tasks.wave())
assert.Equal(t, SyncPhaseSync, tasks.lastPhase())
assert.Equal(t, -1, tasks.lastWave())
assert.False(t, tasks.multiStep())
})
t.Run("Double", func(t *testing.T) {
tasks := syncTasks{
{liveObj: Annotate(NewPod(), common.AnnotationSyncWave, "-1"), phase: SyncPhasePreSync},
{liveObj: Annotate(NewPod(), common.AnnotationSyncWave, "1"), phase: SyncPhasePostSync},
}
assert.Equal(t, SyncPhasePreSync, tasks.phase())
assert.Equal(t, -1, tasks.wave())
assert.Equal(t, SyncPhasePostSync, tasks.lastPhase())
assert.Equal(t, 1, tasks.lastWave())
assert.True(t, tasks.multiStep())
})
}

View File

@@ -91,4 +91,37 @@ Argo CD automatically sets the `app.kubernetes.io/instance` label and uses it to
!!! note When you make this change your applications will become out of sync and will need re-syncing.
See [#1482](https://github.com/argoproj/argo-cd/issues/1482).
See [#1482](https://github.com/argoproj/argo-cd/issues/1482).
# How Do I Fix "invalid cookie, longer than max length 4093"?
Argo CD uses a JWT as the auth token. You likely are part of many groups and have gone over the 4KB limit which is set for cookies.
You can get the list of groups by opening "developer tools -> network"
* Click log in
* Find the call to `<argocd_instance>/auth/callback?code=<random_string>`
Decode the token at https://jwt.io/. That will provide the list of teams that you can remove yourself from.
See [#2165](https://github.com/argoproj/argo-cd/issues/2165).
## Why Am I Getting `rpc error: code = Unavailable desc = transport is closing` When Using The CLI?
Maybe you're behind a proxy that does not support HTTP 2? Try the `--grcp-web` flag.:
```bash
argocd ... --grcp-web
```
## Why Am I Getting `x509: certificate signed by unknown authority` When Using The CLI?
Your not running your server with correct certs.
If you're not running in a production system (e.g. you're testing Argo CD out), try the `--insecure` flag:
```bash
argocd ... --insecure
```
!!! warning "Do not use `--insecure` in production"

View File

@@ -18,6 +18,11 @@ data:
# Unless set to 'false' then user ids are hashed before sending to google analytics
ga.anonymizeusers: 'false'
# the URL for getting chat help, this will typically be your Slack channel for support
help.chatUrl: 'https://mycorp.slack.com/argo-cd'
# the text for getting chat help, defaults to "Chat now!"
help.chatText: 'Chat now!'
# A dex connector configuration (optional). See SSO configuration documentation:
# https://github.com/argoproj/argo-cd/blob/master/docs/sso.md
# https://github.com/dexidp/dex/tree/master/Documentation/connectors

View File

@@ -10,7 +10,20 @@ AUTOGENMSG="# This is an auto-generated file. DO NOT EDIT"
cd ${SRCROOT}/manifests/ha/base/redis-ha && ./generate.sh
IMAGE_NAMESPACE="${IMAGE_NAMESPACE:-argoproj}"
IMAGE_TAG="${IMAGE_TAG:-latest}"
IMAGE_TAG="${IMAGE_TAG:-}"
# if the tag has not been declared, and we are on a release branch, use the VERSION file.
if [ "$IMAGE_TAG" = "" ]; then
branch=$(git rev-parse --abbrev-ref HEAD)
if [[ $branch = release-* ]]; then
pwd
IMAGE_TAG=v$(cat $SRCROOT/VERSION)
fi
fi
# otherwise, use latest
if [ "$IMAGE_TAG" = "" ]; then
IMAGE_TAG=latest
fi
cd ${SRCROOT}/manifests/base && kustomize edit set image argoproj/argocd=${IMAGE_NAMESPACE}/argocd:${IMAGE_TAG} argoproj/argocd-ui=${IMAGE_NAMESPACE}/argocd-ui:${IMAGE_TAG}
cd ${SRCROOT}/manifests/ha/base && kustomize edit set image argoproj/argocd=${IMAGE_NAMESPACE}/argocd:${IMAGE_TAG} argoproj/argocd-ui=${IMAGE_NAMESPACE}/argocd-ui:${IMAGE_TAG}

View File

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

View File

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

View File

@@ -2901,7 +2901,7 @@ spec:
- argocd-redis-ha-announce-2:26379
- --sentinelmaster
- argocd
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2955,7 +2955,7 @@ spec:
- cp
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -3010,7 +3010,7 @@ spec:
- argocd-redis-ha-announce-2:26379
- --sentinelmaster
- argocd
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 5
@@ -3084,7 +3084,7 @@ spec:
- argocd-redis-ha-announce-2:26379
- --sentinelmaster
- argocd
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -2816,7 +2816,7 @@ spec:
- argocd-redis-ha-announce-2:26379
- --sentinelmaster
- argocd
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2870,7 +2870,7 @@ spec:
- cp
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -2925,7 +2925,7 @@ spec:
- argocd-redis-ha-announce-2:26379
- --sentinelmaster
- argocd
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 5
@@ -2999,7 +2999,7 @@ spec:
- argocd-redis-ha-announce-2:26379
- --sentinelmaster
- argocd
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -2665,7 +2665,7 @@ spec:
- "20"
- --operation-processors
- "10"
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2719,7 +2719,7 @@ spec:
- cp
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -2782,7 +2782,7 @@ spec:
- argocd-repo-server
- --redis
- argocd-redis:6379
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 5
@@ -2833,7 +2833,7 @@ spec:
- argocd-server
- --staticassets
- /shared/app
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -2580,7 +2580,7 @@ spec:
- "20"
- --operation-processors
- "10"
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2634,7 +2634,7 @@ spec:
- cp
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -2697,7 +2697,7 @@ spec:
- argocd-repo-server
- --redis
- argocd-redis:6379
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
livenessProbe:
initialDelaySeconds: 5
@@ -2748,7 +2748,7 @@ spec:
- argocd-server
- --staticassets
- /shared/app
image: argoproj/argocd:latest
image: argoproj/argocd:v1.2.0
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -43,7 +43,7 @@ func (m *SettingsQuery) Reset() { *m = SettingsQuery{} }
func (m *SettingsQuery) String() string { return proto.CompactTextString(m) }
func (*SettingsQuery) ProtoMessage() {}
func (*SettingsQuery) Descriptor() ([]byte, []int) {
return fileDescriptor_settings_7350a88adeab0893, []int{0}
return fileDescriptor_settings_ab575d97e47167cb, []int{0}
}
func (m *SettingsQuery) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -73,24 +73,26 @@ func (m *SettingsQuery) XXX_DiscardUnknown() {
var xxx_messageInfo_SettingsQuery proto.InternalMessageInfo
type Settings struct {
URL string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
DexConfig *DexConfig `protobuf:"bytes,2,opt,name=dexConfig" json:"dexConfig,omitempty"`
OIDCConfig *OIDCConfig `protobuf:"bytes,3,opt,name=oidcConfig" json:"oidcConfig,omitempty"`
AppLabelKey string `protobuf:"bytes,4,opt,name=appLabelKey,proto3" json:"appLabelKey,omitempty"`
ResourceOverrides map[string]*v1alpha1.ResourceOverride `protobuf:"bytes,5,rep,name=resourceOverrides" json:"resourceOverrides,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"`
StatusBadgeEnabled bool `protobuf:"varint,6,opt,name=statusBadgeEnabled,proto3" json:"statusBadgeEnabled,omitempty"`
GoogleAnalytics *GoogleAnalyticsConfig `protobuf:"bytes,7,opt,name=googleAnalytics" json:"googleAnalytics,omitempty"`
KustomizeOptions *v1alpha1.KustomizeOptions `protobuf:"bytes,8,opt,name=kustomizeOptions" json:"kustomizeOptions,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
URL string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
DexConfig *DexConfig `protobuf:"bytes,2,opt,name=dexConfig" json:"dexConfig,omitempty"`
OIDCConfig *OIDCConfig `protobuf:"bytes,3,opt,name=oidcConfig" json:"oidcConfig,omitempty"`
AppLabelKey string `protobuf:"bytes,4,opt,name=appLabelKey,proto3" json:"appLabelKey,omitempty"`
ResourceOverrides map[string]*v1alpha1.ResourceOverride `protobuf:"bytes,5,rep,name=resourceOverrides" json:"resourceOverrides,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"`
StatusBadgeEnabled bool `protobuf:"varint,6,opt,name=statusBadgeEnabled,proto3" json:"statusBadgeEnabled,omitempty"`
GoogleAnalytics *GoogleAnalyticsConfig `protobuf:"bytes,7,opt,name=googleAnalytics" json:"googleAnalytics,omitempty"`
KustomizeOptions *v1alpha1.KustomizeOptions `protobuf:"bytes,8,opt,name=kustomizeOptions" json:"kustomizeOptions,omitempty"`
// Help settings
Help *Help `protobuf:"bytes,9,opt,name=help" json:"help,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Settings) Reset() { *m = Settings{} }
func (m *Settings) String() string { return proto.CompactTextString(m) }
func (*Settings) ProtoMessage() {}
func (*Settings) Descriptor() ([]byte, []int) {
return fileDescriptor_settings_7350a88adeab0893, []int{1}
return fileDescriptor_settings_ab575d97e47167cb, []int{1}
}
func (m *Settings) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -175,6 +177,13 @@ func (m *Settings) GetKustomizeOptions() *v1alpha1.KustomizeOptions {
return nil
}
func (m *Settings) GetHelp() *Help {
if m != nil {
return m.Help
}
return nil
}
type GoogleAnalyticsConfig struct {
TrackingID string `protobuf:"bytes,1,opt,name=trackingID,proto3" json:"trackingID,omitempty"`
AnonymizeUsers bool `protobuf:"varint,2,opt,name=anonymizeUsers,proto3" json:"anonymizeUsers,omitempty"`
@@ -187,7 +196,7 @@ func (m *GoogleAnalyticsConfig) Reset() { *m = GoogleAnalyticsConfig{} }
func (m *GoogleAnalyticsConfig) String() string { return proto.CompactTextString(m) }
func (*GoogleAnalyticsConfig) ProtoMessage() {}
func (*GoogleAnalyticsConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_settings_7350a88adeab0893, []int{2}
return fileDescriptor_settings_ab575d97e47167cb, []int{2}
}
func (m *GoogleAnalyticsConfig) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -230,6 +239,64 @@ func (m *GoogleAnalyticsConfig) GetAnonymizeUsers() bool {
return false
}
// Help settings
type Help struct {
// the URL for getting chat help, this will typically be your Slack channel for support
ChatUrl string `protobuf:"bytes,1,opt,name=chatUrl,proto3" json:"chatUrl,omitempty"`
// the text for getting chat help, defaults to "Chat now!"
ChatText string `protobuf:"bytes,2,opt,name=chatText,proto3" json:"chatText,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Help) Reset() { *m = Help{} }
func (m *Help) String() string { return proto.CompactTextString(m) }
func (*Help) ProtoMessage() {}
func (*Help) Descriptor() ([]byte, []int) {
return fileDescriptor_settings_ab575d97e47167cb, []int{3}
}
func (m *Help) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *Help) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_Help.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalTo(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (dst *Help) XXX_Merge(src proto.Message) {
xxx_messageInfo_Help.Merge(dst, src)
}
func (m *Help) XXX_Size() int {
return m.Size()
}
func (m *Help) XXX_DiscardUnknown() {
xxx_messageInfo_Help.DiscardUnknown(m)
}
var xxx_messageInfo_Help proto.InternalMessageInfo
func (m *Help) GetChatUrl() string {
if m != nil {
return m.ChatUrl
}
return ""
}
func (m *Help) GetChatText() string {
if m != nil {
return m.ChatText
}
return ""
}
type DexConfig struct {
Connectors []*Connector `protobuf:"bytes,1,rep,name=connectors" json:"connectors,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
@@ -241,7 +308,7 @@ func (m *DexConfig) Reset() { *m = DexConfig{} }
func (m *DexConfig) String() string { return proto.CompactTextString(m) }
func (*DexConfig) ProtoMessage() {}
func (*DexConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_settings_7350a88adeab0893, []int{3}
return fileDescriptor_settings_ab575d97e47167cb, []int{4}
}
func (m *DexConfig) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -289,7 +356,7 @@ func (m *Connector) Reset() { *m = Connector{} }
func (m *Connector) String() string { return proto.CompactTextString(m) }
func (*Connector) ProtoMessage() {}
func (*Connector) Descriptor() ([]byte, []int) {
return fileDescriptor_settings_7350a88adeab0893, []int{4}
return fileDescriptor_settings_ab575d97e47167cb, []int{5}
}
func (m *Connector) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -347,7 +414,7 @@ func (m *OIDCConfig) Reset() { *m = OIDCConfig{} }
func (m *OIDCConfig) String() string { return proto.CompactTextString(m) }
func (*OIDCConfig) ProtoMessage() {}
func (*OIDCConfig) Descriptor() ([]byte, []int) {
return fileDescriptor_settings_7350a88adeab0893, []int{5}
return fileDescriptor_settings_ab575d97e47167cb, []int{6}
}
func (m *OIDCConfig) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -416,6 +483,7 @@ func init() {
proto.RegisterType((*Settings)(nil), "cluster.Settings")
proto.RegisterMapType((map[string]*v1alpha1.ResourceOverride)(nil), "cluster.Settings.ResourceOverridesEntry")
proto.RegisterType((*GoogleAnalyticsConfig)(nil), "cluster.GoogleAnalyticsConfig")
proto.RegisterType((*Help)(nil), "cluster.Help")
proto.RegisterType((*DexConfig)(nil), "cluster.DexConfig")
proto.RegisterType((*Connector)(nil), "cluster.Connector")
proto.RegisterType((*OIDCConfig)(nil), "cluster.OIDCConfig")
@@ -621,6 +689,16 @@ func (m *Settings) MarshalTo(dAtA []byte) (int, error) {
}
i += n5
}
if m.Help != nil {
dAtA[i] = 0x4a
i++
i = encodeVarintSettings(dAtA, i, uint64(m.Help.Size()))
n6, err := m.Help.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n6
}
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
}
@@ -664,6 +742,39 @@ func (m *GoogleAnalyticsConfig) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *Help) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Help) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.ChatUrl) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintSettings(dAtA, i, uint64(len(m.ChatUrl)))
i += copy(dAtA[i:], m.ChatUrl)
}
if len(m.ChatText) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintSettings(dAtA, i, uint64(len(m.ChatText)))
i += copy(dAtA[i:], m.ChatText)
}
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
}
return i, nil
}
func (m *DexConfig) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -851,6 +962,10 @@ func (m *Settings) Size() (n int) {
l = m.KustomizeOptions.Size()
n += 1 + l + sovSettings(uint64(l))
}
if m.Help != nil {
l = m.Help.Size()
n += 1 + l + sovSettings(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@@ -873,6 +988,23 @@ func (m *GoogleAnalyticsConfig) Size() (n int) {
return n
}
func (m *Help) Size() (n int) {
var l int
_ = l
l = len(m.ChatUrl)
if l > 0 {
n += 1 + l + sovSettings(uint64(l))
}
l = len(m.ChatText)
if l > 0 {
n += 1 + l + sovSettings(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func (m *DexConfig) Size() (n int) {
var l int
_ = l
@@ -1362,6 +1494,39 @@ func (m *Settings) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 9:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Help", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSettings
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthSettings
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Help == nil {
m.Help = &Help{}
}
if err := m.Help.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipSettings(dAtA[iNdEx:])
@@ -1484,6 +1649,115 @@ func (m *GoogleAnalyticsConfig) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *Help) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSettings
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Help: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Help: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ChatUrl", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSettings
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthSettings
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ChatUrl = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ChatText", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSettings
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthSettings
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ChatText = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipSettings(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthSettings
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *DexConfig) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
@@ -1977,53 +2251,56 @@ var (
)
func init() {
proto.RegisterFile("server/settings/settings.proto", fileDescriptor_settings_7350a88adeab0893)
proto.RegisterFile("server/settings/settings.proto", fileDescriptor_settings_ab575d97e47167cb)
}
var fileDescriptor_settings_7350a88adeab0893 = []byte{
// 699 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xcd, 0x6e, 0xd3, 0x40,
0x10, 0x96, 0x9b, 0xfe, 0x24, 0x13, 0x68, 0xda, 0x05, 0x2a, 0x13, 0xa1, 0x24, 0xca, 0x01, 0xe5,
0x82, 0x4d, 0xd2, 0x0b, 0xe2, 0x02, 0x24, 0xa9, 0x4a, 0x68, 0xa5, 0x8a, 0xad, 0xca, 0x01, 0x09,
0x55, 0x1b, 0x7b, 0x71, 0x4d, 0xdc, 0x5d, 0x6b, 0x77, 0x1d, 0x08, 0x47, 0xde, 0x00, 0x71, 0xe6,
0x11, 0x78, 0x0f, 0x8e, 0x48, 0xdc, 0x23, 0x14, 0xf1, 0x20, 0xc8, 0xeb, 0x9f, 0x84, 0x24, 0x07,
0x24, 0x6e, 0xe3, 0xef, 0xdb, 0x6f, 0x76, 0x66, 0xfd, 0xcd, 0x40, 0x4d, 0x52, 0x31, 0xa6, 0xc2,
0x96, 0x54, 0x29, 0x9f, 0x79, 0x32, 0x0f, 0xac, 0x50, 0x70, 0xc5, 0xd1, 0x8e, 0x13, 0x44, 0x52,
0x51, 0x51, 0xbd, 0xed, 0x71, 0x8f, 0x6b, 0xcc, 0x8e, 0xa3, 0x84, 0xae, 0xde, 0xf3, 0x38, 0xf7,
0x02, 0x6a, 0x93, 0xd0, 0xb7, 0x09, 0x63, 0x5c, 0x11, 0xe5, 0x73, 0x96, 0x8a, 0xab, 0x03, 0xcf,
0x57, 0x57, 0xd1, 0xd0, 0x72, 0xf8, 0xb5, 0x4d, 0x84, 0x96, 0xbf, 0xd3, 0xc1, 0x03, 0xc7, 0xb5,
0xc3, 0x91, 0x17, 0xcb, 0xa4, 0x4d, 0xc2, 0x30, 0xf0, 0x1d, 0x2d, 0xb4, 0xc7, 0x6d, 0x12, 0x84,
0x57, 0xa4, 0x6d, 0x7b, 0x94, 0x51, 0x41, 0x14, 0x75, 0x93, 0x54, 0xcd, 0x0a, 0xdc, 0x3c, 0x4f,
0x2b, 0x7b, 0x19, 0x51, 0x31, 0x69, 0x7e, 0xdd, 0x82, 0x62, 0x86, 0xa0, 0xbb, 0x50, 0x88, 0x44,
0x60, 0x1a, 0x0d, 0xa3, 0x55, 0xea, 0xee, 0xcc, 0xa6, 0xf5, 0xc2, 0x05, 0x3e, 0xc5, 0x31, 0x86,
0x1e, 0x42, 0xc9, 0xa5, 0x1f, 0x7a, 0x9c, 0xbd, 0xf5, 0x3d, 0x73, 0xa3, 0x61, 0xb4, 0xca, 0x1d,
0x64, 0xa5, 0x4d, 0x59, 0xfd, 0x8c, 0xc1, 0xf3, 0x43, 0xa8, 0x07, 0xc0, 0x7d, 0xd7, 0x49, 0x25,
0x05, 0x2d, 0xb9, 0x95, 0x4b, 0xce, 0x06, 0xfd, 0x5e, 0x42, 0x75, 0x77, 0x67, 0xd3, 0x3a, 0xcc,
0xbf, 0xf1, 0x82, 0x0c, 0x35, 0xa0, 0x4c, 0xc2, 0xf0, 0x94, 0x0c, 0x69, 0x70, 0x42, 0x27, 0xe6,
0x66, 0x5c, 0x19, 0x5e, 0x84, 0xd0, 0x2b, 0xd8, 0x17, 0x54, 0xf2, 0x48, 0x38, 0xf4, 0x6c, 0x4c,
0x85, 0xf0, 0x5d, 0x2a, 0xcd, 0xad, 0x46, 0xa1, 0x55, 0xee, 0xb4, 0xf2, 0xdb, 0xb2, 0x0e, 0x2d,
0xbc, 0x7c, 0xf4, 0x88, 0x29, 0x31, 0xc1, 0xab, 0x29, 0x90, 0x05, 0x48, 0x2a, 0xa2, 0x22, 0xd9,
0x25, 0xae, 0x47, 0x8f, 0x18, 0x19, 0x06, 0xd4, 0x35, 0xb7, 0x1b, 0x46, 0xab, 0x88, 0xd7, 0x30,
0xe8, 0x39, 0x54, 0x92, 0x9f, 0xf8, 0x8c, 0x91, 0x60, 0xa2, 0x7c, 0x47, 0x9a, 0x3b, 0xba, 0xe7,
0x5a, 0x5e, 0xc5, 0xf1, 0xdf, 0x7c, 0xda, 0xee, 0xb2, 0x0c, 0xbd, 0x87, 0xbd, 0x51, 0x24, 0x15,
0xbf, 0xf6, 0x3f, 0xd2, 0xb3, 0x50, 0x1b, 0xc1, 0x2c, 0xea, 0x54, 0x27, 0xd6, 0xdc, 0x09, 0x56,
0xe6, 0x04, 0x1d, 0x5c, 0x3a, 0xae, 0x15, 0x8e, 0x3c, 0x2b, 0x76, 0x82, 0xb5, 0xe0, 0x04, 0x2b,
0x73, 0x82, 0x75, 0xb2, 0x94, 0x12, 0xaf, 0x5c, 0x52, 0xfd, 0x6c, 0xc0, 0xc1, 0xfa, 0x07, 0x42,
0x7b, 0x50, 0x18, 0xd1, 0x49, 0xe2, 0x0c, 0x1c, 0x87, 0x88, 0xc0, 0xd6, 0x98, 0x04, 0x11, 0x4d,
0xcd, 0xf0, 0x3f, 0xa5, 0x2d, 0xdf, 0x89, 0x93, 0xcc, 0x8f, 0x37, 0x1e, 0x19, 0xcd, 0x4b, 0xb8,
0xb3, 0xf6, 0xd9, 0x50, 0x0d, 0x40, 0x09, 0xe2, 0x8c, 0x7c, 0xe6, 0x0d, 0xfa, 0x69, 0x61, 0x0b,
0x08, 0xba, 0x0f, 0xbb, 0x84, 0x71, 0x36, 0x89, 0x1b, 0xbc, 0x90, 0x54, 0x48, 0x5d, 0x68, 0x11,
0x2f, 0xa1, 0xcd, 0x27, 0x50, 0xca, 0xed, 0x8b, 0x3a, 0x00, 0x0e, 0x67, 0x8c, 0x3a, 0x8a, 0x0b,
0x69, 0x1a, 0xda, 0x45, 0x73, 0x9b, 0xf7, 0x32, 0x0a, 0x2f, 0x9c, 0x6a, 0x1e, 0x42, 0x29, 0x27,
0x10, 0x82, 0x4d, 0x46, 0xae, 0x69, 0x5a, 0x8f, 0x8e, 0x63, 0x4c, 0x4d, 0xc2, 0xe4, 0xa1, 0x4a,
0x58, 0xc7, 0xcd, 0x6f, 0x06, 0x2c, 0x58, 0x7e, 0xad, 0xec, 0x00, 0xb6, 0x7d, 0x29, 0x23, 0x2a,
0x52, 0x61, 0xfa, 0x85, 0x5a, 0x50, 0x74, 0x02, 0x9f, 0x32, 0x35, 0xe8, 0xeb, 0xa9, 0x2a, 0x75,
0x6f, 0xcc, 0xa6, 0xf5, 0x62, 0x2f, 0xc5, 0x70, 0xce, 0xa2, 0x36, 0x94, 0x9d, 0xc0, 0xcf, 0x88,
0x64, 0x78, 0xba, 0x95, 0xd9, 0xb4, 0x5e, 0xee, 0x9d, 0x0e, 0xf2, 0xf3, 0x8b, 0x67, 0xe2, 0x4b,
0xa5, 0xc3, 0xc3, 0x74, 0x84, 0x4a, 0x38, 0xfd, 0xea, 0xbc, 0x81, 0x4a, 0x36, 0x43, 0xe7, 0x54,
0x8c, 0x7d, 0x87, 0xa2, 0x17, 0x50, 0x38, 0xa6, 0x0a, 0x1d, 0xac, 0x0c, 0x99, 0x5e, 0x2c, 0xd5,
0xfd, 0x15, 0xbc, 0x69, 0x7e, 0xfa, 0xf9, 0xfb, 0xcb, 0x06, 0x42, 0x7b, 0x7a, 0xcf, 0x8d, 0xdb,
0xf9, 0x92, 0xec, 0x3e, 0xfd, 0x3e, 0xab, 0x19, 0x3f, 0x66, 0x35, 0xe3, 0xd7, 0xac, 0x66, 0xbc,
0xee, 0xfc, 0xc3, 0xbe, 0x4b, 0x9a, 0xcc, 0x33, 0x0c, 0xb7, 0xf5, 0x7e, 0x3b, 0xfc, 0x13, 0x00,
0x00, 0xff, 0xff, 0x5b, 0xcc, 0xdb, 0x51, 0x89, 0x05, 0x00, 0x00,
var fileDescriptor_settings_ab575d97e47167cb = []byte{
// 750 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xcd, 0x6e, 0x23, 0x45,
0x10, 0xd6, 0xc4, 0xf9, 0xf1, 0x94, 0xd9, 0x4d, 0xb6, 0x81, 0x68, 0xb0, 0x90, 0x63, 0xe6, 0x80,
0x7c, 0x61, 0x86, 0x78, 0x2f, 0x08, 0x21, 0x01, 0x76, 0x56, 0xbb, 0x26, 0x91, 0x22, 0x7a, 0x09,
0x07, 0x24, 0xb4, 0xea, 0xf4, 0x14, 0xe3, 0xc1, 0x93, 0xee, 0x51, 0x77, 0x8f, 0x59, 0x73, 0xe4,
0x0d, 0x10, 0xcf, 0xc1, 0x3b, 0x70, 0xe4, 0x88, 0xc4, 0xdd, 0x42, 0x16, 0x0f, 0x82, 0xa6, 0xe7,
0xc7, 0xc6, 0xf6, 0x01, 0x89, 0x5b, 0x55, 0x7d, 0xf5, 0xd5, 0x4f, 0x77, 0x55, 0x41, 0x4f, 0xa3,
0x9a, 0xa3, 0x0a, 0x35, 0x1a, 0x93, 0x88, 0x58, 0x37, 0x42, 0x90, 0x29, 0x69, 0x24, 0x39, 0xe1,
0x69, 0xae, 0x0d, 0xaa, 0xee, 0x5b, 0xb1, 0x8c, 0xa5, 0xb5, 0x85, 0x85, 0x54, 0xc2, 0xdd, 0x77,
0x63, 0x29, 0xe3, 0x14, 0x43, 0x96, 0x25, 0x21, 0x13, 0x42, 0x1a, 0x66, 0x12, 0x29, 0x2a, 0x72,
0x77, 0x12, 0x27, 0x66, 0x9a, 0xdf, 0x07, 0x5c, 0x3e, 0x84, 0x4c, 0x59, 0xfa, 0xf7, 0x56, 0xf8,
0x80, 0x47, 0x61, 0x36, 0x8b, 0x0b, 0x9a, 0x0e, 0x59, 0x96, 0xa5, 0x09, 0xb7, 0xc4, 0x70, 0x7e,
0xc9, 0xd2, 0x6c, 0xca, 0x2e, 0xc3, 0x18, 0x05, 0x2a, 0x66, 0x30, 0x2a, 0x43, 0xf9, 0xa7, 0xf0,
0xe8, 0x65, 0x55, 0xd9, 0x97, 0x39, 0xaa, 0x85, 0xff, 0xdb, 0x11, 0xb4, 0x6b, 0x0b, 0x79, 0x07,
0x5a, 0xb9, 0x4a, 0x3d, 0xa7, 0xef, 0x0c, 0xdc, 0xd1, 0xc9, 0x6a, 0x79, 0xd1, 0xba, 0xa3, 0x37,
0xb4, 0xb0, 0x91, 0x0f, 0xc1, 0x8d, 0xf0, 0xf5, 0x58, 0x8a, 0xef, 0x92, 0xd8, 0x3b, 0xe8, 0x3b,
0x83, 0xce, 0x90, 0x04, 0x55, 0x53, 0xc1, 0x55, 0x8d, 0xd0, 0xb5, 0x13, 0x19, 0x03, 0xc8, 0x24,
0xe2, 0x15, 0xa5, 0x65, 0x29, 0x6f, 0x36, 0x94, 0xdb, 0xc9, 0xd5, 0xb8, 0x84, 0x46, 0x8f, 0x57,
0xcb, 0x0b, 0x58, 0xeb, 0x74, 0x83, 0x46, 0xfa, 0xd0, 0x61, 0x59, 0x76, 0xc3, 0xee, 0x31, 0xbd,
0xc6, 0x85, 0x77, 0x58, 0x54, 0x46, 0x37, 0x4d, 0xe4, 0x6b, 0x78, 0xa2, 0x50, 0xcb, 0x5c, 0x71,
0xbc, 0x9d, 0xa3, 0x52, 0x49, 0x84, 0xda, 0x3b, 0xea, 0xb7, 0x06, 0x9d, 0xe1, 0xa0, 0xc9, 0x56,
0x77, 0x18, 0xd0, 0x6d, 0xd7, 0x67, 0xc2, 0xa8, 0x05, 0xdd, 0x0d, 0x41, 0x02, 0x20, 0xda, 0x30,
0x93, 0xeb, 0x11, 0x8b, 0x62, 0x7c, 0x26, 0xd8, 0x7d, 0x8a, 0x91, 0x77, 0xdc, 0x77, 0x06, 0x6d,
0xba, 0x07, 0x21, 0x2f, 0xe0, 0xb4, 0xfc, 0xc4, 0xcf, 0x05, 0x4b, 0x17, 0x26, 0xe1, 0xda, 0x3b,
0xb1, 0x3d, 0xf7, 0x9a, 0x2a, 0x9e, 0xff, 0x1b, 0xaf, 0xda, 0xdd, 0xa6, 0x91, 0x1f, 0xe0, 0x6c,
0x96, 0x6b, 0x23, 0x1f, 0x92, 0x1f, 0xf1, 0x36, 0xb3, 0x83, 0xe0, 0xb5, 0x6d, 0xa8, 0xeb, 0x60,
0x3d, 0x09, 0x41, 0x3d, 0x09, 0x56, 0x78, 0xc5, 0xa3, 0x20, 0x9b, 0xc5, 0x41, 0x31, 0x09, 0xc1,
0xc6, 0x24, 0x04, 0xf5, 0x24, 0x04, 0xd7, 0x5b, 0x21, 0xe9, 0x4e, 0x12, 0xf2, 0x1e, 0x1c, 0x4e,
0x31, 0xcd, 0x3c, 0xd7, 0x26, 0x7b, 0xd4, 0xd4, 0xfd, 0x02, 0xd3, 0x8c, 0x5a, 0xa8, 0xfb, 0xb3,
0x03, 0xe7, 0xfb, 0xdf, 0x90, 0x9c, 0x41, 0x6b, 0x86, 0x8b, 0x72, 0x78, 0x68, 0x21, 0x12, 0x06,
0x47, 0x73, 0x96, 0xe6, 0x58, 0xcd, 0xcb, 0xff, 0xa9, 0x7e, 0x3b, 0x27, 0x2d, 0x23, 0x7f, 0x7c,
0xf0, 0x91, 0xe3, 0xbf, 0x82, 0xb7, 0xf7, 0xbe, 0x2c, 0xe9, 0x01, 0x18, 0xc5, 0xf8, 0x2c, 0x11,
0xf1, 0xe4, 0xaa, 0x2a, 0x6c, 0xc3, 0x42, 0xde, 0x87, 0xc7, 0x4c, 0x48, 0xb1, 0x28, 0xde, 0xe0,
0x4e, 0xa3, 0xd2, 0xb6, 0xd0, 0x36, 0xdd, 0xb2, 0xfa, 0x9f, 0xc0, 0x61, 0xf1, 0x04, 0xc4, 0x83,
0x13, 0x3e, 0x65, 0xe6, 0xae, 0x5e, 0x11, 0x5a, 0xab, 0xa4, 0x0b, 0xed, 0x42, 0xfc, 0x0a, 0x5f,
0x1b, 0x1b, 0xc3, 0xa5, 0x8d, 0xee, 0x7f, 0x0a, 0x6e, 0xb3, 0x1f, 0x64, 0x08, 0xc0, 0xa5, 0x10,
0xc8, 0x8d, 0x54, 0xda, 0x73, 0xec, 0x98, 0xae, 0xf7, 0x68, 0x5c, 0x43, 0x74, 0xc3, 0xcb, 0x7f,
0x0a, 0x6e, 0x03, 0x10, 0x02, 0x87, 0x82, 0x3d, 0x60, 0x55, 0x80, 0x95, 0x0b, 0x9b, 0x59, 0x64,
0x58, 0x65, 0xb6, 0xb2, 0xff, 0xab, 0x03, 0x1b, 0x3b, 0xb5, 0x97, 0x76, 0x0e, 0xc7, 0x89, 0xd6,
0x39, 0xaa, 0x8a, 0x58, 0x69, 0x64, 0x00, 0x6d, 0x9e, 0x26, 0x28, 0xcc, 0xe4, 0xca, 0xae, 0xad,
0x3b, 0x7a, 0x63, 0xb5, 0xbc, 0x68, 0x8f, 0x2b, 0x1b, 0x6d, 0x50, 0x72, 0x09, 0x1d, 0x9e, 0x26,
0x35, 0x50, 0x6e, 0xe7, 0xe8, 0x74, 0xb5, 0xbc, 0xe8, 0x8c, 0x6f, 0x26, 0x8d, 0xff, 0xa6, 0x4f,
0x91, 0x54, 0x73, 0x99, 0x55, 0x3b, 0xea, 0xd2, 0x4a, 0x1b, 0x7e, 0x0b, 0xa7, 0xf5, 0x92, 0xbe,
0x44, 0x35, 0x4f, 0x38, 0x92, 0x2f, 0xa0, 0xf5, 0x1c, 0x0d, 0x39, 0xdf, 0xd9, 0x62, 0x7b, 0xb9,
0xba, 0x4f, 0x76, 0xec, 0xbe, 0xf7, 0xd3, 0x9f, 0x7f, 0xff, 0x72, 0x40, 0xc8, 0x99, 0x3d, 0xa4,
0xf3, 0xcb, 0xe6, 0x0a, 0x8f, 0x3e, 0xfb, 0x7d, 0xd5, 0x73, 0xfe, 0x58, 0xf5, 0x9c, 0xbf, 0x56,
0x3d, 0xe7, 0x9b, 0xe1, 0x7f, 0x38, 0xa8, 0x65, 0x93, 0x4d, 0x84, 0xfb, 0x63, 0x7b, 0x40, 0x9f,
0xfe, 0x13, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xa4, 0xe4, 0xcb, 0xea, 0x05, 0x00, 0x00,
}

File diff suppressed because it is too large Load Diff

View File

@@ -584,6 +584,8 @@ message ResourceDiff {
optional string liveState = 6;
optional string diff = 7;
optional bool hook = 8;
}
// ResourceIgnoreDifferences contains resource filter and list of json paths which should be ignored during comparison with live state.

View File

@@ -2097,6 +2097,12 @@ func schema_pkg_apis_application_v1alpha1_ResourceDiff(ref common.ReferenceCallb
Format: "",
},
},
"hook": {
SchemaProps: spec.SchemaProps{
Type: []string{"boolean"},
Format: "",
},
},
},
},
},

View File

@@ -786,6 +786,7 @@ type ResourceDiff struct {
TargetState string `json:"targetState,omitempty" protobuf:"bytes,5,opt,name=targetState"`
LiveState string `json:"liveState,omitempty" protobuf:"bytes,6,opt,name=liveState"`
Diff string `json:"diff,omitempty" protobuf:"bytes,7,opt,name=diff"`
Hook bool `json:"hook,omitempty" protobuf:"bytes,8,opt,name=hook"`
}
// ConnectionStatus represents connection status

View File

@@ -189,28 +189,33 @@ func (s *Service) GenerateManifest(c context.Context, q *apiclient.ManifestReque
return &res, nil
}
func checkPath(root, path string) error {
info, err := os.Stat(filepath.Join(root, path))
func appPath(root, path string) (string, error) {
if filepath.IsAbs(path) {
return "", fmt.Errorf("%s: app path is absolute", path)
}
appPath := filepath.Join(root, path)
if !strings.HasPrefix(appPath, filepath.Clean(root)) {
return "", fmt.Errorf("%s: app path outside repo", path)
}
info, err := os.Stat(appPath)
if os.IsNotExist(err) {
return fmt.Errorf("%s: app path does not exist", path)
return "", fmt.Errorf("%s: app path does not exist", path)
}
if err != nil {
return err
return "", err
}
if !info.IsDir() {
return fmt.Errorf("%s: app path is not a directory", path)
return "", fmt.Errorf("%s: app path is not a directory", path)
}
return nil
return appPath, nil
}
// GenerateManifests generates manifests from a path
func GenerateManifests(root, path string, q *apiclient.ManifestRequest) (*apiclient.ManifestResponse, error) {
err := checkPath(root, path)
appPath, err := appPath(root, path)
if err != nil {
return nil, err
}
appPath := filepath.Join(root, path)
var targetObjs []*unstructured.Unstructured
var dest *v1alpha1.ApplicationDestination

View File

@@ -90,16 +90,51 @@ func TestRecurseManifestsInDir(t *testing.T) {
assert.Equal(t, 2, len(res1.Manifests))
}
func TestPathRoot(t *testing.T) {
_, err := appPath("./testdata", "/")
assert.EqualError(t, err, "/: app path is absolute")
}
func TestPathAbsolute(t *testing.T) {
_, err := appPath("./testdata", "/etc/passwd")
assert.EqualError(t, err, "/etc/passwd: app path is absolute")
}
func TestPathDotDot(t *testing.T) {
_, err := appPath("./testdata", "..")
assert.EqualError(t, err, "..: app path outside repo")
}
func TestPathDotDotSlash(t *testing.T) {
_, err := appPath("./testdata", "../")
assert.EqualError(t, err, "../: app path outside repo")
}
func TestPathDot(t *testing.T) {
_, err := appPath("./testdata", ".")
assert.NoError(t, err)
}
func TestPathDotSlash(t *testing.T) {
_, err := appPath("./testdata", "./")
assert.NoError(t, err)
}
func TestNonExistentPath(t *testing.T) {
_, err := GenerateManifests("./testdata", "does-not-exist", nil)
_, err := appPath("./testdata", "does-not-exist")
assert.EqualError(t, err, "does-not-exist: app path does not exist")
}
func TestPathNotDir(t *testing.T) {
_, err := GenerateManifests("./testdata", "file.txt", nil)
_, err := appPath("./testdata", "file.txt")
assert.EqualError(t, err, "file.txt: app path is not a directory")
}
func TestGenerateManifests_NonExistentPath(t *testing.T) {
_, err := GenerateManifests("./testdata", "does-not-exist", nil)
assert.EqualError(t, err, "does-not-exist: app path does not exist")
}
func TestGenerateJsonnetManifestInDir(t *testing.T) {
q := apiclient.ManifestRequest{
ApplicationSource: &argoappv1.ApplicationSource{

View File

@@ -660,6 +660,14 @@ func newAPIServerMetricsServer(port int) *http.Server {
}
}
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
// newStaticAssetsHandler returns an HTTP handler to serve UI static assets
func newStaticAssetsHandler(dir string, baseHRef string) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
@@ -670,7 +678,7 @@ func newStaticAssetsHandler(dir string, baseHRef string) func(http.ResponseWrite
break
}
}
fileRequest := r.URL.Path != "/index.html" && strings.Contains(r.URL.Path, ".")
fileRequest := r.URL.Path != "/index.html" && fileExists(path.Join(dir, r.URL.Path))
// serve index.html for non file requests to support HTML5 History API
if acceptHTML && !fileRequest && (r.Method == "GET" || r.Method == "HEAD") {

View File

@@ -39,6 +39,10 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin
if err != nil {
return nil, err
}
help, err := s.mgr.GetHelp()
if err != nil {
return nil, err
}
overrides := make(map[string]*v1alpha1.ResourceOverride)
for k := range resourceOverrides {
@@ -58,6 +62,10 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin
TrackingID: gaSettings.TrackingID,
AnonymizeUsers: gaSettings.AnonymizeUsers,
},
Help: &settingspkg.Help{
ChatUrl: help.ChatURL,
ChatText: help.ChatText,
},
}
if argoCDSettings.DexConfig != "" {
var cfg settingspkg.DexConfig

View File

@@ -23,6 +23,8 @@ message Settings {
bool statusBadgeEnabled = 6;
GoogleAnalyticsConfig googleAnalytics = 7;
github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.KustomizeOptions kustomizeOptions = 8;
// Help settings
Help help = 9;
}
message GoogleAnalyticsConfig {
@@ -30,6 +32,14 @@ message GoogleAnalyticsConfig {
bool anonymizeUsers = 2;
}
// Help settings
message Help {
// the URL for getting chat help, this will typically be your Slack channel for support
string chatUrl = 1;
// the text for getting chat help, defaults to "Chat now!"
string chatText = 2;
}
message DexConfig {
repeated Connector connectors = 1;
}

View File

@@ -16,13 +16,13 @@ func TestDeletingAppStuckInSync(t *testing.T) {
Path("hook").
When().
PatchFile("hook.yaml", `[{"op": "replace", "path": "/spec/containers/0/command", "value": ["sh", "-c", "until ls /tmp/done; do sleep 0.1; done"]}]`).
PatchFile("pod.yaml", `[{"op": "add", "path": "/metadata/annotations", "value": {"argocd.argoproj.io/sync-wave": "1"}}]`).
Create().
Sync().
Then().
// stuck in running state
Expect(OperationPhaseIs(OperationRunning)).
Expect(SyncStatusIs(SyncStatusCodeSynced)).
Expect(ResourceResultNumbering(2)).
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
When().
Delete(true).
Then().

View File

@@ -284,7 +284,7 @@ func TestAppWithSecrets(t *testing.T) {
diffOutput, err := fixture.RunCli("app", "diff", app.Name)
assert.Error(t, err)
assert.Contains(t, diffOutput, "username: '*********'")
assert.Contains(t, diffOutput, "username: +++++++++")
// local diff should ignore secrets
diffOutput, err = fixture.RunCli("app", "diff", app.Name, "--local", "testdata/secrets")

View File

@@ -19,11 +19,12 @@ func TestCliAppCommand(t *testing.T) {
output, err := RunCli("app", "sync", Name(), "--timeout", "90")
assert.NoError(t, err)
vars := map[string]interface{}{"Name": Name(), "Namespace": DeploymentNamespace()}
assert.Contains(t, NormalizeOutput(output), Tmpl(`Pod {{.Namespace}} pod Synced Healthy pod/pod created`, vars))
assert.Contains(t, NormalizeOutput(output), Tmpl(`Pod {{.Namespace}} pod Synced Progressing pod/pod created`, vars))
assert.Contains(t, NormalizeOutput(output), Tmpl(`Pod {{.Namespace}} hook Succeeded Sync pod/hook created`, vars))
}).
Then().
Expect(OperationPhaseIs(OperationSucceeded)).
Expect(HealthIs(HealthStatusHealthy)).
And(func(_ *Application) {
output, err := RunCli("app", "list")
assert.NoError(t, err)

View File

@@ -43,6 +43,11 @@ func (c *Context) CustomCACertAdded() *Context {
return c
}
func (c *Context) CustomSSHKnownHostsAdded() *Context {
certs.AddCustomSSHKnownHostsKeys()
return c
}
func (c *Context) HTTPSRepoURLAdded() *Context {
repos.AddHTTPSRepo(false)
return c

View File

@@ -1,12 +1,15 @@
package certs
import (
"io/ioutil"
"path/filepath"
"github.com/argoproj/argo-cd/errors"
"github.com/argoproj/argo-cd/test/e2e/fixture"
)
// Add a custom CA certificate to the test and also create the certificate file
// on the file system, so argocd-server and argocd-repo-server can use it.
func AddCustomCACert() {
caCertPath, err := filepath.Abs("../fixture/certs/argocd-test-ca.crt")
errors.CheckError(err)
@@ -14,4 +17,23 @@ func AddCustomCACert() {
errors.FailOnErr(fixture.RunCli(args...))
args = []string{"cert", "add-tls", "127.0.0.1", "--from", caCertPath}
errors.FailOnErr(fixture.RunCli(args...))
certData, err := ioutil.ReadFile(caCertPath)
errors.CheckError(err)
err = ioutil.WriteFile(fixture.TmpDir+"/app/config/tls/localhost", certData, 0644)
errors.CheckError(err)
err = ioutil.WriteFile(fixture.TmpDir+"/app/config/tls/127.0.0.1", certData, 0644)
errors.CheckError(err)
}
func AddCustomSSHKnownHostsKeys() {
knownHostsPath, err := filepath.Abs("../fixture/certs/ssh_known_hosts")
errors.CheckError(err)
args := []string{"cert", "add-ssh", "--batch", "--from", knownHostsPath}
errors.FailOnErr(fixture.RunCli(args...))
knownHostsData, err := ioutil.ReadFile(knownHostsPath)
errors.CheckError(err)
err = ioutil.WriteFile(fixture.TmpDir+"/app/config/ssh/ssh_known_hosts", knownHostsData, 0644)
errors.CheckError(err)
}

View File

@@ -40,7 +40,7 @@ const (
ArgoCDNamespace = "argocd-e2e"
// ensure all repos are in one directory tree, so we can easily clean them up
tmpDir = "/tmp/argo-e2e"
TmpDir = "/tmp/argo-e2e"
repoDir = "testdata.git"
GuestbookPath = "guestbook"
@@ -127,7 +127,7 @@ func Name() string {
}
func repoDirectory() string {
return path.Join(tmpDir, repoDir)
return path.Join(TmpDir, repoDir)
}
func RepoURL(urlType RepoURLType) string {
@@ -336,7 +336,7 @@ func EnsureCleanState(t *testing.T) {
SetTLSCerts()
// remove tmp dir
CheckError(os.RemoveAll(tmpDir))
CheckError(os.RemoveAll(TmpDir))
// name based on test name
name = dnsFriendly(t.Name())
@@ -344,11 +344,11 @@ func EnsureCleanState(t *testing.T) {
id = name + "-" + strings.ToLower(rand.RandString(5))
// create tmp dir
FailOnErr(Run("", "mkdir", "-p", tmpDir))
FailOnErr(Run("", "mkdir", "-p", TmpDir))
// create TLS and SSH certificate directories
FailOnErr(Run("", "mkdir", "-p", tmpDir+"/app/config/tls"))
FailOnErr(Run("", "mkdir", "-p", tmpDir+"/app/config/ssh"))
FailOnErr(Run("", "mkdir", "-p", TmpDir+"/app/config/tls"))
FailOnErr(Run("", "mkdir", "-p", TmpDir+"/app/config/ssh"))
// set-up tmp repo, must have unique name
FailOnErr(Run("", "cp", "-Rf", "testdata", repoDirectory()))

View File

@@ -45,6 +45,21 @@ func testHookSuccessful(t *testing.T, hookType HookType, podHookPhase OperationP
Expect(ResourceResultIs(ResourceResult{Version: "v1", Kind: "Pod", Namespace: DeploymentNamespace(), Name: "hook", Message: "pod/hook created", HookType: hookType, HookPhase: OperationSucceeded, SyncPhase: SyncPhase(hookType)}))
}
// make sure that that hooks do not appear in "argocd app diff"
func TestHookDiff(t *testing.T) {
Given(t).
Path("hook").
When().
Create().
Then().
And(func(_ *Application) {
output, err := RunCli("app", "diff", Name())
assert.Error(t, err)
assert.Contains(t, output, "name: pod")
assert.NotContains(t, output, "name: hook")
})
}
// make sure that if pre-sync fails, we fail the app and we do not create the pod
func TestPreSyncHookFailure(t *testing.T) {
Given(t).
@@ -67,7 +82,7 @@ func TestPreSyncHookFailure(t *testing.T) {
Expect(ResourceSyncStatusIs("Pod", "pod", SyncStatusCodeOutOfSync))
}
// make sure that if pre-sync fails, we fail the app and we did create the pod
// make sure that if sync fails, we fail the app and we did create the pod
func TestSyncHookFailure(t *testing.T) {
Given(t).
Path("hook").
@@ -85,6 +100,19 @@ func TestSyncHookFailure(t *testing.T) {
Expect(ResourceSyncStatusIs("Pod", "pod", SyncStatusCodeSynced))
}
// make sure that if the deployments fails, we still get success and synced
func TestSyncHookResourceFailure(t *testing.T) {
Given(t).
Path("hook-and-deployment").
When().
Create().
Sync().
Then().
Expect(OperationPhaseIs(OperationSucceeded)).
Expect(SyncStatusIs(SyncStatusCodeSynced)).
Expect(HealthIs(HealthStatusProgressing))
}
// make sure that if post-sync fails, we fail the app and we did not create the pod
func TestPostSyncHookFailure(t *testing.T) {
Given(t).

View File

@@ -9,7 +9,7 @@ import (
. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
)
func TestCanAccessSSHRepo(t *testing.T) {
func TestCanAccessInsecureSSHRepo(t *testing.T) {
Given(t).
SSHInsecureRepoURLAdded().
RepoURLType(fixture.RepoURLTypeSSH).
@@ -20,3 +20,16 @@ func TestCanAccessSSHRepo(t *testing.T) {
Then().
Expect(OperationPhaseIs(OperationSucceeded))
}
func TestCanAccessSSHRepo(t *testing.T) {
Given(t).
CustomSSHKnownHostsAdded().
SSHRepoURLAdded().
RepoURLType(fixture.RepoURLTypeSSH).
Path("config-map").
When().
Create().
Sync().
Then().
Expect(OperationPhaseIs(OperationSucceeded))
}

View File

@@ -0,0 +1,28 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: main
image: nginx:latest
imagePullPolicy: IfNotPresent
readinessProbe:
failureThreshold: 3
httpGet:
path: /does-not-exist
port: 8080
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 5
successThreshold: 3
timeoutSeconds: 1

View File

@@ -0,0 +1,16 @@
apiVersion: batch/v1
kind: Job
metadata:
name: my-hook
annotations:
argocd.argoproj.io/hook: Sync
spec:
template:
spec:
containers:
- command:
- "true"
image: "alpine:latest"
imagePullPolicy: IfNotPresent
name: main
restartPolicy: Never

View File

@@ -0,0 +1,3 @@
[localhost]:2222 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLle3IiLWy+Cwz6/JT3K8PSGAEZAJnaxiWk0u9wkAvbZ9wHTffctg25coBa8J4Oo1l5GTIkezib2C4PjCE01BZM=
[localhost]:2222 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDhRWyu6rg0Kd0ugLxNGZ8gzUjasF4Z0oT16RUC/L9EkJWATAu4TkkoozZ5AcejlS29jUZXTkKt0La4dmIooeMDNd8b5vg1dWzSDDHwxd8Wa/4XZsUlL6zkUFrnqOPaFc/7EwM3I30064zT/Gt0BVvQUxKoT/TTea2KhQqeLmlWh4cVWJBuhZ8YODUf2VD4TSYfvpcqW/jVw2oG8Pj3WIaaG2+Bcp4Q4sJS2K+2kkiqmZ/hiPK1X/UbMRN2zWQBp5UPWFY2ctuC9B8yhLwAyMkHzuWLfB39dNEdn1jTjDsOUWbC3kDsWHsY5gtBxN30NizBWC+83NpaWbrzAlGb0JV1
[localhost]:2222 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2t7Tcavp5oUqbbSwEKRaGwEq94b8BFK16AEBbgRCTp

View File

@@ -1,15 +1,30 @@
import { Layout, NavigationManager, Notifications, NotificationsManager, PageContext, Popup, PopupManager, PopupProps } from 'argo-ui';
import {
DataLoader,
Layout,
NavigationManager,
Notifications,
NotificationsManager,
PageContext,
Popup,
PopupManager,
PopupProps,
} from 'argo-ui';
import * as cookie from 'cookie';
import { createBrowserHistory } from 'history';
import {createBrowserHistory} from 'history';
import * as jwtDecode from 'jwt-decode';
import * as PropTypes from 'prop-types';
import * as React from 'react';
import { Helmet } from 'react-helmet';
import { Redirect, Route, RouteComponentProps, Router, Switch } from 'react-router';
import {Helmet} from 'react-helmet';
import {Redirect, Route, RouteComponentProps, Router, Switch} from 'react-router';
import { services } from './shared/services';
import applications from './applications';
import help from './help';
import login from './login';
import settings from './settings';
import {Provider} from './shared/context';
import {services} from './shared/services';
import requests from './shared/services/requests';
import { hashCode } from './shared/utils';
import {hashCode} from './shared/utils';
services.viewPreferences.init();
const bases = document.getElementsByTagName('base');
@@ -17,12 +32,6 @@ const base = bases.length > 0 ? bases[0].getAttribute('href') || '/' : '/';
export const history = createBrowserHistory({ basename: base });
requests.setApiRoot(`${base}api/v1`);
import applications from './applications';
import help from './help';
import login from './login';
import settings from './settings';
import { Provider } from './shared/context';
const routes: {[path: string]: { component: React.ComponentType<RouteComponentProps<any>>, noLayout?: boolean } } = {
'/login': { component: login.component as any, noLayout: true },
'/applications': { component: applications.component },
@@ -165,6 +174,13 @@ export class App extends React.Component<{}, { popupProps: PopupProps, error: Er
<Redirect path='*' to='/'/>
</Switch>
</Router>
<DataLoader load={() => services.authService.settings()}>{(s) => (
s.help && s.help.chatUrl && <div style={{position: 'fixed', right: 10, bottom: 10}}>
<a href={s.help.chatUrl} className='argo-button argo-button--special'>
<i className='fas fa-comment-alt'/> {s.help.chatText}
</a>
</div> || null
)}</DataLoader>
</Provider>
</PageContext.Provider>
<Notifications notifications={this.notificationsManager.notifications}/>

View File

@@ -33,10 +33,13 @@ export const ApplicationResourcesDiff = (props: ApplicationResourcesDiffProps) =
return {
a: live ? jsYaml.safeDump(live, {indent: 2}) : '',
b: target ? jsYaml.safeDump(target, {indent: 2}) : '',
hook: state.hook,
// doubles as sort order
name: (state.group || '') + '/' + state.kind + '/' + state.namespace + '/' + state.name,
};
}).filter((i) => i.a !== i.b)
})
.filter((i) => !i.hook)
.filter((i) => i.a !== i.b)
.map((i) => {
const context = pref.appDetails.compactDiff ? 2 : Number.MAX_SAFE_INTEGER;
// react-diff-view, awesome as it is, does not accept unidiff format, you must add a git header section

View File

@@ -1,5 +1,6 @@
import { DropDownMenu, Tooltip } from 'argo-ui';
import * as React from 'react';
const GitUrlParse = require('git-url-parse');
import { Cluster } from '../../../shared/components';
import { Consumer } from '../../../shared/context';
@@ -10,7 +11,7 @@ import * as AppUtils from '../utils';
require('./applications-table.scss');
function shortRepo(repo: string) {
const url = new URL(repo);
const url = GitUrlParse(repo);
return <Tooltip content={repo}><span>{url.pathname.slice(1)}</span></Tooltip>;
}

View File

@@ -61,7 +61,7 @@ export interface OperationState {
finishedAt: models.Time;
}
export type HookType = 'PreSync' | 'Sync' | 'PostSync' | 'Skip';
export type HookType = 'PreSync' | 'Sync' | 'PostSync' | 'SyncFail' | 'Skip';
export interface RevisionMetadata {
author: string;
@@ -278,6 +278,7 @@ export interface ResourceDiff {
targetState: State;
liveState: State;
diff: string;
hook: boolean;
}
export interface SyncStatus {
@@ -328,6 +329,10 @@ export interface AuthSettings {
oidcConfig: {
name: string;
};
help: {
chatUrl: string;
chatText: string;
};
}
export type ConnectionStatus = 'Unknown' | 'Successful' | 'Failed';

View File

@@ -65,10 +65,10 @@ const (
)
// Regular expression that matches a valid hostname
var validHostNameRegexp = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]))*$`)
var validHostNameRegexp = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]))*(\.){0,1}$`)
// Regular expression that matches a valid FQDN
var validFQDNRegexp = regexp.MustCompile(`^([a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$`)
var validFQDNRegexp = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]))*(\.){1}$`)
// Can be used to test whether a given string represents a valid hostname
// If fqdn is true, given string must also be a FQDN representation.

View File

@@ -357,31 +357,58 @@ func Test_SSHFingerPrintSHA256FromString(t *testing.T) {
}
func Test_ServerNameWithoutPort(t *testing.T) {
hostNameList := []string{"localhost", "localhost:9443", "localhost:", "localhost:abc"}
for _, hostName := range hostNameList {
assert.Equal(t, "localhost", ServerNameWithoutPort(hostName))
hostNames := map[string]string{
"localhost": "localhost",
"localhost:9443": "localhost",
"localhost:": "localhost",
"localhost:abc": "localhost",
"localhost.:22": "localhost.",
"foo.example.com:443": "foo.example.com",
"foo.example.com.:443": "foo.example.com.",
}
for inp, res := range hostNames {
assert.Equal(t, res, ServerNameWithoutPort(inp))
}
}
func Test_ValidHostnames(t *testing.T) {
hostNameList := []string{"localhost", "localhost.localdomain", "foo.example.com", "argocd-server.svc.kubernetes.local"}
for idx, hostName := range hostNameList {
assert.Equal(t, true, IsValidHostname(hostName, false))
if idx != 0 {
assert.Equal(t, true, IsValidHostname(hostName, true))
} else {
assert.Equal(t, false, IsValidHostname(hostName, true))
}
hostNames := map[string]bool{
"localhost": true,
"localhost.localdomain": true,
"foo.example.com": true,
"argocd-server.svc.kubernetes.local": true,
"localhost.": true,
"github.com.": true,
"localhost..": false,
"localhost..localdomain": false,
".localhost": false,
"local_host": false,
"localhost.local_domain": false,
}
for hostName, valid := range hostNames {
assert.Equal(t, valid, IsValidHostname(hostName, false))
}
}
func Test_InvalidHostnames(t *testing.T) {
hostNameList := []string{"localhost.a", "localhost.", "localhost..localdomain", ".foo.example.com", "argocd_server.svc.kubernetes.local"}
for idx, hostName := range hostNameList {
if idx == 0 {
assert.Equal(t, false, IsValidHostname(hostName, true))
} else {
assert.Equal(t, false, IsValidHostname(hostName, false))
}
func Test_ValidFQDNs(t *testing.T) {
hostNames := map[string]bool{
"localhost": false,
"localhost.localdomain": false,
"foo.example.com.": true,
"argocd-server.svc.kubernetes.local": false,
"localhost.": true,
"github.com.": true,
"localhost..": false,
"localhost..localdomain": false,
"localhost..localdomain.": false,
".localhost": false,
"local_host": false,
"localhost.local_domain": false,
"localhost.local_domain.": false,
}
for hostName, valid := range hostNames {
assert.Equal(t, valid, IsValidHostname(hostName, true))
}
}

View File

@@ -2,11 +2,14 @@ package db
import (
"fmt"
"regexp"
"strings"
"golang.org/x/crypto/ssh"
"golang.org/x/net/context"
log "github.com/sirupsen/logrus"
"github.com/argoproj/argo-cd/common"
appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
certutil "github.com/argoproj/argo-cd/util/cert"
@@ -169,9 +172,24 @@ func (db *db) CreateRepoCertificate(ctx context.Context, certificates *appsv1.Re
// Each request can contain multiple certificates of different types, so we
// make sure to handle each request accordingly.
for _, certificate := range certificates.Items {
// Ensure valid repo server name was given
if !certutil.IsValidHostname(certificate.ServerName, false) {
// Ensure valid repo server name was given only for https certificates.
// For SSH known host entries, we let Go's ssh library do the validation
// later on.
if certificate.CertType == "https" && !certutil.IsValidHostname(certificate.ServerName, false) {
return nil, fmt.Errorf("Invalid hostname in request: %s", certificate.ServerName)
} else if certificate.CertType == "ssh" {
// Matches "[hostname]:port" format
reExtract := regexp.MustCompile(`^\[(.*)\]\:[0-9]+$`)
matches := reExtract.FindStringSubmatch(certificate.ServerName)
var hostnameToCheck string
if len(matches) == 0 {
hostnameToCheck = certificate.ServerName
} else {
hostnameToCheck = matches[1]
}
if !certutil.IsValidHostname(hostnameToCheck, false) {
return nil, fmt.Errorf("Invalid hostname in request: %s", hostnameToCheck)
}
}
if certificate.CertType == "ssh" {
@@ -201,14 +219,18 @@ func (db *db) CreateRepoCertificate(ctx context.Context, certificates *appsv1.Re
}
// Make sure that we received a valid public host key by parsing it
_, _, rawKeyData, _, _, err := ssh.ParseKnownHosts([]byte(fmt.Sprintf("%s %s %s", certificate.ServerName, certificate.CertSubType, certificate.CertData)))
_, hostnames, rawKeyData, _, _, err := ssh.ParseKnownHosts([]byte(fmt.Sprintf("%s %s %s", certificate.ServerName, certificate.CertSubType, certificate.CertData)))
if err != nil {
return nil, err
}
if len(hostnames) == 0 {
log.Errorf("Could not parse hostname for key from token %s", certificate.ServerName)
}
if newEntry {
sshKnownHostsList = append(sshKnownHostsList, &SSHKnownHostsEntry{
Host: certificate.ServerName,
Host: hostnames[0],
Data: string(certificate.CertData),
SubType: certificate.CertSubType,
})

View File

@@ -292,9 +292,9 @@ func Test_ListCertificate(t *testing.T) {
HostNamePattern: "*",
CertType: "ssh",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, len(certList.Items), Test_NumSSHKnownHostsExpected)
assert.Len(t, certList.Items, Test_NumSSHKnownHostsExpected)
for idx, entry := range certList.Items {
assert.Equal(t, entry.ServerName, Test_SSH_Hostname_Entries[idx])
assert.Equal(t, entry.CertSubType, Test_SSH_Subtypes[idx])
@@ -306,9 +306,9 @@ func Test_ListCertificate(t *testing.T) {
HostNamePattern: "*",
CertType: "https",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, len(certList.Items), Test_NumTLSCertificatesExpected)
assert.Len(t, certList.Items, Test_NumTLSCertificatesExpected)
// List all certificates using selector
// Expected: List of 10 entries
@@ -316,16 +316,16 @@ func Test_ListCertificate(t *testing.T) {
HostNamePattern: "*",
CertType: "*",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, len(certList.Items), Test_NumTLSCertificatesExpected+Test_NumSSHKnownHostsExpected)
assert.Len(t, certList.Items, Test_NumTLSCertificatesExpected+Test_NumSSHKnownHostsExpected)
// List all certificates using nil selector
// Expected: List of 10 entries
certList, err = db.ListRepoCertificates(context.Background(), nil)
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, len(certList.Items), Test_NumTLSCertificatesExpected+Test_NumSSHKnownHostsExpected)
assert.Len(t, certList.Items, Test_NumTLSCertificatesExpected+Test_NumSSHKnownHostsExpected)
// List all certificates matching a host name pattern
// Expected: List of 4 entries, all with servername gitlab.com
@@ -333,9 +333,9 @@ func Test_ListCertificate(t *testing.T) {
HostNamePattern: "gitlab.com",
CertType: "*",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 4, len(certList.Items))
assert.Len(t, certList.Items, 4)
for _, entry := range certList.Items {
assert.Equal(t, "gitlab.com", entry.ServerName)
}
@@ -345,9 +345,9 @@ func Test_ListCertificate(t *testing.T) {
HostNamePattern: "gitlab.com",
CertType: "https",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 1, len(certList.Items))
assert.Len(t, certList.Items, 1)
assert.Equal(t, "gitlab.com", certList.Items[0].ServerName)
assert.Equal(t, "https", certList.Items[0].CertType)
}
@@ -367,9 +367,23 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
},
},
}, false)
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 1, len(certList.Items))
assert.Len(t, certList.Items, 1)
// Valid known hosts entry
certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{
Items: []v1alpha1.RepositoryCertificate{
{
ServerName: "[foo.example.com]:2222",
CertType: "ssh",
CertData: []byte("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDioSMcGxdVkHaQzRjP71nY4mgVHXjuZiYN9NBiUxNZ0DYGjTIENI3uV45XxrS6PQfoyekUlVlHK2jwpcPrqAg6rlAdMD5WIxzvCnFjCuPA6Ljk8p0ZmYbvriDcgtj+UfGEdyUTgxH2gch6KwTY0eAbLue15IuXtoNzpLxk29iGRi5ZXNAbSBjeB3hm2PKLa6LnDqdkvc+nqoYqn1Fvx7ZJIh0apBCJpOtHPON4rnl7QQvNg9pWulZ5GKcpYMRfTpvHyFTEyrsVT5GH38l9s355GqU7GxQ/i6Tj1D0MKrIB2WmdjOnujM/ELLsrkYspMhn8ZRpCphN/LTcrOWsb0AM69drvYlhc6cnNAtC4UXp0GUy1HsBiJCsUm9/1Gz23VLDRvWop8yE8+PE3Ho5eL7ad9wmOG0mSOYEqVvAstmd8vzbD6oRuY8qV8X3tt9ph2tMAve0Qbo0NN3c51c9OfdXtJaSyckjEjaK7zjnArnYfladZZVlf2Tv8FsV0sJmfSAE="),
},
},
}, false)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Len(t, certList.Items, 1)
// Invalid hostname
// Result: Error
@@ -382,7 +396,7 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
},
},
}, false)
assert.NotNil(t, err)
assert.Error(t, err)
assert.Nil(t, certList)
// Check if it really was added
@@ -391,9 +405,9 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
HostNamePattern: "foo.example.com",
CertType: "ssh",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 1, len(certList.Items))
assert.Len(t, certList.Items, 1)
// Existing cert, same data, no upsert
// Result: no error, should return 0 added certificates
@@ -406,9 +420,9 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
},
},
}, false)
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 0, len(certList.Items))
assert.Len(t, certList.Items, 0)
// Existing cert, different data, no upsert
// Result: Error
@@ -421,7 +435,7 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
},
},
}, false)
assert.NotNil(t, err)
assert.Error(t, err)
assert.Nil(t, certList)
// Existing cert, different data, upsert
@@ -434,9 +448,9 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
},
},
}, true)
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 1, len(certList.Items))
assert.Len(t, certList.Items, 1)
// Invalid known hosts entry, case 1: key sub type missing
// Result: Error
@@ -449,7 +463,7 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
},
},
}, false)
assert.NotNil(t, err)
assert.Error(t, err)
assert.Nil(t, certList)
// Invalid known hosts entry, case 2: invalid base64 data
@@ -463,7 +477,7 @@ func Test_CreateSSHKnownHostEntries(t *testing.T) {
},
},
}, false)
assert.NotNil(t, err)
assert.Error(t, err)
assert.Nil(t, certList)
}
@@ -483,22 +497,22 @@ func Test_CreateTLSCertificates(t *testing.T) {
},
},
}, false)
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 1, len(certList.Items))
assert.Len(t, certList.Items, 1)
// Invalid hostname
// Result: Error
certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{
Items: []v1alpha1.RepositoryCertificate{
{
ServerName: "foo.example.",
ServerName: "foo..example",
CertType: "https",
CertData: []byte(Test_TLSValidSingleCert),
},
},
}, false)
assert.NotNil(t, err)
assert.Error(t, err)
assert.Nil(t, certList)
// Check if it really was added
@@ -507,9 +521,9 @@ func Test_CreateTLSCertificates(t *testing.T) {
HostNamePattern: "foo.example.com",
CertType: "https",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 1, len(certList.Items))
assert.Len(t, certList.Items, 1)
// Valid TLS certificates, multiple PEMs in data
// Expected: List of 2 entry
@@ -522,9 +536,9 @@ func Test_CreateTLSCertificates(t *testing.T) {
},
},
}, false)
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 2, len(certList.Items))
assert.Len(t, certList.Items, 2)
// Check if it really was added
// Result: Return new certificate
@@ -532,9 +546,9 @@ func Test_CreateTLSCertificates(t *testing.T) {
HostNamePattern: "bar.example.com",
CertType: "https",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 2, len(certList.Items))
assert.Len(t, certList.Items, 2)
// Valid TLS certificate, existing cert, same data, no upsert
// Expected: List of 0 entry
@@ -547,9 +561,9 @@ func Test_CreateTLSCertificates(t *testing.T) {
},
},
}, false)
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 0, len(certList.Items))
assert.Len(t, certList.Items, 0)
// Valid TLS certificate, existing cert, different data, no upsert
// Expected: Error
@@ -562,7 +576,7 @@ func Test_CreateTLSCertificates(t *testing.T) {
},
},
}, false)
assert.NotNil(t, err)
assert.Error(t, err)
assert.Nil(t, certList)
// Valid TLS certificate, existing cert, different data, upsert
@@ -576,9 +590,9 @@ func Test_CreateTLSCertificates(t *testing.T) {
},
},
}, true)
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 2, len(certList.Items))
assert.Len(t, certList.Items, 2)
// Check if upsert was successful
// Expected: List of 2 entries, matching hostnames & cert types
@@ -586,9 +600,9 @@ func Test_CreateTLSCertificates(t *testing.T) {
HostNamePattern: "foo.example.com",
CertType: "https",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 2, len(certList.Items))
assert.Len(t, certList.Items, 2)
for _, entry := range certList.Items {
assert.Equal(t, "foo.example.com", entry.ServerName)
assert.Equal(t, "https", entry.CertType)
@@ -605,7 +619,7 @@ func Test_CreateTLSCertificates(t *testing.T) {
},
},
}, false)
assert.NotNil(t, err)
assert.Error(t, err)
assert.Nil(t, certList)
// Valid PEM data, new cert, but invalid certificate
@@ -619,7 +633,7 @@ func Test_CreateTLSCertificates(t *testing.T) {
},
},
}, false)
assert.NotNil(t, err)
assert.Error(t, err)
assert.Nil(t, certList)
// Invalid PEM data, existing cert, upsert
@@ -633,7 +647,7 @@ func Test_CreateTLSCertificates(t *testing.T) {
},
},
}, true)
assert.NotNil(t, err)
assert.Error(t, err)
assert.Nil(t, certList)
// Valid PEM data, existing cert, but invalid certificate, upsert
@@ -647,7 +661,7 @@ func Test_CreateTLSCertificates(t *testing.T) {
},
},
}, true)
assert.NotNil(t, err)
assert.Error(t, err)
assert.Nil(t, certList)
}
@@ -663,9 +677,9 @@ func Test_RemoveSSHKnownHosts(t *testing.T) {
HostNamePattern: "github.com",
CertType: "ssh",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 1, len(certList.Items))
assert.Len(t, certList.Items, 1)
// Check whether entry was really removed
// Expected: List of 0 entries
@@ -673,9 +687,9 @@ func Test_RemoveSSHKnownHosts(t *testing.T) {
HostNamePattern: "github.com",
CertType: "ssh",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 0, len(certList.Items))
assert.Len(t, certList.Items, 0)
// Remove single SSH known hosts entry by sub type
// Expected: List of 1 entry
@@ -683,9 +697,9 @@ func Test_RemoveSSHKnownHosts(t *testing.T) {
CertType: "ssh",
CertSubType: "ssh-ed25519",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 1, len(certList.Items))
assert.Len(t, certList.Items, 1)
// Check whether entry was really removed
// Expected: List of 0 entries
@@ -693,27 +707,27 @@ func Test_RemoveSSHKnownHosts(t *testing.T) {
CertType: "ssh",
CertSubType: "ssh-ed25519",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 0, len(certList.Items))
assert.Len(t, certList.Items, 0)
// Remove all remaining SSH known hosts entries
// Expected: List of 5 entry
certList, err = db.RemoveRepoCertificates(context.Background(), &CertificateListSelector{
CertType: "ssh",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 5, len(certList.Items))
assert.Len(t, certList.Items, 5)
// Check whether the entries were really removed
// Expected: List of 0 entries
certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{
CertType: "ssh",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 0, len(certList.Items))
assert.Len(t, certList.Items, 0)
}
func Test_RemoveTLSCertificates(t *testing.T) {
@@ -727,9 +741,9 @@ func Test_RemoveTLSCertificates(t *testing.T) {
HostNamePattern: "gitlab.com",
CertType: "https",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 1, len(certList.Items))
assert.Len(t, certList.Items, 1)
// Check whether entry was really removed
// Expected: List of 0 entries
@@ -737,9 +751,9 @@ func Test_RemoveTLSCertificates(t *testing.T) {
HostNamePattern: "gitlab.com",
CertType: "https",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 0, len(certList.Items))
assert.Len(t, certList.Items, 0)
// Remove all TLS certificate entry for hostname
// Expected: List of 2 entry
@@ -747,9 +761,9 @@ func Test_RemoveTLSCertificates(t *testing.T) {
HostNamePattern: "test.example.com",
CertType: "https",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 2, len(certList.Items))
assert.Len(t, certList.Items, 2)
// Check whether entries were really removed
// Expected: List of 0 entries
@@ -757,8 +771,8 @@ func Test_RemoveTLSCertificates(t *testing.T) {
HostNamePattern: "test.example.com",
CertType: "https",
})
assert.Nil(t, err)
assert.NoError(t, err)
assert.NotNil(t, certList)
assert.Equal(t, 0, len(certList.Items))
assert.Len(t, certList.Items, 0)
}

View File

@@ -387,7 +387,8 @@ func HideSecretData(target *unstructured.Unstructured, live *unstructured.Unstru
}
for k := range keys {
nextReplacement := "*********"
// we use "+" rather than the more common "*"
nextReplacement := "+++++++++"
valToReplacement := make(map[string]string)
for _, obj := range []*unstructured.Unstructured{target, live, orig} {
var data map[string]interface{}
@@ -409,7 +410,7 @@ func HideSecretData(target *unstructured.Unstructured, live *unstructured.Unstru
replacement, ok := valToReplacement[val]
if !ok {
replacement = nextReplacement
nextReplacement = nextReplacement + "*"
nextReplacement = nextReplacement + "+"
valToReplacement[val] = replacement
}
data[k] = replacement

View File

@@ -534,9 +534,9 @@ func secretData(obj *unstructured.Unstructured) map[string]interface{} {
}
const (
replacement1 = "*********"
replacement2 = "**********"
replacement3 = "***********"
replacement1 = "+++++++++"
replacement2 = "++++++++++"
replacement3 = "+++++++++++"
)
func TestHideSecretDataSameKeysDifferentValues(t *testing.T) {

View File

@@ -14,6 +14,7 @@ import (
argoexec "github.com/argoproj/pkg/exec"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/knownhosts"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/config"
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -195,6 +196,13 @@ func newAuth(repoURL string, creds Creds) (transport.AuthMethod, error) {
auth := &ssh2.PublicKeys{User: sshUser, Signer: signer}
if creds.insecure {
auth.HostKeyCallback = ssh.InsecureIgnoreHostKey()
} else {
// Set up validation of SSH known hosts for using our ssh_known_hosts
// file.
auth.HostKeyCallback, err = knownhosts.New(certutil.GetSSHKnownHostsDataPath())
if err != nil {
log.Errorf("Could not set-up SSH known hosts callback: %v", err)
}
}
return auth, nil
case HTTPSCreds:

View File

@@ -10,6 +10,7 @@ import (
log "github.com/sirupsen/logrus"
"github.com/argoproj/argo-cd/util"
certutil "github.com/argoproj/argo-cd/util/cert"
)
type Creds interface {
@@ -171,6 +172,9 @@ func (c SSHCreds) Environ() (io.Closer, []string, error) {
// StrictHostKeyChecking will add the host to the knownhosts file, we don't want that - a security issue really,
// UserKnownHostsFile=/dev/null is therefore used so we write the new insecure host to /dev/null
args = append(args, "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null")
} else {
knownHostsFile := certutil.GetSSHKnownHostsDataPath()
args = append(args, "-o", "StrictHostKeyChecking=yes", "-o", fmt.Sprintf("UserKnownHostsFile=%s", knownHostsFile))
}
env = append(env, []string{fmt.Sprintf("GIT_SSH_COMMAND=%s", strings.Join(args, " "))}...)
return sshPrivateKeyFile(file.Name()), env, nil

View File

@@ -209,7 +209,9 @@ func TestLsRemote(t *testing.T) {
// Running this test requires git-lfs to be installed on your machine.
func TestLFSClient(t *testing.T) {
test.CIOnly(t)
// temporary disable LFS test
// TODO(alexmt): dockerize tests in and enabled it
t.Skip()
tempDir, err := ioutil.TempDir("", "git-client-lfs-test-")
assert.NoError(t, err)

View File

@@ -18,8 +18,9 @@ func MakeCookieMetadata(key, value string, flags ...string) (string, error) {
header := strings.Join(components, "; ")
const maxLength = 4093
if len(header) > maxLength {
return "", fmt.Errorf("invalid cookie, longer than max length %v", maxLength)
headerLength := len(header)
if headerLength > maxLength {
return "", fmt.Errorf("invalid cookie, at %d long it is longer than the max length of %d", headerLength, maxLength)
}
return header, nil
}

View File

@@ -14,6 +14,6 @@ func TestCookieMaxLength(t *testing.T) {
assert.Equal(t, "foo=bar", cookie)
cookie, err = MakeCookieMetadata("foo", strings.Repeat("_", 4093-3))
assert.Error(t, err)
assert.EqualError(t, err, "invalid cookie, at 4094 long it is longer than the max length of 4093")
assert.Equal(t, "", cookie)
}

View File

@@ -234,19 +234,20 @@ func (a *ClientApp) HandleCallback(w http.ResponseWriter, r *http.Request) {
if a.secureCookie {
flags = append(flags, "Secure")
}
cookie, err := httputil.MakeCookieMetadata(common.AuthCookieName, idTokenRAW, flags...)
if err != nil {
http.Error(w, fmt.Sprintf("%v", err), http.StatusInternalServerError)
return
}
w.Header().Set("Set-Cookie", cookie)
var claims jwt.MapClaims
err = idToken.Claims(&claims)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
cookie, err := httputil.MakeCookieMetadata(common.AuthCookieName, idTokenRAW, flags...)
if err != nil {
claimsJSON, _ := json.Marshal(claims)
http.Error(w, fmt.Sprintf("claims=%s, err=%v", claimsJSON, err), http.StatusInternalServerError)
return
}
w.Header().Set("Set-Cookie", cookie)
claimsJSON, _ := json.Marshal(claims)
log.Infof("Web login successful. Claims: %s", claimsJSON)
if os.Getenv(common.EnvVarSSODebug) == "1" {

View File

@@ -7,7 +7,6 @@ import (
"crypto/x509"
"encoding/base64"
"fmt"
"io/ioutil"
"os"
"strings"
"sync"
@@ -28,7 +27,6 @@ import (
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/util"
certutil "github.com/argoproj/argo-cd/util/cert"
"github.com/argoproj/argo-cd/util/password"
tlsutil "github.com/argoproj/argo-cd/util/tls"
)
@@ -75,6 +73,14 @@ type GoogleAnalytics struct {
AnonymizeUsers bool `json:"anonymizeUsers,omitempty"`
}
// Help settings
type Help struct {
// the URL for getting chat help, this will typically be your Slack channel for support
ChatURL string `json:"chatUrl,omitempty"`
// the text for getting chat help, defaults to "Chat now!"
ChatText string `json:"chatText,omitempty"`
}
type OIDCConfig struct {
Name string `json:"name,omitempty"`
Issuer string `json:"issuer,omitempty"`
@@ -125,6 +131,10 @@ const (
settingServerSignatureKey = "server.secretkey"
// gaTrackingID holds Google Analytics tracking id
gaTrackingID = "ga.trackingid"
// the URL for getting chat help, this will typically be your Slack channel for support
helpChatURL = "help.chatUrl"
// the text for getting chat help, defaults to "Chat now!"
helpChatText = "help.chatText"
// gaAnonymizeUsers specifies if user ids should be anonymized (hashed) before sending to Google Analytics. True unless value is set to 'false'
gaAnonymizeUsers = "ga.anonymizeusers"
// settingServerCertificate designates the key for the public cert used in TLS
@@ -307,12 +317,7 @@ func (mgr *SettingsManager) GetKustomizeBuildOptions() (string, error) {
if err != nil {
return "", err
}
value, ok := argoCDCM.Data[kustomizeBuildOptions]
if !ok {
return "", err
}
return value, nil
return argoCDCM.Data[kustomizeBuildOptions], nil
}
func (mgr *SettingsManager) GetHelmRepositories() ([]HelmRepoCredentials, error) {
@@ -393,6 +398,21 @@ func (mgr *SettingsManager) GetGoogleAnalytics() (*GoogleAnalytics, error) {
}, nil
}
func (mgr *SettingsManager) GetHelp() (*Help, error) {
argoCDCM, err := mgr.getConfigMap()
if err != nil {
return nil, err
}
chatText, ok := argoCDCM.Data[helpChatText]
if !ok {
chatText = "Chat now!"
}
return &Help{
ChatURL: argoCDCM.Data[helpChatURL],
ChatText: chatText,
}, nil
}
// GetSettings retrieves settings from the ArgoCDConfigMap and secret.
func (mgr *SettingsManager) GetSettings() (*ArgoCDSettings, error) {
err := mgr.ensureSynced(false)
@@ -689,18 +709,6 @@ func (mgr *SettingsManager) SaveSSHKnownHostsData(ctx context.Context, knownHost
return err
}
// If we are running outside a K8S cluster, the ConfigMap mount will not
// automatically write out the SSH known hosts data. We need this mechanism
// for running E2E tests.
if os.Getenv(common.EnvVarFakeInClusterConfig) == "true" {
knownHostsPath := certutil.GetSSHKnownHostsDataPath()
err := ioutil.WriteFile(knownHostsPath, []byte(sshKnownHostsData), 0644)
// We don't return error, but let the user know through log
if err != nil {
log.Errorf("Could not write SSH known hosts data: %v", err)
}
}
return mgr.ResyncInformers()
}
@@ -721,42 +729,6 @@ func (mgr *SettingsManager) SaveTLSCertificateData(ctx context.Context, tlsCerti
return err
}
// If we are running outside a K8S cluster, the ConfigMap mount will not
// automatically write out the TLS certificate data. We need this mechanism
// for running E2E tests.
//
// The paradigm here is, that we first remove all files in the TLS data
// directory (there should be only TLS certs in it), and then recreate each
// single cert that is still in the tlsCertificates data map.
if os.Getenv(common.EnvVarFakeInClusterConfig) == "true" {
tlsDataPath := certutil.GetTLSCertificateDataPath()
// First throw way everything
tlsFiles, err := ioutil.ReadDir(tlsDataPath)
if err != nil {
log.Errorf("Could not open TLS certificate dir %s: %v", tlsDataPath, err)
} else {
for _, file := range tlsFiles {
tlsCertPath := fmt.Sprintf("%s/%s", tlsDataPath, file.Name())
log.Debugf("Deleting TLS certificate file %s", tlsCertPath)
err := os.Remove(tlsCertPath)
if err != nil {
log.Errorf("Could not delete TLS cert file %s: %v", tlsCertPath, err)
}
}
}
// Recreate configured TLS certificates
for hostName, certData := range tlsCertificates {
certPath := fmt.Sprintf("%s/%s", tlsDataPath, hostName)
log.Debugf("Writing TLS Certificate data to %s", certPath)
err := ioutil.WriteFile(certPath, []byte(certData), 0644)
if err != nil {
log.Errorf("Could not write PEM data to %s: %v", certPath, err)
}
}
}
return mgr.ResyncInformers()
}

View File

@@ -13,7 +13,7 @@ import (
"k8s.io/client-go/kubernetes/fake"
)
func TestGetRepositories(t *testing.T) {
func fixtures(data map[string]string) (*fake.Clientset, *SettingsManager) {
kubeClient := fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: common.ArgoCDConfigMapName,
@@ -22,27 +22,24 @@ func TestGetRepositories(t *testing.T) {
"app.kubernetes.io/part-of": "argocd",
},
},
Data: map[string]string{
"repositories": "\n - url: http://foo\n",
},
Data: data,
})
settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
return kubeClient, settingsManager
}
func TestGetRepositories(t *testing.T) {
_, settingsManager := fixtures(map[string]string{
"repositories": "\n - url: http://foo\n",
})
filter, err := settingsManager.GetRepositories()
assert.NoError(t, err)
assert.Equal(t, []RepoCredentials{{URL: "http://foo"}}, filter)
}
func TestSaveRepositories(t *testing.T) {
kubeClient := fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: common.ArgoCDConfigMapName,
Namespace: "default",
Labels: map[string]string{
"app.kubernetes.io/part-of": "argocd",
},
},
})
settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
kubeClient, settingsManager := fixtures(nil)
err := settingsManager.SaveRepositories([]RepoCredentials{{URL: "http://foo"}})
assert.NoError(t, err)
cm, err := kubeClient.CoreV1().ConfigMaps("default").Get(common.ArgoCDConfigMapName, metav1.GetOptions{})
@@ -51,39 +48,20 @@ func TestSaveRepositories(t *testing.T) {
}
func TestGetRepositoryCredentials(t *testing.T) {
kubeClient := fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: common.ArgoCDConfigMapName,
Namespace: "default",
Labels: map[string]string{
"app.kubernetes.io/part-of": "argocd",
},
},
Data: map[string]string{
"repository.credentials": "\n - url: http://foo\n",
},
_, settingsManager := fixtures(map[string]string{
"repository.credentials": "\n - url: http://foo\n",
})
settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
filter, err := settingsManager.GetRepositoryCredentials()
assert.NoError(t, err)
assert.Equal(t, []RepoCredentials{{URL: "http://foo"}}, filter)
}
func TestGetResourceFilter(t *testing.T) {
kubeClient := fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: common.ArgoCDConfigMapName,
Namespace: "default",
Labels: map[string]string{
"app.kubernetes.io/part-of": "argocd",
},
},
Data: map[string]string{
"resource.exclusions": "\n - apiGroups: [\"group1\"]\n kinds: [\"kind1\"]\n clusters: [\"cluster1\"]\n",
"resource.inclusions": "\n - apiGroups: [\"group2\"]\n kinds: [\"kind2\"]\n clusters: [\"cluster2\"]\n",
},
})
settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
data := map[string]string{
"resource.exclusions": "\n - apiGroups: [\"group1\"]\n kinds: [\"kind1\"]\n clusters: [\"cluster1\"]\n",
"resource.inclusions": "\n - apiGroups: [\"group2\"]\n kinds: [\"kind2\"]\n clusters: [\"cluster2\"]\n",
}
_, settingsManager := fixtures(data)
filter, err := settingsManager.GetResourcesFilter()
assert.NoError(t, err)
assert.Equal(t, &ResourcesFilter{
@@ -91,26 +69,16 @@ func TestGetResourceFilter(t *testing.T) {
ResourceInclusions: []FilteredResource{{APIGroups: []string{"group2"}, Kinds: []string{"kind2"}, Clusters: []string{"cluster2"}}},
}, filter)
}
func TestGetConfigManagementPlugins(t *testing.T) {
kubeClient := fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: common.ArgoCDConfigMapName,
Namespace: "default",
Labels: map[string]string{
"app.kubernetes.io/part-of": "argocd",
},
},
Data: map[string]string{
"configManagementPlugins": `
data := map[string]string{
"configManagementPlugins": `
- name: kasane
init:
command: [kasane, update]
generate:
command: [kasane, show]`,
},
})
settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
}
_, settingsManager := fixtures(data)
plugins, err := settingsManager.GetConfigManagementPlugins()
assert.NoError(t, err)
assert.ElementsMatch(t, []v1alpha1.ConfigManagementPlugin{{
@@ -121,42 +89,22 @@ func TestGetConfigManagementPlugins(t *testing.T) {
}
func TestGetAppInstanceLabelKey(t *testing.T) {
kubeClient := fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: common.ArgoCDConfigMapName,
Namespace: "default",
Labels: map[string]string{
"app.kubernetes.io/part-of": "argocd",
},
},
Data: map[string]string{
"application.instanceLabelKey": "testLabel",
},
_, settingsManager := fixtures(map[string]string{
"application.instanceLabelKey": "testLabel",
})
settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
label, err := settingsManager.GetAppInstanceLabelKey()
assert.NoError(t, err)
assert.Equal(t, "testLabel", label)
}
func TestGetResourceOverrides(t *testing.T) {
kubeClient := fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: common.ArgoCDConfigMapName,
Namespace: "default",
Labels: map[string]string{
"app.kubernetes.io/part-of": "argocd",
},
},
Data: map[string]string{
"resource.customizations": `
_, settingsManager := fixtures(map[string]string{
"resource.customizations": `
admissionregistration.k8s.io/MutatingWebhookConfiguration:
ignoreDifferences: |
jsonPointers:
- /webhooks/0/clientConfig/caBundle`,
},
})
settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
overrides, err := settingsManager.GetResourceOverrides()
assert.NoError(t, err)
@@ -168,20 +116,29 @@ func TestGetResourceOverrides(t *testing.T) {
}, webHookOverrides)
}
func TestGetHelmRepositories(t *testing.T) {
kubeClient := fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: common.ArgoCDConfigMapName,
Namespace: "default",
Labels: map[string]string{
"app.kubernetes.io/part-of": "argocd",
},
},
Data: map[string]string{
"helm.repositories": "\n - url: http://foo\n",
},
func TestSettingsManager_GetKustomizeBuildOptions(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
_, settingsManager := fixtures(map[string]string{})
options, err := settingsManager.GetKustomizeBuildOptions()
assert.NoError(t, err)
assert.Empty(t, options)
})
t.Run("Set", func(t *testing.T) {
_, settingsManager := fixtures(map[string]string{"kustomize.buildOptions": "foo"})
options, err := settingsManager.GetKustomizeBuildOptions()
assert.NoError(t, err)
assert.Equal(t, "foo", options)
})
}
func TestGetHelmRepositories(t *testing.T) {
_, settingsManager := fixtures(map[string]string{
"helm.repositories": "\n - url: http://foo\n",
})
settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
helmRepositories, err := settingsManager.GetHelmRepositories()
assert.NoError(t, err)
@@ -189,21 +146,32 @@ func TestGetHelmRepositories(t *testing.T) {
}
func TestGetGoogleAnalytics(t *testing.T) {
kubeClient := fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: common.ArgoCDConfigMapName,
Namespace: "default",
Labels: map[string]string{
"app.kubernetes.io/part-of": "argocd",
},
},
Data: map[string]string{
"ga.trackingid": "123",
},
_, settingsManager := fixtures(map[string]string{
"ga.trackingid": "123",
})
settingsManager := NewSettingsManager(context.Background(), kubeClient, "default")
ga, err := settingsManager.GetGoogleAnalytics()
assert.NoError(t, err)
assert.Equal(t, "123", ga.TrackingID)
assert.Equal(t, true, ga.AnonymizeUsers)
}
func TestSettingsManager_GetHelp(t *testing.T) {
t.Run("Default", func(t *testing.T) {
_, settingsManager := fixtures(nil)
h, err := settingsManager.GetHelp()
assert.NoError(t, err)
assert.Empty(t, h.ChatURL)
assert.Equal(t, "Chat now!", h.ChatText)
})
t.Run("Set", func(t *testing.T) {
_, settingsManager := fixtures(map[string]string{
"help.chatUrl": "foo",
"help.chatText": "bar",
})
h, err := settingsManager.GetHelp()
assert.NoError(t, err)
assert.Equal(t, "foo", h.ChatURL)
assert.Equal(t, "bar", h.ChatText)
})
}