diff --git a/api/base.go b/api/base.go index 7a7ff80df..7fac8e9b8 100644 --- a/api/base.go +++ b/api/base.go @@ -19,6 +19,7 @@ import ( "encoding/json" "fmt" "net/http" + "strconv" "github.com/astaxie/beego/validation" "github.com/vmware/harbor/auth" @@ -120,3 +121,18 @@ func (b *BaseAPI) Redirect(statusCode int, resouceID string) { b.Ctx.Redirect(statusCode, resoucreURI) } + +// GetIDFromURL checks the ID in request URL +func (b *BaseAPI) GetIDFromURL() int64 { + idStr := b.Ctx.Input.Param(":id") + if len(idStr) == 0 { + b.CustomAbort(http.StatusBadRequest, "invalid ID in URL") + } + + id, err := strconv.ParseInt(idStr, 10, 64) + if err != nil || id <= 0 { + b.CustomAbort(http.StatusBadRequest, "invalid ID in URL") + } + + return id +} diff --git a/api/replication_policy.go b/api/replication_policy.go index 57a7c91a2..419e95bf8 100644 --- a/api/replication_policy.go +++ b/api/replication_policy.go @@ -30,38 +30,45 @@ func (pa *RepPolicyAPI) Prepare() { if !isAdmin { pa.CustomAbort(http.StatusForbidden, "") } - idStr := pa.Ctx.Input.Param(":id") - if len(idStr) > 0 { - pa.policyID, err = strconv.ParseInt(idStr, 10, 64) - if err != nil { - log.Errorf("Error parsing policy id: %s, error: %v", idStr, err) - pa.CustomAbort(http.StatusBadRequest, "invalid policy id") - } - p, err := dao.GetRepPolicy(pa.policyID) - if err != nil { - log.Errorf("Error occurred in GetRepPolicy, error: %v", err) - pa.CustomAbort(http.StatusInternalServerError, "Internal error.") - } - if p == nil { - pa.CustomAbort(http.StatusNotFound, fmt.Sprintf("policy does not exist, id: %v", pa.policyID)) - } - pa.policy = p - } } -// Get gets all the policies according to the project +// Get ... func (pa *RepPolicyAPI) Get() { - projectID, err := pa.GetInt64("project_id") + id := pa.GetIDFromURL() + policy, err := dao.GetRepPolicy(id) if err != nil { - log.Errorf("Failed to get project id, error: %v", err) - pa.RenderError(http.StatusBadRequest, "Invalid project id") - return + log.Errorf("failed to get policy %d: %v", id, err) + pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } - policies, err := dao.GetRepPolicyByProject(projectID) + + if policy == nil { + pa.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound)) + } + + pa.Data["json"] = policy + pa.ServeJSON() +} + +// List filters policies by name and project_id, if name and project_id +// are nil, List returns all policies +func (pa *RepPolicyAPI) List() { + name := pa.GetString("name") + projectIDStr := pa.GetString("project_id") + + var projectID int64 + var err error + + if len(projectIDStr) != 0 { + projectID, err = strconv.ParseInt(projectIDStr, 10, 64) + if err != nil || projectID <= 0 { + pa.CustomAbort(http.StatusBadRequest, "invalid project ID") + } + } + + policies, err := dao.FilterRepPolicies(name, projectID) if err != nil { - log.Errorf("Failed to query policies from db, error: %v", err) - pa.RenderError(http.StatusInternalServerError, "Failed to query policies") - return + log.Errorf("failed to filter policies %s project ID %d: %v", name, projectID, err) + pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } pa.Data["json"] = policies pa.ServeJSON() diff --git a/api/target.go b/api/target.go index f60ece674..eee639b32 100644 --- a/api/target.go +++ b/api/target.go @@ -120,7 +120,7 @@ func (t *TargetAPI) Ping() { // Get ... func (t *TargetAPI) Get() { - id := t.getIDFromURL() + id := t.GetIDFromURL() target, err := dao.GetRepTarget(id) if err != nil { @@ -205,7 +205,7 @@ func (t *TargetAPI) Post() { // Put ... func (t *TargetAPI) Put() { - id := t.getIDFromURL() + id := t.GetIDFromURL() originTarget, err := dao.GetRepTarget(id) if err != nil { @@ -246,7 +246,7 @@ func (t *TargetAPI) Put() { // Delete ... func (t *TargetAPI) Delete() { - id := t.getIDFromURL() + id := t.GetIDFromURL() target, err := dao.GetRepTarget(id) if err != nil { @@ -263,17 +263,3 @@ func (t *TargetAPI) Delete() { t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } } - -func (t *TargetAPI) getIDFromURL() int64 { - idStr := t.Ctx.Input.Param(":id") - if len(idStr) == 0 { - t.CustomAbort(http.StatusBadRequest, "invalid target ID") - } - - id, err := strconv.ParseInt(idStr, 10, 64) - if err != nil || id <= 0 { - t.CustomAbort(http.StatusBadRequest, "invalid target ID") - } - - return id -} diff --git a/dao/dao_test.go b/dao/dao_test.go index ccd847abc..dd193b900 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -833,12 +833,6 @@ func TestUpdateRepTarget(t *testing.T) { } } -func TestGetAllRepTargets(t *testing.T) { - if _, err := GetAllRepTargets(); err != nil { - t.Fatalf("failed to get all targets: %v", err) - } -} - func TestFilterRepTargets(t *testing.T) { targets, err := FilterRepTargets("test") if err != nil { @@ -1130,7 +1124,7 @@ func TestDeleteRepPolicy(t *testing.T) { } t.Logf("delete rep policy, id: %d", policyID) p, err := GetRepPolicy(policyID) - if err != nil { + if err != nil && err != orm.ErrNoRows { t.Errorf("Error occured in GetRepPolicy:%v", err) } if p != nil { diff --git a/dao/replication_job.go b/dao/replication_job.go index c6b3707f8..1df9657a9 100644 --- a/dao/replication_job.go +++ b/dao/replication_job.go @@ -51,27 +51,22 @@ func UpdateRepTarget(target models.RepTarget) error { return err } -// GetAllRepTargets ... -func GetAllRepTargets() ([]*models.RepTarget, error) { - o := GetOrmer() - - qs := o.QueryTable(&models.RepTarget{}) - var targets []*models.RepTarget - _, err := qs.All(&targets) - return targets, err -} - // FilterRepTargets filters targets by name func FilterRepTargets(name string) ([]*models.RepTarget, error) { - if len(name) == 0 { - return GetAllRepTargets() - } - o := GetOrmer() + + var args []interface{} + + sql := `select * from replication_target ` + if len(name) != 0 { + sql += `where name like ? ` + args = append(args, "%"+name+"%") + } + sql += `order by creation_time` + var targets []*models.RepTarget - sql := "select * from replication_target where name like ?" - if _, err := o.Raw(sql, "%"+name+"%").QueryRows(&targets); err != nil { + if _, err := o.Raw(sql, args).QueryRows(&targets); err != nil { return nil, err } @@ -103,31 +98,77 @@ func AddRepPolicy(policy models.RepPolicy) (int64, error) { // GetRepPolicy ... func GetRepPolicy(id int64) (*models.RepPolicy, error) { o := GetOrmer() - p := models.RepPolicy{ID: id} - err := o.Read(&p) - if err == orm.ErrNoRows { - return nil, nil + sql := `select * from replication_policy where id = ?` + + var policy models.RepPolicy + + if err := o.Raw(sql, id).QueryRow(&policy); err != nil { + return nil, err } - return &p, err + + return &policy, nil +} + +// FilterRepPolicies filters policies by name and project ID +func FilterRepPolicies(name string, projectID int64) ([]*models.RepPolicy, error) { + o := GetOrmer() + + var args []interface{} + + sql := `select rp.id, rp.project_id, p.name as project_name, rp.target_id, + rt.name as target_name, rp.name, rp.enabled, rp.description, + rp.cron_str, rp.start_time, rp.creation_time, rp.update_time + from replication_policy rp + join project p on rp.project_id=p.project_id + join replication_target rt on rp.target_id=rt.id ` + + if len(name) != 0 && projectID != 0 { + sql += `where rp.name like ? and rp.project_id = ? ` + args = append(args, "%"+name+"%") + args = append(args, projectID) + } else if len(name) != 0 { + sql += `where rp.name like ? ` + args = append(args, "%"+name+"%") + } else if projectID != 0 { + sql += `where rp.project_id = ? ` + args = append(args, projectID) + } + + sql += `order by rp.creation_time` + + var policies []*models.RepPolicy + if _, err := o.Raw(sql, args).QueryRows(&policies); err != nil { + return nil, err + } + return policies, nil } // GetRepPolicyByName ... func GetRepPolicyByName(name string) (*models.RepPolicy, error) { o := GetOrmer() - p := models.RepPolicy{Name: name} - err := o.Read(&p, "Name") - if err == orm.ErrNoRows { - return nil, nil + sql := `select * from replication_policy where name = ?` + + var policy models.RepPolicy + + if err := o.Raw(sql, name).QueryRow(&policy); err != nil { + return nil, err } - return &p, err + + return &policy, nil } // GetRepPolicyByProject ... func GetRepPolicyByProject(projectID int64) ([]*models.RepPolicy, error) { - var res []*models.RepPolicy o := GetOrmer() - _, err := o.QueryTable("replication_policy").Filter("project_id", projectID).All(&res) - return res, err + sql := `select * from replication_policy where project_id = ?` + + var policies []*models.RepPolicy + + if _, err := o.Raw(sql, projectID).QueryRows(&policies); err != nil { + return nil, err + } + + return policies, nil } // DeleteRepPolicy ... diff --git a/models/replication_job.go b/models/replication_job.go index 7f3f94082..c3bf6be86 100644 --- a/models/replication_job.go +++ b/models/replication_job.go @@ -31,10 +31,12 @@ const ( // RepPolicy is the model for a replication policy, which associate to a project and a target (destination) type RepPolicy struct { - ID int64 `orm:"column(id)" json:"id"` - ProjectID int64 `orm:"column(project_id)" json:"project_id"` - TargetID int64 `orm:"column(target_id)" json:"target_id"` - Name string `orm:"column(name)" json:"name"` + ID int64 `orm:"column(id)" json:"id"` + ProjectID int64 `orm:"column(project_id)" json:"project_id"` + ProjectName string `json:"project_name,omitempty"` + TargetID int64 `orm:"column(target_id)" json:"target_id"` + TargetName string `json:"target_name,omitempty"` + Name string `orm:"column(name)" json:"name"` // Target RepTarget `orm:"-" json:"target"` Enabled int `orm:"column(enabled)" json:"enabled"` Description string `orm:"column(description)" json:"description"` diff --git a/ui/router.go b/ui/router.go index 16a7bf800..1eae007db 100644 --- a/ui/router.go +++ b/ui/router.go @@ -64,7 +64,8 @@ func initRouters() { beego.Router("/api/repositories/manifests", &api.RepositoryAPI{}, "get:GetManifests") beego.Router("/api/jobs/replication/?:id([0-9]+)", &api.RepJobAPI{}) beego.Router("/api/jobs/replication/:id([0-9]+)/log", &api.RepJobAPI{}, "get:GetLog") - beego.Router("/api/policies/replication", &api.RepPolicyAPI{}) + beego.Router("/api/policies/replication/:id([0-9]+)", &api.RepPolicyAPI{}) + beego.Router("/api/policies/replication", &api.RepPolicyAPI{}, "get:List") beego.Router("/api/policies/replication/:id([0-9]+)/enablement", &api.RepPolicyAPI{}, "put:UpdateEnablement") beego.Router("/api/targets/", &api.TargetAPI{}, "get:List") beego.Router("/api/targets/:id([0-9]+)", &api.TargetAPI{})