diff --git a/pkg/bootstrap/isogen/executor.go b/pkg/bootstrap/isogen/executor.go index 9427bd879..0126a30e1 100644 --- a/pkg/bootstrap/isogen/executor.go +++ b/pkg/bootstrap/isogen/executor.go @@ -83,22 +83,16 @@ func (c *Executor) Run(evtCh chan events.Event, opts ifc.RunOptions) { return } - evtCh <- events.Event{ - Type: events.IsogenType, - IsogenEvent: events.IsogenEvent{ - Operation: events.IsogenStart, - Message: "starting ISO generation", - }, - } + evtCh <- events.NewEvent().WithIsogenEvent(events.IsogenEvent{ + Operation: events.IsogenStart, + Message: "starting ISO generation", + }) if opts.DryRun { log.Print("command isogen will be executed") - evtCh <- events.Event{ - Type: events.IsogenType, - IsogenEvent: events.IsogenEvent{ - Operation: events.IsogenEnd, - }, - } + evtCh <- events.NewEvent().WithIsogenEvent(events.IsogenEvent{ + Operation: events.IsogenEnd, + }) return } @@ -131,26 +125,20 @@ func (c *Executor) Run(evtCh chan events.Event, opts ifc.RunOptions) { return } - evtCh <- events.Event{ - Type: events.IsogenType, - IsogenEvent: events.IsogenEvent{ - Operation: events.IsogenValidation, - Message: "image is generated successfully, verifying artifacts", - }, - } + evtCh <- events.NewEvent().WithIsogenEvent(events.IsogenEvent{ + Operation: events.IsogenValidation, + Message: "image is generated successfully, verifying artifacts", + }) err = verifyArtifacts(c.imgConf) if err != nil { handleError(evtCh, err) return } - evtCh <- events.Event{ - Type: events.IsogenType, - IsogenEvent: events.IsogenEvent{ - Operation: events.IsogenEnd, - Message: "iso generation is complete and artifacts verified", - }, - } + evtCh <- events.NewEvent().WithIsogenEvent(events.IsogenEvent{ + Operation: events.IsogenEnd, + Message: "iso generation is complete and artifacts verified", + }) } // Validate executor configuration and documents @@ -166,10 +154,7 @@ func (c *Executor) Render(w io.Writer, _ ifc.RenderOptions) error { } func handleError(ch chan<- events.Event, err error) { - ch <- events.Event{ - Type: events.ErrorType, - ErrorEvent: events.ErrorEvent{ - Error: err, - }, - } + ch <- events.NewEvent().WithErrorEvent(events.ErrorEvent{ + Error: err, + }) } diff --git a/pkg/bootstrap/isogen/executor_test.go b/pkg/bootstrap/isogen/executor_test.go index e3a5ad04f..0ba914a6e 100644 --- a/pkg/bootstrap/isogen/executor_test.go +++ b/pkg/bootstrap/isogen/executor_test.go @@ -16,6 +16,7 @@ package isogen import ( "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -109,24 +110,15 @@ func TestExecutorRun(t *testing.T) { waitUntilFinished: func() error { return nil }, }, expectedEvt: []events.Event{ - { - Type: events.IsogenType, - IsogenEvent: events.IsogenEvent{ - Operation: events.IsogenStart, - }, - }, - { - Type: events.IsogenType, - IsogenEvent: events.IsogenEvent{ - Operation: events.IsogenValidation, - }, - }, - { - Type: events.IsogenType, - IsogenEvent: events.IsogenEvent{ - Operation: events.IsogenEnd, - }, - }, + events.NewEvent().WithIsogenEvent(events.IsogenEvent{ + Operation: events.IsogenStart, + }), + events.NewEvent().WithIsogenEvent(events.IsogenEvent{ + Operation: events.IsogenValidation, + }), + events.NewEvent().WithIsogenEvent(events.IsogenEvent{ + Operation: events.IsogenEnd, + }), }, }, { @@ -140,12 +132,9 @@ func TestExecutorRun(t *testing.T) { }, expectedEvt: []events.Event{ - { - Type: events.IsogenType, - IsogenEvent: events.IsogenEvent{ - Operation: events.IsogenStart, - }, - }, + events.NewEvent().WithIsogenEvent(events.IsogenEvent{ + Operation: events.IsogenStart, + }), wrapError(container.ErrRunContainerCommand{Cmd: "super fail"}), }, }, @@ -163,24 +152,27 @@ func TestExecutorRun(t *testing.T) { go executor.Run(ch, ifc.RunOptions{}) var actualEvt []events.Event for evt := range ch { + // Skip timestamp for comparison + evt.Timestamp = time.Time{} if evt.Type == events.IsogenType { // Set message to empty string, so it's not compared evt.IsogenEvent.Message = "" } actualEvt = append(actualEvt, evt) } + for i := range tt.expectedEvt { + // Skip timestamp for comparison + tt.expectedEvt[i].Timestamp = time.Time{} + } assert.Equal(t, tt.expectedEvt, actualEvt) }) } } func wrapError(err error) events.Event { - return events.Event{ - Type: events.ErrorType, - ErrorEvent: events.ErrorEvent{ - Error: err, - }, - } + return events.NewEvent().WithErrorEvent(events.ErrorEvent{ + Error: err, + }) } func testBundleFactory(path string) document.BundleFactoryFunc { diff --git a/pkg/clusterctl/client/executor.go b/pkg/clusterctl/client/executor.go index 0f31d9ce4..fd2564d65 100644 --- a/pkg/clusterctl/client/executor.go +++ b/pkg/clusterctl/client/executor.go @@ -84,13 +84,10 @@ func (c *ClusterctlExecutor) Run(evtCh chan events.Event, opts ifc.RunOptions) { } func (c *ClusterctlExecutor) move(opts ifc.RunOptions, evtCh chan events.Event) { - evtCh <- events.Event{ - Type: events.ClusterctlType, - ClusterctlEvent: events.ClusterctlEvent{ - Operation: events.ClusterctlMoveStart, - Message: "starting clusterctl move executor", - }, - } + evtCh <- events.NewEvent().WithClusterctlEvent(events.ClusterctlEvent{ + Operation: events.ClusterctlMoveStart, + Message: "starting clusterctl move executor", + }) ns := c.options.MoveOptions.Namespace kubeConfigFile, cleanup, err := c.kubecfg.GetFile() if err != nil { @@ -113,23 +110,17 @@ func (c *ClusterctlExecutor) move(opts ifc.RunOptions, evtCh chan events.Event) } } - evtCh <- events.Event{ - Type: events.ClusterctlType, - ClusterctlEvent: events.ClusterctlEvent{ - Operation: events.ClusterctlMoveEnd, - Message: "clusterctl move completed successfully", - }, - } + evtCh <- events.NewEvent().WithClusterctlEvent(events.ClusterctlEvent{ + Operation: events.ClusterctlMoveEnd, + Message: "clusterctl move completed successfully", + }) } func (c *ClusterctlExecutor) init(opts ifc.RunOptions, evtCh chan events.Event) { - evtCh <- events.Event{ - Type: events.ClusterctlType, - ClusterctlEvent: events.ClusterctlEvent{ - Operation: events.ClusterctlInitStart, - Message: "starting clusterctl init executor", - }, - } + evtCh <- events.NewEvent().WithClusterctlEvent(events.ClusterctlEvent{ + Operation: events.ClusterctlInitStart, + Message: "starting clusterctl init executor", + }) kubeConfigFile, cleanup, err := c.kubecfg.GetFile() if err != nil { c.handleErr(err, evtCh) @@ -141,13 +132,10 @@ func (c *ClusterctlExecutor) init(opts ifc.RunOptions, evtCh chan events.Event) if opts.DryRun { // TODO (dukov) add more details to dry-run log.Print("command 'clusterctl init' is going to be executed") - evtCh <- events.Event{ - Type: events.ClusterctlType, - ClusterctlEvent: events.ClusterctlEvent{ - Operation: events.ClusterctlInitEnd, - Message: "clusterctl init dry-run completed successfully", - }, - } + evtCh <- events.NewEvent().WithClusterctlEvent(events.ClusterctlEvent{ + Operation: events.ClusterctlInitEnd, + Message: "clusterctl init dry-run completed successfully", + }) return } // Use cluster name as context in kubeconfig file @@ -155,22 +143,16 @@ func (c *ClusterctlExecutor) init(opts ifc.RunOptions, evtCh chan events.Event) if err != nil { c.handleErr(err, evtCh) } - evtCh <- events.Event{ - Type: events.ClusterctlType, - ClusterctlEvent: events.ClusterctlEvent{ - Operation: events.ClusterctlInitEnd, - Message: "clusterctl init completed successfully", - }, - } + evtCh <- events.NewEvent().WithClusterctlEvent(events.ClusterctlEvent{ + Operation: events.ClusterctlInitEnd, + Message: "clusterctl init completed successfully", + }) } func (c *ClusterctlExecutor) handleErr(err error, evtCh chan events.Event) { - evtCh <- events.Event{ - Type: events.ErrorType, - ErrorEvent: events.ErrorEvent{ - Error: err, - }, - } + evtCh <- events.NewEvent().WithErrorEvent(events.ErrorEvent{ + Error: err, + }) } // Validate executor configuration and documents diff --git a/pkg/clusterctl/client/executor_test.go b/pkg/clusterctl/client/executor_test.go index c980cfdc2..7ac228474 100644 --- a/pkg/clusterctl/client/executor_test.go +++ b/pkg/clusterctl/client/executor_test.go @@ -19,6 +19,7 @@ import ( "errors" "fmt" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -122,12 +123,9 @@ func TestExecutorRun(t *testing.T) { }, bundlePath: "testdata/executor_init", expectedEvt: []events.Event{ - { - Type: events.ClusterctlType, - ClusterctlEvent: events.ClusterctlEvent{ - Operation: events.ClusterctlInitStart, - }, - }, + events.NewEvent().WithClusterctlEvent(events.ClusterctlEvent{ + Operation: events.ClusterctlInitStart, + }), wrapError(errTmpFile), }, }, @@ -146,18 +144,12 @@ func TestExecutorRun(t *testing.T) { }, bundlePath: "testdata/executor_init", expectedEvt: []events.Event{ - { - Type: events.ClusterctlType, - ClusterctlEvent: events.ClusterctlEvent{ - Operation: events.ClusterctlInitStart, - }, - }, - { - Type: events.ClusterctlType, - ClusterctlEvent: events.ClusterctlEvent{ - Operation: events.ClusterctlInitEnd, - }, - }, + events.NewEvent().WithClusterctlEvent(events.ClusterctlEvent{ + Operation: events.ClusterctlInitStart, + }), + events.NewEvent().WithClusterctlEvent(events.ClusterctlEvent{ + Operation: events.ClusterctlInitEnd, + }), }, }, // TODO add move tests here @@ -180,12 +172,18 @@ func TestExecutorRun(t *testing.T) { go executor.Run(ch, ifc.RunOptions{DryRun: true}) var actualEvt []events.Event for evt := range ch { + // Skip timmestamp for comparison + evt.Timestamp = time.Time{} if evt.Type == events.ClusterctlType { // Set message to empty string, so it's not compared evt.ClusterctlEvent.Message = "" } actualEvt = append(actualEvt, evt) } + for i := range tt.expectedEvt { + // Skip timmestamp for comparison + tt.expectedEvt[i].Timestamp = time.Time{} + } assert.Equal(t, tt.expectedEvt, actualEvt) }) } @@ -238,10 +236,7 @@ func executorDoc(t *testing.T, action string) document.Document { } func wrapError(err error) events.Event { - return events.Event{ - Type: events.ErrorType, - ErrorEvent: events.ErrorEvent{ - Error: err, - }, - } + return events.NewEvent().WithErrorEvent(events.ErrorEvent{ + Error: err, + }) } diff --git a/pkg/events/events.go b/pkg/events/events.go index a5aa821cd..4268fcff0 100644 --- a/pkg/events/events.go +++ b/pkg/events/events.go @@ -15,6 +15,8 @@ package events import ( + "time" + applyevent "sigs.k8s.io/cli-utils/pkg/apply/event" statuspollerevent "sigs.k8s.io/cli-utils/pkg/kstatus/polling/event" ) @@ -40,6 +42,7 @@ const ( // Event holds all possible events that can be produced by airship type Event struct { Type Type + Timestamp time.Time ApplierEvent applyevent.Event ErrorEvent ErrorEvent StatusPollerEvent statuspollerevent.Event @@ -47,11 +50,25 @@ type Event struct { IsogenEvent IsogenEvent } +// NewEvent create new event with timestamp +func NewEvent() Event { + return Event{ + Timestamp: time.Now(), + } +} + // ErrorEvent is produced when error is encountered type ErrorEvent struct { Error error } +// WithErrorEvent sets type and actual error event +func (e Event) WithErrorEvent(event ErrorEvent) Event { + e.Type = ErrorType + e.ErrorEvent = event + return e +} + // ClusterctlOperation type type ClusterctlOperation int @@ -72,6 +89,13 @@ type ClusterctlEvent struct { Message string } +// WithClusterctlEvent sets type and actual clusterctl event +func (e Event) WithClusterctlEvent(concreteEvent ClusterctlEvent) Event { + e.Type = ClusterctlType + e.ClusterctlEvent = concreteEvent + return e +} + // IsogenOperation type type IsogenOperation int @@ -89,3 +113,10 @@ type IsogenEvent struct { Operation IsogenOperation Message string } + +// WithIsogenEvent sets type and actual isogen event +func (e Event) WithIsogenEvent(concreteEvent IsogenEvent) Event { + e.Type = IsogenType + e.IsogenEvent = concreteEvent + return e +}