Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/docker-up/dockerd/args.go
2498 views
1
// Copyright (c) 2025 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 dockerd
6
7
import (
8
"bufio"
9
"encoding/json"
10
"fmt"
11
"os"
12
"strconv"
13
"strings"
14
15
"github.com/sirupsen/logrus"
16
"golang.org/x/xerrors"
17
)
18
19
const (
20
gitpodUserId = 33333
21
)
22
23
type ConvertUserArg func(arg string, value interface{}) ([]string, error)
24
25
var allowedDockerArgs = map[string]ConvertUserArg{
26
"remap-user": convertRemapUser,
27
// TODO(gpl): Why this allow-list instead of a converter lookup only?
28
"proxies": nil,
29
"http-proxy": nil,
30
"https-proxy": nil,
31
}
32
33
func ParseUserArgs(log *logrus.Entry, userArgs string) ([]string, error) {
34
if userArgs == "" {
35
return nil, nil
36
}
37
38
var providedDockerArgs map[string]interface{}
39
if err := json.Unmarshal([]byte(userArgs), &providedDockerArgs); err != nil {
40
return nil, xerrors.Errorf("unable to deserialize docker args: %w", err)
41
}
42
43
return mapUserArgs(log, providedDockerArgs)
44
}
45
46
func mapUserArgs(log *logrus.Entry, jsonObj map[string]interface{}) ([]string, error) {
47
args := []string{}
48
for userArg, userValue := range jsonObj {
49
converter, exists := allowedDockerArgs[userArg]
50
if !exists {
51
// TODO(gpl): Why this allow-list instead of a converter lookup only?
52
continue
53
}
54
55
if converter != nil {
56
cargs, err := converter(userArg, userValue)
57
if err != nil {
58
return nil, xerrors.Errorf("could not convert %v - %v: %w", userArg, userValue, err)
59
}
60
args = append(args, cargs...)
61
continue
62
}
63
64
strValue, ok := (userValue).(string)
65
if ok {
66
args = append(args, fmt.Sprintf("--%s=%s", userArg, strValue))
67
continue
68
}
69
70
bValue, ok := (userValue).(bool)
71
if ok {
72
args = append(args, fmt.Sprintf("--%s=%t", userArg, bValue))
73
continue
74
}
75
76
obj, ok := (userValue).(map[string]interface{})
77
if ok {
78
nestedArgs, err := mapUserArgs(log, obj)
79
if err != nil {
80
return nil, xerrors.Errorf("could not convert nested arg %v - %v: %w", userArg, userValue, err)
81
}
82
args = append(args, nestedArgs...)
83
continue
84
}
85
86
log.WithField("arg", userArg).WithField("value", userValue).Warn("could not map userArg to dockerd argument, skipping.")
87
}
88
89
return args, nil
90
}
91
92
func convertRemapUser(arg string, value interface{}) ([]string, error) {
93
v, ok := (value).(string)
94
if !ok {
95
return nil, xerrors.Errorf("userns-remap expects a string argument")
96
}
97
98
id, err := strconv.Atoi(v)
99
if err != nil {
100
return nil, err
101
}
102
103
for _, f := range []string{"/etc/subuid", "/etc/subgid"} {
104
err := adaptSubid(f, id)
105
if err != nil {
106
return nil, xerrors.Errorf("could not adapt subid files: %w", err)
107
}
108
}
109
110
return []string{"--userns-remap", "gitpod"}, nil
111
}
112
113
func adaptSubid(oldfile string, id int) error {
114
uid, err := os.Open(oldfile)
115
if err != nil {
116
return err
117
}
118
119
newfile, err := os.Create(oldfile + ".new")
120
if err != nil {
121
return err
122
}
123
124
mappingFmt := func(username string, id int, size int) string { return fmt.Sprintf("%s:%d:%d\n", username, id, size) }
125
126
if id != 0 {
127
newfile.WriteString(mappingFmt("gitpod", 1, id))
128
newfile.WriteString(mappingFmt("gitpod", gitpodUserId, 1))
129
} else {
130
newfile.WriteString(mappingFmt("gitpod", gitpodUserId, 1))
131
newfile.WriteString(mappingFmt("gitpod", 1, gitpodUserId-1))
132
newfile.WriteString(mappingFmt("gitpod", gitpodUserId+1, 32200)) // map rest of user ids in the user namespace
133
}
134
135
uidScanner := bufio.NewScanner(uid)
136
for uidScanner.Scan() {
137
l := uidScanner.Text()
138
if !strings.HasPrefix(l, "gitpod") {
139
newfile.WriteString(l + "\n")
140
}
141
}
142
143
if err = os.Rename(newfile.Name(), oldfile); err != nil {
144
return err
145
}
146
147
return nil
148
}
149
150