Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing build fix #2406

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions pkg/component/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -791,11 +791,8 @@ func Build(client *occlient.Client, componentName string, applicationName string
}

defer s.End(false)
if err := client.FollowBuildLog(buildName, stdout); err != nil {
return errors.Wrapf(err, "unable to follow logs for %s", buildName)
}

if err := client.WaitForBuildToFinish(buildName); err != nil {
if err := client.WaitForBuildToFinish(buildName, stdout); err != nil {
return errors.Wrapf(err, "unable to build %s, error: %s", buildName, b.String())
}
s.End(true)
Expand Down
52 changes: 38 additions & 14 deletions pkg/occlient/occlient.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ type CreateArgs struct {

const (
OcUpdateTimeout = 5 * time.Minute
OcBuildTimeout = 5 * time.Minute
OpenShiftNameSpace = "openshift"

// The length of the string to be generated for names of resources
Expand Down Expand Up @@ -1672,33 +1673,55 @@ func (c *Client) StartBuild(name string) (string, error) {
}

// WaitForBuildToFinish block and waits for build to finish. Returns error if build failed or was canceled.
func (c *Client) WaitForBuildToFinish(buildName string) error {
func (c *Client) WaitForBuildToFinish(buildName string, stdout io.Writer) error {
// following indicates if we have already setup the following logic
following := false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need more description on this, bit confused why we're setting following to false then true when going through the channel loop.

glog.V(4).Infof("Waiting for %s build to finish", buildName)

// start a watch on the build resources and look for the given build name
w, err := c.buildClient.Builds(c.Namespace).Watch(metav1.ListOptions{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand this is not touched in the proposed PR but can we add a comment that describes what this all about? At least I didn't understand a thing here. 😞

FieldSelector: fields.Set{"metadata.name": buildName}.AsSelector().String(),
})
if err != nil {
return errors.Wrapf(err, "unable to watch build")
}
defer w.Stop()
timeout := time.After(OcBuildTimeout)
for {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't understand what's going on in this for loop either. 😞

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can help here a bit. So here first thing to observe is the select statement on a quick TLDR: select statements are like channel collectors - listen on multiple channels at once, more here https://tour.golang.org/concurrency/5.

now the Build().Watch() returns a channel which returns messages on as per the pod status. Now the change that has been done here is
we wait for the pod to start before we start following the logs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as for the need for the following, The w.ResultChan() can send multiple messages of type BuildPhaseRunning. But we dont have to follow logs multiple times, just the first time should be good enough. Hence this flag.
Think of it as a singleton

val, ok := <-w.ResultChan()
if !ok {
break
}
if e, ok := val.Object.(*buildv1.Build); ok {
glog.V(4).Infof("Status of %s build is %s", e.Name, e.Status.Phase)
switch e.Status.Phase {
case buildv1.BuildPhaseComplete:
glog.V(4).Infof("Build %s completed.", e.Name)
return nil
case buildv1.BuildPhaseFailed, buildv1.BuildPhaseCancelled, buildv1.BuildPhaseError:
return errors.Errorf("build %s status %s", e.Name, e.Status.Phase)
select {
// when a event is received regarding the given buildName
case val, ok := <-w.ResultChan():
if !ok {
break
}
// cast the object returned to a build object and check the phase of the build
if e, ok := val.Object.(*buildv1.Build); ok {
glog.V(4).Infof("Status of %s build is %s", e.Name, e.Status.Phase)
switch e.Status.Phase {
case buildv1.BuildPhaseComplete:
// the build is completed thus return
glog.V(4).Infof("Build %s completed.", e.Name)
return nil
case buildv1.BuildPhaseFailed, buildv1.BuildPhaseCancelled, buildv1.BuildPhaseError:
// the build failed/got cancelled/error occurred thus return with error
return errors.Errorf("build %s status %s", e.Name, e.Status.Phase)
case buildv1.BuildPhaseRunning:
// since the pod is ready and the build is now running, start following the logs
if !following {
// setting following to true as we need to set it up only once
following = true
err := c.FollowBuildLog(buildName, stdout)
if err != nil {
return err
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this above looks good!

}
}
case <-timeout:
// timeout has occurred while waiting for the build to start/complete, so error out
return errors.Errorf("timeout waiting for build %s to start", buildName)
}
}
return nil
}

// WaitAndGetDC block and waits until the DeploymentConfig has updated it's annotation
Expand Down Expand Up @@ -1845,6 +1868,7 @@ func (c *Client) FollowBuildLog(buildName string, stdout io.Writer) error {
}

rd, err := c.buildClient.RESTClient().Get().
Timeout(OcBuildTimeout).
Namespace(c.Namespace).
Resource("builds").
Name(buildName).
Expand Down
2 changes: 1 addition & 1 deletion pkg/occlient/occlient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2091,7 +2091,7 @@ func TestWaitForBuildToFinish(t *testing.T) {
return true, fkWatch, nil
})

err := fkclient.WaitForBuildToFinish(tt.buildName)
err := fkclient.WaitForBuildToFinish(tt.buildName, os.Stdout)
if !tt.wantErr == (err != nil) {
t.Errorf(" client.WaitForBuildToFinish(string) unexpected error %v, wantErr %v", err, tt.wantErr)
return
Expand Down