This commit is contained in:
Steven Masley 2024-05-01 17:15:03 -05:00 committed by GitHub
commit bf88bde7cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 95 additions and 53 deletions

View File

@ -944,7 +944,19 @@ 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. This is just an easy way to pass the types
// to a single loop. Ensuring each provisioner has a unique suffix with their index.
daemons := make([]codersdk.ProvisionerType, 0)
for i := int64(0); i < vals.Provisioner.DaemonsTerraform.Value(); i++ {
daemons = append(daemons, codersdk.ProvisionerTypeTerraform)
}
for i := int64(0); i < vals.Provisioner.DaemonsEcho.Value(); i++ {
daemons = append(daemons, 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 +964,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 +1352,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 +1373,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 +1401,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 +1440,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,

View File

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

View File

@ -460,8 +460,8 @@ updating, and deleting workspace resources.
server.
--provisioner-daemons int, $CODER_PROVISIONER_DAEMONS (default: 3)
Number of provisioner daemons to create on start. If builds are stuck
in queued state for a long time, consider increasing this.
Number of terraform provisioner daemons to create on start. If builds
are stuck in queued state for a long time, consider increasing this.
TELEMETRY OPTIONS:
Telemetry is critical to our ability to improve Coder. We strip all

View File

@ -375,14 +375,14 @@ telemetry:
# Tune the behavior of the provisioner, which is responsible for creating,
# updating, and deleting workspace resources.
provisioning:
# Number of provisioner daemons to create on start. If builds are stuck in queued
# state for a long time, consider increasing this.
# Number of terraform provisioner daemons to create on start. If builds are stuck
# in queued state for a long time, consider increasing this.
# (default: 3, type: int)
daemons: 3
# Whether to use echo provisioner daemons instead of Terraform. This is for E2E
# tests.
# (default: false, type: bool)
daemonsEcho: false
# Number of built-in echo provisioners to create on start. Can be done alongside
# actual terraform provisioners. This is for E2E tests.
# (default: 0, type: int)
daemonsEcho: 0
# Deprecated and ignored.
# (default: 1s, type: duration)
daemonPollInterval: 1s

3
coderd/apidoc/docs.go generated
View File

@ -10487,10 +10487,11 @@ const docTemplate = `{
"type": "string"
},
"daemons": {
"description": "DaemonsTerraform is the number of built-in terraform provisioners. The\njson is 'daemons' for legacy reasons.",
"type": "integer"
},
"daemons_echo": {
"type": "boolean"
"type": "integer"
},
"force_cancel_interval": {
"type": "integer"

View File

@ -9423,10 +9423,11 @@
"type": "string"
},
"daemons": {
"description": "DaemonsTerraform is the number of built-in terraform provisioners. The\njson is 'daemons' for legacy reasons.",
"type": "integer"
},
"daemons_echo": {
"type": "boolean"
"type": "integer"
},
"force_cancel_interval": {
"type": "integer"

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 is the number of built-in terraform provisioners. The
// json is 'daemons' for legacy reasons.
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",

2
docs/api/general.md generated
View File

@ -326,7 +326,7 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \
"daemon_poll_jitter": 0,
"daemon_psk": "string",
"daemons": 0,
"daemons_echo": true,
"daemons_echo": 0,
"force_cancel_interval": 0
},
"proxy_health_status_interval": 0,

22
docs/api/schemas.md generated
View File

@ -2054,7 +2054,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
"daemon_poll_jitter": 0,
"daemon_psk": "string",
"daemons": 0,
"daemons_echo": true,
"daemons_echo": 0,
"force_cancel_interval": 0
},
"proxy_health_status_interval": 0,
@ -2427,7 +2427,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
"daemon_poll_jitter": 0,
"daemon_psk": "string",
"daemons": 0,
"daemons_echo": true,
"daemons_echo": 0,
"force_cancel_interval": 0
},
"proxy_health_status_interval": 0,
@ -3693,21 +3693,21 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
"daemon_poll_jitter": 0,
"daemon_psk": "string",
"daemons": 0,
"daemons_echo": true,
"daemons_echo": 0,
"force_cancel_interval": 0
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
| ----------------------- | ------- | -------- | ------------ | ----------- |
| `daemon_poll_interval` | integer | false | | |
| `daemon_poll_jitter` | integer | false | | |
| `daemon_psk` | string | false | | |
| `daemons` | integer | false | | |
| `daemons_echo` | boolean | false | | |
| `force_cancel_interval` | integer | false | | |
| Name | Type | Required | Restrictions | Description |
| ----------------------- | ------- | -------- | ------------ | --------------------------------------------------------------------------------------------------- |
| `daemon_poll_interval` | integer | false | | |
| `daemon_poll_jitter` | integer | false | | |
| `daemon_psk` | string | false | | |
| `daemons` | integer | false | | Daemons is the number of built-in terraform provisioners. The json is 'daemons' for legacy reasons. |
| `daemons_echo` | integer | false | | |
| `force_cancel_interval` | integer | false | | |
## codersdk.ProvisionerDaemon

2
docs/cli/server.md generated
View File

@ -711,7 +711,7 @@ Enables capturing of logs as events in traces. This is useful for debugging, but
| YAML | <code>provisioning.daemons</code> |
| Default | <code>3</code> |
Number of provisioner daemons to create on start. If builds are stuck in queued state for a long time, consider increasing this.
Number of terraform provisioner daemons to create on start. If builds are stuck in queued state for a long time, consider increasing this.
### --provisioner-daemon-poll-interval

View File

@ -461,8 +461,8 @@ updating, and deleting workspace resources.
server.
--provisioner-daemons int, $CODER_PROVISIONER_DAEMONS (default: 3)
Number of provisioner daemons to create on start. If builds are stuck
in queued state for a long time, consider increasing this.
Number of terraform provisioner daemons to create on start. If builds
are stuck in queued state for a long time, consider increasing this.
TELEMETRY OPTIONS:
Telemetry is critical to our ability to improve Coder. We strip all

View File

@ -58,8 +58,9 @@ export default defineConfig({
"--in-memory",
"--telemetry=false",
"--dangerous-disable-rate-limits",
"--provisioner-daemons 10",
"--provisioner-daemons-echo",
// TODO: Enable some terraform provisioners
"--provisioner-daemons 0",
"--provisioner-daemons-echo 10",
"--web-terminal-renderer=dom",
"--pprof-enable",
]

View File

@ -838,7 +838,7 @@ export interface PrometheusConfig {
// From codersdk/deployment.go
export interface ProvisionerConfig {
readonly daemons: number;
readonly daemons_echo: boolean;
readonly daemons_echo: number;
readonly daemon_poll_interval: number;
readonly daemon_poll_jitter: number;
readonly force_cancel_interval: number;

View File

@ -4,6 +4,7 @@ import CloseIcon from "@mui/icons-material/Close";
import Person from "@mui/icons-material/Person";
import Sell from "@mui/icons-material/Sell";
import SwapHoriz from "@mui/icons-material/SwapHoriz";
import ViewInArIcon from "@mui/icons-material/ViewInAr";
import IconButton from "@mui/material/IconButton";
import Tooltip from "@mui/material/Tooltip";
import type { FC } from "react";
@ -115,6 +116,18 @@ export const ProvisionerDaemonsPage: FC = () => {
gap: 12,
}}
>
{
// Add pills for the supported provisioenr types.
daemon.provisioners.map((provType) => {
return (
<Tooltip title="Type" key={daemon.id + provType}>
<Pill icon={<ViewInArIcon />}>
<code>{provType}</code>
</Pill>
</Tooltip>
);
})
}
<Tooltip title="API Version">
<Pill icon={<SwapHoriz />}>
<code>{daemon.api_version}</code>