Skip to content

Commit

Permalink
Merge pull request #910 from nmeyerhans/fix-error-type
Browse files Browse the repository at this point in the history
Fix type assertion bug
  • Loading branch information
nmeyerhans committed Aug 2, 2017
2 parents c16753b + c8405db commit 1bc9d68
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 16 deletions.
2 changes: 1 addition & 1 deletion agent/engine/docker_container_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ func (dg *dockerGoClient) StopContainer(dockerID string, timeout time.Duration)
if err == context.DeadlineExceeded {
return DockerContainerMetadata{Error: &DockerTimeoutError{timeout, "stopped"}}
}
return DockerContainerMetadata{Error: &CannotStopContainerError{err}}
return DockerContainerMetadata{Error: CannotStopContainerError{err}}
}
}

Expand Down
2 changes: 1 addition & 1 deletion agent/engine/docker_task_engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ func TestTaskTransitionWhenStopContainerReturnsTransientErrorBeforeSucceeding(t
client.EXPECT().ContainerEvents(gomock.Any()).Return(eventStream, nil)
mockTime.EXPECT().After(gomock.Any()).AnyTimes()
containerStoppingError := DockerContainerMetadata{
Error: &CannotStopContainerError{errors.New("Error stopping container")},
Error: CannotStopContainerError{errors.New("Error stopping container")},
}
for _, container := range sleepTask.Containers {
gomock.InOrder(
Expand Down
19 changes: 15 additions & 4 deletions agent/engine/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ type engineError interface {
ErrorName() string
}

type cannotStopContainerError interface {
engineError
IsRetriableError() bool
}

// impossibleTransitionError is an error that occurs when an event causes a
// container to try and transition to a state that it cannot be moved to
type impossibleTransitionError struct {
Expand Down Expand Up @@ -154,15 +159,21 @@ func (err CannotStopContainerError) ErrorName() string {
return "CannotStopContainerError"
}

func (err CannotStopContainerError) IsUnretriableError() bool {
// IsRetriableError returns a boolean indicating whether the call that
// generated the error can be retried.
// When stopping a container, most errors that we can get should be
// considered retriable. However, in the case where the container is
// already stopped or doesn't exist at all, there's no sense in
// retrying.
func (err CannotStopContainerError) IsRetriableError() bool {
if _, ok := err.fromError.(*docker.NoSuchContainer); ok {
return true
return false
}
if _, ok := err.fromError.(*docker.ContainerNotRunning); ok {
return true
return false
}

return false
return true
}

// CannotPullContainerError indicates any error when trying to pull
Expand Down
12 changes: 6 additions & 6 deletions agent/engine/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ import (
"github.com/stretchr/testify/assert"
)

func TestUnretriableErrorReturnsTrueForNoSuchContainer(t *testing.T) {
func TestRetriableErrorReturnsFalseForNoSuchContainer(t *testing.T) {
err := CannotStopContainerError{&docker.NoSuchContainer{}}
assert.True(t, err.IsUnretriableError(), "No such container error should be treated as unretriable docker error")
assert.False(t, err.IsRetriableError(), "No such container error should be treated as unretriable docker error")
}

func TestUnretriableErrorReturnsTrueForContainerNotRunning(t *testing.T) {
func TestRetriableErrorReturnsFalseForContainerNotRunning(t *testing.T) {
err := CannotStopContainerError{&docker.ContainerNotRunning{}}
assert.True(t, err.IsUnretriableError(), "ContainerNotRunning error should be treated as unretriable docker error")
assert.False(t, err.IsRetriableError(), "ContainerNotRunning error should be treated as unretriable docker error")
}

func TestUnretriableErrorReturnsFalse(t *testing.T) {
func TestRetriableErrorReturnsTrue(t *testing.T) {
err := CannotStopContainerError{errors.New("error")}
assert.False(t, err.IsUnretriableError(), "Non unretriable error treated as unretriable docker error")
assert.True(t, err.IsRetriableError(), "Non unretriable error treated as unretriable docker error")
}
9 changes: 5 additions & 4 deletions agent/engine/task_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,8 @@ func (mtask *managedTask) handleContainerChange(containerChange dockerContainerC
}
// If docker returned a transient error while trying to stop a container,
// reset the known status to the current status and return
cannotStopContainerError, ok := event.Error.(*CannotStopContainerError)
if ok && !cannotStopContainerError.IsUnretriableError() {
cannotStopContainerError, ok := event.Error.(cannotStopContainerError)
if ok && cannotStopContainerError.IsRetriableError() {
seelog.Infof("Error stopping the container, ignoring state change; error: %s, task: %v",
cannotStopContainerError.Error(), mtask.Task)
container.SetKnownStatus(currentKnownStatus)
Expand All @@ -266,8 +266,9 @@ func (mtask *managedTask) handleContainerChange(containerChange dockerContainerC
// clearly can't just continue trying to transition it to stopped
// again and again... In this case, assume it's stopped (or close
// enough) and get on with it
// This actually happens a lot for the case of stopping something that was not running.
llog.Info("Error for 'docker stop' of container; assuming it's stopped anyways", "err", event.Error)
// This can happen in cases where the container we tried to stop
// was already stopped or did not exist at all.
seelog.Warnf("'docker stop' returned %s: %s", event.Error.ErrorName(), event.Error.Error())
container.SetKnownStatus(api.ContainerStopped)
container.SetDesiredStatus(api.ContainerStopped)
} else if event.Status == api.ContainerPulled {
Expand Down

0 comments on commit 1bc9d68

Please sign in to comment.