chore: allow terraform & echo built-in provisioners

Built-in provisioners server their respective types, not both.
This commit is contained in:
Steven Masley 2024-05-01 15:54:14 -05:00
parent 845407fe7a
commit e26141fcfd
No known key found for this signature in database
5 changed files with 47 additions and 24 deletions

View File

@ -944,7 +944,13 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
var provisionerdWaitGroup sync.WaitGroup
defer provisionerdWaitGroup.Wait()
provisionerdMetrics := provisionerd.NewMetrics(options.PrometheusRegistry)
for i := int64(0); i < vals.Provisioner.Daemons.Value(); i++ {
// Create a list of daemon types. The length is the total number of built in provisioners, and
// the slice value is the type for each.
daemons := append(
fill(make([]codersdk.ProvisionerType, vals.Provisioner.DaemonsTerraform.Value()), codersdk.ProvisionerTypeTerraform),
fill(make([]codersdk.ProvisionerType, vals.Provisioner.DaemonsEcho.Value()), codersdk.ProvisionerTypeEcho)...,
)
for i, provisionerType := range daemons {
suffix := fmt.Sprintf("%d", i)
// The suffix is added to the hostname, so we may need to trim to fit into
// the 64 character limit.
@ -952,7 +958,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
name := fmt.Sprintf("%s-%s", hostname, suffix)
daemonCacheDir := filepath.Join(cacheDir, fmt.Sprintf("provisioner-%d", i))
daemon, err := newProvisionerDaemon(
ctx, coderAPI, provisionerdMetrics, logger, vals, daemonCacheDir, errCh, &provisionerdWaitGroup, name,
ctx, coderAPI, provisionerdMetrics, logger, vals, daemonCacheDir, errCh, &provisionerdWaitGroup, name, provisionerType,
)
if err != nil {
return xerrors.Errorf("create provisioner daemon: %w", err)
@ -1340,6 +1346,7 @@ func newProvisionerDaemon(
errCh chan error,
wg *sync.WaitGroup,
name string,
provisionerType codersdk.ProvisionerType,
) (srv *provisionerd.Server, err error) {
ctx, cancel := context.WithCancel(ctx)
defer func() {
@ -1360,7 +1367,8 @@ func newProvisionerDaemon(
}
connector := provisionerd.LocalProvisioners{}
if cfg.Provisioner.DaemonsEcho {
switch provisionerType {
case codersdk.ProvisionerTypeEcho:
echoClient, echoServer := drpc.MemTransportPipe()
wg.Add(1)
go func() {
@ -1387,7 +1395,7 @@ func newProvisionerDaemon(
}
}()
connector[string(database.ProvisionerTypeEcho)] = sdkproto.NewDRPCProvisionerClient(echoClient)
} else {
case codersdk.ProvisionerTypeTerraform:
tfDir := filepath.Join(cacheDir, "tf")
err = os.MkdirAll(tfDir, 0o700)
if err != nil {
@ -1426,12 +1434,14 @@ func newProvisionerDaemon(
}()
connector[string(database.ProvisionerTypeTerraform)] = sdkproto.NewDRPCProvisionerClient(terraformClient)
default:
return nil, fmt.Errorf("unknown provisioner type %q", provisionerType)
}
return provisionerd.New(func(dialCtx context.Context) (proto.DRPCProvisionerDaemonClient, error) {
// This debounces calls to listen every second. Read the comment
// in provisionerdserver.go to learn more!
return coderAPI.CreateInMemoryProvisionerDaemon(dialCtx, name)
return coderAPI.CreateInMemoryProvisionerDaemon(dialCtx, name, []codersdk.ProvisionerType{provisionerType})
}, &provisionerd.Options{
Logger: logger.Named(fmt.Sprintf("provisionerd-%s", name)),
UpdateInterval: time.Second,
@ -2574,3 +2584,11 @@ func getPostgresDB(ctx context.Context, logger slog.Logger, postgresURL string,
return sqlDB, dbURL, nil
}
// fill will fill the src with the value 'v'
func fill[T any](src []T, v T) []T {
for i := range src {
src[i] = v
}
return src
}

View File

@ -1367,7 +1367,7 @@ func TestServer(t *testing.T) {
"--in-memory",
"--http-address", ":0",
"--access-url", "http://example.com",
"--provisioner-daemons-echo",
"--provisioner-daemons-echo=3",
"--log-human", fiName,
)
clitest.Start(t, root)
@ -1385,7 +1385,7 @@ func TestServer(t *testing.T) {
"--in-memory",
"--http-address", ":0",
"--access-url", "http://example.com",
"--provisioner-daemons-echo",
"--provisioner-daemons-echo=3",
"--log-human", fi,
)
clitest.Start(t, root)
@ -1403,7 +1403,7 @@ func TestServer(t *testing.T) {
"--in-memory",
"--http-address", ":0",
"--access-url", "http://example.com",
"--provisioner-daemons-echo",
"--provisioner-daemons-echo=3",
"--log-json", fi,
)
clitest.Start(t, root)
@ -1424,7 +1424,7 @@ func TestServer(t *testing.T) {
"--in-memory",
"--http-address", ":0",
"--access-url", "http://example.com",
"--provisioner-daemons-echo",
"--provisioner-daemons-echo=3",
"--log-stackdriver", fi,
)
// Attach pty so we get debug output from the command if this test

View File

@ -1351,7 +1351,7 @@ func compressHandler(h http.Handler) http.Handler {
// CreateInMemoryProvisionerDaemon is an in-memory connection to a provisionerd.
// Useful when starting coderd and provisionerd in the same process.
func (api *API) CreateInMemoryProvisionerDaemon(dialCtx context.Context, name string) (client proto.DRPCProvisionerDaemonClient, err error) {
func (api *API) CreateInMemoryProvisionerDaemon(dialCtx context.Context, name string, provisionerTypes []codersdk.ProvisionerType) (client proto.DRPCProvisionerDaemonClient, err error) {
tracer := api.TracerProvider.Tracer(tracing.TracerName)
clientSession, serverSession := drpc.MemTransportPipe()
defer func() {
@ -1368,18 +1368,21 @@ func (api *API) CreateInMemoryProvisionerDaemon(dialCtx context.Context, name st
return nil, xerrors.Errorf("unable to fetch default org for in memory provisioner: %w", err)
}
dbTypes := make([]database.ProvisionerType, 0, len(provisionerTypes))
for _, tp := range provisionerTypes {
dbTypes = append(dbTypes, database.ProvisionerType(tp))
}
//nolint:gocritic // in-memory provisioners are owned by system
daemon, err := api.Database.UpsertProvisionerDaemon(dbauthz.AsSystemRestricted(dialCtx), database.UpsertProvisionerDaemonParams{
Name: name,
OrganizationID: defaultOrg.ID,
CreatedAt: dbtime.Now(),
Provisioners: []database.ProvisionerType{
database.ProvisionerTypeEcho, database.ProvisionerTypeTerraform,
},
Tags: provisionersdk.MutateTags(uuid.Nil, nil),
LastSeenAt: sql.NullTime{Time: dbtime.Now(), Valid: true},
Version: buildinfo.Version(),
APIVersion: proto.CurrentVersion.String(),
Provisioners: dbTypes,
Tags: provisionersdk.MutateTags(uuid.Nil, nil),
LastSeenAt: sql.NullTime{Time: dbtime.Now(), Valid: true},
Version: buildinfo.Version(),
APIVersion: proto.CurrentVersion.String(),
})
if err != nil {
return nil, xerrors.Errorf("failed to create in-memory provisioner daemon: %w", err)

View File

@ -578,7 +578,7 @@ func NewProvisionerDaemon(t testing.TB, coderAPI *coderd.API) io.Closer {
}()
daemon := provisionerd.New(func(dialCtx context.Context) (provisionerdproto.DRPCProvisionerDaemonClient, error) {
return coderAPI.CreateInMemoryProvisionerDaemon(dialCtx, "test")
return coderAPI.CreateInMemoryProvisionerDaemon(dialCtx, "test", []codersdk.ProvisionerType{codersdk.ProvisionerTypeEcho})
}, &provisionerd.Options{
Logger: coderAPI.Logger.Named("provisionerd").Leveled(slog.LevelDebug),
UpdateInterval: 250 * time.Millisecond,

View File

@ -406,8 +406,10 @@ type ExternalAuthConfig struct {
}
type ProvisionerConfig struct {
Daemons serpent.Int64 `json:"daemons" typescript:",notnull"`
DaemonsEcho serpent.Bool `json:"daemons_echo" typescript:",notnull"`
// DaemonsTerraform for legacy reasons is just called "daemons". It is the default
// choice.
DaemonsTerraform serpent.Int64 `json:"daemons" typescript:",notnull"`
DaemonsEcho serpent.Int64 `json:"daemons_echo" typescript:",notnull"`
DaemonPollInterval serpent.Duration `json:"daemon_poll_interval" typescript:",notnull"`
DaemonPollJitter serpent.Duration `json:"daemon_poll_jitter" typescript:",notnull"`
ForceCancelInterval serpent.Duration `json:"force_cancel_interval" typescript:",notnull"`
@ -1404,21 +1406,21 @@ when required by your organization's security policy.`,
// Provisioner settings
{
Name: "Provisioner Daemons",
Description: "Number of provisioner daemons to create on start. If builds are stuck in queued state for a long time, consider increasing this.",
Description: "Number of terraform provisioner daemons to create on start. If builds are stuck in queued state for a long time, consider increasing this.",
Flag: "provisioner-daemons",
Env: "CODER_PROVISIONER_DAEMONS",
Default: "3",
Value: &c.Provisioner.Daemons,
Value: &c.Provisioner.DaemonsTerraform,
Group: &deploymentGroupProvisioning,
YAML: "daemons",
},
{
Name: "Echo Provisioner",
Description: "Whether to use echo provisioner daemons instead of Terraform. This is for E2E tests.",
Description: "Number of built-in echo provisioners to create on start. Can be done alongside actual terraform provisioners. This is for E2E tests.",
Flag: "provisioner-daemons-echo",
Env: "CODER_PROVISIONER_DAEMONS_ECHO",
Hidden: true,
Default: "false",
Default: "0",
Value: &c.Provisioner.DaemonsEcho,
Group: &deploymentGroupProvisioning,
YAML: "daemonsEcho",