diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ea628d07877..037a1a0a2cb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -143,6 +143,7 @@ /cmd/frontend/graphqlbackend/campaigns.go @sourcegraph/campaigns /doc/user/campaigns @sourcegraph/campaigns /enterprise/internal/campaigns @sourcegraph/campaigns +/enterprise/cmd/frontend/internal/campaigns @sourcegraph/campaigns /internal/campaigns @sourcegraph/campaigns /web/**/campaigns/** @sourcegraph/campaigns @@ -230,6 +231,7 @@ Dockerfile @sourcegraph/distribution /enterprise/cmd/precise-code-intel-worker/ @sourcegraph/code-intel /enterprise/cmd/precise-code-intel-indexer/ @sourcegraph/code-intel /enterprise/internal/codeintel @sourcegraph/code-intel +/enterprise/cmd/frontend/internal/codeintel @sourcegraph/code-intel /cmd/frontend/graphqlbackend/codeintel.go @sourcegraph/code-intel /internal/cmd/precise-code-intel-tester @sourcegraph/code-intel diff --git a/enterprise/cmd/frontend/internal/authz/init.go b/enterprise/cmd/frontend/internal/authz/init.go new file mode 100644 index 00000000000..d98c2a7930c --- /dev/null +++ b/enterprise/cmd/frontend/internal/authz/init.go @@ -0,0 +1,36 @@ +package authz + +import ( + "context" + "time" + + "github.com/sourcegraph/sourcegraph/cmd/frontend/enterprise" + eauthz "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/authz" + "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/authz/resolvers" + eiauthz "github.com/sourcegraph/sourcegraph/enterprise/internal/authz" + "github.com/sourcegraph/sourcegraph/internal/authz" + "github.com/sourcegraph/sourcegraph/internal/conf" + "github.com/sourcegraph/sourcegraph/internal/db" + "github.com/sourcegraph/sourcegraph/internal/db/dbconn" +) + +func Init(ctx context.Context, enterpriseServices *enterprise.Services) error { + eauthz.Init(dbconn.Global, msResolutionClock) + + go func() { + t := time.NewTicker(5 * time.Second) + for range t.C { + allowAccessByDefault, authzProviders, _, _ := + eiauthz.ProvidersFromConfig(ctx, conf.Get(), db.ExternalServices) + authz.SetProviders(allowAccessByDefault, authzProviders) + } + }() + + enterpriseServices.AuthzResolver = resolvers.NewResolver(dbconn.Global, func() time.Time { + return time.Now().UTC().Truncate(time.Microsecond) + }) + + return nil +} + +var msResolutionClock = func() time.Time { return time.Now().UTC().Truncate(time.Microsecond) } diff --git a/enterprise/cmd/frontend/internal/campaigns/init.go b/enterprise/cmd/frontend/internal/campaigns/init.go new file mode 100644 index 00000000000..9e4515eaea8 --- /dev/null +++ b/enterprise/cmd/frontend/internal/campaigns/init.go @@ -0,0 +1,37 @@ +package campaigns + +import ( + "context" + "database/sql" + "time" + + "github.com/sourcegraph/sourcegraph/cmd/frontend/enterprise" + "github.com/sourcegraph/sourcegraph/cmd/repo-updater/repos" + "github.com/sourcegraph/sourcegraph/enterprise/internal/campaigns" + "github.com/sourcegraph/sourcegraph/enterprise/internal/campaigns/resolvers" + "github.com/sourcegraph/sourcegraph/internal/db/dbconn" + "github.com/sourcegraph/sourcegraph/internal/db/globalstatedb" +) + +func Init(ctx context.Context, enterpriseServices *enterprise.Services) error { + globalState, err := globalstatedb.Get(ctx) + if err != nil { + return err + } + + campaignsStore := campaigns.NewStoreWithClock(dbconn.Global, msResolutionClock) + repositories := repos.NewDBStore(dbconn.Global, sql.TxOptions{}) + + enterpriseServices.CampaignsResolver = resolvers.NewResolver(dbconn.Global) + enterpriseServices.GithubWebhook = campaigns.NewGitHubWebhook(campaignsStore, repositories, msResolutionClock) + enterpriseServices.BitbucketServerWebhook = campaigns.NewBitbucketServerWebhook( + campaignsStore, + repositories, + msResolutionClock, + "sourcegraph-"+globalState.SiteID, + ) + + return nil +} + +var msResolutionClock = func() time.Time { return time.Now().UTC().Truncate(time.Microsecond) } diff --git a/enterprise/cmd/frontend/internal/codeintel/init.go b/enterprise/cmd/frontend/internal/codeintel/init.go new file mode 100644 index 00000000000..b82ffd4163c --- /dev/null +++ b/enterprise/cmd/frontend/internal/codeintel/init.go @@ -0,0 +1,67 @@ +package codeintel + +import ( + "context" + "fmt" + "net/http" + "strconv" + + "github.com/inconshreveable/log15" + "github.com/opentracing/opentracing-go" + "github.com/prometheus/client_golang/prometheus" + + "github.com/sourcegraph/sourcegraph/cmd/frontend/enterprise" + codeintelapi "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/api" + bundles "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/bundles/client" + codeintelgitserver "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/gitserver" + codeintelhttpapi "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/httpapi" + codeintelresolvers "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/resolvers" + codeintelgqlresolvers "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/resolvers/graphql" + "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/store" + "github.com/sourcegraph/sourcegraph/internal/db/basestore" + "github.com/sourcegraph/sourcegraph/internal/db/dbconn" + "github.com/sourcegraph/sourcegraph/internal/env" + "github.com/sourcegraph/sourcegraph/internal/observation" + "github.com/sourcegraph/sourcegraph/internal/trace" +) + +var bundleManagerURL = env.Get("PRECISE_CODE_INTEL_BUNDLE_MANAGER_URL", "", "HTTP address for internal LSIF bundle manager server.") +var rawHunkCacheSize = env.Get("PRECISE_CODE_INTEL_HUNK_CACHE_CAPACITY", "1000", "Maximum number of git diff hunk objects that can be loaded into the hunk cache at once.") + +func Init(ctx context.Context, enterpriseServices *enterprise.Services) error { + if bundleManagerURL == "" { + return fmt.Errorf("invalid value for PRECISE_CODE_INTEL_BUNDLE_MANAGER_URL: no value supplied") + } + + hunkCacheSize, err := strconv.ParseInt(rawHunkCacheSize, 10, 64) + if err != nil { + return fmt.Errorf("invalid int %q for PRECISE_CODE_INTEL_HUNK_CACHE_CAPACITY: %s", rawHunkCacheSize, err) + } + + observationContext := &observation.Context{ + Logger: log15.Root(), + Tracer: &trace.Tracer{Tracer: opentracing.GlobalTracer()}, + Registerer: prometheus.DefaultRegisterer, + } + + store := store.NewObserved(store.NewWithHandle(basestore.NewHandleWithDB(dbconn.Global)), observationContext) + bundleManagerClient := bundles.New(bundleManagerURL) + api := codeintelapi.NewObserved(codeintelapi.New(store, bundleManagerClient, codeintelgitserver.DefaultClient), observationContext) + hunkCache, err := codeintelresolvers.NewHunkCache(int(hunkCacheSize)) + if err != nil { + return fmt.Errorf("failed to initialize hunk cache: %s", err) + } + + enterpriseServices.CodeIntelResolver = codeintelgqlresolvers.NewResolver(codeintelresolvers.NewResolver( + store, + bundleManagerClient, + api, + hunkCache, + )) + + enterpriseServices.NewCodeIntelUploadHandler = func(internal bool) http.Handler { + return codeintelhttpapi.NewUploadHandler(store, bundleManagerClient, internal) + } + + return nil +} diff --git a/enterprise/cmd/frontend/internal/licensing/init/init.go b/enterprise/cmd/frontend/internal/licensing/init/init.go new file mode 100644 index 00000000000..2d8a5be9a8d --- /dev/null +++ b/enterprise/cmd/frontend/internal/licensing/init/init.go @@ -0,0 +1,69 @@ +package init + +import ( + "context" + + "github.com/sourcegraph/sourcegraph/cmd/frontend/enterprise" + "github.com/sourcegraph/sourcegraph/cmd/frontend/envvar" + "github.com/sourcegraph/sourcegraph/cmd/frontend/graphqlbackend" + "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/dotcom/productsubscription" + "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/licensing" + "github.com/sourcegraph/sourcegraph/internal/db" + "github.com/sourcegraph/sourcegraph/internal/goroutine" + + _ "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/auth" + _ "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/graphqlbackend" + _ "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/registry" +) + +// TODO(efritz) - de-globalize assignments in this function +// TODO(efritz) - refactor licensing packages - this is a huge mess! +func Init(ctx context.Context, enterpriseServices *enterprise.Services) error { + // Enforce the license's max user count by preventing the creation of new users when the max is + // reached. + db.Users.PreCreateUser = licensing.NewPreCreateUserHook(&usersStore{}) + + // Make the Site.productSubscription.productNameWithBrand GraphQL field (and other places) use the + // proper product name. + graphqlbackend.GetProductNameWithBrand = licensing.ProductNameWithBrand + + // Make the Site.productSubscription.actualUserCount and Site.productSubscription.actualUserCountDate + // GraphQL fields return the proper max user count and timestamp on the current license. + graphqlbackend.ActualUserCount = licensing.ActualUserCount + graphqlbackend.ActualUserCountDate = licensing.ActualUserCountDate + + noLicenseMaximumAllowedUserCount := licensing.NoLicenseMaximumAllowedUserCount + graphqlbackend.NoLicenseMaximumAllowedUserCount = &noLicenseMaximumAllowedUserCount + + noLicenseWarningUserCount := licensing.NoLicenseWarningUserCount + graphqlbackend.NoLicenseWarningUserCount = &noLicenseWarningUserCount + + // Make the Site.productSubscription GraphQL field return the actual info about the product license, + // if any. + graphqlbackend.GetConfiguredProductLicenseInfo = func() (*graphqlbackend.ProductLicenseInfo, error) { + info, err := licensing.GetConfiguredProductLicenseInfo() + if info == nil || err != nil { + return nil, err + } + return &graphqlbackend.ProductLicenseInfo{ + TagsValue: info.Tags, + UserCountValue: info.UserCount, + ExpiresAtValue: info.ExpiresAt, + }, nil + } + + goroutine.Go(func() { + licensing.StartMaxUserCount(&usersStore{}) + }) + if envvar.SourcegraphDotComMode() { + goroutine.Go(productsubscription.StartCheckForUpcomingLicenseExpirations) + } + + return nil +} + +type usersStore struct{} + +func (usersStore) Count(ctx context.Context) (int, error) { + return db.Users.Count(ctx, nil) +} diff --git a/enterprise/cmd/frontend/main.go b/enterprise/cmd/frontend/main.go index 05dc15ca75d..bd4716ec18a 100644 --- a/enterprise/cmd/frontend/main.go +++ b/enterprise/cmd/frontend/main.go @@ -7,195 +7,48 @@ package main import ( "context" - "database/sql" + "fmt" "log" - "net/http" "os" "strconv" - "time" - - "github.com/inconshreveable/log15" - "github.com/opentracing/opentracing-go" - "github.com/prometheus/client_golang/prometheus" "github.com/sourcegraph/sourcegraph/cmd/frontend/enterprise" - "github.com/sourcegraph/sourcegraph/cmd/frontend/envvar" - "github.com/sourcegraph/sourcegraph/cmd/frontend/graphqlbackend" "github.com/sourcegraph/sourcegraph/cmd/frontend/shared" - "github.com/sourcegraph/sourcegraph/cmd/repo-updater/repos" + "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/authz" + "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/campaigns" + "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/codeintel" + licensing "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/licensing/init" + _ "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/auth" - eauthz "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/authz" - authzResolvers "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/authz/resolvers" - "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/dotcom/productsubscription" _ "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/graphqlbackend" - "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/licensing" _ "github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend/internal/registry" - eiauthz "github.com/sourcegraph/sourcegraph/enterprise/internal/authz" - "github.com/sourcegraph/sourcegraph/enterprise/internal/campaigns" - campaignsResolvers "github.com/sourcegraph/sourcegraph/enterprise/internal/campaigns/resolvers" - codeintelapi "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/api" - bundles "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/bundles/client" - codeintelgitserver "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/gitserver" - codeintelhttpapi "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/httpapi" - codeintelresolvers "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/resolvers" - codeintelgqlresolvers "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/resolvers/graphql" - "github.com/sourcegraph/sourcegraph/enterprise/internal/codeintel/store" - "github.com/sourcegraph/sourcegraph/internal/authz" - "github.com/sourcegraph/sourcegraph/internal/conf" - "github.com/sourcegraph/sourcegraph/internal/db" - "github.com/sourcegraph/sourcegraph/internal/db/basestore" - "github.com/sourcegraph/sourcegraph/internal/db/dbconn" - "github.com/sourcegraph/sourcegraph/internal/db/globalstatedb" - "github.com/sourcegraph/sourcegraph/internal/env" - "github.com/sourcegraph/sourcegraph/internal/goroutine" - "github.com/sourcegraph/sourcegraph/internal/observation" - "github.com/sourcegraph/sourcegraph/internal/trace" ) func main() { - shared.Main(func() enterprise.Services { - debug, _ := strconv.ParseBool(os.Getenv("DEBUG")) - if debug { - log.Println("enterprise edition") + shared.Main(enterpriseSetupHook) +} + +var initFunctions = map[string]func(ctx context.Context, enterpriseServices *enterprise.Services) error{ + "authz": authz.Init, + "campaigns": campaigns.Init, + "codeintel": codeintel.Init, + "licensing": licensing.Init, +} + +func enterpriseSetupHook() enterprise.Services { + debug, _ := strconv.ParseBool(os.Getenv("DEBUG")) + if debug { + log.Println("enterprise edition") + } + + ctx := context.Background() + enterpriseServices := enterprise.DefaultServices() + + for name, fn := range initFunctions { + if err := fn(ctx, &enterpriseServices); err != nil { + log.Fatal(fmt.Sprintf("failed to initialize %s: %s", name, err)) } + } - ctx := context.Background() - enterpriseServices := enterprise.DefaultServices() - - initLicensing() - initAuthz(ctx, &enterpriseServices) - initCampaigns(ctx, &enterpriseServices) - initCodeIntel(&enterpriseServices) - - return enterpriseServices - }) -} - -var msResolutionClock = func() time.Time { - return time.Now().UTC().Truncate(time.Microsecond) -} - -func initLicensing() { - // TODO(efritz) - de-globalize assignments in this function - - // Enforce the license's max user count by preventing the creation of new users when the max is - // reached. - db.Users.PreCreateUser = licensing.NewPreCreateUserHook(&usersStore{}) - - // Make the Site.productSubscription.productNameWithBrand GraphQL field (and other places) use the - // proper product name. - graphqlbackend.GetProductNameWithBrand = licensing.ProductNameWithBrand - - // Make the Site.productSubscription.actualUserCount and Site.productSubscription.actualUserCountDate - // GraphQL fields return the proper max user count and timestamp on the current license. - graphqlbackend.ActualUserCount = licensing.ActualUserCount - graphqlbackend.ActualUserCountDate = licensing.ActualUserCountDate - - noLicenseMaximumAllowedUserCount := licensing.NoLicenseMaximumAllowedUserCount - graphqlbackend.NoLicenseMaximumAllowedUserCount = &noLicenseMaximumAllowedUserCount - - noLicenseWarningUserCount := licensing.NoLicenseWarningUserCount - graphqlbackend.NoLicenseWarningUserCount = &noLicenseWarningUserCount - - // Make the Site.productSubscription GraphQL field return the actual info about the product license, - // if any. - graphqlbackend.GetConfiguredProductLicenseInfo = func() (*graphqlbackend.ProductLicenseInfo, error) { - info, err := licensing.GetConfiguredProductLicenseInfo() - if info == nil || err != nil { - return nil, err - } - return &graphqlbackend.ProductLicenseInfo{ - TagsValue: info.Tags, - UserCountValue: info.UserCount, - ExpiresAtValue: info.ExpiresAt, - }, nil - } - - goroutine.Go(func() { - licensing.StartMaxUserCount(&usersStore{}) - }) - if envvar.SourcegraphDotComMode() { - goroutine.Go(productsubscription.StartCheckForUpcomingLicenseExpirations) - } -} - -func initAuthz(ctx context.Context, enterpriseServices *enterprise.Services) { - eauthz.Init(dbconn.Global, msResolutionClock) - - go func() { - t := time.NewTicker(5 * time.Second) - for range t.C { - allowAccessByDefault, authzProviders, _, _ := - eiauthz.ProvidersFromConfig(ctx, conf.Get(), db.ExternalServices) - authz.SetProviders(allowAccessByDefault, authzProviders) - } - }() - - enterpriseServices.AuthzResolver = authzResolvers.NewResolver(dbconn.Global, func() time.Time { - return time.Now().UTC().Truncate(time.Microsecond) - }) -} - -func initCampaigns(ctx context.Context, enterpriseServices *enterprise.Services) { - globalState, err := globalstatedb.Get(ctx) - if err != nil { - log.Fatalf("FATAL: %v", err) - } - - campaignsStore := campaigns.NewStoreWithClock(dbconn.Global, msResolutionClock) - repositories := repos.NewDBStore(dbconn.Global, sql.TxOptions{}) - - enterpriseServices.CampaignsResolver = campaignsResolvers.NewResolver(dbconn.Global) - enterpriseServices.GithubWebhook = campaigns.NewGitHubWebhook(campaignsStore, repositories, msResolutionClock) - enterpriseServices.BitbucketServerWebhook = campaigns.NewBitbucketServerWebhook( - campaignsStore, - repositories, - msResolutionClock, - "sourcegraph-"+globalState.SiteID, - ) -} - -var bundleManagerURL = env.Get("PRECISE_CODE_INTEL_BUNDLE_MANAGER_URL", "", "HTTP address for internal LSIF bundle manager server.") -var rawHunkCacheSize = env.Get("PRECISE_CODE_INTEL_HUNK_CACHE_CAPACITY", "1000", "Maximum number of git diff hunk objects that can be loaded into the hunk cache at once.") - -func initCodeIntel(enterpriseServices *enterprise.Services) { - if bundleManagerURL == "" { - log.Fatalf("invalid value for PRECISE_CODE_INTEL_BUNDLE_MANAGER_URL: no value supplied") - } - - hunkCacheSize, err := strconv.ParseInt(rawHunkCacheSize, 10, 64) - if err != nil { - log.Fatalf("invalid int %q for PRECISE_CODE_INTEL_HUNK_CACHE_CAPACITY: %s", rawHunkCacheSize, err) - } - - observationContext := &observation.Context{ - Logger: log15.Root(), - Tracer: &trace.Tracer{Tracer: opentracing.GlobalTracer()}, - Registerer: prometheus.DefaultRegisterer, - } - - store := store.NewObserved(store.NewWithHandle(basestore.NewHandleWithDB(dbconn.Global)), observationContext) - bundleManagerClient := bundles.New(bundleManagerURL) - api := codeintelapi.NewObserved(codeintelapi.New(store, bundleManagerClient, codeintelgitserver.DefaultClient), observationContext) - hunkCache, err := codeintelresolvers.NewHunkCache(int(hunkCacheSize)) - if err != nil { - log.Fatalf("failed to initialize hunk cache: %s", err) - } - - enterpriseServices.CodeIntelResolver = codeintelgqlresolvers.NewResolver(codeintelresolvers.NewResolver( - store, - bundleManagerClient, - api, - hunkCache, - )) - - enterpriseServices.NewCodeIntelUploadHandler = func(internal bool) http.Handler { - return codeintelhttpapi.NewUploadHandler(store, bundleManagerClient, internal) - } -} - -type usersStore struct{} - -func (usersStore) Count(ctx context.Context) (int, error) { - return db.Users.Count(ctx, nil) + return enterpriseServices }