diff --git a/cli/cliutil/hostname.go b/cli/cliutil/hostname.go
new file mode 100644
index 0000000000..92badcf5e3
--- /dev/null
+++ b/cli/cliutil/hostname.go
@@ -0,0 +1,40 @@
+package cliutil
+
+import (
+ "os"
+ "strings"
+ "sync"
+)
+
+var (
+ hostname string
+ hostnameOnce sync.Once
+)
+
+// Hostname returns the hostname of the machine, lowercased,
+// with any trailing domain suffix stripped.
+// It is cached after the first call.
+// If the hostname cannot be determined, for any reason,
+// localhost will be returned instead.
+func Hostname() string {
+ hostnameOnce.Do(func() { hostname = getHostname() })
+ return hostname
+}
+
+func getHostname() string {
+ h, err := os.Hostname()
+ if err != nil {
+ // Something must be very wrong if this fails.
+ // We'll just return localhost and hope for the best.
+ return "localhost"
+ }
+
+ // On some platforms, the hostname can be an FQDN. We only want the hostname.
+ if idx := strings.Index(h, "."); idx != -1 {
+ h = h[:idx]
+ }
+
+ // For the sake of consistency, we also want to lowercase the hostname.
+ // Per RFC 4343, DNS lookups must be case-insensitive.
+ return strings.ToLower(h)
+}
diff --git a/cli/server.go b/cli/server.go
index 99dccc1088..7161795fd4 100644
--- a/cli/server.go
+++ b/cli/server.go
@@ -62,6 +62,7 @@ import (
"github.com/coder/coder/v2/buildinfo"
"github.com/coder/coder/v2/cli/clibase"
"github.com/coder/coder/v2/cli/cliui"
+ "github.com/coder/coder/v2/cli/cliutil"
"github.com/coder/coder/v2/cli/config"
"github.com/coder/coder/v2/coderd"
"github.com/coder/coder/v2/coderd/autobuild"
@@ -86,6 +87,7 @@ import (
"github.com/coder/coder/v2/coderd/unhanger"
"github.com/coder/coder/v2/coderd/updatecheck"
"github.com/coder/coder/v2/coderd/util/slice"
+ stringutil "github.com/coder/coder/v2/coderd/util/strings"
"github.com/coder/coder/v2/coderd/workspaceapps"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/cryptorand"
@@ -875,9 +877,14 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
defer provisionerdWaitGroup.Wait()
provisionerdMetrics := provisionerd.NewMetrics(options.PrometheusRegistry)
for i := int64(0); i < vals.Provisioner.Daemons.Value(); i++ {
+ 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.
+ hostname := stringutil.Truncate(cliutil.Hostname(), 63-len(suffix))
+ 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,
+ ctx, coderAPI, provisionerdMetrics, logger, vals, daemonCacheDir, errCh, &provisionerdWaitGroup, name,
)
if err != nil {
return xerrors.Errorf("create provisioner daemon: %w", err)
@@ -1243,6 +1250,7 @@ func newProvisionerDaemon(
cacheDir string,
errCh chan error,
wg *sync.WaitGroup,
+ name string,
) (srv *provisionerd.Server, err error) {
ctx, cancel := context.WithCancel(ctx)
defer func() {
@@ -1334,9 +1342,9 @@ func newProvisionerDaemon(
return provisionerd.New(func(ctx context.Context) (proto.DRPCProvisionerDaemonClient, error) {
// This debounces calls to listen every second. Read the comment
// in provisionerdserver.go to learn more!
- return coderAPI.CreateInMemoryProvisionerDaemon(ctx)
+ return coderAPI.CreateInMemoryProvisionerDaemon(ctx, name)
}, &provisionerd.Options{
- Logger: logger.Named("provisionerd"),
+ Logger: logger.Named(fmt.Sprintf("provisionerd-%s", name)),
UpdateInterval: time.Second,
ForceCancelInterval: cfg.Provisioner.ForceCancelInterval.Value(),
Connector: connector,
diff --git a/coderd/coderd.go b/coderd/coderd.go
index 2a6078bf27..bacc84de58 100644
--- a/coderd/coderd.go
+++ b/coderd/coderd.go
@@ -21,7 +21,6 @@ import (
"github.com/go-chi/chi/v5/middleware"
"github.com/google/uuid"
"github.com/klauspost/compress/zstd"
- "github.com/moby/moby/pkg/namesgenerator"
"github.com/prometheus/client_golang/prometheus"
httpSwagger "github.com/swaggo/http-swagger/v2"
"go.opentelemetry.io/otel/trace"
@@ -1150,7 +1149,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(ctx context.Context) (client proto.DRPCProvisionerDaemonClient, err error) {
+func (api *API) CreateInMemoryProvisionerDaemon(ctx context.Context, name string) (client proto.DRPCProvisionerDaemonClient, err error) {
tracer := api.TracerProvider.Tracer(tracing.TracerName)
clientSession, serverSession := provisionersdk.MemTransportPipe()
defer func() {
@@ -1165,9 +1164,8 @@ func (api *API) CreateInMemoryProvisionerDaemon(ctx context.Context) (client pro
}
mux := drpcmux.New()
- name := namesgenerator.GetRandomName(1)
+ api.Logger.Info(ctx, "starting in-memory provisioner daemon", slog.F("name", name))
logger := api.Logger.Named(fmt.Sprintf("inmem-provisionerd-%s", name))
- logger.Info(ctx, "starting in-memory provisioner daemon")
srv, err := provisionerdserver.NewServer(
api.ctx,
api.AccessURL,
diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go
index f5ed26cfe9..036a390235 100644
--- a/coderd/coderdtest/coderdtest.go
+++ b/coderd/coderdtest/coderdtest.go
@@ -530,7 +530,7 @@ func NewProvisionerDaemon(t testing.TB, coderAPI *coderd.API) io.Closer {
}()
daemon := provisionerd.New(func(ctx context.Context) (provisionerdproto.DRPCProvisionerDaemonClient, error) {
- return coderAPI.CreateInMemoryProvisionerDaemon(ctx)
+ return coderAPI.CreateInMemoryProvisionerDaemon(ctx, t.Name())
}, &provisionerd.Options{
Logger: coderAPI.Logger.Named("provisionerd").Leveled(slog.LevelDebug),
UpdateInterval: 250 * time.Millisecond,
@@ -567,6 +567,8 @@ func NewExternalProvisionerDaemon(t testing.TB, client *codersdk.Client, org uui
daemon := provisionerd.New(func(ctx context.Context) (provisionerdproto.DRPCProvisionerDaemonClient, error) {
return client.ServeProvisionerDaemon(ctx, codersdk.ServeProvisionerDaemonRequest{
+ ID: uuid.New(),
+ Name: t.Name(),
Organization: org,
Provisioners: []codersdk.ProvisionerType{codersdk.ProvisionerTypeEcho},
Tags: tags,
diff --git a/coderd/util/strings/strings.go b/coderd/util/strings/strings.go
index fda9f0e7c6..f416bba463 100644
--- a/coderd/util/strings/strings.go
+++ b/coderd/util/strings/strings.go
@@ -17,3 +17,14 @@ func JoinWithConjunction(s []string) string {
s[last],
)
}
+
+// Truncate returns the first n characters of s.
+func Truncate(s string, n int) string {
+ if n < 1 {
+ return ""
+ }
+ if len(s) <= n {
+ return s
+ }
+ return s[:n]
+}
diff --git a/coderd/util/strings/strings_test.go b/coderd/util/strings/strings_test.go
index a107a7754f..2db9c9e236 100644
--- a/coderd/util/strings/strings_test.go
+++ b/coderd/util/strings/strings_test.go
@@ -14,3 +14,27 @@ func TestJoinWithConjunction(t *testing.T) {
require.Equal(t, "foo and bar", strings.JoinWithConjunction([]string{"foo", "bar"}))
require.Equal(t, "foo, bar and baz", strings.JoinWithConjunction([]string{"foo", "bar", "baz"}))
}
+
+func TestTruncate(t *testing.T) {
+ t.Parallel()
+
+ for _, tt := range []struct {
+ s string
+ n int
+ expected string
+ }{
+ {"foo", 4, "foo"},
+ {"foo", 3, "foo"},
+ {"foo", 2, "fo"},
+ {"foo", 1, "f"},
+ {"foo", 0, ""},
+ {"foo", -1, ""},
+ } {
+ tt := tt
+ t.Run(tt.expected, func(t *testing.T) {
+ t.Parallel()
+ actual := strings.Truncate(tt.s, tt.n)
+ require.Equal(t, tt.expected, actual)
+ })
+ }
+}
diff --git a/codersdk/provisionerdaemons.go b/codersdk/provisionerdaemons.go
index abc7823680..50440d24ac 100644
--- a/codersdk/provisionerdaemons.go
+++ b/codersdk/provisionerdaemons.go
@@ -177,6 +177,8 @@ func (c *Client) provisionerJobLogsAfter(ctx context.Context, path string, after
type ServeProvisionerDaemonRequest struct {
// ID is a unique ID for a provisioner daemon.
ID uuid.UUID `json:"id" format:"uuid"`
+ // Name is the human-readable unique identifier for the daemon.
+ Name string `json:"name" example:"my-cool-provisioner-daemon"`
// Organization is the organization for the URL. At present provisioner daemons ARE NOT scoped to organizations
// and so the organization ID is optional.
Organization uuid.UUID `json:"organization" format:"uuid"`
@@ -198,6 +200,7 @@ func (c *Client) ServeProvisionerDaemon(ctx context.Context, req ServeProvisione
}
query := serverURL.Query()
query.Add("id", req.ID.String())
+ query.Add("name", req.Name)
for _, provisioner := range req.Provisioners {
query.Add("provisioner", string(provisioner))
}
diff --git a/docs/cli/provisionerd_start.md b/docs/cli/provisionerd_start.md
index 8f7e72b012..e28a8adafe 100644
--- a/docs/cli/provisionerd_start.md
+++ b/docs/cli/provisionerd_start.md
@@ -22,6 +22,15 @@ coder provisionerd start [flags]
Directory to store cached data.
+### --name
+
+| | |
+| ----------- | ------------------------------------------- |
+| Type | string
|
+| Environment | $CODER_PROVISIONER_DAEMON_NAME
|
+
+Name of this provisioner daemon. Defaults to the current hostname without FQDN.
+
### --poll-interval
| | |
diff --git a/enterprise/cli/provisionerdaemons.go b/enterprise/cli/provisionerdaemons.go
index 6583f1b1a8..c11dfeecca 100644
--- a/enterprise/cli/provisionerdaemons.go
+++ b/enterprise/cli/provisionerdaemons.go
@@ -6,6 +6,7 @@ import (
"context"
"fmt"
"os"
+ "regexp"
"time"
"github.com/google/uuid"
@@ -16,6 +17,7 @@ import (
agpl "github.com/coder/coder/v2/cli"
"github.com/coder/coder/v2/cli/clibase"
"github.com/coder/coder/v2/cli/cliui"
+ "github.com/coder/coder/v2/cli/cliutil"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/provisionerdserver"
"github.com/coder/coder/v2/codersdk"
@@ -41,6 +43,16 @@ func (r *RootCmd) provisionerDaemons() *clibase.Cmd {
return cmd
}
+func validateProvisionerDaemonName(name string) error {
+ if len(name) > 64 {
+ return xerrors.Errorf("name cannot be greater than 64 characters in length")
+ }
+ if ok, err := regexp.MatchString(`^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$`, name); err != nil || !ok {
+ return xerrors.Errorf("name %q is not a valid hostname", name)
+ }
+ return nil
+}
+
func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd {
var (
cacheDir string
@@ -48,6 +60,7 @@ func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd {
pollInterval time.Duration
pollJitter time.Duration
preSharedKey string
+ name string
)
client := new(codersdk.Client)
cmd := &clibase.Cmd{
@@ -68,6 +81,14 @@ func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd {
return err
}
+ if name == "" {
+ name = cliutil.Hostname()
+ }
+
+ if err := validateProvisionerDaemonName(name); err != nil {
+ return err
+ }
+
logger := slog.Make(sloghuman.Sink(inv.Stderr))
if ok, _ := inv.ParsedFlags().GetBool("verbose"); ok {
logger = logger.Leveled(slog.LevelDebug)
@@ -122,7 +143,7 @@ func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd {
}
}()
- logger.Info(ctx, "starting provisioner daemon", slog.F("tags", tags))
+ logger.Info(ctx, "starting provisioner daemon", slog.F("tags", tags), slog.F("name", name))
connector := provisionerd.LocalProvisioners{
string(database.ProvisionerTypeTerraform): proto.NewDRPCProvisionerClient(terraformClient),
@@ -130,7 +151,8 @@ func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd {
id := uuid.New()
srv := provisionerd.New(func(ctx context.Context) (provisionerdproto.DRPCProvisionerDaemonClient, error) {
return client.ServeProvisionerDaemon(ctx, codersdk.ServeProvisionerDaemonRequest{
- ID: id,
+ ID: id,
+ Name: name,
Provisioners: []codersdk.ProvisionerType{
codersdk.ProvisionerTypeTerraform,
},
@@ -205,6 +227,13 @@ func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd {
Description: "Pre-shared key to authenticate with Coder server.",
Value: clibase.StringOf(&preSharedKey),
},
+ {
+ Flag: "name",
+ Env: "CODER_PROVISIONER_DAEMON_NAME",
+ Description: "Name of this provisioner daemon. Defaults to the current hostname without FQDN.",
+ Value: clibase.StringOf(&name),
+ Default: "",
+ },
}
return cmd
diff --git a/enterprise/cli/provisionerdaemons_test.go b/enterprise/cli/provisionerdaemons_test.go
index ff8ca63f57..4f1e09ad43 100644
--- a/enterprise/cli/provisionerdaemons_test.go
+++ b/enterprise/cli/provisionerdaemons_test.go
@@ -26,7 +26,7 @@ func TestProvisionerDaemon_PSK(t *testing.T) {
},
},
})
- inv, conf := newCLI(t, "provisionerd", "start", "--psk=provisionersftw")
+ inv, conf := newCLI(t, "provisionerd", "start", "--psk=provisionersftw", "--name=matt-daemon")
err := conf.URL().Write(client.URL.String())
require.NoError(t, err)
pty := ptytest.New(t).Attach(inv)
@@ -34,6 +34,7 @@ func TestProvisionerDaemon_PSK(t *testing.T) {
defer cancel()
clitest.Start(t, inv)
pty.ExpectMatchContext(ctx, "starting provisioner daemon")
+ pty.ExpectMatchContext(ctx, "matt-daemon")
}
func TestProvisionerDaemon_SessionToken(t *testing.T) {
diff --git a/enterprise/cli/testdata/coder_provisionerd_start_--help.golden b/enterprise/cli/testdata/coder_provisionerd_start_--help.golden
index 80d28883a8..b497c5ab62 100644
--- a/enterprise/cli/testdata/coder_provisionerd_start_--help.golden
+++ b/enterprise/cli/testdata/coder_provisionerd_start_--help.golden
@@ -9,6 +9,10 @@ OPTIONS:
-c, --cache-dir string, $CODER_CACHE_DIRECTORY (default: [cache dir])
Directory to store cached data.
+ --name string, $CODER_PROVISIONER_DAEMON_NAME
+ Name of this provisioner daemon. Defaults to the current hostname
+ without FQDN.
+
--poll-interval duration, $CODER_PROVISIONERD_POLL_INTERVAL (default: 1s)
Deprecated and ignored.
diff --git a/enterprise/coderd/provisionerdaemons.go b/enterprise/coderd/provisionerdaemons.go
index 3b3c3b6f02..38b65b442a 100644
--- a/enterprise/coderd/provisionerdaemons.go
+++ b/enterprise/coderd/provisionerdaemons.go
@@ -178,6 +178,13 @@ func (api *API) provisionerDaemonServe(rw http.ResponseWriter, r *http.Request)
}
}
+ name := namesgenerator.GetRandomName(10)
+ if vals, ok := r.URL.Query()["name"]; ok && len(vals) > 0 {
+ name = vals[0]
+ } else {
+ api.Logger.Warn(ctx, "unnamed provisioner daemon")
+ }
+
tags, authorized := api.provisionerDaemonAuth.authorize(r, tags)
if !authorized {
api.Logger.Warn(ctx, "unauthorized provisioner daemon serve request", slog.F("tags", tags))
@@ -206,7 +213,6 @@ func (api *API) provisionerDaemonServe(rw http.ResponseWriter, r *http.Request)
}
}
- name := namesgenerator.GetRandomName(1)
log := api.Logger.With(
slog.F("name", name),
slog.F("provisioners", provisioners),
diff --git a/enterprise/coderd/provisionerdaemons_test.go b/enterprise/coderd/provisionerdaemons_test.go
index b1348c2878..5d21a84111 100644
--- a/enterprise/coderd/provisionerdaemons_test.go
+++ b/enterprise/coderd/provisionerdaemons_test.go
@@ -40,6 +40,8 @@ func TestProvisionerDaemonServe(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
srv, err := templateAdminClient.ServeProvisionerDaemon(ctx, codersdk.ServeProvisionerDaemonRequest{
+ ID: uuid.New(),
+ Name: t.Name(),
Organization: user.OrganizationID,
Provisioners: []codersdk.ProvisionerType{
codersdk.ProvisionerTypeEcho,
@@ -57,6 +59,8 @@ func TestProvisionerDaemonServe(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
_, err := templateAdminClient.ServeProvisionerDaemon(ctx, codersdk.ServeProvisionerDaemonRequest{
+ ID: uuid.New(),
+ Name: t.Name(),
Organization: user.OrganizationID,
Provisioners: []codersdk.ProvisionerType{
codersdk.ProvisionerTypeEcho,
@@ -80,6 +84,8 @@ func TestProvisionerDaemonServe(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
_, err := another.ServeProvisionerDaemon(ctx, codersdk.ServeProvisionerDaemonRequest{
+ ID: uuid.New(),
+ Name: t.Name(),
Organization: user.OrganizationID,
Provisioners: []codersdk.ProvisionerType{
codersdk.ProvisionerTypeEcho,
@@ -105,6 +111,8 @@ func TestProvisionerDaemonServe(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
_, err := another.ServeProvisionerDaemon(ctx, codersdk.ServeProvisionerDaemonRequest{
+ ID: uuid.New(),
+ Name: t.Name(),
Organization: user.OrganizationID,
Provisioners: []codersdk.ProvisionerType{
codersdk.ProvisionerTypeEcho,
@@ -245,6 +253,8 @@ func TestProvisionerDaemonServe(t *testing.T) {
another := codersdk.New(client.URL)
pd := provisionerd.New(func(ctx context.Context) (provisionerdproto.DRPCProvisionerDaemonClient, error) {
return another.ServeProvisionerDaemon(ctx, codersdk.ServeProvisionerDaemonRequest{
+ ID: uuid.New(),
+ Name: t.Name(),
Organization: user.OrganizationID,
Provisioners: []codersdk.ProvisionerType{
codersdk.ProvisionerTypeEcho,
@@ -321,6 +331,8 @@ func TestProvisionerDaemonServe(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
_, err := another.ServeProvisionerDaemon(ctx, codersdk.ServeProvisionerDaemonRequest{
+ ID: uuid.New(),
+ Name: t.Name(),
Organization: user.OrganizationID,
Provisioners: []codersdk.ProvisionerType{
codersdk.ProvisionerTypeEcho,
@@ -350,6 +362,8 @@ func TestProvisionerDaemonServe(t *testing.T) {
defer cancel()
another := codersdk.New(client.URL)
_, err := another.ServeProvisionerDaemon(ctx, codersdk.ServeProvisionerDaemonRequest{
+ ID: uuid.New(),
+ Name: t.Name(),
Organization: user.OrganizationID,
Provisioners: []codersdk.ProvisionerType{
codersdk.ProvisionerTypeEcho,
@@ -377,6 +391,8 @@ func TestProvisionerDaemonServe(t *testing.T) {
defer cancel()
another := codersdk.New(client.URL)
_, err := another.ServeProvisionerDaemon(ctx, codersdk.ServeProvisionerDaemonRequest{
+ ID: uuid.New(),
+ Name: t.Name(),
Organization: user.OrganizationID,
Provisioners: []codersdk.ProvisionerType{
codersdk.ProvisionerTypeEcho,
diff --git a/enterprise/replicasync/replicasync.go b/enterprise/replicasync/replicasync.go
index 0414de3dc4..b7e46b99f6 100644
--- a/enterprise/replicasync/replicasync.go
+++ b/enterprise/replicasync/replicasync.go
@@ -8,7 +8,6 @@ import (
"fmt"
"net/http"
"net/url"
- "os"
"strings"
"sync"
"time"
@@ -19,6 +18,7 @@ import (
"cdr.dev/slog"
"github.com/coder/coder/v2/buildinfo"
+ "github.com/coder/coder/v2/cli/cliutil"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/database/dbtime"
@@ -57,10 +57,7 @@ func New(ctx context.Context, logger slog.Logger, db database.Store, ps pubsub.P
// primary purpose is to clean up dead replicas.
options.CleanupInterval = 30 * time.Minute
}
- hostname, err := os.Hostname()
- if err != nil {
- return nil, xerrors.Errorf("get hostname: %w", err)
- }
+ hostname := cliutil.Hostname()
databaseLatency, err := db.Ping(ctx)
if err != nil {
return nil, xerrors.Errorf("ping database: %w", err)
diff --git a/enterprise/wsproxy/wsproxy.go b/enterprise/wsproxy/wsproxy.go
index b0194d69d3..d83f760c8f 100644
--- a/enterprise/wsproxy/wsproxy.go
+++ b/enterprise/wsproxy/wsproxy.go
@@ -7,7 +7,6 @@ import (
"fmt"
"net/http"
"net/url"
- "os"
"reflect"
"regexp"
"strings"
@@ -27,6 +26,7 @@ import (
"cdr.dev/slog"
"github.com/coder/coder/v2/buildinfo"
+ "github.com/coder/coder/v2/cli/cliutil"
"github.com/coder/coder/v2/coderd"
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/coderd/httpmw"
@@ -206,10 +206,7 @@ func New(ctx context.Context, opts *Options) (*Server, error) {
// Register the workspace proxy with the primary coderd instance and start a
// goroutine to periodically re-register.
replicaID := uuid.New()
- osHostname, err := os.Hostname()
- if err != nil {
- return nil, xerrors.Errorf("get OS hostname: %w", err)
- }
+ osHostname := cliutil.Hostname()
regResp, registerDone, err := client.RegisterWorkspaceProxyLoop(ctx, wsproxysdk.RegisterWorkspaceProxyLoopOpts{
Logger: opts.Logger,
Request: wsproxysdk.RegisterWorkspaceProxyRequest{
diff --git a/scripts/coder-dev.sh b/scripts/coder-dev.sh
index 69696351ea..d379e226b6 100755
--- a/scripts/coder-dev.sh
+++ b/scripts/coder-dev.sh
@@ -20,6 +20,9 @@ fi
if [[ ${1:-} == exp ]] && [[ ${2:-} == scaletest ]]; then
BINARY_TYPE=coder
fi
+if [[ ${1:-} == provisionerd ]]; then
+ BINARY_TYPE=coder
+fi
RELATIVE_BINARY_PATH="build/${BINARY_TYPE}_${GOOS}_${GOARCH}"
# To preserve the CWD when running the binary, we need to use pushd and popd to