enterprise-portal: initialize service with dotcom DB connection (#62525)

Closes https://linear.app/sourcegraph/issue/CORE-96 - this scaffolds an initial Enterprise Portal service, as described in [RFC 885](https://docs.google.com/document/d/1tiaW1IVKm_YSSYhH-z7Q8sv4HSO_YJ_Uu6eYDjX7uU4/edit#heading=h.tdaxc5h34u7q), with a test setup to verify that we are able to connect to the Sourcegraph.com database and query from it. This will be used to implement the read-only RPCs proposed in #62263 

## Test plan

- [x] Publish image by hand:
  ```sh
  bazel run //cmd/enterprise-portal:candidate_push --stamp -- --tag insiders --repository us.gcr.io/sourcegraph-dev/enterprise-portal
  ```
- [x] Deploy in an MSP environment with appropriate permissions configured on the dotcom database, verify connection works: https://github.com/sourcegraph/managed-services/pull/1368 https://github.com/sourcegraph/managed-services/pull/1377
This commit is contained in:
Robert Lin 2024-05-09 16:30:39 -07:00 committed by GitHub
parent 022b4ad95f
commit e37a78bbd3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 286 additions and 1 deletions

View File

@ -0,0 +1,62 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
load("//dev:oci_defs.bzl", "image_repository", "oci_image", "oci_push", "oci_tarball")
load("@rules_pkg//:pkg.bzl", "pkg_tar")
load("@container_structure_test//:defs.bzl", "container_structure_test")
go_library(
name = "enterprise-portal_lib",
srcs = ["main.go"],
importpath = "github.com/sourcegraph/sourcegraph/cmd/enterprise-portal",
visibility = ["//visibility:private"],
deps = [
"//cmd/enterprise-portal/service",
"//lib/managedservicesplatform/runtime",
],
)
go_binary(
name = "enterprise-portal",
embed = [":enterprise-portal_lib"],
visibility = ["//visibility:public"],
)
pkg_tar(
name = "tar_enterprise-portal",
srcs = [":enterprise-portal"],
)
oci_image(
name = "image",
base = "//wolfi-images/sourcegraph-base:base_image",
entrypoint = [
"/sbin/tini",
"--",
"/enterprise-portal",
],
tars = [":tar_enterprise-portal"],
user = "sourcegraph",
)
oci_tarball(
name = "image_tarball",
image = ":image",
repo_tags = ["enterprise-portal:candidate"],
)
container_structure_test(
name = "image_test",
timeout = "short",
configs = ["image_test.yaml"],
driver = "docker",
image = ":image",
tags = [
"exclusive",
"requires-network",
],
)
oci_push(
name = "candidate_push",
image = ":image",
repository = image_repository("enterprise-portal"),
)

View File

@ -0,0 +1,3 @@
# See https://github.com/sourcegraph/codenotify for documentation.
**/* @sourcegraph/core-services

View File

@ -0,0 +1,3 @@
# enterprise-portal
**WIP** - refer to [RFC 885 Sourcegraph Enterprise Portal (go/enterprise-portal)](https://docs.google.com/document/d/1tiaW1IVKm_YSSYhH-z7Q8sv4HSO_YJ_Uu6eYDjX7uU4/edit#heading=h.tdaxc5h34u7q) for more details.

View File

@ -0,0 +1,15 @@
schemaVersion: "2.0.0"
commandTests:
- name: "binary is runnable"
command: "/enterprise-portal"
envVars:
- key: "SANITY_CHECK"
value: "true"
- name: "not running as root"
command: "/usr/bin/id"
args:
- -u
excludedOutput: ["^0"]
exitCode: 0

View File

@ -0,0 +1,12 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "dotcomdb",
srcs = ["dotcomdb.go"],
importpath = "github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/dotcomdb",
visibility = ["//cmd/enterprise-portal:__subpackages__"],
deps = [
"//lib/errors",
"@com_github_jackc_pgx_v5//:pgx",
],
)

View File

@ -0,0 +1,32 @@
package dotcomdb
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
type Database struct {
conn *pgx.Conn
}
// NewDatabase wraps a direct connection to the Sourcegraph.com database. It
// ONLY executes read queries, so the connection can (and should) be
// authenticated by a read-only user.
func NewDatabase(conn *pgx.Conn) *Database {
return &Database{conn: conn}
}
func (d *Database) Ping(ctx context.Context) error {
if err := d.conn.Ping(ctx); err != nil {
return errors.Wrap(err, "sqlDB.PingContext")
}
if _, err := d.conn.Exec(ctx, "SELECT current_user;"); err != nil {
return errors.Wrap(err, "sqlDB.Exec SELECT current_user")
}
return nil
}
func (d *Database) Close(ctx context.Context) error { return d.conn.Close(ctx) }

View File

@ -0,0 +1,10 @@
package main
import (
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/service"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/runtime"
)
func main() {
runtime.Start(&service.Service{})
}

View File

@ -0,0 +1,25 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "service",
srcs = [
"config.go",
"dotcomdb.go",
"service.go",
"state.go",
],
importpath = "github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/service",
visibility = ["//visibility:public"],
deps = [
"//cmd/enterprise-portal/internal/dotcomdb",
"//internal/httpserver",
"//internal/trace/policy",
"//internal/version",
"//lib/background",
"//lib/errors",
"//lib/managedservicesplatform/cloudsql",
"//lib/managedservicesplatform/runtime",
"@com_github_jackc_pgx_v5//:pgx",
"@com_github_sourcegraph_log//:log",
],
)

View File

@ -0,0 +1,26 @@
package service
import (
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/cloudsql"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/runtime"
)
// Config is the configuration for the Enterprise Portal.
type Config struct {
DotComDB struct {
cloudsql.ConnConfig
PGDSNOverride *string
}
}
func (c *Config) Load(env *runtime.Env) {
c.DotComDB.ConnConfig = cloudsql.ConnConfig{
ConnectionName: env.GetOptional("DOTCOM_CLOUDSQL_CONNECTION_NAME",
"Sourcegraph.com Cloud SQL connection name"),
User: env.GetOptional("DOTCOM_CLOUDSQL_USER", "Sourcegraph.com Cloud SQL user"),
Database: env.Get("DOTCOM_CLOUDSQL_DATABASE", "sourcegraph", "Sourcegraph.com database"),
}
c.DotComDB.PGDSNOverride = env.GetOptional("DOTCOM_PGDSN_OVERRIDE",
"For local dev: custom PostgreSQL DSN, overrides DOTCOM_CLOUDSQL_* options")
}

View File

@ -0,0 +1,32 @@
package service
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/dotcomdb"
"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/cloudsql"
)
func newDotComDBConn(ctx context.Context, config Config) (*dotcomdb.Database, error) {
if config.DotComDB.PGDSNOverride != nil {
config, err := pgx.ParseConfig(*config.DotComDB.PGDSNOverride)
if err != nil {
return nil, errors.Wrap(err, "rendered PGDSN is invalid")
}
conn, err := pgx.ConnectConfig(ctx, config)
if err != nil {
return nil, err
}
return dotcomdb.NewDatabase(conn), nil
}
// Use IAM auth to connect to the Cloud SQL database.
conn, err := cloudsql.Connect(ctx, config.DotComDB.ConnConfig)
if err != nil {
return nil, errors.Wrap(err, "contract.GetPostgreSQLDB")
}
return dotcomdb.NewDatabase(conn), nil
}

View File

@ -0,0 +1,55 @@
package service
import (
"context"
"fmt"
"net/http"
"time"
"github.com/sourcegraph/log"
"github.com/sourcegraph/sourcegraph/internal/httpserver"
"github.com/sourcegraph/sourcegraph/internal/trace/policy"
"github.com/sourcegraph/sourcegraph/internal/version"
"github.com/sourcegraph/sourcegraph/lib/background"
"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/runtime"
)
// Service is the implementation of the Enterprise Portal service.
type Service struct{}
var _ runtime.Service[Config] = (*Service)(nil)
func (Service) Name() string { return "enterprise-portal" }
func (Service) Version() string { return version.Version() }
func (Service) Initialize(ctx context.Context, logger log.Logger, contract runtime.Contract, config Config) (background.Routine, error) {
// We use Sourcegraph tracing code, so explicitly configure a trace policy
policy.SetTracePolicy(policy.TraceAll)
dotcomDB, err := newDotComDBConn(ctx, config)
if err != nil {
return nil, errors.Wrap(err, "newDotComDBConn")
}
defer dotcomDB.Close(context.Background())
// Simple test for now, move elsewhere later
if err := dotcomDB.Ping(context.Background()); err != nil {
return nil, errors.Wrap(err, "dotcomDB.Ping")
}
httpServer := http.NewServeMux()
contract.Diagnostics.RegisterDiagnosticsHandlers(httpServer, serviceState{})
listenAddr := fmt.Sprintf(":%d", contract.Port)
server := httpserver.NewFromAddr(
listenAddr,
&http.Server{
ReadTimeout: 2 * time.Minute,
WriteTimeout: 2 * time.Minute,
Handler: httpServer,
},
)
return server, nil
}

View File

@ -0,0 +1,10 @@
package service
import (
"context"
"net/url"
)
type serviceState struct{}
func (s serviceState) Healthy(_ context.Context, _ url.Values) error { return nil }

2
go.mod
View File

@ -271,6 +271,7 @@ require (
github.com/hashicorp/terraform-cdk-go/cdktf v0.17.3
github.com/invopop/jsonschema v0.12.0
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa
github.com/jackc/pgx/v5 v5.5.4
github.com/jomei/notionapi v1.13.0
github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1
github.com/mitchellh/hashstructure/v2 v2.0.2
@ -379,7 +380,6 @@ require (
github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgx/v5 v5.5.4 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/knadh/koanf/v2 v2.0.1 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect