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 | |
parent | 64a0f90dfbe5d255b1fb7df0aa481575037694a1 (diff) |
Remove serverless code from Pages
Diffstat (limited to 'internal')
-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 | ||||
-rw-r--r-- | internal/source/domains.go | 24 | ||||
-rw-r--r-- | internal/source/domains_test.go | 31 | ||||
-rw-r--r-- | internal/source/gitlab/api/lookup_path.go | 15 | ||||
-rw-r--r-- | internal/source/gitlab/factory.go | 14 | ||||
-rw-r--r-- | internal/source/gitlab/factory_test.go | 29 |
12 files changed, 0 insertions, 502 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 -} diff --git a/internal/source/domains.go b/internal/source/domains.go index 7507938a..f1c275b6 100644 --- a/internal/source/domains.go +++ b/internal/source/domains.go @@ -2,7 +2,6 @@ package source import ( "fmt" - "regexp" "gitlab.com/gitlab-org/labkit/log" @@ -12,13 +11,6 @@ import ( "gitlab.com/gitlab-org/gitlab-pages/internal/source/gitlab" ) -var ( - // serverlessDomainRegex is a regular expression we use to check if a domain - // is a serverless domain, to short circuit gitlab source rollout. It can be - // removed after the rollout is done - serverlessDomainRegex = regexp.MustCompile(`^[^.]+-[[:xdigit:]]{2}a1[[:xdigit:]]{10}f2[[:xdigit:]]{2}[[:xdigit:]]+-?.*`) -) - type configSource int const ( @@ -134,13 +126,6 @@ func (d *Domains) IsReady() bool { } func (d *Domains) source(domain string) Source { - // This check is only needed until we enable `d.gitlab` source in all - // environments (including on-premises installations) followed by removal of - // `d.disk` source. This can be safely removed afterwards. - if IsServerlessDomain(domain) { - return d.gitlab - } - switch d.configSource { case sourceDisk: return d.disk @@ -155,12 +140,3 @@ func (d *Domains) source(domain string) Source { } } -// IsServerlessDomain checks if a domain requested is a serverless domain we -// need to handle differently. -// -// Domain is a serverless domain when it matches `serverlessDomainRegex`. The -// regular expression is also defined on the gitlab-rails side, see -// https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/serverless/domain.rb#L7 -func IsServerlessDomain(domain string) bool { - return serverlessDomainRegex.MatchString(domain) -} diff --git a/internal/source/domains_test.go b/internal/source/domains_test.go index a9404eef..7c351718 100644 --- a/internal/source/domains_test.go +++ b/internal/source/domains_test.go @@ -149,37 +149,6 @@ func TestGetDomain(t *testing.T) { require.NoError(t, err) require.Nil(t, domain) }) - - t.Run("when requesting a serverless domain", func(t *testing.T) { - testDomain := "func-aba1aabbccddeef2abaabbcc.serverless.gitlab.io" - - newSource := NewMockSource() - newSource.On("GetDomain", testDomain). - Return(&domain.Domain{Name: testDomain}, nil). - Once() - - defer newSource.AssertExpectations(t) - - domains := newTestDomains(t, newSource, sourceGitlab) - - domain, err := domains.GetDomain(testDomain) - require.NoError(t, err) - require.NotNil(t, domain) - }) -} - -func TestIsServerlessDomain(t *testing.T) { - t.Run("when a domain is serverless domain", func(t *testing.T) { - require.True(t, IsServerlessDomain("some-function-aba1aabbccddeef2abaabbcc.serverless.gitlab.io")) - }) - - t.Run("when a domain is serverless domain with environment", func(t *testing.T) { - require.True(t, IsServerlessDomain("some-function-aba1aabbccddeef2abaabbcc-testing.serverless.gitlab.io")) - }) - - t.Run("when a domain is not a serverless domain", func(t *testing.T) { - require.False(t, IsServerlessDomain("somedomain.gitlab.io")) - }) } func newTestDomains(t *testing.T, gitlabSource *MockSource, config configSource) *Domains { diff --git a/internal/source/gitlab/api/lookup_path.go b/internal/source/gitlab/api/lookup_path.go index 77b264ff..eac358ce 100644 --- a/internal/source/gitlab/api/lookup_path.go +++ b/internal/source/gitlab/api/lookup_path.go @@ -13,20 +13,5 @@ type LookupPath struct { type Source struct { Type string `json:"type,omitempty"` Path string `json:"path,omitempty"` - Serverless Serverless `json:"serverless,omitempty"` } -// Serverless describes serverless serving configuration -type Serverless struct { - Service string `json:"service,omitempty"` - Cluster Cluster `json:"cluster,omitempty"` -} - -// Cluster describes serverless cluster configuration -type Cluster struct { - Address string `json:"address,omitempty"` - Port string `json:"port,omitempty"` - Hostname string `json:"hostname,omitempty"` - CertificateCert string `json:"cert,omitempty"` - CertificateKey string `json:"key,omitempty"` -} diff --git a/internal/source/gitlab/factory.go b/internal/source/gitlab/factory.go index 700d3b8e..027150fe 100644 --- a/internal/source/gitlab/factory.go +++ b/internal/source/gitlab/factory.go @@ -45,20 +45,6 @@ func (g *Gitlab) fabricateServing(lookup api.LookupPath) (serving.Serving, error return local.Instance(), nil case "zip": return zip.Instance(), nil - case "serverless": - log.Errorf("attempted to fabricate serverless serving for project %d", lookup.ProjectID) - - // This feature has been disalbed, for more details see - // https://gitlab.com/gitlab-org/gitlab-pages/-/issues/467 - // - // serving, err := serverless.NewFromAPISource(source.Serverless) - // if err != nil { - // log.WithError(err).Errorf("could not fabricate serving for project %d", lookup.ProjectID) - // - // break - // } - // - // return serving } return nil, fmt.Errorf("gitlab: unknown serving source type: %q", source.Type) diff --git a/internal/source/gitlab/factory_test.go b/internal/source/gitlab/factory_test.go index 54a46c38..e88aa7f9 100644 --- a/internal/source/gitlab/factory_test.go +++ b/internal/source/gitlab/factory_test.go @@ -1,12 +1,10 @@ package gitlab import ( - "fmt" "testing" "github.com/stretchr/testify/require" - "gitlab.com/gitlab-org/gitlab-pages/internal/fixture" "gitlab.com/gitlab-org/gitlab-pages/internal/serving/disk" "gitlab.com/gitlab-org/gitlab-pages/internal/source/gitlab/api" ) @@ -60,31 +58,4 @@ func TestFabricateServing(t *testing.T) { require.Nil(t, srv) }) - t.Run("when lookup path requires serverless serving", func(t *testing.T) { - g := Gitlab{} - - lookup := api.LookupPath{ - Prefix: "/", - Source: api.Source{ - Type: "serverless", - Serverless: api.Serverless{ - Service: "my-func.knative.example.com", - Cluster: api.Cluster{ - Address: "127.0.0.10", - Port: "443", - Hostname: "my-cluster.example.com", - CertificateCert: fixture.Certificate, - CertificateKey: fixture.Key, - }, - }, - }, - } - - srv, err := g.fabricateServing(lookup) - require.EqualError(t, err, fmt.Sprintf("gitlab: unknown serving source type: %q", lookup.Source.Type)) - - // Serverless serving has been deprecated. - // require.IsType(t, &serverless.Serverless{}, fabricateServing(lookup)) - require.Nil(t, srv) - }) } |