Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6f6787d

Browse files
committed
fix(cli): handle version mismatch re MatchedProvisioners response (#15682)
* Modifies `MatchedProvisioners` response of `codersdk.TemplateVersion`to be a pointer* CLI now checks for absence of `*MatchedProvisioners` before showingwarning regarding provisioners* Extracts logic for warning about provisioners to a function* Improves test coverage for CLI template push with`coder_workspace_tags`.(cherry picked from commit3014713)
1 parent24b8cfe commit6f6787d

File tree

6 files changed

+206
-114
lines changed

6 files changed

+206
-114
lines changed

‎cli/templatepush.go

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -416,30 +416,7 @@ func createValidTemplateVersion(inv *serpent.Invocation, args createValidTemplat
416416
iferr!=nil {
417417
returnnil,err
418418
}
419-
vartagsJSON strings.Builder
420-
iferr:=json.NewEncoder(&tagsJSON).Encode(version.Job.Tags);err!=nil {
421-
// Fall back to the less-pretty string representation.
422-
tagsJSON.Reset()
423-
_,_=tagsJSON.WriteString(fmt.Sprintf("%v",version.Job.Tags))
424-
}
425-
ifversion.MatchedProvisioners.Count==0 {
426-
cliui.Warnf(inv.Stderr,`No provisioners are available to handle the job!
427-
Please contact your deployment administrator for assistance.
428-
Details:
429-
Provisioner job ID : %s
430-
Requested tags : %s
431-
`,version.Job.ID,tagsJSON.String())
432-
}elseifversion.MatchedProvisioners.Available==0 {
433-
cliui.Warnf(inv.Stderr,`All available provisioner daemons have been silent for a while.
434-
Your build will proceed once they become available.
435-
If this persists, please contact your deployment administrator for assistance.
436-
Details:
437-
Provisioner job ID : %s
438-
Requested tags : %s
439-
Most recently seen : %s
440-
`,version.Job.ID,strings.TrimSpace(tagsJSON.String()),version.MatchedProvisioners.MostRecentlySeen.Time)
441-
}
442-
419+
WarnMatchedProvisioners(inv,version)
443420
err=cliui.ProvisionerJob(inv.Context(),inv.Stdout, cliui.ProvisionerJobOptions{
444421
Fetch:func() (codersdk.ProvisionerJob,error) {
445422
version,err:=client.TemplateVersion(inv.Context(),version.ID)
@@ -505,6 +482,41 @@ func ParseProvisionerTags(rawTags []string) (map[string]string, error) {
505482
returntags,nil
506483
}
507484

485+
var (
486+
warnNoMatchedProvisioners=`Your build has been enqueued, but there are no provisioners that accept the required tags. Once a compatible provisioner becomes available, your build will continue. Please contact your administrator.
487+
Details:
488+
Provisioner job ID : %s
489+
Requested tags : %s
490+
`
491+
warnNoAvailableProvisioners=`Provisioners that accept the required tags have not responded for longer than expected. This may delay your build. Please contact your administrator if your build does not complete.
492+
Details:
493+
Provisioner job ID : %s
494+
Requested tags : %s
495+
Most recently seen : %s
496+
`
497+
)
498+
499+
funcWarnMatchedProvisioners(inv*serpent.Invocation,tv codersdk.TemplateVersion) {
500+
iftv.MatchedProvisioners==nil {
501+
// Nothing in the response, nothing to do here!
502+
return
503+
}
504+
vartagsJSON strings.Builder
505+
iferr:=json.NewEncoder(&tagsJSON).Encode(tv.Job.Tags);err!=nil {
506+
// Fall back to the less-pretty string representation.
507+
tagsJSON.Reset()
508+
_,_=tagsJSON.WriteString(fmt.Sprintf("%v",tv.Job.Tags))
509+
}
510+
iftv.MatchedProvisioners.Count==0 {
511+
cliui.Warnf(inv.Stderr,warnNoMatchedProvisioners,tv.Job.ID,tagsJSON.String())
512+
return
513+
}
514+
iftv.MatchedProvisioners.Available==0 {
515+
cliui.Warnf(inv.Stderr,warnNoAvailableProvisioners,tv.Job.ID,strings.TrimSpace(tagsJSON.String()),tv.MatchedProvisioners.MostRecentlySeen.Time)
516+
return
517+
}
518+
}
519+
508520
// prettyDirectoryPath returns a prettified path when inside the users
509521
// home directory. Falls back to dir if the users home directory cannot
510522
// discerned. This function calls filepath.Clean on the result.

‎cli/templatepush_test.go

Lines changed: 156 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cli_test
33
import (
44
"bytes"
55
"context"
6+
"database/sql"
67
"os"
78
"path/filepath"
89
"runtime"
@@ -18,6 +19,7 @@ import (
1819
"github.com/coder/coder/v2/coderd/coderdtest"
1920
"github.com/coder/coder/v2/coderd/database"
2021
"github.com/coder/coder/v2/coderd/database/dbtestutil"
22+
"github.com/coder/coder/v2/coderd/database/dbtime"
2123
"github.com/coder/coder/v2/coderd/rbac"
2224
"github.com/coder/coder/v2/codersdk"
2325
"github.com/coder/coder/v2/provisioner/echo"
@@ -412,84 +414,162 @@ func TestTemplatePush(t *testing.T) {
412414

413415
t.Run("WorkspaceTagsTerraform",func(t*testing.T) {
414416
t.Parallel()
415-
ctx:=testutil.Context(t,testutil.WaitShort)
416417

417-
// Start an instance **without** a built-in provisioner.
418-
// We're not actually testing that the Terraform applies.
419-
// What we test is that a provisioner job is created with the expected
420-
// tags based on the __content__ of the Terraform.
421-
store,ps:=dbtestutil.NewDB(t)
422-
client:=coderdtest.New(t,&coderdtest.Options{
423-
Database:store,
424-
Pubsub:ps,
425-
})
426-
427-
owner:=coderdtest.CreateFirstUser(t,client)
428-
templateAdmin,_:=coderdtest.CreateAnotherUser(t,client,owner.OrganizationID,rbac.RoleTemplateAdmin())
429-
430-
// Create a tar file with some pre-defined content
431-
tarFile:=testutil.CreateTar(t,map[string]string{
432-
"main.tf":`
433-
variable "a" {
434-
type = string
435-
default = "1"
436-
}
437-
data "coder_parameter" "b" {
438-
type = string
439-
default = "2"
440-
}
441-
resource "null_resource" "test" {}
442-
data "coder_workspace_tags" "tags" {
443-
tags = {
444-
"foo": "bar",
445-
"a": var.a,
446-
"b": data.coder_parameter.b.value,
447-
}
448-
}`,
449-
})
450-
451-
// Write the tar file to disk.
452-
tempDir:=t.TempDir()
453-
err:=tfparse.WriteArchive(tarFile,"application/x-tar",tempDir)
454-
require.NoError(t,err)
455-
456-
// Run `coder templates push`
457-
templateName:=strings.ReplaceAll(testutil.GetRandomName(t),"_","-")
458-
varstdout,stderr strings.Builder
459-
inv,root:=clitest.New(t,"templates","push",templateName,"-d",tempDir,"--yes")
460-
inv.Stdout=&stdout
461-
inv.Stderr=&stderr
462-
clitest.SetupConfig(t,templateAdmin,root)
463-
464-
// Don't forget to clean up!
465-
cancelCtx,cancel:=context.WithCancel(ctx)
466-
t.Cleanup(cancel)
467-
done:=make(chanerror)
468-
gofunc() {
469-
done<-inv.WithContext(cancelCtx).Run()
470-
}()
471-
472-
// Assert that a provisioner job was created with the desired tags.
473-
wantTags:=database.StringMap(provisionersdk.MutateTags(uuid.Nil,map[string]string{
474-
"foo":"bar",
475-
"a":"1",
476-
"b":"2",
477-
}))
478-
require.Eventually(t,func()bool {
479-
jobs,err:=store.GetProvisionerJobsCreatedAfter(ctx, time.Time{})
480-
if!assert.NoError(t,err) {
481-
returnfalse
482-
}
483-
iflen(jobs)==0 {
484-
returnfalse
485-
}
486-
returnassert.EqualValues(t,wantTags,jobs[0].Tags)
487-
},testutil.WaitShort,testutil.IntervalSlow)
488-
489-
cancel()
490-
<-done
418+
tests:= []struct {
419+
namestring
420+
setupDaemonfunc(ctx context.Context,store database.Store,owner codersdk.CreateFirstUserResponse,tags database.StringMap,now time.Time)error
421+
expectOutputstring
422+
}{
423+
{
424+
name:"no provisioners available",
425+
setupDaemon:func(_ context.Context,_ database.Store,_ codersdk.CreateFirstUserResponse,_ database.StringMap,_ time.Time)error {
426+
returnnil
427+
},
428+
expectOutput:"there are no provisioners that accept the required tags",
429+
},
430+
{
431+
name:"provisioner stale",
432+
setupDaemon:func(ctx context.Context,store database.Store,owner codersdk.CreateFirstUserResponse,tags database.StringMap,now time.Time)error {
433+
pk,err:=store.InsertProvisionerKey(ctx, database.InsertProvisionerKeyParams{
434+
ID:uuid.New(),
435+
CreatedAt:now,
436+
OrganizationID:owner.OrganizationID,
437+
Name:"test",
438+
Tags:tags,
439+
HashedSecret: []byte("secret"),
440+
})
441+
iferr!=nil {
442+
returnerr
443+
}
444+
oneHourAgo:=now.Add(-time.Hour)
445+
_,err=store.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
446+
Provisioners: []database.ProvisionerType{database.ProvisionerTypeTerraform},
447+
LastSeenAt: sql.NullTime{Time:oneHourAgo,Valid:true},
448+
CreatedAt:oneHourAgo,
449+
Name:"test",
450+
Tags:tags,
451+
OrganizationID:owner.OrganizationID,
452+
KeyID:pk.ID,
453+
})
454+
returnerr
455+
},
456+
expectOutput:"Provisioners that accept the required tags have not responded for longer than expected",
457+
},
458+
{
459+
name:"active provisioner",
460+
setupDaemon:func(ctx context.Context,store database.Store,owner codersdk.CreateFirstUserResponse,tags database.StringMap,now time.Time)error {
461+
pk,err:=store.InsertProvisionerKey(ctx, database.InsertProvisionerKeyParams{
462+
ID:uuid.New(),
463+
CreatedAt:now,
464+
OrganizationID:owner.OrganizationID,
465+
Name:"test",
466+
Tags:tags,
467+
HashedSecret: []byte("secret"),
468+
})
469+
iferr!=nil {
470+
returnerr
471+
}
472+
_,err=store.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
473+
Provisioners: []database.ProvisionerType{database.ProvisionerTypeTerraform},
474+
LastSeenAt: sql.NullTime{Time:now,Valid:true},
475+
CreatedAt:now,
476+
Name:"test-active",
477+
Tags:tags,
478+
OrganizationID:owner.OrganizationID,
479+
KeyID:pk.ID,
480+
})
481+
returnerr
482+
},
483+
expectOutput:"",
484+
},
485+
}
491486

492-
require.Contains(t,stderr.String(),"No provisioners are available to handle the job!")
487+
for_,tt:=rangetests {
488+
tt:=tt
489+
t.Run(tt.name,func(t*testing.T) {
490+
t.Parallel()
491+
492+
// Start an instance **without** a built-in provisioner.
493+
// We're not actually testing that the Terraform applies.
494+
// What we test is that a provisioner job is created with the expected
495+
// tags based on the __content__ of the Terraform.
496+
store,ps:=dbtestutil.NewDB(t)
497+
client:=coderdtest.New(t,&coderdtest.Options{
498+
Database:store,
499+
Pubsub:ps,
500+
})
501+
502+
owner:=coderdtest.CreateFirstUser(t,client)
503+
templateAdmin,_:=coderdtest.CreateAnotherUser(t,client,owner.OrganizationID,rbac.RoleTemplateAdmin())
504+
505+
// Create a tar file with some pre-defined content
506+
tarFile:=testutil.CreateTar(t,map[string]string{
507+
"main.tf":`
508+
variable "a" {
509+
type = string
510+
default = "1"
511+
}
512+
data "coder_parameter" "b" {
513+
type = string
514+
default = "2"
515+
}
516+
resource "null_resource" "test" {}
517+
data "coder_workspace_tags" "tags" {
518+
tags = {
519+
"a": var.a,
520+
"b": data.coder_parameter.b.value,
521+
"test_name": "`+tt.name+`"
522+
}
523+
}`,
524+
})
525+
526+
// Write the tar file to disk.
527+
tempDir:=t.TempDir()
528+
err:=tfparse.WriteArchive(tarFile,"application/x-tar",tempDir)
529+
require.NoError(t,err)
530+
531+
wantTags:=database.StringMap(provisionersdk.MutateTags(uuid.Nil,map[string]string{
532+
"a":"1",
533+
"b":"2",
534+
"test_name":tt.name,
535+
}))
536+
537+
templateName:=strings.ReplaceAll(testutil.GetRandomName(t),"_","-")
538+
539+
inv,root:=clitest.New(t,"templates","push",templateName,"-d",tempDir,"--yes")
540+
clitest.SetupConfig(t,templateAdmin,root)
541+
pty:=ptytest.New(t).Attach(inv)
542+
543+
ctx:=testutil.Context(t,testutil.WaitShort)
544+
now:=dbtime.Now()
545+
require.NoError(t,tt.setupDaemon(ctx,store,owner,wantTags,now))
546+
547+
cancelCtx,cancel:=context.WithCancel(ctx)
548+
t.Cleanup(cancel)
549+
done:=make(chanerror)
550+
gofunc() {
551+
done<-inv.WithContext(cancelCtx).Run()
552+
}()
553+
554+
require.Eventually(t,func()bool {
555+
jobs,err:=store.GetProvisionerJobsCreatedAfter(ctx, time.Time{})
556+
if!assert.NoError(t,err) {
557+
returnfalse
558+
}
559+
iflen(jobs)==0 {
560+
returnfalse
561+
}
562+
returnassert.EqualValues(t,wantTags,jobs[0].Tags)
563+
},testutil.WaitShort,testutil.IntervalFast)
564+
565+
iftt.expectOutput!="" {
566+
pty.ExpectMatch(tt.expectOutput)
567+
}
568+
569+
cancel()
570+
<-done
571+
})
572+
}
493573
})
494574

495575
t.Run("ChangeTags",func(t*testing.T) {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp