From fc72884676d73c7092a6376e646603e1272584b3 Mon Sep 17 00:00:00 2001 From: Kostiantyn Kalynovskyi Date: Fri, 18 Sep 2020 12:05:15 -0500 Subject: [PATCH] Fix clusterctl, IsoGen executors to emit proper events Change-Id: Ib69d9c85f7d27b83726f925d5a802c8e950c3a86 --- pkg/bootstrap/isogen/errors.go | 23 +++++++++++++++++++++++ pkg/bootstrap/isogen/executor.go | 17 ++++++++++++++++- pkg/bootstrap/isogen/executor_test.go | 8 ++++++++ pkg/clusterctl/client/executor.go | 10 ++++++++++ pkg/clusterctl/client/executor_test.go | 7 +++++++ pkg/events/errors.go | 2 +- pkg/events/events.go | 2 ++ pkg/events/processor.go | 6 ++++++ 8 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 pkg/bootstrap/isogen/errors.go diff --git a/pkg/bootstrap/isogen/errors.go b/pkg/bootstrap/isogen/errors.go new file mode 100644 index 000000000..30a21d782 --- /dev/null +++ b/pkg/bootstrap/isogen/errors.go @@ -0,0 +1,23 @@ +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package isogen + +// ErrIsoGenNilBundle is returned when isogen executor is not provided with bundle +type ErrIsoGenNilBundle struct { +} + +func (e ErrIsoGenNilBundle) Error() string { + return "Cannot build iso with empty bundle, no data source is available" +} diff --git a/pkg/bootstrap/isogen/executor.go b/pkg/bootstrap/isogen/executor.go index 732c5218b..5f3f8abd0 100644 --- a/pkg/bootstrap/isogen/executor.go +++ b/pkg/bootstrap/isogen/executor.go @@ -53,7 +53,10 @@ func RegisterExecutor(registry map[schema.GroupVersionKind]ifc.ExecutorFactory) // NewExecutor creates instance of phase executor func NewExecutor(cfg ifc.ExecutorConfig) (ifc.Executor, error) { - apiObj := &v1alpha1.ImageConfiguration{} + apiObj := &v1alpha1.ImageConfiguration{ + Container: &v1alpha1.Container{}, + Builder: &v1alpha1.Builder{}, + } err := cfg.ExecutorDocument.ToAPIObject(apiObj, v1alpha1.Scheme) if err != nil { return nil, err @@ -70,15 +73,23 @@ func NewExecutor(cfg ifc.ExecutorConfig) (ifc.Executor, error) { func (c *Executor) Run(evtCh chan events.Event, opts ifc.RunOptions) { defer close(evtCh) + if c.ExecutorBundle == nil { + handleError(evtCh, ErrIsoGenNilBundle{}) + return + } + evtCh <- events.Event{ + Type: events.IsogenType, IsogenEvent: 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, }, @@ -106,8 +117,10 @@ func (c *Executor) Run(evtCh chan events.Event, opts ifc.RunOptions) { } evtCh <- events.Event{ + Type: events.IsogenType, IsogenEvent: events.IsogenEvent{ Operation: events.IsogenValidation, + Message: "image is generated successfully, verifying artifacts", }, } err = verifyArtifacts(c.imgConf) @@ -117,8 +130,10 @@ func (c *Executor) Run(evtCh chan events.Event, opts ifc.RunOptions) { } evtCh <- events.Event{ + Type: events.IsogenType, IsogenEvent: events.IsogenEvent{ Operation: events.IsogenEnd, + Message: "iso generation is complete and artifacts verified", }, } } diff --git a/pkg/bootstrap/isogen/executor_test.go b/pkg/bootstrap/isogen/executor_test.go index 0282b1b32..0eb5269f8 100644 --- a/pkg/bootstrap/isogen/executor_test.go +++ b/pkg/bootstrap/isogen/executor_test.go @@ -110,16 +110,19 @@ func TestExecutorRun(t *testing.T) { }, 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, }, @@ -138,6 +141,7 @@ func TestExecutorRun(t *testing.T) { expectedEvt: []events.Event{ { + Type: events.IsogenType, IsogenEvent: events.IsogenEvent{ Operation: events.IsogenStart, }, @@ -160,6 +164,10 @@ func TestExecutorRun(t *testing.T) { go executor.Run(ch, ifc.RunOptions{}) var actualEvt []events.Event for evt := range ch { + if evt.Type == events.IsogenType { + // Set message to empty string, so it's not compared + evt.IsogenEvent.Message = "" + } actualEvt = append(actualEvt, evt) } assert.Equal(t, tt.expectedEvt, actualEvt) diff --git a/pkg/clusterctl/client/executor.go b/pkg/clusterctl/client/executor.go index e0f969ec2..595eaee53 100644 --- a/pkg/clusterctl/client/executor.go +++ b/pkg/clusterctl/client/executor.go @@ -88,8 +88,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", }, } ns := c.options.MoveOptions.Namespace @@ -115,16 +117,20 @@ 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", }, } } 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", }, } kubeConfigFile, cleanup, err := c.kubecfg.GetFile() @@ -139,8 +145,10 @@ func (c *ClusterctlExecutor) init(opts ifc.RunOptions, evtCh chan events.Event) // 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", }, } return @@ -151,8 +159,10 @@ func (c *ClusterctlExecutor) init(opts ifc.RunOptions, evtCh chan events.Event) c.handleErr(err, evtCh) } evtCh <- events.Event{ + Type: events.ClusterctlType, ClusterctlEvent: events.ClusterctlEvent{ Operation: events.ClusterctlInitEnd, + Message: "clusterctl init completed successfully", }, } } diff --git a/pkg/clusterctl/client/executor_test.go b/pkg/clusterctl/client/executor_test.go index ebc178e34..9de06b43c 100644 --- a/pkg/clusterctl/client/executor_test.go +++ b/pkg/clusterctl/client/executor_test.go @@ -128,6 +128,7 @@ func TestExecutorRun(t *testing.T) { bundlePath: "testdata/executor_init", expectedEvt: []events.Event{ { + Type: events.ClusterctlType, ClusterctlEvent: events.ClusterctlEvent{ Operation: events.ClusterctlInitStart, }, @@ -151,11 +152,13 @@ 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, }, @@ -185,6 +188,10 @@ func TestExecutorRun(t *testing.T) { go executor.Run(ch, ifc.RunOptions{DryRun: true}) var actualEvt []events.Event for evt := range ch { + if evt.Type == events.ClusterctlType { + // Set message to empty string, so it's not compared + evt.ClusterctlEvent.Message = "" + } actualEvt = append(actualEvt, evt) } assert.Equal(t, tt.expectedEvt, actualEvt) diff --git a/pkg/events/errors.go b/pkg/events/errors.go index 063a15cf8..f8368d27d 100644 --- a/pkg/events/errors.go +++ b/pkg/events/errors.go @@ -25,5 +25,5 @@ type ErrEventReceived struct { func (e ErrEventReceived) Error() string { // TODO make printing more readable here - return fmt.Sprintf("Applying of resources to kubernetes cluster has failed, errors are:\n%v", e.Errors) + return fmt.Sprintf("Error events received on channel, errors are:\n%v", e.Errors) } diff --git a/pkg/events/events.go b/pkg/events/events.go index 27dd1108e..1c653bfe2 100644 --- a/pkg/events/events.go +++ b/pkg/events/events.go @@ -69,6 +69,7 @@ const ( // ClusterctlEvent is produced by clusterctl executor type ClusterctlEvent struct { Operation ClusterctlOperation + Message string } // IsogenOperation type @@ -86,4 +87,5 @@ const ( // IsogenEvent needs to to track events in isogen executor type IsogenEvent struct { Operation IsogenOperation + Message string } diff --git a/pkg/events/processor.go b/pkg/events/processor.go index 9f4eecc40..4f1056143 100644 --- a/pkg/events/processor.go +++ b/pkg/events/processor.go @@ -52,7 +52,13 @@ func (p *DefaultProcessor) Process(ch <-chan Event) error { case ApplierType: p.processApplierEvent(e.ApplierEvent) case ErrorType: + log.Printf("Received error on event channel %v", e.ErrorEvent) p.errors = append(p.errors, e.ErrorEvent.Error) + case ClusterctlType, IsogenType: + // TODO each event needs to be interface that allows us to print it for example + // Stringer interface or AsYAML for further processing. + // For now we print the event object as is + log.Printf("Received event: %v", e) case StatusPollerType: log.Fatalf("Processing for status poller events are not yet implemented") case WaitType: