diff options
author | feistel <6742251-feistel@users.noreply.gitlab.com> | 2021-05-20 22:04:58 +0300 |
---|---|---|
committer | feistel <6742251-feistel@users.noreply.gitlab.com> | 2021-05-20 22:04:58 +0300 |
commit | 4bfd134cde3aa29610454f83b24421b618ea083b (patch) | |
tree | eabd887c1895edc80bc3d25914ca39691e11df67 /internal/serving | |
parent | 64a0f90dfbe5d255b1fb7df0aa481575037694a1 (diff) |
Remove serverless code from Pages
Diffstat (limited to 'internal/serving')
-rw-r--r-- | internal/serving/serverless/certs.go | 26 | ||||
-rw-r--r-- | internal/serving/serverless/cluster.go | 28 | ||||
-rw-r--r-- | internal/serving/serverless/director.go | 20 | ||||
-rw-r--r-- | internal/serving/serverless/errors.go | 26 | ||||
-rw-r--r-- | internal/serving/serverless/serverless.go | 73 | ||||
-rw-r--r-- | internal/serving/serverless/serverless_test.go | 165 | ||||
-rw-r--r-- | internal/serving/serverless/transport.go | 51 |
7 files changed, 0 insertions, 389 deletions
diff --git a/internal/serving/serverless/certs.go b/internal/serving/serverless/certs.go deleted file mode 100644 index 674e8b25..00000000 --- a/internal/serving/serverless/certs.go +++ /dev/null @@ -1,26 +0,0 @@ -package serverless - -import ( - "crypto/tls" - "crypto/x509" -) - -// Certs holds definition of certificates we use to perform mTLS -// handshake with a cluster -type Certs struct { - RootCerts *x509.CertPool - Certificate tls.Certificate -} - -// NewClusterCerts creates a new cluster configuration from cert / key pair -func NewClusterCerts(clientCert, clientKey string) (*Certs, error) { - cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey)) - if err != nil { - return nil, err - } - - caCertPool := x509.NewCertPool() - caCertPool.AppendCertsFromPEM([]byte(clientCert)) - - return &Certs{RootCerts: caCertPool, Certificate: cert}, nil -} diff --git a/internal/serving/serverless/cluster.go b/internal/serving/serverless/cluster.go deleted file mode 100644 index 6bdd51da..00000000 --- a/internal/serving/serverless/cluster.go +++ /dev/null @@ -1,28 +0,0 @@ -package serverless - -import ( - "crypto/tls" - "strings" -) - -// Cluster represent a Knative cluster that we want to proxy requests to -type Cluster struct { - Address string // Address is a real IP address of a cluster ingress - Port string // Port is a real port of HTTP TLS service - Name string // Name is a cluster name, used in cluster certificates - Certs *Certs -} - -// Host returns a real cluster location based on IP address and port -func (c Cluster) Host() string { - return strings.Join([]string{c.Address, c.Port}, ":") -} - -// TLSConfig builds a new tls.Config and returns a pointer to it -func (c Cluster) TLSConfig() *tls.Config { - return &tls.Config{ - Certificates: []tls.Certificate{c.Certs.Certificate}, - RootCAs: c.Certs.RootCerts, - ServerName: c.Name, - } -} diff --git a/internal/serving/serverless/director.go b/internal/serving/serverless/director.go deleted file mode 100644 index 3f1bc99a..00000000 --- a/internal/serving/serverless/director.go +++ /dev/null @@ -1,20 +0,0 @@ -package serverless - -import ( - "net/http" - - "github.com/tomasen/realip" -) - -// NewDirectorFunc returns a director function capable of configuring a proxy -// request -func NewDirectorFunc(service string) func(*http.Request) { - return func(request *http.Request) { - request.Host = service - request.URL.Host = service - request.URL.Scheme = "https" - request.Header.Set("User-Agent", "GitLab Pages Daemon") - request.Header.Set("X-Forwarded-For", realip.FromRequest(request)) - request.Header.Set("X-Forwarded-Proto", "https") - } -} diff --git a/internal/serving/serverless/errors.go b/internal/serving/serverless/errors.go deleted file mode 100644 index d208a11d..00000000 --- a/internal/serving/serverless/errors.go +++ /dev/null @@ -1,26 +0,0 @@ -package serverless - -import ( - "encoding/json" - "net/http" -) - -// NewErrorHandler returns a func(http.ResponseWriter, *http.Request, error) -// responsible for handling proxy errors -func NewErrorHandler() func(http.ResponseWriter, *http.Request, error) { - return func(w http.ResponseWriter, r *http.Request, err error) { - w.WriteHeader(http.StatusInternalServerError) - - message := "cluster error: " + err.Error() - msgmap := map[string]string{"error": message} - - json, err := json.Marshal(msgmap) - if err != nil { - w.Write([]byte(message)) - return - } - - w.Header().Set("Content-Type", "application/json") - w.Write(json) - } -} diff --git a/internal/serving/serverless/serverless.go b/internal/serving/serverless/serverless.go deleted file mode 100644 index f8bd4e87..00000000 --- a/internal/serving/serverless/serverless.go +++ /dev/null @@ -1,73 +0,0 @@ -package serverless - -import ( - "errors" - "net/http/httputil" - - "gitlab.com/gitlab-org/gitlab-pages/internal/config" - "gitlab.com/gitlab-org/gitlab-pages/internal/httperrors" - "gitlab.com/gitlab-org/gitlab-pages/internal/serving" - "gitlab.com/gitlab-org/gitlab-pages/internal/source/gitlab/api" - "gitlab.com/gitlab-org/gitlab-pages/metrics" -) - -// Serverless is a servering used to proxy requests between a client and -// Knative cluster. -type Serverless struct { - proxy *httputil.ReverseProxy -} - -// NewFromAPISource returns a serverless serving instance built from GitLab API -// response -func NewFromAPISource(config api.Serverless) (serving.Serving, error) { - if len(config.Service) == 0 { - return nil, errors.New("incomplete serverless serving config") - } - - certs, err := NewClusterCerts( - config.Cluster.CertificateCert, - config.Cluster.CertificateKey, - ) - if err != nil { - return nil, err - } - - cluster := Cluster{ - Name: config.Cluster.Hostname, - Address: config.Cluster.Address, - Port: config.Cluster.Port, - Certs: certs, - } - - return New(config.Service, cluster), nil -} - -// New returns a new serving instance -func New(service string, cluster Cluster) serving.Serving { - proxy := httputil.ReverseProxy{ - Director: NewDirectorFunc(service), - Transport: NewTransport(cluster), - ErrorHandler: NewErrorHandler(), - } - - return &Serverless{proxy: &proxy} -} - -// ServeFileHTTP handle an incoming request and proxies it to Knative cluster -func (s *Serverless) ServeFileHTTP(h serving.Handler) bool { - metrics.ServerlessRequests.Inc() - - s.proxy.ServeHTTP(h.Writer, h.Request) - - return true -} - -// ServeNotFoundHTTP responds with 404 -func (s *Serverless) ServeNotFoundHTTP(h serving.Handler) { - httperrors.Serve404(h.Writer) -} - -// Reconfigure noop -func (s *Serverless) Reconfigure(*config.Config) error { - return nil -} diff --git a/internal/serving/serverless/serverless_test.go b/internal/serving/serverless/serverless_test.go deleted file mode 100644 index ebd14343..00000000 --- a/internal/serving/serverless/serverless_test.go +++ /dev/null @@ -1,165 +0,0 @@ -package serverless - -import ( - "crypto/tls" - "io/ioutil" - "net/http" - "net/http/httptest" - "net/url" - "testing" - - "github.com/stretchr/testify/require" - - "gitlab.com/gitlab-org/gitlab-pages/internal/fixture" - "gitlab.com/gitlab-org/gitlab-pages/internal/serving" -) - -func withTestCluster(t *testing.T, cert, key string, block func(*http.ServeMux, *url.URL, *Certs)) { - mux := http.NewServeMux() - cluster := httptest.NewUnstartedServer(mux) - - certs, err := NewClusterCerts(fixture.Certificate, fixture.Key) - require.NoError(t, err) - - cluster.TLS = &tls.Config{ - Certificates: []tls.Certificate{certs.Certificate}, - RootCAs: certs.RootCerts, - } - - cluster.StartTLS() - defer cluster.Close() - - address, err := url.Parse(cluster.URL) - require.NoError(t, err) - - block(mux, address, certs) -} - -func TestServeFileHTTP(t *testing.T) { - t.Run("when proxying simple request to a cluster", func(t *testing.T) { - withTestCluster(t, fixture.Certificate, fixture.Key, func(mux *http.ServeMux, server *url.URL, certs *Certs) { - serverless := New( - "my-func.my-namespace-123.knative.example.com", - Cluster{ - Name: "knative.gitlab-example.com", - Address: server.Hostname(), - Port: server.Port(), - Certs: certs, - }, - ) - - writer := httptest.NewRecorder() - request := httptest.NewRequest("GET", "http://example.gitlab.com/", nil) - handler := serving.Handler{Writer: writer, Request: request} - request.Header.Set("X-Real-IP", "127.0.0.105") - - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "my-func.my-namespace-123.knative.example.com", r.Host) - require.Equal(t, "GitLab Pages Daemon", r.Header.Get("User-Agent")) - require.Equal(t, "https", r.Header.Get("X-Forwarded-Proto")) - require.Contains(t, r.Header.Get("X-Forwarded-For"), "127.0.0.105") - }) - - served := serverless.ServeFileHTTP(handler) - result := writer.Result() - - require.True(t, served) - require.Equal(t, http.StatusOK, result.StatusCode) - }) - }) - - t.Run("when proxying request with invalid hostname", func(t *testing.T) { - withTestCluster(t, fixture.Certificate, fixture.Key, func(mux *http.ServeMux, server *url.URL, certs *Certs) { - serverless := New( - "my-func.my-namespace-123.knative.example.com", - Cluster{ - Name: "knative.invalid-gitlab-example.com", - Address: server.Hostname(), - Port: server.Port(), - Certs: certs, - }, - ) - - writer := httptest.NewRecorder() - request := httptest.NewRequest("GET", "http://example.gitlab.com/", nil) - handler := serving.Handler{Writer: writer, Request: request} - - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusBadRequest) - }) - - served := serverless.ServeFileHTTP(handler) - result := writer.Result() - body, err := ioutil.ReadAll(writer.Body) - require.NoError(t, err) - - require.True(t, served) - require.Equal(t, http.StatusInternalServerError, result.StatusCode) - require.Contains(t, string(body), "cluster error: x509: certificate") - }) - }) - - t.Run("when a cluster responds with an error", func(t *testing.T) { - withTestCluster(t, fixture.Certificate, fixture.Key, func(mux *http.ServeMux, server *url.URL, certs *Certs) { - serverless := New( - "my-func.my-namespace-123.knative.example.com", - Cluster{ - Name: "knative.gitlab-example.com", - Address: server.Hostname(), - Port: server.Port(), - Certs: certs, - }, - ) - - writer := httptest.NewRecorder() - request := httptest.NewRequest("GET", "http://example.gitlab.com/", nil) - handler := serving.Handler{Writer: writer, Request: request} - - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusServiceUnavailable) - w.Write([]byte("sorry, service unavailable")) - }) - - served := serverless.ServeFileHTTP(handler) - result := writer.Result() - body, err := ioutil.ReadAll(writer.Body) - require.NoError(t, err) - - require.True(t, served) - require.Equal(t, http.StatusServiceUnavailable, result.StatusCode) - require.Contains(t, string(body), "sorry, service unavailable") - }) - }) - - t.Run("when a cluster responds correctly", func(t *testing.T) { - withTestCluster(t, fixture.Certificate, fixture.Key, func(mux *http.ServeMux, server *url.URL, certs *Certs) { - serverless := New( - "my-func.my-namespace-123.knative.example.com", - Cluster{ - Name: "knative.gitlab-example.com", - Address: server.Hostname(), - Port: server.Port(), - Certs: certs, - }, - ) - - writer := httptest.NewRecorder() - request := httptest.NewRequest("GET", "http://example.gitlab.com/", nil) - handler := serving.Handler{Writer: writer, Request: request} - - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write([]byte("OK")) - }) - - served := serverless.ServeFileHTTP(handler) - result := writer.Result() - body, err := ioutil.ReadAll(writer.Body) - require.NoError(t, err) - - require.True(t, served) - require.Equal(t, http.StatusOK, result.StatusCode) - require.Contains(t, string(body), "OK") - }) - }) -} diff --git a/internal/serving/serverless/transport.go b/internal/serving/serverless/transport.go deleted file mode 100644 index b7fabb13..00000000 --- a/internal/serving/serverless/transport.go +++ /dev/null @@ -1,51 +0,0 @@ -package serverless - -import ( - "context" - "net" - "net/http" - "time" - - "gitlab.com/gitlab-org/gitlab-pages/metrics" -) - -// Transport is a struct that handle the proxy connection round trip to Knative -// cluster -type Transport struct { - cluster Cluster - transport *http.Transport -} - -// NewTransport fabricates as new transport type -func NewTransport(cluster Cluster) *Transport { - dialer := net.Dialer{ - Timeout: 4 * time.Minute, - KeepAlive: 6 * time.Minute, - } - - dialContext := func(ctx context.Context, network, address string) (net.Conn, error) { - address = cluster.Host() - - return dialer.DialContext(ctx, network, address) - } - - return &Transport{ - cluster: cluster, - transport: &http.Transport{ - DialContext: dialContext, - TLSHandshakeTimeout: 5 * time.Second, - TLSClientConfig: cluster.TLSConfig(), - }, - } -} - -// RoundTrip performs a connection to a Knative cluster and returns a response -func (t *Transport) RoundTrip(request *http.Request) (*http.Response, error) { - start := time.Now() - - response, err := t.transport.RoundTrip(request) - - metrics.ServerlessLatency.Observe(time.Since(start).Seconds()) - - return response, err -} |