chore: append template metadata to protobuf config (#20558)

Adds some extra meta data sent to provisioners. Also adds a field
`reuse_terraform_workspace` to tell the provisioner whether or not to
use the caching experiment.
This commit is contained in:
Steven Masley
2025-11-12 12:46:39 -06:00
committed by GitHub
parent 5e85663ce3
commit 9149c1e9f2
13 changed files with 665 additions and 523 deletions
+1
View File
@@ -622,6 +622,7 @@ func (t TemplateVersionBuilder) Do() TemplateVersionResponse {
}
payload, err := json.Marshal(provisionerdserver.TemplateVersionImportJob{
TemplateID: t.seed.TemplateID,
TemplateVersionID: t.seed.ID,
})
require.NoError(t.t, err)
@@ -43,6 +43,7 @@ import (
"github.com/coder/coder/v2/coderd/tracing"
"github.com/coder/coder/v2/coderd/usage"
"github.com/coder/coder/v2/coderd/usage/usagetypes"
"github.com/coder/coder/v2/coderd/util/ptr"
"github.com/coder/coder/v2/coderd/util/slice"
"github.com/coder/coder/v2/coderd/wspubsub"
"github.com/coder/coder/v2/codersdk"
@@ -697,13 +698,14 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
protoJob.Type = &proto.AcquiredJob_WorkspaceBuild_{
WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{
WorkspaceBuildId: workspaceBuild.ID.String(),
WorkspaceName: workspace.Name,
State: workspaceBuild.ProvisionerState,
RichParameterValues: convertRichParameterValues(workspaceBuildParameters),
PreviousParameterValues: convertRichParameterValues(lastWorkspaceBuildParameters),
VariableValues: asVariableValues(templateVariables),
ExternalAuthProviders: externalAuthProviders,
WorkspaceBuildId: workspaceBuild.ID.String(),
WorkspaceName: workspace.Name,
State: workspaceBuild.ProvisionerState,
RichParameterValues: convertRichParameterValues(workspaceBuildParameters),
PreviousParameterValues: convertRichParameterValues(lastWorkspaceBuildParameters),
VariableValues: asVariableValues(templateVariables),
ExternalAuthProviders: externalAuthProviders,
ExpReuseTerraformWorkspace: ptr.Ref(false), // TODO: Toggle based on experiment
Metadata: &sdkproto.Metadata{
CoderUrl: s.AccessURL.String(),
WorkspaceTransition: transition,
@@ -773,6 +775,11 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
return nil, failJob(err.Error())
}
templateID := ""
if input.TemplateID.Valid {
templateID = input.TemplateID.UUID.String()
}
protoJob.Type = &proto.AcquiredJob_TemplateImport_{
TemplateImport: &proto.AcquiredJob_TemplateImport{
UserVariableValues: convertVariableValues(userVariableValues),
@@ -781,6 +788,8 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
// There is no owner for a template import, but we can assume
// the "Everyone" group as a placeholder.
WorkspaceOwnerGroups: []string{database.EveryoneGroup},
TemplateId: templateID,
TemplateVersionId: input.TemplateVersionID.String(),
},
},
}
@@ -3210,6 +3219,10 @@ func auditActionFromTransition(transition database.WorkspaceTransition) database
}
type TemplateVersionImportJob struct {
// TemplateID is not guaranteed to be set. Template versions can be created
// without being associated with a template. Resulting in a template id of
// `uuid.Nil`
TemplateID uuid.NullUUID `json:"template_id"`
TemplateVersionID uuid.UUID `json:"template_version_id"`
UserVariableValues []codersdk.VariableValue `json:"user_variable_values"`
}
@@ -26,6 +26,7 @@ import (
"storj.io/drpc"
"cdr.dev/slog/sloggers/slogtest"
"github.com/coder/coder/v2/coderd/util/ptr"
"github.com/coder/quartz"
"github.com/coder/serpent"
@@ -59,24 +60,24 @@ import (
)
func testTemplateScheduleStore() *atomic.Pointer[schedule.TemplateScheduleStore] {
ptr := &atomic.Pointer[schedule.TemplateScheduleStore]{}
poitr := &atomic.Pointer[schedule.TemplateScheduleStore]{}
store := schedule.NewAGPLTemplateScheduleStore()
ptr.Store(&store)
return ptr
poitr.Store(&store)
return poitr
}
func testUserQuietHoursScheduleStore() *atomic.Pointer[schedule.UserQuietHoursScheduleStore] {
ptr := &atomic.Pointer[schedule.UserQuietHoursScheduleStore]{}
poitr := &atomic.Pointer[schedule.UserQuietHoursScheduleStore]{}
store := schedule.NewAGPLUserQuietHoursScheduleStore()
ptr.Store(&store)
return ptr
poitr.Store(&store)
return poitr
}
func testUsageInserter() *atomic.Pointer[usage.Inserter] {
ptr := &atomic.Pointer[usage.Inserter]{}
poitr := &atomic.Pointer[usage.Inserter]{}
inserter := usage.NewAGPLInserter()
ptr.Store(&inserter)
return ptr
poitr.Store(&inserter)
return poitr
}
func TestAcquireJob_LongPoll(t *testing.T) {
@@ -474,8 +475,9 @@ func TestAcquireJob(t *testing.T) {
})
want, err := json.Marshal(&proto.AcquiredJob_WorkspaceBuild_{
WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{
WorkspaceBuildId: build.ID.String(),
WorkspaceName: workspace.Name,
ExpReuseTerraformWorkspace: ptr.Ref(false),
WorkspaceBuildId: build.ID.String(),
WorkspaceName: workspace.Name,
VariableValues: []*sdkproto.VariableValue{
{
Name: "first",
@@ -629,6 +631,7 @@ func TestAcquireJob(t *testing.T) {
Metadata: &sdkproto.Metadata{
CoderUrl: (&url.URL{}).String(),
WorkspaceOwnerGroups: []string{database.EveryoneGroup},
TemplateVersionId: uuid.Nil.String(),
},
},
})
@@ -677,6 +680,7 @@ func TestAcquireJob(t *testing.T) {
Metadata: &sdkproto.Metadata{
CoderUrl: (&url.URL{}).String(),
WorkspaceOwnerGroups: []string{database.EveryoneGroup},
TemplateVersionId: version.ID.String(),
},
},
})
@@ -4392,11 +4396,11 @@ type fakeUsageInserter struct {
var _ usage.Inserter = &fakeUsageInserter{}
func newFakeUsageInserter() (*fakeUsageInserter, *atomic.Pointer[usage.Inserter]) {
ptr := &atomic.Pointer[usage.Inserter]{}
poitr := &atomic.Pointer[usage.Inserter]{}
fake := &fakeUsageInserter{}
var inserter usage.Inserter = fake
ptr.Store(&inserter)
return fake, ptr
poitr.Store(&inserter)
return fake, poitr
}
func (f *fakeUsageInserter) InsertDiscreteUsageEvent(_ context.Context, _ database.Store, event usagetypes.DiscreteEvent) error {
+5 -1
View File
@@ -1609,9 +1609,13 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
var matchedProvisioners codersdk.MatchedProvisioners
err = api.Database.InTx(func(tx database.Store) error {
jobID := uuid.New()
templateVersionID := uuid.New()
jobInput, err := json.Marshal(provisionerdserver.TemplateVersionImportJob{
TemplateID: uuid.NullUUID{
UUID: req.TemplateID,
Valid: req.TemplateID != uuid.Nil,
},
TemplateVersionID: templateVersionID,
UserVariableValues: req.UserVariableValues,
})
+9
View File
@@ -10,6 +10,15 @@ import (
"github.com/microcosm-cc/bluemonday"
)
// EmptyToNil returns a `nil` for an empty string, or a pointer to the string
// otherwise. Useful when needing to treat zero values as nil in APIs.
func EmptyToNil(s string) *string {
if s == "" {
return nil
}
return &s
}
// JoinWithConjunction joins a slice of strings with commas except for the last
// two which are joined with "and".
func JoinWithConjunction(s []string) string {