mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-22 14:52:17 +01:00
Merge pull request #7482 from wy65701436/chart-upload
Fix chart upload issue on event based
This commit is contained in:
commit
69d9a28860
@ -14,6 +14,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
hlog "github.com/goharbor/harbor/src/common/utils/log"
|
||||
"k8s.io/helm/pkg/chartutil"
|
||||
"k8s.io/helm/pkg/proto/hapi/chart"
|
||||
helm_repo "k8s.io/helm/pkg/repo"
|
||||
)
|
||||
|
||||
@ -71,13 +72,7 @@ type ChartOperator struct{}
|
||||
|
||||
// GetChartDetails parse the details from the provided content bytes
|
||||
func (cho *ChartOperator) GetChartDetails(content []byte) (*ChartVersionDetails, error) {
|
||||
if content == nil || len(content) == 0 {
|
||||
return nil, errors.New("zero content")
|
||||
}
|
||||
|
||||
// Load chart from in-memory content
|
||||
reader := bytes.NewReader(content)
|
||||
chartData, err := chartutil.LoadArchive(reader)
|
||||
chartData, err := cho.GetChartData(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -164,6 +159,21 @@ func (cho *ChartOperator) GetChartList(content []byte) ([]*ChartInfo, error) {
|
||||
return chartList, nil
|
||||
}
|
||||
|
||||
// GetChartData returns raw data of chart
|
||||
func (cho *ChartOperator) GetChartData(content []byte) (*chart.Chart, error) {
|
||||
if content == nil || len(content) == 0 {
|
||||
return nil, errors.New("zero content")
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(content)
|
||||
chartData, err := chartutil.LoadArchive(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return chartData, nil
|
||||
}
|
||||
|
||||
// GetChartVersions returns the chart versions
|
||||
func (cho *ChartOperator) GetChartVersions(content []byte) (ChartVersions, error) {
|
||||
if content == nil || len(content) == 0 {
|
||||
|
@ -17,7 +17,6 @@ import (
|
||||
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"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -88,32 +87,21 @@ func director(target *url.URL, cred *Credential, req *http.Request) {
|
||||
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
|
||||
// 201 and has chart_upload_event 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{
|
||||
Repository: &model.Repository{
|
||||
Name: fmt.Sprintf("%s/%s", chartUploadSplitted[0], chartUploadSplitted[1]),
|
||||
},
|
||||
Vtags: []string{chartUploadSplitted[2]},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := replication.EventHandler.Handle(e); err != nil {
|
||||
hlog.Errorf("failed to handle event: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
chartUploadEvent := res.Request.Context().Value(common.ChartUploadCtxKey)
|
||||
e, ok := chartUploadEvent.(*rep_event.Event)
|
||||
if !ok {
|
||||
hlog.Error("failed to convert chart upload context into replication event.")
|
||||
} else {
|
||||
// Todo: it used as the replacement of webhook, will be removed when webhook to be introduced.
|
||||
go func() {
|
||||
if err := replication.EventHandler.Handle(e); err != nil {
|
||||
hlog.Errorf("failed to handle event: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Accept cases
|
||||
|
@ -139,5 +139,5 @@ const (
|
||||
|
||||
OIDCCallbackPath = "/c/oidc/callback"
|
||||
|
||||
ChartUploadCtxKey = contextKey("chart_upload")
|
||||
ChartUploadCtxKey = contextKey("chart_upload_event")
|
||||
)
|
||||
|
@ -19,6 +19,8 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
hlog "github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
rep_event "github.com/goharbor/harbor/src/replication/event"
|
||||
"github.com/goharbor/harbor/src/replication/model"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -296,30 +298,13 @@ func (cra *ChartRepositoryAPI) UploadChartVersion() {
|
||||
cra.SendInternalServerError(err)
|
||||
return
|
||||
}
|
||||
if err := cra.addEventContext(formFiles, cra.Ctx.Request); err != nil {
|
||||
hlog.Errorf("Failed to add chart upload context, %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 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, req)
|
||||
chartController.ProxyTraffic(cra.Ctx.ResponseWriter, cra.Ctx.Request)
|
||||
}
|
||||
|
||||
// UploadChartProvFile handles POST /api/:repo/prov
|
||||
@ -428,6 +413,53 @@ type formFile struct {
|
||||
mustHave bool
|
||||
}
|
||||
|
||||
// The func is for event based chart replication policy.
|
||||
// It will add a context for uploading request with key chart_upload, and consumed by upload response.
|
||||
func (cra *ChartRepositoryAPI) addEventContext(files []formFile, request *http.Request) error {
|
||||
if len(files) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if f.formField == formFieldNameForChart {
|
||||
mFile, _, err := cra.GetFile(f.formField)
|
||||
if err != nil {
|
||||
hlog.Errorf("failed to read file content for upload event, %v", err)
|
||||
return err
|
||||
}
|
||||
var Buf bytes.Buffer
|
||||
_, err = io.Copy(&Buf, mFile)
|
||||
if err != nil {
|
||||
hlog.Errorf("failed to copy file content for upload event, %v", err)
|
||||
return err
|
||||
}
|
||||
chartOpr := chartserver.ChartOperator{}
|
||||
chartDetails, err := chartOpr.GetChartData(Buf.Bytes())
|
||||
if err != nil {
|
||||
hlog.Errorf("failed to get chart content for upload event, %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
e := &rep_event.Event{
|
||||
Type: rep_event.EventTypeChartUpload,
|
||||
Resource: &model.Resource{
|
||||
Type: model.ResourceTypeChart,
|
||||
Metadata: &model.ResourceMetadata{
|
||||
Repository: &model.Repository{
|
||||
Name: fmt.Sprintf("%s/%s", cra.namespace, chartDetails.Metadata.Name),
|
||||
},
|
||||
Vtags: []string{chartDetails.Metadata.Version},
|
||||
},
|
||||
},
|
||||
}
|
||||
*request = *(request.WithContext(context.WithValue(request.Context(), common.ChartUploadCtxKey, e)))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// If the files are uploaded with multipart/form-data mimetype, beego will extract the data
|
||||
// from the request automatically. Then the request passed to the backend server with proxying
|
||||
// way will have empty content.
|
||||
@ -449,6 +481,7 @@ func (cra *ChartRepositoryAPI) rewriteFileContent(files []formFile, request *htt
|
||||
// Process files by key one by one
|
||||
for _, f := range files {
|
||||
mFile, mHeader, err := cra.GetFile(f.formField)
|
||||
|
||||
// Handle error case by case
|
||||
if err != nil {
|
||||
formatedErr := fmt.Errorf("Get file content with multipart header from key '%s' failed with error: %s", f.formField, err.Error())
|
||||
@ -470,6 +503,7 @@ func (cra *ChartRepositoryAPI) rewriteFileContent(files []formFile, request *htt
|
||||
if err != nil {
|
||||
return fmt.Errorf("Copy file stream in multipart form data failed with error: %s", err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
request.Header.Set(headerContentType, w.FormDataContentType())
|
||||
|
Loading…
Reference in New Issue
Block a user