Skip to content

Commit baa157f

Browse files
committed
Merge remote-tracking branch 'origin/main' into agent-metadata
2 parents 93de24e + d7d210d commit baa157f

File tree

8 files changed

+166
-20
lines changed

8 files changed

+166
-20
lines changed

coderd/provisionerjobs.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,8 @@ func (api *API) followProvisionerJobLogs(actor rbac.Subject, jobID uuid.UUID) (<
347347
logger := api.Logger.With(slog.F("job_id", jobID))
348348

349349
var (
350-
bufferedLogs = make(chan *database.ProvisionerJobLog, 128)
350+
// With debug logging enabled length = 128 is insufficient
351+
bufferedLogs = make(chan *database.ProvisionerJobLog, 1024)
351352
endOfLogs atomic.Bool
352353
lastSentLogID atomic.Int64
353354
)

provisioner/terraform/executor.go

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,17 @@ func (e *executor) planResources(ctx, killCtx context.Context, planfilePath stri
259259
modules = append(modules, plan.PriorState.Values.RootModule)
260260
}
261261
modules = append(modules, plan.PlannedValues.RootModule)
262-
return ConvertState(modules, rawGraph)
262+
263+
rawParameterNames, err := rawRichParameterNames(e.workdir)
264+
if err != nil {
265+
return nil, xerrors.Errorf("raw rich parameter names: %w", err)
266+
}
267+
268+
state, err := ConvertState(modules, rawGraph, rawParameterNames)
269+
if err != nil {
270+
return nil, err
271+
}
272+
return state, nil
263273
}
264274

265275
// showPlan must only be called while the lock is held.
@@ -366,9 +376,14 @@ func (e *executor) stateResources(ctx, killCtx context.Context) (*State, error)
366376
}
367377
converted := &State{}
368378
if state.Values != nil {
379+
rawParameterNames, err := rawRichParameterNames(e.workdir)
380+
if err != nil {
381+
return nil, xerrors.Errorf("raw rich parameter names: %w", err)
382+
}
383+
369384
converted, err = ConvertState([]*tfjson.StateModule{
370385
state.Values.RootModule,
371-
}, rawGraph)
386+
}, rawGraph, rawParameterNames)
372387
if err != nil {
373388
return nil, err
374389
}
@@ -445,7 +460,27 @@ func readAndLog(sink logSink, r io.Reader, done chan<- any, level proto.LogLevel
445460
defer close(done)
446461
scanner := bufio.NewScanner(r)
447462
for scanner.Scan() {
448-
sink.Log(&proto.Log{Level: level, Output: scanner.Text()})
463+
var log terraformProvisionLog
464+
err := json.Unmarshal(scanner.Bytes(), &log)
465+
if err != nil {
466+
if strings.TrimSpace(scanner.Text()) == "" {
467+
continue
468+
}
469+
470+
sink.Log(&proto.Log{Level: level, Output: scanner.Text()})
471+
continue
472+
}
473+
474+
logLevel := convertTerraformLogLevel(log.Level, sink)
475+
if logLevel == proto.LogLevel_TRACE {
476+
continue // skip TRACE log entries as they produce a lot of noise
477+
}
478+
479+
// Degrade JSON log entries marked as INFO as these are logs produced in debug mode.
480+
if logLevel == proto.LogLevel_INFO {
481+
logLevel = proto.LogLevel_DEBUG
482+
}
483+
sink.Log(&proto.Log{Level: logLevel, Output: log.Message})
449484
}
450485
}
451486

provisioner/terraform/parameters.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package terraform
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path"
7+
"strings"
8+
9+
"github.com/hashicorp/hcl/v2"
10+
"github.com/hashicorp/hcl/v2/hclparse"
11+
)
12+
13+
var terraformWithCoderParametersSchema = &hcl.BodySchema{
14+
Blocks: []hcl.BlockHeaderSchema{
15+
{
16+
Type: "data",
17+
LabelNames: []string{"coder_parameter", "*"},
18+
},
19+
},
20+
}
21+
22+
func rawRichParameterNames(workdir string) ([]string, error) {
23+
entries, err := os.ReadDir(workdir)
24+
if err != nil {
25+
return nil, err
26+
}
27+
28+
var coderParameterNames []string
29+
for _, entry := range entries {
30+
if !strings.HasSuffix(entry.Name(), ".tf") {
31+
continue
32+
}
33+
34+
hclFilepath := path.Join(workdir, entry.Name())
35+
parser := hclparse.NewParser()
36+
parsedHCL, diags := parser.ParseHCLFile(hclFilepath)
37+
if diags.HasErrors() {
38+
return nil, hcl.Diagnostics{
39+
{
40+
Severity: hcl.DiagError,
41+
Summary: "Failed to parse HCL file",
42+
Detail: fmt.Sprintf("parser.ParseHCLFile can't parse %q file", hclFilepath),
43+
},
44+
}
45+
}
46+
47+
content, _, _ := parsedHCL.Body.PartialContent(terraformWithCoderParametersSchema)
48+
for _, block := range content.Blocks {
49+
if block.Type == "data" && block.Labels[0] == "coder_parameter" && len(block.Labels) == 2 {
50+
coderParameterNames = append(coderParameterNames, block.Labels[1])
51+
}
52+
}
53+
}
54+
return coderParameterNames, nil
55+
}

provisioner/terraform/provision.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ func provisionEnv(config *proto.Provision_Config, params []*proto.ParameterValue
236236
for _, gitAuth := range gitAuth {
237237
env = append(env, provider.GitAuthAccessTokenEnvironmentVariable(gitAuth.Id)+"="+gitAuth.AccessToken)
238238
}
239+
// FIXME env = append(env, "TF_LOG=JSON")
239240
return env, nil
240241
}
241242

provisioner/terraform/provision_test.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -328,11 +328,17 @@ func TestProvision(t *testing.T) {
328328
required_providers {
329329
coder = {
330330
source = "coder/coder"
331-
version = "0.6.6"
331+
version = "0.6.20"
332332
}
333333
}
334334
}
335335
336+
data "coder_parameter" "sample" {
337+
name = "Sample"
338+
type = "string"
339+
default = "foobaz"
340+
}
341+
336342
data "coder_parameter" "example" {
337343
name = "Example"
338344
type = "string"
@@ -347,6 +353,10 @@ func TestProvision(t *testing.T) {
347353
},
348354
Request: &proto.Provision_Plan{
349355
RichParameterValues: []*proto.RichParameterValue{
356+
{
357+
Name: "Sample",
358+
Value: "foofoo",
359+
},
350360
{
351361
Name: "Example",
352362
Value: "foobaz",
@@ -356,6 +366,18 @@ func TestProvision(t *testing.T) {
356366
Response: &proto.Provision_Response{
357367
Type: &proto.Provision_Response_Complete{
358368
Complete: &proto.Provision_Complete{
369+
Parameters: []*proto.RichParameter{
370+
{
371+
Name: "Sample",
372+
Type: "string",
373+
DefaultValue: "foobaz",
374+
},
375+
{
376+
Name: "Example",
377+
Type: "string",
378+
DefaultValue: "foobar",
379+
},
380+
},
359381
Resources: []*proto.Resource{{
360382
Name: "example",
361383
Type: "null_resource",
@@ -441,6 +463,7 @@ func TestProvision(t *testing.T) {
441463
planRequest.GetPlan().Config = &proto.Provision_Config{}
442464
}
443465
planRequest.GetPlan().ParameterValues = testCase.Request.ParameterValues
466+
planRequest.GetPlan().RichParameterValues = testCase.Request.RichParameterValues
444467
planRequest.GetPlan().GitAuthProviders = testCase.Request.GitAuthProviders
445468
if testCase.Request.Config != nil {
446469
planRequest.GetPlan().Config.State = testCase.Request.Config.State
@@ -499,15 +522,20 @@ func TestProvision(t *testing.T) {
499522
}
500523

501524
if testCase.Response != nil {
525+
require.Equal(t, testCase.Response.GetComplete().Error, msg.GetComplete().Error)
526+
502527
resourcesGot, err := json.Marshal(msg.GetComplete().Resources)
503528
require.NoError(t, err)
504-
505529
resourcesWant, err := json.Marshal(testCase.Response.GetComplete().Resources)
506530
require.NoError(t, err)
507531

508-
require.Equal(t, testCase.Response.GetComplete().Error, msg.GetComplete().Error)
509-
510532
require.Equal(t, string(resourcesWant), string(resourcesGot))
533+
534+
parametersGot, err := json.Marshal(msg.GetComplete().Parameters)
535+
require.NoError(t, err)
536+
parametersWant, err := json.Marshal(testCase.Response.GetComplete().Parameters)
537+
require.NoError(t, err)
538+
require.Equal(t, string(parametersWant), string(parametersGot))
511539
}
512540
break
513541
}

provisioner/terraform/resources.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ type State struct {
9292
// ConvertState consumes Terraform state and a GraphViz representation
9393
// produced by `terraform graph` to produce resources consumable by Coder.
9494
// nolint:gocyclo
95-
func ConvertState(modules []*tfjson.StateModule, rawGraph string) (*State, error) {
95+
func ConvertState(modules []*tfjson.StateModule, rawGraph string, rawParameterNames []string) (*State, error) {
9696
parsedGraph, err := gographviz.ParseString(rawGraph)
9797
if err != nil {
9898
return nil, xerrors.Errorf("parse graph: %w", err)
@@ -463,10 +463,7 @@ func ConvertState(modules []*tfjson.StateModule, rawGraph string) (*State, error
463463
}
464464

465465
parameters := make([]*proto.RichParameter, 0)
466-
for _, resource := range tfResourcesRichParameters {
467-
if resource.Type != "coder_parameter" {
468-
continue
469-
}
466+
for _, resource := range orderedRichParametersResources(tfResourcesRichParameters, rawParameterNames) {
470467
var param provider.Parameter
471468
err = mapstructure.Decode(resource.AttributeValues, &param)
472469
if err != nil {
@@ -650,3 +647,19 @@ func findResourcesInGraph(graph *gographviz.Graph, tfResourcesByLabel map[string
650647

651648
return graphResources
652649
}
650+
651+
func orderedRichParametersResources(tfResourcesRichParameters []*tfjson.StateResource, orderedNames []string) []*tfjson.StateResource {
652+
if len(orderedNames) == 0 {
653+
return tfResourcesRichParameters
654+
}
655+
656+
ordered := make([]*tfjson.StateResource, len(orderedNames))
657+
for i, name := range orderedNames {
658+
for _, resource := range tfResourcesRichParameters {
659+
if resource.Name == name {
660+
ordered[i] = resource
661+
}
662+
}
663+
}
664+
return ordered
665+
}

provisioner/terraform/resources_test.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"path/filepath"
77
"runtime"
88
"sort"
9+
"strings"
910
"testing"
1011

1112
protobuf "github.com/golang/protobuf/proto"
@@ -366,7 +367,7 @@ func TestConvertResources(t *testing.T) {
366367
// and that no errors occur!
367368
modules = append(modules, tfPlan.PlannedValues.RootModule)
368369
}
369-
state, err := terraform.ConvertState(modules, string(tfPlanGraph))
370+
state, err := terraform.ConvertState(modules, string(tfPlanGraph), richParameterResourceNames(expected.parameters))
370371
require.NoError(t, err)
371372
sortResources(state.Resources)
372373
sort.Strings(state.GitAuthProviders)
@@ -419,7 +420,7 @@ func TestConvertResources(t *testing.T) {
419420
tfStateGraph, err := os.ReadFile(filepath.Join(dir, folderName+".tfstate.dot"))
420421
require.NoError(t, err)
421422

422-
state, err := terraform.ConvertState([]*tfjson.StateModule{tfState.Values.RootModule}, string(tfStateGraph))
423+
state, err := terraform.ConvertState([]*tfjson.StateModule{tfState.Values.RootModule}, string(tfStateGraph), richParameterResourceNames(expected.parameters))
423424
require.NoError(t, err)
424425
sortResources(state.Resources)
425426
sort.Strings(state.GitAuthProviders)
@@ -478,7 +479,7 @@ func TestAppSlugValidation(t *testing.T) {
478479
}
479480
}
480481

481-
state, err := terraform.ConvertState([]*tfjson.StateModule{tfPlan.PlannedValues.RootModule}, string(tfPlanGraph))
482+
state, err := terraform.ConvertState([]*tfjson.StateModule{tfPlan.PlannedValues.RootModule}, string(tfPlanGraph), nil)
482483
require.Nil(t, state)
483484
require.Error(t, err)
484485
require.ErrorContains(t, err, "invalid app slug")
@@ -490,7 +491,7 @@ func TestAppSlugValidation(t *testing.T) {
490491
}
491492
}
492493

493-
state, err = terraform.ConvertState([]*tfjson.StateModule{tfPlan.PlannedValues.RootModule}, string(tfPlanGraph))
494+
state, err = terraform.ConvertState([]*tfjson.StateModule{tfPlan.PlannedValues.RootModule}, string(tfPlanGraph), nil)
494495
require.Nil(t, state)
495496
require.Error(t, err)
496497
require.ErrorContains(t, err, "duplicate app slug")
@@ -540,7 +541,7 @@ func TestInstanceTypeAssociation(t *testing.T) {
540541
subgraph "root" {
541542
"[root] `+tc.ResourceType+`.dev" [label = "`+tc.ResourceType+`.dev", shape = "box"]
542543
}
543-
}`)
544+
}`, nil)
544545
require.NoError(t, err)
545546
require.Len(t, state.Resources, 1)
546547
require.Equal(t, state.Resources[0].GetInstanceType(), instanceType)
@@ -611,7 +612,7 @@ func TestInstanceIDAssociation(t *testing.T) {
611612
"[root] `+tc.ResourceType+`.dev" -> "[root] coder_agent.dev"
612613
}
613614
}
614-
`)
615+
`, nil)
615616
require.NoError(t, err)
616617
require.Len(t, state.Resources, 1)
617618
require.Len(t, state.Resources[0].Agents, 1)
@@ -640,3 +641,11 @@ func sortResources(resources []*proto.Resource) {
640641
})
641642
}
642643
}
644+
645+
func richParameterResourceNames(parameters []*proto.RichParameter) []string {
646+
var names []string
647+
for _, p := range parameters {
648+
names = append(names, strings.ToLower(p.Name))
649+
}
650+
return names
651+
}

site/src/components/Logs/Logs.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,11 @@ const useStyles = makeStyles<
108108
backgroundColor: theme.palette.error.dark,
109109
},
110110

111-
"&.warning": {
111+
"&.debug": {
112+
backgroundColor: theme.palette.grey[900],
113+
},
114+
115+
"&.warn": {
112116
backgroundColor: theme.palette.warning.dark,
113117
},
114118
},

0 commit comments

Comments
 (0)