Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,5 @@
"typos.config": ".github/workflows/typos.toml",
"[markdown]": {
"editor.defaultFormatter": "DavidAnson.vscode-markdownlint"
},
"biome.configurationPath": "./site/biome.jsonc",
"biome.lsp.bin": "./site/node_modules/.bin/biome"
}
}
33 changes: 31 additions & 2 deletions cli/provisioners.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package cli

import (
"fmt"
"time"

"golang.org/x/xerrors"

"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/coderd/util/slice"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/serpent"
)
Expand Down Expand Up @@ -39,7 +41,10 @@ func (r *RootCmd) provisionerList() *serpent.Command {
cliui.TableFormat([]provisionerDaemonRow{}, []string{"created at", "last seen at", "key name", "name", "version", "status", "tags"}),
cliui.JSONFormat(),
)
limit int64
limit int64
offline bool
status []string
maxAge time.Duration
)

cmd := &serpent.Command{
Expand All @@ -59,7 +64,10 @@ func (r *RootCmd) provisionerList() *serpent.Command {
}

daemons, err := client.OrganizationProvisionerDaemons(ctx, org.ID, &codersdk.OrganizationProvisionerDaemonsOptions{
Limit: int(limit),
Limit: int(limit),
Offline: offline,
Status: slice.StringEnums[codersdk.ProvisionerDaemonStatus](status),
MaxAge: maxAge,
})
if err != nil {
return xerrors.Errorf("list provisioner daemons: %w", err)
Expand Down Expand Up @@ -98,6 +106,27 @@ func (r *RootCmd) provisionerList() *serpent.Command {
Default: "50",
Value: serpent.Int64Of(&limit),
},
{
Flag: "show-offline",
FlagShorthand: "f",
Env: "CODER_PROVISIONER_SHOW_OFFLINE",
Description: "Show offline provisioners.",
Value: serpent.BoolOf(&offline),
},
{
Flag: "status",
FlagShorthand: "s",
Env: "CODER_PROVISIONER_LIST_STATUS",
Description: "Filter by provisioner status.",
Value: serpent.EnumArrayOf(&status, slice.ToStrings(codersdk.ProvisionerDaemonStatusEnums())...),
},
{
Flag: "max-age",
FlagShorthand: "m",
Env: "CODER_PROVISIONER_LIST_MAX_AGE",
Description: "Filter provisioners by maximum age.",
Value: serpent.DurationOf(&maxAge),
},
}...)

orgContext.AttachOptions(cmd)
Expand Down
68 changes: 68 additions & 0 deletions cli/provisioners_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,74 @@ func TestProvisioners_Golden(t *testing.T) {
clitest.TestGoldenFile(t, t.Name(), got.Bytes(), replace)
})

t.Run("list with offline provisioner daemons", func(t *testing.T) {
t.Parallel()

var got bytes.Buffer
inv, root := clitest.New(t,
"provisioners",
"list",
"--show-offline",
)
inv.Stdout = &got
clitest.SetupConfig(t, templateAdminClient, root)
err := inv.Run()
require.NoError(t, err)

clitest.TestGoldenFile(t, t.Name(), got.Bytes(), replace)
})

t.Run("list provisioner daemons by status", func(t *testing.T) {
t.Parallel()

var got bytes.Buffer
inv, root := clitest.New(t,
"provisioners",
"list",
"--status=idle,offline,busy",
)
inv.Stdout = &got
clitest.SetupConfig(t, templateAdminClient, root)
err := inv.Run()
require.NoError(t, err)

clitest.TestGoldenFile(t, t.Name(), got.Bytes(), replace)
})

t.Run("list provisioner daemons without offline", func(t *testing.T) {
t.Parallel()

var got bytes.Buffer
inv, root := clitest.New(t,
"provisioners",
"list",
"--status=idle,busy",
)
inv.Stdout = &got
clitest.SetupConfig(t, templateAdminClient, root)
err := inv.Run()
require.NoError(t, err)

clitest.TestGoldenFile(t, t.Name(), got.Bytes(), replace)
})

t.Run("list provisioner daemons by max age", func(t *testing.T) {
t.Parallel()

var got bytes.Buffer
inv, root := clitest.New(t,
"provisioners",
"list",
"--max-age=1h",
)
inv.Stdout = &got
clitest.SetupConfig(t, templateAdminClient, root)
err := inv.Run()
require.NoError(t, err)

clitest.TestGoldenFile(t, t.Name(), got.Bytes(), replace)
})

// Test jobs list with template admin as members are currently
// unable to access provisioner jobs. In the future (with RBAC
// changes), we may allow them to view _their_ jobs.
Expand Down
9 changes: 4 additions & 5 deletions cli/testdata/TestProvisioners_Golden/list.golden
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
ID CREATED AT LAST SEEN AT NAME VERSION TAGS KEY NAME STATUS CURRENT JOB ID CURRENT JOB STATUS PREVIOUS JOB ID PREVIOUS JOB STATUS ORGANIZATION
00000000-0000-0000-aaaa-000000000000 ====[timestamp]===== ====[timestamp]===== default-provisioner v0.0.0-devel map[owner: scope:organization] built-in idle <nil> <nil> 00000000-0000-0000-bbbb-000000000001 succeeded Coder
00000000-0000-0000-aaaa-000000000001 ====[timestamp]===== ====[timestamp]===== provisioner-1 v0.0.0 map[foo:bar owner: scope:organization] built-in busy 00000000-0000-0000-bbbb-000000000002 running <nil> <nil> Coder
00000000-0000-0000-aaaa-000000000002 ====[timestamp]===== ====[timestamp]===== provisioner-2 v0.0.0 map[owner: scope:organization] built-in offline <nil> <nil> 00000000-0000-0000-bbbb-000000000003 succeeded Coder
00000000-0000-0000-aaaa-000000000003 ====[timestamp]===== ====[timestamp]===== provisioner-3 v0.0.0 map[owner: scope:organization] built-in idle <nil> <nil> <nil> <nil> Coder
ID CREATED AT LAST SEEN AT NAME VERSION TAGS KEY NAME STATUS CURRENT JOB ID CURRENT JOB STATUS PREVIOUS JOB ID PREVIOUS JOB STATUS ORGANIZATION
00000000-0000-0000-aaaa-000000000000 ====[timestamp]===== ====[timestamp]===== default-provisioner v0.0.0-devel map[owner: scope:organization] built-in idle <nil> <nil> 00000000-0000-0000-bbbb-000000000001 succeeded Coder
00000000-0000-0000-aaaa-000000000001 ====[timestamp]===== ====[timestamp]===== provisioner-1 v0.0.0 map[foo:bar owner: scope:organization] built-in busy 00000000-0000-0000-bbbb-000000000002 running <nil> <nil> Coder
00000000-0000-0000-aaaa-000000000003 ====[timestamp]===== ====[timestamp]===== provisioner-3 v0.0.0 map[owner: scope:organization] built-in idle <nil> <nil> <nil> <nil> Coder
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATED AT LAST SEEN AT KEY NAME NAME VERSION STATUS TAGS
====[timestamp]===== ====[timestamp]===== built-in default-provisioner v0.0.0-devel idle map[owner: scope:organization]
====[timestamp]===== ====[timestamp]===== built-in provisioner-1 v0.0.0 busy map[foo:bar owner: scope:organization]
====[timestamp]===== ====[timestamp]===== built-in provisioner-3 v0.0.0 idle map[owner: scope:organization]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CREATED AT LAST SEEN AT KEY NAME NAME VERSION STATUS TAGS
====[timestamp]===== ====[timestamp]===== built-in default-provisioner v0.0.0-devel idle map[owner: scope:organization]
====[timestamp]===== ====[timestamp]===== built-in provisioner-1 v0.0.0 busy map[foo:bar owner: scope:organization]
====[timestamp]===== ====[timestamp]===== built-in provisioner-2 v0.0.0 offline map[owner: scope:organization]
====[timestamp]===== ====[timestamp]===== built-in provisioner-3 v0.0.0 idle map[owner: scope:organization]
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATED AT LAST SEEN AT KEY NAME NAME VERSION STATUS TAGS
====[timestamp]===== ====[timestamp]===== built-in default-provisioner v0.0.0-devel idle map[owner: scope:organization]
====[timestamp]===== ====[timestamp]===== built-in provisioner-1 v0.0.0 busy map[foo:bar owner: scope:organization]
====[timestamp]===== ====[timestamp]===== built-in provisioner-3 v0.0.0 idle map[owner: scope:organization]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CREATED AT LAST SEEN AT KEY NAME NAME VERSION STATUS TAGS
====[timestamp]===== ====[timestamp]===== built-in default-provisioner v0.0.0-devel idle map[owner: scope:organization]
====[timestamp]===== ====[timestamp]===== built-in provisioner-1 v0.0.0 busy map[foo:bar owner: scope:organization]
====[timestamp]===== ====[timestamp]===== built-in provisioner-2 v0.0.0 offline map[owner: scope:organization]
====[timestamp]===== ====[timestamp]===== built-in provisioner-3 v0.0.0 idle map[owner: scope:organization]
9 changes: 9 additions & 0 deletions cli/testdata/coder_provisioner_list_--help.golden
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,17 @@ OPTIONS:
-l, --limit int, $CODER_PROVISIONER_LIST_LIMIT (default: 50)
Limit the number of provisioners returned.

-m, --max-age duration, $CODER_PROVISIONER_LIST_MAX_AGE
Filter provisioners by maximum age.

-o, --output table|json (default: table)
Output format.

-f, --show-offline bool, $CODER_PROVISIONER_SHOW_OFFLINE
Show offline provisioners.

-s, --status [offline|idle|busy], $CODER_PROVISIONER_LIST_STATUS
Filter by provisioner status.

———
Run `coder --help` for a list of global options.
20 changes: 6 additions & 14 deletions coderd/agentapi/stats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,12 @@ func TestUpdateStates(t *testing.T) {
Name: "tpl",
}
workspace = database.Workspace{
ID: uuid.New(),
OwnerID: user.ID,
TemplateID: template.ID,
Name: "xyz",
TemplateName: template.Name,
ID: uuid.New(),
OwnerID: user.ID,
OwnerUsername: user.Username,
TemplateID: template.ID,
Name: "xyz",
TemplateName: template.Name,
}
agent = database.WorkspaceAgent{
ID: uuid.New(),
Expand Down Expand Up @@ -138,9 +139,6 @@ func TestUpdateStates(t *testing.T) {
// Workspace gets fetched.
dbM.EXPECT().GetWorkspaceByAgentID(gomock.Any(), agent.ID).Return(workspace, nil)

// User gets fetched to hit the UpdateAgentMetricsFn.
dbM.EXPECT().GetUserByID(gomock.Any(), user.ID).Return(user, nil)

// We expect an activity bump because ConnectionCount > 0.
dbM.EXPECT().ActivityBumpWorkspace(gomock.Any(), database.ActivityBumpWorkspaceParams{
WorkspaceID: workspace.ID,
Expand Down Expand Up @@ -380,9 +378,6 @@ func TestUpdateStates(t *testing.T) {
LastUsedAt: now.UTC(),
}).Return(nil)

// User gets fetched to hit the UpdateAgentMetricsFn.
dbM.EXPECT().GetUserByID(gomock.Any(), user.ID).Return(user, nil)

resp, err := api.UpdateStats(context.Background(), req)
require.NoError(t, err)
require.Equal(t, &agentproto.UpdateStatsResponse{
Expand Down Expand Up @@ -498,9 +493,6 @@ func TestUpdateStates(t *testing.T) {
LastUsedAt: now,
}).Return(nil)

// User gets fetched to hit the UpdateAgentMetricsFn.
dbM.EXPECT().GetUserByID(gomock.Any(), user.ID).Return(user, nil)

// Ensure that pubsub notifications are sent.
notifyDescription := make(chan struct{})
ps.SubscribeWithErr(wspubsub.WorkspaceEventChannel(workspace.OwnerID),
Expand Down
1 change: 1 addition & 0 deletions coderd/database/check_constraint.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion coderd/database/dump.sql

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE users
DROP CONSTRAINT IF EXISTS users_username_min_length;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ALTER TABLE users
ADD CONSTRAINT users_username_min_length
CHECK (length(username) >= 1);
Loading
Loading