mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 18:25:56 +01:00
provide POST api/repostitores/xxx/tags/xxx/scan to trigger image scan
This commit is contained in:
parent
15384317e0
commit
41346fe8c0
@ -80,3 +80,9 @@ type ComponentsOverviewEntry struct {
|
||||
Sev int `json:"severity"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
// ImageScanReq represents the request body to send to job service for image scan
|
||||
type ImageScanReq struct {
|
||||
Repo string `json:"repository"`
|
||||
Tag string `json:"tag"`
|
||||
}
|
||||
|
@ -31,20 +31,15 @@ type ImageScanJob struct {
|
||||
jobBaseAPI
|
||||
}
|
||||
|
||||
type imageScanReq struct {
|
||||
Repo string `json:"repository"`
|
||||
Tag string `json:"tag"`
|
||||
}
|
||||
|
||||
// Prepare ...
|
||||
func (isj *ImageScanJob) Prepare() {
|
||||
//TODO:add authenticate to check secret when integrate with UI API.
|
||||
//isj.authenticate()
|
||||
//TODO Uncomment to enable security check.
|
||||
// isj.authenticate()
|
||||
}
|
||||
|
||||
// Post creates a scanner job and hand it to statemachine.
|
||||
func (isj *ImageScanJob) Post() {
|
||||
var data imageScanReq
|
||||
var data models.ImageScanReq
|
||||
isj.DecodeJSONReq(&data)
|
||||
log.Debugf("data: %+v", data)
|
||||
regURL, err := config.LocalRegURL()
|
||||
|
@ -610,7 +610,6 @@ func (ra *RepositoryAPI) GetTopRepos() {
|
||||
//GetSignatures returns signatures of a repository
|
||||
func (ra *RepositoryAPI) GetSignatures() {
|
||||
repoName := ra.GetString(":splat")
|
||||
|
||||
targets, err := notary.GetInternalTargets(config.InternalNotaryEndpoint(),
|
||||
ra.SecurityCtx.GetUsername(), repoName)
|
||||
if err != nil {
|
||||
@ -621,6 +620,38 @@ func (ra *RepositoryAPI) GetSignatures() {
|
||||
ra.ServeJSON()
|
||||
}
|
||||
|
||||
//ScanImage handles
|
||||
func (ra *RepositoryAPI) ScanImage() {
|
||||
repoName := ra.GetString(":splat")
|
||||
tag := ra.GetString(":tag")
|
||||
projectName, _ := utils.ParseRepository(repoName)
|
||||
exist, err := ra.ProjectMgr.Exist(projectName)
|
||||
if err != nil {
|
||||
ra.HandleInternalServerError(fmt.Sprintf("failed to check the existence of project %s: %v",
|
||||
projectName, err))
|
||||
return
|
||||
}
|
||||
if !exist {
|
||||
ra.HandleNotFound(fmt.Sprintf("project %s not found", projectName))
|
||||
return
|
||||
}
|
||||
if !ra.SecurityCtx.IsAuthenticated() {
|
||||
ra.HandleUnauthorized()
|
||||
return
|
||||
}
|
||||
if !ra.SecurityCtx.HasAllPerm(projectName) {
|
||||
ra.HandleForbidden(ra.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
err = TriggerImageScan(repoName, tag)
|
||||
//TODO better check existence
|
||||
if err != nil {
|
||||
log.Errorf("Error while calling job service to trigger image scan: %v", err)
|
||||
ra.HandleInternalServerError("Failed to scan image, please check log for details")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func getSignatures(repository, username string) (map[string]*notary.Target, error) {
|
||||
targets, err := notary.GetInternalTargets(config.InternalNotaryEndpoint(),
|
||||
username, repository)
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"sort"
|
||||
@ -26,10 +27,10 @@ import (
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils"
|
||||
registry_error "github.com/vmware/harbor/src/common/utils/error"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/common/utils/registry"
|
||||
"github.com/vmware/harbor/src/common/utils/registry/auth"
|
||||
registry_error "github.com/vmware/harbor/src/common/utils/error"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
"github.com/vmware/harbor/src/ui/projectmanager"
|
||||
)
|
||||
@ -92,32 +93,9 @@ func TriggerReplication(policyID int64, repository string,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
url := buildReplicationURL()
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addAuthentication(req)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
return nil
|
||||
}
|
||||
|
||||
b, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return fmt.Errorf("%d %s", resp.StatusCode, string(b))
|
||||
return requestAsUI("POST", url, bytes.NewBuffer(b), http.StatusOK)
|
||||
}
|
||||
|
||||
// GetPoliciesByRepository returns policies according the repository
|
||||
@ -451,6 +429,11 @@ func initRegistryClient() (r *registry.Registry, err error) {
|
||||
return registryClient, nil
|
||||
}
|
||||
|
||||
func buildScanJobURL() string {
|
||||
url := config.InternalJobServiceURL()
|
||||
return fmt.Sprintf("%s/api/jobs/scan", url)
|
||||
}
|
||||
|
||||
func buildReplicationURL() string {
|
||||
url := config.InternalJobServiceURL()
|
||||
return fmt.Sprintf("%s/api/jobs/replication", url)
|
||||
@ -535,3 +518,42 @@ func NewRepositoryClient(endpoint string, insecure bool, username, repository, s
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// TriggerImageScan triggers an image scan job on jobservice.
|
||||
func TriggerImageScan(repository string, tag string) error {
|
||||
data := &models.ImageScanReq{
|
||||
Repo: repository,
|
||||
Tag: tag,
|
||||
}
|
||||
b, err := json.Marshal(&data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
url := buildScanJobURL()
|
||||
return requestAsUI("POST", url, bytes.NewBuffer(b), http.StatusOK)
|
||||
}
|
||||
|
||||
// Do not use this when you want to handle the response
|
||||
// TODO: add a response handler to replace expectSC *when needed*
|
||||
func requestAsUI(method, url string, body io.Reader, expectSC int) error {
|
||||
req, err := http.NewRequest(method, url, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addAuthentication(req)
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != expectSC {
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("Unexpected status code: %d, text: %s", resp.StatusCode, string(b))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -76,6 +76,7 @@ func initRouters() {
|
||||
beego.Router("/api/repositories/*", &api.RepositoryAPI{}, "delete:Delete")
|
||||
beego.Router("/api/repositories/*/tags/:tag", &api.RepositoryAPI{}, "delete:Delete")
|
||||
beego.Router("/api/repositories/*/tags", &api.RepositoryAPI{}, "get:GetTags")
|
||||
beego.Router("/api/repositories/*/tags/:tag/scan", &api.RepositoryAPI{}, "post:ScanImage")
|
||||
beego.Router("/api/repositories/*/tags/:tag/manifest", &api.RepositoryAPI{}, "get:GetManifests")
|
||||
beego.Router("/api/repositories/*/signatures", &api.RepositoryAPI{}, "get:GetSignatures")
|
||||
beego.Router("/api/jobs/replication/", &api.RepJobAPI{}, "get:List")
|
||||
|
Loading…
Reference in New Issue
Block a user