Skip to content

Commit e641afa

Browse files
author
Christian Weichel
committed
[workspacekit] Move all user namespace setup stuff to its own component
To keep supervisor free from CGO e.g. libcap or libseccomp
1 parent a3135d6 commit e641afa

File tree

15 files changed

+800
-125
lines changed

15 files changed

+800
-125
lines changed

components/supervisor/BUILD.yaml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,14 @@ packages:
1818
config:
1919
buildFlags:
2020
- "-ldflags=-w"
21-
# build with >= go1.16beta1 to make libcap work without CGO. See
22-
# - https://pkg.go.dev/kernel.org/pub/linux/libs/security/libcap/cap, search for allthreadssyscall
23-
# - https://github.com/golang/go/issues/1435
24-
goVersion: go1.16beta1
2521
- name: docker
2622
type: docker
2723
srcs:
2824
- "supervisor-config.json"
2925
deps:
3026
- :app
3127
- components/supervisor/frontend:app
28+
- components/workspacekit/go:app
3229
argdeps:
3330
- imageRepoBase
3431
config:

components/supervisor/go.mod

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ replace github.com/Sirupsen/logrus v1.6.0 => github.com/sirupsen/logrus v1.6.0 /
1111

1212
require (
1313
github.com/Netflix/go-env v0.0.0-20200908232752-3e802f601e28
14-
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 // indirect
1514
github.com/creack/pty v1.1.11
1615
github.com/gitpod-io/gitpod/common-go v0.0.0-00010101000000-000000000000
1716
github.com/gitpod-io/gitpod/content-service v0.0.0-00010101000000-000000000000
@@ -24,20 +23,18 @@ require (
2423
github.com/google/go-cmp v0.5.2
2524
github.com/google/uuid v1.1.4
2625
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1
26+
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
2727
github.com/prometheus/procfs v0.0.8 // indirect
28-
github.com/rootless-containers/rootlesskit v0.10.1
2928
github.com/sirupsen/logrus v1.7.0
3029
github.com/soheilhy/cmux v0.1.4
3130
github.com/spf13/cobra v1.1.1
32-
github.com/ugorji/go v1.1.4 // indirect
33-
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 // indirect
3431
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
3532
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
3633
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061
3734
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
3835
google.golang.org/grpc v1.34.0
3936
google.golang.org/grpc/examples v0.0.0-20200902210233-8630cac324bf // indirect
40-
kernel.org/pub/linux/libs/security/libcap/cap v0.2.46
37+
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
4138
)
4239

4340
replace github.com/gitpod-io/gitpod/common-go => ../common-go // leeway

components/supervisor/go.sum

Lines changed: 2 additions & 98 deletions
Large diffs are not rendered by default.

components/supervisor/leeway.Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ COPY components-supervisor-frontend--app/node_modules/@gitpod/supervisor-fronten
1212
WORKDIR "/.supervisor"
1313
COPY components-supervisor--app/supervisor /.supervisor/supervisor
1414
COPY supervisor-config.json /.supervisor/supervisor-config.json
15+
COPY components-workspacekit--app/workspacekit /.supervisor/workspacekit
1516

1617
ENTRYPOINT ["/.supervisor/supervisor"]

components/workspacekit/BUILD.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
packages:
2+
- name: app
3+
type: go
4+
srcs:
5+
- go.mod
6+
- go.sum
7+
- "**/*.go"
8+
deps:
9+
- components/common-go:lib
10+
- components/ws-daemon-api/go:lib
11+
- components/content-service-api/go:lib
12+
config:
13+
packaging: app
14+
buildCommand: ["go", "build", "-ldflags", "-w -extldflags \"-static\""]

components/supervisor/cmd/rings.go renamed to components/workspacekit/cmd/rings.go

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ import (
1717
"time"
1818

1919
"github.com/gitpod-io/gitpod/common-go/log"
20-
"github.com/gitpod-io/gitpod/supervisor/pkg/supervisor"
2120
daemonapi "github.com/gitpod-io/gitpod/ws-daemon/api"
21+
2222
"github.com/rootless-containers/rootlesskit/pkg/msgutil"
2323
"github.com/rootless-containers/rootlesskit/pkg/sigproxy"
2424
sigproxysignal "github.com/rootless-containers/rootlesskit/pkg/sigproxy/signal"
2525
"github.com/spf13/cobra"
2626
"golang.org/x/sys/unix"
27+
"google.golang.org/grpc"
2728
"kernel.org/pub/linux/libs/security/libcap/cap"
2829
)
2930

@@ -38,9 +39,8 @@ const (
3839
)
3940

4041
var ring0Cmd = &cobra.Command{
41-
Use: "ring0",
42-
Short: "starts the supervisor ring0",
43-
Hidden: true,
42+
Use: "ring0",
43+
Short: "starts ring0 - enter here",
4444
Run: func(_ *cobra.Command, args []string) {
4545
log.Init(ServiceName, Version, true, true)
4646
log := log.WithField("ring", 0)
@@ -56,7 +56,7 @@ var ring0Cmd = &cobra.Command{
5656
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
5757
defer cancel()
5858

59-
client, conn, err := supervisor.ConnectToInWorkspaceDaemonService(ctx)
59+
client, conn, err := connectToInWorkspaceDaemonService(ctx)
6060
if err != nil {
6161
log.WithError(err).Error("cannot connect to daemon")
6262
return
@@ -150,9 +150,8 @@ var ring1Opts struct {
150150
MappingEstablished bool
151151
}
152152
var ring1Cmd = &cobra.Command{
153-
Use: "ring1",
154-
Short: "starts the supervisor ring1",
155-
Hidden: true,
153+
Use: "ring1",
154+
Short: "starts ring1",
156155
Run: func(_cmd *cobra.Command, args []string) {
157156
log.Init(ServiceName, Version, true, true)
158157
log := log.WithField("ring", 1)
@@ -169,7 +168,7 @@ var ring1Cmd = &cobra.Command{
169168
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
170169
defer cancel()
171170

172-
client, conn, err := supervisor.ConnectToInWorkspaceDaemonService(ctx)
171+
client, conn, err := connectToInWorkspaceDaemonService(ctx)
173172
if err != nil {
174173
log.WithError(err).Error("cannot connect to daemon")
175174
failed = true
@@ -325,10 +324,12 @@ var ring1Cmd = &cobra.Command{
325324
},
326325
}
327326

327+
var ring2Opts struct {
328+
SupervisorPath string
329+
}
328330
var ring2Cmd = &cobra.Command{
329-
Use: "ring2",
330-
Short: "starts the supervisor ring2",
331-
Hidden: true,
331+
Use: "ring2",
332+
Short: "starts ring2",
332333
Run: func(_cmd *cobra.Command, args []string) {
333334
log.Init(ServiceName, Version, true, true)
334335
log := log.WithField("ring", 2)
@@ -377,7 +378,7 @@ var ring2Cmd = &cobra.Command{
377378
failed = true
378379
return
379380
}
380-
err = unix.Exec("/proc/self/exe", []string{"supervisor", "run", "--inns"}, os.Environ())
381+
err = unix.Exec(ring2Opts.SupervisorPath, []string{"supervisor", "run", "--inns"}, os.Environ())
381382
if err != nil {
382383
log.WithError(err).Error("cannot exec")
383384
failed = true
@@ -463,10 +464,47 @@ type ringSyncMsg struct {
463464
Rootfs string `json:"rootfs"`
464465
}
465466

467+
// ConnectToInWorkspaceDaemonService attempts to connect to the InWorkspaceService offered by the ws-daemon.
468+
func connectToInWorkspaceDaemonService(ctx context.Context) (daemonapi.InWorkspaceServiceClient, *grpc.ClientConn, error) {
469+
const socketFN = "/.workspace/daemon.sock"
470+
471+
t := time.NewTicker(500 * time.Millisecond)
472+
defer t.Stop()
473+
for {
474+
if _, err := os.Stat(socketFN); err == nil {
475+
break
476+
}
477+
478+
select {
479+
case <-t.C:
480+
continue
481+
case <-ctx.Done():
482+
return nil, nil, fmt.Errorf("socket did not appear before context was canceled")
483+
}
484+
}
485+
486+
conn, err := grpc.DialContext(ctx, "unix://"+socketFN, grpc.WithInsecure())
487+
if err != nil {
488+
return nil, nil, err
489+
}
490+
return daemonapi.NewInWorkspaceServiceClient(conn), conn, nil
491+
}
492+
466493
func init() {
467494
rootCmd.AddCommand(ring0Cmd)
468495
rootCmd.AddCommand(ring1Cmd)
469496
rootCmd.AddCommand(ring2Cmd)
470497

498+
supervisorPath := os.Getenv("GITPOD_WORKSPACEKIT_SUPERVISOR_PATH")
499+
if supervisorPath == "" {
500+
wd, err := os.Getwd()
501+
if err == nil {
502+
supervisorPath = "supervisor"
503+
} else {
504+
supervisorPath = filepath.Join(wd, "supervisor")
505+
}
506+
}
507+
471508
ring1Cmd.Flags().BoolVar(&ring1Opts.MappingEstablished, "mapping-established", false, "true if the UID/GID mapping has already been established")
509+
ring2Cmd.Flags().StringVar(&ring2Opts.SupervisorPath, "supervisor-path", supervisorPath, "path to the supervisor binary (taken from $GITPOD_WORKSPACEKIT_SUPERVISOR_PATH, defaults to '$PWD/supervisor')")
472510
}

components/workspacekit/cmd/root.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) 2020 Gitpod GmbH. All rights reserved.
2+
// Licensed under the GNU Affero General Public License (AGPL).
3+
// See License-AGPL.txt in the project root for license information.
4+
5+
package cmd
6+
7+
import (
8+
"fmt"
9+
"os"
10+
11+
"github.com/gitpod-io/gitpod/common-go/log"
12+
"github.com/spf13/cobra"
13+
)
14+
15+
// rootCmd represents the base command when called without any subcommands
16+
var rootCmd = &cobra.Command{
17+
Use: "workspacekit",
18+
Short: "Prepares a container for running a Gitpod workspace",
19+
}
20+
21+
var (
22+
// ServiceName is the name we use for tracing/logging
23+
ServiceName = "workspacekit"
24+
// Version of this service - set during build
25+
Version = ""
26+
)
27+
28+
// Execute adds all child commands to the root command and sets flags appropriately.
29+
// This is called by main.main(). It only needs to happen once to the rootCmd.
30+
func Execute() {
31+
log.Init(ServiceName, Version, false, true)
32+
33+
if err := rootCmd.Execute(); err != nil {
34+
fmt.Println(err)
35+
os.Exit(1)
36+
}
37+
}

components/workspacekit/go.mod

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
module github.com/gitpod-io/gitpod/workspacekit
2+
3+
go 1.15
4+
5+
replace github.com/seccomp/libseccomp-golang => github.com/kinvolk/libseccomp-golang v0.9.2-0.20201113182948-883917843313
6+
7+
require (
8+
github.com/gitpod-io/gitpod/common-go v0.0.0-00010101000000-000000000000
9+
github.com/gitpod-io/gitpod/ws-daemon/api v0.0.0-00010101000000-000000000000
10+
github.com/rootless-containers/rootlesskit v0.11.1
11+
github.com/seccomp/libseccomp-golang v0.9.1
12+
github.com/spf13/cobra v1.1.1
13+
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78
14+
google.golang.org/grpc v1.34.0
15+
kernel.org/pub/linux/libs/security/libcap/cap v0.2.46
16+
)
17+
18+
replace github.com/gitpod-io/gitpod/common-go => ../common-go // leeway
19+
20+
replace github.com/gitpod-io/gitpod/content-service/api => ../content-service-api/go // leeway
21+
22+
replace github.com/gitpod-io/gitpod/ws-daemon/api => ../ws-daemon-api/go // leeway
23+
24+
replace k8s.io/api => k8s.io/api v0.20.1 // leeway indirect from components/common-go:lib
25+
26+
replace k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.20.1 // leeway indirect from components/common-go:lib
27+
28+
replace k8s.io/apimachinery => k8s.io/apimachinery v0.20.1 // leeway indirect from components/common-go:lib
29+
30+
replace k8s.io/apiserver => k8s.io/apiserver v0.20.1 // leeway indirect from components/common-go:lib
31+
32+
replace k8s.io/cli-runtime => k8s.io/cli-runtime v0.20.1 // leeway indirect from components/common-go:lib
33+
34+
replace k8s.io/client-go => k8s.io/client-go v0.20.1 // leeway indirect from components/common-go:lib
35+
36+
replace k8s.io/cloud-provider => k8s.io/cloud-provider v0.20.1 // leeway indirect from components/common-go:lib
37+
38+
replace k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.20.1 // leeway indirect from components/common-go:lib
39+
40+
replace k8s.io/code-generator => k8s.io/code-generator v0.20.1 // leeway indirect from components/common-go:lib
41+
42+
replace k8s.io/component-base => k8s.io/component-base v0.20.1 // leeway indirect from components/common-go:lib
43+
44+
replace k8s.io/cri-api => k8s.io/cri-api v0.20.1 // leeway indirect from components/common-go:lib
45+
46+
replace k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.20.1 // leeway indirect from components/common-go:lib
47+
48+
replace k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.20.1 // leeway indirect from components/common-go:lib
49+
50+
replace k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.20.1 // leeway indirect from components/common-go:lib
51+
52+
replace k8s.io/kube-proxy => k8s.io/kube-proxy v0.20.1 // leeway indirect from components/common-go:lib
53+
54+
replace k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.20.1 // leeway indirect from components/common-go:lib
55+
56+
replace k8s.io/kubelet => k8s.io/kubelet v0.20.1 // leeway indirect from components/common-go:lib
57+
58+
replace k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.20.1 // leeway indirect from components/common-go:lib
59+
60+
replace k8s.io/metrics => k8s.io/metrics v0.20.1 // leeway indirect from components/common-go:lib
61+
62+
replace k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.20.1 // leeway indirect from components/common-go:lib
63+
64+
replace k8s.io/component-helpers => k8s.io/component-helpers v0.20.1 // leeway indirect from components/common-go:lib
65+
66+
replace k8s.io/controller-manager => k8s.io/controller-manager v0.20.1 // leeway indirect from components/common-go:lib
67+
68+
replace k8s.io/kubectl => k8s.io/kubectl v0.20.1 // leeway indirect from components/common-go:lib
69+
70+
replace k8s.io/mount-utils => k8s.io/mount-utils v0.20.1 // leeway indirect from components/common-go:lib

0 commit comments

Comments
 (0)