- Notifications
You must be signed in to change notification settings - Fork1k
feat(cli): add provisioner job cancel command#16252
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
efdcbba
f217a5e
eb3f94e
57f76d6
8e8b451
31007a7
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
package cli_test | ||
import ( | ||
"bytes" | ||
"database/sql" | ||
"encoding/json" | ||
"fmt" | ||
"testing" | ||
"time" | ||
"github.com/aws/smithy-go/ptr" | ||
"github.com/google/uuid" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"github.com/coder/coder/v2/cli/clitest" | ||
"github.com/coder/coder/v2/coderd/coderdtest" | ||
"github.com/coder/coder/v2/coderd/database" | ||
"github.com/coder/coder/v2/coderd/database/dbgen" | ||
"github.com/coder/coder/v2/coderd/database/dbtestutil" | ||
"github.com/coder/coder/v2/coderd/rbac" | ||
"github.com/coder/coder/v2/codersdk" | ||
"github.com/coder/coder/v2/testutil" | ||
) | ||
func TestProvisionerJobs(t *testing.T) { | ||
t.Parallel() | ||
mafredri marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
db, ps := dbtestutil.NewDB(t) | ||
client, _, coderdAPI := coderdtest.NewWithAPI(t, &coderdtest.Options{ | ||
IncludeProvisionerDaemon: false, | ||
Database: db, | ||
Pubsub: ps, | ||
}) | ||
owner := coderdtest.CreateFirstUser(t, client) | ||
templateAdminClient, templateAdmin := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.ScopedRoleOrgTemplateAdmin(owner.OrganizationID)) | ||
memberClient, member := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) | ||
// Create initial resources with a running provisioner. | ||
firstProvisioner := coderdtest.NewTaggedProvisionerDaemon(t, coderdAPI, "default-provisioner", map[string]string{"owner": "", "scope": "organization"}) | ||
t.Cleanup(func() { _ = firstProvisioner.Close() }) | ||
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, completeWithAgent()) | ||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) | ||
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID, func(req *codersdk.CreateTemplateRequest) { | ||
req.AllowUserCancelWorkspaceJobs = ptr.Bool(true) | ||
}) | ||
// Stop the provisioner so it doesn't grab any more jobs. | ||
firstProvisioner.Close() | ||
t.Run("Cancel", func(t *testing.T) { | ||
t.Parallel() | ||
// Set up test helpers. | ||
type jobInput struct { | ||
WorkspaceBuildID string `json:"workspace_build_id,omitempty"` | ||
TemplateVersionID string `json:"template_version_id,omitempty"` | ||
DryRun bool `json:"dry_run,omitempty"` | ||
} | ||
prepareJob := func(t *testing.T, input jobInput) database.ProvisionerJob { | ||
t.Helper() | ||
inputBytes, err := json.Marshal(input) | ||
require.NoError(t, err) | ||
var typ database.ProvisionerJobType | ||
switch { | ||
case input.WorkspaceBuildID != "": | ||
typ = database.ProvisionerJobTypeWorkspaceBuild | ||
case input.TemplateVersionID != "": | ||
if input.DryRun { | ||
typ = database.ProvisionerJobTypeTemplateVersionDryRun | ||
} else { | ||
typ = database.ProvisionerJobTypeTemplateVersionImport | ||
} | ||
default: | ||
t.Fatal("invalid input") | ||
} | ||
var ( | ||
tags = database.StringMap{"owner": "", "scope": "organization", "foo": uuid.New().String()} | ||
_ = dbgen.ProvisionerDaemon(t, db, database.ProvisionerDaemon{Tags: tags}) | ||
job = dbgen.ProvisionerJob(t, db, coderdAPI.Pubsub, database.ProvisionerJob{ | ||
InitiatorID: member.ID, | ||
Input: json.RawMessage(inputBytes), | ||
Type: typ, | ||
Tags: tags, | ||
StartedAt: sql.NullTime{Time: coderdAPI.Clock.Now().Add(-time.Minute), Valid: true}, | ||
}) | ||
) | ||
return job | ||
} | ||
prepareWorkspaceBuildJob := func(t *testing.T) database.ProvisionerJob { | ||
t.Helper() | ||
var ( | ||
wbID = uuid.New() | ||
job = prepareJob(t, jobInput{WorkspaceBuildID: wbID.String()}) | ||
w = dbgen.Workspace(t, db, database.WorkspaceTable{ | ||
OrganizationID: owner.OrganizationID, | ||
OwnerID: member.ID, | ||
TemplateID: template.ID, | ||
}) | ||
_ = dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ | ||
ID: wbID, | ||
InitiatorID: member.ID, | ||
WorkspaceID: w.ID, | ||
TemplateVersionID: version.ID, | ||
JobID: job.ID, | ||
}) | ||
) | ||
return job | ||
} | ||
prepareTemplateVersionImportJobBuilder := func(t *testing.T, dryRun bool) database.ProvisionerJob { | ||
t.Helper() | ||
var ( | ||
tvID = uuid.New() | ||
job = prepareJob(t, jobInput{TemplateVersionID: tvID.String(), DryRun: dryRun}) | ||
_ = dbgen.TemplateVersion(t, db, database.TemplateVersion{ | ||
OrganizationID: owner.OrganizationID, | ||
CreatedBy: templateAdmin.ID, | ||
ID: tvID, | ||
TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true}, | ||
JobID: job.ID, | ||
}) | ||
) | ||
return job | ||
} | ||
prepareTemplateVersionImportJob := func(t *testing.T) database.ProvisionerJob { | ||
return prepareTemplateVersionImportJobBuilder(t, false) | ||
} | ||
prepareTemplateVersionImportJobDryRun := func(t *testing.T) database.ProvisionerJob { | ||
return prepareTemplateVersionImportJobBuilder(t, true) | ||
} | ||
// Run the cancellation test suite. | ||
for _, tt := range []struct { | ||
role string | ||
client *codersdk.Client | ||
name string | ||
prepare func(*testing.T) database.ProvisionerJob | ||
wantCancelled bool | ||
}{ | ||
{"Owner", client, "WorkspaceBuild", prepareWorkspaceBuildJob, true}, | ||
{"Owner", client, "TemplateVersionImport", prepareTemplateVersionImportJob, true}, | ||
{"Owner", client, "TemplateVersionImportDryRun", prepareTemplateVersionImportJobDryRun, true}, | ||
{"TemplateAdmin", templateAdminClient, "WorkspaceBuild", prepareWorkspaceBuildJob, false}, | ||
{"TemplateAdmin", templateAdminClient, "TemplateVersionImport", prepareTemplateVersionImportJob, true}, | ||
{"TemplateAdmin", templateAdminClient, "TemplateVersionImportDryRun", prepareTemplateVersionImportJobDryRun, false}, | ||
{"Member", memberClient, "WorkspaceBuild", prepareWorkspaceBuildJob, false}, | ||
{"Member", memberClient, "TemplateVersionImport", prepareTemplateVersionImportJob, false}, | ||
{"Member", memberClient, "TemplateVersionImportDryRun", prepareTemplateVersionImportJobDryRun, false}, | ||
} { | ||
tt := tt | ||
wantMsg := "OK" | ||
if !tt.wantCancelled { | ||
wantMsg = "FAIL" | ||
} | ||
t.Run(fmt.Sprintf("%s/%s/%v", tt.role, tt.name, wantMsg), func(t *testing.T) { | ||
t.Parallel() | ||
job := tt.prepare(t) | ||
require.False(t, job.CanceledAt.Valid, "job.CanceledAt.Valid") | ||
inv, root := clitest.New(t, "provisioner", "jobs", "cancel", job.ID.String()) | ||
clitest.SetupConfig(t, tt.client, root) | ||
var buf bytes.Buffer | ||
inv.Stdout = &buf | ||
err := inv.Run() | ||
if tt.wantCancelled { | ||
assert.NoError(t, err) | ||
} else { | ||
assert.Error(t, err) | ||
} | ||
job, err = db.GetProvisionerJobByID(testutil.Context(t, testutil.WaitShort), job.ID) | ||
require.NoError(t, err) | ||
assert.Equal(t, tt.wantCancelled, job.CanceledAt.Valid, "job.CanceledAt.Valid") | ||
assert.Equal(t, tt.wantCancelled, job.CanceledAt.Time.After(job.StartedAt.Time), "job.CanceledAt.Time") | ||
if tt.wantCancelled { | ||
assert.Contains(t, buf.String(), "Job canceled") | ||
} else { | ||
assert.NotContains(t, buf.String(), "Job canceled") | ||
} | ||
}) | ||
} | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
coder v0.0.0-devel | ||
USAGE: | ||
coder provisioner jobs cancel [flags] <job_id> | ||
Cancel a provisioner job | ||
OPTIONS: | ||
-O, --org string, $CODER_ORGANIZATION | ||
Select which organization (uuid or name) to use. | ||
——— | ||
Run `coder --help` for a list of global options. |
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.