Skip to content

Commit a04fc83

Browse files
committed
Merge branch 'main' of github.com:coder/coder into bq/3075
2 parents fdfc130 + 7d07e67 commit a04fc83

40 files changed

+830
-151
lines changed

.github/workflows/coder.yaml

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,18 +219,25 @@ jobs:
219219
run: go run scripts/datadog-cireport/main.go gotests.xml
220220

221221
- uses: codecov/codecov-action@v3
222+
# This action has a tendency to error out unexpectedly, it has
223+
# the `fail_ci_if_error` option that defaults to `false`, but
224+
# that is no guarantee, see:
225+
# https://github.com/codecov/codecov-action/issues/788
226+
continue-on-error: true
222227
if: github.actor != 'dependabot[bot]' && !github.event.pull_request.head.repo.fork
223228
with:
224229
token: ${{ secrets.CODECOV_TOKEN }}
225230
files: ./gotests.coverage
226231
flags: unittest-go-${{ matrix.os }}
227-
# this flakes and sometimes fails the build
228-
fail_ci_if_error: false
229232

230233
test-go-postgres:
231234
name: "test/go/postgres"
232235
runs-on: ubuntu-latest
233-
timeout-minutes: 20
236+
# This timeout must be greater than the timeout set by `go test` in
237+
# `make test-postgres` to ensure we receive a trace of running
238+
# goroutines. Setting this to the timeout +5m should work quite well
239+
# even if some of the preceding steps are slow.
240+
timeout-minutes: 25
234241
steps:
235242
- uses: actions/checkout@v3
236243

@@ -281,13 +288,16 @@ jobs:
281288
run: go run scripts/datadog-cireport/main.go gotests.xml
282289

283290
- uses: codecov/codecov-action@v3
291+
# This action has a tendency to error out unexpectedly, it has
292+
# the `fail_ci_if_error` option that defaults to `false`, but
293+
# that is no guarantee, see:
294+
# https://github.com/codecov/codecov-action/issues/788
295+
continue-on-error: true
284296
if: github.actor != 'dependabot[bot]' && !github.event.pull_request.head.repo.fork
285297
with:
286298
token: ${{ secrets.CODECOV_TOKEN }}
287299
files: ./gotests.coverage
288300
flags: unittest-go-postgres-${{ matrix.os }}
289-
# this flakes and sometimes fails the build
290-
fail_ci_if_error: false
291301

292302
deploy:
293303
name: "deploy"
@@ -431,13 +441,16 @@ jobs:
431441
working-directory: site
432442

433443
- uses: codecov/codecov-action@v3
444+
# This action has a tendency to error out unexpectedly, it has
445+
# the `fail_ci_if_error` option that defaults to `false`, but
446+
# that is no guarantee, see:
447+
# https://github.com/codecov/codecov-action/issues/788
448+
continue-on-error: true
434449
if: github.actor != 'dependabot[bot]' && !github.event.pull_request.head.repo.fork
435450
with:
436451
token: ${{ secrets.CODECOV_TOKEN }}
437452
files: ./site/coverage/lcov.info
438453
flags: unittest-js
439-
# this flakes and sometimes fails the build
440-
fail_ci_if_error: false
441454

442455
- name: Upload DataDog Trace
443456
if: always() && github.actor != 'dependabot[bot]' && !github.event.pull_request.head.repo.fork

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,11 @@ test: test-clean
171171
gotestsum -- -v -short ./...
172172
.PHONY: test
173173

174+
# When updating -timeout for this test, keep in sync with
175+
# test-go-postgres (.github/workflows/coder.yaml).
174176
test-postgres: test-clean test-postgres-docker
175177
DB=ci DB_FROM=$(shell go run scripts/migrate-ci/main.go) gotestsum --junitfile="gotests.xml" --packages="./..." -- \
176-
-covermode=atomic -coverprofile="gotests.coverage" -timeout=30m \
178+
-covermode=atomic -coverprofile="gotests.coverage" -timeout=20m \
177179
-coverpkg=./...,github.com/coder/coder/codersdk \
178180
-count=1 -race -failfast
179181
.PHONY: test-postgres

agent/agent_test.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ func TestAgent(t *testing.T) {
206206

207207
t.Run("StartupScript", func(t *testing.T) {
208208
t.Parallel()
209-
tempPath := filepath.Join(os.TempDir(), "content.txt")
209+
tempPath := filepath.Join(t.TempDir(), "content.txt")
210210
content := "somethingnice"
211211
setupAgent(t, agent.Metadata{
212212
StartupScript: fmt.Sprintf("echo %s > %s", content, tempPath),
@@ -324,12 +324,7 @@ func TestAgent(t *testing.T) {
324324
t.Skip("Unix socket forwarding isn't supported on Windows")
325325
}
326326

327-
tmpDir, err := os.MkdirTemp("", "coderd_agent_test_")
328-
require.NoError(t, err, "create temp dir for unix listener")
329-
t.Cleanup(func() {
330-
_ = os.RemoveAll(tmpDir)
331-
})
332-
327+
tmpDir := t.TempDir()
333328
l, err := net.Listen("unix", filepath.Join(tmpDir, "test.sock"))
334329
require.NoError(t, err, "create UDP listener")
335330
return l

cli/cliflag/cliflag.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,33 @@ import (
1717
"strings"
1818
"time"
1919

20+
"github.com/spf13/cobra"
2021
"github.com/spf13/pflag"
2122
)
2223

24+
// IsSetBool returns the value of the boolean flag if it is set.
25+
// It returns false if the flag isn't set or if any error occurs attempting
26+
// to parse the value of the flag.
27+
func IsSetBool(cmd *cobra.Command, name string) bool {
28+
val, ok := IsSet(cmd, name)
29+
if !ok {
30+
return false
31+
}
32+
33+
b, err := strconv.ParseBool(val)
34+
return err == nil && b
35+
}
36+
37+
// IsSet returns the string value of the flag and whether it was set.
38+
func IsSet(cmd *cobra.Command, name string) (string, bool) {
39+
flag := cmd.Flag(name)
40+
if flag == nil {
41+
return "", false
42+
}
43+
44+
return flag.Value.String(), flag.Changed
45+
}
46+
2347
// String sets a string flag on the given flag set.
2448
func String(flagset *pflag.FlagSet, name, shorthand, env, def, usage string) {
2549
v, ok := os.LookupEnv(env)
@@ -67,6 +91,22 @@ func Uint8VarP(flagset *pflag.FlagSet, ptr *uint8, name string, shorthand string
6791
flagset.Uint8VarP(ptr, name, shorthand, uint8(vi64), fmtUsage(usage, env))
6892
}
6993

94+
func Bool(flagset *pflag.FlagSet, name, shorthand, env string, def bool, usage string) {
95+
val, ok := os.LookupEnv(env)
96+
if !ok || val == "" {
97+
flagset.BoolP(name, shorthand, def, fmtUsage(usage, env))
98+
return
99+
}
100+
101+
valb, err := strconv.ParseBool(val)
102+
if err != nil {
103+
flagset.BoolP(name, shorthand, def, fmtUsage(usage, env))
104+
return
105+
}
106+
107+
flagset.BoolP(name, shorthand, valb, fmtUsage(usage, env))
108+
}
109+
70110
// BoolVarP sets a bool flag on the given flag set.
71111
func BoolVarP(flagset *pflag.FlagSet, ptr *bool, name string, shorthand string, env string, def bool, usage string) {
72112
val, ok := os.LookupEnv(env)

cli/configssh.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,18 +89,23 @@ func sshFetchWorkspaceConfigs(ctx context.Context, client *codersdk.Client) ([]s
8989
}
9090

9191
wc := sshWorkspaceConfig{Name: workspace.Name}
92+
var agents []codersdk.WorkspaceAgent
9293
for _, resource := range resources {
9394
if resource.Transition != codersdk.WorkspaceTransitionStart {
9495
continue
9596
}
96-
for _, agent := range resource.Agents {
97-
hostname := workspace.Name
98-
if len(resource.Agents) > 1 {
99-
hostname += "." + agent.Name
100-
}
101-
wc.Hosts = append(wc.Hosts, hostname)
102-
}
97+
agents = append(agents, resource.Agents...)
98+
}
99+
100+
// handle both WORKSPACE and WORKSPACE.AGENT syntax
101+
if len(agents) == 1 {
102+
wc.Hosts = append(wc.Hosts, workspace.Name)
103+
}
104+
for _, agent := range agents {
105+
hostname := workspace.Name + "." + agent.Name
106+
wc.Hosts = append(wc.Hosts, hostname)
103107
}
108+
104109
workspaceConfigs[i] = wc
105110

106111
return nil

cli/configssh_test.go

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package cli_test
22

33
import (
4+
"bufio"
5+
"bytes"
46
"context"
57
"fmt"
68
"io"
@@ -692,3 +694,152 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
692694
})
693695
}
694696
}
697+
698+
func TestConfigSSH_Hostnames(t *testing.T) {
699+
t.Parallel()
700+
701+
type resourceSpec struct {
702+
name string
703+
agents []string
704+
}
705+
tests := []struct {
706+
name string
707+
resources []resourceSpec
708+
expected []string
709+
}{
710+
{
711+
name: "one resource with one agent",
712+
resources: []resourceSpec{
713+
{name: "foo", agents: []string{"agent1"}},
714+
},
715+
expected: []string{"coder.@", "coder.@.agent1"},
716+
},
717+
{
718+
name: "one resource with two agents",
719+
resources: []resourceSpec{
720+
{name: "foo", agents: []string{"agent1", "agent2"}},
721+
},
722+
expected: []string{"coder.@.agent1", "coder.@.agent2"},
723+
},
724+
{
725+
name: "two resources with one agent",
726+
resources: []resourceSpec{
727+
{name: "foo", agents: []string{"agent1"}},
728+
{name: "bar"},
729+
},
730+
expected: []string{"coder.@", "coder.@.agent1"},
731+
},
732+
{
733+
name: "two resources with two agents",
734+
resources: []resourceSpec{
735+
{name: "foo", agents: []string{"agent1"}},
736+
{name: "bar", agents: []string{"agent2"}},
737+
},
738+
expected: []string{"coder.@.agent1", "coder.@.agent2"},
739+
},
740+
}
741+
742+
for _, tt := range tests {
743+
tt := tt
744+
t.Run(tt.name, func(t *testing.T) {
745+
t.Parallel()
746+
747+
var resources []*proto.Resource
748+
for _, resourceSpec := range tt.resources {
749+
resource := &proto.Resource{
750+
Name: resourceSpec.name,
751+
Type: "aws_instance",
752+
}
753+
for _, agentName := range resourceSpec.agents {
754+
resource.Agents = append(resource.Agents, &proto.Agent{
755+
Id: uuid.NewString(),
756+
Name: agentName,
757+
})
758+
}
759+
resources = append(resources, resource)
760+
}
761+
762+
provisionResponse := []*proto.Provision_Response{{
763+
Type: &proto.Provision_Response_Complete{
764+
Complete: &proto.Provision_Complete{
765+
Resources: resources,
766+
},
767+
},
768+
}}
769+
770+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true})
771+
user := coderdtest.CreateFirstUser(t, client)
772+
// authToken := uuid.NewString()
773+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
774+
Parse: echo.ParseComplete,
775+
ProvisionDryRun: provisionResponse,
776+
Provision: provisionResponse,
777+
})
778+
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
779+
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
780+
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
781+
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
782+
783+
sshConfigFile, _ := sshConfigFileNames(t)
784+
785+
cmd, root := clitest.New(t, "config-ssh", "--ssh-config-file", sshConfigFile)
786+
clitest.SetupConfig(t, client, root)
787+
doneChan := make(chan struct{})
788+
pty := ptytest.New(t)
789+
cmd.SetIn(pty.Input())
790+
cmd.SetOut(pty.Output())
791+
go func() {
792+
defer close(doneChan)
793+
err := cmd.Execute()
794+
assert.NoError(t, err)
795+
}()
796+
797+
matches := []struct {
798+
match, write string
799+
}{
800+
{match: "Continue?", write: "yes"},
801+
}
802+
for _, m := range matches {
803+
pty.ExpectMatch(m.match)
804+
pty.WriteLine(m.write)
805+
}
806+
807+
<-doneChan
808+
809+
var expectedHosts []string
810+
for _, hostnamePattern := range tt.expected {
811+
hostname := strings.ReplaceAll(hostnamePattern, "@", workspace.Name)
812+
expectedHosts = append(expectedHosts, hostname)
813+
}
814+
815+
hosts := sshConfigFileParseHosts(t, sshConfigFile)
816+
require.ElementsMatch(t, expectedHosts, hosts)
817+
})
818+
}
819+
}
820+
821+
// sshConfigFileParseHosts reads a file in the format of .ssh/config and extracts
822+
// the hostnames that are listed in "Host" directives.
823+
func sshConfigFileParseHosts(t *testing.T, name string) []string {
824+
t.Helper()
825+
b, err := os.ReadFile(name)
826+
require.NoError(t, err)
827+
828+
var result []string
829+
lineScanner := bufio.NewScanner(bytes.NewBuffer(b))
830+
for lineScanner.Scan() {
831+
line := lineScanner.Text()
832+
line = strings.TrimSpace(line)
833+
834+
tokenScanner := bufio.NewScanner(bytes.NewBufferString(line))
835+
tokenScanner.Split(bufio.ScanWords)
836+
ok := tokenScanner.Scan()
837+
if ok && tokenScanner.Text() == "Host" {
838+
for tokenScanner.Scan() {
839+
result = append(result, tokenScanner.Text())
840+
}
841+
}
842+
}
843+
844+
return result
845+
}

cli/create_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ func TestCreate(t *testing.T) {
192192
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
193193
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
194194
tempDir := t.TempDir()
195+
removeTmpDirUntilSuccessAfterTest(t, tempDir)
195196
parameterFile, _ := os.CreateTemp(tempDir, "testParameterFile*.yaml")
196197
_, _ = parameterFile.WriteString("region: \"bingo\"\nusername: \"boingo\"")
197198
cmd, root := clitest.New(t, "create", "", "--parameter-file", parameterFile.Name())
@@ -217,7 +218,6 @@ func TestCreate(t *testing.T) {
217218
pty.WriteLine(value)
218219
}
219220
<-doneChan
220-
removeTmpDirUntilSuccess(t, tempDir)
221221
})
222222

223223
t.Run("WithParameterFileNotContainingTheValue", func(t *testing.T) {
@@ -234,6 +234,7 @@ func TestCreate(t *testing.T) {
234234
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
235235
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
236236
tempDir := t.TempDir()
237+
removeTmpDirUntilSuccessAfterTest(t, tempDir)
237238
parameterFile, _ := os.CreateTemp(tempDir, "testParameterFile*.yaml")
238239
_, _ = parameterFile.WriteString("zone: \"bananas\"")
239240
cmd, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, "--parameter-file", parameterFile.Name())
@@ -248,7 +249,6 @@ func TestCreate(t *testing.T) {
248249
assert.EqualError(t, err, "Parameter value absent in parameter file for \"region\"!")
249250
}()
250251
<-doneChan
251-
removeTmpDirUntilSuccess(t, tempDir)
252252
})
253253

254254
t.Run("FailedDryRun", func(t *testing.T) {

cli/login.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ func login() *cobra.Command {
7373
// on a very old client.
7474
err = checkVersions(cmd, client)
7575
if err != nil {
76-
return xerrors.Errorf("check versions: %w", err)
76+
// Checking versions isn't a fatal error so we print a warning
77+
// and proceed.
78+
_, _ = fmt.Fprintln(cmd.ErrOrStderr(), cliui.Styles.Warn.Render(err.Error()))
7779
}
7880

7981
hasInitialUser, err := client.HasFirstUser(cmd.Context())

0 commit comments

Comments
 (0)