Skip to content

Commit bd33e9d

Browse files
committed
[supervisor] Use workspace info
1 parent 41d86a4 commit bd33e9d

File tree

4 files changed

+35
-161
lines changed

4 files changed

+35
-161
lines changed

components/supervisor/go.mod

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,21 @@ require (
3737
)
3838

3939
require (
40+
github.com/gitpod-io/gitpod/ws-daemon/api v0.0.0-00010101000000-000000000000
4041
github.com/prometheus/client_golang v1.12.1
4142
github.com/prometheus/client_model v0.2.0
4243
github.com/prometheus/common v0.32.1
4344
github.com/prometheus/pushgateway v1.4.2
4445
golang.org/x/net v0.0.0-20220412020605-290c469a71a5
4546
)
4647

48+
require (
49+
github.com/fatih/camelcase v1.0.0 // indirect
50+
github.com/fatih/gomodifytags v1.14.0 // indirect
51+
github.com/fatih/structtag v1.2.0 // indirect
52+
golang.org/x/tools v0.1.5 // indirect
53+
)
54+
4755
require (
4856
cloud.google.com/go v0.100.2 // indirect
4957
cloud.google.com/go/compute v1.6.0 // indirect

components/supervisor/go.sum

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,13 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m
134134
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
135135
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
136136
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
137+
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
138+
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
137139
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
140+
github.com/fatih/gomodifytags v1.14.0 h1:4D0ZKYMUgY3bvDn2S7TwOJAsgg5o3UhpwDZtkP9FviU=
141+
github.com/fatih/gomodifytags v1.14.0/go.mod h1:TbUyEjH1Zo0GkJd2Q52oVYqYcJ0eGNqG8bsiOb75P9c=
142+
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
143+
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
138144
github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
139145
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
140146
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@@ -564,6 +570,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
564570
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
565571
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
566572
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
573+
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
567574
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
568575
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
569576
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -733,6 +740,7 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
733740
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
734741
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
735742
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
743+
golang.org/x/tools v0.0.0-20180824175216-6c1c5e93cdc1/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
736744
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
737745
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
738746
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -787,6 +795,7 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
787795
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
788796
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
789797
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
798+
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
790799
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
791800
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
792801
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

components/supervisor/pkg/supervisor/services_test.go

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,6 @@ import (
1818
"github.com/gitpod-io/gitpod/supervisor/api"
1919
)
2020

21-
func TestResourcesStatus(t *testing.T) {
22-
memory, err := resolveMemoryStatus()
23-
if err != nil {
24-
t.Fatal(err)
25-
}
26-
t.Log(memory)
27-
cpu, err := resolveCPUStatus()
28-
if err != nil {
29-
t.Fatal(err)
30-
}
31-
t.Log(cpu)
32-
}
33-
3421
func TestInMemoryTokenServiceGetToken(t *testing.T) {
3522
type Expectation struct {
3623
Resp *api.GetTokenResponse

components/supervisor/pkg/supervisor/top.go

Lines changed: 18 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -6,168 +6,38 @@ package supervisor
66

77
import (
88
"context"
9-
"io/ioutil"
10-
"strconv"
11-
"strings"
12-
"time"
139

1410
"golang.org/x/xerrors"
1511

16-
linuxproc "github.com/c9s/goprocinfo/linux"
1712
"github.com/gitpod-io/gitpod/supervisor/api"
13+
daemonapi "github.com/gitpod-io/gitpod/ws-daemon/api"
14+
"google.golang.org/grpc"
15+
"google.golang.org/grpc/credentials/insecure"
1816
)
1917

2018
// Top provides workspace resources status information.
2119
func Top(ctx context.Context) (*api.ResourcesStatusResponse, error) {
22-
memory, err := resolveMemoryStatus()
23-
if err != nil {
24-
return nil, err
25-
}
26-
cpu, err := resolveCPUStatus()
27-
if err != nil {
28-
return nil, err
29-
}
30-
return &api.ResourcesStatusResponse{
31-
Memory: memory,
32-
Cpu: cpu,
33-
}, nil
34-
}
35-
36-
func resolveMemoryStatus() (*api.ResourceStatus, error) {
37-
content, err := ioutil.ReadFile("/sys/fs/cgroup/memory/memory.limit_in_bytes")
38-
if err != nil {
39-
return nil, xerrors.Errorf("failed to read memory.limit_in_bytes: %w", err)
40-
}
41-
limit, err := strconv.Atoi(strings.TrimSpace(string(content)))
42-
if err != nil {
43-
return nil, xerrors.Errorf("failed to parse memory.limit_in_bytes: %w", err)
44-
}
45-
memInfo, err := linuxproc.ReadMemInfo("/proc/meminfo")
46-
if err != nil {
47-
return nil, xerrors.Errorf("failed to read meminfo: %w", err)
48-
}
49-
memTotal := int(memInfo.MemTotal) * 1024
50-
if limit > memTotal && memTotal > 0 {
51-
limit = memTotal
52-
}
20+
const socketFN = "/.supervisor/info.sock"
5321

54-
content, err = ioutil.ReadFile("/sys/fs/cgroup/memory/memory.usage_in_bytes")
55-
if err != nil {
56-
return nil, xerrors.Errorf("failed to read memory.usage_in_bytes: %w", err)
57-
}
58-
used, err := strconv.Atoi(strings.TrimSpace(string(content)))
22+
conn, err := grpc.DialContext(ctx, "unix://"+socketFN, grpc.WithTransportCredentials(insecure.NewCredentials()))
5923
if err != nil {
60-
return nil, xerrors.Errorf("failed to parse memory.usage_in_bytes: %w", err)
24+
return nil, xerrors.Errorf("could not dial context: %w", err)
6125
}
6226

63-
content, err = ioutil.ReadFile("/sys/fs/cgroup/memory/memory.stat")
27+
client := daemonapi.NewWorkspaceInfoServiceClient(conn)
28+
resp, err := client.WorkspaceInfo(ctx, &daemonapi.WorkspaceInfoRequest{})
6429
if err != nil {
65-
return nil, xerrors.Errorf("failed to read memory.stat: %w", err)
30+
return nil, xerrors.Errorf("could not retrieve workspace info: %w", err)
6631
}
67-
statLines := strings.Split(strings.TrimSpace(string(content)), "\n")
68-
stat := make(map[string]string, len(statLines))
69-
for _, line := range statLines {
70-
tokens := strings.Split(line, " ")
71-
stat[tokens[0]] = tokens[1]
72-
}
73-
// substract evictable memory
74-
value, ok := stat["total_inactive_file"]
75-
if ok {
76-
totalInactiveFile, err := strconv.Atoi(value)
77-
if err != nil {
78-
return nil, xerrors.Errorf("failed to parse total_inactive_file: %w", err)
79-
}
80-
if used < totalInactiveFile {
81-
used = 0
82-
} else {
83-
used -= totalInactiveFile
84-
}
85-
}
86-
return &api.ResourceStatus{
87-
Limit: int64(limit),
88-
Used: int64(used),
89-
}, nil
90-
}
91-
92-
func resolveCPUStatus() (*api.ResourceStatus, error) {
93-
t, err := resolveCPUStat()
94-
if err != nil {
95-
return nil, err
96-
}
97-
98-
time.Sleep(time.Second)
9932

100-
t2, err := resolveCPUStat()
101-
if err != nil {
102-
return nil, err
103-
}
104-
105-
cpuUsage := t2.usage - t.usage
106-
totalTime := t2.uptime - t.uptime
107-
used := cpuUsage / totalTime * 1000
108-
109-
content, err := ioutil.ReadFile("/sys/fs/cgroup/cpu/cpu.cfs_quota_us")
110-
if err != nil {
111-
return nil, xerrors.Errorf("failed to read cpu.cfs_quota_us: %w", err)
112-
}
113-
quota, err := strconv.Atoi(strings.TrimSpace(string(content)))
114-
if err != nil {
115-
return nil, xerrors.Errorf("failed to parse cpu.cfs_quota_us: %w", err)
116-
}
117-
118-
var limit int
119-
if quota > 0 {
120-
content, err = ioutil.ReadFile("/sys/fs/cgroup/cpu/cpu.cfs_period_us")
121-
if err != nil {
122-
return nil, xerrors.Errorf("failed to read cpu.cfs_period_us: %w", err)
123-
}
124-
period, err := strconv.Atoi(strings.TrimSpace(string(content)))
125-
if err != nil {
126-
return nil, xerrors.Errorf("failed to parse cpu.cfs_period_us: %w", err)
127-
}
128-
129-
limit = quota / period * 1000
130-
} else {
131-
content, err = ioutil.ReadFile("/sys/fs/cgroup/cpu/cpuacct.usage_percpu")
132-
if err != nil {
133-
return nil, xerrors.Errorf("failed to read cpuacct.usage_percpu: %w", err)
134-
}
135-
limit = len(strings.Split(strings.TrimSpace(string(content)), " ")) * 1000
136-
}
137-
138-
return &api.ResourceStatus{
139-
Limit: int64(limit),
140-
Used: int64(used),
141-
}, nil
142-
}
143-
144-
type cpuStat struct {
145-
usage float64
146-
uptime float64
147-
}
148-
149-
func resolveCPUStat() (*cpuStat, error) {
150-
content, err := ioutil.ReadFile("/sys/fs/cgroup/cpu/cpuacct.usage")
151-
if err != nil {
152-
return nil, xerrors.Errorf("failed to read cpuacct.usage: %w", err)
153-
}
154-
usage, err := strconv.ParseFloat(strings.TrimSpace(string(content)), 64)
155-
if err != nil {
156-
return nil, xerrors.Errorf("failed to parse cpuacct.usage: %w", err)
157-
}
158-
// convert from nanoseconds to seconds
159-
usage *= 1e-9
160-
content, err = ioutil.ReadFile("/proc/uptime")
161-
if err != nil {
162-
return nil, xerrors.Errorf("failed to read uptime: %w", err)
163-
}
164-
values := strings.Split(strings.TrimSpace(string(content)), " ")
165-
uptime, err := strconv.ParseFloat(values[0], 64)
166-
if err != nil {
167-
return nil, xerrors.Errorf("failed to parse uptime: %w", err)
168-
}
169-
return &cpuStat{
170-
usage: usage,
171-
uptime: uptime,
33+
return &api.ResourcesStatusResponse{
34+
Memory: &api.ResourceStatus{
35+
Limit: resp.Resources.Memory.Limit,
36+
Used: resp.Resources.Memory.Used,
37+
},
38+
Cpu: &api.ResourceStatus{
39+
Limit: resp.Resources.Cpu.Limit,
40+
Used: resp.Resources.Cpu.Used,
41+
},
17242
}, nil
17343
}

0 commit comments

Comments
 (0)