Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-06-30 18:08:27 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-06-30 18:08:27 +0300
commit9376fdc13edb5fb822431df943fa088b6a273316 (patch)
treef12ac6debd2c3efc59f1629062628f40996e752f /workhorse/internal/api
parent7c28a677895df5195ed6342921934734646c90c9 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'workhorse/internal/api')
-rw-r--r--workhorse/internal/api/api.go46
-rw-r--r--workhorse/internal/api/api_test.go74
2 files changed, 120 insertions, 0 deletions
diff --git a/workhorse/internal/api/api.go b/workhorse/internal/api/api.go
index 5dae6eb01bb..db1c4cbbc27 100644
--- a/workhorse/internal/api/api.go
+++ b/workhorse/internal/api/api.go
@@ -3,6 +3,7 @@ package api
import (
"bytes"
"encoding/json"
+ "errors"
"fmt"
"io"
"net/http"
@@ -29,6 +30,8 @@ const (
ResponseContentType = "application/vnd.gitlab-workhorse+json"
failureResponseLimit = 32768
+
+ geoProxyEndpointPath = "/api/v4/geo/proxy"
)
type API struct {
@@ -37,6 +40,8 @@ type API struct {
Version string
}
+var ErrNotGeoSecondary = errors.New("this is not a Geo secondary site")
+
var (
requestsCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
@@ -61,6 +66,10 @@ func NewAPI(myURL *url.URL, version string, roundTripper http.RoundTripper) *API
}
}
+type GeoProxyEndpointResponse struct {
+ GeoProxyURL string `json:"geo_proxy_url"`
+}
+
type HandleFunc func(http.ResponseWriter, *http.Request, *Response)
type MultipartUploadParams struct {
@@ -389,3 +398,40 @@ func bufferResponse(r io.Reader) (*bytes.Buffer, error) {
func validResponseContentType(resp *http.Response) bool {
return helper.IsContentType(ResponseContentType, resp.Header.Get("Content-Type"))
}
+
+// TODO: Cache the result of the API requests https://gitlab.com/gitlab-org/gitlab/-/issues/329671
+func (api *API) GetGeoProxyURL() (*url.URL, error) {
+ geoProxyApiUrl := *api.URL
+ geoProxyApiUrl.Path, geoProxyApiUrl.RawPath = joinURLPath(api.URL, geoProxyEndpointPath)
+ geoProxyApiReq := &http.Request{
+ Method: "GET",
+ URL: &geoProxyApiUrl,
+ Header: make(http.Header),
+ }
+
+ httpResponse, err := api.doRequestWithoutRedirects(geoProxyApiReq)
+ if err != nil {
+ return nil, fmt.Errorf("GetGeoProxyURL: do request: %v", err)
+ }
+ defer httpResponse.Body.Close()
+
+ if httpResponse.StatusCode != http.StatusOK {
+ return nil, fmt.Errorf("GetGeoProxyURL: Received HTTP status code: %v", httpResponse.StatusCode)
+ }
+
+ response := &GeoProxyEndpointResponse{}
+ if err := json.NewDecoder(httpResponse.Body).Decode(response); err != nil {
+ return nil, fmt.Errorf("GetGeoProxyURL: decode response: %v", err)
+ }
+
+ if response.GeoProxyURL == "" {
+ return nil, ErrNotGeoSecondary
+ }
+
+ geoProxyURL, err := url.Parse(response.GeoProxyURL)
+ if err != nil {
+ return nil, fmt.Errorf("GetGeoProxyURL: Could not parse Geo proxy URL: %v, err: %v", response.GeoProxyURL, err)
+ }
+
+ return geoProxyURL, nil
+}
diff --git a/workhorse/internal/api/api_test.go b/workhorse/internal/api/api_test.go
new file mode 100644
index 00000000000..5ab677c4233
--- /dev/null
+++ b/workhorse/internal/api/api_test.go
@@ -0,0 +1,74 @@
+package api
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "regexp"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/labkit/log"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/secret"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/upstream/roundtripper"
+)
+
+func TestGetGeoProxyURLWhenGeoSecondary(t *testing.T) {
+ geoProxyURL, err := getGeoProxyURLGivenResponse(t, `{"geo_proxy_url":"http://primary"}`)
+
+ require.NoError(t, err)
+ require.NotNil(t, geoProxyURL)
+ require.Equal(t, "http://primary", geoProxyURL.String())
+}
+
+func TestGetGeoProxyURLWhenGeoPrimaryOrNonGeo(t *testing.T) {
+ geoProxyURL, err := getGeoProxyURLGivenResponse(t, "{}")
+
+ require.Error(t, err)
+ require.Equal(t, ErrNotGeoSecondary, err)
+ require.Nil(t, geoProxyURL)
+}
+
+func getGeoProxyURLGivenResponse(t *testing.T, givenInternalApiResponse string) (*url.URL, error) {
+ t.Helper()
+ ts := testRailsServer(regexp.MustCompile(`/api/v4/geo/proxy`), 200, givenInternalApiResponse)
+ defer ts.Close()
+ backend := helper.URLMustParse(ts.URL)
+ version := "123"
+ rt := roundtripper.NewTestBackendRoundTripper(backend)
+ testhelper.ConfigureSecret()
+
+ apiClient := NewAPI(backend, version, rt)
+
+ geoProxyURL, err := apiClient.GetGeoProxyURL()
+
+ return geoProxyURL, err
+}
+
+func testRailsServer(url *regexp.Regexp, code int, body string) *httptest.Server {
+ return testhelper.TestServerWithHandler(url, func(w http.ResponseWriter, r *http.Request) {
+ // return a 204 No Content response if we don't receive the JWT header
+ if r.Header.Get(secret.RequestHeader) == "" {
+ w.WriteHeader(204)
+ return
+ }
+
+ w.Header().Set("Content-Type", ResponseContentType)
+
+ logEntry := log.WithFields(log.Fields{
+ "method": r.Method,
+ "url": r.URL,
+ })
+ logEntryWithCode := logEntry.WithField("code", code)
+
+ // Write pure string
+ logEntryWithCode.Info("UPSTREAM")
+
+ w.WriteHeader(code)
+ fmt.Fprint(w, body)
+ })
+}