Skip to content

Commit 293a9b0

Browse files
committed
Merge remote-tracking branch 'origin/main' into stevenmasley/oidc_role_sync
2 parents 3ad152f + dc8b731 commit 293a9b0

File tree

176 files changed

+11810
-1406
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

176 files changed

+11810
-1406
lines changed

.github/actions/setup-node/action.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ runs:
1313
cache-dependency-path: "site/yarn.lock"
1414
- name: Install node_modules
1515
shell: bash
16-
run: ./scripts/yarn_install.sh
16+
run: ../scripts/yarn_install.sh
17+
working-directory: site

.github/workflows/pr-deploy.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ concurrency:
2222

2323
jobs:
2424
pr_commented:
25-
if: github.event_name == 'issue_comment' && contains(github.event.comment.body, '/deploy-pr') && github.event.comment.author_association == 'MEMBER' || github.event_name == 'workflow_dispatch'
25+
if: (github.event_name == 'issue_comment' && contains(github.event.comment.body, '/deploy-pr') && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR' || github.event.comment.author_association == 'OWNER')) || github.event_name == 'workflow_dispatch'
2626
outputs:
2727
PR_NUMBER: ${{ steps.pr_number.outputs.PR_NUMBER }}
2828
PR_TITLE: ${{ steps.pr_number.outputs.PR_TITLE }}

.github/workflows/release.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,11 @@ jobs:
259259
env:
260260
CODER_BASE_IMAGE_TAG: ${{ steps.image-base-tag.outputs.tag }}
261261

262+
- name: Generate offline docs
263+
run: |
264+
version="$(./scripts/version.sh)"
265+
make -j build/coder_docs_"$version".tgz
266+
262267
- name: ls build
263268
run: ls -lh build
264269

.prettierrc.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
printWidth: 80
55
semi: false
66
trailingComma: all
7+
useTabs: false
8+
tabWidth: 2
79
overrides:
810
- files:
911
- README.md

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,10 +356,18 @@ build/coder_helm_$(VERSION).tgz:
356356
--output "$@"
357357

358358
site/out/index.html: site/package.json $(shell find ./site $(FIND_EXCLUSIONS) -type f \( -name '*.ts' -o -name '*.tsx' \))
359-
./scripts/yarn_install.sh
360359
cd site
360+
../scripts/yarn_install.sh
361361
yarn build
362362

363+
offlinedocs/out/index.html: $(shell find ./offlinedocs $(FIND_EXCLUSIONS) -type f) $(shell find ./docs $(FIND_EXCLUSIONS) -type f | sed 's: :\\ :g')
364+
cd offlinedocs
365+
../scripts/yarn_install.sh
366+
yarn export
367+
368+
build/coder_docs_$(VERSION).tgz: offlinedocs/out/index.html
369+
tar -czf "$@" -C offlinedocs/out .
370+
363371
install: build/coder_$(VERSION)_$(GOOS)_$(GOARCH)$(GOOS_BIN_EXT)
364372
install_dir="$$(go env GOPATH)/bin"
365373
output_file="$${install_dir}/coder$(GOOS_BIN_EXT)"

cli/clistat/cgroup.go

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"strconv"
77
"strings"
88

9+
"github.com/hashicorp/go-multierror"
910
"github.com/spf13/afero"
1011
"golang.org/x/xerrors"
1112
"tailscale.com/types/ptr"
@@ -15,11 +16,10 @@ import (
1516
// Ref: https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
1617
const (
1718
// CPU usage of all tasks in cgroup in nanoseconds.
18-
cgroupV1CPUAcctUsage = "/sys/fs/cgroup/cpu/cpuacct.usage"
19-
// Alternate path
20-
cgroupV1CPUAcctUsageAlt = "/sys/fs/cgroup/cpu,cpuacct/cpuacct.usage"
19+
cgroupV1CPUAcctUsage = "/sys/fs/cgroup/cpu,cpuacct/cpuacct.usage"
2120
// CFS quota and period for cgroup in MICROseconds
22-
cgroupV1CFSQuotaUs = "/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us"
21+
cgroupV1CFSQuotaUs = "/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us"
22+
// CFS period for cgroup in MICROseconds
2323
cgroupV1CFSPeriodUs = "/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us"
2424
// Maximum memory usable by cgroup in bytes
2525
cgroupV1MemoryMaxUsageBytes = "/sys/fs/cgroup/memory/memory.max_usage_in_bytes"
@@ -153,12 +153,26 @@ func (s *Statter) cGroupV2CPUTotal() (total float64, err error) {
153153
func (s *Statter) cGroupV1CPUTotal() (float64, error) {
154154
periodUs, err := readInt64(s.fs, cgroupV1CFSPeriodUs)
155155
if err != nil {
156-
return 0, xerrors.Errorf("read cpu period: %w", err)
156+
// Try alternate path under /sys/fs/cpu
157+
var merr error
158+
merr = multierror.Append(merr, xerrors.Errorf("get cpu period: %w", err))
159+
periodUs, err = readInt64(s.fs, strings.Replace(cgroupV1CFSPeriodUs, "cpu,cpuacct", "cpu", 1))
160+
if err != nil {
161+
merr = multierror.Append(merr, xerrors.Errorf("get cpu period: %w", err))
162+
return 0, merr
163+
}
157164
}
158165

159166
quotaUs, err := readInt64(s.fs, cgroupV1CFSQuotaUs)
160167
if err != nil {
161-
return 0, xerrors.Errorf("read cpu quota: %w", err)
168+
// Try alternate path under /sys/fs/cpu
169+
var merr error
170+
merr = multierror.Append(merr, xerrors.Errorf("get cpu quota: %w", err))
171+
quotaUs, err = readInt64(s.fs, strings.Replace(cgroupV1CFSQuotaUs, "cpu,cpuacct", "cpu", 1))
172+
if err != nil {
173+
merr = multierror.Append(merr, xerrors.Errorf("get cpu quota: %w", err))
174+
return 0, merr
175+
}
162176
}
163177

164178
if quotaUs < 0 {
@@ -171,18 +185,28 @@ func (s *Statter) cGroupV1CPUTotal() (float64, error) {
171185
func (s *Statter) cGroupV1CPUUsed() (float64, error) {
172186
usageNs, err := readInt64(s.fs, cgroupV1CPUAcctUsage)
173187
if err != nil {
174-
// try alternate path
175-
usageNs, err = readInt64(s.fs, cgroupV1CPUAcctUsageAlt)
188+
// Try alternate path under /sys/fs/cgroup/cpuacct
189+
var merr error
190+
merr = multierror.Append(merr, xerrors.Errorf("read cpu used: %w", err))
191+
usageNs, err = readInt64(s.fs, strings.Replace(cgroupV1CPUAcctUsage, "cpu,cpuacct", "cpuacct", 1))
176192
if err != nil {
177-
return 0, xerrors.Errorf("read cpu used: %w", err)
193+
merr = multierror.Append(merr, xerrors.Errorf("read cpu used: %w", err))
194+
return 0, merr
178195
}
179196
}
180197

181198
// usage is in ns, convert to us
182199
usageNs /= 1000
183200
periodUs, err := readInt64(s.fs, cgroupV1CFSPeriodUs)
184201
if err != nil {
185-
return 0, xerrors.Errorf("get cpu period: %w", err)
202+
// Try alternate path under /sys/fs/cpu
203+
var merr error
204+
merr = multierror.Append(merr, xerrors.Errorf("get cpu period: %w", err))
205+
periodUs, err = readInt64(s.fs, strings.Replace(cgroupV1CFSPeriodUs, "cpu,cpuacct", "cpu", 1))
206+
if err != nil {
207+
merr = multierror.Append(merr, xerrors.Errorf("get cpu period: %w", err))
208+
return 0, merr
209+
}
186210
}
187211

188212
return float64(usageNs) / float64(periodUs), nil

cli/clistat/stat_internal_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,24 @@ func TestStatter(t *testing.T) {
153153
assert.Equal(t, "cores", cpu.Unit)
154154
})
155155

156+
t.Run("ContainerCPU/AltPath", func(t *testing.T) {
157+
t.Parallel()
158+
fs := initFS(t, fsContainerCgroupV1AltPath)
159+
fakeWait := func(time.Duration) {
160+
// Fake 1 second in ns of usage
161+
mungeFS(t, fs, "/sys/fs/cgroup/cpuacct/cpuacct.usage", "100000000")
162+
}
163+
s, err := New(WithFS(fs), withNproc(2), withWait(fakeWait))
164+
require.NoError(t, err)
165+
cpu, err := s.ContainerCPU()
166+
require.NoError(t, err)
167+
require.NotNil(t, cpu)
168+
assert.Equal(t, 1.0, cpu.Used)
169+
require.NotNil(t, cpu.Total)
170+
assert.Equal(t, 2.5, *cpu.Total)
171+
assert.Equal(t, "cores", cpu.Unit)
172+
})
173+
156174
t.Run("ContainerMemory", func(t *testing.T) {
157175
t.Parallel()
158176
fs := initFS(t, fsContainerCgroupV1)
@@ -366,4 +384,15 @@ proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0`,
366384
cgroupV1MemoryUsageBytes: "536870912",
367385
cgroupV1MemoryStat: "total_inactive_file 268435456",
368386
}
387+
fsContainerCgroupV1AltPath = map[string]string{
388+
procOneCgroup: "0::/docker/aa86ac98959eeedeae0ecb6e0c9ddd8ae8b97a9d0fdccccf7ea7a474f4e0bb1f",
389+
procMounts: `overlay / overlay rw,relatime,lowerdir=/some/path:/some/path,upperdir=/some/path:/some/path,workdir=/some/path:/some/path 0 0
390+
proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0`,
391+
"/sys/fs/cgroup/cpuacct/cpuacct.usage": "0",
392+
"/sys/fs/cgroup/cpu/cpu.cfs_quota_us": "250000",
393+
"/sys/fs/cgroup/cpu/cpu.cfs_period_us": "100000",
394+
cgroupV1MemoryMaxUsageBytes: "1073741824",
395+
cgroupV1MemoryUsageBytes: "536870912",
396+
cgroupV1MemoryStat: "total_inactive_file 268435456",
397+
}
369398
)

cli/create.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,6 @@ func (r *RootCmd) create() *clibase.Cmd {
149149
var ttlMillis *int64
150150
if stopAfter > 0 {
151151
ttlMillis = ptr.Ref(stopAfter.Milliseconds())
152-
} else if template.MaxTTLMillis > 0 {
153-
ttlMillis = &template.MaxTTLMillis
154152
}
155153

156154
workspace, err := client.CreateWorkspace(inv.Context(), organization.ID, workspaceOwner, codersdk.CreateWorkspaceRequest{

cli/portforward.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func (r *RootCmd) portForward() *clibase.Cmd {
3232
client := new(codersdk.Client)
3333
cmd := &clibase.Cmd{
3434
Use: "port-forward <workspace>",
35-
Short: "Forward ports from machine to a workspace",
35+
Short: `Forward ports from a workspace to the local machine. Forward ports from a workspace to the local machine. For reverse port forwarding, use "coder ssh -R".`,
3636
Aliases: []string{"tunnel"},
3737
Long: formatExamples(
3838
example{

cli/remoteforward.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
"net"
8+
"regexp"
9+
"strconv"
10+
11+
gossh "golang.org/x/crypto/ssh"
12+
"golang.org/x/xerrors"
13+
14+
"github.com/coder/coder/agent/agentssh"
15+
)
16+
17+
// cookieAddr is a special net.Addr accepted by sshRemoteForward() which includes a
18+
// cookie which is written to the connection before forwarding.
19+
type cookieAddr struct {
20+
net.Addr
21+
cookie []byte
22+
}
23+
24+
// Format:
25+
// remote_port:local_address:local_port
26+
var remoteForwardRegex = regexp.MustCompile(`^(\d+):(.+):(\d+)$`)
27+
28+
func validateRemoteForward(flag string) bool {
29+
return remoteForwardRegex.MatchString(flag)
30+
}
31+
32+
func parseRemoteForward(flag string) (net.Addr, net.Addr, error) {
33+
matches := remoteForwardRegex.FindStringSubmatch(flag)
34+
35+
remotePort, err := strconv.Atoi(matches[1])
36+
if err != nil {
37+
return nil, nil, xerrors.Errorf("remote port is invalid: %w", err)
38+
}
39+
localAddress, err := net.ResolveIPAddr("ip", matches[2])
40+
if err != nil {
41+
return nil, nil, xerrors.Errorf("local address is invalid: %w", err)
42+
}
43+
localPort, err := strconv.Atoi(matches[3])
44+
if err != nil {
45+
return nil, nil, xerrors.Errorf("local port is invalid: %w", err)
46+
}
47+
48+
localAddr := &net.TCPAddr{
49+
IP: localAddress.IP,
50+
Port: localPort,
51+
}
52+
53+
remoteAddr := &net.TCPAddr{
54+
IP: net.ParseIP("127.0.0.1"),
55+
Port: remotePort,
56+
}
57+
return localAddr, remoteAddr, nil
58+
}
59+
60+
// sshRemoteForward starts forwarding connections from a remote listener to a
61+
// local address via SSH in a goroutine.
62+
//
63+
// Accepts a `cookieAddr` as the local address.
64+
func sshRemoteForward(ctx context.Context, stderr io.Writer, sshClient *gossh.Client, localAddr, remoteAddr net.Addr) (io.Closer, error) {
65+
listener, err := sshClient.Listen(remoteAddr.Network(), remoteAddr.String())
66+
if err != nil {
67+
return nil, xerrors.Errorf("listen on remote SSH address %s: %w", remoteAddr.String(), err)
68+
}
69+
70+
go func() {
71+
for {
72+
remoteConn, err := listener.Accept()
73+
if err != nil {
74+
if ctx.Err() == nil {
75+
_, _ = fmt.Fprintf(stderr, "Accept SSH listener connection: %+v\n", err)
76+
}
77+
return
78+
}
79+
80+
go func() {
81+
defer remoteConn.Close()
82+
83+
localConn, err := net.Dial(localAddr.Network(), localAddr.String())
84+
if err != nil {
85+
_, _ = fmt.Fprintf(stderr, "Dial local address %s: %+v\n", localAddr.String(), err)
86+
return
87+
}
88+
defer localConn.Close()
89+
90+
if c, ok := localAddr.(cookieAddr); ok {
91+
_, err = localConn.Write(c.cookie)
92+
if err != nil {
93+
_, _ = fmt.Fprintf(stderr, "Write cookie to local connection: %+v\n", err)
94+
return
95+
}
96+
}
97+
98+
agentssh.Bicopy(ctx, localConn, remoteConn)
99+
}()
100+
}
101+
}()
102+
103+
return listener, nil
104+
}

cli/schedule_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,8 @@ func TestScheduleOverride(t *testing.T) {
316316
stdoutBuf = &bytes.Buffer{}
317317
)
318318
require.Zero(t, template.DefaultTTLMillis)
319-
require.Zero(t, template.MaxTTLMillis)
319+
require.Empty(t, template.RestartRequirement.DaysOfWeek)
320+
require.Zero(t, template.RestartRequirement.Weeks)
320321

321322
// Unset the workspace TTL
322323
err = client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{TTLMillis: nil})

cli/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
496496
FilesRateLimit: filesRateLimit,
497497
HTTPClient: httpClient,
498498
TemplateScheduleStore: &atomic.Pointer[schedule.TemplateScheduleStore]{},
499+
UserQuietHoursScheduleStore: &atomic.Pointer[schedule.UserQuietHoursScheduleStore]{},
499500
SSHConfig: codersdk.SSHConfigResponse{
500501
HostnamePrefix: cfg.SSHConfig.DeploymentName.String(),
501502
SSHConfigOptions: configSSHOptions,

0 commit comments

Comments
 (0)