2018-07-02 13:34:04 +02:00
|
|
|
package chartserver
|
|
|
|
|
|
|
|
import (
|
2018-07-06 14:53:13 +02:00
|
|
|
"encoding/json"
|
2018-07-12 07:43:49 +02:00
|
|
|
"errors"
|
2018-07-06 14:53:13 +02:00
|
|
|
"fmt"
|
2018-07-02 13:34:04 +02:00
|
|
|
"net/http"
|
2018-07-06 14:53:13 +02:00
|
|
|
"net/url"
|
2018-07-14 09:49:38 +02:00
|
|
|
"path"
|
2018-07-06 14:53:13 +02:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/ghodss/yaml"
|
2018-07-08 05:17:55 +02:00
|
|
|
hlog "github.com/vmware/harbor/src/common/utils/log"
|
2018-07-06 14:53:13 +02:00
|
|
|
helm_repo "k8s.io/helm/pkg/repo"
|
2018-07-02 13:34:04 +02:00
|
|
|
)
|
|
|
|
|
2018-07-12 07:43:49 +02:00
|
|
|
const (
|
|
|
|
//NamespaceContextKey is context key for the namespace
|
|
|
|
NamespaceContextKey ContextKey = ":repo"
|
|
|
|
)
|
|
|
|
|
|
|
|
//ContextKey is defined for add value in the context of http request
|
|
|
|
type ContextKey string
|
|
|
|
|
2018-07-02 13:34:04 +02:00
|
|
|
//ManipulationHandler includes all the handler methods for the purpose of manipulating the
|
|
|
|
//chart repository
|
|
|
|
type ManipulationHandler struct {
|
|
|
|
//Proxy used to to transfer the traffic of requests
|
|
|
|
//It's mainly used to talk to the backend chart server
|
2018-07-03 15:36:20 +02:00
|
|
|
trafficProxy *ProxyEngine
|
2018-07-02 13:34:04 +02:00
|
|
|
|
|
|
|
//Parse and process the chart version to provide required info data
|
|
|
|
chartOperator *ChartOperator
|
2018-07-06 14:53:13 +02:00
|
|
|
|
|
|
|
//HTTP client used to call the realted APIs of the backend chart repositories
|
|
|
|
apiClient *ChartClient
|
|
|
|
|
|
|
|
//Point to the url of the backend server
|
|
|
|
backendServerAddress *url.URL
|
2018-07-08 05:17:55 +02:00
|
|
|
|
|
|
|
//Cache the chart data
|
|
|
|
chartCache *ChartCache
|
2018-07-02 13:34:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//ListCharts lists all the charts under the specified namespace
|
2018-07-03 15:36:20 +02:00
|
|
|
func (mh *ManipulationHandler) ListCharts(w http.ResponseWriter, req *http.Request) {
|
2018-07-14 09:49:38 +02:00
|
|
|
url := strings.TrimPrefix(req.URL.String(), "/")
|
|
|
|
url = fmt.Sprintf("%s/%s", mh.backendServerAddress.String(), url)
|
2018-07-06 14:53:13 +02:00
|
|
|
|
2018-07-14 09:49:38 +02:00
|
|
|
content, err := mh.apiClient.GetContent(url)
|
2018-07-06 14:53:13 +02:00
|
|
|
if err != nil {
|
2018-07-23 11:41:40 +02:00
|
|
|
WriteInternalError(w, err)
|
2018-07-06 14:53:13 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
chartList, err := mh.chartOperator.GetChartList(content)
|
|
|
|
if err != nil {
|
2018-07-23 11:41:40 +02:00
|
|
|
WriteInternalError(w, err)
|
2018-07-06 14:53:13 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
jsonData, err := json.Marshal(chartList)
|
|
|
|
if err != nil {
|
2018-07-23 11:41:40 +02:00
|
|
|
WriteInternalError(w, err)
|
2018-07-06 14:53:13 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
writeJSONData(w, jsonData)
|
2018-07-03 15:36:20 +02:00
|
|
|
}
|
2018-07-02 13:34:04 +02:00
|
|
|
|
|
|
|
//GetChart returns all the chart versions under the specified chart
|
2018-07-03 15:36:20 +02:00
|
|
|
func (mh *ManipulationHandler) GetChart(w http.ResponseWriter, req *http.Request) {
|
|
|
|
mh.trafficProxy.ServeHTTP(w, req)
|
|
|
|
}
|
2018-07-02 13:34:04 +02:00
|
|
|
|
|
|
|
//GetChartVersion get the specified version for one chart
|
|
|
|
//This handler should return the details of the chart version,
|
|
|
|
//maybe including metadata,dependencies and values etc.
|
2018-07-03 15:36:20 +02:00
|
|
|
func (mh *ManipulationHandler) GetChartVersion(w http.ResponseWriter, req *http.Request) {
|
2018-07-14 09:49:38 +02:00
|
|
|
chartV, err := mh.getChartVersion(req.URL.String())
|
2018-07-06 14:53:13 +02:00
|
|
|
if err != nil {
|
2018-07-23 11:41:40 +02:00
|
|
|
WriteInternalError(w, err)
|
2018-07-06 14:53:13 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-07-08 05:17:55 +02:00
|
|
|
//Query cache
|
|
|
|
chartDetails := mh.chartCache.GetChart(chartV.Digest)
|
|
|
|
if chartDetails == nil {
|
|
|
|
//NOT hit!!
|
2018-07-12 07:43:49 +02:00
|
|
|
var namespace string
|
|
|
|
|
|
|
|
repoValue := req.Context().Value(NamespaceContextKey)
|
|
|
|
if repoValue != nil {
|
|
|
|
if ns, ok := repoValue.(string); ok {
|
|
|
|
namespace = ns
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(strings.TrimSpace(namespace)) == 0 {
|
2018-07-23 11:41:40 +02:00
|
|
|
WriteInternalError(w, errors.New("failed to extract namespace from the request"))
|
2018-07-12 07:43:49 +02:00
|
|
|
return
|
|
|
|
}
|
2018-07-08 05:17:55 +02:00
|
|
|
|
|
|
|
content, err := mh.getChartVersionContent(namespace, chartV.URLs[0])
|
|
|
|
if err != nil {
|
2018-07-23 11:41:40 +02:00
|
|
|
WriteInternalError(w, err)
|
2018-07-08 05:17:55 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
//Process bytes and get more details of chart version
|
|
|
|
chartDetails, err = mh.chartOperator.GetChartDetails(content)
|
|
|
|
if err != nil {
|
2018-07-23 11:41:40 +02:00
|
|
|
WriteInternalError(w, err)
|
2018-07-08 05:17:55 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
chartDetails.Metadata = chartV
|
|
|
|
|
|
|
|
//Put it into the cache for next access
|
|
|
|
mh.chartCache.PutChart(chartDetails)
|
|
|
|
} else {
|
|
|
|
//Just logged
|
|
|
|
hlog.Debugf("Get detailed data from cache for chart: %s:%s (%s)",
|
|
|
|
chartDetails.Metadata.Name,
|
|
|
|
chartDetails.Metadata.Version,
|
|
|
|
chartDetails.Metadata.Digest)
|
2018-07-06 14:53:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bytes, err := json.Marshal(chartDetails)
|
|
|
|
if err != nil {
|
2018-07-23 11:41:40 +02:00
|
|
|
WriteInternalError(w, err)
|
2018-07-06 14:53:13 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
writeJSONData(w, bytes)
|
2018-07-03 15:36:20 +02:00
|
|
|
}
|
2018-07-02 13:34:04 +02:00
|
|
|
|
|
|
|
//UploadChartVersion will save the new version of the chart to the backend storage
|
2018-07-03 15:36:20 +02:00
|
|
|
func (mh *ManipulationHandler) UploadChartVersion(w http.ResponseWriter, req *http.Request) {
|
|
|
|
mh.trafficProxy.ServeHTTP(w, req)
|
|
|
|
}
|
2018-07-02 13:34:04 +02:00
|
|
|
|
|
|
|
//UploadProvenanceFile will save the provenance file of the chart to the backend storage
|
2018-07-03 15:36:20 +02:00
|
|
|
func (mh *ManipulationHandler) UploadProvenanceFile(w http.ResponseWriter, req *http.Request) {
|
|
|
|
mh.trafficProxy.ServeHTTP(w, req)
|
|
|
|
}
|
2018-07-02 13:34:04 +02:00
|
|
|
|
|
|
|
//DeleteChartVersion will delete the specified version of the chart
|
2018-07-03 15:36:20 +02:00
|
|
|
func (mh *ManipulationHandler) DeleteChartVersion(w http.ResponseWriter, req *http.Request) {
|
|
|
|
mh.trafficProxy.ServeHTTP(w, req)
|
|
|
|
}
|
2018-07-06 14:53:13 +02:00
|
|
|
|
|
|
|
//Get the basic metadata of chart version
|
2018-07-14 09:49:38 +02:00
|
|
|
func (mh *ManipulationHandler) getChartVersion(subPath string) (*helm_repo.ChartVersion, error) {
|
|
|
|
url := fmt.Sprintf("%s/%s", mh.backendServerAddress.String(), strings.TrimPrefix(subPath, "/"))
|
2018-07-06 14:53:13 +02:00
|
|
|
|
2018-07-14 09:49:38 +02:00
|
|
|
content, err := mh.apiClient.GetContent(url)
|
2018-07-06 14:53:13 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
chartVersion := &helm_repo.ChartVersion{}
|
|
|
|
if err := yaml.Unmarshal(content, chartVersion); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return chartVersion, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//Get the content bytes of the chart version
|
2018-07-14 09:49:38 +02:00
|
|
|
func (mh *ManipulationHandler) getChartVersionContent(namespace string, subPath string) ([]byte, error) {
|
|
|
|
url := path.Join(namespace, subPath)
|
|
|
|
url = fmt.Sprintf("%s/%s", mh.backendServerAddress.String(), url)
|
2018-07-06 14:53:13 +02:00
|
|
|
|
2018-07-14 09:49:38 +02:00
|
|
|
return mh.apiClient.GetContent(url)
|
2018-07-06 14:53:13 +02:00
|
|
|
}
|