mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat!: extract provisioner tags from coder_workspace_tags data source (#15578)
Relates to https://github.com/coder/coder/issues/15087 and https://github.com/coder/coder/issues/15427 - Extracts provisioner job tags from `coder_workspace_tags` on template version creation using `provisioner/terraform/tfparse` added in https://github.com/coder/coder/pull/15236 - Drops a WARN log in coderd if no matching provisioners found. - Also drops a warning message in the CLI if no provisioners are found. - To support both CLI and UI warnings, added a `codersdk.MatchedProvisioners` struct to the `TemplateVersion` response containing details of how many provisioners were around at the time of the insert. Co-authored-by: Mathias Fredriksson <mafredri@gmail.com>
This commit is contained in:
co-authored by
Mathias Fredriksson
parent
648cdd006c
commit
1cdc3e8921
@@ -2,6 +2,7 @@ package cli
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -415,6 +416,29 @@ func createValidTemplateVersion(inv *serpent.Invocation, args createValidTemplat
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var tagsJSON strings.Builder
|
||||
if err := json.NewEncoder(&tagsJSON).Encode(version.Job.Tags); err != nil {
|
||||
// Fall back to the less-pretty string representation.
|
||||
tagsJSON.Reset()
|
||||
_, _ = tagsJSON.WriteString(fmt.Sprintf("%v", version.Job.Tags))
|
||||
}
|
||||
if version.MatchedProvisioners.Count == 0 {
|
||||
cliui.Warnf(inv.Stderr, `No provisioners are available to handle the job!
|
||||
Please contact your deployment administrator for assistance.
|
||||
Details:
|
||||
Provisioner job ID : %s
|
||||
Requested tags : %s
|
||||
`, version.Job.ID, tagsJSON.String())
|
||||
} else if version.MatchedProvisioners.Available == 0 {
|
||||
cliui.Warnf(inv.Stderr, `All available provisioner daemons have been silent for a while.
|
||||
Your build will proceed once they become available.
|
||||
If this persists, please contact your deployment administrator for assistance.
|
||||
Details:
|
||||
Provisioner job ID : %s
|
||||
Requested tags : %s
|
||||
Most recently seen : %s
|
||||
`, version.Job.ID, strings.TrimSpace(tagsJSON.String()), version.MatchedProvisioners.MostRecentlySeen.Time)
|
||||
}
|
||||
|
||||
err = cliui.ProvisionerJob(inv.Context(), inv.Stdout, cliui.ProvisionerJobOptions{
|
||||
Fetch: func() (codersdk.ProvisionerJob, error) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -16,9 +17,12 @@ import (
|
||||
"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/dbtestutil"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/provisioner/echo"
|
||||
"github.com/coder/coder/v2/provisioner/terraform/tfparse"
|
||||
"github.com/coder/coder/v2/provisionersdk"
|
||||
"github.com/coder/coder/v2/provisionersdk/proto"
|
||||
"github.com/coder/coder/v2/pty/ptytest"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
@@ -406,6 +410,88 @@ func TestTemplatePush(t *testing.T) {
|
||||
t.Run("ProvisionerTags", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("WorkspaceTagsTerraform", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := testutil.Context(t, testutil.WaitShort)
|
||||
|
||||
// Start an instance **without** a built-in provisioner.
|
||||
// We're not actually testing that the Terraform applies.
|
||||
// What we test is that a provisioner job is created with the expected
|
||||
// tags based on the __content__ of the Terraform.
|
||||
store, ps := dbtestutil.NewDB(t)
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
Database: store,
|
||||
Pubsub: ps,
|
||||
})
|
||||
|
||||
owner := coderdtest.CreateFirstUser(t, client)
|
||||
templateAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin())
|
||||
|
||||
// Create a tar file with some pre-defined content
|
||||
tarFile := testutil.CreateTar(t, map[string]string{
|
||||
"main.tf": `
|
||||
variable "a" {
|
||||
type = string
|
||||
default = "1"
|
||||
}
|
||||
data "coder_parameter" "b" {
|
||||
type = string
|
||||
default = "2"
|
||||
}
|
||||
resource "null_resource" "test" {}
|
||||
data "coder_workspace_tags" "tags" {
|
||||
tags = {
|
||||
"foo": "bar",
|
||||
"a": var.a,
|
||||
"b": data.coder_parameter.b.value,
|
||||
}
|
||||
}`,
|
||||
})
|
||||
|
||||
// Write the tar file to disk.
|
||||
tempDir := t.TempDir()
|
||||
err := tfparse.WriteArchive(tarFile, "application/x-tar", tempDir)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Run `coder templates push`
|
||||
templateName := strings.ReplaceAll(testutil.GetRandomName(t), "_", "-")
|
||||
var stdout, stderr strings.Builder
|
||||
inv, root := clitest.New(t, "templates", "push", templateName, "-d", tempDir, "--yes")
|
||||
inv.Stdout = &stdout
|
||||
inv.Stderr = &stderr
|
||||
clitest.SetupConfig(t, templateAdmin, root)
|
||||
|
||||
// Don't forget to clean up!
|
||||
cancelCtx, cancel := context.WithCancel(ctx)
|
||||
t.Cleanup(cancel)
|
||||
done := make(chan error)
|
||||
go func() {
|
||||
done <- inv.WithContext(cancelCtx).Run()
|
||||
}()
|
||||
|
||||
// Assert that a provisioner job was created with the desired tags.
|
||||
wantTags := database.StringMap(provisionersdk.MutateTags(uuid.Nil, map[string]string{
|
||||
"foo": "bar",
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
}))
|
||||
require.Eventually(t, func() bool {
|
||||
jobs, err := store.GetProvisionerJobsCreatedAfter(ctx, time.Time{})
|
||||
if !assert.NoError(t, err) {
|
||||
return false
|
||||
}
|
||||
if len(jobs) == 0 {
|
||||
return false
|
||||
}
|
||||
return assert.EqualValues(t, wantTags, jobs[0].Tags)
|
||||
}, testutil.WaitShort, testutil.IntervalSlow)
|
||||
|
||||
cancel()
|
||||
<-done
|
||||
|
||||
require.Contains(t, stderr.String(), "No provisioners are available to handle the job!")
|
||||
})
|
||||
|
||||
t.Run("ChangeTags", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user