diff --git a/api/job.go b/api/job.go deleted file mode 100644 index 48930b7ef..000000000 --- a/api/job.go +++ /dev/null @@ -1,87 +0,0 @@ -package api - -/* -import ( - "encoding/json" - "fmt" - "github.com/vmware/harbor/dao" - "github.com/vmware/harbor/job" - "github.com/vmware/harbor/models" - "github.com/vmware/harbor/utils/log" - "net/http" - "strconv" -) - -type JobAPI struct { - BaseAPI -} - - -func (ja *JobAPI) Post() { - var je models.JobEntry - ja.DecodeJSONReq(&je) - res, err := json.Marshal(je.Options) - if !job.RunnerExists(je.Type) { - log.Errorf("runner for type %s is not registered", je.Type) - ja.RenderError(http.StatusBadRequest, fmt.Sprintf("runner for type %s is not registered", je.Type)) - return - } - je.OptionsStr = string(res) - if err != nil { - log.Warningf("Error marshaling options: %v", err) - } - res, err = json.Marshal(je.Parms) - je.ParmsStr = string(res) - if err != nil { - log.Warningf("Error marshaling parms: %v", err) - } - jobID, err := dao.AddJob(je) - if err != nil { - log.Errorf("Failed to add job to DB, error: %v", err) - ja.RenderError(http.StatusInternalServerError, "Failed to add job") - return - } - je.ID = jobID - log.Debugf("job Id:%d, type: %s", je.ID, je.Type) - job.Schedule(je) -} - -func (ja *JobAPI) Get() { - idStr := ja.Ctx.Input.Param(":id") - if len(idStr) > 0 { - jobID, err := strconv.ParseInt(idStr, 10, 64) - if err != nil { - log.Errorf("Failed to parse job id in url: %s", idStr) - ja.RenderError(http.StatusBadRequest, "invalid job id") - return - } - je, err := dao.GetJob(jobID) - if err != nil { - log.Errorf("Failed to query job from db, error: %v", err) - ja.RenderError(http.StatusInternalServerError, "Failed to query job") - return - } - if je == nil { - log.Errorf("job does not exist, id: %d", jobID) - ja.RenderError(http.StatusNotFound, "") - return - } - logs, err := dao.GetJobLogs(jobID) - if err != nil { - log.Errorf("Failed to get job logs, error: %v", err) - ja.RenderError(http.StatusInternalServerError, "Failed to query job") - return - } - je.Logs = logs - ja.Data["json"] = je - } else { - jobs, err := dao.ListJobs() - if err != nil { - log.Errorf("Failed to list jobs, error:%v", err) - ja.RenderError(http.StatusInternalServerError, "Failed to query job") - } - log.Debugf("jobs: %v", jobs) - ja.Data["json"] = jobs - } - ja.ServeJSON() -}*/ diff --git a/api/replication.go b/api/jobs/replication.go similarity index 96% rename from api/replication.go rename to api/jobs/replication.go index 0c8543a80..4d955b7f3 100644 --- a/api/replication.go +++ b/api/jobs/replication.go @@ -3,6 +3,7 @@ package api import ( "encoding/json" "fmt" + "github.com/vmware/harbor/api" "github.com/vmware/harbor/dao" "github.com/vmware/harbor/job" "github.com/vmware/harbor/models" @@ -16,7 +17,7 @@ import ( ) type ReplicationJob struct { - BaseAPI + api.BaseAPI } type ReplicationReq struct { @@ -102,7 +103,7 @@ func getRepoList(projectID int64) ([]string, error) { defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - log.Errorf("Failed to read the response body, error: %v") + log.Errorf("Failed to read the response body, error: %v", err) return nil, err } var repoList []string diff --git a/api/replication_job.go b/api/replication_job.go new file mode 100644 index 000000000..0c6f0f67b --- /dev/null +++ b/api/replication_job.go @@ -0,0 +1,41 @@ +package api + +import ( + "github.com/vmware/harbor/dao" + "github.com/vmware/harbor/utils/log" + "net/http" +) + +type RepJobAPI struct { + BaseAPI +} + +func (ja *RepJobAPI) Prepare() { + uid := ja.ValidateUser() + isAdmin, err := dao.IsAdminRole(uid) + if err != nil { + log.Errorf("Failed to Check if the user is admin, error: %v, uid: %d", err, uid) + } + if !isAdmin { + ja.CustomAbort(http.StatusForbidden, "") + } +} + +func (ja *RepJobAPI) Get() { + policyID, err := ja.GetInt64("policy_id") + if err != nil { + log.Errorf("Failed to get policy id, error: %v", err) + ja.RenderError(http.StatusBadRequest, "Invalid policy id") + return + } + jobs, err := dao.GetRepJobByPolicy(policyID) + if err != nil { + log.Errorf("Failed to query job from db, error: %v", err) + ja.RenderError(http.StatusInternalServerError, "Failed to query job") + return + } + ja.Data["json"] = jobs + ja.ServeJSON() +} + +//TODO:add Post handler to call job service API to submit jobs by policy diff --git a/api/replication_policy.go b/api/replication_policy.go new file mode 100644 index 000000000..174e898f0 --- /dev/null +++ b/api/replication_policy.go @@ -0,0 +1,97 @@ +package api + +import ( + "fmt" + "github.com/vmware/harbor/dao" + "github.com/vmware/harbor/models" + "github.com/vmware/harbor/utils/log" + "net/http" + "strconv" +) + +type RepPolicyAPI struct { + BaseAPI + policyID int64 +} + +func (pa *RepPolicyAPI) Prepare() { + uid := pa.ValidateUser() + var err error + isAdmin, err := dao.IsAdminRole(uid) + if err != nil { + log.Errorf("Failed to Check if the user is admin, error: %v, uid: %d", err, uid) + } + 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)) + } + } +} + +// Get ... +func (pa *RepPolicyAPI) Get() { + projectID, err := pa.GetInt64("project_id") + if err != nil { + log.Errorf("Failed to get project id, error: %v", err) + pa.RenderError(http.StatusBadRequest, "Invalid project id") + return + } + policies, err := dao.GetRepPolicyByProject(projectID) + if err != nil { + log.Errorf("Failed to query policies from db, error: %v", err) + pa.RenderError(http.StatusInternalServerError, "Failed to query policies") + return + } + pa.Data["json"] = policies + pa.ServeJSON() +} + +// Post ... +func (pa *RepPolicyAPI) Post() { + policy := models.RepPolicy{} + pa.DecodeJSONReq(&policy) + pid, err := dao.AddRepPolicy(policy) + if err != nil { + log.Errorf("Failed to add policy to DB, error: %v", err) + pa.RenderError(http.StatusInternalServerError, "Internal Error") + return + } + pa.Redirect(http.StatusCreated, strconv.FormatInt(pid, 10)) +} + +type enablementReq struct { + Enabled int `json:"enabled"` +} + +func (pa *RepPolicyAPI) UpdateEnablement() { + e := enablementReq{} + var err error + pa.DecodeJSONReq(&e) + if e.Enabled == 1 { + err = dao.EnableRepPolicy(pa.policyID) + } else if e.Enabled == 0 { + err = dao.DisableRepPolicy(pa.policyID) + } else { + pa.RenderError(http.StatusBadRequest, "invalid enabled value") + return + } + if err != nil { + log.Errorf("Failed to update policy enablement in DB, error: %v", err) + pa.RenderError(http.StatusInternalServerError, "Internal Error") + return + } +} diff --git a/dao/dao_test.go b/dao/dao_test.go index f381e03cd..de7259a60 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -734,7 +734,7 @@ func TestDeleteUser(t *testing.T) { } } -var targetID, policyID, jobID int64 +var targetID, policyID, policyID2, policyID3, jobID, jobID2, jobID3 int64 func TestAddRepTarget(t *testing.T) { target := models.RepTarget{ @@ -849,17 +849,17 @@ func TestAddRepPolicy2(t *testing.T) { Description: "whatever", Name: "mypolicy", } - id, err := AddRepPolicy(policy2) - t.Logf("added policy, id: %d", id) + policyID2, err := AddRepPolicy(policy2) + t.Logf("added policy, id: %d", policyID2) if err != nil { t.Errorf("Error occurred in AddRepPolicy: %v", err) } - p, err := GetRepPolicy(id) + p, err := GetRepPolicy(policyID2) if err != nil { - t.Errorf("Error occurred in GetPolicy: %v, id: %d", err, id) + t.Errorf("Error occurred in GetPolicy: %v, id: %d", err, policyID2) } if p == nil { - t.Errorf("Unable to find a policy with id: %d", id) + t.Errorf("Unable to find a policy with id: %d", policyID2) } var tm time.Time if p.StartTime.After(tm) { @@ -910,6 +910,57 @@ func TestUpdateRepJobStatus(t *testing.T) { } } +func TestGetRepPolicyByProject(t *testing.T) { + p1, err := GetRepPolicyByProject(99) + if err != nil { + t.Errorf("Error occured in GetRepPolicyByProject:%v, project ID: %d", err, 99) + return + } + if len(p1) > 0 { + t.Errorf("Unexpected length of policy list, expected: 0, in fact: %d, project id: %d", len(p1), 99) + return + } + + p2, err := GetRepPolicyByProject(1) + if err != nil { + t.Errorf("Error occuered in GetRepPolicyByProject:%v, project ID: %d", err, 2) + return + } + if len(p2) != 1 { + t.Errorf("Unexpected length of policy list, expected: 1, in fact: %d, project id: %d", len(p2), 1) + return + } + if p2[0].ID != policyID { + t.Errorf("Unexpecred policy id in result, expected: %d, in fact: %d", policyID, p2[0].ID) + return + } +} + +func TestGetRepJobByPolicy(t *testing.T) { + jobs, err := GetRepJobByPolicy(999) + if err != nil { + log.Errorf("Error occured in GetRepJobByPolicy: %v, policy ID: %d", err, 999) + return + } + if len(jobs) > 0 { + log.Errorf("Unexpected length of jobs, expected: 0, in fact: %d", len(jobs)) + return + } + jobs, err = GetRepJobByPolicy(policyID) + if err != nil { + log.Errorf("Error occured in GetRepJobByPolicy: %v, policy ID: %d", err, policyID) + return + } + if len(jobs) != 1 { + log.Errorf("Unexpected length of jobs, expected: 1, in fact: %d", len(jobs)) + return + } + if jobs[0].ID != jobID { + log.Errorf("Unexpected job ID in the result, expected: %d, in fact: %d", jobID, jobs[0].ID) + return + } +} + func TestDeleteRepTarget(t *testing.T) { err := DeleteRepTarget(targetID) if err != nil { diff --git a/dao/replication_job.go b/dao/replication_job.go index 4e049d182..235ed03a3 100644 --- a/dao/replication_job.go +++ b/dao/replication_job.go @@ -55,6 +55,12 @@ func GetRepPolicy(id int64) (*models.RepPolicy, error) { } return &p, err } +func GetRepPolicyByProject(projectID int64) ([]*models.RepPolicy, error) { + var res []*models.RepPolicy + o := orm.NewOrm() + _, err := o.QueryTable("replication_policy").Filter("project_id", projectID).All(&res) + return res, err +} func DeleteRepPolicy(id int64) error { o := orm.NewOrm() _, err := o.Delete(&models.RepPolicy{ID: id}) @@ -95,6 +101,12 @@ func GetRepJob(id int64) (*models.RepJob, error) { } return &j, err } +func GetRepJobByPolicy(policyID int64) ([]*models.RepJob, error) { + o := orm.NewOrm() + var res []*models.RepJob + _, err := o.QueryTable("replication_job").Filter("policy_id", policyID).All(&res) + return res, err +} func DeleteRepJob(id int64) error { o := orm.NewOrm() _, err := o.Delete(&models.RepJob{ID: id}) diff --git a/jobservice/router.go b/jobservice/router.go index a9c028038..d224d44ea 100644 --- a/jobservice/router.go +++ b/jobservice/router.go @@ -1,7 +1,7 @@ package main import ( - "github.com/vmware/harbor/api" + api "github.com/vmware/harbor/api/jobs" "github.com/astaxie/beego" ) diff --git a/models/replication_job.go b/models/replication_job.go index 885cb311c..2c2566dd3 100644 --- a/models/replication_job.go +++ b/models/replication_job.go @@ -18,11 +18,11 @@ const ( ) 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"` - Target RepTarget `orm:"-" json:"target"` + 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"` + // Target RepTarget `orm:"-" json:"target"` Enabled int `orm:"column(enabled)" json:"enabled"` Description string `orm:"column(description)" json:"description"` CronStr string `orm:"column(cron_str)" json:"cron_str"` @@ -32,12 +32,12 @@ type RepPolicy struct { } type RepJob struct { - ID int64 `orm:"column(id)" json:"id"` - Status string `orm:"column(status)" json:"status"` - Repository string `orm:"column(repository)" json:"repository"` - PolicyID int64 `orm:"column(policy_id)" json:"policy_id"` - Operation string `orm:"column(operation)" json:"operation"` - Policy RepPolicy `orm:"-" json:"policy"` + ID int64 `orm:"column(id)" json:"id"` + Status string `orm:"column(status)" json:"status"` + Repository string `orm:"column(repository)" json:"repository"` + PolicyID int64 `orm:"column(policy_id)" json:"policy_id"` + Operation string `orm:"column(operation)" json:"operation"` + // Policy RepPolicy `orm:"-" json:"policy"` CreationTime time.Time `orm:"column(creation_time);auto_now_add" json:"creation_time"` UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"` }