2016-06-16 08:57:45 +02:00
|
|
|
/*
|
2016-06-17 05:34:52 +02:00
|
|
|
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
2016-06-16 08:57:45 +02:00
|
|
|
*/
|
|
|
|
|
2016-05-17 12:49:02 +02:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
2016-05-27 12:46:07 +02:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2016-05-25 09:25:16 +02:00
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
2016-05-27 09:04:20 +02:00
|
|
|
"strconv"
|
2016-06-29 10:58:16 +02:00
|
|
|
"time"
|
2016-05-25 09:25:16 +02:00
|
|
|
|
2016-05-17 12:49:02 +02:00
|
|
|
"github.com/vmware/harbor/dao"
|
2016-05-27 12:46:07 +02:00
|
|
|
"github.com/vmware/harbor/models"
|
2016-05-17 12:49:02 +02:00
|
|
|
"github.com/vmware/harbor/utils/log"
|
|
|
|
)
|
|
|
|
|
2016-05-27 12:46:07 +02:00
|
|
|
// RepJobAPI handles request to /api/replicationJobs /api/replicationJobs/:id/log
|
2016-05-17 12:49:02 +02:00
|
|
|
type RepJobAPI struct {
|
|
|
|
BaseAPI
|
2016-05-27 12:46:07 +02:00
|
|
|
jobID int64
|
2016-05-17 12:49:02 +02:00
|
|
|
}
|
|
|
|
|
2016-05-27 12:46:07 +02:00
|
|
|
// Prepare validates that whether user has system admin role
|
|
|
|
func (ra *RepJobAPI) Prepare() {
|
|
|
|
uid := ra.ValidateUser()
|
2016-05-17 12:49:02 +02:00
|
|
|
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 {
|
2016-05-27 12:46:07 +02:00
|
|
|
ra.CustomAbort(http.StatusForbidden, "")
|
|
|
|
}
|
|
|
|
|
|
|
|
idStr := ra.Ctx.Input.Param(":id")
|
|
|
|
if len(idStr) != 0 {
|
|
|
|
id, err := strconv.ParseInt(idStr, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
ra.CustomAbort(http.StatusBadRequest, "ID is invalid")
|
|
|
|
}
|
|
|
|
ra.jobID = id
|
2016-05-17 12:49:02 +02:00
|
|
|
}
|
2016-05-25 09:25:16 +02:00
|
|
|
|
2016-05-17 12:49:02 +02:00
|
|
|
}
|
|
|
|
|
2016-06-17 05:44:40 +02:00
|
|
|
// List filters jobs according to the policy and repository
|
2016-06-17 05:34:52 +02:00
|
|
|
func (ra *RepJobAPI) List() {
|
|
|
|
var policyID int64
|
2016-06-27 10:24:04 +02:00
|
|
|
var repository, status string
|
2016-06-29 10:58:16 +02:00
|
|
|
var startTime, endTime *time.Time
|
2016-07-06 08:12:16 +02:00
|
|
|
var num int
|
2016-06-17 05:34:52 +02:00
|
|
|
var err error
|
|
|
|
|
|
|
|
policyIDStr := ra.GetString("policy_id")
|
|
|
|
if len(policyIDStr) != 0 {
|
|
|
|
policyID, err = strconv.ParseInt(policyIDStr, 10, 64)
|
|
|
|
if err != nil || policyID <= 0 {
|
|
|
|
ra.CustomAbort(http.StatusBadRequest, fmt.Sprintf("invalid policy ID: %s", policyIDStr))
|
|
|
|
}
|
2016-05-17 12:49:02 +02:00
|
|
|
}
|
2016-06-17 05:34:52 +02:00
|
|
|
|
2016-07-06 08:12:16 +02:00
|
|
|
numStr := ra.GetString("num")
|
|
|
|
if len(numStr) != 0 {
|
|
|
|
num, err = strconv.Atoi(numStr)
|
|
|
|
if err != nil {
|
|
|
|
ra.CustomAbort(http.StatusBadRequest, fmt.Sprintf("invalid num: %s", numStr))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if num <= 0 {
|
|
|
|
num = 200
|
|
|
|
}
|
|
|
|
|
2016-06-29 10:58:16 +02:00
|
|
|
endTimeStr := ra.GetString("end_time")
|
|
|
|
if len(endTimeStr) != 0 {
|
|
|
|
i, err := strconv.ParseInt(endTimeStr, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
ra.CustomAbort(http.StatusBadRequest, "invalid end_time")
|
|
|
|
}
|
|
|
|
t := time.Unix(i, 0)
|
|
|
|
endTime = &t
|
|
|
|
}
|
|
|
|
|
|
|
|
startTimeStr := ra.GetString("start_time")
|
|
|
|
if len(startTimeStr) != 0 {
|
|
|
|
i, err := strconv.ParseInt(startTimeStr, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
ra.CustomAbort(http.StatusBadRequest, "invalid start_time")
|
|
|
|
}
|
|
|
|
t := time.Unix(i, 0)
|
|
|
|
startTime = &t
|
|
|
|
}
|
|
|
|
|
|
|
|
if startTime == nil && endTime == nil {
|
|
|
|
// if start_time and end_time are both null, list jobs of last 10 days
|
|
|
|
t := time.Now().UTC().AddDate(0, 0, -10)
|
|
|
|
startTime = &t
|
|
|
|
}
|
|
|
|
|
2016-06-17 05:34:52 +02:00
|
|
|
repository = ra.GetString("repository")
|
2016-06-27 10:24:04 +02:00
|
|
|
status = ra.GetString("status")
|
2016-06-17 05:34:52 +02:00
|
|
|
|
2016-07-06 08:12:16 +02:00
|
|
|
jobs, err := dao.FilterRepJobs(policyID, repository, status, startTime, endTime, num)
|
2016-05-17 12:49:02 +02:00
|
|
|
if err != nil {
|
2016-06-27 10:24:04 +02:00
|
|
|
log.Errorf("failed to filter jobs according policy ID %d, repository %s, status %s: %v", policyID, repository, status, err)
|
2016-05-27 12:46:07 +02:00
|
|
|
ra.RenderError(http.StatusInternalServerError, "Failed to query job")
|
2016-05-17 12:49:02 +02:00
|
|
|
return
|
|
|
|
}
|
2016-05-27 12:46:07 +02:00
|
|
|
ra.Data["json"] = jobs
|
|
|
|
ra.ServeJSON()
|
2016-05-17 12:49:02 +02:00
|
|
|
}
|
|
|
|
|
2016-05-27 12:46:07 +02:00
|
|
|
// Delete ...
|
|
|
|
func (ra *RepJobAPI) Delete() {
|
|
|
|
if ra.jobID == 0 {
|
|
|
|
ra.CustomAbort(http.StatusBadRequest, "id is nil")
|
2016-05-25 09:25:16 +02:00
|
|
|
}
|
|
|
|
|
2016-05-27 12:46:07 +02:00
|
|
|
job, err := dao.GetRepJob(ra.jobID)
|
2016-05-25 09:25:16 +02:00
|
|
|
if err != nil {
|
2016-05-27 12:46:07 +02:00
|
|
|
log.Errorf("failed to get job %d: %v", ra.jobID, err)
|
|
|
|
ra.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
2016-05-25 09:25:16 +02:00
|
|
|
}
|
|
|
|
|
2016-07-31 14:21:19 +02:00
|
|
|
if job == nil {
|
|
|
|
ra.CustomAbort(http.StatusNotFound, fmt.Sprintf("job %d not found", ra.jobID))
|
|
|
|
}
|
|
|
|
|
2016-05-27 12:46:07 +02:00
|
|
|
if job.Status == models.JobPending || job.Status == models.JobRunning {
|
|
|
|
ra.CustomAbort(http.StatusBadRequest, fmt.Sprintf("job is %s, can not be deleted", job.Status))
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = dao.DeleteRepJob(ra.jobID); err != nil {
|
|
|
|
log.Errorf("failed to deleted job %d: %v", ra.jobID, err)
|
|
|
|
ra.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetLog ...
|
|
|
|
func (ra *RepJobAPI) GetLog() {
|
|
|
|
if ra.jobID == 0 {
|
|
|
|
ra.CustomAbort(http.StatusBadRequest, "id is nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := http.Get(buildJobLogURL(strconv.FormatInt(ra.jobID, 10)))
|
2016-05-25 09:25:16 +02:00
|
|
|
if err != nil {
|
2016-05-27 12:46:07 +02:00
|
|
|
log.Errorf("failed to get log for job %d: %v", ra.jobID, err)
|
|
|
|
ra.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
2016-05-25 09:25:16 +02:00
|
|
|
}
|
2016-07-14 11:50:25 +02:00
|
|
|
defer resp.Body.Close()
|
2016-05-25 09:25:16 +02:00
|
|
|
if resp.StatusCode == http.StatusOK {
|
2016-06-28 05:06:56 +02:00
|
|
|
ra.Ctx.ResponseWriter.Header().Set(http.CanonicalHeaderKey("Content-Length"), resp.Header.Get(http.CanonicalHeaderKey("Content-Length")))
|
|
|
|
ra.Ctx.ResponseWriter.Header().Set(http.CanonicalHeaderKey("Content-Type"), "text/plain")
|
2016-05-27 12:46:07 +02:00
|
|
|
|
|
|
|
if _, err = io.Copy(ra.Ctx.ResponseWriter, resp.Body); err != nil {
|
2016-05-25 09:25:16 +02:00
|
|
|
log.Errorf("failed to write log to response; %v", err)
|
2016-05-27 12:46:07 +02:00
|
|
|
ra.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
2016-05-25 09:25:16 +02:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-05-27 12:46:07 +02:00
|
|
|
b, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("failed to read reponse body: %v", err)
|
|
|
|
ra.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
|
|
|
}
|
|
|
|
|
|
|
|
ra.CustomAbort(resp.StatusCode, string(b))
|
2016-05-25 09:25:16 +02:00
|
|
|
}
|
|
|
|
|
2016-05-17 12:49:02 +02:00
|
|
|
//TODO:add Post handler to call job service API to submit jobs by policy
|