mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 15:12:02 +00:00
msp/runtime: split contract into JobContract and ServiceContract (#63494)
Splits the runtime contract into a JobContract and ServiceContract. This lets better handle initialisation such as env vars which is conditional depending on the contract type. ## Test plan <!-- REQUIRED; info at https://docs-legacy.sourcegraph.com/dev/background-information/testing_principles --> ci
This commit is contained in:
parent
aae480a77b
commit
ea9c45df8f
@ -37,7 +37,7 @@ 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) {
|
||||
func (Service) Initialize(ctx context.Context, logger log.Logger, contract runtime.ServiceContract, config Config) (background.Routine, error) {
|
||||
// We use Sourcegraph tracing code, so explicitly configure a trace policy
|
||||
policy.SetTracePolicy(policy.TraceAll)
|
||||
|
||||
@ -46,7 +46,7 @@ func (Service) Initialize(ctx context.Context, logger log.Logger, contract runti
|
||||
return nil, errors.Wrap(err, "initialize Redis client")
|
||||
}
|
||||
|
||||
dbHandle, err := database.NewHandle(ctx, logger, contract, redisClient, version.Version())
|
||||
dbHandle, err := database.NewHandle(ctx, logger, contract.Contract, redisClient, version.Version())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "initialize database handle")
|
||||
}
|
||||
@ -76,7 +76,7 @@ func (Service) Initialize(ctx context.Context, logger log.Logger, contract runti
|
||||
return nil, errors.Wrap(err, "create Sourcegraph Accounts client")
|
||||
}
|
||||
|
||||
iamClient, closeIAMClient, err := newIAMClient(ctx, logger, contract, redisClient)
|
||||
iamClient, closeIAMClient, err := newIAMClient(ctx, logger, contract.Contract, redisClient)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "initialize IAM client")
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ func (s Service) Version() string { return version.Version() }
|
||||
func (s Service) Initialize(
|
||||
ctx context.Context,
|
||||
logger log.Logger,
|
||||
contract runtime.Contract,
|
||||
contract runtime.ServiceContract,
|
||||
config Config,
|
||||
) (background.Routine, error) {
|
||||
logger.Info("starting service")
|
||||
@ -42,7 +42,7 @@ func (s Service) Initialize(
|
||||
if !config.StatelessMode {
|
||||
var err error
|
||||
|
||||
if bq, err = bigquery.NewClient(ctx, contract); err != nil {
|
||||
if bq, err = bigquery.NewClient(ctx, contract.Contract); err != nil {
|
||||
return nil, errors.Wrap(err, "bigquery")
|
||||
}
|
||||
if err := bq.Write(ctx, "service.initialized"); err != nil {
|
||||
@ -50,7 +50,7 @@ func (s Service) Initialize(
|
||||
}
|
||||
logger.Info("bigquery connection success")
|
||||
|
||||
if rd, err = redis.NewClient(ctx, contract); err != nil {
|
||||
if rd, err = redis.NewClient(ctx, contract.Contract); err != nil {
|
||||
return nil, errors.Wrap(err, "redis")
|
||||
}
|
||||
if err := rd.Ping(ctx); err != nil {
|
||||
@ -58,18 +58,17 @@ func (s Service) Initialize(
|
||||
}
|
||||
logger.Info("redis connection success")
|
||||
|
||||
if pg, err = postgresql.NewClient(ctx, contract); err != nil {
|
||||
if pg, err = postgresql.NewClient(ctx, contract.Contract); err != nil {
|
||||
return nil, errors.Wrap(err, "postgresl")
|
||||
}
|
||||
if err := pg.Ping(ctx); err != nil {
|
||||
return nil, errors.Wrap(err, "postgresql.Ping")
|
||||
}
|
||||
logger.Info("postgresql connection success")
|
||||
|
||||
}
|
||||
|
||||
h := http.NewServeMux()
|
||||
if err := httpapi.Register(h, contract, config.HTTPAPI); err != nil {
|
||||
if err := httpapi.Register(h, contract.Contract, config.HTTPAPI); err != nil {
|
||||
return nil, errors.Wrap(err, "httpapi.Register")
|
||||
}
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ var _ runtime.Service[Config] = (*Service)(nil)
|
||||
func (Service) Name() string { return "pings" }
|
||||
func (Service) Version() string { return version.Version() }
|
||||
|
||||
func (Service) Initialize(ctx context.Context, logger log.Logger, contract runtime.Contract, config Config) (background.Routine, error) {
|
||||
func (Service) Initialize(ctx context.Context, logger log.Logger, contract runtime.ServiceContract, config Config) (background.Routine, error) {
|
||||
pubsubClient, err := pubsub.NewTopicClient(config.PubSub.ProjectID, config.PubSub.TopicID)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("create Pub/Sub client: %v", err)
|
||||
|
||||
@ -42,7 +42,7 @@ var _ runtime.Service[Config] = (*Service)(nil)
|
||||
func (Service) Name() string { return "telemetry-gateway" }
|
||||
func (Service) Version() string { return version.Version() }
|
||||
|
||||
func (Service) Initialize(ctx context.Context, logger log.Logger, contract runtime.Contract, config Config) (background.Routine, error) {
|
||||
func (Service) Initialize(ctx context.Context, logger log.Logger, contract runtime.ServiceContract, config Config) (background.Routine, error) {
|
||||
// We use Sourcegraph tracing code, so explicitly configure a trace policy
|
||||
policy.SetTracePolicy(policy.TraceAll)
|
||||
|
||||
|
||||
@ -415,7 +415,7 @@ func main() {
|
||||
type Service struct{}
|
||||
|
||||
// Initialize implements runtime.Service.
|
||||
func (s Service) Initialize(ctx context.Context, logger log.Logger, contract runtime.Contract, config config.Config) (background.Routine, error) {
|
||||
func (s Service) Initialize(ctx context.Context, logger log.Logger, contract runtime.ServiceContract, config config.Config) (background.Routine, error) {
|
||||
logger.Info("config loaded from environment", log.Object("config", log.String("SlackChannel", config.SlackChannel), log.Bool("Production", config.Production)))
|
||||
|
||||
bqWriter, err := contract.BigQuery.GetTableWriter(context.Background(), "agent_status")
|
||||
|
||||
@ -39,7 +39,7 @@ func (s Service) Version() string { return version.Version() }
|
||||
func (s Service) Initialize(
|
||||
ctx context.Context,
|
||||
logger log.Logger,
|
||||
contract runtime.Contract,
|
||||
contract runtime.ServiceContract,
|
||||
config Config,
|
||||
) (background.Routine, error) {
|
||||
logger.Info("starting service")
|
||||
|
||||
@ -8,6 +8,14 @@ import (
|
||||
// configuration.
|
||||
type Contract = contract.Contract
|
||||
|
||||
// ServiceContract loads standardized MSP-provisioned (Managed Services Platform)
|
||||
// configuration.
|
||||
type ServiceContract = contract.ServiceContract
|
||||
|
||||
// JobContract loads standardized MSP-provisioned (Managed Services Platform)
|
||||
// configuration.
|
||||
type JobContract = contract.JobContract
|
||||
|
||||
// Env carries pre-parsed environment variables and variables requested and
|
||||
// errors encountered.
|
||||
type Env = contract.Env
|
||||
|
||||
@ -65,10 +65,6 @@ type Contract struct {
|
||||
// in. In local development, this should be 'unknown' if ENVIRONMENT_ID is
|
||||
// not set.
|
||||
EnvironmentID string
|
||||
// Port is the port the service must listen on.
|
||||
Port int
|
||||
// ExternalDNSName is the DNS name the service uses, if one is configured.
|
||||
ExternalDNSName *string
|
||||
|
||||
// RedisEndpoint is the full connection string of a MSP Redis instance if
|
||||
// provisioned, including any prerequisite authentication.
|
||||
@ -90,6 +86,23 @@ type Contract struct {
|
||||
internal internalContract
|
||||
}
|
||||
|
||||
// ServiceContract loads standardized MSP-provisioned (Managed Services Platform)
|
||||
// configuration for a service.
|
||||
type ServiceContract struct {
|
||||
// Port is the port the service must listen on.
|
||||
Port int
|
||||
// ExternalDNSName is the DNS name the service uses, if one is configured.
|
||||
ExternalDNSName *string
|
||||
|
||||
Contract
|
||||
}
|
||||
|
||||
// JobContract loads standardized MSP-provisioned (Managed Services Platform)
|
||||
// configuration for a job.
|
||||
type JobContract struct {
|
||||
Contract
|
||||
}
|
||||
|
||||
type ServiceMetadataProvider interface {
|
||||
// Name is the service name, typically the all-lowercase, dash-delimited,
|
||||
// machine-friendly 'id' of the service in its corresponding MSP service
|
||||
@ -112,9 +125,25 @@ type internalContract struct {
|
||||
environmentID string
|
||||
}
|
||||
|
||||
// New returns a new Contract instance from configuration parsed from the Env
|
||||
// NewService returns a new Contract instance from configuration parsed from the Env
|
||||
// instance. Values are expected per the 'MSP contract'.
|
||||
func New(logger log.Logger, service ServiceMetadataProvider, env *Env) Contract {
|
||||
func NewService(logger log.Logger, service ServiceMetadataProvider, env *Env) ServiceContract {
|
||||
return ServiceContract{
|
||||
Port: env.GetInt("PORT", "", "service port"),
|
||||
ExternalDNSName: env.GetOptional("EXTERNAL_DNS_NAME", "external DNS name provisioned for the service"),
|
||||
Contract: newBase(logger, service, env),
|
||||
}
|
||||
}
|
||||
|
||||
// NewJob returns a new Contract instance from configuration parsed from the Env
|
||||
// instance. Values are expected per the 'MSP contract'.
|
||||
func NewJob(logger log.Logger, service ServiceMetadataProvider, env *Env) JobContract {
|
||||
return JobContract{
|
||||
Contract: newBase(logger, service, env),
|
||||
}
|
||||
}
|
||||
|
||||
func newBase(logger log.Logger, service ServiceMetadataProvider, env *Env) Contract {
|
||||
defaultGCPProjectID := pointers.Deref(env.GetOptional("GOOGLE_CLOUD_PROJECT", "GCP project ID"), "")
|
||||
internal := internalContract{
|
||||
logger: logger,
|
||||
@ -124,11 +153,9 @@ func New(logger log.Logger, service ServiceMetadataProvider, env *Env) Contract
|
||||
isMSP := env.GetBool("MSP", "false", "indicates if we are running in a MSP environment")
|
||||
|
||||
return Contract{
|
||||
MSP: isMSP,
|
||||
EnvironmentID: internal.environmentID,
|
||||
Port: env.GetInt("PORT", "", "service port"),
|
||||
ExternalDNSName: env.GetOptional("EXTERNAL_DNS_NAME", "external DNS name provisioned for the service"),
|
||||
RedisEndpoint: env.GetOptional("REDIS_ENDPOINT", "full Redis address, including any prerequisite authentication"),
|
||||
MSP: isMSP,
|
||||
EnvironmentID: internal.environmentID,
|
||||
RedisEndpoint: env.GetOptional("REDIS_ENDPOINT", "full Redis address, including any prerequisite authentication"),
|
||||
|
||||
PostgreSQL: loadPostgreSQLContract(env, isMSP),
|
||||
BigQuery: loadBigQueryContract(env),
|
||||
|
||||
@ -17,11 +17,11 @@ func (m mockServiceMetadata) Name() string { return "mock-name" }
|
||||
func (m mockServiceMetadata) Version() string { return "mock-version" }
|
||||
|
||||
func TestNewContract(t *testing.T) {
|
||||
t.Run("sanity check", func(t *testing.T) {
|
||||
t.Run("service sanity check", func(t *testing.T) {
|
||||
e, err := contract.ParseEnv([]string{"MSP=true"})
|
||||
require.NoError(t, err)
|
||||
|
||||
c := contract.New(logtest.Scoped(t), mockServiceMetadata{}, e)
|
||||
c := contract.NewService(logtest.Scoped(t), mockServiceMetadata{}, e)
|
||||
assert.NotZero(t, c)
|
||||
assert.True(t, c.MSP)
|
||||
|
||||
@ -30,5 +30,16 @@ func TestNewContract(t *testing.T) {
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("job sanity check", func(t *testing.T) {
|
||||
e, err := contract.ParseEnv([]string{"MSP=true"})
|
||||
require.NoError(t, err)
|
||||
c := contract.NewJob(logtest.Scoped(t), mockServiceMetadata{}, e)
|
||||
assert.NotZero(t, c)
|
||||
assert.True(t, c.MSP)
|
||||
|
||||
// Not expected to error, as there are no required env vars.
|
||||
err = e.Validate()
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
// TODO: Add more validation tests
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ type Job[ConfigT any] interface {
|
||||
Execute(
|
||||
ctx context.Context,
|
||||
logger log.Logger,
|
||||
contract Contract,
|
||||
contract JobContract,
|
||||
config ConfigT,
|
||||
) error
|
||||
}
|
||||
@ -66,7 +66,7 @@ func ExecuteJob[
|
||||
|
||||
// Load configuration variables from environment
|
||||
config.Load(env)
|
||||
ctr := contract.New(log.Scoped("msp.contract"), job, env)
|
||||
ctr := contract.NewJob(log.Scoped("msp.contract"), job, env)
|
||||
|
||||
// Fast-exit with configuration facts if requested
|
||||
if *showHelp {
|
||||
|
||||
@ -21,7 +21,7 @@ type Service[ConfigT any] interface {
|
||||
Initialize(
|
||||
ctx context.Context,
|
||||
logger log.Logger,
|
||||
contract Contract,
|
||||
contract ServiceContract,
|
||||
config ConfigT,
|
||||
) (background.Routine, error)
|
||||
}
|
||||
@ -69,7 +69,7 @@ func Start[
|
||||
|
||||
// Load configuration variables from environment
|
||||
config.Load(env)
|
||||
ctr := contract.New(log.Scoped("msp.contract"), service, env)
|
||||
ctr := contract.NewService(log.Scoped("msp.contract"), service, env)
|
||||
|
||||
// Fast-exit with configuration facts if requested
|
||||
if *showHelp {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user