Check the status behind error when trying to update the scan schedule

Check the status behind error when trying to update the scan schedule

Signed-off-by: Wenkai Yin <yinw@vmware.com>
This commit is contained in:
Wenkai Yin 2019-09-09 13:31:10 +08:00
parent f200125abb
commit 3b07be5a72
5 changed files with 71 additions and 42 deletions

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"regexp"
"strings" "strings"
commonhttp "github.com/goharbor/harbor/src/common/http" commonhttp "github.com/goharbor/harbor/src/common/http"
@ -18,7 +19,9 @@ import (
var ( var (
// GlobalClient is an instance of the default client that can be used globally // GlobalClient is an instance of the default client that can be used globally
// Notes: the client needs to be initialized before can be used // Notes: the client needs to be initialized before can be used
GlobalClient Client GlobalClient Client
statusBehindErrorPattern = "mismatch job status for stopping job: .*, job status (.*) is behind Running"
statusBehindErrorReg = regexp.MustCompile(statusBehindErrorPattern)
) )
// Client wraps interface to access jobservice. // Client wraps interface to access jobservice.
@ -30,6 +33,21 @@ type Client interface {
// TODO Redirect joblog when we see there's memory issue. // TODO Redirect joblog when we see there's memory issue.
} }
// StatusBehindError represents the error got when trying to stop a success/failed job
type StatusBehindError struct {
status string
}
// Error returns the detail message about the error
func (s *StatusBehindError) Error() string {
return "status behind error"
}
// Status returns the current status of the job
func (s *StatusBehindError) Status() string {
return s.status
}
// DefaultClient is the default implementation of Client interface // DefaultClient is the default implementation of Client interface
type DefaultClient struct { type DefaultClient struct {
endpoint string endpoint string
@ -156,5 +174,25 @@ func (d *DefaultClient) PostAction(uuid, action string) error {
}{ }{
Action: action, Action: action,
} }
return d.client.Post(url, req) if err := d.client.Post(url, req); err != nil {
status, flag := isStatusBehindError(err)
if flag {
return &StatusBehindError{
status: status,
}
}
return err
}
return nil
}
func isStatusBehindError(err error) (string, bool) {
if err == nil {
return "", false
}
strs := statusBehindErrorReg.FindStringSubmatch(err.Error())
if len(strs) != 2 {
return "", false
}
return strs[1], true
} }

View File

@ -1,11 +1,13 @@
package job package job
import ( import (
"errors"
"os"
"testing"
"github.com/goharbor/harbor/src/common/job/models" "github.com/goharbor/harbor/src/common/job/models"
"github.com/goharbor/harbor/src/common/job/test" "github.com/goharbor/harbor/src/common/job/test"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"os"
"testing"
) )
var ( var (
@ -62,3 +64,20 @@ func TestPostAction(t *testing.T) {
err2 := testClient.PostAction(ID, "stop") err2 := testClient.PostAction(ID, "stop")
assert.Nil(err2) assert.Nil(err2)
} }
func TestIsStatusBehindError(t *testing.T) {
// nil error
status, flag := isStatusBehindError(nil)
assert.False(t, flag)
// not status behind error
err := errors.New("not status behind error")
status, flag = isStatusBehindError(err)
assert.False(t, flag)
// status behind error
err = errors.New("mismatch job status for stopping job: 9feedf9933jffs, job status Error is behind Running")
status, flag = isStatusBehindError(err)
assert.True(t, flag)
assert.Equal(t, "Error", status)
}

View File

@ -62,9 +62,12 @@ func (aj *AJAPI) updateSchedule(ajr models.AdminJobReq) {
// stop the scheduled job and remove it. // stop the scheduled job and remove it.
if err = utils_core.GetJobServiceClient().PostAction(jobs[0].UUID, common_job.JobActionStop); err != nil { if err = utils_core.GetJobServiceClient().PostAction(jobs[0].UUID, common_job.JobActionStop); err != nil {
if e, ok := err.(*common_http.Error); !ok || e.Code != http.StatusNotFound { _, ok := err.(*common_job.StatusBehindError)
aj.SendInternalServerError(err) if !ok {
return if e, ok := err.(*common_http.Error); !ok || e.Code != http.StatusNotFound {
aj.SendInternalServerError(err)
return
}
} }
} }

View File

@ -16,7 +16,6 @@ package operation
import ( import (
"fmt" "fmt"
"regexp"
"strings" "strings"
"time" "time"
@ -49,9 +48,7 @@ const (
) )
var ( var (
statusBehindErrorPattern = "mismatch job status for stopping job: .*, job status (.*) is behind Running" jobNotFoundErrorMsg = "object is not found"
statusBehindErrorReg = regexp.MustCompile(statusBehindErrorPattern)
jobNotFoundErrorMsg = "object is not found"
) )
// NewController returns a controller implementation // NewController returns a controller implementation
@ -163,8 +160,9 @@ func (c *controller) StopReplication(executionID int64) error {
continue continue
} }
if err = c.scheduler.Stop(task.JobID); err != nil { if err = c.scheduler.Stop(task.JobID); err != nil {
status, flag := isStatusBehindError(err) isStatusBehindError, ok := err.(*job.StatusBehindError)
if flag { if ok {
status := isStatusBehindError.Status()
switch hjob.Status(status) { switch hjob.Status(status) {
case hjob.ErrorStatus: case hjob.ErrorStatus:
status = models.TaskStatusFailed status = models.TaskStatusFailed
@ -215,17 +213,6 @@ func isTaskInFinalStatus(task *models.Task) bool {
return false return false
} }
func isStatusBehindError(err error) (string, bool) {
if err == nil {
return "", false
}
strs := statusBehindErrorReg.FindStringSubmatch(err.Error())
if len(strs) != 2 {
return "", false
}
return strs[1], true
}
func isJobNotFoundError(err error) bool { func isJobNotFoundError(err error) bool {
if err == nil { if err == nil {
return false return false

View File

@ -15,7 +15,6 @@
package operation package operation
import ( import (
"errors"
"io" "io"
"os" "os"
"testing" "testing"
@ -382,20 +381,3 @@ func TestIsTaskRunning(t *testing.T) {
assert.Equal(t, c.isFinalStatus, isTaskInFinalStatus(c.task)) assert.Equal(t, c.isFinalStatus, isTaskInFinalStatus(c.task))
} }
} }
func TestIsStatusBehindError(t *testing.T) {
// nil error
status, flag := isStatusBehindError(nil)
assert.False(t, flag)
// not status behind error
err := errors.New("not status behind error")
status, flag = isStatusBehindError(err)
assert.False(t, flag)
// status behind error
err = errors.New("mismatch job status for stopping job: 9feedf9933jffs, job status Error is behind Running")
status, flag = isStatusBehindError(err)
assert.True(t, flag)
assert.Equal(t, "Error", status)
}