@@ -36,10 +36,14 @@ import (
3636 . "github.com/onsi/gomega"
3737 "github.com/otiai10/copy"
3838 corev1 "k8s.io/api/core/v1"
39+ // apimeta "k8s.io/apimachinery/pkg/api/meta"
3940 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4041 "k8s.io/apimachinery/pkg/types"
42+ ctrl "sigs.k8s.io/controller-runtime"
43+ "sigs.k8s.io/controller-runtime/pkg/client"
4144
4245 imagev1_reflect "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
46+ "github.com/fluxcd/pkg/apis/meta"
4347 "github.com/fluxcd/pkg/gittestserver"
4448 sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
4549
@@ -185,29 +189,9 @@ var _ = Describe("ImageUpdateAutomation", func() {
185189 BeforeEach (func () {
186190 // Insert a setter reference into the deployment file,
187191 // before creating the automation object itself.
188- tmp , err := ioutil .TempDir ("" , "gotest-imageauto-setters" )
189- Expect (err ).ToNot (HaveOccurred ())
190- defer os .RemoveAll (tmp )
191- repo , err := git .PlainClone (tmp , false , & git.CloneOptions {
192- URL : repoURL ,
193- ReferenceName : plumbing .NewBranchReferenceName (defaultBranch ),
192+ commitInRepo (repoURL , "Install setter marker" , func (tmp string ) {
193+ replaceMarker (tmp , policyKey )
194194 })
195- Expect (err ).ToNot (HaveOccurred ())
196-
197- replaceMarker (tmp , policyKey )
198- worktree , err := repo .Worktree ()
199- Expect (err ).ToNot (HaveOccurred ())
200- _ , err = worktree .Add ("deploy.yaml" )
201- Expect (err ).ToNot (HaveOccurred ())
202- _ , err = worktree .Commit ("Install setter marker" , & git.CommitOptions {
203- Author : & object.Signature {
204- Name : "Testbot" ,
205- 206- When : time .Now (),
207- },
208- })
209- Expect (err ).ToNot (HaveOccurred ())
210- Expect (repo .Push (& git.PushOptions {RemoteName : "origin" })).To (Succeed ())
211195
212196 // pull the head commit we just pushed, so it's not
213197 // considered a new commit when checking for a commit
@@ -226,6 +210,7 @@ var _ = Describe("ImageUpdateAutomation", func() {
226210 Namespace : updateKey .Namespace ,
227211 },
228212 Spec : imagev1.ImageUpdateAutomationSpec {
213+ RunInterval : & metav1.Duration {Duration : 2 * time .Hour }, // this is to ensure any subsequent run should be outside the scope of the testing
229214 Checkout : imagev1.GitCheckoutSpec {
230215 GitRepositoryRef : corev1.LocalObjectReference {
231216 Name : gitRepoKey .Name ,
@@ -256,22 +241,87 @@ var _ = Describe("ImageUpdateAutomation", func() {
256241 Expect (err ).ToNot (HaveOccurred ())
257242 Expect (commit .Message ).To (Equal (commitMessage ))
258243
259- tmp , err := ioutil .TempDir ("" , "gotest-imageauto" )
260- Expect (err ).ToNot (HaveOccurred ())
261- defer os .RemoveAll (tmp )
244+ compareRepoWithExpected (repoURL , "testdata/appconfig-setters-expected" , func (tmp string ) {
245+ replaceMarker (tmp , policyKey )
246+ })
247+ })
262248
263- expected , err := ioutil .TempDir ("" , "gotest-imageauto-expected" )
264- Expect (err ).ToNot (HaveOccurred ())
265- defer os .RemoveAll (expected )
266- copy .Copy ("testdata/appconfig-setters-expected" , expected )
267- replaceMarker (expected , policyKey )
249+ It ("stops updating when suspended" , func () {
250+ // suspend it, and check that it is marked as unready.
251+ var updatePatch imagev1.ImageUpdateAutomation
252+ updatePatch .Name = updateKey .Name
253+ updatePatch .Namespace = updateKey .Namespace
254+ updatePatch .Spec .Suspend = true
255+ Expect (k8sClient .Patch (context .Background (), & updatePatch , client .Merge )).To (Succeed ())
256+ // wait for the suspension to reach the cache
257+ var newUpdate imagev1.ImageUpdateAutomation
258+ Eventually (func () bool {
259+ if err := imageAutoReconciler .Get (context .Background (), updateKey , & newUpdate ); err != nil {
260+ return false
261+ }
262+ return newUpdate .Spec .Suspend
263+ }, timeout , time .Second ).Should (BeTrue ())
264+ // run the reconciliation explicitly, and make sure it
265+ // doesn't do anything
266+ result , err := imageAutoReconciler .Reconcile (ctrl.Request {
267+ NamespacedName : updateKey ,
268+ })
269+ Expect (err ).To (BeNil ())
270+ Expect (result ).To (Equal (ctrl.Result {})) // this ought to fail, since it should be rescheduled; but if not, additional checks lie below
271+
272+ var checkUpdate imagev1.ImageUpdateAutomation
273+ Expect (k8sClient .Get (context .Background (), updateKey , & checkUpdate )).To (Succeed ())
274+ Expect (checkUpdate .Status .ObservedGeneration ).NotTo (Equal (checkUpdate .ObjectMeta .Generation ))
275+ })
268276
269- _ , err = git .PlainClone (tmp , false , & git.CloneOptions {
270- URL : repoURL ,
271- ReferenceName : plumbing .NewBranchReferenceName (defaultBranch ),
277+ It ("runs when the reconcile request annotation is added" , func () {
278+ println ("[DEBUG]" , updateKey .String ())
279+ // the automation has run, and is not expected to run
280+ // again for 2 hours. Make a commit to the git repo
281+ // which needs to be undone by automation, then add
282+ // the annotation and make sure it runs again.
283+ Expect (k8sClient .Get (context .Background (), updateKey , updateBySetters )).To (Succeed ())
284+ Expect (updateBySetters .Status .LastAutomationRunTime ).ToNot (BeNil ())
285+ lastRunTime := updateBySetters .Status .LastAutomationRunTime .Time
286+
287+ commitInRepo (repoURL , "Revert image update" , func (tmp string ) {
288+ // revert the change made by copying the old version
289+ // of the file back over then restoring the setter
290+ // marker
291+ copy .Copy ("testdata/appconfig/deploy.yaml" , filepath .Join (tmp , "deploy.yaml" ))
292+ replaceMarker (tmp , policyKey )
293+ })
294+ // check that it was reverted correctly
295+ compareRepoWithExpected (repoURL , "testdata/appconfig" , func (tmp string ) {
296+ replaceMarker (tmp , policyKey )
297+ })
298+
299+ ts := time .Now ().String ()
300+ var updatePatch imagev1.ImageUpdateAutomation
301+ updatePatch .Name = updateKey .Name
302+ updatePatch .Namespace = updateKey .Namespace
303+ updatePatch .ObjectMeta .Annotations = map [string ]string {
304+ meta .ReconcileRequestAnnotation : ts ,
305+ }
306+ Expect (k8sClient .Patch (context .Background (), & updatePatch , client .Merge )).To (Succeed ())
307+
308+ // ... this is where the reconciler is supposed to do its work ...
309+
310+ var newUpdate imagev1.ImageUpdateAutomation
311+ Eventually (func () bool {
312+ if err := k8sClient .Get (context .Background (), updateKey , & newUpdate ); err != nil {
313+ return false
314+ }
315+ newLastRun := newUpdate .Status .LastAutomationRunTime
316+ return newLastRun != nil && newLastRun .Time .After (lastRunTime )
317+ }, timeout , time .Second ).Should (BeTrue ())
318+ // check that the annotation was recorded as seen
319+ Expect (newUpdate .Status .LastHandledReconcileAt ).To (Equal (ts ))
320+
321+ // check that a new commit was made
322+ compareRepoWithExpected (repoURL , "testdata/appconfig-setters-expected" , func (tmp string ) {
323+ replaceMarker (tmp , policyKey )
272324 })
273- Expect (err ).ToNot (HaveOccurred ())
274- test .ExpectMatchingDirectories (tmp , expected )
275325 })
276326 })
277327 })
@@ -307,6 +357,51 @@ func waitForNewHead(repo *git.Repository) {
307357 }, timeout , time .Second ).Should (BeTrue ())
308358}
309359
360+ func compareRepoWithExpected (repoURL , fixture string , changeFixture func (tmp string )) {
361+ expected , err := ioutil .TempDir ("" , "gotest-imageauto-expected" )
362+ Expect (err ).ToNot (HaveOccurred ())
363+ defer os .RemoveAll (expected )
364+ copy .Copy (fixture , expected )
365+ changeFixture (expected )
366+
367+ tmp , err := ioutil .TempDir ("" , "gotest-imageauto" )
368+ Expect (err ).ToNot (HaveOccurred ())
369+ defer os .RemoveAll (tmp )
370+ _ , err = git .PlainClone (tmp , false , & git.CloneOptions {
371+ URL : repoURL ,
372+ ReferenceName : plumbing .NewBranchReferenceName (defaultBranch ),
373+ })
374+ Expect (err ).ToNot (HaveOccurred ())
375+ test .ExpectMatchingDirectories (tmp , expected )
376+ }
377+
378+ func commitInRepo (repoURL , msg string , changeFiles func (path string )) {
379+ tmp , err := ioutil .TempDir ("" , "gotest-imageauto" )
380+ Expect (err ).ToNot (HaveOccurred ())
381+ defer os .RemoveAll (tmp )
382+ repo , err := git .PlainClone (tmp , false , & git.CloneOptions {
383+ URL : repoURL ,
384+ ReferenceName : plumbing .NewBranchReferenceName (defaultBranch ),
385+ })
386+ Expect (err ).ToNot (HaveOccurred ())
387+
388+ changeFiles (tmp )
389+
390+ worktree , err := repo .Worktree ()
391+ Expect (err ).ToNot (HaveOccurred ())
392+ _ , err = worktree .Add ("." )
393+ Expect (err ).ToNot (HaveOccurred ())
394+ _ , err = worktree .Commit (msg , & git.CommitOptions {
395+ Author : & object.Signature {
396+ Name : "Testbot" ,
397+ 398+ When : time .Now (),
399+ },
400+ })
401+ Expect (err ).ToNot (HaveOccurred ())
402+ Expect (repo .Push (& git.PushOptions {RemoteName : "origin" })).To (Succeed ())
403+ }
404+
310405// Initialise a git server with a repo including the files in dir.
311406func initGitRepo (gitServer * gittestserver.GitServer , fixture , repositoryPath string ) error {
312407 fs := memfs .New ()
0 commit comments