mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-24 01:27:49 +01:00
Add event trigger to helm upload/deletion replication
Signed-off-by: wang yan <wangyan@vmware.com>
This commit is contained in:
parent
f0fa90d10f
commit
7a373c2eed
@ -7,7 +7,13 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/goharbor/harbor/src/replication"
|
||||
rep_event "github.com/goharbor/harbor/src/replication/event"
|
||||
"github.com/goharbor/harbor/src/replication/model"
|
||||
helm_repo "k8s.io/helm/pkg/repo"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// ListCharts gets the chart list under the namespace
|
||||
@ -63,7 +69,38 @@ func (c *Controller) DeleteChartVersion(namespace, chartName, version string) er
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s", c.APIPrefix(namespace), chartName, version)
|
||||
|
||||
return c.apiClient.DeleteContent(url)
|
||||
err := c.apiClient.DeleteContent(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// send notification to replication handler
|
||||
// Todo: it used as the replacement of webhook, will be removed when webhook to be introduced.
|
||||
if os.Getenv("UTTEST") != "true" {
|
||||
go func() {
|
||||
e := &rep_event.Event{
|
||||
Type: rep_event.EventTypeChartDelete,
|
||||
Resource: &model.Resource{
|
||||
Type: model.ResourceTypeChart,
|
||||
Deleted: true,
|
||||
Metadata: &model.ResourceMetadata{
|
||||
Namespace: &model.Namespace{
|
||||
Name: namespace,
|
||||
},
|
||||
Repository: &model.Repository{
|
||||
Name: chartName,
|
||||
},
|
||||
Vtags: []string{version},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := replication.EventHandler.Handle(e); err != nil {
|
||||
log.Errorf("failed to handle event: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetChartVersion returns the summary of the specified chart version.
|
||||
|
@ -4,6 +4,11 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
hlog "github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/replication"
|
||||
rep_event "github.com/goharbor/harbor/src/replication/event"
|
||||
"github.com/goharbor/harbor/src/replication/model"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
@ -80,6 +85,39 @@ func director(target *url.URL, cred *Credential, req *http.Request) {
|
||||
|
||||
// Modify the http response
|
||||
func modifyResponse(res *http.Response) error {
|
||||
// Upload chart success, then to the notification to replication handler
|
||||
if res.StatusCode == http.StatusCreated {
|
||||
// 201 and has chart_upload(namespace-repository-version) context
|
||||
// means this response is for uploading chart success.
|
||||
chartUpload := res.Request.Context().Value(common.ChartUploadCtxKey).(string)
|
||||
if chartUpload != "" {
|
||||
chartUploadSplitted := strings.Split(chartUpload, ":")
|
||||
if len(chartUploadSplitted) == 3 {
|
||||
// Todo: it used as the replacement of webhook, will be removed when webhook to be introduced.
|
||||
go func() {
|
||||
e := &rep_event.Event{
|
||||
Type: rep_event.EventTypeChartUpload,
|
||||
Resource: &model.Resource{
|
||||
Type: model.ResourceTypeChart,
|
||||
Metadata: &model.ResourceMetadata{
|
||||
Namespace: &model.Namespace{
|
||||
Name: chartUploadSplitted[0],
|
||||
},
|
||||
Repository: &model.Repository{
|
||||
Name: chartUploadSplitted[1],
|
||||
},
|
||||
Vtags: []string{chartUploadSplitted[2]},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := replication.EventHandler.Handle(e); err != nil {
|
||||
hlog.Errorf("failed to handle event: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Accept cases
|
||||
// Success or redirect
|
||||
if res.StatusCode >= http.StatusOK && res.StatusCode <= http.StatusTemporaryRedirect {
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
package common
|
||||
|
||||
type contextKey string
|
||||
|
||||
// const variables
|
||||
const (
|
||||
DBAuth = "db_auth"
|
||||
@ -136,4 +138,6 @@ const (
|
||||
RobotTokenDuration = "robot_token_duration"
|
||||
|
||||
OIDCCallbackPath = "/c/oidc/callback"
|
||||
|
||||
ChartUploadCtxKey = contextKey("chart_upload")
|
||||
)
|
||||
|
@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -297,8 +298,28 @@ func (cra *ChartRepositoryAPI) UploadChartVersion() {
|
||||
}
|
||||
}
|
||||
|
||||
// set namespace/repository/version for replication event.
|
||||
_, header, err := cra.GetFile(formFieldNameForChart)
|
||||
if err != nil {
|
||||
cra.SendInternalServerError(err)
|
||||
return
|
||||
}
|
||||
|
||||
req := cra.Ctx.Request
|
||||
charFileName := header.Filename
|
||||
if !strings.HasSuffix(charFileName, ".tgz") {
|
||||
cra.SendInternalServerError(fmt.Errorf("chart file expected %s to end with .tgz", charFileName))
|
||||
return
|
||||
}
|
||||
charFileName = strings.TrimSuffix(charFileName, ".tgz")
|
||||
// colon cannot be used as namespace
|
||||
charFileName = strings.Replace(charFileName, "-", ":", -1)
|
||||
// value sample: library:redis:4.0.3 (namespace:repository:version)
|
||||
ctx := context.WithValue(cra.Ctx.Request.Context(), common.ChartUploadCtxKey, cra.namespace+":"+charFileName)
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
// Directly proxy to the backend
|
||||
chartController.ProxyTraffic(cra.Ctx.ResponseWriter, cra.Ctx.Request)
|
||||
chartController.ProxyTraffic(cra.Ctx.ResponseWriter, req)
|
||||
}
|
||||
|
||||
// UploadChartProvFile handles POST /api/:repo/prov
|
||||
|
@ -108,7 +108,7 @@ func (c *controller) createFlow(executionID int64, policy *model.Policy, resourc
|
||||
{
|
||||
Type: model.FilterTypeName,
|
||||
// TODO only filter the repo part?
|
||||
Value: resource.Metadata.GetResourceName(),
|
||||
Value: resource.Metadata.Repository.Name,
|
||||
},
|
||||
{
|
||||
Type: model.FilterTypeTag,
|
||||
|
@ -118,7 +118,7 @@ func filterResources(resources []*model.Resource, filters []*model.Filter) ([]*m
|
||||
for _, filter := range filters {
|
||||
switch filter.Type {
|
||||
case model.FilterTypeResource:
|
||||
resourceType, ok := filter.Value.(string)
|
||||
resourceType, ok := filter.Value.(model.ResourceType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%v is not a valid string", filter.Value)
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ func TestFilterResources(t *testing.T) {
|
||||
filters := []*model.Filter{
|
||||
{
|
||||
Type: model.FilterTypeResource,
|
||||
Value: string(model.ResourceTypeChart),
|
||||
Value: model.ResourceTypeChart,
|
||||
},
|
||||
{
|
||||
Type: model.FilterTypeName,
|
||||
|
Loading…
Reference in New Issue
Block a user