mirror of
https://github.com/goharbor/harbor.git
synced 2024-09-30 22:37:43 +02:00
Merge pull request #5242 from steven-zou/chart_repo_supporting
Implement the related handler methods of the transparent operations
This commit is contained in:
commit
e1474ac50b
@ -2,15 +2,16 @@ package chartserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//BaseHandler defines the handlers related with the chart server itself.
|
//BaseHandler defines the handlers related with the chart server itself.
|
||||||
type BaseHandler struct {
|
type BaseHandler struct {
|
||||||
//Proxy used to to transfer the traffic of requests
|
//Proxy used to to transfer the traffic of requests
|
||||||
//It's mainly used to talk to the backend chart server
|
//It's mainly used to talk to the backend chart server
|
||||||
trafficProxy *httputil.ReverseProxy
|
trafficProxy *ProxyEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetHealthStatus will return the health status of the backend chart repository server
|
//GetHealthStatus will return the health status of the backend chart repository server
|
||||||
func (bh *BaseHandler) GetHealthStatus(w http.ResponseWriter, req *http.Request) {}
|
func (bh *BaseHandler) GetHealthStatus(w http.ResponseWriter, req *http.Request) {
|
||||||
|
bh.trafficProxy.ServeHTTP(w, req)
|
||||||
|
}
|
||||||
|
@ -2,7 +2,6 @@ package chartserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/http/httputil"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,8 +28,8 @@ func NewController(backendServer *url.URL) (*Controller, error) {
|
|||||||
return nil, errors.New("failed to create chartserver.Controller: backend sever address is required")
|
return nil, errors.New("failed to create chartserver.Controller: backend sever address is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
//Currently, no customization requirements needed, so let's use the simple proxy here now
|
//Use customized reverse proxy
|
||||||
proxy := httputil.NewSingleHostReverseProxy(backendServer)
|
proxy := NewProxyEngine(backendServer)
|
||||||
|
|
||||||
//Initialize chart operator for use
|
//Initialize chart operator for use
|
||||||
operator := &ChartOperator{}
|
operator := &ChartOperator{}
|
||||||
|
@ -2,7 +2,6 @@ package chartserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//ManipulationHandler includes all the handler methods for the purpose of manipulating the
|
//ManipulationHandler includes all the handler methods for the purpose of manipulating the
|
||||||
@ -10,28 +9,41 @@ import (
|
|||||||
type ManipulationHandler struct {
|
type ManipulationHandler struct {
|
||||||
//Proxy used to to transfer the traffic of requests
|
//Proxy used to to transfer the traffic of requests
|
||||||
//It's mainly used to talk to the backend chart server
|
//It's mainly used to talk to the backend chart server
|
||||||
trafficProxy *httputil.ReverseProxy
|
trafficProxy *ProxyEngine
|
||||||
|
|
||||||
//Parse and process the chart version to provide required info data
|
//Parse and process the chart version to provide required info data
|
||||||
chartOperator *ChartOperator
|
chartOperator *ChartOperator
|
||||||
}
|
}
|
||||||
|
|
||||||
//ListCharts lists all the charts under the specified namespace
|
//ListCharts lists all the charts under the specified namespace
|
||||||
func (mh *ManipulationHandler) ListCharts(w http.ResponseWriter, req *http.Request) {}
|
func (mh *ManipulationHandler) ListCharts(w http.ResponseWriter, req *http.Request) {
|
||||||
|
mh.trafficProxy.ServeHTTP(w, req)
|
||||||
|
}
|
||||||
|
|
||||||
//GetChart returns all the chart versions under the specified chart
|
//GetChart returns all the chart versions under the specified chart
|
||||||
func (mh *ManipulationHandler) GetChart(w http.ResponseWriter, req *http.Request) {}
|
func (mh *ManipulationHandler) GetChart(w http.ResponseWriter, req *http.Request) {
|
||||||
|
mh.trafficProxy.ServeHTTP(w, req)
|
||||||
|
}
|
||||||
|
|
||||||
//GetChartVersion get the specified version for one chart
|
//GetChartVersion get the specified version for one chart
|
||||||
//This handler should return the details of the chart version,
|
//This handler should return the details of the chart version,
|
||||||
//maybe including metadata,dependencies and values etc.
|
//maybe including metadata,dependencies and values etc.
|
||||||
func (mh *ManipulationHandler) GetChartVersion(w http.ResponseWriter, req *http.Request) {}
|
func (mh *ManipulationHandler) GetChartVersion(w http.ResponseWriter, req *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusNotImplemented)
|
||||||
|
w.Write([]byte("not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
//UploadChartVersion will save the new version of the chart to the backend storage
|
//UploadChartVersion will save the new version of the chart to the backend storage
|
||||||
func (mh *ManipulationHandler) UploadChartVersion(w http.ResponseWriter, req *http.Request) {}
|
func (mh *ManipulationHandler) UploadChartVersion(w http.ResponseWriter, req *http.Request) {
|
||||||
|
mh.trafficProxy.ServeHTTP(w, req)
|
||||||
|
}
|
||||||
|
|
||||||
//UploadProvenanceFile will save the provenance file of the chart to the backend storage
|
//UploadProvenanceFile will save the provenance file of the chart to the backend storage
|
||||||
func (mh *ManipulationHandler) UploadProvenanceFile(w http.ResponseWriter, req *http.Request) {}
|
func (mh *ManipulationHandler) UploadProvenanceFile(w http.ResponseWriter, req *http.Request) {
|
||||||
|
mh.trafficProxy.ServeHTTP(w, req)
|
||||||
|
}
|
||||||
|
|
||||||
//DeleteChartVersion will delete the specified version of the chart
|
//DeleteChartVersion will delete the specified version of the chart
|
||||||
func (mh *ManipulationHandler) DeleteChartVersion(w http.ResponseWriter, req *http.Request) {}
|
func (mh *ManipulationHandler) DeleteChartVersion(w http.ResponseWriter, req *http.Request) {
|
||||||
|
mh.trafficProxy.ServeHTTP(w, req)
|
||||||
|
}
|
||||||
|
@ -2,7 +2,6 @@ package chartserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//RepositoryHandler defines all the handlers to handle the requests related with chart repository
|
//RepositoryHandler defines all the handlers to handle the requests related with chart repository
|
||||||
@ -10,18 +9,24 @@ import (
|
|||||||
type RepositoryHandler struct {
|
type RepositoryHandler struct {
|
||||||
//Proxy used to to transfer the traffic of requests
|
//Proxy used to to transfer the traffic of requests
|
||||||
//It's mainly used to talk to the backend chart server
|
//It's mainly used to talk to the backend chart server
|
||||||
trafficProxy *httputil.ReverseProxy
|
trafficProxy *ProxyEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetIndexFileWithNS will read the index.yaml data under the specified namespace
|
//GetIndexFileWithNS will read the index.yaml data under the specified namespace
|
||||||
func (rh *RepositoryHandler) GetIndexFileWithNS(w http.ResponseWriter, req *http.Request) {
|
func (rh *RepositoryHandler) GetIndexFileWithNS(w http.ResponseWriter, req *http.Request) {
|
||||||
|
rh.trafficProxy.ServeHTTP(w, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetIndexFile will read the index.yaml under all namespaces and merge them as a single one
|
//GetIndexFile will read the index.yaml under all namespaces and merge them as a single one
|
||||||
//Please be aware that, to support this function, the backend chart repository server should
|
//Please be aware that, to support this function, the backend chart repository server should
|
||||||
//enable multi-tenancies
|
//enable multi-tenancies
|
||||||
func (rh *RepositoryHandler) GetIndexFile(w http.ResponseWriter, req *http.Request) {}
|
func (rh *RepositoryHandler) GetIndexFile(w http.ResponseWriter, req *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusNotImplemented)
|
||||||
|
w.Write([]byte("not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
//DownloadChartObject will download the stored chart object to the client
|
//DownloadChartObject will download the stored chart object to the client
|
||||||
//e.g: helm install
|
//e.g: helm install
|
||||||
func (rh *RepositoryHandler) DownloadChartObject(w http.ResponseWriter, req *http.Request) {}
|
func (rh *RepositoryHandler) DownloadChartObject(w http.ResponseWriter, req *http.Request) {
|
||||||
|
rh.trafficProxy.ServeHTTP(w, req)
|
||||||
|
}
|
||||||
|
115
src/chartserver/reverse_proxy.go
Normal file
115
src/chartserver/reverse_proxy.go
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
package chartserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
userName = "chart_controller"
|
||||||
|
passwordKey = "UI_SECRET"
|
||||||
|
agentHarbor = "HARBOR"
|
||||||
|
authHeader = "Authorization"
|
||||||
|
contentLengthHeader = "Content-Length"
|
||||||
|
)
|
||||||
|
|
||||||
|
//ProxyEngine is used to proxy the related traffics
|
||||||
|
type ProxyEngine struct {
|
||||||
|
//The backend target server the traffic will be forwarded to
|
||||||
|
//Just in case we'll use it
|
||||||
|
backend *url.URL
|
||||||
|
|
||||||
|
//Use go reverse proxy as engine
|
||||||
|
engine *httputil.ReverseProxy
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewProxyEngine is constructor of NewProxyEngine
|
||||||
|
func NewProxyEngine(target *url.URL) *ProxyEngine {
|
||||||
|
return &ProxyEngine{
|
||||||
|
backend: target,
|
||||||
|
engine: &httputil.ReverseProxy{
|
||||||
|
ErrorLog: log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile),
|
||||||
|
Director: func(req *http.Request) {
|
||||||
|
director(target, req)
|
||||||
|
},
|
||||||
|
ModifyResponse: modifyResponse,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//ServeHTTP serves the incoming http requests
|
||||||
|
func (pe *ProxyEngine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
pe.engine.ServeHTTP(w, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Overwrite the http requests
|
||||||
|
func director(target *url.URL, req *http.Request) {
|
||||||
|
targetQuery := target.RawQuery
|
||||||
|
|
||||||
|
//Overwrite the request URL to the target path
|
||||||
|
req.URL.Scheme = target.Scheme
|
||||||
|
req.URL.Host = target.Host
|
||||||
|
req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
|
||||||
|
if targetQuery == "" || req.URL.RawQuery == "" {
|
||||||
|
req.URL.RawQuery = targetQuery + req.URL.RawQuery
|
||||||
|
} else {
|
||||||
|
req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
|
||||||
|
}
|
||||||
|
if _, ok := req.Header["User-Agent"]; !ok {
|
||||||
|
req.Header.Set("User-Agent", agentHarbor)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the password from the env
|
||||||
|
//Ignore the empty checking, the backend server should return the right status code
|
||||||
|
//with invalid credential
|
||||||
|
password := os.Getenv(passwordKey)
|
||||||
|
|
||||||
|
//Add authentication header
|
||||||
|
req.SetBasicAuth(userName, password)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Modify the http response
|
||||||
|
func modifyResponse(res *http.Response) error {
|
||||||
|
//Detect the 401 code, if it is,
|
||||||
|
//overwrite it to 500.
|
||||||
|
//We also re-write the error content
|
||||||
|
if res.StatusCode == http.StatusUnauthorized {
|
||||||
|
errorObj := make(map[string]string)
|
||||||
|
errorObj["error"] = "operation request from unauthentic source is rejected"
|
||||||
|
content, err := json.Marshal(errorObj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
size := len(content)
|
||||||
|
body := ioutil.NopCloser(bytes.NewReader(content))
|
||||||
|
res.Body = body
|
||||||
|
res.ContentLength = int64(size)
|
||||||
|
res.Header.Set(contentLengthHeader, strconv.Itoa(size))
|
||||||
|
res.StatusCode = http.StatusInternalServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//Join the path
|
||||||
|
//Copy from the go reverse proxy
|
||||||
|
func singleJoiningSlash(a, b string) string {
|
||||||
|
aslash := strings.HasSuffix(a, "/")
|
||||||
|
bslash := strings.HasPrefix(b, "/")
|
||||||
|
switch {
|
||||||
|
case aslash && bslash:
|
||||||
|
return a + b[1:]
|
||||||
|
case !aslash && !bslash:
|
||||||
|
return a + "/" + b
|
||||||
|
}
|
||||||
|
return a + b
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user