diff --git a/Gopkg.lock b/Gopkg.lock index 4735537222857..2ace1688d5f09 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -232,6 +232,12 @@ revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" version = "v2.0.1" +[[projects]] + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + [[projects]] name = "github.com/sirupsen/logrus" packages = ["."] @@ -256,6 +262,23 @@ revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66" version = "v1.0.0" +[[projects]] + name = "github.com/stretchr/objx" + packages = ["."] + revision = "facf9a85c22f48d2f52f2380e4efce1768749a89" + version = "v0.1" + +[[projects]] + name = "github.com/stretchr/testify" + packages = [ + ".", + "assert", + "http", + "mock" + ] + revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" + version = "v1.2.1" + [[projects]] branch = "master" name = "golang.org/x/crypto" @@ -583,6 +606,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "477de633045a1e9822c4e605e845790162eb15d9a0d414156b790b2b359ab48b" + inputs-digest = "1c5da7222d742c9013f8f72546a3f7c477a3628ad668ac46e5d1fd46fa22b5f4" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 4955754e0a2b7..238dbd8376e28 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -30,3 +30,7 @@ required = [ [[constraint]] branch = "release-6.0" name = "k8s.io/client-go" + +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.2.1" diff --git a/application/comparator.go b/application/comparator.go new file mode 100644 index 0000000000000..76144603e6f18 --- /dev/null +++ b/application/comparator.go @@ -0,0 +1,32 @@ +package application + +import ( + "time" + + "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// AppComparator defines methods which allow to compare application spec and actual application state. +type AppComparator interface { + CompareAppState(appRepoPath string, app *v1alpha1.Application) (*v1alpha1.ComparisonResult, error) +} + +// KsonnetAppComparator allows to compare application using KSonnet CLI +type KsonnetAppComparator struct { +} + +// CompareAppState compares application spec and real app state using KSonnet +func (ks *KsonnetAppComparator) CompareAppState(appRepoPath string, app *v1alpha1.Application) (*v1alpha1.ComparisonResult, error) { + // TODO (amatyushentsev): Implement actual comparison + return &v1alpha1.ComparisonResult{ + Status: v1alpha1.ComparisonStatusEqual, + ComparedTo: app.Spec.Source, + ComparedAt: metav1.Time{Time: time.Now().UTC()}, + }, nil +} + +// NewKsonnetAppComparator creates new instance of Ksonnet app comparator +func NewKsonnetAppComparator() AppComparator { + return &KsonnetAppComparator{} +} diff --git a/application/manager.go b/application/manager.go index e55cc117f1232..219662a72dded 100644 --- a/application/manager.go +++ b/application/manager.go @@ -21,6 +21,7 @@ type Manager struct { gitClient git.Client repoService repository.RepositoryServiceServer statusRefreshTimeout time.Duration + appComparator AppComparator } // NeedRefreshAppStatus answers if application status needs to be refreshed. Returns true if application never been compared, has changed or comparison result has expired. @@ -66,7 +67,7 @@ func (m *Manager) tryRefreshAppStatus(app *v1alpha1.Application) (*v1alpha1.Appl if err != nil { return nil, err } - comparisonResult, err := m.compareAppState(appRepoPath, app) + comparisonResult, err := m.appComparator.CompareAppState(appRepoPath, app) if err != nil { return nil, err } @@ -75,20 +76,16 @@ func (m *Manager) tryRefreshAppStatus(app *v1alpha1.Application) (*v1alpha1.Appl }, nil } -func (m *Manager) compareAppState(appRepoPath string, app *v1alpha1.Application) (*v1alpha1.ComparisonResult, error) { - // TODO (amatyushentsev): Implement actual comparison - return &v1alpha1.ComparisonResult{ - Status: v1alpha1.ComparisonStatusEqual, - ComparedTo: app.Spec.Source, - ComparedAt: metav1.Time{Time: time.Now().UTC()}, - }, nil -} - -// NewAppManager creates new instance of app.Manager -func NewAppManager(gitClient git.Client, repoService repository.RepositoryServiceServer, statusRefreshTimeout time.Duration) *Manager { +// NewAppManager creates new instance of app manager. +func NewAppManager( + gitClient git.Client, + repoService repository.RepositoryServiceServer, + appComparator AppComparator, + statusRefreshTimeout time.Duration) *Manager { return &Manager{ gitClient: gitClient, repoService: repoService, statusRefreshTimeout: statusRefreshTimeout, + appComparator: appComparator, } } diff --git a/application/manager_test.go b/application/manager_test.go new file mode 100644 index 0000000000000..e8f36a7ded8d3 --- /dev/null +++ b/application/manager_test.go @@ -0,0 +1,73 @@ +package application_test + +import ( + "testing" + + "time" + + "github.com/argoproj/argo-cd/application" + "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestManager(t *testing.T) { + + refreshTimeout := time.Second * 10 + appSource := v1alpha1.ApplicationSource{ + Environment: "prod/us-west-2", + Path: "apps/elk", + TargetRevision: "master", + RepoURL: "http://my-git-repo.git", + } + + t.Run("NeedRefreshAppStatus", func(t *testing.T) { + + manager := application.NewAppManager(nil, nil, nil, refreshTimeout) + t.Run("TestReturnsTrueIfAppWasNotCompared", func(t *testing.T) { + needRefresh := manager.NeedRefreshAppStatus(&v1alpha1.Application{ + Spec: v1alpha1.ApplicationSpec{Source: appSource}, + Status: v1alpha1.ApplicationStatus{ + ComparisonResult: v1alpha1.ComparisonResult{Status: v1alpha1.ComparisonStatusUnknown}, + }, + }) + assert.True(t, needRefresh) + }) + + t.Run("TestReturnsFalseIfAppWasComparedBeforeRefreshTimeoutExpires", func(t *testing.T) { + needRefresh := manager.NeedRefreshAppStatus(&v1alpha1.Application{ + Spec: v1alpha1.ApplicationSpec{Source: appSource}, + Status: v1alpha1.ApplicationStatus{ + ComparisonResult: v1alpha1.ComparisonResult{Status: v1alpha1.ComparisonStatusEqual, ComparedAt: metav1.Time{Time: time.Now()}, ComparedTo: appSource}, + }, + }) + assert.False(t, needRefresh) + }) + + t.Run("TestReturnsTrueIfAppWasComparedAfterRefreshTimeoutExpires", func(t *testing.T) { + needRefresh := manager.NeedRefreshAppStatus(&v1alpha1.Application{ + Spec: v1alpha1.ApplicationSpec{Source: appSource}, + Status: v1alpha1.ApplicationStatus{ + ComparisonResult: v1alpha1.ComparisonResult{ + Status: v1alpha1.ComparisonStatusEqual, + ComparedAt: metav1.Time{Time: time.Now().Add(-(refreshTimeout + time.Second))}, + ComparedTo: appSource, + }, + }, + }) + assert.True(t, needRefresh) + }) + + t.Run("TestReturnsTrueApplicationSourceHasChanged", func(t *testing.T) { + updatedSource := *appSource.DeepCopy() + updatedSource.TargetRevision = "abc" + needRefresh := manager.NeedRefreshAppStatus(&v1alpha1.Application{ + Spec: v1alpha1.ApplicationSpec{Source: appSource}, + Status: v1alpha1.ApplicationStatus{ + ComparisonResult: v1alpha1.ComparisonResult{Status: v1alpha1.ComparisonStatusEqual, ComparedAt: metav1.Time{Time: time.Now()}, ComparedTo: updatedSource}, + }, + }) + assert.True(t, needRefresh) + }) + }) +} diff --git a/cmd/argocd-application-controller/main.go b/cmd/argocd-application-controller/main.go index 2fd6bf7b043c5..f351c5f1a7fa5 100644 --- a/cmd/argocd-application-controller/main.go +++ b/cmd/argocd-application-controller/main.go @@ -44,7 +44,11 @@ func newCommand() *cobra.Command { namespace := "default" appResyncPeriod := time.Minute * 10 - appManager := application.NewAppManager(nativeGitClient, repository.NewServer(namespace, kubeClient, appClient), appResyncPeriod) + appManager := application.NewAppManager( + nativeGitClient, + repository.NewServer(namespace, kubeClient, appClient), + application.NewKsonnetAppComparator(), + appResyncPeriod) appController := controller.NewApplicationController(kubeClient, appClient, appManager, appResyncPeriod)